xref: /onnv-gate/usr/src/uts/common/inet/ip/spdsock.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 2005 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 #include <sys/param.h>
30*0Sstevel@tonic-gate #include <sys/types.h>
31*0Sstevel@tonic-gate #include <sys/stream.h>
32*0Sstevel@tonic-gate #include <sys/strsubr.h>
33*0Sstevel@tonic-gate #include <sys/strsun.h>
34*0Sstevel@tonic-gate #include <sys/stropts.h>
35*0Sstevel@tonic-gate #include <sys/vnode.h>
36*0Sstevel@tonic-gate #include <sys/sysmacros.h>
37*0Sstevel@tonic-gate #define	_SUN_TPI_VERSION 2
38*0Sstevel@tonic-gate #include <sys/tihdr.h>
39*0Sstevel@tonic-gate #include <sys/ddi.h>
40*0Sstevel@tonic-gate #include <sys/sunddi.h>
41*0Sstevel@tonic-gate #include <sys/mkdev.h>
42*0Sstevel@tonic-gate #include <sys/debug.h>
43*0Sstevel@tonic-gate #include <sys/kmem.h>
44*0Sstevel@tonic-gate #include <sys/cmn_err.h>
45*0Sstevel@tonic-gate #include <sys/proc.h>
46*0Sstevel@tonic-gate #include <sys/suntpi.h>
47*0Sstevel@tonic-gate #include <sys/policy.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #include <sys/socket.h>
50*0Sstevel@tonic-gate #include <netinet/in.h>
51*0Sstevel@tonic-gate #include <net/pfkeyv2.h>
52*0Sstevel@tonic-gate #include <net/pfpolicy.h>
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate #include <inet/common.h>
55*0Sstevel@tonic-gate #include <netinet/ip6.h>
56*0Sstevel@tonic-gate #include <inet/ip.h>
57*0Sstevel@tonic-gate #include <inet/ip6.h>
58*0Sstevel@tonic-gate #include <inet/mi.h>
59*0Sstevel@tonic-gate #include <inet/nd.h>
60*0Sstevel@tonic-gate #include <inet/optcom.h>
61*0Sstevel@tonic-gate #include <inet/ipsec_info.h>
62*0Sstevel@tonic-gate #include <inet/ipsec_impl.h>
63*0Sstevel@tonic-gate #include <inet/spdsock.h>
64*0Sstevel@tonic-gate #include <inet/sadb.h>
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate #include <sys/isa_defs.h>
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /*
69*0Sstevel@tonic-gate  * This is a transport provider for the PF_POLICY IPsec policy
70*0Sstevel@tonic-gate  * management socket, which provides a management interface into the
71*0Sstevel@tonic-gate  * SPD, allowing policy rules to be added, deleted, and queried.
72*0Sstevel@tonic-gate  *
73*0Sstevel@tonic-gate  * This effectively replaces the old private SIOC*IPSECONFIG ioctls
74*0Sstevel@tonic-gate  * with an extensible interface which will hopefully be public some
75*0Sstevel@tonic-gate  * day.
76*0Sstevel@tonic-gate  *
77*0Sstevel@tonic-gate  * See <net/pfpolicy.h> for more details on the protocol.
78*0Sstevel@tonic-gate  *
79*0Sstevel@tonic-gate  * We link against drv/ip and call directly into it to manipulate the
80*0Sstevel@tonic-gate  * SPD; see ipsec_impl.h for the policy data structures and spd.c for
81*0Sstevel@tonic-gate  * the code which maintains them.
82*0Sstevel@tonic-gate  *
83*0Sstevel@tonic-gate  * The MT model of this is QPAIR with the addition of some explicit
84*0Sstevel@tonic-gate  * locking to protect system-wide policy data structures.
85*0Sstevel@tonic-gate  */
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate static vmem_t *spdsock_vmem;		/* for minor numbers. */
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate #define	ALIGNED64(x) IS_P2ALIGNED((x), sizeof (uint64_t))
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages (from rts.c...) */
92*0Sstevel@tonic-gate static struct T_info_ack spdsock_g_t_info_ack = {
93*0Sstevel@tonic-gate 	T_INFO_ACK,
94*0Sstevel@tonic-gate 	T_INFINITE,	/* TSDU_size. Maximum size messages. */
95*0Sstevel@tonic-gate 	T_INVALID,	/* ETSDU_size. No expedited data. */
96*0Sstevel@tonic-gate 	T_INVALID,	/* CDATA_size. No connect data. */
97*0Sstevel@tonic-gate 	T_INVALID,	/* DDATA_size. No disconnect data. */
98*0Sstevel@tonic-gate 	0,		/* ADDR_size. */
99*0Sstevel@tonic-gate 	0,		/* OPT_size. No user-settable options */
100*0Sstevel@tonic-gate 	64 * 1024,	/* TIDU_size. spdsock allows maximum size messages. */
101*0Sstevel@tonic-gate 	T_COTS,		/* SERV_type. spdsock supports connection oriented. */
102*0Sstevel@tonic-gate 	TS_UNBND,	/* CURRENT_state. This is set from spdsock_state. */
103*0Sstevel@tonic-gate 	(XPG4_1)	/* Provider flags */
104*0Sstevel@tonic-gate };
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate /* Named Dispatch Parameter Management Structure */
107*0Sstevel@tonic-gate typedef struct spdsockpparam_s {
108*0Sstevel@tonic-gate 	uint_t	spdsock_param_min;
109*0Sstevel@tonic-gate 	uint_t	spdsock_param_max;
110*0Sstevel@tonic-gate 	uint_t	spdsock_param_value;
111*0Sstevel@tonic-gate 	char *spdsock_param_name;
112*0Sstevel@tonic-gate } spdsockparam_t;
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate /*
115*0Sstevel@tonic-gate  * Table of NDD variables supported by spdsock. These are loaded into
116*0Sstevel@tonic-gate  * spdsock_g_nd in spdsock_init_nd.
117*0Sstevel@tonic-gate  * All of these are alterable, within the min/max values given, at run time.
118*0Sstevel@tonic-gate  */
119*0Sstevel@tonic-gate static	spdsockparam_t	spdsock_param_arr[] = {
120*0Sstevel@tonic-gate 	/* min	max	value	name */
121*0Sstevel@tonic-gate 	{ 4096, 65536,	8192,	"spdsock_xmit_hiwat"},
122*0Sstevel@tonic-gate 	{ 0,	65536,	1024,	"spdsock_xmit_lowat"},
123*0Sstevel@tonic-gate 	{ 4096, 65536,	8192,	"spdsock_recv_hiwat"},
124*0Sstevel@tonic-gate 	{ 65536, 1024*1024*1024, 256*1024,	"spdsock_max_buf"},
125*0Sstevel@tonic-gate 	{ 0,	3,	0,	"spdsock_debug"},
126*0Sstevel@tonic-gate };
127*0Sstevel@tonic-gate #define	spdsock_xmit_hiwat	spdsock_param_arr[0].spdsock_param_value
128*0Sstevel@tonic-gate #define	spdsock_xmit_lowat	spdsock_param_arr[1].spdsock_param_value
129*0Sstevel@tonic-gate #define	spdsock_recv_hiwat	spdsock_param_arr[2].spdsock_param_value
130*0Sstevel@tonic-gate #define	spdsock_max_buf		spdsock_param_arr[3].spdsock_param_value
131*0Sstevel@tonic-gate #define	spdsock_debug		spdsock_param_arr[4].spdsock_param_value
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate kmutex_t spdsock_param_lock;	/* Protects the NDD variables. */
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate /*
136*0Sstevel@tonic-gate  * To save algorithm update messages that are processed only after IPsec
137*0Sstevel@tonic-gate  * is loaded.
138*0Sstevel@tonic-gate  */
139*0Sstevel@tonic-gate static spd_ext_t *spdsock_extv_algs[SPD_EXT_MAX + 1];
140*0Sstevel@tonic-gate static mblk_t *spdsock_mp_algs = NULL;
141*0Sstevel@tonic-gate static boolean_t spdsock_algs_pending = B_FALSE;
142*0Sstevel@tonic-gate static ipsec_alginfo_t *spdsock_algs[IPSEC_NALGTYPES][IPSEC_MAX_ALGS];
143*0Sstevel@tonic-gate static ipsec_algs_exec_mode_t spdsock_algs_exec_mode[IPSEC_NALGTYPES];
144*0Sstevel@tonic-gate static kmutex_t spdsock_alg_lock;
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate #define	ss0dbg(a)	printf a
147*0Sstevel@tonic-gate /* NOTE:  != 0 instead of > 0 so lint doesn't complain. */
148*0Sstevel@tonic-gate #define	ss1dbg(a)	if (spdsock_debug != 0) printf a
149*0Sstevel@tonic-gate #define	ss2dbg(a)	if (spdsock_debug > 1) printf a
150*0Sstevel@tonic-gate #define	ss3dbg(a)	if (spdsock_debug > 2) printf a
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate static IDP spdsock_g_nd;
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate static int spdsock_close(queue_t *);
155*0Sstevel@tonic-gate static int spdsock_open(queue_t *, dev_t *, int, int, cred_t *);
156*0Sstevel@tonic-gate static void spdsock_wput(queue_t *, mblk_t *);
157*0Sstevel@tonic-gate static void spdsock_wsrv(queue_t *);
158*0Sstevel@tonic-gate static void spdsock_rsrv(queue_t *);
159*0Sstevel@tonic-gate static void spdsock_loadcheck(void *);
160*0Sstevel@tonic-gate static void spdsock_merge_algs(void);
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate static struct module_info info = {
163*0Sstevel@tonic-gate 	5138, "spdsock", 1, INFPSZ, 512, 128
164*0Sstevel@tonic-gate };
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate static struct qinit rinit = {
167*0Sstevel@tonic-gate 	NULL, (pfi_t)spdsock_rsrv, spdsock_open, spdsock_close,
168*0Sstevel@tonic-gate 	NULL, &info
169*0Sstevel@tonic-gate };
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate static struct qinit winit = {
172*0Sstevel@tonic-gate 	(pfi_t)spdsock_wput, (pfi_t)spdsock_wsrv, NULL, NULL, NULL, &info
173*0Sstevel@tonic-gate };
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate struct streamtab spdsockinfo = {
176*0Sstevel@tonic-gate 	&rinit, &winit
177*0Sstevel@tonic-gate };
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate /* mapping from alg type to protocol number, as per RFC 2407 */
180*0Sstevel@tonic-gate static const uint_t algproto[] = {
181*0Sstevel@tonic-gate 	PROTO_IPSEC_AH,
182*0Sstevel@tonic-gate 	PROTO_IPSEC_ESP,
183*0Sstevel@tonic-gate };
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate #define	NALGPROTOS	(sizeof (algproto) / sizeof (algproto[0]))
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate /* mapping from kernel exec mode to spdsock exec mode */
188*0Sstevel@tonic-gate static const uint_t execmodes[] = {
189*0Sstevel@tonic-gate 	SPD_ALG_EXEC_MODE_SYNC,
190*0Sstevel@tonic-gate 	SPD_ALG_EXEC_MODE_ASYNC
191*0Sstevel@tonic-gate };
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate #define	NEXECMODES	(sizeof (execmodes) / sizeof (execmodes[0]))
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate /* ARGSUSED */
196*0Sstevel@tonic-gate static int
197*0Sstevel@tonic-gate spdsock_param_get(q, mp, cp, cr)
198*0Sstevel@tonic-gate 	queue_t	*q;
199*0Sstevel@tonic-gate 	mblk_t	*mp;
200*0Sstevel@tonic-gate 	caddr_t	cp;
201*0Sstevel@tonic-gate 	cred_t *cr;
202*0Sstevel@tonic-gate {
203*0Sstevel@tonic-gate 	spdsockparam_t	*spdsockpa = (spdsockparam_t *)cp;
204*0Sstevel@tonic-gate 	uint_t value;
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	mutex_enter(&spdsock_param_lock);
207*0Sstevel@tonic-gate 	value = spdsockpa->spdsock_param_value;
208*0Sstevel@tonic-gate 	mutex_exit(&spdsock_param_lock);
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	(void) mi_mpprintf(mp, "%u", value);
211*0Sstevel@tonic-gate 	return (0);
212*0Sstevel@tonic-gate }
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate /* This routine sets an NDD variable in a spdsockparam_t structure. */
215*0Sstevel@tonic-gate /* ARGSUSED */
216*0Sstevel@tonic-gate static int
217*0Sstevel@tonic-gate spdsock_param_set(q, mp, value, cp, cr)
218*0Sstevel@tonic-gate 	queue_t	*q;
219*0Sstevel@tonic-gate 	mblk_t	*mp;
220*0Sstevel@tonic-gate 	char *value;
221*0Sstevel@tonic-gate 	caddr_t	cp;
222*0Sstevel@tonic-gate 	cred_t *cr;
223*0Sstevel@tonic-gate {
224*0Sstevel@tonic-gate 	ulong_t	new_value;
225*0Sstevel@tonic-gate 	spdsockparam_t	*spdsockpa = (spdsockparam_t *)cp;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	/* Convert the value from a string into a long integer. */
228*0Sstevel@tonic-gate 	if (ddi_strtoul(value, NULL, 10, &new_value) != 0)
229*0Sstevel@tonic-gate 		return (EINVAL);
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	mutex_enter(&spdsock_param_lock);
232*0Sstevel@tonic-gate 	/*
233*0Sstevel@tonic-gate 	 * Fail the request if the new value does not lie within the
234*0Sstevel@tonic-gate 	 * required bounds.
235*0Sstevel@tonic-gate 	 */
236*0Sstevel@tonic-gate 	if (new_value < spdsockpa->spdsock_param_min ||
237*0Sstevel@tonic-gate 	    new_value > spdsockpa->spdsock_param_max) {
238*0Sstevel@tonic-gate 		mutex_exit(&spdsock_param_lock);
239*0Sstevel@tonic-gate 		return (EINVAL);
240*0Sstevel@tonic-gate 	}
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	/* Set the new value */
243*0Sstevel@tonic-gate 	spdsockpa->spdsock_param_value = new_value;
244*0Sstevel@tonic-gate 	mutex_exit(&spdsock_param_lock);
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	return (0);
247*0Sstevel@tonic-gate }
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate boolean_t
250*0Sstevel@tonic-gate spdsock_ddi_init(void)
251*0Sstevel@tonic-gate {
252*0Sstevel@tonic-gate 	spdsockparam_t *ssp = spdsock_param_arr;
253*0Sstevel@tonic-gate 	int count = A_CNT(spdsock_param_arr);
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	if (!spdsock_g_nd) {
256*0Sstevel@tonic-gate 		for (; count-- > 0; ssp++) {
257*0Sstevel@tonic-gate 			if (ssp->spdsock_param_name != NULL &&
258*0Sstevel@tonic-gate 			    (ssp->spdsock_param_name[0] != '\0')) {
259*0Sstevel@tonic-gate 				if (!nd_load(&spdsock_g_nd,
260*0Sstevel@tonic-gate 				    ssp->spdsock_param_name,
261*0Sstevel@tonic-gate 				    spdsock_param_get, spdsock_param_set,
262*0Sstevel@tonic-gate 				    (caddr_t)ssp)) {
263*0Sstevel@tonic-gate 					nd_free(&spdsock_g_nd);
264*0Sstevel@tonic-gate 					return (B_FALSE);
265*0Sstevel@tonic-gate 				}
266*0Sstevel@tonic-gate 			}
267*0Sstevel@tonic-gate 		}
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	spdsock_max_optsize = optcom_max_optsize(
271*0Sstevel@tonic-gate 	    spdsock_opt_obj.odb_opt_des_arr, spdsock_opt_obj.odb_opt_arr_cnt);
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	spdsock_vmem = vmem_create("spdsock", (void *)1, MAXMIN, 1,
274*0Sstevel@tonic-gate 	    NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER);
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	mutex_init(&spdsock_param_lock, NULL, MUTEX_DEFAULT, NULL);
277*0Sstevel@tonic-gate 	mutex_init(&spdsock_alg_lock, NULL, MUTEX_DEFAULT, NULL);
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	return (B_TRUE);
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate void
283*0Sstevel@tonic-gate spdsock_ddi_destroy(void)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	vmem_destroy(spdsock_vmem);
286*0Sstevel@tonic-gate 	mutex_destroy(&spdsock_param_lock);
287*0Sstevel@tonic-gate 	mutex_destroy(&spdsock_alg_lock);
288*0Sstevel@tonic-gate 	nd_free(&spdsock_g_nd);
289*0Sstevel@tonic-gate }
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate /*
292*0Sstevel@tonic-gate  * NOTE: large quantities of this should be shared with keysock.
293*0Sstevel@tonic-gate  * Would be nice to combine some of this into a common module, but
294*0Sstevel@tonic-gate  * not possible given time pressures.
295*0Sstevel@tonic-gate  */
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate /*
298*0Sstevel@tonic-gate  * High-level reality checking of extensions.
299*0Sstevel@tonic-gate  */
300*0Sstevel@tonic-gate /* ARGSUSED */ /* XXX */
301*0Sstevel@tonic-gate static boolean_t
302*0Sstevel@tonic-gate ext_check(spd_ext_t *ext)
303*0Sstevel@tonic-gate {
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	return (B_TRUE);	/* For now... */
306*0Sstevel@tonic-gate }
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate /* Return values for spdsock_get_ext(). */
311*0Sstevel@tonic-gate #define	KGE_OK	0
312*0Sstevel@tonic-gate #define	KGE_DUP	1
313*0Sstevel@tonic-gate #define	KGE_UNK	2
314*0Sstevel@tonic-gate #define	KGE_LEN	3
315*0Sstevel@tonic-gate #define	KGE_CHK	4
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate /*
318*0Sstevel@tonic-gate  * Parse basic extension headers and return in the passed-in pointer vector.
319*0Sstevel@tonic-gate  * Return values include:
320*0Sstevel@tonic-gate  *
321*0Sstevel@tonic-gate  *	KGE_OK	Everything's nice and parsed out.
322*0Sstevel@tonic-gate  *		If there are no extensions, place NULL in extv[0].
323*0Sstevel@tonic-gate  *	KGE_DUP	There is a duplicate extension.
324*0Sstevel@tonic-gate  *		First instance in appropriate bin.  First duplicate in
325*0Sstevel@tonic-gate  *		extv[0].
326*0Sstevel@tonic-gate  *	KGE_UNK	Unknown extension type encountered.  extv[0] contains
327*0Sstevel@tonic-gate  *		unknown header.
328*0Sstevel@tonic-gate  *	KGE_LEN	Extension length error.
329*0Sstevel@tonic-gate  *	KGE_CHK	High-level reality check failed on specific extension.
330*0Sstevel@tonic-gate  *
331*0Sstevel@tonic-gate  * My apologies for some of the pointer arithmetic in here.  I'm thinking
332*0Sstevel@tonic-gate  * like an assembly programmer, yet trying to make the compiler happy.
333*0Sstevel@tonic-gate  */
334*0Sstevel@tonic-gate static int
335*0Sstevel@tonic-gate spdsock_get_ext(spd_ext_t *extv[], spd_msg_t *basehdr, uint_t msgsize)
336*0Sstevel@tonic-gate {
337*0Sstevel@tonic-gate 	bzero(extv, sizeof (spd_ext_t *) * (SPD_EXT_MAX + 1));
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	/* Use extv[0] as the "current working pointer". */
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	extv[0] = (spd_ext_t *)(basehdr + 1);
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	while (extv[0] < (spd_ext_t *)(((uint8_t *)basehdr) + msgsize)) {
344*0Sstevel@tonic-gate 		/* Check for unknown headers. */
345*0Sstevel@tonic-gate 		if (extv[0]->spd_ext_type == 0 ||
346*0Sstevel@tonic-gate 		    extv[0]->spd_ext_type > SPD_EXT_MAX)
347*0Sstevel@tonic-gate 			return (KGE_UNK);
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 		/*
350*0Sstevel@tonic-gate 		 * Check length.  Use uint64_t because extlen is in units
351*0Sstevel@tonic-gate 		 * of 64-bit words.  If length goes beyond the msgsize,
352*0Sstevel@tonic-gate 		 * return an error.  (Zero length also qualifies here.)
353*0Sstevel@tonic-gate 		 */
354*0Sstevel@tonic-gate 		if (extv[0]->spd_ext_len == 0 ||
355*0Sstevel@tonic-gate 		    (void *)((uint64_t *)extv[0] + extv[0]->spd_ext_len) >
356*0Sstevel@tonic-gate 		    (void *)((uint8_t *)basehdr + msgsize))
357*0Sstevel@tonic-gate 			return (KGE_LEN);
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 		/* Check for redundant headers. */
360*0Sstevel@tonic-gate 		if (extv[extv[0]->spd_ext_type] != NULL)
361*0Sstevel@tonic-gate 			return (KGE_DUP);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 		/*
364*0Sstevel@tonic-gate 		 * Reality check the extension if possible at the spdsock
365*0Sstevel@tonic-gate 		 * level.
366*0Sstevel@tonic-gate 		 */
367*0Sstevel@tonic-gate 		if (!ext_check(extv[0]))
368*0Sstevel@tonic-gate 			return (KGE_CHK);
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 		/* If I make it here, assign the appropriate bin. */
371*0Sstevel@tonic-gate 		extv[extv[0]->spd_ext_type] = extv[0];
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 		/* Advance pointer (See above for uint64_t ptr reasoning.) */
374*0Sstevel@tonic-gate 		extv[0] = (spd_ext_t *)
375*0Sstevel@tonic-gate 		    ((uint64_t *)extv[0] + extv[0]->spd_ext_len);
376*0Sstevel@tonic-gate 	}
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	/* Everything's cool. */
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 	/*
381*0Sstevel@tonic-gate 	 * If extv[0] == NULL, then there are no extension headers in this
382*0Sstevel@tonic-gate 	 * message.  Ensure that this is the case.
383*0Sstevel@tonic-gate 	 */
384*0Sstevel@tonic-gate 	if (extv[0] == (spd_ext_t *)(basehdr + 1))
385*0Sstevel@tonic-gate 		extv[0] = NULL;
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	return (KGE_OK);
388*0Sstevel@tonic-gate }
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate static const int bad_ext_diag[] = {
391*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_MALFORMED_LCLPORT,
392*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_MALFORMED_REMPORT,
393*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_MALFORMED_PROTO,
394*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_MALFORMED_LCLADDR,
395*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_MALFORMED_REMADDR,
396*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_MALFORMED_ACTION,
397*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_MALFORMED_RULE,
398*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_MALFORMED_RULESET,
399*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_MALFORMED_ICMP_TYPECODE
400*0Sstevel@tonic-gate };
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate static const int dup_ext_diag[] = {
403*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_DUPLICATE_LCLPORT,
404*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_DUPLICATE_REMPORT,
405*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_DUPLICATE_PROTO,
406*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_DUPLICATE_LCLADDR,
407*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_DUPLICATE_REMADDR,
408*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_DUPLICATE_ACTION,
409*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_DUPLICATE_RULE,
410*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_DUPLICATE_RULESET,
411*0Sstevel@tonic-gate 	SPD_DIAGNOSTIC_DUPLICATE_ICMP_TYPECODE
412*0Sstevel@tonic-gate };
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate /*
415*0Sstevel@tonic-gate  * Transmit a PF_POLICY error message to the instance either pointed to
416*0Sstevel@tonic-gate  * by ks, the instance with serial number serial, or more, depending.
417*0Sstevel@tonic-gate  *
418*0Sstevel@tonic-gate  * The faulty message (or a reasonable facsimile thereof) is in mp.
419*0Sstevel@tonic-gate  * This function will free mp or recycle it for delivery, thereby causing
420*0Sstevel@tonic-gate  * the stream head to free it.
421*0Sstevel@tonic-gate  */
422*0Sstevel@tonic-gate static void
423*0Sstevel@tonic-gate spdsock_error(queue_t *q, mblk_t *mp, int error, int diagnostic)
424*0Sstevel@tonic-gate {
425*0Sstevel@tonic-gate 	spd_msg_t *spmsg = (spd_msg_t *)mp->b_rptr;
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_type == M_DATA);
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 	if (spmsg->spd_msg_type < SPD_MIN ||
430*0Sstevel@tonic-gate 	    spmsg->spd_msg_type > SPD_MAX)
431*0Sstevel@tonic-gate 		spmsg->spd_msg_type = SPD_RESERVED;
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	/*
434*0Sstevel@tonic-gate 	 * Strip out extension headers.
435*0Sstevel@tonic-gate 	 */
436*0Sstevel@tonic-gate 	ASSERT(mp->b_rptr + sizeof (*spmsg) <= mp->b_datap->db_lim);
437*0Sstevel@tonic-gate 	mp->b_wptr = mp->b_rptr + sizeof (*spmsg);
438*0Sstevel@tonic-gate 	spmsg->spd_msg_len = SPD_8TO64(sizeof (spd_msg_t));
439*0Sstevel@tonic-gate 	spmsg->spd_msg_errno = (uint8_t)error;
440*0Sstevel@tonic-gate 	spmsg->spd_msg_diagnostic = (uint16_t)diagnostic;
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	qreply(q, mp);
443*0Sstevel@tonic-gate }
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate static void
446*0Sstevel@tonic-gate spdsock_diag(queue_t *q, mblk_t *mp, int diagnostic)
447*0Sstevel@tonic-gate {
448*0Sstevel@tonic-gate 	spdsock_error(q, mp, EINVAL, diagnostic);
449*0Sstevel@tonic-gate }
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate static void
452*0Sstevel@tonic-gate spd_echo(queue_t *q, mblk_t *mp)
453*0Sstevel@tonic-gate {
454*0Sstevel@tonic-gate 	qreply(q, mp);
455*0Sstevel@tonic-gate }
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate /* ARGSUSED */
458*0Sstevel@tonic-gate static void
459*0Sstevel@tonic-gate spdsock_flush(queue_t *q, ipsec_policy_head_t *iph,
460*0Sstevel@tonic-gate     mblk_t *mp, spd_ext_t **extv)
461*0Sstevel@tonic-gate {
462*0Sstevel@tonic-gate 	rw_enter(&iph->iph_lock, RW_WRITER);
463*0Sstevel@tonic-gate 	ipsec_polhead_flush(iph);
464*0Sstevel@tonic-gate 	rw_exit(&iph->iph_lock);
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	spd_echo(q, mp);
467*0Sstevel@tonic-gate }
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate static boolean_t
470*0Sstevel@tonic-gate spdsock_ext_to_sel(spd_ext_t **extv, ipsec_selkey_t *sel, int *diag)
471*0Sstevel@tonic-gate {
472*0Sstevel@tonic-gate 	bzero(sel, sizeof (*sel));
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	if (extv[SPD_EXT_PROTO] != NULL) {
475*0Sstevel@tonic-gate 		struct spd_proto *pr =
476*0Sstevel@tonic-gate 		    (struct spd_proto *)extv[SPD_EXT_PROTO];
477*0Sstevel@tonic-gate 		sel->ipsl_proto = pr->spd_proto_number;
478*0Sstevel@tonic-gate 		sel->ipsl_valid |= IPSL_PROTOCOL;
479*0Sstevel@tonic-gate 	}
480*0Sstevel@tonic-gate 	if (extv[SPD_EXT_LCLPORT] != NULL) {
481*0Sstevel@tonic-gate 		struct spd_portrange *pr =
482*0Sstevel@tonic-gate 		    (struct spd_portrange *)extv[SPD_EXT_LCLPORT];
483*0Sstevel@tonic-gate 		sel->ipsl_lport = pr->spd_ports_minport;
484*0Sstevel@tonic-gate 		sel->ipsl_valid |= IPSL_LOCAL_PORT;
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 	if (extv[SPD_EXT_REMPORT] != NULL) {
487*0Sstevel@tonic-gate 		struct spd_portrange *pr =
488*0Sstevel@tonic-gate 		    (struct spd_portrange *)extv[SPD_EXT_REMPORT];
489*0Sstevel@tonic-gate 		sel->ipsl_rport = pr->spd_ports_minport;
490*0Sstevel@tonic-gate 		sel->ipsl_valid |= IPSL_REMOTE_PORT;
491*0Sstevel@tonic-gate 	}
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	if (extv[SPD_EXT_ICMP_TYPECODE] != NULL) {
494*0Sstevel@tonic-gate 		struct spd_typecode *tc=
495*0Sstevel@tonic-gate 		    (struct spd_typecode *)extv[SPD_EXT_ICMP_TYPECODE];
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 		sel->ipsl_valid |= IPSL_ICMP_TYPE;
498*0Sstevel@tonic-gate 		sel->ipsl_icmp_type = tc->spd_typecode_type;
499*0Sstevel@tonic-gate 		if (tc->spd_typecode_type_end < tc->spd_typecode_type)
500*0Sstevel@tonic-gate 			sel->ipsl_icmp_type_end = tc->spd_typecode_type;
501*0Sstevel@tonic-gate 		else
502*0Sstevel@tonic-gate 			sel->ipsl_icmp_type_end = tc->spd_typecode_type_end;
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 		if (tc->spd_typecode_code != 255) {
505*0Sstevel@tonic-gate 			sel->ipsl_valid |= IPSL_ICMP_CODE;
506*0Sstevel@tonic-gate 			sel->ipsl_icmp_code = tc->spd_typecode_code;
507*0Sstevel@tonic-gate 			if (tc->spd_typecode_code_end < tc->spd_typecode_code)
508*0Sstevel@tonic-gate 				sel->ipsl_icmp_code_end = tc->spd_typecode_code;
509*0Sstevel@tonic-gate 			else
510*0Sstevel@tonic-gate 				sel->ipsl_icmp_code_end =
511*0Sstevel@tonic-gate 				    tc->spd_typecode_code_end;
512*0Sstevel@tonic-gate 		}
513*0Sstevel@tonic-gate 	}
514*0Sstevel@tonic-gate #define	ADDR2SEL(sel, extv, field, pfield, extn, bit)			      \
515*0Sstevel@tonic-gate 	if ((extv)[(extn)] != NULL) {					      \
516*0Sstevel@tonic-gate 		uint_t addrlen;						      \
517*0Sstevel@tonic-gate 		struct spd_address *ap = 				      \
518*0Sstevel@tonic-gate 			(struct spd_address *)((extv)[(extn)]); 	      \
519*0Sstevel@tonic-gate 		addrlen = (ap->spd_address_af == AF_INET6) ? 		      \
520*0Sstevel@tonic-gate 			IPV6_ADDR_LEN : IP_ADDR_LEN;			      \
521*0Sstevel@tonic-gate 		if (SPD_64TO8(ap->spd_address_len) < 			      \
522*0Sstevel@tonic-gate 			(addrlen + sizeof (*ap))) {			      \
523*0Sstevel@tonic-gate 			*diag = SPD_DIAGNOSTIC_BAD_ADDR_LEN;		      \
524*0Sstevel@tonic-gate 			return (B_FALSE);				      \
525*0Sstevel@tonic-gate 		}							      \
526*0Sstevel@tonic-gate 		bcopy((ap+1), &((sel)->field), addrlen);		      \
527*0Sstevel@tonic-gate 		(sel)->pfield = ap->spd_address_prefixlen;		      \
528*0Sstevel@tonic-gate 		(sel)->ipsl_valid |= (bit);				      \
529*0Sstevel@tonic-gate 		(sel)->ipsl_valid |= (ap->spd_address_af == AF_INET6) ?	      \
530*0Sstevel@tonic-gate 			IPSL_IPV6 : IPSL_IPV4;				      \
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	ADDR2SEL(sel, extv, ipsl_local, ipsl_local_pfxlen,
534*0Sstevel@tonic-gate 	    SPD_EXT_LCLADDR, IPSL_LOCAL_ADDR);
535*0Sstevel@tonic-gate 	ADDR2SEL(sel, extv, ipsl_remote, ipsl_remote_pfxlen,
536*0Sstevel@tonic-gate 	    SPD_EXT_REMADDR, IPSL_REMOTE_ADDR);
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 	if ((sel->ipsl_valid & (IPSL_IPV6|IPSL_IPV4)) ==
539*0Sstevel@tonic-gate 	    (IPSL_IPV6|IPSL_IPV4)) {
540*0Sstevel@tonic-gate 		*diag = SPD_DIAGNOSTIC_MIXED_AF;
541*0Sstevel@tonic-gate 		return (B_FALSE);
542*0Sstevel@tonic-gate 	}
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate #undef ADDR2SEL
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	return (B_TRUE);
547*0Sstevel@tonic-gate }
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate static boolean_t
550*0Sstevel@tonic-gate spd_convert_type(uint32_t type, ipsec_act_t *act)
551*0Sstevel@tonic-gate {
552*0Sstevel@tonic-gate 	switch (type) {
553*0Sstevel@tonic-gate 	case SPD_ACTTYPE_DROP:
554*0Sstevel@tonic-gate 		act->ipa_type = IPSEC_ACT_DISCARD;
555*0Sstevel@tonic-gate 		return (B_TRUE);
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 	case SPD_ACTTYPE_PASS:
558*0Sstevel@tonic-gate 		act->ipa_type = IPSEC_ACT_CLEAR;
559*0Sstevel@tonic-gate 		return (B_TRUE);
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 	case SPD_ACTTYPE_IPSEC:
562*0Sstevel@tonic-gate 		act->ipa_type = IPSEC_ACT_APPLY;
563*0Sstevel@tonic-gate 		return (B_TRUE);
564*0Sstevel@tonic-gate 	}
565*0Sstevel@tonic-gate 	return (B_FALSE);
566*0Sstevel@tonic-gate }
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate static boolean_t
569*0Sstevel@tonic-gate spd_convert_flags(uint32_t flags, ipsec_act_t *act)
570*0Sstevel@tonic-gate {
571*0Sstevel@tonic-gate 	/*
572*0Sstevel@tonic-gate 	 * Note use of !! for boolean canonicalization.
573*0Sstevel@tonic-gate 	 */
574*0Sstevel@tonic-gate 	act->ipa_apply.ipp_use_ah = !!(flags & SPD_APPLY_AH);
575*0Sstevel@tonic-gate 	act->ipa_apply.ipp_use_esp = !!(flags & SPD_APPLY_ESP);
576*0Sstevel@tonic-gate 	act->ipa_apply.ipp_use_espa = !!(flags & SPD_APPLY_ESPA);
577*0Sstevel@tonic-gate 	act->ipa_apply.ipp_use_se = !!(flags & SPD_APPLY_SE);
578*0Sstevel@tonic-gate 	act->ipa_apply.ipp_use_unique = !!(flags & SPD_APPLY_UNIQUE);
579*0Sstevel@tonic-gate 	return (B_TRUE);
580*0Sstevel@tonic-gate }
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate static void
583*0Sstevel@tonic-gate spdsock_reset_act(ipsec_act_t *act)
584*0Sstevel@tonic-gate {
585*0Sstevel@tonic-gate 	bzero(act, sizeof (*act));
586*0Sstevel@tonic-gate 	act->ipa_apply.ipp_espe_maxbits = IPSEC_MAX_KEYBITS;
587*0Sstevel@tonic-gate 	act->ipa_apply.ipp_espa_maxbits = IPSEC_MAX_KEYBITS;
588*0Sstevel@tonic-gate 	act->ipa_apply.ipp_ah_maxbits = IPSEC_MAX_KEYBITS;
589*0Sstevel@tonic-gate }
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate /*
592*0Sstevel@tonic-gate  * Sanity check action against reality, and shrink-wrap key sizes..
593*0Sstevel@tonic-gate  */
594*0Sstevel@tonic-gate static boolean_t
595*0Sstevel@tonic-gate spdsock_check_action(ipsec_act_t *act, int *diag)
596*0Sstevel@tonic-gate {
597*0Sstevel@tonic-gate 	if ((act->ipa_type != IPSEC_ACT_APPLY) &&
598*0Sstevel@tonic-gate 	    (act->ipa_apply.ipp_use_ah ||
599*0Sstevel@tonic-gate 		act->ipa_apply.ipp_use_esp ||
600*0Sstevel@tonic-gate 		act->ipa_apply.ipp_use_espa ||
601*0Sstevel@tonic-gate 		act->ipa_apply.ipp_use_se ||
602*0Sstevel@tonic-gate 		act->ipa_apply.ipp_use_unique)) {
603*0Sstevel@tonic-gate 		*diag = SPD_DIAGNOSTIC_ADD_INCON_FLAGS;
604*0Sstevel@tonic-gate 		return (B_FALSE);
605*0Sstevel@tonic-gate 	}
606*0Sstevel@tonic-gate 	if ((act->ipa_type == IPSEC_ACT_APPLY) &&
607*0Sstevel@tonic-gate 	    !act->ipa_apply.ipp_use_ah &&
608*0Sstevel@tonic-gate 	    !act->ipa_apply.ipp_use_esp) {
609*0Sstevel@tonic-gate 		*diag = SPD_DIAGNOSTIC_ADD_INCON_FLAGS;
610*0Sstevel@tonic-gate 		return (B_FALSE);
611*0Sstevel@tonic-gate 	}
612*0Sstevel@tonic-gate 	return (ipsec_check_action(act, diag));
613*0Sstevel@tonic-gate }
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate /*
616*0Sstevel@tonic-gate  * We may be short a few error checks here..
617*0Sstevel@tonic-gate  */
618*0Sstevel@tonic-gate static boolean_t
619*0Sstevel@tonic-gate spdsock_ext_to_actvec(spd_ext_t **extv, ipsec_act_t **actpp, uint_t *nactp,
620*0Sstevel@tonic-gate     int *diag)
621*0Sstevel@tonic-gate {
622*0Sstevel@tonic-gate 	struct spd_ext_actions *sactp =
623*0Sstevel@tonic-gate 	    (struct spd_ext_actions *)extv[SPD_EXT_ACTION];
624*0Sstevel@tonic-gate 	ipsec_act_t act, *actp, *endactp;
625*0Sstevel@tonic-gate 	struct spd_attribute *attrp, *endattrp;
626*0Sstevel@tonic-gate 	uint64_t *endp;
627*0Sstevel@tonic-gate 	int nact;
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	*actpp = NULL;
630*0Sstevel@tonic-gate 	*nactp = 0;
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	if (sactp == NULL) {
633*0Sstevel@tonic-gate 		*diag = SPD_DIAGNOSTIC_NO_ACTION_EXT;
634*0Sstevel@tonic-gate 		return (B_FALSE);
635*0Sstevel@tonic-gate 	}
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	/*
638*0Sstevel@tonic-gate 	 * Parse the "action" extension and convert into an action chain.
639*0Sstevel@tonic-gate 	 */
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	nact = sactp->spd_actions_count;
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	endp = (uint64_t *)sactp;
644*0Sstevel@tonic-gate 	endp += sactp->spd_actions_len;
645*0Sstevel@tonic-gate 	endattrp = (struct spd_attribute *)endp;
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	actp = kmem_alloc(sizeof (*actp) * nact, KM_NOSLEEP);
648*0Sstevel@tonic-gate 	if (actp == NULL) {
649*0Sstevel@tonic-gate 		*diag = SPD_DIAGNOSTIC_ADD_NO_MEM;
650*0Sstevel@tonic-gate 		return (B_FALSE);
651*0Sstevel@tonic-gate 	}
652*0Sstevel@tonic-gate 	*actpp = actp;
653*0Sstevel@tonic-gate 	*nactp = nact;
654*0Sstevel@tonic-gate 	endactp = actp + nact;
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	spdsock_reset_act(&act);
657*0Sstevel@tonic-gate 	attrp = (struct spd_attribute *)(&sactp[1]);
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	for (; attrp < endattrp; attrp++) {
660*0Sstevel@tonic-gate 		switch (attrp->spd_attr_tag) {
661*0Sstevel@tonic-gate 		case SPD_ATTR_NOP:
662*0Sstevel@tonic-gate 			break;
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 		case SPD_ATTR_EMPTY:
665*0Sstevel@tonic-gate 			spdsock_reset_act(&act);
666*0Sstevel@tonic-gate 			break;
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 		case SPD_ATTR_END:
669*0Sstevel@tonic-gate 			attrp = endattrp;
670*0Sstevel@tonic-gate 			/* FALLTHRU */
671*0Sstevel@tonic-gate 		case SPD_ATTR_NEXT:
672*0Sstevel@tonic-gate 			if (actp >= endactp) {
673*0Sstevel@tonic-gate 				*diag = SPD_DIAGNOSTIC_ADD_WRONG_ACT_COUNT;
674*0Sstevel@tonic-gate 				goto fail;
675*0Sstevel@tonic-gate 			}
676*0Sstevel@tonic-gate 			if (!spdsock_check_action(&act, diag))
677*0Sstevel@tonic-gate 				goto fail;
678*0Sstevel@tonic-gate 			*actp++ = act;
679*0Sstevel@tonic-gate 			break;
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 		case SPD_ATTR_TYPE:
682*0Sstevel@tonic-gate 			if (!spd_convert_type(attrp->spd_attr_value, &act)) {
683*0Sstevel@tonic-gate 				*diag = SPD_DIAGNOSTIC_ADD_BAD_TYPE;
684*0Sstevel@tonic-gate 				goto fail;
685*0Sstevel@tonic-gate 			}
686*0Sstevel@tonic-gate 			break;
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 		case SPD_ATTR_FLAGS:
689*0Sstevel@tonic-gate 			if (!spd_convert_flags(attrp->spd_attr_value, &act)) {
690*0Sstevel@tonic-gate 				*diag = SPD_DIAGNOSTIC_ADD_BAD_FLAGS;
691*0Sstevel@tonic-gate 				goto fail;
692*0Sstevel@tonic-gate 			}
693*0Sstevel@tonic-gate 			break;
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 		case SPD_ATTR_AH_AUTH:
696*0Sstevel@tonic-gate 			act.ipa_apply.ipp_auth_alg = attrp->spd_attr_value;
697*0Sstevel@tonic-gate 			break;
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 		case SPD_ATTR_ESP_ENCR:
700*0Sstevel@tonic-gate 			act.ipa_apply.ipp_encr_alg = attrp->spd_attr_value;
701*0Sstevel@tonic-gate 			break;
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 		case SPD_ATTR_ESP_AUTH:
704*0Sstevel@tonic-gate 			act.ipa_apply.ipp_esp_auth_alg = attrp->spd_attr_value;
705*0Sstevel@tonic-gate 			break;
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 		case SPD_ATTR_ENCR_MINBITS:
708*0Sstevel@tonic-gate 			act.ipa_apply.ipp_espe_minbits = attrp->spd_attr_value;
709*0Sstevel@tonic-gate 			break;
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 		case SPD_ATTR_ENCR_MAXBITS:
712*0Sstevel@tonic-gate 			act.ipa_apply.ipp_espe_maxbits = attrp->spd_attr_value;
713*0Sstevel@tonic-gate 			break;
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 		case SPD_ATTR_AH_MINBITS:
716*0Sstevel@tonic-gate 			act.ipa_apply.ipp_ah_minbits = attrp->spd_attr_value;
717*0Sstevel@tonic-gate 			break;
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 		case SPD_ATTR_AH_MAXBITS:
720*0Sstevel@tonic-gate 			act.ipa_apply.ipp_ah_maxbits = attrp->spd_attr_value;
721*0Sstevel@tonic-gate 			break;
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 		case SPD_ATTR_ESPA_MINBITS:
724*0Sstevel@tonic-gate 			act.ipa_apply.ipp_espa_minbits = attrp->spd_attr_value;
725*0Sstevel@tonic-gate 			break;
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 		case SPD_ATTR_ESPA_MAXBITS:
728*0Sstevel@tonic-gate 			act.ipa_apply.ipp_espa_maxbits = attrp->spd_attr_value;
729*0Sstevel@tonic-gate 			break;
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 		case SPD_ATTR_LIFE_SOFT_TIME:
732*0Sstevel@tonic-gate 		case SPD_ATTR_LIFE_HARD_TIME:
733*0Sstevel@tonic-gate 		case SPD_ATTR_LIFE_SOFT_BYTES:
734*0Sstevel@tonic-gate 		case SPD_ATTR_LIFE_HARD_BYTES:
735*0Sstevel@tonic-gate 			break;
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 		case SPD_ATTR_KM_PROTO:
738*0Sstevel@tonic-gate 			act.ipa_apply.ipp_km_proto = attrp->spd_attr_value;
739*0Sstevel@tonic-gate 			break;
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 		case SPD_ATTR_KM_COOKIE:
742*0Sstevel@tonic-gate 			act.ipa_apply.ipp_km_cookie = attrp->spd_attr_value;
743*0Sstevel@tonic-gate 			break;
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 		case SPD_ATTR_REPLAY_DEPTH:
746*0Sstevel@tonic-gate 			act.ipa_apply.ipp_replay_depth = attrp->spd_attr_value;
747*0Sstevel@tonic-gate 			break;
748*0Sstevel@tonic-gate 		}
749*0Sstevel@tonic-gate 	}
750*0Sstevel@tonic-gate 	if (actp != endactp) {
751*0Sstevel@tonic-gate 		*diag = SPD_DIAGNOSTIC_ADD_WRONG_ACT_COUNT;
752*0Sstevel@tonic-gate 		goto fail;
753*0Sstevel@tonic-gate 	}
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 	return (B_TRUE);
756*0Sstevel@tonic-gate fail:
757*0Sstevel@tonic-gate 	ipsec_actvec_free(*actpp, nact);
758*0Sstevel@tonic-gate 	*actpp = NULL;
759*0Sstevel@tonic-gate 	return (B_FALSE);
760*0Sstevel@tonic-gate }
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate typedef struct
763*0Sstevel@tonic-gate {
764*0Sstevel@tonic-gate 	ipsec_policy_t *pol;
765*0Sstevel@tonic-gate 	int dir;
766*0Sstevel@tonic-gate } tmprule_t;
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate static int
769*0Sstevel@tonic-gate mkrule(ipsec_policy_head_t *iph, struct spd_rule *rule,
770*0Sstevel@tonic-gate     ipsec_selkey_t *sel, ipsec_act_t *actp, int nact, uint_t dir, uint_t af,
771*0Sstevel@tonic-gate     tmprule_t **rp)
772*0Sstevel@tonic-gate {
773*0Sstevel@tonic-gate 	ipsec_policy_t *pol;
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	sel->ipsl_valid &= ~(IPSL_IPV6|IPSL_IPV4);
776*0Sstevel@tonic-gate 	sel->ipsl_valid |= af;
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 	pol = ipsec_policy_create(sel, actp, nact, rule->spd_rule_priority);
779*0Sstevel@tonic-gate 	if (pol == NULL)
780*0Sstevel@tonic-gate 		return (ENOMEM);
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	(*rp)->pol = pol;
783*0Sstevel@tonic-gate 	(*rp)->dir = dir;
784*0Sstevel@tonic-gate 	(*rp)++;
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	if (!ipsec_check_policy(iph, pol, dir))
787*0Sstevel@tonic-gate 		return (EEXIST);
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 	rule->spd_rule_index = pol->ipsp_index;
790*0Sstevel@tonic-gate 	return (0);
791*0Sstevel@tonic-gate }
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate static int
794*0Sstevel@tonic-gate mkrulepair(ipsec_policy_head_t *iph, struct spd_rule *rule,
795*0Sstevel@tonic-gate     ipsec_selkey_t *sel, ipsec_act_t *actp, int nact, uint_t dir, uint_t afs,
796*0Sstevel@tonic-gate     tmprule_t **rp)
797*0Sstevel@tonic-gate {
798*0Sstevel@tonic-gate 	int error;
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 	if (afs & IPSL_IPV4) {
801*0Sstevel@tonic-gate 		error = mkrule(iph, rule, sel, actp, nact, dir, IPSL_IPV4, rp);
802*0Sstevel@tonic-gate 		if (error != 0)
803*0Sstevel@tonic-gate 			return (error);
804*0Sstevel@tonic-gate 	}
805*0Sstevel@tonic-gate 	if (afs & IPSL_IPV6) {
806*0Sstevel@tonic-gate 		error = mkrule(iph, rule, sel, actp, nact, dir, IPSL_IPV6, rp);
807*0Sstevel@tonic-gate 		if (error != 0)
808*0Sstevel@tonic-gate 			return (error);
809*0Sstevel@tonic-gate 	}
810*0Sstevel@tonic-gate 	return (0);
811*0Sstevel@tonic-gate }
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate static void
815*0Sstevel@tonic-gate spdsock_addrule(queue_t *q, ipsec_policy_head_t *iph,
816*0Sstevel@tonic-gate     mblk_t *mp, spd_ext_t **extv)
817*0Sstevel@tonic-gate {
818*0Sstevel@tonic-gate 	ipsec_selkey_t sel;
819*0Sstevel@tonic-gate 	ipsec_act_t *actp;
820*0Sstevel@tonic-gate 	uint_t nact;
821*0Sstevel@tonic-gate 	int diag, error, afs;
822*0Sstevel@tonic-gate 	struct spd_rule *rule = (struct spd_rule *)extv[SPD_EXT_RULE];
823*0Sstevel@tonic-gate 	tmprule_t rules[4], *rulep = &rules[0];
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	if (rule == NULL) {
826*0Sstevel@tonic-gate 		spdsock_diag(q, mp, SPD_DIAGNOSTIC_NO_RULE_EXT);
827*0Sstevel@tonic-gate 		return;
828*0Sstevel@tonic-gate 	}
829*0Sstevel@tonic-gate 
830*0Sstevel@tonic-gate 	if (rule->spd_rule_index != 0) {
831*0Sstevel@tonic-gate 		spdsock_diag(q, mp, SPD_DIAGNOSTIC_INVALID_RULE_INDEX);
832*0Sstevel@tonic-gate 		return;
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	if (!spdsock_ext_to_sel(extv, &sel, &diag)) {
836*0Sstevel@tonic-gate 		spdsock_diag(q, mp, diag);
837*0Sstevel@tonic-gate 		return;
838*0Sstevel@tonic-gate 	}
839*0Sstevel@tonic-gate 
840*0Sstevel@tonic-gate 	if (!spdsock_ext_to_actvec(extv, &actp, &nact, &diag)) {
841*0Sstevel@tonic-gate 		spdsock_diag(q, mp, diag);
842*0Sstevel@tonic-gate 		return;
843*0Sstevel@tonic-gate 	}
844*0Sstevel@tonic-gate 	/*
845*0Sstevel@tonic-gate 	 * If no addresses were specified, add both.
846*0Sstevel@tonic-gate 	 */
847*0Sstevel@tonic-gate 	afs = sel.ipsl_valid & (IPSL_IPV6|IPSL_IPV4);
848*0Sstevel@tonic-gate 	if (afs == 0)
849*0Sstevel@tonic-gate 		afs = (IPSL_IPV6|IPSL_IPV4);
850*0Sstevel@tonic-gate 
851*0Sstevel@tonic-gate 	rw_enter(&iph->iph_lock, RW_WRITER);
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate 	if (rule->spd_rule_flags & SPD_RULE_FLAG_OUTBOUND) {
854*0Sstevel@tonic-gate 		error = mkrulepair(iph, rule, &sel, actp, nact,
855*0Sstevel@tonic-gate 		    IPSEC_TYPE_OUTBOUND, afs, &rulep);
856*0Sstevel@tonic-gate 		if (error != 0)
857*0Sstevel@tonic-gate 			goto fail;
858*0Sstevel@tonic-gate 	}
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	if (rule->spd_rule_flags & SPD_RULE_FLAG_INBOUND) {
861*0Sstevel@tonic-gate 		error = mkrulepair(iph, rule, &sel, actp, nact,
862*0Sstevel@tonic-gate 		    IPSEC_TYPE_INBOUND, afs, &rulep);
863*0Sstevel@tonic-gate 		if (error != 0)
864*0Sstevel@tonic-gate 			goto fail;
865*0Sstevel@tonic-gate 	}
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 	while ((--rulep) >= &rules[0])
868*0Sstevel@tonic-gate 		ipsec_enter_policy(iph, rulep->pol, rulep->dir);
869*0Sstevel@tonic-gate 
870*0Sstevel@tonic-gate 	rw_exit(&iph->iph_lock);
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	ipsec_actvec_free(actp, nact);
873*0Sstevel@tonic-gate 	spd_echo(q, mp);
874*0Sstevel@tonic-gate 	return;
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate fail:
877*0Sstevel@tonic-gate 	rw_exit(&iph->iph_lock);
878*0Sstevel@tonic-gate 	while ((--rulep) >= &rules[0]) {
879*0Sstevel@tonic-gate 		IPPOL_REFRELE(rulep->pol);
880*0Sstevel@tonic-gate 	}
881*0Sstevel@tonic-gate 	ipsec_actvec_free(actp, nact);
882*0Sstevel@tonic-gate 	spdsock_error(q, mp, error, 0);
883*0Sstevel@tonic-gate }
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate void
886*0Sstevel@tonic-gate spdsock_deleterule(queue_t *q, ipsec_policy_head_t *iph,
887*0Sstevel@tonic-gate     mblk_t *mp, spd_ext_t **extv)
888*0Sstevel@tonic-gate {
889*0Sstevel@tonic-gate 	ipsec_selkey_t sel;
890*0Sstevel@tonic-gate 	struct spd_rule *rule = (struct spd_rule *)extv[SPD_EXT_RULE];
891*0Sstevel@tonic-gate 	int diag;
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	if (rule == NULL) {
894*0Sstevel@tonic-gate 		spdsock_diag(q, mp, SPD_DIAGNOSTIC_NO_RULE_EXT);
895*0Sstevel@tonic-gate 		return;
896*0Sstevel@tonic-gate 	}
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate 	if (rule->spd_rule_index != 0) {
899*0Sstevel@tonic-gate 		if (ipsec_policy_delete_index(iph, rule->spd_rule_index) != 0) {
900*0Sstevel@tonic-gate 			spdsock_error(q, mp, ESRCH, 0);
901*0Sstevel@tonic-gate 			return;
902*0Sstevel@tonic-gate 		}
903*0Sstevel@tonic-gate 	} else {
904*0Sstevel@tonic-gate 		if (!spdsock_ext_to_sel(extv, &sel, &diag)) {
905*0Sstevel@tonic-gate 			spdsock_diag(q, mp, diag);
906*0Sstevel@tonic-gate 			return;
907*0Sstevel@tonic-gate 		}
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate 		if (rule->spd_rule_flags & SPD_RULE_FLAG_INBOUND) {
910*0Sstevel@tonic-gate 			if (!ipsec_policy_delete(iph, &sel,
911*0Sstevel@tonic-gate 			    IPSEC_TYPE_INBOUND))
912*0Sstevel@tonic-gate 				goto fail;
913*0Sstevel@tonic-gate 		}
914*0Sstevel@tonic-gate 
915*0Sstevel@tonic-gate 		if (rule->spd_rule_flags & SPD_RULE_FLAG_OUTBOUND) {
916*0Sstevel@tonic-gate 			if (!ipsec_policy_delete(iph, &sel,
917*0Sstevel@tonic-gate 			    IPSEC_TYPE_OUTBOUND))
918*0Sstevel@tonic-gate 				goto fail;
919*0Sstevel@tonic-gate 		}
920*0Sstevel@tonic-gate 	}
921*0Sstevel@tonic-gate 	spd_echo(q, mp);
922*0Sstevel@tonic-gate 	return;
923*0Sstevel@tonic-gate fail:
924*0Sstevel@tonic-gate 	spdsock_error(q, mp, ESRCH, 0);
925*0Sstevel@tonic-gate }
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate void
928*0Sstevel@tonic-gate spdsock_flip(queue_t *q, mblk_t *mp)
929*0Sstevel@tonic-gate {
930*0Sstevel@tonic-gate 	ipsec_swap_policy();	/* can't fail */
931*0Sstevel@tonic-gate 	spd_echo(q, mp);
932*0Sstevel@tonic-gate }
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate /*
935*0Sstevel@tonic-gate  * Unimplemented feature
936*0Sstevel@tonic-gate  */
937*0Sstevel@tonic-gate /* ARGSUSED */
938*0Sstevel@tonic-gate static void
939*0Sstevel@tonic-gate spdsock_lookup(queue_t *q, ipsec_policy_head_t *iph,
940*0Sstevel@tonic-gate     mblk_t *mp, spd_ext_t **extv)
941*0Sstevel@tonic-gate {
942*0Sstevel@tonic-gate 	spdsock_error(q, mp, EINVAL, 0);
943*0Sstevel@tonic-gate }
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate static mblk_t *
947*0Sstevel@tonic-gate spdsock_dump_ruleset(mblk_t *req, ipsec_policy_head_t *iph,
948*0Sstevel@tonic-gate     uint32_t count, uint16_t error)
949*0Sstevel@tonic-gate {
950*0Sstevel@tonic-gate 	size_t len = sizeof (spd_ruleset_ext_t) + sizeof (spd_msg_t);
951*0Sstevel@tonic-gate 	spd_msg_t *msg;
952*0Sstevel@tonic-gate 	spd_ruleset_ext_t *ruleset;
953*0Sstevel@tonic-gate 	mblk_t *m = allocb(len, BPRI_HI);
954*0Sstevel@tonic-gate 
955*0Sstevel@tonic-gate 	ASSERT(RW_READ_HELD(&iph->iph_lock));
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 	if (m == NULL) {
958*0Sstevel@tonic-gate 		return (NULL);
959*0Sstevel@tonic-gate 	}
960*0Sstevel@tonic-gate 	msg = (spd_msg_t *)m->b_rptr;
961*0Sstevel@tonic-gate 	ruleset = (spd_ruleset_ext_t *)(&msg[1]);
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 	m->b_wptr = (uint8_t *)&ruleset[1];
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 	*msg = *(spd_msg_t *)(req->b_rptr);
966*0Sstevel@tonic-gate 	msg->spd_msg_len = SPD_8TO64(len);
967*0Sstevel@tonic-gate 	msg->spd_msg_errno = error;
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	ruleset->spd_ruleset_len = SPD_8TO64(sizeof (*ruleset));
970*0Sstevel@tonic-gate 	ruleset->spd_ruleset_type = SPD_EXT_RULESET;
971*0Sstevel@tonic-gate 	ruleset->spd_ruleset_count = count;
972*0Sstevel@tonic-gate 	ruleset->spd_ruleset_version = iph->iph_gen;
973*0Sstevel@tonic-gate 	return (m);
974*0Sstevel@tonic-gate }
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate static mblk_t *
977*0Sstevel@tonic-gate spdsock_dump_finish(spdsock_t *ss, int error)
978*0Sstevel@tonic-gate {
979*0Sstevel@tonic-gate 	mblk_t *m;
980*0Sstevel@tonic-gate 	ipsec_policy_head_t *iph = ss->spdsock_dump_head;
981*0Sstevel@tonic-gate 	mblk_t *req = ss->spdsock_dump_req;
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate 	rw_enter(&iph->iph_lock, RW_READER);
984*0Sstevel@tonic-gate 	m = spdsock_dump_ruleset(req, iph, ss->spdsock_dump_count, error);
985*0Sstevel@tonic-gate 	rw_exit(&iph->iph_lock);
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 	ss->spdsock_dump_req = NULL;
988*0Sstevel@tonic-gate 	freemsg(req);
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 	return (m);
991*0Sstevel@tonic-gate }
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate /*
994*0Sstevel@tonic-gate  * Rule encoding functions.
995*0Sstevel@tonic-gate  * We do a two-pass encode.
996*0Sstevel@tonic-gate  * If base != NULL, fill in encoded rule part starting at base+offset.
997*0Sstevel@tonic-gate  * Always return "offset" plus length of to-be-encoded data.
998*0Sstevel@tonic-gate  */
999*0Sstevel@tonic-gate static uint_t
1000*0Sstevel@tonic-gate spdsock_encode_typecode(uint8_t *base, uint_t offset, uint8_t type,
1001*0Sstevel@tonic-gate     uint8_t type_end, uint8_t code, uint8_t code_end)
1002*0Sstevel@tonic-gate {
1003*0Sstevel@tonic-gate 	struct spd_typecode *tcp;
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1006*0Sstevel@tonic-gate 
1007*0Sstevel@tonic-gate 	if (base != NULL) {
1008*0Sstevel@tonic-gate 		tcp = (struct spd_typecode *)(base + offset);
1009*0Sstevel@tonic-gate 		tcp->spd_typecode_len = SPD_8TO64(sizeof (*tcp));
1010*0Sstevel@tonic-gate 		tcp->spd_typecode_exttype = SPD_EXT_ICMP_TYPECODE;
1011*0Sstevel@tonic-gate 		tcp->spd_typecode_code = code;
1012*0Sstevel@tonic-gate 		tcp->spd_typecode_type = type;
1013*0Sstevel@tonic-gate 		tcp->spd_typecode_type_end = type_end;
1014*0Sstevel@tonic-gate 		tcp->spd_typecode_code_end = code_end;
1015*0Sstevel@tonic-gate 	}
1016*0Sstevel@tonic-gate 	offset += sizeof (*tcp);
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1019*0Sstevel@tonic-gate 
1020*0Sstevel@tonic-gate 	return (offset);
1021*0Sstevel@tonic-gate }
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate static uint_t
1024*0Sstevel@tonic-gate spdsock_encode_proto(uint8_t *base, uint_t offset, uint8_t proto)
1025*0Sstevel@tonic-gate {
1026*0Sstevel@tonic-gate 	struct spd_proto *spp;
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 	if (base != NULL) {
1031*0Sstevel@tonic-gate 		spp = (struct spd_proto *)(base + offset);
1032*0Sstevel@tonic-gate 		spp->spd_proto_len = SPD_8TO64(sizeof (*spp));
1033*0Sstevel@tonic-gate 		spp->spd_proto_exttype = SPD_EXT_PROTO;
1034*0Sstevel@tonic-gate 		spp->spd_proto_number = proto;
1035*0Sstevel@tonic-gate 		spp->spd_proto_reserved1 = 0;
1036*0Sstevel@tonic-gate 		spp->spd_proto_reserved2 = 0;
1037*0Sstevel@tonic-gate 	}
1038*0Sstevel@tonic-gate 	offset += sizeof (*spp);
1039*0Sstevel@tonic-gate 
1040*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1041*0Sstevel@tonic-gate 
1042*0Sstevel@tonic-gate 	return (offset);
1043*0Sstevel@tonic-gate }
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate static uint_t
1046*0Sstevel@tonic-gate spdsock_encode_port(uint8_t *base, uint_t offset, uint16_t ext, uint16_t port)
1047*0Sstevel@tonic-gate {
1048*0Sstevel@tonic-gate 	struct spd_portrange *spp;
1049*0Sstevel@tonic-gate 
1050*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate 	if (base != NULL) {
1053*0Sstevel@tonic-gate 		spp = (struct spd_portrange *)(base + offset);
1054*0Sstevel@tonic-gate 		spp->spd_ports_len = SPD_8TO64(sizeof (*spp));
1055*0Sstevel@tonic-gate 		spp->spd_ports_exttype = ext;
1056*0Sstevel@tonic-gate 		spp->spd_ports_minport = port;
1057*0Sstevel@tonic-gate 		spp->spd_ports_maxport = port;
1058*0Sstevel@tonic-gate 	}
1059*0Sstevel@tonic-gate 	offset += sizeof (*spp);
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1062*0Sstevel@tonic-gate 
1063*0Sstevel@tonic-gate 	return (offset);
1064*0Sstevel@tonic-gate }
1065*0Sstevel@tonic-gate 
1066*0Sstevel@tonic-gate static uint_t
1067*0Sstevel@tonic-gate spdsock_encode_addr(uint8_t *base, uint_t offset, uint16_t ext,
1068*0Sstevel@tonic-gate     const ipsec_selkey_t *sel, const ipsec_addr_t *addr, uint_t pfxlen)
1069*0Sstevel@tonic-gate {
1070*0Sstevel@tonic-gate 	struct spd_address *sae;
1071*0Sstevel@tonic-gate 	ipsec_addr_t *spdaddr;
1072*0Sstevel@tonic-gate 	uint_t start = offset;
1073*0Sstevel@tonic-gate 	uint_t addrlen;
1074*0Sstevel@tonic-gate 	uint_t af;
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate 	if (sel->ipsl_valid & IPSL_IPV4) {
1077*0Sstevel@tonic-gate 		af = AF_INET;
1078*0Sstevel@tonic-gate 		addrlen = IP_ADDR_LEN;
1079*0Sstevel@tonic-gate 	} else {
1080*0Sstevel@tonic-gate 		af = AF_INET6;
1081*0Sstevel@tonic-gate 		addrlen = IPV6_ADDR_LEN;
1082*0Sstevel@tonic-gate 	}
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate 	if (base != NULL) {
1087*0Sstevel@tonic-gate 		sae = (struct spd_address *)(base + offset);
1088*0Sstevel@tonic-gate 		sae->spd_address_exttype = ext;
1089*0Sstevel@tonic-gate 		sae->spd_address_af = af;
1090*0Sstevel@tonic-gate 		sae->spd_address_prefixlen = pfxlen;
1091*0Sstevel@tonic-gate 		sae->spd_address_reserved2 = 0;
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate 		spdaddr = (ipsec_addr_t *)(&sae[1]);
1094*0Sstevel@tonic-gate 		bcopy(addr, spdaddr, addrlen);
1095*0Sstevel@tonic-gate 	}
1096*0Sstevel@tonic-gate 	offset += sizeof (*sae);
1097*0Sstevel@tonic-gate 	addrlen = roundup(addrlen, sizeof (uint64_t));
1098*0Sstevel@tonic-gate 	offset += addrlen;
1099*0Sstevel@tonic-gate 
1100*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1101*0Sstevel@tonic-gate 
1102*0Sstevel@tonic-gate 	if (base != NULL)
1103*0Sstevel@tonic-gate 		sae->spd_address_len = SPD_8TO64(offset - start);
1104*0Sstevel@tonic-gate 	return (offset);
1105*0Sstevel@tonic-gate }
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate static uint_t
1108*0Sstevel@tonic-gate spdsock_encode_sel(uint8_t *base, uint_t offset, const ipsec_sel_t *sel)
1109*0Sstevel@tonic-gate {
1110*0Sstevel@tonic-gate 	const ipsec_selkey_t *selkey = &sel->ipsl_key;
1111*0Sstevel@tonic-gate 
1112*0Sstevel@tonic-gate 	if (selkey->ipsl_valid & IPSL_PROTOCOL)
1113*0Sstevel@tonic-gate 		offset = spdsock_encode_proto(base, offset, selkey->ipsl_proto);
1114*0Sstevel@tonic-gate 	if (selkey->ipsl_valid & IPSL_LOCAL_PORT)
1115*0Sstevel@tonic-gate 		offset = spdsock_encode_port(base, offset, SPD_EXT_LCLPORT,
1116*0Sstevel@tonic-gate 		    selkey->ipsl_lport);
1117*0Sstevel@tonic-gate 	if (selkey->ipsl_valid & IPSL_REMOTE_PORT)
1118*0Sstevel@tonic-gate 		offset = spdsock_encode_port(base, offset, SPD_EXT_REMPORT,
1119*0Sstevel@tonic-gate 		    selkey->ipsl_rport);
1120*0Sstevel@tonic-gate 	if (selkey->ipsl_valid & IPSL_REMOTE_ADDR)
1121*0Sstevel@tonic-gate 		offset = spdsock_encode_addr(base, offset, SPD_EXT_REMADDR,
1122*0Sstevel@tonic-gate 		    selkey, &selkey->ipsl_remote, selkey->ipsl_remote_pfxlen);
1123*0Sstevel@tonic-gate 	if (selkey->ipsl_valid & IPSL_LOCAL_ADDR)
1124*0Sstevel@tonic-gate 		offset = spdsock_encode_addr(base, offset, SPD_EXT_LCLADDR,
1125*0Sstevel@tonic-gate 		    selkey, &selkey->ipsl_local, selkey->ipsl_local_pfxlen);
1126*0Sstevel@tonic-gate 	if (selkey->ipsl_valid & IPSL_ICMP_TYPE) {
1127*0Sstevel@tonic-gate 		offset = spdsock_encode_typecode(base, offset,
1128*0Sstevel@tonic-gate 		    selkey->ipsl_icmp_type, selkey->ipsl_icmp_type_end,
1129*0Sstevel@tonic-gate 		    (selkey->ipsl_valid & IPSL_ICMP_CODE) ?
1130*0Sstevel@tonic-gate 			selkey->ipsl_icmp_code : 255,
1131*0Sstevel@tonic-gate 		    (selkey->ipsl_valid & IPSL_ICMP_CODE) ?
1132*0Sstevel@tonic-gate 			selkey->ipsl_icmp_code_end : 255);
1133*0Sstevel@tonic-gate 	}
1134*0Sstevel@tonic-gate 	return (offset);
1135*0Sstevel@tonic-gate }
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate static uint_t
1138*0Sstevel@tonic-gate spdsock_encode_actattr(uint8_t *base, uint_t offset, uint32_t tag,
1139*0Sstevel@tonic-gate     uint32_t value)
1140*0Sstevel@tonic-gate {
1141*0Sstevel@tonic-gate 	struct spd_attribute *attr;
1142*0Sstevel@tonic-gate 
1143*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 	if (base != NULL) {
1146*0Sstevel@tonic-gate 		attr = (struct spd_attribute *)(base + offset);
1147*0Sstevel@tonic-gate 		attr->spd_attr_tag = tag;
1148*0Sstevel@tonic-gate 		attr->spd_attr_value = value;
1149*0Sstevel@tonic-gate 	}
1150*0Sstevel@tonic-gate 	offset += sizeof (struct spd_attribute);
1151*0Sstevel@tonic-gate 
1152*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1153*0Sstevel@tonic-gate 
1154*0Sstevel@tonic-gate 	return (offset);
1155*0Sstevel@tonic-gate }
1156*0Sstevel@tonic-gate 
1157*0Sstevel@tonic-gate 
1158*0Sstevel@tonic-gate #define	EMIT(t, v) offset = spdsock_encode_actattr(base, offset, (t), (v))
1159*0Sstevel@tonic-gate 
1160*0Sstevel@tonic-gate static uint_t
1161*0Sstevel@tonic-gate spdsock_encode_action(uint8_t *base, uint_t offset, const ipsec_action_t *ap)
1162*0Sstevel@tonic-gate {
1163*0Sstevel@tonic-gate 	const struct ipsec_act *act = &(ap->ipa_act);
1164*0Sstevel@tonic-gate 	uint_t flags;
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate 	EMIT(SPD_ATTR_EMPTY, 0);
1167*0Sstevel@tonic-gate 	switch (act->ipa_type) {
1168*0Sstevel@tonic-gate 	case IPSEC_ACT_DISCARD:
1169*0Sstevel@tonic-gate 	case IPSEC_ACT_REJECT:
1170*0Sstevel@tonic-gate 		EMIT(SPD_ATTR_TYPE, SPD_ACTTYPE_DROP);
1171*0Sstevel@tonic-gate 		break;
1172*0Sstevel@tonic-gate 	case IPSEC_ACT_BYPASS:
1173*0Sstevel@tonic-gate 	case IPSEC_ACT_CLEAR:
1174*0Sstevel@tonic-gate 		EMIT(SPD_ATTR_TYPE, SPD_ACTTYPE_PASS);
1175*0Sstevel@tonic-gate 		break;
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 	case IPSEC_ACT_APPLY:
1178*0Sstevel@tonic-gate 		EMIT(SPD_ATTR_TYPE, SPD_ACTTYPE_IPSEC);
1179*0Sstevel@tonic-gate 		flags = 0;
1180*0Sstevel@tonic-gate 		if (act->ipa_apply.ipp_use_ah)
1181*0Sstevel@tonic-gate 			flags |= SPD_APPLY_AH;
1182*0Sstevel@tonic-gate 		if (act->ipa_apply.ipp_use_esp)
1183*0Sstevel@tonic-gate 			flags |= SPD_APPLY_ESP;
1184*0Sstevel@tonic-gate 		if (act->ipa_apply.ipp_use_espa)
1185*0Sstevel@tonic-gate 			flags |= SPD_APPLY_ESPA;
1186*0Sstevel@tonic-gate 		if (act->ipa_apply.ipp_use_se)
1187*0Sstevel@tonic-gate 			flags |= SPD_APPLY_SE;
1188*0Sstevel@tonic-gate 		if (act->ipa_apply.ipp_use_unique)
1189*0Sstevel@tonic-gate 			flags |= SPD_APPLY_UNIQUE;
1190*0Sstevel@tonic-gate 		EMIT(SPD_ATTR_FLAGS, flags);
1191*0Sstevel@tonic-gate 		if (flags & SPD_APPLY_AH) {
1192*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_AH_AUTH, act->ipa_apply.ipp_auth_alg);
1193*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_AH_MINBITS,
1194*0Sstevel@tonic-gate 			    act->ipa_apply.ipp_ah_minbits);
1195*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_AH_MAXBITS,
1196*0Sstevel@tonic-gate 			    act->ipa_apply.ipp_ah_maxbits);
1197*0Sstevel@tonic-gate 		}
1198*0Sstevel@tonic-gate 		if (flags & SPD_APPLY_ESP) {
1199*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_ESP_ENCR, act->ipa_apply.ipp_encr_alg);
1200*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_ENCR_MINBITS,
1201*0Sstevel@tonic-gate 			    act->ipa_apply.ipp_espe_minbits);
1202*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_ENCR_MAXBITS,
1203*0Sstevel@tonic-gate 			    act->ipa_apply.ipp_espe_maxbits);
1204*0Sstevel@tonic-gate 			if (flags & SPD_APPLY_ESPA) {
1205*0Sstevel@tonic-gate 				EMIT(SPD_ATTR_ESP_AUTH,
1206*0Sstevel@tonic-gate 				    act->ipa_apply.ipp_esp_auth_alg);
1207*0Sstevel@tonic-gate 				EMIT(SPD_ATTR_ESPA_MINBITS,
1208*0Sstevel@tonic-gate 				    act->ipa_apply.ipp_espa_minbits);
1209*0Sstevel@tonic-gate 				EMIT(SPD_ATTR_ESPA_MAXBITS,
1210*0Sstevel@tonic-gate 				    act->ipa_apply.ipp_espa_maxbits);
1211*0Sstevel@tonic-gate 			}
1212*0Sstevel@tonic-gate 		}
1213*0Sstevel@tonic-gate 		if (act->ipa_apply.ipp_km_proto != 0)
1214*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_KM_PROTO, act->ipa_apply.ipp_km_proto);
1215*0Sstevel@tonic-gate 		if (act->ipa_apply.ipp_km_cookie != 0)
1216*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_KM_PROTO, act->ipa_apply.ipp_km_cookie);
1217*0Sstevel@tonic-gate 		if (act->ipa_apply.ipp_replay_depth != 0)
1218*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_REPLAY_DEPTH,
1219*0Sstevel@tonic-gate 			    act->ipa_apply.ipp_replay_depth);
1220*0Sstevel@tonic-gate 		/* Add more here */
1221*0Sstevel@tonic-gate 		break;
1222*0Sstevel@tonic-gate 	}
1223*0Sstevel@tonic-gate 
1224*0Sstevel@tonic-gate 	return (offset);
1225*0Sstevel@tonic-gate }
1226*0Sstevel@tonic-gate 
1227*0Sstevel@tonic-gate static uint_t
1228*0Sstevel@tonic-gate spdsock_encode_action_list(uint8_t *base, uint_t offset,
1229*0Sstevel@tonic-gate     const ipsec_action_t *ap)
1230*0Sstevel@tonic-gate {
1231*0Sstevel@tonic-gate 	struct spd_ext_actions *act;
1232*0Sstevel@tonic-gate 	uint_t nact = 0;
1233*0Sstevel@tonic-gate 	uint_t start = offset;
1234*0Sstevel@tonic-gate 
1235*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1236*0Sstevel@tonic-gate 
1237*0Sstevel@tonic-gate 	if (base != NULL) {
1238*0Sstevel@tonic-gate 		act = (struct spd_ext_actions *)(base + offset);
1239*0Sstevel@tonic-gate 		act->spd_actions_len = 0;
1240*0Sstevel@tonic-gate 		act->spd_actions_exttype = SPD_EXT_ACTION;
1241*0Sstevel@tonic-gate 		act->spd_actions_count = 0;
1242*0Sstevel@tonic-gate 		act->spd_actions_reserved = 0;
1243*0Sstevel@tonic-gate 	}
1244*0Sstevel@tonic-gate 
1245*0Sstevel@tonic-gate 	offset += sizeof (*act);
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1248*0Sstevel@tonic-gate 
1249*0Sstevel@tonic-gate 	while (ap != NULL) {
1250*0Sstevel@tonic-gate 		offset = spdsock_encode_action(base, offset, ap);
1251*0Sstevel@tonic-gate 		ap = ap->ipa_next;
1252*0Sstevel@tonic-gate 		nact++;
1253*0Sstevel@tonic-gate 		if (ap != NULL) {
1254*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_NEXT, 0);
1255*0Sstevel@tonic-gate 		}
1256*0Sstevel@tonic-gate 	}
1257*0Sstevel@tonic-gate 	EMIT(SPD_ATTR_END, 0);
1258*0Sstevel@tonic-gate 
1259*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1260*0Sstevel@tonic-gate 
1261*0Sstevel@tonic-gate 	if (base != NULL) {
1262*0Sstevel@tonic-gate 		act->spd_actions_count = nact;
1263*0Sstevel@tonic-gate 		act->spd_actions_len = SPD_8TO64(offset - start);
1264*0Sstevel@tonic-gate 	}
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate 	return (offset);
1267*0Sstevel@tonic-gate }
1268*0Sstevel@tonic-gate 
1269*0Sstevel@tonic-gate #undef EMIT
1270*0Sstevel@tonic-gate 
1271*0Sstevel@tonic-gate /* ARGSUSED */
1272*0Sstevel@tonic-gate static uint_t
1273*0Sstevel@tonic-gate spdsock_rule_flags(uint_t dir, uint_t af)
1274*0Sstevel@tonic-gate {
1275*0Sstevel@tonic-gate 	uint_t flags = 0;
1276*0Sstevel@tonic-gate 
1277*0Sstevel@tonic-gate 	if (dir == IPSEC_TYPE_INBOUND)
1278*0Sstevel@tonic-gate 		flags |= SPD_RULE_FLAG_INBOUND;
1279*0Sstevel@tonic-gate 	if (dir == IPSEC_TYPE_OUTBOUND)
1280*0Sstevel@tonic-gate 		flags |= SPD_RULE_FLAG_OUTBOUND;
1281*0Sstevel@tonic-gate 
1282*0Sstevel@tonic-gate 	return (flags);
1283*0Sstevel@tonic-gate }
1284*0Sstevel@tonic-gate 
1285*0Sstevel@tonic-gate 
1286*0Sstevel@tonic-gate static uint_t
1287*0Sstevel@tonic-gate spdsock_encode_rule_head(uint8_t *base, uint_t offset,
1288*0Sstevel@tonic-gate     spd_msg_t *req, const ipsec_policy_t *rule, uint_t dir, uint_t af)
1289*0Sstevel@tonic-gate {
1290*0Sstevel@tonic-gate 	struct spd_msg *spmsg;
1291*0Sstevel@tonic-gate 	struct spd_rule *spr;
1292*0Sstevel@tonic-gate 
1293*0Sstevel@tonic-gate 	uint_t start = offset;
1294*0Sstevel@tonic-gate 
1295*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1296*0Sstevel@tonic-gate 
1297*0Sstevel@tonic-gate 	if (base != NULL) {
1298*0Sstevel@tonic-gate 		spmsg = (struct spd_msg *)(base + offset);
1299*0Sstevel@tonic-gate 		bzero(spmsg, sizeof (*spmsg));
1300*0Sstevel@tonic-gate 		spmsg->spd_msg_version = PF_POLICY_V1;
1301*0Sstevel@tonic-gate 		spmsg->spd_msg_type = SPD_DUMP;
1302*0Sstevel@tonic-gate 		spmsg->spd_msg_seq = req->spd_msg_seq;
1303*0Sstevel@tonic-gate 		spmsg->spd_msg_pid = req->spd_msg_pid;
1304*0Sstevel@tonic-gate 	}
1305*0Sstevel@tonic-gate 	offset += sizeof (struct spd_msg);
1306*0Sstevel@tonic-gate 
1307*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1308*0Sstevel@tonic-gate 
1309*0Sstevel@tonic-gate 	if (base != NULL) {
1310*0Sstevel@tonic-gate 		spr = (struct spd_rule *)(base + offset);
1311*0Sstevel@tonic-gate 		spr->spd_rule_type = SPD_EXT_RULE;
1312*0Sstevel@tonic-gate 		spr->spd_rule_priority = rule->ipsp_prio;
1313*0Sstevel@tonic-gate 		spr->spd_rule_flags = spdsock_rule_flags(dir, af);
1314*0Sstevel@tonic-gate 		spr->spd_rule_unused = 0;
1315*0Sstevel@tonic-gate 		spr->spd_rule_len = SPD_8TO64(sizeof (*spr));
1316*0Sstevel@tonic-gate 		spr->spd_rule_index = rule->ipsp_index;
1317*0Sstevel@tonic-gate 	}
1318*0Sstevel@tonic-gate 	offset += sizeof (struct spd_rule);
1319*0Sstevel@tonic-gate 	offset = spdsock_encode_sel(base, offset, rule->ipsp_sel);
1320*0Sstevel@tonic-gate 	offset = spdsock_encode_action_list(base, offset, rule->ipsp_act);
1321*0Sstevel@tonic-gate 
1322*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(offset));
1323*0Sstevel@tonic-gate 
1324*0Sstevel@tonic-gate 	if (base != NULL) {
1325*0Sstevel@tonic-gate 		spmsg->spd_msg_len = SPD_8TO64(offset - start);
1326*0Sstevel@tonic-gate 	}
1327*0Sstevel@tonic-gate 	return (offset);
1328*0Sstevel@tonic-gate }
1329*0Sstevel@tonic-gate 
1330*0Sstevel@tonic-gate /* ARGSUSED */
1331*0Sstevel@tonic-gate static mblk_t *
1332*0Sstevel@tonic-gate spdsock_encode_rule(mblk_t *req, const ipsec_policy_t *rule,
1333*0Sstevel@tonic-gate     uint_t dir, uint_t af)
1334*0Sstevel@tonic-gate {
1335*0Sstevel@tonic-gate 	mblk_t *m;
1336*0Sstevel@tonic-gate 	uint_t len;
1337*0Sstevel@tonic-gate 	spd_msg_t *mreq = (spd_msg_t *)req->b_rptr;
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 	/*
1340*0Sstevel@tonic-gate 	 * Figure out how much space we'll need.
1341*0Sstevel@tonic-gate 	 */
1342*0Sstevel@tonic-gate 	len = spdsock_encode_rule_head(NULL, 0, mreq, rule, dir, af);
1343*0Sstevel@tonic-gate 
1344*0Sstevel@tonic-gate 	/*
1345*0Sstevel@tonic-gate 	 * Allocate mblk.
1346*0Sstevel@tonic-gate 	 */
1347*0Sstevel@tonic-gate 	m = allocb(len, BPRI_HI);
1348*0Sstevel@tonic-gate 	if (m == NULL)
1349*0Sstevel@tonic-gate 		return (NULL);
1350*0Sstevel@tonic-gate 
1351*0Sstevel@tonic-gate 	/*
1352*0Sstevel@tonic-gate 	 * Fill it in..
1353*0Sstevel@tonic-gate 	 */
1354*0Sstevel@tonic-gate 	m->b_wptr = m->b_rptr + len;
1355*0Sstevel@tonic-gate 	bzero(m->b_rptr, len);
1356*0Sstevel@tonic-gate 	(void) spdsock_encode_rule_head(m->b_rptr, 0, mreq, rule, dir, af);
1357*0Sstevel@tonic-gate 	return (m);
1358*0Sstevel@tonic-gate }
1359*0Sstevel@tonic-gate 
1360*0Sstevel@tonic-gate static ipsec_policy_t *
1361*0Sstevel@tonic-gate spdsock_dump_next_rule(spdsock_t *ss, ipsec_policy_head_t *iph)
1362*0Sstevel@tonic-gate {
1363*0Sstevel@tonic-gate 	ipsec_policy_t *cur;
1364*0Sstevel@tonic-gate 
1365*0Sstevel@tonic-gate 	ASSERT(RW_READ_HELD(&iph->iph_lock));
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	cur = ss->spdsock_dump_cur_rule;
1368*0Sstevel@tonic-gate 
1369*0Sstevel@tonic-gate 	if (cur == NULL) {
1370*0Sstevel@tonic-gate 		int af = ss->spdsock_dump_cur_af;
1371*0Sstevel@tonic-gate 		int type = ss->spdsock_dump_cur_type;
1372*0Sstevel@tonic-gate 		do {
1373*0Sstevel@tonic-gate 			af++;
1374*0Sstevel@tonic-gate 			if (af >= IPSEC_NAF) {
1375*0Sstevel@tonic-gate 				af = IPSEC_AF_V4;
1376*0Sstevel@tonic-gate 				type++;
1377*0Sstevel@tonic-gate 				if (type >= IPSEC_NTYPES)
1378*0Sstevel@tonic-gate 					return (NULL);
1379*0Sstevel@tonic-gate 			}
1380*0Sstevel@tonic-gate 			cur = iph->iph_root[type].ipr[af];
1381*0Sstevel@tonic-gate 		} while (cur == NULL);
1382*0Sstevel@tonic-gate 		ss->spdsock_dump_cur_af = af;
1383*0Sstevel@tonic-gate 		ss->spdsock_dump_cur_type = type;
1384*0Sstevel@tonic-gate 	}
1385*0Sstevel@tonic-gate 	ss->spdsock_dump_count++;
1386*0Sstevel@tonic-gate 	ss->spdsock_dump_cur_rule = cur->ipsp_links.itl_next;
1387*0Sstevel@tonic-gate 	return (cur);
1388*0Sstevel@tonic-gate }
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate static mblk_t *
1391*0Sstevel@tonic-gate spdsock_dump_next_record(spdsock_t *ss)
1392*0Sstevel@tonic-gate {
1393*0Sstevel@tonic-gate 	ipsec_policy_head_t *iph;
1394*0Sstevel@tonic-gate 	ipsec_policy_t *rule;
1395*0Sstevel@tonic-gate 	mblk_t *m;
1396*0Sstevel@tonic-gate 	mblk_t *req = ss->spdsock_dump_req;
1397*0Sstevel@tonic-gate 
1398*0Sstevel@tonic-gate 	iph = ss->spdsock_dump_head;
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate 	ASSERT(iph != NULL);
1401*0Sstevel@tonic-gate 
1402*0Sstevel@tonic-gate 	rw_enter(&iph->iph_lock, RW_READER);
1403*0Sstevel@tonic-gate 
1404*0Sstevel@tonic-gate 	if (iph->iph_gen != ss->spdsock_dump_gen) {
1405*0Sstevel@tonic-gate 		rw_exit(&iph->iph_lock);
1406*0Sstevel@tonic-gate 		return (spdsock_dump_finish(ss, EAGAIN));
1407*0Sstevel@tonic-gate 	}
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 	rule = spdsock_dump_next_rule(ss, iph);
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 	if (!rule) {
1412*0Sstevel@tonic-gate 		rw_exit(&iph->iph_lock);
1413*0Sstevel@tonic-gate 		return (spdsock_dump_finish(ss, 0));
1414*0Sstevel@tonic-gate 	}
1415*0Sstevel@tonic-gate 
1416*0Sstevel@tonic-gate 	m = spdsock_encode_rule(req, rule, ss->spdsock_dump_cur_type,
1417*0Sstevel@tonic-gate 	    ss->spdsock_dump_cur_af);
1418*0Sstevel@tonic-gate 	rw_exit(&iph->iph_lock);
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 	if (m == NULL)
1421*0Sstevel@tonic-gate 		return (spdsock_dump_finish(ss, ENOMEM));
1422*0Sstevel@tonic-gate 	return (m);
1423*0Sstevel@tonic-gate }
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate /*
1426*0Sstevel@tonic-gate  * Dump records until we run into flow-control back-pressure.
1427*0Sstevel@tonic-gate  */
1428*0Sstevel@tonic-gate static void
1429*0Sstevel@tonic-gate spdsock_dump_some(queue_t *q, spdsock_t *ss)
1430*0Sstevel@tonic-gate {
1431*0Sstevel@tonic-gate 	mblk_t *m, *dataind;
1432*0Sstevel@tonic-gate 
1433*0Sstevel@tonic-gate 	while ((ss->spdsock_dump_req != NULL) && canputnext(q)) {
1434*0Sstevel@tonic-gate 		m = spdsock_dump_next_record(ss);
1435*0Sstevel@tonic-gate 		if (m == NULL)
1436*0Sstevel@tonic-gate 			return;
1437*0Sstevel@tonic-gate 		dataind = allocb(sizeof (struct T_data_req), BPRI_HI);
1438*0Sstevel@tonic-gate 		if (dataind == NULL) {
1439*0Sstevel@tonic-gate 			freemsg(m);
1440*0Sstevel@tonic-gate 			return;
1441*0Sstevel@tonic-gate 		}
1442*0Sstevel@tonic-gate 		dataind->b_cont = m;
1443*0Sstevel@tonic-gate 		dataind->b_wptr += sizeof (struct T_data_req);
1444*0Sstevel@tonic-gate 		((struct T_data_ind *)dataind->b_rptr)->PRIM_type = T_DATA_IND;
1445*0Sstevel@tonic-gate 		((struct T_data_ind *)dataind->b_rptr)->MORE_flag = 0;
1446*0Sstevel@tonic-gate 		dataind->b_datap->db_type = M_PROTO;
1447*0Sstevel@tonic-gate 		putnext(q, dataind);
1448*0Sstevel@tonic-gate 	}
1449*0Sstevel@tonic-gate }
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate /*
1452*0Sstevel@tonic-gate  * Start dumping.
1453*0Sstevel@tonic-gate  * Format a start-of-dump record, and set up the stream and kick the rsrv
1454*0Sstevel@tonic-gate  * procedure to continue the job..
1455*0Sstevel@tonic-gate  */
1456*0Sstevel@tonic-gate /* ARGSUSED */
1457*0Sstevel@tonic-gate static void
1458*0Sstevel@tonic-gate spdsock_dump(queue_t *q, ipsec_policy_head_t *iph,
1459*0Sstevel@tonic-gate     mblk_t *mp, spd_ext_t **extv)
1460*0Sstevel@tonic-gate {
1461*0Sstevel@tonic-gate 	spdsock_t *ss = (spdsock_t *)q->q_ptr;
1462*0Sstevel@tonic-gate 	mblk_t *mr;
1463*0Sstevel@tonic-gate 
1464*0Sstevel@tonic-gate 	rw_enter(&iph->iph_lock, RW_READER);
1465*0Sstevel@tonic-gate 
1466*0Sstevel@tonic-gate 	mr = spdsock_dump_ruleset(mp, iph, 0, 0);
1467*0Sstevel@tonic-gate 
1468*0Sstevel@tonic-gate 	if (!mr) {
1469*0Sstevel@tonic-gate 		rw_exit(&iph->iph_lock);
1470*0Sstevel@tonic-gate 		spdsock_error(q, mp, ENOMEM, 0);
1471*0Sstevel@tonic-gate 		return;
1472*0Sstevel@tonic-gate 	}
1473*0Sstevel@tonic-gate 
1474*0Sstevel@tonic-gate 	ss->spdsock_dump_req = mp;
1475*0Sstevel@tonic-gate 	ss->spdsock_dump_head = iph;
1476*0Sstevel@tonic-gate 	ss->spdsock_dump_gen = iph->iph_gen;
1477*0Sstevel@tonic-gate 	ss->spdsock_dump_cur_type = 0;
1478*0Sstevel@tonic-gate 	ss->spdsock_dump_cur_af = IPSEC_AF_V4;
1479*0Sstevel@tonic-gate 	ss->spdsock_dump_cur_rule = iph->iph_root[0].ipr[IPSEC_AF_V4];
1480*0Sstevel@tonic-gate 	ss->spdsock_dump_count = 0;
1481*0Sstevel@tonic-gate 
1482*0Sstevel@tonic-gate 	rw_exit(&iph->iph_lock);
1483*0Sstevel@tonic-gate 
1484*0Sstevel@tonic-gate 	qreply(q, mr);
1485*0Sstevel@tonic-gate 	qenable(OTHERQ(q));
1486*0Sstevel@tonic-gate }
1487*0Sstevel@tonic-gate 
1488*0Sstevel@tonic-gate void
1489*0Sstevel@tonic-gate spdsock_clone(queue_t *q, mblk_t *mp)
1490*0Sstevel@tonic-gate {
1491*0Sstevel@tonic-gate 	int error = ipsec_clone_system_policy();
1492*0Sstevel@tonic-gate 	if (error != 0)
1493*0Sstevel@tonic-gate 		spdsock_error(q, mp, error, 0);
1494*0Sstevel@tonic-gate 	else
1495*0Sstevel@tonic-gate 		spd_echo(q, mp);
1496*0Sstevel@tonic-gate }
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate /*
1499*0Sstevel@tonic-gate  * Process a SPD_ALGLIST request. The caller expects separate alg entries
1500*0Sstevel@tonic-gate  * for AH authentication, ESP authentication, and ESP encryption.
1501*0Sstevel@tonic-gate  * The same distinction is then used when setting the min and max key
1502*0Sstevel@tonic-gate  * sizes when defining policies.
1503*0Sstevel@tonic-gate  */
1504*0Sstevel@tonic-gate 
1505*0Sstevel@tonic-gate #define	SPDSOCK_AH_AUTH		0
1506*0Sstevel@tonic-gate #define	SPDSOCK_ESP_AUTH	1
1507*0Sstevel@tonic-gate #define	SPDSOCK_ESP_ENCR	2
1508*0Sstevel@tonic-gate #define	SPDSOCK_NTYPES		3
1509*0Sstevel@tonic-gate 
1510*0Sstevel@tonic-gate static const uint_t algattr[SPDSOCK_NTYPES] = {
1511*0Sstevel@tonic-gate 	SPD_ATTR_AH_AUTH,
1512*0Sstevel@tonic-gate 	SPD_ATTR_ESP_AUTH,
1513*0Sstevel@tonic-gate 	SPD_ATTR_ESP_ENCR
1514*0Sstevel@tonic-gate };
1515*0Sstevel@tonic-gate static const uint_t minbitsattr[SPDSOCK_NTYPES] = {
1516*0Sstevel@tonic-gate 	SPD_ATTR_AH_MINBITS,
1517*0Sstevel@tonic-gate 	SPD_ATTR_ESPA_MINBITS,
1518*0Sstevel@tonic-gate 	SPD_ATTR_ENCR_MINBITS
1519*0Sstevel@tonic-gate };
1520*0Sstevel@tonic-gate static const uint_t maxbitsattr[SPDSOCK_NTYPES] = {
1521*0Sstevel@tonic-gate 	SPD_ATTR_AH_MAXBITS,
1522*0Sstevel@tonic-gate 	SPD_ATTR_ESPA_MAXBITS,
1523*0Sstevel@tonic-gate 	SPD_ATTR_ENCR_MAXBITS
1524*0Sstevel@tonic-gate };
1525*0Sstevel@tonic-gate static const uint_t defbitsattr[SPDSOCK_NTYPES] = {
1526*0Sstevel@tonic-gate 	SPD_ATTR_AH_DEFBITS,
1527*0Sstevel@tonic-gate 	SPD_ATTR_ESPA_DEFBITS,
1528*0Sstevel@tonic-gate 	SPD_ATTR_ENCR_DEFBITS
1529*0Sstevel@tonic-gate };
1530*0Sstevel@tonic-gate static const uint_t incrbitsattr[SPDSOCK_NTYPES] = {
1531*0Sstevel@tonic-gate 	SPD_ATTR_AH_INCRBITS,
1532*0Sstevel@tonic-gate 	SPD_ATTR_ESPA_INCRBITS,
1533*0Sstevel@tonic-gate 	SPD_ATTR_ENCR_INCRBITS
1534*0Sstevel@tonic-gate };
1535*0Sstevel@tonic-gate 
1536*0Sstevel@tonic-gate #define	ATTRPERALG	6	/* fixed attributes per algs */
1537*0Sstevel@tonic-gate 
1538*0Sstevel@tonic-gate void
1539*0Sstevel@tonic-gate spdsock_alglist(queue_t *q, mblk_t *mp)
1540*0Sstevel@tonic-gate {
1541*0Sstevel@tonic-gate 	uint_t algtype;
1542*0Sstevel@tonic-gate 	uint_t algidx;
1543*0Sstevel@tonic-gate 	uint_t algcount;
1544*0Sstevel@tonic-gate 	uint_t size;
1545*0Sstevel@tonic-gate 	mblk_t *m;
1546*0Sstevel@tonic-gate 	uint8_t *cur;
1547*0Sstevel@tonic-gate 	spd_msg_t *msg;
1548*0Sstevel@tonic-gate 	struct spd_ext_actions *act;
1549*0Sstevel@tonic-gate 	struct spd_attribute *attr;
1550*0Sstevel@tonic-gate 
1551*0Sstevel@tonic-gate 	mutex_enter(&alg_lock);
1552*0Sstevel@tonic-gate 
1553*0Sstevel@tonic-gate 	/*
1554*0Sstevel@tonic-gate 	 * The SPD client expects to receive separate entries for
1555*0Sstevel@tonic-gate 	 * AH authentication and ESP authentication supported algorithms.
1556*0Sstevel@tonic-gate 	 *
1557*0Sstevel@tonic-gate 	 * Don't return the "any" algorithms, if defined, as no
1558*0Sstevel@tonic-gate 	 * kernel policies can be set for these algorithms.
1559*0Sstevel@tonic-gate 	 */
1560*0Sstevel@tonic-gate 	algcount = 2 * ipsec_nalgs[IPSEC_ALG_AUTH] +
1561*0Sstevel@tonic-gate 	    ipsec_nalgs[IPSEC_ALG_ENCR];
1562*0Sstevel@tonic-gate 
1563*0Sstevel@tonic-gate 	if (ipsec_alglists[IPSEC_ALG_AUTH][SADB_AALG_NONE] != NULL)
1564*0Sstevel@tonic-gate 		algcount--;
1565*0Sstevel@tonic-gate 	if (ipsec_alglists[IPSEC_ALG_ENCR][SADB_EALG_NONE] != NULL)
1566*0Sstevel@tonic-gate 		algcount--;
1567*0Sstevel@tonic-gate 
1568*0Sstevel@tonic-gate 	/*
1569*0Sstevel@tonic-gate 	 * For each algorithm, we encode:
1570*0Sstevel@tonic-gate 	 * ALG / MINBITS / MAXBITS / DEFBITS / INCRBITS / {END, NEXT}
1571*0Sstevel@tonic-gate 	 */
1572*0Sstevel@tonic-gate 
1573*0Sstevel@tonic-gate 	size = sizeof (spd_msg_t) + sizeof (struct spd_ext_actions) +
1574*0Sstevel@tonic-gate 	    ATTRPERALG * sizeof (struct spd_attribute) * algcount;
1575*0Sstevel@tonic-gate 
1576*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(size));
1577*0Sstevel@tonic-gate 
1578*0Sstevel@tonic-gate 	m = allocb(size, BPRI_HI);
1579*0Sstevel@tonic-gate 	if (m == NULL) {
1580*0Sstevel@tonic-gate 		mutex_exit(&alg_lock);
1581*0Sstevel@tonic-gate 		spdsock_error(q, mp, ENOMEM, 0);
1582*0Sstevel@tonic-gate 		return;
1583*0Sstevel@tonic-gate 	}
1584*0Sstevel@tonic-gate 
1585*0Sstevel@tonic-gate 	m->b_wptr = m->b_rptr + size;
1586*0Sstevel@tonic-gate 	cur = m->b_rptr;
1587*0Sstevel@tonic-gate 
1588*0Sstevel@tonic-gate 	msg = (spd_msg_t *)cur;
1589*0Sstevel@tonic-gate 	bcopy(mp->b_rptr, cur, sizeof (*msg));
1590*0Sstevel@tonic-gate 
1591*0Sstevel@tonic-gate 	msg->spd_msg_len = SPD_8TO64(size);
1592*0Sstevel@tonic-gate 	msg->spd_msg_errno = 0;
1593*0Sstevel@tonic-gate 	msg->spd_msg_diagnostic = 0;
1594*0Sstevel@tonic-gate 
1595*0Sstevel@tonic-gate 	cur += sizeof (*msg);
1596*0Sstevel@tonic-gate 
1597*0Sstevel@tonic-gate 	act = (struct spd_ext_actions *)cur;
1598*0Sstevel@tonic-gate 	cur += sizeof (*act);
1599*0Sstevel@tonic-gate 
1600*0Sstevel@tonic-gate 	act->spd_actions_len = SPD_8TO64(size - sizeof (spd_msg_t));
1601*0Sstevel@tonic-gate 	act->spd_actions_exttype = SPD_EXT_ACTION;
1602*0Sstevel@tonic-gate 	act->spd_actions_count = algcount;
1603*0Sstevel@tonic-gate 	act->spd_actions_reserved = 0;
1604*0Sstevel@tonic-gate 
1605*0Sstevel@tonic-gate 	attr = (struct spd_attribute *)cur;
1606*0Sstevel@tonic-gate 
1607*0Sstevel@tonic-gate #define	EMIT(tag, value) {					\
1608*0Sstevel@tonic-gate 		attr->spd_attr_tag = (tag); 			\
1609*0Sstevel@tonic-gate 		attr->spd_attr_value = (value); 		\
1610*0Sstevel@tonic-gate 		attr++;			  			\
1611*0Sstevel@tonic-gate 	}
1612*0Sstevel@tonic-gate 
1613*0Sstevel@tonic-gate 	/*
1614*0Sstevel@tonic-gate 	 * If you change the number of EMIT's here, change
1615*0Sstevel@tonic-gate 	 * ATTRPERALG above to match
1616*0Sstevel@tonic-gate 	 */
1617*0Sstevel@tonic-gate #define	EMITALGATTRS(_type) {					\
1618*0Sstevel@tonic-gate 		EMIT(algattr[_type], algid); 		/* 1 */	\
1619*0Sstevel@tonic-gate 		EMIT(minbitsattr[_type], minbits);	/* 2 */	\
1620*0Sstevel@tonic-gate 		EMIT(maxbitsattr[_type], maxbits);	/* 3 */	\
1621*0Sstevel@tonic-gate 		EMIT(defbitsattr[_type], defbits);	/* 4 */	\
1622*0Sstevel@tonic-gate 		EMIT(incrbitsattr[_type], incr);	/* 5 */	\
1623*0Sstevel@tonic-gate 		EMIT(SPD_ATTR_NEXT, 0);			/* 6 */	\
1624*0Sstevel@tonic-gate 	}
1625*0Sstevel@tonic-gate 
1626*0Sstevel@tonic-gate 	for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
1627*0Sstevel@tonic-gate 		for (algidx = 0; algidx < ipsec_nalgs[algtype]; algidx++) {
1628*0Sstevel@tonic-gate 			int algid = ipsec_sortlist[algtype][algidx];
1629*0Sstevel@tonic-gate 			ipsec_alginfo_t *alg = ipsec_alglists[algtype][algid];
1630*0Sstevel@tonic-gate 			uint_t minbits = alg->alg_minbits;
1631*0Sstevel@tonic-gate 			uint_t maxbits = alg->alg_maxbits;
1632*0Sstevel@tonic-gate 			uint_t defbits = alg->alg_default_bits;
1633*0Sstevel@tonic-gate 			uint_t incr = alg->alg_increment;
1634*0Sstevel@tonic-gate 
1635*0Sstevel@tonic-gate 			if (algtype == IPSEC_ALG_AUTH) {
1636*0Sstevel@tonic-gate 				if (algid == SADB_AALG_NONE)
1637*0Sstevel@tonic-gate 					continue;
1638*0Sstevel@tonic-gate 				EMITALGATTRS(SPDSOCK_AH_AUTH);
1639*0Sstevel@tonic-gate 				EMITALGATTRS(SPDSOCK_ESP_AUTH);
1640*0Sstevel@tonic-gate 			} else {
1641*0Sstevel@tonic-gate 				if (algid == SADB_EALG_NONE)
1642*0Sstevel@tonic-gate 					continue;
1643*0Sstevel@tonic-gate 				ASSERT(algtype == IPSEC_ALG_ENCR);
1644*0Sstevel@tonic-gate 				EMITALGATTRS(SPDSOCK_ESP_ENCR);
1645*0Sstevel@tonic-gate 			}
1646*0Sstevel@tonic-gate 		}
1647*0Sstevel@tonic-gate 	}
1648*0Sstevel@tonic-gate 
1649*0Sstevel@tonic-gate 	mutex_exit(&alg_lock);
1650*0Sstevel@tonic-gate 
1651*0Sstevel@tonic-gate #undef EMITALGATTRS
1652*0Sstevel@tonic-gate #undef EMIT
1653*0Sstevel@tonic-gate #undef ATTRPERALG
1654*0Sstevel@tonic-gate 
1655*0Sstevel@tonic-gate 	attr--;
1656*0Sstevel@tonic-gate 	attr->spd_attr_tag = SPD_ATTR_END;
1657*0Sstevel@tonic-gate 
1658*0Sstevel@tonic-gate 	freemsg(mp);
1659*0Sstevel@tonic-gate 	qreply(q, m);
1660*0Sstevel@tonic-gate }
1661*0Sstevel@tonic-gate 
1662*0Sstevel@tonic-gate /*
1663*0Sstevel@tonic-gate  * Process a SPD_DUMPALGS request.
1664*0Sstevel@tonic-gate  */
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate #define	ATTRPERALG	7	/* fixed attributes per algs */
1667*0Sstevel@tonic-gate 
1668*0Sstevel@tonic-gate void
1669*0Sstevel@tonic-gate spdsock_dumpalgs(queue_t *q, mblk_t *mp)
1670*0Sstevel@tonic-gate {
1671*0Sstevel@tonic-gate 	uint_t algtype;
1672*0Sstevel@tonic-gate 	uint_t algidx;
1673*0Sstevel@tonic-gate 	uint_t size;
1674*0Sstevel@tonic-gate 	mblk_t *m;
1675*0Sstevel@tonic-gate 	uint8_t *cur;
1676*0Sstevel@tonic-gate 	spd_msg_t *msg;
1677*0Sstevel@tonic-gate 	struct spd_ext_actions *act;
1678*0Sstevel@tonic-gate 	struct spd_attribute *attr;
1679*0Sstevel@tonic-gate 	ipsec_alginfo_t *alg;
1680*0Sstevel@tonic-gate 	uint_t algid;
1681*0Sstevel@tonic-gate 	uint_t i;
1682*0Sstevel@tonic-gate 	uint_t alg_size;
1683*0Sstevel@tonic-gate 
1684*0Sstevel@tonic-gate 	mutex_enter(&alg_lock);
1685*0Sstevel@tonic-gate 
1686*0Sstevel@tonic-gate 	/*
1687*0Sstevel@tonic-gate 	 * For each algorithm, we encode:
1688*0Sstevel@tonic-gate 	 * ALG / MINBITS / MAXBITS / DEFBITS / INCRBITS / {END, NEXT}
1689*0Sstevel@tonic-gate 	 *
1690*0Sstevel@tonic-gate 	 * ALG_ID / ALG_PROTO / ALG_INCRBITS / ALG_NKEYSIZES / ALG_KEYSIZE*
1691*0Sstevel@tonic-gate 	 * ALG_NBLOCKSIZES / ALG_BLOCKSIZE* / ALG_MECHNAME / {END, NEXT}
1692*0Sstevel@tonic-gate 	 */
1693*0Sstevel@tonic-gate 
1694*0Sstevel@tonic-gate 	/*
1695*0Sstevel@tonic-gate 	 * Compute the size of the SPD message.
1696*0Sstevel@tonic-gate 	 */
1697*0Sstevel@tonic-gate 	size = sizeof (spd_msg_t) + sizeof (struct spd_ext_actions);
1698*0Sstevel@tonic-gate 
1699*0Sstevel@tonic-gate 	for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
1700*0Sstevel@tonic-gate 		for (algidx = 0; algidx < ipsec_nalgs[algtype]; algidx++) {
1701*0Sstevel@tonic-gate 			algid = ipsec_sortlist[algtype][algidx];
1702*0Sstevel@tonic-gate 			alg = ipsec_alglists[algtype][algid];
1703*0Sstevel@tonic-gate 			alg_size = sizeof (struct spd_attribute) *
1704*0Sstevel@tonic-gate 			    (ATTRPERALG + alg->alg_nkey_sizes +
1705*0Sstevel@tonic-gate 			    alg->alg_nblock_sizes) + CRYPTO_MAX_MECH_NAME;
1706*0Sstevel@tonic-gate 			size += alg_size;
1707*0Sstevel@tonic-gate 		}
1708*0Sstevel@tonic-gate 	}
1709*0Sstevel@tonic-gate 
1710*0Sstevel@tonic-gate 	ASSERT(ALIGNED64(size));
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate 	m = allocb(size, BPRI_HI);
1713*0Sstevel@tonic-gate 	if (m == NULL) {
1714*0Sstevel@tonic-gate 		mutex_exit(&alg_lock);
1715*0Sstevel@tonic-gate 		spdsock_error(q, mp, ENOMEM, 0);
1716*0Sstevel@tonic-gate 		return;
1717*0Sstevel@tonic-gate 	}
1718*0Sstevel@tonic-gate 
1719*0Sstevel@tonic-gate 	m->b_wptr = m->b_rptr + size;
1720*0Sstevel@tonic-gate 	cur = m->b_rptr;
1721*0Sstevel@tonic-gate 
1722*0Sstevel@tonic-gate 	msg = (spd_msg_t *)cur;
1723*0Sstevel@tonic-gate 	bcopy(mp->b_rptr, cur, sizeof (*msg));
1724*0Sstevel@tonic-gate 
1725*0Sstevel@tonic-gate 	msg->spd_msg_len = SPD_8TO64(size);
1726*0Sstevel@tonic-gate 	msg->spd_msg_errno = 0;
1727*0Sstevel@tonic-gate 	msg->spd_msg_diagnostic = 0;
1728*0Sstevel@tonic-gate 
1729*0Sstevel@tonic-gate 	cur += sizeof (*msg);
1730*0Sstevel@tonic-gate 
1731*0Sstevel@tonic-gate 	act = (struct spd_ext_actions *)cur;
1732*0Sstevel@tonic-gate 	cur += sizeof (*act);
1733*0Sstevel@tonic-gate 
1734*0Sstevel@tonic-gate 	act->spd_actions_len = SPD_8TO64(size - sizeof (spd_msg_t));
1735*0Sstevel@tonic-gate 	act->spd_actions_exttype = SPD_EXT_ACTION;
1736*0Sstevel@tonic-gate 	act->spd_actions_count = ipsec_nalgs[IPSEC_ALG_AUTH] +
1737*0Sstevel@tonic-gate 	    ipsec_nalgs[IPSEC_ALG_ENCR];
1738*0Sstevel@tonic-gate 	act->spd_actions_reserved = 0;
1739*0Sstevel@tonic-gate 
1740*0Sstevel@tonic-gate 	attr = (struct spd_attribute *)cur;
1741*0Sstevel@tonic-gate 
1742*0Sstevel@tonic-gate #define	EMIT(tag, value) {					\
1743*0Sstevel@tonic-gate 		attr->spd_attr_tag = (tag); 			\
1744*0Sstevel@tonic-gate 		attr->spd_attr_value = (value); 		\
1745*0Sstevel@tonic-gate 		attr++;			  			\
1746*0Sstevel@tonic-gate 	}
1747*0Sstevel@tonic-gate 
1748*0Sstevel@tonic-gate 	for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
1749*0Sstevel@tonic-gate 		for (algidx = 0; algidx < ipsec_nalgs[algtype]; algidx++) {
1750*0Sstevel@tonic-gate 
1751*0Sstevel@tonic-gate 			algid = ipsec_sortlist[algtype][algidx];
1752*0Sstevel@tonic-gate 			alg = ipsec_alglists[algtype][algid];
1753*0Sstevel@tonic-gate 
1754*0Sstevel@tonic-gate 			/*
1755*0Sstevel@tonic-gate 			 * If you change the number of EMIT's here, change
1756*0Sstevel@tonic-gate 			 * ATTRPERALG above to match
1757*0Sstevel@tonic-gate 			 */
1758*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_ALG_ID, algid);
1759*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_ALG_PROTO, algproto[algtype]);
1760*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_ALG_INCRBITS, alg->alg_increment);
1761*0Sstevel@tonic-gate 
1762*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_ALG_NKEYSIZES, alg->alg_nkey_sizes);
1763*0Sstevel@tonic-gate 			for (i = 0; i < alg->alg_nkey_sizes; i++)
1764*0Sstevel@tonic-gate 				EMIT(SPD_ATTR_ALG_KEYSIZE,
1765*0Sstevel@tonic-gate 				    alg->alg_key_sizes[i]);
1766*0Sstevel@tonic-gate 
1767*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_ALG_NBLOCKSIZES, alg->alg_nblock_sizes);
1768*0Sstevel@tonic-gate 			for (i = 0; i < alg->alg_nblock_sizes; i++)
1769*0Sstevel@tonic-gate 				EMIT(SPD_ATTR_ALG_BLOCKSIZE,
1770*0Sstevel@tonic-gate 				    alg->alg_block_sizes[i]);
1771*0Sstevel@tonic-gate 
1772*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_ALG_MECHNAME, CRYPTO_MAX_MECH_NAME);
1773*0Sstevel@tonic-gate 			bcopy(alg->alg_mech_name, attr, CRYPTO_MAX_MECH_NAME);
1774*0Sstevel@tonic-gate 			attr = (struct spd_attribute *)((char *)attr +
1775*0Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
1776*0Sstevel@tonic-gate 
1777*0Sstevel@tonic-gate 			EMIT(SPD_ATTR_NEXT, 0);
1778*0Sstevel@tonic-gate 		}
1779*0Sstevel@tonic-gate 	}
1780*0Sstevel@tonic-gate 
1781*0Sstevel@tonic-gate 	mutex_exit(&alg_lock);
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate #undef EMITALGATTRS
1784*0Sstevel@tonic-gate #undef EMIT
1785*0Sstevel@tonic-gate #undef ATTRPERALG
1786*0Sstevel@tonic-gate 
1787*0Sstevel@tonic-gate 	attr--;
1788*0Sstevel@tonic-gate 	attr->spd_attr_tag = SPD_ATTR_END;
1789*0Sstevel@tonic-gate 
1790*0Sstevel@tonic-gate 	freemsg(mp);
1791*0Sstevel@tonic-gate 	qreply(q, m);
1792*0Sstevel@tonic-gate }
1793*0Sstevel@tonic-gate 
1794*0Sstevel@tonic-gate /*
1795*0Sstevel@tonic-gate  * Do the actual work of processing an SPD_UPDATEALGS request. Can
1796*0Sstevel@tonic-gate  * be invoked either once IPsec is loaded on a cached request, or
1797*0Sstevel@tonic-gate  * when a request is received while IPsec is loaded.
1798*0Sstevel@tonic-gate  */
1799*0Sstevel@tonic-gate static void
1800*0Sstevel@tonic-gate spdsock_do_updatealg(spd_ext_t *extv[], int *diag)
1801*0Sstevel@tonic-gate {
1802*0Sstevel@tonic-gate 	struct spd_ext_actions *actp;
1803*0Sstevel@tonic-gate 	struct spd_attribute *attr, *endattr;
1804*0Sstevel@tonic-gate 	uint64_t *start, *end;
1805*0Sstevel@tonic-gate 	ipsec_alginfo_t *alg = NULL;
1806*0Sstevel@tonic-gate 	ipsec_algtype_t alg_type = 0;
1807*0Sstevel@tonic-gate 	boolean_t skip_alg = B_TRUE, doing_proto = B_FALSE;
1808*0Sstevel@tonic-gate 	uint_t i, cur_key, cur_block, algid;
1809*0Sstevel@tonic-gate 
1810*0Sstevel@tonic-gate 	*diag = -1;
1811*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&spdsock_alg_lock));
1812*0Sstevel@tonic-gate 
1813*0Sstevel@tonic-gate 	/* parse the message, building the list of algorithms */
1814*0Sstevel@tonic-gate 
1815*0Sstevel@tonic-gate 	actp = (struct spd_ext_actions *)extv[SPD_EXT_ACTION];
1816*0Sstevel@tonic-gate 	if (actp == NULL) {
1817*0Sstevel@tonic-gate 		*diag = SPD_DIAGNOSTIC_NO_ACTION_EXT;
1818*0Sstevel@tonic-gate 		return;
1819*0Sstevel@tonic-gate 	}
1820*0Sstevel@tonic-gate 
1821*0Sstevel@tonic-gate 	start = (uint64_t *)actp;
1822*0Sstevel@tonic-gate 	end = (start + actp->spd_actions_len);
1823*0Sstevel@tonic-gate 	endattr = (struct spd_attribute *)end;
1824*0Sstevel@tonic-gate 	attr = (struct spd_attribute *)&actp[1];
1825*0Sstevel@tonic-gate 
1826*0Sstevel@tonic-gate 	bzero(spdsock_algs, IPSEC_NALGTYPES * IPSEC_MAX_ALGS *
1827*0Sstevel@tonic-gate 	    sizeof (ipsec_alginfo_t *));
1828*0Sstevel@tonic-gate 
1829*0Sstevel@tonic-gate 	alg = kmem_zalloc(sizeof (*alg), KM_SLEEP);
1830*0Sstevel@tonic-gate 
1831*0Sstevel@tonic-gate #define	ALG_KEY_SIZES(a)   (((a)->alg_nkey_sizes + 1) * sizeof (uint16_t))
1832*0Sstevel@tonic-gate #define	ALG_BLOCK_SIZES(a) (((a)->alg_nblock_sizes + 1) * sizeof (uint16_t))
1833*0Sstevel@tonic-gate 
1834*0Sstevel@tonic-gate 	while (attr < endattr) {
1835*0Sstevel@tonic-gate 		switch (attr->spd_attr_tag) {
1836*0Sstevel@tonic-gate 		case SPD_ATTR_NOP:
1837*0Sstevel@tonic-gate 		case SPD_ATTR_EMPTY:
1838*0Sstevel@tonic-gate 			break;
1839*0Sstevel@tonic-gate 		case SPD_ATTR_END:
1840*0Sstevel@tonic-gate 			attr = endattr;
1841*0Sstevel@tonic-gate 			/* FALLTHRU */
1842*0Sstevel@tonic-gate 		case SPD_ATTR_NEXT:
1843*0Sstevel@tonic-gate 			if (doing_proto) {
1844*0Sstevel@tonic-gate 				doing_proto = B_FALSE;
1845*0Sstevel@tonic-gate 				break;
1846*0Sstevel@tonic-gate 			}
1847*0Sstevel@tonic-gate 			if (skip_alg) {
1848*0Sstevel@tonic-gate 				ipsec_alg_free(alg);
1849*0Sstevel@tonic-gate 			} else {
1850*0Sstevel@tonic-gate 				ipsec_alg_free(
1851*0Sstevel@tonic-gate 				    spdsock_algs[alg_type][alg->alg_id]);
1852*0Sstevel@tonic-gate 				spdsock_algs[alg_type][alg->alg_id] = alg;
1853*0Sstevel@tonic-gate 			}
1854*0Sstevel@tonic-gate 			alg = kmem_zalloc(sizeof (*alg), KM_SLEEP);
1855*0Sstevel@tonic-gate 			break;
1856*0Sstevel@tonic-gate 
1857*0Sstevel@tonic-gate 		case SPD_ATTR_ALG_ID:
1858*0Sstevel@tonic-gate 			if (attr->spd_attr_value >= IPSEC_MAX_ALGS) {
1859*0Sstevel@tonic-gate 				ss1dbg(("spdsock_do_updatealg: "
1860*0Sstevel@tonic-gate 				    "invalid alg id %d\n",
1861*0Sstevel@tonic-gate 				    attr->spd_attr_value));
1862*0Sstevel@tonic-gate 				*diag = SPD_DIAGNOSTIC_ALG_ID_RANGE;
1863*0Sstevel@tonic-gate 				goto bail;
1864*0Sstevel@tonic-gate 			}
1865*0Sstevel@tonic-gate 			alg->alg_id = attr->spd_attr_value;
1866*0Sstevel@tonic-gate 			break;
1867*0Sstevel@tonic-gate 
1868*0Sstevel@tonic-gate 		case SPD_ATTR_ALG_PROTO:
1869*0Sstevel@tonic-gate 			/* find the alg type */
1870*0Sstevel@tonic-gate 			for (i = 0; i < NALGPROTOS; i++)
1871*0Sstevel@tonic-gate 				if (algproto[i] == attr->spd_attr_value)
1872*0Sstevel@tonic-gate 					break;
1873*0Sstevel@tonic-gate 			skip_alg = (i == NALGPROTOS);
1874*0Sstevel@tonic-gate 			if (!skip_alg)
1875*0Sstevel@tonic-gate 				alg_type = i;
1876*0Sstevel@tonic-gate 			break;
1877*0Sstevel@tonic-gate 
1878*0Sstevel@tonic-gate 		case SPD_ATTR_ALG_INCRBITS:
1879*0Sstevel@tonic-gate 			alg->alg_increment = attr->spd_attr_value;
1880*0Sstevel@tonic-gate 			break;
1881*0Sstevel@tonic-gate 
1882*0Sstevel@tonic-gate 		case SPD_ATTR_ALG_NKEYSIZES:
1883*0Sstevel@tonic-gate 			if (alg->alg_key_sizes != NULL) {
1884*0Sstevel@tonic-gate 				kmem_free(alg->alg_key_sizes,
1885*0Sstevel@tonic-gate 				    ALG_KEY_SIZES(alg));
1886*0Sstevel@tonic-gate 			}
1887*0Sstevel@tonic-gate 			alg->alg_nkey_sizes = attr->spd_attr_value;
1888*0Sstevel@tonic-gate 			/*
1889*0Sstevel@tonic-gate 			 * Allocate room for the trailing zero key size
1890*0Sstevel@tonic-gate 			 * value as well.
1891*0Sstevel@tonic-gate 			 */
1892*0Sstevel@tonic-gate 			alg->alg_key_sizes = kmem_zalloc(ALG_KEY_SIZES(alg),
1893*0Sstevel@tonic-gate 			    KM_SLEEP);
1894*0Sstevel@tonic-gate 			cur_key = 0;
1895*0Sstevel@tonic-gate 			break;
1896*0Sstevel@tonic-gate 
1897*0Sstevel@tonic-gate 		case SPD_ATTR_ALG_KEYSIZE:
1898*0Sstevel@tonic-gate 			if (alg->alg_key_sizes == NULL ||
1899*0Sstevel@tonic-gate 			    cur_key >= alg->alg_nkey_sizes) {
1900*0Sstevel@tonic-gate 				ss1dbg(("spdsock_do_updatealg: "
1901*0Sstevel@tonic-gate 					"too many key sizes\n"));
1902*0Sstevel@tonic-gate 				*diag = SPD_DIAGNOSTIC_ALG_NUM_KEY_SIZES;
1903*0Sstevel@tonic-gate 				goto bail;
1904*0Sstevel@tonic-gate 			}
1905*0Sstevel@tonic-gate 			alg->alg_key_sizes[cur_key++] = attr->spd_attr_value;
1906*0Sstevel@tonic-gate 			break;
1907*0Sstevel@tonic-gate 
1908*0Sstevel@tonic-gate 		case SPD_ATTR_ALG_NBLOCKSIZES:
1909*0Sstevel@tonic-gate 			if (alg->alg_block_sizes != NULL) {
1910*0Sstevel@tonic-gate 				kmem_free(alg->alg_block_sizes,
1911*0Sstevel@tonic-gate 				    ALG_BLOCK_SIZES(alg));
1912*0Sstevel@tonic-gate 			}
1913*0Sstevel@tonic-gate 			alg->alg_nblock_sizes = attr->spd_attr_value;
1914*0Sstevel@tonic-gate 			/*
1915*0Sstevel@tonic-gate 			 * Allocate room for the trailing zero block size
1916*0Sstevel@tonic-gate 			 * value as well.
1917*0Sstevel@tonic-gate 			 */
1918*0Sstevel@tonic-gate 			alg->alg_block_sizes = kmem_zalloc(ALG_BLOCK_SIZES(alg),
1919*0Sstevel@tonic-gate 			    KM_SLEEP);
1920*0Sstevel@tonic-gate 			cur_block = 0;
1921*0Sstevel@tonic-gate 			break;
1922*0Sstevel@tonic-gate 
1923*0Sstevel@tonic-gate 		case SPD_ATTR_ALG_BLOCKSIZE:
1924*0Sstevel@tonic-gate 			if (alg->alg_block_sizes == NULL ||
1925*0Sstevel@tonic-gate 			    cur_block >= alg->alg_nblock_sizes) {
1926*0Sstevel@tonic-gate 				ss1dbg(("spdsock_do_updatealg: "
1927*0Sstevel@tonic-gate 					"too many block sizes\n"));
1928*0Sstevel@tonic-gate 				*diag = SPD_DIAGNOSTIC_ALG_NUM_BLOCK_SIZES;
1929*0Sstevel@tonic-gate 				goto bail;
1930*0Sstevel@tonic-gate 			}
1931*0Sstevel@tonic-gate 			alg->alg_block_sizes[cur_block++] =
1932*0Sstevel@tonic-gate 			    attr->spd_attr_value;
1933*0Sstevel@tonic-gate 			break;
1934*0Sstevel@tonic-gate 
1935*0Sstevel@tonic-gate 		case SPD_ATTR_ALG_MECHNAME: {
1936*0Sstevel@tonic-gate 			char *mech_name;
1937*0Sstevel@tonic-gate 
1938*0Sstevel@tonic-gate 			if (attr->spd_attr_value > CRYPTO_MAX_MECH_NAME) {
1939*0Sstevel@tonic-gate 				ss1dbg(("spdsock_do_updatealg: "
1940*0Sstevel@tonic-gate 					"mech name too long\n"));
1941*0Sstevel@tonic-gate 				*diag = SPD_DIAGNOSTIC_ALG_MECH_NAME_LEN;
1942*0Sstevel@tonic-gate 				goto bail;
1943*0Sstevel@tonic-gate 			}
1944*0Sstevel@tonic-gate 			mech_name = (char *)(attr + 1);
1945*0Sstevel@tonic-gate 			bcopy(mech_name, alg->alg_mech_name,
1946*0Sstevel@tonic-gate 			    attr->spd_attr_value);
1947*0Sstevel@tonic-gate 			alg->alg_mech_name[CRYPTO_MAX_MECH_NAME-1] = '\0';
1948*0Sstevel@tonic-gate 			attr = (struct spd_attribute *)((char *)attr +
1949*0Sstevel@tonic-gate 			    attr->spd_attr_value);
1950*0Sstevel@tonic-gate 			break;
1951*0Sstevel@tonic-gate 		}
1952*0Sstevel@tonic-gate 
1953*0Sstevel@tonic-gate 		case SPD_ATTR_PROTO_ID:
1954*0Sstevel@tonic-gate 			doing_proto = B_TRUE;
1955*0Sstevel@tonic-gate 			for (i = 0; i < NALGPROTOS; i++) {
1956*0Sstevel@tonic-gate 				if (algproto[i] == attr->spd_attr_value) {
1957*0Sstevel@tonic-gate 					alg_type = i;
1958*0Sstevel@tonic-gate 					break;
1959*0Sstevel@tonic-gate 				}
1960*0Sstevel@tonic-gate 			}
1961*0Sstevel@tonic-gate 			break;
1962*0Sstevel@tonic-gate 
1963*0Sstevel@tonic-gate 		case SPD_ATTR_PROTO_EXEC_MODE:
1964*0Sstevel@tonic-gate 			if (!doing_proto)
1965*0Sstevel@tonic-gate 				break;
1966*0Sstevel@tonic-gate 			for (i = 0; i < NEXECMODES; i++) {
1967*0Sstevel@tonic-gate 				if (execmodes[i] == attr->spd_attr_value) {
1968*0Sstevel@tonic-gate 					spdsock_algs_exec_mode[alg_type] = i;
1969*0Sstevel@tonic-gate 					break;
1970*0Sstevel@tonic-gate 				}
1971*0Sstevel@tonic-gate 			}
1972*0Sstevel@tonic-gate 			break;
1973*0Sstevel@tonic-gate 		}
1974*0Sstevel@tonic-gate 		attr++;
1975*0Sstevel@tonic-gate 	}
1976*0Sstevel@tonic-gate 
1977*0Sstevel@tonic-gate #undef	ALG_KEY_SIZES
1978*0Sstevel@tonic-gate #undef	ALG_BLOCK_SIZES
1979*0Sstevel@tonic-gate 
1980*0Sstevel@tonic-gate 	/* update the algorithm tables */
1981*0Sstevel@tonic-gate 	spdsock_merge_algs();
1982*0Sstevel@tonic-gate bail:
1983*0Sstevel@tonic-gate 	/* cleanup */
1984*0Sstevel@tonic-gate 	ipsec_alg_free(alg);
1985*0Sstevel@tonic-gate 	for (alg_type = 0; alg_type < IPSEC_NALGTYPES; alg_type++)
1986*0Sstevel@tonic-gate 		for (algid = 0; algid < IPSEC_MAX_ALGS; algid++)
1987*0Sstevel@tonic-gate 			if (spdsock_algs[alg_type][algid] != NULL)
1988*0Sstevel@tonic-gate 				ipsec_alg_free(spdsock_algs[alg_type][algid]);
1989*0Sstevel@tonic-gate }
1990*0Sstevel@tonic-gate 
1991*0Sstevel@tonic-gate /*
1992*0Sstevel@tonic-gate  * Process an SPD_UPDATEALGS request. If IPsec is not loaded, queue
1993*0Sstevel@tonic-gate  * the request until IPsec loads. If IPsec is loaded, act on it
1994*0Sstevel@tonic-gate  * immediately.
1995*0Sstevel@tonic-gate  */
1996*0Sstevel@tonic-gate 
1997*0Sstevel@tonic-gate static void
1998*0Sstevel@tonic-gate spdsock_updatealg(queue_t *q, mblk_t *mp, spd_ext_t *extv[])
1999*0Sstevel@tonic-gate {
2000*0Sstevel@tonic-gate 	if (!ipsec_loaded()) {
2001*0Sstevel@tonic-gate 		/*
2002*0Sstevel@tonic-gate 		 * IPsec is not loaded, save request and return nicely,
2003*0Sstevel@tonic-gate 		 * the message will be processed once IPsec loads.
2004*0Sstevel@tonic-gate 		 */
2005*0Sstevel@tonic-gate 		mblk_t *new_mp;
2006*0Sstevel@tonic-gate 
2007*0Sstevel@tonic-gate 		/* last update message wins */
2008*0Sstevel@tonic-gate 		if ((new_mp = copymsg(mp)) == NULL) {
2009*0Sstevel@tonic-gate 			spdsock_error(q, mp, ENOMEM, 0);
2010*0Sstevel@tonic-gate 			return;
2011*0Sstevel@tonic-gate 		}
2012*0Sstevel@tonic-gate 		mutex_enter(&spdsock_alg_lock);
2013*0Sstevel@tonic-gate 		bcopy(extv, spdsock_extv_algs,
2014*0Sstevel@tonic-gate 		    sizeof (spd_ext_t *) * (SPD_EXT_MAX + 1));
2015*0Sstevel@tonic-gate 		if (spdsock_mp_algs != NULL)
2016*0Sstevel@tonic-gate 			freemsg(spdsock_mp_algs);
2017*0Sstevel@tonic-gate 		spdsock_mp_algs = mp;
2018*0Sstevel@tonic-gate 		spdsock_algs_pending = B_TRUE;
2019*0Sstevel@tonic-gate 		mutex_exit(&spdsock_alg_lock);
2020*0Sstevel@tonic-gate 
2021*0Sstevel@tonic-gate 		spd_echo(q, new_mp);
2022*0Sstevel@tonic-gate 	} else {
2023*0Sstevel@tonic-gate 		/*
2024*0Sstevel@tonic-gate 		 * IPsec is loaded, act on the message immediately.
2025*0Sstevel@tonic-gate 		 */
2026*0Sstevel@tonic-gate 		int diag;
2027*0Sstevel@tonic-gate 
2028*0Sstevel@tonic-gate 		mutex_enter(&spdsock_alg_lock);
2029*0Sstevel@tonic-gate 		spdsock_do_updatealg(extv, &diag);
2030*0Sstevel@tonic-gate 		mutex_exit(&spdsock_alg_lock);
2031*0Sstevel@tonic-gate 		if (diag == -1)
2032*0Sstevel@tonic-gate 			spd_echo(q, mp);
2033*0Sstevel@tonic-gate 		else
2034*0Sstevel@tonic-gate 			spdsock_diag(q, mp, diag);
2035*0Sstevel@tonic-gate 	}
2036*0Sstevel@tonic-gate }
2037*0Sstevel@tonic-gate 
2038*0Sstevel@tonic-gate static void
2039*0Sstevel@tonic-gate spdsock_parse(queue_t *q, mblk_t *mp)
2040*0Sstevel@tonic-gate {
2041*0Sstevel@tonic-gate 	spd_msg_t *spmsg;
2042*0Sstevel@tonic-gate 	spd_ext_t *extv[SPD_EXT_MAX + 1];
2043*0Sstevel@tonic-gate 	uint_t msgsize;
2044*0Sstevel@tonic-gate 	ipsec_policy_head_t *iph;
2045*0Sstevel@tonic-gate 
2046*0Sstevel@tonic-gate 	/* Make sure nothing's below me. */
2047*0Sstevel@tonic-gate 	ASSERT(WR(q)->q_next == NULL);
2048*0Sstevel@tonic-gate 
2049*0Sstevel@tonic-gate 	spmsg = (spd_msg_t *)mp->b_rptr;
2050*0Sstevel@tonic-gate 
2051*0Sstevel@tonic-gate 	msgsize = SPD_64TO8(spmsg->spd_msg_len);
2052*0Sstevel@tonic-gate 
2053*0Sstevel@tonic-gate 	if (msgdsize(mp) != msgsize) {
2054*0Sstevel@tonic-gate 		/*
2055*0Sstevel@tonic-gate 		 * Message len incorrect w.r.t. actual size.  Send an error
2056*0Sstevel@tonic-gate 		 * (EMSGSIZE).	It may be necessary to massage things a
2057*0Sstevel@tonic-gate 		 * bit.	 For example, if the spd_msg_type is hosed,
2058*0Sstevel@tonic-gate 		 * I need to set it to SPD_RESERVED to get delivery to
2059*0Sstevel@tonic-gate 		 * do the right thing.	Then again, maybe just letting
2060*0Sstevel@tonic-gate 		 * the error delivery do the right thing.
2061*0Sstevel@tonic-gate 		 */
2062*0Sstevel@tonic-gate 		ss2dbg(("mblk (%lu) and base (%d) message sizes don't jibe.\n",
2063*0Sstevel@tonic-gate 		    msgdsize(mp), msgsize));
2064*0Sstevel@tonic-gate 		spdsock_error(q, mp, EMSGSIZE, SPD_DIAGNOSTIC_NONE);
2065*0Sstevel@tonic-gate 		return;
2066*0Sstevel@tonic-gate 	}
2067*0Sstevel@tonic-gate 
2068*0Sstevel@tonic-gate 	if (msgsize > (uint_t)(mp->b_wptr - mp->b_rptr)) {
2069*0Sstevel@tonic-gate 
2070*0Sstevel@tonic-gate 		/* Get all message into one mblk. */
2071*0Sstevel@tonic-gate 		if (pullupmsg(mp, -1) == 0) {
2072*0Sstevel@tonic-gate 			/*
2073*0Sstevel@tonic-gate 			 * Something screwy happened.
2074*0Sstevel@tonic-gate 			 */
2075*0Sstevel@tonic-gate 			ss3dbg(("spdsock_parse: pullupmsg() failed.\n"));
2076*0Sstevel@tonic-gate 			return;
2077*0Sstevel@tonic-gate 		} else {
2078*0Sstevel@tonic-gate 			spmsg = (spd_msg_t *)mp->b_rptr;
2079*0Sstevel@tonic-gate 		}
2080*0Sstevel@tonic-gate 	}
2081*0Sstevel@tonic-gate 
2082*0Sstevel@tonic-gate 	switch (spdsock_get_ext(extv, spmsg, msgsize)) {
2083*0Sstevel@tonic-gate 	case KGE_DUP:
2084*0Sstevel@tonic-gate 		/* Handle duplicate extension. */
2085*0Sstevel@tonic-gate 		ss1dbg(("Got duplicate extension of type %d.\n",
2086*0Sstevel@tonic-gate 		    extv[0]->spd_ext_type));
2087*0Sstevel@tonic-gate 		spdsock_diag(q, mp, dup_ext_diag[extv[0]->spd_ext_type]);
2088*0Sstevel@tonic-gate 		return;
2089*0Sstevel@tonic-gate 	case KGE_UNK:
2090*0Sstevel@tonic-gate 		/* Handle unknown extension. */
2091*0Sstevel@tonic-gate 		ss1dbg(("Got unknown extension of type %d.\n",
2092*0Sstevel@tonic-gate 		    extv[0]->spd_ext_type));
2093*0Sstevel@tonic-gate 		spdsock_diag(q, mp, SPD_DIAGNOSTIC_UNKNOWN_EXT);
2094*0Sstevel@tonic-gate 		return;
2095*0Sstevel@tonic-gate 	case KGE_LEN:
2096*0Sstevel@tonic-gate 		/* Length error. */
2097*0Sstevel@tonic-gate 		ss1dbg(("Length %d on extension type %d overrun or 0.\n",
2098*0Sstevel@tonic-gate 		    extv[0]->spd_ext_len, extv[0]->spd_ext_type));
2099*0Sstevel@tonic-gate 		spdsock_diag(q, mp, SPD_DIAGNOSTIC_BAD_EXTLEN);
2100*0Sstevel@tonic-gate 		return;
2101*0Sstevel@tonic-gate 	case KGE_CHK:
2102*0Sstevel@tonic-gate 		/* Reality check failed. */
2103*0Sstevel@tonic-gate 		ss1dbg(("Reality check failed on extension type %d.\n",
2104*0Sstevel@tonic-gate 		    extv[0]->spd_ext_type));
2105*0Sstevel@tonic-gate 		spdsock_diag(q, mp, bad_ext_diag[extv[0]->spd_ext_type]);
2106*0Sstevel@tonic-gate 		return;
2107*0Sstevel@tonic-gate 	default:
2108*0Sstevel@tonic-gate 		/* Default case is no errors. */
2109*0Sstevel@tonic-gate 		break;
2110*0Sstevel@tonic-gate 	}
2111*0Sstevel@tonic-gate 
2112*0Sstevel@tonic-gate 	/*
2113*0Sstevel@tonic-gate 	 * Which rule set are we operating on today?
2114*0Sstevel@tonic-gate 	 */
2115*0Sstevel@tonic-gate 
2116*0Sstevel@tonic-gate 	switch (spmsg->spd_msg_spdid) {
2117*0Sstevel@tonic-gate 	case SPD_ACTIVE:
2118*0Sstevel@tonic-gate 		iph = ipsec_system_policy();
2119*0Sstevel@tonic-gate 		break;
2120*0Sstevel@tonic-gate 
2121*0Sstevel@tonic-gate 	case SPD_STANDBY:
2122*0Sstevel@tonic-gate 		iph = ipsec_inactive_policy();
2123*0Sstevel@tonic-gate 		break;
2124*0Sstevel@tonic-gate 
2125*0Sstevel@tonic-gate 	default:
2126*0Sstevel@tonic-gate 		spdsock_diag(q, mp, SPD_DIAGNOSTIC_BAD_SPDID);
2127*0Sstevel@tonic-gate 		return;
2128*0Sstevel@tonic-gate 	}
2129*0Sstevel@tonic-gate 
2130*0Sstevel@tonic-gate 	/*
2131*0Sstevel@tonic-gate 	 * Special-case SPD_UPDATEALGS so as not to load IPsec.
2132*0Sstevel@tonic-gate 	 */
2133*0Sstevel@tonic-gate 	if (!ipsec_loaded() && spmsg->spd_msg_type != SPD_UPDATEALGS) {
2134*0Sstevel@tonic-gate 		spdsock_t *ss = (spdsock_t *)q->q_ptr;
2135*0Sstevel@tonic-gate 
2136*0Sstevel@tonic-gate 		ASSERT(ss != NULL);
2137*0Sstevel@tonic-gate 		ipsec_loader_loadnow();
2138*0Sstevel@tonic-gate 		ss->spdsock_timeout_arg = mp;
2139*0Sstevel@tonic-gate 		ss->spdsock_timeout = qtimeout(q, spdsock_loadcheck,
2140*0Sstevel@tonic-gate 		    q, LOADCHECK_INTERVAL);
2141*0Sstevel@tonic-gate 		return;
2142*0Sstevel@tonic-gate 	}
2143*0Sstevel@tonic-gate 
2144*0Sstevel@tonic-gate 	switch (spmsg->spd_msg_type) {
2145*0Sstevel@tonic-gate 	case SPD_UPDATEALGS:
2146*0Sstevel@tonic-gate 		spdsock_updatealg(q, mp, extv);
2147*0Sstevel@tonic-gate 		return;
2148*0Sstevel@tonic-gate 	case SPD_FLUSH:
2149*0Sstevel@tonic-gate 		spdsock_flush(q, iph, mp, extv);
2150*0Sstevel@tonic-gate 		return;
2151*0Sstevel@tonic-gate 
2152*0Sstevel@tonic-gate 	case SPD_ADDRULE:
2153*0Sstevel@tonic-gate 		spdsock_addrule(q, iph, mp, extv);
2154*0Sstevel@tonic-gate 		return;
2155*0Sstevel@tonic-gate 
2156*0Sstevel@tonic-gate 	case SPD_DELETERULE:
2157*0Sstevel@tonic-gate 		spdsock_deleterule(q, iph, mp, extv);
2158*0Sstevel@tonic-gate 		return;
2159*0Sstevel@tonic-gate 
2160*0Sstevel@tonic-gate 	case SPD_FLIP:
2161*0Sstevel@tonic-gate 		spdsock_flip(q, mp);
2162*0Sstevel@tonic-gate 		return;
2163*0Sstevel@tonic-gate 
2164*0Sstevel@tonic-gate 	case SPD_LOOKUP:
2165*0Sstevel@tonic-gate 		spdsock_lookup(q, iph, mp, extv);
2166*0Sstevel@tonic-gate 		return;
2167*0Sstevel@tonic-gate 
2168*0Sstevel@tonic-gate 	case SPD_DUMP:
2169*0Sstevel@tonic-gate 		spdsock_dump(q, iph, mp, extv);
2170*0Sstevel@tonic-gate 		return;
2171*0Sstevel@tonic-gate 
2172*0Sstevel@tonic-gate 	case SPD_CLONE:
2173*0Sstevel@tonic-gate 		spdsock_clone(q, mp);
2174*0Sstevel@tonic-gate 		return;
2175*0Sstevel@tonic-gate 
2176*0Sstevel@tonic-gate 	case SPD_ALGLIST:
2177*0Sstevel@tonic-gate 		spdsock_alglist(q, mp);
2178*0Sstevel@tonic-gate 		return;
2179*0Sstevel@tonic-gate 
2180*0Sstevel@tonic-gate 	case SPD_DUMPALGS:
2181*0Sstevel@tonic-gate 		spdsock_dumpalgs(q, mp);
2182*0Sstevel@tonic-gate 		return;
2183*0Sstevel@tonic-gate 
2184*0Sstevel@tonic-gate 	default:
2185*0Sstevel@tonic-gate 		spdsock_diag(q, mp, SPD_DIAGNOSTIC_BAD_MSG_TYPE);
2186*0Sstevel@tonic-gate 		return;
2187*0Sstevel@tonic-gate 	}
2188*0Sstevel@tonic-gate }
2189*0Sstevel@tonic-gate 
2190*0Sstevel@tonic-gate /*
2191*0Sstevel@tonic-gate  * If an algorithm mapping was received before IPsec was loaded, process it.
2192*0Sstevel@tonic-gate  * Called from the IPsec loader.
2193*0Sstevel@tonic-gate  */
2194*0Sstevel@tonic-gate void
2195*0Sstevel@tonic-gate spdsock_update_pending_algs(void)
2196*0Sstevel@tonic-gate {
2197*0Sstevel@tonic-gate 	mutex_enter(&spdsock_alg_lock);
2198*0Sstevel@tonic-gate 	if (spdsock_algs_pending) {
2199*0Sstevel@tonic-gate 		int diag;
2200*0Sstevel@tonic-gate 		spdsock_do_updatealg(spdsock_extv_algs, &diag);
2201*0Sstevel@tonic-gate 		spdsock_algs_pending = B_FALSE;
2202*0Sstevel@tonic-gate 	}
2203*0Sstevel@tonic-gate 	mutex_exit(&spdsock_alg_lock);
2204*0Sstevel@tonic-gate }
2205*0Sstevel@tonic-gate 
2206*0Sstevel@tonic-gate static void
2207*0Sstevel@tonic-gate spdsock_loadcheck(void *arg)
2208*0Sstevel@tonic-gate {
2209*0Sstevel@tonic-gate 	queue_t *q = (queue_t *)arg;
2210*0Sstevel@tonic-gate 	spdsock_t *ss = (spdsock_t *)q->q_ptr;
2211*0Sstevel@tonic-gate 	mblk_t *mp;
2212*0Sstevel@tonic-gate 
2213*0Sstevel@tonic-gate 	ASSERT(ss != NULL);
2214*0Sstevel@tonic-gate 
2215*0Sstevel@tonic-gate 	ss->spdsock_timeout = 0;
2216*0Sstevel@tonic-gate 	mp = ss->spdsock_timeout_arg;
2217*0Sstevel@tonic-gate 	ASSERT(mp != NULL);
2218*0Sstevel@tonic-gate 	ss->spdsock_timeout_arg = NULL;
2219*0Sstevel@tonic-gate 	if (ipsec_failed())
2220*0Sstevel@tonic-gate 		spdsock_error(q, mp, EPROTONOSUPPORT, 0);
2221*0Sstevel@tonic-gate 	else
2222*0Sstevel@tonic-gate 		spdsock_parse(q, mp);
2223*0Sstevel@tonic-gate }
2224*0Sstevel@tonic-gate 
2225*0Sstevel@tonic-gate /*
2226*0Sstevel@tonic-gate  * Copy relevant state bits.
2227*0Sstevel@tonic-gate  */
2228*0Sstevel@tonic-gate static void
2229*0Sstevel@tonic-gate spdsock_copy_info(struct T_info_ack *tap, spdsock_t *ss)
2230*0Sstevel@tonic-gate {
2231*0Sstevel@tonic-gate 	*tap = spdsock_g_t_info_ack;
2232*0Sstevel@tonic-gate 	tap->CURRENT_state = ss->spdsock_state;
2233*0Sstevel@tonic-gate 	tap->OPT_size = spdsock_max_optsize;
2234*0Sstevel@tonic-gate }
2235*0Sstevel@tonic-gate 
2236*0Sstevel@tonic-gate /*
2237*0Sstevel@tonic-gate  * This routine responds to T_CAPABILITY_REQ messages.  It is called by
2238*0Sstevel@tonic-gate  * spdsock_wput.  Much of the T_CAPABILITY_ACK information is copied from
2239*0Sstevel@tonic-gate  * spdsock_g_t_info_ack.  The current state of the stream is copied from
2240*0Sstevel@tonic-gate  * spdsock_state.
2241*0Sstevel@tonic-gate  */
2242*0Sstevel@tonic-gate static void
2243*0Sstevel@tonic-gate spdsock_capability_req(queue_t *q, mblk_t *mp)
2244*0Sstevel@tonic-gate {
2245*0Sstevel@tonic-gate 	spdsock_t *ss = (spdsock_t *)q->q_ptr;
2246*0Sstevel@tonic-gate 	t_uscalar_t cap_bits1;
2247*0Sstevel@tonic-gate 	struct T_capability_ack	*tcap;
2248*0Sstevel@tonic-gate 
2249*0Sstevel@tonic-gate 	cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1;
2250*0Sstevel@tonic-gate 
2251*0Sstevel@tonic-gate 	mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack),
2252*0Sstevel@tonic-gate 		mp->b_datap->db_type, T_CAPABILITY_ACK);
2253*0Sstevel@tonic-gate 	if (mp == NULL)
2254*0Sstevel@tonic-gate 		return;
2255*0Sstevel@tonic-gate 
2256*0Sstevel@tonic-gate 	tcap = (struct T_capability_ack *)mp->b_rptr;
2257*0Sstevel@tonic-gate 	tcap->CAP_bits1 = 0;
2258*0Sstevel@tonic-gate 
2259*0Sstevel@tonic-gate 	if (cap_bits1 & TC1_INFO) {
2260*0Sstevel@tonic-gate 		spdsock_copy_info(&tcap->INFO_ack, ss);
2261*0Sstevel@tonic-gate 		tcap->CAP_bits1 |= TC1_INFO;
2262*0Sstevel@tonic-gate 	}
2263*0Sstevel@tonic-gate 
2264*0Sstevel@tonic-gate 	qreply(q, mp);
2265*0Sstevel@tonic-gate }
2266*0Sstevel@tonic-gate 
2267*0Sstevel@tonic-gate /*
2268*0Sstevel@tonic-gate  * This routine responds to T_INFO_REQ messages. It is called by
2269*0Sstevel@tonic-gate  * spdsock_wput_other.
2270*0Sstevel@tonic-gate  * Most of the T_INFO_ACK information is copied from spdsock_g_t_info_ack.
2271*0Sstevel@tonic-gate  * The current state of the stream is copied from spdsock_state.
2272*0Sstevel@tonic-gate  */
2273*0Sstevel@tonic-gate static void
2274*0Sstevel@tonic-gate spdsock_info_req(q, mp)
2275*0Sstevel@tonic-gate 	queue_t	*q;
2276*0Sstevel@tonic-gate 	mblk_t	*mp;
2277*0Sstevel@tonic-gate {
2278*0Sstevel@tonic-gate 	mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO,
2279*0Sstevel@tonic-gate 	    T_INFO_ACK);
2280*0Sstevel@tonic-gate 	if (mp == NULL)
2281*0Sstevel@tonic-gate 		return;
2282*0Sstevel@tonic-gate 	spdsock_copy_info((struct T_info_ack *)mp->b_rptr,
2283*0Sstevel@tonic-gate 	    (spdsock_t *)q->q_ptr);
2284*0Sstevel@tonic-gate 	qreply(q, mp);
2285*0Sstevel@tonic-gate }
2286*0Sstevel@tonic-gate 
2287*0Sstevel@tonic-gate /*
2288*0Sstevel@tonic-gate  * spdsock_err_ack. This routine creates a
2289*0Sstevel@tonic-gate  * T_ERROR_ACK message and passes it
2290*0Sstevel@tonic-gate  * upstream.
2291*0Sstevel@tonic-gate  */
2292*0Sstevel@tonic-gate static void
2293*0Sstevel@tonic-gate spdsock_err_ack(q, mp, t_error, sys_error)
2294*0Sstevel@tonic-gate 	queue_t	*q;
2295*0Sstevel@tonic-gate 	mblk_t	*mp;
2296*0Sstevel@tonic-gate 	int	t_error;
2297*0Sstevel@tonic-gate 	int	sys_error;
2298*0Sstevel@tonic-gate {
2299*0Sstevel@tonic-gate 	if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL)
2300*0Sstevel@tonic-gate 		qreply(q, mp);
2301*0Sstevel@tonic-gate }
2302*0Sstevel@tonic-gate 
2303*0Sstevel@tonic-gate /*
2304*0Sstevel@tonic-gate  * This routine retrieves the current status of socket options.
2305*0Sstevel@tonic-gate  * It returns the size of the option retrieved.
2306*0Sstevel@tonic-gate  */
2307*0Sstevel@tonic-gate /* ARGSUSED */
2308*0Sstevel@tonic-gate int
2309*0Sstevel@tonic-gate spdsock_opt_get(queue_t *q, int level, int name, uchar_t *ptr)
2310*0Sstevel@tonic-gate {
2311*0Sstevel@tonic-gate 	int *i1 = (int *)ptr;
2312*0Sstevel@tonic-gate 
2313*0Sstevel@tonic-gate 	switch (level) {
2314*0Sstevel@tonic-gate 	case SOL_SOCKET:
2315*0Sstevel@tonic-gate 		switch (name) {
2316*0Sstevel@tonic-gate 		case SO_TYPE:
2317*0Sstevel@tonic-gate 			*i1 = SOCK_RAW;
2318*0Sstevel@tonic-gate 			break;
2319*0Sstevel@tonic-gate 		/*
2320*0Sstevel@tonic-gate 		 * The following two items can be manipulated,
2321*0Sstevel@tonic-gate 		 * but changing them should do nothing.
2322*0Sstevel@tonic-gate 		 */
2323*0Sstevel@tonic-gate 		case SO_SNDBUF:
2324*0Sstevel@tonic-gate 			*i1 = (int)q->q_hiwat;
2325*0Sstevel@tonic-gate 			break;
2326*0Sstevel@tonic-gate 		case SO_RCVBUF:
2327*0Sstevel@tonic-gate 			*i1 = (int)(RD(q)->q_hiwat);
2328*0Sstevel@tonic-gate 			break;
2329*0Sstevel@tonic-gate 		}
2330*0Sstevel@tonic-gate 		break;
2331*0Sstevel@tonic-gate 	default:
2332*0Sstevel@tonic-gate 		return (0);
2333*0Sstevel@tonic-gate 	}
2334*0Sstevel@tonic-gate 	return (sizeof (int));
2335*0Sstevel@tonic-gate }
2336*0Sstevel@tonic-gate 
2337*0Sstevel@tonic-gate /*
2338*0Sstevel@tonic-gate  * This routine sets socket options.
2339*0Sstevel@tonic-gate  */
2340*0Sstevel@tonic-gate /* ARGSUSED */
2341*0Sstevel@tonic-gate int
2342*0Sstevel@tonic-gate spdsock_opt_set(queue_t *q, uint_t mgmt_flags, int level, int name,
2343*0Sstevel@tonic-gate     uint_t inlen, uchar_t *invalp, uint_t *outlenp, uchar_t *outvalp,
2344*0Sstevel@tonic-gate     void *thisdg_attrs, cred_t *cr, mblk_t *mblk)
2345*0Sstevel@tonic-gate {
2346*0Sstevel@tonic-gate 	int *i1 = (int *)invalp;
2347*0Sstevel@tonic-gate 
2348*0Sstevel@tonic-gate 	switch (level) {
2349*0Sstevel@tonic-gate 	case SOL_SOCKET:
2350*0Sstevel@tonic-gate 		switch (name) {
2351*0Sstevel@tonic-gate 		case SO_SNDBUF:
2352*0Sstevel@tonic-gate 			if (*i1 > spdsock_max_buf)
2353*0Sstevel@tonic-gate 				return (ENOBUFS);
2354*0Sstevel@tonic-gate 			q->q_hiwat = *i1;
2355*0Sstevel@tonic-gate 			break;
2356*0Sstevel@tonic-gate 		case SO_RCVBUF:
2357*0Sstevel@tonic-gate 			if (*i1 > spdsock_max_buf)
2358*0Sstevel@tonic-gate 				return (ENOBUFS);
2359*0Sstevel@tonic-gate 			RD(q)->q_hiwat = *i1;
2360*0Sstevel@tonic-gate 			(void) mi_set_sth_hiwat(RD(q), *i1);
2361*0Sstevel@tonic-gate 			break;
2362*0Sstevel@tonic-gate 		}
2363*0Sstevel@tonic-gate 		break;
2364*0Sstevel@tonic-gate 	}
2365*0Sstevel@tonic-gate 	return (0);
2366*0Sstevel@tonic-gate }
2367*0Sstevel@tonic-gate 
2368*0Sstevel@tonic-gate 
2369*0Sstevel@tonic-gate /*
2370*0Sstevel@tonic-gate  * Handle STREAMS messages.
2371*0Sstevel@tonic-gate  */
2372*0Sstevel@tonic-gate static void
2373*0Sstevel@tonic-gate spdsock_wput_other(queue_t *q, mblk_t *mp)
2374*0Sstevel@tonic-gate {
2375*0Sstevel@tonic-gate 	struct iocblk *iocp;
2376*0Sstevel@tonic-gate 	int error;
2377*0Sstevel@tonic-gate 
2378*0Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
2379*0Sstevel@tonic-gate 	case M_PROTO:
2380*0Sstevel@tonic-gate 	case M_PCPROTO:
2381*0Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) < sizeof (long)) {
2382*0Sstevel@tonic-gate 			ss3dbg((
2383*0Sstevel@tonic-gate 			    "spdsock_wput_other: Not big enough M_PROTO\n"));
2384*0Sstevel@tonic-gate 			freemsg(mp);
2385*0Sstevel@tonic-gate 			return;
2386*0Sstevel@tonic-gate 		}
2387*0Sstevel@tonic-gate 		switch (((union T_primitives *)mp->b_rptr)->type) {
2388*0Sstevel@tonic-gate 		case T_CAPABILITY_REQ:
2389*0Sstevel@tonic-gate 			spdsock_capability_req(q, mp);
2390*0Sstevel@tonic-gate 			return;
2391*0Sstevel@tonic-gate 		case T_INFO_REQ:
2392*0Sstevel@tonic-gate 			spdsock_info_req(q, mp);
2393*0Sstevel@tonic-gate 			return;
2394*0Sstevel@tonic-gate 		case T_SVR4_OPTMGMT_REQ:
2395*0Sstevel@tonic-gate 			(void) svr4_optcom_req(q, mp, DB_CREDDEF(mp, kcred),
2396*0Sstevel@tonic-gate 			    &spdsock_opt_obj);
2397*0Sstevel@tonic-gate 			return;
2398*0Sstevel@tonic-gate 		case T_OPTMGMT_REQ:
2399*0Sstevel@tonic-gate 			(void) tpi_optcom_req(q, mp, DB_CREDDEF(mp, kcred),
2400*0Sstevel@tonic-gate 			    &spdsock_opt_obj);
2401*0Sstevel@tonic-gate 			return;
2402*0Sstevel@tonic-gate 		case T_DATA_REQ:
2403*0Sstevel@tonic-gate 		case T_EXDATA_REQ:
2404*0Sstevel@tonic-gate 		case T_ORDREL_REQ:
2405*0Sstevel@tonic-gate 			/* Illegal for spdsock. */
2406*0Sstevel@tonic-gate 			freemsg(mp);
2407*0Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_ERROR, EPROTO);
2408*0Sstevel@tonic-gate 			return;
2409*0Sstevel@tonic-gate 		default:
2410*0Sstevel@tonic-gate 			/* Not supported by spdsock. */
2411*0Sstevel@tonic-gate 			spdsock_err_ack(q, mp, TNOTSUPPORT, 0);
2412*0Sstevel@tonic-gate 			return;
2413*0Sstevel@tonic-gate 		}
2414*0Sstevel@tonic-gate 	case M_IOCTL:
2415*0Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
2416*0Sstevel@tonic-gate 		error = EINVAL;
2417*0Sstevel@tonic-gate 
2418*0Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
2419*0Sstevel@tonic-gate 		case ND_SET:
2420*0Sstevel@tonic-gate 		case ND_GET:
2421*0Sstevel@tonic-gate 			if (nd_getset(q, spdsock_g_nd, mp)) {
2422*0Sstevel@tonic-gate 				qreply(q, mp);
2423*0Sstevel@tonic-gate 				return;
2424*0Sstevel@tonic-gate 			} else
2425*0Sstevel@tonic-gate 				error = ENOENT;
2426*0Sstevel@tonic-gate 			/* FALLTHRU */
2427*0Sstevel@tonic-gate 		default:
2428*0Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
2429*0Sstevel@tonic-gate 			return;
2430*0Sstevel@tonic-gate 		}
2431*0Sstevel@tonic-gate 	case M_FLUSH:
2432*0Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW) {
2433*0Sstevel@tonic-gate 			flushq(q, FLUSHALL);
2434*0Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
2435*0Sstevel@tonic-gate 		}
2436*0Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
2437*0Sstevel@tonic-gate 			qreply(q, mp);
2438*0Sstevel@tonic-gate 			return;
2439*0Sstevel@tonic-gate 		}
2440*0Sstevel@tonic-gate 		/* Else FALLTHRU */
2441*0Sstevel@tonic-gate 	}
2442*0Sstevel@tonic-gate 
2443*0Sstevel@tonic-gate 	/* If fell through, just black-hole the message. */
2444*0Sstevel@tonic-gate 	freemsg(mp);
2445*0Sstevel@tonic-gate }
2446*0Sstevel@tonic-gate 
2447*0Sstevel@tonic-gate static void
2448*0Sstevel@tonic-gate spdsock_wput(queue_t *q, mblk_t *mp)
2449*0Sstevel@tonic-gate {
2450*0Sstevel@tonic-gate 	uint8_t *rptr = mp->b_rptr;
2451*0Sstevel@tonic-gate 	mblk_t *mp1;
2452*0Sstevel@tonic-gate 	spdsock_t *ss = (spdsock_t *)q->q_ptr;
2453*0Sstevel@tonic-gate 
2454*0Sstevel@tonic-gate 	/*
2455*0Sstevel@tonic-gate 	 * If we're dumping, defer processing other messages until the
2456*0Sstevel@tonic-gate 	 * dump completes.
2457*0Sstevel@tonic-gate 	 */
2458*0Sstevel@tonic-gate 	if (ss->spdsock_dump_req != NULL) {
2459*0Sstevel@tonic-gate 		if (!putq(q, mp))
2460*0Sstevel@tonic-gate 			freemsg(mp);
2461*0Sstevel@tonic-gate 		return;
2462*0Sstevel@tonic-gate 	}
2463*0Sstevel@tonic-gate 
2464*0Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
2465*0Sstevel@tonic-gate 	case M_DATA:
2466*0Sstevel@tonic-gate 		/*
2467*0Sstevel@tonic-gate 		 * Silently discard.
2468*0Sstevel@tonic-gate 		 */
2469*0Sstevel@tonic-gate 		ss2dbg(("raw M_DATA in spdsock.\n"));
2470*0Sstevel@tonic-gate 		freemsg(mp);
2471*0Sstevel@tonic-gate 		return;
2472*0Sstevel@tonic-gate 	case M_PROTO:
2473*0Sstevel@tonic-gate 	case M_PCPROTO:
2474*0Sstevel@tonic-gate 		if ((mp->b_wptr - rptr) >= sizeof (struct T_data_req)) {
2475*0Sstevel@tonic-gate 			if (((union T_primitives *)rptr)->type == T_DATA_REQ) {
2476*0Sstevel@tonic-gate 				if ((mp1 = mp->b_cont) == NULL) {
2477*0Sstevel@tonic-gate 					/* No data after T_DATA_REQ. */
2478*0Sstevel@tonic-gate 					ss2dbg(("No data after DATA_REQ.\n"));
2479*0Sstevel@tonic-gate 					freemsg(mp);
2480*0Sstevel@tonic-gate 					return;
2481*0Sstevel@tonic-gate 				}
2482*0Sstevel@tonic-gate 				freeb(mp);
2483*0Sstevel@tonic-gate 				mp = mp1;
2484*0Sstevel@tonic-gate 				ss2dbg(("T_DATA_REQ\n"));
2485*0Sstevel@tonic-gate 				break;	/* Out of switch. */
2486*0Sstevel@tonic-gate 			}
2487*0Sstevel@tonic-gate 		}
2488*0Sstevel@tonic-gate 		/* FALLTHRU */
2489*0Sstevel@tonic-gate 	default:
2490*0Sstevel@tonic-gate 		ss3dbg(("In default wput case (%d %d).\n",
2491*0Sstevel@tonic-gate 		    mp->b_datap->db_type, ((union T_primitives *)rptr)->type));
2492*0Sstevel@tonic-gate 		spdsock_wput_other(q, mp);
2493*0Sstevel@tonic-gate 		return;
2494*0Sstevel@tonic-gate 	}
2495*0Sstevel@tonic-gate 
2496*0Sstevel@tonic-gate 	/* I now have a PF_POLICY message in an M_DATA block. */
2497*0Sstevel@tonic-gate 	spdsock_parse(q, mp);
2498*0Sstevel@tonic-gate }
2499*0Sstevel@tonic-gate 
2500*0Sstevel@tonic-gate /*
2501*0Sstevel@tonic-gate  * Device open procedure, called when new queue pair created.
2502*0Sstevel@tonic-gate  * We are passed the read-side queue.
2503*0Sstevel@tonic-gate  */
2504*0Sstevel@tonic-gate /* ARGSUSED */
2505*0Sstevel@tonic-gate static int
2506*0Sstevel@tonic-gate spdsock_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
2507*0Sstevel@tonic-gate {
2508*0Sstevel@tonic-gate 	spdsock_t *ss;
2509*0Sstevel@tonic-gate 	queue_t *oq = OTHERQ(q);
2510*0Sstevel@tonic-gate 	minor_t ssminor;
2511*0Sstevel@tonic-gate 
2512*0Sstevel@tonic-gate 	if (secpolicy_net_config(credp, B_FALSE) != 0)
2513*0Sstevel@tonic-gate 		return (EPERM);
2514*0Sstevel@tonic-gate 
2515*0Sstevel@tonic-gate 	if (q->q_ptr != NULL)
2516*0Sstevel@tonic-gate 		return (0);  /* Re-open of an already open instance. */
2517*0Sstevel@tonic-gate 
2518*0Sstevel@tonic-gate 	if (sflag & MODOPEN)
2519*0Sstevel@tonic-gate 		return (EINVAL);
2520*0Sstevel@tonic-gate 
2521*0Sstevel@tonic-gate 	ss2dbg(("Made it into PF_POLICY socket open.\n"));
2522*0Sstevel@tonic-gate 
2523*0Sstevel@tonic-gate 	ssminor = (minor_t)(uintptr_t)vmem_alloc(spdsock_vmem, 1, VM_NOSLEEP);
2524*0Sstevel@tonic-gate 	if (ssminor == 0)
2525*0Sstevel@tonic-gate 		return (ENOMEM);
2526*0Sstevel@tonic-gate 
2527*0Sstevel@tonic-gate 	ss = kmem_zalloc(sizeof (spdsock_t), KM_NOSLEEP);
2528*0Sstevel@tonic-gate 	if (ss == NULL) {
2529*0Sstevel@tonic-gate 		vmem_free(spdsock_vmem, (void *)(uintptr_t)ssminor, 1);
2530*0Sstevel@tonic-gate 		return (ENOMEM);
2531*0Sstevel@tonic-gate 	}
2532*0Sstevel@tonic-gate 
2533*0Sstevel@tonic-gate 	ss->spdsock_minor = ssminor;
2534*0Sstevel@tonic-gate 	ss->spdsock_state = TS_UNBND;
2535*0Sstevel@tonic-gate 	ss->spdsock_dump_req = NULL;
2536*0Sstevel@tonic-gate 
2537*0Sstevel@tonic-gate 	q->q_ptr = ss;
2538*0Sstevel@tonic-gate 	oq->q_ptr = ss;
2539*0Sstevel@tonic-gate 
2540*0Sstevel@tonic-gate 	q->q_hiwat = spdsock_recv_hiwat;
2541*0Sstevel@tonic-gate 
2542*0Sstevel@tonic-gate 	oq->q_hiwat = spdsock_xmit_hiwat;
2543*0Sstevel@tonic-gate 	oq->q_lowat = spdsock_xmit_lowat;
2544*0Sstevel@tonic-gate 
2545*0Sstevel@tonic-gate 	qprocson(q);
2546*0Sstevel@tonic-gate 	(void) mi_set_sth_hiwat(q, spdsock_recv_hiwat);
2547*0Sstevel@tonic-gate 
2548*0Sstevel@tonic-gate 	*devp = makedevice(getmajor(*devp), ss->spdsock_minor);
2549*0Sstevel@tonic-gate 	return (0);
2550*0Sstevel@tonic-gate }
2551*0Sstevel@tonic-gate 
2552*0Sstevel@tonic-gate /*
2553*0Sstevel@tonic-gate  * Read-side service procedure, invoked when we get back-enabled
2554*0Sstevel@tonic-gate  * when buffer space becomes available.
2555*0Sstevel@tonic-gate  *
2556*0Sstevel@tonic-gate  * Dump another chunk if we were dumping before; when we finish, kick
2557*0Sstevel@tonic-gate  * the write-side queue in case it's waiting for read queue space.
2558*0Sstevel@tonic-gate  */
2559*0Sstevel@tonic-gate void
2560*0Sstevel@tonic-gate spdsock_rsrv(queue_t *q)
2561*0Sstevel@tonic-gate {
2562*0Sstevel@tonic-gate 	spdsock_t *ss = q->q_ptr;
2563*0Sstevel@tonic-gate 
2564*0Sstevel@tonic-gate 	if (ss->spdsock_dump_req != NULL)
2565*0Sstevel@tonic-gate 		spdsock_dump_some(q, ss);
2566*0Sstevel@tonic-gate 
2567*0Sstevel@tonic-gate 	if (ss->spdsock_dump_req == NULL)
2568*0Sstevel@tonic-gate 		qenable(OTHERQ(q));
2569*0Sstevel@tonic-gate }
2570*0Sstevel@tonic-gate 
2571*0Sstevel@tonic-gate /*
2572*0Sstevel@tonic-gate  * Write-side service procedure, invoked when we defer processing
2573*0Sstevel@tonic-gate  * if another message is received while a dump is in progress.
2574*0Sstevel@tonic-gate  */
2575*0Sstevel@tonic-gate void
2576*0Sstevel@tonic-gate spdsock_wsrv(queue_t *q)
2577*0Sstevel@tonic-gate {
2578*0Sstevel@tonic-gate 	spdsock_t *ss = q->q_ptr;
2579*0Sstevel@tonic-gate 	mblk_t *mp;
2580*0Sstevel@tonic-gate 
2581*0Sstevel@tonic-gate 	if (ss->spdsock_dump_req != NULL) {
2582*0Sstevel@tonic-gate 		qenable(OTHERQ(q));
2583*0Sstevel@tonic-gate 		return;
2584*0Sstevel@tonic-gate 	}
2585*0Sstevel@tonic-gate 
2586*0Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
2587*0Sstevel@tonic-gate 		if (ipsec_loaded()) {
2588*0Sstevel@tonic-gate 			spdsock_wput(q, mp);
2589*0Sstevel@tonic-gate 			if (ss->spdsock_dump_req != NULL)
2590*0Sstevel@tonic-gate 				return;
2591*0Sstevel@tonic-gate 		} else if (!ipsec_failed()) {
2592*0Sstevel@tonic-gate 			(void) putq(q, mp);
2593*0Sstevel@tonic-gate 		} else {
2594*0Sstevel@tonic-gate 			spdsock_error(q, mp, EPFNOSUPPORT, 0);
2595*0Sstevel@tonic-gate 		}
2596*0Sstevel@tonic-gate 	}
2597*0Sstevel@tonic-gate }
2598*0Sstevel@tonic-gate 
2599*0Sstevel@tonic-gate static int
2600*0Sstevel@tonic-gate spdsock_close(queue_t *q)
2601*0Sstevel@tonic-gate {
2602*0Sstevel@tonic-gate 	spdsock_t *ss = q->q_ptr;
2603*0Sstevel@tonic-gate 
2604*0Sstevel@tonic-gate 	qprocsoff(q);
2605*0Sstevel@tonic-gate 
2606*0Sstevel@tonic-gate 	/* Safe assumption. */
2607*0Sstevel@tonic-gate 	ASSERT(ss != NULL);
2608*0Sstevel@tonic-gate 
2609*0Sstevel@tonic-gate 	if (ss->spdsock_timeout != 0)
2610*0Sstevel@tonic-gate 		(void) quntimeout(q, ss->spdsock_timeout);
2611*0Sstevel@tonic-gate 
2612*0Sstevel@tonic-gate 	ss3dbg(("Driver close, PF_POLICY socket is going away.\n"));
2613*0Sstevel@tonic-gate 
2614*0Sstevel@tonic-gate 	vmem_free(spdsock_vmem, (void *)(uintptr_t)ss->spdsock_minor, 1);
2615*0Sstevel@tonic-gate 
2616*0Sstevel@tonic-gate 	kmem_free(ss, sizeof (spdsock_t));
2617*0Sstevel@tonic-gate 	return (0);
2618*0Sstevel@tonic-gate }
2619*0Sstevel@tonic-gate 
2620*0Sstevel@tonic-gate /*
2621*0Sstevel@tonic-gate  * Merge the IPsec algorithms tables with the received algorithm information.
2622*0Sstevel@tonic-gate  */
2623*0Sstevel@tonic-gate void
2624*0Sstevel@tonic-gate spdsock_merge_algs(void)
2625*0Sstevel@tonic-gate {
2626*0Sstevel@tonic-gate 	ipsec_alginfo_t *alg, *oalg;
2627*0Sstevel@tonic-gate 	ipsec_algtype_t algtype;
2628*0Sstevel@tonic-gate 	uint_t algidx, algid, nalgs;
2629*0Sstevel@tonic-gate 	crypto_mech_name_t *mechs;
2630*0Sstevel@tonic-gate 	uint_t mech_count, mech_idx;
2631*0Sstevel@tonic-gate 
2632*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&spdsock_alg_lock));
2633*0Sstevel@tonic-gate 
2634*0Sstevel@tonic-gate 	/*
2635*0Sstevel@tonic-gate 	 * Get the list of supported mechanisms from the crypto framework.
2636*0Sstevel@tonic-gate 	 * If a mechanism is supported by KCF, resolve its mechanism
2637*0Sstevel@tonic-gate 	 * id and mark it as being valid. This operation must be done
2638*0Sstevel@tonic-gate 	 * without holding alg_lock, since it can cause a provider
2639*0Sstevel@tonic-gate 	 * module to be loaded and the provider notification callback to
2640*0Sstevel@tonic-gate 	 * be invoked.
2641*0Sstevel@tonic-gate 	 */
2642*0Sstevel@tonic-gate 	mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
2643*0Sstevel@tonic-gate 	for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
2644*0Sstevel@tonic-gate 		for (algid = 0; algid < IPSEC_MAX_ALGS; algid++) {
2645*0Sstevel@tonic-gate 			int algflags = 0;
2646*0Sstevel@tonic-gate 			crypto_mech_type_t mt = CRYPTO_MECHANISM_INVALID;
2647*0Sstevel@tonic-gate 
2648*0Sstevel@tonic-gate 			if ((alg = spdsock_algs[algtype][algid]) == NULL)
2649*0Sstevel@tonic-gate 				continue;
2650*0Sstevel@tonic-gate 
2651*0Sstevel@tonic-gate 			/*
2652*0Sstevel@tonic-gate 			 * The NULL encryption algorithm is a special
2653*0Sstevel@tonic-gate 			 * case because there are no mechanisms, yet
2654*0Sstevel@tonic-gate 			 * the algorithm is still valid.
2655*0Sstevel@tonic-gate 			 */
2656*0Sstevel@tonic-gate 			if (alg->alg_id == SADB_EALG_NULL) {
2657*0Sstevel@tonic-gate 				alg->alg_mech_type = CRYPTO_MECHANISM_INVALID;
2658*0Sstevel@tonic-gate 				alg->alg_flags = ALG_FLAG_VALID;
2659*0Sstevel@tonic-gate 				continue;
2660*0Sstevel@tonic-gate 			}
2661*0Sstevel@tonic-gate 
2662*0Sstevel@tonic-gate 			for (mech_idx = 0; mech_idx < mech_count; mech_idx++) {
2663*0Sstevel@tonic-gate 				if (strncmp(alg->alg_mech_name, mechs[mech_idx],
2664*0Sstevel@tonic-gate 				    CRYPTO_MAX_MECH_NAME) == 0) {
2665*0Sstevel@tonic-gate 					mt = crypto_mech2id(alg->alg_mech_name);
2666*0Sstevel@tonic-gate 					ASSERT(mt != CRYPTO_MECHANISM_INVALID);
2667*0Sstevel@tonic-gate 					algflags = ALG_FLAG_VALID;
2668*0Sstevel@tonic-gate 					break;
2669*0Sstevel@tonic-gate 				}
2670*0Sstevel@tonic-gate 			}
2671*0Sstevel@tonic-gate 			alg->alg_mech_type = mt;
2672*0Sstevel@tonic-gate 			alg->alg_flags = algflags;
2673*0Sstevel@tonic-gate 		}
2674*0Sstevel@tonic-gate 	}
2675*0Sstevel@tonic-gate 
2676*0Sstevel@tonic-gate 	mutex_enter(&alg_lock);
2677*0Sstevel@tonic-gate 
2678*0Sstevel@tonic-gate 	/*
2679*0Sstevel@tonic-gate 	 * For each algorithm currently defined, check if it is
2680*0Sstevel@tonic-gate 	 * present in the new tables created from the SPD_UPDATEALGS
2681*0Sstevel@tonic-gate 	 * message received from user-space.
2682*0Sstevel@tonic-gate 	 * Delete the algorithm entries that are currently defined
2683*0Sstevel@tonic-gate 	 * but not part of the new tables.
2684*0Sstevel@tonic-gate 	 */
2685*0Sstevel@tonic-gate 	for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
2686*0Sstevel@tonic-gate 		nalgs = ipsec_nalgs[algtype];
2687*0Sstevel@tonic-gate 		for (algidx = 0; algidx < nalgs; algidx++) {
2688*0Sstevel@tonic-gate 			algid = ipsec_sortlist[algtype][algidx];
2689*0Sstevel@tonic-gate 			if (spdsock_algs[algtype][algid] == NULL)
2690*0Sstevel@tonic-gate 				ipsec_alg_unreg(algtype, algid);
2691*0Sstevel@tonic-gate 		}
2692*0Sstevel@tonic-gate 	}
2693*0Sstevel@tonic-gate 
2694*0Sstevel@tonic-gate 	/*
2695*0Sstevel@tonic-gate 	 * For each algorithm we just received, check if it is
2696*0Sstevel@tonic-gate 	 * present in the currently defined tables. If it is, swap
2697*0Sstevel@tonic-gate 	 * the entry with the one we just allocated.
2698*0Sstevel@tonic-gate 	 * If the new algorithm is not in the current tables,
2699*0Sstevel@tonic-gate 	 * add it.
2700*0Sstevel@tonic-gate 	 */
2701*0Sstevel@tonic-gate 	for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
2702*0Sstevel@tonic-gate 		for (algid = 0; algid < IPSEC_MAX_ALGS; algid++) {
2703*0Sstevel@tonic-gate 			if ((alg = spdsock_algs[algtype][algid]) == NULL)
2704*0Sstevel@tonic-gate 				continue;
2705*0Sstevel@tonic-gate 
2706*0Sstevel@tonic-gate 			if ((oalg = ipsec_alglists[algtype][algid]) == NULL) {
2707*0Sstevel@tonic-gate 				/*
2708*0Sstevel@tonic-gate 				 * New algorithm, add it to the algorithm
2709*0Sstevel@tonic-gate 				 * table.
2710*0Sstevel@tonic-gate 				 */
2711*0Sstevel@tonic-gate 				ipsec_alg_reg(algtype, alg);
2712*0Sstevel@tonic-gate 			} else {
2713*0Sstevel@tonic-gate 				/*
2714*0Sstevel@tonic-gate 				 * Algorithm is already in the table. Swap
2715*0Sstevel@tonic-gate 				 * the existing entry with the new one.
2716*0Sstevel@tonic-gate 				 */
2717*0Sstevel@tonic-gate 				ipsec_alg_fix_min_max(alg, algtype);
2718*0Sstevel@tonic-gate 				ipsec_alglists[algtype][algid] = alg;
2719*0Sstevel@tonic-gate 				ipsec_alg_free(oalg);
2720*0Sstevel@tonic-gate 			}
2721*0Sstevel@tonic-gate 			spdsock_algs[algtype][algid] = NULL;
2722*0Sstevel@tonic-gate 		}
2723*0Sstevel@tonic-gate 	}
2724*0Sstevel@tonic-gate 
2725*0Sstevel@tonic-gate 	for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++)
2726*0Sstevel@tonic-gate 		ipsec_algs_exec_mode[algtype] = spdsock_algs_exec_mode[algtype];
2727*0Sstevel@tonic-gate 
2728*0Sstevel@tonic-gate 	mutex_exit(&alg_lock);
2729*0Sstevel@tonic-gate 
2730*0Sstevel@tonic-gate 	crypto_free_mech_list(mechs, mech_count);
2731*0Sstevel@tonic-gate 
2732*0Sstevel@tonic-gate 	ipsecah_algs_changed();
2733*0Sstevel@tonic-gate 	ipsecesp_algs_changed();
2734*0Sstevel@tonic-gate }
2735