10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52465Sdanmcd * Common Development and Distribution License (the "License"). 62465Sdanmcd * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 228730Sdanmcd@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/param.h> 270Sstevel@tonic-gate #include <sys/types.h> 280Sstevel@tonic-gate #include <sys/stream.h> 290Sstevel@tonic-gate #include <sys/strsubr.h> 300Sstevel@tonic-gate #include <sys/strsun.h> 310Sstevel@tonic-gate #include <sys/stropts.h> 320Sstevel@tonic-gate #include <sys/vnode.h> 333448Sdh155122 #include <sys/zone.h> 340Sstevel@tonic-gate #include <sys/strlog.h> 350Sstevel@tonic-gate #include <sys/sysmacros.h> 360Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 370Sstevel@tonic-gate #include <sys/tihdr.h> 380Sstevel@tonic-gate #include <sys/timod.h> 390Sstevel@tonic-gate #include <sys/tiuser.h> 400Sstevel@tonic-gate #include <sys/ddi.h> 410Sstevel@tonic-gate #include <sys/sunddi.h> 420Sstevel@tonic-gate #include <sys/sunldi.h> 430Sstevel@tonic-gate #include <sys/file.h> 440Sstevel@tonic-gate #include <sys/modctl.h> 450Sstevel@tonic-gate #include <sys/debug.h> 460Sstevel@tonic-gate #include <sys/kmem.h> 470Sstevel@tonic-gate #include <sys/cmn_err.h> 480Sstevel@tonic-gate #include <sys/proc.h> 490Sstevel@tonic-gate #include <sys/suntpi.h> 500Sstevel@tonic-gate #include <sys/atomic.h> 510Sstevel@tonic-gate #include <sys/mkdev.h> 520Sstevel@tonic-gate #include <sys/policy.h> 533448Sdh155122 #include <sys/disp.h> 540Sstevel@tonic-gate 550Sstevel@tonic-gate #include <sys/socket.h> 560Sstevel@tonic-gate #include <netinet/in.h> 570Sstevel@tonic-gate #include <net/pfkeyv2.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate #include <inet/common.h> 600Sstevel@tonic-gate #include <netinet/ip6.h> 610Sstevel@tonic-gate #include <inet/ip.h> 628348SEric.Yu@Sun.COM #include <inet/proto_set.h> 630Sstevel@tonic-gate #include <inet/nd.h> 640Sstevel@tonic-gate #include <inet/optcom.h> 650Sstevel@tonic-gate #include <inet/ipsec_info.h> 660Sstevel@tonic-gate #include <inet/ipsec_impl.h> 670Sstevel@tonic-gate #include <inet/keysock.h> 680Sstevel@tonic-gate 690Sstevel@tonic-gate #include <sys/isa_defs.h> 700Sstevel@tonic-gate 710Sstevel@tonic-gate /* 720Sstevel@tonic-gate * This is a transport provider for the PF_KEY key mangement socket. 730Sstevel@tonic-gate * (See RFC 2367 for details.) 740Sstevel@tonic-gate * Downstream messages are wrapped in a keysock consumer interface KEYSOCK_IN 750Sstevel@tonic-gate * messages (see ipsec_info.h), and passed to the appropriate consumer. 760Sstevel@tonic-gate * Upstream messages are generated for all open PF_KEY sockets, when 770Sstevel@tonic-gate * appropriate, as well as the sender (as long as SO_USELOOPBACK is enabled) 780Sstevel@tonic-gate * in reply to downstream messages. 790Sstevel@tonic-gate * 800Sstevel@tonic-gate * Upstream messages must be created asynchronously for the following 810Sstevel@tonic-gate * situations: 820Sstevel@tonic-gate * 830Sstevel@tonic-gate * 1.) A keysock consumer requires an SA, and there is currently none. 840Sstevel@tonic-gate * 2.) An SA expires, either hard or soft lifetime. 850Sstevel@tonic-gate * 3.) Other events a consumer deems fit. 860Sstevel@tonic-gate * 870Sstevel@tonic-gate * The MT model of this is PERMOD, with shared put procedures. Two types of 880Sstevel@tonic-gate * messages, SADB_FLUSH and SADB_DUMP, need to lock down the perimeter to send 890Sstevel@tonic-gate * down the *multiple* messages they create. 900Sstevel@tonic-gate */ 910Sstevel@tonic-gate 920Sstevel@tonic-gate static vmem_t *keysock_vmem; /* for minor numbers. */ 930Sstevel@tonic-gate 940Sstevel@tonic-gate #define KEYSOCK_MAX_CONSUMERS 256 950Sstevel@tonic-gate 960Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages (from rts.c...) */ 970Sstevel@tonic-gate static struct T_info_ack keysock_g_t_info_ack = { 980Sstevel@tonic-gate T_INFO_ACK, 990Sstevel@tonic-gate T_INFINITE, /* TSDU_size. Maximum size messages. */ 1000Sstevel@tonic-gate T_INVALID, /* ETSDU_size. No expedited data. */ 1010Sstevel@tonic-gate T_INVALID, /* CDATA_size. No connect data. */ 1020Sstevel@tonic-gate T_INVALID, /* DDATA_size. No disconnect data. */ 1030Sstevel@tonic-gate 0, /* ADDR_size. */ 1040Sstevel@tonic-gate 0, /* OPT_size. No user-settable options */ 1050Sstevel@tonic-gate 64 * 1024, /* TIDU_size. keysock allows maximum size messages. */ 1060Sstevel@tonic-gate T_COTS, /* SERV_type. keysock supports connection oriented. */ 1070Sstevel@tonic-gate TS_UNBND, /* CURRENT_state. This is set from keysock_state. */ 1080Sstevel@tonic-gate (XPG4_1) /* Provider flags */ 1090Sstevel@tonic-gate }; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /* Named Dispatch Parameter Management Structure */ 1123448Sdh155122 typedef struct keysockparam_s { 1130Sstevel@tonic-gate uint_t keysock_param_min; 1140Sstevel@tonic-gate uint_t keysock_param_max; 1150Sstevel@tonic-gate uint_t keysock_param_value; 1160Sstevel@tonic-gate char *keysock_param_name; 1170Sstevel@tonic-gate } keysockparam_t; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * Table of NDD variables supported by keysock. These are loaded into 1210Sstevel@tonic-gate * keysock_g_nd in keysock_init_nd. 1220Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 1230Sstevel@tonic-gate */ 1243448Sdh155122 static keysockparam_t lcl_param_arr[] = { 1250Sstevel@tonic-gate /* min max value name */ 1260Sstevel@tonic-gate { 4096, 65536, 8192, "keysock_xmit_hiwat"}, 1270Sstevel@tonic-gate { 0, 65536, 1024, "keysock_xmit_lowat"}, 1280Sstevel@tonic-gate { 4096, 65536, 8192, "keysock_recv_hiwat"}, 1290Sstevel@tonic-gate { 65536, 1024*1024*1024, 256*1024, "keysock_max_buf"}, 1300Sstevel@tonic-gate { 0, 3, 0, "keysock_debug"}, 1310Sstevel@tonic-gate }; 1323448Sdh155122 #define keystack_xmit_hiwat keystack_params[0].keysock_param_value 1333448Sdh155122 #define keystack_xmit_lowat keystack_params[1].keysock_param_value 1343448Sdh155122 #define keystack_recv_hiwat keystack_params[2].keysock_param_value 1353448Sdh155122 #define keystack_max_buf keystack_params[3].keysock_param_value 1363448Sdh155122 #define keystack_debug keystack_params[4].keysock_param_value 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate #define ks0dbg(a) printf a 1390Sstevel@tonic-gate /* NOTE: != 0 instead of > 0 so lint doesn't complain. */ 1403448Sdh155122 #define ks1dbg(keystack, a) if (keystack->keystack_debug != 0) printf a 1413448Sdh155122 #define ks2dbg(keystack, a) if (keystack->keystack_debug > 1) printf a 1423448Sdh155122 #define ks3dbg(keystack, a) if (keystack->keystack_debug > 2) printf a 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate static int keysock_close(queue_t *); 1450Sstevel@tonic-gate static int keysock_open(queue_t *, dev_t *, int, int, cred_t *); 1460Sstevel@tonic-gate static void keysock_wput(queue_t *, mblk_t *); 1470Sstevel@tonic-gate static void keysock_rput(queue_t *, mblk_t *); 1480Sstevel@tonic-gate static void keysock_rsrv(queue_t *); 1490Sstevel@tonic-gate static void keysock_passup(mblk_t *, sadb_msg_t *, minor_t, 1503448Sdh155122 keysock_consumer_t *, boolean_t, keysock_stack_t *); 1513448Sdh155122 static void *keysock_stack_init(netstackid_t stackid, netstack_t *ns); 1523448Sdh155122 static void keysock_stack_fini(netstackid_t stackid, void *arg); 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate static struct module_info info = { 1550Sstevel@tonic-gate 5138, "keysock", 1, INFPSZ, 512, 128 1560Sstevel@tonic-gate }; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate static struct qinit rinit = { 1590Sstevel@tonic-gate (pfi_t)keysock_rput, (pfi_t)keysock_rsrv, keysock_open, keysock_close, 1600Sstevel@tonic-gate NULL, &info 1610Sstevel@tonic-gate }; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate static struct qinit winit = { 1640Sstevel@tonic-gate (pfi_t)keysock_wput, NULL, NULL, NULL, NULL, &info 1650Sstevel@tonic-gate }; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate struct streamtab keysockinfo = { 1680Sstevel@tonic-gate &rinit, &winit 1690Sstevel@tonic-gate }; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate extern struct modlinkage *keysock_modlp; 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate /* 1740Sstevel@tonic-gate * Plumb IPsec. 1750Sstevel@tonic-gate * 1760Sstevel@tonic-gate * NOTE: New "default" modules will need to be loaded here if needed before 1770Sstevel@tonic-gate * boot time. 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* Keep these in global space to keep the lint from complaining. */ 1810Sstevel@tonic-gate static char *IPSECESP = "ipsecesp"; 1820Sstevel@tonic-gate static char *IPSECESPDEV = "/devices/pseudo/ipsecesp@0:ipsecesp"; 1830Sstevel@tonic-gate static char *IPSECAH = "ipsecah"; 1840Sstevel@tonic-gate static char *IPSECAHDEV = "/devices/pseudo/ipsecah@0:ipsecah"; 1850Sstevel@tonic-gate static char *IP6DEV = "/devices/pseudo/ip6@0:ip6"; 1860Sstevel@tonic-gate static char *KEYSOCK = "keysock"; 1870Sstevel@tonic-gate static char *STRMOD = "strmod"; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * Load the other ipsec modules and plumb them together. 1910Sstevel@tonic-gate */ 1920Sstevel@tonic-gate int 1933448Sdh155122 keysock_plumb_ipsec(netstack_t *ns) 1940Sstevel@tonic-gate { 1950Sstevel@tonic-gate ldi_handle_t lh, ip6_lh = NULL; 1960Sstevel@tonic-gate ldi_ident_t li = NULL; 1970Sstevel@tonic-gate int err = 0; 1980Sstevel@tonic-gate int muxid, rval; 1990Sstevel@tonic-gate boolean_t esp_present = B_TRUE; 2003448Sdh155122 cred_t *cr; 2013448Sdh155122 keysock_stack_t *keystack = ns->netstack_keysock; 2020Sstevel@tonic-gate 2033448Sdh155122 #ifdef NS_DEBUG 2043448Sdh155122 (void) printf("keysock_plumb_ipsec(%d)\n", 2053448Sdh155122 ns->netstack_stackid); 2063448Sdh155122 #endif 2070Sstevel@tonic-gate 2083448Sdh155122 keystack->keystack_plumbed = 0; /* we're trying again.. */ 2093448Sdh155122 2103448Sdh155122 cr = zone_get_kcred(netstackid_to_zoneid( 2115240Snordmark keystack->keystack_netstack->netstack_stackid)); 2123448Sdh155122 ASSERT(cr != NULL); 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * Load up the drivers (AH/ESP). 2150Sstevel@tonic-gate * 2160Sstevel@tonic-gate * I do this separately from the actual plumbing in case this function 2170Sstevel@tonic-gate * ever gets called from a diskless boot before the root filesystem is 2180Sstevel@tonic-gate * up. I don't have to worry about "keysock" because, well, if I'm 2190Sstevel@tonic-gate * here, keysock must've loaded successfully. 2200Sstevel@tonic-gate */ 2210Sstevel@tonic-gate if (i_ddi_attach_pseudo_node(IPSECAH) == NULL) { 2220Sstevel@tonic-gate ks0dbg(("IPsec: AH failed to attach.\n")); 2230Sstevel@tonic-gate goto bail; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate if (i_ddi_attach_pseudo_node(IPSECESP) == NULL) { 2260Sstevel@tonic-gate ks0dbg(("IPsec: ESP failed to attach.\n")); 2270Sstevel@tonic-gate esp_present = B_FALSE; 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * Set up the IP streams for AH and ESP, as well as tacking keysock 2320Sstevel@tonic-gate * on top of them. Assume keysock has set the autopushes up already. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* Open IP. */ 2360Sstevel@tonic-gate err = ldi_ident_from_mod(keysock_modlp, &li); 2370Sstevel@tonic-gate if (err) { 2380Sstevel@tonic-gate ks0dbg(("IPsec: lid_ident_from_mod failed (err %d).\n", 2390Sstevel@tonic-gate err)); 2400Sstevel@tonic-gate goto bail; 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2433448Sdh155122 err = ldi_open_by_name(IP6DEV, FREAD|FWRITE, cr, &ip6_lh, li); 2440Sstevel@tonic-gate if (err) { 2450Sstevel@tonic-gate ks0dbg(("IPsec: Open of IP6 failed (err %d).\n", err)); 2460Sstevel@tonic-gate goto bail; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate /* PLINK KEYSOCK/AH */ 2503448Sdh155122 err = ldi_open_by_name(IPSECAHDEV, FREAD|FWRITE, cr, &lh, li); 2510Sstevel@tonic-gate if (err) { 2520Sstevel@tonic-gate ks0dbg(("IPsec: Open of AH failed (err %d).\n", err)); 2530Sstevel@tonic-gate goto bail; 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate err = ldi_ioctl(lh, 2563448Sdh155122 I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, cr, &rval); 2570Sstevel@tonic-gate if (err) { 2580Sstevel@tonic-gate ks0dbg(("IPsec: Push of KEYSOCK onto AH failed (err %d).\n", 2590Sstevel@tonic-gate err)); 2603448Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2610Sstevel@tonic-gate goto bail; 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh, 2645240Snordmark FREAD+FWRITE+FNOCTTY+FKIOCTL, cr, &muxid); 2650Sstevel@tonic-gate if (err) { 2660Sstevel@tonic-gate ks0dbg(("IPsec: PLINK of KEYSOCK/AH failed (err %d).\n", err)); 2673448Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2680Sstevel@tonic-gate goto bail; 2690Sstevel@tonic-gate } 2703448Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* PLINK KEYSOCK/ESP */ 2730Sstevel@tonic-gate if (esp_present) { 2740Sstevel@tonic-gate err = ldi_open_by_name(IPSECESPDEV, 2753448Sdh155122 FREAD|FWRITE, cr, &lh, li); 2760Sstevel@tonic-gate if (err) { 2770Sstevel@tonic-gate ks0dbg(("IPsec: Open of ESP failed (err %d).\n", err)); 2780Sstevel@tonic-gate goto bail; 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate err = ldi_ioctl(lh, 2813448Sdh155122 I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, cr, &rval); 2820Sstevel@tonic-gate if (err) { 2830Sstevel@tonic-gate ks0dbg(("IPsec: " 2840Sstevel@tonic-gate "Push of KEYSOCK onto ESP failed (err %d).\n", 2850Sstevel@tonic-gate err)); 2863448Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2870Sstevel@tonic-gate goto bail; 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh, 2905240Snordmark FREAD+FWRITE+FNOCTTY+FKIOCTL, cr, &muxid); 2910Sstevel@tonic-gate if (err) { 2920Sstevel@tonic-gate ks0dbg(("IPsec: " 2930Sstevel@tonic-gate "PLINK of KEYSOCK/ESP failed (err %d).\n", err)); 2943448Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2950Sstevel@tonic-gate goto bail; 2960Sstevel@tonic-gate } 2973448Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate bail: 3013448Sdh155122 keystack->keystack_plumbed = (err == 0) ? 1 : -1; 3020Sstevel@tonic-gate if (ip6_lh != NULL) { 3033448Sdh155122 (void) ldi_close(ip6_lh, FREAD|FWRITE, cr); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate if (li != NULL) 3060Sstevel@tonic-gate ldi_ident_release(li); 3073448Sdh155122 #ifdef NS_DEBUG 3083448Sdh155122 (void) printf("keysock_plumb_ipsec -> %d\n", 3093448Sdh155122 keystack->keystack_plumbed); 3103448Sdh155122 #endif 3113448Sdh155122 crfree(cr); 3120Sstevel@tonic-gate return (err); 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate /* ARGSUSED */ 3160Sstevel@tonic-gate static int 3170Sstevel@tonic-gate keysock_param_get(q, mp, cp, cr) 3180Sstevel@tonic-gate queue_t *q; 3190Sstevel@tonic-gate mblk_t *mp; 3200Sstevel@tonic-gate caddr_t cp; 3210Sstevel@tonic-gate cred_t *cr; 3220Sstevel@tonic-gate { 3230Sstevel@tonic-gate keysockparam_t *keysockpa = (keysockparam_t *)cp; 3240Sstevel@tonic-gate uint_t value; 3253448Sdh155122 keysock_t *ks = (keysock_t *)q->q_ptr; 3263448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 3270Sstevel@tonic-gate 3283448Sdh155122 mutex_enter(&keystack->keystack_param_lock); 3290Sstevel@tonic-gate value = keysockpa->keysock_param_value; 3303448Sdh155122 mutex_exit(&keystack->keystack_param_lock); 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", value); 3330Sstevel@tonic-gate return (0); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /* This routine sets an NDD variable in a keysockparam_t structure. */ 3370Sstevel@tonic-gate /* ARGSUSED */ 3380Sstevel@tonic-gate static int 3390Sstevel@tonic-gate keysock_param_set(q, mp, value, cp, cr) 3400Sstevel@tonic-gate queue_t *q; 3410Sstevel@tonic-gate mblk_t *mp; 3420Sstevel@tonic-gate char *value; 3430Sstevel@tonic-gate caddr_t cp; 3440Sstevel@tonic-gate cred_t *cr; 3450Sstevel@tonic-gate { 3460Sstevel@tonic-gate ulong_t new_value; 3470Sstevel@tonic-gate keysockparam_t *keysockpa = (keysockparam_t *)cp; 3483448Sdh155122 keysock_t *ks = (keysock_t *)q->q_ptr; 3493448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate /* Convert the value from a string into a long integer. */ 3520Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0) 3530Sstevel@tonic-gate return (EINVAL); 3540Sstevel@tonic-gate 3553448Sdh155122 mutex_enter(&keystack->keystack_param_lock); 3560Sstevel@tonic-gate /* 3570Sstevel@tonic-gate * Fail the request if the new value does not lie within the 3580Sstevel@tonic-gate * required bounds. 3590Sstevel@tonic-gate */ 3600Sstevel@tonic-gate if (new_value < keysockpa->keysock_param_min || 3610Sstevel@tonic-gate new_value > keysockpa->keysock_param_max) { 3623448Sdh155122 mutex_exit(&keystack->keystack_param_lock); 3630Sstevel@tonic-gate return (EINVAL); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* Set the new value */ 3670Sstevel@tonic-gate keysockpa->keysock_param_value = new_value; 3683448Sdh155122 mutex_exit(&keystack->keystack_param_lock); 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate return (0); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* 3743448Sdh155122 * Initialize keysock at module load time 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate boolean_t 3770Sstevel@tonic-gate keysock_ddi_init(void) 3780Sstevel@tonic-gate { 3790Sstevel@tonic-gate keysock_max_optsize = optcom_max_optsize( 3800Sstevel@tonic-gate keysock_opt_obj.odb_opt_des_arr, keysock_opt_obj.odb_opt_arr_cnt); 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate keysock_vmem = vmem_create("keysock", (void *)1, MAXMIN, 1, 3830Sstevel@tonic-gate NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER); 3840Sstevel@tonic-gate 3853448Sdh155122 /* 3863448Sdh155122 * We want to be informed each time a stack is created or 3873448Sdh155122 * destroyed in the kernel, so we can maintain the 3883448Sdh155122 * set of keysock_stack_t's. 3893448Sdh155122 */ 3903448Sdh155122 netstack_register(NS_KEYSOCK, keysock_stack_init, NULL, 3913448Sdh155122 keysock_stack_fini); 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate return (B_TRUE); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /* 3973448Sdh155122 * Walk through the param array specified registering each element with the 3983448Sdh155122 * named dispatch handler. 3993448Sdh155122 */ 4003448Sdh155122 static boolean_t 4013448Sdh155122 keysock_param_register(IDP *ndp, keysockparam_t *ksp, int cnt) 4023448Sdh155122 { 4033448Sdh155122 for (; cnt-- > 0; ksp++) { 4043448Sdh155122 if (ksp->keysock_param_name != NULL && 4053448Sdh155122 ksp->keysock_param_name[0]) { 4063448Sdh155122 if (!nd_load(ndp, 4073448Sdh155122 ksp->keysock_param_name, 4083448Sdh155122 keysock_param_get, keysock_param_set, 4093448Sdh155122 (caddr_t)ksp)) { 4103448Sdh155122 nd_free(ndp); 4113448Sdh155122 return (B_FALSE); 4123448Sdh155122 } 4133448Sdh155122 } 4143448Sdh155122 } 4153448Sdh155122 return (B_TRUE); 4163448Sdh155122 } 4173448Sdh155122 4183448Sdh155122 /* 4193448Sdh155122 * Initialize keysock for one stack instance 4203448Sdh155122 */ 4213448Sdh155122 /* ARGSUSED */ 4223448Sdh155122 static void * 4233448Sdh155122 keysock_stack_init(netstackid_t stackid, netstack_t *ns) 4243448Sdh155122 { 4253448Sdh155122 keysock_stack_t *keystack; 4263448Sdh155122 keysockparam_t *ksp; 4273448Sdh155122 4283448Sdh155122 keystack = (keysock_stack_t *)kmem_zalloc(sizeof (*keystack), KM_SLEEP); 4293448Sdh155122 keystack->keystack_netstack = ns; 4303448Sdh155122 4313448Sdh155122 keystack->keystack_acquire_seq = 0xffffffff; 4323448Sdh155122 4333448Sdh155122 ksp = (keysockparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP); 4343448Sdh155122 keystack->keystack_params = ksp; 4353448Sdh155122 bcopy(lcl_param_arr, ksp, sizeof (lcl_param_arr)); 4363448Sdh155122 4373448Sdh155122 (void) keysock_param_register(&keystack->keystack_g_nd, ksp, 4383448Sdh155122 A_CNT(lcl_param_arr)); 4393448Sdh155122 4403448Sdh155122 mutex_init(&keystack->keystack_list_lock, NULL, MUTEX_DEFAULT, NULL); 4413448Sdh155122 mutex_init(&keystack->keystack_consumers_lock, 4423448Sdh155122 NULL, MUTEX_DEFAULT, NULL); 4433448Sdh155122 mutex_init(&keystack->keystack_param_lock, NULL, MUTEX_DEFAULT, NULL); 4443448Sdh155122 return (keystack); 4453448Sdh155122 } 4463448Sdh155122 4473448Sdh155122 /* 4480Sstevel@tonic-gate * Free NDD variable space, and other destructors, for keysock. 4490Sstevel@tonic-gate */ 4500Sstevel@tonic-gate void 4510Sstevel@tonic-gate keysock_ddi_destroy(void) 4520Sstevel@tonic-gate { 4533448Sdh155122 netstack_unregister(NS_KEYSOCK); 4540Sstevel@tonic-gate vmem_destroy(keysock_vmem); 4553448Sdh155122 } 4563448Sdh155122 4573448Sdh155122 /* 4583448Sdh155122 * Remove one stack instance from keysock 4593448Sdh155122 */ 4603448Sdh155122 /* ARGSUSED */ 4613448Sdh155122 static void 4623448Sdh155122 keysock_stack_fini(netstackid_t stackid, void *arg) 4633448Sdh155122 { 4643448Sdh155122 keysock_stack_t *keystack = (keysock_stack_t *)arg; 4653448Sdh155122 4663448Sdh155122 nd_free(&keystack->keystack_g_nd); 4673448Sdh155122 kmem_free(keystack->keystack_params, sizeof (lcl_param_arr)); 4683448Sdh155122 keystack->keystack_params = NULL; 4693448Sdh155122 4703448Sdh155122 mutex_destroy(&keystack->keystack_list_lock); 4713448Sdh155122 mutex_destroy(&keystack->keystack_consumers_lock); 4723448Sdh155122 mutex_destroy(&keystack->keystack_param_lock); 4733448Sdh155122 4743448Sdh155122 kmem_free(keystack, sizeof (*keystack)); 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate /* 4780Sstevel@tonic-gate * Close routine for keysock. 4790Sstevel@tonic-gate */ 4800Sstevel@tonic-gate static int 4810Sstevel@tonic-gate keysock_close(queue_t *q) 4820Sstevel@tonic-gate { 4830Sstevel@tonic-gate keysock_t *ks; 4840Sstevel@tonic-gate keysock_consumer_t *kc; 4850Sstevel@tonic-gate void *ptr = q->q_ptr; 4860Sstevel@tonic-gate int size; 4873448Sdh155122 keysock_stack_t *keystack; 4883448Sdh155122 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate qprocsoff(q); 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate /* Safe assumption. */ 4930Sstevel@tonic-gate ASSERT(ptr != NULL); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate if (WR(q)->q_next) { 4960Sstevel@tonic-gate kc = (keysock_consumer_t *)ptr; 4973448Sdh155122 keystack = kc->kc_keystack; 4983448Sdh155122 4993448Sdh155122 ks1dbg(keystack, ("Module close, removing a consumer (%d).\n", 5000Sstevel@tonic-gate kc->kc_sa_type)); 5010Sstevel@tonic-gate /* 5020Sstevel@tonic-gate * Because of PERMOD open/close exclusive perimeter, I 5030Sstevel@tonic-gate * can inspect KC_FLUSHING w/o locking down kc->kc_lock. 5040Sstevel@tonic-gate */ 5050Sstevel@tonic-gate if (kc->kc_flags & KC_FLUSHING) { 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * If this decrement was the last one, send 5080Sstevel@tonic-gate * down the next pending one, if any. 5090Sstevel@tonic-gate * 5100Sstevel@tonic-gate * With a PERMOD perimeter, the mutexes ops aren't 5110Sstevel@tonic-gate * really necessary, but if we ever loosen up, we will 5120Sstevel@tonic-gate * have this bit covered already. 5130Sstevel@tonic-gate */ 5143448Sdh155122 keystack->keystack_flushdump--; 5153448Sdh155122 if (keystack->keystack_flushdump == 0) { 5160Sstevel@tonic-gate /* 5170Sstevel@tonic-gate * The flush/dump terminated by having a 5180Sstevel@tonic-gate * consumer go away. I need to send up to the 5190Sstevel@tonic-gate * appropriate keysock all of the relevant 5200Sstevel@tonic-gate * information. Unfortunately, I don't 5210Sstevel@tonic-gate * have that handy. 5220Sstevel@tonic-gate */ 5230Sstevel@tonic-gate ks0dbg(("Consumer went away while flushing or" 5240Sstevel@tonic-gate " dumping.\n")); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate size = sizeof (keysock_consumer_t); 5283448Sdh155122 mutex_enter(&keystack->keystack_consumers_lock); 5293448Sdh155122 keystack->keystack_consumers[kc->kc_sa_type] = NULL; 5303448Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 5310Sstevel@tonic-gate mutex_destroy(&kc->kc_lock); 5323448Sdh155122 netstack_rele(kc->kc_keystack->keystack_netstack); 5330Sstevel@tonic-gate } else { 5340Sstevel@tonic-gate ks = (keysock_t *)ptr; 5353448Sdh155122 keystack = ks->keysock_keystack; 5363448Sdh155122 5373448Sdh155122 ks3dbg(keystack, 5383448Sdh155122 ("Driver close, PF_KEY socket is going away.\n")); 5390Sstevel@tonic-gate if ((ks->keysock_flags & KEYSOCK_EXTENDED) != 0) 5403448Sdh155122 atomic_add_32(&keystack->keystack_num_extended, -1); 5410Sstevel@tonic-gate size = sizeof (keysock_t); 5423448Sdh155122 mutex_enter(&keystack->keystack_list_lock); 5430Sstevel@tonic-gate *(ks->keysock_ptpn) = ks->keysock_next; 5440Sstevel@tonic-gate if (ks->keysock_next != NULL) 5450Sstevel@tonic-gate ks->keysock_next->keysock_ptpn = ks->keysock_ptpn; 5463448Sdh155122 mutex_exit(&keystack->keystack_list_lock); 5470Sstevel@tonic-gate mutex_destroy(&ks->keysock_lock); 5482465Sdanmcd vmem_free(keysock_vmem, (void *)(uintptr_t)ks->keysock_serial, 5492465Sdanmcd 1); 5503448Sdh155122 netstack_rele(ks->keysock_keystack->keystack_netstack); 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate /* Now I'm free. */ 5540Sstevel@tonic-gate kmem_free(ptr, size); 5550Sstevel@tonic-gate return (0); 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate /* 5580Sstevel@tonic-gate * Open routine for keysock. 5590Sstevel@tonic-gate */ 5600Sstevel@tonic-gate /* ARGSUSED */ 5610Sstevel@tonic-gate static int 5620Sstevel@tonic-gate keysock_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 5630Sstevel@tonic-gate { 5640Sstevel@tonic-gate keysock_t *ks; 5650Sstevel@tonic-gate keysock_consumer_t *kc; 5660Sstevel@tonic-gate mblk_t *mp; 5670Sstevel@tonic-gate ipsec_info_t *ii; 5683448Sdh155122 netstack_t *ns; 5693448Sdh155122 keysock_stack_t *keystack; 5700Sstevel@tonic-gate 5713448Sdh155122 if (secpolicy_ip_config(credp, B_FALSE) != 0) { 5720Sstevel@tonic-gate /* Privilege debugging will log the error */ 5730Sstevel@tonic-gate return (EPERM); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate if (q->q_ptr != NULL) 5770Sstevel@tonic-gate return (0); /* Re-open of an already open instance. */ 5780Sstevel@tonic-gate 5793448Sdh155122 ns = netstack_find_by_cred(credp); 5803448Sdh155122 ASSERT(ns != NULL); 5813448Sdh155122 keystack = ns->netstack_keysock; 5823448Sdh155122 ASSERT(keystack != NULL); 5833448Sdh155122 5843448Sdh155122 ks3dbg(keystack, ("Entering keysock open.\n")); 5853448Sdh155122 5863448Sdh155122 if (keystack->keystack_plumbed < 1) { 5873448Sdh155122 netstack_t *ns = keystack->keystack_netstack; 5883448Sdh155122 5893448Sdh155122 keystack->keystack_plumbed = 0; 5903448Sdh155122 #ifdef NS_DEBUG 5913448Sdh155122 printf("keysock_open(%d) - plumb\n", 5923448Sdh155122 keystack->keystack_netstack->netstack_stackid); 5933448Sdh155122 #endif 5940Sstevel@tonic-gate /* 5950Sstevel@tonic-gate * Don't worry about ipsec_failure being true here. 5960Sstevel@tonic-gate * (See ip.c). An open of keysock should try and force 5970Sstevel@tonic-gate * the issue. Maybe it was a transient failure. 5980Sstevel@tonic-gate */ 5993448Sdh155122 ipsec_loader_loadnow(ns->netstack_ipsec); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate if (sflag & MODOPEN) { 6030Sstevel@tonic-gate /* Initialize keysock_consumer state here. */ 6040Sstevel@tonic-gate kc = kmem_zalloc(sizeof (keysock_consumer_t), KM_NOSLEEP); 6053448Sdh155122 if (kc == NULL) { 6063448Sdh155122 netstack_rele(keystack->keystack_netstack); 6070Sstevel@tonic-gate return (ENOMEM); 6083448Sdh155122 } 6090Sstevel@tonic-gate mutex_init(&kc->kc_lock, NULL, MUTEX_DEFAULT, 0); 6100Sstevel@tonic-gate kc->kc_rq = q; 6110Sstevel@tonic-gate kc->kc_wq = WR(q); 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate q->q_ptr = kc; 6140Sstevel@tonic-gate WR(q)->q_ptr = kc; 6150Sstevel@tonic-gate 6163448Sdh155122 kc->kc_keystack = keystack; 6170Sstevel@tonic-gate qprocson(q); 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate /* 6200Sstevel@tonic-gate * Send down initial message to whatever I was pushed on top 6210Sstevel@tonic-gate * of asking for its consumer type. The reply will set it. 6220Sstevel@tonic-gate */ 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* Allocate it. */ 6250Sstevel@tonic-gate mp = allocb(sizeof (ipsec_info_t), BPRI_HI); 6260Sstevel@tonic-gate if (mp == NULL) { 6273448Sdh155122 ks1dbg(keystack, ( 6280Sstevel@tonic-gate "keysock_open: Cannot allocate KEYSOCK_HELLO.\n")); 6290Sstevel@tonic-gate /* Do I need to set these to null? */ 6300Sstevel@tonic-gate q->q_ptr = NULL; 6310Sstevel@tonic-gate WR(q)->q_ptr = NULL; 6320Sstevel@tonic-gate mutex_destroy(&kc->kc_lock); 6330Sstevel@tonic-gate kmem_free(kc, sizeof (*kc)); 6343448Sdh155122 netstack_rele(keystack->keystack_netstack); 6350Sstevel@tonic-gate return (ENOMEM); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /* If I allocated okay, putnext to what I was pushed atop. */ 6390Sstevel@tonic-gate mp->b_wptr += sizeof (ipsec_info_t); 6400Sstevel@tonic-gate mp->b_datap->db_type = M_CTL; 6410Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 6420Sstevel@tonic-gate ii->ipsec_info_type = KEYSOCK_HELLO; 6430Sstevel@tonic-gate /* Length only of type/len. */ 6440Sstevel@tonic-gate ii->ipsec_info_len = sizeof (ii->ipsec_allu); 6453448Sdh155122 ks2dbg(keystack, ("Ready to putnext KEYSOCK_HELLO.\n")); 6460Sstevel@tonic-gate putnext(kc->kc_wq, mp); 6470Sstevel@tonic-gate } else { 6480Sstevel@tonic-gate minor_t ksminor; 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate /* Initialize keysock state. */ 6510Sstevel@tonic-gate 6523448Sdh155122 ks2dbg(keystack, ("Made it into PF_KEY socket open.\n")); 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate ksminor = (minor_t)(uintptr_t) 6550Sstevel@tonic-gate vmem_alloc(keysock_vmem, 1, VM_NOSLEEP); 6563448Sdh155122 if (ksminor == 0) { 6573448Sdh155122 netstack_rele(keystack->keystack_netstack); 6580Sstevel@tonic-gate return (ENOMEM); 6593448Sdh155122 } 6600Sstevel@tonic-gate ks = kmem_zalloc(sizeof (keysock_t), KM_NOSLEEP); 6610Sstevel@tonic-gate if (ks == NULL) { 6620Sstevel@tonic-gate vmem_free(keysock_vmem, (void *)(uintptr_t)ksminor, 1); 6633448Sdh155122 netstack_rele(keystack->keystack_netstack); 6640Sstevel@tonic-gate return (ENOMEM); 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate mutex_init(&ks->keysock_lock, NULL, MUTEX_DEFAULT, 0); 6680Sstevel@tonic-gate ks->keysock_rq = q; 6690Sstevel@tonic-gate ks->keysock_wq = WR(q); 6700Sstevel@tonic-gate ks->keysock_state = TS_UNBND; 6710Sstevel@tonic-gate ks->keysock_serial = ksminor; 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate q->q_ptr = ks; 6740Sstevel@tonic-gate WR(q)->q_ptr = ks; 6753448Sdh155122 ks->keysock_keystack = keystack; 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate /* 6780Sstevel@tonic-gate * The receive hiwat is only looked at on the stream head 6790Sstevel@tonic-gate * queue. Store in q_hiwat in order to return on SO_RCVBUF 6800Sstevel@tonic-gate * getsockopts. 6810Sstevel@tonic-gate */ 6820Sstevel@tonic-gate 6833448Sdh155122 q->q_hiwat = keystack->keystack_recv_hiwat; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * The transmit hiwat/lowat is only looked at on IP's queue. 6870Sstevel@tonic-gate * Store in q_hiwat/q_lowat in order to return on 6880Sstevel@tonic-gate * SO_SNDBUF/SO_SNDLOWAT getsockopts. 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate 6913448Sdh155122 WR(q)->q_hiwat = keystack->keystack_xmit_hiwat; 6923448Sdh155122 WR(q)->q_lowat = keystack->keystack_xmit_lowat; 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), ksminor); 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate /* 6970Sstevel@tonic-gate * Thread keysock into the global keysock list. 6980Sstevel@tonic-gate */ 6993448Sdh155122 mutex_enter(&keystack->keystack_list_lock); 7003448Sdh155122 ks->keysock_next = keystack->keystack_list; 7013448Sdh155122 ks->keysock_ptpn = &keystack->keystack_list; 7023448Sdh155122 if (keystack->keystack_list != NULL) { 7033448Sdh155122 keystack->keystack_list->keysock_ptpn = 7043448Sdh155122 &ks->keysock_next; 7053448Sdh155122 } 7063448Sdh155122 keystack->keystack_list = ks; 7073448Sdh155122 mutex_exit(&keystack->keystack_list_lock); 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate qprocson(q); 7108348SEric.Yu@Sun.COM (void) proto_set_rx_hiwat(q, NULL, 7118348SEric.Yu@Sun.COM keystack->keystack_recv_hiwat); 7120Sstevel@tonic-gate /* 7130Sstevel@tonic-gate * Wait outside the keysock module perimeter for IPsec 7140Sstevel@tonic-gate * plumbing to be completed. If it fails, keysock_close() 7150Sstevel@tonic-gate * undoes everything we just did. 7160Sstevel@tonic-gate */ 7173448Sdh155122 if (!ipsec_loader_wait(q, 7183448Sdh155122 keystack->keystack_netstack->netstack_ipsec)) { 7190Sstevel@tonic-gate (void) keysock_close(q); 7200Sstevel@tonic-gate return (EPFNOSUPPORT); 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate return (0); 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_wput(). */ 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate /* 7300Sstevel@tonic-gate * Copy relevant state bits. 7310Sstevel@tonic-gate */ 7320Sstevel@tonic-gate static void 7330Sstevel@tonic-gate keysock_copy_info(struct T_info_ack *tap, keysock_t *ks) 7340Sstevel@tonic-gate { 7350Sstevel@tonic-gate *tap = keysock_g_t_info_ack; 7360Sstevel@tonic-gate tap->CURRENT_state = ks->keysock_state; 7370Sstevel@tonic-gate tap->OPT_size = keysock_max_optsize; 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate /* 7410Sstevel@tonic-gate * This routine responds to T_CAPABILITY_REQ messages. It is called by 7420Sstevel@tonic-gate * keysock_wput. Much of the T_CAPABILITY_ACK information is copied from 7430Sstevel@tonic-gate * keysock_g_t_info_ack. The current state of the stream is copied from 7440Sstevel@tonic-gate * keysock_state. 7450Sstevel@tonic-gate */ 7460Sstevel@tonic-gate static void 7470Sstevel@tonic-gate keysock_capability_req(queue_t *q, mblk_t *mp) 7480Sstevel@tonic-gate { 7490Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 7500Sstevel@tonic-gate t_uscalar_t cap_bits1; 7510Sstevel@tonic-gate struct T_capability_ack *tcap; 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1; 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack), 7565240Snordmark mp->b_datap->db_type, T_CAPABILITY_ACK); 7570Sstevel@tonic-gate if (mp == NULL) 7580Sstevel@tonic-gate return; 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate tcap = (struct T_capability_ack *)mp->b_rptr; 7610Sstevel@tonic-gate tcap->CAP_bits1 = 0; 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 7640Sstevel@tonic-gate keysock_copy_info(&tcap->INFO_ack, ks); 7650Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_INFO; 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate qreply(q, mp); 7690Sstevel@tonic-gate } 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate /* 7720Sstevel@tonic-gate * This routine responds to T_INFO_REQ messages. It is called by 7730Sstevel@tonic-gate * keysock_wput_other. 7740Sstevel@tonic-gate * Most of the T_INFO_ACK information is copied from keysock_g_t_info_ack. 7750Sstevel@tonic-gate * The current state of the stream is copied from keysock_state. 7760Sstevel@tonic-gate */ 7770Sstevel@tonic-gate static void 7780Sstevel@tonic-gate keysock_info_req(q, mp) 7790Sstevel@tonic-gate queue_t *q; 7800Sstevel@tonic-gate mblk_t *mp; 7810Sstevel@tonic-gate { 7820Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO, 7830Sstevel@tonic-gate T_INFO_ACK); 7840Sstevel@tonic-gate if (mp == NULL) 7850Sstevel@tonic-gate return; 7860Sstevel@tonic-gate keysock_copy_info((struct T_info_ack *)mp->b_rptr, 7870Sstevel@tonic-gate (keysock_t *)q->q_ptr); 7880Sstevel@tonic-gate qreply(q, mp); 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate /* 7920Sstevel@tonic-gate * keysock_err_ack. This routine creates a 7930Sstevel@tonic-gate * T_ERROR_ACK message and passes it 7940Sstevel@tonic-gate * upstream. 7950Sstevel@tonic-gate */ 7960Sstevel@tonic-gate static void 7970Sstevel@tonic-gate keysock_err_ack(q, mp, t_error, sys_error) 7980Sstevel@tonic-gate queue_t *q; 7990Sstevel@tonic-gate mblk_t *mp; 8000Sstevel@tonic-gate int t_error; 8010Sstevel@tonic-gate int sys_error; 8020Sstevel@tonic-gate { 8030Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) 8040Sstevel@tonic-gate qreply(q, mp); 8050Sstevel@tonic-gate } 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate /* 8080Sstevel@tonic-gate * This routine retrieves the current status of socket options. 8090Sstevel@tonic-gate * It returns the size of the option retrieved. 8100Sstevel@tonic-gate */ 8110Sstevel@tonic-gate /* ARGSUSED */ 8120Sstevel@tonic-gate int 8130Sstevel@tonic-gate keysock_opt_get(queue_t *q, int level, int name, uchar_t *ptr) 8140Sstevel@tonic-gate { 8150Sstevel@tonic-gate int *i1 = (int *)ptr; 8160Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate switch (level) { 8190Sstevel@tonic-gate case SOL_SOCKET: 8200Sstevel@tonic-gate mutex_enter(&ks->keysock_lock); 8210Sstevel@tonic-gate switch (name) { 8220Sstevel@tonic-gate case SO_TYPE: 8230Sstevel@tonic-gate *i1 = SOCK_RAW; 8240Sstevel@tonic-gate break; 8250Sstevel@tonic-gate case SO_USELOOPBACK: 8260Sstevel@tonic-gate *i1 = (int)(!((ks->keysock_flags & KEYSOCK_NOLOOP) == 8270Sstevel@tonic-gate KEYSOCK_NOLOOP)); 8280Sstevel@tonic-gate break; 8290Sstevel@tonic-gate /* 8300Sstevel@tonic-gate * The following two items can be manipulated, 8310Sstevel@tonic-gate * but changing them should do nothing. 8320Sstevel@tonic-gate */ 8330Sstevel@tonic-gate case SO_SNDBUF: 8340Sstevel@tonic-gate *i1 = (int)q->q_hiwat; 8350Sstevel@tonic-gate break; 8360Sstevel@tonic-gate case SO_RCVBUF: 8370Sstevel@tonic-gate *i1 = (int)(RD(q)->q_hiwat); 8380Sstevel@tonic-gate break; 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate mutex_exit(&ks->keysock_lock); 8410Sstevel@tonic-gate break; 8420Sstevel@tonic-gate default: 8430Sstevel@tonic-gate return (0); 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate return (sizeof (int)); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate /* 8490Sstevel@tonic-gate * This routine sets socket options. 8500Sstevel@tonic-gate */ 8510Sstevel@tonic-gate /* ARGSUSED */ 8520Sstevel@tonic-gate int 8530Sstevel@tonic-gate keysock_opt_set(queue_t *q, uint_t mgmt_flags, int level, 8540Sstevel@tonic-gate int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp, 8550Sstevel@tonic-gate uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk) 8560Sstevel@tonic-gate { 8578730Sdanmcd@sun.com int *i1 = (int *)invalp, errno = 0; 8580Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 8593448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate switch (level) { 8620Sstevel@tonic-gate case SOL_SOCKET: 8630Sstevel@tonic-gate mutex_enter(&ks->keysock_lock); 8640Sstevel@tonic-gate switch (name) { 8650Sstevel@tonic-gate case SO_USELOOPBACK: 8660Sstevel@tonic-gate if (!(*i1)) 8670Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_NOLOOP; 8680Sstevel@tonic-gate else ks->keysock_flags &= ~KEYSOCK_NOLOOP; 8690Sstevel@tonic-gate break; 8700Sstevel@tonic-gate case SO_SNDBUF: 8713448Sdh155122 if (*i1 > keystack->keystack_max_buf) 8728730Sdanmcd@sun.com errno = ENOBUFS; 8738730Sdanmcd@sun.com else q->q_hiwat = *i1; 8740Sstevel@tonic-gate break; 8750Sstevel@tonic-gate case SO_RCVBUF: 8768730Sdanmcd@sun.com if (*i1 > keystack->keystack_max_buf) { 8778730Sdanmcd@sun.com errno = ENOBUFS; 8788730Sdanmcd@sun.com } else { 8798730Sdanmcd@sun.com RD(q)->q_hiwat = *i1; 8808730Sdanmcd@sun.com (void) proto_set_rx_hiwat(RD(q), NULL, *i1); 8818730Sdanmcd@sun.com } 8820Sstevel@tonic-gate break; 8838730Sdanmcd@sun.com default: 8848730Sdanmcd@sun.com errno = EINVAL; 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate mutex_exit(&ks->keysock_lock); 8870Sstevel@tonic-gate break; 8888730Sdanmcd@sun.com default: 8898730Sdanmcd@sun.com errno = EINVAL; 8900Sstevel@tonic-gate } 8918730Sdanmcd@sun.com return (errno); 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* 8950Sstevel@tonic-gate * Handle STREAMS messages. 8960Sstevel@tonic-gate */ 8970Sstevel@tonic-gate static void 8980Sstevel@tonic-gate keysock_wput_other(queue_t *q, mblk_t *mp) 8990Sstevel@tonic-gate { 9000Sstevel@tonic-gate struct iocblk *iocp; 9010Sstevel@tonic-gate int error; 9023448Sdh155122 keysock_t *ks = (keysock_t *)q->q_ptr; 9033448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 9043448Sdh155122 cred_t *cr; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate switch (mp->b_datap->db_type) { 9070Sstevel@tonic-gate case M_PROTO: 9080Sstevel@tonic-gate case M_PCPROTO: 9090Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (long)) { 9103448Sdh155122 ks3dbg(keystack, ( 9110Sstevel@tonic-gate "keysock_wput_other: Not big enough M_PROTO\n")); 9120Sstevel@tonic-gate freemsg(mp); 9130Sstevel@tonic-gate return; 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate switch (((union T_primitives *)mp->b_rptr)->type) { 9160Sstevel@tonic-gate case T_CAPABILITY_REQ: 9170Sstevel@tonic-gate keysock_capability_req(q, mp); 9183448Sdh155122 break; 9190Sstevel@tonic-gate case T_INFO_REQ: 9200Sstevel@tonic-gate keysock_info_req(q, mp); 9213448Sdh155122 break; 9220Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 9230Sstevel@tonic-gate case T_OPTMGMT_REQ: 924*8778SErik.Nordmark@Sun.COM /* 925*8778SErik.Nordmark@Sun.COM * All Solaris components should pass a db_credp 926*8778SErik.Nordmark@Sun.COM * for this TPI message, hence we ASSERT. 927*8778SErik.Nordmark@Sun.COM * But in case there is some other M_PROTO that looks 928*8778SErik.Nordmark@Sun.COM * like a TPI message sent by some other kernel 929*8778SErik.Nordmark@Sun.COM * component, we check and return an error. 930*8778SErik.Nordmark@Sun.COM */ 931*8778SErik.Nordmark@Sun.COM cr = msg_getcred(mp, NULL); 932*8778SErik.Nordmark@Sun.COM ASSERT(cr != NULL); 933*8778SErik.Nordmark@Sun.COM if (cr == NULL) { 934*8778SErik.Nordmark@Sun.COM keysock_err_ack(q, mp, TSYSERR, EINVAL); 935*8778SErik.Nordmark@Sun.COM return; 936*8778SErik.Nordmark@Sun.COM } 937*8778SErik.Nordmark@Sun.COM if (((union T_primitives *)mp->b_rptr)->type == 938*8778SErik.Nordmark@Sun.COM T_SVR4_OPTMGMT_REQ) { 939*8778SErik.Nordmark@Sun.COM (void) svr4_optcom_req(q, mp, cr, 940*8778SErik.Nordmark@Sun.COM &keysock_opt_obj, B_FALSE); 941*8778SErik.Nordmark@Sun.COM } else { 942*8778SErik.Nordmark@Sun.COM (void) tpi_optcom_req(q, mp, cr, 943*8778SErik.Nordmark@Sun.COM &keysock_opt_obj, B_FALSE); 944*8778SErik.Nordmark@Sun.COM } 9453448Sdh155122 break; 9460Sstevel@tonic-gate case T_DATA_REQ: 9470Sstevel@tonic-gate case T_EXDATA_REQ: 9480Sstevel@tonic-gate case T_ORDREL_REQ: 9490Sstevel@tonic-gate /* Illegal for keysock. */ 9500Sstevel@tonic-gate freemsg(mp); 9510Sstevel@tonic-gate (void) putnextctl1(RD(q), M_ERROR, EPROTO); 9523448Sdh155122 break; 9530Sstevel@tonic-gate default: 9540Sstevel@tonic-gate /* Not supported by keysock. */ 9550Sstevel@tonic-gate keysock_err_ack(q, mp, TNOTSUPPORT, 0); 9563448Sdh155122 break; 9570Sstevel@tonic-gate } 9583448Sdh155122 return; 9590Sstevel@tonic-gate case M_IOCTL: 9600Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 9610Sstevel@tonic-gate error = EINVAL; 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate switch (iocp->ioc_cmd) { 9640Sstevel@tonic-gate case ND_SET: 9650Sstevel@tonic-gate case ND_GET: 9663448Sdh155122 if (nd_getset(q, keystack->keystack_g_nd, mp)) { 9670Sstevel@tonic-gate qreply(q, mp); 9680Sstevel@tonic-gate return; 9690Sstevel@tonic-gate } else 9700Sstevel@tonic-gate error = ENOENT; 9710Sstevel@tonic-gate /* FALLTHRU */ 9720Sstevel@tonic-gate default: 9730Sstevel@tonic-gate miocnak(q, mp, 0, error); 9740Sstevel@tonic-gate return; 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate case M_FLUSH: 9770Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 9780Sstevel@tonic-gate flushq(q, FLUSHALL); 9790Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 9800Sstevel@tonic-gate } 9810Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 9820Sstevel@tonic-gate qreply(q, mp); 9830Sstevel@tonic-gate return; 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate /* Else FALLTHRU */ 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate /* If fell through, just black-hole the message. */ 9890Sstevel@tonic-gate freemsg(mp); 9900Sstevel@tonic-gate } 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate /* 9930Sstevel@tonic-gate * Transmit a PF_KEY error message to the instance either pointed to 9940Sstevel@tonic-gate * by ks, the instance with serial number serial, or more, depending. 9950Sstevel@tonic-gate * 9960Sstevel@tonic-gate * The faulty message (or a reasonable facsimile thereof) is in mp. 9970Sstevel@tonic-gate * This function will free mp or recycle it for delivery, thereby causing 9980Sstevel@tonic-gate * the stream head to free it. 9990Sstevel@tonic-gate */ 10000Sstevel@tonic-gate static void 10010Sstevel@tonic-gate keysock_error(keysock_t *ks, mblk_t *mp, int error, int diagnostic) 10020Sstevel@tonic-gate { 10030Sstevel@tonic-gate sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr; 10043448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate ASSERT(mp->b_datap->db_type == M_DATA); 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate if (samsg->sadb_msg_type < SADB_GETSPI || 10090Sstevel@tonic-gate samsg->sadb_msg_type > SADB_MAX) 10100Sstevel@tonic-gate samsg->sadb_msg_type = SADB_RESERVED; 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate /* 10130Sstevel@tonic-gate * Strip out extension headers. 10140Sstevel@tonic-gate */ 10150Sstevel@tonic-gate ASSERT(mp->b_rptr + sizeof (*samsg) <= mp->b_datap->db_lim); 10160Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (*samsg); 10170Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (sadb_msg_t)); 10180Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)error; 10190Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = (uint16_t)diagnostic; 10200Sstevel@tonic-gate 10213448Sdh155122 keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE, keystack); 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate /* 10250Sstevel@tonic-gate * Pass down a message to a consumer. Wrap it in KEYSOCK_IN, and copy 10260Sstevel@tonic-gate * in the extv if passed in. 10270Sstevel@tonic-gate */ 10280Sstevel@tonic-gate static void 10290Sstevel@tonic-gate keysock_passdown(keysock_t *ks, mblk_t *mp, uint8_t satype, sadb_ext_t *extv[], 10300Sstevel@tonic-gate boolean_t flushmsg) 10310Sstevel@tonic-gate { 10320Sstevel@tonic-gate keysock_consumer_t *kc; 10330Sstevel@tonic-gate mblk_t *wrapper; 10340Sstevel@tonic-gate keysock_in_t *ksi; 10350Sstevel@tonic-gate int i; 10363448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate wrapper = allocb(sizeof (ipsec_info_t), BPRI_HI); 10390Sstevel@tonic-gate if (wrapper == NULL) { 10403448Sdh155122 ks3dbg(keystack, ("keysock_passdown: allocb failed.\n")); 10410Sstevel@tonic-gate if (extv[SADB_EXT_KEY_ENCRYPT] != NULL) 10420Sstevel@tonic-gate bzero(extv[SADB_EXT_KEY_ENCRYPT], 10430Sstevel@tonic-gate SADB_64TO8( 10445240Snordmark extv[SADB_EXT_KEY_ENCRYPT]->sadb_ext_len)); 10450Sstevel@tonic-gate if (extv[SADB_EXT_KEY_AUTH] != NULL) 10460Sstevel@tonic-gate bzero(extv[SADB_EXT_KEY_AUTH], 10470Sstevel@tonic-gate SADB_64TO8( 10485240Snordmark extv[SADB_EXT_KEY_AUTH]->sadb_ext_len)); 10490Sstevel@tonic-gate if (flushmsg) { 10500Sstevel@tonic-gate ks0dbg(( 10510Sstevel@tonic-gate "keysock: Downwards flush/dump message failed!\n")); 10520Sstevel@tonic-gate /* If this is true, I hold the perimeter. */ 10533448Sdh155122 keystack->keystack_flushdump--; 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate freemsg(mp); 10560Sstevel@tonic-gate return; 10570Sstevel@tonic-gate } 10580Sstevel@tonic-gate 10590Sstevel@tonic-gate wrapper->b_datap->db_type = M_CTL; 10600Sstevel@tonic-gate ksi = (keysock_in_t *)wrapper->b_rptr; 10610Sstevel@tonic-gate ksi->ks_in_type = KEYSOCK_IN; 10620Sstevel@tonic-gate ksi->ks_in_len = sizeof (keysock_in_t); 10630Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_SRC] != NULL) 10640Sstevel@tonic-gate ksi->ks_in_srctype = KS_IN_ADDR_UNKNOWN; 10650Sstevel@tonic-gate else ksi->ks_in_srctype = KS_IN_ADDR_NOTTHERE; 10660Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_DST] != NULL) 10670Sstevel@tonic-gate ksi->ks_in_dsttype = KS_IN_ADDR_UNKNOWN; 10680Sstevel@tonic-gate else ksi->ks_in_dsttype = KS_IN_ADDR_NOTTHERE; 10690Sstevel@tonic-gate for (i = 0; i <= SADB_EXT_MAX; i++) 10700Sstevel@tonic-gate ksi->ks_in_extv[i] = extv[i]; 10710Sstevel@tonic-gate ksi->ks_in_serial = ks->keysock_serial; 10720Sstevel@tonic-gate wrapper->b_wptr += sizeof (ipsec_info_t); 10730Sstevel@tonic-gate wrapper->b_cont = mp; 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate /* 10760Sstevel@tonic-gate * Find the appropriate consumer where the message is passed down. 10770Sstevel@tonic-gate */ 10783448Sdh155122 kc = keystack->keystack_consumers[satype]; 10790Sstevel@tonic-gate if (kc == NULL) { 10800Sstevel@tonic-gate freeb(wrapper); 10810Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE); 10820Sstevel@tonic-gate if (flushmsg) { 10830Sstevel@tonic-gate ks0dbg(( 10840Sstevel@tonic-gate "keysock: Downwards flush/dump message failed!\n")); 10850Sstevel@tonic-gate /* If this is true, I hold the perimeter. */ 10863448Sdh155122 keystack->keystack_flushdump--; 10870Sstevel@tonic-gate } 10880Sstevel@tonic-gate return; 10890Sstevel@tonic-gate } 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate /* 10920Sstevel@tonic-gate * NOTE: There used to be code in here to spin while a flush or 10930Sstevel@tonic-gate * dump finished. Keysock now assumes that consumers have enough 10940Sstevel@tonic-gate * MT-savviness to deal with that. 10950Sstevel@tonic-gate */ 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate /* 10980Sstevel@tonic-gate * Current consumers (AH and ESP) are guaranteed to return a 10990Sstevel@tonic-gate * FLUSH or DUMP message back, so when we reach here, we don't 11000Sstevel@tonic-gate * have to worry about keysock_flushdumps. 11010Sstevel@tonic-gate */ 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate putnext(kc->kc_wq, wrapper); 11040Sstevel@tonic-gate } 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate /* 11070Sstevel@tonic-gate * High-level reality checking of extensions. 11080Sstevel@tonic-gate */ 11090Sstevel@tonic-gate static boolean_t 11103448Sdh155122 ext_check(sadb_ext_t *ext, keysock_stack_t *keystack) 11110Sstevel@tonic-gate { 11120Sstevel@tonic-gate int i; 11130Sstevel@tonic-gate uint64_t *lp; 11140Sstevel@tonic-gate sadb_ident_t *id; 11150Sstevel@tonic-gate char *idstr; 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate switch (ext->sadb_ext_type) { 11180Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC: 11190Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST: 11203055Sdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC: 11213055Sdanmcd case SADB_X_EXT_ADDRESS_INNER_DST: 11220Sstevel@tonic-gate /* Check for at least enough addtl length for a sockaddr. */ 11230Sstevel@tonic-gate if (ext->sadb_ext_len <= SADB_8TO64(sizeof (sadb_address_t))) 11240Sstevel@tonic-gate return (B_FALSE); 11250Sstevel@tonic-gate break; 11260Sstevel@tonic-gate case SADB_EXT_LIFETIME_HARD: 11270Sstevel@tonic-gate case SADB_EXT_LIFETIME_SOFT: 11280Sstevel@tonic-gate case SADB_EXT_LIFETIME_CURRENT: 11290Sstevel@tonic-gate if (ext->sadb_ext_len != SADB_8TO64(sizeof (sadb_lifetime_t))) 11300Sstevel@tonic-gate return (B_FALSE); 11310Sstevel@tonic-gate break; 11320Sstevel@tonic-gate case SADB_EXT_SPIRANGE: 11330Sstevel@tonic-gate /* See if the SPI range is legit. */ 11340Sstevel@tonic-gate if (htonl(((sadb_spirange_t *)ext)->sadb_spirange_min) > 11350Sstevel@tonic-gate htonl(((sadb_spirange_t *)ext)->sadb_spirange_max)) 11360Sstevel@tonic-gate return (B_FALSE); 11370Sstevel@tonic-gate break; 11380Sstevel@tonic-gate case SADB_EXT_KEY_AUTH: 11390Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT: 11400Sstevel@tonic-gate /* Key length check. */ 11410Sstevel@tonic-gate if (((sadb_key_t *)ext)->sadb_key_bits == 0) 11420Sstevel@tonic-gate return (B_FALSE); 11430Sstevel@tonic-gate /* 11440Sstevel@tonic-gate * Check to see if the key length (in bits) is less than the 11450Sstevel@tonic-gate * extension length (in 8-bits words). 11460Sstevel@tonic-gate */ 11470Sstevel@tonic-gate if ((roundup(SADB_1TO8(((sadb_key_t *)ext)->sadb_key_bits), 8) + 11480Sstevel@tonic-gate sizeof (sadb_key_t)) != SADB_64TO8(ext->sadb_ext_len)) { 11493448Sdh155122 ks1dbg(keystack, ( 11500Sstevel@tonic-gate "ext_check: Key bits/length inconsistent.\n")); 11513448Sdh155122 ks1dbg(keystack, ("%d bits, len is %d bytes.\n", 11520Sstevel@tonic-gate ((sadb_key_t *)ext)->sadb_key_bits, 11530Sstevel@tonic-gate SADB_64TO8(ext->sadb_ext_len))); 11540Sstevel@tonic-gate return (B_FALSE); 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate /* All-zeroes key check. */ 11580Sstevel@tonic-gate lp = (uint64_t *)(((char *)ext) + sizeof (sadb_key_t)); 11590Sstevel@tonic-gate for (i = 0; 11600Sstevel@tonic-gate i < (ext->sadb_ext_len - SADB_8TO64(sizeof (sadb_key_t))); 11610Sstevel@tonic-gate i++) 11620Sstevel@tonic-gate if (lp[i] != 0) 11630Sstevel@tonic-gate break; /* Out of for loop. */ 11640Sstevel@tonic-gate /* If finished the loop naturally, it's an all zero key. */ 11650Sstevel@tonic-gate if (lp[i] == 0) 11660Sstevel@tonic-gate return (B_FALSE); 11670Sstevel@tonic-gate break; 11680Sstevel@tonic-gate case SADB_EXT_IDENTITY_SRC: 11690Sstevel@tonic-gate case SADB_EXT_IDENTITY_DST: 11700Sstevel@tonic-gate /* 11710Sstevel@tonic-gate * Make sure the strings in these identities are 11720Sstevel@tonic-gate * null-terminated. RFC 2367 underspecified how to handle 11730Sstevel@tonic-gate * such a case. I "proactively" null-terminate the string 11740Sstevel@tonic-gate * at the last byte if it's not terminated sooner. 11750Sstevel@tonic-gate */ 11760Sstevel@tonic-gate id = (sadb_ident_t *)ext; 11770Sstevel@tonic-gate i = SADB_64TO8(id->sadb_ident_len); 11780Sstevel@tonic-gate i -= sizeof (sadb_ident_t); 11790Sstevel@tonic-gate idstr = (char *)(id + 1); 11800Sstevel@tonic-gate while (*idstr != '\0' && i > 0) { 11810Sstevel@tonic-gate i--; 11820Sstevel@tonic-gate idstr++; 11830Sstevel@tonic-gate } 11840Sstevel@tonic-gate if (i == 0) { 11850Sstevel@tonic-gate /* 11860Sstevel@tonic-gate * I.e., if the bozo user didn't NULL-terminate the 11870Sstevel@tonic-gate * string... 11880Sstevel@tonic-gate */ 11890Sstevel@tonic-gate idstr--; 11900Sstevel@tonic-gate *idstr = '\0'; 11910Sstevel@tonic-gate } 11920Sstevel@tonic-gate break; 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate return (B_TRUE); /* For now... */ 11950Sstevel@tonic-gate } 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate /* Return values for keysock_get_ext(). */ 11980Sstevel@tonic-gate #define KGE_OK 0 11990Sstevel@tonic-gate #define KGE_DUP 1 12000Sstevel@tonic-gate #define KGE_UNK 2 12010Sstevel@tonic-gate #define KGE_LEN 3 12020Sstevel@tonic-gate #define KGE_CHK 4 12030Sstevel@tonic-gate 12040Sstevel@tonic-gate /* 12050Sstevel@tonic-gate * Parse basic extension headers and return in the passed-in pointer vector. 12060Sstevel@tonic-gate * Return values include: 12070Sstevel@tonic-gate * 12080Sstevel@tonic-gate * KGE_OK Everything's nice and parsed out. 12090Sstevel@tonic-gate * If there are no extensions, place NULL in extv[0]. 12100Sstevel@tonic-gate * KGE_DUP There is a duplicate extension. 12110Sstevel@tonic-gate * First instance in appropriate bin. First duplicate in 12120Sstevel@tonic-gate * extv[0]. 12130Sstevel@tonic-gate * KGE_UNK Unknown extension type encountered. extv[0] contains 12140Sstevel@tonic-gate * unknown header. 12150Sstevel@tonic-gate * KGE_LEN Extension length error. 12160Sstevel@tonic-gate * KGE_CHK High-level reality check failed on specific extension. 12170Sstevel@tonic-gate * 12180Sstevel@tonic-gate * My apologies for some of the pointer arithmetic in here. I'm thinking 12190Sstevel@tonic-gate * like an assembly programmer, yet trying to make the compiler happy. 12200Sstevel@tonic-gate */ 12210Sstevel@tonic-gate static int 12223448Sdh155122 keysock_get_ext(sadb_ext_t *extv[], sadb_msg_t *basehdr, uint_t msgsize, 12233448Sdh155122 keysock_stack_t *keystack) 12240Sstevel@tonic-gate { 12250Sstevel@tonic-gate bzero(extv, sizeof (sadb_ext_t *) * (SADB_EXT_MAX + 1)); 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate /* Use extv[0] as the "current working pointer". */ 12280Sstevel@tonic-gate 12290Sstevel@tonic-gate extv[0] = (sadb_ext_t *)(basehdr + 1); 12300Sstevel@tonic-gate 12310Sstevel@tonic-gate while (extv[0] < (sadb_ext_t *)(((uint8_t *)basehdr) + msgsize)) { 12320Sstevel@tonic-gate /* Check for unknown headers. */ 12330Sstevel@tonic-gate if (extv[0]->sadb_ext_type == 0 || 12340Sstevel@tonic-gate extv[0]->sadb_ext_type > SADB_EXT_MAX) 12350Sstevel@tonic-gate return (KGE_UNK); 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate /* 12380Sstevel@tonic-gate * Check length. Use uint64_t because extlen is in units 12390Sstevel@tonic-gate * of 64-bit words. If length goes beyond the msgsize, 12400Sstevel@tonic-gate * return an error. (Zero length also qualifies here.) 12410Sstevel@tonic-gate */ 12420Sstevel@tonic-gate if (extv[0]->sadb_ext_len == 0 || 12430Sstevel@tonic-gate (void *)((uint64_t *)extv[0] + extv[0]->sadb_ext_len) > 12440Sstevel@tonic-gate (void *)((uint8_t *)basehdr + msgsize)) 12450Sstevel@tonic-gate return (KGE_LEN); 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate /* Check for redundant headers. */ 12480Sstevel@tonic-gate if (extv[extv[0]->sadb_ext_type] != NULL) 12490Sstevel@tonic-gate return (KGE_DUP); 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate /* 12520Sstevel@tonic-gate * Reality check the extension if possible at the keysock 12530Sstevel@tonic-gate * level. 12540Sstevel@tonic-gate */ 12553448Sdh155122 if (!ext_check(extv[0], keystack)) 12560Sstevel@tonic-gate return (KGE_CHK); 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate /* If I make it here, assign the appropriate bin. */ 12590Sstevel@tonic-gate extv[extv[0]->sadb_ext_type] = extv[0]; 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate /* Advance pointer (See above for uint64_t ptr reasoning.) */ 12620Sstevel@tonic-gate extv[0] = (sadb_ext_t *) 12630Sstevel@tonic-gate ((uint64_t *)extv[0] + extv[0]->sadb_ext_len); 12640Sstevel@tonic-gate } 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate /* Everything's cool. */ 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate /* 12690Sstevel@tonic-gate * If extv[0] == NULL, then there are no extension headers in this 12700Sstevel@tonic-gate * message. Ensure that this is the case. 12710Sstevel@tonic-gate */ 12720Sstevel@tonic-gate if (extv[0] == (sadb_ext_t *)(basehdr + 1)) 12730Sstevel@tonic-gate extv[0] = NULL; 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate return (KGE_OK); 12760Sstevel@tonic-gate } 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate /* 12790Sstevel@tonic-gate * qwriter() callback to handle flushes and dumps. This routine will hold 12800Sstevel@tonic-gate * the inner perimeter. 12810Sstevel@tonic-gate */ 12820Sstevel@tonic-gate void 12830Sstevel@tonic-gate keysock_do_flushdump(queue_t *q, mblk_t *mp) 12840Sstevel@tonic-gate { 12850Sstevel@tonic-gate int i, start, finish; 12860Sstevel@tonic-gate mblk_t *mp1 = NULL; 12870Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 12880Sstevel@tonic-gate sadb_ext_t *extv[SADB_EXT_MAX + 1]; 12890Sstevel@tonic-gate sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr; 12903448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate /* 12930Sstevel@tonic-gate * I am guaranteed this will work. I did the work in keysock_parse() 12940Sstevel@tonic-gate * already. 12950Sstevel@tonic-gate */ 12963448Sdh155122 (void) keysock_get_ext(extv, samsg, SADB_64TO8(samsg->sadb_msg_len), 12973448Sdh155122 keystack); 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate /* 13000Sstevel@tonic-gate * I hold the perimeter, therefore I don't need to use atomic ops. 13010Sstevel@tonic-gate */ 13023448Sdh155122 if (keystack->keystack_flushdump != 0) { 13030Sstevel@tonic-gate /* XXX Should I instead use EBUSY? */ 13040Sstevel@tonic-gate /* XXX Or is there a way to queue these up? */ 13050Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, SADB_X_DIAGNOSTIC_NONE); 13060Sstevel@tonic-gate return; 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 13100Sstevel@tonic-gate start = 0; 13110Sstevel@tonic-gate finish = KEYSOCK_MAX_CONSUMERS - 1; 13120Sstevel@tonic-gate } else { 13130Sstevel@tonic-gate start = samsg->sadb_msg_satype; 13140Sstevel@tonic-gate finish = samsg->sadb_msg_satype; 13150Sstevel@tonic-gate } 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate /* 13180Sstevel@tonic-gate * Fill up keysock_flushdump with the number of outstanding dumps 13190Sstevel@tonic-gate * and/or flushes. 13200Sstevel@tonic-gate */ 13210Sstevel@tonic-gate 13223448Sdh155122 keystack->keystack_flushdump_errno = 0; 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate /* 13250Sstevel@tonic-gate * Okay, I hold the perimeter. Eventually keysock_flushdump will 13260Sstevel@tonic-gate * contain the number of consumers with outstanding flush operations. 13270Sstevel@tonic-gate * 13280Sstevel@tonic-gate * SO, here's the plan: 13290Sstevel@tonic-gate * * For each relevant consumer (Might be one, might be all) 13300Sstevel@tonic-gate * * Twiddle on the FLUSHING flag. 13310Sstevel@tonic-gate * * Pass down the FLUSH/DUMP message. 13320Sstevel@tonic-gate * 13330Sstevel@tonic-gate * When I see upbound FLUSH/DUMP messages, I will decrement the 13340Sstevel@tonic-gate * keysock_flushdump. When I decrement it to 0, I will pass the 13350Sstevel@tonic-gate * FLUSH/DUMP message back up to the PF_KEY sockets. Because I will 13360Sstevel@tonic-gate * pass down the right SA type to the consumer (either its own, or 13370Sstevel@tonic-gate * that of UNSPEC), the right one will be reflected from each consumer, 13380Sstevel@tonic-gate * and accordingly back to the socket. 13390Sstevel@tonic-gate */ 13400Sstevel@tonic-gate 13413448Sdh155122 mutex_enter(&keystack->keystack_consumers_lock); 13420Sstevel@tonic-gate for (i = start; i <= finish; i++) { 13433448Sdh155122 if (keystack->keystack_consumers[i] != NULL) { 13440Sstevel@tonic-gate mp1 = copymsg(mp); 13450Sstevel@tonic-gate if (mp1 == NULL) { 13460Sstevel@tonic-gate ks0dbg(("SADB_FLUSH copymsg() failed.\n")); 13470Sstevel@tonic-gate /* 13480Sstevel@tonic-gate * Error? And what about outstanding 13490Sstevel@tonic-gate * flushes? Oh, yeah, they get sucked up and 13500Sstevel@tonic-gate * the counter is decremented. Consumers 13510Sstevel@tonic-gate * (see keysock_passdown()) are guaranteed 13520Sstevel@tonic-gate * to deliver back a flush request, even if 13530Sstevel@tonic-gate * it's an error. 13540Sstevel@tonic-gate */ 13550Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, 13560Sstevel@tonic-gate SADB_X_DIAGNOSTIC_NONE); 13570Sstevel@tonic-gate return; 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate /* 13600Sstevel@tonic-gate * Because my entry conditions are met above, the 13610Sstevel@tonic-gate * following assertion should hold true. 13620Sstevel@tonic-gate */ 13633448Sdh155122 mutex_enter(&keystack->keystack_consumers[i]->kc_lock); 13643448Sdh155122 ASSERT((keystack->keystack_consumers[i]->kc_flags & 13655240Snordmark KC_FLUSHING) == 0); 13663448Sdh155122 keystack->keystack_consumers[i]->kc_flags |= 13673448Sdh155122 KC_FLUSHING; 13683448Sdh155122 mutex_exit(&(keystack->keystack_consumers[i]->kc_lock)); 13690Sstevel@tonic-gate /* Always increment the number of flushes... */ 13703448Sdh155122 keystack->keystack_flushdump++; 13710Sstevel@tonic-gate /* Guaranteed to return a message. */ 13720Sstevel@tonic-gate keysock_passdown(ks, mp1, i, extv, B_TRUE); 13730Sstevel@tonic-gate } else if (start == finish) { 13740Sstevel@tonic-gate /* 13750Sstevel@tonic-gate * In case where start == finish, and there's no 13760Sstevel@tonic-gate * consumer, should we force an error? Yes. 13770Sstevel@tonic-gate */ 13783448Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 13790Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 13800Sstevel@tonic-gate SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE); 13810Sstevel@tonic-gate return; 13820Sstevel@tonic-gate } 13830Sstevel@tonic-gate } 13843448Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 13850Sstevel@tonic-gate 13863448Sdh155122 if (keystack->keystack_flushdump == 0) { 13870Sstevel@tonic-gate /* 13880Sstevel@tonic-gate * There were no consumers at all for this message. 13890Sstevel@tonic-gate * XXX For now return ESRCH. 13900Sstevel@tonic-gate */ 13910Sstevel@tonic-gate keysock_error(ks, mp, ESRCH, SADB_X_DIAGNOSTIC_NO_SADBS); 13920Sstevel@tonic-gate } else { 13930Sstevel@tonic-gate /* Otherwise, free the original message. */ 13940Sstevel@tonic-gate freemsg(mp); 13950Sstevel@tonic-gate } 13960Sstevel@tonic-gate } 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate /* 13990Sstevel@tonic-gate * Get the right diagnostic for a duplicate. Should probably use a static 14000Sstevel@tonic-gate * table lookup. 14010Sstevel@tonic-gate */ 14020Sstevel@tonic-gate int 14030Sstevel@tonic-gate keysock_duplicate(int ext_type) 14040Sstevel@tonic-gate { 14050Sstevel@tonic-gate int rc = 0; 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate switch (ext_type) { 14080Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC: 14090Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_SRC; 14100Sstevel@tonic-gate break; 14110Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST: 14120Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_DST; 14130Sstevel@tonic-gate break; 14143055Sdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC: 14153055Sdanmcd rc = SADB_X_DIAGNOSTIC_DUPLICATE_INNER_SRC; 14163055Sdanmcd break; 14173055Sdanmcd case SADB_X_EXT_ADDRESS_INNER_DST: 14183055Sdanmcd rc = SADB_X_DIAGNOSTIC_DUPLICATE_INNER_DST; 14193055Sdanmcd break; 14200Sstevel@tonic-gate case SADB_EXT_SA: 14210Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_SA; 14220Sstevel@tonic-gate break; 14230Sstevel@tonic-gate case SADB_EXT_SPIRANGE: 14240Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_RANGE; 14250Sstevel@tonic-gate break; 14260Sstevel@tonic-gate case SADB_EXT_KEY_AUTH: 14270Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_AKEY; 14280Sstevel@tonic-gate break; 14290Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT: 14300Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_EKEY; 14310Sstevel@tonic-gate break; 14320Sstevel@tonic-gate } 14330Sstevel@tonic-gate return (rc); 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate /* 14370Sstevel@tonic-gate * Get the right diagnostic for a reality check failure. Should probably use 14380Sstevel@tonic-gate * a static table lookup. 14390Sstevel@tonic-gate */ 14400Sstevel@tonic-gate int 14410Sstevel@tonic-gate keysock_malformed(int ext_type) 14420Sstevel@tonic-gate { 14430Sstevel@tonic-gate int rc = 0; 14440Sstevel@tonic-gate 14450Sstevel@tonic-gate switch (ext_type) { 14460Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC: 14470Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_SRC; 14480Sstevel@tonic-gate break; 14490Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST: 14500Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_DST; 14510Sstevel@tonic-gate break; 14523055Sdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC: 14533055Sdanmcd rc = SADB_X_DIAGNOSTIC_MALFORMED_INNER_SRC; 14543055Sdanmcd break; 14553055Sdanmcd case SADB_X_EXT_ADDRESS_INNER_DST: 14563055Sdanmcd rc = SADB_X_DIAGNOSTIC_MALFORMED_INNER_DST; 14573055Sdanmcd break; 14580Sstevel@tonic-gate case SADB_EXT_SA: 14590Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_SA; 14600Sstevel@tonic-gate break; 14610Sstevel@tonic-gate case SADB_EXT_SPIRANGE: 14620Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_RANGE; 14630Sstevel@tonic-gate break; 14640Sstevel@tonic-gate case SADB_EXT_KEY_AUTH: 14650Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_AKEY; 14660Sstevel@tonic-gate break; 14670Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT: 14680Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_EKEY; 14690Sstevel@tonic-gate break; 14700Sstevel@tonic-gate } 14710Sstevel@tonic-gate return (rc); 14720Sstevel@tonic-gate } 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate /* 14750Sstevel@tonic-gate * Keysock massaging of an inverse ACQUIRE. Consult policy, 14760Sstevel@tonic-gate * and construct an appropriate response. 14770Sstevel@tonic-gate */ 14780Sstevel@tonic-gate static void 14790Sstevel@tonic-gate keysock_inverse_acquire(mblk_t *mp, sadb_msg_t *samsg, sadb_ext_t *extv[], 14800Sstevel@tonic-gate keysock_t *ks) 14810Sstevel@tonic-gate { 14820Sstevel@tonic-gate mblk_t *reply_mp; 14833448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 14840Sstevel@tonic-gate 14850Sstevel@tonic-gate /* 14860Sstevel@tonic-gate * Reality check things... 14870Sstevel@tonic-gate */ 14880Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_SRC] == NULL) { 14890Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_SRC); 14900Sstevel@tonic-gate return; 14910Sstevel@tonic-gate } 14920Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_DST] == NULL) { 14930Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_DST); 14943055Sdanmcd return; 14953055Sdanmcd } 14963055Sdanmcd 14973055Sdanmcd if (extv[SADB_X_EXT_ADDRESS_INNER_SRC] != NULL && 14983055Sdanmcd extv[SADB_X_EXT_ADDRESS_INNER_DST] == NULL) { 14993055Sdanmcd keysock_error(ks, mp, EINVAL, 15003055Sdanmcd SADB_X_DIAGNOSTIC_MISSING_INNER_DST); 15013055Sdanmcd return; 15023055Sdanmcd } 15033055Sdanmcd 15043055Sdanmcd if (extv[SADB_X_EXT_ADDRESS_INNER_SRC] == NULL && 15053055Sdanmcd extv[SADB_X_EXT_ADDRESS_INNER_DST] != NULL) { 15063055Sdanmcd keysock_error(ks, mp, EINVAL, 15073055Sdanmcd SADB_X_DIAGNOSTIC_MISSING_INNER_SRC); 15083055Sdanmcd return; 15090Sstevel@tonic-gate } 15100Sstevel@tonic-gate 15113448Sdh155122 reply_mp = ipsec_construct_inverse_acquire(samsg, extv, 15123448Sdh155122 keystack->keystack_netstack); 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate if (reply_mp != NULL) { 15150Sstevel@tonic-gate freemsg(mp); 15160Sstevel@tonic-gate keysock_passup(reply_mp, (sadb_msg_t *)reply_mp->b_rptr, 15173448Sdh155122 ks->keysock_serial, NULL, B_FALSE, keystack); 15180Sstevel@tonic-gate } else { 15190Sstevel@tonic-gate keysock_error(ks, mp, samsg->sadb_msg_errno, 15200Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic); 15210Sstevel@tonic-gate } 15220Sstevel@tonic-gate } 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate /* 15250Sstevel@tonic-gate * Spew an extended REGISTER down to the relevant consumers. 15260Sstevel@tonic-gate */ 15270Sstevel@tonic-gate static void 15280Sstevel@tonic-gate keysock_extended_register(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[]) 15290Sstevel@tonic-gate { 15300Sstevel@tonic-gate sadb_x_ereg_t *ereg = (sadb_x_ereg_t *)extv[SADB_X_EXT_EREG]; 15310Sstevel@tonic-gate uint8_t *satypes, *fencepost; 15320Sstevel@tonic-gate mblk_t *downmp; 15330Sstevel@tonic-gate sadb_ext_t *downextv[SADB_EXT_MAX + 1]; 15343448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 15350Sstevel@tonic-gate 15360Sstevel@tonic-gate if (ks->keysock_registered[0] != 0 || ks->keysock_registered[1] != 0 || 15370Sstevel@tonic-gate ks->keysock_registered[2] != 0 || ks->keysock_registered[3] != 0) { 15380Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0); 15390Sstevel@tonic-gate } 15400Sstevel@tonic-gate 15410Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_EXTENDED; 15420Sstevel@tonic-gate if (ereg == NULL) { 15430Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 15440Sstevel@tonic-gate } else { 15450Sstevel@tonic-gate ASSERT(mp->b_rptr + msgdsize(mp) == mp->b_wptr); 15460Sstevel@tonic-gate fencepost = (uint8_t *)mp->b_wptr; 15470Sstevel@tonic-gate satypes = ereg->sadb_x_ereg_satypes; 15480Sstevel@tonic-gate while (*satypes != SADB_SATYPE_UNSPEC && satypes != fencepost) { 15490Sstevel@tonic-gate downmp = copymsg(mp); 15500Sstevel@tonic-gate if (downmp == NULL) { 15510Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, 0); 15520Sstevel@tonic-gate return; 15530Sstevel@tonic-gate } 15540Sstevel@tonic-gate /* 15550Sstevel@tonic-gate * Since we've made it here, keysock_get_ext will work! 15560Sstevel@tonic-gate */ 15570Sstevel@tonic-gate (void) keysock_get_ext(downextv, 15583448Sdh155122 (sadb_msg_t *)downmp->b_rptr, msgdsize(downmp), 15593448Sdh155122 keystack); 15600Sstevel@tonic-gate keysock_passdown(ks, downmp, *satypes, downextv, 15610Sstevel@tonic-gate B_FALSE); 15620Sstevel@tonic-gate ++satypes; 15630Sstevel@tonic-gate } 15640Sstevel@tonic-gate freemsg(mp); 15650Sstevel@tonic-gate } 15660Sstevel@tonic-gate 15670Sstevel@tonic-gate /* 15680Sstevel@tonic-gate * Set global to indicate we prefer an extended ACQUIRE. 15690Sstevel@tonic-gate */ 15703448Sdh155122 atomic_add_32(&keystack->keystack_num_extended, 1); 15710Sstevel@tonic-gate } 15720Sstevel@tonic-gate 15737749SThejaswini.Singarajipura@Sun.COM static void 15747749SThejaswini.Singarajipura@Sun.COM keysock_delpair_all(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[]) 15757749SThejaswini.Singarajipura@Sun.COM { 15767749SThejaswini.Singarajipura@Sun.COM int i, start, finish; 15777749SThejaswini.Singarajipura@Sun.COM mblk_t *mp1 = NULL; 15787749SThejaswini.Singarajipura@Sun.COM keysock_stack_t *keystack = ks->keysock_keystack; 15797749SThejaswini.Singarajipura@Sun.COM 15807749SThejaswini.Singarajipura@Sun.COM start = 0; 15817749SThejaswini.Singarajipura@Sun.COM finish = KEYSOCK_MAX_CONSUMERS - 1; 15827749SThejaswini.Singarajipura@Sun.COM 15837749SThejaswini.Singarajipura@Sun.COM for (i = start; i <= finish; i++) { 15847749SThejaswini.Singarajipura@Sun.COM if (keystack->keystack_consumers[i] != NULL) { 15857749SThejaswini.Singarajipura@Sun.COM mp1 = copymsg(mp); 15867749SThejaswini.Singarajipura@Sun.COM if (mp1 == NULL) { 15877749SThejaswini.Singarajipura@Sun.COM keysock_error(ks, mp, ENOMEM, 15887749SThejaswini.Singarajipura@Sun.COM SADB_X_DIAGNOSTIC_NONE); 15897749SThejaswini.Singarajipura@Sun.COM return; 15907749SThejaswini.Singarajipura@Sun.COM } 15917749SThejaswini.Singarajipura@Sun.COM keysock_passdown(ks, mp1, i, extv, B_FALSE); 15927749SThejaswini.Singarajipura@Sun.COM } 15937749SThejaswini.Singarajipura@Sun.COM } 15947749SThejaswini.Singarajipura@Sun.COM } 15957749SThejaswini.Singarajipura@Sun.COM 15960Sstevel@tonic-gate /* 15970Sstevel@tonic-gate * Handle PF_KEY messages. 15980Sstevel@tonic-gate */ 15990Sstevel@tonic-gate static void 16000Sstevel@tonic-gate keysock_parse(queue_t *q, mblk_t *mp) 16010Sstevel@tonic-gate { 16020Sstevel@tonic-gate sadb_msg_t *samsg; 16030Sstevel@tonic-gate sadb_ext_t *extv[SADB_EXT_MAX + 1]; 16040Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 16050Sstevel@tonic-gate uint_t msgsize; 16060Sstevel@tonic-gate uint8_t satype; 16073448Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate /* Make sure I'm a PF_KEY socket. (i.e. nothing's below me) */ 16100Sstevel@tonic-gate ASSERT(WR(q)->q_next == NULL); 16110Sstevel@tonic-gate 16120Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_rptr; 16133448Sdh155122 ks2dbg(keystack, ("Received possible PF_KEY message, type %d.\n", 16140Sstevel@tonic-gate samsg->sadb_msg_type)); 16150Sstevel@tonic-gate 16160Sstevel@tonic-gate msgsize = SADB_64TO8(samsg->sadb_msg_len); 16170Sstevel@tonic-gate 16180Sstevel@tonic-gate if (msgdsize(mp) != msgsize) { 16190Sstevel@tonic-gate /* 16200Sstevel@tonic-gate * Message len incorrect w.r.t. actual size. Send an error 16210Sstevel@tonic-gate * (EMSGSIZE). It may be necessary to massage things a 16220Sstevel@tonic-gate * bit. For example, if the sadb_msg_type is hosed, 16230Sstevel@tonic-gate * I need to set it to SADB_RESERVED to get delivery to 16240Sstevel@tonic-gate * do the right thing. Then again, maybe just letting 16250Sstevel@tonic-gate * the error delivery do the right thing. 16260Sstevel@tonic-gate */ 16273448Sdh155122 ks2dbg(keystack, 16283448Sdh155122 ("mblk (%lu) and base (%d) message sizes don't jibe.\n", 16290Sstevel@tonic-gate msgdsize(mp), msgsize)); 16300Sstevel@tonic-gate keysock_error(ks, mp, EMSGSIZE, SADB_X_DIAGNOSTIC_NONE); 16310Sstevel@tonic-gate return; 16320Sstevel@tonic-gate } 16330Sstevel@tonic-gate 16340Sstevel@tonic-gate if (msgsize > (uint_t)(mp->b_wptr - mp->b_rptr)) { 16350Sstevel@tonic-gate /* Get all message into one mblk. */ 16360Sstevel@tonic-gate if (pullupmsg(mp, -1) == 0) { 16370Sstevel@tonic-gate /* 16380Sstevel@tonic-gate * Something screwy happened. 16390Sstevel@tonic-gate */ 16403448Sdh155122 ks3dbg(keystack, 16413448Sdh155122 ("keysock_parse: pullupmsg() failed.\n")); 16420Sstevel@tonic-gate return; 16430Sstevel@tonic-gate } else { 16440Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_rptr; 16450Sstevel@tonic-gate } 16460Sstevel@tonic-gate } 16470Sstevel@tonic-gate 16483448Sdh155122 switch (keysock_get_ext(extv, samsg, msgsize, keystack)) { 16490Sstevel@tonic-gate case KGE_DUP: 16500Sstevel@tonic-gate /* Handle duplicate extension. */ 16513448Sdh155122 ks1dbg(keystack, ("Got duplicate extension of type %d.\n", 16520Sstevel@tonic-gate extv[0]->sadb_ext_type)); 16530Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 16540Sstevel@tonic-gate keysock_duplicate(extv[0]->sadb_ext_type)); 16550Sstevel@tonic-gate return; 16560Sstevel@tonic-gate case KGE_UNK: 16570Sstevel@tonic-gate /* Handle unknown extension. */ 16583448Sdh155122 ks1dbg(keystack, ("Got unknown extension of type %d.\n", 16590Sstevel@tonic-gate extv[0]->sadb_ext_type)); 16600Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_EXT); 16610Sstevel@tonic-gate return; 16620Sstevel@tonic-gate case KGE_LEN: 16630Sstevel@tonic-gate /* Length error. */ 16643448Sdh155122 ks1dbg(keystack, 16653448Sdh155122 ("Length %d on extension type %d overrun or 0.\n", 16660Sstevel@tonic-gate extv[0]->sadb_ext_len, extv[0]->sadb_ext_type)); 16670Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_BAD_EXTLEN); 16680Sstevel@tonic-gate return; 16690Sstevel@tonic-gate case KGE_CHK: 16700Sstevel@tonic-gate /* Reality check failed. */ 16713448Sdh155122 ks1dbg(keystack, 16723448Sdh155122 ("Reality check failed on extension type %d.\n", 16730Sstevel@tonic-gate extv[0]->sadb_ext_type)); 16740Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 16750Sstevel@tonic-gate keysock_malformed(extv[0]->sadb_ext_type)); 16760Sstevel@tonic-gate return; 16770Sstevel@tonic-gate default: 16780Sstevel@tonic-gate /* Default case is no errors. */ 16790Sstevel@tonic-gate break; 16800Sstevel@tonic-gate } 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 16830Sstevel@tonic-gate case SADB_REGISTER: 16840Sstevel@tonic-gate /* 16850Sstevel@tonic-gate * There's a semantic weirdness in that a message OTHER than 16860Sstevel@tonic-gate * the return REGISTER message may be passed up if I set the 16870Sstevel@tonic-gate * registered bit BEFORE I pass it down. 16880Sstevel@tonic-gate * 16890Sstevel@tonic-gate * SOOOO, I'll not twiddle any registered bits until I see 16900Sstevel@tonic-gate * the upbound REGISTER (with a serial number in it). 16910Sstevel@tonic-gate */ 16920Sstevel@tonic-gate if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 16930Sstevel@tonic-gate /* Handle extended register here. */ 16940Sstevel@tonic-gate keysock_extended_register(ks, mp, extv); 16950Sstevel@tonic-gate return; 16960Sstevel@tonic-gate } else if (ks->keysock_flags & KEYSOCK_EXTENDED) { 16970Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0); 16980Sstevel@tonic-gate return; 16990Sstevel@tonic-gate } 17000Sstevel@tonic-gate /* FALLTHRU */ 17010Sstevel@tonic-gate case SADB_GETSPI: 17020Sstevel@tonic-gate case SADB_ADD: 17030Sstevel@tonic-gate case SADB_UPDATE: 17046668Smarkfen case SADB_X_UPDATEPAIR: 17050Sstevel@tonic-gate case SADB_DELETE: 17066668Smarkfen case SADB_X_DELPAIR: 17070Sstevel@tonic-gate case SADB_GET: 17080Sstevel@tonic-gate /* 17090Sstevel@tonic-gate * Pass down to appropriate consumer. 17100Sstevel@tonic-gate */ 17110Sstevel@tonic-gate if (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC) 17120Sstevel@tonic-gate keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv, 17130Sstevel@tonic-gate B_FALSE); 17140Sstevel@tonic-gate else keysock_error(ks, mp, EINVAL, 17150Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 17160Sstevel@tonic-gate return; 17177749SThejaswini.Singarajipura@Sun.COM case SADB_X_DELPAIR_STATE: 17187749SThejaswini.Singarajipura@Sun.COM if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 17197749SThejaswini.Singarajipura@Sun.COM keysock_delpair_all(ks, mp, extv); 17207749SThejaswini.Singarajipura@Sun.COM } else { 17217749SThejaswini.Singarajipura@Sun.COM keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv, 17227749SThejaswini.Singarajipura@Sun.COM B_FALSE); 17237749SThejaswini.Singarajipura@Sun.COM } 17247749SThejaswini.Singarajipura@Sun.COM return; 17250Sstevel@tonic-gate case SADB_ACQUIRE: 17260Sstevel@tonic-gate /* 17270Sstevel@tonic-gate * If I _receive_ an acquire, this means I should spread it 17280Sstevel@tonic-gate * out to registered sockets. Unless there's an errno... 17290Sstevel@tonic-gate * 17300Sstevel@tonic-gate * Need ADDRESS, may have ID, SENS, and PROP, unless errno, 17310Sstevel@tonic-gate * in which case there should be NO extensions. 17320Sstevel@tonic-gate * 17330Sstevel@tonic-gate * Return to registered. 17340Sstevel@tonic-gate */ 17350Sstevel@tonic-gate if (samsg->sadb_msg_errno != 0) { 17360Sstevel@tonic-gate satype = samsg->sadb_msg_satype; 17370Sstevel@tonic-gate if (satype == SADB_SATYPE_UNSPEC) { 17380Sstevel@tonic-gate if (!(ks->keysock_flags & KEYSOCK_EXTENDED)) { 17390Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 17400Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 17410Sstevel@tonic-gate return; 17420Sstevel@tonic-gate } 17430Sstevel@tonic-gate /* 17440Sstevel@tonic-gate * Reassign satype based on the first 17450Sstevel@tonic-gate * flags that KEYSOCK_SETREG says. 17460Sstevel@tonic-gate */ 17470Sstevel@tonic-gate while (satype <= SADB_SATYPE_MAX) { 17480Sstevel@tonic-gate if (KEYSOCK_ISREG(ks, satype)) 17490Sstevel@tonic-gate break; 17500Sstevel@tonic-gate satype++; 17510Sstevel@tonic-gate } 17520Sstevel@tonic-gate if (satype > SADB_SATYPE_MAX) { 17530Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0); 17540Sstevel@tonic-gate return; 17550Sstevel@tonic-gate } 17560Sstevel@tonic-gate } 17570Sstevel@tonic-gate keysock_passdown(ks, mp, satype, extv, B_FALSE); 17580Sstevel@tonic-gate } else { 17593448Sdh155122 if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 17600Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 17610Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 17623448Sdh155122 } else { 17633448Sdh155122 keysock_passup(mp, samsg, 0, NULL, B_FALSE, 17643448Sdh155122 keystack); 17653448Sdh155122 } 17660Sstevel@tonic-gate } 17670Sstevel@tonic-gate return; 17680Sstevel@tonic-gate case SADB_EXPIRE: 17690Sstevel@tonic-gate /* 17700Sstevel@tonic-gate * If someone sends this in, then send out to all senders. 17710Sstevel@tonic-gate * (Save maybe ESP or AH, I have to be careful here.) 17720Sstevel@tonic-gate * 17730Sstevel@tonic-gate * Need ADDRESS, may have ID and SENS. 17740Sstevel@tonic-gate * 17750Sstevel@tonic-gate * XXX for now this is unsupported. 17760Sstevel@tonic-gate */ 17770Sstevel@tonic-gate break; 17780Sstevel@tonic-gate case SADB_FLUSH: 17790Sstevel@tonic-gate /* 17807749SThejaswini.Singarajipura@Sun.COM * Nuke all SAs. 17810Sstevel@tonic-gate * 17820Sstevel@tonic-gate * No extensions at all. Return to all listeners. 17830Sstevel@tonic-gate * 17840Sstevel@tonic-gate * Question: Should I hold a lock here to prevent 17850Sstevel@tonic-gate * additions/deletions while flushing? 17860Sstevel@tonic-gate * Answer: No. (See keysock_passdown() for details.) 17870Sstevel@tonic-gate */ 17880Sstevel@tonic-gate if (extv[0] != NULL) { 17890Sstevel@tonic-gate /* 17907749SThejaswini.Singarajipura@Sun.COM * FLUSH messages shouldn't have extensions. 17910Sstevel@tonic-gate * Return EINVAL. 17920Sstevel@tonic-gate */ 17933448Sdh155122 ks2dbg(keystack, ("FLUSH message with extension.\n")); 17940Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_NO_EXT); 17950Sstevel@tonic-gate return; 17960Sstevel@tonic-gate } 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate /* Passing down of DUMP/FLUSH messages are special. */ 17990Sstevel@tonic-gate qwriter(q, mp, keysock_do_flushdump, PERIM_INNER); 18000Sstevel@tonic-gate return; 18017749SThejaswini.Singarajipura@Sun.COM case SADB_DUMP: /* not used by normal applications */ 18027749SThejaswini.Singarajipura@Sun.COM if ((extv[0] != NULL) && 18037749SThejaswini.Singarajipura@Sun.COM ((msgsize > 18047749SThejaswini.Singarajipura@Sun.COM (sizeof (sadb_msg_t) + sizeof (sadb_x_edump_t))) || 18057749SThejaswini.Singarajipura@Sun.COM (extv[SADB_X_EXT_EDUMP] == NULL))) { 18067749SThejaswini.Singarajipura@Sun.COM keysock_error(ks, mp, EINVAL, 18077749SThejaswini.Singarajipura@Sun.COM SADB_X_DIAGNOSTIC_NO_EXT); 18087749SThejaswini.Singarajipura@Sun.COM return; 18097749SThejaswini.Singarajipura@Sun.COM } 18107749SThejaswini.Singarajipura@Sun.COM qwriter(q, mp, keysock_do_flushdump, PERIM_INNER); 18117749SThejaswini.Singarajipura@Sun.COM return; 18120Sstevel@tonic-gate case SADB_X_PROMISC: 18130Sstevel@tonic-gate /* 18140Sstevel@tonic-gate * Promiscuous processing message. 18150Sstevel@tonic-gate */ 18160Sstevel@tonic-gate if (samsg->sadb_msg_satype == 0) 18170Sstevel@tonic-gate ks->keysock_flags &= ~KEYSOCK_PROMISC; 18180Sstevel@tonic-gate else 18190Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_PROMISC; 18203448Sdh155122 keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE, 18213448Sdh155122 keystack); 18220Sstevel@tonic-gate return; 18230Sstevel@tonic-gate case SADB_X_INVERSE_ACQUIRE: 18240Sstevel@tonic-gate keysock_inverse_acquire(mp, samsg, extv, ks); 18250Sstevel@tonic-gate return; 18260Sstevel@tonic-gate default: 18273448Sdh155122 ks2dbg(keystack, ("Got unknown message type %d.\n", 18280Sstevel@tonic-gate samsg->sadb_msg_type)); 18290Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_MSG); 18300Sstevel@tonic-gate return; 18310Sstevel@tonic-gate } 18320Sstevel@tonic-gate 18330Sstevel@tonic-gate /* As a placeholder... */ 18340Sstevel@tonic-gate ks0dbg(("keysock_parse(): Hit EOPNOTSUPP\n")); 18350Sstevel@tonic-gate keysock_error(ks, mp, EOPNOTSUPP, SADB_X_DIAGNOSTIC_NONE); 18360Sstevel@tonic-gate } 18370Sstevel@tonic-gate 18380Sstevel@tonic-gate /* 18390Sstevel@tonic-gate * wput routing for PF_KEY/keysock/whatever. Unlike the routing socket, 18400Sstevel@tonic-gate * I don't convert to ioctl()'s for IP. I am the end-all driver as far 18410Sstevel@tonic-gate * as PF_KEY sockets are concerned. I do some conversion, but not as much 18420Sstevel@tonic-gate * as IP/rts does. 18430Sstevel@tonic-gate */ 18440Sstevel@tonic-gate static void 18450Sstevel@tonic-gate keysock_wput(queue_t *q, mblk_t *mp) 18460Sstevel@tonic-gate { 18470Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 18480Sstevel@tonic-gate mblk_t *mp1; 18493448Sdh155122 keysock_t *ks; 18503448Sdh155122 keysock_stack_t *keystack; 18510Sstevel@tonic-gate 18520Sstevel@tonic-gate if (WR(q)->q_next) { 18530Sstevel@tonic-gate keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr; 18543448Sdh155122 keystack = kc->kc_keystack; 18553448Sdh155122 18563448Sdh155122 ks3dbg(keystack, ("In keysock_wput\n")); 18570Sstevel@tonic-gate 18580Sstevel@tonic-gate /* 18590Sstevel@tonic-gate * We shouldn't get writes on a consumer instance. 18600Sstevel@tonic-gate * But for now, just passthru. 18610Sstevel@tonic-gate */ 18623448Sdh155122 ks1dbg(keystack, ("Huh? wput for an consumer instance (%d)?\n", 18630Sstevel@tonic-gate kc->kc_sa_type)); 18640Sstevel@tonic-gate putnext(q, mp); 18650Sstevel@tonic-gate return; 18660Sstevel@tonic-gate } 18673448Sdh155122 ks = (keysock_t *)q->q_ptr; 18683448Sdh155122 keystack = ks->keysock_keystack; 18693448Sdh155122 18703448Sdh155122 ks3dbg(keystack, ("In keysock_wput\n")); 18710Sstevel@tonic-gate 18720Sstevel@tonic-gate switch (mp->b_datap->db_type) { 18730Sstevel@tonic-gate case M_DATA: 18740Sstevel@tonic-gate /* 18750Sstevel@tonic-gate * Silently discard. 18760Sstevel@tonic-gate */ 18773448Sdh155122 ks2dbg(keystack, ("raw M_DATA in keysock.\n")); 18780Sstevel@tonic-gate freemsg(mp); 18790Sstevel@tonic-gate return; 18800Sstevel@tonic-gate case M_PROTO: 18810Sstevel@tonic-gate case M_PCPROTO: 18820Sstevel@tonic-gate if ((mp->b_wptr - rptr) >= sizeof (struct T_data_req)) { 18830Sstevel@tonic-gate if (((union T_primitives *)rptr)->type == T_DATA_REQ) { 18840Sstevel@tonic-gate if ((mp1 = mp->b_cont) == NULL) { 18850Sstevel@tonic-gate /* No data after T_DATA_REQ. */ 18863448Sdh155122 ks2dbg(keystack, 18873448Sdh155122 ("No data after DATA_REQ.\n")); 18880Sstevel@tonic-gate freemsg(mp); 18890Sstevel@tonic-gate return; 18900Sstevel@tonic-gate } 18910Sstevel@tonic-gate freeb(mp); 18920Sstevel@tonic-gate mp = mp1; 18933448Sdh155122 ks2dbg(keystack, ("T_DATA_REQ\n")); 18940Sstevel@tonic-gate break; /* Out of switch. */ 18950Sstevel@tonic-gate } 18960Sstevel@tonic-gate } 18970Sstevel@tonic-gate /* FALLTHRU */ 18980Sstevel@tonic-gate default: 18993448Sdh155122 ks3dbg(keystack, ("In default wput case (%d %d).\n", 19000Sstevel@tonic-gate mp->b_datap->db_type, ((union T_primitives *)rptr)->type)); 19010Sstevel@tonic-gate keysock_wput_other(q, mp); 19020Sstevel@tonic-gate return; 19030Sstevel@tonic-gate } 19040Sstevel@tonic-gate 19050Sstevel@tonic-gate /* I now have a PF_KEY message in an M_DATA block, pointed to by mp. */ 19060Sstevel@tonic-gate keysock_parse(q, mp); 19070Sstevel@tonic-gate } 19080Sstevel@tonic-gate 19090Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_rput(). */ 19100Sstevel@tonic-gate 19110Sstevel@tonic-gate /* 19120Sstevel@tonic-gate * Called upon receipt of a KEYSOCK_HELLO_ACK to set up the appropriate 19130Sstevel@tonic-gate * state vectors. 19140Sstevel@tonic-gate */ 19150Sstevel@tonic-gate static void 19160Sstevel@tonic-gate keysock_link_consumer(uint8_t satype, keysock_consumer_t *kc) 19170Sstevel@tonic-gate { 19180Sstevel@tonic-gate keysock_t *ks; 19193448Sdh155122 keysock_stack_t *keystack = kc->kc_keystack; 19200Sstevel@tonic-gate 19213448Sdh155122 mutex_enter(&keystack->keystack_consumers_lock); 19220Sstevel@tonic-gate mutex_enter(&kc->kc_lock); 19233448Sdh155122 if (keystack->keystack_consumers[satype] != NULL) { 19240Sstevel@tonic-gate ks0dbg(( 19250Sstevel@tonic-gate "Hmmmm, someone closed %d before the HELLO_ACK happened.\n", 19260Sstevel@tonic-gate satype)); 19270Sstevel@tonic-gate /* 19280Sstevel@tonic-gate * Perhaps updating the new below-me consumer with what I have 19290Sstevel@tonic-gate * so far would work too? 19300Sstevel@tonic-gate */ 19310Sstevel@tonic-gate mutex_exit(&kc->kc_lock); 19323448Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 19330Sstevel@tonic-gate } else { 19340Sstevel@tonic-gate /* Add new below-me consumer. */ 19353448Sdh155122 keystack->keystack_consumers[satype] = kc; 19360Sstevel@tonic-gate 19370Sstevel@tonic-gate kc->kc_flags = 0; 19380Sstevel@tonic-gate kc->kc_sa_type = satype; 19390Sstevel@tonic-gate mutex_exit(&kc->kc_lock); 19403448Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 19410Sstevel@tonic-gate 19420Sstevel@tonic-gate /* Scan the keysock list. */ 19433448Sdh155122 mutex_enter(&keystack->keystack_list_lock); 19443448Sdh155122 for (ks = keystack->keystack_list; ks != NULL; 19453448Sdh155122 ks = ks->keysock_next) { 19460Sstevel@tonic-gate if (KEYSOCK_ISREG(ks, satype)) { 19470Sstevel@tonic-gate /* 19480Sstevel@tonic-gate * XXX Perhaps send an SADB_REGISTER down on 19490Sstevel@tonic-gate * the socket's behalf. 19500Sstevel@tonic-gate */ 19513448Sdh155122 ks1dbg(keystack, 19523448Sdh155122 ("Socket %u registered already for " 19530Sstevel@tonic-gate "new consumer.\n", ks->keysock_serial)); 19540Sstevel@tonic-gate } 19550Sstevel@tonic-gate } 19563448Sdh155122 mutex_exit(&keystack->keystack_list_lock); 19570Sstevel@tonic-gate } 19580Sstevel@tonic-gate } 19590Sstevel@tonic-gate 19600Sstevel@tonic-gate /* 19610Sstevel@tonic-gate * Generate a KEYSOCK_OUT_ERR message for my consumer. 19620Sstevel@tonic-gate */ 19630Sstevel@tonic-gate static void 19640Sstevel@tonic-gate keysock_out_err(keysock_consumer_t *kc, int ks_errno, mblk_t *mp) 19650Sstevel@tonic-gate { 19660Sstevel@tonic-gate keysock_out_err_t *kse; 19670Sstevel@tonic-gate mblk_t *imp; 19683448Sdh155122 keysock_stack_t *keystack = kc->kc_keystack; 19690Sstevel@tonic-gate 19700Sstevel@tonic-gate imp = allocb(sizeof (ipsec_info_t), BPRI_HI); 19710Sstevel@tonic-gate if (imp == NULL) { 19723448Sdh155122 ks1dbg(keystack, ("keysock_out_err: Can't alloc message.\n")); 19730Sstevel@tonic-gate return; 19740Sstevel@tonic-gate } 19750Sstevel@tonic-gate 19760Sstevel@tonic-gate imp->b_datap->db_type = M_CTL; 19770Sstevel@tonic-gate imp->b_wptr += sizeof (ipsec_info_t); 19780Sstevel@tonic-gate 19790Sstevel@tonic-gate kse = (keysock_out_err_t *)imp->b_rptr; 19800Sstevel@tonic-gate imp->b_cont = mp; 19810Sstevel@tonic-gate kse->ks_err_type = KEYSOCK_OUT_ERR; 19820Sstevel@tonic-gate kse->ks_err_len = sizeof (*kse); 19830Sstevel@tonic-gate /* Is serial necessary? */ 19840Sstevel@tonic-gate kse->ks_err_serial = 0; 19850Sstevel@tonic-gate kse->ks_err_errno = ks_errno; 19860Sstevel@tonic-gate 19870Sstevel@tonic-gate /* 19880Sstevel@tonic-gate * XXX What else do I need to do here w.r.t. information 19890Sstevel@tonic-gate * to tell the consumer what caused this error? 19900Sstevel@tonic-gate * 19910Sstevel@tonic-gate * I believe the answer is the PF_KEY ACQUIRE (or other) message 19920Sstevel@tonic-gate * attached in mp, which is appended at the end. I believe the 19930Sstevel@tonic-gate * db_ref won't matter here, because the PF_KEY message is only read 19940Sstevel@tonic-gate * for KEYSOCK_OUT_ERR. 19950Sstevel@tonic-gate */ 19960Sstevel@tonic-gate 19970Sstevel@tonic-gate putnext(kc->kc_wq, imp); 19980Sstevel@tonic-gate } 19990Sstevel@tonic-gate 20000Sstevel@tonic-gate /* XXX this is a hack errno. */ 20010Sstevel@tonic-gate #define EIPSECNOSA 255 20020Sstevel@tonic-gate 20030Sstevel@tonic-gate /* 20040Sstevel@tonic-gate * Route message (pointed by mp, header in samsg) toward appropriate 20050Sstevel@tonic-gate * sockets. Assume the message's creator did its job correctly. 20060Sstevel@tonic-gate * 20070Sstevel@tonic-gate * This should be a function that is followed by a return in its caller. 20080Sstevel@tonic-gate * The compiler _should_ be able to use tail-call optimizations to make the 20090Sstevel@tonic-gate * large ## of parameters not a huge deal. 20100Sstevel@tonic-gate */ 20110Sstevel@tonic-gate static void 20120Sstevel@tonic-gate keysock_passup(mblk_t *mp, sadb_msg_t *samsg, minor_t serial, 20133448Sdh155122 keysock_consumer_t *kc, boolean_t persistent, keysock_stack_t *keystack) 20140Sstevel@tonic-gate { 20150Sstevel@tonic-gate keysock_t *ks; 20160Sstevel@tonic-gate uint8_t satype = samsg->sadb_msg_satype; 20170Sstevel@tonic-gate boolean_t toall = B_FALSE, allreg = B_FALSE, allereg = B_FALSE, 20180Sstevel@tonic-gate setalg = B_FALSE; 20190Sstevel@tonic-gate mblk_t *mp1; 20200Sstevel@tonic-gate int err = EIPSECNOSA; 20210Sstevel@tonic-gate 20220Sstevel@tonic-gate /* Convert mp, which is M_DATA, into an M_PROTO of type T_DATA_IND */ 20230Sstevel@tonic-gate mp1 = allocb(sizeof (struct T_data_req), BPRI_HI); 20240Sstevel@tonic-gate if (mp1 == NULL) { 20250Sstevel@tonic-gate err = ENOMEM; 20260Sstevel@tonic-gate goto error; 20270Sstevel@tonic-gate } 20280Sstevel@tonic-gate mp1->b_wptr += sizeof (struct T_data_req); 20290Sstevel@tonic-gate ((struct T_data_ind *)mp1->b_rptr)->PRIM_type = T_DATA_IND; 20300Sstevel@tonic-gate ((struct T_data_ind *)mp1->b_rptr)->MORE_flag = 0; 20310Sstevel@tonic-gate mp1->b_datap->db_type = M_PROTO; 20320Sstevel@tonic-gate mp1->b_cont = mp; 20330Sstevel@tonic-gate mp = mp1; 20340Sstevel@tonic-gate 20350Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 20360Sstevel@tonic-gate case SADB_FLUSH: 20370Sstevel@tonic-gate case SADB_GETSPI: 20380Sstevel@tonic-gate case SADB_UPDATE: 20396668Smarkfen case SADB_X_UPDATEPAIR: 20400Sstevel@tonic-gate case SADB_ADD: 20410Sstevel@tonic-gate case SADB_DELETE: 20426668Smarkfen case SADB_X_DELPAIR: 20430Sstevel@tonic-gate case SADB_EXPIRE: 20440Sstevel@tonic-gate /* 20450Sstevel@tonic-gate * These are most likely replies. Don't worry about 20460Sstevel@tonic-gate * KEYSOCK_OUT_ERR handling. Deliver to all sockets. 20470Sstevel@tonic-gate */ 20483448Sdh155122 ks3dbg(keystack, 20493448Sdh155122 ("Delivering normal message (%d) to all sockets.\n", 20500Sstevel@tonic-gate samsg->sadb_msg_type)); 20510Sstevel@tonic-gate toall = B_TRUE; 20520Sstevel@tonic-gate break; 20530Sstevel@tonic-gate case SADB_REGISTER: 20540Sstevel@tonic-gate /* 20550Sstevel@tonic-gate * REGISTERs come up for one of three reasons: 20560Sstevel@tonic-gate * 20570Sstevel@tonic-gate * 1.) In response to a normal SADB_REGISTER 20580Sstevel@tonic-gate * (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC && 20590Sstevel@tonic-gate * serial != 0) 20600Sstevel@tonic-gate * Deliver to normal SADB_REGISTERed sockets. 20610Sstevel@tonic-gate * 2.) In response to an extended REGISTER 20620Sstevel@tonic-gate * (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) 20630Sstevel@tonic-gate * Deliver to extended REGISTERed socket. 20640Sstevel@tonic-gate * 3.) Spontaneous algorithm changes 20650Sstevel@tonic-gate * (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC && 20660Sstevel@tonic-gate * serial == 0) 20670Sstevel@tonic-gate * Deliver to REGISTERed sockets of all sorts. 20680Sstevel@tonic-gate */ 20690Sstevel@tonic-gate if (kc == NULL) { 20700Sstevel@tonic-gate /* Here because of keysock_error() call. */ 20710Sstevel@tonic-gate ASSERT(samsg->sadb_msg_errno != 0); 20720Sstevel@tonic-gate break; /* Out of switch. */ 20730Sstevel@tonic-gate } 20743448Sdh155122 ks3dbg(keystack, ("Delivering REGISTER.\n")); 20750Sstevel@tonic-gate if (satype == SADB_SATYPE_UNSPEC) { 20760Sstevel@tonic-gate /* REGISTER Reason #2 */ 20770Sstevel@tonic-gate allereg = B_TRUE; 20780Sstevel@tonic-gate /* 20790Sstevel@tonic-gate * Rewhack SA type so PF_KEY socket holder knows what 20800Sstevel@tonic-gate * consumer generated this algorithm list. 20810Sstevel@tonic-gate */ 20820Sstevel@tonic-gate satype = kc->kc_sa_type; 20830Sstevel@tonic-gate samsg->sadb_msg_satype = satype; 20840Sstevel@tonic-gate setalg = B_TRUE; 20850Sstevel@tonic-gate } else if (serial == 0) { 20860Sstevel@tonic-gate /* REGISTER Reason #3 */ 20870Sstevel@tonic-gate allreg = B_TRUE; 20880Sstevel@tonic-gate allereg = B_TRUE; 20890Sstevel@tonic-gate } else { 20900Sstevel@tonic-gate /* REGISTER Reason #1 */ 20910Sstevel@tonic-gate allreg = B_TRUE; 20920Sstevel@tonic-gate setalg = B_TRUE; 20930Sstevel@tonic-gate } 20940Sstevel@tonic-gate break; 20950Sstevel@tonic-gate case SADB_ACQUIRE: 20960Sstevel@tonic-gate /* 20970Sstevel@tonic-gate * ACQUIREs are either extended (sadb_msg_satype == 0) or 20980Sstevel@tonic-gate * regular (sadb_msg_satype != 0). And we're guaranteed 20990Sstevel@tonic-gate * that serial == 0 for an ACQUIRE. 21000Sstevel@tonic-gate */ 21013448Sdh155122 ks3dbg(keystack, ("Delivering ACQUIRE.\n")); 21020Sstevel@tonic-gate allereg = (satype == SADB_SATYPE_UNSPEC); 21030Sstevel@tonic-gate allreg = !allereg; 21040Sstevel@tonic-gate /* 21050Sstevel@tonic-gate * Corner case - if we send a regular ACQUIRE and there's 21060Sstevel@tonic-gate * extended ones registered, don't send an error down to 21070Sstevel@tonic-gate * consumers if nobody's listening and prematurely destroy 21080Sstevel@tonic-gate * their ACQUIRE record. This might be too hackish of a 21090Sstevel@tonic-gate * solution. 21100Sstevel@tonic-gate */ 21113448Sdh155122 if (allreg && keystack->keystack_num_extended > 0) 21120Sstevel@tonic-gate err = 0; 21130Sstevel@tonic-gate break; 21140Sstevel@tonic-gate case SADB_X_PROMISC: 21150Sstevel@tonic-gate case SADB_X_INVERSE_ACQUIRE: 21160Sstevel@tonic-gate case SADB_DUMP: 21170Sstevel@tonic-gate case SADB_GET: 21180Sstevel@tonic-gate default: 21190Sstevel@tonic-gate /* 21200Sstevel@tonic-gate * Deliver to the sender and promiscuous only. 21210Sstevel@tonic-gate */ 21223448Sdh155122 ks3dbg(keystack, ("Delivering sender/promisc only (%d).\n", 21230Sstevel@tonic-gate samsg->sadb_msg_type)); 21240Sstevel@tonic-gate break; 21250Sstevel@tonic-gate } 21260Sstevel@tonic-gate 21273448Sdh155122 mutex_enter(&keystack->keystack_list_lock); 21283448Sdh155122 for (ks = keystack->keystack_list; ks != NULL; ks = ks->keysock_next) { 21290Sstevel@tonic-gate /* Delivery loop. */ 21300Sstevel@tonic-gate 21310Sstevel@tonic-gate /* 21320Sstevel@tonic-gate * Check special keysock-setting cases (REGISTER replies) 21330Sstevel@tonic-gate * here. 21340Sstevel@tonic-gate */ 21350Sstevel@tonic-gate if (setalg && serial == ks->keysock_serial) { 21360Sstevel@tonic-gate ASSERT(kc != NULL); 21370Sstevel@tonic-gate ASSERT(kc->kc_sa_type == satype); 21380Sstevel@tonic-gate KEYSOCK_SETREG(ks, satype); 21390Sstevel@tonic-gate } 21400Sstevel@tonic-gate 21410Sstevel@tonic-gate /* 21420Sstevel@tonic-gate * NOLOOP takes precedence over PROMISC. So if you've set 21430Sstevel@tonic-gate * !SO_USELOOPBACK, don't expect to see any data... 21440Sstevel@tonic-gate */ 21450Sstevel@tonic-gate if (ks->keysock_flags & KEYSOCK_NOLOOP) 21460Sstevel@tonic-gate continue; 21470Sstevel@tonic-gate 21480Sstevel@tonic-gate /* 21490Sstevel@tonic-gate * Messages to all, or promiscuous sockets just GET the 21500Sstevel@tonic-gate * message. Perform rules-type checking iff it's not for all 21510Sstevel@tonic-gate * listeners or the socket is in promiscuous mode. 21520Sstevel@tonic-gate * 21530Sstevel@tonic-gate * NOTE:Because of the (kc != NULL && ISREG()), make sure 21540Sstevel@tonic-gate * extended ACQUIREs arrive off a consumer that is 21550Sstevel@tonic-gate * part of the extended REGISTER set of consumers. 21560Sstevel@tonic-gate */ 21570Sstevel@tonic-gate if (serial != ks->keysock_serial && 21580Sstevel@tonic-gate !toall && 21590Sstevel@tonic-gate !(ks->keysock_flags & KEYSOCK_PROMISC) && 21600Sstevel@tonic-gate !((ks->keysock_flags & KEYSOCK_EXTENDED) ? 21615240Snordmark allereg : allreg && kc != NULL && 21625240Snordmark KEYSOCK_ISREG(ks, kc->kc_sa_type))) 21630Sstevel@tonic-gate continue; 21640Sstevel@tonic-gate 21650Sstevel@tonic-gate mp1 = dupmsg(mp); 21660Sstevel@tonic-gate if (mp1 == NULL) { 21673448Sdh155122 ks2dbg(keystack, ( 21680Sstevel@tonic-gate "keysock_passup(): dupmsg() failed.\n")); 21690Sstevel@tonic-gate mp1 = mp; 21700Sstevel@tonic-gate mp = NULL; 21710Sstevel@tonic-gate err = ENOMEM; 21720Sstevel@tonic-gate } 21730Sstevel@tonic-gate 21740Sstevel@tonic-gate /* 21750Sstevel@tonic-gate * At this point, we can deliver or attempt to deliver 21760Sstevel@tonic-gate * this message. We're free of obligation to report 21770Sstevel@tonic-gate * no listening PF_KEY sockets. So set err to 0. 21780Sstevel@tonic-gate */ 21790Sstevel@tonic-gate err = 0; 21800Sstevel@tonic-gate 21810Sstevel@tonic-gate /* 21820Sstevel@tonic-gate * See if we canputnext(), as well as see if the message 21830Sstevel@tonic-gate * needs to be queued if we can't. 21840Sstevel@tonic-gate */ 21850Sstevel@tonic-gate if (!canputnext(ks->keysock_rq)) { 21860Sstevel@tonic-gate if (persistent) { 21870Sstevel@tonic-gate if (putq(ks->keysock_rq, mp1) == 0) { 21883448Sdh155122 ks1dbg(keystack, ( 21890Sstevel@tonic-gate "keysock_passup: putq failed.\n")); 21900Sstevel@tonic-gate } else { 21910Sstevel@tonic-gate continue; 21920Sstevel@tonic-gate } 21930Sstevel@tonic-gate } 21940Sstevel@tonic-gate freemsg(mp1); 21950Sstevel@tonic-gate continue; 21960Sstevel@tonic-gate } 21970Sstevel@tonic-gate 21983448Sdh155122 ks3dbg(keystack, 21993448Sdh155122 ("Putting to serial %d.\n", ks->keysock_serial)); 22000Sstevel@tonic-gate /* 22010Sstevel@tonic-gate * Unlike the specific keysock instance case, this 22020Sstevel@tonic-gate * will only hit for listeners, so we will only 22030Sstevel@tonic-gate * putnext() if we can. 22040Sstevel@tonic-gate */ 22050Sstevel@tonic-gate putnext(ks->keysock_rq, mp1); 22060Sstevel@tonic-gate if (mp == NULL) 22070Sstevel@tonic-gate break; /* out of for loop. */ 22080Sstevel@tonic-gate } 22093448Sdh155122 mutex_exit(&keystack->keystack_list_lock); 22100Sstevel@tonic-gate 22110Sstevel@tonic-gate error: 22120Sstevel@tonic-gate if ((err != 0) && (kc != NULL)) { 22130Sstevel@tonic-gate /* 22140Sstevel@tonic-gate * Generate KEYSOCK_OUT_ERR for consumer. 22150Sstevel@tonic-gate * Basically, I send this back if I have not been able to 22160Sstevel@tonic-gate * transmit (for whatever reason) 22170Sstevel@tonic-gate */ 22183448Sdh155122 ks1dbg(keystack, 22193448Sdh155122 ("keysock_passup(): No registered of type %d.\n", 22200Sstevel@tonic-gate satype)); 22210Sstevel@tonic-gate if (mp != NULL) { 22220Sstevel@tonic-gate if (mp->b_datap->db_type == M_PROTO) { 22230Sstevel@tonic-gate mp1 = mp; 22240Sstevel@tonic-gate mp = mp->b_cont; 22250Sstevel@tonic-gate freeb(mp1); 22260Sstevel@tonic-gate } 22270Sstevel@tonic-gate /* 22280Sstevel@tonic-gate * Do a copymsg() because people who get 22290Sstevel@tonic-gate * KEYSOCK_OUT_ERR may alter the message contents. 22300Sstevel@tonic-gate */ 22310Sstevel@tonic-gate mp1 = copymsg(mp); 22320Sstevel@tonic-gate if (mp1 == NULL) { 22333448Sdh155122 ks2dbg(keystack, 22343448Sdh155122 ("keysock_passup: copymsg() failed.\n")); 22350Sstevel@tonic-gate mp1 = mp; 22360Sstevel@tonic-gate mp = NULL; 22370Sstevel@tonic-gate } 22380Sstevel@tonic-gate keysock_out_err(kc, err, mp1); 22390Sstevel@tonic-gate } 22400Sstevel@tonic-gate } 22410Sstevel@tonic-gate 22420Sstevel@tonic-gate /* 22430Sstevel@tonic-gate * XXX Blank the message somehow. This is difficult because we don't 22440Sstevel@tonic-gate * know at this point if the message has db_ref > 1, etc. 22450Sstevel@tonic-gate * 22460Sstevel@tonic-gate * Optimally, keysock messages containing actual keying material would 22470Sstevel@tonic-gate * be allocated with esballoc(), with a zeroing free function. 22480Sstevel@tonic-gate */ 22490Sstevel@tonic-gate if (mp != NULL) 22500Sstevel@tonic-gate freemsg(mp); 22510Sstevel@tonic-gate } 22520Sstevel@tonic-gate 22530Sstevel@tonic-gate /* 22540Sstevel@tonic-gate * Keysock's read service procedure is there only for PF_KEY reply 22550Sstevel@tonic-gate * messages that really need to reach the top. 22560Sstevel@tonic-gate */ 22570Sstevel@tonic-gate static void 22580Sstevel@tonic-gate keysock_rsrv(queue_t *q) 22590Sstevel@tonic-gate { 22600Sstevel@tonic-gate mblk_t *mp; 22610Sstevel@tonic-gate 22620Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 22630Sstevel@tonic-gate if (canputnext(q)) { 22640Sstevel@tonic-gate putnext(q, mp); 22650Sstevel@tonic-gate } else { 22660Sstevel@tonic-gate (void) putbq(q, mp); 22670Sstevel@tonic-gate return; 22680Sstevel@tonic-gate } 22690Sstevel@tonic-gate } 22700Sstevel@tonic-gate } 22710Sstevel@tonic-gate 22720Sstevel@tonic-gate /* 22730Sstevel@tonic-gate * The read procedure should only be invoked by a keysock consumer, like 22740Sstevel@tonic-gate * ESP, AH, etc. I should only see KEYSOCK_OUT and KEYSOCK_HELLO_ACK 22750Sstevel@tonic-gate * messages on my read queues. 22760Sstevel@tonic-gate */ 22770Sstevel@tonic-gate static void 22780Sstevel@tonic-gate keysock_rput(queue_t *q, mblk_t *mp) 22790Sstevel@tonic-gate { 22800Sstevel@tonic-gate keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr; 22810Sstevel@tonic-gate ipsec_info_t *ii; 22820Sstevel@tonic-gate keysock_hello_ack_t *ksa; 22830Sstevel@tonic-gate minor_t serial; 22840Sstevel@tonic-gate mblk_t *mp1; 22850Sstevel@tonic-gate sadb_msg_t *samsg; 22863448Sdh155122 keysock_stack_t *keystack = kc->kc_keystack; 22870Sstevel@tonic-gate 22880Sstevel@tonic-gate /* Make sure I'm a consumer instance. (i.e. something's below me) */ 22890Sstevel@tonic-gate ASSERT(WR(q)->q_next != NULL); 22900Sstevel@tonic-gate 22910Sstevel@tonic-gate if (mp->b_datap->db_type != M_CTL) { 22920Sstevel@tonic-gate /* 22930Sstevel@tonic-gate * Keysock should only see keysock consumer interface 22940Sstevel@tonic-gate * messages (see ipsec_info.h) on its read procedure. 22950Sstevel@tonic-gate * To be robust, however, putnext() up so the STREAM head can 22960Sstevel@tonic-gate * deal with it appropriately. 22970Sstevel@tonic-gate */ 22983448Sdh155122 ks1dbg(keystack, 22993448Sdh155122 ("Hmmm, a non M_CTL (%d, 0x%x) on keysock_rput.\n", 23000Sstevel@tonic-gate mp->b_datap->db_type, mp->b_datap->db_type)); 23010Sstevel@tonic-gate putnext(q, mp); 23020Sstevel@tonic-gate return; 23030Sstevel@tonic-gate } 23040Sstevel@tonic-gate 23050Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 23060Sstevel@tonic-gate 23070Sstevel@tonic-gate switch (ii->ipsec_info_type) { 23080Sstevel@tonic-gate case KEYSOCK_OUT: 23090Sstevel@tonic-gate /* 23100Sstevel@tonic-gate * A consumer needs to pass a response message or an ACQUIRE 23110Sstevel@tonic-gate * UP. I assume that the consumer has done the right 23120Sstevel@tonic-gate * thing w.r.t. message creation, etc. 23130Sstevel@tonic-gate */ 23140Sstevel@tonic-gate serial = ((keysock_out_t *)mp->b_rptr)->ks_out_serial; 23150Sstevel@tonic-gate mp1 = mp->b_cont; /* Get M_DATA portion. */ 23160Sstevel@tonic-gate freeb(mp); 23170Sstevel@tonic-gate samsg = (sadb_msg_t *)mp1->b_rptr; 23180Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_FLUSH || 23190Sstevel@tonic-gate (samsg->sadb_msg_type == SADB_DUMP && 23205240Snordmark samsg->sadb_msg_len == SADB_8TO64(sizeof (*samsg)))) { 23210Sstevel@tonic-gate /* 23220Sstevel@tonic-gate * If I'm an end-of-FLUSH or an end-of-DUMP marker... 23230Sstevel@tonic-gate */ 23243448Sdh155122 ASSERT(keystack->keystack_flushdump != 0); 23253448Sdh155122 /* Am I flushing? */ 23260Sstevel@tonic-gate 23270Sstevel@tonic-gate mutex_enter(&kc->kc_lock); 23280Sstevel@tonic-gate kc->kc_flags &= ~KC_FLUSHING; 23290Sstevel@tonic-gate mutex_exit(&kc->kc_lock); 23300Sstevel@tonic-gate 23310Sstevel@tonic-gate if (samsg->sadb_msg_errno != 0) 23323448Sdh155122 keystack->keystack_flushdump_errno = 23333448Sdh155122 samsg->sadb_msg_errno; 23340Sstevel@tonic-gate 23350Sstevel@tonic-gate /* 23360Sstevel@tonic-gate * Lower the atomic "flushing" count. If it's 23370Sstevel@tonic-gate * the last one, send up the end-of-{FLUSH,DUMP} to 23380Sstevel@tonic-gate * the appropriate PF_KEY socket. 23390Sstevel@tonic-gate */ 23403448Sdh155122 if (atomic_add_32_nv(&keystack->keystack_flushdump, 23413448Sdh155122 -1) != 0) { 23423448Sdh155122 ks1dbg(keystack, 23433448Sdh155122 ("One flush/dump message back from %d," 23440Sstevel@tonic-gate " more to go.\n", samsg->sadb_msg_satype)); 23450Sstevel@tonic-gate freemsg(mp1); 23460Sstevel@tonic-gate return; 23470Sstevel@tonic-gate } 23480Sstevel@tonic-gate 23490Sstevel@tonic-gate samsg->sadb_msg_errno = 23503448Sdh155122 (uint8_t)keystack->keystack_flushdump_errno; 23510Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_DUMP) { 23520Sstevel@tonic-gate samsg->sadb_msg_seq = 0; 23530Sstevel@tonic-gate } 23540Sstevel@tonic-gate } 23550Sstevel@tonic-gate keysock_passup(mp1, samsg, serial, kc, 23563448Sdh155122 (samsg->sadb_msg_type == SADB_DUMP), keystack); 23570Sstevel@tonic-gate return; 23580Sstevel@tonic-gate case KEYSOCK_HELLO_ACK: 23590Sstevel@tonic-gate /* Aha, now we can link in the consumer! */ 23600Sstevel@tonic-gate ksa = (keysock_hello_ack_t *)ii; 23610Sstevel@tonic-gate keysock_link_consumer(ksa->ks_hello_satype, kc); 23620Sstevel@tonic-gate freemsg(mp); 23630Sstevel@tonic-gate return; 23640Sstevel@tonic-gate default: 23653448Sdh155122 ks1dbg(keystack, ("Hmmm, an IPsec info I'm not used to, 0x%x\n", 23660Sstevel@tonic-gate ii->ipsec_info_type)); 23670Sstevel@tonic-gate putnext(q, mp); 23680Sstevel@tonic-gate } 23690Sstevel@tonic-gate } 23700Sstevel@tonic-gate 23710Sstevel@tonic-gate /* 23720Sstevel@tonic-gate * So we can avoid external linking problems.... 23730Sstevel@tonic-gate */ 23740Sstevel@tonic-gate boolean_t 23753448Sdh155122 keysock_extended_reg(netstack_t *ns) 23760Sstevel@tonic-gate { 23773448Sdh155122 keysock_stack_t *keystack = ns->netstack_keysock; 23783448Sdh155122 23793448Sdh155122 return (keystack->keystack_num_extended != 0); 23800Sstevel@tonic-gate } 23810Sstevel@tonic-gate 23820Sstevel@tonic-gate uint32_t 23833448Sdh155122 keysock_next_seq(netstack_t *ns) 23840Sstevel@tonic-gate { 23853448Sdh155122 keysock_stack_t *keystack = ns->netstack_keysock; 23863448Sdh155122 23873448Sdh155122 return (atomic_add_32_nv(&keystack->keystack_acquire_seq, -1)); 23880Sstevel@tonic-gate } 2389