Home | History | Annotate | Download | only in ip
      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