17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51dc8613eSdanmcd * Common Development and Distribution License (the "License"). 61dc8613eSdanmcd * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22b9c2bf66SDan McDonald * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/param.h> 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/stream.h> 297c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 307c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 317c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 327c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 33f4b3ec61Sdh155122 #include <sys/zone.h> 347c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 367c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 377c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 387c478bd9Sstevel@tonic-gate #include <sys/timod.h> 397c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 407c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 417c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 427c478bd9Sstevel@tonic-gate #include <sys/sunldi.h> 437c478bd9Sstevel@tonic-gate #include <sys/file.h> 447c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 457c478bd9Sstevel@tonic-gate #include <sys/debug.h> 467c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 477c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 487c478bd9Sstevel@tonic-gate #include <sys/proc.h> 497c478bd9Sstevel@tonic-gate #include <sys/suntpi.h> 507c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 517c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 527c478bd9Sstevel@tonic-gate #include <sys/policy.h> 53f4b3ec61Sdh155122 #include <sys/disp.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #include <sys/socket.h> 567c478bd9Sstevel@tonic-gate #include <netinet/in.h> 577c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #include <inet/common.h> 607c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 617c478bd9Sstevel@tonic-gate #include <inet/ip.h> 620f1702c5SYu Xiangning #include <inet/proto_set.h> 637c478bd9Sstevel@tonic-gate #include <inet/nd.h> 647c478bd9Sstevel@tonic-gate #include <inet/optcom.h> 657c478bd9Sstevel@tonic-gate #include <inet/ipsec_info.h> 667c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h> 677c478bd9Sstevel@tonic-gate #include <inet/keysock.h> 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * This is a transport provider for the PF_KEY key mangement socket. 737c478bd9Sstevel@tonic-gate * (See RFC 2367 for details.) 747c478bd9Sstevel@tonic-gate * Downstream messages are wrapped in a keysock consumer interface KEYSOCK_IN 757c478bd9Sstevel@tonic-gate * messages (see ipsec_info.h), and passed to the appropriate consumer. 767c478bd9Sstevel@tonic-gate * Upstream messages are generated for all open PF_KEY sockets, when 777c478bd9Sstevel@tonic-gate * appropriate, as well as the sender (as long as SO_USELOOPBACK is enabled) 787c478bd9Sstevel@tonic-gate * in reply to downstream messages. 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * Upstream messages must be created asynchronously for the following 817c478bd9Sstevel@tonic-gate * situations: 827c478bd9Sstevel@tonic-gate * 837c478bd9Sstevel@tonic-gate * 1.) A keysock consumer requires an SA, and there is currently none. 847c478bd9Sstevel@tonic-gate * 2.) An SA expires, either hard or soft lifetime. 857c478bd9Sstevel@tonic-gate * 3.) Other events a consumer deems fit. 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * The MT model of this is PERMOD, with shared put procedures. Two types of 887c478bd9Sstevel@tonic-gate * messages, SADB_FLUSH and SADB_DUMP, need to lock down the perimeter to send 897c478bd9Sstevel@tonic-gate * down the *multiple* messages they create. 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate static vmem_t *keysock_vmem; /* for minor numbers. */ 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate #define KEYSOCK_MAX_CONSUMERS 256 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages (from rts.c...) */ 977c478bd9Sstevel@tonic-gate static struct T_info_ack keysock_g_t_info_ack = { 987c478bd9Sstevel@tonic-gate T_INFO_ACK, 997c478bd9Sstevel@tonic-gate T_INFINITE, /* TSDU_size. Maximum size messages. */ 1007c478bd9Sstevel@tonic-gate T_INVALID, /* ETSDU_size. No expedited data. */ 1017c478bd9Sstevel@tonic-gate T_INVALID, /* CDATA_size. No connect data. */ 1027c478bd9Sstevel@tonic-gate T_INVALID, /* DDATA_size. No disconnect data. */ 1037c478bd9Sstevel@tonic-gate 0, /* ADDR_size. */ 1047c478bd9Sstevel@tonic-gate 0, /* OPT_size. No user-settable options */ 1057c478bd9Sstevel@tonic-gate 64 * 1024, /* TIDU_size. keysock allows maximum size messages. */ 1067c478bd9Sstevel@tonic-gate T_COTS, /* SERV_type. keysock supports connection oriented. */ 1077c478bd9Sstevel@tonic-gate TS_UNBND, /* CURRENT_state. This is set from keysock_state. */ 1087c478bd9Sstevel@tonic-gate (XPG4_1) /* Provider flags */ 1097c478bd9Sstevel@tonic-gate }; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* Named Dispatch Parameter Management Structure */ 112f4b3ec61Sdh155122 typedef struct keysockparam_s { 1137c478bd9Sstevel@tonic-gate uint_t keysock_param_min; 1147c478bd9Sstevel@tonic-gate uint_t keysock_param_max; 1157c478bd9Sstevel@tonic-gate uint_t keysock_param_value; 1167c478bd9Sstevel@tonic-gate char *keysock_param_name; 1177c478bd9Sstevel@tonic-gate } keysockparam_t; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * Table of NDD variables supported by keysock. These are loaded into 1217c478bd9Sstevel@tonic-gate * keysock_g_nd in keysock_init_nd. 1227c478bd9Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 1237c478bd9Sstevel@tonic-gate */ 124f4b3ec61Sdh155122 static keysockparam_t lcl_param_arr[] = { 1257c478bd9Sstevel@tonic-gate /* min max value name */ 1267c478bd9Sstevel@tonic-gate { 4096, 65536, 8192, "keysock_xmit_hiwat"}, 1277c478bd9Sstevel@tonic-gate { 0, 65536, 1024, "keysock_xmit_lowat"}, 1287c478bd9Sstevel@tonic-gate { 4096, 65536, 8192, "keysock_recv_hiwat"}, 1297c478bd9Sstevel@tonic-gate { 65536, 1024*1024*1024, 256*1024, "keysock_max_buf"}, 1307c478bd9Sstevel@tonic-gate { 0, 3, 0, "keysock_debug"}, 1317c478bd9Sstevel@tonic-gate }; 132f4b3ec61Sdh155122 #define keystack_xmit_hiwat keystack_params[0].keysock_param_value 133f4b3ec61Sdh155122 #define keystack_xmit_lowat keystack_params[1].keysock_param_value 134f4b3ec61Sdh155122 #define keystack_recv_hiwat keystack_params[2].keysock_param_value 135f4b3ec61Sdh155122 #define keystack_max_buf keystack_params[3].keysock_param_value 136f4b3ec61Sdh155122 #define keystack_debug keystack_params[4].keysock_param_value 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate #define ks0dbg(a) printf a 1397c478bd9Sstevel@tonic-gate /* NOTE: != 0 instead of > 0 so lint doesn't complain. */ 140f4b3ec61Sdh155122 #define ks1dbg(keystack, a) if (keystack->keystack_debug != 0) printf a 141f4b3ec61Sdh155122 #define ks2dbg(keystack, a) if (keystack->keystack_debug > 1) printf a 142f4b3ec61Sdh155122 #define ks3dbg(keystack, a) if (keystack->keystack_debug > 2) printf a 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate static int keysock_close(queue_t *); 1457c478bd9Sstevel@tonic-gate static int keysock_open(queue_t *, dev_t *, int, int, cred_t *); 1467c478bd9Sstevel@tonic-gate static void keysock_wput(queue_t *, mblk_t *); 1477c478bd9Sstevel@tonic-gate static void keysock_rput(queue_t *, mblk_t *); 1487c478bd9Sstevel@tonic-gate static void keysock_rsrv(queue_t *); 1497c478bd9Sstevel@tonic-gate static void keysock_passup(mblk_t *, sadb_msg_t *, minor_t, 150f4b3ec61Sdh155122 keysock_consumer_t *, boolean_t, keysock_stack_t *); 151f4b3ec61Sdh155122 static void *keysock_stack_init(netstackid_t stackid, netstack_t *ns); 152f4b3ec61Sdh155122 static void keysock_stack_fini(netstackid_t stackid, void *arg); 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate static struct module_info info = { 1557c478bd9Sstevel@tonic-gate 5138, "keysock", 1, INFPSZ, 512, 128 1567c478bd9Sstevel@tonic-gate }; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate static struct qinit rinit = { 1597c478bd9Sstevel@tonic-gate (pfi_t)keysock_rput, (pfi_t)keysock_rsrv, keysock_open, keysock_close, 1607c478bd9Sstevel@tonic-gate NULL, &info 1617c478bd9Sstevel@tonic-gate }; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate static struct qinit winit = { 1647c478bd9Sstevel@tonic-gate (pfi_t)keysock_wput, NULL, NULL, NULL, NULL, &info 1657c478bd9Sstevel@tonic-gate }; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate struct streamtab keysockinfo = { 1687c478bd9Sstevel@tonic-gate &rinit, &winit 1697c478bd9Sstevel@tonic-gate }; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate extern struct modlinkage *keysock_modlp; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * Plumb IPsec. 1757c478bd9Sstevel@tonic-gate * 1767c478bd9Sstevel@tonic-gate * NOTE: New "default" modules will need to be loaded here if needed before 1777c478bd9Sstevel@tonic-gate * boot time. 1787c478bd9Sstevel@tonic-gate */ 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* Keep these in global space to keep the lint from complaining. */ 1817c478bd9Sstevel@tonic-gate static char *IPSECESP = "ipsecesp"; 1827c478bd9Sstevel@tonic-gate static char *IPSECESPDEV = "/devices/pseudo/ipsecesp@0:ipsecesp"; 1837c478bd9Sstevel@tonic-gate static char *IPSECAH = "ipsecah"; 1847c478bd9Sstevel@tonic-gate static char *IPSECAHDEV = "/devices/pseudo/ipsecah@0:ipsecah"; 1857c478bd9Sstevel@tonic-gate static char *IP6DEV = "/devices/pseudo/ip6@0:ip6"; 1867c478bd9Sstevel@tonic-gate static char *KEYSOCK = "keysock"; 1877c478bd9Sstevel@tonic-gate static char *STRMOD = "strmod"; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * Load the other ipsec modules and plumb them together. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate int 193f4b3ec61Sdh155122 keysock_plumb_ipsec(netstack_t *ns) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate ldi_handle_t lh, ip6_lh = NULL; 1967c478bd9Sstevel@tonic-gate ldi_ident_t li = NULL; 1977c478bd9Sstevel@tonic-gate int err = 0; 1987c478bd9Sstevel@tonic-gate int muxid, rval; 1997c478bd9Sstevel@tonic-gate boolean_t esp_present = B_TRUE; 200f4b3ec61Sdh155122 cred_t *cr; 201f4b3ec61Sdh155122 keysock_stack_t *keystack = ns->netstack_keysock; 2027c478bd9Sstevel@tonic-gate 203f4b3ec61Sdh155122 #ifdef NS_DEBUG 204f4b3ec61Sdh155122 (void) printf("keysock_plumb_ipsec(%d)\n", 205f4b3ec61Sdh155122 ns->netstack_stackid); 206f4b3ec61Sdh155122 #endif 2077c478bd9Sstevel@tonic-gate 208f4b3ec61Sdh155122 keystack->keystack_plumbed = 0; /* we're trying again.. */ 2097c478bd9Sstevel@tonic-gate 210f4b3ec61Sdh155122 cr = zone_get_kcred(netstackid_to_zoneid( 211f4b3ec61Sdh155122 keystack->keystack_netstack->netstack_stackid)); 212f4b3ec61Sdh155122 ASSERT(cr != NULL); 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * Load up the drivers (AH/ESP). 2157c478bd9Sstevel@tonic-gate * 2167c478bd9Sstevel@tonic-gate * I do this separately from the actual plumbing in case this function 2177c478bd9Sstevel@tonic-gate * ever gets called from a diskless boot before the root filesystem is 2187c478bd9Sstevel@tonic-gate * up. I don't have to worry about "keysock" because, well, if I'm 2197c478bd9Sstevel@tonic-gate * here, keysock must've loaded successfully. 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate if (i_ddi_attach_pseudo_node(IPSECAH) == NULL) { 2227c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: AH failed to attach.\n")); 2237c478bd9Sstevel@tonic-gate goto bail; 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate if (i_ddi_attach_pseudo_node(IPSECESP) == NULL) { 2267c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: ESP failed to attach.\n")); 2277c478bd9Sstevel@tonic-gate esp_present = B_FALSE; 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * Set up the IP streams for AH and ESP, as well as tacking keysock 2327c478bd9Sstevel@tonic-gate * on top of them. Assume keysock has set the autopushes up already. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* Open IP. */ 2367c478bd9Sstevel@tonic-gate err = ldi_ident_from_mod(keysock_modlp, &li); 2377c478bd9Sstevel@tonic-gate if (err) { 2387c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: lid_ident_from_mod failed (err %d).\n", 2397c478bd9Sstevel@tonic-gate err)); 2407c478bd9Sstevel@tonic-gate goto bail; 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 243f4b3ec61Sdh155122 err = ldi_open_by_name(IP6DEV, FREAD|FWRITE, cr, &ip6_lh, li); 2447c478bd9Sstevel@tonic-gate if (err) { 2457c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: Open of IP6 failed (err %d).\n", err)); 2467c478bd9Sstevel@tonic-gate goto bail; 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* PLINK KEYSOCK/AH */ 250f4b3ec61Sdh155122 err = ldi_open_by_name(IPSECAHDEV, FREAD|FWRITE, cr, &lh, li); 2517c478bd9Sstevel@tonic-gate if (err) { 2527c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: Open of AH failed (err %d).\n", err)); 2537c478bd9Sstevel@tonic-gate goto bail; 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate err = ldi_ioctl(lh, 256f4b3ec61Sdh155122 I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, cr, &rval); 2577c478bd9Sstevel@tonic-gate if (err) { 2587c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: Push of KEYSOCK onto AH failed (err %d).\n", 2597c478bd9Sstevel@tonic-gate err)); 260f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2617c478bd9Sstevel@tonic-gate goto bail; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh, 264f4b3ec61Sdh155122 FREAD+FWRITE+FNOCTTY+FKIOCTL, cr, &muxid); 2657c478bd9Sstevel@tonic-gate if (err) { 2667c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: PLINK of KEYSOCK/AH failed (err %d).\n", err)); 267f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2687c478bd9Sstevel@tonic-gate goto bail; 2697c478bd9Sstevel@tonic-gate } 270f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* PLINK KEYSOCK/ESP */ 2737c478bd9Sstevel@tonic-gate if (esp_present) { 2747c478bd9Sstevel@tonic-gate err = ldi_open_by_name(IPSECESPDEV, 275f4b3ec61Sdh155122 FREAD|FWRITE, cr, &lh, li); 2767c478bd9Sstevel@tonic-gate if (err) { 2777c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: Open of ESP failed (err %d).\n", err)); 2787c478bd9Sstevel@tonic-gate goto bail; 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate err = ldi_ioctl(lh, 281f4b3ec61Sdh155122 I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, cr, &rval); 2827c478bd9Sstevel@tonic-gate if (err) { 2837c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: " 2847c478bd9Sstevel@tonic-gate "Push of KEYSOCK onto ESP failed (err %d).\n", 2857c478bd9Sstevel@tonic-gate err)); 286f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2877c478bd9Sstevel@tonic-gate goto bail; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh, 290f4b3ec61Sdh155122 FREAD+FWRITE+FNOCTTY+FKIOCTL, cr, &muxid); 2917c478bd9Sstevel@tonic-gate if (err) { 2927c478bd9Sstevel@tonic-gate ks0dbg(("IPsec: " 2937c478bd9Sstevel@tonic-gate "PLINK of KEYSOCK/ESP failed (err %d).\n", err)); 294f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2957c478bd9Sstevel@tonic-gate goto bail; 2967c478bd9Sstevel@tonic-gate } 297f4b3ec61Sdh155122 (void) ldi_close(lh, FREAD|FWRITE, cr); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate bail: 301f4b3ec61Sdh155122 keystack->keystack_plumbed = (err == 0) ? 1 : -1; 3027c478bd9Sstevel@tonic-gate if (ip6_lh != NULL) { 303f4b3ec61Sdh155122 (void) ldi_close(ip6_lh, FREAD|FWRITE, cr); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate if (li != NULL) 3067c478bd9Sstevel@tonic-gate ldi_ident_release(li); 307f4b3ec61Sdh155122 #ifdef NS_DEBUG 308f4b3ec61Sdh155122 (void) printf("keysock_plumb_ipsec -> %d\n", 309f4b3ec61Sdh155122 keystack->keystack_plumbed); 310f4b3ec61Sdh155122 #endif 311f4b3ec61Sdh155122 crfree(cr); 3127c478bd9Sstevel@tonic-gate return (err); 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3167c478bd9Sstevel@tonic-gate static int 3177c478bd9Sstevel@tonic-gate keysock_param_get(q, mp, cp, cr) 3187c478bd9Sstevel@tonic-gate queue_t *q; 3197c478bd9Sstevel@tonic-gate mblk_t *mp; 3207c478bd9Sstevel@tonic-gate caddr_t cp; 3217c478bd9Sstevel@tonic-gate cred_t *cr; 3227c478bd9Sstevel@tonic-gate { 3237c478bd9Sstevel@tonic-gate keysockparam_t *keysockpa = (keysockparam_t *)cp; 3247c478bd9Sstevel@tonic-gate uint_t value; 325f4b3ec61Sdh155122 keysock_t *ks = (keysock_t *)q->q_ptr; 326f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 3277c478bd9Sstevel@tonic-gate 328f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_param_lock); 3297c478bd9Sstevel@tonic-gate value = keysockpa->keysock_param_value; 330f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_param_lock); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", value); 3337c478bd9Sstevel@tonic-gate return (0); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* This routine sets an NDD variable in a keysockparam_t structure. */ 3377c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3387c478bd9Sstevel@tonic-gate static int 3397c478bd9Sstevel@tonic-gate keysock_param_set(q, mp, value, cp, cr) 3407c478bd9Sstevel@tonic-gate queue_t *q; 3417c478bd9Sstevel@tonic-gate mblk_t *mp; 3427c478bd9Sstevel@tonic-gate char *value; 3437c478bd9Sstevel@tonic-gate caddr_t cp; 3447c478bd9Sstevel@tonic-gate cred_t *cr; 3457c478bd9Sstevel@tonic-gate { 3467c478bd9Sstevel@tonic-gate ulong_t new_value; 3477c478bd9Sstevel@tonic-gate keysockparam_t *keysockpa = (keysockparam_t *)cp; 348f4b3ec61Sdh155122 keysock_t *ks = (keysock_t *)q->q_ptr; 349f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* Convert the value from a string into a long integer. */ 3527c478bd9Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0) 3537c478bd9Sstevel@tonic-gate return (EINVAL); 3547c478bd9Sstevel@tonic-gate 355f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_param_lock); 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * Fail the request if the new value does not lie within the 3587c478bd9Sstevel@tonic-gate * required bounds. 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate if (new_value < keysockpa->keysock_param_min || 3617c478bd9Sstevel@tonic-gate new_value > keysockpa->keysock_param_max) { 362f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_param_lock); 3637c478bd9Sstevel@tonic-gate return (EINVAL); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* Set the new value */ 3677c478bd9Sstevel@tonic-gate keysockpa->keysock_param_value = new_value; 368f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_param_lock); 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate return (0); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* 374f4b3ec61Sdh155122 * Initialize keysock at module load time 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate boolean_t 3777c478bd9Sstevel@tonic-gate keysock_ddi_init(void) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate keysock_max_optsize = optcom_max_optsize( 3807c478bd9Sstevel@tonic-gate keysock_opt_obj.odb_opt_des_arr, keysock_opt_obj.odb_opt_arr_cnt); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate keysock_vmem = vmem_create("keysock", (void *)1, MAXMIN, 1, 3837c478bd9Sstevel@tonic-gate NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER); 3847c478bd9Sstevel@tonic-gate 385f4b3ec61Sdh155122 /* 386f4b3ec61Sdh155122 * We want to be informed each time a stack is created or 387f4b3ec61Sdh155122 * destroyed in the kernel, so we can maintain the 388f4b3ec61Sdh155122 * set of keysock_stack_t's. 389f4b3ec61Sdh155122 */ 390f4b3ec61Sdh155122 netstack_register(NS_KEYSOCK, keysock_stack_init, NULL, 391f4b3ec61Sdh155122 keysock_stack_fini); 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate return (B_TRUE); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 397f4b3ec61Sdh155122 * Walk through the param array specified registering each element with the 398f4b3ec61Sdh155122 * named dispatch handler. 399f4b3ec61Sdh155122 */ 400f4b3ec61Sdh155122 static boolean_t 401f4b3ec61Sdh155122 keysock_param_register(IDP *ndp, keysockparam_t *ksp, int cnt) 402f4b3ec61Sdh155122 { 403f4b3ec61Sdh155122 for (; cnt-- > 0; ksp++) { 404f4b3ec61Sdh155122 if (ksp->keysock_param_name != NULL && 405f4b3ec61Sdh155122 ksp->keysock_param_name[0]) { 406f4b3ec61Sdh155122 if (!nd_load(ndp, 407f4b3ec61Sdh155122 ksp->keysock_param_name, 408f4b3ec61Sdh155122 keysock_param_get, keysock_param_set, 409f4b3ec61Sdh155122 (caddr_t)ksp)) { 410f4b3ec61Sdh155122 nd_free(ndp); 411f4b3ec61Sdh155122 return (B_FALSE); 412f4b3ec61Sdh155122 } 413f4b3ec61Sdh155122 } 414f4b3ec61Sdh155122 } 415f4b3ec61Sdh155122 return (B_TRUE); 416f4b3ec61Sdh155122 } 417f4b3ec61Sdh155122 418f4b3ec61Sdh155122 /* 419f4b3ec61Sdh155122 * Initialize keysock for one stack instance 420f4b3ec61Sdh155122 */ 421f4b3ec61Sdh155122 /* ARGSUSED */ 422f4b3ec61Sdh155122 static void * 423f4b3ec61Sdh155122 keysock_stack_init(netstackid_t stackid, netstack_t *ns) 424f4b3ec61Sdh155122 { 425f4b3ec61Sdh155122 keysock_stack_t *keystack; 426f4b3ec61Sdh155122 keysockparam_t *ksp; 427f4b3ec61Sdh155122 428f4b3ec61Sdh155122 keystack = (keysock_stack_t *)kmem_zalloc(sizeof (*keystack), KM_SLEEP); 429f4b3ec61Sdh155122 keystack->keystack_netstack = ns; 430f4b3ec61Sdh155122 431f4b3ec61Sdh155122 keystack->keystack_acquire_seq = 0xffffffff; 432f4b3ec61Sdh155122 433f4b3ec61Sdh155122 ksp = (keysockparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP); 434f4b3ec61Sdh155122 keystack->keystack_params = ksp; 435f4b3ec61Sdh155122 bcopy(lcl_param_arr, ksp, sizeof (lcl_param_arr)); 436f4b3ec61Sdh155122 437f4b3ec61Sdh155122 (void) keysock_param_register(&keystack->keystack_g_nd, ksp, 438f4b3ec61Sdh155122 A_CNT(lcl_param_arr)); 439f4b3ec61Sdh155122 440f4b3ec61Sdh155122 mutex_init(&keystack->keystack_list_lock, NULL, MUTEX_DEFAULT, NULL); 441f4b3ec61Sdh155122 mutex_init(&keystack->keystack_consumers_lock, 442f4b3ec61Sdh155122 NULL, MUTEX_DEFAULT, NULL); 443f4b3ec61Sdh155122 mutex_init(&keystack->keystack_param_lock, NULL, MUTEX_DEFAULT, NULL); 444f4b3ec61Sdh155122 return (keystack); 445f4b3ec61Sdh155122 } 446f4b3ec61Sdh155122 447f4b3ec61Sdh155122 /* 4487c478bd9Sstevel@tonic-gate * Free NDD variable space, and other destructors, for keysock. 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate void 4517c478bd9Sstevel@tonic-gate keysock_ddi_destroy(void) 4527c478bd9Sstevel@tonic-gate { 453f4b3ec61Sdh155122 netstack_unregister(NS_KEYSOCK); 4547c478bd9Sstevel@tonic-gate vmem_destroy(keysock_vmem); 455f4b3ec61Sdh155122 } 456f4b3ec61Sdh155122 457f4b3ec61Sdh155122 /* 458f4b3ec61Sdh155122 * Remove one stack instance from keysock 459f4b3ec61Sdh155122 */ 460f4b3ec61Sdh155122 /* ARGSUSED */ 461f4b3ec61Sdh155122 static void 462f4b3ec61Sdh155122 keysock_stack_fini(netstackid_t stackid, void *arg) 463f4b3ec61Sdh155122 { 464f4b3ec61Sdh155122 keysock_stack_t *keystack = (keysock_stack_t *)arg; 465f4b3ec61Sdh155122 466f4b3ec61Sdh155122 nd_free(&keystack->keystack_g_nd); 467f4b3ec61Sdh155122 kmem_free(keystack->keystack_params, sizeof (lcl_param_arr)); 468f4b3ec61Sdh155122 keystack->keystack_params = NULL; 469f4b3ec61Sdh155122 470f4b3ec61Sdh155122 mutex_destroy(&keystack->keystack_list_lock); 471f4b3ec61Sdh155122 mutex_destroy(&keystack->keystack_consumers_lock); 472f4b3ec61Sdh155122 mutex_destroy(&keystack->keystack_param_lock); 473f4b3ec61Sdh155122 474f4b3ec61Sdh155122 kmem_free(keystack, sizeof (*keystack)); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * Close routine for keysock. 4797c478bd9Sstevel@tonic-gate */ 4807c478bd9Sstevel@tonic-gate static int 4817c478bd9Sstevel@tonic-gate keysock_close(queue_t *q) 4827c478bd9Sstevel@tonic-gate { 4837c478bd9Sstevel@tonic-gate keysock_t *ks; 4847c478bd9Sstevel@tonic-gate keysock_consumer_t *kc; 4857c478bd9Sstevel@tonic-gate void *ptr = q->q_ptr; 4867c478bd9Sstevel@tonic-gate int size; 487f4b3ec61Sdh155122 keysock_stack_t *keystack; 488f4b3ec61Sdh155122 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate qprocsoff(q); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate /* Safe assumption. */ 4937c478bd9Sstevel@tonic-gate ASSERT(ptr != NULL); 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate if (WR(q)->q_next) { 4967c478bd9Sstevel@tonic-gate kc = (keysock_consumer_t *)ptr; 497f4b3ec61Sdh155122 keystack = kc->kc_keystack; 498f4b3ec61Sdh155122 499f4b3ec61Sdh155122 ks1dbg(keystack, ("Module close, removing a consumer (%d).\n", 5007c478bd9Sstevel@tonic-gate kc->kc_sa_type)); 5017c478bd9Sstevel@tonic-gate /* 5027c478bd9Sstevel@tonic-gate * Because of PERMOD open/close exclusive perimeter, I 5037c478bd9Sstevel@tonic-gate * can inspect KC_FLUSHING w/o locking down kc->kc_lock. 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate if (kc->kc_flags & KC_FLUSHING) { 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * If this decrement was the last one, send 5087c478bd9Sstevel@tonic-gate * down the next pending one, if any. 5097c478bd9Sstevel@tonic-gate * 5107c478bd9Sstevel@tonic-gate * With a PERMOD perimeter, the mutexes ops aren't 5117c478bd9Sstevel@tonic-gate * really necessary, but if we ever loosen up, we will 5127c478bd9Sstevel@tonic-gate * have this bit covered already. 5137c478bd9Sstevel@tonic-gate */ 514f4b3ec61Sdh155122 keystack->keystack_flushdump--; 515f4b3ec61Sdh155122 if (keystack->keystack_flushdump == 0) { 5167c478bd9Sstevel@tonic-gate /* 5177c478bd9Sstevel@tonic-gate * The flush/dump terminated by having a 5187c478bd9Sstevel@tonic-gate * consumer go away. I need to send up to the 5197c478bd9Sstevel@tonic-gate * appropriate keysock all of the relevant 5207c478bd9Sstevel@tonic-gate * information. Unfortunately, I don't 5217c478bd9Sstevel@tonic-gate * have that handy. 5227c478bd9Sstevel@tonic-gate */ 5237c478bd9Sstevel@tonic-gate ks0dbg(("Consumer went away while flushing or" 5247c478bd9Sstevel@tonic-gate " dumping.\n")); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate size = sizeof (keysock_consumer_t); 528f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_consumers_lock); 529f4b3ec61Sdh155122 keystack->keystack_consumers[kc->kc_sa_type] = NULL; 530f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 5317c478bd9Sstevel@tonic-gate mutex_destroy(&kc->kc_lock); 532f4b3ec61Sdh155122 netstack_rele(kc->kc_keystack->keystack_netstack); 5337c478bd9Sstevel@tonic-gate } else { 5347c478bd9Sstevel@tonic-gate ks = (keysock_t *)ptr; 535f4b3ec61Sdh155122 keystack = ks->keysock_keystack; 536f4b3ec61Sdh155122 537f4b3ec61Sdh155122 ks3dbg(keystack, 538f4b3ec61Sdh155122 ("Driver close, PF_KEY socket is going away.\n")); 5397c478bd9Sstevel@tonic-gate if ((ks->keysock_flags & KEYSOCK_EXTENDED) != 0) 540*1a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&keystack->keystack_num_extended); 5417c478bd9Sstevel@tonic-gate size = sizeof (keysock_t); 542f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_list_lock); 5437c478bd9Sstevel@tonic-gate *(ks->keysock_ptpn) = ks->keysock_next; 5447c478bd9Sstevel@tonic-gate if (ks->keysock_next != NULL) 5457c478bd9Sstevel@tonic-gate ks->keysock_next->keysock_ptpn = ks->keysock_ptpn; 546f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_list_lock); 5477c478bd9Sstevel@tonic-gate mutex_destroy(&ks->keysock_lock); 5481dc8613eSdanmcd vmem_free(keysock_vmem, (void *)(uintptr_t)ks->keysock_serial, 5491dc8613eSdanmcd 1); 550f4b3ec61Sdh155122 netstack_rele(ks->keysock_keystack->keystack_netstack); 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate /* Now I'm free. */ 5547c478bd9Sstevel@tonic-gate kmem_free(ptr, size); 5557c478bd9Sstevel@tonic-gate return (0); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate /* 5587c478bd9Sstevel@tonic-gate * Open routine for keysock. 5597c478bd9Sstevel@tonic-gate */ 5607c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5617c478bd9Sstevel@tonic-gate static int 5627c478bd9Sstevel@tonic-gate keysock_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 5637c478bd9Sstevel@tonic-gate { 5647c478bd9Sstevel@tonic-gate keysock_t *ks; 5657c478bd9Sstevel@tonic-gate keysock_consumer_t *kc; 5667c478bd9Sstevel@tonic-gate mblk_t *mp; 5677c478bd9Sstevel@tonic-gate ipsec_info_t *ii; 568f4b3ec61Sdh155122 netstack_t *ns; 569f4b3ec61Sdh155122 keysock_stack_t *keystack; 5707c478bd9Sstevel@tonic-gate 571f4b3ec61Sdh155122 if (secpolicy_ip_config(credp, B_FALSE) != 0) { 5727c478bd9Sstevel@tonic-gate /* Privilege debugging will log the error */ 5737c478bd9Sstevel@tonic-gate return (EPERM); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate if (q->q_ptr != NULL) 5777c478bd9Sstevel@tonic-gate return (0); /* Re-open of an already open instance. */ 5787c478bd9Sstevel@tonic-gate 579f4b3ec61Sdh155122 ns = netstack_find_by_cred(credp); 580f4b3ec61Sdh155122 ASSERT(ns != NULL); 581f4b3ec61Sdh155122 keystack = ns->netstack_keysock; 582f4b3ec61Sdh155122 ASSERT(keystack != NULL); 583f4b3ec61Sdh155122 584f4b3ec61Sdh155122 ks3dbg(keystack, ("Entering keysock open.\n")); 585f4b3ec61Sdh155122 586f4b3ec61Sdh155122 if (keystack->keystack_plumbed < 1) { 587f4b3ec61Sdh155122 netstack_t *ns = keystack->keystack_netstack; 588f4b3ec61Sdh155122 589f4b3ec61Sdh155122 keystack->keystack_plumbed = 0; 590f4b3ec61Sdh155122 #ifdef NS_DEBUG 591f4b3ec61Sdh155122 printf("keysock_open(%d) - plumb\n", 592f4b3ec61Sdh155122 keystack->keystack_netstack->netstack_stackid); 593f4b3ec61Sdh155122 #endif 5947c478bd9Sstevel@tonic-gate /* 5957c478bd9Sstevel@tonic-gate * Don't worry about ipsec_failure being true here. 5967c478bd9Sstevel@tonic-gate * (See ip.c). An open of keysock should try and force 5977c478bd9Sstevel@tonic-gate * the issue. Maybe it was a transient failure. 5987c478bd9Sstevel@tonic-gate */ 599f4b3ec61Sdh155122 ipsec_loader_loadnow(ns->netstack_ipsec); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate if (sflag & MODOPEN) { 6037c478bd9Sstevel@tonic-gate /* Initialize keysock_consumer state here. */ 6047c478bd9Sstevel@tonic-gate kc = kmem_zalloc(sizeof (keysock_consumer_t), KM_NOSLEEP); 605f4b3ec61Sdh155122 if (kc == NULL) { 606f4b3ec61Sdh155122 netstack_rele(keystack->keystack_netstack); 6077c478bd9Sstevel@tonic-gate return (ENOMEM); 608f4b3ec61Sdh155122 } 6097c478bd9Sstevel@tonic-gate mutex_init(&kc->kc_lock, NULL, MUTEX_DEFAULT, 0); 6107c478bd9Sstevel@tonic-gate kc->kc_rq = q; 6117c478bd9Sstevel@tonic-gate kc->kc_wq = WR(q); 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate q->q_ptr = kc; 6147c478bd9Sstevel@tonic-gate WR(q)->q_ptr = kc; 6157c478bd9Sstevel@tonic-gate 616f4b3ec61Sdh155122 kc->kc_keystack = keystack; 6177c478bd9Sstevel@tonic-gate qprocson(q); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate /* 6207c478bd9Sstevel@tonic-gate * Send down initial message to whatever I was pushed on top 6217c478bd9Sstevel@tonic-gate * of asking for its consumer type. The reply will set it. 6227c478bd9Sstevel@tonic-gate */ 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* Allocate it. */ 6257c478bd9Sstevel@tonic-gate mp = allocb(sizeof (ipsec_info_t), BPRI_HI); 6267c478bd9Sstevel@tonic-gate if (mp == NULL) { 627f4b3ec61Sdh155122 ks1dbg(keystack, ( 6287c478bd9Sstevel@tonic-gate "keysock_open: Cannot allocate KEYSOCK_HELLO.\n")); 6297c478bd9Sstevel@tonic-gate /* Do I need to set these to null? */ 6307c478bd9Sstevel@tonic-gate q->q_ptr = NULL; 6317c478bd9Sstevel@tonic-gate WR(q)->q_ptr = NULL; 6327c478bd9Sstevel@tonic-gate mutex_destroy(&kc->kc_lock); 6337c478bd9Sstevel@tonic-gate kmem_free(kc, sizeof (*kc)); 634f4b3ec61Sdh155122 netstack_rele(keystack->keystack_netstack); 6357c478bd9Sstevel@tonic-gate return (ENOMEM); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* If I allocated okay, putnext to what I was pushed atop. */ 6397c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (ipsec_info_t); 6407c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_CTL; 6417c478bd9Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 6427c478bd9Sstevel@tonic-gate ii->ipsec_info_type = KEYSOCK_HELLO; 6437c478bd9Sstevel@tonic-gate /* Length only of type/len. */ 6447c478bd9Sstevel@tonic-gate ii->ipsec_info_len = sizeof (ii->ipsec_allu); 645f4b3ec61Sdh155122 ks2dbg(keystack, ("Ready to putnext KEYSOCK_HELLO.\n")); 6467c478bd9Sstevel@tonic-gate putnext(kc->kc_wq, mp); 6477c478bd9Sstevel@tonic-gate } else { 6487c478bd9Sstevel@tonic-gate minor_t ksminor; 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* Initialize keysock state. */ 6517c478bd9Sstevel@tonic-gate 652f4b3ec61Sdh155122 ks2dbg(keystack, ("Made it into PF_KEY socket open.\n")); 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate ksminor = (minor_t)(uintptr_t) 6557c478bd9Sstevel@tonic-gate vmem_alloc(keysock_vmem, 1, VM_NOSLEEP); 656f4b3ec61Sdh155122 if (ksminor == 0) { 657f4b3ec61Sdh155122 netstack_rele(keystack->keystack_netstack); 6587c478bd9Sstevel@tonic-gate return (ENOMEM); 659f4b3ec61Sdh155122 } 6607c478bd9Sstevel@tonic-gate ks = kmem_zalloc(sizeof (keysock_t), KM_NOSLEEP); 6617c478bd9Sstevel@tonic-gate if (ks == NULL) { 6627c478bd9Sstevel@tonic-gate vmem_free(keysock_vmem, (void *)(uintptr_t)ksminor, 1); 663f4b3ec61Sdh155122 netstack_rele(keystack->keystack_netstack); 6647c478bd9Sstevel@tonic-gate return (ENOMEM); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate mutex_init(&ks->keysock_lock, NULL, MUTEX_DEFAULT, 0); 6687c478bd9Sstevel@tonic-gate ks->keysock_rq = q; 6697c478bd9Sstevel@tonic-gate ks->keysock_wq = WR(q); 6707c478bd9Sstevel@tonic-gate ks->keysock_state = TS_UNBND; 6717c478bd9Sstevel@tonic-gate ks->keysock_serial = ksminor; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate q->q_ptr = ks; 6747c478bd9Sstevel@tonic-gate WR(q)->q_ptr = ks; 675f4b3ec61Sdh155122 ks->keysock_keystack = keystack; 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * The receive hiwat is only looked at on the stream head 6797c478bd9Sstevel@tonic-gate * queue. Store in q_hiwat in order to return on SO_RCVBUF 6807c478bd9Sstevel@tonic-gate * getsockopts. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate 683f4b3ec61Sdh155122 q->q_hiwat = keystack->keystack_recv_hiwat; 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate /* 6867c478bd9Sstevel@tonic-gate * The transmit hiwat/lowat is only looked at on IP's queue. 6877c478bd9Sstevel@tonic-gate * Store in q_hiwat/q_lowat in order to return on 6887c478bd9Sstevel@tonic-gate * SO_SNDBUF/SO_SNDLOWAT getsockopts. 6897c478bd9Sstevel@tonic-gate */ 6907c478bd9Sstevel@tonic-gate 691f4b3ec61Sdh155122 WR(q)->q_hiwat = keystack->keystack_xmit_hiwat; 692f4b3ec61Sdh155122 WR(q)->q_lowat = keystack->keystack_xmit_lowat; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), ksminor); 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* 6977c478bd9Sstevel@tonic-gate * Thread keysock into the global keysock list. 6987c478bd9Sstevel@tonic-gate */ 699f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_list_lock); 700f4b3ec61Sdh155122 ks->keysock_next = keystack->keystack_list; 701f4b3ec61Sdh155122 ks->keysock_ptpn = &keystack->keystack_list; 702f4b3ec61Sdh155122 if (keystack->keystack_list != NULL) { 703f4b3ec61Sdh155122 keystack->keystack_list->keysock_ptpn = 704f4b3ec61Sdh155122 &ks->keysock_next; 705f4b3ec61Sdh155122 } 706f4b3ec61Sdh155122 keystack->keystack_list = ks; 707f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_list_lock); 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate qprocson(q); 7100f1702c5SYu Xiangning (void) proto_set_rx_hiwat(q, NULL, 7110f1702c5SYu Xiangning keystack->keystack_recv_hiwat); 7127c478bd9Sstevel@tonic-gate /* 7137c478bd9Sstevel@tonic-gate * Wait outside the keysock module perimeter for IPsec 7147c478bd9Sstevel@tonic-gate * plumbing to be completed. If it fails, keysock_close() 7157c478bd9Sstevel@tonic-gate * undoes everything we just did. 7167c478bd9Sstevel@tonic-gate */ 717f4b3ec61Sdh155122 if (!ipsec_loader_wait(q, 718f4b3ec61Sdh155122 keystack->keystack_netstack->netstack_ipsec)) { 7197c478bd9Sstevel@tonic-gate (void) keysock_close(q); 7207c478bd9Sstevel@tonic-gate return (EPFNOSUPPORT); 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate return (0); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_wput(). */ 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* 7307c478bd9Sstevel@tonic-gate * Copy relevant state bits. 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate static void 7337c478bd9Sstevel@tonic-gate keysock_copy_info(struct T_info_ack *tap, keysock_t *ks) 7347c478bd9Sstevel@tonic-gate { 7357c478bd9Sstevel@tonic-gate *tap = keysock_g_t_info_ack; 7367c478bd9Sstevel@tonic-gate tap->CURRENT_state = ks->keysock_state; 7377c478bd9Sstevel@tonic-gate tap->OPT_size = keysock_max_optsize; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* 7417c478bd9Sstevel@tonic-gate * This routine responds to T_CAPABILITY_REQ messages. It is called by 7427c478bd9Sstevel@tonic-gate * keysock_wput. Much of the T_CAPABILITY_ACK information is copied from 7437c478bd9Sstevel@tonic-gate * keysock_g_t_info_ack. The current state of the stream is copied from 7447c478bd9Sstevel@tonic-gate * keysock_state. 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate static void 7477c478bd9Sstevel@tonic-gate keysock_capability_req(queue_t *q, mblk_t *mp) 7487c478bd9Sstevel@tonic-gate { 7497c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 7507c478bd9Sstevel@tonic-gate t_uscalar_t cap_bits1; 7517c478bd9Sstevel@tonic-gate struct T_capability_ack *tcap; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1; 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack), 7567c478bd9Sstevel@tonic-gate mp->b_datap->db_type, T_CAPABILITY_ACK); 7577c478bd9Sstevel@tonic-gate if (mp == NULL) 7587c478bd9Sstevel@tonic-gate return; 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate tcap = (struct T_capability_ack *)mp->b_rptr; 7617c478bd9Sstevel@tonic-gate tcap->CAP_bits1 = 0; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 7647c478bd9Sstevel@tonic-gate keysock_copy_info(&tcap->INFO_ack, ks); 7657c478bd9Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_INFO; 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate qreply(q, mp); 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* 7727c478bd9Sstevel@tonic-gate * This routine responds to T_INFO_REQ messages. It is called by 7737c478bd9Sstevel@tonic-gate * keysock_wput_other. 7747c478bd9Sstevel@tonic-gate * Most of the T_INFO_ACK information is copied from keysock_g_t_info_ack. 7757c478bd9Sstevel@tonic-gate * The current state of the stream is copied from keysock_state. 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate static void 7787c478bd9Sstevel@tonic-gate keysock_info_req(q, mp) 7797c478bd9Sstevel@tonic-gate queue_t *q; 7807c478bd9Sstevel@tonic-gate mblk_t *mp; 7817c478bd9Sstevel@tonic-gate { 7827c478bd9Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO, 7837c478bd9Sstevel@tonic-gate T_INFO_ACK); 7847c478bd9Sstevel@tonic-gate if (mp == NULL) 7857c478bd9Sstevel@tonic-gate return; 7867c478bd9Sstevel@tonic-gate keysock_copy_info((struct T_info_ack *)mp->b_rptr, 7877c478bd9Sstevel@tonic-gate (keysock_t *)q->q_ptr); 7887c478bd9Sstevel@tonic-gate qreply(q, mp); 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * keysock_err_ack. This routine creates a 7937c478bd9Sstevel@tonic-gate * T_ERROR_ACK message and passes it 7947c478bd9Sstevel@tonic-gate * upstream. 7957c478bd9Sstevel@tonic-gate */ 7967c478bd9Sstevel@tonic-gate static void 7977c478bd9Sstevel@tonic-gate keysock_err_ack(q, mp, t_error, sys_error) 7987c478bd9Sstevel@tonic-gate queue_t *q; 7997c478bd9Sstevel@tonic-gate mblk_t *mp; 8007c478bd9Sstevel@tonic-gate int t_error; 8017c478bd9Sstevel@tonic-gate int sys_error; 8027c478bd9Sstevel@tonic-gate { 8037c478bd9Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) 8047c478bd9Sstevel@tonic-gate qreply(q, mp); 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate /* 8087c478bd9Sstevel@tonic-gate * This routine retrieves the current status of socket options. 8097c478bd9Sstevel@tonic-gate * It returns the size of the option retrieved. 8107c478bd9Sstevel@tonic-gate */ 8117c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8127c478bd9Sstevel@tonic-gate int 8137c478bd9Sstevel@tonic-gate keysock_opt_get(queue_t *q, int level, int name, uchar_t *ptr) 8147c478bd9Sstevel@tonic-gate { 8157c478bd9Sstevel@tonic-gate int *i1 = (int *)ptr; 8167c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate switch (level) { 8197c478bd9Sstevel@tonic-gate case SOL_SOCKET: 8207c478bd9Sstevel@tonic-gate mutex_enter(&ks->keysock_lock); 8217c478bd9Sstevel@tonic-gate switch (name) { 8227c478bd9Sstevel@tonic-gate case SO_TYPE: 8237c478bd9Sstevel@tonic-gate *i1 = SOCK_RAW; 8247c478bd9Sstevel@tonic-gate break; 8257c478bd9Sstevel@tonic-gate case SO_USELOOPBACK: 8267c478bd9Sstevel@tonic-gate *i1 = (int)(!((ks->keysock_flags & KEYSOCK_NOLOOP) == 8277c478bd9Sstevel@tonic-gate KEYSOCK_NOLOOP)); 8287c478bd9Sstevel@tonic-gate break; 8297c478bd9Sstevel@tonic-gate /* 8307c478bd9Sstevel@tonic-gate * The following two items can be manipulated, 8317c478bd9Sstevel@tonic-gate * but changing them should do nothing. 8327c478bd9Sstevel@tonic-gate */ 8337c478bd9Sstevel@tonic-gate case SO_SNDBUF: 8347c478bd9Sstevel@tonic-gate *i1 = (int)q->q_hiwat; 8357c478bd9Sstevel@tonic-gate break; 8367c478bd9Sstevel@tonic-gate case SO_RCVBUF: 8377c478bd9Sstevel@tonic-gate *i1 = (int)(RD(q)->q_hiwat); 8387c478bd9Sstevel@tonic-gate break; 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate mutex_exit(&ks->keysock_lock); 8417c478bd9Sstevel@tonic-gate break; 8427c478bd9Sstevel@tonic-gate default: 8437c478bd9Sstevel@tonic-gate return (0); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate return (sizeof (int)); 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate /* 8497c478bd9Sstevel@tonic-gate * This routine sets socket options. 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8527c478bd9Sstevel@tonic-gate int 8537c478bd9Sstevel@tonic-gate keysock_opt_set(queue_t *q, uint_t mgmt_flags, int level, 8547c478bd9Sstevel@tonic-gate int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp, 855bd670b35SErik Nordmark uchar_t *outvalp, void *thisdg_attrs, cred_t *cr) 8567c478bd9Sstevel@tonic-gate { 857b9c2bf66SDan McDonald int *i1 = (int *)invalp, errno = 0; 8587c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 859f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate switch (level) { 8627c478bd9Sstevel@tonic-gate case SOL_SOCKET: 8637c478bd9Sstevel@tonic-gate mutex_enter(&ks->keysock_lock); 8647c478bd9Sstevel@tonic-gate switch (name) { 8657c478bd9Sstevel@tonic-gate case SO_USELOOPBACK: 8667c478bd9Sstevel@tonic-gate if (!(*i1)) 8677c478bd9Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_NOLOOP; 8687c478bd9Sstevel@tonic-gate else ks->keysock_flags &= ~KEYSOCK_NOLOOP; 8697c478bd9Sstevel@tonic-gate break; 8707c478bd9Sstevel@tonic-gate case SO_SNDBUF: 871f4b3ec61Sdh155122 if (*i1 > keystack->keystack_max_buf) 872b9c2bf66SDan McDonald errno = ENOBUFS; 873b9c2bf66SDan McDonald else q->q_hiwat = *i1; 8747c478bd9Sstevel@tonic-gate break; 8757c478bd9Sstevel@tonic-gate case SO_RCVBUF: 876b9c2bf66SDan McDonald if (*i1 > keystack->keystack_max_buf) { 877b9c2bf66SDan McDonald errno = ENOBUFS; 878b9c2bf66SDan McDonald } else { 8797c478bd9Sstevel@tonic-gate RD(q)->q_hiwat = *i1; 8800f1702c5SYu Xiangning (void) proto_set_rx_hiwat(RD(q), NULL, *i1); 881b9c2bf66SDan McDonald } 8827c478bd9Sstevel@tonic-gate break; 883b9c2bf66SDan McDonald default: 884b9c2bf66SDan McDonald errno = EINVAL; 8857c478bd9Sstevel@tonic-gate } 8867c478bd9Sstevel@tonic-gate mutex_exit(&ks->keysock_lock); 8877c478bd9Sstevel@tonic-gate break; 888b9c2bf66SDan McDonald default: 889b9c2bf66SDan McDonald errno = EINVAL; 8907c478bd9Sstevel@tonic-gate } 891b9c2bf66SDan McDonald return (errno); 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate /* 8957c478bd9Sstevel@tonic-gate * Handle STREAMS messages. 8967c478bd9Sstevel@tonic-gate */ 8977c478bd9Sstevel@tonic-gate static void 8987c478bd9Sstevel@tonic-gate keysock_wput_other(queue_t *q, mblk_t *mp) 8997c478bd9Sstevel@tonic-gate { 9007c478bd9Sstevel@tonic-gate struct iocblk *iocp; 9017c478bd9Sstevel@tonic-gate int error; 902f4b3ec61Sdh155122 keysock_t *ks = (keysock_t *)q->q_ptr; 903f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 904f4b3ec61Sdh155122 cred_t *cr; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 9077c478bd9Sstevel@tonic-gate case M_PROTO: 9087c478bd9Sstevel@tonic-gate case M_PCPROTO: 9097c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (long)) { 910f4b3ec61Sdh155122 ks3dbg(keystack, ( 9117c478bd9Sstevel@tonic-gate "keysock_wput_other: Not big enough M_PROTO\n")); 9127c478bd9Sstevel@tonic-gate freemsg(mp); 9137c478bd9Sstevel@tonic-gate return; 9147c478bd9Sstevel@tonic-gate } 9157c478bd9Sstevel@tonic-gate switch (((union T_primitives *)mp->b_rptr)->type) { 9167c478bd9Sstevel@tonic-gate case T_CAPABILITY_REQ: 9177c478bd9Sstevel@tonic-gate keysock_capability_req(q, mp); 918f4b3ec61Sdh155122 break; 9197c478bd9Sstevel@tonic-gate case T_INFO_REQ: 9207c478bd9Sstevel@tonic-gate keysock_info_req(q, mp); 921f4b3ec61Sdh155122 break; 9227c478bd9Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 9237c478bd9Sstevel@tonic-gate case T_OPTMGMT_REQ: 924de8c4a14SErik Nordmark /* 925de8c4a14SErik Nordmark * All Solaris components should pass a db_credp 926de8c4a14SErik Nordmark * for this TPI message, hence we ASSERT. 927de8c4a14SErik Nordmark * But in case there is some other M_PROTO that looks 928de8c4a14SErik Nordmark * like a TPI message sent by some other kernel 929de8c4a14SErik Nordmark * component, we check and return an error. 930de8c4a14SErik Nordmark */ 931de8c4a14SErik Nordmark cr = msg_getcred(mp, NULL); 932de8c4a14SErik Nordmark ASSERT(cr != NULL); 933de8c4a14SErik Nordmark if (cr == NULL) { 934de8c4a14SErik Nordmark keysock_err_ack(q, mp, TSYSERR, EINVAL); 935de8c4a14SErik Nordmark return; 936de8c4a14SErik Nordmark } 937de8c4a14SErik Nordmark if (((union T_primitives *)mp->b_rptr)->type == 938de8c4a14SErik Nordmark T_SVR4_OPTMGMT_REQ) { 939bd670b35SErik Nordmark svr4_optcom_req(q, mp, cr, &keysock_opt_obj); 940de8c4a14SErik Nordmark } else { 941bd670b35SErik Nordmark tpi_optcom_req(q, mp, cr, &keysock_opt_obj); 942de8c4a14SErik Nordmark } 943f4b3ec61Sdh155122 break; 9447c478bd9Sstevel@tonic-gate case T_DATA_REQ: 9457c478bd9Sstevel@tonic-gate case T_EXDATA_REQ: 9467c478bd9Sstevel@tonic-gate case T_ORDREL_REQ: 9477c478bd9Sstevel@tonic-gate /* Illegal for keysock. */ 9487c478bd9Sstevel@tonic-gate freemsg(mp); 9497c478bd9Sstevel@tonic-gate (void) putnextctl1(RD(q), M_ERROR, EPROTO); 950f4b3ec61Sdh155122 break; 9517c478bd9Sstevel@tonic-gate default: 9527c478bd9Sstevel@tonic-gate /* Not supported by keysock. */ 9537c478bd9Sstevel@tonic-gate keysock_err_ack(q, mp, TNOTSUPPORT, 0); 954f4b3ec61Sdh155122 break; 9557c478bd9Sstevel@tonic-gate } 956f4b3ec61Sdh155122 return; 9577c478bd9Sstevel@tonic-gate case M_IOCTL: 9587c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 9597c478bd9Sstevel@tonic-gate error = EINVAL; 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 9627c478bd9Sstevel@tonic-gate case ND_SET: 9637c478bd9Sstevel@tonic-gate case ND_GET: 964f4b3ec61Sdh155122 if (nd_getset(q, keystack->keystack_g_nd, mp)) { 9657c478bd9Sstevel@tonic-gate qreply(q, mp); 9667c478bd9Sstevel@tonic-gate return; 9677c478bd9Sstevel@tonic-gate } else 9687c478bd9Sstevel@tonic-gate error = ENOENT; 9697c478bd9Sstevel@tonic-gate /* FALLTHRU */ 9707c478bd9Sstevel@tonic-gate default: 9717c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error); 9727c478bd9Sstevel@tonic-gate return; 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate case M_FLUSH: 9757c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) { 9767c478bd9Sstevel@tonic-gate flushq(q, FLUSHALL); 9777c478bd9Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW; 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) { 9807c478bd9Sstevel@tonic-gate qreply(q, mp); 9817c478bd9Sstevel@tonic-gate return; 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate /* Else FALLTHRU */ 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate /* If fell through, just black-hole the message. */ 9877c478bd9Sstevel@tonic-gate freemsg(mp); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* 9917c478bd9Sstevel@tonic-gate * Transmit a PF_KEY error message to the instance either pointed to 9927c478bd9Sstevel@tonic-gate * by ks, the instance with serial number serial, or more, depending. 9937c478bd9Sstevel@tonic-gate * 9947c478bd9Sstevel@tonic-gate * The faulty message (or a reasonable facsimile thereof) is in mp. 9957c478bd9Sstevel@tonic-gate * This function will free mp or recycle it for delivery, thereby causing 9967c478bd9Sstevel@tonic-gate * the stream head to free it. 9977c478bd9Sstevel@tonic-gate */ 9987c478bd9Sstevel@tonic-gate static void 9997c478bd9Sstevel@tonic-gate keysock_error(keysock_t *ks, mblk_t *mp, int error, int diagnostic) 10007c478bd9Sstevel@tonic-gate { 10017c478bd9Sstevel@tonic-gate sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr; 1002f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_type == M_DATA); 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_type < SADB_GETSPI || 10077c478bd9Sstevel@tonic-gate samsg->sadb_msg_type > SADB_MAX) 10087c478bd9Sstevel@tonic-gate samsg->sadb_msg_type = SADB_RESERVED; 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate /* 10117c478bd9Sstevel@tonic-gate * Strip out extension headers. 10127c478bd9Sstevel@tonic-gate */ 10137c478bd9Sstevel@tonic-gate ASSERT(mp->b_rptr + sizeof (*samsg) <= mp->b_datap->db_lim); 10147c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (*samsg); 10157c478bd9Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (sadb_msg_t)); 10167c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)error; 10177c478bd9Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = (uint16_t)diagnostic; 10187c478bd9Sstevel@tonic-gate 1019f4b3ec61Sdh155122 keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE, keystack); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * Pass down a message to a consumer. Wrap it in KEYSOCK_IN, and copy 10247c478bd9Sstevel@tonic-gate * in the extv if passed in. 10257c478bd9Sstevel@tonic-gate */ 10267c478bd9Sstevel@tonic-gate static void 10277c478bd9Sstevel@tonic-gate keysock_passdown(keysock_t *ks, mblk_t *mp, uint8_t satype, sadb_ext_t *extv[], 10287c478bd9Sstevel@tonic-gate boolean_t flushmsg) 10297c478bd9Sstevel@tonic-gate { 10307c478bd9Sstevel@tonic-gate keysock_consumer_t *kc; 10317c478bd9Sstevel@tonic-gate mblk_t *wrapper; 10327c478bd9Sstevel@tonic-gate keysock_in_t *ksi; 10337c478bd9Sstevel@tonic-gate int i; 1034f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate wrapper = allocb(sizeof (ipsec_info_t), BPRI_HI); 10377c478bd9Sstevel@tonic-gate if (wrapper == NULL) { 1038f4b3ec61Sdh155122 ks3dbg(keystack, ("keysock_passdown: allocb failed.\n")); 10397c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_KEY_ENCRYPT] != NULL) 10407c478bd9Sstevel@tonic-gate bzero(extv[SADB_EXT_KEY_ENCRYPT], 10417c478bd9Sstevel@tonic-gate SADB_64TO8( 10427c478bd9Sstevel@tonic-gate extv[SADB_EXT_KEY_ENCRYPT]->sadb_ext_len)); 10437c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_KEY_AUTH] != NULL) 10447c478bd9Sstevel@tonic-gate bzero(extv[SADB_EXT_KEY_AUTH], 10457c478bd9Sstevel@tonic-gate SADB_64TO8( 10467c478bd9Sstevel@tonic-gate extv[SADB_EXT_KEY_AUTH]->sadb_ext_len)); 10477c478bd9Sstevel@tonic-gate if (flushmsg) { 10487c478bd9Sstevel@tonic-gate ks0dbg(( 10497c478bd9Sstevel@tonic-gate "keysock: Downwards flush/dump message failed!\n")); 10507c478bd9Sstevel@tonic-gate /* If this is true, I hold the perimeter. */ 1051f4b3ec61Sdh155122 keystack->keystack_flushdump--; 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate freemsg(mp); 10547c478bd9Sstevel@tonic-gate return; 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate wrapper->b_datap->db_type = M_CTL; 10587c478bd9Sstevel@tonic-gate ksi = (keysock_in_t *)wrapper->b_rptr; 10597c478bd9Sstevel@tonic-gate ksi->ks_in_type = KEYSOCK_IN; 10607c478bd9Sstevel@tonic-gate ksi->ks_in_len = sizeof (keysock_in_t); 10617c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_SRC] != NULL) 10627c478bd9Sstevel@tonic-gate ksi->ks_in_srctype = KS_IN_ADDR_UNKNOWN; 10637c478bd9Sstevel@tonic-gate else ksi->ks_in_srctype = KS_IN_ADDR_NOTTHERE; 10647c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_DST] != NULL) 10657c478bd9Sstevel@tonic-gate ksi->ks_in_dsttype = KS_IN_ADDR_UNKNOWN; 10667c478bd9Sstevel@tonic-gate else ksi->ks_in_dsttype = KS_IN_ADDR_NOTTHERE; 10677c478bd9Sstevel@tonic-gate for (i = 0; i <= SADB_EXT_MAX; i++) 10687c478bd9Sstevel@tonic-gate ksi->ks_in_extv[i] = extv[i]; 10697c478bd9Sstevel@tonic-gate ksi->ks_in_serial = ks->keysock_serial; 10707c478bd9Sstevel@tonic-gate wrapper->b_wptr += sizeof (ipsec_info_t); 10717c478bd9Sstevel@tonic-gate wrapper->b_cont = mp; 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate /* 10747c478bd9Sstevel@tonic-gate * Find the appropriate consumer where the message is passed down. 10757c478bd9Sstevel@tonic-gate */ 1076f4b3ec61Sdh155122 kc = keystack->keystack_consumers[satype]; 10777c478bd9Sstevel@tonic-gate if (kc == NULL) { 10787c478bd9Sstevel@tonic-gate freeb(wrapper); 10797c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE); 10807c478bd9Sstevel@tonic-gate if (flushmsg) { 10817c478bd9Sstevel@tonic-gate ks0dbg(( 10827c478bd9Sstevel@tonic-gate "keysock: Downwards flush/dump message failed!\n")); 10837c478bd9Sstevel@tonic-gate /* If this is true, I hold the perimeter. */ 1084f4b3ec61Sdh155122 keystack->keystack_flushdump--; 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate return; 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate /* 10907c478bd9Sstevel@tonic-gate * NOTE: There used to be code in here to spin while a flush or 10917c478bd9Sstevel@tonic-gate * dump finished. Keysock now assumes that consumers have enough 10927c478bd9Sstevel@tonic-gate * MT-savviness to deal with that. 10937c478bd9Sstevel@tonic-gate */ 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate /* 10967c478bd9Sstevel@tonic-gate * Current consumers (AH and ESP) are guaranteed to return a 10977c478bd9Sstevel@tonic-gate * FLUSH or DUMP message back, so when we reach here, we don't 10987c478bd9Sstevel@tonic-gate * have to worry about keysock_flushdumps. 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate putnext(kc->kc_wq, wrapper); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate /* 11057c478bd9Sstevel@tonic-gate * High-level reality checking of extensions. 11067c478bd9Sstevel@tonic-gate */ 11077c478bd9Sstevel@tonic-gate static boolean_t 1108f4b3ec61Sdh155122 ext_check(sadb_ext_t *ext, keysock_stack_t *keystack) 11097c478bd9Sstevel@tonic-gate { 11107c478bd9Sstevel@tonic-gate int i; 11117c478bd9Sstevel@tonic-gate uint64_t *lp; 11127c478bd9Sstevel@tonic-gate sadb_ident_t *id; 11137c478bd9Sstevel@tonic-gate char *idstr; 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate switch (ext->sadb_ext_type) { 11167c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC: 11177c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST: 11188810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC: 11198810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_DST: 11207c478bd9Sstevel@tonic-gate /* Check for at least enough addtl length for a sockaddr. */ 11217c478bd9Sstevel@tonic-gate if (ext->sadb_ext_len <= SADB_8TO64(sizeof (sadb_address_t))) 11227c478bd9Sstevel@tonic-gate return (B_FALSE); 11237c478bd9Sstevel@tonic-gate break; 11247c478bd9Sstevel@tonic-gate case SADB_EXT_LIFETIME_HARD: 11257c478bd9Sstevel@tonic-gate case SADB_EXT_LIFETIME_SOFT: 11267c478bd9Sstevel@tonic-gate case SADB_EXT_LIFETIME_CURRENT: 11277c478bd9Sstevel@tonic-gate if (ext->sadb_ext_len != SADB_8TO64(sizeof (sadb_lifetime_t))) 11287c478bd9Sstevel@tonic-gate return (B_FALSE); 11297c478bd9Sstevel@tonic-gate break; 11307c478bd9Sstevel@tonic-gate case SADB_EXT_SPIRANGE: 11317c478bd9Sstevel@tonic-gate /* See if the SPI range is legit. */ 11327c478bd9Sstevel@tonic-gate if (htonl(((sadb_spirange_t *)ext)->sadb_spirange_min) > 11337c478bd9Sstevel@tonic-gate htonl(((sadb_spirange_t *)ext)->sadb_spirange_max)) 11347c478bd9Sstevel@tonic-gate return (B_FALSE); 11357c478bd9Sstevel@tonic-gate break; 11367c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_AUTH: 11377c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT: 11387c478bd9Sstevel@tonic-gate /* Key length check. */ 11397c478bd9Sstevel@tonic-gate if (((sadb_key_t *)ext)->sadb_key_bits == 0) 11407c478bd9Sstevel@tonic-gate return (B_FALSE); 11417c478bd9Sstevel@tonic-gate /* 11427c478bd9Sstevel@tonic-gate * Check to see if the key length (in bits) is less than the 11437c478bd9Sstevel@tonic-gate * extension length (in 8-bits words). 11447c478bd9Sstevel@tonic-gate */ 11457c478bd9Sstevel@tonic-gate if ((roundup(SADB_1TO8(((sadb_key_t *)ext)->sadb_key_bits), 8) + 11467c478bd9Sstevel@tonic-gate sizeof (sadb_key_t)) != SADB_64TO8(ext->sadb_ext_len)) { 1147f4b3ec61Sdh155122 ks1dbg(keystack, ( 11487c478bd9Sstevel@tonic-gate "ext_check: Key bits/length inconsistent.\n")); 1149f4b3ec61Sdh155122 ks1dbg(keystack, ("%d bits, len is %d bytes.\n", 11507c478bd9Sstevel@tonic-gate ((sadb_key_t *)ext)->sadb_key_bits, 11517c478bd9Sstevel@tonic-gate SADB_64TO8(ext->sadb_ext_len))); 11527c478bd9Sstevel@tonic-gate return (B_FALSE); 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate /* All-zeroes key check. */ 11567c478bd9Sstevel@tonic-gate lp = (uint64_t *)(((char *)ext) + sizeof (sadb_key_t)); 11577c478bd9Sstevel@tonic-gate for (i = 0; 11587c478bd9Sstevel@tonic-gate i < (ext->sadb_ext_len - SADB_8TO64(sizeof (sadb_key_t))); 11597c478bd9Sstevel@tonic-gate i++) 11607c478bd9Sstevel@tonic-gate if (lp[i] != 0) 11617c478bd9Sstevel@tonic-gate break; /* Out of for loop. */ 11627c478bd9Sstevel@tonic-gate /* If finished the loop naturally, it's an all zero key. */ 11637c478bd9Sstevel@tonic-gate if (lp[i] == 0) 11647c478bd9Sstevel@tonic-gate return (B_FALSE); 11657c478bd9Sstevel@tonic-gate break; 11667c478bd9Sstevel@tonic-gate case SADB_EXT_IDENTITY_SRC: 11677c478bd9Sstevel@tonic-gate case SADB_EXT_IDENTITY_DST: 11687c478bd9Sstevel@tonic-gate /* 11697c478bd9Sstevel@tonic-gate * Make sure the strings in these identities are 11707c478bd9Sstevel@tonic-gate * null-terminated. RFC 2367 underspecified how to handle 11717c478bd9Sstevel@tonic-gate * such a case. I "proactively" null-terminate the string 11727c478bd9Sstevel@tonic-gate * at the last byte if it's not terminated sooner. 11737c478bd9Sstevel@tonic-gate */ 11747c478bd9Sstevel@tonic-gate id = (sadb_ident_t *)ext; 11757c478bd9Sstevel@tonic-gate i = SADB_64TO8(id->sadb_ident_len); 11767c478bd9Sstevel@tonic-gate i -= sizeof (sadb_ident_t); 11777c478bd9Sstevel@tonic-gate idstr = (char *)(id + 1); 11787c478bd9Sstevel@tonic-gate while (*idstr != '\0' && i > 0) { 11797c478bd9Sstevel@tonic-gate i--; 11807c478bd9Sstevel@tonic-gate idstr++; 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate if (i == 0) { 11837c478bd9Sstevel@tonic-gate /* 11847c478bd9Sstevel@tonic-gate * I.e., if the bozo user didn't NULL-terminate the 11857c478bd9Sstevel@tonic-gate * string... 11867c478bd9Sstevel@tonic-gate */ 11877c478bd9Sstevel@tonic-gate idstr--; 11887c478bd9Sstevel@tonic-gate *idstr = '\0'; 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate break; 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate return (B_TRUE); /* For now... */ 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate /* Return values for keysock_get_ext(). */ 11967c478bd9Sstevel@tonic-gate #define KGE_OK 0 11977c478bd9Sstevel@tonic-gate #define KGE_DUP 1 11987c478bd9Sstevel@tonic-gate #define KGE_UNK 2 11997c478bd9Sstevel@tonic-gate #define KGE_LEN 3 12007c478bd9Sstevel@tonic-gate #define KGE_CHK 4 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate /* 12037c478bd9Sstevel@tonic-gate * Parse basic extension headers and return in the passed-in pointer vector. 12047c478bd9Sstevel@tonic-gate * Return values include: 12057c478bd9Sstevel@tonic-gate * 12067c478bd9Sstevel@tonic-gate * KGE_OK Everything's nice and parsed out. 12077c478bd9Sstevel@tonic-gate * If there are no extensions, place NULL in extv[0]. 12087c478bd9Sstevel@tonic-gate * KGE_DUP There is a duplicate extension. 12097c478bd9Sstevel@tonic-gate * First instance in appropriate bin. First duplicate in 12107c478bd9Sstevel@tonic-gate * extv[0]. 12117c478bd9Sstevel@tonic-gate * KGE_UNK Unknown extension type encountered. extv[0] contains 12127c478bd9Sstevel@tonic-gate * unknown header. 12137c478bd9Sstevel@tonic-gate * KGE_LEN Extension length error. 12147c478bd9Sstevel@tonic-gate * KGE_CHK High-level reality check failed on specific extension. 12157c478bd9Sstevel@tonic-gate * 12167c478bd9Sstevel@tonic-gate * My apologies for some of the pointer arithmetic in here. I'm thinking 12177c478bd9Sstevel@tonic-gate * like an assembly programmer, yet trying to make the compiler happy. 12187c478bd9Sstevel@tonic-gate */ 12197c478bd9Sstevel@tonic-gate static int 1220f4b3ec61Sdh155122 keysock_get_ext(sadb_ext_t *extv[], sadb_msg_t *basehdr, uint_t msgsize, 1221f4b3ec61Sdh155122 keysock_stack_t *keystack) 12227c478bd9Sstevel@tonic-gate { 12237c478bd9Sstevel@tonic-gate bzero(extv, sizeof (sadb_ext_t *) * (SADB_EXT_MAX + 1)); 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate /* Use extv[0] as the "current working pointer". */ 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate extv[0] = (sadb_ext_t *)(basehdr + 1); 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate while (extv[0] < (sadb_ext_t *)(((uint8_t *)basehdr) + msgsize)) { 12307c478bd9Sstevel@tonic-gate /* Check for unknown headers. */ 12317c478bd9Sstevel@tonic-gate if (extv[0]->sadb_ext_type == 0 || 12327c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_type > SADB_EXT_MAX) 12337c478bd9Sstevel@tonic-gate return (KGE_UNK); 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate /* 12367c478bd9Sstevel@tonic-gate * Check length. Use uint64_t because extlen is in units 12377c478bd9Sstevel@tonic-gate * of 64-bit words. If length goes beyond the msgsize, 12387c478bd9Sstevel@tonic-gate * return an error. (Zero length also qualifies here.) 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate if (extv[0]->sadb_ext_len == 0 || 12417c478bd9Sstevel@tonic-gate (void *)((uint64_t *)extv[0] + extv[0]->sadb_ext_len) > 12427c478bd9Sstevel@tonic-gate (void *)((uint8_t *)basehdr + msgsize)) 12437c478bd9Sstevel@tonic-gate return (KGE_LEN); 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate /* Check for redundant headers. */ 12467c478bd9Sstevel@tonic-gate if (extv[extv[0]->sadb_ext_type] != NULL) 12477c478bd9Sstevel@tonic-gate return (KGE_DUP); 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate /* 12507c478bd9Sstevel@tonic-gate * Reality check the extension if possible at the keysock 12517c478bd9Sstevel@tonic-gate * level. 12527c478bd9Sstevel@tonic-gate */ 1253f4b3ec61Sdh155122 if (!ext_check(extv[0], keystack)) 12547c478bd9Sstevel@tonic-gate return (KGE_CHK); 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate /* If I make it here, assign the appropriate bin. */ 12577c478bd9Sstevel@tonic-gate extv[extv[0]->sadb_ext_type] = extv[0]; 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate /* Advance pointer (See above for uint64_t ptr reasoning.) */ 12607c478bd9Sstevel@tonic-gate extv[0] = (sadb_ext_t *) 12617c478bd9Sstevel@tonic-gate ((uint64_t *)extv[0] + extv[0]->sadb_ext_len); 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate /* Everything's cool. */ 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * If extv[0] == NULL, then there are no extension headers in this 12687c478bd9Sstevel@tonic-gate * message. Ensure that this is the case. 12697c478bd9Sstevel@tonic-gate */ 12707c478bd9Sstevel@tonic-gate if (extv[0] == (sadb_ext_t *)(basehdr + 1)) 12717c478bd9Sstevel@tonic-gate extv[0] = NULL; 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate return (KGE_OK); 12747c478bd9Sstevel@tonic-gate } 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate /* 12777c478bd9Sstevel@tonic-gate * qwriter() callback to handle flushes and dumps. This routine will hold 12787c478bd9Sstevel@tonic-gate * the inner perimeter. 12797c478bd9Sstevel@tonic-gate */ 12807c478bd9Sstevel@tonic-gate void 12817c478bd9Sstevel@tonic-gate keysock_do_flushdump(queue_t *q, mblk_t *mp) 12827c478bd9Sstevel@tonic-gate { 12837c478bd9Sstevel@tonic-gate int i, start, finish; 12847c478bd9Sstevel@tonic-gate mblk_t *mp1 = NULL; 12857c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 12867c478bd9Sstevel@tonic-gate sadb_ext_t *extv[SADB_EXT_MAX + 1]; 12877c478bd9Sstevel@tonic-gate sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr; 1288f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate /* 12917c478bd9Sstevel@tonic-gate * I am guaranteed this will work. I did the work in keysock_parse() 12927c478bd9Sstevel@tonic-gate * already. 12937c478bd9Sstevel@tonic-gate */ 1294f4b3ec61Sdh155122 (void) keysock_get_ext(extv, samsg, SADB_64TO8(samsg->sadb_msg_len), 1295f4b3ec61Sdh155122 keystack); 12967c478bd9Sstevel@tonic-gate 12977c478bd9Sstevel@tonic-gate /* 12987c478bd9Sstevel@tonic-gate * I hold the perimeter, therefore I don't need to use atomic ops. 12997c478bd9Sstevel@tonic-gate */ 1300f4b3ec61Sdh155122 if (keystack->keystack_flushdump != 0) { 13017c478bd9Sstevel@tonic-gate /* XXX Should I instead use EBUSY? */ 13027c478bd9Sstevel@tonic-gate /* XXX Or is there a way to queue these up? */ 13037c478bd9Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, SADB_X_DIAGNOSTIC_NONE); 13047c478bd9Sstevel@tonic-gate return; 13057c478bd9Sstevel@tonic-gate } 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 13087c478bd9Sstevel@tonic-gate start = 0; 13097c478bd9Sstevel@tonic-gate finish = KEYSOCK_MAX_CONSUMERS - 1; 13107c478bd9Sstevel@tonic-gate } else { 13117c478bd9Sstevel@tonic-gate start = samsg->sadb_msg_satype; 13127c478bd9Sstevel@tonic-gate finish = samsg->sadb_msg_satype; 13137c478bd9Sstevel@tonic-gate } 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate /* 13167c478bd9Sstevel@tonic-gate * Fill up keysock_flushdump with the number of outstanding dumps 13177c478bd9Sstevel@tonic-gate * and/or flushes. 13187c478bd9Sstevel@tonic-gate */ 13197c478bd9Sstevel@tonic-gate 1320f4b3ec61Sdh155122 keystack->keystack_flushdump_errno = 0; 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate /* 13237c478bd9Sstevel@tonic-gate * Okay, I hold the perimeter. Eventually keysock_flushdump will 13247c478bd9Sstevel@tonic-gate * contain the number of consumers with outstanding flush operations. 13257c478bd9Sstevel@tonic-gate * 13267c478bd9Sstevel@tonic-gate * SO, here's the plan: 13277c478bd9Sstevel@tonic-gate * * For each relevant consumer (Might be one, might be all) 13287c478bd9Sstevel@tonic-gate * * Twiddle on the FLUSHING flag. 13297c478bd9Sstevel@tonic-gate * * Pass down the FLUSH/DUMP message. 13307c478bd9Sstevel@tonic-gate * 13317c478bd9Sstevel@tonic-gate * When I see upbound FLUSH/DUMP messages, I will decrement the 13327c478bd9Sstevel@tonic-gate * keysock_flushdump. When I decrement it to 0, I will pass the 13337c478bd9Sstevel@tonic-gate * FLUSH/DUMP message back up to the PF_KEY sockets. Because I will 13347c478bd9Sstevel@tonic-gate * pass down the right SA type to the consumer (either its own, or 13357c478bd9Sstevel@tonic-gate * that of UNSPEC), the right one will be reflected from each consumer, 13367c478bd9Sstevel@tonic-gate * and accordingly back to the socket. 13377c478bd9Sstevel@tonic-gate */ 13387c478bd9Sstevel@tonic-gate 1339f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_consumers_lock); 13407c478bd9Sstevel@tonic-gate for (i = start; i <= finish; i++) { 1341f4b3ec61Sdh155122 if (keystack->keystack_consumers[i] != NULL) { 13427c478bd9Sstevel@tonic-gate mp1 = copymsg(mp); 13437c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 13447c478bd9Sstevel@tonic-gate ks0dbg(("SADB_FLUSH copymsg() failed.\n")); 13457c478bd9Sstevel@tonic-gate /* 13467c478bd9Sstevel@tonic-gate * Error? And what about outstanding 13477c478bd9Sstevel@tonic-gate * flushes? Oh, yeah, they get sucked up and 13487c478bd9Sstevel@tonic-gate * the counter is decremented. Consumers 13497c478bd9Sstevel@tonic-gate * (see keysock_passdown()) are guaranteed 13507c478bd9Sstevel@tonic-gate * to deliver back a flush request, even if 13517c478bd9Sstevel@tonic-gate * it's an error. 13527c478bd9Sstevel@tonic-gate */ 13537c478bd9Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, 13547c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_NONE); 13557c478bd9Sstevel@tonic-gate return; 13567c478bd9Sstevel@tonic-gate } 13577c478bd9Sstevel@tonic-gate /* 13587c478bd9Sstevel@tonic-gate * Because my entry conditions are met above, the 13597c478bd9Sstevel@tonic-gate * following assertion should hold true. 13607c478bd9Sstevel@tonic-gate */ 1361f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_consumers[i]->kc_lock); 1362f4b3ec61Sdh155122 ASSERT((keystack->keystack_consumers[i]->kc_flags & 1363f4b3ec61Sdh155122 KC_FLUSHING) == 0); 1364f4b3ec61Sdh155122 keystack->keystack_consumers[i]->kc_flags |= 1365f4b3ec61Sdh155122 KC_FLUSHING; 1366f4b3ec61Sdh155122 mutex_exit(&(keystack->keystack_consumers[i]->kc_lock)); 13677c478bd9Sstevel@tonic-gate /* Always increment the number of flushes... */ 1368f4b3ec61Sdh155122 keystack->keystack_flushdump++; 13697c478bd9Sstevel@tonic-gate /* Guaranteed to return a message. */ 13707c478bd9Sstevel@tonic-gate keysock_passdown(ks, mp1, i, extv, B_TRUE); 13717c478bd9Sstevel@tonic-gate } else if (start == finish) { 13727c478bd9Sstevel@tonic-gate /* 13737c478bd9Sstevel@tonic-gate * In case where start == finish, and there's no 13747c478bd9Sstevel@tonic-gate * consumer, should we force an error? Yes. 13757c478bd9Sstevel@tonic-gate */ 1376f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 13777c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 13787c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE); 13797c478bd9Sstevel@tonic-gate return; 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate } 1382f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 13837c478bd9Sstevel@tonic-gate 1384f4b3ec61Sdh155122 if (keystack->keystack_flushdump == 0) { 13857c478bd9Sstevel@tonic-gate /* 13867c478bd9Sstevel@tonic-gate * There were no consumers at all for this message. 13877c478bd9Sstevel@tonic-gate * XXX For now return ESRCH. 13887c478bd9Sstevel@tonic-gate */ 13897c478bd9Sstevel@tonic-gate keysock_error(ks, mp, ESRCH, SADB_X_DIAGNOSTIC_NO_SADBS); 13907c478bd9Sstevel@tonic-gate } else { 13917c478bd9Sstevel@tonic-gate /* Otherwise, free the original message. */ 13927c478bd9Sstevel@tonic-gate freemsg(mp); 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* 13977c478bd9Sstevel@tonic-gate * Get the right diagnostic for a duplicate. Should probably use a static 13987c478bd9Sstevel@tonic-gate * table lookup. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate int 14017c478bd9Sstevel@tonic-gate keysock_duplicate(int ext_type) 14027c478bd9Sstevel@tonic-gate { 14037c478bd9Sstevel@tonic-gate int rc = 0; 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate switch (ext_type) { 14067c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC: 14077c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_SRC; 14087c478bd9Sstevel@tonic-gate break; 14097c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST: 14107c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_DST; 14117c478bd9Sstevel@tonic-gate break; 14128810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC: 14138810c16bSdanmcd rc = SADB_X_DIAGNOSTIC_DUPLICATE_INNER_SRC; 14148810c16bSdanmcd break; 14158810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_DST: 14168810c16bSdanmcd rc = SADB_X_DIAGNOSTIC_DUPLICATE_INNER_DST; 14178810c16bSdanmcd break; 14187c478bd9Sstevel@tonic-gate case SADB_EXT_SA: 14197c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_SA; 14207c478bd9Sstevel@tonic-gate break; 14217c478bd9Sstevel@tonic-gate case SADB_EXT_SPIRANGE: 14227c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_RANGE; 14237c478bd9Sstevel@tonic-gate break; 14247c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_AUTH: 14257c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_AKEY; 14267c478bd9Sstevel@tonic-gate break; 14277c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT: 14287c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_DUPLICATE_EKEY; 14297c478bd9Sstevel@tonic-gate break; 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate return (rc); 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate /* 14357c478bd9Sstevel@tonic-gate * Get the right diagnostic for a reality check failure. Should probably use 14367c478bd9Sstevel@tonic-gate * a static table lookup. 14377c478bd9Sstevel@tonic-gate */ 14387c478bd9Sstevel@tonic-gate int 14397c478bd9Sstevel@tonic-gate keysock_malformed(int ext_type) 14407c478bd9Sstevel@tonic-gate { 14417c478bd9Sstevel@tonic-gate int rc = 0; 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate switch (ext_type) { 14447c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC: 14457c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_SRC; 14467c478bd9Sstevel@tonic-gate break; 14477c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST: 14487c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_DST; 14497c478bd9Sstevel@tonic-gate break; 14508810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC: 14518810c16bSdanmcd rc = SADB_X_DIAGNOSTIC_MALFORMED_INNER_SRC; 14528810c16bSdanmcd break; 14538810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_DST: 14548810c16bSdanmcd rc = SADB_X_DIAGNOSTIC_MALFORMED_INNER_DST; 14558810c16bSdanmcd break; 14567c478bd9Sstevel@tonic-gate case SADB_EXT_SA: 14577c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_SA; 14587c478bd9Sstevel@tonic-gate break; 14597c478bd9Sstevel@tonic-gate case SADB_EXT_SPIRANGE: 14607c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_RANGE; 14617c478bd9Sstevel@tonic-gate break; 14627c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_AUTH: 14637c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_AKEY; 14647c478bd9Sstevel@tonic-gate break; 14657c478bd9Sstevel@tonic-gate case SADB_EXT_KEY_ENCRYPT: 14667c478bd9Sstevel@tonic-gate rc = SADB_X_DIAGNOSTIC_MALFORMED_EKEY; 14677c478bd9Sstevel@tonic-gate break; 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate return (rc); 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate /* 14737c478bd9Sstevel@tonic-gate * Keysock massaging of an inverse ACQUIRE. Consult policy, 14747c478bd9Sstevel@tonic-gate * and construct an appropriate response. 14757c478bd9Sstevel@tonic-gate */ 14767c478bd9Sstevel@tonic-gate static void 14777c478bd9Sstevel@tonic-gate keysock_inverse_acquire(mblk_t *mp, sadb_msg_t *samsg, sadb_ext_t *extv[], 14787c478bd9Sstevel@tonic-gate keysock_t *ks) 14797c478bd9Sstevel@tonic-gate { 14807c478bd9Sstevel@tonic-gate mblk_t *reply_mp; 1481f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate /* 14847c478bd9Sstevel@tonic-gate * Reality check things... 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_SRC] == NULL) { 14877c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_SRC); 14887c478bd9Sstevel@tonic-gate return; 14897c478bd9Sstevel@tonic-gate } 14907c478bd9Sstevel@tonic-gate if (extv[SADB_EXT_ADDRESS_DST] == NULL) { 14917c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_DST); 14928810c16bSdanmcd return; 14938810c16bSdanmcd } 14948810c16bSdanmcd 14958810c16bSdanmcd if (extv[SADB_X_EXT_ADDRESS_INNER_SRC] != NULL && 14968810c16bSdanmcd extv[SADB_X_EXT_ADDRESS_INNER_DST] == NULL) { 14978810c16bSdanmcd keysock_error(ks, mp, EINVAL, 14988810c16bSdanmcd SADB_X_DIAGNOSTIC_MISSING_INNER_DST); 14998810c16bSdanmcd return; 15008810c16bSdanmcd } 15018810c16bSdanmcd 15028810c16bSdanmcd if (extv[SADB_X_EXT_ADDRESS_INNER_SRC] == NULL && 15038810c16bSdanmcd extv[SADB_X_EXT_ADDRESS_INNER_DST] != NULL) { 15048810c16bSdanmcd keysock_error(ks, mp, EINVAL, 15058810c16bSdanmcd SADB_X_DIAGNOSTIC_MISSING_INNER_SRC); 15068810c16bSdanmcd return; 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 1509f4b3ec61Sdh155122 reply_mp = ipsec_construct_inverse_acquire(samsg, extv, 1510f4b3ec61Sdh155122 keystack->keystack_netstack); 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate if (reply_mp != NULL) { 15137c478bd9Sstevel@tonic-gate freemsg(mp); 15147c478bd9Sstevel@tonic-gate keysock_passup(reply_mp, (sadb_msg_t *)reply_mp->b_rptr, 1515f4b3ec61Sdh155122 ks->keysock_serial, NULL, B_FALSE, keystack); 15167c478bd9Sstevel@tonic-gate } else { 15177c478bd9Sstevel@tonic-gate keysock_error(ks, mp, samsg->sadb_msg_errno, 15187c478bd9Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate /* 15237c478bd9Sstevel@tonic-gate * Spew an extended REGISTER down to the relevant consumers. 15247c478bd9Sstevel@tonic-gate */ 15257c478bd9Sstevel@tonic-gate static void 15267c478bd9Sstevel@tonic-gate keysock_extended_register(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[]) 15277c478bd9Sstevel@tonic-gate { 15287c478bd9Sstevel@tonic-gate sadb_x_ereg_t *ereg = (sadb_x_ereg_t *)extv[SADB_X_EXT_EREG]; 15297c478bd9Sstevel@tonic-gate uint8_t *satypes, *fencepost; 15307c478bd9Sstevel@tonic-gate mblk_t *downmp; 15317c478bd9Sstevel@tonic-gate sadb_ext_t *downextv[SADB_EXT_MAX + 1]; 1532f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate if (ks->keysock_registered[0] != 0 || ks->keysock_registered[1] != 0 || 15357c478bd9Sstevel@tonic-gate ks->keysock_registered[2] != 0 || ks->keysock_registered[3] != 0) { 15367c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0); 15377c478bd9Sstevel@tonic-gate } 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_EXTENDED; 15407c478bd9Sstevel@tonic-gate if (ereg == NULL) { 15417c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 15427c478bd9Sstevel@tonic-gate } else { 15437c478bd9Sstevel@tonic-gate ASSERT(mp->b_rptr + msgdsize(mp) == mp->b_wptr); 15447c478bd9Sstevel@tonic-gate fencepost = (uint8_t *)mp->b_wptr; 15457c478bd9Sstevel@tonic-gate satypes = ereg->sadb_x_ereg_satypes; 15467c478bd9Sstevel@tonic-gate while (*satypes != SADB_SATYPE_UNSPEC && satypes != fencepost) { 15477c478bd9Sstevel@tonic-gate downmp = copymsg(mp); 15487c478bd9Sstevel@tonic-gate if (downmp == NULL) { 15497c478bd9Sstevel@tonic-gate keysock_error(ks, mp, ENOMEM, 0); 15507c478bd9Sstevel@tonic-gate return; 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate /* 15537c478bd9Sstevel@tonic-gate * Since we've made it here, keysock_get_ext will work! 15547c478bd9Sstevel@tonic-gate */ 15557c478bd9Sstevel@tonic-gate (void) keysock_get_ext(downextv, 1556f4b3ec61Sdh155122 (sadb_msg_t *)downmp->b_rptr, msgdsize(downmp), 1557f4b3ec61Sdh155122 keystack); 15587c478bd9Sstevel@tonic-gate keysock_passdown(ks, downmp, *satypes, downextv, 15597c478bd9Sstevel@tonic-gate B_FALSE); 15607c478bd9Sstevel@tonic-gate ++satypes; 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate freemsg(mp); 15637c478bd9Sstevel@tonic-gate } 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate /* 15667c478bd9Sstevel@tonic-gate * Set global to indicate we prefer an extended ACQUIRE. 15677c478bd9Sstevel@tonic-gate */ 1568*1a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&keystack->keystack_num_extended); 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate 15719c2c14abSThejaswini Singarajipura static void 15729c2c14abSThejaswini Singarajipura keysock_delpair_all(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[]) 15739c2c14abSThejaswini Singarajipura { 15749c2c14abSThejaswini Singarajipura int i, start, finish; 15759c2c14abSThejaswini Singarajipura mblk_t *mp1 = NULL; 15769c2c14abSThejaswini Singarajipura keysock_stack_t *keystack = ks->keysock_keystack; 15779c2c14abSThejaswini Singarajipura 15789c2c14abSThejaswini Singarajipura start = 0; 15799c2c14abSThejaswini Singarajipura finish = KEYSOCK_MAX_CONSUMERS - 1; 15809c2c14abSThejaswini Singarajipura 15819c2c14abSThejaswini Singarajipura for (i = start; i <= finish; i++) { 15829c2c14abSThejaswini Singarajipura if (keystack->keystack_consumers[i] != NULL) { 15839c2c14abSThejaswini Singarajipura mp1 = copymsg(mp); 15849c2c14abSThejaswini Singarajipura if (mp1 == NULL) { 15859c2c14abSThejaswini Singarajipura keysock_error(ks, mp, ENOMEM, 15869c2c14abSThejaswini Singarajipura SADB_X_DIAGNOSTIC_NONE); 15879c2c14abSThejaswini Singarajipura return; 15889c2c14abSThejaswini Singarajipura } 15899c2c14abSThejaswini Singarajipura keysock_passdown(ks, mp1, i, extv, B_FALSE); 15909c2c14abSThejaswini Singarajipura } 15919c2c14abSThejaswini Singarajipura } 15929c2c14abSThejaswini Singarajipura } 15939c2c14abSThejaswini Singarajipura 15947c478bd9Sstevel@tonic-gate /* 15957c478bd9Sstevel@tonic-gate * Handle PF_KEY messages. 15967c478bd9Sstevel@tonic-gate */ 15977c478bd9Sstevel@tonic-gate static void 15987c478bd9Sstevel@tonic-gate keysock_parse(queue_t *q, mblk_t *mp) 15997c478bd9Sstevel@tonic-gate { 16007c478bd9Sstevel@tonic-gate sadb_msg_t *samsg; 16017c478bd9Sstevel@tonic-gate sadb_ext_t *extv[SADB_EXT_MAX + 1]; 16027c478bd9Sstevel@tonic-gate keysock_t *ks = (keysock_t *)q->q_ptr; 16037c478bd9Sstevel@tonic-gate uint_t msgsize; 16047c478bd9Sstevel@tonic-gate uint8_t satype; 1605f4b3ec61Sdh155122 keysock_stack_t *keystack = ks->keysock_keystack; 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate /* Make sure I'm a PF_KEY socket. (i.e. nothing's below me) */ 16087c478bd9Sstevel@tonic-gate ASSERT(WR(q)->q_next == NULL); 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_rptr; 1611f4b3ec61Sdh155122 ks2dbg(keystack, ("Received possible PF_KEY message, type %d.\n", 16127c478bd9Sstevel@tonic-gate samsg->sadb_msg_type)); 16137c478bd9Sstevel@tonic-gate 16147c478bd9Sstevel@tonic-gate msgsize = SADB_64TO8(samsg->sadb_msg_len); 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate if (msgdsize(mp) != msgsize) { 16177c478bd9Sstevel@tonic-gate /* 16187c478bd9Sstevel@tonic-gate * Message len incorrect w.r.t. actual size. Send an error 16197c478bd9Sstevel@tonic-gate * (EMSGSIZE). It may be necessary to massage things a 16207c478bd9Sstevel@tonic-gate * bit. For example, if the sadb_msg_type is hosed, 16217c478bd9Sstevel@tonic-gate * I need to set it to SADB_RESERVED to get delivery to 16227c478bd9Sstevel@tonic-gate * do the right thing. Then again, maybe just letting 16237c478bd9Sstevel@tonic-gate * the error delivery do the right thing. 16247c478bd9Sstevel@tonic-gate */ 1625f4b3ec61Sdh155122 ks2dbg(keystack, 1626f4b3ec61Sdh155122 ("mblk (%lu) and base (%d) message sizes don't jibe.\n", 16277c478bd9Sstevel@tonic-gate msgdsize(mp), msgsize)); 16287c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EMSGSIZE, SADB_X_DIAGNOSTIC_NONE); 16297c478bd9Sstevel@tonic-gate return; 16307c478bd9Sstevel@tonic-gate } 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate if (msgsize > (uint_t)(mp->b_wptr - mp->b_rptr)) { 16337c478bd9Sstevel@tonic-gate /* Get all message into one mblk. */ 16347c478bd9Sstevel@tonic-gate if (pullupmsg(mp, -1) == 0) { 16357c478bd9Sstevel@tonic-gate /* 16367c478bd9Sstevel@tonic-gate * Something screwy happened. 16377c478bd9Sstevel@tonic-gate */ 1638f4b3ec61Sdh155122 ks3dbg(keystack, 1639f4b3ec61Sdh155122 ("keysock_parse: pullupmsg() failed.\n")); 16407c478bd9Sstevel@tonic-gate return; 16417c478bd9Sstevel@tonic-gate } else { 16427c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_rptr; 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate 1646f4b3ec61Sdh155122 switch (keysock_get_ext(extv, samsg, msgsize, keystack)) { 16477c478bd9Sstevel@tonic-gate case KGE_DUP: 16487c478bd9Sstevel@tonic-gate /* Handle duplicate extension. */ 1649f4b3ec61Sdh155122 ks1dbg(keystack, ("Got duplicate extension of type %d.\n", 16507c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_type)); 16517c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 16527c478bd9Sstevel@tonic-gate keysock_duplicate(extv[0]->sadb_ext_type)); 16537c478bd9Sstevel@tonic-gate return; 16547c478bd9Sstevel@tonic-gate case KGE_UNK: 16557c478bd9Sstevel@tonic-gate /* Handle unknown extension. */ 1656f4b3ec61Sdh155122 ks1dbg(keystack, ("Got unknown extension of type %d.\n", 16577c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_type)); 16587c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_EXT); 16597c478bd9Sstevel@tonic-gate return; 16607c478bd9Sstevel@tonic-gate case KGE_LEN: 16617c478bd9Sstevel@tonic-gate /* Length error. */ 1662f4b3ec61Sdh155122 ks1dbg(keystack, 1663f4b3ec61Sdh155122 ("Length %d on extension type %d overrun or 0.\n", 16647c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_len, extv[0]->sadb_ext_type)); 16657c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_BAD_EXTLEN); 16667c478bd9Sstevel@tonic-gate return; 16677c478bd9Sstevel@tonic-gate case KGE_CHK: 16687c478bd9Sstevel@tonic-gate /* Reality check failed. */ 1669f4b3ec61Sdh155122 ks1dbg(keystack, 1670f4b3ec61Sdh155122 ("Reality check failed on extension type %d.\n", 16717c478bd9Sstevel@tonic-gate extv[0]->sadb_ext_type)); 16727c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 16737c478bd9Sstevel@tonic-gate keysock_malformed(extv[0]->sadb_ext_type)); 16747c478bd9Sstevel@tonic-gate return; 16757c478bd9Sstevel@tonic-gate default: 16767c478bd9Sstevel@tonic-gate /* Default case is no errors. */ 16777c478bd9Sstevel@tonic-gate break; 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 16817c478bd9Sstevel@tonic-gate case SADB_REGISTER: 16827c478bd9Sstevel@tonic-gate /* 16837c478bd9Sstevel@tonic-gate * There's a semantic weirdness in that a message OTHER than 16847c478bd9Sstevel@tonic-gate * the return REGISTER message may be passed up if I set the 16857c478bd9Sstevel@tonic-gate * registered bit BEFORE I pass it down. 16867c478bd9Sstevel@tonic-gate * 16877c478bd9Sstevel@tonic-gate * SOOOO, I'll not twiddle any registered bits until I see 16887c478bd9Sstevel@tonic-gate * the upbound REGISTER (with a serial number in it). 16897c478bd9Sstevel@tonic-gate */ 16907c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 16917c478bd9Sstevel@tonic-gate /* Handle extended register here. */ 16927c478bd9Sstevel@tonic-gate keysock_extended_register(ks, mp, extv); 16937c478bd9Sstevel@tonic-gate return; 16947c478bd9Sstevel@tonic-gate } else if (ks->keysock_flags & KEYSOCK_EXTENDED) { 16957c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0); 16967c478bd9Sstevel@tonic-gate return; 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate /* FALLTHRU */ 16997c478bd9Sstevel@tonic-gate case SADB_GETSPI: 17007c478bd9Sstevel@tonic-gate case SADB_ADD: 17017c478bd9Sstevel@tonic-gate case SADB_UPDATE: 170238d95a78Smarkfen case SADB_X_UPDATEPAIR: 17037c478bd9Sstevel@tonic-gate case SADB_DELETE: 170438d95a78Smarkfen case SADB_X_DELPAIR: 17057c478bd9Sstevel@tonic-gate case SADB_GET: 17067c478bd9Sstevel@tonic-gate /* 17077c478bd9Sstevel@tonic-gate * Pass down to appropriate consumer. 17087c478bd9Sstevel@tonic-gate */ 17097c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC) 17107c478bd9Sstevel@tonic-gate keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv, 17117c478bd9Sstevel@tonic-gate B_FALSE); 17127c478bd9Sstevel@tonic-gate else keysock_error(ks, mp, EINVAL, 17137c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 17147c478bd9Sstevel@tonic-gate return; 17159c2c14abSThejaswini Singarajipura case SADB_X_DELPAIR_STATE: 17169c2c14abSThejaswini Singarajipura if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 17179c2c14abSThejaswini Singarajipura keysock_delpair_all(ks, mp, extv); 17189c2c14abSThejaswini Singarajipura } else { 17199c2c14abSThejaswini Singarajipura keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv, 17209c2c14abSThejaswini Singarajipura B_FALSE); 17219c2c14abSThejaswini Singarajipura } 17229c2c14abSThejaswini Singarajipura return; 17237c478bd9Sstevel@tonic-gate case SADB_ACQUIRE: 17247c478bd9Sstevel@tonic-gate /* 17257c478bd9Sstevel@tonic-gate * If I _receive_ an acquire, this means I should spread it 17267c478bd9Sstevel@tonic-gate * out to registered sockets. Unless there's an errno... 17277c478bd9Sstevel@tonic-gate * 17287c478bd9Sstevel@tonic-gate * Need ADDRESS, may have ID, SENS, and PROP, unless errno, 17297c478bd9Sstevel@tonic-gate * in which case there should be NO extensions. 17307c478bd9Sstevel@tonic-gate * 17317c478bd9Sstevel@tonic-gate * Return to registered. 17327c478bd9Sstevel@tonic-gate */ 17337c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_errno != 0) { 17347c478bd9Sstevel@tonic-gate satype = samsg->sadb_msg_satype; 17357c478bd9Sstevel@tonic-gate if (satype == SADB_SATYPE_UNSPEC) { 17367c478bd9Sstevel@tonic-gate if (!(ks->keysock_flags & KEYSOCK_EXTENDED)) { 17377c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 17387c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 17397c478bd9Sstevel@tonic-gate return; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate /* 17427c478bd9Sstevel@tonic-gate * Reassign satype based on the first 17437c478bd9Sstevel@tonic-gate * flags that KEYSOCK_SETREG says. 17447c478bd9Sstevel@tonic-gate */ 17457c478bd9Sstevel@tonic-gate while (satype <= SADB_SATYPE_MAX) { 17467c478bd9Sstevel@tonic-gate if (KEYSOCK_ISREG(ks, satype)) 17477c478bd9Sstevel@tonic-gate break; 17487c478bd9Sstevel@tonic-gate satype++; 17497c478bd9Sstevel@tonic-gate } 17507c478bd9Sstevel@tonic-gate if (satype > SADB_SATYPE_MAX) { 17517c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EBUSY, 0); 17527c478bd9Sstevel@tonic-gate return; 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate } 17557c478bd9Sstevel@tonic-gate keysock_passdown(ks, mp, satype, extv, B_FALSE); 17567c478bd9Sstevel@tonic-gate } else { 1757f4b3ec61Sdh155122 if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) { 17587c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, 17597c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_SATYPE_NEEDED); 1760f4b3ec61Sdh155122 } else { 1761f4b3ec61Sdh155122 keysock_passup(mp, samsg, 0, NULL, B_FALSE, 1762f4b3ec61Sdh155122 keystack); 1763f4b3ec61Sdh155122 } 17647c478bd9Sstevel@tonic-gate } 17657c478bd9Sstevel@tonic-gate return; 17667c478bd9Sstevel@tonic-gate case SADB_EXPIRE: 17677c478bd9Sstevel@tonic-gate /* 17687c478bd9Sstevel@tonic-gate * If someone sends this in, then send out to all senders. 17697c478bd9Sstevel@tonic-gate * (Save maybe ESP or AH, I have to be careful here.) 17707c478bd9Sstevel@tonic-gate * 17717c478bd9Sstevel@tonic-gate * Need ADDRESS, may have ID and SENS. 17727c478bd9Sstevel@tonic-gate * 17737c478bd9Sstevel@tonic-gate * XXX for now this is unsupported. 17747c478bd9Sstevel@tonic-gate */ 17757c478bd9Sstevel@tonic-gate break; 17767c478bd9Sstevel@tonic-gate case SADB_FLUSH: 17777c478bd9Sstevel@tonic-gate /* 17789c2c14abSThejaswini Singarajipura * Nuke all SAs. 17797c478bd9Sstevel@tonic-gate * 17807c478bd9Sstevel@tonic-gate * No extensions at all. Return to all listeners. 17817c478bd9Sstevel@tonic-gate * 17827c478bd9Sstevel@tonic-gate * Question: Should I hold a lock here to prevent 17837c478bd9Sstevel@tonic-gate * additions/deletions while flushing? 17847c478bd9Sstevel@tonic-gate * Answer: No. (See keysock_passdown() for details.) 17857c478bd9Sstevel@tonic-gate */ 17867c478bd9Sstevel@tonic-gate if (extv[0] != NULL) { 17877c478bd9Sstevel@tonic-gate /* 17889c2c14abSThejaswini Singarajipura * FLUSH messages shouldn't have extensions. 17897c478bd9Sstevel@tonic-gate * Return EINVAL. 17907c478bd9Sstevel@tonic-gate */ 1791f4b3ec61Sdh155122 ks2dbg(keystack, ("FLUSH message with extension.\n")); 17927c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_NO_EXT); 17937c478bd9Sstevel@tonic-gate return; 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate /* Passing down of DUMP/FLUSH messages are special. */ 17977c478bd9Sstevel@tonic-gate qwriter(q, mp, keysock_do_flushdump, PERIM_INNER); 17987c478bd9Sstevel@tonic-gate return; 17999c2c14abSThejaswini Singarajipura case SADB_DUMP: /* not used by normal applications */ 18009c2c14abSThejaswini Singarajipura if ((extv[0] != NULL) && 18019c2c14abSThejaswini Singarajipura ((msgsize > 18029c2c14abSThejaswini Singarajipura (sizeof (sadb_msg_t) + sizeof (sadb_x_edump_t))) || 18039c2c14abSThejaswini Singarajipura (extv[SADB_X_EXT_EDUMP] == NULL))) { 18049c2c14abSThejaswini Singarajipura keysock_error(ks, mp, EINVAL, 18059c2c14abSThejaswini Singarajipura SADB_X_DIAGNOSTIC_NO_EXT); 18069c2c14abSThejaswini Singarajipura return; 18079c2c14abSThejaswini Singarajipura } 18089c2c14abSThejaswini Singarajipura qwriter(q, mp, keysock_do_flushdump, PERIM_INNER); 18099c2c14abSThejaswini Singarajipura return; 18107c478bd9Sstevel@tonic-gate case SADB_X_PROMISC: 18117c478bd9Sstevel@tonic-gate /* 18127c478bd9Sstevel@tonic-gate * Promiscuous processing message. 18137c478bd9Sstevel@tonic-gate */ 18147c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_satype == 0) 18157c478bd9Sstevel@tonic-gate ks->keysock_flags &= ~KEYSOCK_PROMISC; 18167c478bd9Sstevel@tonic-gate else 18177c478bd9Sstevel@tonic-gate ks->keysock_flags |= KEYSOCK_PROMISC; 1818f4b3ec61Sdh155122 keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE, 1819f4b3ec61Sdh155122 keystack); 18207c478bd9Sstevel@tonic-gate return; 18217c478bd9Sstevel@tonic-gate case SADB_X_INVERSE_ACQUIRE: 18227c478bd9Sstevel@tonic-gate keysock_inverse_acquire(mp, samsg, extv, ks); 18237c478bd9Sstevel@tonic-gate return; 18247c478bd9Sstevel@tonic-gate default: 1825f4b3ec61Sdh155122 ks2dbg(keystack, ("Got unknown message type %d.\n", 18267c478bd9Sstevel@tonic-gate samsg->sadb_msg_type)); 18277c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_MSG); 18287c478bd9Sstevel@tonic-gate return; 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate /* As a placeholder... */ 18327c478bd9Sstevel@tonic-gate ks0dbg(("keysock_parse(): Hit EOPNOTSUPP\n")); 18337c478bd9Sstevel@tonic-gate keysock_error(ks, mp, EOPNOTSUPP, SADB_X_DIAGNOSTIC_NONE); 18347c478bd9Sstevel@tonic-gate } 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate /* 18377c478bd9Sstevel@tonic-gate * wput routing for PF_KEY/keysock/whatever. Unlike the routing socket, 18387c478bd9Sstevel@tonic-gate * I don't convert to ioctl()'s for IP. I am the end-all driver as far 18397c478bd9Sstevel@tonic-gate * as PF_KEY sockets are concerned. I do some conversion, but not as much 18407c478bd9Sstevel@tonic-gate * as IP/rts does. 18417c478bd9Sstevel@tonic-gate */ 18427c478bd9Sstevel@tonic-gate static void 18437c478bd9Sstevel@tonic-gate keysock_wput(queue_t *q, mblk_t *mp) 18447c478bd9Sstevel@tonic-gate { 18457c478bd9Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 18467c478bd9Sstevel@tonic-gate mblk_t *mp1; 1847f4b3ec61Sdh155122 keysock_t *ks; 1848f4b3ec61Sdh155122 keysock_stack_t *keystack; 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate if (WR(q)->q_next) { 18517c478bd9Sstevel@tonic-gate keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr; 1852f4b3ec61Sdh155122 keystack = kc->kc_keystack; 1853f4b3ec61Sdh155122 1854f4b3ec61Sdh155122 ks3dbg(keystack, ("In keysock_wput\n")); 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate /* 18577c478bd9Sstevel@tonic-gate * We shouldn't get writes on a consumer instance. 18587c478bd9Sstevel@tonic-gate * But for now, just passthru. 18597c478bd9Sstevel@tonic-gate */ 1860f4b3ec61Sdh155122 ks1dbg(keystack, ("Huh? wput for an consumer instance (%d)?\n", 18617c478bd9Sstevel@tonic-gate kc->kc_sa_type)); 18627c478bd9Sstevel@tonic-gate putnext(q, mp); 18637c478bd9Sstevel@tonic-gate return; 18647c478bd9Sstevel@tonic-gate } 1865f4b3ec61Sdh155122 ks = (keysock_t *)q->q_ptr; 1866f4b3ec61Sdh155122 keystack = ks->keysock_keystack; 1867f4b3ec61Sdh155122 1868f4b3ec61Sdh155122 ks3dbg(keystack, ("In keysock_wput\n")); 18697c478bd9Sstevel@tonic-gate 18707c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 18717c478bd9Sstevel@tonic-gate case M_DATA: 18727c478bd9Sstevel@tonic-gate /* 18737c478bd9Sstevel@tonic-gate * Silently discard. 18747c478bd9Sstevel@tonic-gate */ 1875f4b3ec61Sdh155122 ks2dbg(keystack, ("raw M_DATA in keysock.\n")); 18767c478bd9Sstevel@tonic-gate freemsg(mp); 18777c478bd9Sstevel@tonic-gate return; 18787c478bd9Sstevel@tonic-gate case M_PROTO: 18797c478bd9Sstevel@tonic-gate case M_PCPROTO: 18807c478bd9Sstevel@tonic-gate if ((mp->b_wptr - rptr) >= sizeof (struct T_data_req)) { 18817c478bd9Sstevel@tonic-gate if (((union T_primitives *)rptr)->type == T_DATA_REQ) { 18827c478bd9Sstevel@tonic-gate if ((mp1 = mp->b_cont) == NULL) { 18837c478bd9Sstevel@tonic-gate /* No data after T_DATA_REQ. */ 1884f4b3ec61Sdh155122 ks2dbg(keystack, 1885f4b3ec61Sdh155122 ("No data after DATA_REQ.\n")); 18867c478bd9Sstevel@tonic-gate freemsg(mp); 18877c478bd9Sstevel@tonic-gate return; 18887c478bd9Sstevel@tonic-gate } 18897c478bd9Sstevel@tonic-gate freeb(mp); 18907c478bd9Sstevel@tonic-gate mp = mp1; 1891f4b3ec61Sdh155122 ks2dbg(keystack, ("T_DATA_REQ\n")); 18927c478bd9Sstevel@tonic-gate break; /* Out of switch. */ 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate } 18957c478bd9Sstevel@tonic-gate /* FALLTHRU */ 18967c478bd9Sstevel@tonic-gate default: 1897f4b3ec61Sdh155122 ks3dbg(keystack, ("In default wput case (%d %d).\n", 18987c478bd9Sstevel@tonic-gate mp->b_datap->db_type, ((union T_primitives *)rptr)->type)); 18997c478bd9Sstevel@tonic-gate keysock_wput_other(q, mp); 19007c478bd9Sstevel@tonic-gate return; 19017c478bd9Sstevel@tonic-gate } 19027c478bd9Sstevel@tonic-gate 19037c478bd9Sstevel@tonic-gate /* I now have a PF_KEY message in an M_DATA block, pointed to by mp. */ 19047c478bd9Sstevel@tonic-gate keysock_parse(q, mp); 19057c478bd9Sstevel@tonic-gate } 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_rput(). */ 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate * Called upon receipt of a KEYSOCK_HELLO_ACK to set up the appropriate 19117c478bd9Sstevel@tonic-gate * state vectors. 19127c478bd9Sstevel@tonic-gate */ 19137c478bd9Sstevel@tonic-gate static void 19147c478bd9Sstevel@tonic-gate keysock_link_consumer(uint8_t satype, keysock_consumer_t *kc) 19157c478bd9Sstevel@tonic-gate { 19167c478bd9Sstevel@tonic-gate keysock_t *ks; 1917f4b3ec61Sdh155122 keysock_stack_t *keystack = kc->kc_keystack; 19187c478bd9Sstevel@tonic-gate 1919f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_consumers_lock); 19207c478bd9Sstevel@tonic-gate mutex_enter(&kc->kc_lock); 1921f4b3ec61Sdh155122 if (keystack->keystack_consumers[satype] != NULL) { 19227c478bd9Sstevel@tonic-gate ks0dbg(( 19237c478bd9Sstevel@tonic-gate "Hmmmm, someone closed %d before the HELLO_ACK happened.\n", 19247c478bd9Sstevel@tonic-gate satype)); 19257c478bd9Sstevel@tonic-gate /* 19267c478bd9Sstevel@tonic-gate * Perhaps updating the new below-me consumer with what I have 19277c478bd9Sstevel@tonic-gate * so far would work too? 19287c478bd9Sstevel@tonic-gate */ 19297c478bd9Sstevel@tonic-gate mutex_exit(&kc->kc_lock); 1930f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 19317c478bd9Sstevel@tonic-gate } else { 19327c478bd9Sstevel@tonic-gate /* Add new below-me consumer. */ 1933f4b3ec61Sdh155122 keystack->keystack_consumers[satype] = kc; 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate kc->kc_flags = 0; 19367c478bd9Sstevel@tonic-gate kc->kc_sa_type = satype; 19377c478bd9Sstevel@tonic-gate mutex_exit(&kc->kc_lock); 1938f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_consumers_lock); 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate /* Scan the keysock list. */ 1941f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_list_lock); 1942f4b3ec61Sdh155122 for (ks = keystack->keystack_list; ks != NULL; 1943f4b3ec61Sdh155122 ks = ks->keysock_next) { 19447c478bd9Sstevel@tonic-gate if (KEYSOCK_ISREG(ks, satype)) { 19457c478bd9Sstevel@tonic-gate /* 19467c478bd9Sstevel@tonic-gate * XXX Perhaps send an SADB_REGISTER down on 19477c478bd9Sstevel@tonic-gate * the socket's behalf. 19487c478bd9Sstevel@tonic-gate */ 1949f4b3ec61Sdh155122 ks1dbg(keystack, 1950f4b3ec61Sdh155122 ("Socket %u registered already for " 19517c478bd9Sstevel@tonic-gate "new consumer.\n", ks->keysock_serial)); 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate } 1954f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_list_lock); 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate /* 19597c478bd9Sstevel@tonic-gate * Generate a KEYSOCK_OUT_ERR message for my consumer. 19607c478bd9Sstevel@tonic-gate */ 19617c478bd9Sstevel@tonic-gate static void 19627c478bd9Sstevel@tonic-gate keysock_out_err(keysock_consumer_t *kc, int ks_errno, mblk_t *mp) 19637c478bd9Sstevel@tonic-gate { 19647c478bd9Sstevel@tonic-gate keysock_out_err_t *kse; 19657c478bd9Sstevel@tonic-gate mblk_t *imp; 1966f4b3ec61Sdh155122 keysock_stack_t *keystack = kc->kc_keystack; 19677c478bd9Sstevel@tonic-gate 19687c478bd9Sstevel@tonic-gate imp = allocb(sizeof (ipsec_info_t), BPRI_HI); 19697c478bd9Sstevel@tonic-gate if (imp == NULL) { 1970f4b3ec61Sdh155122 ks1dbg(keystack, ("keysock_out_err: Can't alloc message.\n")); 19717c478bd9Sstevel@tonic-gate return; 19727c478bd9Sstevel@tonic-gate } 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate imp->b_datap->db_type = M_CTL; 19757c478bd9Sstevel@tonic-gate imp->b_wptr += sizeof (ipsec_info_t); 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate kse = (keysock_out_err_t *)imp->b_rptr; 19787c478bd9Sstevel@tonic-gate imp->b_cont = mp; 19797c478bd9Sstevel@tonic-gate kse->ks_err_type = KEYSOCK_OUT_ERR; 19807c478bd9Sstevel@tonic-gate kse->ks_err_len = sizeof (*kse); 19817c478bd9Sstevel@tonic-gate /* Is serial necessary? */ 19827c478bd9Sstevel@tonic-gate kse->ks_err_serial = 0; 19837c478bd9Sstevel@tonic-gate kse->ks_err_errno = ks_errno; 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate /* 19867c478bd9Sstevel@tonic-gate * XXX What else do I need to do here w.r.t. information 19877c478bd9Sstevel@tonic-gate * to tell the consumer what caused this error? 19887c478bd9Sstevel@tonic-gate * 19897c478bd9Sstevel@tonic-gate * I believe the answer is the PF_KEY ACQUIRE (or other) message 19907c478bd9Sstevel@tonic-gate * attached in mp, which is appended at the end. I believe the 19917c478bd9Sstevel@tonic-gate * db_ref won't matter here, because the PF_KEY message is only read 19927c478bd9Sstevel@tonic-gate * for KEYSOCK_OUT_ERR. 19937c478bd9Sstevel@tonic-gate */ 19947c478bd9Sstevel@tonic-gate 19957c478bd9Sstevel@tonic-gate putnext(kc->kc_wq, imp); 19967c478bd9Sstevel@tonic-gate } 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate /* XXX this is a hack errno. */ 19997c478bd9Sstevel@tonic-gate #define EIPSECNOSA 255 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate /* 20027c478bd9Sstevel@tonic-gate * Route message (pointed by mp, header in samsg) toward appropriate 20037c478bd9Sstevel@tonic-gate * sockets. Assume the message's creator did its job correctly. 20047c478bd9Sstevel@tonic-gate * 20057c478bd9Sstevel@tonic-gate * This should be a function that is followed by a return in its caller. 20067c478bd9Sstevel@tonic-gate * The compiler _should_ be able to use tail-call optimizations to make the 20077c478bd9Sstevel@tonic-gate * large ## of parameters not a huge deal. 20087c478bd9Sstevel@tonic-gate */ 20097c478bd9Sstevel@tonic-gate static void 20107c478bd9Sstevel@tonic-gate keysock_passup(mblk_t *mp, sadb_msg_t *samsg, minor_t serial, 2011f4b3ec61Sdh155122 keysock_consumer_t *kc, boolean_t persistent, keysock_stack_t *keystack) 20127c478bd9Sstevel@tonic-gate { 20137c478bd9Sstevel@tonic-gate keysock_t *ks; 20147c478bd9Sstevel@tonic-gate uint8_t satype = samsg->sadb_msg_satype; 20157c478bd9Sstevel@tonic-gate boolean_t toall = B_FALSE, allreg = B_FALSE, allereg = B_FALSE, 20167c478bd9Sstevel@tonic-gate setalg = B_FALSE; 20177c478bd9Sstevel@tonic-gate mblk_t *mp1; 20187c478bd9Sstevel@tonic-gate int err = EIPSECNOSA; 20197c478bd9Sstevel@tonic-gate 20207c478bd9Sstevel@tonic-gate /* Convert mp, which is M_DATA, into an M_PROTO of type T_DATA_IND */ 20217c478bd9Sstevel@tonic-gate mp1 = allocb(sizeof (struct T_data_req), BPRI_HI); 20227c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 20237c478bd9Sstevel@tonic-gate err = ENOMEM; 20247c478bd9Sstevel@tonic-gate goto error; 20257c478bd9Sstevel@tonic-gate } 20267c478bd9Sstevel@tonic-gate mp1->b_wptr += sizeof (struct T_data_req); 20277c478bd9Sstevel@tonic-gate ((struct T_data_ind *)mp1->b_rptr)->PRIM_type = T_DATA_IND; 20287c478bd9Sstevel@tonic-gate ((struct T_data_ind *)mp1->b_rptr)->MORE_flag = 0; 20297c478bd9Sstevel@tonic-gate mp1->b_datap->db_type = M_PROTO; 20307c478bd9Sstevel@tonic-gate mp1->b_cont = mp; 20317c478bd9Sstevel@tonic-gate mp = mp1; 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 20347c478bd9Sstevel@tonic-gate case SADB_FLUSH: 20357c478bd9Sstevel@tonic-gate case SADB_GETSPI: 20367c478bd9Sstevel@tonic-gate case SADB_UPDATE: 203738d95a78Smarkfen case SADB_X_UPDATEPAIR: 20387c478bd9Sstevel@tonic-gate case SADB_ADD: 20397c478bd9Sstevel@tonic-gate case SADB_DELETE: 204038d95a78Smarkfen case SADB_X_DELPAIR: 20417c478bd9Sstevel@tonic-gate case SADB_EXPIRE: 20427c478bd9Sstevel@tonic-gate /* 20437c478bd9Sstevel@tonic-gate * These are most likely replies. Don't worry about 20447c478bd9Sstevel@tonic-gate * KEYSOCK_OUT_ERR handling. Deliver to all sockets. 20457c478bd9Sstevel@tonic-gate */ 2046f4b3ec61Sdh155122 ks3dbg(keystack, 2047f4b3ec61Sdh155122 ("Delivering normal message (%d) to all sockets.\n", 20487c478bd9Sstevel@tonic-gate samsg->sadb_msg_type)); 20497c478bd9Sstevel@tonic-gate toall = B_TRUE; 20507c478bd9Sstevel@tonic-gate break; 20517c478bd9Sstevel@tonic-gate case SADB_REGISTER: 20527c478bd9Sstevel@tonic-gate /* 20537c478bd9Sstevel@tonic-gate * REGISTERs come up for one of three reasons: 20547c478bd9Sstevel@tonic-gate * 20557c478bd9Sstevel@tonic-gate * 1.) In response to a normal SADB_REGISTER 20567c478bd9Sstevel@tonic-gate * (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC && 20577c478bd9Sstevel@tonic-gate * serial != 0) 20587c478bd9Sstevel@tonic-gate * Deliver to normal SADB_REGISTERed sockets. 20597c478bd9Sstevel@tonic-gate * 2.) In response to an extended REGISTER 20607c478bd9Sstevel@tonic-gate * (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) 20617c478bd9Sstevel@tonic-gate * Deliver to extended REGISTERed socket. 20627c478bd9Sstevel@tonic-gate * 3.) Spontaneous algorithm changes 20637c478bd9Sstevel@tonic-gate * (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC && 20647c478bd9Sstevel@tonic-gate * serial == 0) 20657c478bd9Sstevel@tonic-gate * Deliver to REGISTERed sockets of all sorts. 20667c478bd9Sstevel@tonic-gate */ 20677c478bd9Sstevel@tonic-gate if (kc == NULL) { 20687c478bd9Sstevel@tonic-gate /* Here because of keysock_error() call. */ 20697c478bd9Sstevel@tonic-gate ASSERT(samsg->sadb_msg_errno != 0); 20707c478bd9Sstevel@tonic-gate break; /* Out of switch. */ 20717c478bd9Sstevel@tonic-gate } 2072f4b3ec61Sdh155122 ks3dbg(keystack, ("Delivering REGISTER.\n")); 20737c478bd9Sstevel@tonic-gate if (satype == SADB_SATYPE_UNSPEC) { 20747c478bd9Sstevel@tonic-gate /* REGISTER Reason #2 */ 20757c478bd9Sstevel@tonic-gate allereg = B_TRUE; 20767c478bd9Sstevel@tonic-gate /* 20777c478bd9Sstevel@tonic-gate * Rewhack SA type so PF_KEY socket holder knows what 20787c478bd9Sstevel@tonic-gate * consumer generated this algorithm list. 20797c478bd9Sstevel@tonic-gate */ 20807c478bd9Sstevel@tonic-gate satype = kc->kc_sa_type; 20817c478bd9Sstevel@tonic-gate samsg->sadb_msg_satype = satype; 20827c478bd9Sstevel@tonic-gate setalg = B_TRUE; 20837c478bd9Sstevel@tonic-gate } else if (serial == 0) { 20847c478bd9Sstevel@tonic-gate /* REGISTER Reason #3 */ 20857c478bd9Sstevel@tonic-gate allreg = B_TRUE; 20867c478bd9Sstevel@tonic-gate allereg = B_TRUE; 20877c478bd9Sstevel@tonic-gate } else { 20887c478bd9Sstevel@tonic-gate /* REGISTER Reason #1 */ 20897c478bd9Sstevel@tonic-gate allreg = B_TRUE; 20907c478bd9Sstevel@tonic-gate setalg = B_TRUE; 20917c478bd9Sstevel@tonic-gate } 20927c478bd9Sstevel@tonic-gate break; 20937c478bd9Sstevel@tonic-gate case SADB_ACQUIRE: 20947c478bd9Sstevel@tonic-gate /* 20957c478bd9Sstevel@tonic-gate * ACQUIREs are either extended (sadb_msg_satype == 0) or 20967c478bd9Sstevel@tonic-gate * regular (sadb_msg_satype != 0). And we're guaranteed 20977c478bd9Sstevel@tonic-gate * that serial == 0 for an ACQUIRE. 20987c478bd9Sstevel@tonic-gate */ 2099f4b3ec61Sdh155122 ks3dbg(keystack, ("Delivering ACQUIRE.\n")); 21007c478bd9Sstevel@tonic-gate allereg = (satype == SADB_SATYPE_UNSPEC); 21017c478bd9Sstevel@tonic-gate allreg = !allereg; 21027c478bd9Sstevel@tonic-gate /* 21037c478bd9Sstevel@tonic-gate * Corner case - if we send a regular ACQUIRE and there's 21047c478bd9Sstevel@tonic-gate * extended ones registered, don't send an error down to 21057c478bd9Sstevel@tonic-gate * consumers if nobody's listening and prematurely destroy 21067c478bd9Sstevel@tonic-gate * their ACQUIRE record. This might be too hackish of a 21077c478bd9Sstevel@tonic-gate * solution. 21087c478bd9Sstevel@tonic-gate */ 2109f4b3ec61Sdh155122 if (allreg && keystack->keystack_num_extended > 0) 21107c478bd9Sstevel@tonic-gate err = 0; 21117c478bd9Sstevel@tonic-gate break; 21127c478bd9Sstevel@tonic-gate case SADB_X_PROMISC: 21137c478bd9Sstevel@tonic-gate case SADB_X_INVERSE_ACQUIRE: 21147c478bd9Sstevel@tonic-gate case SADB_DUMP: 21157c478bd9Sstevel@tonic-gate case SADB_GET: 21167c478bd9Sstevel@tonic-gate default: 21177c478bd9Sstevel@tonic-gate /* 21187c478bd9Sstevel@tonic-gate * Deliver to the sender and promiscuous only. 21197c478bd9Sstevel@tonic-gate */ 2120f4b3ec61Sdh155122 ks3dbg(keystack, ("Delivering sender/promisc only (%d).\n", 21217c478bd9Sstevel@tonic-gate samsg->sadb_msg_type)); 21227c478bd9Sstevel@tonic-gate break; 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 2125f4b3ec61Sdh155122 mutex_enter(&keystack->keystack_list_lock); 2126f4b3ec61Sdh155122 for (ks = keystack->keystack_list; ks != NULL; ks = ks->keysock_next) { 21277c478bd9Sstevel@tonic-gate /* Delivery loop. */ 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate /* 21307c478bd9Sstevel@tonic-gate * Check special keysock-setting cases (REGISTER replies) 21317c478bd9Sstevel@tonic-gate * here. 21327c478bd9Sstevel@tonic-gate */ 21337c478bd9Sstevel@tonic-gate if (setalg && serial == ks->keysock_serial) { 21347c478bd9Sstevel@tonic-gate ASSERT(kc != NULL); 21357c478bd9Sstevel@tonic-gate ASSERT(kc->kc_sa_type == satype); 21367c478bd9Sstevel@tonic-gate KEYSOCK_SETREG(ks, satype); 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate /* 21407c478bd9Sstevel@tonic-gate * NOLOOP takes precedence over PROMISC. So if you've set 21417c478bd9Sstevel@tonic-gate * !SO_USELOOPBACK, don't expect to see any data... 21427c478bd9Sstevel@tonic-gate */ 21437c478bd9Sstevel@tonic-gate if (ks->keysock_flags & KEYSOCK_NOLOOP) 21447c478bd9Sstevel@tonic-gate continue; 21457c478bd9Sstevel@tonic-gate 21467c478bd9Sstevel@tonic-gate /* 21477c478bd9Sstevel@tonic-gate * Messages to all, or promiscuous sockets just GET the 21487c478bd9Sstevel@tonic-gate * message. Perform rules-type checking iff it's not for all 21497c478bd9Sstevel@tonic-gate * listeners or the socket is in promiscuous mode. 21507c478bd9Sstevel@tonic-gate * 21517c478bd9Sstevel@tonic-gate * NOTE:Because of the (kc != NULL && ISREG()), make sure 21527c478bd9Sstevel@tonic-gate * extended ACQUIREs arrive off a consumer that is 21537c478bd9Sstevel@tonic-gate * part of the extended REGISTER set of consumers. 21547c478bd9Sstevel@tonic-gate */ 21557c478bd9Sstevel@tonic-gate if (serial != ks->keysock_serial && 21567c478bd9Sstevel@tonic-gate !toall && 21577c478bd9Sstevel@tonic-gate !(ks->keysock_flags & KEYSOCK_PROMISC) && 21587c478bd9Sstevel@tonic-gate !((ks->keysock_flags & KEYSOCK_EXTENDED) ? 21597c478bd9Sstevel@tonic-gate allereg : allreg && kc != NULL && 21607c478bd9Sstevel@tonic-gate KEYSOCK_ISREG(ks, kc->kc_sa_type))) 21617c478bd9Sstevel@tonic-gate continue; 21627c478bd9Sstevel@tonic-gate 21637c478bd9Sstevel@tonic-gate mp1 = dupmsg(mp); 21647c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 2165f4b3ec61Sdh155122 ks2dbg(keystack, ( 21667c478bd9Sstevel@tonic-gate "keysock_passup(): dupmsg() failed.\n")); 21677c478bd9Sstevel@tonic-gate mp1 = mp; 21687c478bd9Sstevel@tonic-gate mp = NULL; 21697c478bd9Sstevel@tonic-gate err = ENOMEM; 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate 21727c478bd9Sstevel@tonic-gate /* 21737c478bd9Sstevel@tonic-gate * At this point, we can deliver or attempt to deliver 21747c478bd9Sstevel@tonic-gate * this message. We're free of obligation to report 21757c478bd9Sstevel@tonic-gate * no listening PF_KEY sockets. So set err to 0. 21767c478bd9Sstevel@tonic-gate */ 21777c478bd9Sstevel@tonic-gate err = 0; 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate /* 21807c478bd9Sstevel@tonic-gate * See if we canputnext(), as well as see if the message 21817c478bd9Sstevel@tonic-gate * needs to be queued if we can't. 21827c478bd9Sstevel@tonic-gate */ 21837c478bd9Sstevel@tonic-gate if (!canputnext(ks->keysock_rq)) { 21847c478bd9Sstevel@tonic-gate if (persistent) { 21857c478bd9Sstevel@tonic-gate if (putq(ks->keysock_rq, mp1) == 0) { 2186f4b3ec61Sdh155122 ks1dbg(keystack, ( 21877c478bd9Sstevel@tonic-gate "keysock_passup: putq failed.\n")); 21887c478bd9Sstevel@tonic-gate } else { 21897c478bd9Sstevel@tonic-gate continue; 21907c478bd9Sstevel@tonic-gate } 21917c478bd9Sstevel@tonic-gate } 21927c478bd9Sstevel@tonic-gate freemsg(mp1); 21937c478bd9Sstevel@tonic-gate continue; 21947c478bd9Sstevel@tonic-gate } 21957c478bd9Sstevel@tonic-gate 2196f4b3ec61Sdh155122 ks3dbg(keystack, 2197f4b3ec61Sdh155122 ("Putting to serial %d.\n", ks->keysock_serial)); 21987c478bd9Sstevel@tonic-gate /* 21997c478bd9Sstevel@tonic-gate * Unlike the specific keysock instance case, this 22007c478bd9Sstevel@tonic-gate * will only hit for listeners, so we will only 22017c478bd9Sstevel@tonic-gate * putnext() if we can. 22027c478bd9Sstevel@tonic-gate */ 22037c478bd9Sstevel@tonic-gate putnext(ks->keysock_rq, mp1); 22047c478bd9Sstevel@tonic-gate if (mp == NULL) 22057c478bd9Sstevel@tonic-gate break; /* out of for loop. */ 22067c478bd9Sstevel@tonic-gate } 2207f4b3ec61Sdh155122 mutex_exit(&keystack->keystack_list_lock); 22087c478bd9Sstevel@tonic-gate 22097c478bd9Sstevel@tonic-gate error: 22107c478bd9Sstevel@tonic-gate if ((err != 0) && (kc != NULL)) { 22117c478bd9Sstevel@tonic-gate /* 22127c478bd9Sstevel@tonic-gate * Generate KEYSOCK_OUT_ERR for consumer. 22137c478bd9Sstevel@tonic-gate * Basically, I send this back if I have not been able to 22147c478bd9Sstevel@tonic-gate * transmit (for whatever reason) 22157c478bd9Sstevel@tonic-gate */ 2216f4b3ec61Sdh155122 ks1dbg(keystack, 2217f4b3ec61Sdh155122 ("keysock_passup(): No registered of type %d.\n", 22187c478bd9Sstevel@tonic-gate satype)); 22197c478bd9Sstevel@tonic-gate if (mp != NULL) { 22207c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_PROTO) { 22217c478bd9Sstevel@tonic-gate mp1 = mp; 22227c478bd9Sstevel@tonic-gate mp = mp->b_cont; 22237c478bd9Sstevel@tonic-gate freeb(mp1); 22247c478bd9Sstevel@tonic-gate } 22257c478bd9Sstevel@tonic-gate /* 22267c478bd9Sstevel@tonic-gate * Do a copymsg() because people who get 22277c478bd9Sstevel@tonic-gate * KEYSOCK_OUT_ERR may alter the message contents. 22287c478bd9Sstevel@tonic-gate */ 22297c478bd9Sstevel@tonic-gate mp1 = copymsg(mp); 22307c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 2231f4b3ec61Sdh155122 ks2dbg(keystack, 2232f4b3ec61Sdh155122 ("keysock_passup: copymsg() failed.\n")); 22337c478bd9Sstevel@tonic-gate mp1 = mp; 22347c478bd9Sstevel@tonic-gate mp = NULL; 22357c478bd9Sstevel@tonic-gate } 22367c478bd9Sstevel@tonic-gate keysock_out_err(kc, err, mp1); 22377c478bd9Sstevel@tonic-gate } 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate /* 22417c478bd9Sstevel@tonic-gate * XXX Blank the message somehow. This is difficult because we don't 22427c478bd9Sstevel@tonic-gate * know at this point if the message has db_ref > 1, etc. 22437c478bd9Sstevel@tonic-gate * 22447c478bd9Sstevel@tonic-gate * Optimally, keysock messages containing actual keying material would 22457c478bd9Sstevel@tonic-gate * be allocated with esballoc(), with a zeroing free function. 22467c478bd9Sstevel@tonic-gate */ 22477c478bd9Sstevel@tonic-gate if (mp != NULL) 22487c478bd9Sstevel@tonic-gate freemsg(mp); 22497c478bd9Sstevel@tonic-gate } 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate /* 22527c478bd9Sstevel@tonic-gate * Keysock's read service procedure is there only for PF_KEY reply 22537c478bd9Sstevel@tonic-gate * messages that really need to reach the top. 22547c478bd9Sstevel@tonic-gate */ 22557c478bd9Sstevel@tonic-gate static void 22567c478bd9Sstevel@tonic-gate keysock_rsrv(queue_t *q) 22577c478bd9Sstevel@tonic-gate { 22587c478bd9Sstevel@tonic-gate mblk_t *mp; 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) { 22617c478bd9Sstevel@tonic-gate if (canputnext(q)) { 22627c478bd9Sstevel@tonic-gate putnext(q, mp); 22637c478bd9Sstevel@tonic-gate } else { 22647c478bd9Sstevel@tonic-gate (void) putbq(q, mp); 22657c478bd9Sstevel@tonic-gate return; 22667c478bd9Sstevel@tonic-gate } 22677c478bd9Sstevel@tonic-gate } 22687c478bd9Sstevel@tonic-gate } 22697c478bd9Sstevel@tonic-gate 22707c478bd9Sstevel@tonic-gate /* 22717c478bd9Sstevel@tonic-gate * The read procedure should only be invoked by a keysock consumer, like 22727c478bd9Sstevel@tonic-gate * ESP, AH, etc. I should only see KEYSOCK_OUT and KEYSOCK_HELLO_ACK 22737c478bd9Sstevel@tonic-gate * messages on my read queues. 22747c478bd9Sstevel@tonic-gate */ 22757c478bd9Sstevel@tonic-gate static void 22767c478bd9Sstevel@tonic-gate keysock_rput(queue_t *q, mblk_t *mp) 22777c478bd9Sstevel@tonic-gate { 22787c478bd9Sstevel@tonic-gate keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr; 22797c478bd9Sstevel@tonic-gate ipsec_info_t *ii; 22807c478bd9Sstevel@tonic-gate keysock_hello_ack_t *ksa; 22817c478bd9Sstevel@tonic-gate minor_t serial; 22827c478bd9Sstevel@tonic-gate mblk_t *mp1; 22837c478bd9Sstevel@tonic-gate sadb_msg_t *samsg; 2284f4b3ec61Sdh155122 keysock_stack_t *keystack = kc->kc_keystack; 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate /* Make sure I'm a consumer instance. (i.e. something's below me) */ 22877c478bd9Sstevel@tonic-gate ASSERT(WR(q)->q_next != NULL); 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type != M_CTL) { 22907c478bd9Sstevel@tonic-gate /* 22917c478bd9Sstevel@tonic-gate * Keysock should only see keysock consumer interface 22927c478bd9Sstevel@tonic-gate * messages (see ipsec_info.h) on its read procedure. 22937c478bd9Sstevel@tonic-gate * To be robust, however, putnext() up so the STREAM head can 22947c478bd9Sstevel@tonic-gate * deal with it appropriately. 22957c478bd9Sstevel@tonic-gate */ 2296f4b3ec61Sdh155122 ks1dbg(keystack, 2297f4b3ec61Sdh155122 ("Hmmm, a non M_CTL (%d, 0x%x) on keysock_rput.\n", 22987c478bd9Sstevel@tonic-gate mp->b_datap->db_type, mp->b_datap->db_type)); 22997c478bd9Sstevel@tonic-gate putnext(q, mp); 23007c478bd9Sstevel@tonic-gate return; 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate 23037c478bd9Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate switch (ii->ipsec_info_type) { 23067c478bd9Sstevel@tonic-gate case KEYSOCK_OUT: 23077c478bd9Sstevel@tonic-gate /* 23087c478bd9Sstevel@tonic-gate * A consumer needs to pass a response message or an ACQUIRE 23097c478bd9Sstevel@tonic-gate * UP. I assume that the consumer has done the right 23107c478bd9Sstevel@tonic-gate * thing w.r.t. message creation, etc. 23117c478bd9Sstevel@tonic-gate */ 23127c478bd9Sstevel@tonic-gate serial = ((keysock_out_t *)mp->b_rptr)->ks_out_serial; 23137c478bd9Sstevel@tonic-gate mp1 = mp->b_cont; /* Get M_DATA portion. */ 23147c478bd9Sstevel@tonic-gate freeb(mp); 23157c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp1->b_rptr; 23167c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_FLUSH || 23177c478bd9Sstevel@tonic-gate (samsg->sadb_msg_type == SADB_DUMP && 23187c478bd9Sstevel@tonic-gate samsg->sadb_msg_len == SADB_8TO64(sizeof (*samsg)))) { 23197c478bd9Sstevel@tonic-gate /* 23207c478bd9Sstevel@tonic-gate * If I'm an end-of-FLUSH or an end-of-DUMP marker... 23217c478bd9Sstevel@tonic-gate */ 2322f4b3ec61Sdh155122 ASSERT(keystack->keystack_flushdump != 0); 2323f4b3ec61Sdh155122 /* Am I flushing? */ 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate mutex_enter(&kc->kc_lock); 23267c478bd9Sstevel@tonic-gate kc->kc_flags &= ~KC_FLUSHING; 23277c478bd9Sstevel@tonic-gate mutex_exit(&kc->kc_lock); 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_errno != 0) 2330f4b3ec61Sdh155122 keystack->keystack_flushdump_errno = 2331f4b3ec61Sdh155122 samsg->sadb_msg_errno; 23327c478bd9Sstevel@tonic-gate 23337c478bd9Sstevel@tonic-gate /* 23347c478bd9Sstevel@tonic-gate * Lower the atomic "flushing" count. If it's 23357c478bd9Sstevel@tonic-gate * the last one, send up the end-of-{FLUSH,DUMP} to 23367c478bd9Sstevel@tonic-gate * the appropriate PF_KEY socket. 23377c478bd9Sstevel@tonic-gate */ 2338*1a5e258fSJosef 'Jeff' Sipek if (atomic_dec_32_nv(&keystack->keystack_flushdump) != 2339*1a5e258fSJosef 'Jeff' Sipek 0) { 2340f4b3ec61Sdh155122 ks1dbg(keystack, 2341f4b3ec61Sdh155122 ("One flush/dump message back from %d," 23427c478bd9Sstevel@tonic-gate " more to go.\n", samsg->sadb_msg_satype)); 23437c478bd9Sstevel@tonic-gate freemsg(mp1); 23447c478bd9Sstevel@tonic-gate return; 23457c478bd9Sstevel@tonic-gate } 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = 2348f4b3ec61Sdh155122 (uint8_t)keystack->keystack_flushdump_errno; 23497c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_DUMP) { 23507c478bd9Sstevel@tonic-gate samsg->sadb_msg_seq = 0; 23517c478bd9Sstevel@tonic-gate } 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate keysock_passup(mp1, samsg, serial, kc, 2354f4b3ec61Sdh155122 (samsg->sadb_msg_type == SADB_DUMP), keystack); 23557c478bd9Sstevel@tonic-gate return; 23567c478bd9Sstevel@tonic-gate case KEYSOCK_HELLO_ACK: 23577c478bd9Sstevel@tonic-gate /* Aha, now we can link in the consumer! */ 23587c478bd9Sstevel@tonic-gate ksa = (keysock_hello_ack_t *)ii; 23597c478bd9Sstevel@tonic-gate keysock_link_consumer(ksa->ks_hello_satype, kc); 23607c478bd9Sstevel@tonic-gate freemsg(mp); 23617c478bd9Sstevel@tonic-gate return; 23627c478bd9Sstevel@tonic-gate default: 2363f4b3ec61Sdh155122 ks1dbg(keystack, ("Hmmm, an IPsec info I'm not used to, 0x%x\n", 23647c478bd9Sstevel@tonic-gate ii->ipsec_info_type)); 23657c478bd9Sstevel@tonic-gate putnext(q, mp); 23667c478bd9Sstevel@tonic-gate } 23677c478bd9Sstevel@tonic-gate } 23687c478bd9Sstevel@tonic-gate 23697c478bd9Sstevel@tonic-gate /* 23707c478bd9Sstevel@tonic-gate * So we can avoid external linking problems.... 23717c478bd9Sstevel@tonic-gate */ 23727c478bd9Sstevel@tonic-gate boolean_t 2373f4b3ec61Sdh155122 keysock_extended_reg(netstack_t *ns) 23747c478bd9Sstevel@tonic-gate { 2375f4b3ec61Sdh155122 keysock_stack_t *keystack = ns->netstack_keysock; 2376f4b3ec61Sdh155122 2377f4b3ec61Sdh155122 return (keystack->keystack_num_extended != 0); 23787c478bd9Sstevel@tonic-gate } 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate uint32_t 2381f4b3ec61Sdh155122 keysock_next_seq(netstack_t *ns) 23827c478bd9Sstevel@tonic-gate { 2383f4b3ec61Sdh155122 keysock_stack_t *keystack = ns->netstack_keysock; 2384f4b3ec61Sdh155122 2385*1a5e258fSJosef 'Jeff' Sipek return (atomic_dec_32_nv(&keystack->keystack_acquire_seq)); 23867c478bd9Sstevel@tonic-gate } 2387