1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 3448 dh155122 * Common Development and Distribution License (the "License"). 6 3448 dh155122 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 11042 Erik * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #include <sys/types.h> 27 0 stevel #include <sys/stream.h> 28 0 stevel #include <sys/sysmacros.h> 29 0 stevel #include <sys/callb.h> 30 0 stevel #include <sys/ddi.h> 31 0 stevel #include <sys/sunddi.h> 32 0 stevel #include <sys/proc.h> 33 0 stevel #include <sys/modctl.h> 34 0 stevel #include <sys/disp.h> 35 3448 dh155122 #include <inet/ip.h> 36 0 stevel #include <inet/ipsec_impl.h> 37 3448 dh155122 #include <inet/optcom.h> 38 3448 dh155122 #include <inet/keysock.h> 39 0 stevel 40 0 stevel /* 41 3448 dh155122 * Loader commands for ipsec_loader_sig 42 0 stevel */ 43 0 stevel #define IPSEC_LOADER_EXITNOW -1 44 0 stevel #define IPSEC_LOADER_LOADNOW 1 45 0 stevel 46 0 stevel /* 47 0 stevel * NOTE: This function is entered w/o holding any STREAMS perimeters. 48 0 stevel */ 49 0 stevel static void 50 3448 dh155122 ipsec_loader(void *arg) 51 0 stevel { 52 0 stevel callb_cpr_t cprinfo; 53 0 stevel boolean_t ipsec_failure = B_FALSE; 54 3448 dh155122 ipsec_stack_t *ipss = (ipsec_stack_t *)arg; 55 0 stevel 56 3448 dh155122 CALLB_CPR_INIT(&cprinfo, &ipss->ipsec_loader_lock, callb_generic_cpr, 57 0 stevel "ipsec_loader"); 58 3448 dh155122 mutex_enter(&ipss->ipsec_loader_lock); 59 0 stevel for (;;) { 60 0 stevel 61 0 stevel /* 62 0 stevel * Wait for someone to tell me to continue. 63 0 stevel */ 64 3448 dh155122 while (ipss->ipsec_loader_sig == IPSEC_LOADER_WAIT) { 65 0 stevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 66 3448 dh155122 cv_wait(&ipss->ipsec_loader_sig_cv, 67 3448 dh155122 &ipss->ipsec_loader_lock); 68 3448 dh155122 CALLB_CPR_SAFE_END(&cprinfo, &ipss->ipsec_loader_lock); 69 0 stevel } 70 0 stevel 71 0 stevel /* IPSEC_LOADER_EXITNOW implies signal by _fini(). */ 72 3448 dh155122 if (ipss->ipsec_loader_sig == IPSEC_LOADER_EXITNOW) { 73 0 stevel /* 74 0 stevel * Let user patch ipsec_loader_tid to 75 0 stevel * 0 to try again. 76 0 stevel */ 77 3448 dh155122 ipss->ipsec_loader_state = IPSEC_LOADER_FAILED; 78 3448 dh155122 ipss->ipsec_loader_sig = IPSEC_LOADER_WAIT; 79 0 stevel 80 0 stevel /* ipsec_loader_lock is held at this point! */ 81 3448 dh155122 ASSERT(MUTEX_HELD(&ipss->ipsec_loader_lock)); 82 0 stevel CALLB_CPR_EXIT(&cprinfo); 83 7373 sommerfeld ASSERT(MUTEX_NOT_HELD(&ipss->ipsec_loader_lock)); 84 0 stevel thread_exit(); 85 0 stevel } 86 3448 dh155122 mutex_exit(&ipss->ipsec_loader_lock); 87 0 stevel 88 0 stevel /* 89 0 stevel * Load IPsec, which is done by modloading keysock and calling 90 0 stevel * keysock_plumb_ipsec(). 91 0 stevel */ 92 0 stevel 93 0 stevel /* Pardon my hardcoding... */ 94 0 stevel if (modload("drv", "keysock") == -1) { 95 0 stevel cmn_err(CE_WARN, "IP: Cannot load keysock."); 96 0 stevel /* 97 0 stevel * Only this function can set ipsec_failure. If the 98 0 stevel * damage can be repaired, use adb to set this to 99 0 stevel * B_FALSE and try again. 100 0 stevel */ 101 0 stevel ipsec_failure = B_TRUE; 102 3448 dh155122 } else if (keysock_plumb_ipsec(ipss->ipsec_netstack) != 0) { 103 0 stevel cmn_err(CE_WARN, "IP: Cannot plumb IPsec."); 104 0 stevel /* 105 0 stevel * Only this function can set ipsec_failure. If the 106 0 stevel * damage can be repaired, use adb to set this to 107 0 stevel * B_FALSE and try again. 108 0 stevel */ 109 0 stevel ipsec_failure = B_TRUE; 110 0 stevel } else { 111 0 stevel ipsec_failure = B_FALSE; 112 0 stevel } 113 0 stevel 114 3448 dh155122 mutex_enter(&ipss->ipsec_loader_lock); 115 0 stevel if (ipsec_failure) { 116 3448 dh155122 if (ipss->ipsec_loader_sig == IPSEC_LOADER_LOADNOW) 117 3448 dh155122 ipss->ipsec_loader_sig = IPSEC_LOADER_WAIT; 118 3448 dh155122 ipss->ipsec_loader_state = IPSEC_LOADER_FAILED; 119 0 stevel } else { 120 3448 dh155122 ipss->ipsec_loader_state = IPSEC_LOADER_SUCCEEDED; 121 0 stevel } 122 3448 dh155122 mutex_exit(&ipss->ipsec_loader_lock); 123 0 stevel 124 3448 dh155122 mutex_enter(&ipss->ipsec_loader_lock); 125 0 stevel if (!ipsec_failure) { 126 0 stevel CALLB_CPR_EXIT(&cprinfo); 127 7373 sommerfeld ASSERT(MUTEX_NOT_HELD(&ipss->ipsec_loader_lock)); 128 0 stevel ipsec_register_prov_update(); 129 0 stevel thread_exit(); 130 0 stevel } 131 0 stevel } 132 0 stevel } 133 0 stevel 134 0 stevel /* 135 0 stevel * Called from ip_ddi_init() to initialize ipsec loader thread. 136 0 stevel */ 137 0 stevel void 138 3448 dh155122 ipsec_loader_init(ipsec_stack_t *ipss) 139 0 stevel { 140 3448 dh155122 mutex_init(&ipss->ipsec_loader_lock, NULL, MUTEX_DEFAULT, NULL); 141 3448 dh155122 cv_init(&ipss->ipsec_loader_sig_cv, NULL, CV_DEFAULT, NULL); 142 0 stevel } 143 0 stevel 144 0 stevel /* 145 0 stevel * Called from ip_ddi_destroy() to take down ipsec loader thread. 146 0 stevel */ 147 0 stevel void 148 3448 dh155122 ipsec_loader_destroy(ipsec_stack_t *ipss) 149 0 stevel { 150 0 stevel kt_did_t tid; 151 0 stevel 152 3448 dh155122 mutex_enter(&ipss->ipsec_loader_lock); 153 3448 dh155122 tid = ipss->ipsec_loader_tid; 154 0 stevel if (tid != 0) { 155 3448 dh155122 ipss->ipsec_loader_sig = IPSEC_LOADER_EXITNOW; 156 3448 dh155122 cv_signal(&ipss->ipsec_loader_sig_cv); 157 3448 dh155122 ipss->ipsec_loader_tid = 0; 158 0 stevel } 159 3448 dh155122 mutex_exit(&ipss->ipsec_loader_lock); 160 0 stevel 161 0 stevel /* 162 0 stevel * Wait for ipsec_loader() to finish before we destroy 163 0 stevel * cvs and mutexes. 164 0 stevel */ 165 0 stevel if (tid != 0) 166 0 stevel thread_join(tid); 167 0 stevel 168 3448 dh155122 mutex_destroy(&ipss->ipsec_loader_lock); 169 3448 dh155122 cv_destroy(&ipss->ipsec_loader_sig_cv); 170 0 stevel } 171 0 stevel 172 0 stevel void 173 3448 dh155122 ipsec_loader_start(ipsec_stack_t *ipss) 174 0 stevel { 175 0 stevel kthread_t *tp; 176 0 stevel 177 3448 dh155122 mutex_enter(&ipss->ipsec_loader_lock); 178 0 stevel 179 3448 dh155122 if (ipss->ipsec_loader_tid == 0) { 180 3448 dh155122 tp = thread_create(NULL, 0, ipsec_loader, ipss, 0, &p0, 181 0 stevel TS_RUN, MAXCLSYSPRI); 182 3448 dh155122 ipss->ipsec_loader_tid = tp->t_did; 183 0 stevel } 184 0 stevel /* Else we lost the race, oh well. */ 185 3448 dh155122 mutex_exit(&ipss->ipsec_loader_lock); 186 0 stevel } 187 0 stevel 188 0 stevel void 189 3448 dh155122 ipsec_loader_loadnow(ipsec_stack_t *ipss) 190 0 stevel { 191 0 stevel /* 192 0 stevel * It is possible that an algorithm update message was 193 0 stevel * received before IPsec is loaded. Such messages are 194 0 stevel * saved in spdsock for later processing. Since IPsec 195 0 stevel * loading can be initiated by interfaces different 196 0 stevel * than spdsock, we must trigger the processing of 197 0 stevel * update messages from the ipsec loader. 198 0 stevel */ 199 3448 dh155122 spdsock_update_pending_algs(ipss->ipsec_netstack); 200 0 stevel 201 3448 dh155122 mutex_enter(&ipss->ipsec_loader_lock); 202 3448 dh155122 if ((ipss->ipsec_loader_state == IPSEC_LOADER_WAIT) && 203 3448 dh155122 (ipss->ipsec_loader_sig == IPSEC_LOADER_WAIT)) { 204 3448 dh155122 ipss->ipsec_loader_sig = IPSEC_LOADER_LOADNOW; 205 3448 dh155122 cv_signal(&ipss->ipsec_loader_sig_cv); 206 0 stevel } 207 3448 dh155122 mutex_exit(&ipss->ipsec_loader_lock); 208 0 stevel } 209 0 stevel 210 0 stevel /* 211 0 stevel * Dummy callback routine (placeholder) to avoid keysock plumbing 212 0 stevel * races. Used in conjunction with qtimeout() and qwait() to wait 213 0 stevel * until ipsec has loaded -- the qwait() in ipsec_loader_loadwait will 214 0 stevel * wake up once this routine returns. 215 0 stevel */ 216 0 stevel 217 0 stevel /* ARGSUSED */ 218 0 stevel static void 219 0 stevel loader_nop(void *ignoreme) 220 0 stevel { 221 0 stevel } 222 0 stevel 223 0 stevel /* 224 0 stevel * Called from keysock driver open to delay until ipsec is done loading. 225 0 stevel * Returns B_TRUE if it worked, B_FALSE if it didn't. 226 0 stevel */ 227 0 stevel boolean_t 228 3448 dh155122 ipsec_loader_wait(queue_t *q, ipsec_stack_t *ipss) 229 0 stevel { 230 0 stevel /* 231 0 stevel * 30ms delay per loop is arbitrary; it takes ~300ms to 232 0 stevel * load and plumb ipsec on an ultra-1. 233 0 stevel */ 234 0 stevel 235 3448 dh155122 while (ipss->ipsec_loader_state == IPSEC_LOADER_WAIT) { 236 0 stevel (void) qtimeout(q, loader_nop, 0, drv_usectohz(30000)); 237 0 stevel qwait(q); 238 0 stevel } 239 0 stevel 240 3448 dh155122 return (ipss->ipsec_loader_state == IPSEC_LOADER_SUCCEEDED); 241 0 stevel } 242 0 stevel 243 0 stevel /* 244 0 stevel * Just check to see if IPsec is loaded (or not). 245 0 stevel */ 246 0 stevel boolean_t 247 3448 dh155122 ipsec_loaded(ipsec_stack_t *ipss) 248 0 stevel { 249 3448 dh155122 return (ipss->ipsec_loader_state == IPSEC_LOADER_SUCCEEDED); 250 0 stevel } 251 0 stevel 252 0 stevel /* 253 0 stevel * Check to see if IPsec loading failed. 254 0 stevel */ 255 0 stevel boolean_t 256 3448 dh155122 ipsec_failed(ipsec_stack_t *ipss) 257 0 stevel { 258 3448 dh155122 return (ipss->ipsec_loader_state == IPSEC_LOADER_FAILED); 259 0 stevel } 260