xref: /illumos-gate/usr/src/uts/common/inet/ip/keysock.c (revision 4f2d1f9d)
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  */
25f8cbe0e7SDan McDonald /*
26f8cbe0e7SDan McDonald  * Copyright 2017 Joyent, Inc.
27f8cbe0e7SDan McDonald  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/param.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/stream.h>
327c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
337c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
347c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
357c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
36f4b3ec61Sdh #include <sys/zone.h>
377c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
387c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
397c478bd9Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
407c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
417c478bd9Sstevel@tonic-gate #include <sys/timod.h>
427c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
437c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
457c478bd9Sstevel@tonic-gate #include <sys/sunldi.h>
467c478bd9Sstevel@tonic-gate #include <sys/file.h>
477c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
487c478bd9Sstevel@tonic-gate #include <sys/debug.h>
497c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
507c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
517c478bd9Sstevel@tonic-gate #include <sys/proc.h>
527c478bd9Sstevel@tonic-gate #include <sys/suntpi.h>
537c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
547c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
557c478bd9Sstevel@tonic-gate #include <sys/policy.h>
56f4b3ec61Sdh #include <sys/disp.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <sys/socket.h>
597c478bd9Sstevel@tonic-gate #include <netinet/in.h>
607c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h>
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #include <inet/common.h>
637c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
647c478bd9Sstevel@tonic-gate #include <inet/ip.h>
650f1702c5SYu Xiangning #include <inet/proto_set.h>
667c478bd9Sstevel@tonic-gate #include <inet/nd.h>
677c478bd9Sstevel@tonic-gate #include <inet/optcom.h>
687c478bd9Sstevel@tonic-gate #include <inet/ipsec_info.h>
697c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h>
707c478bd9Sstevel@tonic-gate #include <inet/keysock.h>
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * This is a transport provider for the PF_KEY key mangement socket.
767c478bd9Sstevel@tonic-gate  * (See RFC 2367 for details.)
777c478bd9Sstevel@tonic-gate  * Downstream messages are wrapped in a keysock consumer interface KEYSOCK_IN
787c478bd9Sstevel@tonic-gate  * messages (see ipsec_info.h), and passed to the appropriate consumer.
797c478bd9Sstevel@tonic-gate  * Upstream messages are generated for all open PF_KEY sockets, when
807c478bd9Sstevel@tonic-gate  * appropriate, as well as the sender (as long as SO_USELOOPBACK is enabled)
817c478bd9Sstevel@tonic-gate  * in reply to downstream messages.
827c478bd9Sstevel@tonic-gate  *
837c478bd9Sstevel@tonic-gate  * Upstream messages must be created asynchronously for the following
847c478bd9Sstevel@tonic-gate  * situations:
857c478bd9Sstevel@tonic-gate  *
867c478bd9Sstevel@tonic-gate  *	1.) A keysock consumer requires an SA, and there is currently none.
877c478bd9Sstevel@tonic-gate  *	2.) An SA expires, either hard or soft lifetime.
887c478bd9Sstevel@tonic-gate  *	3.) Other events a consumer deems fit.
897c478bd9Sstevel@tonic-gate  *
907c478bd9Sstevel@tonic-gate  * The MT model of this is PERMOD, with shared put procedures.  Two types of
917c478bd9Sstevel@tonic-gate  * messages, SADB_FLUSH and SADB_DUMP, need to lock down the perimeter to send
927c478bd9Sstevel@tonic-gate  * down the *multiple* messages they create.
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate static vmem_t *keysock_vmem;		/* for minor numbers. */
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate #define	KEYSOCK_MAX_CONSUMERS 256
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages (from rts.c...) */
1007c478bd9Sstevel@tonic-gate static struct T_info_ack keysock_g_t_info_ack = {
1017c478bd9Sstevel@tonic-gate 	T_INFO_ACK,
1027c478bd9Sstevel@tonic-gate 	T_INFINITE,	/* TSDU_size. Maximum size messages. */
1037c478bd9Sstevel@tonic-gate 	T_INVALID,	/* ETSDU_size. No expedited data. */
1047c478bd9Sstevel@tonic-gate 	T_INVALID,	/* CDATA_size. No connect data. */
1057c478bd9Sstevel@tonic-gate 	T_INVALID,	/* DDATA_size. No disconnect data. */
1067c478bd9Sstevel@tonic-gate 	0,		/* ADDR_size. */
1077c478bd9Sstevel@tonic-gate 	0,		/* OPT_size. No user-settable options */
1087c478bd9Sstevel@tonic-gate 	64 * 1024,	/* TIDU_size. keysock allows maximum size messages. */
1097c478bd9Sstevel@tonic-gate 	T_COTS,		/* SERV_type. keysock supports connection oriented. */
1107c478bd9Sstevel@tonic-gate 	TS_UNBND,	/* CURRENT_state. This is set from keysock_state. */
1117c478bd9Sstevel@tonic-gate 	(XPG4_1)	/* Provider flags */
1127c478bd9Sstevel@tonic-gate };
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /* Named Dispatch Parameter Management Structure */
115f4b3ec61Sdh typedef struct keysockparam_s {
1167c478bd9Sstevel@tonic-gate 	uint_t	keysock_param_min;
1177c478bd9Sstevel@tonic-gate 	uint_t	keysock_param_max;
1187c478bd9Sstevel@tonic-gate 	uint_t	keysock_param_value;
1197c478bd9Sstevel@tonic-gate 	char	*keysock_param_name;
1207c478bd9Sstevel@tonic-gate } keysockparam_t;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate  * Table of NDD variables supported by keysock. These are loaded into
1247c478bd9Sstevel@tonic-gate  * keysock_g_nd in keysock_init_nd.
1257c478bd9Sstevel@tonic-gate  * All of these are alterable, within the min/max values given, at run time.
1267c478bd9Sstevel@tonic-gate  */
127f4b3ec61Sdh static	keysockparam_t	lcl_param_arr[] = {
1287c478bd9Sstevel@tonic-gate 	/* min	max	value	name */
1297c478bd9Sstevel@tonic-gate 	{ 4096, 65536,	8192,	"keysock_xmit_hiwat"},
1307c478bd9Sstevel@tonic-gate 	{ 0,	65536,	1024,	"keysock_xmit_lowat"},
1317c478bd9Sstevel@tonic-gate 	{ 4096, 65536,	8192,	"keysock_recv_hiwat"},
1327c478bd9Sstevel@tonic-gate 	{ 65536, 1024*1024*1024, 256*1024,	"keysock_max_buf"},
1337c478bd9Sstevel@tonic-gate 	{ 0,	3,	0,	"keysock_debug"},
1347c478bd9Sstevel@tonic-gate };
135f4b3ec61Sdh #define	keystack_xmit_hiwat	keystack_params[0].keysock_param_value
136f4b3ec61Sdh #define	keystack_xmit_lowat	keystack_params[1].keysock_param_value
137f4b3ec61Sdh #define	keystack_recv_hiwat	keystack_params[2].keysock_param_value
138f4b3ec61Sdh #define	keystack_max_buf	keystack_params[3].keysock_param_value
139f4b3ec61Sdh #define	keystack_debug	keystack_params[4].keysock_param_value
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate #define	ks0dbg(a)	printf a
1427c478bd9Sstevel@tonic-gate /* NOTE:  != 0 instead of > 0 so lint doesn't complain. */
143f4b3ec61Sdh #define	ks1dbg(keystack, a)	if (keystack->keystack_debug != 0) printf a
144f4b3ec61Sdh #define	ks2dbg(keystack, a)	if (keystack->keystack_debug > 1) printf a
145f4b3ec61Sdh #define	ks3dbg(keystack, a)	if (keystack->keystack_debug > 2) printf a
1467c478bd9Sstevel@tonic-gate 
1475e1743f0SToomas Soome static int keysock_close(queue_t *, int, cred_t *);
1487c478bd9Sstevel@tonic-gate static int keysock_open(queue_t *, dev_t *, int, int, cred_t *);
149*4f2d1f9dSToomas Soome static int keysock_wput(queue_t *, mblk_t *);
150*4f2d1f9dSToomas Soome static int keysock_rput(queue_t *, mblk_t *);
151*4f2d1f9dSToomas Soome static int keysock_rsrv(queue_t *);
1527c478bd9Sstevel@tonic-gate static void keysock_passup(mblk_t *, sadb_msg_t *, minor_t,
153f4b3ec61Sdh     keysock_consumer_t *, boolean_t, keysock_stack_t *);
154f4b3ec61Sdh static void *keysock_stack_init(netstackid_t stackid, netstack_t *ns);
155f4b3ec61Sdh static void keysock_stack_fini(netstackid_t stackid, void *arg);
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate static struct module_info info = {
1587c478bd9Sstevel@tonic-gate 	5138, "keysock", 1, INFPSZ, 512, 128
1597c478bd9Sstevel@tonic-gate };
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static struct qinit rinit = {
162*4f2d1f9dSToomas Soome 	keysock_rput, keysock_rsrv, keysock_open, keysock_close,
1637c478bd9Sstevel@tonic-gate 	NULL, &info
1647c478bd9Sstevel@tonic-gate };
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static struct qinit winit = {
167*4f2d1f9dSToomas Soome 	keysock_wput, NULL, NULL, NULL, NULL, &info
1687c478bd9Sstevel@tonic-gate };
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate struct streamtab keysockinfo = {
1717c478bd9Sstevel@tonic-gate 	&rinit, &winit
1727c478bd9Sstevel@tonic-gate };
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate extern struct modlinkage *keysock_modlp;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate  * Plumb IPsec.
1787c478bd9Sstevel@tonic-gate  *
1797c478bd9Sstevel@tonic-gate  * NOTE:  New "default" modules will need to be loaded here if needed before
1807c478bd9Sstevel@tonic-gate  *	  boot time.
1817c478bd9Sstevel@tonic-gate  */
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /* Keep these in global space to keep the lint from complaining. */
1847c478bd9Sstevel@tonic-gate static char *IPSECESP = "ipsecesp";
1857c478bd9Sstevel@tonic-gate static char *IPSECESPDEV = "/devices/pseudo/ipsecesp@0:ipsecesp";
1867c478bd9Sstevel@tonic-gate static char *IPSECAH = "ipsecah";
1877c478bd9Sstevel@tonic-gate static char *IPSECAHDEV = "/devices/pseudo/ipsecah@0:ipsecah";
1887c478bd9Sstevel@tonic-gate static char *IP6DEV = "/devices/pseudo/ip6@0:ip6";
1897c478bd9Sstevel@tonic-gate static char *KEYSOCK = "keysock";
1907c478bd9Sstevel@tonic-gate static char *STRMOD = "strmod";
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate  * Load the other ipsec modules and plumb them together.
1947c478bd9Sstevel@tonic-gate  */
1957c478bd9Sstevel@tonic-gate int
keysock_plumb_ipsec(netstack_t * ns)196f4b3ec61Sdh keysock_plumb_ipsec(netstack_t *ns)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate 	ldi_handle_t	lh, ip6_lh = NULL;
1997c478bd9Sstevel@tonic-gate 	ldi_ident_t	li = NULL;
2007c478bd9Sstevel@tonic-gate 	int		err = 0;
2017c478bd9Sstevel@tonic-gate 	int		muxid, rval;
2027c478bd9Sstevel@tonic-gate 	boolean_t	esp_present = B_TRUE;
203f4b3ec61Sdh 	cred_t		*cr;
204f4b3ec61Sdh 	keysock_stack_t *keystack = ns->netstack_keysock;
2057c478bd9Sstevel@tonic-gate 
206f4b3ec61Sdh #ifdef NS_DEBUG
207f4b3ec61Sdh 	(void) printf("keysock_plumb_ipsec(%d)\n",
208f4b3ec61Sdh 	    ns->netstack_stackid);
209f4b3ec61Sdh #endif
2107c478bd9Sstevel@tonic-gate 
211f4b3ec61Sdh 	keystack->keystack_plumbed = 0;	/* we're trying again.. */
2127c478bd9Sstevel@tonic-gate 
213f4b3ec61Sdh 	cr = zone_get_kcred(netstackid_to_zoneid(
214fc80c0dfSnordmark 	    keystack->keystack_netstack->netstack_stackid));
215f4b3ec61Sdh 	ASSERT(cr != NULL);
2167c478bd9Sstevel@tonic-gate 	/*
2177c478bd9Sstevel@tonic-gate 	 * Load up the drivers (AH/ESP).
2187c478bd9Sstevel@tonic-gate 	 *
2197c478bd9Sstevel@tonic-gate 	 * I do this separately from the actual plumbing in case this function
2207c478bd9Sstevel@tonic-gate 	 * ever gets called from a diskless boot before the root filesystem is
2217c478bd9Sstevel@tonic-gate 	 * up.  I don't have to worry about "keysock" because, well, if I'm
2227c478bd9Sstevel@tonic-gate 	 * here, keysock must've loaded successfully.
2237c478bd9Sstevel@tonic-gate 	 */
2247c478bd9Sstevel@tonic-gate 	if (i_ddi_attach_pseudo_node(IPSECAH) == NULL) {
2257c478bd9Sstevel@tonic-gate 		ks0dbg(("IPsec:  AH failed to attach.\n"));
2267c478bd9Sstevel@tonic-gate 		goto bail;
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 	if (i_ddi_attach_pseudo_node(IPSECESP) == NULL) {
2297c478bd9Sstevel@tonic-gate 		ks0dbg(("IPsec:  ESP failed to attach.\n"));
2307c478bd9Sstevel@tonic-gate 		esp_present = B_FALSE;
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/*
2347c478bd9Sstevel@tonic-gate 	 * Set up the IP streams for AH and ESP, as well as tacking keysock
2357c478bd9Sstevel@tonic-gate 	 * on top of them.  Assume keysock has set the autopushes up already.
2367c478bd9Sstevel@tonic-gate 	 */
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	/* Open IP. */
2397c478bd9Sstevel@tonic-gate 	err = ldi_ident_from_mod(keysock_modlp, &li);
2407c478bd9Sstevel@tonic-gate 	if (err) {
2417c478bd9Sstevel@tonic-gate 		ks0dbg(("IPsec:  lid_ident_from_mod failed (err %d).\n",
2427c478bd9Sstevel@tonic-gate 		    err));
2437c478bd9Sstevel@tonic-gate 		goto bail;
2447c478bd9Sstevel@tonic-gate 	}
2457c478bd9Sstevel@tonic-gate 
246f4b3ec61Sdh 	err = ldi_open_by_name(IP6DEV, FREAD|FWRITE, cr, &ip6_lh, li);
2477c478bd9Sstevel@tonic-gate 	if (err) {
2487c478bd9Sstevel@tonic-gate 		ks0dbg(("IPsec:  Open of IP6 failed (err %d).\n", err));
2497c478bd9Sstevel@tonic-gate 		goto bail;
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	/* PLINK KEYSOCK/AH */
253f4b3ec61Sdh 	err = ldi_open_by_name(IPSECAHDEV, FREAD|FWRITE, cr, &lh, li);
2547c478bd9Sstevel@tonic-gate 	if (err) {
2557c478bd9Sstevel@tonic-gate 		ks0dbg(("IPsec:  Open of AH failed (err %d).\n", err));
2567c478bd9Sstevel@tonic-gate 		goto bail;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 	err = ldi_ioctl(lh,
259f4b3ec61Sdh 	    I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, cr, &rval);
2607c478bd9Sstevel@tonic-gate 	if (err) {
2617c478bd9Sstevel@tonic-gate 		ks0dbg(("IPsec:  Push of KEYSOCK onto AH failed (err %d).\n",
2627c478bd9Sstevel@tonic-gate 		    err));
263f4b3ec61Sdh 		(void) ldi_close(lh, FREAD|FWRITE, cr);
2647c478bd9Sstevel@tonic-gate 		goto bail;
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 	err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh,
267fc80c0dfSnordmark 	    FREAD+FWRITE+FNOCTTY+FKIOCTL, cr, &muxid);
2687c478bd9Sstevel@tonic-gate 	if (err) {
2697c478bd9Sstevel@tonic-gate 		ks0dbg(("IPsec:  PLINK of KEYSOCK/AH failed (err %d).\n", err));
270f4b3ec61Sdh 		(void) ldi_close(lh, FREAD|FWRITE, cr);
2717c478bd9Sstevel@tonic-gate 		goto bail;
2727c478bd9Sstevel@tonic-gate 	}
273f4b3ec61Sdh 	(void) ldi_close(lh, FREAD|FWRITE, cr);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/* PLINK KEYSOCK/ESP */
2767c478bd9Sstevel@tonic-gate 	if (esp_present) {
2777c478bd9Sstevel@tonic-gate 		err = ldi_open_by_name(IPSECESPDEV,
278f4b3ec61Sdh 		    FREAD|FWRITE, cr, &lh, li);
2797c478bd9Sstevel@tonic-gate 		if (err) {
2807c478bd9Sstevel@tonic-gate 			ks0dbg(("IPsec:  Open of ESP failed (err %d).\n", err));
2817c478bd9Sstevel@tonic-gate 			goto bail;
2827c478bd9Sstevel@tonic-gate 		}
2837c478bd9Sstevel@tonic-gate 		err = ldi_ioctl(lh,
284f4b3ec61Sdh 		    I_PUSH, (intptr_t)KEYSOCK, FKIOCTL, cr, &rval);
2857c478bd9Sstevel@tonic-gate 		if (err) {
2867c478bd9Sstevel@tonic-gate 			ks0dbg(("IPsec:  "
2877c478bd9Sstevel@tonic-gate 			    "Push of KEYSOCK onto ESP failed (err %d).\n",
2887c478bd9Sstevel@tonic-gate 			    err));
289f4b3ec61Sdh 			(void) ldi_close(lh, FREAD|FWRITE, cr);
2907c478bd9Sstevel@tonic-gate 			goto bail;
2917c478bd9Sstevel@tonic-gate 		}
2927c478bd9Sstevel@tonic-gate 		err = ldi_ioctl(ip6_lh, I_PLINK, (intptr_t)lh,
293fc80c0dfSnordmark 		    FREAD+FWRITE+FNOCTTY+FKIOCTL, cr, &muxid);
2947c478bd9Sstevel@tonic-gate 		if (err) {
2957c478bd9Sstevel@tonic-gate 			ks0dbg(("IPsec:  "
2967c478bd9Sstevel@tonic-gate 			    "PLINK of KEYSOCK/ESP failed (err %d).\n", err));
297f4b3ec61Sdh 			(void) ldi_close(lh, FREAD|FWRITE, cr);
2987c478bd9Sstevel@tonic-gate 			goto bail;
2997c478bd9Sstevel@tonic-gate 		}
300f4b3ec61Sdh 		(void) ldi_close(lh, FREAD|FWRITE, cr);
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate bail:
304f4b3ec61Sdh 	keystack->keystack_plumbed = (err == 0) ? 1 : -1;
3057c478bd9Sstevel@tonic-gate 	if (ip6_lh != NULL) {
306f4b3ec61Sdh 		(void) ldi_close(ip6_lh, FREAD|FWRITE, cr);
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 	if (li != NULL)
3097c478bd9Sstevel@tonic-gate 		ldi_ident_release(li);
310f4b3ec61Sdh #ifdef NS_DEBUG
311f4b3ec61Sdh 	(void) printf("keysock_plumb_ipsec -> %d\n",
312f4b3ec61Sdh 	    keystack->keystack_plumbed);
313f4b3ec61Sdh #endif
314f4b3ec61Sdh 	crfree(cr);
3157c478bd9Sstevel@tonic-gate 	return (err);
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate /* ARGSUSED */
3197c478bd9Sstevel@tonic-gate static int
keysock_param_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * cr)320f8cbe0e7SDan McDonald keysock_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	keysockparam_t	*keysockpa = (keysockparam_t *)cp;
3237c478bd9Sstevel@tonic-gate 	uint_t value;
324f4b3ec61Sdh 	keysock_t *ks = (keysock_t *)q->q_ptr;
325f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
3267c478bd9Sstevel@tonic-gate 
327f4b3ec61Sdh 	mutex_enter(&keystack->keystack_param_lock);
3287c478bd9Sstevel@tonic-gate 	value = keysockpa->keysock_param_value;
329f4b3ec61Sdh 	mutex_exit(&keystack->keystack_param_lock);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	(void) mi_mpprintf(mp, "%u", value);
3327c478bd9Sstevel@tonic-gate 	return (0);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /* This routine sets an NDD variable in a keysockparam_t structure. */
3367c478bd9Sstevel@tonic-gate /* ARGSUSED */
3377c478bd9Sstevel@tonic-gate static int
keysock_param_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp,cred_t * cr)338f8cbe0e7SDan McDonald keysock_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate 	ulong_t	new_value;
3417c478bd9Sstevel@tonic-gate 	keysockparam_t	*keysockpa = (keysockparam_t *)cp;
342f4b3ec61Sdh 	keysock_t *ks = (keysock_t *)q->q_ptr;
343f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	/* Convert the value from a string into a long integer. */
3467c478bd9Sstevel@tonic-gate 	if (ddi_strtoul(value, NULL, 10, &new_value) != 0)
3477c478bd9Sstevel@tonic-gate 		return (EINVAL);
3487c478bd9Sstevel@tonic-gate 
349f4b3ec61Sdh 	mutex_enter(&keystack->keystack_param_lock);
3507c478bd9Sstevel@tonic-gate 	/*
3517c478bd9Sstevel@tonic-gate 	 * Fail the request if the new value does not lie within the
3527c478bd9Sstevel@tonic-gate 	 * required bounds.
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate 	if (new_value < keysockpa->keysock_param_min ||
3557c478bd9Sstevel@tonic-gate 	    new_value > keysockpa->keysock_param_max) {
356f4b3ec61Sdh 		mutex_exit(&keystack->keystack_param_lock);
3577c478bd9Sstevel@tonic-gate 		return (EINVAL);
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/* Set the new value */
3617c478bd9Sstevel@tonic-gate 	keysockpa->keysock_param_value = new_value;
362f4b3ec61Sdh 	mutex_exit(&keystack->keystack_param_lock);
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	return (0);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate /*
368f4b3ec61Sdh  * Initialize keysock at module load time
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate boolean_t
keysock_ddi_init(void)3717c478bd9Sstevel@tonic-gate keysock_ddi_init(void)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	keysock_max_optsize = optcom_max_optsize(
3747c478bd9Sstevel@tonic-gate 	    keysock_opt_obj.odb_opt_des_arr, keysock_opt_obj.odb_opt_arr_cnt);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	keysock_vmem = vmem_create("keysock", (void *)1, MAXMIN, 1,
3777c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER);
3787c478bd9Sstevel@tonic-gate 
379f4b3ec61Sdh 	/*
380f4b3ec61Sdh 	 * We want to be informed each time a stack is created or
381f4b3ec61Sdh 	 * destroyed in the kernel, so we can maintain the
382f4b3ec61Sdh 	 * set of keysock_stack_t's.
383f4b3ec61Sdh 	 */
384f4b3ec61Sdh 	netstack_register(NS_KEYSOCK, keysock_stack_init, NULL,
385f4b3ec61Sdh 	    keysock_stack_fini);
386f4b3ec61Sdh 
387f4b3ec61Sdh 	return (B_TRUE);
388f4b3ec61Sdh }
3897c478bd9Sstevel@tonic-gate 
390f4b3ec61Sdh /*
391f4b3ec61Sdh  * Walk through the param array specified registering each element with the
392f4b3ec61Sdh  * named dispatch handler.
393f4b3ec61Sdh  */
394f4b3ec61Sdh static boolean_t
keysock_param_register(IDP * ndp,keysockparam_t * ksp,int cnt)395f4b3ec61Sdh keysock_param_register(IDP *ndp, keysockparam_t *ksp, int cnt)
396f4b3ec61Sdh {
397f4b3ec61Sdh 	for (; cnt-- > 0; ksp++) {
398f4b3ec61Sdh 		if (ksp->keysock_param_name != NULL &&
399f4b3ec61Sdh 		    ksp->keysock_param_name[0]) {
400f4b3ec61Sdh 			if (!nd_load(ndp,
401f4b3ec61Sdh 			    ksp->keysock_param_name,
402f4b3ec61Sdh 			    keysock_param_get, keysock_param_set,
403f4b3ec61Sdh 			    (caddr_t)ksp)) {
404f4b3ec61Sdh 				nd_free(ndp);
405f4b3ec61Sdh 				return (B_FALSE);
406f4b3ec61Sdh 			}
407f4b3ec61Sdh 		}
408f4b3ec61Sdh 	}
4097c478bd9Sstevel@tonic-gate 	return (B_TRUE);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
412f4b3ec61Sdh /*
413f4b3ec61Sdh  * Initialize keysock for one stack instance
414f4b3ec61Sdh  */
415f4b3ec61Sdh /* ARGSUSED */
416f4b3ec61Sdh static void *
keysock_stack_init(netstackid_t stackid,netstack_t * ns)417f4b3ec61Sdh keysock_stack_init(netstackid_t stackid, netstack_t *ns)
418f4b3ec61Sdh {
419f4b3ec61Sdh 	keysock_stack_t	*keystack;
420f4b3ec61Sdh 	keysockparam_t *ksp;
421f4b3ec61Sdh 
422f4b3ec61Sdh 	keystack = (keysock_stack_t *)kmem_zalloc(sizeof (*keystack), KM_SLEEP);
423f4b3ec61Sdh 	keystack->keystack_netstack = ns;
424f4b3ec61Sdh 
425f4b3ec61Sdh 	keystack->keystack_acquire_seq = 0xffffffff;
426f4b3ec61Sdh 
427f4b3ec61Sdh 	ksp = (keysockparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP);
428f4b3ec61Sdh 	keystack->keystack_params = ksp;
429f4b3ec61Sdh 	bcopy(lcl_param_arr, ksp, sizeof (lcl_param_arr));
430f4b3ec61Sdh 
431f4b3ec61Sdh 	(void) keysock_param_register(&keystack->keystack_g_nd, ksp,
432f4b3ec61Sdh 	    A_CNT(lcl_param_arr));
433f4b3ec61Sdh 
434f4b3ec61Sdh 	mutex_init(&keystack->keystack_list_lock, NULL, MUTEX_DEFAULT, NULL);
435f4b3ec61Sdh 	mutex_init(&keystack->keystack_consumers_lock,
436f4b3ec61Sdh 	    NULL, MUTEX_DEFAULT, NULL);
437f4b3ec61Sdh 	mutex_init(&keystack->keystack_param_lock, NULL, MUTEX_DEFAULT, NULL);
438f4b3ec61Sdh 	return (keystack);
439f4b3ec61Sdh }
440f4b3ec61Sdh 
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate  * Free NDD variable space, and other destructors, for keysock.
4437c478bd9Sstevel@tonic-gate  */
4447c478bd9Sstevel@tonic-gate void
keysock_ddi_destroy(void)4457c478bd9Sstevel@tonic-gate keysock_ddi_destroy(void)
4467c478bd9Sstevel@tonic-gate {
447f4b3ec61Sdh 	netstack_unregister(NS_KEYSOCK);
4487c478bd9Sstevel@tonic-gate 	vmem_destroy(keysock_vmem);
449f4b3ec61Sdh }
450f4b3ec61Sdh 
451f4b3ec61Sdh /*
452f4b3ec61Sdh  * Remove one stack instance from keysock
453f4b3ec61Sdh  */
454f4b3ec61Sdh /* ARGSUSED */
455f4b3ec61Sdh static void
keysock_stack_fini(netstackid_t stackid,void * arg)456f4b3ec61Sdh keysock_stack_fini(netstackid_t stackid, void *arg)
457f4b3ec61Sdh {
458f4b3ec61Sdh 	keysock_stack_t *keystack = (keysock_stack_t *)arg;
459f4b3ec61Sdh 
460f4b3ec61Sdh 	nd_free(&keystack->keystack_g_nd);
461f4b3ec61Sdh 	kmem_free(keystack->keystack_params, sizeof (lcl_param_arr));
462f4b3ec61Sdh 	keystack->keystack_params = NULL;
463f4b3ec61Sdh 
464f4b3ec61Sdh 	mutex_destroy(&keystack->keystack_list_lock);
465f4b3ec61Sdh 	mutex_destroy(&keystack->keystack_consumers_lock);
466f4b3ec61Sdh 	mutex_destroy(&keystack->keystack_param_lock);
467f4b3ec61Sdh 
468f4b3ec61Sdh 	kmem_free(keystack, sizeof (*keystack));
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate /*
4727c478bd9Sstevel@tonic-gate  * Close routine for keysock.
4737c478bd9Sstevel@tonic-gate  */
4745e1743f0SToomas Soome /* ARGSUSED */
4757c478bd9Sstevel@tonic-gate static int
keysock_close(queue_t * q,int flags __unused,cred_t * credp __unused)4765e1743f0SToomas Soome keysock_close(queue_t *q, int flags __unused, cred_t *credp __unused)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate 	keysock_t *ks;
4797c478bd9Sstevel@tonic-gate 	keysock_consumer_t *kc;
4807c478bd9Sstevel@tonic-gate 	void *ptr = q->q_ptr;
4817c478bd9Sstevel@tonic-gate 	int size;
482f4b3ec61Sdh 	keysock_stack_t	*keystack;
483f4b3ec61Sdh 
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	qprocsoff(q);
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/* Safe assumption. */
4887c478bd9Sstevel@tonic-gate 	ASSERT(ptr != NULL);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (WR(q)->q_next) {
4917c478bd9Sstevel@tonic-gate 		kc = (keysock_consumer_t *)ptr;
492f4b3ec61Sdh 		keystack = kc->kc_keystack;
493f4b3ec61Sdh 
494f4b3ec61Sdh 		ks1dbg(keystack, ("Module close, removing a consumer (%d).\n",
4957c478bd9Sstevel@tonic-gate 		    kc->kc_sa_type));
4967c478bd9Sstevel@tonic-gate 		/*
4977c478bd9Sstevel@tonic-gate 		 * Because of PERMOD open/close exclusive perimeter, I
4987c478bd9Sstevel@tonic-gate 		 * can inspect KC_FLUSHING w/o locking down kc->kc_lock.
4997c478bd9Sstevel@tonic-gate 		 */
5007c478bd9Sstevel@tonic-gate 		if (kc->kc_flags & KC_FLUSHING) {
5017c478bd9Sstevel@tonic-gate 			/*
5027c478bd9Sstevel@tonic-gate 			 * If this decrement was the last one, send
5037c478bd9Sstevel@tonic-gate 			 * down the next pending one, if any.
5047c478bd9Sstevel@tonic-gate 			 *
5057c478bd9Sstevel@tonic-gate 			 * With a PERMOD perimeter, the mutexes ops aren't
5067c478bd9Sstevel@tonic-gate 			 * really necessary, but if we ever loosen up, we will
5077c478bd9Sstevel@tonic-gate 			 * have this bit covered already.
5087c478bd9Sstevel@tonic-gate 			 */
509f4b3ec61Sdh 			keystack->keystack_flushdump--;
510f4b3ec61Sdh 			if (keystack->keystack_flushdump == 0) {
5117c478bd9Sstevel@tonic-gate 				/*
5127c478bd9Sstevel@tonic-gate 				 * The flush/dump terminated by having a
5137c478bd9Sstevel@tonic-gate 				 * consumer go away.  I need to send up to the
5147c478bd9Sstevel@tonic-gate 				 * appropriate keysock all of the relevant
5157c478bd9Sstevel@tonic-gate 				 * information.  Unfortunately, I don't
5167c478bd9Sstevel@tonic-gate 				 * have that handy.
5177c478bd9Sstevel@tonic-gate 				 */
5187c478bd9Sstevel@tonic-gate 				ks0dbg(("Consumer went away while flushing or"
5197c478bd9Sstevel@tonic-gate 				    " dumping.\n"));
5207c478bd9Sstevel@tonic-gate 			}
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 		size = sizeof (keysock_consumer_t);
523f4b3ec61Sdh 		mutex_enter(&keystack->keystack_consumers_lock);
524f4b3ec61Sdh 		keystack->keystack_consumers[kc->kc_sa_type] = NULL;
525f4b3ec61Sdh 		mutex_exit(&keystack->keystack_consumers_lock);
5267c478bd9Sstevel@tonic-gate 		mutex_destroy(&kc->kc_lock);
527f4b3ec61Sdh 		netstack_rele(kc->kc_keystack->keystack_netstack);
5287c478bd9Sstevel@tonic-gate 	} else {
5297c478bd9Sstevel@tonic-gate 		ks = (keysock_t *)ptr;
530f4b3ec61Sdh 		keystack = ks->keysock_keystack;
531f4b3ec61Sdh 
532f4b3ec61Sdh 		ks3dbg(keystack,
533f4b3ec61Sdh 		    ("Driver close, PF_KEY socket is going away.\n"));
5347c478bd9Sstevel@tonic-gate 		if ((ks->keysock_flags & KEYSOCK_EXTENDED) != 0)
5351a5e258fSJosef 'Jeff' Sipek 			atomic_dec_32(&keystack->keystack_num_extended);
5367c478bd9Sstevel@tonic-gate 		size = sizeof (keysock_t);
537f4b3ec61Sdh 		mutex_enter(&keystack->keystack_list_lock);
5387c478bd9Sstevel@tonic-gate 		*(ks->keysock_ptpn) = ks->keysock_next;
5397c478bd9Sstevel@tonic-gate 		if (ks->keysock_next != NULL)
5407c478bd9Sstevel@tonic-gate 			ks->keysock_next->keysock_ptpn = ks->keysock_ptpn;
541f4b3ec61Sdh 		mutex_exit(&keystack->keystack_list_lock);
5427c478bd9Sstevel@tonic-gate 		mutex_destroy(&ks->keysock_lock);
5431dc8613eSdanmcd 		vmem_free(keysock_vmem, (void *)(uintptr_t)ks->keysock_serial,
5441dc8613eSdanmcd 		    1);
545f4b3ec61Sdh 		netstack_rele(ks->keysock_keystack->keystack_netstack);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	/* Now I'm free. */
5497c478bd9Sstevel@tonic-gate 	kmem_free(ptr, size);
5507c478bd9Sstevel@tonic-gate 	return (0);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate /*
5537c478bd9Sstevel@tonic-gate  * Open routine for keysock.
5547c478bd9Sstevel@tonic-gate  */
5557c478bd9Sstevel@tonic-gate /* ARGSUSED */
5567c478bd9Sstevel@tonic-gate static int
keysock_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)5577c478bd9Sstevel@tonic-gate keysock_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate 	keysock_t *ks;
5607c478bd9Sstevel@tonic-gate 	keysock_consumer_t *kc;
5617c478bd9Sstevel@tonic-gate 	mblk_t *mp;
5627c478bd9Sstevel@tonic-gate 	ipsec_info_t *ii;
563f4b3ec61Sdh 	netstack_t *ns;
564f4b3ec61Sdh 	keysock_stack_t *keystack;
5657c478bd9Sstevel@tonic-gate 
566f4b3ec61Sdh 	if (secpolicy_ip_config(credp, B_FALSE) != 0) {
5677c478bd9Sstevel@tonic-gate 		/* Privilege debugging will log the error */
5687c478bd9Sstevel@tonic-gate 		return (EPERM);
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL)
5727c478bd9Sstevel@tonic-gate 		return (0);  /* Re-open of an already open instance. */
5737c478bd9Sstevel@tonic-gate 
574f4b3ec61Sdh 	ns = netstack_find_by_cred(credp);
575f4b3ec61Sdh 	ASSERT(ns != NULL);
576f4b3ec61Sdh 	keystack = ns->netstack_keysock;
577f4b3ec61Sdh 	ASSERT(keystack != NULL);
578f4b3ec61Sdh 
579f4b3ec61Sdh 	ks3dbg(keystack, ("Entering keysock open.\n"));
580f4b3ec61Sdh 
581f4b3ec61Sdh 	if (keystack->keystack_plumbed < 1) {
582f4b3ec61Sdh 		netstack_t *ns = keystack->keystack_netstack;
583f4b3ec61Sdh 
584f4b3ec61Sdh 		keystack->keystack_plumbed = 0;
585f4b3ec61Sdh #ifdef NS_DEBUG
586f4b3ec61Sdh 		printf("keysock_open(%d) - plumb\n",
587f4b3ec61Sdh 		    keystack->keystack_netstack->netstack_stackid);
588f4b3ec61Sdh #endif
5897c478bd9Sstevel@tonic-gate 		/*
5907c478bd9Sstevel@tonic-gate 		 * Don't worry about ipsec_failure being true here.
5917c478bd9Sstevel@tonic-gate 		 * (See ip.c).  An open of keysock should try and force
5927c478bd9Sstevel@tonic-gate 		 * the issue.  Maybe it was a transient failure.
5937c478bd9Sstevel@tonic-gate 		 */
594f4b3ec61Sdh 		ipsec_loader_loadnow(ns->netstack_ipsec);
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	if (sflag & MODOPEN) {
5987c478bd9Sstevel@tonic-gate 		/* Initialize keysock_consumer state here. */
5997c478bd9Sstevel@tonic-gate 		kc = kmem_zalloc(sizeof (keysock_consumer_t), KM_NOSLEEP);
600f4b3ec61Sdh 		if (kc == NULL) {
601f4b3ec61Sdh 			netstack_rele(keystack->keystack_netstack);
6027c478bd9Sstevel@tonic-gate 			return (ENOMEM);
603f4b3ec61Sdh 		}
6047c478bd9Sstevel@tonic-gate 		mutex_init(&kc->kc_lock, NULL, MUTEX_DEFAULT, 0);
6057c478bd9Sstevel@tonic-gate 		kc->kc_rq = q;
6067c478bd9Sstevel@tonic-gate 		kc->kc_wq = WR(q);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 		q->q_ptr = kc;
6097c478bd9Sstevel@tonic-gate 		WR(q)->q_ptr = kc;
6107c478bd9Sstevel@tonic-gate 
611f4b3ec61Sdh 		kc->kc_keystack = keystack;
6127c478bd9Sstevel@tonic-gate 		qprocson(q);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 		/*
6157c478bd9Sstevel@tonic-gate 		 * Send down initial message to whatever I was pushed on top
6167c478bd9Sstevel@tonic-gate 		 * of asking for its consumer type.  The reply will set it.
6177c478bd9Sstevel@tonic-gate 		 */
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 		/* Allocate it. */
6207c478bd9Sstevel@tonic-gate 		mp = allocb(sizeof (ipsec_info_t), BPRI_HI);
6217c478bd9Sstevel@tonic-gate 		if (mp == NULL) {
622f4b3ec61Sdh 			ks1dbg(keystack, (
6237c478bd9Sstevel@tonic-gate 			    "keysock_open:  Cannot allocate KEYSOCK_HELLO.\n"));
6247c478bd9Sstevel@tonic-gate 			/* Do I need to set these to null? */
6257c478bd9Sstevel@tonic-gate 			q->q_ptr = NULL;
6267c478bd9Sstevel@tonic-gate 			WR(q)->q_ptr = NULL;
6277c478bd9Sstevel@tonic-gate 			mutex_destroy(&kc->kc_lock);
6287c478bd9Sstevel@tonic-gate 			kmem_free(kc, sizeof (*kc));
629f4b3ec61Sdh 			netstack_rele(keystack->keystack_netstack);
6307c478bd9Sstevel@tonic-gate 			return (ENOMEM);
6317c478bd9Sstevel@tonic-gate 		}
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 		/* If I allocated okay, putnext to what I was pushed atop. */
6347c478bd9Sstevel@tonic-gate 		mp->b_wptr += sizeof (ipsec_info_t);
6357c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_CTL;
6367c478bd9Sstevel@tonic-gate 		ii = (ipsec_info_t *)mp->b_rptr;
6377c478bd9Sstevel@tonic-gate 		ii->ipsec_info_type = KEYSOCK_HELLO;
6387c478bd9Sstevel@tonic-gate 		/* Length only of type/len. */
6397c478bd9Sstevel@tonic-gate 		ii->ipsec_info_len = sizeof (ii->ipsec_allu);
640f4b3ec61Sdh 		ks2dbg(keystack, ("Ready to putnext KEYSOCK_HELLO.\n"));
6417c478bd9Sstevel@tonic-gate 		putnext(kc->kc_wq, mp);
6427c478bd9Sstevel@tonic-gate 	} else {
6437c478bd9Sstevel@tonic-gate 		minor_t ksminor;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 		/* Initialize keysock state. */
6467c478bd9Sstevel@tonic-gate 
647f4b3ec61Sdh 		ks2dbg(keystack, ("Made it into PF_KEY socket open.\n"));
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 		ksminor = (minor_t)(uintptr_t)
6507c478bd9Sstevel@tonic-gate 		    vmem_alloc(keysock_vmem, 1, VM_NOSLEEP);
651f4b3ec61Sdh 		if (ksminor == 0) {
652f4b3ec61Sdh 			netstack_rele(keystack->keystack_netstack);
6537c478bd9Sstevel@tonic-gate 			return (ENOMEM);
654f4b3ec61Sdh 		}
6557c478bd9Sstevel@tonic-gate 		ks = kmem_zalloc(sizeof (keysock_t), KM_NOSLEEP);
6567c478bd9Sstevel@tonic-gate 		if (ks == NULL) {
6577c478bd9Sstevel@tonic-gate 			vmem_free(keysock_vmem, (void *)(uintptr_t)ksminor, 1);
658f4b3ec61Sdh 			netstack_rele(keystack->keystack_netstack);
6597c478bd9Sstevel@tonic-gate 			return (ENOMEM);
6607c478bd9Sstevel@tonic-gate 		}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 		mutex_init(&ks->keysock_lock, NULL, MUTEX_DEFAULT, 0);
6637c478bd9Sstevel@tonic-gate 		ks->keysock_rq = q;
6647c478bd9Sstevel@tonic-gate 		ks->keysock_wq = WR(q);
6657c478bd9Sstevel@tonic-gate 		ks->keysock_state = TS_UNBND;
6667c478bd9Sstevel@tonic-gate 		ks->keysock_serial = ksminor;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 		q->q_ptr = ks;
6697c478bd9Sstevel@tonic-gate 		WR(q)->q_ptr = ks;
670f4b3ec61Sdh 		ks->keysock_keystack = keystack;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 		/*
6737c478bd9Sstevel@tonic-gate 		 * The receive hiwat is only looked at on the stream head
6747c478bd9Sstevel@tonic-gate 		 * queue.  Store in q_hiwat in order to return on SO_RCVBUF
6757c478bd9Sstevel@tonic-gate 		 * getsockopts.
6767c478bd9Sstevel@tonic-gate 		 */
6777c478bd9Sstevel@tonic-gate 
678f4b3ec61Sdh 		q->q_hiwat = keystack->keystack_recv_hiwat;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 		/*
6817c478bd9Sstevel@tonic-gate 		 * The transmit hiwat/lowat is only looked at on IP's queue.
6827c478bd9Sstevel@tonic-gate 		 * Store in q_hiwat/q_lowat in order to return on
6837c478bd9Sstevel@tonic-gate 		 * SO_SNDBUF/SO_SNDLOWAT getsockopts.
6847c478bd9Sstevel@tonic-gate 		 */
6857c478bd9Sstevel@tonic-gate 
686f4b3ec61Sdh 		WR(q)->q_hiwat = keystack->keystack_xmit_hiwat;
687f4b3ec61Sdh 		WR(q)->q_lowat = keystack->keystack_xmit_lowat;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 		*devp = makedevice(getmajor(*devp), ksminor);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 		/*
6927c478bd9Sstevel@tonic-gate 		 * Thread keysock into the global keysock list.
6937c478bd9Sstevel@tonic-gate 		 */
694f4b3ec61Sdh 		mutex_enter(&keystack->keystack_list_lock);
695f4b3ec61Sdh 		ks->keysock_next = keystack->keystack_list;
696f4b3ec61Sdh 		ks->keysock_ptpn = &keystack->keystack_list;
697f4b3ec61Sdh 		if (keystack->keystack_list != NULL) {
698f4b3ec61Sdh 			keystack->keystack_list->keysock_ptpn =
699f4b3ec61Sdh 			    &ks->keysock_next;
700f4b3ec61Sdh 		}
701f4b3ec61Sdh 		keystack->keystack_list = ks;
702f4b3ec61Sdh 		mutex_exit(&keystack->keystack_list_lock);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 		qprocson(q);
7050f1702c5SYu Xiangning 		(void) proto_set_rx_hiwat(q, NULL,
7060f1702c5SYu Xiangning 		    keystack->keystack_recv_hiwat);
7077c478bd9Sstevel@tonic-gate 		/*
7087c478bd9Sstevel@tonic-gate 		 * Wait outside the keysock module perimeter for IPsec
7097c478bd9Sstevel@tonic-gate 		 * plumbing to be completed.  If it fails, keysock_close()
7107c478bd9Sstevel@tonic-gate 		 * undoes everything we just did.
7117c478bd9Sstevel@tonic-gate 		 */
712f4b3ec61Sdh 		if (!ipsec_loader_wait(q,
713f4b3ec61Sdh 		    keystack->keystack_netstack->netstack_ipsec)) {
7145e1743f0SToomas Soome 			(void) keysock_close(q, 0, credp);
7157c478bd9Sstevel@tonic-gate 			return (EPFNOSUPPORT);
7167c478bd9Sstevel@tonic-gate 		}
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	return (0);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_wput(). */
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate /*
7257c478bd9Sstevel@tonic-gate  * Copy relevant state bits.
7267c478bd9Sstevel@tonic-gate  */
7277c478bd9Sstevel@tonic-gate static void
keysock_copy_info(struct T_info_ack * tap,keysock_t * ks)7287c478bd9Sstevel@tonic-gate keysock_copy_info(struct T_info_ack *tap, keysock_t *ks)
7297c478bd9Sstevel@tonic-gate {
7307c478bd9Sstevel@tonic-gate 	*tap = keysock_g_t_info_ack;
7317c478bd9Sstevel@tonic-gate 	tap->CURRENT_state = ks->keysock_state;
7327c478bd9Sstevel@tonic-gate 	tap->OPT_size = keysock_max_optsize;
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate /*
7367c478bd9Sstevel@tonic-gate  * This routine responds to T_CAPABILITY_REQ messages.  It is called by
7377c478bd9Sstevel@tonic-gate  * keysock_wput.  Much of the T_CAPABILITY_ACK information is copied from
7387c478bd9Sstevel@tonic-gate  * keysock_g_t_info_ack.  The current state of the stream is copied from
7397c478bd9Sstevel@tonic-gate  * keysock_state.
7407c478bd9Sstevel@tonic-gate  */
7417c478bd9Sstevel@tonic-gate static void
keysock_capability_req(queue_t * q,mblk_t * mp)7427c478bd9Sstevel@tonic-gate keysock_capability_req(queue_t *q, mblk_t *mp)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate 	keysock_t *ks = (keysock_t *)q->q_ptr;
7457c478bd9Sstevel@tonic-gate 	t_uscalar_t cap_bits1;
7467c478bd9Sstevel@tonic-gate 	struct T_capability_ack	*tcap;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack),
751fc80c0dfSnordmark 	    mp->b_datap->db_type, T_CAPABILITY_ACK);
7527c478bd9Sstevel@tonic-gate 	if (mp == NULL)
7537c478bd9Sstevel@tonic-gate 		return;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	tcap = (struct T_capability_ack *)mp->b_rptr;
7567c478bd9Sstevel@tonic-gate 	tcap->CAP_bits1 = 0;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if (cap_bits1 & TC1_INFO) {
7597c478bd9Sstevel@tonic-gate 		keysock_copy_info(&tcap->INFO_ack, ks);
7607c478bd9Sstevel@tonic-gate 		tcap->CAP_bits1 |= TC1_INFO;
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	qreply(q, mp);
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate /*
7677c478bd9Sstevel@tonic-gate  * This routine responds to T_INFO_REQ messages. It is called by
7687c478bd9Sstevel@tonic-gate  * keysock_wput_other.
7697c478bd9Sstevel@tonic-gate  * Most of the T_INFO_ACK information is copied from keysock_g_t_info_ack.
7707c478bd9Sstevel@tonic-gate  * The current state of the stream is copied from keysock_state.
7717c478bd9Sstevel@tonic-gate  */
7727c478bd9Sstevel@tonic-gate static void
keysock_info_req(queue_t * q,mblk_t * mp)773f8cbe0e7SDan McDonald keysock_info_req(queue_t *q, mblk_t *mp)
7747c478bd9Sstevel@tonic-gate {
7757c478bd9Sstevel@tonic-gate 	mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO,
7767c478bd9Sstevel@tonic-gate 	    T_INFO_ACK);
7777c478bd9Sstevel@tonic-gate 	if (mp == NULL)
7787c478bd9Sstevel@tonic-gate 		return;
7797c478bd9Sstevel@tonic-gate 	keysock_copy_info((struct T_info_ack *)mp->b_rptr,
7807c478bd9Sstevel@tonic-gate 	    (keysock_t *)q->q_ptr);
7817c478bd9Sstevel@tonic-gate 	qreply(q, mp);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate  * keysock_err_ack. This routine creates a
7867c478bd9Sstevel@tonic-gate  * T_ERROR_ACK message and passes it
7877c478bd9Sstevel@tonic-gate  * upstream.
7887c478bd9Sstevel@tonic-gate  */
7897c478bd9Sstevel@tonic-gate static void
keysock_err_ack(queue_t * q,mblk_t * mp,int t_error,int sys_error)790f8cbe0e7SDan McDonald keysock_err_ack(queue_t *q, mblk_t *mp, int t_error, int sys_error)
7917c478bd9Sstevel@tonic-gate {
7927c478bd9Sstevel@tonic-gate 	if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL)
7937c478bd9Sstevel@tonic-gate 		qreply(q, mp);
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate /*
7977c478bd9Sstevel@tonic-gate  * This routine retrieves the current status of socket options.
7987c478bd9Sstevel@tonic-gate  * It returns the size of the option retrieved.
7997c478bd9Sstevel@tonic-gate  */
8007c478bd9Sstevel@tonic-gate /* ARGSUSED */
8017c478bd9Sstevel@tonic-gate int
keysock_opt_get(queue_t * q,int level,int name,uchar_t * ptr)8027c478bd9Sstevel@tonic-gate keysock_opt_get(queue_t *q, int level, int name, uchar_t *ptr)
8037c478bd9Sstevel@tonic-gate {
8047c478bd9Sstevel@tonic-gate 	int *i1 = (int *)ptr;
8057c478bd9Sstevel@tonic-gate 	keysock_t *ks = (keysock_t *)q->q_ptr;
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	switch (level) {
8087c478bd9Sstevel@tonic-gate 	case SOL_SOCKET:
8097c478bd9Sstevel@tonic-gate 		mutex_enter(&ks->keysock_lock);
8107c478bd9Sstevel@tonic-gate 		switch (name) {
8117c478bd9Sstevel@tonic-gate 		case SO_TYPE:
8127c478bd9Sstevel@tonic-gate 			*i1 = SOCK_RAW;
8137c478bd9Sstevel@tonic-gate 			break;
8147c478bd9Sstevel@tonic-gate 		case SO_USELOOPBACK:
8157c478bd9Sstevel@tonic-gate 			*i1 = (int)(!((ks->keysock_flags & KEYSOCK_NOLOOP) ==
8167c478bd9Sstevel@tonic-gate 			    KEYSOCK_NOLOOP));
8177c478bd9Sstevel@tonic-gate 			break;
8187c478bd9Sstevel@tonic-gate 		/*
8197c478bd9Sstevel@tonic-gate 		 * The following two items can be manipulated,
8207c478bd9Sstevel@tonic-gate 		 * but changing them should do nothing.
8217c478bd9Sstevel@tonic-gate 		 */
8227c478bd9Sstevel@tonic-gate 		case SO_SNDBUF:
8237c478bd9Sstevel@tonic-gate 			*i1 = (int)q->q_hiwat;
8247c478bd9Sstevel@tonic-gate 			break;
8257c478bd9Sstevel@tonic-gate 		case SO_RCVBUF:
8267c478bd9Sstevel@tonic-gate 			*i1 = (int)(RD(q)->q_hiwat);
8277c478bd9Sstevel@tonic-gate 			break;
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 		mutex_exit(&ks->keysock_lock);
8307c478bd9Sstevel@tonic-gate 		break;
8317c478bd9Sstevel@tonic-gate 	default:
8327c478bd9Sstevel@tonic-gate 		return (0);
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate 	return (sizeof (int));
8357c478bd9Sstevel@tonic-gate }
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate /*
8387c478bd9Sstevel@tonic-gate  * This routine sets socket options.
8397c478bd9Sstevel@tonic-gate  */
8407c478bd9Sstevel@tonic-gate /* ARGSUSED */
8417c478bd9Sstevel@tonic-gate int
keysock_opt_set(queue_t * q,uint_t mgmt_flags,int level,int name,uint_t inlen,uchar_t * invalp,uint_t * outlenp,uchar_t * outvalp,void * thisdg_attrs,cred_t * cr)8427c478bd9Sstevel@tonic-gate keysock_opt_set(queue_t *q, uint_t mgmt_flags, int level,
8437c478bd9Sstevel@tonic-gate     int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
844bd670b35SErik Nordmark     uchar_t *outvalp, void *thisdg_attrs, cred_t *cr)
8457c478bd9Sstevel@tonic-gate {
846b9c2bf66SDan McDonald 	int *i1 = (int *)invalp, errno = 0;
8477c478bd9Sstevel@tonic-gate 	keysock_t *ks = (keysock_t *)q->q_ptr;
848f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	switch (level) {
8517c478bd9Sstevel@tonic-gate 	case SOL_SOCKET:
8527c478bd9Sstevel@tonic-gate 		mutex_enter(&ks->keysock_lock);
8537c478bd9Sstevel@tonic-gate 		switch (name) {
8547c478bd9Sstevel@tonic-gate 		case SO_USELOOPBACK:
8557c478bd9Sstevel@tonic-gate 			if (!(*i1))
8567c478bd9Sstevel@tonic-gate 				ks->keysock_flags |= KEYSOCK_NOLOOP;
8577c478bd9Sstevel@tonic-gate 			else ks->keysock_flags &= ~KEYSOCK_NOLOOP;
8587c478bd9Sstevel@tonic-gate 			break;
8597c478bd9Sstevel@tonic-gate 		case SO_SNDBUF:
860f4b3ec61Sdh 			if (*i1 > keystack->keystack_max_buf)
861b9c2bf66SDan McDonald 				errno = ENOBUFS;
862b9c2bf66SDan McDonald 			else q->q_hiwat = *i1;
8637c478bd9Sstevel@tonic-gate 			break;
8647c478bd9Sstevel@tonic-gate 		case SO_RCVBUF:
865b9c2bf66SDan McDonald 			if (*i1 > keystack->keystack_max_buf) {
866b9c2bf66SDan McDonald 				errno = ENOBUFS;
867b9c2bf66SDan McDonald 			} else {
868b9c2bf66SDan McDonald 				RD(q)->q_hiwat = *i1;
869b9c2bf66SDan McDonald 				(void) proto_set_rx_hiwat(RD(q), NULL, *i1);
870b9c2bf66SDan McDonald 			}
8717c478bd9Sstevel@tonic-gate 			break;
872b9c2bf66SDan McDonald 		default:
873b9c2bf66SDan McDonald 			errno = EINVAL;
8747c478bd9Sstevel@tonic-gate 		}
8757c478bd9Sstevel@tonic-gate 		mutex_exit(&ks->keysock_lock);
8767c478bd9Sstevel@tonic-gate 		break;
877b9c2bf66SDan McDonald 	default:
878b9c2bf66SDan McDonald 		errno = EINVAL;
8797c478bd9Sstevel@tonic-gate 	}
880b9c2bf66SDan McDonald 	return (errno);
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate 
883f8cbe0e7SDan McDonald /*
884f8cbe0e7SDan McDonald  * Handle STREAMS ioctl copyin for getsockname() for both PF_KEY and
885f8cbe0e7SDan McDonald  * PF_POLICY.
886f8cbe0e7SDan McDonald  */
887f8cbe0e7SDan McDonald void
keysock_spdsock_wput_iocdata(queue_t * q,mblk_t * mp,sa_family_t family)888f8cbe0e7SDan McDonald keysock_spdsock_wput_iocdata(queue_t *q, mblk_t *mp, sa_family_t family)
889f8cbe0e7SDan McDonald {
890f8cbe0e7SDan McDonald 	mblk_t *mp1;
891f8cbe0e7SDan McDonald 	STRUCT_HANDLE(strbuf, sb);
892f8cbe0e7SDan McDonald 	/* What size of sockaddr do we need? */
893f8cbe0e7SDan McDonald 	const uint_t addrlen = sizeof (struct sockaddr);
894f8cbe0e7SDan McDonald 
895f8cbe0e7SDan McDonald 	/* We only handle TI_GET{MY,PEER}NAME (get{sock,peer}name()). */
896f8cbe0e7SDan McDonald 	switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) {
897f8cbe0e7SDan McDonald 	case TI_GETMYNAME:
898f8cbe0e7SDan McDonald 	case TI_GETPEERNAME:
899f8cbe0e7SDan McDonald 		break;
900f8cbe0e7SDan McDonald 	default:
901f8cbe0e7SDan McDonald 		freemsg(mp);
902f8cbe0e7SDan McDonald 		return;
903f8cbe0e7SDan McDonald 	}
904f8cbe0e7SDan McDonald 
905f8cbe0e7SDan McDonald 	switch (mi_copy_state(q, mp, &mp1)) {
906f8cbe0e7SDan McDonald 	case -1:
907f8cbe0e7SDan McDonald 		return;
908f8cbe0e7SDan McDonald 	case MI_COPY_CASE(MI_COPY_IN, 1):
909f8cbe0e7SDan McDonald 		break;
910f8cbe0e7SDan McDonald 	case MI_COPY_CASE(MI_COPY_OUT, 1):
911f8cbe0e7SDan McDonald 		/*
912f8cbe0e7SDan McDonald 		 * The address has been copied out, so now
913f8cbe0e7SDan McDonald 		 * copyout the strbuf.
914f8cbe0e7SDan McDonald 		 */
915f8cbe0e7SDan McDonald 		mi_copyout(q, mp);
916f8cbe0e7SDan McDonald 		return;
917f8cbe0e7SDan McDonald 	case MI_COPY_CASE(MI_COPY_OUT, 2):
918f8cbe0e7SDan McDonald 		/*
919f8cbe0e7SDan McDonald 		 * The address and strbuf have been copied out.
920f8cbe0e7SDan McDonald 		 * We're done, so just acknowledge the original
921f8cbe0e7SDan McDonald 		 * M_IOCTL.
922f8cbe0e7SDan McDonald 		 */
923f8cbe0e7SDan McDonald 		mi_copy_done(q, mp, 0);
924f8cbe0e7SDan McDonald 		return;
925f8cbe0e7SDan McDonald 	default:
926f8cbe0e7SDan McDonald 		/*
927f8cbe0e7SDan McDonald 		 * Something strange has happened, so acknowledge
928f8cbe0e7SDan McDonald 		 * the original M_IOCTL with an EPROTO error.
929f8cbe0e7SDan McDonald 		 */
930f8cbe0e7SDan McDonald 		mi_copy_done(q, mp, EPROTO);
931f8cbe0e7SDan McDonald 		return;
932f8cbe0e7SDan McDonald 	}
933f8cbe0e7SDan McDonald 
934f8cbe0e7SDan McDonald 	/*
935f8cbe0e7SDan McDonald 	 * Now we have the strbuf structure for TI_GET{MY,PEER}NAME. Next we
936f8cbe0e7SDan McDonald 	 * copyout the requested address and then we'll copyout the strbuf.
937f8cbe0e7SDan McDonald 	 * Regardless of sockname or peername, we just return a sockaddr with
938f8cbe0e7SDan McDonald 	 * sa_family set.
939f8cbe0e7SDan McDonald 	 */
940f8cbe0e7SDan McDonald 	STRUCT_SET_HANDLE(sb, ((struct iocblk *)mp->b_rptr)->ioc_flag,
941f8cbe0e7SDan McDonald 	    (void *)mp1->b_rptr);
942f8cbe0e7SDan McDonald 
943f8cbe0e7SDan McDonald 	if (STRUCT_FGET(sb, maxlen) < addrlen) {
944f8cbe0e7SDan McDonald 		mi_copy_done(q, mp, EINVAL);
945f8cbe0e7SDan McDonald 		return;
946f8cbe0e7SDan McDonald 	}
947f8cbe0e7SDan McDonald 
948f8cbe0e7SDan McDonald 	mp1 = mi_copyout_alloc(q, mp, STRUCT_FGETP(sb, buf), addrlen, B_TRUE);
949f8cbe0e7SDan McDonald 	if (mp1 == NULL)
950f8cbe0e7SDan McDonald 		return;
951f8cbe0e7SDan McDonald 
952f8cbe0e7SDan McDonald 	STRUCT_FSET(sb, len, addrlen);
953f8cbe0e7SDan McDonald 	((struct sockaddr *)mp1->b_wptr)->sa_family = family;
954f8cbe0e7SDan McDonald 	mp1->b_wptr += addrlen;
955f8cbe0e7SDan McDonald 	mi_copyout(q, mp);
956f8cbe0e7SDan McDonald }
957f8cbe0e7SDan McDonald 
9587c478bd9Sstevel@tonic-gate /*
9597c478bd9Sstevel@tonic-gate  * Handle STREAMS messages.
9607c478bd9Sstevel@tonic-gate  */
9617c478bd9Sstevel@tonic-gate static void
keysock_wput_other(queue_t * q,mblk_t * mp)9627c478bd9Sstevel@tonic-gate keysock_wput_other(queue_t *q, mblk_t *mp)
9637c478bd9Sstevel@tonic-gate {
9647c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
9657c478bd9Sstevel@tonic-gate 	int error;
966f4b3ec61Sdh 	keysock_t *ks = (keysock_t *)q->q_ptr;
967f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
968f4b3ec61Sdh 	cred_t		*cr;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
9717c478bd9Sstevel@tonic-gate 	case M_PROTO:
9727c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
9737c478bd9Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) < sizeof (long)) {
974f4b3ec61Sdh 			ks3dbg(keystack, (
9757c478bd9Sstevel@tonic-gate 			    "keysock_wput_other: Not big enough M_PROTO\n"));
9767c478bd9Sstevel@tonic-gate 			freemsg(mp);
9777c478bd9Sstevel@tonic-gate 			return;
9787c478bd9Sstevel@tonic-gate 		}
9797c478bd9Sstevel@tonic-gate 		switch (((union T_primitives *)mp->b_rptr)->type) {
9807c478bd9Sstevel@tonic-gate 		case T_CAPABILITY_REQ:
9817c478bd9Sstevel@tonic-gate 			keysock_capability_req(q, mp);
982f4b3ec61Sdh 			break;
9837c478bd9Sstevel@tonic-gate 		case T_INFO_REQ:
9847c478bd9Sstevel@tonic-gate 			keysock_info_req(q, mp);
985f4b3ec61Sdh 			break;
9867c478bd9Sstevel@tonic-gate 		case T_SVR4_OPTMGMT_REQ:
9877c478bd9Sstevel@tonic-gate 		case T_OPTMGMT_REQ:
988de8c4a14SErik Nordmark 			/*
989de8c4a14SErik Nordmark 			 * All Solaris components should pass a db_credp
990de8c4a14SErik Nordmark 			 * for this TPI message, hence we ASSERT.
991de8c4a14SErik Nordmark 			 * But in case there is some other M_PROTO that looks
992de8c4a14SErik Nordmark 			 * like a TPI message sent by some other kernel
993de8c4a14SErik Nordmark 			 * component, we check and return an error.
994de8c4a14SErik Nordmark 			 */
995de8c4a14SErik Nordmark 			cr = msg_getcred(mp, NULL);
996de8c4a14SErik Nordmark 			ASSERT(cr != NULL);
997de8c4a14SErik Nordmark 			if (cr == NULL) {
998de8c4a14SErik Nordmark 				keysock_err_ack(q, mp, TSYSERR, EINVAL);
999de8c4a14SErik Nordmark 				return;
1000de8c4a14SErik Nordmark 			}
1001de8c4a14SErik Nordmark 			if (((union T_primitives *)mp->b_rptr)->type ==
1002de8c4a14SErik Nordmark 			    T_SVR4_OPTMGMT_REQ) {
1003bd670b35SErik Nordmark 				svr4_optcom_req(q, mp, cr, &keysock_opt_obj);
1004de8c4a14SErik Nordmark 			} else {
1005bd670b35SErik Nordmark 				tpi_optcom_req(q, mp, cr, &keysock_opt_obj);
1006de8c4a14SErik Nordmark 			}
1007f4b3ec61Sdh 			break;
10087c478bd9Sstevel@tonic-gate 		case T_DATA_REQ:
10097c478bd9Sstevel@tonic-gate 		case T_EXDATA_REQ:
10107c478bd9Sstevel@tonic-gate 		case T_ORDREL_REQ:
10117c478bd9Sstevel@tonic-gate 			/* Illegal for keysock. */
10127c478bd9Sstevel@tonic-gate 			freemsg(mp);
10137c478bd9Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_ERROR, EPROTO);
1014f4b3ec61Sdh 			break;
10157c478bd9Sstevel@tonic-gate 		default:
10167c478bd9Sstevel@tonic-gate 			/* Not supported by keysock. */
10177c478bd9Sstevel@tonic-gate 			keysock_err_ack(q, mp, TNOTSUPPORT, 0);
1018f4b3ec61Sdh 			break;
10197c478bd9Sstevel@tonic-gate 		}
1020f4b3ec61Sdh 		return;
1021f8cbe0e7SDan McDonald 	case M_IOCDATA:
1022f8cbe0e7SDan McDonald 		keysock_spdsock_wput_iocdata(q, mp, PF_KEY);
1023f8cbe0e7SDan McDonald 		return;
10247c478bd9Sstevel@tonic-gate 	case M_IOCTL:
10257c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
10267c478bd9Sstevel@tonic-gate 		error = EINVAL;
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
1029f8cbe0e7SDan McDonald 		case TI_GETMYNAME:
1030f8cbe0e7SDan McDonald 		case TI_GETPEERNAME:
1031f8cbe0e7SDan McDonald 			/*
1032f8cbe0e7SDan McDonald 			 * For pfiles(1) observability with getsockname().
1033f8cbe0e7SDan McDonald 			 * See keysock_spdsock_wput_iocdata() for the rest of
1034f8cbe0e7SDan McDonald 			 * this.
1035f8cbe0e7SDan McDonald 			 */
1036f8cbe0e7SDan McDonald 			mi_copyin(q, mp, NULL,
1037f8cbe0e7SDan McDonald 			    SIZEOF_STRUCT(strbuf, iocp->ioc_flag));
1038f8cbe0e7SDan McDonald 			return;
10397c478bd9Sstevel@tonic-gate 		case ND_SET:
10407c478bd9Sstevel@tonic-gate 		case ND_GET:
1041f4b3ec61Sdh 			if (nd_getset(q, keystack->keystack_g_nd, mp)) {
10427c478bd9Sstevel@tonic-gate 				qreply(q, mp);
10437c478bd9Sstevel@tonic-gate 				return;
10447c478bd9Sstevel@tonic-gate 			} else
10457c478bd9Sstevel@tonic-gate 				error = ENOENT;
10467c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
10477c478bd9Sstevel@tonic-gate 		default:
10487c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
10497c478bd9Sstevel@tonic-gate 			return;
10507c478bd9Sstevel@tonic-gate 		}
10517c478bd9Sstevel@tonic-gate 	case M_FLUSH:
10527c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
10537c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHALL);
10547c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
10557c478bd9Sstevel@tonic-gate 		}
10567c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
10577c478bd9Sstevel@tonic-gate 			qreply(q, mp);
10587c478bd9Sstevel@tonic-gate 			return;
10597c478bd9Sstevel@tonic-gate 		}
10607c478bd9Sstevel@tonic-gate 		/* Else FALLTHRU */
10617c478bd9Sstevel@tonic-gate 	}
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	/* If fell through, just black-hole the message. */
10647c478bd9Sstevel@tonic-gate 	freemsg(mp);
10657c478bd9Sstevel@tonic-gate }
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate /*
10687c478bd9Sstevel@tonic-gate  * Transmit a PF_KEY error message to the instance either pointed to
10697c478bd9Sstevel@tonic-gate  * by ks, the instance with serial number serial, or more, depending.
10707c478bd9Sstevel@tonic-gate  *
10717c478bd9Sstevel@tonic-gate  * The faulty message (or a reasonable facsimile thereof) is in mp.
10727c478bd9Sstevel@tonic-gate  * This function will free mp or recycle it for delivery, thereby causing
10737c478bd9Sstevel@tonic-gate  * the stream head to free it.
10747c478bd9Sstevel@tonic-gate  */
10757c478bd9Sstevel@tonic-gate static void
keysock_error(keysock_t * ks,mblk_t * mp,int error,int diagnostic)10767c478bd9Sstevel@tonic-gate keysock_error(keysock_t *ks, mblk_t *mp, int error, int diagnostic)
10777c478bd9Sstevel@tonic-gate {
10787c478bd9Sstevel@tonic-gate 	sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr;
1079f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_DATA);
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	if (samsg->sadb_msg_type < SADB_GETSPI ||
10847c478bd9Sstevel@tonic-gate 	    samsg->sadb_msg_type > SADB_MAX)
10857c478bd9Sstevel@tonic-gate 		samsg->sadb_msg_type = SADB_RESERVED;
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	/*
10887c478bd9Sstevel@tonic-gate 	 * Strip out extension headers.
10897c478bd9Sstevel@tonic-gate 	 */
10907c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_rptr + sizeof (*samsg) <= mp->b_datap->db_lim);
10917c478bd9Sstevel@tonic-gate 	mp->b_wptr = mp->b_rptr + sizeof (*samsg);
10927c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_len = SADB_8TO64(sizeof (sadb_msg_t));
10937c478bd9Sstevel@tonic-gate 	samsg->sadb_msg_errno = (uint8_t)error;
10947c478bd9Sstevel@tonic-gate 	samsg->sadb_x_msg_diagnostic = (uint16_t)diagnostic;
10957c478bd9Sstevel@tonic-gate 
1096f4b3ec61Sdh 	keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE, keystack);
10977c478bd9Sstevel@tonic-gate }
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate /*
11007c478bd9Sstevel@tonic-gate  * Pass down a message to a consumer.  Wrap it in KEYSOCK_IN, and copy
11017c478bd9Sstevel@tonic-gate  * in the extv if passed in.
11027c478bd9Sstevel@tonic-gate  */
11037c478bd9Sstevel@tonic-gate static void
keysock_passdown(keysock_t * ks,mblk_t * mp,uint8_t satype,sadb_ext_t * extv[],boolean_t flushmsg)11047c478bd9Sstevel@tonic-gate keysock_passdown(keysock_t *ks, mblk_t *mp, uint8_t satype, sadb_ext_t *extv[],
11057c478bd9Sstevel@tonic-gate     boolean_t flushmsg)
11067c478bd9Sstevel@tonic-gate {
11077c478bd9Sstevel@tonic-gate 	keysock_consumer_t *kc;
11087c478bd9Sstevel@tonic-gate 	mblk_t *wrapper;
11097c478bd9Sstevel@tonic-gate 	keysock_in_t *ksi;
11107c478bd9Sstevel@tonic-gate 	int i;
1111f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	wrapper = allocb(sizeof (ipsec_info_t), BPRI_HI);
11147c478bd9Sstevel@tonic-gate 	if (wrapper == NULL) {
1115f4b3ec61Sdh 		ks3dbg(keystack, ("keysock_passdown: allocb failed.\n"));
11167c478bd9Sstevel@tonic-gate 		if (extv[SADB_EXT_KEY_ENCRYPT] != NULL)
11177c478bd9Sstevel@tonic-gate 			bzero(extv[SADB_EXT_KEY_ENCRYPT],
11187c478bd9Sstevel@tonic-gate 			    SADB_64TO8(
1119fc80c0dfSnordmark 			    extv[SADB_EXT_KEY_ENCRYPT]->sadb_ext_len));
11207c478bd9Sstevel@tonic-gate 		if (extv[SADB_EXT_KEY_AUTH] != NULL)
11217c478bd9Sstevel@tonic-gate 			bzero(extv[SADB_EXT_KEY_AUTH],
11227c478bd9Sstevel@tonic-gate 			    SADB_64TO8(
1123fc80c0dfSnordmark 			    extv[SADB_EXT_KEY_AUTH]->sadb_ext_len));
11247c478bd9Sstevel@tonic-gate 		if (flushmsg) {
11257c478bd9Sstevel@tonic-gate 			ks0dbg((
11267c478bd9Sstevel@tonic-gate 			    "keysock: Downwards flush/dump message failed!\n"));
11277c478bd9Sstevel@tonic-gate 			/* If this is true, I hold the perimeter. */
1128f4b3ec61Sdh 			keystack->keystack_flushdump--;
11297c478bd9Sstevel@tonic-gate 		}
11307c478bd9Sstevel@tonic-gate 		freemsg(mp);
11317c478bd9Sstevel@tonic-gate 		return;
11327c478bd9Sstevel@tonic-gate 	}
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	wrapper->b_datap->db_type = M_CTL;
11357c478bd9Sstevel@tonic-gate 	ksi = (keysock_in_t *)wrapper->b_rptr;
11367c478bd9Sstevel@tonic-gate 	ksi->ks_in_type = KEYSOCK_IN;
11377c478bd9Sstevel@tonic-gate 	ksi->ks_in_len = sizeof (keysock_in_t);
11387c478bd9Sstevel@tonic-gate 	if (extv[SADB_EXT_ADDRESS_SRC] != NULL)
11397c478bd9Sstevel@tonic-gate 		ksi->ks_in_srctype = KS_IN_ADDR_UNKNOWN;
11407c478bd9Sstevel@tonic-gate 	else ksi->ks_in_srctype = KS_IN_ADDR_NOTTHERE;
11417c478bd9Sstevel@tonic-gate 	if (extv[SADB_EXT_ADDRESS_DST] != NULL)
11427c478bd9Sstevel@tonic-gate 		ksi->ks_in_dsttype = KS_IN_ADDR_UNKNOWN;
11437c478bd9Sstevel@tonic-gate 	else ksi->ks_in_dsttype = KS_IN_ADDR_NOTTHERE;
11447c478bd9Sstevel@tonic-gate 	for (i = 0; i <= SADB_EXT_MAX; i++)
11457c478bd9Sstevel@tonic-gate 		ksi->ks_in_extv[i] = extv[i];
11467c478bd9Sstevel@tonic-gate 	ksi->ks_in_serial = ks->keysock_serial;
11477c478bd9Sstevel@tonic-gate 	wrapper->b_wptr += sizeof (ipsec_info_t);
11487c478bd9Sstevel@tonic-gate 	wrapper->b_cont = mp;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	/*
11517c478bd9Sstevel@tonic-gate 	 * Find the appropriate consumer where the message is passed down.
11527c478bd9Sstevel@tonic-gate 	 */
1153f4b3ec61Sdh 	kc = keystack->keystack_consumers[satype];
11547c478bd9Sstevel@tonic-gate 	if (kc == NULL) {
11557c478bd9Sstevel@tonic-gate 		freeb(wrapper);
11567c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE);
11577c478bd9Sstevel@tonic-gate 		if (flushmsg) {
11587c478bd9Sstevel@tonic-gate 			ks0dbg((
11597c478bd9Sstevel@tonic-gate 			    "keysock: Downwards flush/dump message failed!\n"));
11607c478bd9Sstevel@tonic-gate 			/* If this is true, I hold the perimeter. */
1161f4b3ec61Sdh 			keystack->keystack_flushdump--;
11627c478bd9Sstevel@tonic-gate 		}
11637c478bd9Sstevel@tonic-gate 		return;
11647c478bd9Sstevel@tonic-gate 	}
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	/*
11677c478bd9Sstevel@tonic-gate 	 * NOTE: There used to be code in here to spin while a flush or
11687c478bd9Sstevel@tonic-gate 	 *	 dump finished.  Keysock now assumes that consumers have enough
11697c478bd9Sstevel@tonic-gate 	 *	 MT-savviness to deal with that.
11707c478bd9Sstevel@tonic-gate 	 */
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	/*
11737c478bd9Sstevel@tonic-gate 	 * Current consumers (AH and ESP) are guaranteed to return a
11747c478bd9Sstevel@tonic-gate 	 * FLUSH or DUMP message back, so when we reach here, we don't
11757c478bd9Sstevel@tonic-gate 	 * have to worry about keysock_flushdumps.
11767c478bd9Sstevel@tonic-gate 	 */
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	putnext(kc->kc_wq, wrapper);
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate /*
11827c478bd9Sstevel@tonic-gate  * High-level reality checking of extensions.
11837c478bd9Sstevel@tonic-gate  */
11847c478bd9Sstevel@tonic-gate static boolean_t
ext_check(sadb_ext_t * ext,keysock_stack_t * keystack)1185f4b3ec61Sdh ext_check(sadb_ext_t *ext, keysock_stack_t *keystack)
11867c478bd9Sstevel@tonic-gate {
11877c478bd9Sstevel@tonic-gate 	int i;
11887c478bd9Sstevel@tonic-gate 	uint64_t *lp;
11897c478bd9Sstevel@tonic-gate 	sadb_ident_t *id;
11907c478bd9Sstevel@tonic-gate 	char *idstr;
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	switch (ext->sadb_ext_type) {
11937c478bd9Sstevel@tonic-gate 	case SADB_EXT_ADDRESS_SRC:
11947c478bd9Sstevel@tonic-gate 	case SADB_EXT_ADDRESS_DST:
11958810c16bSdanmcd 	case SADB_X_EXT_ADDRESS_INNER_SRC:
11968810c16bSdanmcd 	case SADB_X_EXT_ADDRESS_INNER_DST:
11977c478bd9Sstevel@tonic-gate 		/* Check for at least enough addtl length for a sockaddr. */
11987c478bd9Sstevel@tonic-gate 		if (ext->sadb_ext_len <= SADB_8TO64(sizeof (sadb_address_t)))
11997c478bd9Sstevel@tonic-gate 			return (B_FALSE);
12007c478bd9Sstevel@tonic-gate 		break;
12017c478bd9Sstevel@tonic-gate 	case SADB_EXT_LIFETIME_HARD:
12027c478bd9Sstevel@tonic-gate 	case SADB_EXT_LIFETIME_SOFT:
12037c478bd9Sstevel@tonic-gate 	case SADB_EXT_LIFETIME_CURRENT:
12047c478bd9Sstevel@tonic-gate 		if (ext->sadb_ext_len != SADB_8TO64(sizeof (sadb_lifetime_t)))
12057c478bd9Sstevel@tonic-gate 			return (B_FALSE);
12067c478bd9Sstevel@tonic-gate 		break;
12077c478bd9Sstevel@tonic-gate 	case SADB_EXT_SPIRANGE:
12087c478bd9Sstevel@tonic-gate 		/* See if the SPI range is legit. */
12097c478bd9Sstevel@tonic-gate 		if (htonl(((sadb_spirange_t *)ext)->sadb_spirange_min) >
12107c478bd9Sstevel@tonic-gate 		    htonl(((sadb_spirange_t *)ext)->sadb_spirange_max))
12117c478bd9Sstevel@tonic-gate 			return (B_FALSE);
12127c478bd9Sstevel@tonic-gate 		break;
12137c478bd9Sstevel@tonic-gate 	case SADB_EXT_KEY_AUTH:
12147c478bd9Sstevel@tonic-gate 	case SADB_EXT_KEY_ENCRYPT:
12157c478bd9Sstevel@tonic-gate 		/* Key length check. */
12167c478bd9Sstevel@tonic-gate 		if (((sadb_key_t *)ext)->sadb_key_bits == 0)
12177c478bd9Sstevel@tonic-gate 			return (B_FALSE);
12187c478bd9Sstevel@tonic-gate 		/*
12197c478bd9Sstevel@tonic-gate 		 * Check to see if the key length (in bits) is less than the
12207c478bd9Sstevel@tonic-gate 		 * extension length (in 8-bits words).
12217c478bd9Sstevel@tonic-gate 		 */
12227c478bd9Sstevel@tonic-gate 		if ((roundup(SADB_1TO8(((sadb_key_t *)ext)->sadb_key_bits), 8) +
12237c478bd9Sstevel@tonic-gate 		    sizeof (sadb_key_t)) != SADB_64TO8(ext->sadb_ext_len)) {
1224f4b3ec61Sdh 			ks1dbg(keystack, (
12257c478bd9Sstevel@tonic-gate 			    "ext_check:  Key bits/length inconsistent.\n"));
1226f4b3ec61Sdh 			ks1dbg(keystack, ("%d bits, len is %d bytes.\n",
12277c478bd9Sstevel@tonic-gate 			    ((sadb_key_t *)ext)->sadb_key_bits,
12287c478bd9Sstevel@tonic-gate 			    SADB_64TO8(ext->sadb_ext_len)));
12297c478bd9Sstevel@tonic-gate 			return (B_FALSE);
12307c478bd9Sstevel@tonic-gate 		}
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 		/* All-zeroes key check. */
12337c478bd9Sstevel@tonic-gate 		lp = (uint64_t *)(((char *)ext) + sizeof (sadb_key_t));
12347c478bd9Sstevel@tonic-gate 		for (i = 0;
12357c478bd9Sstevel@tonic-gate 		    i < (ext->sadb_ext_len - SADB_8TO64(sizeof (sadb_key_t)));
12367c478bd9Sstevel@tonic-gate 		    i++)
12377c478bd9Sstevel@tonic-gate 			if (lp[i] != 0)
12387c478bd9Sstevel@tonic-gate 				break;	/* Out of for loop. */
12397c478bd9Sstevel@tonic-gate 		/* If finished the loop naturally, it's an all zero key. */
12407c478bd9Sstevel@tonic-gate 		if (lp[i] == 0)
12417c478bd9Sstevel@tonic-gate 			return (B_FALSE);
12427c478bd9Sstevel@tonic-gate 		break;
12437c478bd9Sstevel@tonic-gate 	case SADB_EXT_IDENTITY_SRC:
12447c478bd9Sstevel@tonic-gate 	case SADB_EXT_IDENTITY_DST:
12457c478bd9Sstevel@tonic-gate 		/*
12467c478bd9Sstevel@tonic-gate 		 * Make sure the strings in these identities are
12477c478bd9Sstevel@tonic-gate 		 * null-terminated.  RFC 2367 underspecified how to handle
12487c478bd9Sstevel@tonic-gate 		 * such a case.  I "proactively" null-terminate the string
12497c478bd9Sstevel@tonic-gate 		 * at the last byte if it's not terminated sooner.
12507c478bd9Sstevel@tonic-gate 		 */
12517c478bd9Sstevel@tonic-gate 		id = (sadb_ident_t *)ext;
12527c478bd9Sstevel@tonic-gate 		i = SADB_64TO8(id->sadb_ident_len);
12537c478bd9Sstevel@tonic-gate 		i -= sizeof (sadb_ident_t);
12547c478bd9Sstevel@tonic-gate 		idstr = (char *)(id + 1);
12557c478bd9Sstevel@tonic-gate 		while (*idstr != '\0' && i > 0) {
12567c478bd9Sstevel@tonic-gate 			i--;
12577c478bd9Sstevel@tonic-gate 			idstr++;
12587c478bd9Sstevel@tonic-gate 		}
12597c478bd9Sstevel@tonic-gate 		if (i == 0) {
12607c478bd9Sstevel@tonic-gate 			/*
12617c478bd9Sstevel@tonic-gate 			 * I.e., if the bozo user didn't NULL-terminate the
12627c478bd9Sstevel@tonic-gate 			 * string...
12637c478bd9Sstevel@tonic-gate 			 */
12647c478bd9Sstevel@tonic-gate 			idstr--;
12657c478bd9Sstevel@tonic-gate 			*idstr = '\0';
12667c478bd9Sstevel@tonic-gate 		}
12677c478bd9Sstevel@tonic-gate 		break;
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 	return (B_TRUE);	/* For now... */
12707c478bd9Sstevel@tonic-gate }
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate /* Return values for keysock_get_ext(). */
12737c478bd9Sstevel@tonic-gate #define	KGE_OK	0
12747c478bd9Sstevel@tonic-gate #define	KGE_DUP	1
12757c478bd9Sstevel@tonic-gate #define	KGE_UNK	2
12767c478bd9Sstevel@tonic-gate #define	KGE_LEN	3
12777c478bd9Sstevel@tonic-gate #define	KGE_CHK	4
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate /*
12807c478bd9Sstevel@tonic-gate  * Parse basic extension headers and return in the passed-in pointer vector.
12817c478bd9Sstevel@tonic-gate  * Return values include:
12827c478bd9Sstevel@tonic-gate  *
12837c478bd9Sstevel@tonic-gate  *	KGE_OK	Everything's nice and parsed out.
12847c478bd9Sstevel@tonic-gate  *		If there are no extensions, place NULL in extv[0].
12857c478bd9Sstevel@tonic-gate  *	KGE_DUP	There is a duplicate extension.
12867c478bd9Sstevel@tonic-gate  *		First instance in appropriate bin.  First duplicate in
12877c478bd9Sstevel@tonic-gate  *		extv[0].
12887c478bd9Sstevel@tonic-gate  *	KGE_UNK	Unknown extension type encountered.  extv[0] contains
12897c478bd9Sstevel@tonic-gate  *		unknown header.
12907c478bd9Sstevel@tonic-gate  *	KGE_LEN	Extension length error.
12917c478bd9Sstevel@tonic-gate  *	KGE_CHK	High-level reality check failed on specific extension.
12927c478bd9Sstevel@tonic-gate  *
12937c478bd9Sstevel@tonic-gate  * My apologies for some of the pointer arithmetic in here.  I'm thinking
12947c478bd9Sstevel@tonic-gate  * like an assembly programmer, yet trying to make the compiler happy.
12957c478bd9Sstevel@tonic-gate  */
12967c478bd9Sstevel@tonic-gate static int
keysock_get_ext(sadb_ext_t * extv[],sadb_msg_t * basehdr,uint_t msgsize,keysock_stack_t * keystack)1297f4b3ec61Sdh keysock_get_ext(sadb_ext_t *extv[], sadb_msg_t *basehdr, uint_t msgsize,
1298f4b3ec61Sdh     keysock_stack_t *keystack)
12997c478bd9Sstevel@tonic-gate {
13007c478bd9Sstevel@tonic-gate 	bzero(extv, sizeof (sadb_ext_t *) * (SADB_EXT_MAX + 1));
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	/* Use extv[0] as the "current working pointer". */
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	extv[0] = (sadb_ext_t *)(basehdr + 1);
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	while (extv[0] < (sadb_ext_t *)(((uint8_t *)basehdr) + msgsize)) {
13077c478bd9Sstevel@tonic-gate 		/* Check for unknown headers. */
13087c478bd9Sstevel@tonic-gate 		if (extv[0]->sadb_ext_type == 0 ||
13097c478bd9Sstevel@tonic-gate 		    extv[0]->sadb_ext_type > SADB_EXT_MAX)
13107c478bd9Sstevel@tonic-gate 			return (KGE_UNK);
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 		/*
13137c478bd9Sstevel@tonic-gate 		 * Check length.  Use uint64_t because extlen is in units
13147c478bd9Sstevel@tonic-gate 		 * of 64-bit words.  If length goes beyond the msgsize,
13157c478bd9Sstevel@tonic-gate 		 * return an error.  (Zero length also qualifies here.)
13167c478bd9Sstevel@tonic-gate 		 */
13177c478bd9Sstevel@tonic-gate 		if (extv[0]->sadb_ext_len == 0 ||
13187c478bd9Sstevel@tonic-gate 		    (void *)((uint64_t *)extv[0] + extv[0]->sadb_ext_len) >
13197c478bd9Sstevel@tonic-gate 		    (void *)((uint8_t *)basehdr + msgsize))
13207c478bd9Sstevel@tonic-gate 			return (KGE_LEN);
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 		/* Check for redundant headers. */
13237c478bd9Sstevel@tonic-gate 		if (extv[extv[0]->sadb_ext_type] != NULL)
13247c478bd9Sstevel@tonic-gate 			return (KGE_DUP);
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 		/*
13277c478bd9Sstevel@tonic-gate 		 * Reality check the extension if possible at the keysock
13287c478bd9Sstevel@tonic-gate 		 * level.
13297c478bd9Sstevel@tonic-gate 		 */
1330f4b3ec61Sdh 		if (!ext_check(extv[0], keystack))
13317c478bd9Sstevel@tonic-gate 			return (KGE_CHK);
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 		/* If I make it here, assign the appropriate bin. */
13347c478bd9Sstevel@tonic-gate 		extv[extv[0]->sadb_ext_type] = extv[0];
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 		/* Advance pointer (See above for uint64_t ptr reasoning.) */
13377c478bd9Sstevel@tonic-gate 		extv[0] = (sadb_ext_t *)
13387c478bd9Sstevel@tonic-gate 		    ((uint64_t *)extv[0] + extv[0]->sadb_ext_len);
13397c478bd9Sstevel@tonic-gate 	}
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 	/* Everything's cool. */
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	/*
13447c478bd9Sstevel@tonic-gate 	 * If extv[0] == NULL, then there are no extension headers in this
13457c478bd9Sstevel@tonic-gate 	 * message.  Ensure that this is the case.
13467c478bd9Sstevel@tonic-gate 	 */
13477c478bd9Sstevel@tonic-gate 	if (extv[0] == (sadb_ext_t *)(basehdr + 1))
13487c478bd9Sstevel@tonic-gate 		extv[0] = NULL;
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	return (KGE_OK);
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate /*
13547c478bd9Sstevel@tonic-gate  * qwriter() callback to handle flushes and dumps.  This routine will hold
13557c478bd9Sstevel@tonic-gate  * the inner perimeter.
13567c478bd9Sstevel@tonic-gate  */
13577c478bd9Sstevel@tonic-gate void
keysock_do_flushdump(queue_t * q,mblk_t * mp)13587c478bd9Sstevel@tonic-gate keysock_do_flushdump(queue_t *q, mblk_t *mp)
13597c478bd9Sstevel@tonic-gate {
13607c478bd9Sstevel@tonic-gate 	int i, start, finish;
13617c478bd9Sstevel@tonic-gate 	mblk_t *mp1 = NULL;
13627c478bd9Sstevel@tonic-gate 	keysock_t *ks = (keysock_t *)q->q_ptr;
13637c478bd9Sstevel@tonic-gate 	sadb_ext_t *extv[SADB_EXT_MAX + 1];
13647c478bd9Sstevel@tonic-gate 	sadb_msg_t *samsg = (sadb_msg_t *)mp->b_rptr;
1365f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	/*
13687c478bd9Sstevel@tonic-gate 	 * I am guaranteed this will work.  I did the work in keysock_parse()
13697c478bd9Sstevel@tonic-gate 	 * already.
13707c478bd9Sstevel@tonic-gate 	 */
1371f4b3ec61Sdh 	(void) keysock_get_ext(extv, samsg, SADB_64TO8(samsg->sadb_msg_len),
1372f4b3ec61Sdh 	    keystack);
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	/*
13757c478bd9Sstevel@tonic-gate 	 * I hold the perimeter, therefore I don't need to use atomic ops.
13767c478bd9Sstevel@tonic-gate 	 */
1377f4b3ec61Sdh 	if (keystack->keystack_flushdump != 0) {
13787c478bd9Sstevel@tonic-gate 		/* XXX Should I instead use EBUSY? */
13797c478bd9Sstevel@tonic-gate 		/* XXX Or is there a way to queue these up? */
13807c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, ENOMEM, SADB_X_DIAGNOSTIC_NONE);
13817c478bd9Sstevel@tonic-gate 		return;
13827c478bd9Sstevel@tonic-gate 	}
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) {
13857c478bd9Sstevel@tonic-gate 		start = 0;
13867c478bd9Sstevel@tonic-gate 		finish = KEYSOCK_MAX_CONSUMERS - 1;
13877c478bd9Sstevel@tonic-gate 	} else {
13887c478bd9Sstevel@tonic-gate 		start = samsg->sadb_msg_satype;
13897c478bd9Sstevel@tonic-gate 		finish = samsg->sadb_msg_satype;
13907c478bd9Sstevel@tonic-gate 	}
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	/*
13937c478bd9Sstevel@tonic-gate 	 * Fill up keysock_flushdump with the number of outstanding dumps
13947c478bd9Sstevel@tonic-gate 	 * and/or flushes.
13957c478bd9Sstevel@tonic-gate 	 */
13967c478bd9Sstevel@tonic-gate 
1397f4b3ec61Sdh 	keystack->keystack_flushdump_errno = 0;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 	/*
14007c478bd9Sstevel@tonic-gate 	 * Okay, I hold the perimeter.  Eventually keysock_flushdump will
14017c478bd9Sstevel@tonic-gate 	 * contain the number of consumers with outstanding flush operations.
14027c478bd9Sstevel@tonic-gate 	 *
14037c478bd9Sstevel@tonic-gate 	 * SO, here's the plan:
14047c478bd9Sstevel@tonic-gate 	 *	* For each relevant consumer (Might be one, might be all)
14057c478bd9Sstevel@tonic-gate 	 *		* Twiddle on the FLUSHING flag.
14067c478bd9Sstevel@tonic-gate 	 *		* Pass down the FLUSH/DUMP message.
14077c478bd9Sstevel@tonic-gate 	 *
14087c478bd9Sstevel@tonic-gate 	 * When I see upbound FLUSH/DUMP messages, I will decrement the
14097c478bd9Sstevel@tonic-gate 	 * keysock_flushdump.  When I decrement it to 0, I will pass the
14107c478bd9Sstevel@tonic-gate 	 * FLUSH/DUMP message back up to the PF_KEY sockets.  Because I will
14117c478bd9Sstevel@tonic-gate 	 * pass down the right SA type to the consumer (either its own, or
14127c478bd9Sstevel@tonic-gate 	 * that of UNSPEC), the right one will be reflected from each consumer,
14137c478bd9Sstevel@tonic-gate 	 * and accordingly back to the socket.
14147c478bd9Sstevel@tonic-gate 	 */
14157c478bd9Sstevel@tonic-gate 
1416f4b3ec61Sdh 	mutex_enter(&keystack->keystack_consumers_lock);
14177c478bd9Sstevel@tonic-gate 	for (i = start; i <= finish; i++) {
1418f4b3ec61Sdh 		if (keystack->keystack_consumers[i] != NULL) {
14197c478bd9Sstevel@tonic-gate 			mp1 = copymsg(mp);
14207c478bd9Sstevel@tonic-gate 			if (mp1 == NULL) {
14217c478bd9Sstevel@tonic-gate 				ks0dbg(("SADB_FLUSH copymsg() failed.\n"));
14227c478bd9Sstevel@tonic-gate 				/*
14237c478bd9Sstevel@tonic-gate 				 * Error?  And what about outstanding
14247c478bd9Sstevel@tonic-gate 				 * flushes?  Oh, yeah, they get sucked up and
14257c478bd9Sstevel@tonic-gate 				 * the counter is decremented.  Consumers
14267c478bd9Sstevel@tonic-gate 				 * (see keysock_passdown()) are guaranteed
14277c478bd9Sstevel@tonic-gate 				 * to deliver back a flush request, even if
14287c478bd9Sstevel@tonic-gate 				 * it's an error.
14297c478bd9Sstevel@tonic-gate 				 */
14307c478bd9Sstevel@tonic-gate 				keysock_error(ks, mp, ENOMEM,
14317c478bd9Sstevel@tonic-gate 				    SADB_X_DIAGNOSTIC_NONE);
14327c478bd9Sstevel@tonic-gate 				return;
14337c478bd9Sstevel@tonic-gate 			}
14347c478bd9Sstevel@tonic-gate 			/*
14357c478bd9Sstevel@tonic-gate 			 * Because my entry conditions are met above, the
14367c478bd9Sstevel@tonic-gate 			 * following assertion should hold true.
14377c478bd9Sstevel@tonic-gate 			 */
1438f4b3ec61Sdh 			mutex_enter(&keystack->keystack_consumers[i]->kc_lock);
1439f4b3ec61Sdh 			ASSERT((keystack->keystack_consumers[i]->kc_flags &
1440fc80c0dfSnordmark 			    KC_FLUSHING) == 0);
1441f4b3ec61Sdh 			keystack->keystack_consumers[i]->kc_flags |=
1442f4b3ec61Sdh 			    KC_FLUSHING;
1443f4b3ec61Sdh 			mutex_exit(&(keystack->keystack_consumers[i]->kc_lock));
14447c478bd9Sstevel@tonic-gate 			/* Always increment the number of flushes... */
1445f4b3ec61Sdh 			keystack->keystack_flushdump++;
14467c478bd9Sstevel@tonic-gate 			/* Guaranteed to return a message. */
14477c478bd9Sstevel@tonic-gate 			keysock_passdown(ks, mp1, i, extv, B_TRUE);
14487c478bd9Sstevel@tonic-gate 		} else if (start == finish) {
14497c478bd9Sstevel@tonic-gate 			/*
14507c478bd9Sstevel@tonic-gate 			 * In case where start == finish, and there's no
14517c478bd9Sstevel@tonic-gate 			 * consumer, should we force an error?  Yes.
14527c478bd9Sstevel@tonic-gate 			 */
1453f4b3ec61Sdh 			mutex_exit(&keystack->keystack_consumers_lock);
14547c478bd9Sstevel@tonic-gate 			keysock_error(ks, mp, EINVAL,
14557c478bd9Sstevel@tonic-gate 			    SADB_X_DIAGNOSTIC_UNKNOWN_SATYPE);
14567c478bd9Sstevel@tonic-gate 			return;
14577c478bd9Sstevel@tonic-gate 		}
14587c478bd9Sstevel@tonic-gate 	}
1459f4b3ec61Sdh 	mutex_exit(&keystack->keystack_consumers_lock);
14607c478bd9Sstevel@tonic-gate 
1461f4b3ec61Sdh 	if (keystack->keystack_flushdump == 0) {
14627c478bd9Sstevel@tonic-gate 		/*
14637c478bd9Sstevel@tonic-gate 		 * There were no consumers at all for this message.
14647c478bd9Sstevel@tonic-gate 		 * XXX For now return ESRCH.
14657c478bd9Sstevel@tonic-gate 		 */
14667c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, ESRCH, SADB_X_DIAGNOSTIC_NO_SADBS);
14677c478bd9Sstevel@tonic-gate 	} else {
14687c478bd9Sstevel@tonic-gate 		/* Otherwise, free the original message. */
14697c478bd9Sstevel@tonic-gate 		freemsg(mp);
14707c478bd9Sstevel@tonic-gate 	}
14717c478bd9Sstevel@tonic-gate }
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate /*
14747c478bd9Sstevel@tonic-gate  * Get the right diagnostic for a duplicate.  Should probably use a static
14757c478bd9Sstevel@tonic-gate  * table lookup.
14767c478bd9Sstevel@tonic-gate  */
14777c478bd9Sstevel@tonic-gate int
keysock_duplicate(int ext_type)14787c478bd9Sstevel@tonic-gate keysock_duplicate(int ext_type)
14797c478bd9Sstevel@tonic-gate {
14807c478bd9Sstevel@tonic-gate 	int rc = 0;
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	switch (ext_type) {
14837c478bd9Sstevel@tonic-gate 	case SADB_EXT_ADDRESS_SRC:
14847c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_DUPLICATE_SRC;
14857c478bd9Sstevel@tonic-gate 		break;
14867c478bd9Sstevel@tonic-gate 	case SADB_EXT_ADDRESS_DST:
14877c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_DUPLICATE_DST;
14887c478bd9Sstevel@tonic-gate 		break;
14898810c16bSdanmcd 	case SADB_X_EXT_ADDRESS_INNER_SRC:
14908810c16bSdanmcd 		rc = SADB_X_DIAGNOSTIC_DUPLICATE_INNER_SRC;
14918810c16bSdanmcd 		break;
14928810c16bSdanmcd 	case SADB_X_EXT_ADDRESS_INNER_DST:
14938810c16bSdanmcd 		rc = SADB_X_DIAGNOSTIC_DUPLICATE_INNER_DST;
14948810c16bSdanmcd 		break;
14957c478bd9Sstevel@tonic-gate 	case SADB_EXT_SA:
14967c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_DUPLICATE_SA;
14977c478bd9Sstevel@tonic-gate 		break;
14987c478bd9Sstevel@tonic-gate 	case SADB_EXT_SPIRANGE:
14997c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_DUPLICATE_RANGE;
15007c478bd9Sstevel@tonic-gate 		break;
15017c478bd9Sstevel@tonic-gate 	case SADB_EXT_KEY_AUTH:
15027c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_DUPLICATE_AKEY;
15037c478bd9Sstevel@tonic-gate 		break;
15047c478bd9Sstevel@tonic-gate 	case SADB_EXT_KEY_ENCRYPT:
15057c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_DUPLICATE_EKEY;
15067c478bd9Sstevel@tonic-gate 		break;
15077c478bd9Sstevel@tonic-gate 	}
15087c478bd9Sstevel@tonic-gate 	return (rc);
15097c478bd9Sstevel@tonic-gate }
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate /*
15127c478bd9Sstevel@tonic-gate  * Get the right diagnostic for a reality check failure.  Should probably use
15137c478bd9Sstevel@tonic-gate  * a static table lookup.
15147c478bd9Sstevel@tonic-gate  */
15157c478bd9Sstevel@tonic-gate int
keysock_malformed(int ext_type)15167c478bd9Sstevel@tonic-gate keysock_malformed(int ext_type)
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate 	int rc = 0;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	switch (ext_type) {
15217c478bd9Sstevel@tonic-gate 	case SADB_EXT_ADDRESS_SRC:
15227c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_MALFORMED_SRC;
15237c478bd9Sstevel@tonic-gate 		break;
15247c478bd9Sstevel@tonic-gate 	case SADB_EXT_ADDRESS_DST:
15257c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_MALFORMED_DST;
15267c478bd9Sstevel@tonic-gate 		break;
15278810c16bSdanmcd 	case SADB_X_EXT_ADDRESS_INNER_SRC:
15288810c16bSdanmcd 		rc = SADB_X_DIAGNOSTIC_MALFORMED_INNER_SRC;
15298810c16bSdanmcd 		break;
15308810c16bSdanmcd 	case SADB_X_EXT_ADDRESS_INNER_DST:
15318810c16bSdanmcd 		rc = SADB_X_DIAGNOSTIC_MALFORMED_INNER_DST;
15328810c16bSdanmcd 		break;
15337c478bd9Sstevel@tonic-gate 	case SADB_EXT_SA:
15347c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_MALFORMED_SA;
15357c478bd9Sstevel@tonic-gate 		break;
15367c478bd9Sstevel@tonic-gate 	case SADB_EXT_SPIRANGE:
15377c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_MALFORMED_RANGE;
15387c478bd9Sstevel@tonic-gate 		break;
15397c478bd9Sstevel@tonic-gate 	case SADB_EXT_KEY_AUTH:
15407c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_MALFORMED_AKEY;
15417c478bd9Sstevel@tonic-gate 		break;
15427c478bd9Sstevel@tonic-gate 	case SADB_EXT_KEY_ENCRYPT:
15437c478bd9Sstevel@tonic-gate 		rc = SADB_X_DIAGNOSTIC_MALFORMED_EKEY;
15447c478bd9Sstevel@tonic-gate 		break;
15457c478bd9Sstevel@tonic-gate 	}
15467c478bd9Sstevel@tonic-gate 	return (rc);
15477c478bd9Sstevel@tonic-gate }
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate /*
15507c478bd9Sstevel@tonic-gate  * Keysock massaging of an inverse ACQUIRE.  Consult policy,
15517c478bd9Sstevel@tonic-gate  * and construct an appropriate response.
15527c478bd9Sstevel@tonic-gate  */
15537c478bd9Sstevel@tonic-gate static void
keysock_inverse_acquire(mblk_t * mp,sadb_msg_t * samsg,sadb_ext_t * extv[],keysock_t * ks)15547c478bd9Sstevel@tonic-gate keysock_inverse_acquire(mblk_t *mp, sadb_msg_t *samsg, sadb_ext_t *extv[],
15557c478bd9Sstevel@tonic-gate     keysock_t *ks)
15567c478bd9Sstevel@tonic-gate {
15577c478bd9Sstevel@tonic-gate 	mblk_t *reply_mp;
1558f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	/*
15617c478bd9Sstevel@tonic-gate 	 * Reality check things...
15627c478bd9Sstevel@tonic-gate 	 */
15637c478bd9Sstevel@tonic-gate 	if (extv[SADB_EXT_ADDRESS_SRC] == NULL) {
15647c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_SRC);
15657c478bd9Sstevel@tonic-gate 		return;
15667c478bd9Sstevel@tonic-gate 	}
15677c478bd9Sstevel@tonic-gate 	if (extv[SADB_EXT_ADDRESS_DST] == NULL) {
15687c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_MISSING_DST);
15698810c16bSdanmcd 		return;
15708810c16bSdanmcd 	}
15718810c16bSdanmcd 
15728810c16bSdanmcd 	if (extv[SADB_X_EXT_ADDRESS_INNER_SRC] != NULL &&
15738810c16bSdanmcd 	    extv[SADB_X_EXT_ADDRESS_INNER_DST] == NULL) {
15748810c16bSdanmcd 		keysock_error(ks, mp, EINVAL,
15758810c16bSdanmcd 		    SADB_X_DIAGNOSTIC_MISSING_INNER_DST);
15768810c16bSdanmcd 		return;
15778810c16bSdanmcd 	}
15788810c16bSdanmcd 
15798810c16bSdanmcd 	if (extv[SADB_X_EXT_ADDRESS_INNER_SRC] == NULL &&
15808810c16bSdanmcd 	    extv[SADB_X_EXT_ADDRESS_INNER_DST] != NULL) {
15818810c16bSdanmcd 		keysock_error(ks, mp, EINVAL,
15828810c16bSdanmcd 		    SADB_X_DIAGNOSTIC_MISSING_INNER_SRC);
15838810c16bSdanmcd 		return;
15847c478bd9Sstevel@tonic-gate 	}
15857c478bd9Sstevel@tonic-gate 
1586f4b3ec61Sdh 	reply_mp = ipsec_construct_inverse_acquire(samsg, extv,
1587f4b3ec61Sdh 	    keystack->keystack_netstack);
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	if (reply_mp != NULL) {
15907c478bd9Sstevel@tonic-gate 		freemsg(mp);
15917c478bd9Sstevel@tonic-gate 		keysock_passup(reply_mp, (sadb_msg_t *)reply_mp->b_rptr,
1592f4b3ec61Sdh 		    ks->keysock_serial, NULL, B_FALSE, keystack);
15937c478bd9Sstevel@tonic-gate 	} else {
15947c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, samsg->sadb_msg_errno,
15957c478bd9Sstevel@tonic-gate 		    samsg->sadb_x_msg_diagnostic);
15967c478bd9Sstevel@tonic-gate 	}
15977c478bd9Sstevel@tonic-gate }
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate /*
16007c478bd9Sstevel@tonic-gate  * Spew an extended REGISTER down to the relevant consumers.
16017c478bd9Sstevel@tonic-gate  */
16027c478bd9Sstevel@tonic-gate static void
keysock_extended_register(keysock_t * ks,mblk_t * mp,sadb_ext_t * extv[])16037c478bd9Sstevel@tonic-gate keysock_extended_register(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[])
16047c478bd9Sstevel@tonic-gate {
16057c478bd9Sstevel@tonic-gate 	sadb_x_ereg_t *ereg = (sadb_x_ereg_t *)extv[SADB_X_EXT_EREG];
16067c478bd9Sstevel@tonic-gate 	uint8_t *satypes, *fencepost;
16077c478bd9Sstevel@tonic-gate 	mblk_t *downmp;
16087c478bd9Sstevel@tonic-gate 	sadb_ext_t *downextv[SADB_EXT_MAX + 1];
1609f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 	if (ks->keysock_registered[0] != 0 || ks->keysock_registered[1] != 0 ||
16127c478bd9Sstevel@tonic-gate 	    ks->keysock_registered[2] != 0 || ks->keysock_registered[3] != 0) {
16137c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EBUSY, 0);
16147c478bd9Sstevel@tonic-gate 	}
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 	ks->keysock_flags |= KEYSOCK_EXTENDED;
16177c478bd9Sstevel@tonic-gate 	if (ereg == NULL) {
16187c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_SATYPE_NEEDED);
16197c478bd9Sstevel@tonic-gate 	} else {
16207c478bd9Sstevel@tonic-gate 		ASSERT(mp->b_rptr + msgdsize(mp) == mp->b_wptr);
16217c478bd9Sstevel@tonic-gate 		fencepost = (uint8_t *)mp->b_wptr;
16227c478bd9Sstevel@tonic-gate 		satypes = ereg->sadb_x_ereg_satypes;
16237c478bd9Sstevel@tonic-gate 		while (*satypes != SADB_SATYPE_UNSPEC && satypes != fencepost) {
16247c478bd9Sstevel@tonic-gate 			downmp = copymsg(mp);
16257c478bd9Sstevel@tonic-gate 			if (downmp == NULL) {
16267c478bd9Sstevel@tonic-gate 				keysock_error(ks, mp, ENOMEM, 0);
16277c478bd9Sstevel@tonic-gate 				return;
16287c478bd9Sstevel@tonic-gate 			}
16297c478bd9Sstevel@tonic-gate 			/*
16307c478bd9Sstevel@tonic-gate 			 * Since we've made it here, keysock_get_ext will work!
16317c478bd9Sstevel@tonic-gate 			 */
16327c478bd9Sstevel@tonic-gate 			(void) keysock_get_ext(downextv,
1633f4b3ec61Sdh 			    (sadb_msg_t *)downmp->b_rptr, msgdsize(downmp),
1634f4b3ec61Sdh 			    keystack);
16357c478bd9Sstevel@tonic-gate 			keysock_passdown(ks, downmp, *satypes, downextv,
16367c478bd9Sstevel@tonic-gate 			    B_FALSE);
16377c478bd9Sstevel@tonic-gate 			++satypes;
16387c478bd9Sstevel@tonic-gate 		}
16397c478bd9Sstevel@tonic-gate 		freemsg(mp);
16407c478bd9Sstevel@tonic-gate 	}
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	/*
16437c478bd9Sstevel@tonic-gate 	 * Set global to indicate we prefer an extended ACQUIRE.
16447c478bd9Sstevel@tonic-gate 	 */
16451a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&keystack->keystack_num_extended);
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate 
16489c2c14abSThejaswini Singarajipura static void
keysock_delpair_all(keysock_t * ks,mblk_t * mp,sadb_ext_t * extv[])16499c2c14abSThejaswini Singarajipura keysock_delpair_all(keysock_t *ks, mblk_t *mp, sadb_ext_t *extv[])
16509c2c14abSThejaswini Singarajipura {
16519c2c14abSThejaswini Singarajipura 	int i, start, finish;
16529c2c14abSThejaswini Singarajipura 	mblk_t *mp1 = NULL;
16539c2c14abSThejaswini Singarajipura 	keysock_stack_t *keystack = ks->keysock_keystack;
16549c2c14abSThejaswini Singarajipura 
16559c2c14abSThejaswini Singarajipura 	start = 0;
16569c2c14abSThejaswini Singarajipura 	finish = KEYSOCK_MAX_CONSUMERS - 1;
16579c2c14abSThejaswini Singarajipura 
16589c2c14abSThejaswini Singarajipura 	for (i = start; i <= finish; i++) {
16599c2c14abSThejaswini Singarajipura 		if (keystack->keystack_consumers[i] != NULL) {
16609c2c14abSThejaswini Singarajipura 			mp1 = copymsg(mp);
16619c2c14abSThejaswini Singarajipura 			if (mp1 == NULL) {
16629c2c14abSThejaswini Singarajipura 				keysock_error(ks, mp, ENOMEM,
16639c2c14abSThejaswini Singarajipura 				    SADB_X_DIAGNOSTIC_NONE);
16649c2c14abSThejaswini Singarajipura 				return;
16659c2c14abSThejaswini Singarajipura 			}
16669c2c14abSThejaswini Singarajipura 			keysock_passdown(ks, mp1, i, extv, B_FALSE);
16679c2c14abSThejaswini Singarajipura 		}
16689c2c14abSThejaswini Singarajipura 	}
16699c2c14abSThejaswini Singarajipura }
16709c2c14abSThejaswini Singarajipura 
16717c478bd9Sstevel@tonic-gate /*
16727c478bd9Sstevel@tonic-gate  * Handle PF_KEY messages.
16737c478bd9Sstevel@tonic-gate  */
16747c478bd9Sstevel@tonic-gate static void
keysock_parse(queue_t * q,mblk_t * mp)16757c478bd9Sstevel@tonic-gate keysock_parse(queue_t *q, mblk_t *mp)
16767c478bd9Sstevel@tonic-gate {
16777c478bd9Sstevel@tonic-gate 	sadb_msg_t *samsg;
16787c478bd9Sstevel@tonic-gate 	sadb_ext_t *extv[SADB_EXT_MAX + 1];
16797c478bd9Sstevel@tonic-gate 	keysock_t *ks = (keysock_t *)q->q_ptr;
16807c478bd9Sstevel@tonic-gate 	uint_t msgsize;
16817c478bd9Sstevel@tonic-gate 	uint8_t satype;
1682f4b3ec61Sdh 	keysock_stack_t	*keystack = ks->keysock_keystack;
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	/* Make sure I'm a PF_KEY socket.  (i.e. nothing's below me) */
16857c478bd9Sstevel@tonic-gate 	ASSERT(WR(q)->q_next == NULL);
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 	samsg = (sadb_msg_t *)mp->b_rptr;
1688f4b3ec61Sdh 	ks2dbg(keystack, ("Received possible PF_KEY message, type %d.\n",
16897c478bd9Sstevel@tonic-gate 	    samsg->sadb_msg_type));
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 	msgsize = SADB_64TO8(samsg->sadb_msg_len);
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	if (msgdsize(mp) != msgsize) {
16947c478bd9Sstevel@tonic-gate 		/*
16957c478bd9Sstevel@tonic-gate 		 * Message len incorrect w.r.t. actual size.  Send an error
16967c478bd9Sstevel@tonic-gate 		 * (EMSGSIZE).	It may be necessary to massage things a
16977c478bd9Sstevel@tonic-gate 		 * bit.	 For example, if the sadb_msg_type is hosed,
16987c478bd9Sstevel@tonic-gate 		 * I need to set it to SADB_RESERVED to get delivery to
16997c478bd9Sstevel@tonic-gate 		 * do the right thing.	Then again, maybe just letting
17007c478bd9Sstevel@tonic-gate 		 * the error delivery do the right thing.
17017c478bd9Sstevel@tonic-gate 		 */
1702f4b3ec61Sdh 		ks2dbg(keystack,
1703f4b3ec61Sdh 		    ("mblk (%lu) and base (%d) message sizes don't jibe.\n",
17047c478bd9Sstevel@tonic-gate 		    msgdsize(mp), msgsize));
17057c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EMSGSIZE, SADB_X_DIAGNOSTIC_NONE);
17067c478bd9Sstevel@tonic-gate 		return;
17077c478bd9Sstevel@tonic-gate 	}
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 	if (msgsize > (uint_t)(mp->b_wptr - mp->b_rptr)) {
17107c478bd9Sstevel@tonic-gate 		/* Get all message into one mblk. */
17117c478bd9Sstevel@tonic-gate 		if (pullupmsg(mp, -1) == 0) {
17127c478bd9Sstevel@tonic-gate 			/*
17137c478bd9Sstevel@tonic-gate 			 * Something screwy happened.
17147c478bd9Sstevel@tonic-gate 			 */
1715f4b3ec61Sdh 			ks3dbg(keystack,
1716f4b3ec61Sdh 			    ("keysock_parse: pullupmsg() failed.\n"));
17177c478bd9Sstevel@tonic-gate 			return;
17187c478bd9Sstevel@tonic-gate 		} else {
17197c478bd9Sstevel@tonic-gate 			samsg = (sadb_msg_t *)mp->b_rptr;
17207c478bd9Sstevel@tonic-gate 		}
17217c478bd9Sstevel@tonic-gate 	}
17227c478bd9Sstevel@tonic-gate 
1723f4b3ec61Sdh 	switch (keysock_get_ext(extv, samsg, msgsize, keystack)) {
17247c478bd9Sstevel@tonic-gate 	case KGE_DUP:
17257c478bd9Sstevel@tonic-gate 		/* Handle duplicate extension. */
1726f4b3ec61Sdh 		ks1dbg(keystack, ("Got duplicate extension of type %d.\n",
17277c478bd9Sstevel@tonic-gate 		    extv[0]->sadb_ext_type));
17287c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EINVAL,
17297c478bd9Sstevel@tonic-gate 		    keysock_duplicate(extv[0]->sadb_ext_type));
17307c478bd9Sstevel@tonic-gate 		return;
17317c478bd9Sstevel@tonic-gate 	case KGE_UNK:
17327c478bd9Sstevel@tonic-gate 		/* Handle unknown extension. */
1733f4b3ec61Sdh 		ks1dbg(keystack, ("Got unknown extension of type %d.\n",
17347c478bd9Sstevel@tonic-gate 		    extv[0]->sadb_ext_type));
17357c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_EXT);
17367c478bd9Sstevel@tonic-gate 		return;
17377c478bd9Sstevel@tonic-gate 	case KGE_LEN:
17387c478bd9Sstevel@tonic-gate 		/* Length error. */
1739f4b3ec61Sdh 		ks1dbg(keystack,
1740f4b3ec61Sdh 		    ("Length %d on extension type %d overrun or 0.\n",
17417c478bd9Sstevel@tonic-gate 		    extv[0]->sadb_ext_len, extv[0]->sadb_ext_type));
17427c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_BAD_EXTLEN);
17437c478bd9Sstevel@tonic-gate 		return;
17447c478bd9Sstevel@tonic-gate 	case KGE_CHK:
17457c478bd9Sstevel@tonic-gate 		/* Reality check failed. */
1746f4b3ec61Sdh 		ks1dbg(keystack,
1747f4b3ec61Sdh 		    ("Reality check failed on extension type %d.\n",
17487c478bd9Sstevel@tonic-gate 		    extv[0]->sadb_ext_type));
17497c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EINVAL,
17507c478bd9Sstevel@tonic-gate 		    keysock_malformed(extv[0]->sadb_ext_type));
17517c478bd9Sstevel@tonic-gate 		return;
17527c478bd9Sstevel@tonic-gate 	default:
17537c478bd9Sstevel@tonic-gate 		/* Default case is no errors. */
17547c478bd9Sstevel@tonic-gate 		break;
17557c478bd9Sstevel@tonic-gate 	}
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	switch (samsg->sadb_msg_type) {
17587c478bd9Sstevel@tonic-gate 	case SADB_REGISTER:
17597c478bd9Sstevel@tonic-gate 		/*
17607c478bd9Sstevel@tonic-gate 		 * There's a semantic weirdness in that a message OTHER than
17617c478bd9Sstevel@tonic-gate 		 * the return REGISTER message may be passed up if I set the
17627c478bd9Sstevel@tonic-gate 		 * registered bit BEFORE I pass it down.
17637c478bd9Sstevel@tonic-gate 		 *
17647c478bd9Sstevel@tonic-gate 		 * SOOOO, I'll not twiddle any registered bits until I see
17657c478bd9Sstevel@tonic-gate 		 * the upbound REGISTER (with a serial number in it).
17667c478bd9Sstevel@tonic-gate 		 */
17677c478bd9Sstevel@tonic-gate 		if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) {
17687c478bd9Sstevel@tonic-gate 			/* Handle extended register here. */
17697c478bd9Sstevel@tonic-gate 			keysock_extended_register(ks, mp, extv);
17707c478bd9Sstevel@tonic-gate 			return;
17717c478bd9Sstevel@tonic-gate 		} else if (ks->keysock_flags & KEYSOCK_EXTENDED) {
17727c478bd9Sstevel@tonic-gate 			keysock_error(ks, mp, EBUSY, 0);
17737c478bd9Sstevel@tonic-gate 			return;
17747c478bd9Sstevel@tonic-gate 		}
17757c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
17767c478bd9Sstevel@tonic-gate 	case SADB_GETSPI:
17777c478bd9Sstevel@tonic-gate 	case SADB_ADD:
17787c478bd9Sstevel@tonic-gate 	case SADB_UPDATE:
177938d95a78Smarkfen 	case SADB_X_UPDATEPAIR:
17807c478bd9Sstevel@tonic-gate 	case SADB_DELETE:
178138d95a78Smarkfen 	case SADB_X_DELPAIR:
17827c478bd9Sstevel@tonic-gate 	case SADB_GET:
17837c478bd9Sstevel@tonic-gate 		/*
17847c478bd9Sstevel@tonic-gate 		 * Pass down to appropriate consumer.
17857c478bd9Sstevel@tonic-gate 		 */
17867c478bd9Sstevel@tonic-gate 		if (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC)
17877c478bd9Sstevel@tonic-gate 			keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv,
17887c478bd9Sstevel@tonic-gate 			    B_FALSE);
17897c478bd9Sstevel@tonic-gate 		else keysock_error(ks, mp, EINVAL,
17907c478bd9Sstevel@tonic-gate 		    SADB_X_DIAGNOSTIC_SATYPE_NEEDED);
17917c478bd9Sstevel@tonic-gate 		return;
17929c2c14abSThejaswini Singarajipura 	case SADB_X_DELPAIR_STATE:
17939c2c14abSThejaswini Singarajipura 		if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) {
17949c2c14abSThejaswini Singarajipura 			keysock_delpair_all(ks, mp, extv);
17959c2c14abSThejaswini Singarajipura 		} else {
17969c2c14abSThejaswini Singarajipura 			keysock_passdown(ks, mp, samsg->sadb_msg_satype, extv,
17979c2c14abSThejaswini Singarajipura 			    B_FALSE);
17989c2c14abSThejaswini Singarajipura 		}
17999c2c14abSThejaswini Singarajipura 		return;
18007c478bd9Sstevel@tonic-gate 	case SADB_ACQUIRE:
18017c478bd9Sstevel@tonic-gate 		/*
18027c478bd9Sstevel@tonic-gate 		 * If I _receive_ an acquire, this means I should spread it
18037c478bd9Sstevel@tonic-gate 		 * out to registered sockets.  Unless there's an errno...
18047c478bd9Sstevel@tonic-gate 		 *
18057c478bd9Sstevel@tonic-gate 		 * Need ADDRESS, may have ID, SENS, and PROP, unless errno,
18067c478bd9Sstevel@tonic-gate 		 * in which case there should be NO extensions.
18077c478bd9Sstevel@tonic-gate 		 *
18087c478bd9Sstevel@tonic-gate 		 * Return to registered.
18097c478bd9Sstevel@tonic-gate 		 */
18107c478bd9Sstevel@tonic-gate 		if (samsg->sadb_msg_errno != 0) {
18117c478bd9Sstevel@tonic-gate 			satype = samsg->sadb_msg_satype;
18127c478bd9Sstevel@tonic-gate 			if (satype == SADB_SATYPE_UNSPEC) {
18137c478bd9Sstevel@tonic-gate 				if (!(ks->keysock_flags & KEYSOCK_EXTENDED)) {
18147c478bd9Sstevel@tonic-gate 					keysock_error(ks, mp, EINVAL,
18157c478bd9Sstevel@tonic-gate 					    SADB_X_DIAGNOSTIC_SATYPE_NEEDED);
18167c478bd9Sstevel@tonic-gate 					return;
18177c478bd9Sstevel@tonic-gate 				}
18187c478bd9Sstevel@tonic-gate 				/*
18197c478bd9Sstevel@tonic-gate 				 * Reassign satype based on the first
18207c478bd9Sstevel@tonic-gate 				 * flags that KEYSOCK_SETREG says.
18217c478bd9Sstevel@tonic-gate 				 */
18227c478bd9Sstevel@tonic-gate 				while (satype <= SADB_SATYPE_MAX) {
18237c478bd9Sstevel@tonic-gate 					if (KEYSOCK_ISREG(ks, satype))
18247c478bd9Sstevel@tonic-gate 						break;
18257c478bd9Sstevel@tonic-gate 					satype++;
18267c478bd9Sstevel@tonic-gate 				}
18277c478bd9Sstevel@tonic-gate 				if (satype > SADB_SATYPE_MAX) {
18287c478bd9Sstevel@tonic-gate 					keysock_error(ks, mp, EBUSY, 0);
18297c478bd9Sstevel@tonic-gate 					return;
18307c478bd9Sstevel@tonic-gate 				}
18317c478bd9Sstevel@tonic-gate 			}
18327c478bd9Sstevel@tonic-gate 			keysock_passdown(ks, mp, satype, extv, B_FALSE);
18337c478bd9Sstevel@tonic-gate 		} else {
1834f4b3ec61Sdh 			if (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC) {
18357c478bd9Sstevel@tonic-gate 				keysock_error(ks, mp, EINVAL,
18367c478bd9Sstevel@tonic-gate 				    SADB_X_DIAGNOSTIC_SATYPE_NEEDED);
1837f4b3ec61Sdh 			} else {
1838f4b3ec61Sdh 				keysock_passup(mp, samsg, 0, NULL, B_FALSE,
1839f4b3ec61Sdh 				    keystack);
1840f4b3ec61Sdh 			}
18417c478bd9Sstevel@tonic-gate 		}
18427c478bd9Sstevel@tonic-gate 		return;
18437c478bd9Sstevel@tonic-gate 	case SADB_EXPIRE:
18447c478bd9Sstevel@tonic-gate 		/*
18457c478bd9Sstevel@tonic-gate 		 * If someone sends this in, then send out to all senders.
18467c478bd9Sstevel@tonic-gate 		 * (Save maybe ESP or AH, I have to be careful here.)
18477c478bd9Sstevel@tonic-gate 		 *
18487c478bd9Sstevel@tonic-gate 		 * Need ADDRESS, may have ID and SENS.
18497c478bd9Sstevel@tonic-gate 		 *
18507c478bd9Sstevel@tonic-gate 		 * XXX for now this is unsupported.
18517c478bd9Sstevel@tonic-gate 		 */
18527c478bd9Sstevel@tonic-gate 		break;
18537c478bd9Sstevel@tonic-gate 	case SADB_FLUSH:
18547c478bd9Sstevel@tonic-gate 		/*
18559c2c14abSThejaswini Singarajipura 		 * Nuke all SAs.
18567c478bd9Sstevel@tonic-gate 		 *
18577c478bd9Sstevel@tonic-gate 		 * No extensions at all.  Return to all listeners.
18587c478bd9Sstevel@tonic-gate 		 *
18597c478bd9Sstevel@tonic-gate 		 * Question:	Should I hold a lock here to prevent
18607c478bd9Sstevel@tonic-gate 		 *		additions/deletions while flushing?
18617c478bd9Sstevel@tonic-gate 		 * Answer:	No.  (See keysock_passdown() for details.)
18627c478bd9Sstevel@tonic-gate 		 */
18637c478bd9Sstevel@tonic-gate 		if (extv[0] != NULL) {
18647c478bd9Sstevel@tonic-gate 			/*
18659c2c14abSThejaswini Singarajipura 			 * FLUSH messages shouldn't have extensions.
18667c478bd9Sstevel@tonic-gate 			 * Return EINVAL.
18677c478bd9Sstevel@tonic-gate 			 */
1868f4b3ec61Sdh 			ks2dbg(keystack, ("FLUSH message with extension.\n"));
18697c478bd9Sstevel@tonic-gate 			keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_NO_EXT);
18707c478bd9Sstevel@tonic-gate 			return;
18717c478bd9Sstevel@tonic-gate 		}
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 		/* Passing down of DUMP/FLUSH messages are special. */
18749c2c14abSThejaswini Singarajipura 		qwriter(q, mp, keysock_do_flushdump, PERIM_INNER);
18759c2c14abSThejaswini Singarajipura 		return;
18769c2c14abSThejaswini Singarajipura 	case SADB_DUMP:	 /* not used by normal applications */
18779c2c14abSThejaswini Singarajipura 		if ((extv[0] != NULL) &&
18789c2c14abSThejaswini Singarajipura 		    ((msgsize >
18799c2c14abSThejaswini Singarajipura 		    (sizeof (sadb_msg_t) + sizeof (sadb_x_edump_t))) ||
18809c2c14abSThejaswini Singarajipura 		    (extv[SADB_X_EXT_EDUMP] == NULL))) {
18819c2c14abSThejaswini Singarajipura 				keysock_error(ks, mp, EINVAL,
18829c2c14abSThejaswini Singarajipura 				    SADB_X_DIAGNOSTIC_NO_EXT);
18839c2c14abSThejaswini Singarajipura 				return;
18849c2c14abSThejaswini Singarajipura 		}
18857c478bd9Sstevel@tonic-gate 		qwriter(q, mp, keysock_do_flushdump, PERIM_INNER);
18867c478bd9Sstevel@tonic-gate 		return;
18877c478bd9Sstevel@tonic-gate 	case SADB_X_PROMISC:
18887c478bd9Sstevel@tonic-gate 		/*
18897c478bd9Sstevel@tonic-gate 		 * Promiscuous processing message.
18907c478bd9Sstevel@tonic-gate 		 */
18917c478bd9Sstevel@tonic-gate 		if (samsg->sadb_msg_satype == 0)
18927c478bd9Sstevel@tonic-gate 			ks->keysock_flags &= ~KEYSOCK_PROMISC;
18937c478bd9Sstevel@tonic-gate 		else
18947c478bd9Sstevel@tonic-gate 			ks->keysock_flags |= KEYSOCK_PROMISC;
1895f4b3ec61Sdh 		keysock_passup(mp, samsg, ks->keysock_serial, NULL, B_FALSE,
1896f4b3ec61Sdh 		    keystack);
18977c478bd9Sstevel@tonic-gate 		return;
18987c478bd9Sstevel@tonic-gate 	case SADB_X_INVERSE_ACQUIRE:
18997c478bd9Sstevel@tonic-gate 		keysock_inverse_acquire(mp, samsg, extv, ks);
19007c478bd9Sstevel@tonic-gate 		return;
19017c478bd9Sstevel@tonic-gate 	default:
1902f4b3ec61Sdh 		ks2dbg(keystack, ("Got unknown message type %d.\n",
19037c478bd9Sstevel@tonic-gate 		    samsg->sadb_msg_type));
19047c478bd9Sstevel@tonic-gate 		keysock_error(ks, mp, EINVAL, SADB_X_DIAGNOSTIC_UNKNOWN_MSG);
19057c478bd9Sstevel@tonic-gate 		return;
19067c478bd9Sstevel@tonic-gate 	}
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	/* As a placeholder... */
19097c478bd9Sstevel@tonic-gate 	ks0dbg(("keysock_parse():  Hit EOPNOTSUPP\n"));
19107c478bd9Sstevel@tonic-gate 	keysock_error(ks, mp, EOPNOTSUPP, SADB_X_DIAGNOSTIC_NONE);
19117c478bd9Sstevel@tonic-gate }
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate /*
19147c478bd9Sstevel@tonic-gate  * wput routing for PF_KEY/keysock/whatever.  Unlike the routing socket,
19157c478bd9Sstevel@tonic-gate  * I don't convert to ioctl()'s for IP.  I am the end-all driver as far
19167c478bd9Sstevel@tonic-gate  * as PF_KEY sockets are concerned.  I do some conversion, but not as much
19177c478bd9Sstevel@tonic-gate  * as IP/rts does.
19187c478bd9Sstevel@tonic-gate  */
1919*4f2d1f9dSToomas Soome static int
keysock_wput(queue_t * q,mblk_t * mp)19207c478bd9Sstevel@tonic-gate keysock_wput(queue_t *q, mblk_t *mp)
19217c478bd9Sstevel@tonic-gate {
19227c478bd9Sstevel@tonic-gate 	uchar_t *rptr = mp->b_rptr;
19237c478bd9Sstevel@tonic-gate 	mblk_t *mp1;
1924f4b3ec61Sdh 	keysock_t *ks;
1925f4b3ec61Sdh 	keysock_stack_t	*keystack;
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 	if (WR(q)->q_next) {
19287c478bd9Sstevel@tonic-gate 		keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr;
1929f4b3ec61Sdh 		keystack = kc->kc_keystack;
1930f4b3ec61Sdh 
1931f4b3ec61Sdh 		ks3dbg(keystack, ("In keysock_wput\n"));
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 		/*
19347c478bd9Sstevel@tonic-gate 		 * We shouldn't get writes on a consumer instance.
19357c478bd9Sstevel@tonic-gate 		 * But for now, just passthru.
19367c478bd9Sstevel@tonic-gate 		 */
1937f4b3ec61Sdh 		ks1dbg(keystack, ("Huh?  wput for an consumer instance (%d)?\n",
19387c478bd9Sstevel@tonic-gate 		    kc->kc_sa_type));
19397c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1940*4f2d1f9dSToomas Soome 		return (0);
19417c478bd9Sstevel@tonic-gate 	}
1942f4b3ec61Sdh 	ks = (keysock_t *)q->q_ptr;
1943f4b3ec61Sdh 	keystack = ks->keysock_keystack;
1944f4b3ec61Sdh 
1945f4b3ec61Sdh 	ks3dbg(keystack, ("In keysock_wput\n"));
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
19487c478bd9Sstevel@tonic-gate 	case M_DATA:
19497c478bd9Sstevel@tonic-gate 		/*
19507c478bd9Sstevel@tonic-gate 		 * Silently discard.
19517c478bd9Sstevel@tonic-gate 		 */
1952f4b3ec61Sdh 		ks2dbg(keystack, ("raw M_DATA in keysock.\n"));
19537c478bd9Sstevel@tonic-gate 		freemsg(mp);
1954*4f2d1f9dSToomas Soome 		return (0);
19557c478bd9Sstevel@tonic-gate 	case M_PROTO:
19567c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
19577c478bd9Sstevel@tonic-gate 		if ((mp->b_wptr - rptr) >= sizeof (struct T_data_req)) {
19587c478bd9Sstevel@tonic-gate 			if (((union T_primitives *)rptr)->type == T_DATA_REQ) {
19597c478bd9Sstevel@tonic-gate 				if ((mp1 = mp->b_cont) == NULL) {
19607c478bd9Sstevel@tonic-gate 					/* No data after T_DATA_REQ. */
1961f4b3ec61Sdh 					ks2dbg(keystack,
1962f4b3ec61Sdh 					    ("No data after DATA_REQ.\n"));
19637c478bd9Sstevel@tonic-gate 					freemsg(mp);
1964*4f2d1f9dSToomas Soome 					return (0);
19657c478bd9Sstevel@tonic-gate 				}
19667c478bd9Sstevel@tonic-gate 				freeb(mp);
19677c478bd9Sstevel@tonic-gate 				mp = mp1;
1968f4b3ec61Sdh 				ks2dbg(keystack, ("T_DATA_REQ\n"));
19697c478bd9Sstevel@tonic-gate 				break;	/* Out of switch. */
19707c478bd9Sstevel@tonic-gate 			}
19717c478bd9Sstevel@tonic-gate 		}
19727c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
19737c478bd9Sstevel@tonic-gate 	default:
1974f4b3ec61Sdh 		ks3dbg(keystack, ("In default wput case (%d %d).\n",
19757c478bd9Sstevel@tonic-gate 		    mp->b_datap->db_type, ((union T_primitives *)rptr)->type));
19767c478bd9Sstevel@tonic-gate 		keysock_wput_other(q, mp);
1977*4f2d1f9dSToomas Soome 		return (0);
19787c478bd9Sstevel@tonic-gate 	}
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 	/* I now have a PF_KEY message in an M_DATA block, pointed to by mp. */
19817c478bd9Sstevel@tonic-gate 	keysock_parse(q, mp);
1982*4f2d1f9dSToomas Soome 	return (0);
19837c478bd9Sstevel@tonic-gate }
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate /* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_rput(). */
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate /*
19887c478bd9Sstevel@tonic-gate  * Called upon receipt of a KEYSOCK_HELLO_ACK to set up the appropriate
19897c478bd9Sstevel@tonic-gate  * state vectors.
19907c478bd9Sstevel@tonic-gate  */
19917c478bd9Sstevel@tonic-gate static void
keysock_link_consumer(uint8_t satype,keysock_consumer_t * kc)19927c478bd9Sstevel@tonic-gate keysock_link_consumer(uint8_t satype, keysock_consumer_t *kc)
19937c478bd9Sstevel@tonic-gate {
19947c478bd9Sstevel@tonic-gate 	keysock_t *ks;
1995f4b3ec61Sdh 	keysock_stack_t	*keystack = kc->kc_keystack;
19967c478bd9Sstevel@tonic-gate 
1997f4b3ec61Sdh 	mutex_enter(&keystack->keystack_consumers_lock);
19987c478bd9Sstevel@tonic-gate 	mutex_enter(&kc->kc_lock);
1999f4b3ec61Sdh 	if (keystack->keystack_consumers[satype] != NULL) {
20007c478bd9Sstevel@tonic-gate 		ks0dbg((
20017c478bd9Sstevel@tonic-gate 		    "Hmmmm, someone closed %d before the HELLO_ACK happened.\n",
20027c478bd9Sstevel@tonic-gate 		    satype));
20037c478bd9Sstevel@tonic-gate 		/*
20047c478bd9Sstevel@tonic-gate 		 * Perhaps updating the new below-me consumer with what I have
20057c478bd9Sstevel@tonic-gate 		 * so far would work too?
20067c478bd9Sstevel@tonic-gate 		 */
20077c478bd9Sstevel@tonic-gate 		mutex_exit(&kc->kc_lock);
2008f4b3ec61Sdh 		mutex_exit(&keystack->keystack_consumers_lock);
20097c478bd9Sstevel@tonic-gate 	} else {
20107c478bd9Sstevel@tonic-gate 		/* Add new below-me consumer. */
2011f4b3ec61Sdh 		keystack->keystack_consumers[satype] = kc;
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate 		kc->kc_flags = 0;
20147c478bd9Sstevel@tonic-gate 		kc->kc_sa_type = satype;
20157c478bd9Sstevel@tonic-gate 		mutex_exit(&kc->kc_lock);
2016f4b3ec61Sdh 		mutex_exit(&keystack->keystack_consumers_lock);
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate 		/* Scan the keysock list. */
2019f4b3ec61Sdh 		mutex_enter(&keystack->keystack_list_lock);
2020f4b3ec61Sdh 		for (ks = keystack->keystack_list; ks != NULL;
2021f4b3ec61Sdh 		    ks = ks->keysock_next) {
20227c478bd9Sstevel@tonic-gate 			if (KEYSOCK_ISREG(ks, satype)) {
20237c478bd9Sstevel@tonic-gate 				/*
20247c478bd9Sstevel@tonic-gate 				 * XXX Perhaps send an SADB_REGISTER down on
20257c478bd9Sstevel@tonic-gate 				 * the socket's behalf.
20267c478bd9Sstevel@tonic-gate 				 */
2027f4b3ec61Sdh 				ks1dbg(keystack,
2028f4b3ec61Sdh 				    ("Socket %u registered already for "
20297c478bd9Sstevel@tonic-gate 				    "new consumer.\n", ks->keysock_serial));
20307c478bd9Sstevel@tonic-gate 			}
20317c478bd9Sstevel@tonic-gate 		}
2032f4b3ec61Sdh 		mutex_exit(&keystack->keystack_list_lock);
20337c478bd9Sstevel@tonic-gate 	}
20347c478bd9Sstevel@tonic-gate }
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate /*
20377c478bd9Sstevel@tonic-gate  * Generate a KEYSOCK_OUT_ERR message for my consumer.
20387c478bd9Sstevel@tonic-gate  */
20397c478bd9Sstevel@tonic-gate static void
keysock_out_err(keysock_consumer_t * kc,int ks_errno,mblk_t * mp)20407c478bd9Sstevel@tonic-gate keysock_out_err(keysock_consumer_t *kc, int ks_errno, mblk_t *mp)
20417c478bd9Sstevel@tonic-gate {
20427c478bd9Sstevel@tonic-gate 	keysock_out_err_t *kse;
20437c478bd9Sstevel@tonic-gate 	mblk_t *imp;
2044f4b3ec61Sdh 	keysock_stack_t	*keystack = kc->kc_keystack;
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate 	imp = allocb(sizeof (ipsec_info_t), BPRI_HI);
20477c478bd9Sstevel@tonic-gate 	if (imp == NULL) {
2048f4b3ec61Sdh 		ks1dbg(keystack, ("keysock_out_err:  Can't alloc message.\n"));
20497c478bd9Sstevel@tonic-gate 		return;
20507c478bd9Sstevel@tonic-gate 	}
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	imp->b_datap->db_type = M_CTL;
20537c478bd9Sstevel@tonic-gate 	imp->b_wptr += sizeof (ipsec_info_t);
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate 	kse = (keysock_out_err_t *)imp->b_rptr;
20567c478bd9Sstevel@tonic-gate 	imp->b_cont = mp;
20577c478bd9Sstevel@tonic-gate 	kse->ks_err_type = KEYSOCK_OUT_ERR;
20587c478bd9Sstevel@tonic-gate 	kse->ks_err_len = sizeof (*kse);
20597c478bd9Sstevel@tonic-gate 	/* Is serial necessary? */
20607c478bd9Sstevel@tonic-gate 	kse->ks_err_serial = 0;
20617c478bd9Sstevel@tonic-gate 	kse->ks_err_errno = ks_errno;
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	/*
20647c478bd9Sstevel@tonic-gate 	 * XXX What else do I need to do here w.r.t. information
20657c478bd9Sstevel@tonic-gate 	 * to tell the consumer what caused this error?
20667c478bd9Sstevel@tonic-gate 	 *
20677c478bd9Sstevel@tonic-gate 	 * I believe the answer is the PF_KEY ACQUIRE (or other) message
20687c478bd9Sstevel@tonic-gate 	 * attached in mp, which is appended at the end.  I believe the
20697c478bd9Sstevel@tonic-gate 	 * db_ref won't matter here, because the PF_KEY message is only read
20707c478bd9Sstevel@tonic-gate 	 * for KEYSOCK_OUT_ERR.
20717c478bd9Sstevel@tonic-gate 	 */
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	putnext(kc->kc_wq, imp);
20747c478bd9Sstevel@tonic-gate }
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate /* XXX this is a hack errno. */
20777c478bd9Sstevel@tonic-gate #define	EIPSECNOSA 255
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate /*
20807c478bd9Sstevel@tonic-gate  * Route message (pointed by mp, header in samsg) toward appropriate
20817c478bd9Sstevel@tonic-gate  * sockets.  Assume the message's creator did its job correctly.
20827c478bd9Sstevel@tonic-gate  *
20837c478bd9Sstevel@tonic-gate  * This should be a function that is followed by a return in its caller.
20847c478bd9Sstevel@tonic-gate  * The compiler _should_ be able to use tail-call optimizations to make the
20857c478bd9Sstevel@tonic-gate  * large ## of parameters not a huge deal.
20867c478bd9Sstevel@tonic-gate  */
20877c478bd9Sstevel@tonic-gate static void
keysock_passup(mblk_t * mp,sadb_msg_t * samsg,minor_t serial,keysock_consumer_t * kc,boolean_t persistent,keysock_stack_t * keystack)20887c478bd9Sstevel@tonic-gate keysock_passup(mblk_t *mp, sadb_msg_t *samsg, minor_t serial,
2089f4b3ec61Sdh     keysock_consumer_t *kc, boolean_t persistent, keysock_stack_t *keystack)
20907c478bd9Sstevel@tonic-gate {
20917c478bd9Sstevel@tonic-gate 	keysock_t *ks;
20927c478bd9Sstevel@tonic-gate 	uint8_t satype = samsg->sadb_msg_satype;
20937c478bd9Sstevel@tonic-gate 	boolean_t toall = B_FALSE, allreg = B_FALSE, allereg = B_FALSE,
20947c478bd9Sstevel@tonic-gate 	    setalg = B_FALSE;
20957c478bd9Sstevel@tonic-gate 	mblk_t *mp1;
20967c478bd9Sstevel@tonic-gate 	int err = EIPSECNOSA;
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate 	/* Convert mp, which is M_DATA, into an M_PROTO of type T_DATA_IND */
20997c478bd9Sstevel@tonic-gate 	mp1 = allocb(sizeof (struct T_data_req), BPRI_HI);
21007c478bd9Sstevel@tonic-gate 	if (mp1 == NULL) {
21017c478bd9Sstevel@tonic-gate 		err = ENOMEM;
21027c478bd9Sstevel@tonic-gate 		goto error;
21037c478bd9Sstevel@tonic-gate 	}
21047c478bd9Sstevel@tonic-gate 	mp1->b_wptr += sizeof (struct T_data_req);
21057c478bd9Sstevel@tonic-gate 	((struct T_data_ind *)mp1->b_rptr)->PRIM_type = T_DATA_IND;
21067c478bd9Sstevel@tonic-gate 	((struct T_data_ind *)mp1->b_rptr)->MORE_flag = 0;
21077c478bd9Sstevel@tonic-gate 	mp1->b_datap->db_type = M_PROTO;
21087c478bd9Sstevel@tonic-gate 	mp1->b_cont = mp;
21097c478bd9Sstevel@tonic-gate 	mp = mp1;
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 	switch (samsg->sadb_msg_type) {
21127c478bd9Sstevel@tonic-gate 	case SADB_FLUSH:
21137c478bd9Sstevel@tonic-gate 	case SADB_GETSPI:
21147c478bd9Sstevel@tonic-gate 	case SADB_UPDATE:
211538d95a78Smarkfen 	case SADB_X_UPDATEPAIR:
21167c478bd9Sstevel@tonic-gate 	case SADB_ADD:
21177c478bd9Sstevel@tonic-gate 	case SADB_DELETE:
211838d95a78Smarkfen 	case SADB_X_DELPAIR:
21197c478bd9Sstevel@tonic-gate 	case SADB_EXPIRE:
21207c478bd9Sstevel@tonic-gate 		/*
21217c478bd9Sstevel@tonic-gate 		 * These are most likely replies.  Don't worry about
21227c478bd9Sstevel@tonic-gate 		 * KEYSOCK_OUT_ERR handling.  Deliver to all sockets.
21237c478bd9Sstevel@tonic-gate 		 */
2124f4b3ec61Sdh 		ks3dbg(keystack,
2125f4b3ec61Sdh 		    ("Delivering normal message (%d) to all sockets.\n",
21267c478bd9Sstevel@tonic-gate 		    samsg->sadb_msg_type));
21277c478bd9Sstevel@tonic-gate 		toall = B_TRUE;
21287c478bd9Sstevel@tonic-gate 		break;
21297c478bd9Sstevel@tonic-gate 	case SADB_REGISTER:
21307c478bd9Sstevel@tonic-gate 		/*
21317c478bd9Sstevel@tonic-gate 		 * REGISTERs come up for one of three reasons:
21327c478bd9Sstevel@tonic-gate 		 *
21337c478bd9Sstevel@tonic-gate 		 *	1.) In response to a normal SADB_REGISTER
21347c478bd9Sstevel@tonic-gate 		 *		(samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC &&
21357c478bd9Sstevel@tonic-gate 		 *		    serial != 0)
21367c478bd9Sstevel@tonic-gate 		 *		Deliver to normal SADB_REGISTERed sockets.
21377c478bd9Sstevel@tonic-gate 		 *	2.) In response to an extended REGISTER
21387c478bd9Sstevel@tonic-gate 		 *		(samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC)
21397c478bd9Sstevel@tonic-gate 		 *		Deliver to extended REGISTERed socket.
21407c478bd9Sstevel@tonic-gate 		 *	3.) Spontaneous algorithm changes
21417c478bd9Sstevel@tonic-gate 		 *		(samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC &&
21427c478bd9Sstevel@tonic-gate 		 *		    serial == 0)
21437c478bd9Sstevel@tonic-gate 		 *		Deliver to REGISTERed sockets of all sorts.
21447c478bd9Sstevel@tonic-gate 		 */
21457c478bd9Sstevel@tonic-gate 		if (kc == NULL) {
21467c478bd9Sstevel@tonic-gate 			/* Here because of keysock_error() call. */
21477c478bd9Sstevel@tonic-gate 			ASSERT(samsg->sadb_msg_errno != 0);
21487c478bd9Sstevel@tonic-gate 			break;	/* Out of switch. */
21497c478bd9Sstevel@tonic-gate 		}
2150f4b3ec61Sdh 		ks3dbg(keystack, ("Delivering REGISTER.\n"));
21517c478bd9Sstevel@tonic-gate 		if (satype == SADB_SATYPE_UNSPEC) {
21527c478bd9Sstevel@tonic-gate 			/* REGISTER Reason #2 */
21537c478bd9Sstevel@tonic-gate 			allereg = B_TRUE;
21547c478bd9Sstevel@tonic-gate 			/*
21557c478bd9Sstevel@tonic-gate 			 * Rewhack SA type so PF_KEY socket holder knows what
21567c478bd9Sstevel@tonic-gate 			 * consumer generated this algorithm list.
21577c478bd9Sstevel@tonic-gate 			 */
21587c478bd9Sstevel@tonic-gate 			satype = kc->kc_sa_type;
21597c478bd9Sstevel@tonic-gate 			samsg->sadb_msg_satype = satype;
21607c478bd9Sstevel@tonic-gate 			setalg = B_TRUE;
21617c478bd9Sstevel@tonic-gate 		} else if (serial == 0) {
21627c478bd9Sstevel@tonic-gate 			/* REGISTER Reason #3 */
21637c478bd9Sstevel@tonic-gate 			allreg = B_TRUE;
21647c478bd9Sstevel@tonic-gate 			allereg = B_TRUE;
21657c478bd9Sstevel@tonic-gate 		} else {
21667c478bd9Sstevel@tonic-gate 			/* REGISTER Reason #1 */
21677c478bd9Sstevel@tonic-gate 			allreg = B_TRUE;
21687c478bd9Sstevel@tonic-gate 			setalg = B_TRUE;
21697c478bd9Sstevel@tonic-gate 		}
21707c478bd9Sstevel@tonic-gate 		break;
21717c478bd9Sstevel@tonic-gate 	case SADB_ACQUIRE:
21727c478bd9Sstevel@tonic-gate 		/*
21737c478bd9Sstevel@tonic-gate 		 * ACQUIREs are either extended (sadb_msg_satype == 0) or
21747c478bd9Sstevel@tonic-gate 		 * regular (sadb_msg_satype != 0).  And we're guaranteed
21757c478bd9Sstevel@tonic-gate 		 * that serial == 0 for an ACQUIRE.
21767c478bd9Sstevel@tonic-gate 		 */
2177f4b3ec61Sdh 		ks3dbg(keystack, ("Delivering ACQUIRE.\n"));
21787c478bd9Sstevel@tonic-gate 		allereg = (satype == SADB_SATYPE_UNSPEC);
21797c478bd9Sstevel@tonic-gate 		allreg = !allereg;
21807c478bd9Sstevel@tonic-gate 		/*
21817c478bd9Sstevel@tonic-gate 		 * Corner case - if we send a regular ACQUIRE and there's
21827c478bd9Sstevel@tonic-gate 		 * extended ones registered, don't send an error down to
21837c478bd9Sstevel@tonic-gate 		 * consumers if nobody's listening and prematurely destroy
21847c478bd9Sstevel@tonic-gate 		 * their ACQUIRE record.  This might be too hackish of a
21857c478bd9Sstevel@tonic-gate 		 * solution.
21867c478bd9Sstevel@tonic-gate 		 */
2187f4b3ec61Sdh 		if (allreg && keystack->keystack_num_extended > 0)
21887c478bd9Sstevel@tonic-gate 			err = 0;
21897c478bd9Sstevel@tonic-gate 		break;
21907c478bd9Sstevel@tonic-gate 	case SADB_X_PROMISC:
21917c478bd9Sstevel@tonic-gate 	case SADB_X_INVERSE_ACQUIRE:
21927c478bd9Sstevel@tonic-gate 	case SADB_DUMP:
21937c478bd9Sstevel@tonic-gate 	case SADB_GET:
21947c478bd9Sstevel@tonic-gate 	default:
21957c478bd9Sstevel@tonic-gate 		/*
21967c478bd9Sstevel@tonic-gate 		 * Deliver to the sender and promiscuous only.
21977c478bd9Sstevel@tonic-gate 		 */
2198f4b3ec61Sdh 		ks3dbg(keystack, ("Delivering sender/promisc only (%d).\n",
21997c478bd9Sstevel@tonic-gate 		    samsg->sadb_msg_type));
22007c478bd9Sstevel@tonic-gate 		break;
22017c478bd9Sstevel@tonic-gate 	}
22027c478bd9Sstevel@tonic-gate 
2203f4b3ec61Sdh 	mutex_enter(&keystack->keystack_list_lock);
2204f4b3ec61Sdh 	for (ks = keystack->keystack_list; ks != NULL; ks = ks->keysock_next) {
22057c478bd9Sstevel@tonic-gate 		/* Delivery loop. */
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 		/*
22087c478bd9Sstevel@tonic-gate 		 * Check special keysock-setting cases (REGISTER replies)
22097c478bd9Sstevel@tonic-gate 		 * here.
22107c478bd9Sstevel@tonic-gate 		 */
22117c478bd9Sstevel@tonic-gate 		if (setalg && serial == ks->keysock_serial) {
22127c478bd9Sstevel@tonic-gate 			ASSERT(kc != NULL);
22137c478bd9Sstevel@tonic-gate 			ASSERT(kc->kc_sa_type == satype);
22147c478bd9Sstevel@tonic-gate 			KEYSOCK_SETREG(ks, satype);
22157c478bd9Sstevel@tonic-gate 		}
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 		/*
22187c478bd9Sstevel@tonic-gate 		 * NOLOOP takes precedence over PROMISC.  So if you've set
22197c478bd9Sstevel@tonic-gate 		 * !SO_USELOOPBACK, don't expect to see any data...
22207c478bd9Sstevel@tonic-gate 		 */
22217c478bd9Sstevel@tonic-gate 		if (ks->keysock_flags & KEYSOCK_NOLOOP)
22227c478bd9Sstevel@tonic-gate 			continue;
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 		/*
22257c478bd9Sstevel@tonic-gate 		 * Messages to all, or promiscuous sockets just GET the
22267c478bd9Sstevel@tonic-gate 		 * message.  Perform rules-type checking iff it's not for all
22277c478bd9Sstevel@tonic-gate 		 * listeners or the socket is in promiscuous mode.
22287c478bd9Sstevel@tonic-gate 		 *
22297c478bd9Sstevel@tonic-gate 		 * NOTE:Because of the (kc != NULL && ISREG()), make sure
22307c478bd9Sstevel@tonic-gate 		 *	extended ACQUIREs arrive off a consumer that is
22317c478bd9Sstevel@tonic-gate 		 *	part of the extended REGISTER set of consumers.
22327c478bd9Sstevel@tonic-gate 		 */
22337c478bd9Sstevel@tonic-gate 		if (serial != ks->keysock_serial &&
22347c478bd9Sstevel@tonic-gate 		    !toall &&
22357c478bd9Sstevel@tonic-gate 		    !(ks->keysock_flags & KEYSOCK_PROMISC) &&
22367c478bd9Sstevel@tonic-gate 		    !((ks->keysock_flags & KEYSOCK_EXTENDED) ?
2237fc80c0dfSnordmark 		    allereg : allreg && kc != NULL &&
2238fc80c0dfSnordmark 		    KEYSOCK_ISREG(ks, kc->kc_sa_type)))
22397c478bd9Sstevel@tonic-gate 			continue;
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 		mp1 = dupmsg(mp);
22427c478bd9Sstevel@tonic-gate 		if (mp1 == NULL) {
2243f4b3ec61Sdh 			ks2dbg(keystack, (
22447c478bd9Sstevel@tonic-gate 			    "keysock_passup():  dupmsg() failed.\n"));
22457c478bd9Sstevel@tonic-gate 			mp1 = mp;
22467c478bd9Sstevel@tonic-gate 			mp = NULL;
22477c478bd9Sstevel@tonic-gate 			err = ENOMEM;
22487c478bd9Sstevel@tonic-gate 		}
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 		/*
22517c478bd9Sstevel@tonic-gate 		 * At this point, we can deliver or attempt to deliver
22527c478bd9Sstevel@tonic-gate 		 * this message.  We're free of obligation to report
22537c478bd9Sstevel@tonic-gate 		 * no listening PF_KEY sockets.  So set err to 0.
22547c478bd9Sstevel@tonic-gate 		 */
22557c478bd9Sstevel@tonic-gate 		err = 0;
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 		/*
22587c478bd9Sstevel@tonic-gate 		 * See if we canputnext(), as well as see if the message
22597c478bd9Sstevel@tonic-gate 		 * needs to be queued if we can't.
22607c478bd9Sstevel@tonic-gate 		 */
22617c478bd9Sstevel@tonic-gate 		if (!canputnext(ks->keysock_rq)) {
22627c478bd9Sstevel@tonic-gate 			if (persistent) {
22637c478bd9Sstevel@tonic-gate 				if (putq(ks->keysock_rq, mp1) == 0) {
2264f4b3ec61Sdh 					ks1dbg(keystack, (
22657c478bd9Sstevel@tonic-gate 					    "keysock_passup: putq failed.\n"));
22667c478bd9Sstevel@tonic-gate 				} else {
22677c478bd9Sstevel@tonic-gate 					continue;
22687c478bd9Sstevel@tonic-gate 				}
22697c478bd9Sstevel@tonic-gate 			}
22707c478bd9Sstevel@tonic-gate 			freemsg(mp1);
22717c478bd9Sstevel@tonic-gate 			continue;
22727c478bd9Sstevel@tonic-gate 		}
22737c478bd9Sstevel@tonic-gate 
2274f4b3ec61Sdh 		ks3dbg(keystack,
2275f4b3ec61Sdh 		    ("Putting to serial %d.\n", ks->keysock_serial));
22767c478bd9Sstevel@tonic-gate 		/*
22777c478bd9Sstevel@tonic-gate 		 * Unlike the specific keysock instance case, this
22787c478bd9Sstevel@tonic-gate 		 * will only hit for listeners, so we will only
22797c478bd9Sstevel@tonic-gate 		 * putnext() if we can.
22807c478bd9Sstevel@tonic-gate 		 */
22817c478bd9Sstevel@tonic-gate 		putnext(ks->keysock_rq, mp1);
22827c478bd9Sstevel@tonic-gate 		if (mp == NULL)
22837c478bd9Sstevel@tonic-gate 			break;	/* out of for loop. */
22847c478bd9Sstevel@tonic-gate 	}
2285f4b3ec61Sdh 	mutex_exit(&keystack->keystack_list_lock);
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate error:
22887c478bd9Sstevel@tonic-gate 	if ((err != 0) && (kc != NULL)) {
22897c478bd9Sstevel@tonic-gate 		/*
22907c478bd9Sstevel@tonic-gate 		 * Generate KEYSOCK_OUT_ERR for consumer.
22917c478bd9Sstevel@tonic-gate 		 * Basically, I send this back if I have not been able to
22927c478bd9Sstevel@tonic-gate 		 * transmit (for whatever reason)
22937c478bd9Sstevel@tonic-gate 		 */
2294f4b3ec61Sdh 		ks1dbg(keystack,
2295f4b3ec61Sdh 		    ("keysock_passup():  No registered of type %d.\n",
22967c478bd9Sstevel@tonic-gate 		    satype));
22977c478bd9Sstevel@tonic-gate 		if (mp != NULL) {
22987c478bd9Sstevel@tonic-gate 			if (mp->b_datap->db_type == M_PROTO) {
22997c478bd9Sstevel@tonic-gate 				mp1 = mp;
23007c478bd9Sstevel@tonic-gate 				mp = mp->b_cont;
23017c478bd9Sstevel@tonic-gate 				freeb(mp1);
23027c478bd9Sstevel@tonic-gate 			}
23037c478bd9Sstevel@tonic-gate 			/*
23047c478bd9Sstevel@tonic-gate 			 * Do a copymsg() because people who get
23057c478bd9Sstevel@tonic-gate 			 * KEYSOCK_OUT_ERR may alter the message contents.
23067c478bd9Sstevel@tonic-gate 			 */
23077c478bd9Sstevel@tonic-gate 			mp1 = copymsg(mp);
23087c478bd9Sstevel@tonic-gate 			if (mp1 == NULL) {
2309f4b3ec61Sdh 				ks2dbg(keystack,
2310f4b3ec61Sdh 				    ("keysock_passup: copymsg() failed.\n"));
23117c478bd9Sstevel@tonic-gate 				mp1 = mp;
23127c478bd9Sstevel@tonic-gate 				mp = NULL;
23137c478bd9Sstevel@tonic-gate 			}
23147c478bd9Sstevel@tonic-gate 			keysock_out_err(kc, err, mp1);
23157c478bd9Sstevel@tonic-gate 		}
23167c478bd9Sstevel@tonic-gate 	}
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 	/*
23197c478bd9Sstevel@tonic-gate 	 * XXX Blank the message somehow.  This is difficult because we don't
23207c478bd9Sstevel@tonic-gate 	 * know at this point if the message has db_ref > 1, etc.
23217c478bd9Sstevel@tonic-gate 	 *
23227c478bd9Sstevel@tonic-gate 	 * Optimally, keysock messages containing actual keying material would
23237c478bd9Sstevel@tonic-gate 	 * be allocated with esballoc(), with a zeroing free function.
23247c478bd9Sstevel@tonic-gate 	 */
23257c478bd9Sstevel@tonic-gate 	if (mp != NULL)
23267c478bd9Sstevel@tonic-gate 		freemsg(mp);
23277c478bd9Sstevel@tonic-gate }
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate /*
23307c478bd9Sstevel@tonic-gate  * Keysock's read service procedure is there only for PF_KEY reply
23317c478bd9Sstevel@tonic-gate  * messages that really need to reach the top.
23327c478bd9Sstevel@tonic-gate  */
2333*4f2d1f9dSToomas Soome static int
keysock_rsrv(queue_t * q)23347c478bd9Sstevel@tonic-gate keysock_rsrv(queue_t *q)
23357c478bd9Sstevel@tonic-gate {
23367c478bd9Sstevel@tonic-gate 	mblk_t *mp;
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
23397c478bd9Sstevel@tonic-gate 		if (canputnext(q)) {
23407c478bd9Sstevel@tonic-gate 			putnext(q, mp);
23417c478bd9Sstevel@tonic-gate 		} else {
23427c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
2343*4f2d1f9dSToomas Soome 			return (0);
23447c478bd9Sstevel@tonic-gate 		}
23457c478bd9Sstevel@tonic-gate 	}
2346*4f2d1f9dSToomas Soome 	return (0);
23477c478bd9Sstevel@tonic-gate }
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate /*
23507c478bd9Sstevel@tonic-gate  * The read procedure should only be invoked by a keysock consumer, like
23517c478bd9Sstevel@tonic-gate  * ESP, AH, etc.  I should only see KEYSOCK_OUT and KEYSOCK_HELLO_ACK
23527c478bd9Sstevel@tonic-gate  * messages on my read queues.
23537c478bd9Sstevel@tonic-gate  */
2354*4f2d1f9dSToomas Soome static int
keysock_rput(queue_t * q,mblk_t * mp)23557c478bd9Sstevel@tonic-gate keysock_rput(queue_t *q, mblk_t *mp)
23567c478bd9Sstevel@tonic-gate {
23577c478bd9Sstevel@tonic-gate 	keysock_consumer_t *kc = (keysock_consumer_t *)q->q_ptr;
23587c478bd9Sstevel@tonic-gate 	ipsec_info_t *ii;
23597c478bd9Sstevel@tonic-gate 	keysock_hello_ack_t *ksa;
23607c478bd9Sstevel@tonic-gate 	minor_t serial;
23617c478bd9Sstevel@tonic-gate 	mblk_t *mp1;
23627c478bd9Sstevel@tonic-gate 	sadb_msg_t *samsg;
2363f4b3ec61Sdh 	keysock_stack_t	*keystack = kc->kc_keystack;
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 	/* Make sure I'm a consumer instance.  (i.e. something's below me) */
23667c478bd9Sstevel@tonic-gate 	ASSERT(WR(q)->q_next != NULL);
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type != M_CTL) {
23697c478bd9Sstevel@tonic-gate 		/*
23707c478bd9Sstevel@tonic-gate 		 * Keysock should only see keysock consumer interface
23717c478bd9Sstevel@tonic-gate 		 * messages (see ipsec_info.h) on its read procedure.
23727c478bd9Sstevel@tonic-gate 		 * To be robust, however, putnext() up so the STREAM head can
23737c478bd9Sstevel@tonic-gate 		 * deal with it appropriately.
23747c478bd9Sstevel@tonic-gate 		 */
2375f4b3ec61Sdh 		ks1dbg(keystack,
2376f4b3ec61Sdh 		    ("Hmmm, a non M_CTL (%d, 0x%x) on keysock_rput.\n",
23777c478bd9Sstevel@tonic-gate 		    mp->b_datap->db_type, mp->b_datap->db_type));
23787c478bd9Sstevel@tonic-gate 		putnext(q, mp);
2379*4f2d1f9dSToomas Soome 		return (0);
23807c478bd9Sstevel@tonic-gate 	}
23817c478bd9Sstevel@tonic-gate 
23827c478bd9Sstevel@tonic-gate 	ii = (ipsec_info_t *)mp->b_rptr;
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate 	switch (ii->ipsec_info_type) {
23857c478bd9Sstevel@tonic-gate 	case KEYSOCK_OUT:
23867c478bd9Sstevel@tonic-gate 		/*
23877c478bd9Sstevel@tonic-gate 		 * A consumer needs to pass a response message or an ACQUIRE
23887c478bd9Sstevel@tonic-gate 		 * UP.  I assume that the consumer has done the right
23897c478bd9Sstevel@tonic-gate 		 * thing w.r.t. message creation, etc.
23907c478bd9Sstevel@tonic-gate 		 */
23917c478bd9Sstevel@tonic-gate 		serial = ((keysock_out_t *)mp->b_rptr)->ks_out_serial;
23927c478bd9Sstevel@tonic-gate 		mp1 = mp->b_cont;	/* Get M_DATA portion. */
23937c478bd9Sstevel@tonic-gate 		freeb(mp);
23947c478bd9Sstevel@tonic-gate 		samsg = (sadb_msg_t *)mp1->b_rptr;
23957c478bd9Sstevel@tonic-gate 		if (samsg->sadb_msg_type == SADB_FLUSH ||
23967c478bd9Sstevel@tonic-gate 		    (samsg->sadb_msg_type == SADB_DUMP &&
2397fc80c0dfSnordmark 		    samsg->sadb_msg_len == SADB_8TO64(sizeof (*samsg)))) {
23987c478bd9Sstevel@tonic-gate 			/*
23997c478bd9Sstevel@tonic-gate 			 * If I'm an end-of-FLUSH or an end-of-DUMP marker...
24007c478bd9Sstevel@tonic-gate 			 */
2401f4b3ec61Sdh 			ASSERT(keystack->keystack_flushdump != 0);
2402f4b3ec61Sdh 						/* Am I flushing? */
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 			mutex_enter(&kc->kc_lock);
24057c478bd9Sstevel@tonic-gate 			kc->kc_flags &= ~KC_FLUSHING;
24067c478bd9Sstevel@tonic-gate 			mutex_exit(&kc->kc_lock);
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 			if (samsg->sadb_msg_errno != 0)
2409f4b3ec61Sdh 				keystack->keystack_flushdump_errno =
2410f4b3ec61Sdh 				    samsg->sadb_msg_errno;
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 			/*
24137c478bd9Sstevel@tonic-gate 			 * Lower the atomic "flushing" count.  If it's
24147c478bd9Sstevel@tonic-gate 			 * the last one, send up the end-of-{FLUSH,DUMP} to
24157c478bd9Sstevel@tonic-gate 			 * the appropriate PF_KEY socket.
24167c478bd9Sstevel@tonic-gate 			 */
24171a5e258fSJosef 'Jeff' Sipek 			if (atomic_dec_32_nv(&keystack->keystack_flushdump) !=
24181a5e258fSJosef 'Jeff' Sipek 			    0) {
2419f4b3ec61Sdh 				ks1dbg(keystack,
2420f4b3ec61Sdh 				    ("One flush/dump message back from %d,"
24217c478bd9Sstevel@tonic-gate 				    " more to go.\n", samsg->sadb_msg_satype));
24227c478bd9Sstevel@tonic-gate 				freemsg(mp1);
2423*4f2d1f9dSToomas Soome 				return (0);
24247c478bd9Sstevel@tonic-gate 			}
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 			samsg->sadb_msg_errno =
2427f4b3ec61Sdh 			    (uint8_t)keystack->keystack_flushdump_errno;
24287c478bd9Sstevel@tonic-gate 			if (samsg->sadb_msg_type == SADB_DUMP) {
24297c478bd9Sstevel@tonic-gate 				samsg->sadb_msg_seq = 0;
24307c478bd9Sstevel@tonic-gate 			}
24317c478bd9Sstevel@tonic-gate 		}
24327c478bd9Sstevel@tonic-gate 		keysock_passup(mp1, samsg, serial, kc,
2433f4b3ec61Sdh 		    (samsg->sadb_msg_type == SADB_DUMP), keystack);
2434*4f2d1f9dSToomas Soome 		return (0);
24357c478bd9Sstevel@tonic-gate 	case KEYSOCK_HELLO_ACK:
24367c478bd9Sstevel@tonic-gate 		/* Aha, now we can link in the consumer! */
24377c478bd9Sstevel@tonic-gate 		ksa = (keysock_hello_ack_t *)ii;
24387c478bd9Sstevel@tonic-gate 		keysock_link_consumer(ksa->ks_hello_satype, kc);
24397c478bd9Sstevel@tonic-gate 		freemsg(mp);
2440*4f2d1f9dSToomas Soome 		return (0);
24417c478bd9Sstevel@tonic-gate 	default:
2442f4b3ec61Sdh 		ks1dbg(keystack, ("Hmmm, an IPsec info I'm not used to, 0x%x\n",
24437c478bd9Sstevel@tonic-gate 		    ii->ipsec_info_type));
24447c478bd9Sstevel@tonic-gate 		putnext(q, mp);
24457c478bd9Sstevel@tonic-gate 	}
2446*4f2d1f9dSToomas Soome 	return (0);
24477c478bd9Sstevel@tonic-gate }
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate /*
24507c478bd9Sstevel@tonic-gate  * So we can avoid external linking problems....
24517c478bd9Sstevel@tonic-gate  */
24527c478bd9Sstevel@tonic-gate boolean_t
keysock_extended_reg(netstack_t * ns)2453f4b3ec61Sdh keysock_extended_reg(netstack_t *ns)
24547c478bd9Sstevel@tonic-gate {
2455f4b3ec61Sdh 	keysock_stack_t	*keystack = ns->netstack_keysock;
2456f4b3ec61Sdh 
2457f4b3ec61Sdh 	return (keystack->keystack_num_extended != 0);
24587c478bd9Sstevel@tonic-gate }
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate uint32_t
keysock_next_seq(netstack_t * ns)2461f4b3ec61Sdh keysock_next_seq(netstack_t *ns)
24627c478bd9Sstevel@tonic-gate {
2463f4b3ec61Sdh 	keysock_stack_t	*keystack = ns->netstack_keysock;
2464f4b3ec61Sdh 
24651a5e258fSJosef 'Jeff' Sipek 	return (atomic_dec_32_nv(&keystack->keystack_acquire_seq));
24667c478bd9Sstevel@tonic-gate }
2467