17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5f4b3ec61Sdh155122 * Common Development and Distribution License (the "License"). 6f4b3ec61Sdh155122 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*bd670b35SErik Nordmark * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/stream.h> 287c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 297c478bd9Sstevel@tonic-gate #include <sys/callb.h> 307c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 317c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 327c478bd9Sstevel@tonic-gate #include <sys/proc.h> 337c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 347c478bd9Sstevel@tonic-gate #include <sys/disp.h> 35f4b3ec61Sdh155122 #include <inet/ip.h> 367c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h> 37f4b3ec61Sdh155122 #include <inet/optcom.h> 38f4b3ec61Sdh155122 #include <inet/keysock.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 41f4b3ec61Sdh155122 * Loader commands for ipsec_loader_sig 427c478bd9Sstevel@tonic-gate */ 437c478bd9Sstevel@tonic-gate #define IPSEC_LOADER_EXITNOW -1 447c478bd9Sstevel@tonic-gate #define IPSEC_LOADER_LOADNOW 1 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate /* 477c478bd9Sstevel@tonic-gate * NOTE: This function is entered w/o holding any STREAMS perimeters. 487c478bd9Sstevel@tonic-gate */ 497c478bd9Sstevel@tonic-gate static void 50f4b3ec61Sdh155122 ipsec_loader(void *arg) 517c478bd9Sstevel@tonic-gate { 527c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo; 537c478bd9Sstevel@tonic-gate boolean_t ipsec_failure = B_FALSE; 54f4b3ec61Sdh155122 ipsec_stack_t *ipss = (ipsec_stack_t *)arg; 557c478bd9Sstevel@tonic-gate 56f4b3ec61Sdh155122 CALLB_CPR_INIT(&cprinfo, &ipss->ipsec_loader_lock, callb_generic_cpr, 577c478bd9Sstevel@tonic-gate "ipsec_loader"); 58f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_loader_lock); 597c478bd9Sstevel@tonic-gate for (;;) { 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * Wait for someone to tell me to continue. 637c478bd9Sstevel@tonic-gate */ 64f4b3ec61Sdh155122 while (ipss->ipsec_loader_sig == IPSEC_LOADER_WAIT) { 657c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 66f4b3ec61Sdh155122 cv_wait(&ipss->ipsec_loader_sig_cv, 67f4b3ec61Sdh155122 &ipss->ipsec_loader_lock); 68f4b3ec61Sdh155122 CALLB_CPR_SAFE_END(&cprinfo, &ipss->ipsec_loader_lock); 697c478bd9Sstevel@tonic-gate } 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* IPSEC_LOADER_EXITNOW implies signal by _fini(). */ 72f4b3ec61Sdh155122 if (ipss->ipsec_loader_sig == IPSEC_LOADER_EXITNOW) { 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * Let user patch ipsec_loader_tid to 757c478bd9Sstevel@tonic-gate * 0 to try again. 767c478bd9Sstevel@tonic-gate */ 77f4b3ec61Sdh155122 ipss->ipsec_loader_state = IPSEC_LOADER_FAILED; 78f4b3ec61Sdh155122 ipss->ipsec_loader_sig = IPSEC_LOADER_WAIT; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* ipsec_loader_lock is held at this point! */ 81f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(&ipss->ipsec_loader_lock)); 827c478bd9Sstevel@tonic-gate CALLB_CPR_EXIT(&cprinfo); 830c0328cdSBill Sommerfeld ASSERT(MUTEX_NOT_HELD(&ipss->ipsec_loader_lock)); 847c478bd9Sstevel@tonic-gate thread_exit(); 857c478bd9Sstevel@tonic-gate } 86f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_loader_lock); 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * Load IPsec, which is done by modloading keysock and calling 907c478bd9Sstevel@tonic-gate * keysock_plumb_ipsec(). 917c478bd9Sstevel@tonic-gate */ 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* Pardon my hardcoding... */ 947c478bd9Sstevel@tonic-gate if (modload("drv", "keysock") == -1) { 957c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "IP: Cannot load keysock."); 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * Only this function can set ipsec_failure. If the 987c478bd9Sstevel@tonic-gate * damage can be repaired, use adb to set this to 997c478bd9Sstevel@tonic-gate * B_FALSE and try again. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate ipsec_failure = B_TRUE; 102f4b3ec61Sdh155122 } else if (keysock_plumb_ipsec(ipss->ipsec_netstack) != 0) { 1037c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "IP: Cannot plumb IPsec."); 1047c478bd9Sstevel@tonic-gate /* 1057c478bd9Sstevel@tonic-gate * Only this function can set ipsec_failure. If the 1067c478bd9Sstevel@tonic-gate * damage can be repaired, use adb to set this to 1077c478bd9Sstevel@tonic-gate * B_FALSE and try again. 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate ipsec_failure = B_TRUE; 1107c478bd9Sstevel@tonic-gate } else { 1117c478bd9Sstevel@tonic-gate ipsec_failure = B_FALSE; 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 114f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_loader_lock); 1157c478bd9Sstevel@tonic-gate if (ipsec_failure) { 116f4b3ec61Sdh155122 if (ipss->ipsec_loader_sig == IPSEC_LOADER_LOADNOW) 117f4b3ec61Sdh155122 ipss->ipsec_loader_sig = IPSEC_LOADER_WAIT; 118f4b3ec61Sdh155122 ipss->ipsec_loader_state = IPSEC_LOADER_FAILED; 1197c478bd9Sstevel@tonic-gate } else { 120f4b3ec61Sdh155122 ipss->ipsec_loader_state = IPSEC_LOADER_SUCCEEDED; 1217c478bd9Sstevel@tonic-gate } 122f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_loader_lock); 1237c478bd9Sstevel@tonic-gate 124f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_loader_lock); 1257c478bd9Sstevel@tonic-gate if (!ipsec_failure) { 1267c478bd9Sstevel@tonic-gate CALLB_CPR_EXIT(&cprinfo); 1270c0328cdSBill Sommerfeld ASSERT(MUTEX_NOT_HELD(&ipss->ipsec_loader_lock)); 1287c478bd9Sstevel@tonic-gate ipsec_register_prov_update(); 1297c478bd9Sstevel@tonic-gate thread_exit(); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * Called from ip_ddi_init() to initialize ipsec loader thread. 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate void 138f4b3ec61Sdh155122 ipsec_loader_init(ipsec_stack_t *ipss) 1397c478bd9Sstevel@tonic-gate { 140f4b3ec61Sdh155122 mutex_init(&ipss->ipsec_loader_lock, NULL, MUTEX_DEFAULT, NULL); 141f4b3ec61Sdh155122 cv_init(&ipss->ipsec_loader_sig_cv, NULL, CV_DEFAULT, NULL); 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* 1457c478bd9Sstevel@tonic-gate * Called from ip_ddi_destroy() to take down ipsec loader thread. 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate void 148f4b3ec61Sdh155122 ipsec_loader_destroy(ipsec_stack_t *ipss) 1497c478bd9Sstevel@tonic-gate { 1507c478bd9Sstevel@tonic-gate kt_did_t tid; 1517c478bd9Sstevel@tonic-gate 152f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_loader_lock); 153f4b3ec61Sdh155122 tid = ipss->ipsec_loader_tid; 1547c478bd9Sstevel@tonic-gate if (tid != 0) { 155f4b3ec61Sdh155122 ipss->ipsec_loader_sig = IPSEC_LOADER_EXITNOW; 156f4b3ec61Sdh155122 cv_signal(&ipss->ipsec_loader_sig_cv); 157f4b3ec61Sdh155122 ipss->ipsec_loader_tid = 0; 1587c478bd9Sstevel@tonic-gate } 159f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_loader_lock); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 1627c478bd9Sstevel@tonic-gate * Wait for ipsec_loader() to finish before we destroy 1637c478bd9Sstevel@tonic-gate * cvs and mutexes. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate if (tid != 0) 1667c478bd9Sstevel@tonic-gate thread_join(tid); 1677c478bd9Sstevel@tonic-gate 168f4b3ec61Sdh155122 mutex_destroy(&ipss->ipsec_loader_lock); 169f4b3ec61Sdh155122 cv_destroy(&ipss->ipsec_loader_sig_cv); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate void 173f4b3ec61Sdh155122 ipsec_loader_start(ipsec_stack_t *ipss) 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate kthread_t *tp; 1767c478bd9Sstevel@tonic-gate 177f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_loader_lock); 1787c478bd9Sstevel@tonic-gate 179f4b3ec61Sdh155122 if (ipss->ipsec_loader_tid == 0) { 180f4b3ec61Sdh155122 tp = thread_create(NULL, 0, ipsec_loader, ipss, 0, &p0, 1817c478bd9Sstevel@tonic-gate TS_RUN, MAXCLSYSPRI); 182f4b3ec61Sdh155122 ipss->ipsec_loader_tid = tp->t_did; 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate /* Else we lost the race, oh well. */ 185f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_loader_lock); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate void 189f4b3ec61Sdh155122 ipsec_loader_loadnow(ipsec_stack_t *ipss) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * It is possible that an algorithm update message was 1937c478bd9Sstevel@tonic-gate * received before IPsec is loaded. Such messages are 1947c478bd9Sstevel@tonic-gate * saved in spdsock for later processing. Since IPsec 1957c478bd9Sstevel@tonic-gate * loading can be initiated by interfaces different 1967c478bd9Sstevel@tonic-gate * than spdsock, we must trigger the processing of 1977c478bd9Sstevel@tonic-gate * update messages from the ipsec loader. 1987c478bd9Sstevel@tonic-gate */ 199f4b3ec61Sdh155122 spdsock_update_pending_algs(ipss->ipsec_netstack); 2007c478bd9Sstevel@tonic-gate 201f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_loader_lock); 202f4b3ec61Sdh155122 if ((ipss->ipsec_loader_state == IPSEC_LOADER_WAIT) && 203f4b3ec61Sdh155122 (ipss->ipsec_loader_sig == IPSEC_LOADER_WAIT)) { 204f4b3ec61Sdh155122 ipss->ipsec_loader_sig = IPSEC_LOADER_LOADNOW; 205f4b3ec61Sdh155122 cv_signal(&ipss->ipsec_loader_sig_cv); 2067c478bd9Sstevel@tonic-gate } 207f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_loader_lock); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * Dummy callback routine (placeholder) to avoid keysock plumbing 2127c478bd9Sstevel@tonic-gate * races. Used in conjunction with qtimeout() and qwait() to wait 2137c478bd9Sstevel@tonic-gate * until ipsec has loaded -- the qwait() in ipsec_loader_loadwait will 2147c478bd9Sstevel@tonic-gate * wake up once this routine returns. 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2187c478bd9Sstevel@tonic-gate static void 2197c478bd9Sstevel@tonic-gate loader_nop(void *ignoreme) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate /* 2247c478bd9Sstevel@tonic-gate * Called from keysock driver open to delay until ipsec is done loading. 2257c478bd9Sstevel@tonic-gate * Returns B_TRUE if it worked, B_FALSE if it didn't. 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate boolean_t 228f4b3ec61Sdh155122 ipsec_loader_wait(queue_t *q, ipsec_stack_t *ipss) 2297c478bd9Sstevel@tonic-gate { 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * 30ms delay per loop is arbitrary; it takes ~300ms to 2327c478bd9Sstevel@tonic-gate * load and plumb ipsec on an ultra-1. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate 235f4b3ec61Sdh155122 while (ipss->ipsec_loader_state == IPSEC_LOADER_WAIT) { 2367c478bd9Sstevel@tonic-gate (void) qtimeout(q, loader_nop, 0, drv_usectohz(30000)); 2377c478bd9Sstevel@tonic-gate qwait(q); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 240f4b3ec61Sdh155122 return (ipss->ipsec_loader_state == IPSEC_LOADER_SUCCEEDED); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate /* 2447c478bd9Sstevel@tonic-gate * Just check to see if IPsec is loaded (or not). 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate boolean_t 247f4b3ec61Sdh155122 ipsec_loaded(ipsec_stack_t *ipss) 2487c478bd9Sstevel@tonic-gate { 249f4b3ec61Sdh155122 return (ipss->ipsec_loader_state == IPSEC_LOADER_SUCCEEDED); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * Check to see if IPsec loading failed. 2547c478bd9Sstevel@tonic-gate */ 2557c478bd9Sstevel@tonic-gate boolean_t 256f4b3ec61Sdh155122 ipsec_failed(ipsec_stack_t *ipss) 2577c478bd9Sstevel@tonic-gate { 258f4b3ec61Sdh155122 return (ipss->ipsec_loader_state == IPSEC_LOADER_FAILED); 2597c478bd9Sstevel@tonic-gate } 260