4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/stream.h>
28 #include <sys/sysmacros.h>
29 #include <sys/callb.h>
31 #include <sys/sunddi.h>
33 #include <sys/modctl.h>
36 #include <inet/ipsec_impl.h>
37 #include <inet/optcom.h>
38 #include <inet/keysock.h>
41 * Loader commands for ipsec_loader_sig
43 #define IPSEC_LOADER_EXITNOW -1
44 #define IPSEC_LOADER_LOADNOW 1
47 * NOTE: This function is entered w/o holding any STREAMS perimeters.
50 ipsec_loader(void *arg
)
53 boolean_t ipsec_failure
= B_FALSE
;
54 ipsec_stack_t
*ipss
= (ipsec_stack_t
*)arg
;
56 CALLB_CPR_INIT(&cprinfo
, &ipss
->ipsec_loader_lock
, callb_generic_cpr
,
58 mutex_enter(&ipss
->ipsec_loader_lock
);
62 * Wait for someone to tell me to continue.
64 while (ipss
->ipsec_loader_sig
== IPSEC_LOADER_WAIT
) {
65 CALLB_CPR_SAFE_BEGIN(&cprinfo
);
66 cv_wait(&ipss
->ipsec_loader_sig_cv
,
67 &ipss
->ipsec_loader_lock
);
68 CALLB_CPR_SAFE_END(&cprinfo
, &ipss
->ipsec_loader_lock
);
71 /* IPSEC_LOADER_EXITNOW implies signal by _fini(). */
72 if (ipss
->ipsec_loader_sig
== IPSEC_LOADER_EXITNOW
) {
74 * Let user patch ipsec_loader_tid to
77 ipss
->ipsec_loader_state
= IPSEC_LOADER_FAILED
;
78 ipss
->ipsec_loader_sig
= IPSEC_LOADER_WAIT
;
80 /* ipsec_loader_lock is held at this point! */
81 ASSERT(MUTEX_HELD(&ipss
->ipsec_loader_lock
));
82 CALLB_CPR_EXIT(&cprinfo
);
83 ASSERT(MUTEX_NOT_HELD(&ipss
->ipsec_loader_lock
));
86 mutex_exit(&ipss
->ipsec_loader_lock
);
89 * Load IPsec, which is done by modloading keysock and calling
90 * keysock_plumb_ipsec().
93 /* Pardon my hardcoding... */
94 if (modload("drv", "keysock") == -1) {
95 cmn_err(CE_WARN
, "IP: Cannot load keysock.");
97 * Only this function can set ipsec_failure. If the
98 * damage can be repaired, use adb to set this to
99 * B_FALSE and try again.
101 ipsec_failure
= B_TRUE
;
102 } else if (keysock_plumb_ipsec(ipss
->ipsec_netstack
) != 0) {
103 cmn_err(CE_WARN
, "IP: Cannot plumb IPsec.");
105 * Only this function can set ipsec_failure. If the
106 * damage can be repaired, use adb to set this to
107 * B_FALSE and try again.
109 ipsec_failure
= B_TRUE
;
111 ipsec_failure
= B_FALSE
;
114 mutex_enter(&ipss
->ipsec_loader_lock
);
116 if (ipss
->ipsec_loader_sig
== IPSEC_LOADER_LOADNOW
)
117 ipss
->ipsec_loader_sig
= IPSEC_LOADER_WAIT
;
118 ipss
->ipsec_loader_state
= IPSEC_LOADER_FAILED
;
120 ipss
->ipsec_loader_state
= IPSEC_LOADER_SUCCEEDED
;
122 mutex_exit(&ipss
->ipsec_loader_lock
);
124 mutex_enter(&ipss
->ipsec_loader_lock
);
125 if (!ipsec_failure
) {
126 CALLB_CPR_EXIT(&cprinfo
);
127 ASSERT(MUTEX_NOT_HELD(&ipss
->ipsec_loader_lock
));
128 ipsec_register_prov_update();
135 * Called from ip_ddi_init() to initialize ipsec loader thread.
138 ipsec_loader_init(ipsec_stack_t
*ipss
)
140 mutex_init(&ipss
->ipsec_loader_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
141 cv_init(&ipss
->ipsec_loader_sig_cv
, NULL
, CV_DEFAULT
, NULL
);
145 * Called from ip_ddi_destroy() to take down ipsec loader thread.
148 ipsec_loader_destroy(ipsec_stack_t
*ipss
)
152 mutex_enter(&ipss
->ipsec_loader_lock
);
153 tid
= ipss
->ipsec_loader_tid
;
155 ipss
->ipsec_loader_sig
= IPSEC_LOADER_EXITNOW
;
156 cv_signal(&ipss
->ipsec_loader_sig_cv
);
157 ipss
->ipsec_loader_tid
= 0;
159 mutex_exit(&ipss
->ipsec_loader_lock
);
162 * Wait for ipsec_loader() to finish before we destroy
168 mutex_destroy(&ipss
->ipsec_loader_lock
);
169 cv_destroy(&ipss
->ipsec_loader_sig_cv
);
173 ipsec_loader_start(ipsec_stack_t
*ipss
)
177 mutex_enter(&ipss
->ipsec_loader_lock
);
179 if (ipss
->ipsec_loader_tid
== 0) {
180 tp
= thread_create(NULL
, 0, ipsec_loader
, ipss
, 0, &p0
,
181 TS_RUN
, MAXCLSYSPRI
);
182 ipss
->ipsec_loader_tid
= tp
->t_did
;
184 /* Else we lost the race, oh well. */
185 mutex_exit(&ipss
->ipsec_loader_lock
);
189 ipsec_loader_loadnow(ipsec_stack_t
*ipss
)
192 * It is possible that an algorithm update message was
193 * received before IPsec is loaded. Such messages are
194 * saved in spdsock for later processing. Since IPsec
195 * loading can be initiated by interfaces different
196 * than spdsock, we must trigger the processing of
197 * update messages from the ipsec loader.
199 spdsock_update_pending_algs(ipss
->ipsec_netstack
);
201 mutex_enter(&ipss
->ipsec_loader_lock
);
202 if ((ipss
->ipsec_loader_state
== IPSEC_LOADER_WAIT
) &&
203 (ipss
->ipsec_loader_sig
== IPSEC_LOADER_WAIT
)) {
204 ipss
->ipsec_loader_sig
= IPSEC_LOADER_LOADNOW
;
205 cv_signal(&ipss
->ipsec_loader_sig_cv
);
207 mutex_exit(&ipss
->ipsec_loader_lock
);
211 * Dummy callback routine (placeholder) to avoid keysock plumbing
212 * races. Used in conjunction with qtimeout() and qwait() to wait
213 * until ipsec has loaded -- the qwait() in ipsec_loader_loadwait will
214 * wake up once this routine returns.
219 loader_nop(void *ignoreme
)
224 * Called from keysock driver open to delay until ipsec is done loading.
225 * Returns B_TRUE if it worked, B_FALSE if it didn't.
228 ipsec_loader_wait(queue_t
*q
, ipsec_stack_t
*ipss
)
231 * 30ms delay per loop is arbitrary; it takes ~300ms to
232 * load and plumb ipsec on an ultra-1.
235 while (ipss
->ipsec_loader_state
== IPSEC_LOADER_WAIT
) {
236 (void) qtimeout(q
, loader_nop
, 0, drv_usectohz(30000));
240 return (ipss
->ipsec_loader_state
== IPSEC_LOADER_SUCCEEDED
);
244 * Just check to see if IPsec is loaded (or not).
247 ipsec_loaded(ipsec_stack_t
*ipss
)
249 return (ipss
->ipsec_loader_state
== IPSEC_LOADER_SUCCEEDED
);
253 * Check to see if IPsec loading failed.
256 ipsec_failed(ipsec_stack_t
*ipss
)
258 return (ipss
->ipsec_loader_state
== IPSEC_LOADER_FAILED
);