1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #include <sys/param.h> 31*0Sstevel@tonic-gate #include <sys/types.h> 32*0Sstevel@tonic-gate #include <sys/stream.h> 33*0Sstevel@tonic-gate #include <sys/strsubr.h> 34*0Sstevel@tonic-gate #include <sys/strsun.h> 35*0Sstevel@tonic-gate #include <sys/stropts.h> 36*0Sstevel@tonic-gate #include <sys/vnode.h> 37*0Sstevel@tonic-gate #include <sys/strlog.h> 38*0Sstevel@tonic-gate #include <sys/sysmacros.h> 39*0Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 40*0Sstevel@tonic-gate #include <sys/tihdr.h> 41*0Sstevel@tonic-gate #include <sys/timod.h> 42*0Sstevel@tonic-gate #include <sys/tiuser.h> 43*0Sstevel@tonic-gate #include <sys/ddi.h> 44*0Sstevel@tonic-gate #include <sys/sunddi.h> 45*0Sstevel@tonic-gate #include <sys/sunldi.h> 46*0Sstevel@tonic-gate #include <sys/file.h> 47*0Sstevel@tonic-gate #include <sys/modctl.h> 48*0Sstevel@tonic-gate #include <sys/debug.h> 49*0Sstevel@tonic-gate #include <sys/kmem.h> 50*0Sstevel@tonic-gate #include <sys/cmn_err.h> 51*0Sstevel@tonic-gate #include <sys/proc.h> 52*0Sstevel@tonic-gate #include <sys/suntpi.h> 53*0Sstevel@tonic-gate #include <sys/atomic.h> 54*0Sstevel@tonic-gate #include <sys/mkdev.h> 55*0Sstevel@tonic-gate #include <sys/policy.h> 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate #include <sys/socket.h> 58*0Sstevel@tonic-gate #include <netinet/in.h> 59*0Sstevel@tonic-gate #include <net/pfkeyv2.h> 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #include <inet/common.h> 62*0Sstevel@tonic-gate #include <netinet/ip6.h> 63*0Sstevel@tonic-gate #include <inet/ip.h> 64*0Sstevel@tonic-gate #include <inet/mi.h> 65*0Sstevel@tonic-gate #include <inet/nd.h> 66*0Sstevel@tonic-gate #include <inet/optcom.h> 67*0Sstevel@tonic-gate #include <inet/ipsec_info.h> 68*0Sstevel@tonic-gate #include <inet/ipsec_impl.h> 69*0Sstevel@tonic-gate #include <inet/keysock.h> 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate #include <sys/isa_defs.h> 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate /* 74*0Sstevel@tonic-gate * This is a transport provider for the PF_KEY key mangement socket. 75*0Sstevel@tonic-gate * (See RFC 2367 for details.) 76*0Sstevel@tonic-gate * Downstream messages are wrapped in a keysock consumer interface KEYSOCK_IN 77*0Sstevel@tonic-gate * messages (see ipsec_info.h), and passed to the appropriate consumer. 78*0Sstevel@tonic-gate * Upstream messages are generated for all open PF_KEY sockets, when 79*0Sstevel@tonic-gate * appropriate, as well as the sender (as long as SO_USELOOPBACK is enabled) 80*0Sstevel@tonic-gate * in reply to downstream messages. 81*0Sstevel@tonic-gate * 82*0Sstevel@tonic-gate * Upstream messages must be created asynchronously for the following 83*0Sstevel@tonic-gate * situations: 84*0Sstevel@tonic-gate * 85*0Sstevel@tonic-gate * 1.) A keysock consumer requires an SA, and there is currently none. 86*0Sstevel@tonic-gate * 2.) An SA expires, either hard or soft lifetime. 87*0Sstevel@tonic-gate * 3.) Other events a consumer deems fit. 88*0Sstevel@tonic-gate * 89*0Sstevel@tonic-gate * The MT model of this is PERMOD, with shared put procedures. Two types of 90*0Sstevel@tonic-gate * messages, SADB_FLUSH and SADB_DUMP, need to lock down the perimeter to send 91*0Sstevel@tonic-gate * down the *multiple* messages they create. 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* List of open PF_KEY sockets, protected by keysock_list_lock. */ 95*0Sstevel@tonic-gate static kmutex_t keysock_list_lock; 96*0Sstevel@tonic-gate static keysock_t *keysock_list; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate static vmem_t *keysock_vmem; /* for minor numbers. */ 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* Consumers table. If an entry is NULL, keysock maintains the table. */ 101*0Sstevel@tonic-gate static kmutex_t keysock_consumers_lock; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate #define KEYSOCK_MAX_CONSUMERS 256 104*0Sstevel@tonic-gate static keysock_consumer_t *keysock_consumers[KEYSOCK_MAX_CONSUMERS]; 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages (from rts.c...) */ 107*0Sstevel@tonic-gate static struct T_info_ack keysock_g_t_info_ack = { 108*0Sstevel@tonic-gate T_INFO_ACK, 109*0Sstevel@tonic-gate T_INFINITE, /* TSDU_size. Maximum size messages. */ 110*0Sstevel@tonic-gate T_INVALID, /* ETSDU_size. No expedited data. */ 111*0Sstevel@tonic-gate T_INVALID, /* CDATA_size. No connect data. */ 112*0Sstevel@tonic-gate T_INVALID, /* DDATA_size. No disconnect data. */ 113*0Sstevel@tonic-gate 0, /* ADDR_size. */ 114*0Sstevel@tonic-gate 0, /* OPT_size. No user-settable options */ 115*0Sstevel@tonic-gate 64 * 1024, /* TIDU_size. keysock allows maximum size messages. */ 116*0Sstevel@tonic-gate T_COTS, /* SERV_type. keysock supports connection oriented. */ 117*0Sstevel@tonic-gate TS_UNBND, /* CURRENT_state. This is set from keysock_state. */ 118*0Sstevel@tonic-gate (XPG4_1) /* Provider flags */ 119*0Sstevel@tonic-gate }; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /* Named Dispatch Parameter Management Structure */ 122*0Sstevel@tonic-gate typedef struct keysockpparam_s { 123*0Sstevel@tonic-gate uint_t keysock_param_min; 124*0Sstevel@tonic-gate uint_t keysock_param_max; 125*0Sstevel@tonic-gate uint_t keysock_param_value; 126*0Sstevel@tonic-gate char *keysock_param_name; 127*0Sstevel@tonic-gate } keysockparam_t; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate /* 130*0Sstevel@tonic-gate * Table of NDD variables supported by keysock. These are loaded into 131*0Sstevel@tonic-gate * keysock_g_nd in keysock_init_nd. 132*0Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 133*0Sstevel@tonic-gate */ 134*0Sstevel@tonic-gate static keysockparam_t keysock_param_arr[] = { 135*0Sstevel@tonic-gate /* min max value name */ 136*0Sstevel@tonic-gate { 4096, 65536, 8192, "keysock_xmit_hiwat"}, 137*0Sstevel@tonic-gate { 0, 65536, 1024, "keysock_xmit_lowat"}, 138*0Sstevel@tonic-gate { 4096, 65536, 8192, "keysock_recv_hiwat"}, 139*0Sstevel@tonic-gate { 65536, 1024*1024*1024, 256*1024, "keysock_max_buf"}, 140*0Sstevel@tonic-gate { 0, 3, 0, "keysock_debug"}, 141*0Sstevel@tonic-gate }; 142*0Sstevel@tonic-gate #define keysock_xmit_hiwat keysock_param_arr[0].keysock_param_value 143*0Sstevel@tonic-gate #define keysock_xmit_lowat keysock_param_arr[1].keysock_param_value 144*0Sstevel@tonic-gate #define keysock_recv_hiwat keysock_param_arr[2].keysock_param_value 145*0Sstevel@tonic-gate #define keysock_max_buf keysock_param_arr[3].keysock_param_value 146*0Sstevel@tonic-gate #define keysock_debug keysock_param_arr[4].keysock_param_value 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate kmutex_t keysock_param_lock; /* Protects the NDD variables. */ 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate #define ks0dbg(a) printf a 151*0Sstevel@tonic-gate /* NOTE: != 0 instead of > 0 so lint doesn't complain. */ 152*0Sstevel@tonic-gate #define ks1dbg(a) if (keysock_debug != 0) printf a 153*0Sstevel@tonic-gate #define ks2dbg(a) if (keysock_debug > 1) printf a 154*0Sstevel@tonic-gate #define ks3dbg(a) if (keysock_debug > 2) printf a 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate static IDP keysock_g_nd; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* 159*0Sstevel@tonic-gate * State for flush/dump. This would normally be a boolean_t, but 160*0Sstevel@tonic-gate * cas32() works best for a known 32-bit quantity. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate static uint32_t keysock_flushdump; 163*0Sstevel@tonic-gate static int keysock_flushdump_errno; 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate static int keysock_close(queue_t *); 166*0Sstevel@tonic-gate static int keysock_open(queue_t *, dev_t *, int, int, cred_t *); 167*0Sstevel@tonic-gate static void keysock_wput(queue_t *, mblk_t *); 168*0Sstevel@tonic-gate static void keysock_rput(queue_t *, mblk_t *); 169*0Sstevel@tonic-gate static void keysock_rsrv(queue_t *); 170*0Sstevel@tonic-gate static void keysock_passup(mblk_t *, sadb_msg_t *, minor_t, 171*0Sstevel@tonic-gate keysock_consumer_t *, boolean_t); 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate static struct module_info info = { 174*0Sstevel@tonic-gate 5138, "keysock", 1, INFPSZ, 512, 128 175*0Sstevel@tonic-gate }; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate static struct qinit rinit = { 178*0Sstevel@tonic-gate (pfi_t)keysock_rput, (pfi_t)keysock_rsrv, keysock_open, keysock_close, 179*0Sstevel@tonic-gate NULL, &info 180*0Sstevel@tonic-gate }; 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate static struct qinit winit = { 183*0Sstevel@tonic-gate (pfi_t)keysock_wput, NULL, NULL, NULL, NULL, &info 184*0Sstevel@tonic-gate }; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate struct streamtab keysockinfo = { 187*0Sstevel@tonic-gate &rinit, &winit 188*0Sstevel@tonic-gate }; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate extern struct modlinkage *keysock_modlp; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate /* 193*0Sstevel@tonic-gate * Plumb IPsec. 194*0Sstevel@tonic-gate * 195*0Sstevel@tonic-gate * NOTE: New "default" modules will need to be loaded here if needed before 196*0Sstevel@tonic-gate * boot time. 197*0Sstevel@tonic-gate */ 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate /* Keep these in global space to keep the lint from complaining. */ 200*0Sstevel@tonic-gate static char *IPSECESP = "ipsecesp"; 201*0Sstevel@tonic-gate static char *IPSECESPDEV = "/devices/pseudo/ipsecesp@0:ipsecesp"; 202*0Sstevel@tonic-gate static char *IPSECAH = "ipsecah"; 203*0Sstevel@tonic-gate static char *IPSECAHDEV = "/devices/pseudo/ipsecah@0:ipsecah"; 204*0Sstevel@tonic-gate static char *IP6DEV = "/devices/pseudo/ip6@0:ip6"; 205*0Sstevel@tonic-gate static char *KEYSOCK = "keysock"; 206*0Sstevel@tonic-gate static char *STRMOD = "strmod"; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* 209*0Sstevel@tonic-gate * keysock_plumbed: zero if plumb not attempted, positive if it succeeded, 210*0Sstevel@tonic-gate * negative if it failed. 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate static int keysock_plumbed = 0; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate /* 215*0Sstevel@tonic-gate * This integer counts the number of extended REGISTERed sockets. This 216*0Sstevel@tonic-gate * determines if we should send extended REGISTERs. 217*0Sstevel@tonic-gate */ 218*0Sstevel@tonic-gate static uint32_t keysock_num_extended = 0; 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate /* 221*0Sstevel@tonic-gate * Global sequence space for SADB_ACQUIRE messages of any sort. 222*0Sstevel@tonic-gate */ 223*0Sstevel@tonic-gate static uint32_t keysock_acquire_seq = 0xffffffff; 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate /* 226*0Sstevel@tonic-gate * Load the other ipsec modules and plumb them together. 227*0Sstevel@tonic-gate */ 228*0Sstevel@tonic-gate int 229*0Sstevel@tonic-gate keysock_plumb_ipsec(void) 230*0Sstevel@tonic-gate { 231*0Sstevel@tonic-gate ldi_handle_t lh, ip6_lh = NULL; 232*0Sstevel@tonic-gate ldi_ident_t li = NULL; 233*0Sstevel@tonic-gate int err = 0; 234*0Sstevel@tonic-gate int muxid, rval; 235*0Sstevel@tonic-gate boolean_t esp_present = B_TRUE; 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate keysock_plumbed = 0; /* we're trying again.. */ 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate /* 241*0Sstevel@tonic-gate * Load up the drivers (AH/ESP). 242*0Sstevel@tonic-gate * 243*0Sstevel@tonic-gate * I do this separately from the actual plumbing in case this function 244*0Sstevel@tonic-gate * ever gets called from a diskless boot before the root filesystem is 245*0Sstevel@tonic-gate * up. I don't have to worry about "keysock" because, well, if I'm 246*0Sstevel@tonic-gate * here, keysock must've loaded successfully. 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate if (i_ddi_attach_pseudo_node(IPSECAH) == NULL) { 249*0Sstevel@tonic-gate ks0dbg(("IPsec: AH failed to attach.\n")); 250*0Sstevel@tonic-gate goto bail; 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate if (i_ddi_attach_pseudo_node(IPSECESP) == NULL) { 253*0Sstevel@tonic-gate ks0dbg(("IPsec: ESP failed to attach.\n")); 254*0Sstevel@tonic-gate esp_present = B_FALSE; 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * Set up the IP streams for AH and ESP, as well as tacking keysock 259*0Sstevel@tonic-gate * on top of them. Assume keysock has set the autopushes up already. 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* Open IP. */ 263*0Sstevel@tonic-gate err = ldi_ident_from_mod(keysock_modlp, &li); 264*0Sstevel@tonic-gate if (err) { 265*0Sstevel@tonic-gate ks0dbg(("IPsec: lid_ident_from_mod failed (err %d).\n", 266*0Sstevel@tonic-gate err)); 267*0Sstevel@tonic-gate goto bail; 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate err = ldi_open_by_name(IP6DEV, FREAD|FWRITE, CRED(), &ip6_lh, li); 271*0Sstevel@tonic-gate if (err) { 272*0Sstevel@tonic-gate ks0dbg(("IPsec: Open of IP6 failed (err %d).\n", err)); 273*0Sstevel@tonic-gate goto bail; 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* PLINK KEYSOCK/AH */ 277*0Sstevel@tonic-gate err = ldi_open_by_name(IPSECAHDEV, FREAD|FWRITE, CRED(), &lh, li); 278*0Sstevel@tonic-gate if (err) { 279*0Sstevel@tonic-gate ks0dbg(("IPsec: Open of AH failed (err %d).\n", err)); 280*0Sstevel@tonic-gate goto bail; 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate err = ldi_ioctl(lh, 283*0Sstevel@tonic-gate I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, CRED(), &rval); 284*0Sstevel@tonic-gate if (err) { 285*0Sstevel@tonic-gate ks0dbg(("IPsec: Push of KEYSOCK onto AH failed (err %d).\n", 286*0Sstevel@tonic-gate err)); 287*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 288*0Sstevel@tonic-gate goto bail; 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh, 291*0Sstevel@tonic-gate FREAD+FWRITE+FNOCTTY+FKIOCTL, kcred, &muxid); 292*0Sstevel@tonic-gate if (err) { 293*0Sstevel@tonic-gate ks0dbg(("IPsec: PLINK of KEYSOCK/AH failed (err %d).\n", err)); 294*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 295*0Sstevel@tonic-gate goto bail; 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate /* PLINK KEYSOCK/ESP */ 300*0Sstevel@tonic-gate if (esp_present) { 301*0Sstevel@tonic-gate err = ldi_open_by_name(IPSECESPDEV, 302*0Sstevel@tonic-gate FREAD|FWRITE, CRED(), &lh, li); 303*0Sstevel@tonic-gate if (err) { 304*0Sstevel@tonic-gate ks0dbg(("IPsec: Open of ESP failed (err %d).\n", err)); 305*0Sstevel@tonic-gate goto bail; 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate err = ldi_ioctl(lh, 308*0Sstevel@tonic-gate I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, CRED(), &rval); 309*0Sstevel@tonic-gate if (err) { 310*0Sstevel@tonic-gate ks0dbg(("IPsec: " 311*0Sstevel@tonic-gate "Push of KEYSOCK onto ESP failed (err %d).\n", 312*0Sstevel@tonic-gate err)); 313*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 314*0Sstevel@tonic-gate goto bail; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh, 317*0Sstevel@tonic-gate FREAD+FWRITE+FNOCTTY+FKIOCTL, kcred, &muxid); 318*0Sstevel@tonic-gate if (err) { 319*0Sstevel@tonic-gate ks0dbg(("IPsec: " 320*0Sstevel@tonic-gate "PLINK of KEYSOCK/ESP failed (err %d).\n", err)); 321*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 322*0Sstevel@tonic-gate goto bail; 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate (void) ldi_close(lh, FREAD|FWRITE, CRED()); 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate bail: 328*0Sstevel@tonic-gate keysock_plumbed = (err == 0) ? 1 : -1; 329*0Sstevel@tonic-gate if (ip6_lh != NULL) { 330*0Sstevel@tonic-gate (void) ldi_close(ip6_lh, FREAD|FWRITE, CRED()); 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate if (li != NULL) 333*0Sstevel@tonic-gate ldi_ident_release(li); 334*0Sstevel@tonic-gate return (err); 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate /* ARGSUSED */ 338*0Sstevel@tonic-gate static int 339*0Sstevel@tonic-gate keysock_param_get(q, mp, cp, cr) 340*0Sstevel@tonic-gate queue_t *q; 341*0Sstevel@tonic-gate mblk_t *mp; 342*0Sstevel@tonic-gate caddr_t cp; 343*0Sstevel@tonic-gate cred_t *cr; 344*0Sstevel@tonic-gate { 345*0Sstevel@tonic-gate keysockparam_t *keysockpa = (keysockparam_t *)cp; 346*0Sstevel@tonic-gate uint_t value; 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate mutex_enter(&keysock_param_lock); 349*0Sstevel@tonic-gate value = keysockpa->keysock_param_value; 350*0Sstevel@tonic-gate mutex_exit(&keysock_param_lock); 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", value); 353*0Sstevel@tonic-gate return (0); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate /* This routine sets an NDD variable in a keysockparam_t structure. */ 357*0Sstevel@tonic-gate /* ARGSUSED */ 358*0Sstevel@tonic-gate static int 359*0Sstevel@tonic-gate keysock_param_set(q, mp, value, cp, cr) 360*0Sstevel@tonic-gate queue_t *q; 361*0Sstevel@tonic-gate mblk_t *mp; 362*0Sstevel@tonic-gate char *value; 363*0Sstevel@tonic-gate caddr_t cp; 364*0Sstevel@tonic-gate cred_t *cr; 365*0Sstevel@tonic-gate { 366*0Sstevel@tonic-gate ulong_t new_value; 367*0Sstevel@tonic-gate keysockparam_t *keysockpa = (keysockparam_t *)cp; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate /* Convert the value from a string into a long integer. */ 370*0Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0) 371*0Sstevel@tonic-gate return (EINVAL); 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate mutex_enter(&keysock_param_lock); 374*0Sstevel@tonic-gate /* 375*0Sstevel@tonic-gate * Fail the request if the new value does not lie within the 376*0Sstevel@tonic-gate * required bounds. 377*0Sstevel@tonic-gate */ 378*0Sstevel@tonic-gate if (new_value < keysockpa->keysock_param_min || 379*0Sstevel@tonic-gate new_value > keysockpa->keysock_param_max) { 380*0Sstevel@tonic-gate mutex_exit(&keysock_param_lock); 381*0Sstevel@tonic-gate return (EINVAL); 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate /* Set the new value */ 385*0Sstevel@tonic-gate keysockpa->keysock_param_value = new_value; 386*0Sstevel@tonic-gate mutex_exit(&keysock_param_lock); 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate return (0); 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate /* 392*0Sstevel@tonic-gate * Initialize NDD variables, and other things, for keysock. 393*0Sstevel@tonic-gate */ 394*0Sstevel@tonic-gate boolean_t 395*0Sstevel@tonic-gate keysock_ddi_init(void) 396*0Sstevel@tonic-gate { 397*0Sstevel@tonic-gate keysockparam_t *ksp = keysock_param_arr; 398*0Sstevel@tonic-gate int count = A_CNT(keysock_param_arr); 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate if (!keysock_g_nd) { 401*0Sstevel@tonic-gate for (; count-- > 0; ksp++) { 402*0Sstevel@tonic-gate if (ksp->keysock_param_name != NULL && 403*0Sstevel@tonic-gate ksp->keysock_param_name[0]) { 404*0Sstevel@tonic-gate if (!nd_load(&keysock_g_nd, 405*0Sstevel@tonic-gate ksp->keysock_param_name, 406*0Sstevel@tonic-gate keysock_param_get, keysock_param_set, 407*0Sstevel@tonic-gate (caddr_t)ksp)) { 408*0Sstevel@tonic-gate nd_free(&keysock_g_nd); 409*0Sstevel@tonic-gate return (B_FALSE); 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate keysock_max_optsize = optcom_max_optsize( 416*0Sstevel@tonic-gate keysock_opt_obj.odb_opt_des_arr, keysock_opt_obj.odb_opt_arr_cnt); 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate keysock_vmem = vmem_create("keysock", (void *)1, MAXMIN, 1, 419*0Sstevel@tonic-gate NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER); 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate mutex_init(&keysock_list_lock, NULL, MUTEX_DEFAULT, NULL); 422*0Sstevel@tonic-gate mutex_init(&keysock_consumers_lock, NULL, MUTEX_DEFAULT, NULL); 423*0Sstevel@tonic-gate mutex_init(&keysock_param_lock, NULL, MUTEX_DEFAULT, NULL); 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate return (B_TRUE); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * Free NDD variable space, and other destructors, for keysock. 430*0Sstevel@tonic-gate */ 431*0Sstevel@tonic-gate void 432*0Sstevel@tonic-gate keysock_ddi_destroy(void) 433*0Sstevel@tonic-gate { 434*0Sstevel@tonic-gate /* XXX Free instances? */ 435*0Sstevel@tonic-gate ks0dbg(("keysock_ddi_destroy being called.\n")); 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate vmem_destroy(keysock_vmem); 438*0Sstevel@tonic-gate mutex_destroy(&keysock_list_lock); 439*0Sstevel@tonic-gate mutex_destroy(&keysock_consumers_lock); 440*0Sstevel@tonic-gate mutex_destroy(&keysock_param_lock); 441*0Sstevel@tonic-gate nd_free(&keysock_g_nd); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate /* 445*0Sstevel@tonic-gate * Close routine for keysock. 446*0Sstevel@tonic-gate */ 447*0Sstevel@tonic-gate static int 448*0Sstevel@tonic-gate keysock_close(queue_t *q) 449*0Sstevel@tonic-gate { 450*0Sstevel@tonic-gate keysock_t *ks; 451*0Sstevel@tonic-gate keysock_consumer_t *kc; 452*0Sstevel@tonic-gate void *ptr = q->q_ptr; 453*0Sstevel@tonic-gate int size; 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate qprocsoff(q); 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate /* Safe assumption. */ 458*0Sstevel@tonic-gate ASSERT(ptr != NULL); 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate if (WR(q)->q_next) { 461*0Sstevel@tonic-gate kc = (keysock_consumer_t *)ptr; 462*0Sstevel@tonic-gate ks0dbg(("Module close, removing a consumer (%d).\n", 463*0Sstevel@tonic-gate kc->kc_sa_type)); 464*0Sstevel@tonic-gate /* 465*0Sstevel@tonic-gate * Because of PERMOD open/close exclusive perimeter, I 466*0Sstevel@tonic-gate * can inspect KC_FLUSHING w/o locking down kc->kc_lock. 467*0Sstevel@tonic-gate */ 468*0Sstevel@tonic-gate if (kc->kc_flags & KC_FLUSHING) { 469*0Sstevel@tonic-gate /* 470*0Sstevel@tonic-gate * If this decrement was the last one, send 471*0Sstevel@tonic-gate * down the next pending one, if any. 472*0Sstevel@tonic-gate * 473*0Sstevel@tonic-gate * With a PERMOD perimeter, the mutexes ops aren't 474*0Sstevel@tonic-gate * really necessary, but if we ever loosen up, we will 475*0Sstevel@tonic-gate * have this bit covered already. 476*0Sstevel@tonic-gate */ 477*0Sstevel@tonic-gate keysock_flushdump--; 478*0Sstevel@tonic-gate if (keysock_flushdump == 0) { 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * The flush/dump terminated by having a 481*0Sstevel@tonic-gate * consumer go away. I need to send up to the 482*0Sstevel@tonic-gate * appropriate keysock all of the relevant 483*0Sstevel@tonic-gate * information. Unfortunately, I don't 484*0Sstevel@tonic-gate * have that handy. 485*0Sstevel@tonic-gate */ 486*0Sstevel@tonic-gate ks0dbg(("Consumer went away while flushing or" 487*0Sstevel@tonic-gate " dumping.\n")); 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate } 490*0Sstevel@tonic-gate size = sizeof (keysock_consumer_t); 491*0Sstevel@tonic-gate mutex_enter(&keysock_consumers_lock); 492*0Sstevel@tonic-gate keysock_consumers[kc->kc_sa_type] = NULL; 493*0Sstevel@tonic-gate mutex_exit(&keysock_consumers_lock); 494*0Sstevel@tonic-gate mutex_destroy(&kc->kc_lock); 495*0Sstevel@tonic-gate } else { 496*0Sstevel@tonic-gate ks3dbg(("Driver close, PF_KEY socket is going away.\n")); 497*0Sstevel@tonic-gate ks = (keysock_t *)ptr; 498*0Sstevel@tonic-gate if ((ks->keysock_flags & KEYSOCK_EXTENDED) != 0) 499*0Sstevel@tonic-gate atomic_add_32(&keysock_num_extended, -1); 500*0Sstevel@tonic-gate size = sizeof (keysock_t); 501*0Sstevel@tonic-gate mutex_enter(&keysock_list_lock); 502*0Sstevel@tonic-gate *(ks->keysock_ptpn) = ks->keysock_next; 503*0Sstevel@tonic-gate if (ks->keysock_next != NULL) 504*0Sstevel@tonic-gate ks->keysock_next->keysock_ptpn = ks->keysock_ptpn; 505*0Sstevel@tonic-gate mutex_exit(&keysock_list_lock); 506*0Sstevel@tonic-gate mutex_destroy(&ks->keysock_lock); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate /* Now I'm free. */ 510*0Sstevel@tonic-gate kmem_free(ptr, size); 511*0Sstevel@tonic-gate return (0); 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate /* 514*0Sstevel@tonic-gate * Open routine for keysock. 515*0Sstevel@tonic-gate */ 516*0Sstevel@tonic-gate /* ARGSUSED */ 517*0Sstevel@tonic-gate static int 518*0Sstevel@tonic-gate keysock_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 519*0Sstevel@tonic-gate { 520*0Sstevel@tonic-gate keysock_t *ks; 521*0Sstevel@tonic-gate keysock_consumer_t *kc; 522*0Sstevel@tonic-gate mblk_t *mp; 523*0Sstevel@tonic-gate ipsec_info_t *ii; 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate ks3dbg(("Entering keysock open.\n")); 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate if (secpolicy_net_config(credp, B_FALSE) != 0) { 528*0Sstevel@tonic-gate /* Privilege debugging will log the error */ 529*0Sstevel@tonic-gate return (EPERM); 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate if (q->q_ptr != NULL) 533*0Sstevel@tonic-gate return (0); /* Re-open of an already open instance. */ 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate if (keysock_plumbed < 1) { 536*0Sstevel@tonic-gate keysock_plumbed = 0; 537*0Sstevel@tonic-gate /* 538*0Sstevel@tonic-gate * Don't worry about ipsec_failure being true here. 539*0Sstevel@tonic-gate * (See ip.c). An open of keysock should try and force 540*0Sstevel@tonic-gate * the issue. Maybe it was a transient failure. 541*0Sstevel@tonic-gate */ 542*0Sstevel@tonic-gate ipsec_loader_loadnow(); 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate if (sflag & MODOPEN) { 546*0Sstevel@tonic-gate /* Initialize keysock_consumer state here. */ 547*0Sstevel@tonic-gate kc = kmem_zalloc(sizeof (keysock_consumer_t), KM_NOSLEEP); 548*0Sstevel@tonic-gate if (kc == NULL) 549*0Sstevel@tonic-gate return (ENOMEM); 550*0Sstevel@tonic-gate mutex_init(&kc->kc_lock, NULL, MUTEX_DEFAULT, 0); 551*0Sstevel@tonic-gate kc->kc_rq = q; 552*0Sstevel@tonic-gate kc->kc_wq = WR(q); 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate q->q_ptr = kc; 555*0Sstevel@tonic-gate WR(q)->q_ptr = kc; 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate qprocson(q); 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate /* 560*0Sstevel@tonic-gate * Send down initial message to whatever I was pushed on top 561*0Sstevel@tonic-gate * of asking for its consumer type. The reply will set it. 562*0Sstevel@tonic-gate */ 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate /* Allocate it. */ 565*0Sstevel@tonic-gate mp = allocb(sizeof (ipsec_info_t), BPRI_HI); 566*0Sstevel@tonic-gate if (mp == NULL) { 567*0Sstevel@tonic-gate ks1dbg(( 568*0Sstevel@tonic-gate "keysock_open: Cannot allocate KEYSOCK_HELLO.\n")); 569*0Sstevel@tonic-gate /* Do I need to set these to null? */ 570*0Sstevel@tonic-gate q->q_ptr = NULL; 571*0Sstevel@tonic-gate WR(q)->q_ptr = NULL; 572*0Sstevel@tonic-gate mutex_destroy(&kc->kc_lock); 573*0Sstevel@tonic-gate kmem_free(kc, sizeof (*kc)); 574*0Sstevel@tonic-gate return (ENOMEM); 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate /* If I allocated okay, putnext to what I was pushed atop. */ 578*0Sstevel@tonic-gate mp->b_wptr += sizeof (ipsec_info_t); 579*0Sstevel@tonic-gate mp->b_datap->db_type = M_CTL; 580*0Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 581*0Sstevel@tonic-gate ii->ipsec_info_type = KEYSOCK_HELLO; 582*0Sstevel@tonic-gate /* Length only of type/len. */ 583*0Sstevel@tonic-gate ii->ipsec_info_len = sizeof (ii->ipsec_allu); 584*0Sstevel@tonic-gate ks2dbg(("Ready to putnext KEYSOCK_HELLO.\n")); 585*0Sstevel@tonic-gate putnext(kc->kc_wq, mp); 586*0Sstevel@tonic-gate } else { 587*0Sstevel@tonic-gate minor_t ksminor; 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate /* Initialize keysock state. */ 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate ks2dbg(("Made it into PF_KEY socket open.\n")); 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate ksminor = (minor_t)(uintptr_t) 594*0Sstevel@tonic-gate vmem_alloc(keysock_vmem, 1, VM_NOSLEEP); 595*0Sstevel@tonic-gate if (ksminor == 0) 596*0Sstevel@tonic-gate return (ENOMEM); 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate ks = kmem_zalloc(sizeof (keysock_t), KM_NOSLEEP); 599*0Sstevel@tonic-gate if (ks == NULL) { 600*0Sstevel@tonic-gate vmem_free(keysock_vmem, (void *)(uintptr_t)ksminor, 1); 601*0Sstevel@tonic-gate return (ENOMEM); 602*0Sstevel@tonic-gate } 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate mutex_init(&ks->keysock_lock, NULL, MUTEX_DEFAULT, 0); 605*0Sstevel@tonic-gate ks->keysock_rq = q; 606*0Sstevel@tonic-gate ks->keysock_wq = WR(q); 607*0Sstevel@tonic-gate ks->keysock_state = TS_UNBND; 608*0Sstevel@tonic-gate ks->keysock_serial = ksminor; 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate q->q_ptr = ks; 611*0Sstevel@tonic-gate WR(q)->q_ptr = ks; 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate /* 614*0Sstevel@tonic-gate * The receive hiwat is only looked at on the stream head 615*0Sstevel@tonic-gate * queue. Store in q_hiwat in order to return on SO_RCVBUF 616*0Sstevel@tonic-gate * getsockopts. 617*0Sstevel@tonic-gate */ 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate q->q_hiwat = keysock_recv_hiwat; 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate /* 622*0Sstevel@tonic-gate * The transmit hiwat/lowat is only looked at on IP's queue. 623*0Sstevel@tonic-gate * Store in q_hiwat/q_lowat in order to return on 624*0Sstevel@tonic-gate * SO_SNDBUF/SO_SNDLOWAT getsockopts. 625*0Sstevel@tonic-gate */ 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate WR(q)->q_hiwat = keysock_xmit_hiwat; 628*0Sstevel@tonic-gate WR(q)->q_lowat = keysock_xmit_lowat; 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), ksminor); 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate /* 633*0Sstevel@tonic-gate * Thread keysock into the global keysock list. 634*0Sstevel@tonic-gate */ 635*0Sstevel@tonic-gate mutex_enter(&keysock_list_lock); 636*0Sstevel@tonic-gate ks->keysock_next = keysock_list; 637*0Sstevel@tonic-gate ks->keysock_ptpn = &keysock_list; 638*0Sstevel@tonic-gate if (keysock_list != NULL) 639*0Sstevel@tonic-gate keysock_list->keysock_ptpn = &ks->keysock_next; 640*0Sstevel@tonic-gate keysock_list = ks; 641*0Sstevel@tonic-gate mutex_exit(&keysock_list_lock); 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate qprocson(q); 644*0Sstevel@tonic-gate (void) mi_set_sth_hiwat(q, keysock_recv_hiwat); 645*0Sstevel@tonic-gate /* 646*0Sstevel@tonic-gate * Wait outside the keysock module perimeter for IPsec 647*0Sstevel@tonic-gate * plumbing to be completed. If it fails, keysock_close() 648*0Sstevel@tonic-gate * undoes everything we just did. 649*0Sstevel@tonic-gate */ 650*0Sstevel@tonic-gate if (!ipsec_loader_wait(q)) { 651*0Sstevel@tonic-gate (void) keysock_close(q); 652*0Sstevel@tonic-gate return (EPFNOSUPPORT); 653*0Sstevel@tonic-gate } 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate return (0); 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_wput(). */ 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate /* 662*0Sstevel@tonic-gate * Copy relevant state bits. 663*0Sstevel@tonic-gate */ 664*0Sstevel@tonic-gate static void 665*0Sstevel@tonic-gate keysock_copy_info(struct T_info_ack *tap, keysock_t *ks) 666*0Sstevel@tonic-gate { 667*0Sstevel@tonic-gate *tap = keysock_g_t_info_ack; 668*0Sstevel@tonic-gate tap->CURRENT_state = ks->keysock_state; 669*0Sstevel@tonic-gate tap->OPT_size = keysock_max_optsize; 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate /* 673*0Sstevel@tonic-gate * This routine responds to T_CAPABILITY_REQ messages. It is called by 674*0Sstevel@tonic-gate * keysock_wput. Much of the T_CAPABILITY_ACK information is copied from 675*0Sstevel@tonic-gate * keysock_g_t_info_ack. The current state of the stream is copied from 676*0Sstevel@tonic-gate * keysock_state. 677*0Sstevel@tonic-gate */ 678*0Sstevel@tonic-gate static void 679*0Sstevel@tonic-gate keysock_capability_req(queue_t *q, mblk_t *mp) 680*0Sstevel@tonic-gate { 681*0Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 682*0Sstevel@tonic-gate t_uscalar_t cap_bits1; 683*0Sstevel@tonic-gate struct T_capability_ack *tcap; 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack), 688*0Sstevel@tonic-gate mp->b_datap->db_type, T_CAPABILITY_ACK); 689*0Sstevel@tonic-gate if (mp == NULL) 690*0Sstevel@tonic-gate return; 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate tcap = (struct T_capability_ack *)mp->b_rptr; 693*0Sstevel@tonic-gate tcap->CAP_bits1 = 0; 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 696*0Sstevel@tonic-gate keysock_copy_info(&tcap->INFO_ack, ks); 697*0Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_INFO; 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate qreply(q, mp); 701*0Sstevel@tonic-gate } 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate /* 704*0Sstevel@tonic-gate * This routine responds to T_INFO_REQ messages. It is called by 705*0Sstevel@tonic-gate * keysock_wput_other. 706*0Sstevel@tonic-gate * Most of the T_INFO_ACK information is copied from keysock_g_t_info_ack. 707*0Sstevel@tonic-gate * The current state of the stream is copied from keysock_state. 708*0Sstevel@tonic-gate */ 709*0Sstevel@tonic-gate static void 710*0Sstevel@tonic-gate keysock_info_req(q, mp) 711*0Sstevel@tonic-gate queue_t *q; 712*0Sstevel@tonic-gate mblk_t *mp; 713*0Sstevel@tonic-gate { 714*0Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO, 715*0Sstevel@tonic-gate T_INFO_ACK); 716*0Sstevel@tonic-gate if (mp == NULL) 717*0Sstevel@tonic-gate return; 718*0Sstevel@tonic-gate keysock_copy_info((struct T_info_ack *)mp->b_rptr, 719*0Sstevel@tonic-gate (keysock_t *)q->q_ptr); 720*0Sstevel@tonic-gate qreply(q, mp); 721*0Sstevel@tonic-gate } 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate /* 724*0Sstevel@tonic-gate * keysock_err_ack. This routine creates a 725*0Sstevel@tonic-gate * T_ERROR_ACK message and passes it 726*0Sstevel@tonic-gate * upstream. 727*0Sstevel@tonic-gate */ 728*0Sstevel@tonic-gate static void 729*0Sstevel@tonic-gate keysock_err_ack(q, mp, t_error, sys_error) 730*0Sstevel@tonic-gate queue_t *q; 731*0Sstevel@tonic-gate mblk_t *mp; 732*0Sstevel@tonic-gate int t_error; 733*0Sstevel@tonic-gate int sys_error; 734*0Sstevel@tonic-gate { 735*0Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) 736*0Sstevel@tonic-gate qreply(q, mp); 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate /* 740*0Sstevel@tonic-gate * This routine retrieves the current status of socket options. 741*0Sstevel@tonic-gate * It returns the size of the option retrieved. 742*0Sstevel@tonic-gate */ 743*0Sstevel@tonic-gate /* ARGSUSED */ 744*0Sstevel@tonic-gate int 745*0Sstevel@tonic-gate keysock_opt_get(queue_t *q, int level, int name, uchar_t *ptr) 746*0Sstevel@tonic-gate { 747*0Sstevel@tonic-gate int *i1 = (int *)ptr; 748*0Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate switch (level) { 751*0Sstevel@tonic-gate case SOL_SOCKET: 752*0Sstevel@tonic-gate mutex_enter(&ks->keysock_lock); 753*0Sstevel@tonic-gate switch (name) { 754*0Sstevel@tonic-gate case SO_TYPE: 755*0Sstevel@tonic-gate *i1 = SOCK_RAW; 756*0Sstevel@tonic-gate break; 757*0Sstevel@tonic-gate case SO_USELOOPBACK: 758*0Sstevel@tonic-gate *i1 = (int)(!((ks->keysock_flags & KEYSOCK_NOLOOP) == 759*0Sstevel@tonic-gate KEYSOCK_NOLOOP)); 760*0Sstevel@tonic-gate break; 761*0Sstevel@tonic-gate /* 762*0Sstevel@tonic-gate * The following two items can be manipulated, 763*0Sstevel@tonic-gate * but changing them should do nothing. 764*0Sstevel@tonic-gate */ 765*0Sstevel@tonic-gate case SO_SNDBUF: 766*0Sstevel@tonic-gate *i1 = (int)q->q_hiwat; 767*0Sstevel@tonic-gate break; 768*0Sstevel@tonic-gate case SO_RCVBUF: 769*0Sstevel@tonic-gate *i1 = (int)(RD(q)->q_hiwat); 770*0Sstevel@tonic-gate break; 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate mutex_exit(&ks->keysock_lock); 773*0Sstevel@tonic-gate break; 774*0Sstevel@tonic-gate default: 775*0Sstevel@tonic-gate return (0); 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate return (sizeof (int)); 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate /* 781*0Sstevel@tonic-gate * This routine sets socket options. 782*0Sstevel@tonic-gate */ 783*0Sstevel@tonic-gate /* ARGSUSED */ 784*0Sstevel@tonic-gate int 785*0Sstevel@tonic-gate keysock_opt_set(queue_t *q, uint_t mgmt_flags, int level, 786*0Sstevel@tonic-gate int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp, 787*0Sstevel@tonic-gate uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk) 788*0Sstevel@tonic-gate { 789*0Sstevel@tonic-gate int *i1 = (int *)invalp; 790*0Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate switch (level) { 793*0Sstevel@tonic-gate case SOL_SOCKET: 794*0Sstevel@tonic-gate mutex_enter(&ks->keysock_lock); 795*0Sstevel@tonic-gate switch (name) { 796*0Sstevel@tonic-gate case SO_USELOOPBACK: 797*0Sstevel@tonic-gate if (!(*i1)) 798*0Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_NOLOOP; 799*0Sstevel@tonic-gate else ks->keysock_flags &= ~KEYSOCK_NOLOOP; 800*0Sstevel@tonic-gate break; 801*0Sstevel@tonic-gate case SO_SNDBUF: 802*0Sstevel@tonic-gate if (*i1 > keysock_max_buf) 803*0Sstevel@tonic-gate return (ENOBUFS); 804*0Sstevel@tonic-gate q->q_hiwat = *i1; 805*0Sstevel@tonic-gate break; 806*0Sstevel@tonic-gate case SO_RCVBUF: 807*0Sstevel@tonic-gate if (*i1 > keysock_max_buf) 808*0Sstevel@tonic-gate return (ENOBUFS); 809*0Sstevel@tonic-gate RD(q)->q_hiwat = *i1; 810*0Sstevel@tonic-gate (void) mi_set_sth_hiwat(RD(q), *i1); 811*0Sstevel@tonic-gate break; 812*0Sstevel@tonic-gate } 813*0Sstevel@tonic-gate mutex_exit(&ks->keysock_lock); 814*0Sstevel@tonic-gate break; 815*0Sstevel@tonic-gate } 816*0Sstevel@tonic-gate return (0); 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate /* 820*0Sstevel@tonic-gate * Handle STREAMS messages. 821*0Sstevel@tonic-gate */ 822*0Sstevel@tonic-gate static void 823*0Sstevel@tonic-gate keysock_wput_other(queue_t *q, mblk_t *mp) 824*0Sstevel@tonic-gate { 825*0Sstevel@tonic-gate struct iocblk *iocp; 826*0Sstevel@tonic-gate int error; 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 829*0Sstevel@tonic-gate case M_PROTO: 830*0Sstevel@tonic-gate case M_PCPROTO: 831*0Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (long)) { 832*0Sstevel@tonic-gate ks3dbg(( 833*0Sstevel@tonic-gate "keysock_wput_other: Not big enough M_PROTO\n")); 834*0Sstevel@tonic-gate freemsg(mp); 835*0Sstevel@tonic-gate return; 836*0Sstevel@tonic-gate } 837*0Sstevel@tonic-gate switch (((union T_primitives *)mp->b_rptr)->type) { 838*0Sstevel@tonic-gate case T_CAPABILITY_REQ: 839*0Sstevel@tonic-gate keysock_capability_req(q, mp); 840*0Sstevel@tonic-gate return; 841*0Sstevel@tonic-gate case T_INFO_REQ: 842*0Sstevel@tonic-gate keysock_info_req(q, mp); 843*0Sstevel@tonic-gate return; 844*0Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 845*0Sstevel@tonic-gate (void) svr4_optcom_req(q, mp, DB_CREDDEF(mp, kcred), 846*0Sstevel@tonic-gate &keysock_opt_obj); 847*0Sstevel@tonic-gate return; 848*0Sstevel@tonic-gate case T_OPTMGMT_REQ: 849*0Sstevel@tonic-gate (void) tpi_optcom_req(q, mp, DB_CREDDEF(mp, kcred), 850*0Sstevel@tonic-gate &keysock_opt_obj); 851*0Sstevel@tonic-gate return; 852*0Sstevel@tonic-gate case T_DATA_REQ: 853*0Sstevel@tonic-gate case T_EXDATA_REQ: 854*0Sstevel@tonic-gate case T_ORDREL_REQ: 855*0Sstevel@tonic-gate /* Illegal for keysock. */ 856*0Sstevel@tonic-gate freemsg(mp); 857*0Sstevel@tonic-gate (void) putnextctl1(RD(q), M_ERROR, EPROTO); 858*0Sstevel@tonic-gate return; 859*0Sstevel@tonic-gate default: 860*0Sstevel@tonic-gate /* Not supported by keysock. */ 861*0Sstevel@tonic-gate keysock_err_ack(q, mp, TNOTSUPPORT, 0); 862*0Sstevel@tonic-gate return; 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate case M_IOCTL: 865*0Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 866*0Sstevel@tonic-gate error = EINVAL; 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate switch (iocp->ioc_cmd) { 869*0Sstevel@tonic-gate case ND_SET: 870*0Sstevel@tonic-gate case ND_GET: 871*0Sstevel@tonic-gate if (nd_getset(q, keysock_g_nd, mp)) { 872*0Sstevel@tonic-gate qreply(q, mp); 873*0Sstevel@tonic-gate return; 874*0Sstevel@tonic-gate } else 875*0Sstevel@tonic-gate error = ENOENT; 876*0Sstevel@tonic-gate /* FALLTHRU */ 877*0Sstevel@tonic-gate default: 878*0Sstevel@tonic-gate miocnak(q, mp, 0, error); 879*0Sstevel@tonic-gate return; 880*0Sstevel@tonic-gate } 881*0Sstevel@tonic-gate case M_FLUSH: 882*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 883*0Sstevel@tonic-gate flushq(q, FLUSHALL); 884*0Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 885*0Sstevel@tonic-gate } 886*0Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 887*0Sstevel@tonic-gate qreply(q, mp); 888*0Sstevel@tonic-gate return; 889*0Sstevel@tonic-gate } 890*0Sstevel@tonic-gate /* Else FALLTHRU */ 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate /* If fell through, just black-hole the message. */ 894*0Sstevel@tonic-gate freemsg(mp); 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate /* 898*0Sstevel@tonic-gate * Transmit a PF_KEY error message to the instance either pointed to 899*0Sstevel@tonic-gate * by ks, the instance with serial number serial, or more, depending. 900*0Sstevel@tonic-gate * 901*0Sstevel@tonic-gate * The faulty message (or a reasonable facsimile thereof) is in mp. 902*0Sstevel@tonic-gate * This function will free mp or recycle it for delivery, thereby causing 903*0Sstevel@tonic-gate * the stream head to free it. 904*0Sstevel@tonic-gate */ 905*0Sstevel@tonic-gate static void 906*0Sstevel@tonic-gate keysock_error(keysock_t *ks, mblk_t *mp, int error, int diagnostic) 907*0Sstevel@tonic-gate { 908*0Sstevel@tonic-gate sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr; 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate ASSERT(mp->b_datap->db_type == M_DATA); 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate if (samsg->sadb_msg_type < SADB_GETSPI || 913*0Sstevel@tonic-gate samsg->sadb_msg_type > SADB_MAX) 914*0Sstevel@tonic-gate samsg->sadb_msg_type = SADB_RESERVED; 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate /* 917*0Sstevel@tonic-gate * Strip out extension headers. 918*0Sstevel@tonic-gate */ 919*0Sstevel@tonic-gate ASSERT(mp->b_rptr + sizeof (*samsg) <= mp->b_datap->db_lim); 920*0Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (*samsg); 921*0Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (sadb_msg_t)); 922*0Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)error; 923*0Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = (uint16_t)diagnostic; 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE); 926*0Sstevel@tonic-gate } 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate /* 929*0Sstevel@tonic-gate * Pass down a message to a consumer. Wrap it in KEYSOCK_IN, and copy 930*0Sstevel@tonic-gate * in the extv if passed in. 931*0Sstevel@tonic-gate */ 932*0Sstevel@tonic-gate static void 933*0Sstevel@tonic-gate keysock_passdown(keysock_t *ks, mblk_t *mp, uint8_t satype, sadb_ext_t *extv[], 934*0Sstevel@tonic-gate boolean_t flushmsg) 935*0Sstevel@tonic-gate { 936*0Sstevel@tonic-gate keysock_consumer_t *kc; 937*0Sstevel@tonic-gate mblk_t *wrapper; 938*0Sstevel@tonic-gate keysock_in_t *ksi; 939*0Sstevel@tonic-gate int i; 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate wrapper = allocb(sizeof (ipsec_info_t), BPRI_HI); 942*0Sstevel@tonic-gate if (wrapper == NULL) { 943*0Sstevel@tonic-gate ks3dbg(("keysock_passdown: allocb failed.\n")); 944*0Sstevel@tonic-gate if (extv[SADB_EXT_KEY_ENCRYPT] != NULL) 945*0Sstevel@tonic-gate bzero(extv[SADB_EXT_KEY_ENCRYPT], 946*0Sstevel@tonic-gate SADB_64TO8( 947*0Sstevel@tonic-gate extv[SADB_EXT_KEY_ENCRYPT]->sadb_ext_len)); 948*0Sstevel@tonic-gate if (extv[SADB_EXT_KEY_AUTH] != NULL) 949*0Sstevel@tonic-gate bzero(extv[SADB_EXT_KEY_AUTH], 950*0Sstevel@tonic-gate SADB_64TO8( 951*0Sstevel@tonic-gate extv[SADB_EXT_KEY_AUTH]->sadb_ext_len)); 952*0Sstevel@tonic-gate if (flushmsg) { 953*0Sstevel@tonic-gate ks0dbg(( 954*0Sstevel@tonic-gate "keysock: Downwards flush/dump message failed!\n")); 955*0Sstevel@tonic-gate /* If this is true, I hold the perimeter. */ 956*0Sstevel@tonic-gate keysock_flushdump--; 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate freemsg(mp); 959*0Sstevel@tonic-gate return; 960*0Sstevel@tonic-gate } 961*0Sstevel@tonic-gate 962*0Sstevel@tonic-gate wrapper->b_datap->db_type = M_CTL; 963*0Sstevel@tonic-gate ksi = (keysock_in_t *)wrapper->b_rptr; 964*0Sstevel@tonic-gate ksi->ks_in_type = KEYSOCK_IN; 965*0Sstevel@tonic-gate ksi->ks_in_len = sizeof (keysock_in_t); 966*0Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_SRC] != NULL) 967*0Sstevel@tonic-gate ksi->ks_in_srctype = KS_IN_ADDR_UNKNOWN; 968*0Sstevel@tonic-gate else ksi->ks_in_srctype = KS_IN_ADDR_NOTTHERE; 969*0Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_DST] != NULL) 970*0Sstevel@tonic-gate ksi->ks_in_dsttype = KS_IN_ADDR_UNKNOWN; 971*0Sstevel@tonic-gate else ksi->ks_in_dsttype = KS_IN_ADDR_NOTTHERE; 972*0Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_PROXY] != NULL) 973*0Sstevel@tonic-gate ksi->ks_in_proxytype = KS_IN_ADDR_UNKNOWN; 974*0Sstevel@tonic-gate else ksi->ks_in_proxytype = KS_IN_ADDR_NOTTHERE; 975*0Sstevel@tonic-gate for (i = 0; i <= SADB_EXT_MAX; i++) 976*0Sstevel@tonic-gate ksi->ks_in_extv[i] = extv[i]; 977*0Sstevel@tonic-gate ksi->ks_in_serial = ks->keysock_serial; 978*0Sstevel@tonic-gate wrapper->b_wptr += sizeof (ipsec_info_t); 979*0Sstevel@tonic-gate wrapper->b_cont = mp; 980*0Sstevel@tonic-gate 981*0Sstevel@tonic-gate /* 982*0Sstevel@tonic-gate * Find the appropriate consumer where the message is passed down. 983*0Sstevel@tonic-gate */ 984*0Sstevel@tonic-gate kc = keysock_consumers[satype]; 985*0Sstevel@tonic-gate if (kc == NULL) { 986*0Sstevel@tonic-gate freeb(wrapper); 987*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE); 988*0Sstevel@tonic-gate if (flushmsg) { 989*0Sstevel@tonic-gate ks0dbg(( 990*0Sstevel@tonic-gate "keysock: Downwards flush/dump message failed!\n")); 991*0Sstevel@tonic-gate /* If this is true, I hold the perimeter. */ 992*0Sstevel@tonic-gate keysock_flushdump--; 993*0Sstevel@tonic-gate } 994*0Sstevel@tonic-gate return; 995*0Sstevel@tonic-gate } 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate /* 998*0Sstevel@tonic-gate * NOTE: There used to be code in here to spin while a flush or 999*0Sstevel@tonic-gate * dump finished. Keysock now assumes that consumers have enough 1000*0Sstevel@tonic-gate * MT-savviness to deal with that. 1001*0Sstevel@tonic-gate */ 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate /* 1004*0Sstevel@tonic-gate * Current consumers (AH and ESP) are guaranteed to return a 1005*0Sstevel@tonic-gate * FLUSH or DUMP message back, so when we reach here, we don't 1006*0Sstevel@tonic-gate * have to worry about keysock_flushdumps. 1007*0Sstevel@tonic-gate */ 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gate putnext(kc->kc_wq, wrapper); 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate /* 1013*0Sstevel@tonic-gate * High-level reality checking of extensions. 1014*0Sstevel@tonic-gate */ 1015*0Sstevel@tonic-gate static boolean_t 1016*0Sstevel@tonic-gate ext_check(sadb_ext_t *ext) 1017*0Sstevel@tonic-gate { 1018*0Sstevel@tonic-gate int i; 1019*0Sstevel@tonic-gate uint64_t *lp; 1020*0Sstevel@tonic-gate sadb_ident_t *id; 1021*0Sstevel@tonic-gate char *idstr; 1022*0Sstevel@tonic-gate 1023*0Sstevel@tonic-gate switch (ext->sadb_ext_type) { 1024*0Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC: 1025*0Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST: 1026*0Sstevel@tonic-gate case SADB_EXT_ADDRESS_PROXY: 1027*0Sstevel@tonic-gate /* Check for at least enough addtl length for a sockaddr. */ 1028*0Sstevel@tonic-gate if (ext->sadb_ext_len <= SADB_8TO64(sizeof (sadb_address_t))) 1029*0Sstevel@tonic-gate return (B_FALSE); 1030*0Sstevel@tonic-gate break; 1031*0Sstevel@tonic-gate case SADB_EXT_LIFETIME_HARD: 1032*0Sstevel@tonic-gate case SADB_EXT_LIFETIME_SOFT: 1033*0Sstevel@tonic-gate case SADB_EXT_LIFETIME_CURRENT: 1034*0Sstevel@tonic-gate if (ext->sadb_ext_len != SADB_8TO64(sizeof (sadb_lifetime_t))) 1035*0Sstevel@tonic-gate return (B_FALSE); 1036*0Sstevel@tonic-gate break; 1037*0Sstevel@tonic-gate case SADB_EXT_SPIRANGE: 1038*0Sstevel@tonic-gate /* See if the SPI range is legit. */ 1039*0Sstevel@tonic-gate if (htonl(((sadb_spirange_t *)ext)->sadb_spirange_min) > 1040*0Sstevel@tonic-gate htonl(((sadb_spirange_t *)ext)->sadb_spirange_max)) 1041*0Sstevel@tonic-gate return (B_FALSE); 1042*0Sstevel@tonic-gate break; 1043*0Sstevel@tonic-gate case SADB_EXT_KEY_AUTH: 1044*0Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT: 1045*0Sstevel@tonic-gate /* Key length check. */ 1046*0Sstevel@tonic-gate if (((sadb_key_t *)ext)->sadb_key_bits == 0) 1047*0Sstevel@tonic-gate return (B_FALSE); 1048*0Sstevel@tonic-gate /* 1049*0Sstevel@tonic-gate * Check to see if the key length (in bits) is less than the 1050*0Sstevel@tonic-gate * extension length (in 8-bits words). 1051*0Sstevel@tonic-gate */ 1052*0Sstevel@tonic-gate if ((roundup(SADB_1TO8(((sadb_key_t *)ext)->sadb_key_bits), 8) + 1053*0Sstevel@tonic-gate sizeof (sadb_key_t)) != SADB_64TO8(ext->sadb_ext_len)) { 1054*0Sstevel@tonic-gate ks1dbg(( 1055*0Sstevel@tonic-gate "ext_check: Key bits/length inconsistent.\n")); 1056*0Sstevel@tonic-gate ks1dbg(("%d bits, len is %d bytes.\n", 1057*0Sstevel@tonic-gate ((sadb_key_t *)ext)->sadb_key_bits, 1058*0Sstevel@tonic-gate SADB_64TO8(ext->sadb_ext_len))); 1059*0Sstevel@tonic-gate return (B_FALSE); 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate /* All-zeroes key check. */ 1063*0Sstevel@tonic-gate lp = (uint64_t *)(((char *)ext) + sizeof (sadb_key_t)); 1064*0Sstevel@tonic-gate for (i = 0; 1065*0Sstevel@tonic-gate i < (ext->sadb_ext_len - SADB_8TO64(sizeof (sadb_key_t))); 1066*0Sstevel@tonic-gate i++) 1067*0Sstevel@tonic-gate if (lp[i] != 0) 1068*0Sstevel@tonic-gate break; /* Out of for loop. */ 1069*0Sstevel@tonic-gate /* If finished the loop naturally, it's an all zero key. */ 1070*0Sstevel@tonic-gate if (lp[i] == 0) 1071*0Sstevel@tonic-gate return (B_FALSE); 1072*0Sstevel@tonic-gate break; 1073*0Sstevel@tonic-gate case SADB_EXT_IDENTITY_SRC: 1074*0Sstevel@tonic-gate case SADB_EXT_IDENTITY_DST: 1075*0Sstevel@tonic-gate /* 1076*0Sstevel@tonic-gate * Make sure the strings in these identities are 1077*0Sstevel@tonic-gate * null-terminated. RFC 2367 underspecified how to handle 1078*0Sstevel@tonic-gate * such a case. I "proactively" null-terminate the string 1079*0Sstevel@tonic-gate * at the last byte if it's not terminated sooner. 1080*0Sstevel@tonic-gate */ 1081*0Sstevel@tonic-gate id = (sadb_ident_t *)ext; 1082*0Sstevel@tonic-gate i = SADB_64TO8(id->sadb_ident_len); 1083*0Sstevel@tonic-gate i -= sizeof (sadb_ident_t); 1084*0Sstevel@tonic-gate idstr = (char *)(id + 1); 1085*0Sstevel@tonic-gate while (*idstr != '\0' && i > 0) { 1086*0Sstevel@tonic-gate i--; 1087*0Sstevel@tonic-gate idstr++; 1088*0Sstevel@tonic-gate } 1089*0Sstevel@tonic-gate if (i == 0) { 1090*0Sstevel@tonic-gate /* 1091*0Sstevel@tonic-gate * I.e., if the bozo user didn't NULL-terminate the 1092*0Sstevel@tonic-gate * string... 1093*0Sstevel@tonic-gate */ 1094*0Sstevel@tonic-gate idstr--; 1095*0Sstevel@tonic-gate *idstr = '\0'; 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate break; 1098*0Sstevel@tonic-gate } 1099*0Sstevel@tonic-gate return (B_TRUE); /* For now... */ 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate /* Return values for keysock_get_ext(). */ 1103*0Sstevel@tonic-gate #define KGE_OK 0 1104*0Sstevel@tonic-gate #define KGE_DUP 1 1105*0Sstevel@tonic-gate #define KGE_UNK 2 1106*0Sstevel@tonic-gate #define KGE_LEN 3 1107*0Sstevel@tonic-gate #define KGE_CHK 4 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate /* 1110*0Sstevel@tonic-gate * Parse basic extension headers and return in the passed-in pointer vector. 1111*0Sstevel@tonic-gate * Return values include: 1112*0Sstevel@tonic-gate * 1113*0Sstevel@tonic-gate * KGE_OK Everything's nice and parsed out. 1114*0Sstevel@tonic-gate * If there are no extensions, place NULL in extv[0]. 1115*0Sstevel@tonic-gate * KGE_DUP There is a duplicate extension. 1116*0Sstevel@tonic-gate * First instance in appropriate bin. First duplicate in 1117*0Sstevel@tonic-gate * extv[0]. 1118*0Sstevel@tonic-gate * KGE_UNK Unknown extension type encountered. extv[0] contains 1119*0Sstevel@tonic-gate * unknown header. 1120*0Sstevel@tonic-gate * KGE_LEN Extension length error. 1121*0Sstevel@tonic-gate * KGE_CHK High-level reality check failed on specific extension. 1122*0Sstevel@tonic-gate * 1123*0Sstevel@tonic-gate * My apologies for some of the pointer arithmetic in here. I'm thinking 1124*0Sstevel@tonic-gate * like an assembly programmer, yet trying to make the compiler happy. 1125*0Sstevel@tonic-gate */ 1126*0Sstevel@tonic-gate static int 1127*0Sstevel@tonic-gate keysock_get_ext(sadb_ext_t *extv[], sadb_msg_t *basehdr, uint_t msgsize) 1128*0Sstevel@tonic-gate { 1129*0Sstevel@tonic-gate bzero(extv, sizeof (sadb_ext_t *) * (SADB_EXT_MAX + 1)); 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate /* Use extv[0] as the "current working pointer". */ 1132*0Sstevel@tonic-gate 1133*0Sstevel@tonic-gate extv[0] = (sadb_ext_t *)(basehdr + 1); 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate while (extv[0] < (sadb_ext_t *)(((uint8_t *)basehdr) + msgsize)) { 1136*0Sstevel@tonic-gate /* Check for unknown headers. */ 1137*0Sstevel@tonic-gate if (extv[0]->sadb_ext_type == 0 || 1138*0Sstevel@tonic-gate extv[0]->sadb_ext_type > SADB_EXT_MAX) 1139*0Sstevel@tonic-gate return (KGE_UNK); 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate /* 1142*0Sstevel@tonic-gate * Check length. Use uint64_t because extlen is in units 1143*0Sstevel@tonic-gate * of 64-bit words. If length goes beyond the msgsize, 1144*0Sstevel@tonic-gate * return an error. (Zero length also qualifies here.) 1145*0Sstevel@tonic-gate */ 1146*0Sstevel@tonic-gate if (extv[0]->sadb_ext_len == 0 || 1147*0Sstevel@tonic-gate (void *)((uint64_t *)extv[0] + extv[0]->sadb_ext_len) > 1148*0Sstevel@tonic-gate (void *)((uint8_t *)basehdr + msgsize)) 1149*0Sstevel@tonic-gate return (KGE_LEN); 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate /* Check for redundant headers. */ 1152*0Sstevel@tonic-gate if (extv[extv[0]->sadb_ext_type] != NULL) 1153*0Sstevel@tonic-gate return (KGE_DUP); 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate /* 1156*0Sstevel@tonic-gate * Reality check the extension if possible at the keysock 1157*0Sstevel@tonic-gate * level. 1158*0Sstevel@tonic-gate */ 1159*0Sstevel@tonic-gate if (!ext_check(extv[0])) 1160*0Sstevel@tonic-gate return (KGE_CHK); 1161*0Sstevel@tonic-gate 1162*0Sstevel@tonic-gate /* If I make it here, assign the appropriate bin. */ 1163*0Sstevel@tonic-gate extv[extv[0]->sadb_ext_type] = extv[0]; 1164*0Sstevel@tonic-gate 1165*0Sstevel@tonic-gate /* Advance pointer (See above for uint64_t ptr reasoning.) */ 1166*0Sstevel@tonic-gate extv[0] = (sadb_ext_t *) 1167*0Sstevel@tonic-gate ((uint64_t *)extv[0] + extv[0]->sadb_ext_len); 1168*0Sstevel@tonic-gate } 1169*0Sstevel@tonic-gate 1170*0Sstevel@tonic-gate /* Everything's cool. */ 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate /* 1173*0Sstevel@tonic-gate * If extv[0] == NULL, then there are no extension headers in this 1174*0Sstevel@tonic-gate * message. Ensure that this is the case. 1175*0Sstevel@tonic-gate */ 1176*0Sstevel@tonic-gate if (extv[0] == (sadb_ext_t *)(basehdr + 1)) 1177*0Sstevel@tonic-gate extv[0] = NULL; 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate return (KGE_OK); 1180*0Sstevel@tonic-gate } 1181*0Sstevel@tonic-gate 1182*0Sstevel@tonic-gate /* 1183*0Sstevel@tonic-gate * qwriter() callback to handle flushes and dumps. This routine will hold 1184*0Sstevel@tonic-gate * the inner perimeter. 1185*0Sstevel@tonic-gate */ 1186*0Sstevel@tonic-gate void 1187*0Sstevel@tonic-gate keysock_do_flushdump(queue_t *q, mblk_t *mp) 1188*0Sstevel@tonic-gate { 1189*0Sstevel@tonic-gate int i, start, finish; 1190*0Sstevel@tonic-gate mblk_t *mp1 = NULL; 1191*0Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 1192*0Sstevel@tonic-gate sadb_ext_t *extv[SADB_EXT_MAX + 1]; 1193*0Sstevel@tonic-gate sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr; 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate /* 1196*0Sstevel@tonic-gate * I am guaranteed this will work. I did the work in keysock_parse() 1197*0Sstevel@tonic-gate * already. 1198*0Sstevel@tonic-gate */ 1199*0Sstevel@tonic-gate (void) keysock_get_ext(extv, samsg, SADB_64TO8(samsg->sadb_msg_len)); 1200*0Sstevel@tonic-gate 1201*0Sstevel@tonic-gate /* 1202*0Sstevel@tonic-gate * I hold the perimeter, therefore I don't need to use atomic ops. 1203*0Sstevel@tonic-gate */ 1204*0Sstevel@tonic-gate if (keysock_flushdump != 0) { 1205*0Sstevel@tonic-gate /* XXX Should I instead use EBUSY? */ 1206*0Sstevel@tonic-gate /* XXX Or is there a way to queue these up? */ 1207*0Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, SADB_X_DIAGNOSTIC_NONE); 1208*0Sstevel@tonic-gate return; 1209*0Sstevel@tonic-gate } 1210*0Sstevel@tonic-gate 1211*0Sstevel@tonic-gate if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 1212*0Sstevel@tonic-gate start = 0; 1213*0Sstevel@tonic-gate finish = KEYSOCK_MAX_CONSUMERS - 1; 1214*0Sstevel@tonic-gate } else { 1215*0Sstevel@tonic-gate start = samsg->sadb_msg_satype; 1216*0Sstevel@tonic-gate finish = samsg->sadb_msg_satype; 1217*0Sstevel@tonic-gate } 1218*0Sstevel@tonic-gate 1219*0Sstevel@tonic-gate /* 1220*0Sstevel@tonic-gate * Fill up keysock_flushdump with the number of outstanding dumps 1221*0Sstevel@tonic-gate * and/or flushes. 1222*0Sstevel@tonic-gate */ 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate keysock_flushdump_errno = 0; 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate /* 1227*0Sstevel@tonic-gate * Okay, I hold the perimeter. Eventually keysock_flushdump will 1228*0Sstevel@tonic-gate * contain the number of consumers with outstanding flush operations. 1229*0Sstevel@tonic-gate * 1230*0Sstevel@tonic-gate * SO, here's the plan: 1231*0Sstevel@tonic-gate * * For each relevant consumer (Might be one, might be all) 1232*0Sstevel@tonic-gate * * Twiddle on the FLUSHING flag. 1233*0Sstevel@tonic-gate * * Pass down the FLUSH/DUMP message. 1234*0Sstevel@tonic-gate * 1235*0Sstevel@tonic-gate * When I see upbound FLUSH/DUMP messages, I will decrement the 1236*0Sstevel@tonic-gate * keysock_flushdump. When I decrement it to 0, I will pass the 1237*0Sstevel@tonic-gate * FLUSH/DUMP message back up to the PF_KEY sockets. Because I will 1238*0Sstevel@tonic-gate * pass down the right SA type to the consumer (either its own, or 1239*0Sstevel@tonic-gate * that of UNSPEC), the right one will be reflected from each consumer, 1240*0Sstevel@tonic-gate * and accordingly back to the socket. 1241*0Sstevel@tonic-gate */ 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate mutex_enter(&keysock_consumers_lock); 1244*0Sstevel@tonic-gate for (i = start; i <= finish; i++) { 1245*0Sstevel@tonic-gate if (keysock_consumers[i] != NULL) { 1246*0Sstevel@tonic-gate mp1 = copymsg(mp); 1247*0Sstevel@tonic-gate if (mp1 == NULL) { 1248*0Sstevel@tonic-gate ks0dbg(("SADB_FLUSH copymsg() failed.\n")); 1249*0Sstevel@tonic-gate /* 1250*0Sstevel@tonic-gate * Error? And what about outstanding 1251*0Sstevel@tonic-gate * flushes? Oh, yeah, they get sucked up and 1252*0Sstevel@tonic-gate * the counter is decremented. Consumers 1253*0Sstevel@tonic-gate * (see keysock_passdown()) are guaranteed 1254*0Sstevel@tonic-gate * to deliver back a flush request, even if 1255*0Sstevel@tonic-gate * it's an error. 1256*0Sstevel@tonic-gate */ 1257*0Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, 1258*0Sstevel@tonic-gate SADB_X_DIAGNOSTIC_NONE); 1259*0Sstevel@tonic-gate return; 1260*0Sstevel@tonic-gate } 1261*0Sstevel@tonic-gate /* 1262*0Sstevel@tonic-gate * Because my entry conditions are met above, the 1263*0Sstevel@tonic-gate * following assertion should hold true. 1264*0Sstevel@tonic-gate */ 1265*0Sstevel@tonic-gate mutex_enter(&(keysock_consumers[i]->kc_lock)); 1266*0Sstevel@tonic-gate ASSERT((keysock_consumers[i]->kc_flags & KC_FLUSHING) 1267*0Sstevel@tonic-gate == 0); 1268*0Sstevel@tonic-gate keysock_consumers[i]->kc_flags |= KC_FLUSHING; 1269*0Sstevel@tonic-gate mutex_exit(&(keysock_consumers[i]->kc_lock)); 1270*0Sstevel@tonic-gate /* Always increment the number of flushes... */ 1271*0Sstevel@tonic-gate keysock_flushdump++; 1272*0Sstevel@tonic-gate /* Guaranteed to return a message. */ 1273*0Sstevel@tonic-gate keysock_passdown(ks, mp1, i, extv, B_TRUE); 1274*0Sstevel@tonic-gate } else if (start == finish) { 1275*0Sstevel@tonic-gate /* 1276*0Sstevel@tonic-gate * In case where start == finish, and there's no 1277*0Sstevel@tonic-gate * consumer, should we force an error? Yes. 1278*0Sstevel@tonic-gate */ 1279*0Sstevel@tonic-gate mutex_exit(&keysock_consumers_lock); 1280*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 1281*0Sstevel@tonic-gate SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE); 1282*0Sstevel@tonic-gate return; 1283*0Sstevel@tonic-gate } 1284*0Sstevel@tonic-gate } 1285*0Sstevel@tonic-gate mutex_exit(&keysock_consumers_lock); 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate if (keysock_flushdump == 0) { 1288*0Sstevel@tonic-gate /* 1289*0Sstevel@tonic-gate * There were no consumers at all for this message. 1290*0Sstevel@tonic-gate * XXX For now return ESRCH. 1291*0Sstevel@tonic-gate */ 1292*0Sstevel@tonic-gate keysock_error(ks, mp, ESRCH, SADB_X_DIAGNOSTIC_NO_SADBS); 1293*0Sstevel@tonic-gate } else { 1294*0Sstevel@tonic-gate /* Otherwise, free the original message. */ 1295*0Sstevel@tonic-gate freemsg(mp); 1296*0Sstevel@tonic-gate } 1297*0Sstevel@tonic-gate } 1298*0Sstevel@tonic-gate 1299*0Sstevel@tonic-gate /* 1300*0Sstevel@tonic-gate * Get the right diagnostic for a duplicate. Should probably use a static 1301*0Sstevel@tonic-gate * table lookup. 1302*0Sstevel@tonic-gate */ 1303*0Sstevel@tonic-gate int 1304*0Sstevel@tonic-gate keysock_duplicate(int ext_type) 1305*0Sstevel@tonic-gate { 1306*0Sstevel@tonic-gate int rc = 0; 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate switch (ext_type) { 1309*0Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC: 1310*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_SRC; 1311*0Sstevel@tonic-gate break; 1312*0Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST: 1313*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_DST; 1314*0Sstevel@tonic-gate break; 1315*0Sstevel@tonic-gate case SADB_EXT_SA: 1316*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_SA; 1317*0Sstevel@tonic-gate break; 1318*0Sstevel@tonic-gate case SADB_EXT_SPIRANGE: 1319*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_RANGE; 1320*0Sstevel@tonic-gate break; 1321*0Sstevel@tonic-gate case SADB_EXT_KEY_AUTH: 1322*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_AKEY; 1323*0Sstevel@tonic-gate break; 1324*0Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT: 1325*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_EKEY; 1326*0Sstevel@tonic-gate break; 1327*0Sstevel@tonic-gate } 1328*0Sstevel@tonic-gate return (rc); 1329*0Sstevel@tonic-gate } 1330*0Sstevel@tonic-gate 1331*0Sstevel@tonic-gate /* 1332*0Sstevel@tonic-gate * Get the right diagnostic for a reality check failure. Should probably use 1333*0Sstevel@tonic-gate * a static table lookup. 1334*0Sstevel@tonic-gate */ 1335*0Sstevel@tonic-gate int 1336*0Sstevel@tonic-gate keysock_malformed(int ext_type) 1337*0Sstevel@tonic-gate { 1338*0Sstevel@tonic-gate int rc = 0; 1339*0Sstevel@tonic-gate 1340*0Sstevel@tonic-gate switch (ext_type) { 1341*0Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC: 1342*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_SRC; 1343*0Sstevel@tonic-gate break; 1344*0Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST: 1345*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_DST; 1346*0Sstevel@tonic-gate break; 1347*0Sstevel@tonic-gate case SADB_EXT_SA: 1348*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_SA; 1349*0Sstevel@tonic-gate break; 1350*0Sstevel@tonic-gate case SADB_EXT_SPIRANGE: 1351*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_RANGE; 1352*0Sstevel@tonic-gate break; 1353*0Sstevel@tonic-gate case SADB_EXT_KEY_AUTH: 1354*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_AKEY; 1355*0Sstevel@tonic-gate break; 1356*0Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT: 1357*0Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_EKEY; 1358*0Sstevel@tonic-gate break; 1359*0Sstevel@tonic-gate } 1360*0Sstevel@tonic-gate return (rc); 1361*0Sstevel@tonic-gate } 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gate /* 1364*0Sstevel@tonic-gate * Keysock massaging of an inverse ACQUIRE. Consult policy, 1365*0Sstevel@tonic-gate * and construct an appropriate response. 1366*0Sstevel@tonic-gate */ 1367*0Sstevel@tonic-gate static void 1368*0Sstevel@tonic-gate keysock_inverse_acquire(mblk_t *mp, sadb_msg_t *samsg, sadb_ext_t *extv[], 1369*0Sstevel@tonic-gate keysock_t *ks) 1370*0Sstevel@tonic-gate { 1371*0Sstevel@tonic-gate mblk_t *reply_mp; 1372*0Sstevel@tonic-gate 1373*0Sstevel@tonic-gate /* 1374*0Sstevel@tonic-gate * Reality check things... 1375*0Sstevel@tonic-gate */ 1376*0Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_SRC] == NULL) { 1377*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_SRC); 1378*0Sstevel@tonic-gate return; 1379*0Sstevel@tonic-gate } 1380*0Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_DST] == NULL) { 1381*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_DST); 1382*0Sstevel@tonic-gate } 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gate reply_mp = ipsec_construct_inverse_acquire(samsg, extv); 1385*0Sstevel@tonic-gate 1386*0Sstevel@tonic-gate if (reply_mp != NULL) { 1387*0Sstevel@tonic-gate freemsg(mp); 1388*0Sstevel@tonic-gate keysock_passup(reply_mp, (sadb_msg_t *)reply_mp->b_rptr, 1389*0Sstevel@tonic-gate ks->keysock_serial, NULL, B_FALSE); 1390*0Sstevel@tonic-gate } else { 1391*0Sstevel@tonic-gate keysock_error(ks, mp, samsg->sadb_msg_errno, 1392*0Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic); 1393*0Sstevel@tonic-gate } 1394*0Sstevel@tonic-gate } 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate /* 1397*0Sstevel@tonic-gate * Spew an extended REGISTER down to the relevant consumers. 1398*0Sstevel@tonic-gate */ 1399*0Sstevel@tonic-gate static void 1400*0Sstevel@tonic-gate keysock_extended_register(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[]) 1401*0Sstevel@tonic-gate { 1402*0Sstevel@tonic-gate sadb_x_ereg_t *ereg = (sadb_x_ereg_t *)extv[SADB_X_EXT_EREG]; 1403*0Sstevel@tonic-gate uint8_t *satypes, *fencepost; 1404*0Sstevel@tonic-gate mblk_t *downmp; 1405*0Sstevel@tonic-gate sadb_ext_t *downextv[SADB_EXT_MAX + 1]; 1406*0Sstevel@tonic-gate 1407*0Sstevel@tonic-gate if (ks->keysock_registered[0] != 0 || ks->keysock_registered[1] != 0 || 1408*0Sstevel@tonic-gate ks->keysock_registered[2] != 0 || ks->keysock_registered[3] != 0) { 1409*0Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0); 1410*0Sstevel@tonic-gate } 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_EXTENDED; 1413*0Sstevel@tonic-gate if (ereg == NULL) { 1414*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 1415*0Sstevel@tonic-gate } else { 1416*0Sstevel@tonic-gate ASSERT(mp->b_rptr + msgdsize(mp) == mp->b_wptr); 1417*0Sstevel@tonic-gate fencepost = (uint8_t *)mp->b_wptr; 1418*0Sstevel@tonic-gate satypes = ereg->sadb_x_ereg_satypes; 1419*0Sstevel@tonic-gate while (*satypes != SADB_SATYPE_UNSPEC && satypes != fencepost) { 1420*0Sstevel@tonic-gate downmp = copymsg(mp); 1421*0Sstevel@tonic-gate if (downmp == NULL) { 1422*0Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, 0); 1423*0Sstevel@tonic-gate return; 1424*0Sstevel@tonic-gate } 1425*0Sstevel@tonic-gate /* 1426*0Sstevel@tonic-gate * Since we've made it here, keysock_get_ext will work! 1427*0Sstevel@tonic-gate */ 1428*0Sstevel@tonic-gate (void) keysock_get_ext(downextv, 1429*0Sstevel@tonic-gate (sadb_msg_t *)downmp->b_rptr, msgdsize(downmp)); 1430*0Sstevel@tonic-gate keysock_passdown(ks, downmp, *satypes, downextv, 1431*0Sstevel@tonic-gate B_FALSE); 1432*0Sstevel@tonic-gate ++satypes; 1433*0Sstevel@tonic-gate } 1434*0Sstevel@tonic-gate freemsg(mp); 1435*0Sstevel@tonic-gate } 1436*0Sstevel@tonic-gate 1437*0Sstevel@tonic-gate /* 1438*0Sstevel@tonic-gate * Set global to indicate we prefer an extended ACQUIRE. 1439*0Sstevel@tonic-gate */ 1440*0Sstevel@tonic-gate atomic_add_32(&keysock_num_extended, 1); 1441*0Sstevel@tonic-gate } 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate /* 1444*0Sstevel@tonic-gate * Handle PF_KEY messages. 1445*0Sstevel@tonic-gate */ 1446*0Sstevel@tonic-gate static void 1447*0Sstevel@tonic-gate keysock_parse(queue_t *q, mblk_t *mp) 1448*0Sstevel@tonic-gate { 1449*0Sstevel@tonic-gate sadb_msg_t *samsg; 1450*0Sstevel@tonic-gate sadb_ext_t *extv[SADB_EXT_MAX + 1]; 1451*0Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 1452*0Sstevel@tonic-gate uint_t msgsize; 1453*0Sstevel@tonic-gate uint8_t satype; 1454*0Sstevel@tonic-gate 1455*0Sstevel@tonic-gate /* Make sure I'm a PF_KEY socket. (i.e. nothing's below me) */ 1456*0Sstevel@tonic-gate ASSERT(WR(q)->q_next == NULL); 1457*0Sstevel@tonic-gate 1458*0Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_rptr; 1459*0Sstevel@tonic-gate ks2dbg(("Received possible PF_KEY message, type %d.\n", 1460*0Sstevel@tonic-gate samsg->sadb_msg_type)); 1461*0Sstevel@tonic-gate 1462*0Sstevel@tonic-gate msgsize = SADB_64TO8(samsg->sadb_msg_len); 1463*0Sstevel@tonic-gate 1464*0Sstevel@tonic-gate if (msgdsize(mp) != msgsize) { 1465*0Sstevel@tonic-gate /* 1466*0Sstevel@tonic-gate * Message len incorrect w.r.t. actual size. Send an error 1467*0Sstevel@tonic-gate * (EMSGSIZE). It may be necessary to massage things a 1468*0Sstevel@tonic-gate * bit. For example, if the sadb_msg_type is hosed, 1469*0Sstevel@tonic-gate * I need to set it to SADB_RESERVED to get delivery to 1470*0Sstevel@tonic-gate * do the right thing. Then again, maybe just letting 1471*0Sstevel@tonic-gate * the error delivery do the right thing. 1472*0Sstevel@tonic-gate */ 1473*0Sstevel@tonic-gate ks2dbg(("mblk (%lu) and base (%d) message sizes don't jibe.\n", 1474*0Sstevel@tonic-gate msgdsize(mp), msgsize)); 1475*0Sstevel@tonic-gate keysock_error(ks, mp, EMSGSIZE, SADB_X_DIAGNOSTIC_NONE); 1476*0Sstevel@tonic-gate return; 1477*0Sstevel@tonic-gate } 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate if (msgsize > (uint_t)(mp->b_wptr - mp->b_rptr)) { 1480*0Sstevel@tonic-gate /* Get all message into one mblk. */ 1481*0Sstevel@tonic-gate if (pullupmsg(mp, -1) == 0) { 1482*0Sstevel@tonic-gate /* 1483*0Sstevel@tonic-gate * Something screwy happened. 1484*0Sstevel@tonic-gate */ 1485*0Sstevel@tonic-gate ks3dbg(("keysock_parse: pullupmsg() failed.\n")); 1486*0Sstevel@tonic-gate return; 1487*0Sstevel@tonic-gate } else { 1488*0Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_rptr; 1489*0Sstevel@tonic-gate } 1490*0Sstevel@tonic-gate } 1491*0Sstevel@tonic-gate 1492*0Sstevel@tonic-gate switch (keysock_get_ext(extv, samsg, msgsize)) { 1493*0Sstevel@tonic-gate case KGE_DUP: 1494*0Sstevel@tonic-gate /* Handle duplicate extension. */ 1495*0Sstevel@tonic-gate ks1dbg(("Got duplicate extension of type %d.\n", 1496*0Sstevel@tonic-gate extv[0]->sadb_ext_type)); 1497*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 1498*0Sstevel@tonic-gate keysock_duplicate(extv[0]->sadb_ext_type)); 1499*0Sstevel@tonic-gate return; 1500*0Sstevel@tonic-gate case KGE_UNK: 1501*0Sstevel@tonic-gate /* Handle unknown extension. */ 1502*0Sstevel@tonic-gate ks1dbg(("Got unknown extension of type %d.\n", 1503*0Sstevel@tonic-gate extv[0]->sadb_ext_type)); 1504*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_EXT); 1505*0Sstevel@tonic-gate return; 1506*0Sstevel@tonic-gate case KGE_LEN: 1507*0Sstevel@tonic-gate /* Length error. */ 1508*0Sstevel@tonic-gate ks1dbg(("Length %d on extension type %d overrun or 0.\n", 1509*0Sstevel@tonic-gate extv[0]->sadb_ext_len, extv[0]->sadb_ext_type)); 1510*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_BAD_EXTLEN); 1511*0Sstevel@tonic-gate return; 1512*0Sstevel@tonic-gate case KGE_CHK: 1513*0Sstevel@tonic-gate /* Reality check failed. */ 1514*0Sstevel@tonic-gate ks1dbg(("Reality check failed on extension type %d.\n", 1515*0Sstevel@tonic-gate extv[0]->sadb_ext_type)); 1516*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 1517*0Sstevel@tonic-gate keysock_malformed(extv[0]->sadb_ext_type)); 1518*0Sstevel@tonic-gate return; 1519*0Sstevel@tonic-gate default: 1520*0Sstevel@tonic-gate /* Default case is no errors. */ 1521*0Sstevel@tonic-gate break; 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate 1524*0Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 1525*0Sstevel@tonic-gate case SADB_REGISTER: 1526*0Sstevel@tonic-gate /* 1527*0Sstevel@tonic-gate * There's a semantic weirdness in that a message OTHER than 1528*0Sstevel@tonic-gate * the return REGISTER message may be passed up if I set the 1529*0Sstevel@tonic-gate * registered bit BEFORE I pass it down. 1530*0Sstevel@tonic-gate * 1531*0Sstevel@tonic-gate * SOOOO, I'll not twiddle any registered bits until I see 1532*0Sstevel@tonic-gate * the upbound REGISTER (with a serial number in it). 1533*0Sstevel@tonic-gate */ 1534*0Sstevel@tonic-gate if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 1535*0Sstevel@tonic-gate /* Handle extended register here. */ 1536*0Sstevel@tonic-gate keysock_extended_register(ks, mp, extv); 1537*0Sstevel@tonic-gate return; 1538*0Sstevel@tonic-gate } else if (ks->keysock_flags & KEYSOCK_EXTENDED) { 1539*0Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0); 1540*0Sstevel@tonic-gate return; 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate /* FALLTHRU */ 1543*0Sstevel@tonic-gate case SADB_GETSPI: 1544*0Sstevel@tonic-gate case SADB_ADD: 1545*0Sstevel@tonic-gate case SADB_UPDATE: 1546*0Sstevel@tonic-gate case SADB_DELETE: 1547*0Sstevel@tonic-gate case SADB_GET: 1548*0Sstevel@tonic-gate /* 1549*0Sstevel@tonic-gate * Pass down to appropriate consumer. 1550*0Sstevel@tonic-gate */ 1551*0Sstevel@tonic-gate if (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC) 1552*0Sstevel@tonic-gate keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv, 1553*0Sstevel@tonic-gate B_FALSE); 1554*0Sstevel@tonic-gate else keysock_error(ks, mp, EINVAL, 1555*0Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 1556*0Sstevel@tonic-gate return; 1557*0Sstevel@tonic-gate case SADB_ACQUIRE: 1558*0Sstevel@tonic-gate /* 1559*0Sstevel@tonic-gate * If I _receive_ an acquire, this means I should spread it 1560*0Sstevel@tonic-gate * out to registered sockets. Unless there's an errno... 1561*0Sstevel@tonic-gate * 1562*0Sstevel@tonic-gate * Need ADDRESS, may have ID, SENS, and PROP, unless errno, 1563*0Sstevel@tonic-gate * in which case there should be NO extensions. 1564*0Sstevel@tonic-gate * 1565*0Sstevel@tonic-gate * Return to registered. 1566*0Sstevel@tonic-gate */ 1567*0Sstevel@tonic-gate if (samsg->sadb_msg_errno != 0) { 1568*0Sstevel@tonic-gate satype = samsg->sadb_msg_satype; 1569*0Sstevel@tonic-gate if (satype == SADB_SATYPE_UNSPEC) { 1570*0Sstevel@tonic-gate if (!(ks->keysock_flags & KEYSOCK_EXTENDED)) { 1571*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 1572*0Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 1573*0Sstevel@tonic-gate return; 1574*0Sstevel@tonic-gate } 1575*0Sstevel@tonic-gate /* 1576*0Sstevel@tonic-gate * Reassign satype based on the first 1577*0Sstevel@tonic-gate * flags that KEYSOCK_SETREG says. 1578*0Sstevel@tonic-gate */ 1579*0Sstevel@tonic-gate while (satype <= SADB_SATYPE_MAX) { 1580*0Sstevel@tonic-gate if (KEYSOCK_ISREG(ks, satype)) 1581*0Sstevel@tonic-gate break; 1582*0Sstevel@tonic-gate satype++; 1583*0Sstevel@tonic-gate } 1584*0Sstevel@tonic-gate if (satype > SADB_SATYPE_MAX) { 1585*0Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0); 1586*0Sstevel@tonic-gate return; 1587*0Sstevel@tonic-gate } 1588*0Sstevel@tonic-gate } 1589*0Sstevel@tonic-gate keysock_passdown(ks, mp, satype, extv, B_FALSE); 1590*0Sstevel@tonic-gate } else { 1591*0Sstevel@tonic-gate if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) 1592*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 1593*0Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 1594*0Sstevel@tonic-gate else 1595*0Sstevel@tonic-gate keysock_passup(mp, samsg, 0, NULL, B_FALSE); 1596*0Sstevel@tonic-gate } 1597*0Sstevel@tonic-gate return; 1598*0Sstevel@tonic-gate case SADB_EXPIRE: 1599*0Sstevel@tonic-gate /* 1600*0Sstevel@tonic-gate * If someone sends this in, then send out to all senders. 1601*0Sstevel@tonic-gate * (Save maybe ESP or AH, I have to be careful here.) 1602*0Sstevel@tonic-gate * 1603*0Sstevel@tonic-gate * Need ADDRESS, may have ID and SENS. 1604*0Sstevel@tonic-gate * 1605*0Sstevel@tonic-gate * XXX for now this is unsupported. 1606*0Sstevel@tonic-gate */ 1607*0Sstevel@tonic-gate break; 1608*0Sstevel@tonic-gate case SADB_FLUSH: 1609*0Sstevel@tonic-gate case SADB_DUMP: /* not used by normal applications */ 1610*0Sstevel@tonic-gate /* 1611*0Sstevel@tonic-gate * Nuke all SAs, or dump out the whole SA table to sender only. 1612*0Sstevel@tonic-gate * 1613*0Sstevel@tonic-gate * No extensions at all. Return to all listeners. 1614*0Sstevel@tonic-gate * 1615*0Sstevel@tonic-gate * Question: Should I hold a lock here to prevent 1616*0Sstevel@tonic-gate * additions/deletions while flushing? 1617*0Sstevel@tonic-gate * Answer: No. (See keysock_passdown() for details.) 1618*0Sstevel@tonic-gate */ 1619*0Sstevel@tonic-gate if (extv[0] != NULL) { 1620*0Sstevel@tonic-gate /* 1621*0Sstevel@tonic-gate * FLUSH or DUMP messages shouldn't have extensions. 1622*0Sstevel@tonic-gate * Return EINVAL. 1623*0Sstevel@tonic-gate */ 1624*0Sstevel@tonic-gate ks2dbg(("FLUSH message with extension.\n")); 1625*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_NO_EXT); 1626*0Sstevel@tonic-gate return; 1627*0Sstevel@tonic-gate } 1628*0Sstevel@tonic-gate 1629*0Sstevel@tonic-gate /* Passing down of DUMP/FLUSH messages are special. */ 1630*0Sstevel@tonic-gate qwriter(q, mp, keysock_do_flushdump, PERIM_INNER); 1631*0Sstevel@tonic-gate return; 1632*0Sstevel@tonic-gate case SADB_X_PROMISC: 1633*0Sstevel@tonic-gate /* 1634*0Sstevel@tonic-gate * Promiscuous processing message. 1635*0Sstevel@tonic-gate */ 1636*0Sstevel@tonic-gate if (samsg->sadb_msg_satype == 0) 1637*0Sstevel@tonic-gate ks->keysock_flags &= ~KEYSOCK_PROMISC; 1638*0Sstevel@tonic-gate else 1639*0Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_PROMISC; 1640*0Sstevel@tonic-gate keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE); 1641*0Sstevel@tonic-gate return; 1642*0Sstevel@tonic-gate case SADB_X_INVERSE_ACQUIRE: 1643*0Sstevel@tonic-gate keysock_inverse_acquire(mp, samsg, extv, ks); 1644*0Sstevel@tonic-gate return; 1645*0Sstevel@tonic-gate default: 1646*0Sstevel@tonic-gate ks2dbg(("Got unknown message type %d.\n", 1647*0Sstevel@tonic-gate samsg->sadb_msg_type)); 1648*0Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_MSG); 1649*0Sstevel@tonic-gate return; 1650*0Sstevel@tonic-gate } 1651*0Sstevel@tonic-gate 1652*0Sstevel@tonic-gate /* As a placeholder... */ 1653*0Sstevel@tonic-gate ks0dbg(("keysock_parse(): Hit EOPNOTSUPP\n")); 1654*0Sstevel@tonic-gate keysock_error(ks, mp, EOPNOTSUPP, SADB_X_DIAGNOSTIC_NONE); 1655*0Sstevel@tonic-gate } 1656*0Sstevel@tonic-gate 1657*0Sstevel@tonic-gate /* 1658*0Sstevel@tonic-gate * wput routing for PF_KEY/keysock/whatever. Unlike the routing socket, 1659*0Sstevel@tonic-gate * I don't convert to ioctl()'s for IP. I am the end-all driver as far 1660*0Sstevel@tonic-gate * as PF_KEY sockets are concerned. I do some conversion, but not as much 1661*0Sstevel@tonic-gate * as IP/rts does. 1662*0Sstevel@tonic-gate */ 1663*0Sstevel@tonic-gate static void 1664*0Sstevel@tonic-gate keysock_wput(queue_t *q, mblk_t *mp) 1665*0Sstevel@tonic-gate { 1666*0Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 1667*0Sstevel@tonic-gate mblk_t *mp1; 1668*0Sstevel@tonic-gate 1669*0Sstevel@tonic-gate ks3dbg(("In keysock_wput\n")); 1670*0Sstevel@tonic-gate 1671*0Sstevel@tonic-gate if (WR(q)->q_next) { 1672*0Sstevel@tonic-gate keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr; 1673*0Sstevel@tonic-gate 1674*0Sstevel@tonic-gate /* 1675*0Sstevel@tonic-gate * We shouldn't get writes on a consumer instance. 1676*0Sstevel@tonic-gate * But for now, just passthru. 1677*0Sstevel@tonic-gate */ 1678*0Sstevel@tonic-gate ks1dbg(("Huh? wput for an consumer instance (%d)?\n", 1679*0Sstevel@tonic-gate kc->kc_sa_type)); 1680*0Sstevel@tonic-gate putnext(q, mp); 1681*0Sstevel@tonic-gate return; 1682*0Sstevel@tonic-gate } 1683*0Sstevel@tonic-gate 1684*0Sstevel@tonic-gate switch (mp->b_datap->db_type) { 1685*0Sstevel@tonic-gate case M_DATA: 1686*0Sstevel@tonic-gate /* 1687*0Sstevel@tonic-gate * Silently discard. 1688*0Sstevel@tonic-gate */ 1689*0Sstevel@tonic-gate ks2dbg(("raw M_DATA in keysock.\n")); 1690*0Sstevel@tonic-gate freemsg(mp); 1691*0Sstevel@tonic-gate return; 1692*0Sstevel@tonic-gate case M_PROTO: 1693*0Sstevel@tonic-gate case M_PCPROTO: 1694*0Sstevel@tonic-gate if ((mp->b_wptr - rptr) >= sizeof (struct T_data_req)) { 1695*0Sstevel@tonic-gate if (((union T_primitives *)rptr)->type == T_DATA_REQ) { 1696*0Sstevel@tonic-gate if ((mp1 = mp->b_cont) == NULL) { 1697*0Sstevel@tonic-gate /* No data after T_DATA_REQ. */ 1698*0Sstevel@tonic-gate ks2dbg(("No data after DATA_REQ.\n")); 1699*0Sstevel@tonic-gate freemsg(mp); 1700*0Sstevel@tonic-gate return; 1701*0Sstevel@tonic-gate } 1702*0Sstevel@tonic-gate freeb(mp); 1703*0Sstevel@tonic-gate mp = mp1; 1704*0Sstevel@tonic-gate ks2dbg(("T_DATA_REQ\n")); 1705*0Sstevel@tonic-gate break; /* Out of switch. */ 1706*0Sstevel@tonic-gate } 1707*0Sstevel@tonic-gate } 1708*0Sstevel@tonic-gate /* FALLTHRU */ 1709*0Sstevel@tonic-gate default: 1710*0Sstevel@tonic-gate ks3dbg(("In default wput case (%d %d).\n", 1711*0Sstevel@tonic-gate mp->b_datap->db_type, ((union T_primitives *)rptr)->type)); 1712*0Sstevel@tonic-gate keysock_wput_other(q, mp); 1713*0Sstevel@tonic-gate return; 1714*0Sstevel@tonic-gate } 1715*0Sstevel@tonic-gate 1716*0Sstevel@tonic-gate /* I now have a PF_KEY message in an M_DATA block, pointed to by mp. */ 1717*0Sstevel@tonic-gate keysock_parse(q, mp); 1718*0Sstevel@tonic-gate } 1719*0Sstevel@tonic-gate 1720*0Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_rput(). */ 1721*0Sstevel@tonic-gate 1722*0Sstevel@tonic-gate /* 1723*0Sstevel@tonic-gate * Called upon receipt of a KEYSOCK_HELLO_ACK to set up the appropriate 1724*0Sstevel@tonic-gate * state vectors. 1725*0Sstevel@tonic-gate */ 1726*0Sstevel@tonic-gate static void 1727*0Sstevel@tonic-gate keysock_link_consumer(uint8_t satype, keysock_consumer_t *kc) 1728*0Sstevel@tonic-gate { 1729*0Sstevel@tonic-gate keysock_t *ks; 1730*0Sstevel@tonic-gate 1731*0Sstevel@tonic-gate mutex_enter(&keysock_consumers_lock); 1732*0Sstevel@tonic-gate mutex_enter(&kc->kc_lock); 1733*0Sstevel@tonic-gate if (keysock_consumers[satype] != NULL) { 1734*0Sstevel@tonic-gate ks0dbg(( 1735*0Sstevel@tonic-gate "Hmmmm, someone closed %d before the HELLO_ACK happened.\n", 1736*0Sstevel@tonic-gate satype)); 1737*0Sstevel@tonic-gate /* 1738*0Sstevel@tonic-gate * Perhaps updating the new below-me consumer with what I have 1739*0Sstevel@tonic-gate * so far would work too? 1740*0Sstevel@tonic-gate */ 1741*0Sstevel@tonic-gate mutex_exit(&kc->kc_lock); 1742*0Sstevel@tonic-gate mutex_exit(&keysock_consumers_lock); 1743*0Sstevel@tonic-gate } else { 1744*0Sstevel@tonic-gate /* Add new below-me consumer. */ 1745*0Sstevel@tonic-gate keysock_consumers[satype] = kc; 1746*0Sstevel@tonic-gate 1747*0Sstevel@tonic-gate kc->kc_flags = 0; 1748*0Sstevel@tonic-gate kc->kc_sa_type = satype; 1749*0Sstevel@tonic-gate mutex_exit(&kc->kc_lock); 1750*0Sstevel@tonic-gate mutex_exit(&keysock_consumers_lock); 1751*0Sstevel@tonic-gate 1752*0Sstevel@tonic-gate /* Scan the keysock list. */ 1753*0Sstevel@tonic-gate mutex_enter(&keysock_list_lock); 1754*0Sstevel@tonic-gate for (ks = keysock_list; ks != NULL; ks = ks->keysock_next) { 1755*0Sstevel@tonic-gate if (KEYSOCK_ISREG(ks, satype)) { 1756*0Sstevel@tonic-gate /* 1757*0Sstevel@tonic-gate * XXX Perhaps send an SADB_REGISTER down on 1758*0Sstevel@tonic-gate * the socket's behalf. 1759*0Sstevel@tonic-gate */ 1760*0Sstevel@tonic-gate ks1dbg(("Socket %u registered already for " 1761*0Sstevel@tonic-gate "new consumer.\n", ks->keysock_serial)); 1762*0Sstevel@tonic-gate } 1763*0Sstevel@tonic-gate } 1764*0Sstevel@tonic-gate mutex_exit(&keysock_list_lock); 1765*0Sstevel@tonic-gate } 1766*0Sstevel@tonic-gate } 1767*0Sstevel@tonic-gate 1768*0Sstevel@tonic-gate /* 1769*0Sstevel@tonic-gate * Generate a KEYSOCK_OUT_ERR message for my consumer. 1770*0Sstevel@tonic-gate */ 1771*0Sstevel@tonic-gate static void 1772*0Sstevel@tonic-gate keysock_out_err(keysock_consumer_t *kc, int ks_errno, mblk_t *mp) 1773*0Sstevel@tonic-gate { 1774*0Sstevel@tonic-gate keysock_out_err_t *kse; 1775*0Sstevel@tonic-gate mblk_t *imp; 1776*0Sstevel@tonic-gate 1777*0Sstevel@tonic-gate imp = allocb(sizeof (ipsec_info_t), BPRI_HI); 1778*0Sstevel@tonic-gate if (imp == NULL) { 1779*0Sstevel@tonic-gate ks1dbg(("keysock_out_err: Can't alloc message.\n")); 1780*0Sstevel@tonic-gate return; 1781*0Sstevel@tonic-gate } 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate imp->b_datap->db_type = M_CTL; 1784*0Sstevel@tonic-gate imp->b_wptr += sizeof (ipsec_info_t); 1785*0Sstevel@tonic-gate 1786*0Sstevel@tonic-gate kse = (keysock_out_err_t *)imp->b_rptr; 1787*0Sstevel@tonic-gate imp->b_cont = mp; 1788*0Sstevel@tonic-gate kse->ks_err_type = KEYSOCK_OUT_ERR; 1789*0Sstevel@tonic-gate kse->ks_err_len = sizeof (*kse); 1790*0Sstevel@tonic-gate /* Is serial necessary? */ 1791*0Sstevel@tonic-gate kse->ks_err_serial = 0; 1792*0Sstevel@tonic-gate kse->ks_err_errno = ks_errno; 1793*0Sstevel@tonic-gate 1794*0Sstevel@tonic-gate /* 1795*0Sstevel@tonic-gate * XXX What else do I need to do here w.r.t. information 1796*0Sstevel@tonic-gate * to tell the consumer what caused this error? 1797*0Sstevel@tonic-gate * 1798*0Sstevel@tonic-gate * I believe the answer is the PF_KEY ACQUIRE (or other) message 1799*0Sstevel@tonic-gate * attached in mp, which is appended at the end. I believe the 1800*0Sstevel@tonic-gate * db_ref won't matter here, because the PF_KEY message is only read 1801*0Sstevel@tonic-gate * for KEYSOCK_OUT_ERR. 1802*0Sstevel@tonic-gate */ 1803*0Sstevel@tonic-gate 1804*0Sstevel@tonic-gate putnext(kc->kc_wq, imp); 1805*0Sstevel@tonic-gate } 1806*0Sstevel@tonic-gate 1807*0Sstevel@tonic-gate /* XXX this is a hack errno. */ 1808*0Sstevel@tonic-gate #define EIPSECNOSA 255 1809*0Sstevel@tonic-gate 1810*0Sstevel@tonic-gate /* 1811*0Sstevel@tonic-gate * Route message (pointed by mp, header in samsg) toward appropriate 1812*0Sstevel@tonic-gate * sockets. Assume the message's creator did its job correctly. 1813*0Sstevel@tonic-gate * 1814*0Sstevel@tonic-gate * This should be a function that is followed by a return in its caller. 1815*0Sstevel@tonic-gate * The compiler _should_ be able to use tail-call optimizations to make the 1816*0Sstevel@tonic-gate * large ## of parameters not a huge deal. 1817*0Sstevel@tonic-gate */ 1818*0Sstevel@tonic-gate static void 1819*0Sstevel@tonic-gate keysock_passup(mblk_t *mp, sadb_msg_t *samsg, minor_t serial, 1820*0Sstevel@tonic-gate keysock_consumer_t *kc, boolean_t persistent) 1821*0Sstevel@tonic-gate { 1822*0Sstevel@tonic-gate keysock_t *ks; 1823*0Sstevel@tonic-gate uint8_t satype = samsg->sadb_msg_satype; 1824*0Sstevel@tonic-gate boolean_t toall = B_FALSE, allreg = B_FALSE, allereg = B_FALSE, 1825*0Sstevel@tonic-gate setalg = B_FALSE; 1826*0Sstevel@tonic-gate mblk_t *mp1; 1827*0Sstevel@tonic-gate int err = EIPSECNOSA; 1828*0Sstevel@tonic-gate 1829*0Sstevel@tonic-gate /* Convert mp, which is M_DATA, into an M_PROTO of type T_DATA_IND */ 1830*0Sstevel@tonic-gate mp1 = allocb(sizeof (struct T_data_req), BPRI_HI); 1831*0Sstevel@tonic-gate if (mp1 == NULL) { 1832*0Sstevel@tonic-gate err = ENOMEM; 1833*0Sstevel@tonic-gate goto error; 1834*0Sstevel@tonic-gate } 1835*0Sstevel@tonic-gate mp1->b_wptr += sizeof (struct T_data_req); 1836*0Sstevel@tonic-gate ((struct T_data_ind *)mp1->b_rptr)->PRIM_type = T_DATA_IND; 1837*0Sstevel@tonic-gate ((struct T_data_ind *)mp1->b_rptr)->MORE_flag = 0; 1838*0Sstevel@tonic-gate mp1->b_datap->db_type = M_PROTO; 1839*0Sstevel@tonic-gate mp1->b_cont = mp; 1840*0Sstevel@tonic-gate mp = mp1; 1841*0Sstevel@tonic-gate 1842*0Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 1843*0Sstevel@tonic-gate case SADB_FLUSH: 1844*0Sstevel@tonic-gate case SADB_GETSPI: 1845*0Sstevel@tonic-gate case SADB_UPDATE: 1846*0Sstevel@tonic-gate case SADB_ADD: 1847*0Sstevel@tonic-gate case SADB_DELETE: 1848*0Sstevel@tonic-gate case SADB_EXPIRE: 1849*0Sstevel@tonic-gate /* 1850*0Sstevel@tonic-gate * These are most likely replies. Don't worry about 1851*0Sstevel@tonic-gate * KEYSOCK_OUT_ERR handling. Deliver to all sockets. 1852*0Sstevel@tonic-gate */ 1853*0Sstevel@tonic-gate ks3dbg(("Delivering normal message (%d) to all sockets.\n", 1854*0Sstevel@tonic-gate samsg->sadb_msg_type)); 1855*0Sstevel@tonic-gate toall = B_TRUE; 1856*0Sstevel@tonic-gate break; 1857*0Sstevel@tonic-gate case SADB_REGISTER: 1858*0Sstevel@tonic-gate /* 1859*0Sstevel@tonic-gate * REGISTERs come up for one of three reasons: 1860*0Sstevel@tonic-gate * 1861*0Sstevel@tonic-gate * 1.) In response to a normal SADB_REGISTER 1862*0Sstevel@tonic-gate * (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC && 1863*0Sstevel@tonic-gate * serial != 0) 1864*0Sstevel@tonic-gate * Deliver to normal SADB_REGISTERed sockets. 1865*0Sstevel@tonic-gate * 2.) In response to an extended REGISTER 1866*0Sstevel@tonic-gate * (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) 1867*0Sstevel@tonic-gate * Deliver to extended REGISTERed socket. 1868*0Sstevel@tonic-gate * 3.) Spontaneous algorithm changes 1869*0Sstevel@tonic-gate * (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC && 1870*0Sstevel@tonic-gate * serial == 0) 1871*0Sstevel@tonic-gate * Deliver to REGISTERed sockets of all sorts. 1872*0Sstevel@tonic-gate */ 1873*0Sstevel@tonic-gate if (kc == NULL) { 1874*0Sstevel@tonic-gate /* Here because of keysock_error() call. */ 1875*0Sstevel@tonic-gate ASSERT(samsg->sadb_msg_errno != 0); 1876*0Sstevel@tonic-gate break; /* Out of switch. */ 1877*0Sstevel@tonic-gate } 1878*0Sstevel@tonic-gate ks3dbg(("Delivering REGISTER.\n")); 1879*0Sstevel@tonic-gate if (satype == SADB_SATYPE_UNSPEC) { 1880*0Sstevel@tonic-gate /* REGISTER Reason #2 */ 1881*0Sstevel@tonic-gate allereg = B_TRUE; 1882*0Sstevel@tonic-gate /* 1883*0Sstevel@tonic-gate * Rewhack SA type so PF_KEY socket holder knows what 1884*0Sstevel@tonic-gate * consumer generated this algorithm list. 1885*0Sstevel@tonic-gate */ 1886*0Sstevel@tonic-gate satype = kc->kc_sa_type; 1887*0Sstevel@tonic-gate samsg->sadb_msg_satype = satype; 1888*0Sstevel@tonic-gate setalg = B_TRUE; 1889*0Sstevel@tonic-gate } else if (serial == 0) { 1890*0Sstevel@tonic-gate /* REGISTER Reason #3 */ 1891*0Sstevel@tonic-gate allreg = B_TRUE; 1892*0Sstevel@tonic-gate allereg = B_TRUE; 1893*0Sstevel@tonic-gate } else { 1894*0Sstevel@tonic-gate /* REGISTER Reason #1 */ 1895*0Sstevel@tonic-gate allreg = B_TRUE; 1896*0Sstevel@tonic-gate setalg = B_TRUE; 1897*0Sstevel@tonic-gate } 1898*0Sstevel@tonic-gate break; 1899*0Sstevel@tonic-gate case SADB_ACQUIRE: 1900*0Sstevel@tonic-gate /* 1901*0Sstevel@tonic-gate * ACQUIREs are either extended (sadb_msg_satype == 0) or 1902*0Sstevel@tonic-gate * regular (sadb_msg_satype != 0). And we're guaranteed 1903*0Sstevel@tonic-gate * that serial == 0 for an ACQUIRE. 1904*0Sstevel@tonic-gate */ 1905*0Sstevel@tonic-gate ks3dbg(("Delivering ACQUIRE.\n")); 1906*0Sstevel@tonic-gate allereg = (satype == SADB_SATYPE_UNSPEC); 1907*0Sstevel@tonic-gate allreg = !allereg; 1908*0Sstevel@tonic-gate /* 1909*0Sstevel@tonic-gate * Corner case - if we send a regular ACQUIRE and there's 1910*0Sstevel@tonic-gate * extended ones registered, don't send an error down to 1911*0Sstevel@tonic-gate * consumers if nobody's listening and prematurely destroy 1912*0Sstevel@tonic-gate * their ACQUIRE record. This might be too hackish of a 1913*0Sstevel@tonic-gate * solution. 1914*0Sstevel@tonic-gate */ 1915*0Sstevel@tonic-gate if (allreg && keysock_num_extended > 0) 1916*0Sstevel@tonic-gate err = 0; 1917*0Sstevel@tonic-gate break; 1918*0Sstevel@tonic-gate case SADB_X_PROMISC: 1919*0Sstevel@tonic-gate case SADB_X_INVERSE_ACQUIRE: 1920*0Sstevel@tonic-gate case SADB_DUMP: 1921*0Sstevel@tonic-gate case SADB_GET: 1922*0Sstevel@tonic-gate default: 1923*0Sstevel@tonic-gate /* 1924*0Sstevel@tonic-gate * Deliver to the sender and promiscuous only. 1925*0Sstevel@tonic-gate */ 1926*0Sstevel@tonic-gate ks3dbg(("Delivering sender/promisc only (%d).\n", 1927*0Sstevel@tonic-gate samsg->sadb_msg_type)); 1928*0Sstevel@tonic-gate break; 1929*0Sstevel@tonic-gate } 1930*0Sstevel@tonic-gate 1931*0Sstevel@tonic-gate mutex_enter(&keysock_list_lock); 1932*0Sstevel@tonic-gate for (ks = keysock_list; ks != NULL; ks = ks->keysock_next) { 1933*0Sstevel@tonic-gate /* Delivery loop. */ 1934*0Sstevel@tonic-gate 1935*0Sstevel@tonic-gate /* 1936*0Sstevel@tonic-gate * Check special keysock-setting cases (REGISTER replies) 1937*0Sstevel@tonic-gate * here. 1938*0Sstevel@tonic-gate */ 1939*0Sstevel@tonic-gate if (setalg && serial == ks->keysock_serial) { 1940*0Sstevel@tonic-gate ASSERT(kc != NULL); 1941*0Sstevel@tonic-gate ASSERT(kc->kc_sa_type == satype); 1942*0Sstevel@tonic-gate KEYSOCK_SETREG(ks, satype); 1943*0Sstevel@tonic-gate } 1944*0Sstevel@tonic-gate 1945*0Sstevel@tonic-gate /* 1946*0Sstevel@tonic-gate * NOLOOP takes precedence over PROMISC. So if you've set 1947*0Sstevel@tonic-gate * !SO_USELOOPBACK, don't expect to see any data... 1948*0Sstevel@tonic-gate */ 1949*0Sstevel@tonic-gate if (ks->keysock_flags & KEYSOCK_NOLOOP) 1950*0Sstevel@tonic-gate continue; 1951*0Sstevel@tonic-gate 1952*0Sstevel@tonic-gate /* 1953*0Sstevel@tonic-gate * Messages to all, or promiscuous sockets just GET the 1954*0Sstevel@tonic-gate * message. Perform rules-type checking iff it's not for all 1955*0Sstevel@tonic-gate * listeners or the socket is in promiscuous mode. 1956*0Sstevel@tonic-gate * 1957*0Sstevel@tonic-gate * NOTE:Because of the (kc != NULL && ISREG()), make sure 1958*0Sstevel@tonic-gate * extended ACQUIREs arrive off a consumer that is 1959*0Sstevel@tonic-gate * part of the extended REGISTER set of consumers. 1960*0Sstevel@tonic-gate */ 1961*0Sstevel@tonic-gate if (serial != ks->keysock_serial && 1962*0Sstevel@tonic-gate !toall && 1963*0Sstevel@tonic-gate !(ks->keysock_flags & KEYSOCK_PROMISC) && 1964*0Sstevel@tonic-gate !((ks->keysock_flags & KEYSOCK_EXTENDED) ? 1965*0Sstevel@tonic-gate allereg : allreg && kc != NULL && 1966*0Sstevel@tonic-gate KEYSOCK_ISREG(ks, kc->kc_sa_type))) 1967*0Sstevel@tonic-gate continue; 1968*0Sstevel@tonic-gate 1969*0Sstevel@tonic-gate mp1 = dupmsg(mp); 1970*0Sstevel@tonic-gate if (mp1 == NULL) { 1971*0Sstevel@tonic-gate ks2dbg(( 1972*0Sstevel@tonic-gate "keysock_passup(): dupmsg() failed.\n")); 1973*0Sstevel@tonic-gate mp1 = mp; 1974*0Sstevel@tonic-gate mp = NULL; 1975*0Sstevel@tonic-gate err = ENOMEM; 1976*0Sstevel@tonic-gate } 1977*0Sstevel@tonic-gate 1978*0Sstevel@tonic-gate /* 1979*0Sstevel@tonic-gate * At this point, we can deliver or attempt to deliver 1980*0Sstevel@tonic-gate * this message. We're free of obligation to report 1981*0Sstevel@tonic-gate * no listening PF_KEY sockets. So set err to 0. 1982*0Sstevel@tonic-gate */ 1983*0Sstevel@tonic-gate err = 0; 1984*0Sstevel@tonic-gate 1985*0Sstevel@tonic-gate /* 1986*0Sstevel@tonic-gate * See if we canputnext(), as well as see if the message 1987*0Sstevel@tonic-gate * needs to be queued if we can't. 1988*0Sstevel@tonic-gate */ 1989*0Sstevel@tonic-gate if (!canputnext(ks->keysock_rq)) { 1990*0Sstevel@tonic-gate if (persistent) { 1991*0Sstevel@tonic-gate if (putq(ks->keysock_rq, mp1) == 0) { 1992*0Sstevel@tonic-gate ks1dbg(( 1993*0Sstevel@tonic-gate "keysock_passup: putq failed.\n")); 1994*0Sstevel@tonic-gate } else { 1995*0Sstevel@tonic-gate continue; 1996*0Sstevel@tonic-gate } 1997*0Sstevel@tonic-gate } 1998*0Sstevel@tonic-gate freemsg(mp1); 1999*0Sstevel@tonic-gate continue; 2000*0Sstevel@tonic-gate } 2001*0Sstevel@tonic-gate 2002*0Sstevel@tonic-gate ks3dbg(("Putting to serial %d.\n", ks->keysock_serial)); 2003*0Sstevel@tonic-gate /* 2004*0Sstevel@tonic-gate * Unlike the specific keysock instance case, this 2005*0Sstevel@tonic-gate * will only hit for listeners, so we will only 2006*0Sstevel@tonic-gate * putnext() if we can. 2007*0Sstevel@tonic-gate */ 2008*0Sstevel@tonic-gate putnext(ks->keysock_rq, mp1); 2009*0Sstevel@tonic-gate if (mp == NULL) 2010*0Sstevel@tonic-gate break; /* out of for loop. */ 2011*0Sstevel@tonic-gate } 2012*0Sstevel@tonic-gate mutex_exit(&keysock_list_lock); 2013*0Sstevel@tonic-gate 2014*0Sstevel@tonic-gate error: 2015*0Sstevel@tonic-gate if ((err != 0) && (kc != NULL)) { 2016*0Sstevel@tonic-gate /* 2017*0Sstevel@tonic-gate * Generate KEYSOCK_OUT_ERR for consumer. 2018*0Sstevel@tonic-gate * Basically, I send this back if I have not been able to 2019*0Sstevel@tonic-gate * transmit (for whatever reason) 2020*0Sstevel@tonic-gate */ 2021*0Sstevel@tonic-gate ks1dbg(("keysock_passup(): No registered of type %d.\n", 2022*0Sstevel@tonic-gate satype)); 2023*0Sstevel@tonic-gate if (mp != NULL) { 2024*0Sstevel@tonic-gate if (mp->b_datap->db_type == M_PROTO) { 2025*0Sstevel@tonic-gate mp1 = mp; 2026*0Sstevel@tonic-gate mp = mp->b_cont; 2027*0Sstevel@tonic-gate freeb(mp1); 2028*0Sstevel@tonic-gate } 2029*0Sstevel@tonic-gate /* 2030*0Sstevel@tonic-gate * Do a copymsg() because people who get 2031*0Sstevel@tonic-gate * KEYSOCK_OUT_ERR may alter the message contents. 2032*0Sstevel@tonic-gate */ 2033*0Sstevel@tonic-gate mp1 = copymsg(mp); 2034*0Sstevel@tonic-gate if (mp1 == NULL) { 2035*0Sstevel@tonic-gate ks2dbg(("keysock_passup: copymsg() failed.\n")); 2036*0Sstevel@tonic-gate mp1 = mp; 2037*0Sstevel@tonic-gate mp = NULL; 2038*0Sstevel@tonic-gate } 2039*0Sstevel@tonic-gate keysock_out_err(kc, err, mp1); 2040*0Sstevel@tonic-gate } 2041*0Sstevel@tonic-gate } 2042*0Sstevel@tonic-gate 2043*0Sstevel@tonic-gate /* 2044*0Sstevel@tonic-gate * XXX Blank the message somehow. This is difficult because we don't 2045*0Sstevel@tonic-gate * know at this point if the message has db_ref > 1, etc. 2046*0Sstevel@tonic-gate * 2047*0Sstevel@tonic-gate * Optimally, keysock messages containing actual keying material would 2048*0Sstevel@tonic-gate * be allocated with esballoc(), with a zeroing free function. 2049*0Sstevel@tonic-gate */ 2050*0Sstevel@tonic-gate if (mp != NULL) 2051*0Sstevel@tonic-gate freemsg(mp); 2052*0Sstevel@tonic-gate } 2053*0Sstevel@tonic-gate 2054*0Sstevel@tonic-gate /* 2055*0Sstevel@tonic-gate * Keysock's read service procedure is there only for PF_KEY reply 2056*0Sstevel@tonic-gate * messages that really need to reach the top. 2057*0Sstevel@tonic-gate */ 2058*0Sstevel@tonic-gate static void 2059*0Sstevel@tonic-gate keysock_rsrv(queue_t *q) 2060*0Sstevel@tonic-gate { 2061*0Sstevel@tonic-gate mblk_t *mp; 2062*0Sstevel@tonic-gate 2063*0Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 2064*0Sstevel@tonic-gate if (canputnext(q)) { 2065*0Sstevel@tonic-gate putnext(q, mp); 2066*0Sstevel@tonic-gate } else { 2067*0Sstevel@tonic-gate (void) putbq(q, mp); 2068*0Sstevel@tonic-gate return; 2069*0Sstevel@tonic-gate } 2070*0Sstevel@tonic-gate } 2071*0Sstevel@tonic-gate } 2072*0Sstevel@tonic-gate 2073*0Sstevel@tonic-gate /* 2074*0Sstevel@tonic-gate * The read procedure should only be invoked by a keysock consumer, like 2075*0Sstevel@tonic-gate * ESP, AH, etc. I should only see KEYSOCK_OUT and KEYSOCK_HELLO_ACK 2076*0Sstevel@tonic-gate * messages on my read queues. 2077*0Sstevel@tonic-gate */ 2078*0Sstevel@tonic-gate static void 2079*0Sstevel@tonic-gate keysock_rput(queue_t *q, mblk_t *mp) 2080*0Sstevel@tonic-gate { 2081*0Sstevel@tonic-gate keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr; 2082*0Sstevel@tonic-gate ipsec_info_t *ii; 2083*0Sstevel@tonic-gate keysock_hello_ack_t *ksa; 2084*0Sstevel@tonic-gate minor_t serial; 2085*0Sstevel@tonic-gate mblk_t *mp1; 2086*0Sstevel@tonic-gate sadb_msg_t *samsg; 2087*0Sstevel@tonic-gate 2088*0Sstevel@tonic-gate /* Make sure I'm a consumer instance. (i.e. something's below me) */ 2089*0Sstevel@tonic-gate ASSERT(WR(q)->q_next != NULL); 2090*0Sstevel@tonic-gate 2091*0Sstevel@tonic-gate if (mp->b_datap->db_type != M_CTL) { 2092*0Sstevel@tonic-gate /* 2093*0Sstevel@tonic-gate * Keysock should only see keysock consumer interface 2094*0Sstevel@tonic-gate * messages (see ipsec_info.h) on its read procedure. 2095*0Sstevel@tonic-gate * To be robust, however, putnext() up so the STREAM head can 2096*0Sstevel@tonic-gate * deal with it appropriately. 2097*0Sstevel@tonic-gate */ 2098*0Sstevel@tonic-gate ks1dbg(("Hmmm, a non M_CTL (%d, 0x%x) on keysock_rput.\n", 2099*0Sstevel@tonic-gate mp->b_datap->db_type, mp->b_datap->db_type)); 2100*0Sstevel@tonic-gate putnext(q, mp); 2101*0Sstevel@tonic-gate return; 2102*0Sstevel@tonic-gate } 2103*0Sstevel@tonic-gate 2104*0Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 2105*0Sstevel@tonic-gate 2106*0Sstevel@tonic-gate switch (ii->ipsec_info_type) { 2107*0Sstevel@tonic-gate case KEYSOCK_OUT: 2108*0Sstevel@tonic-gate /* 2109*0Sstevel@tonic-gate * A consumer needs to pass a response message or an ACQUIRE 2110*0Sstevel@tonic-gate * UP. I assume that the consumer has done the right 2111*0Sstevel@tonic-gate * thing w.r.t. message creation, etc. 2112*0Sstevel@tonic-gate */ 2113*0Sstevel@tonic-gate serial = ((keysock_out_t *)mp->b_rptr)->ks_out_serial; 2114*0Sstevel@tonic-gate mp1 = mp->b_cont; /* Get M_DATA portion. */ 2115*0Sstevel@tonic-gate freeb(mp); 2116*0Sstevel@tonic-gate samsg = (sadb_msg_t *)mp1->b_rptr; 2117*0Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_FLUSH || 2118*0Sstevel@tonic-gate (samsg->sadb_msg_type == SADB_DUMP && 2119*0Sstevel@tonic-gate samsg->sadb_msg_len == SADB_8TO64(sizeof (*samsg)))) { 2120*0Sstevel@tonic-gate /* 2121*0Sstevel@tonic-gate * If I'm an end-of-FLUSH or an end-of-DUMP marker... 2122*0Sstevel@tonic-gate */ 2123*0Sstevel@tonic-gate ASSERT(keysock_flushdump != 0); /* Am I flushing? */ 2124*0Sstevel@tonic-gate 2125*0Sstevel@tonic-gate mutex_enter(&kc->kc_lock); 2126*0Sstevel@tonic-gate kc->kc_flags &= ~KC_FLUSHING; 2127*0Sstevel@tonic-gate mutex_exit(&kc->kc_lock); 2128*0Sstevel@tonic-gate 2129*0Sstevel@tonic-gate if (samsg->sadb_msg_errno != 0) 2130*0Sstevel@tonic-gate keysock_flushdump_errno = samsg->sadb_msg_errno; 2131*0Sstevel@tonic-gate 2132*0Sstevel@tonic-gate /* 2133*0Sstevel@tonic-gate * Lower the atomic "flushing" count. If it's 2134*0Sstevel@tonic-gate * the last one, send up the end-of-{FLUSH,DUMP} to 2135*0Sstevel@tonic-gate * the appropriate PF_KEY socket. 2136*0Sstevel@tonic-gate */ 2137*0Sstevel@tonic-gate if (atomic_add_32_nv(&keysock_flushdump, -1) != 0) { 2138*0Sstevel@tonic-gate ks1dbg(("One flush/dump message back from %d," 2139*0Sstevel@tonic-gate " more to go.\n", samsg->sadb_msg_satype)); 2140*0Sstevel@tonic-gate freemsg(mp1); 2141*0Sstevel@tonic-gate return; 2142*0Sstevel@tonic-gate } 2143*0Sstevel@tonic-gate 2144*0Sstevel@tonic-gate samsg->sadb_msg_errno = 2145*0Sstevel@tonic-gate (uint8_t)keysock_flushdump_errno; 2146*0Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_DUMP) { 2147*0Sstevel@tonic-gate samsg->sadb_msg_seq = 0; 2148*0Sstevel@tonic-gate } 2149*0Sstevel@tonic-gate } 2150*0Sstevel@tonic-gate keysock_passup(mp1, samsg, serial, kc, 2151*0Sstevel@tonic-gate (samsg->sadb_msg_type == SADB_DUMP)); 2152*0Sstevel@tonic-gate return; 2153*0Sstevel@tonic-gate case KEYSOCK_HELLO_ACK: 2154*0Sstevel@tonic-gate /* Aha, now we can link in the consumer! */ 2155*0Sstevel@tonic-gate ksa = (keysock_hello_ack_t *)ii; 2156*0Sstevel@tonic-gate keysock_link_consumer(ksa->ks_hello_satype, kc); 2157*0Sstevel@tonic-gate freemsg(mp); 2158*0Sstevel@tonic-gate return; 2159*0Sstevel@tonic-gate default: 2160*0Sstevel@tonic-gate ks1dbg(("Hmmm, an IPsec info I'm not used to, 0x%x\n", 2161*0Sstevel@tonic-gate ii->ipsec_info_type)); 2162*0Sstevel@tonic-gate putnext(q, mp); 2163*0Sstevel@tonic-gate } 2164*0Sstevel@tonic-gate } 2165*0Sstevel@tonic-gate 2166*0Sstevel@tonic-gate /* 2167*0Sstevel@tonic-gate * So we can avoid external linking problems.... 2168*0Sstevel@tonic-gate */ 2169*0Sstevel@tonic-gate boolean_t 2170*0Sstevel@tonic-gate keysock_extended_reg(void) 2171*0Sstevel@tonic-gate { 2172*0Sstevel@tonic-gate return (keysock_num_extended != 0); 2173*0Sstevel@tonic-gate } 2174*0Sstevel@tonic-gate 2175*0Sstevel@tonic-gate uint32_t 2176*0Sstevel@tonic-gate keysock_next_seq(void) 2177*0Sstevel@tonic-gate { 2178*0Sstevel@tonic-gate return (atomic_add_32_nv(&keysock_acquire_seq, -1)); 2179*0Sstevel@tonic-gate } 2180