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