xref: /onnv-gate/usr/src/uts/common/inet/ip/ipsecesp.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/stream.h>
31*0Sstevel@tonic-gate #include <sys/stropts.h>
32*0Sstevel@tonic-gate #include <sys/errno.h>
33*0Sstevel@tonic-gate #include <sys/strlog.h>
34*0Sstevel@tonic-gate #include <sys/tihdr.h>
35*0Sstevel@tonic-gate #include <sys/socket.h>
36*0Sstevel@tonic-gate #include <sys/ddi.h>
37*0Sstevel@tonic-gate #include <sys/sunddi.h>
38*0Sstevel@tonic-gate #include <sys/kmem.h>
39*0Sstevel@tonic-gate #include <sys/sysmacros.h>
40*0Sstevel@tonic-gate #include <sys/cmn_err.h>
41*0Sstevel@tonic-gate #include <sys/vtrace.h>
42*0Sstevel@tonic-gate #include <sys/debug.h>
43*0Sstevel@tonic-gate #include <sys/atomic.h>
44*0Sstevel@tonic-gate #include <sys/strsun.h>
45*0Sstevel@tonic-gate #include <sys/random.h>
46*0Sstevel@tonic-gate #include <netinet/in.h>
47*0Sstevel@tonic-gate #include <net/if.h>
48*0Sstevel@tonic-gate #include <netinet/ip6.h>
49*0Sstevel@tonic-gate #include <net/pfkeyv2.h>
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate #include <inet/common.h>
52*0Sstevel@tonic-gate #include <inet/mi.h>
53*0Sstevel@tonic-gate #include <inet/nd.h>
54*0Sstevel@tonic-gate #include <inet/ip.h>
55*0Sstevel@tonic-gate #include <inet/ip6.h>
56*0Sstevel@tonic-gate #include <inet/sadb.h>
57*0Sstevel@tonic-gate #include <inet/ipsec_info.h>
58*0Sstevel@tonic-gate #include <inet/ipsec_impl.h>
59*0Sstevel@tonic-gate #include <inet/ipsecesp.h>
60*0Sstevel@tonic-gate #include <inet/ipdrop.h>
61*0Sstevel@tonic-gate #include <inet/tcp.h>
62*0Sstevel@tonic-gate #include <sys/kstat.h>
63*0Sstevel@tonic-gate #include <sys/policy.h>
64*0Sstevel@tonic-gate #include <sys/strsun.h>
65*0Sstevel@tonic-gate #include <inet/udp_impl.h>
66*0Sstevel@tonic-gate #include <sys/taskq.h>
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /* EXPORT DELETE START */
69*0Sstevel@tonic-gate #include <sys/iphada.h>
70*0Sstevel@tonic-gate /* EXPORT DELETE END */
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /* Packet dropper for ESP drops. */
73*0Sstevel@tonic-gate static ipdropper_t esp_dropper;
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate static kmutex_t ipsecesp_param_lock; /* Protects ipsecesp_param_arr[] below. */
76*0Sstevel@tonic-gate /*
77*0Sstevel@tonic-gate  * Table of ND variables supported by ipsecesp. These are loaded into
78*0Sstevel@tonic-gate  * ipsecesp_g_nd in ipsecesp_init_nd.
79*0Sstevel@tonic-gate  * All of these are alterable, within the min/max values given, at run time.
80*0Sstevel@tonic-gate  */
81*0Sstevel@tonic-gate static	ipsecespparam_t	ipsecesp_param_arr[] = {
82*0Sstevel@tonic-gate 	/* min	max			value	name */
83*0Sstevel@tonic-gate 	{ 0,	3,			0,	"ipsecesp_debug"},
84*0Sstevel@tonic-gate 	{ 125,	32000, SADB_AGE_INTERVAL_DEFAULT, "ipsecesp_age_interval"},
85*0Sstevel@tonic-gate 	{ 1,	10,			1,	"ipsecesp_reap_delay"},
86*0Sstevel@tonic-gate 	{ 1,	SADB_MAX_REPLAY,	64,	"ipsecesp_replay_size"},
87*0Sstevel@tonic-gate 	{ 1,	300,			15,	"ipsecesp_acquire_timeout"},
88*0Sstevel@tonic-gate 	{ 1,	1800,			90,	"ipsecesp_larval_timeout"},
89*0Sstevel@tonic-gate 	/* Default lifetime values for ACQUIRE messages. */
90*0Sstevel@tonic-gate 	{ 0,	0xffffffffU,	0,	"ipsecesp_default_soft_bytes"},
91*0Sstevel@tonic-gate 	{ 0,	0xffffffffU,	0,	"ipsecesp_default_hard_bytes"},
92*0Sstevel@tonic-gate 	{ 0,	0xffffffffU,	24000,	"ipsecesp_default_soft_addtime"},
93*0Sstevel@tonic-gate 	{ 0,	0xffffffffU,	28800,	"ipsecesp_default_hard_addtime"},
94*0Sstevel@tonic-gate 	{ 0,	0xffffffffU,	0,	"ipsecesp_default_soft_usetime"},
95*0Sstevel@tonic-gate 	{ 0,	0xffffffffU,	0,	"ipsecesp_default_hard_usetime"},
96*0Sstevel@tonic-gate 	{ 0,	1,		0,	"ipsecesp_log_unknown_spi"},
97*0Sstevel@tonic-gate 	{ 0,	2,		1,	"ipsecesp_padding_check"},
98*0Sstevel@tonic-gate };
99*0Sstevel@tonic-gate #define	ipsecesp_debug		ipsecesp_param_arr[0].ipsecesp_param_value
100*0Sstevel@tonic-gate #define	ipsecesp_age_interval	ipsecesp_param_arr[1].ipsecesp_param_value
101*0Sstevel@tonic-gate #define	ipsecesp_age_int_max	ipsecesp_param_arr[1].ipsecesp_param_max
102*0Sstevel@tonic-gate #define	ipsecesp_reap_delay	ipsecesp_param_arr[2].ipsecesp_param_value
103*0Sstevel@tonic-gate #define	ipsecesp_replay_size	ipsecesp_param_arr[3].ipsecesp_param_value
104*0Sstevel@tonic-gate #define	ipsecesp_acquire_timeout ipsecesp_param_arr[4].ipsecesp_param_value
105*0Sstevel@tonic-gate #define	ipsecesp_larval_timeout ipsecesp_param_arr[5].ipsecesp_param_value
106*0Sstevel@tonic-gate #define	ipsecesp_default_soft_bytes \
107*0Sstevel@tonic-gate 	ipsecesp_param_arr[6].ipsecesp_param_value
108*0Sstevel@tonic-gate #define	ipsecesp_default_hard_bytes \
109*0Sstevel@tonic-gate 	ipsecesp_param_arr[7].ipsecesp_param_value
110*0Sstevel@tonic-gate #define	ipsecesp_default_soft_addtime \
111*0Sstevel@tonic-gate 	ipsecesp_param_arr[8].ipsecesp_param_value
112*0Sstevel@tonic-gate #define	ipsecesp_default_hard_addtime \
113*0Sstevel@tonic-gate 	ipsecesp_param_arr[9].ipsecesp_param_value
114*0Sstevel@tonic-gate #define	ipsecesp_default_soft_usetime \
115*0Sstevel@tonic-gate 	ipsecesp_param_arr[10].ipsecesp_param_value
116*0Sstevel@tonic-gate #define	ipsecesp_default_hard_usetime \
117*0Sstevel@tonic-gate 	ipsecesp_param_arr[11].ipsecesp_param_value
118*0Sstevel@tonic-gate #define	ipsecesp_log_unknown_spi \
119*0Sstevel@tonic-gate 	ipsecesp_param_arr[12].ipsecesp_param_value
120*0Sstevel@tonic-gate #define	ipsecesp_padding_check \
121*0Sstevel@tonic-gate 	ipsecesp_param_arr[13].ipsecesp_param_value
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate #define	esp0dbg(a)	printf a
124*0Sstevel@tonic-gate /* NOTE:  != 0 instead of > 0 so lint doesn't complain. */
125*0Sstevel@tonic-gate #define	esp1dbg(a)	if (ipsecesp_debug != 0) printf a
126*0Sstevel@tonic-gate #define	esp2dbg(a)	if (ipsecesp_debug > 1) printf a
127*0Sstevel@tonic-gate #define	esp3dbg(a)	if (ipsecesp_debug > 2) printf a
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate static IDP ipsecesp_g_nd;
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate static int ipsecesp_open(queue_t *, dev_t *, int, int, cred_t *);
132*0Sstevel@tonic-gate static int ipsecesp_close(queue_t *);
133*0Sstevel@tonic-gate static void ipsecesp_rput(queue_t *, mblk_t *);
134*0Sstevel@tonic-gate static void ipsecesp_wput(queue_t *, mblk_t *);
135*0Sstevel@tonic-gate static void esp_send_acquire(ipsacq_t *, mblk_t *);
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate /* EXPORT DELETE START */
138*0Sstevel@tonic-gate static ipsec_status_t esp_outbound_accelerated(mblk_t *, uint_t);
139*0Sstevel@tonic-gate static ipsec_status_t esp_inbound_accelerated(mblk_t *, mblk_t *,
140*0Sstevel@tonic-gate     boolean_t, ipsa_t *);
141*0Sstevel@tonic-gate /* EXPORT DELETE END */
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate static boolean_t esp_register_out(uint32_t, uint32_t, uint_t);
144*0Sstevel@tonic-gate static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t,
145*0Sstevel@tonic-gate     kstat_named_t **);
146*0Sstevel@tonic-gate static ipsec_status_t esp_submit_req_inbound(mblk_t *, ipsa_t *, uint_t);
147*0Sstevel@tonic-gate static ipsec_status_t esp_submit_req_outbound(mblk_t *, ipsa_t *, uchar_t *,
148*0Sstevel@tonic-gate     uint_t);
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate static struct module_info info = {
151*0Sstevel@tonic-gate 	5137, "ipsecesp", 0, INFPSZ, 65536, 1024
152*0Sstevel@tonic-gate };
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate static struct qinit rinit = {
155*0Sstevel@tonic-gate 	(pfi_t)ipsecesp_rput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
156*0Sstevel@tonic-gate 	NULL
157*0Sstevel@tonic-gate };
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate static struct qinit winit = {
160*0Sstevel@tonic-gate 	(pfi_t)ipsecesp_wput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
161*0Sstevel@tonic-gate 	NULL
162*0Sstevel@tonic-gate };
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate struct streamtab ipsecespinfo = {
165*0Sstevel@tonic-gate 	&rinit, &winit, NULL, NULL
166*0Sstevel@tonic-gate };
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate /*
169*0Sstevel@tonic-gate  * Keysock instance of ESP.  "There can be only one." :)
170*0Sstevel@tonic-gate  * Use casptr() on this because I don't set it until KEYSOCK_HELLO comes down.
171*0Sstevel@tonic-gate  * Paired up with the esp_pfkey_q is the esp_event, which will age SAs.
172*0Sstevel@tonic-gate  */
173*0Sstevel@tonic-gate static queue_t *esp_pfkey_q;
174*0Sstevel@tonic-gate static timeout_id_t esp_event;
175*0Sstevel@tonic-gate static taskq_t *esp_taskq;
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate /*
178*0Sstevel@tonic-gate  * OTOH, this one is set at open/close, and I'm D_MTQPAIR for now.
179*0Sstevel@tonic-gate  *
180*0Sstevel@tonic-gate  * Question:	Do I need this, given that all instance's esps->esps_wq point
181*0Sstevel@tonic-gate  *		to IP?
182*0Sstevel@tonic-gate  *
183*0Sstevel@tonic-gate  * Answer:	Yes, because I need to know which queue is BOUND to
184*0Sstevel@tonic-gate  *		IPPROTO_ESP
185*0Sstevel@tonic-gate  */
186*0Sstevel@tonic-gate static mblk_t *esp_ip_unbind;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate /*
189*0Sstevel@tonic-gate  * Stats.  This may eventually become a full-blown SNMP MIB once that spec
190*0Sstevel@tonic-gate  * stabilizes.
191*0Sstevel@tonic-gate  */
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate typedef struct {
194*0Sstevel@tonic-gate 	kstat_named_t esp_stat_num_aalgs;
195*0Sstevel@tonic-gate 	kstat_named_t esp_stat_good_auth;
196*0Sstevel@tonic-gate 	kstat_named_t esp_stat_bad_auth;
197*0Sstevel@tonic-gate 	kstat_named_t esp_stat_bad_padding;
198*0Sstevel@tonic-gate 	kstat_named_t esp_stat_replay_failures;
199*0Sstevel@tonic-gate 	kstat_named_t esp_stat_replay_early_failures;
200*0Sstevel@tonic-gate 	kstat_named_t esp_stat_keysock_in;
201*0Sstevel@tonic-gate 	kstat_named_t esp_stat_out_requests;
202*0Sstevel@tonic-gate 	kstat_named_t esp_stat_acquire_requests;
203*0Sstevel@tonic-gate 	kstat_named_t esp_stat_bytes_expired;
204*0Sstevel@tonic-gate 	kstat_named_t esp_stat_out_discards;
205*0Sstevel@tonic-gate 	kstat_named_t esp_stat_in_accelerated;
206*0Sstevel@tonic-gate 	kstat_named_t esp_stat_out_accelerated;
207*0Sstevel@tonic-gate 	kstat_named_t esp_stat_noaccel;
208*0Sstevel@tonic-gate 	kstat_named_t esp_stat_crypto_sync;
209*0Sstevel@tonic-gate 	kstat_named_t esp_stat_crypto_async;
210*0Sstevel@tonic-gate 	kstat_named_t esp_stat_crypto_failures;
211*0Sstevel@tonic-gate /* EXPORT DELETE START */
212*0Sstevel@tonic-gate 	kstat_named_t esp_stat_num_ealgs;
213*0Sstevel@tonic-gate 	kstat_named_t esp_stat_bad_decrypt;
214*0Sstevel@tonic-gate /* EXPORT DELETE END */
215*0Sstevel@tonic-gate } esp_kstats_t;
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate #define	ESP_BUMP_STAT(x) (esp_kstats->esp_stat_ ## x).value.ui64++
218*0Sstevel@tonic-gate #define	ESP_DEBUMP_STAT(x) (esp_kstats->esp_stat_ ## x).value.ui64--
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate static kstat_t *esp_ksp;
221*0Sstevel@tonic-gate static esp_kstats_t *esp_kstats;
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate static int	esp_kstat_update(kstat_t *, int);
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate static boolean_t
226*0Sstevel@tonic-gate esp_kstat_init(void)
227*0Sstevel@tonic-gate {
228*0Sstevel@tonic-gate 	esp_ksp = kstat_create("ipsecesp", 0, "esp_stat", "net",
229*0Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, sizeof (*esp_kstats) / sizeof (kstat_named_t),
230*0Sstevel@tonic-gate 	    KSTAT_FLAG_PERSISTENT);
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	if (esp_ksp == NULL)
233*0Sstevel@tonic-gate 		return (B_FALSE);
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	esp_kstats = esp_ksp->ks_data;
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	esp_ksp->ks_update = esp_kstat_update;
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate #define	K64 KSTAT_DATA_UINT64
240*0Sstevel@tonic-gate #define	KI(x) kstat_named_init(&(esp_kstats->esp_stat_##x), #x, K64)
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	KI(num_aalgs);
243*0Sstevel@tonic-gate /* EXPORT DELETE START */
244*0Sstevel@tonic-gate 	KI(num_ealgs);
245*0Sstevel@tonic-gate /* EXPORT DELETE END */
246*0Sstevel@tonic-gate 	KI(good_auth);
247*0Sstevel@tonic-gate 	KI(bad_auth);
248*0Sstevel@tonic-gate 	KI(bad_padding);
249*0Sstevel@tonic-gate 	KI(replay_failures);
250*0Sstevel@tonic-gate 	KI(replay_early_failures);
251*0Sstevel@tonic-gate 	KI(keysock_in);
252*0Sstevel@tonic-gate 	KI(out_requests);
253*0Sstevel@tonic-gate 	KI(acquire_requests);
254*0Sstevel@tonic-gate 	KI(bytes_expired);
255*0Sstevel@tonic-gate 	KI(out_discards);
256*0Sstevel@tonic-gate 	KI(in_accelerated);
257*0Sstevel@tonic-gate 	KI(out_accelerated);
258*0Sstevel@tonic-gate 	KI(noaccel);
259*0Sstevel@tonic-gate 	KI(crypto_sync);
260*0Sstevel@tonic-gate 	KI(crypto_async);
261*0Sstevel@tonic-gate 	KI(crypto_failures);
262*0Sstevel@tonic-gate /* EXPORT DELETE START */
263*0Sstevel@tonic-gate 	KI(bad_decrypt);
264*0Sstevel@tonic-gate /* EXPORT DELETE END */
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate #undef KI
267*0Sstevel@tonic-gate #undef K64
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	kstat_install(esp_ksp);
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	return (B_TRUE);
272*0Sstevel@tonic-gate }
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate static int
275*0Sstevel@tonic-gate esp_kstat_update(kstat_t *kp, int rw)
276*0Sstevel@tonic-gate {
277*0Sstevel@tonic-gate 	esp_kstats_t *ekp;
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	if ((kp == NULL) || (kp->ks_data == NULL))
280*0Sstevel@tonic-gate 		return (EIO);
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
283*0Sstevel@tonic-gate 		return (EACCES);
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	ASSERT(kp == esp_ksp);
286*0Sstevel@tonic-gate 	ekp = (esp_kstats_t *)kp->ks_data;
287*0Sstevel@tonic-gate 	ASSERT(ekp == esp_kstats);
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	mutex_enter(&alg_lock);
290*0Sstevel@tonic-gate 	ekp->esp_stat_num_aalgs.value.ui64 = ipsec_nalgs[IPSEC_ALG_AUTH];
291*0Sstevel@tonic-gate /* EXPORT DELETE START */
292*0Sstevel@tonic-gate 	ekp->esp_stat_num_ealgs.value.ui64 = ipsec_nalgs[IPSEC_ALG_ENCR];
293*0Sstevel@tonic-gate /* EXPORT DELETE END */
294*0Sstevel@tonic-gate 	mutex_exit(&alg_lock);
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	return (0);
297*0Sstevel@tonic-gate }
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate #ifdef DEBUG
300*0Sstevel@tonic-gate /*
301*0Sstevel@tonic-gate  * Debug routine, useful to see pre-encryption data.
302*0Sstevel@tonic-gate  */
303*0Sstevel@tonic-gate static char *
304*0Sstevel@tonic-gate dump_msg(mblk_t *mp)
305*0Sstevel@tonic-gate {
306*0Sstevel@tonic-gate 	char tmp_str[3], tmp_line[256];
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	while (mp != NULL) {
309*0Sstevel@tonic-gate 		unsigned char *ptr;
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 		printf("mblk address 0x%p, length %ld, db_ref %d "
312*0Sstevel@tonic-gate 		    "type %d, base 0x%p, lim 0x%p\n",
313*0Sstevel@tonic-gate 		    (void *) mp, (long)(mp->b_wptr - mp->b_rptr),
314*0Sstevel@tonic-gate 		    mp->b_datap->db_ref, mp->b_datap->db_type,
315*0Sstevel@tonic-gate 		    (void *)mp->b_datap->db_base, (void *)mp->b_datap->db_lim);
316*0Sstevel@tonic-gate 		ptr = mp->b_rptr;
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 		tmp_line[0] = '\0';
319*0Sstevel@tonic-gate 		while (ptr < mp->b_wptr) {
320*0Sstevel@tonic-gate 			uint_t diff;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 			diff = (ptr - mp->b_rptr);
323*0Sstevel@tonic-gate 			if (!(diff & 0x1f)) {
324*0Sstevel@tonic-gate 				if (strlen(tmp_line) > 0) {
325*0Sstevel@tonic-gate 					printf("bytes: %s\n", tmp_line);
326*0Sstevel@tonic-gate 					tmp_line[0] = '\0';
327*0Sstevel@tonic-gate 				}
328*0Sstevel@tonic-gate 			}
329*0Sstevel@tonic-gate 			if (!(diff & 0x3))
330*0Sstevel@tonic-gate 				(void) strcat(tmp_line, " ");
331*0Sstevel@tonic-gate 			(void) sprintf(tmp_str, "%02x", *ptr);
332*0Sstevel@tonic-gate 			(void) strcat(tmp_line, tmp_str);
333*0Sstevel@tonic-gate 			ptr++;
334*0Sstevel@tonic-gate 		}
335*0Sstevel@tonic-gate 		if (strlen(tmp_line) > 0)
336*0Sstevel@tonic-gate 			printf("bytes: %s\n", tmp_line);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 		mp = mp->b_cont;
339*0Sstevel@tonic-gate 	}
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	return ("\n");
342*0Sstevel@tonic-gate }
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate #else /* DEBUG */
345*0Sstevel@tonic-gate static char *
346*0Sstevel@tonic-gate dump_msg(mblk_t *mp)
347*0Sstevel@tonic-gate {
348*0Sstevel@tonic-gate 	printf("Find value of mp %p.\n", mp);
349*0Sstevel@tonic-gate 	return ("\n");
350*0Sstevel@tonic-gate }
351*0Sstevel@tonic-gate #endif /* DEBUG */
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate /*
354*0Sstevel@tonic-gate  * Don't have to lock age_interval, as only one thread will access it at
355*0Sstevel@tonic-gate  * a time, because I control the one function that does with timeout().
356*0Sstevel@tonic-gate  */
357*0Sstevel@tonic-gate /* ARGSUSED */
358*0Sstevel@tonic-gate static void
359*0Sstevel@tonic-gate esp_ager(void *ignoreme)
360*0Sstevel@tonic-gate {
361*0Sstevel@tonic-gate 	hrtime_t begin = gethrtime();
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	sadb_ager(&esp_sadb.s_v4, esp_pfkey_q, esp_sadb.s_ip_q,
364*0Sstevel@tonic-gate 	    ipsecesp_reap_delay);
365*0Sstevel@tonic-gate 	sadb_ager(&esp_sadb.s_v6, esp_pfkey_q, esp_sadb.s_ip_q,
366*0Sstevel@tonic-gate 	    ipsecesp_reap_delay);
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	esp_event = sadb_retimeout(begin, esp_pfkey_q, esp_ager,
369*0Sstevel@tonic-gate 	    &(ipsecesp_age_interval), ipsecesp_age_int_max, info.mi_idnum);
370*0Sstevel@tonic-gate }
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate /*
373*0Sstevel@tonic-gate  * Get an ESP NDD parameter.
374*0Sstevel@tonic-gate  */
375*0Sstevel@tonic-gate /* ARGSUSED */
376*0Sstevel@tonic-gate static int
377*0Sstevel@tonic-gate ipsecesp_param_get(q, mp, cp, cr)
378*0Sstevel@tonic-gate 	queue_t	*q;
379*0Sstevel@tonic-gate 	mblk_t	*mp;
380*0Sstevel@tonic-gate 	caddr_t	cp;
381*0Sstevel@tonic-gate 	cred_t *cr;
382*0Sstevel@tonic-gate {
383*0Sstevel@tonic-gate 	ipsecespparam_t	*ipsecesppa = (ipsecespparam_t *)cp;
384*0Sstevel@tonic-gate 	uint_t value;
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	mutex_enter(&ipsecesp_param_lock);
387*0Sstevel@tonic-gate 	value = ipsecesppa->ipsecesp_param_value;
388*0Sstevel@tonic-gate 	mutex_exit(&ipsecesp_param_lock);
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	(void) mi_mpprintf(mp, "%u", value);
391*0Sstevel@tonic-gate 	return (0);
392*0Sstevel@tonic-gate }
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate /*
395*0Sstevel@tonic-gate  * This routine sets an NDD variable in a ipsecespparam_t structure.
396*0Sstevel@tonic-gate  */
397*0Sstevel@tonic-gate /* ARGSUSED */
398*0Sstevel@tonic-gate static int
399*0Sstevel@tonic-gate ipsecesp_param_set(q, mp, value, cp, cr)
400*0Sstevel@tonic-gate 	queue_t	*q;
401*0Sstevel@tonic-gate 	mblk_t	*mp;
402*0Sstevel@tonic-gate 	char	*value;
403*0Sstevel@tonic-gate 	caddr_t	cp;
404*0Sstevel@tonic-gate 	cred_t *cr;
405*0Sstevel@tonic-gate {
406*0Sstevel@tonic-gate 	ulong_t	new_value;
407*0Sstevel@tonic-gate 	ipsecespparam_t	*ipsecesppa = (ipsecespparam_t *)cp;
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	/*
410*0Sstevel@tonic-gate 	 * Fail the request if the new value does not lie within the
411*0Sstevel@tonic-gate 	 * required bounds.
412*0Sstevel@tonic-gate 	 */
413*0Sstevel@tonic-gate 	if (ddi_strtoul(value, NULL, 10, &new_value) != 0 ||
414*0Sstevel@tonic-gate 	    new_value < ipsecesppa->ipsecesp_param_min ||
415*0Sstevel@tonic-gate 	    new_value > ipsecesppa->ipsecesp_param_max) {
416*0Sstevel@tonic-gate 		return (EINVAL);
417*0Sstevel@tonic-gate 	}
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 	/* Set the new value */
420*0Sstevel@tonic-gate 	mutex_enter(&ipsecesp_param_lock);
421*0Sstevel@tonic-gate 	ipsecesppa->ipsecesp_param_value = new_value;
422*0Sstevel@tonic-gate 	mutex_exit(&ipsecesp_param_lock);
423*0Sstevel@tonic-gate 	return (0);
424*0Sstevel@tonic-gate }
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate /*
427*0Sstevel@tonic-gate  * Using lifetime NDD variables, fill in an extended combination's
428*0Sstevel@tonic-gate  * lifetime information.
429*0Sstevel@tonic-gate  */
430*0Sstevel@tonic-gate void
431*0Sstevel@tonic-gate ipsecesp_fill_defs(sadb_x_ecomb_t *ecomb)
432*0Sstevel@tonic-gate {
433*0Sstevel@tonic-gate 	ecomb->sadb_x_ecomb_soft_bytes = ipsecesp_default_soft_bytes;
434*0Sstevel@tonic-gate 	ecomb->sadb_x_ecomb_hard_bytes = ipsecesp_default_hard_bytes;
435*0Sstevel@tonic-gate 	ecomb->sadb_x_ecomb_soft_addtime = ipsecesp_default_soft_addtime;
436*0Sstevel@tonic-gate 	ecomb->sadb_x_ecomb_hard_addtime = ipsecesp_default_hard_addtime;
437*0Sstevel@tonic-gate 	ecomb->sadb_x_ecomb_soft_usetime = ipsecesp_default_soft_usetime;
438*0Sstevel@tonic-gate 	ecomb->sadb_x_ecomb_hard_usetime = ipsecesp_default_hard_usetime;
439*0Sstevel@tonic-gate }
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate /*
442*0Sstevel@tonic-gate  * Initialize things for ESP at module load time.
443*0Sstevel@tonic-gate  */
444*0Sstevel@tonic-gate boolean_t
445*0Sstevel@tonic-gate ipsecesp_ddi_init(void)
446*0Sstevel@tonic-gate {
447*0Sstevel@tonic-gate 	int count;
448*0Sstevel@tonic-gate 	ipsecespparam_t *espp = ipsecesp_param_arr;
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	for (count = A_CNT(ipsecesp_param_arr); count-- > 0; espp++) {
451*0Sstevel@tonic-gate 		if (espp->ipsecesp_param_name != NULL &&
452*0Sstevel@tonic-gate 		    espp->ipsecesp_param_name[0]) {
453*0Sstevel@tonic-gate 			if (!nd_load(&ipsecesp_g_nd, espp->ipsecesp_param_name,
454*0Sstevel@tonic-gate 			    ipsecesp_param_get, ipsecesp_param_set,
455*0Sstevel@tonic-gate 			    (caddr_t)espp)) {
456*0Sstevel@tonic-gate 				nd_free(&ipsecesp_g_nd);
457*0Sstevel@tonic-gate 				return (B_FALSE);
458*0Sstevel@tonic-gate 			}
459*0Sstevel@tonic-gate 		}
460*0Sstevel@tonic-gate 	}
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 	if (!esp_kstat_init()) {
463*0Sstevel@tonic-gate 		nd_free(&ipsecesp_g_nd);
464*0Sstevel@tonic-gate 		return (B_FALSE);
465*0Sstevel@tonic-gate 	}
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	esp_sadb.s_acquire_timeout = &ipsecesp_acquire_timeout;
468*0Sstevel@tonic-gate 	esp_sadb.s_acqfn = esp_send_acquire;
469*0Sstevel@tonic-gate 	sadbp_init(&esp_sadb, SADB_SATYPE_ESP);
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	esp_taskq = taskq_create("esp_taskq", 1, minclsyspri,
472*0Sstevel@tonic-gate 	    IPSEC_TASKQ_MIN, IPSEC_TASKQ_MAX, 0);
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	mutex_init(&ipsecesp_param_lock, NULL, MUTEX_DEFAULT, 0);
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	ip_drop_register(&esp_dropper, "IPsec ESP");
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	return (B_TRUE);
479*0Sstevel@tonic-gate }
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate /*
482*0Sstevel@tonic-gate  * Destroy things for ESP at module unload time.
483*0Sstevel@tonic-gate  */
484*0Sstevel@tonic-gate void
485*0Sstevel@tonic-gate ipsecesp_ddi_destroy(void)
486*0Sstevel@tonic-gate {
487*0Sstevel@tonic-gate 	esp1dbg(("In ipsecesp_ddi_destroy.\n"));
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	sadbp_destroy(&esp_sadb);
490*0Sstevel@tonic-gate 	ip_drop_unregister(&esp_dropper);
491*0Sstevel@tonic-gate 	taskq_destroy(esp_taskq);
492*0Sstevel@tonic-gate 	mutex_destroy(&ipsecesp_param_lock);
493*0Sstevel@tonic-gate 	nd_free(&ipsecesp_g_nd);
494*0Sstevel@tonic-gate 	kstat_delete(esp_ksp);
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate /*
498*0Sstevel@tonic-gate  * ESP module open routine.
499*0Sstevel@tonic-gate  */
500*0Sstevel@tonic-gate /* ARGSUSED */
501*0Sstevel@tonic-gate static int
502*0Sstevel@tonic-gate ipsecesp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
503*0Sstevel@tonic-gate {
504*0Sstevel@tonic-gate 	if (secpolicy_net_config(credp, B_FALSE) != 0) {
505*0Sstevel@tonic-gate 		esp1dbg(("Non-privileged user trying to open ipsecesp.\n"));
506*0Sstevel@tonic-gate 		return (EPERM);
507*0Sstevel@tonic-gate 	}
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	if (q->q_ptr != NULL)
510*0Sstevel@tonic-gate 		return (0);  /* Re-open of an already open instance. */
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate 	if (sflag != MODOPEN)
513*0Sstevel@tonic-gate 		return (EINVAL);
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	/*
516*0Sstevel@tonic-gate 	 * ASSUMPTIONS (because I'm MT_OCEXCL):
517*0Sstevel@tonic-gate 	 *
518*0Sstevel@tonic-gate 	 *	* I'm being pushed on top of IP for all my opens (incl. #1).
519*0Sstevel@tonic-gate 	 *	* Only ipsecesp_open() can write into esp_sadb.s_ip_q.
520*0Sstevel@tonic-gate 	 *	* Because of this, I can check lazily for esp_sadb.s_ip_q.
521*0Sstevel@tonic-gate 	 *
522*0Sstevel@tonic-gate 	 *  If these assumptions are wrong, I'm in BIG trouble...
523*0Sstevel@tonic-gate 	 */
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	q->q_ptr = q; /* just so I know I'm open */
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	if (esp_sadb.s_ip_q == NULL) {
528*0Sstevel@tonic-gate 		struct T_unbind_req *tur;
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 		esp_sadb.s_ip_q = WR(q);
531*0Sstevel@tonic-gate 		/* Allocate an unbind... */
532*0Sstevel@tonic-gate 		esp_ip_unbind = allocb(sizeof (struct T_unbind_req), BPRI_HI);
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 		/*
535*0Sstevel@tonic-gate 		 * Send down T_BIND_REQ to bind IPPROTO_ESP.
536*0Sstevel@tonic-gate 		 * Handle the ACK here in ESP.
537*0Sstevel@tonic-gate 		 */
538*0Sstevel@tonic-gate 		qprocson(q);
539*0Sstevel@tonic-gate 		if (esp_ip_unbind == NULL ||
540*0Sstevel@tonic-gate 		    !sadb_t_bind_req(esp_sadb.s_ip_q, IPPROTO_ESP)) {
541*0Sstevel@tonic-gate 			if (esp_ip_unbind != NULL) {
542*0Sstevel@tonic-gate 				freeb(esp_ip_unbind);
543*0Sstevel@tonic-gate 				esp_ip_unbind = NULL;
544*0Sstevel@tonic-gate 			}
545*0Sstevel@tonic-gate 			q->q_ptr = NULL;
546*0Sstevel@tonic-gate 			return (ENOMEM);
547*0Sstevel@tonic-gate 		}
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 		esp_ip_unbind->b_datap->db_type = M_PROTO;
550*0Sstevel@tonic-gate 		tur = (struct T_unbind_req *)esp_ip_unbind->b_rptr;
551*0Sstevel@tonic-gate 		tur->PRIM_type = T_UNBIND_REQ;
552*0Sstevel@tonic-gate 	} else {
553*0Sstevel@tonic-gate 		qprocson(q);
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	/*
557*0Sstevel@tonic-gate 	 * For now, there's not much I can do.  I'll be getting a message
558*0Sstevel@tonic-gate 	 * passed down to me from keysock (in my wput), and a T_BIND_ACK
559*0Sstevel@tonic-gate 	 * up from IP (in my rput).
560*0Sstevel@tonic-gate 	 */
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	return (0);
563*0Sstevel@tonic-gate }
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate /*
566*0Sstevel@tonic-gate  * ESP module close routine.
567*0Sstevel@tonic-gate  */
568*0Sstevel@tonic-gate static int
569*0Sstevel@tonic-gate ipsecesp_close(queue_t *q)
570*0Sstevel@tonic-gate {
571*0Sstevel@tonic-gate 	/*
572*0Sstevel@tonic-gate 	 * If esp_sadb.s_ip_q is attached to this instance, send a
573*0Sstevel@tonic-gate 	 * T_UNBIND_REQ to IP for the instance before doing
574*0Sstevel@tonic-gate 	 * a qprocsoff().
575*0Sstevel@tonic-gate 	 */
576*0Sstevel@tonic-gate 	if (WR(q) == esp_sadb.s_ip_q && esp_ip_unbind != NULL) {
577*0Sstevel@tonic-gate 		putnext(WR(q), esp_ip_unbind);
578*0Sstevel@tonic-gate 		esp_ip_unbind = NULL;
579*0Sstevel@tonic-gate 	}
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 	/*
582*0Sstevel@tonic-gate 	 * Clean up q_ptr, if needed.
583*0Sstevel@tonic-gate 	 */
584*0Sstevel@tonic-gate 	qprocsoff(q);
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	/* Keysock queue check is safe, because of OCEXCL perimeter. */
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 	if (q == esp_pfkey_q) {
589*0Sstevel@tonic-gate 		esp0dbg(("ipsecesp_close:  Ummm... keysock is closing ESP.\n"));
590*0Sstevel@tonic-gate 		esp_pfkey_q = NULL;
591*0Sstevel@tonic-gate 		/* Detach qtimeouts. */
592*0Sstevel@tonic-gate 		(void) quntimeout(q, esp_event);
593*0Sstevel@tonic-gate 	}
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	if (WR(q) == esp_sadb.s_ip_q) {
596*0Sstevel@tonic-gate 		/*
597*0Sstevel@tonic-gate 		 * If the esp_sadb.s_ip_q is attached to this instance, find
598*0Sstevel@tonic-gate 		 * another.  The OCEXCL outer perimeter helps us here.
599*0Sstevel@tonic-gate 		 */
600*0Sstevel@tonic-gate 		esp_sadb.s_ip_q = NULL;
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 		/*
603*0Sstevel@tonic-gate 		 * Find a replacement queue for esp_sadb.s_ip_q.
604*0Sstevel@tonic-gate 		 */
605*0Sstevel@tonic-gate 		if (esp_pfkey_q != NULL && esp_pfkey_q != RD(q)) {
606*0Sstevel@tonic-gate 			/*
607*0Sstevel@tonic-gate 			 * See if we can use the pfkey_q.
608*0Sstevel@tonic-gate 			 */
609*0Sstevel@tonic-gate 			esp_sadb.s_ip_q = WR(esp_pfkey_q);
610*0Sstevel@tonic-gate 		}
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 		if (esp_sadb.s_ip_q == NULL ||
613*0Sstevel@tonic-gate 		    !sadb_t_bind_req(esp_sadb.s_ip_q, IPPROTO_ESP)) {
614*0Sstevel@tonic-gate 			esp1dbg(("ipsecesp: Can't reassign ip_q.\n"));
615*0Sstevel@tonic-gate 			esp_sadb.s_ip_q = NULL;
616*0Sstevel@tonic-gate 		} else {
617*0Sstevel@tonic-gate 			esp_ip_unbind = allocb(sizeof (struct T_unbind_req),
618*0Sstevel@tonic-gate 			    BPRI_HI);
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 			if (esp_ip_unbind != NULL) {
621*0Sstevel@tonic-gate 				struct T_unbind_req *tur;
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 				esp_ip_unbind->b_datap->db_type = M_PROTO;
624*0Sstevel@tonic-gate 				tur = (struct T_unbind_req *)
625*0Sstevel@tonic-gate 				    esp_ip_unbind->b_rptr;
626*0Sstevel@tonic-gate 				tur->PRIM_type = T_UNBIND_REQ;
627*0Sstevel@tonic-gate 			}
628*0Sstevel@tonic-gate 			/* If it's NULL, I can't do much here. */
629*0Sstevel@tonic-gate 		}
630*0Sstevel@tonic-gate 	}
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	return (0);
633*0Sstevel@tonic-gate }
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate /*
636*0Sstevel@tonic-gate  * Add a number of bytes to what the SA has protected so far.  Return
637*0Sstevel@tonic-gate  * B_TRUE if the SA can still protect that many bytes.
638*0Sstevel@tonic-gate  *
639*0Sstevel@tonic-gate  * Caller must REFRELE the passed-in assoc.  This function must REFRELE
640*0Sstevel@tonic-gate  * any obtained peer SA.
641*0Sstevel@tonic-gate  */
642*0Sstevel@tonic-gate static boolean_t
643*0Sstevel@tonic-gate esp_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound)
644*0Sstevel@tonic-gate {
645*0Sstevel@tonic-gate 	ipsa_t *inassoc, *outassoc;
646*0Sstevel@tonic-gate 	isaf_t *bucket;
647*0Sstevel@tonic-gate 	boolean_t inrc, outrc, isv6;
648*0Sstevel@tonic-gate 	sadb_t *sp;
649*0Sstevel@tonic-gate 	int outhash;
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 	/* No peer?  No problem! */
652*0Sstevel@tonic-gate 	if (!assoc->ipsa_haspeer) {
653*0Sstevel@tonic-gate 		return (sadb_age_bytes(esp_pfkey_q, assoc, bytes,
654*0Sstevel@tonic-gate 		    B_TRUE));
655*0Sstevel@tonic-gate 	}
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	/*
658*0Sstevel@tonic-gate 	 * Otherwise, we want to grab both the original assoc and its peer.
659*0Sstevel@tonic-gate 	 * There might be a race for this, but if it's a real race, two
660*0Sstevel@tonic-gate 	 * expire messages may occur.  We limit this by only sending the
661*0Sstevel@tonic-gate 	 * expire message on one of the peers, we'll pick the inbound
662*0Sstevel@tonic-gate 	 * arbitrarily.
663*0Sstevel@tonic-gate 	 *
664*0Sstevel@tonic-gate 	 * If we need tight synchronization on the peer SA, then we need to
665*0Sstevel@tonic-gate 	 * reconsider.
666*0Sstevel@tonic-gate 	 */
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 	/* Use address length to select IPv6/IPv4 */
669*0Sstevel@tonic-gate 	isv6 = (assoc->ipsa_addrfam == AF_INET6);
670*0Sstevel@tonic-gate 	sp = isv6 ? &esp_sadb.s_v6 : &esp_sadb.s_v4;
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	if (inbound) {
673*0Sstevel@tonic-gate 		inassoc = assoc;
674*0Sstevel@tonic-gate 		if (isv6) {
675*0Sstevel@tonic-gate 			outhash = OUTBOUND_HASH_V6(*((in6_addr_t *)
676*0Sstevel@tonic-gate 			    &inassoc->ipsa_dstaddr));
677*0Sstevel@tonic-gate 		} else {
678*0Sstevel@tonic-gate 			outhash = OUTBOUND_HASH_V4(*((ipaddr_t *)
679*0Sstevel@tonic-gate 				&inassoc->ipsa_dstaddr));
680*0Sstevel@tonic-gate 		}
681*0Sstevel@tonic-gate 		bucket = &sp->sdb_of[outhash];
682*0Sstevel@tonic-gate 		mutex_enter(&bucket->isaf_lock);
683*0Sstevel@tonic-gate 		outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi,
684*0Sstevel@tonic-gate 		    inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr,
685*0Sstevel@tonic-gate 		    inassoc->ipsa_addrfam);
686*0Sstevel@tonic-gate 		mutex_exit(&bucket->isaf_lock);
687*0Sstevel@tonic-gate 		if (outassoc == NULL) {
688*0Sstevel@tonic-gate 			/* Q: Do we wish to set haspeer == B_FALSE? */
689*0Sstevel@tonic-gate 			esp0dbg(("esp_age_bytes: "
690*0Sstevel@tonic-gate 			    "can't find peer for inbound.\n"));
691*0Sstevel@tonic-gate 			return (sadb_age_bytes(esp_pfkey_q, inassoc,
692*0Sstevel@tonic-gate 			    bytes, B_TRUE));
693*0Sstevel@tonic-gate 		}
694*0Sstevel@tonic-gate 	} else {
695*0Sstevel@tonic-gate 		outassoc = assoc;
696*0Sstevel@tonic-gate 		bucket = &sp->sdb_if[INBOUND_HASH(outassoc->ipsa_spi)];
697*0Sstevel@tonic-gate 		mutex_enter(&bucket->isaf_lock);
698*0Sstevel@tonic-gate 		inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi,
699*0Sstevel@tonic-gate 		    outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr,
700*0Sstevel@tonic-gate 		    outassoc->ipsa_addrfam);
701*0Sstevel@tonic-gate 		mutex_exit(&bucket->isaf_lock);
702*0Sstevel@tonic-gate 		if (inassoc == NULL) {
703*0Sstevel@tonic-gate 			/* Q: Do we wish to set haspeer == B_FALSE? */
704*0Sstevel@tonic-gate 			esp0dbg(("esp_age_bytes: "
705*0Sstevel@tonic-gate 			    "can't find peer for outbound.\n"));
706*0Sstevel@tonic-gate 			return (sadb_age_bytes(esp_pfkey_q, outassoc,
707*0Sstevel@tonic-gate 			    bytes, B_TRUE));
708*0Sstevel@tonic-gate 		}
709*0Sstevel@tonic-gate 	}
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 	inrc = sadb_age_bytes(esp_pfkey_q, inassoc, bytes, B_TRUE);
712*0Sstevel@tonic-gate 	outrc = sadb_age_bytes(esp_pfkey_q, outassoc, bytes, B_FALSE);
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	/*
715*0Sstevel@tonic-gate 	 * REFRELE any peer SA.
716*0Sstevel@tonic-gate 	 *
717*0Sstevel@tonic-gate 	 * Because of the multi-line macro nature of IPSA_REFRELE, keep
718*0Sstevel@tonic-gate 	 * them in { }.
719*0Sstevel@tonic-gate 	 */
720*0Sstevel@tonic-gate 	if (inbound) {
721*0Sstevel@tonic-gate 		IPSA_REFRELE(outassoc);
722*0Sstevel@tonic-gate 	} else {
723*0Sstevel@tonic-gate 		IPSA_REFRELE(inassoc);
724*0Sstevel@tonic-gate 	}
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	return (inrc && outrc);
727*0Sstevel@tonic-gate }
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate /*
730*0Sstevel@tonic-gate  * Do incoming NAT-T manipulations for packet.
731*0Sstevel@tonic-gate  */
732*0Sstevel@tonic-gate static ipsec_status_t
733*0Sstevel@tonic-gate esp_fix_natt_checksums(mblk_t *data_mp, ipsa_t *assoc)
734*0Sstevel@tonic-gate {
735*0Sstevel@tonic-gate 	ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
736*0Sstevel@tonic-gate 	tcpha_t *tcph;
737*0Sstevel@tonic-gate 	udpha_t *udpha;
738*0Sstevel@tonic-gate 	/* Initialize to our inbound cksum adjustment... */
739*0Sstevel@tonic-gate 	uint32_t sum = assoc->ipsa_inbound_cksum;
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	switch (ipha->ipha_protocol) {
742*0Sstevel@tonic-gate 	case IPPROTO_TCP:
743*0Sstevel@tonic-gate 		tcph = (tcpha_t *)(data_mp->b_rptr +
744*0Sstevel@tonic-gate 		    IPH_HDR_LENGTH(ipha));
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate #define	DOWN_SUM(x) (x) = ((x) & 0xFFFF) +	 ((x) >> 16)
747*0Sstevel@tonic-gate 		sum += ~ntohs(tcph->tha_sum) & 0xFFFF;
748*0Sstevel@tonic-gate 		DOWN_SUM(sum);
749*0Sstevel@tonic-gate 		DOWN_SUM(sum);
750*0Sstevel@tonic-gate 		tcph->tha_sum = ~htons(sum);
751*0Sstevel@tonic-gate 		break;
752*0Sstevel@tonic-gate 	case IPPROTO_UDP:
753*0Sstevel@tonic-gate 		udpha = (udpha_t *)(data_mp->b_rptr + IPH_HDR_LENGTH(ipha));
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 		if (udpha->uha_checksum != 0) {
756*0Sstevel@tonic-gate 			/* Adujst if the inbound one was not zero. */
757*0Sstevel@tonic-gate 			sum += ~ntohs(udpha->uha_checksum) & 0xFFFF;
758*0Sstevel@tonic-gate 			DOWN_SUM(sum);
759*0Sstevel@tonic-gate 			DOWN_SUM(sum);
760*0Sstevel@tonic-gate 			udpha->uha_checksum = ~htons(sum);
761*0Sstevel@tonic-gate 			if (udpha->uha_checksum == 0)
762*0Sstevel@tonic-gate 				udpha->uha_checksum = 0xFFFF;
763*0Sstevel@tonic-gate 		}
764*0Sstevel@tonic-gate #undef DOWN_SUM
765*0Sstevel@tonic-gate 		break;
766*0Sstevel@tonic-gate 	case IPPROTO_IP:
767*0Sstevel@tonic-gate 		/*
768*0Sstevel@tonic-gate 		 * This case is only an issue for self-encapsulated
769*0Sstevel@tonic-gate 		 * packets.  So for now, fall through.
770*0Sstevel@tonic-gate 		 */
771*0Sstevel@tonic-gate 		break;
772*0Sstevel@tonic-gate 	}
773*0Sstevel@tonic-gate 	return (IPSEC_STATUS_SUCCESS);
774*0Sstevel@tonic-gate }
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate /*
778*0Sstevel@tonic-gate  * Strip ESP header and fix IP header
779*0Sstevel@tonic-gate  * Returns B_TRUE on success, B_FALSE if an error occured.
780*0Sstevel@tonic-gate  */
781*0Sstevel@tonic-gate static boolean_t
782*0Sstevel@tonic-gate esp_strip_header(mblk_t *data_mp, boolean_t isv4, uint32_t ivlen,
783*0Sstevel@tonic-gate     kstat_named_t **counter)
784*0Sstevel@tonic-gate {
785*0Sstevel@tonic-gate 	ipha_t *ipha;
786*0Sstevel@tonic-gate 	ip6_t *ip6h;
787*0Sstevel@tonic-gate 	uint_t divpoint;
788*0Sstevel@tonic-gate 	mblk_t *scratch;
789*0Sstevel@tonic-gate 	uint8_t nexthdr, padlen;
790*0Sstevel@tonic-gate 	uint8_t lastpad;
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	/*
793*0Sstevel@tonic-gate 	 * Strip ESP data and fix IP header.
794*0Sstevel@tonic-gate 	 *
795*0Sstevel@tonic-gate 	 * XXX In case the beginning of esp_inbound() changes to not do a
796*0Sstevel@tonic-gate 	 * pullup, this part of the code can remain unchanged.
797*0Sstevel@tonic-gate 	 */
798*0Sstevel@tonic-gate 	if (isv4) {
799*0Sstevel@tonic-gate 		ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ipha_t));
800*0Sstevel@tonic-gate 		ipha = (ipha_t *)data_mp->b_rptr;
801*0Sstevel@tonic-gate 		ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (esph_t) +
802*0Sstevel@tonic-gate 		    IPH_HDR_LENGTH(ipha));
803*0Sstevel@tonic-gate 		divpoint = IPH_HDR_LENGTH(ipha);
804*0Sstevel@tonic-gate 	} else {
805*0Sstevel@tonic-gate 		ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ip6_t));
806*0Sstevel@tonic-gate 		ip6h = (ip6_t *)data_mp->b_rptr;
807*0Sstevel@tonic-gate 		divpoint = ip_hdr_length_v6(data_mp, ip6h);
808*0Sstevel@tonic-gate 	}
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate 	scratch = data_mp;
811*0Sstevel@tonic-gate 	while (scratch->b_cont != NULL)
812*0Sstevel@tonic-gate 		scratch = scratch->b_cont;
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	ASSERT((scratch->b_wptr - scratch->b_rptr) >= 3);
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate 	/*
817*0Sstevel@tonic-gate 	 * "Next header" and padding length are the last two bytes in the
818*0Sstevel@tonic-gate 	 * ESP-protected datagram, thus the explicit - 1 and - 2.
819*0Sstevel@tonic-gate 	 * lastpad is the last byte of the padding, which can be used for
820*0Sstevel@tonic-gate 	 * a quick check to see if the padding is correct.
821*0Sstevel@tonic-gate 	 */
822*0Sstevel@tonic-gate 	nexthdr = *(scratch->b_wptr - 1);
823*0Sstevel@tonic-gate 	padlen = *(scratch->b_wptr - 2);
824*0Sstevel@tonic-gate 	lastpad = *(scratch->b_wptr - 3);
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate 	if (isv4) {
827*0Sstevel@tonic-gate 		/* Fix part of the IP header. */
828*0Sstevel@tonic-gate 		ipha->ipha_protocol = nexthdr;
829*0Sstevel@tonic-gate 		/*
830*0Sstevel@tonic-gate 		 * Reality check the padlen.  The explicit - 2 is for the
831*0Sstevel@tonic-gate 		 * padding length and the next-header bytes.
832*0Sstevel@tonic-gate 		 */
833*0Sstevel@tonic-gate 		if (padlen >= ntohs(ipha->ipha_length) - sizeof (ipha_t) - 2 -
834*0Sstevel@tonic-gate 		    sizeof (esph_t) - ivlen) {
835*0Sstevel@tonic-gate /* EXPORT DELETE START */
836*0Sstevel@tonic-gate 			ESP_BUMP_STAT(bad_decrypt);
837*0Sstevel@tonic-gate /* EXPORT DELETE END */
838*0Sstevel@tonic-gate 			ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
839*0Sstevel@tonic-gate 			    "Possibly corrupt ESP packet.");
840*0Sstevel@tonic-gate 			esp1dbg(("padlen (%d) is greater than:\n", padlen));
841*0Sstevel@tonic-gate 			esp1dbg(("pkt len(%d) - ip hdr - esp hdr - ivlen(%d) "
842*0Sstevel@tonic-gate 			    "= %d.\n", ntohs(ipha->ipha_length), ivlen,
843*0Sstevel@tonic-gate 			    (int)(ntohs(ipha->ipha_length) - sizeof (ipha_t) -
844*0Sstevel@tonic-gate 				2 - sizeof (esph_t) - ivlen)));
845*0Sstevel@tonic-gate 			*counter = &ipdrops_esp_bad_padlen;
846*0Sstevel@tonic-gate 			return (B_FALSE);
847*0Sstevel@tonic-gate 		}
848*0Sstevel@tonic-gate 
849*0Sstevel@tonic-gate 		/*
850*0Sstevel@tonic-gate 		 * Fix the rest of the header.  The explicit - 2 is for the
851*0Sstevel@tonic-gate 		 * padding length and the next-header bytes.
852*0Sstevel@tonic-gate 		 */
853*0Sstevel@tonic-gate 		ipha->ipha_length = htons(ntohs(ipha->ipha_length) - padlen -
854*0Sstevel@tonic-gate 		    2 - sizeof (esph_t) - ivlen);
855*0Sstevel@tonic-gate 		ipha->ipha_hdr_checksum = 0;
856*0Sstevel@tonic-gate 		ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha);
857*0Sstevel@tonic-gate 	} else {
858*0Sstevel@tonic-gate 		if (ip6h->ip6_nxt == IPPROTO_ESP) {
859*0Sstevel@tonic-gate 			ip6h->ip6_nxt = nexthdr;
860*0Sstevel@tonic-gate 		} else {
861*0Sstevel@tonic-gate 			ip6_pkt_t ipp;
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 			bzero(&ipp, sizeof (ipp));
864*0Sstevel@tonic-gate 			(void) ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL);
865*0Sstevel@tonic-gate 			if (ipp.ipp_dstopts != NULL) {
866*0Sstevel@tonic-gate 				ipp.ipp_dstopts->ip6d_nxt = nexthdr;
867*0Sstevel@tonic-gate 			} else if (ipp.ipp_rthdr != NULL) {
868*0Sstevel@tonic-gate 				ipp.ipp_rthdr->ip6r_nxt = nexthdr;
869*0Sstevel@tonic-gate 			} else if (ipp.ipp_hopopts != NULL) {
870*0Sstevel@tonic-gate 				ipp.ipp_hopopts->ip6h_nxt = nexthdr;
871*0Sstevel@tonic-gate 			} else {
872*0Sstevel@tonic-gate 				/* Panic a DEBUG kernel. */
873*0Sstevel@tonic-gate 				ASSERT(ipp.ipp_hopopts != NULL);
874*0Sstevel@tonic-gate 				/* Otherwise, pretend it's IP + ESP. */
875*0Sstevel@tonic-gate 				cmn_err(CE_WARN, "ESP IPv6 headers wrong.\n");
876*0Sstevel@tonic-gate 				ip6h->ip6_nxt = nexthdr;
877*0Sstevel@tonic-gate 			}
878*0Sstevel@tonic-gate 		}
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 		if (padlen >= ntohs(ip6h->ip6_plen) - 2 - sizeof (esph_t) -
881*0Sstevel@tonic-gate 		    ivlen) {
882*0Sstevel@tonic-gate /* EXPORT DELETE START */
883*0Sstevel@tonic-gate 			ESP_BUMP_STAT(bad_decrypt);
884*0Sstevel@tonic-gate /* EXPORT DELETE END */
885*0Sstevel@tonic-gate 			ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
886*0Sstevel@tonic-gate 			    "Possibly corrupt ESP packet.");
887*0Sstevel@tonic-gate 			esp1dbg(("padlen (%d) is greater than:\n", padlen));
888*0Sstevel@tonic-gate 			esp1dbg(("pkt len(%u) - ip hdr - esp hdr - ivlen(%d)"
889*0Sstevel@tonic-gate 			    " = %u.\n", (unsigned)(ntohs(ip6h->ip6_plen)
890*0Sstevel@tonic-gate 				+ sizeof (ip6_t)), ivlen,
891*0Sstevel@tonic-gate 			    (unsigned)(ntohs(ip6h->ip6_plen) - 2 -
892*0Sstevel@tonic-gate 				sizeof (esph_t) - ivlen)));
893*0Sstevel@tonic-gate 			*counter = &ipdrops_esp_bad_padlen;
894*0Sstevel@tonic-gate 			return (B_FALSE);
895*0Sstevel@tonic-gate 		}
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate 		/*
899*0Sstevel@tonic-gate 		 * Fix the rest of the header.  The explicit - 2 is for the
900*0Sstevel@tonic-gate 		 * padding length and the next-header bytes.  IPv6 is nice,
901*0Sstevel@tonic-gate 		 * because there's no hdr checksum!
902*0Sstevel@tonic-gate 		 */
903*0Sstevel@tonic-gate 		ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - padlen -
904*0Sstevel@tonic-gate 		    2 - sizeof (esph_t) - ivlen);
905*0Sstevel@tonic-gate 	}
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 	if (ipsecesp_padding_check > 0 &&
908*0Sstevel@tonic-gate 		padlen != lastpad && padlen != 0) {
909*0Sstevel@tonic-gate 		ipsec_rl_strlog(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
910*0Sstevel@tonic-gate 		    "Possibly corrupt ESP packet.");
911*0Sstevel@tonic-gate 		esp1dbg(("lastpad (%d) not equal to padlen (%d):\n",
912*0Sstevel@tonic-gate 		    lastpad, padlen));
913*0Sstevel@tonic-gate 		ESP_BUMP_STAT(bad_padding);
914*0Sstevel@tonic-gate 		*counter = &ipdrops_esp_bad_padding;
915*0Sstevel@tonic-gate 		return (B_FALSE);
916*0Sstevel@tonic-gate 	}
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate 	if (ipsecesp_padding_check > 1) {
919*0Sstevel@tonic-gate 		uint8_t *last = (uint8_t *)(scratch->b_wptr - 3);
920*0Sstevel@tonic-gate 		uint8_t lastval = *last;
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate 		/*
923*0Sstevel@tonic-gate 		 * this assert may have to become an if
924*0Sstevel@tonic-gate 		 * and a pullup if we start accepting
925*0Sstevel@tonic-gate 		 * multi-dblk mblks. Any packet here will
926*0Sstevel@tonic-gate 		 * have been pulled up in esp_inbound.
927*0Sstevel@tonic-gate 		 */
928*0Sstevel@tonic-gate 		ASSERT(MBLKL(scratch) >= lastval + 3);
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 		while (lastval != 0) {
931*0Sstevel@tonic-gate 			if (lastval != *last) {
932*0Sstevel@tonic-gate 				ipsec_rl_strlog(info.mi_idnum, 0, 0,
933*0Sstevel@tonic-gate 				    SL_ERROR | SL_WARN,
934*0Sstevel@tonic-gate 				    "Possibly corrupt ESP packet.");
935*0Sstevel@tonic-gate 				esp1dbg(("padding not in correct"
936*0Sstevel@tonic-gate 				    " format:\n"));
937*0Sstevel@tonic-gate 				ESP_BUMP_STAT(bad_padding);
938*0Sstevel@tonic-gate 				*counter = &ipdrops_esp_bad_padding;
939*0Sstevel@tonic-gate 				return (B_FALSE);
940*0Sstevel@tonic-gate 			}
941*0Sstevel@tonic-gate 			lastval--; last--;
942*0Sstevel@tonic-gate 		}
943*0Sstevel@tonic-gate 	}
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	/* Trim off the padding. */
946*0Sstevel@tonic-gate 	ASSERT(data_mp->b_cont == NULL);
947*0Sstevel@tonic-gate 	data_mp->b_wptr -= (padlen + 2);
948*0Sstevel@tonic-gate 
949*0Sstevel@tonic-gate 	/*
950*0Sstevel@tonic-gate 	 * Remove the ESP header.
951*0Sstevel@tonic-gate 	 *
952*0Sstevel@tonic-gate 	 * The above assertions about data_mp's size will make this work.
953*0Sstevel@tonic-gate 	 *
954*0Sstevel@tonic-gate 	 * XXX  Question:  If I send up and get back a contiguous mblk,
955*0Sstevel@tonic-gate 	 * would it be quicker to bcopy over, or keep doing the dupb stuff?
956*0Sstevel@tonic-gate 	 * I go with copying for now.
957*0Sstevel@tonic-gate 	 */
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 	if (IS_P2ALIGNED(data_mp->b_rptr, sizeof (uint32_t)) &&
960*0Sstevel@tonic-gate 	    IS_P2ALIGNED(ivlen, sizeof (uint32_t))) {
961*0Sstevel@tonic-gate 		uint8_t *start = data_mp->b_rptr;
962*0Sstevel@tonic-gate 		uint32_t *src, *dst;
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 		src = (uint32_t *)(start + divpoint);
965*0Sstevel@tonic-gate 		dst = (uint32_t *)(start + divpoint + sizeof (esph_t) + ivlen);
966*0Sstevel@tonic-gate 
967*0Sstevel@tonic-gate 		ASSERT(IS_P2ALIGNED(dst, sizeof (uint32_t)) &&
968*0Sstevel@tonic-gate 		    IS_P2ALIGNED(src, sizeof (uint32_t)));
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 		do {
971*0Sstevel@tonic-gate 			src--;
972*0Sstevel@tonic-gate 			dst--;
973*0Sstevel@tonic-gate 			*dst = *src;
974*0Sstevel@tonic-gate 		} while (src != (uint32_t *)start);
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 		data_mp->b_rptr = (uchar_t *)dst;
977*0Sstevel@tonic-gate 	} else {
978*0Sstevel@tonic-gate 		uint8_t *start = data_mp->b_rptr;
979*0Sstevel@tonic-gate 		uint8_t *src, *dst;
980*0Sstevel@tonic-gate 
981*0Sstevel@tonic-gate 		src = start + divpoint;
982*0Sstevel@tonic-gate 		dst = src + sizeof (esph_t) + ivlen;
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 		do {
985*0Sstevel@tonic-gate 			src--;
986*0Sstevel@tonic-gate 			dst--;
987*0Sstevel@tonic-gate 			*dst = *src;
988*0Sstevel@tonic-gate 		} while (src != start);
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 		data_mp->b_rptr = dst;
991*0Sstevel@tonic-gate 	}
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 	esp2dbg(("data_mp after inbound ESP adjustment:\n"));
994*0Sstevel@tonic-gate 	esp2dbg((dump_msg(data_mp)));
995*0Sstevel@tonic-gate 
996*0Sstevel@tonic-gate 	return (B_TRUE);
997*0Sstevel@tonic-gate }
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate /*
1000*0Sstevel@tonic-gate  * Updating use times can be tricky business if the ipsa_haspeer flag is
1001*0Sstevel@tonic-gate  * set.  This function is called once in an SA's lifetime.
1002*0Sstevel@tonic-gate  *
1003*0Sstevel@tonic-gate  * Caller has to REFRELE "assoc" which is passed in.  This function has
1004*0Sstevel@tonic-gate  * to REFRELE any peer SA that is obtained.
1005*0Sstevel@tonic-gate  */
1006*0Sstevel@tonic-gate static void
1007*0Sstevel@tonic-gate esp_set_usetime(ipsa_t *assoc, boolean_t inbound)
1008*0Sstevel@tonic-gate {
1009*0Sstevel@tonic-gate 	ipsa_t *inassoc, *outassoc;
1010*0Sstevel@tonic-gate 	isaf_t *bucket;
1011*0Sstevel@tonic-gate 	sadb_t *sp;
1012*0Sstevel@tonic-gate 	int outhash;
1013*0Sstevel@tonic-gate 	boolean_t isv6;
1014*0Sstevel@tonic-gate 
1015*0Sstevel@tonic-gate 	/* No peer?  No problem! */
1016*0Sstevel@tonic-gate 	if (!assoc->ipsa_haspeer) {
1017*0Sstevel@tonic-gate 		sadb_set_usetime(assoc);
1018*0Sstevel@tonic-gate 		return;
1019*0Sstevel@tonic-gate 	}
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate 	/*
1022*0Sstevel@tonic-gate 	 * Otherwise, we want to grab both the original assoc and its peer.
1023*0Sstevel@tonic-gate 	 * There might be a race for this, but if it's a real race, the times
1024*0Sstevel@tonic-gate 	 * will be out-of-synch by at most a second, and since our time
1025*0Sstevel@tonic-gate 	 * granularity is a second, this won't be a problem.
1026*0Sstevel@tonic-gate 	 *
1027*0Sstevel@tonic-gate 	 * If we need tight synchronization on the peer SA, then we need to
1028*0Sstevel@tonic-gate 	 * reconsider.
1029*0Sstevel@tonic-gate 	 */
1030*0Sstevel@tonic-gate 
1031*0Sstevel@tonic-gate 	/* Use address length to select IPv6/IPv4 */
1032*0Sstevel@tonic-gate 	isv6 = (assoc->ipsa_addrfam == AF_INET6);
1033*0Sstevel@tonic-gate 	sp = isv6 ? &esp_sadb.s_v6 : &esp_sadb.s_v4;
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 	if (inbound) {
1036*0Sstevel@tonic-gate 		inassoc = assoc;
1037*0Sstevel@tonic-gate 		if (isv6) {
1038*0Sstevel@tonic-gate 			outhash = OUTBOUND_HASH_V6(*((in6_addr_t *)
1039*0Sstevel@tonic-gate 			    &inassoc->ipsa_dstaddr));
1040*0Sstevel@tonic-gate 		} else {
1041*0Sstevel@tonic-gate 			outhash = OUTBOUND_HASH_V4(*((ipaddr_t *)
1042*0Sstevel@tonic-gate 				&inassoc->ipsa_dstaddr));
1043*0Sstevel@tonic-gate 		}
1044*0Sstevel@tonic-gate 		bucket = &sp->sdb_of[outhash];
1045*0Sstevel@tonic-gate 		mutex_enter(&bucket->isaf_lock);
1046*0Sstevel@tonic-gate 		outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi,
1047*0Sstevel@tonic-gate 		    inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr,
1048*0Sstevel@tonic-gate 		    inassoc->ipsa_addrfam);
1049*0Sstevel@tonic-gate 		mutex_exit(&bucket->isaf_lock);
1050*0Sstevel@tonic-gate 		if (outassoc == NULL) {
1051*0Sstevel@tonic-gate 			/* Q: Do we wish to set haspeer == B_FALSE? */
1052*0Sstevel@tonic-gate 			esp0dbg(("esp_set_usetime: "
1053*0Sstevel@tonic-gate 			    "can't find peer for inbound.\n"));
1054*0Sstevel@tonic-gate 			sadb_set_usetime(inassoc);
1055*0Sstevel@tonic-gate 			return;
1056*0Sstevel@tonic-gate 		}
1057*0Sstevel@tonic-gate 	} else {
1058*0Sstevel@tonic-gate 		outassoc = assoc;
1059*0Sstevel@tonic-gate 		bucket = &sp->sdb_if[INBOUND_HASH(outassoc->ipsa_spi)];
1060*0Sstevel@tonic-gate 		mutex_enter(&bucket->isaf_lock);
1061*0Sstevel@tonic-gate 		inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi,
1062*0Sstevel@tonic-gate 		    outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr,
1063*0Sstevel@tonic-gate 		    outassoc->ipsa_addrfam);
1064*0Sstevel@tonic-gate 		mutex_exit(&bucket->isaf_lock);
1065*0Sstevel@tonic-gate 		if (inassoc == NULL) {
1066*0Sstevel@tonic-gate 			/* Q: Do we wish to set haspeer == B_FALSE? */
1067*0Sstevel@tonic-gate 			esp0dbg(("esp_set_usetime: "
1068*0Sstevel@tonic-gate 			    "can't find peer for outbound.\n"));
1069*0Sstevel@tonic-gate 			sadb_set_usetime(outassoc);
1070*0Sstevel@tonic-gate 			return;
1071*0Sstevel@tonic-gate 		}
1072*0Sstevel@tonic-gate 	}
1073*0Sstevel@tonic-gate 
1074*0Sstevel@tonic-gate 	/* Update usetime on both. */
1075*0Sstevel@tonic-gate 	sadb_set_usetime(inassoc);
1076*0Sstevel@tonic-gate 	sadb_set_usetime(outassoc);
1077*0Sstevel@tonic-gate 
1078*0Sstevel@tonic-gate 	/*
1079*0Sstevel@tonic-gate 	 * REFRELE any peer SA.
1080*0Sstevel@tonic-gate 	 *
1081*0Sstevel@tonic-gate 	 * Because of the multi-line macro nature of IPSA_REFRELE, keep
1082*0Sstevel@tonic-gate 	 * them in { }.
1083*0Sstevel@tonic-gate 	 */
1084*0Sstevel@tonic-gate 	if (inbound) {
1085*0Sstevel@tonic-gate 		IPSA_REFRELE(outassoc);
1086*0Sstevel@tonic-gate 	} else {
1087*0Sstevel@tonic-gate 		IPSA_REFRELE(inassoc);
1088*0Sstevel@tonic-gate 	}
1089*0Sstevel@tonic-gate }
1090*0Sstevel@tonic-gate 
1091*0Sstevel@tonic-gate /*
1092*0Sstevel@tonic-gate  * Handle ESP inbound data for IPv4 and IPv6.
1093*0Sstevel@tonic-gate  * On success returns B_TRUE, on failure returns B_FALSE and frees the
1094*0Sstevel@tonic-gate  * mblk chain ipsec_in_mp.
1095*0Sstevel@tonic-gate  */
1096*0Sstevel@tonic-gate ipsec_status_t
1097*0Sstevel@tonic-gate esp_inbound(mblk_t *ipsec_in_mp, void *arg)
1098*0Sstevel@tonic-gate {
1099*0Sstevel@tonic-gate 	mblk_t *data_mp = ipsec_in_mp->b_cont;
1100*0Sstevel@tonic-gate 	ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr;
1101*0Sstevel@tonic-gate 	esph_t *esph = (esph_t *)arg;
1102*0Sstevel@tonic-gate 	ipsa_t *ipsa = ii->ipsec_in_esp_sa;
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate 	if (ipsa->ipsa_usetime == 0)
1105*0Sstevel@tonic-gate 		esp_set_usetime(ipsa, B_TRUE);
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate 	/*
1108*0Sstevel@tonic-gate 	 * We may wish to check replay in-range-only here as an optimization.
1109*0Sstevel@tonic-gate 	 * Include the reality check of ipsa->ipsa_replay >
1110*0Sstevel@tonic-gate 	 * ipsa->ipsa_replay_wsize for times when it's the first N packets,
1111*0Sstevel@tonic-gate 	 * where N == ipsa->ipsa_replay_wsize.
1112*0Sstevel@tonic-gate 	 *
1113*0Sstevel@tonic-gate 	 * Another check that may come here later is the "collision" check.
1114*0Sstevel@tonic-gate 	 * If legitimate packets flow quickly enough, this won't be a problem,
1115*0Sstevel@tonic-gate 	 * but collisions may cause authentication algorithm crunching to
1116*0Sstevel@tonic-gate 	 * take place when it doesn't need to.
1117*0Sstevel@tonic-gate 	 */
1118*0Sstevel@tonic-gate 	if (!sadb_replay_peek(ipsa, esph->esph_replay)) {
1119*0Sstevel@tonic-gate 		ESP_BUMP_STAT(replay_early_failures);
1120*0Sstevel@tonic-gate 		IP_ESP_BUMP_STAT(in_discards);
1121*0Sstevel@tonic-gate 		/*
1122*0Sstevel@tonic-gate 		 * TODO: Extract inbound interface from the IPSEC_IN
1123*0Sstevel@tonic-gate 		 * message's ii->ipsec_in_rill_index.
1124*0Sstevel@tonic-gate 		 */
1125*0Sstevel@tonic-gate 		ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL,
1126*0Sstevel@tonic-gate 		    &ipdrops_esp_early_replay, &esp_dropper);
1127*0Sstevel@tonic-gate 		return (IPSEC_STATUS_FAILED);
1128*0Sstevel@tonic-gate 	}
1129*0Sstevel@tonic-gate 
1130*0Sstevel@tonic-gate /* EXPORT DELETE START */
1131*0Sstevel@tonic-gate 	/*
1132*0Sstevel@tonic-gate 	 * Has this packet already been processed by a hardware
1133*0Sstevel@tonic-gate 	 * IPsec accelerator?
1134*0Sstevel@tonic-gate 	 */
1135*0Sstevel@tonic-gate 	if (ii->ipsec_in_accelerated) {
1136*0Sstevel@tonic-gate 		ipsec_status_t rv;
1137*0Sstevel@tonic-gate 		esp3dbg(("esp_inbound: pkt processed by ill=%d isv6=%d\n",
1138*0Sstevel@tonic-gate 		    ii->ipsec_in_ill_index, !ii->ipsec_in_v4));
1139*0Sstevel@tonic-gate 		rv = esp_inbound_accelerated(ipsec_in_mp,
1140*0Sstevel@tonic-gate 		    data_mp, ii->ipsec_in_v4, ipsa);
1141*0Sstevel@tonic-gate 		return (rv);
1142*0Sstevel@tonic-gate 	}
1143*0Sstevel@tonic-gate 	ESP_BUMP_STAT(noaccel);
1144*0Sstevel@tonic-gate /* EXPORT DELETE END */
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate 	/*
1147*0Sstevel@tonic-gate 	 * Adjust the IP header's payload length to reflect the removal
1148*0Sstevel@tonic-gate 	 * of the ICV.
1149*0Sstevel@tonic-gate 	 */
1150*0Sstevel@tonic-gate 	if (!ii->ipsec_in_v4) {
1151*0Sstevel@tonic-gate 		ip6_t *ip6h = (ip6_t *)data_mp->b_rptr;
1152*0Sstevel@tonic-gate 		ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) -
1153*0Sstevel@tonic-gate 		    ipsa->ipsa_mac_len);
1154*0Sstevel@tonic-gate 	} else {
1155*0Sstevel@tonic-gate 		ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
1156*0Sstevel@tonic-gate 		ipha->ipha_length = htons(ntohs(ipha->ipha_length) -
1157*0Sstevel@tonic-gate 		    ipsa->ipsa_mac_len);
1158*0Sstevel@tonic-gate 	}
1159*0Sstevel@tonic-gate 
1160*0Sstevel@tonic-gate 	/* submit the request to the crypto framework */
1161*0Sstevel@tonic-gate 	return (esp_submit_req_inbound(ipsec_in_mp, ipsa,
1162*0Sstevel@tonic-gate 	    (uint8_t *)esph - data_mp->b_rptr));
1163*0Sstevel@tonic-gate }
1164*0Sstevel@tonic-gate 
1165*0Sstevel@tonic-gate /*
1166*0Sstevel@tonic-gate  * Perform the really difficult work of inserting the proposed situation.
1167*0Sstevel@tonic-gate  * Called while holding the algorithm lock.
1168*0Sstevel@tonic-gate  */
1169*0Sstevel@tonic-gate static void
1170*0Sstevel@tonic-gate esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs)
1171*0Sstevel@tonic-gate {
1172*0Sstevel@tonic-gate 	sadb_comb_t *comb = (sadb_comb_t *)(prop + 1);
1173*0Sstevel@tonic-gate 	ipsec_out_t *io;
1174*0Sstevel@tonic-gate 	ipsec_action_t *ap;
1175*0Sstevel@tonic-gate 	ipsec_prot_t *prot;
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&alg_lock));
1178*0Sstevel@tonic-gate 	io = (ipsec_out_t *)acqrec->ipsacq_mp->b_rptr;
1179*0Sstevel@tonic-gate 	ASSERT(io->ipsec_out_type == IPSEC_OUT);
1180*0Sstevel@tonic-gate 
1181*0Sstevel@tonic-gate 	prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
1182*0Sstevel@tonic-gate 	prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t));
1183*0Sstevel@tonic-gate 	*(uint32_t *)(&prop->sadb_prop_replay) = 0;	/* Quick zero-out! */
1184*0Sstevel@tonic-gate 
1185*0Sstevel@tonic-gate 	prop->sadb_prop_replay = ipsecesp_replay_size;
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate 	/*
1188*0Sstevel@tonic-gate 	 * Based upon algorithm properties, and what-not, prioritize
1189*0Sstevel@tonic-gate 	 * a proposal.  If the IPSEC_OUT message has an algorithm specified,
1190*0Sstevel@tonic-gate 	 * use it first and foremost.
1191*0Sstevel@tonic-gate 	 *
1192*0Sstevel@tonic-gate 	 * For each action in policy list
1193*0Sstevel@tonic-gate 	 *   Add combination.  If I've hit limit, return.
1194*0Sstevel@tonic-gate 	 */
1195*0Sstevel@tonic-gate 
1196*0Sstevel@tonic-gate 	for (ap = acqrec->ipsacq_act; ap != NULL;
1197*0Sstevel@tonic-gate 	    ap = ap->ipa_next) {
1198*0Sstevel@tonic-gate /* EXPORT DELETE START */
1199*0Sstevel@tonic-gate 		ipsec_alginfo_t *ealg = NULL;
1200*0Sstevel@tonic-gate /* EXPORT DELETE END */
1201*0Sstevel@tonic-gate 		ipsec_alginfo_t *aalg = NULL;
1202*0Sstevel@tonic-gate 
1203*0Sstevel@tonic-gate 		if (ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY)
1204*0Sstevel@tonic-gate 			continue;
1205*0Sstevel@tonic-gate 
1206*0Sstevel@tonic-gate 		prot = &ap->ipa_act.ipa_apply;
1207*0Sstevel@tonic-gate 
1208*0Sstevel@tonic-gate 		if (!(prot->ipp_use_esp))
1209*0Sstevel@tonic-gate 			continue;
1210*0Sstevel@tonic-gate 
1211*0Sstevel@tonic-gate 		if (prot->ipp_esp_auth_alg != 0) {
1212*0Sstevel@tonic-gate 			aalg = ipsec_alglists[IPSEC_ALG_AUTH]
1213*0Sstevel@tonic-gate 			    [prot->ipp_esp_auth_alg];
1214*0Sstevel@tonic-gate 			if (aalg == NULL || !ALG_VALID(aalg))
1215*0Sstevel@tonic-gate 				continue;
1216*0Sstevel@tonic-gate 		}
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate /* EXPORT DELETE START */
1219*0Sstevel@tonic-gate 		ASSERT(prot->ipp_encr_alg > 0);
1220*0Sstevel@tonic-gate 		ealg = ipsec_alglists[IPSEC_ALG_ENCR][prot->ipp_encr_alg];
1221*0Sstevel@tonic-gate 		if (ealg == NULL || !ALG_VALID(ealg))
1222*0Sstevel@tonic-gate 			continue;
1223*0Sstevel@tonic-gate /* EXPORT DELETE END */
1224*0Sstevel@tonic-gate 
1225*0Sstevel@tonic-gate 		comb->sadb_comb_flags = 0;
1226*0Sstevel@tonic-gate 		comb->sadb_comb_reserved = 0;
1227*0Sstevel@tonic-gate /* EXPORT DELETE START */
1228*0Sstevel@tonic-gate 		comb->sadb_comb_encrypt = ealg->alg_id;
1229*0Sstevel@tonic-gate 		comb->sadb_comb_encrypt_minbits = prot->ipp_espe_minbits;
1230*0Sstevel@tonic-gate 		comb->sadb_comb_encrypt_maxbits = prot->ipp_espe_maxbits;
1231*0Sstevel@tonic-gate /* EXPORT DELETE END */
1232*0Sstevel@tonic-gate 		if (aalg == NULL) {
1233*0Sstevel@tonic-gate 			comb->sadb_comb_auth = 0;
1234*0Sstevel@tonic-gate 			comb->sadb_comb_auth_minbits = 0;
1235*0Sstevel@tonic-gate 			comb->sadb_comb_auth_maxbits = 0;
1236*0Sstevel@tonic-gate 		} else {
1237*0Sstevel@tonic-gate 			comb->sadb_comb_auth = aalg->alg_id;
1238*0Sstevel@tonic-gate 			comb->sadb_comb_auth_minbits = prot->ipp_espa_minbits;
1239*0Sstevel@tonic-gate 			comb->sadb_comb_auth_maxbits = prot->ipp_espa_maxbits;
1240*0Sstevel@tonic-gate 		}
1241*0Sstevel@tonic-gate 
1242*0Sstevel@tonic-gate 		/*
1243*0Sstevel@tonic-gate 		 * The following may be based on algorithm
1244*0Sstevel@tonic-gate 		 * properties, but in the meantime, we just pick
1245*0Sstevel@tonic-gate 		 * some good, sensible numbers.  Key mgmt. can
1246*0Sstevel@tonic-gate 		 * (and perhaps should) be the place to finalize
1247*0Sstevel@tonic-gate 		 * such decisions.
1248*0Sstevel@tonic-gate 		 */
1249*0Sstevel@tonic-gate 
1250*0Sstevel@tonic-gate 		/*
1251*0Sstevel@tonic-gate 		 * No limits on allocations, since we really don't
1252*0Sstevel@tonic-gate 		 * support that concept currently.
1253*0Sstevel@tonic-gate 		 */
1254*0Sstevel@tonic-gate 		comb->sadb_comb_soft_allocations = 0;
1255*0Sstevel@tonic-gate 		comb->sadb_comb_hard_allocations = 0;
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate 		/*
1258*0Sstevel@tonic-gate 		 * These may want to come from policy rule..
1259*0Sstevel@tonic-gate 		 */
1260*0Sstevel@tonic-gate 		comb->sadb_comb_soft_bytes = ipsecesp_default_soft_bytes;
1261*0Sstevel@tonic-gate 		comb->sadb_comb_hard_bytes = ipsecesp_default_hard_bytes;
1262*0Sstevel@tonic-gate 		comb->sadb_comb_soft_addtime = ipsecesp_default_soft_addtime;
1263*0Sstevel@tonic-gate 		comb->sadb_comb_hard_addtime = ipsecesp_default_hard_addtime;
1264*0Sstevel@tonic-gate 		comb->sadb_comb_soft_usetime = ipsecesp_default_soft_usetime;
1265*0Sstevel@tonic-gate 		comb->sadb_comb_hard_usetime = ipsecesp_default_hard_usetime;
1266*0Sstevel@tonic-gate 
1267*0Sstevel@tonic-gate 		prop->sadb_prop_len += SADB_8TO64(sizeof (*comb));
1268*0Sstevel@tonic-gate 		if (--combs == 0)
1269*0Sstevel@tonic-gate 			break;	/* out of space.. */
1270*0Sstevel@tonic-gate 		comb++;
1271*0Sstevel@tonic-gate 	}
1272*0Sstevel@tonic-gate }
1273*0Sstevel@tonic-gate 
1274*0Sstevel@tonic-gate /*
1275*0Sstevel@tonic-gate  * Prepare and actually send the SADB_ACQUIRE message to PF_KEY.
1276*0Sstevel@tonic-gate  */
1277*0Sstevel@tonic-gate static void
1278*0Sstevel@tonic-gate esp_send_acquire(ipsacq_t *acqrec, mblk_t *extended)
1279*0Sstevel@tonic-gate {
1280*0Sstevel@tonic-gate 	mblk_t *pfkeymp, *msgmp;
1281*0Sstevel@tonic-gate 	uint_t allocsize, combs;
1282*0Sstevel@tonic-gate 	sadb_msg_t *samsg;
1283*0Sstevel@tonic-gate 	sadb_prop_t *prop;
1284*0Sstevel@tonic-gate 	uint8_t *cur, *end;
1285*0Sstevel@tonic-gate 
1286*0Sstevel@tonic-gate 	ESP_BUMP_STAT(acquire_requests);
1287*0Sstevel@tonic-gate 
1288*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&acqrec->ipsacq_lock));
1289*0Sstevel@tonic-gate 
1290*0Sstevel@tonic-gate 	pfkeymp = sadb_keysock_out(0);
1291*0Sstevel@tonic-gate 	if (pfkeymp == NULL) {
1292*0Sstevel@tonic-gate 		esp0dbg(("esp_send_acquire: 1st allocb() failed.\n"));
1293*0Sstevel@tonic-gate 		/* Just bail. */
1294*0Sstevel@tonic-gate 		goto done;
1295*0Sstevel@tonic-gate 	}
1296*0Sstevel@tonic-gate 
1297*0Sstevel@tonic-gate 	/*
1298*0Sstevel@tonic-gate 	 * First, allocate a basic ACQUIRE message.  Beyond that,
1299*0Sstevel@tonic-gate 	 * you need to extract certificate info from
1300*0Sstevel@tonic-gate 	 */
1301*0Sstevel@tonic-gate 	allocsize = sizeof (sadb_msg_t) + sizeof (sadb_address_t) +
1302*0Sstevel@tonic-gate 	    sizeof (sadb_address_t) + sizeof (sadb_prop_t);
1303*0Sstevel@tonic-gate 
1304*0Sstevel@tonic-gate 	switch (acqrec->ipsacq_addrfam) {
1305*0Sstevel@tonic-gate 	case AF_INET:
1306*0Sstevel@tonic-gate 		allocsize += 2 * sizeof (struct sockaddr_in);
1307*0Sstevel@tonic-gate 		break;
1308*0Sstevel@tonic-gate 	case AF_INET6:
1309*0Sstevel@tonic-gate 		allocsize += 2 * sizeof (struct sockaddr_in6);
1310*0Sstevel@tonic-gate 		break;
1311*0Sstevel@tonic-gate 	}
1312*0Sstevel@tonic-gate 
1313*0Sstevel@tonic-gate 	mutex_enter(&alg_lock);
1314*0Sstevel@tonic-gate 
1315*0Sstevel@tonic-gate /* EXPORT DELETE START */
1316*0Sstevel@tonic-gate #if 0
1317*0Sstevel@tonic-gate /* EXPORT DELETE END */
1318*0Sstevel@tonic-gate 	combs = ipsec_nalgs[IPSEC_ALG_AUTH];
1319*0Sstevel@tonic-gate /* EXPORT DELETE START */
1320*0Sstevel@tonic-gate #else
1321*0Sstevel@tonic-gate 	combs = ipsec_nalgs[IPSEC_ALG_AUTH] * ipsec_nalgs[IPSEC_ALG_ENCR];
1322*0Sstevel@tonic-gate #endif
1323*0Sstevel@tonic-gate /* EXPORT DELETE END */
1324*0Sstevel@tonic-gate 
1325*0Sstevel@tonic-gate 	allocsize += combs * sizeof (sadb_comb_t);
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate 	/*
1328*0Sstevel@tonic-gate 	 * XXX If there are:
1329*0Sstevel@tonic-gate 	 *	certificate IDs
1330*0Sstevel@tonic-gate 	 *	proxy address
1331*0Sstevel@tonic-gate 	 *	<Others>
1332*0Sstevel@tonic-gate 	 * add additional allocation size.
1333*0Sstevel@tonic-gate 	 */
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 	msgmp = allocb(allocsize, BPRI_HI);
1336*0Sstevel@tonic-gate 	if (msgmp == NULL) {
1337*0Sstevel@tonic-gate 		esp0dbg(("esp_send_acquire: 2nd allocb() failed.\n"));
1338*0Sstevel@tonic-gate 		/* Just bail. */
1339*0Sstevel@tonic-gate 		freemsg(pfkeymp);
1340*0Sstevel@tonic-gate 		pfkeymp = NULL;
1341*0Sstevel@tonic-gate 		goto done;
1342*0Sstevel@tonic-gate 	}
1343*0Sstevel@tonic-gate 
1344*0Sstevel@tonic-gate 	cur = msgmp->b_rptr;
1345*0Sstevel@tonic-gate 	end = cur + allocsize;
1346*0Sstevel@tonic-gate 	samsg = (sadb_msg_t *)cur;
1347*0Sstevel@tonic-gate 	pfkeymp->b_cont = msgmp;
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 	/* Set up ACQUIRE. */
1350*0Sstevel@tonic-gate 	cur = sadb_setup_acquire(cur, end, acqrec);
1351*0Sstevel@tonic-gate 	if (cur == NULL) {
1352*0Sstevel@tonic-gate 		esp0dbg(("sadb_setup_acquire failed.\n"));
1353*0Sstevel@tonic-gate 		/* Just bail. */
1354*0Sstevel@tonic-gate 		freemsg(pfkeymp);
1355*0Sstevel@tonic-gate 		pfkeymp = NULL;
1356*0Sstevel@tonic-gate 		goto done;
1357*0Sstevel@tonic-gate 	}
1358*0Sstevel@tonic-gate 	samsg->sadb_msg_satype = SADB_SATYPE_ESP;
1359*0Sstevel@tonic-gate 
1360*0Sstevel@tonic-gate 	/* XXX Insert proxy address information here. */
1361*0Sstevel@tonic-gate 
1362*0Sstevel@tonic-gate 	/* XXX Insert identity information here. */
1363*0Sstevel@tonic-gate 
1364*0Sstevel@tonic-gate 	/* XXXMLS Insert sensitivity information here. */
1365*0Sstevel@tonic-gate 
1366*0Sstevel@tonic-gate 	/* Insert proposal here. */
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate 	prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len);
1369*0Sstevel@tonic-gate 	esp_insert_prop(prop, acqrec, combs);
1370*0Sstevel@tonic-gate 	samsg->sadb_msg_len += prop->sadb_prop_len;
1371*0Sstevel@tonic-gate 	msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len);
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate done:
1374*0Sstevel@tonic-gate 	mutex_exit(&alg_lock);
1375*0Sstevel@tonic-gate 
1376*0Sstevel@tonic-gate 	/*
1377*0Sstevel@tonic-gate 	 * Must mutex_exit() before sending PF_KEY message up, in
1378*0Sstevel@tonic-gate 	 * order to avoid recursive mutex_enter() if there are no registered
1379*0Sstevel@tonic-gate 	 * listeners.
1380*0Sstevel@tonic-gate 	 *
1381*0Sstevel@tonic-gate 	 * Once I've sent the message, I'm cool anyway.
1382*0Sstevel@tonic-gate 	 */
1383*0Sstevel@tonic-gate 	mutex_exit(&acqrec->ipsacq_lock);
1384*0Sstevel@tonic-gate 	if (esp_pfkey_q != NULL && pfkeymp != NULL) {
1385*0Sstevel@tonic-gate 		if (extended != NULL) {
1386*0Sstevel@tonic-gate 			putnext(esp_pfkey_q, extended);
1387*0Sstevel@tonic-gate 		}
1388*0Sstevel@tonic-gate 		putnext(esp_pfkey_q, pfkeymp);
1389*0Sstevel@tonic-gate 		return;
1390*0Sstevel@tonic-gate 	}
1391*0Sstevel@tonic-gate 	/* XXX freemsg() works for extended == NULL. */
1392*0Sstevel@tonic-gate 	freemsg(extended);
1393*0Sstevel@tonic-gate 	freemsg(pfkeymp);
1394*0Sstevel@tonic-gate }
1395*0Sstevel@tonic-gate 
1396*0Sstevel@tonic-gate /*
1397*0Sstevel@tonic-gate  * Handle the SADB_GETSPI message.  Create a larval SA.
1398*0Sstevel@tonic-gate  */
1399*0Sstevel@tonic-gate static void
1400*0Sstevel@tonic-gate esp_getspi(mblk_t *mp, keysock_in_t *ksi)
1401*0Sstevel@tonic-gate {
1402*0Sstevel@tonic-gate 	ipsa_t *newbie, *target;
1403*0Sstevel@tonic-gate 	isaf_t *outbound, *inbound;
1404*0Sstevel@tonic-gate 	int rc, diagnostic;
1405*0Sstevel@tonic-gate 	sadb_sa_t *assoc;
1406*0Sstevel@tonic-gate 	keysock_out_t *kso;
1407*0Sstevel@tonic-gate 	uint32_t newspi;
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 	/*
1410*0Sstevel@tonic-gate 	 * Randomly generate a proposed SPI value
1411*0Sstevel@tonic-gate 	 */
1412*0Sstevel@tonic-gate 	(void) random_get_pseudo_bytes((uint8_t *)&newspi, sizeof (uint32_t));
1413*0Sstevel@tonic-gate 	newbie = sadb_getspi(ksi, newspi, &diagnostic);
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 	if (newbie == NULL) {
1416*0Sstevel@tonic-gate 		sadb_pfkey_error(esp_pfkey_q, mp, ENOMEM, diagnostic,
1417*0Sstevel@tonic-gate 		    ksi->ks_in_serial);
1418*0Sstevel@tonic-gate 		return;
1419*0Sstevel@tonic-gate 	} else if (newbie == (ipsa_t *)-1) {
1420*0Sstevel@tonic-gate 		sadb_pfkey_error(esp_pfkey_q, mp, EINVAL, diagnostic,
1421*0Sstevel@tonic-gate 		    ksi->ks_in_serial);
1422*0Sstevel@tonic-gate 		return;
1423*0Sstevel@tonic-gate 	}
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 	/*
1426*0Sstevel@tonic-gate 	 * XXX - We may randomly collide.  We really should recover from this.
1427*0Sstevel@tonic-gate 	 *	 Unfortunately, that could require spending way-too-much-time
1428*0Sstevel@tonic-gate 	 *	 in here.  For now, let the user retry.
1429*0Sstevel@tonic-gate 	 */
1430*0Sstevel@tonic-gate 
1431*0Sstevel@tonic-gate 	if (newbie->ipsa_addrfam == AF_INET6) {
1432*0Sstevel@tonic-gate 		outbound = &esp_sadb.s_v6.sdb_of[
1433*0Sstevel@tonic-gate 		    OUTBOUND_HASH_V6(*(uint32_t *)(newbie->ipsa_dstaddr))];
1434*0Sstevel@tonic-gate 		inbound = &esp_sadb.s_v6.sdb_if[INBOUND_HASH(newbie->ipsa_spi)];
1435*0Sstevel@tonic-gate 	} else {
1436*0Sstevel@tonic-gate 		ASSERT(newbie->ipsa_addrfam == AF_INET);
1437*0Sstevel@tonic-gate 		outbound = &esp_sadb.s_v4.sdb_of[
1438*0Sstevel@tonic-gate 		    OUTBOUND_HASH_V4(*(uint32_t *)(newbie->ipsa_dstaddr))];
1439*0Sstevel@tonic-gate 		inbound = &esp_sadb.s_v4.sdb_if[INBOUND_HASH(newbie->ipsa_spi)];
1440*0Sstevel@tonic-gate 	}
1441*0Sstevel@tonic-gate 
1442*0Sstevel@tonic-gate 	mutex_enter(&outbound->isaf_lock);
1443*0Sstevel@tonic-gate 	mutex_enter(&inbound->isaf_lock);
1444*0Sstevel@tonic-gate 
1445*0Sstevel@tonic-gate 	/*
1446*0Sstevel@tonic-gate 	 * Check for collisions (i.e. did sadb_getspi() return with something
1447*0Sstevel@tonic-gate 	 * that already exists?).
1448*0Sstevel@tonic-gate 	 *
1449*0Sstevel@tonic-gate 	 * Try outbound first.  Even though SADB_GETSPI is traditionally
1450*0Sstevel@tonic-gate 	 * for inbound SAs, you never know what a user might do.
1451*0Sstevel@tonic-gate 	 */
1452*0Sstevel@tonic-gate 	target = ipsec_getassocbyspi(outbound, newbie->ipsa_spi,
1453*0Sstevel@tonic-gate 	    newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, newbie->ipsa_addrfam);
1454*0Sstevel@tonic-gate 	if (target == NULL) {
1455*0Sstevel@tonic-gate 		target = ipsec_getassocbyspi(inbound, newbie->ipsa_spi,
1456*0Sstevel@tonic-gate 		    newbie->ipsa_srcaddr, newbie->ipsa_dstaddr,
1457*0Sstevel@tonic-gate 		    newbie->ipsa_addrfam);
1458*0Sstevel@tonic-gate 	}
1459*0Sstevel@tonic-gate 
1460*0Sstevel@tonic-gate 	/*
1461*0Sstevel@tonic-gate 	 * I don't have collisions elsewhere!
1462*0Sstevel@tonic-gate 	 * (Nor will I because I'm still holding inbound/outbound locks.)
1463*0Sstevel@tonic-gate 	 */
1464*0Sstevel@tonic-gate 
1465*0Sstevel@tonic-gate 	if (target != NULL) {
1466*0Sstevel@tonic-gate 		rc = EEXIST;
1467*0Sstevel@tonic-gate 		IPSA_REFRELE(target);
1468*0Sstevel@tonic-gate 	} else {
1469*0Sstevel@tonic-gate 		/*
1470*0Sstevel@tonic-gate 		 * sadb_insertassoc() also checks for collisions, so
1471*0Sstevel@tonic-gate 		 * if there's a colliding entry, rc will be set
1472*0Sstevel@tonic-gate 		 * to EEXIST.
1473*0Sstevel@tonic-gate 		 */
1474*0Sstevel@tonic-gate 		rc = sadb_insertassoc(newbie, inbound);
1475*0Sstevel@tonic-gate 		(void) drv_getparm(TIME, &newbie->ipsa_hardexpiretime);
1476*0Sstevel@tonic-gate 		newbie->ipsa_hardexpiretime += ipsecesp_larval_timeout;
1477*0Sstevel@tonic-gate 	}
1478*0Sstevel@tonic-gate 
1479*0Sstevel@tonic-gate 	/*
1480*0Sstevel@tonic-gate 	 * Can exit outbound mutex.  Hold inbound until we're done
1481*0Sstevel@tonic-gate 	 * with newbie.
1482*0Sstevel@tonic-gate 	 */
1483*0Sstevel@tonic-gate 	mutex_exit(&outbound->isaf_lock);
1484*0Sstevel@tonic-gate 
1485*0Sstevel@tonic-gate 	if (rc != 0) {
1486*0Sstevel@tonic-gate 		mutex_exit(&inbound->isaf_lock);
1487*0Sstevel@tonic-gate 		IPSA_REFRELE(newbie);
1488*0Sstevel@tonic-gate 		sadb_pfkey_error(esp_pfkey_q, mp, rc, SADB_X_DIAGNOSTIC_NONE,
1489*0Sstevel@tonic-gate 		    ksi->ks_in_serial);
1490*0Sstevel@tonic-gate 		return;
1491*0Sstevel@tonic-gate 	}
1492*0Sstevel@tonic-gate 
1493*0Sstevel@tonic-gate 
1494*0Sstevel@tonic-gate 	/* Can write here because I'm still holding the bucket lock. */
1495*0Sstevel@tonic-gate 	newbie->ipsa_type = SADB_SATYPE_ESP;
1496*0Sstevel@tonic-gate 
1497*0Sstevel@tonic-gate 	/*
1498*0Sstevel@tonic-gate 	 * Construct successful return message.  We have one thing going
1499*0Sstevel@tonic-gate 	 * for us in PF_KEY v2.  That's the fact that
1500*0Sstevel@tonic-gate 	 *	sizeof (sadb_spirange_t) == sizeof (sadb_sa_t)
1501*0Sstevel@tonic-gate 	 */
1502*0Sstevel@tonic-gate 	assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE];
1503*0Sstevel@tonic-gate 	assoc->sadb_sa_exttype = SADB_EXT_SA;
1504*0Sstevel@tonic-gate 	assoc->sadb_sa_spi = newbie->ipsa_spi;
1505*0Sstevel@tonic-gate 	*((uint64_t *)(&assoc->sadb_sa_replay)) = 0;
1506*0Sstevel@tonic-gate 	mutex_exit(&inbound->isaf_lock);
1507*0Sstevel@tonic-gate 
1508*0Sstevel@tonic-gate 	/* Convert KEYSOCK_IN to KEYSOCK_OUT. */
1509*0Sstevel@tonic-gate 	kso = (keysock_out_t *)ksi;
1510*0Sstevel@tonic-gate 	kso->ks_out_len = sizeof (*kso);
1511*0Sstevel@tonic-gate 	kso->ks_out_serial = ksi->ks_in_serial;
1512*0Sstevel@tonic-gate 	kso->ks_out_type = KEYSOCK_OUT;
1513*0Sstevel@tonic-gate 
1514*0Sstevel@tonic-gate 	/*
1515*0Sstevel@tonic-gate 	 * Can safely putnext() to esp_pfkey_q, because this is a turnaround
1516*0Sstevel@tonic-gate 	 * from the esp_pfkey_q.
1517*0Sstevel@tonic-gate 	 */
1518*0Sstevel@tonic-gate 	putnext(esp_pfkey_q, mp);
1519*0Sstevel@tonic-gate }
1520*0Sstevel@tonic-gate 
1521*0Sstevel@tonic-gate /*
1522*0Sstevel@tonic-gate  * Insert the ESP header into a packet.  Duplicate an mblk, and insert a newly
1523*0Sstevel@tonic-gate  * allocated mblk with the ESP header in between the two.
1524*0Sstevel@tonic-gate  */
1525*0Sstevel@tonic-gate static boolean_t
1526*0Sstevel@tonic-gate esp_insert_esp(mblk_t *mp, mblk_t *esp_mp, uint_t divpoint)
1527*0Sstevel@tonic-gate {
1528*0Sstevel@tonic-gate 	mblk_t *split_mp = mp;
1529*0Sstevel@tonic-gate 	uint_t wheretodiv = divpoint;
1530*0Sstevel@tonic-gate 
1531*0Sstevel@tonic-gate 	while ((split_mp->b_wptr - split_mp->b_rptr) < wheretodiv) {
1532*0Sstevel@tonic-gate 		wheretodiv -= (split_mp->b_wptr - split_mp->b_rptr);
1533*0Sstevel@tonic-gate 		split_mp = split_mp->b_cont;
1534*0Sstevel@tonic-gate 		ASSERT(split_mp != NULL);
1535*0Sstevel@tonic-gate 	}
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate 	if (split_mp->b_wptr - split_mp->b_rptr != wheretodiv) {
1538*0Sstevel@tonic-gate 		mblk_t *scratch;
1539*0Sstevel@tonic-gate 
1540*0Sstevel@tonic-gate 		/* "scratch" is the 2nd half, split_mp is the first. */
1541*0Sstevel@tonic-gate 		scratch = dupb(split_mp);
1542*0Sstevel@tonic-gate 		if (scratch == NULL) {
1543*0Sstevel@tonic-gate 			esp1dbg(("esp_insert_esp: can't allocate scratch.\n"));
1544*0Sstevel@tonic-gate 			return (B_FALSE);
1545*0Sstevel@tonic-gate 		}
1546*0Sstevel@tonic-gate 		/* NOTE:  dupb() doesn't set b_cont appropriately. */
1547*0Sstevel@tonic-gate 		scratch->b_cont = split_mp->b_cont;
1548*0Sstevel@tonic-gate 		scratch->b_rptr += wheretodiv;
1549*0Sstevel@tonic-gate 		split_mp->b_wptr = split_mp->b_rptr + wheretodiv;
1550*0Sstevel@tonic-gate 		split_mp->b_cont = scratch;
1551*0Sstevel@tonic-gate 	}
1552*0Sstevel@tonic-gate 	/*
1553*0Sstevel@tonic-gate 	 * At this point, split_mp is exactly "wheretodiv" bytes long, and
1554*0Sstevel@tonic-gate 	 * holds the end of the pre-ESP part of the datagram.
1555*0Sstevel@tonic-gate 	 */
1556*0Sstevel@tonic-gate 	esp_mp->b_cont = split_mp->b_cont;
1557*0Sstevel@tonic-gate 	split_mp->b_cont = esp_mp;
1558*0Sstevel@tonic-gate 
1559*0Sstevel@tonic-gate 	return (B_TRUE);
1560*0Sstevel@tonic-gate }
1561*0Sstevel@tonic-gate 
1562*0Sstevel@tonic-gate /*
1563*0Sstevel@tonic-gate  * Finish processing of an inbound ESP packet after processing by the
1564*0Sstevel@tonic-gate  * crypto framework.
1565*0Sstevel@tonic-gate  * - Remove the ESP header.
1566*0Sstevel@tonic-gate  * - Send packet back to IP.
1567*0Sstevel@tonic-gate  * If authentication was performed on the packet, this function is called
1568*0Sstevel@tonic-gate  * only if the authentication succeeded.
1569*0Sstevel@tonic-gate  * On success returns B_TRUE, on failure returns B_FALSE and frees the
1570*0Sstevel@tonic-gate  * mblk chain ipsec_in_mp.
1571*0Sstevel@tonic-gate  */
1572*0Sstevel@tonic-gate static ipsec_status_t
1573*0Sstevel@tonic-gate esp_in_done(mblk_t *ipsec_in_mp)
1574*0Sstevel@tonic-gate {
1575*0Sstevel@tonic-gate 	ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr;
1576*0Sstevel@tonic-gate 	mblk_t *data_mp;
1577*0Sstevel@tonic-gate 	ipsa_t *assoc;
1578*0Sstevel@tonic-gate 	uint_t espstart;
1579*0Sstevel@tonic-gate 	uint32_t ivlen = 0;
1580*0Sstevel@tonic-gate 	uint_t processed_len;
1581*0Sstevel@tonic-gate 	esph_t *esph;
1582*0Sstevel@tonic-gate 	kstat_named_t *counter;
1583*0Sstevel@tonic-gate 	boolean_t is_natt;
1584*0Sstevel@tonic-gate 
1585*0Sstevel@tonic-gate 	assoc = ii->ipsec_in_esp_sa;
1586*0Sstevel@tonic-gate 	ASSERT(assoc != NULL);
1587*0Sstevel@tonic-gate 
1588*0Sstevel@tonic-gate 	is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0);
1589*0Sstevel@tonic-gate 
1590*0Sstevel@tonic-gate 	/* get the pointer to the ESP header */
1591*0Sstevel@tonic-gate /* EXPORT DELETE START */
1592*0Sstevel@tonic-gate 	if (assoc->ipsa_encr_alg == SADB_EALG_NULL) {
1593*0Sstevel@tonic-gate 		/* authentication-only ESP */
1594*0Sstevel@tonic-gate /* EXPORT DELETE END */
1595*0Sstevel@tonic-gate 		espstart = ii->ipsec_in_crypto_data.cd_offset;
1596*0Sstevel@tonic-gate 		processed_len = ii->ipsec_in_crypto_data.cd_length;
1597*0Sstevel@tonic-gate /* EXPORT DELETE START */
1598*0Sstevel@tonic-gate 	} else {
1599*0Sstevel@tonic-gate 		/* encryption present */
1600*0Sstevel@tonic-gate 		ivlen = assoc->ipsa_iv_len;
1601*0Sstevel@tonic-gate 		if (assoc->ipsa_auth_alg == SADB_AALG_NONE) {
1602*0Sstevel@tonic-gate 			/* encryption-only ESP */
1603*0Sstevel@tonic-gate 			espstart = ii->ipsec_in_crypto_data.cd_offset -
1604*0Sstevel@tonic-gate 				sizeof (esph_t) - assoc->ipsa_iv_len;
1605*0Sstevel@tonic-gate 			processed_len = ii->ipsec_in_crypto_data.cd_length +
1606*0Sstevel@tonic-gate 				ivlen;
1607*0Sstevel@tonic-gate 		} else {
1608*0Sstevel@tonic-gate 			/* encryption with authentication */
1609*0Sstevel@tonic-gate 			espstart = ii->ipsec_in_crypto_dual_data.dd_offset1;
1610*0Sstevel@tonic-gate 			processed_len = ii->ipsec_in_crypto_dual_data.dd_len2 +
1611*0Sstevel@tonic-gate 			    ivlen;
1612*0Sstevel@tonic-gate 		}
1613*0Sstevel@tonic-gate 	}
1614*0Sstevel@tonic-gate /* EXPORT DELETE END */
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate 	data_mp = ipsec_in_mp->b_cont;
1617*0Sstevel@tonic-gate 	esph = (esph_t *)(data_mp->b_rptr + espstart);
1618*0Sstevel@tonic-gate 
1619*0Sstevel@tonic-gate 	if (assoc->ipsa_auth_alg != IPSA_AALG_NONE) {
1620*0Sstevel@tonic-gate 		/* authentication passed if we reach this point */
1621*0Sstevel@tonic-gate 		ESP_BUMP_STAT(good_auth);
1622*0Sstevel@tonic-gate 		data_mp->b_wptr -= assoc->ipsa_mac_len;
1623*0Sstevel@tonic-gate 
1624*0Sstevel@tonic-gate 		/*
1625*0Sstevel@tonic-gate 		 * Check replay window here!
1626*0Sstevel@tonic-gate 		 * For right now, assume keysock will set the replay window
1627*0Sstevel@tonic-gate 		 * size to zero for SAs that have an unspecified sender.
1628*0Sstevel@tonic-gate 		 * This may change...
1629*0Sstevel@tonic-gate 		 */
1630*0Sstevel@tonic-gate 
1631*0Sstevel@tonic-gate 		if (!sadb_replay_check(assoc, esph->esph_replay)) {
1632*0Sstevel@tonic-gate 			/*
1633*0Sstevel@tonic-gate 			 * Log the event. As of now we print out an event.
1634*0Sstevel@tonic-gate 			 * Do not print the replay failure number, or else
1635*0Sstevel@tonic-gate 			 * syslog cannot collate the error messages.  Printing
1636*0Sstevel@tonic-gate 			 * the replay number that failed opens a denial-of-
1637*0Sstevel@tonic-gate 			 * service attack.
1638*0Sstevel@tonic-gate 			 */
1639*0Sstevel@tonic-gate 			ipsec_assocfailure(info.mi_idnum, 0, 0,
1640*0Sstevel@tonic-gate 			    SL_ERROR | SL_WARN,
1641*0Sstevel@tonic-gate 			    "Replay failed for ESP spi 0x%x, dst %s.\n",
1642*0Sstevel@tonic-gate 			    assoc->ipsa_spi, assoc->ipsa_dstaddr,
1643*0Sstevel@tonic-gate 			    assoc->ipsa_addrfam);
1644*0Sstevel@tonic-gate 			ESP_BUMP_STAT(replay_failures);
1645*0Sstevel@tonic-gate 			counter = &ipdrops_esp_replay;
1646*0Sstevel@tonic-gate 			goto drop_and_bail;
1647*0Sstevel@tonic-gate 		}
1648*0Sstevel@tonic-gate 	}
1649*0Sstevel@tonic-gate 
1650*0Sstevel@tonic-gate 	if (!esp_age_bytes(assoc, processed_len, B_TRUE)) {
1651*0Sstevel@tonic-gate 		/* The ipsa has hit hard expiration, LOG and AUDIT. */
1652*0Sstevel@tonic-gate 		ipsec_assocfailure(info.mi_idnum, 0, 0,
1653*0Sstevel@tonic-gate 		    SL_ERROR | SL_WARN,
1654*0Sstevel@tonic-gate 		    "ESP association 0x%x, dst %s had bytes expire.\n",
1655*0Sstevel@tonic-gate 		    assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam);
1656*0Sstevel@tonic-gate 		ESP_BUMP_STAT(bytes_expired);
1657*0Sstevel@tonic-gate 		counter = &ipdrops_esp_bytes_expire;
1658*0Sstevel@tonic-gate 		goto drop_and_bail;
1659*0Sstevel@tonic-gate 	}
1660*0Sstevel@tonic-gate 
1661*0Sstevel@tonic-gate 	/*
1662*0Sstevel@tonic-gate 	 * Remove ESP header and padding from packet.  I hope the compiler
1663*0Sstevel@tonic-gate 	 * spews "branch, predict taken" code for this.
1664*0Sstevel@tonic-gate 	 */
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 	if (esp_strip_header(data_mp, ii->ipsec_in_v4, ivlen, &counter)) {
1667*0Sstevel@tonic-gate 		if (is_natt)
1668*0Sstevel@tonic-gate 			return (esp_fix_natt_checksums(data_mp, assoc));
1669*0Sstevel@tonic-gate 		return (IPSEC_STATUS_SUCCESS);
1670*0Sstevel@tonic-gate 	}
1671*0Sstevel@tonic-gate 
1672*0Sstevel@tonic-gate 	esp1dbg(("esp_in_done: esp_strip_header() failed\n"));
1673*0Sstevel@tonic-gate drop_and_bail:
1674*0Sstevel@tonic-gate 	IP_ESP_BUMP_STAT(in_discards);
1675*0Sstevel@tonic-gate 	/*
1676*0Sstevel@tonic-gate 	 * TODO: Extract inbound interface from the IPSEC_IN message's
1677*0Sstevel@tonic-gate 	 * ii->ipsec_in_rill_index.
1678*0Sstevel@tonic-gate 	 */
1679*0Sstevel@tonic-gate 	ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, counter, &esp_dropper);
1680*0Sstevel@tonic-gate 	return (IPSEC_STATUS_FAILED);
1681*0Sstevel@tonic-gate }
1682*0Sstevel@tonic-gate 
1683*0Sstevel@tonic-gate /*
1684*0Sstevel@tonic-gate  * Called upon failing the inbound ICV check. The message passed as
1685*0Sstevel@tonic-gate  * argument is freed.
1686*0Sstevel@tonic-gate  */
1687*0Sstevel@tonic-gate static void
1688*0Sstevel@tonic-gate esp_log_bad_auth(mblk_t *ipsec_in)
1689*0Sstevel@tonic-gate {
1690*0Sstevel@tonic-gate 	ipsec_in_t *ii = (ipsec_in_t *)ipsec_in->b_rptr;
1691*0Sstevel@tonic-gate 	ipsa_t *assoc = ii->ipsec_in_esp_sa;
1692*0Sstevel@tonic-gate 
1693*0Sstevel@tonic-gate 	/*
1694*0Sstevel@tonic-gate 	 * Log the event. Don't print to the console, block
1695*0Sstevel@tonic-gate 	 * potential denial-of-service attack.
1696*0Sstevel@tonic-gate 	 */
1697*0Sstevel@tonic-gate 	ESP_BUMP_STAT(bad_auth);
1698*0Sstevel@tonic-gate 
1699*0Sstevel@tonic-gate 	ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
1700*0Sstevel@tonic-gate 	    "ESP Authentication failed for spi 0x%x, dst %s.\n",
1701*0Sstevel@tonic-gate 	    assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam);
1702*0Sstevel@tonic-gate 
1703*0Sstevel@tonic-gate 	IP_ESP_BUMP_STAT(in_discards);
1704*0Sstevel@tonic-gate 	/*
1705*0Sstevel@tonic-gate 	 * TODO: Extract inbound interface from the IPSEC_IN
1706*0Sstevel@tonic-gate 	 * message's ii->ipsec_in_rill_index.
1707*0Sstevel@tonic-gate 	 */
1708*0Sstevel@tonic-gate 	ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, &ipdrops_esp_bad_auth,
1709*0Sstevel@tonic-gate 	    &esp_dropper);
1710*0Sstevel@tonic-gate }
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate 
1713*0Sstevel@tonic-gate /*
1714*0Sstevel@tonic-gate  * Invoked for outbound packets after ESP processing. If the packet
1715*0Sstevel@tonic-gate  * also requires AH, performs the AH SA selection and AH processing.
1716*0Sstevel@tonic-gate  * Returns B_TRUE if the AH processing was not needed or if it was
1717*0Sstevel@tonic-gate  * performed successfully. Returns B_FALSE and consumes the passed mblk
1718*0Sstevel@tonic-gate  * if AH processing was required but could not be performed.
1719*0Sstevel@tonic-gate  */
1720*0Sstevel@tonic-gate static boolean_t
1721*0Sstevel@tonic-gate esp_do_outbound_ah(mblk_t *ipsec_mp)
1722*0Sstevel@tonic-gate {
1723*0Sstevel@tonic-gate 	ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr;
1724*0Sstevel@tonic-gate 	ipsec_status_t ipsec_rc;
1725*0Sstevel@tonic-gate 	ipsec_action_t *ap;
1726*0Sstevel@tonic-gate 
1727*0Sstevel@tonic-gate 	ap = io->ipsec_out_act;
1728*0Sstevel@tonic-gate 	if (ap == NULL) {
1729*0Sstevel@tonic-gate 		ipsec_policy_t *pp = io->ipsec_out_policy;
1730*0Sstevel@tonic-gate 		ap = pp->ipsp_act;
1731*0Sstevel@tonic-gate 	}
1732*0Sstevel@tonic-gate 
1733*0Sstevel@tonic-gate 	if (!ap->ipa_want_ah)
1734*0Sstevel@tonic-gate 		return (B_TRUE);
1735*0Sstevel@tonic-gate 
1736*0Sstevel@tonic-gate 	ASSERT(io->ipsec_out_ah_done == B_FALSE);
1737*0Sstevel@tonic-gate 
1738*0Sstevel@tonic-gate 	if (io->ipsec_out_ah_sa == NULL) {
1739*0Sstevel@tonic-gate 		if (!ipsec_outbound_sa(ipsec_mp, IPPROTO_AH)) {
1740*0Sstevel@tonic-gate 			sadb_acquire(ipsec_mp, io, B_TRUE, B_FALSE);
1741*0Sstevel@tonic-gate 			return (B_FALSE);
1742*0Sstevel@tonic-gate 		}
1743*0Sstevel@tonic-gate 	}
1744*0Sstevel@tonic-gate 	ASSERT(io->ipsec_out_ah_sa != NULL);
1745*0Sstevel@tonic-gate 
1746*0Sstevel@tonic-gate 	io->ipsec_out_ah_done = B_TRUE;
1747*0Sstevel@tonic-gate 	ipsec_rc = io->ipsec_out_ah_sa->ipsa_output_func(ipsec_mp);
1748*0Sstevel@tonic-gate 	return (ipsec_rc == IPSEC_STATUS_SUCCESS);
1749*0Sstevel@tonic-gate }
1750*0Sstevel@tonic-gate 
1751*0Sstevel@tonic-gate 
1752*0Sstevel@tonic-gate /*
1753*0Sstevel@tonic-gate  * Kernel crypto framework callback invoked after completion of async
1754*0Sstevel@tonic-gate  * crypto requests.
1755*0Sstevel@tonic-gate  */
1756*0Sstevel@tonic-gate static void
1757*0Sstevel@tonic-gate esp_kcf_callback(void *arg, int status)
1758*0Sstevel@tonic-gate {
1759*0Sstevel@tonic-gate 	mblk_t *ipsec_mp = (mblk_t *)arg;
1760*0Sstevel@tonic-gate 	ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr;
1761*0Sstevel@tonic-gate 	boolean_t is_inbound = (ii->ipsec_in_type == IPSEC_IN);
1762*0Sstevel@tonic-gate 
1763*0Sstevel@tonic-gate 	ASSERT(ipsec_mp->b_cont != NULL);
1764*0Sstevel@tonic-gate 
1765*0Sstevel@tonic-gate 	if (status == CRYPTO_SUCCESS) {
1766*0Sstevel@tonic-gate 		if (is_inbound) {
1767*0Sstevel@tonic-gate 			if (esp_in_done(ipsec_mp) != IPSEC_STATUS_SUCCESS)
1768*0Sstevel@tonic-gate 				return;
1769*0Sstevel@tonic-gate 
1770*0Sstevel@tonic-gate 			/* finish IPsec processing */
1771*0Sstevel@tonic-gate 			ip_fanout_proto_again(ipsec_mp, NULL, NULL, NULL);
1772*0Sstevel@tonic-gate 		} else {
1773*0Sstevel@tonic-gate 			/*
1774*0Sstevel@tonic-gate 			 * If a ICV was computed, it was stored by the
1775*0Sstevel@tonic-gate 			 * crypto framework at the end of the packet.
1776*0Sstevel@tonic-gate 			 */
1777*0Sstevel@tonic-gate 			ipha_t *ipha = (ipha_t *)ipsec_mp->b_cont->b_rptr;
1778*0Sstevel@tonic-gate 
1779*0Sstevel@tonic-gate 			/* do AH processing if needed */
1780*0Sstevel@tonic-gate 			if (!esp_do_outbound_ah(ipsec_mp))
1781*0Sstevel@tonic-gate 				return;
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate 			/* finish IPsec processing */
1784*0Sstevel@tonic-gate 			if (IPH_HDR_VERSION(ipha) == IP_VERSION) {
1785*0Sstevel@tonic-gate 				ip_wput_ipsec_out(NULL, ipsec_mp, ipha, NULL,
1786*0Sstevel@tonic-gate 				    NULL);
1787*0Sstevel@tonic-gate 			} else {
1788*0Sstevel@tonic-gate 				ip6_t *ip6h = (ip6_t *)ipha;
1789*0Sstevel@tonic-gate 				ip_wput_ipsec_out_v6(NULL, ipsec_mp, ip6h,
1790*0Sstevel@tonic-gate 				    NULL, NULL);
1791*0Sstevel@tonic-gate 			}
1792*0Sstevel@tonic-gate 		}
1793*0Sstevel@tonic-gate 
1794*0Sstevel@tonic-gate 	} else if (status == CRYPTO_INVALID_MAC) {
1795*0Sstevel@tonic-gate 		esp_log_bad_auth(ipsec_mp);
1796*0Sstevel@tonic-gate 
1797*0Sstevel@tonic-gate 	} else {
1798*0Sstevel@tonic-gate 		esp1dbg(("esp_kcf_callback: crypto failed with 0x%x\n",
1799*0Sstevel@tonic-gate 		    status));
1800*0Sstevel@tonic-gate 		ESP_BUMP_STAT(crypto_failures);
1801*0Sstevel@tonic-gate 		if (is_inbound)
1802*0Sstevel@tonic-gate 			IP_ESP_BUMP_STAT(in_discards);
1803*0Sstevel@tonic-gate 		else
1804*0Sstevel@tonic-gate 			ESP_BUMP_STAT(out_discards);
1805*0Sstevel@tonic-gate 		ip_drop_packet(ipsec_mp, is_inbound, NULL, NULL,
1806*0Sstevel@tonic-gate 		    &ipdrops_esp_crypto_failed, &esp_dropper);
1807*0Sstevel@tonic-gate 	}
1808*0Sstevel@tonic-gate }
1809*0Sstevel@tonic-gate 
1810*0Sstevel@tonic-gate /*
1811*0Sstevel@tonic-gate  * Invoked on crypto framework failure during inbound and outbound processing.
1812*0Sstevel@tonic-gate  */
1813*0Sstevel@tonic-gate static void
1814*0Sstevel@tonic-gate esp_crypto_failed(mblk_t *mp, boolean_t is_inbound, int kef_rc)
1815*0Sstevel@tonic-gate {
1816*0Sstevel@tonic-gate 	esp1dbg(("crypto failed for %s ESP with 0x%x\n",
1817*0Sstevel@tonic-gate 	    is_inbound ? "inbound" : "outbound", kef_rc));
1818*0Sstevel@tonic-gate 	ip_drop_packet(mp, is_inbound, NULL, NULL, &ipdrops_esp_crypto_failed,
1819*0Sstevel@tonic-gate 	    &esp_dropper);
1820*0Sstevel@tonic-gate 	ESP_BUMP_STAT(crypto_failures);
1821*0Sstevel@tonic-gate 	if (is_inbound)
1822*0Sstevel@tonic-gate 		IP_ESP_BUMP_STAT(in_discards);
1823*0Sstevel@tonic-gate 	else
1824*0Sstevel@tonic-gate 		ESP_BUMP_STAT(out_discards);
1825*0Sstevel@tonic-gate }
1826*0Sstevel@tonic-gate 
1827*0Sstevel@tonic-gate #define	ESP_INIT_CALLREQ(_cr) {						\
1828*0Sstevel@tonic-gate 	(_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_RESTRICTED;		\
1829*0Sstevel@tonic-gate 	(_cr)->cr_callback_arg = ipsec_mp;				\
1830*0Sstevel@tonic-gate 	(_cr)->cr_callback_func = esp_kcf_callback;			\
1831*0Sstevel@tonic-gate }
1832*0Sstevel@tonic-gate 
1833*0Sstevel@tonic-gate #define	ESP_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) {			\
1834*0Sstevel@tonic-gate 	(mac)->cd_format = CRYPTO_DATA_RAW;				\
1835*0Sstevel@tonic-gate 	(mac)->cd_offset = 0;						\
1836*0Sstevel@tonic-gate 	(mac)->cd_length = icvlen;					\
1837*0Sstevel@tonic-gate 	(mac)->cd_raw.iov_base = (char *)icvbuf;			\
1838*0Sstevel@tonic-gate 	(mac)->cd_raw.iov_len = icvlen;					\
1839*0Sstevel@tonic-gate }
1840*0Sstevel@tonic-gate 
1841*0Sstevel@tonic-gate #define	ESP_INIT_CRYPTO_DATA(data, mp, off, len) {			\
1842*0Sstevel@tonic-gate 	if (MBLKL(mp) >= (len) + (off)) {				\
1843*0Sstevel@tonic-gate 		(data)->cd_format = CRYPTO_DATA_RAW;			\
1844*0Sstevel@tonic-gate 		(data)->cd_raw.iov_base = (char *)(mp)->b_rptr;		\
1845*0Sstevel@tonic-gate 		(data)->cd_raw.iov_len = MBLKL(mp);			\
1846*0Sstevel@tonic-gate 		(data)->cd_offset = off;				\
1847*0Sstevel@tonic-gate 	} else {							\
1848*0Sstevel@tonic-gate 		(data)->cd_format = CRYPTO_DATA_MBLK;			\
1849*0Sstevel@tonic-gate 		(data)->cd_mp = mp;			       		\
1850*0Sstevel@tonic-gate 		(data)->cd_offset = off;				\
1851*0Sstevel@tonic-gate 	}								\
1852*0Sstevel@tonic-gate 	(data)->cd_length = len;					\
1853*0Sstevel@tonic-gate }
1854*0Sstevel@tonic-gate 
1855*0Sstevel@tonic-gate /* EXPORT DELETE START */
1856*0Sstevel@tonic-gate #define	ESP_INIT_CRYPTO_DUAL_DATA(data, mp, off1, len1, off2, len2) {	\
1857*0Sstevel@tonic-gate 	(data)->dd_format = CRYPTO_DATA_MBLK;				\
1858*0Sstevel@tonic-gate 	(data)->dd_mp = mp;						\
1859*0Sstevel@tonic-gate 	(data)->dd_len1 = len1;						\
1860*0Sstevel@tonic-gate 	(data)->dd_offset1 = off1;					\
1861*0Sstevel@tonic-gate 	(data)->dd_len2 = len2;						\
1862*0Sstevel@tonic-gate 	(data)->dd_offset2 = off2;					\
1863*0Sstevel@tonic-gate }
1864*0Sstevel@tonic-gate /* EXPORT DELETE END */
1865*0Sstevel@tonic-gate 
1866*0Sstevel@tonic-gate static ipsec_status_t
1867*0Sstevel@tonic-gate esp_submit_req_inbound(mblk_t *ipsec_mp, ipsa_t *assoc, uint_t esph_offset)
1868*0Sstevel@tonic-gate {
1869*0Sstevel@tonic-gate 	ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr;
1870*0Sstevel@tonic-gate 	boolean_t do_auth;
1871*0Sstevel@tonic-gate 	uint_t auth_offset, msg_len, auth_len;
1872*0Sstevel@tonic-gate 	crypto_call_req_t call_req;
1873*0Sstevel@tonic-gate 	mblk_t *esp_mp;
1874*0Sstevel@tonic-gate 	int kef_rc = CRYPTO_FAILED;
1875*0Sstevel@tonic-gate 	uint_t icv_len = assoc->ipsa_mac_len;
1876*0Sstevel@tonic-gate 	crypto_ctx_template_t auth_ctx_tmpl;
1877*0Sstevel@tonic-gate /* EXPORT DELETE START */
1878*0Sstevel@tonic-gate 	boolean_t do_encr;
1879*0Sstevel@tonic-gate 	uint_t encr_offset, encr_len;
1880*0Sstevel@tonic-gate 	uint_t iv_len = assoc->ipsa_iv_len;
1881*0Sstevel@tonic-gate 	crypto_ctx_template_t encr_ctx_tmpl;
1882*0Sstevel@tonic-gate /* EXPORT DELETE END */
1883*0Sstevel@tonic-gate 
1884*0Sstevel@tonic-gate 	ASSERT(ii->ipsec_in_type == IPSEC_IN);
1885*0Sstevel@tonic-gate 
1886*0Sstevel@tonic-gate 	do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE;
1887*0Sstevel@tonic-gate /* EXPORT DELETE START */
1888*0Sstevel@tonic-gate 	do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL;
1889*0Sstevel@tonic-gate 
1890*0Sstevel@tonic-gate 	/*
1891*0Sstevel@tonic-gate 	 * An inbound packet is of the form:
1892*0Sstevel@tonic-gate 	 * IPSEC_IN -> [IP,options,ESP,IV,data,ICV,pad]
1893*0Sstevel@tonic-gate 	 */
1894*0Sstevel@tonic-gate /* EXPORT DELETE END */
1895*0Sstevel@tonic-gate 	esp_mp = ipsec_mp->b_cont;
1896*0Sstevel@tonic-gate 	msg_len = MBLKL(esp_mp);
1897*0Sstevel@tonic-gate 
1898*0Sstevel@tonic-gate 	ESP_INIT_CALLREQ(&call_req);
1899*0Sstevel@tonic-gate 
1900*0Sstevel@tonic-gate 	if (do_auth) {
1901*0Sstevel@tonic-gate 		/* force asynchronous processing? */
1902*0Sstevel@tonic-gate 		if (ipsec_algs_exec_mode[IPSEC_ALG_AUTH] ==
1903*0Sstevel@tonic-gate 		    IPSEC_ALGS_EXEC_ASYNC)
1904*0Sstevel@tonic-gate 			call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE;
1905*0Sstevel@tonic-gate 
1906*0Sstevel@tonic-gate 		/* authentication context template */
1907*0Sstevel@tonic-gate 		IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH,
1908*0Sstevel@tonic-gate 		    auth_ctx_tmpl);
1909*0Sstevel@tonic-gate 
1910*0Sstevel@tonic-gate 		/* ICV to be verified */
1911*0Sstevel@tonic-gate 		ESP_INIT_CRYPTO_MAC(&ii->ipsec_in_crypto_mac,
1912*0Sstevel@tonic-gate 		    icv_len, esp_mp->b_wptr - icv_len);
1913*0Sstevel@tonic-gate 
1914*0Sstevel@tonic-gate 		/* authentication starts at the ESP header */
1915*0Sstevel@tonic-gate 		auth_offset = esph_offset;
1916*0Sstevel@tonic-gate 		auth_len = msg_len - auth_offset - icv_len;
1917*0Sstevel@tonic-gate /* EXPORT DELETE START */
1918*0Sstevel@tonic-gate 		if (!do_encr) {
1919*0Sstevel@tonic-gate 			/* authentication only */
1920*0Sstevel@tonic-gate /* EXPORT DELETE END */
1921*0Sstevel@tonic-gate 			/* initialize input data argument */
1922*0Sstevel@tonic-gate 			ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data,
1923*0Sstevel@tonic-gate 			    esp_mp, auth_offset, auth_len);
1924*0Sstevel@tonic-gate 
1925*0Sstevel@tonic-gate 			/* call the crypto framework */
1926*0Sstevel@tonic-gate 			kef_rc = crypto_mac_verify(&assoc->ipsa_amech,
1927*0Sstevel@tonic-gate 			    &ii->ipsec_in_crypto_data,
1928*0Sstevel@tonic-gate 			    &assoc->ipsa_kcfauthkey, auth_ctx_tmpl,
1929*0Sstevel@tonic-gate 			    &ii->ipsec_in_crypto_mac, &call_req);
1930*0Sstevel@tonic-gate /* EXPORT DELETE START */
1931*0Sstevel@tonic-gate 		}
1932*0Sstevel@tonic-gate /* EXPORT DELETE END */
1933*0Sstevel@tonic-gate 	}
1934*0Sstevel@tonic-gate 
1935*0Sstevel@tonic-gate /* EXPORT DELETE START */
1936*0Sstevel@tonic-gate 	if (do_encr) {
1937*0Sstevel@tonic-gate 		/* force asynchronous processing? */
1938*0Sstevel@tonic-gate 		if (ipsec_algs_exec_mode[IPSEC_ALG_ENCR] ==
1939*0Sstevel@tonic-gate 		    IPSEC_ALGS_EXEC_ASYNC)
1940*0Sstevel@tonic-gate 			call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE;
1941*0Sstevel@tonic-gate 
1942*0Sstevel@tonic-gate 		/* encryption template */
1943*0Sstevel@tonic-gate 		IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR,
1944*0Sstevel@tonic-gate 		    encr_ctx_tmpl);
1945*0Sstevel@tonic-gate 
1946*0Sstevel@tonic-gate 		/* skip IV, since it is passed separately */
1947*0Sstevel@tonic-gate 		encr_offset = esph_offset + sizeof (esph_t) + iv_len;
1948*0Sstevel@tonic-gate 		encr_len = msg_len - encr_offset;
1949*0Sstevel@tonic-gate 
1950*0Sstevel@tonic-gate 		if (!do_auth) {
1951*0Sstevel@tonic-gate 			/* decryption only */
1952*0Sstevel@tonic-gate 			/* initialize input data argument */
1953*0Sstevel@tonic-gate 			ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data,
1954*0Sstevel@tonic-gate 			    esp_mp, encr_offset, encr_len);
1955*0Sstevel@tonic-gate 
1956*0Sstevel@tonic-gate 			/* specify IV */
1957*0Sstevel@tonic-gate 			ii->ipsec_in_crypto_data.cd_miscdata =
1958*0Sstevel@tonic-gate 			    (char *)esp_mp->b_rptr + sizeof (esph_t) +
1959*0Sstevel@tonic-gate 			    esph_offset;
1960*0Sstevel@tonic-gate 
1961*0Sstevel@tonic-gate 			/* call the crypto framework */
1962*0Sstevel@tonic-gate 			kef_rc = crypto_decrypt(&assoc->ipsa_emech,
1963*0Sstevel@tonic-gate 			    &ii->ipsec_in_crypto_data,
1964*0Sstevel@tonic-gate 			    &assoc->ipsa_kcfencrkey, encr_ctx_tmpl,
1965*0Sstevel@tonic-gate 			    NULL, &call_req);
1966*0Sstevel@tonic-gate 		}
1967*0Sstevel@tonic-gate 	}
1968*0Sstevel@tonic-gate 
1969*0Sstevel@tonic-gate 	if (do_auth && do_encr) {
1970*0Sstevel@tonic-gate 		/* dual operation */
1971*0Sstevel@tonic-gate 		/* initialize input data argument */
1972*0Sstevel@tonic-gate 		ESP_INIT_CRYPTO_DUAL_DATA(&ii->ipsec_in_crypto_dual_data,
1973*0Sstevel@tonic-gate 		    esp_mp, auth_offset, auth_len,
1974*0Sstevel@tonic-gate 		    encr_offset, encr_len - icv_len);
1975*0Sstevel@tonic-gate 
1976*0Sstevel@tonic-gate 		/* specify IV */
1977*0Sstevel@tonic-gate 		ii->ipsec_in_crypto_dual_data.dd_miscdata =
1978*0Sstevel@tonic-gate 		    (char *)esp_mp->b_rptr + sizeof (esph_t) + esph_offset;
1979*0Sstevel@tonic-gate 
1980*0Sstevel@tonic-gate 		/* call the framework */
1981*0Sstevel@tonic-gate 		kef_rc = crypto_mac_verify_decrypt(&assoc->ipsa_amech,
1982*0Sstevel@tonic-gate 		    &assoc->ipsa_emech, &ii->ipsec_in_crypto_dual_data,
1983*0Sstevel@tonic-gate 		    &assoc->ipsa_kcfauthkey, &assoc->ipsa_kcfencrkey,
1984*0Sstevel@tonic-gate 		    auth_ctx_tmpl, encr_ctx_tmpl, &ii->ipsec_in_crypto_mac,
1985*0Sstevel@tonic-gate 		    NULL, &call_req);
1986*0Sstevel@tonic-gate 	}
1987*0Sstevel@tonic-gate /* EXPORT DELETE END */
1988*0Sstevel@tonic-gate 
1989*0Sstevel@tonic-gate 	switch (kef_rc) {
1990*0Sstevel@tonic-gate 	case CRYPTO_SUCCESS:
1991*0Sstevel@tonic-gate 		ESP_BUMP_STAT(crypto_sync);
1992*0Sstevel@tonic-gate 		return (esp_in_done(ipsec_mp));
1993*0Sstevel@tonic-gate 	case CRYPTO_QUEUED:
1994*0Sstevel@tonic-gate 		/* esp_kcf_callback() will be invoked on completion */
1995*0Sstevel@tonic-gate 		ESP_BUMP_STAT(crypto_async);
1996*0Sstevel@tonic-gate 		return (IPSEC_STATUS_PENDING);
1997*0Sstevel@tonic-gate 	case CRYPTO_INVALID_MAC:
1998*0Sstevel@tonic-gate 		ESP_BUMP_STAT(crypto_sync);
1999*0Sstevel@tonic-gate 		esp_log_bad_auth(ipsec_mp);
2000*0Sstevel@tonic-gate 		return (IPSEC_STATUS_FAILED);
2001*0Sstevel@tonic-gate 	}
2002*0Sstevel@tonic-gate 
2003*0Sstevel@tonic-gate 	esp_crypto_failed(ipsec_mp, B_TRUE, kef_rc);
2004*0Sstevel@tonic-gate 	return (IPSEC_STATUS_FAILED);
2005*0Sstevel@tonic-gate }
2006*0Sstevel@tonic-gate 
2007*0Sstevel@tonic-gate static ipsec_status_t
2008*0Sstevel@tonic-gate esp_submit_req_outbound(mblk_t *ipsec_mp, ipsa_t *assoc, uchar_t *icv_buf,
2009*0Sstevel@tonic-gate     uint_t payload_len)
2010*0Sstevel@tonic-gate {
2011*0Sstevel@tonic-gate 	ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr;
2012*0Sstevel@tonic-gate 	uint_t auth_len;
2013*0Sstevel@tonic-gate 	crypto_call_req_t call_req;
2014*0Sstevel@tonic-gate 	mblk_t *esp_mp;
2015*0Sstevel@tonic-gate 	int kef_rc = CRYPTO_FAILED;
2016*0Sstevel@tonic-gate 	uint_t icv_len = assoc->ipsa_mac_len;
2017*0Sstevel@tonic-gate 	crypto_ctx_template_t auth_ctx_tmpl;
2018*0Sstevel@tonic-gate 	boolean_t do_auth;
2019*0Sstevel@tonic-gate /* EXPORT DELETE START */
2020*0Sstevel@tonic-gate 	boolean_t do_encr;
2021*0Sstevel@tonic-gate 	uint_t iv_len = assoc->ipsa_iv_len;
2022*0Sstevel@tonic-gate 	crypto_ctx_template_t encr_ctx_tmpl;
2023*0Sstevel@tonic-gate /* EXPORT DELETE END */
2024*0Sstevel@tonic-gate 	boolean_t is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0);
2025*0Sstevel@tonic-gate 	size_t esph_offset = (is_natt ? UDPH_SIZE : 0);
2026*0Sstevel@tonic-gate 
2027*0Sstevel@tonic-gate 	esp3dbg(("esp_submit_req_outbound:%s", is_natt ? "natt" : "not natt"));
2028*0Sstevel@tonic-gate 
2029*0Sstevel@tonic-gate 	ASSERT(io->ipsec_out_type == IPSEC_OUT);
2030*0Sstevel@tonic-gate 
2031*0Sstevel@tonic-gate /* EXPORT DELETE START */
2032*0Sstevel@tonic-gate 	do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL;
2033*0Sstevel@tonic-gate /* EXPORT DELETE END */
2034*0Sstevel@tonic-gate 	do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE;
2035*0Sstevel@tonic-gate 
2036*0Sstevel@tonic-gate 	/*
2037*0Sstevel@tonic-gate 	 *	EXPORT DELETE START
2038*0Sstevel@tonic-gate 	 * Outbound IPsec packets are of the form:
2039*0Sstevel@tonic-gate 	 * IPSEC_OUT -> [IP,options] -> [ESP,IV] -> [data] -> [pad,ICV]
2040*0Sstevel@tonic-gate 	 * unless it's NATT, then it's
2041*0Sstevel@tonic-gate 	 * IPSEC_OUT -> [IP,options] -> [udp][ESP,IV] -> [data] -> [pad,ICV]
2042*0Sstevel@tonic-gate 	 *	EXPORT DELETE END
2043*0Sstevel@tonic-gate 	 * Get a pointer to the mblk containing the ESP header.
2044*0Sstevel@tonic-gate 	 */
2045*0Sstevel@tonic-gate 	ASSERT(ipsec_mp->b_cont != NULL && ipsec_mp->b_cont->b_cont != NULL);
2046*0Sstevel@tonic-gate 	esp_mp = ipsec_mp->b_cont->b_cont;
2047*0Sstevel@tonic-gate 
2048*0Sstevel@tonic-gate 	ESP_INIT_CALLREQ(&call_req);
2049*0Sstevel@tonic-gate 
2050*0Sstevel@tonic-gate 	if (do_auth) {
2051*0Sstevel@tonic-gate 		/* force asynchronous processing? */
2052*0Sstevel@tonic-gate 		if (ipsec_algs_exec_mode[IPSEC_ALG_AUTH] ==
2053*0Sstevel@tonic-gate 		    IPSEC_ALGS_EXEC_ASYNC)
2054*0Sstevel@tonic-gate 			call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE;
2055*0Sstevel@tonic-gate 
2056*0Sstevel@tonic-gate 		/* authentication context template */
2057*0Sstevel@tonic-gate 		IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH,
2058*0Sstevel@tonic-gate 		    auth_ctx_tmpl);
2059*0Sstevel@tonic-gate 
2060*0Sstevel@tonic-gate 		/* where to store the computed mac */
2061*0Sstevel@tonic-gate 		ESP_INIT_CRYPTO_MAC(&io->ipsec_out_crypto_mac,
2062*0Sstevel@tonic-gate 		    icv_len, icv_buf);
2063*0Sstevel@tonic-gate 
2064*0Sstevel@tonic-gate 		/* authentication starts at the ESP header */
2065*0Sstevel@tonic-gate 		auth_len = payload_len +
2066*0Sstevel@tonic-gate /* EXPORT DELETE START */
2067*0Sstevel@tonic-gate 		    iv_len +
2068*0Sstevel@tonic-gate /* EXPORT DELETE END */
2069*0Sstevel@tonic-gate 		    sizeof (esph_t);
2070*0Sstevel@tonic-gate /* EXPORT DELETE START */
2071*0Sstevel@tonic-gate 		if (!do_encr) {
2072*0Sstevel@tonic-gate 			/* authentication only */
2073*0Sstevel@tonic-gate /* EXPORT DELETE END */
2074*0Sstevel@tonic-gate 			/* initialize input data argument */
2075*0Sstevel@tonic-gate 			ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data,
2076*0Sstevel@tonic-gate 			    esp_mp, esph_offset, auth_len);
2077*0Sstevel@tonic-gate 
2078*0Sstevel@tonic-gate 			/* call the crypto framework */
2079*0Sstevel@tonic-gate 			kef_rc = crypto_mac(&assoc->ipsa_amech,
2080*0Sstevel@tonic-gate 			    &io->ipsec_out_crypto_data,
2081*0Sstevel@tonic-gate 			    &assoc->ipsa_kcfauthkey, auth_ctx_tmpl,
2082*0Sstevel@tonic-gate 			    &io->ipsec_out_crypto_mac, &call_req);
2083*0Sstevel@tonic-gate /* EXPORT DELETE START */
2084*0Sstevel@tonic-gate 		}
2085*0Sstevel@tonic-gate /* EXPORT DELETE END */
2086*0Sstevel@tonic-gate 	}
2087*0Sstevel@tonic-gate 
2088*0Sstevel@tonic-gate /* EXPORT DELETE START */
2089*0Sstevel@tonic-gate 	if (do_encr) {
2090*0Sstevel@tonic-gate 		/* force asynchronous processing? */
2091*0Sstevel@tonic-gate 		if (ipsec_algs_exec_mode[IPSEC_ALG_ENCR] ==
2092*0Sstevel@tonic-gate 		    IPSEC_ALGS_EXEC_ASYNC)
2093*0Sstevel@tonic-gate 			call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE;
2094*0Sstevel@tonic-gate 
2095*0Sstevel@tonic-gate 		/* encryption context template */
2096*0Sstevel@tonic-gate 		IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR,
2097*0Sstevel@tonic-gate 		    encr_ctx_tmpl);
2098*0Sstevel@tonic-gate 
2099*0Sstevel@tonic-gate 		if (!do_auth) {
2100*0Sstevel@tonic-gate 			/* encryption only, skip mblk that contains ESP hdr */
2101*0Sstevel@tonic-gate 			/* initialize input data argument */
2102*0Sstevel@tonic-gate 			ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data,
2103*0Sstevel@tonic-gate 			    esp_mp->b_cont, 0, payload_len);
2104*0Sstevel@tonic-gate 
2105*0Sstevel@tonic-gate 			/* specify IV */
2106*0Sstevel@tonic-gate 			io->ipsec_out_crypto_data.cd_miscdata =
2107*0Sstevel@tonic-gate 			    (char *)esp_mp->b_rptr + sizeof (esph_t) +
2108*0Sstevel@tonic-gate 			    esph_offset;
2109*0Sstevel@tonic-gate 
2110*0Sstevel@tonic-gate 			/* call the crypto framework */
2111*0Sstevel@tonic-gate 			kef_rc = crypto_encrypt(&assoc->ipsa_emech,
2112*0Sstevel@tonic-gate 			    &io->ipsec_out_crypto_data,
2113*0Sstevel@tonic-gate 			    &assoc->ipsa_kcfencrkey, encr_ctx_tmpl,
2114*0Sstevel@tonic-gate 			    NULL, &call_req);
2115*0Sstevel@tonic-gate 		}
2116*0Sstevel@tonic-gate 	}
2117*0Sstevel@tonic-gate 
2118*0Sstevel@tonic-gate 	if (do_auth && do_encr) {
2119*0Sstevel@tonic-gate 		/*
2120*0Sstevel@tonic-gate 		 * Encryption and authentication:
2121*0Sstevel@tonic-gate 		 * Pass the pointer to the mblk chain starting at the ESP
2122*0Sstevel@tonic-gate 		 * header to the framework. Skip the ESP header mblk
2123*0Sstevel@tonic-gate 		 * for encryption, which is reflected by an encryption
2124*0Sstevel@tonic-gate 		 * offset equal to the length of that mblk. Start
2125*0Sstevel@tonic-gate 		 * the authentication at the ESP header, i.e. use an
2126*0Sstevel@tonic-gate 		 * authentication offset of zero.
2127*0Sstevel@tonic-gate 		 */
2128*0Sstevel@tonic-gate 		ESP_INIT_CRYPTO_DUAL_DATA(&io->ipsec_out_crypto_dual_data,
2129*0Sstevel@tonic-gate 		    esp_mp, MBLKL(esp_mp), payload_len, esph_offset, auth_len);
2130*0Sstevel@tonic-gate 
2131*0Sstevel@tonic-gate 		/* specify IV */
2132*0Sstevel@tonic-gate 		io->ipsec_out_crypto_dual_data.dd_miscdata =
2133*0Sstevel@tonic-gate 		    (char *)esp_mp->b_rptr + sizeof (esph_t) + esph_offset;
2134*0Sstevel@tonic-gate 
2135*0Sstevel@tonic-gate 		/* call the framework */
2136*0Sstevel@tonic-gate 		kef_rc = crypto_encrypt_mac(&assoc->ipsa_emech,
2137*0Sstevel@tonic-gate 		    &assoc->ipsa_amech, NULL,
2138*0Sstevel@tonic-gate 		    &assoc->ipsa_kcfencrkey, &assoc->ipsa_kcfauthkey,
2139*0Sstevel@tonic-gate 		    encr_ctx_tmpl, auth_ctx_tmpl,
2140*0Sstevel@tonic-gate 		    &io->ipsec_out_crypto_dual_data,
2141*0Sstevel@tonic-gate 		    &io->ipsec_out_crypto_mac, &call_req);
2142*0Sstevel@tonic-gate 	}
2143*0Sstevel@tonic-gate /* EXPORT DELETE END */
2144*0Sstevel@tonic-gate 
2145*0Sstevel@tonic-gate 	switch (kef_rc) {
2146*0Sstevel@tonic-gate 	case CRYPTO_SUCCESS:
2147*0Sstevel@tonic-gate 		ESP_BUMP_STAT(crypto_sync);
2148*0Sstevel@tonic-gate 		return (IPSEC_STATUS_SUCCESS);
2149*0Sstevel@tonic-gate 	case CRYPTO_QUEUED:
2150*0Sstevel@tonic-gate 		/* esp_kcf_callback() will be invoked on completion */
2151*0Sstevel@tonic-gate 		ESP_BUMP_STAT(crypto_async);
2152*0Sstevel@tonic-gate 		return (IPSEC_STATUS_PENDING);
2153*0Sstevel@tonic-gate 	}
2154*0Sstevel@tonic-gate 
2155*0Sstevel@tonic-gate 	esp_crypto_failed(ipsec_mp, B_TRUE, kef_rc);
2156*0Sstevel@tonic-gate 	return (IPSEC_STATUS_FAILED);
2157*0Sstevel@tonic-gate }
2158*0Sstevel@tonic-gate 
2159*0Sstevel@tonic-gate /*
2160*0Sstevel@tonic-gate  * Handle outbound IPsec processing for IPv4 and IPv6
2161*0Sstevel@tonic-gate  * On success returns B_TRUE, on failure returns B_FALSE and frees the
2162*0Sstevel@tonic-gate  * mblk chain ipsec_in_mp.
2163*0Sstevel@tonic-gate  */
2164*0Sstevel@tonic-gate static ipsec_status_t
2165*0Sstevel@tonic-gate esp_outbound(mblk_t *mp)
2166*0Sstevel@tonic-gate {
2167*0Sstevel@tonic-gate 	mblk_t *ipsec_out_mp, *data_mp, *espmp, *tailmp;
2168*0Sstevel@tonic-gate 	ipsec_out_t *io;
2169*0Sstevel@tonic-gate 	ipha_t *ipha;
2170*0Sstevel@tonic-gate 	ip6_t *ip6h;
2171*0Sstevel@tonic-gate 	esph_t *esph;
2172*0Sstevel@tonic-gate 	uint_t af;
2173*0Sstevel@tonic-gate 	uint8_t *nhp;
2174*0Sstevel@tonic-gate 	uintptr_t divpoint, datalen, adj, padlen, i, alloclen;
2175*0Sstevel@tonic-gate 	uintptr_t esplen = sizeof (esph_t);
2176*0Sstevel@tonic-gate 	uint8_t protocol;
2177*0Sstevel@tonic-gate 	ipsa_t *assoc;
2178*0Sstevel@tonic-gate 	uint_t iv_len = 0, mac_len = 0;
2179*0Sstevel@tonic-gate 	uchar_t *icv_buf;
2180*0Sstevel@tonic-gate 	udpha_t *udpha;
2181*0Sstevel@tonic-gate 	boolean_t is_natt = B_FALSE;
2182*0Sstevel@tonic-gate 
2183*0Sstevel@tonic-gate 	ESP_BUMP_STAT(out_requests);
2184*0Sstevel@tonic-gate 
2185*0Sstevel@tonic-gate 	ipsec_out_mp = mp;
2186*0Sstevel@tonic-gate 	data_mp = ipsec_out_mp->b_cont;
2187*0Sstevel@tonic-gate 
2188*0Sstevel@tonic-gate 	/*
2189*0Sstevel@tonic-gate 	 * <sigh> We have to copy the message here, because TCP (for example)
2190*0Sstevel@tonic-gate 	 * keeps a dupb() of the message lying around for retransmission.
2191*0Sstevel@tonic-gate 	 * Since ESP changes the whole of the datagram, we have to create our
2192*0Sstevel@tonic-gate 	 * own copy lest we clobber TCP's data.  Since we have to copy anyway,
2193*0Sstevel@tonic-gate 	 * we might as well make use of msgpullup() and get the mblk into one
2194*0Sstevel@tonic-gate 	 * contiguous piece!
2195*0Sstevel@tonic-gate 	 */
2196*0Sstevel@tonic-gate 	ipsec_out_mp->b_cont = msgpullup(data_mp, -1);
2197*0Sstevel@tonic-gate 	if (ipsec_out_mp->b_cont == NULL) {
2198*0Sstevel@tonic-gate 		esp0dbg(("esp_outbound: msgpullup() failed, "
2199*0Sstevel@tonic-gate 		    "dropping packet.\n"));
2200*0Sstevel@tonic-gate 		ipsec_out_mp->b_cont = data_mp;
2201*0Sstevel@tonic-gate 		/*
2202*0Sstevel@tonic-gate 		 * TODO:  Find the outbound IRE for this packet and
2203*0Sstevel@tonic-gate 		 * pass it to ip_drop_packet().
2204*0Sstevel@tonic-gate 		 */
2205*0Sstevel@tonic-gate 		ip_drop_packet(ipsec_out_mp, B_FALSE, NULL, NULL,
2206*0Sstevel@tonic-gate 		    &ipdrops_esp_nomem, &esp_dropper);
2207*0Sstevel@tonic-gate 		return (IPSEC_STATUS_FAILED);
2208*0Sstevel@tonic-gate 	} else {
2209*0Sstevel@tonic-gate 		freemsg(data_mp);
2210*0Sstevel@tonic-gate 		data_mp = ipsec_out_mp->b_cont;
2211*0Sstevel@tonic-gate 	}
2212*0Sstevel@tonic-gate 
2213*0Sstevel@tonic-gate 	io = (ipsec_out_t *)ipsec_out_mp->b_rptr;
2214*0Sstevel@tonic-gate 
2215*0Sstevel@tonic-gate 	/*
2216*0Sstevel@tonic-gate 	 * Reality check....
2217*0Sstevel@tonic-gate 	 */
2218*0Sstevel@tonic-gate 
2219*0Sstevel@tonic-gate 	ipha = (ipha_t *)data_mp->b_rptr;  /* So we can call esp_acquire(). */
2220*0Sstevel@tonic-gate 
2221*0Sstevel@tonic-gate 	if (io->ipsec_out_v4) {
2222*0Sstevel@tonic-gate 		af = AF_INET;
2223*0Sstevel@tonic-gate 		divpoint = IPH_HDR_LENGTH(ipha);
2224*0Sstevel@tonic-gate 		datalen = ntohs(ipha->ipha_length) - divpoint;
2225*0Sstevel@tonic-gate 		nhp = (uint8_t *)&ipha->ipha_protocol;
2226*0Sstevel@tonic-gate 	} else {
2227*0Sstevel@tonic-gate 		ip6_pkt_t ipp;
2228*0Sstevel@tonic-gate 
2229*0Sstevel@tonic-gate 		af = AF_INET6;
2230*0Sstevel@tonic-gate 		ip6h = (ip6_t *)ipha;
2231*0Sstevel@tonic-gate 		bzero(&ipp, sizeof (ipp));
2232*0Sstevel@tonic-gate 		divpoint = ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL);
2233*0Sstevel@tonic-gate 		if (ipp.ipp_dstopts != NULL &&
2234*0Sstevel@tonic-gate 		    ipp.ipp_dstopts->ip6d_nxt != IPPROTO_ROUTING) {
2235*0Sstevel@tonic-gate 			/*
2236*0Sstevel@tonic-gate 			 * Destination options are tricky.  If we get in here,
2237*0Sstevel@tonic-gate 			 * then we have a terminal header following the
2238*0Sstevel@tonic-gate 			 * destination options.  We need to adjust backwards
2239*0Sstevel@tonic-gate 			 * so we insert ESP BEFORE the destination options
2240*0Sstevel@tonic-gate 			 * bag.  (So that the dstopts get encrypted!)
2241*0Sstevel@tonic-gate 			 *
2242*0Sstevel@tonic-gate 			 * Since this is for outbound packets only, we know
2243*0Sstevel@tonic-gate 			 * that non-terminal destination options only precede
2244*0Sstevel@tonic-gate 			 * routing headers.
2245*0Sstevel@tonic-gate 			 */
2246*0Sstevel@tonic-gate 			divpoint -= ipp.ipp_dstoptslen;
2247*0Sstevel@tonic-gate 		}
2248*0Sstevel@tonic-gate 		datalen = ntohs(ip6h->ip6_plen) + sizeof (ip6_t) - divpoint;
2249*0Sstevel@tonic-gate 
2250*0Sstevel@tonic-gate 		if (ipp.ipp_rthdr != NULL) {
2251*0Sstevel@tonic-gate 			nhp = &ipp.ipp_rthdr->ip6r_nxt;
2252*0Sstevel@tonic-gate 		} else if (ipp.ipp_hopopts != NULL) {
2253*0Sstevel@tonic-gate 			nhp = &ipp.ipp_hopopts->ip6h_nxt;
2254*0Sstevel@tonic-gate 		} else {
2255*0Sstevel@tonic-gate 			ASSERT(divpoint == sizeof (ip6_t));
2256*0Sstevel@tonic-gate 			/* It's probably IP + ESP. */
2257*0Sstevel@tonic-gate 			nhp = &ip6h->ip6_nxt;
2258*0Sstevel@tonic-gate 		}
2259*0Sstevel@tonic-gate 	}
2260*0Sstevel@tonic-gate 	assoc = io->ipsec_out_esp_sa;
2261*0Sstevel@tonic-gate 	ASSERT(assoc != NULL);
2262*0Sstevel@tonic-gate 
2263*0Sstevel@tonic-gate 	if (assoc->ipsa_usetime == 0)
2264*0Sstevel@tonic-gate 		esp_set_usetime(assoc, B_FALSE);
2265*0Sstevel@tonic-gate 
2266*0Sstevel@tonic-gate 	if (assoc->ipsa_auth_alg != SADB_AALG_NONE)
2267*0Sstevel@tonic-gate 		mac_len = assoc->ipsa_mac_len;
2268*0Sstevel@tonic-gate 
2269*0Sstevel@tonic-gate 	if (assoc->ipsa_flags & IPSA_F_NATT) {
2270*0Sstevel@tonic-gate 		/* wedge in fake UDP */
2271*0Sstevel@tonic-gate 		is_natt = B_TRUE;
2272*0Sstevel@tonic-gate 		esplen += UDPH_SIZE;
2273*0Sstevel@tonic-gate 	}
2274*0Sstevel@tonic-gate 
2275*0Sstevel@tonic-gate /* EXPORT DELETE START */
2276*0Sstevel@tonic-gate 	if (assoc->ipsa_encr_alg != SADB_EALG_NULL)
2277*0Sstevel@tonic-gate 		iv_len = assoc->ipsa_iv_len;
2278*0Sstevel@tonic-gate /* EXPORT DELETE END */
2279*0Sstevel@tonic-gate 
2280*0Sstevel@tonic-gate /* EXPORT DELETE START */
2281*0Sstevel@tonic-gate 	/*
2282*0Sstevel@tonic-gate 	 * Set up ESP header and encryption padding for ENCR PI request.
2283*0Sstevel@tonic-gate 	 */
2284*0Sstevel@tonic-gate /* EXPORT DELETE END */
2285*0Sstevel@tonic-gate 
2286*0Sstevel@tonic-gate 	/*
2287*0Sstevel@tonic-gate 	 * Determine the padding length.   Pad to 4-bytes.
2288*0Sstevel@tonic-gate 	 *
2289*0Sstevel@tonic-gate 	 * Include the two additional bytes (hence the - 2) for the padding
2290*0Sstevel@tonic-gate 	 * length and the next header.  Take this into account when
2291*0Sstevel@tonic-gate 	 * calculating the actual length of the padding.
2292*0Sstevel@tonic-gate 	 */
2293*0Sstevel@tonic-gate 
2294*0Sstevel@tonic-gate /* EXPORT DELETE START */
2295*0Sstevel@tonic-gate 	if (assoc->ipsa_encr_alg != SADB_EALG_NULL) {
2296*0Sstevel@tonic-gate 		padlen = ((unsigned)(iv_len - datalen - 2)) % iv_len;
2297*0Sstevel@tonic-gate 	} else {
2298*0Sstevel@tonic-gate /* EXPORT DELETE END */
2299*0Sstevel@tonic-gate 		padlen = ((unsigned)(sizeof (uint32_t) - datalen - 2)) %
2300*0Sstevel@tonic-gate 		    sizeof (uint32_t);
2301*0Sstevel@tonic-gate /* EXPORT DELETE START */
2302*0Sstevel@tonic-gate 	}
2303*0Sstevel@tonic-gate 
2304*0Sstevel@tonic-gate 	/* Allocate ESP header and IV. */
2305*0Sstevel@tonic-gate 	esplen += iv_len;
2306*0Sstevel@tonic-gate /* EXPORT DELETE END */
2307*0Sstevel@tonic-gate 
2308*0Sstevel@tonic-gate 	/*
2309*0Sstevel@tonic-gate 	 * Update association byte-count lifetimes.  Don't forget to take
2310*0Sstevel@tonic-gate 	 * into account the padding length and next-header (hence the + 2).
2311*0Sstevel@tonic-gate 	 *	EXPORT DELETE START
2312*0Sstevel@tonic-gate 	 * Use the amount of data fed into the "encryption algorithm".  This
2313*0Sstevel@tonic-gate 	 * is the IV, the data length, the padding length, and the final two
2314*0Sstevel@tonic-gate 	 * bytes (padlen, and next-header).
2315*0Sstevel@tonic-gate 	 *
2316*0Sstevel@tonic-gate 	 *	EXPORT DELETE END
2317*0Sstevel@tonic-gate 	 */
2318*0Sstevel@tonic-gate 
2319*0Sstevel@tonic-gate 	if (!esp_age_bytes(assoc, datalen + padlen +
2320*0Sstevel@tonic-gate /* EXPORT DELETE START */
2321*0Sstevel@tonic-gate 	    iv_len +
2322*0Sstevel@tonic-gate /* EXPORT DELETE END */
2323*0Sstevel@tonic-gate 	    2, B_FALSE)) {
2324*0Sstevel@tonic-gate 		/*
2325*0Sstevel@tonic-gate 		 * TODO:  Find the outbound IRE for this packet and
2326*0Sstevel@tonic-gate 		 * pass it to ip_drop_packet().
2327*0Sstevel@tonic-gate 		 */
2328*0Sstevel@tonic-gate 		ip_drop_packet(mp, B_FALSE, NULL, NULL,
2329*0Sstevel@tonic-gate 		    &ipdrops_esp_bytes_expire, &esp_dropper);
2330*0Sstevel@tonic-gate 		return (IPSEC_STATUS_FAILED);
2331*0Sstevel@tonic-gate 	}
2332*0Sstevel@tonic-gate 
2333*0Sstevel@tonic-gate 	espmp = allocb(esplen, BPRI_HI);
2334*0Sstevel@tonic-gate 	if (espmp == NULL) {
2335*0Sstevel@tonic-gate 		ESP_BUMP_STAT(out_discards);
2336*0Sstevel@tonic-gate 		esp1dbg(("esp_outbound: can't allocate espmp.\n"));
2337*0Sstevel@tonic-gate 		/*
2338*0Sstevel@tonic-gate 		 * TODO:  Find the outbound IRE for this packet and
2339*0Sstevel@tonic-gate 		 * pass it to ip_drop_packet().
2340*0Sstevel@tonic-gate 		 */
2341*0Sstevel@tonic-gate 		ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_esp_nomem,
2342*0Sstevel@tonic-gate 		    &esp_dropper);
2343*0Sstevel@tonic-gate 		return (IPSEC_STATUS_FAILED);
2344*0Sstevel@tonic-gate 	}
2345*0Sstevel@tonic-gate 	espmp->b_wptr += esplen;
2346*0Sstevel@tonic-gate 	esph = (esph_t *)espmp->b_rptr;
2347*0Sstevel@tonic-gate 
2348*0Sstevel@tonic-gate 	if (is_natt) {
2349*0Sstevel@tonic-gate 		esp3dbg(("esp_outbound: NATT"));
2350*0Sstevel@tonic-gate 
2351*0Sstevel@tonic-gate 		udpha = (udpha_t *)espmp->b_rptr;
2352*0Sstevel@tonic-gate 		udpha->uha_src_port = htons(IPPORT_IKE_NATT);
2353*0Sstevel@tonic-gate 		if (assoc->ipsa_remote_port != 0)
2354*0Sstevel@tonic-gate 			udpha->uha_dst_port = assoc->ipsa_remote_port;
2355*0Sstevel@tonic-gate 		else
2356*0Sstevel@tonic-gate 			udpha->uha_dst_port = htons(IPPORT_IKE_NATT);
2357*0Sstevel@tonic-gate 		/*
2358*0Sstevel@tonic-gate 		 * Set the checksum to 0, so that the ip_wput_ipsec_out()
2359*0Sstevel@tonic-gate 		 * can do the right thing.
2360*0Sstevel@tonic-gate 		 */
2361*0Sstevel@tonic-gate 		udpha->uha_checksum = 0;
2362*0Sstevel@tonic-gate 		esph = (esph_t *)(udpha + 1);
2363*0Sstevel@tonic-gate 	}
2364*0Sstevel@tonic-gate 
2365*0Sstevel@tonic-gate 	esph->esph_spi = assoc->ipsa_spi;
2366*0Sstevel@tonic-gate 
2367*0Sstevel@tonic-gate 	esph->esph_replay = htonl(atomic_add_32_nv(&assoc->ipsa_replay, 1));
2368*0Sstevel@tonic-gate 	if (esph->esph_replay == 0 && assoc->ipsa_replay_wsize != 0) {
2369*0Sstevel@tonic-gate 		/*
2370*0Sstevel@tonic-gate 		 * XXX We have replay counter wrapping.
2371*0Sstevel@tonic-gate 		 * We probably want to nuke this SA (and its peer).
2372*0Sstevel@tonic-gate 		 */
2373*0Sstevel@tonic-gate 		ipsec_assocfailure(info.mi_idnum, 0, 0,
2374*0Sstevel@tonic-gate 		    SL_ERROR | SL_CONSOLE | SL_WARN,
2375*0Sstevel@tonic-gate 		    "Outbound ESP SA (0x%x, %s) has wrapped sequence.\n",
2376*0Sstevel@tonic-gate 		    esph->esph_spi, assoc->ipsa_dstaddr, af);
2377*0Sstevel@tonic-gate 
2378*0Sstevel@tonic-gate 		ESP_BUMP_STAT(out_discards);
2379*0Sstevel@tonic-gate 		sadb_replay_delete(assoc);
2380*0Sstevel@tonic-gate 		/*
2381*0Sstevel@tonic-gate 		 * TODO:  Find the outbound IRE for this packet and
2382*0Sstevel@tonic-gate 		 * pass it to ip_drop_packet().
2383*0Sstevel@tonic-gate 		 */
2384*0Sstevel@tonic-gate 		ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_esp_replay,
2385*0Sstevel@tonic-gate 		    &esp_dropper);
2386*0Sstevel@tonic-gate 		return (IPSEC_STATUS_FAILED);
2387*0Sstevel@tonic-gate 	}
2388*0Sstevel@tonic-gate 
2389*0Sstevel@tonic-gate /* EXPORT DELETE START */
2390*0Sstevel@tonic-gate 	/*
2391*0Sstevel@tonic-gate 	 * Set the IV to a random quantity.  We do not require the
2392*0Sstevel@tonic-gate 	 * highest quality random bits, but for best security with CBC
2393*0Sstevel@tonic-gate 	 * mode ciphers, the value must be unlikely to repeat and also
2394*0Sstevel@tonic-gate 	 * must not be known in advance to an adversary capable of
2395*0Sstevel@tonic-gate 	 * influencing the plaintext.
2396*0Sstevel@tonic-gate 	 */
2397*0Sstevel@tonic-gate 	(void) random_get_pseudo_bytes((uint8_t *)(esph + 1), iv_len);
2398*0Sstevel@tonic-gate /* EXPORT DELETE END */
2399*0Sstevel@tonic-gate 
2400*0Sstevel@tonic-gate 	/* Fix the IP header. */
2401*0Sstevel@tonic-gate 	alloclen = padlen + 2 + mac_len;
2402*0Sstevel@tonic-gate 	adj = alloclen + (espmp->b_wptr - espmp->b_rptr);
2403*0Sstevel@tonic-gate 
2404*0Sstevel@tonic-gate 	protocol = *nhp;
2405*0Sstevel@tonic-gate 
2406*0Sstevel@tonic-gate 	if (io->ipsec_out_v4) {
2407*0Sstevel@tonic-gate 		ipha->ipha_length = htons(ntohs(ipha->ipha_length) + adj);
2408*0Sstevel@tonic-gate 		if (is_natt) {
2409*0Sstevel@tonic-gate 			*nhp = IPPROTO_UDP;
2410*0Sstevel@tonic-gate 			udpha->uha_length = htons(ntohs(ipha->ipha_length) -
2411*0Sstevel@tonic-gate 			    IPH_HDR_LENGTH(ipha));
2412*0Sstevel@tonic-gate 		} else {
2413*0Sstevel@tonic-gate 			*nhp = IPPROTO_ESP;
2414*0Sstevel@tonic-gate 		}
2415*0Sstevel@tonic-gate 		ipha->ipha_hdr_checksum = 0;
2416*0Sstevel@tonic-gate 		ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha);
2417*0Sstevel@tonic-gate 	} else {
2418*0Sstevel@tonic-gate 		ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + adj);
2419*0Sstevel@tonic-gate 		*nhp = IPPROTO_ESP;
2420*0Sstevel@tonic-gate 	}
2421*0Sstevel@tonic-gate 
2422*0Sstevel@tonic-gate 	/* I've got the two ESP mblks, now insert them. */
2423*0Sstevel@tonic-gate 
2424*0Sstevel@tonic-gate 	esp2dbg(("data_mp before outbound ESP adjustment:\n"));
2425*0Sstevel@tonic-gate 	esp2dbg((dump_msg(data_mp)));
2426*0Sstevel@tonic-gate 
2427*0Sstevel@tonic-gate 	if (!esp_insert_esp(data_mp, espmp, divpoint)) {
2428*0Sstevel@tonic-gate 		ESP_BUMP_STAT(out_discards);
2429*0Sstevel@tonic-gate 		/* NOTE:  esp_insert_esp() only fails if there's no memory. */
2430*0Sstevel@tonic-gate 		/*
2431*0Sstevel@tonic-gate 		 * TODO:  Find the outbound IRE for this packet and
2432*0Sstevel@tonic-gate 		 * pass it to ip_drop_packet().
2433*0Sstevel@tonic-gate 		 */
2434*0Sstevel@tonic-gate 		ip_drop_packet(mp, B_FALSE, NULL, NULL, &ipdrops_esp_nomem,
2435*0Sstevel@tonic-gate 		    &esp_dropper);
2436*0Sstevel@tonic-gate 		freeb(espmp);
2437*0Sstevel@tonic-gate 		return (IPSEC_STATUS_FAILED);
2438*0Sstevel@tonic-gate 	}
2439*0Sstevel@tonic-gate 
2440*0Sstevel@tonic-gate 	/* Append padding (and leave room for ICV). */
2441*0Sstevel@tonic-gate 	for (tailmp = data_mp; tailmp->b_cont != NULL; tailmp = tailmp->b_cont)
2442*0Sstevel@tonic-gate 		;
2443*0Sstevel@tonic-gate 	if (tailmp->b_wptr + alloclen > tailmp->b_datap->db_lim) {
2444*0Sstevel@tonic-gate 		tailmp->b_cont = allocb(alloclen, BPRI_HI);
2445*0Sstevel@tonic-gate 		if (tailmp->b_cont == NULL) {
2446*0Sstevel@tonic-gate 			ESP_BUMP_STAT(out_discards);
2447*0Sstevel@tonic-gate 			esp0dbg(("esp_outbound:  Can't allocate tailmp.\n"));
2448*0Sstevel@tonic-gate 			/*
2449*0Sstevel@tonic-gate 			 * TODO:  Find the outbound IRE for this packet and
2450*0Sstevel@tonic-gate 			 * pass it to ip_drop_packet().
2451*0Sstevel@tonic-gate 			 */
2452*0Sstevel@tonic-gate 			ip_drop_packet(mp, B_FALSE, NULL, NULL,
2453*0Sstevel@tonic-gate 			    &ipdrops_esp_nomem, &esp_dropper);
2454*0Sstevel@tonic-gate 			return (IPSEC_STATUS_FAILED);
2455*0Sstevel@tonic-gate 		}
2456*0Sstevel@tonic-gate 		tailmp = tailmp->b_cont;
2457*0Sstevel@tonic-gate 	}
2458*0Sstevel@tonic-gate 
2459*0Sstevel@tonic-gate 	/*
2460*0Sstevel@tonic-gate 	 * If there's padding, N bytes of padding must be of the form 0x1,
2461*0Sstevel@tonic-gate 	 * 0x2, 0x3... 0xN.
2462*0Sstevel@tonic-gate 	 */
2463*0Sstevel@tonic-gate 	for (i = 0; i < padlen; ) {
2464*0Sstevel@tonic-gate 		i++;
2465*0Sstevel@tonic-gate 		*tailmp->b_wptr++ = i;
2466*0Sstevel@tonic-gate 	}
2467*0Sstevel@tonic-gate 	*tailmp->b_wptr++ = i;
2468*0Sstevel@tonic-gate 	*tailmp->b_wptr++ = protocol;
2469*0Sstevel@tonic-gate 
2470*0Sstevel@tonic-gate /* EXPORT DELETE START */
2471*0Sstevel@tonic-gate 	esp2dbg(("data_Mp before encryption:\n"));
2472*0Sstevel@tonic-gate 	esp2dbg((dump_msg(data_mp)));
2473*0Sstevel@tonic-gate 
2474*0Sstevel@tonic-gate 	/*
2475*0Sstevel@tonic-gate 	 * The packet is eligible for hardware acceleration if the
2476*0Sstevel@tonic-gate 	 * following conditions are satisfied:
2477*0Sstevel@tonic-gate 	 *
2478*0Sstevel@tonic-gate 	 * 1. the packet will not be fragmented
2479*0Sstevel@tonic-gate 	 * 2. the provider supports the algorithms specified by SA
2480*0Sstevel@tonic-gate 	 * 3. there is no pending control message being exchanged
2481*0Sstevel@tonic-gate 	 * 4. snoop is not attached
2482*0Sstevel@tonic-gate 	 * 5. the destination address is not a multicast address
2483*0Sstevel@tonic-gate 	 *
2484*0Sstevel@tonic-gate 	 * All five of these conditions are checked by IP prior to
2485*0Sstevel@tonic-gate 	 * sending the packet to ESP.
2486*0Sstevel@tonic-gate 	 *
2487*0Sstevel@tonic-gate 	 * But We, and We Alone, can, nay MUST check if the packet
2488*0Sstevel@tonic-gate 	 * is over NATT, and then disqualify it from hardware
2489*0Sstevel@tonic-gate 	 * acceleration.
2490*0Sstevel@tonic-gate 	 */
2491*0Sstevel@tonic-gate 
2492*0Sstevel@tonic-gate 	if (io->ipsec_out_is_capab_ill && !(assoc->ipsa_flags & IPSA_F_NATT)) {
2493*0Sstevel@tonic-gate 		return (esp_outbound_accelerated(ipsec_out_mp, mac_len));
2494*0Sstevel@tonic-gate 	}
2495*0Sstevel@tonic-gate 	ESP_BUMP_STAT(noaccel);
2496*0Sstevel@tonic-gate 
2497*0Sstevel@tonic-gate 	/*
2498*0Sstevel@tonic-gate 	 * Okay.  I've set up the pre-encryption ESP.  Let's do it!
2499*0Sstevel@tonic-gate 	 */
2500*0Sstevel@tonic-gate /* EXPORT DELETE END */
2501*0Sstevel@tonic-gate 
2502*0Sstevel@tonic-gate 	if (mac_len > 0) {
2503*0Sstevel@tonic-gate 		ASSERT(tailmp->b_wptr + mac_len <= tailmp->b_datap->db_lim);
2504*0Sstevel@tonic-gate 		icv_buf = tailmp->b_wptr;
2505*0Sstevel@tonic-gate 		tailmp->b_wptr += mac_len;
2506*0Sstevel@tonic-gate 	} else {
2507*0Sstevel@tonic-gate 		icv_buf = NULL;
2508*0Sstevel@tonic-gate 	}
2509*0Sstevel@tonic-gate 
2510*0Sstevel@tonic-gate 	return (esp_submit_req_outbound(ipsec_out_mp, assoc, icv_buf,
2511*0Sstevel@tonic-gate 	    datalen + padlen + 2));
2512*0Sstevel@tonic-gate }
2513*0Sstevel@tonic-gate 
2514*0Sstevel@tonic-gate /*
2515*0Sstevel@tonic-gate  * IP calls this to validate the ICMP errors that
2516*0Sstevel@tonic-gate  * we got from the network.
2517*0Sstevel@tonic-gate  */
2518*0Sstevel@tonic-gate ipsec_status_t
2519*0Sstevel@tonic-gate ipsecesp_icmp_error(mblk_t *ipsec_mp)
2520*0Sstevel@tonic-gate {
2521*0Sstevel@tonic-gate 	/*
2522*0Sstevel@tonic-gate 	 * Unless we get an entire packet back, this function is useless.
2523*0Sstevel@tonic-gate 	 * Why?
2524*0Sstevel@tonic-gate 	 *
2525*0Sstevel@tonic-gate 	 * 1.)	Partial packets are useless, because the "next header"
2526*0Sstevel@tonic-gate 	 *	is at the end of the decrypted ESP packet.  Without the
2527*0Sstevel@tonic-gate 	 *	whole packet, this is useless.
2528*0Sstevel@tonic-gate 	 *
2529*0Sstevel@tonic-gate 	 * 2.)	If we every use a stateful cipher, such as a stream or a
2530*0Sstevel@tonic-gate 	 *	one-time pad, we can't do anything.
2531*0Sstevel@tonic-gate 	 *
2532*0Sstevel@tonic-gate 	 * Since the chances of us getting an entire packet back are very
2533*0Sstevel@tonic-gate 	 * very small, we discard here.
2534*0Sstevel@tonic-gate 	 */
2535*0Sstevel@tonic-gate 	IP_ESP_BUMP_STAT(in_discards);
2536*0Sstevel@tonic-gate 	ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, &ipdrops_esp_icmp,
2537*0Sstevel@tonic-gate 	    &esp_dropper);
2538*0Sstevel@tonic-gate 	return (IPSEC_STATUS_FAILED);
2539*0Sstevel@tonic-gate }
2540*0Sstevel@tonic-gate 
2541*0Sstevel@tonic-gate /*
2542*0Sstevel@tonic-gate  * ESP module read put routine.
2543*0Sstevel@tonic-gate  */
2544*0Sstevel@tonic-gate /* ARGSUSED */
2545*0Sstevel@tonic-gate static void
2546*0Sstevel@tonic-gate ipsecesp_rput(queue_t *q, mblk_t *mp)
2547*0Sstevel@tonic-gate {
2548*0Sstevel@tonic-gate 	keysock_in_t *ksi;
2549*0Sstevel@tonic-gate 	int *addrtype;
2550*0Sstevel@tonic-gate 	ire_t *ire;
2551*0Sstevel@tonic-gate 	mblk_t *ire_mp, *last_mp;
2552*0Sstevel@tonic-gate 
2553*0Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
2554*0Sstevel@tonic-gate 	case M_CTL:
2555*0Sstevel@tonic-gate 		/*
2556*0Sstevel@tonic-gate 		 * IPsec request of some variety from IP.  IPSEC_{IN,OUT}
2557*0Sstevel@tonic-gate 		 * are the common cases, but even ICMP error messages from IP
2558*0Sstevel@tonic-gate 		 * may rise up here.
2559*0Sstevel@tonic-gate 		 *
2560*0Sstevel@tonic-gate 		 * Ummmm, actually, this can also be the reflected KEYSOCK_IN
2561*0Sstevel@tonic-gate 		 * message, with an IRE_DB_TYPE hung off at the end.
2562*0Sstevel@tonic-gate 		 */
2563*0Sstevel@tonic-gate 		switch (((ipsec_info_t *)(mp->b_rptr))->ipsec_info_type) {
2564*0Sstevel@tonic-gate 		case KEYSOCK_IN:
2565*0Sstevel@tonic-gate 			last_mp = mp;
2566*0Sstevel@tonic-gate 			while (last_mp->b_cont != NULL &&
2567*0Sstevel@tonic-gate 			    last_mp->b_cont->b_datap->db_type != IRE_DB_TYPE)
2568*0Sstevel@tonic-gate 				last_mp = last_mp->b_cont;
2569*0Sstevel@tonic-gate 
2570*0Sstevel@tonic-gate 			if (last_mp->b_cont == NULL) {
2571*0Sstevel@tonic-gate 				freemsg(mp);
2572*0Sstevel@tonic-gate 				break;	/* Out of switch. */
2573*0Sstevel@tonic-gate 			}
2574*0Sstevel@tonic-gate 
2575*0Sstevel@tonic-gate 			ire_mp = last_mp->b_cont;
2576*0Sstevel@tonic-gate 			last_mp->b_cont = NULL;
2577*0Sstevel@tonic-gate 
2578*0Sstevel@tonic-gate 			ksi = (keysock_in_t *)mp->b_rptr;
2579*0Sstevel@tonic-gate 
2580*0Sstevel@tonic-gate 			if (ksi->ks_in_srctype == KS_IN_ADDR_UNKNOWN)
2581*0Sstevel@tonic-gate 				addrtype = &ksi->ks_in_srctype;
2582*0Sstevel@tonic-gate 			else if (ksi->ks_in_dsttype == KS_IN_ADDR_UNKNOWN)
2583*0Sstevel@tonic-gate 				addrtype = &ksi->ks_in_dsttype;
2584*0Sstevel@tonic-gate 			else if (ksi->ks_in_proxytype == KS_IN_ADDR_UNKNOWN)
2585*0Sstevel@tonic-gate 				addrtype = &ksi->ks_in_proxytype;
2586*0Sstevel@tonic-gate 
2587*0Sstevel@tonic-gate 			ire = (ire_t *)ire_mp->b_rptr;
2588*0Sstevel@tonic-gate 
2589*0Sstevel@tonic-gate 			*addrtype = sadb_addrset(ire);
2590*0Sstevel@tonic-gate 
2591*0Sstevel@tonic-gate 			freemsg(ire_mp);
2592*0Sstevel@tonic-gate 			if (esp_pfkey_q != NULL) {
2593*0Sstevel@tonic-gate 				/*
2594*0Sstevel@tonic-gate 				 * Decrement counter to make up for
2595*0Sstevel@tonic-gate 				 * auto-increment in ipsecesp_wput().
2596*0Sstevel@tonic-gate 				 * I'm running all MT-hot through here, so
2597*0Sstevel@tonic-gate 				 * don't worry about perimeters and lateral
2598*0Sstevel@tonic-gate 				 * puts.
2599*0Sstevel@tonic-gate 				 */
2600*0Sstevel@tonic-gate 				ESP_DEBUMP_STAT(keysock_in);
2601*0Sstevel@tonic-gate 				ipsecesp_wput(WR(esp_pfkey_q), mp);
2602*0Sstevel@tonic-gate 			} else {
2603*0Sstevel@tonic-gate 				freemsg(mp);
2604*0Sstevel@tonic-gate 			}
2605*0Sstevel@tonic-gate 			break;
2606*0Sstevel@tonic-gate 		default:
2607*0Sstevel@tonic-gate 			freemsg(mp);
2608*0Sstevel@tonic-gate 			break;
2609*0Sstevel@tonic-gate 		}
2610*0Sstevel@tonic-gate 		break;
2611*0Sstevel@tonic-gate 	case M_PROTO:
2612*0Sstevel@tonic-gate 	case M_PCPROTO:
2613*0Sstevel@tonic-gate 		/* TPI message of some sort. */
2614*0Sstevel@tonic-gate 		switch (*((t_scalar_t *)mp->b_rptr)) {
2615*0Sstevel@tonic-gate 		case T_BIND_ACK:
2616*0Sstevel@tonic-gate 			esp3dbg(("Thank you IP from ESP for T_BIND_ACK\n"));
2617*0Sstevel@tonic-gate 			break;
2618*0Sstevel@tonic-gate 		case T_ERROR_ACK:
2619*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
2620*0Sstevel@tonic-gate 			    "ipsecesp:  ESP received T_ERROR_ACK from IP.");
2621*0Sstevel@tonic-gate 			/*
2622*0Sstevel@tonic-gate 			 * Make esp_sadb.s_ip_q NULL, and in the
2623*0Sstevel@tonic-gate 			 * future, perhaps try again.
2624*0Sstevel@tonic-gate 			 */
2625*0Sstevel@tonic-gate 			esp_sadb.s_ip_q = NULL;
2626*0Sstevel@tonic-gate 			break;
2627*0Sstevel@tonic-gate 		case T_OK_ACK:
2628*0Sstevel@tonic-gate 			/* Probably from a (rarely sent) T_UNBIND_REQ. */
2629*0Sstevel@tonic-gate 			break;
2630*0Sstevel@tonic-gate 		default:
2631*0Sstevel@tonic-gate 			esp0dbg(("Unknown M_{,PC}PROTO message.\n"));
2632*0Sstevel@tonic-gate 		}
2633*0Sstevel@tonic-gate 		freemsg(mp);
2634*0Sstevel@tonic-gate 		break;
2635*0Sstevel@tonic-gate 	default:
2636*0Sstevel@tonic-gate 		/* For now, passthru message. */
2637*0Sstevel@tonic-gate 		esp2dbg(("ESP got unknown mblk type %d.\n",
2638*0Sstevel@tonic-gate 		    mp->b_datap->db_type));
2639*0Sstevel@tonic-gate 		putnext(q, mp);
2640*0Sstevel@tonic-gate 	}
2641*0Sstevel@tonic-gate }
2642*0Sstevel@tonic-gate 
2643*0Sstevel@tonic-gate /*
2644*0Sstevel@tonic-gate  * Construct an SADB_REGISTER message with the current algorithms.
2645*0Sstevel@tonic-gate  */
2646*0Sstevel@tonic-gate static boolean_t
2647*0Sstevel@tonic-gate esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial)
2648*0Sstevel@tonic-gate {
2649*0Sstevel@tonic-gate 	mblk_t *pfkey_msg_mp, *keysock_out_mp;
2650*0Sstevel@tonic-gate 	sadb_msg_t *samsg;
2651*0Sstevel@tonic-gate 	sadb_supported_t *sasupp_auth = NULL;
2652*0Sstevel@tonic-gate /* EXPORT DELETE START */
2653*0Sstevel@tonic-gate 	sadb_supported_t *sasupp_encr = NULL;
2654*0Sstevel@tonic-gate /* EXPORT DELETE END */
2655*0Sstevel@tonic-gate 	sadb_alg_t *saalg;
2656*0Sstevel@tonic-gate 	uint_t allocsize = sizeof (*samsg);
2657*0Sstevel@tonic-gate 	uint_t i, numalgs_snap;
2658*0Sstevel@tonic-gate 	int current_aalgs;
2659*0Sstevel@tonic-gate 	ipsec_alginfo_t **authalgs;
2660*0Sstevel@tonic-gate 	uint_t num_aalgs;
2661*0Sstevel@tonic-gate /* EXPORT DELETE START */
2662*0Sstevel@tonic-gate 	int current_ealgs;
2663*0Sstevel@tonic-gate 	ipsec_alginfo_t **encralgs;
2664*0Sstevel@tonic-gate 	uint_t num_ealgs;
2665*0Sstevel@tonic-gate /* EXPORT DELETE END */
2666*0Sstevel@tonic-gate 
2667*0Sstevel@tonic-gate 	/* Allocate the KEYSOCK_OUT. */
2668*0Sstevel@tonic-gate 	keysock_out_mp = sadb_keysock_out(serial);
2669*0Sstevel@tonic-gate 	if (keysock_out_mp == NULL) {
2670*0Sstevel@tonic-gate 		esp0dbg(("esp_register_out: couldn't allocate mblk.\n"));
2671*0Sstevel@tonic-gate 		return (B_FALSE);
2672*0Sstevel@tonic-gate 	}
2673*0Sstevel@tonic-gate 
2674*0Sstevel@tonic-gate 	/*
2675*0Sstevel@tonic-gate 	 * Allocate the PF_KEY message that follows KEYSOCK_OUT.
2676*0Sstevel@tonic-gate 	 */
2677*0Sstevel@tonic-gate 
2678*0Sstevel@tonic-gate 	mutex_enter(&alg_lock);
2679*0Sstevel@tonic-gate 
2680*0Sstevel@tonic-gate 	/*
2681*0Sstevel@tonic-gate 	 * Fill SADB_REGISTER message's algorithm descriptors.  Hold
2682*0Sstevel@tonic-gate 	 * down the lock while filling it.
2683*0Sstevel@tonic-gate 	 *
2684*0Sstevel@tonic-gate 	 * Return only valid algorithms, so the number of algorithms
2685*0Sstevel@tonic-gate 	 * to send up may be less than the number of algorithm entries
2686*0Sstevel@tonic-gate 	 * in the table.
2687*0Sstevel@tonic-gate 	 */
2688*0Sstevel@tonic-gate 	authalgs = ipsec_alglists[IPSEC_ALG_AUTH];
2689*0Sstevel@tonic-gate 	for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
2690*0Sstevel@tonic-gate 		if (authalgs[i] != NULL && ALG_VALID(authalgs[i]))
2691*0Sstevel@tonic-gate 			num_aalgs++;
2692*0Sstevel@tonic-gate 
2693*0Sstevel@tonic-gate 	if (num_aalgs != 0) {
2694*0Sstevel@tonic-gate 		allocsize += (num_aalgs * sizeof (*saalg));
2695*0Sstevel@tonic-gate 		allocsize += sizeof (*sasupp_auth);
2696*0Sstevel@tonic-gate 	}
2697*0Sstevel@tonic-gate /* EXPORT DELETE START */
2698*0Sstevel@tonic-gate 	encralgs = ipsec_alglists[IPSEC_ALG_ENCR];
2699*0Sstevel@tonic-gate 	for (num_ealgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++)
2700*0Sstevel@tonic-gate 		if (encralgs[i] != NULL && ALG_VALID(encralgs[i]))
2701*0Sstevel@tonic-gate 			num_ealgs++;
2702*0Sstevel@tonic-gate 
2703*0Sstevel@tonic-gate 	if (num_ealgs != 0) {
2704*0Sstevel@tonic-gate 		allocsize += (num_ealgs * sizeof (*saalg));
2705*0Sstevel@tonic-gate 		allocsize += sizeof (*sasupp_encr);
2706*0Sstevel@tonic-gate 	}
2707*0Sstevel@tonic-gate /* EXPORT DELETE END */
2708*0Sstevel@tonic-gate 	keysock_out_mp->b_cont = allocb(allocsize, BPRI_HI);
2709*0Sstevel@tonic-gate 	if (keysock_out_mp->b_cont == NULL) {
2710*0Sstevel@tonic-gate 		mutex_exit(&alg_lock);
2711*0Sstevel@tonic-gate 		freemsg(keysock_out_mp);
2712*0Sstevel@tonic-gate 		return (B_FALSE);
2713*0Sstevel@tonic-gate 	}
2714*0Sstevel@tonic-gate 
2715*0Sstevel@tonic-gate 	pfkey_msg_mp = keysock_out_mp->b_cont;
2716*0Sstevel@tonic-gate 	pfkey_msg_mp->b_wptr += allocsize;
2717*0Sstevel@tonic-gate 	if (num_aalgs != 0) {
2718*0Sstevel@tonic-gate 		sasupp_auth = (sadb_supported_t *)
2719*0Sstevel@tonic-gate 		    (pfkey_msg_mp->b_rptr + sizeof (*samsg));
2720*0Sstevel@tonic-gate 		saalg = (sadb_alg_t *)(sasupp_auth + 1);
2721*0Sstevel@tonic-gate 
2722*0Sstevel@tonic-gate 		ASSERT(((ulong_t)saalg & 0x7) == 0);
2723*0Sstevel@tonic-gate 
2724*0Sstevel@tonic-gate 		numalgs_snap = 0;
2725*0Sstevel@tonic-gate 		for (i = 0;
2726*0Sstevel@tonic-gate 		    ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs)); i++) {
2727*0Sstevel@tonic-gate 			if (authalgs[i] == NULL || !ALG_VALID(authalgs[i]))
2728*0Sstevel@tonic-gate 				continue;
2729*0Sstevel@tonic-gate 
2730*0Sstevel@tonic-gate 			saalg->sadb_alg_id = authalgs[i]->alg_id;
2731*0Sstevel@tonic-gate 			saalg->sadb_alg_ivlen = 0;
2732*0Sstevel@tonic-gate 			saalg->sadb_alg_minbits	= authalgs[i]->alg_ef_minbits;
2733*0Sstevel@tonic-gate 			saalg->sadb_alg_maxbits	= authalgs[i]->alg_ef_maxbits;
2734*0Sstevel@tonic-gate 			saalg->sadb_x_alg_defincr = authalgs[i]->alg_ef_default;
2735*0Sstevel@tonic-gate 			saalg->sadb_x_alg_increment =
2736*0Sstevel@tonic-gate 			    authalgs[i]->alg_increment;
2737*0Sstevel@tonic-gate 			numalgs_snap++;
2738*0Sstevel@tonic-gate 			saalg++;
2739*0Sstevel@tonic-gate 		}
2740*0Sstevel@tonic-gate 		ASSERT(numalgs_snap == num_aalgs);
2741*0Sstevel@tonic-gate #ifdef DEBUG
2742*0Sstevel@tonic-gate 		/*
2743*0Sstevel@tonic-gate 		 * Reality check to make sure I snagged all of the
2744*0Sstevel@tonic-gate 		 * algorithms.
2745*0Sstevel@tonic-gate 		 */
2746*0Sstevel@tonic-gate 		for (; i < IPSEC_MAX_ALGS; i++) {
2747*0Sstevel@tonic-gate 			if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) {
2748*0Sstevel@tonic-gate 				cmn_err(CE_PANIC, "esp_register_out()! "
2749*0Sstevel@tonic-gate 				    "Missed aalg #%d.\n", i);
2750*0Sstevel@tonic-gate 			}
2751*0Sstevel@tonic-gate 		}
2752*0Sstevel@tonic-gate #endif /* DEBUG */
2753*0Sstevel@tonic-gate 	} else {
2754*0Sstevel@tonic-gate 		saalg = (sadb_alg_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg));
2755*0Sstevel@tonic-gate 	}
2756*0Sstevel@tonic-gate 
2757*0Sstevel@tonic-gate /* EXPORT DELETE START */
2758*0Sstevel@tonic-gate 	if (num_ealgs != 0) {
2759*0Sstevel@tonic-gate 		sasupp_encr = (sadb_supported_t *)saalg;
2760*0Sstevel@tonic-gate 		saalg = (sadb_alg_t *)(sasupp_encr + 1);
2761*0Sstevel@tonic-gate 
2762*0Sstevel@tonic-gate 		numalgs_snap = 0;
2763*0Sstevel@tonic-gate 		for (i = 0;
2764*0Sstevel@tonic-gate 		    ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_ealgs)); i++) {
2765*0Sstevel@tonic-gate 			if (encralgs[i] == NULL || !ALG_VALID(encralgs[i]))
2766*0Sstevel@tonic-gate 				continue;
2767*0Sstevel@tonic-gate 			saalg->sadb_alg_id = encralgs[i]->alg_id;
2768*0Sstevel@tonic-gate 			saalg->sadb_alg_ivlen = encralgs[i]->alg_datalen;
2769*0Sstevel@tonic-gate 			saalg->sadb_alg_minbits	= encralgs[i]->alg_ef_minbits;
2770*0Sstevel@tonic-gate 			saalg->sadb_alg_maxbits	= encralgs[i]->alg_ef_maxbits;
2771*0Sstevel@tonic-gate 			saalg->sadb_x_alg_defincr = encralgs[i]->alg_ef_default;
2772*0Sstevel@tonic-gate 			saalg->sadb_x_alg_increment =
2773*0Sstevel@tonic-gate 			    encralgs[i]->alg_increment;
2774*0Sstevel@tonic-gate 			numalgs_snap++;
2775*0Sstevel@tonic-gate 			saalg++;
2776*0Sstevel@tonic-gate 		}
2777*0Sstevel@tonic-gate 		ASSERT(numalgs_snap == num_ealgs);
2778*0Sstevel@tonic-gate #ifdef DEBUG
2779*0Sstevel@tonic-gate 		/*
2780*0Sstevel@tonic-gate 		 * Reality check to make sure I snagged all of the
2781*0Sstevel@tonic-gate 		 * algorithms.
2782*0Sstevel@tonic-gate 		 */
2783*0Sstevel@tonic-gate 		for (; i < IPSEC_MAX_ALGS; i++) {
2784*0Sstevel@tonic-gate 			if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) {
2785*0Sstevel@tonic-gate 				cmn_err(CE_PANIC, "esp_register_out()! "
2786*0Sstevel@tonic-gate 				    "Missed ealg #%d.\n", i);
2787*0Sstevel@tonic-gate 			}
2788*0Sstevel@tonic-gate 		}
2789*0Sstevel@tonic-gate #endif /* DEBUG */
2790*0Sstevel@tonic-gate 	}
2791*0Sstevel@tonic-gate /* EXPORT DELETE END */
2792*0Sstevel@tonic-gate 
2793*0Sstevel@tonic-gate 	current_aalgs = num_aalgs;
2794*0Sstevel@tonic-gate /* EXPORT DELETE START */
2795*0Sstevel@tonic-gate 	current_ealgs = num_ealgs;
2796*0Sstevel@tonic-gate /* EXPORT DELETE END */
2797*0Sstevel@tonic-gate 
2798*0Sstevel@tonic-gate 	mutex_exit(&alg_lock);
2799*0Sstevel@tonic-gate 
2800*0Sstevel@tonic-gate 	/* Now fill the rest of the SADB_REGISTER message. */
2801*0Sstevel@tonic-gate 
2802*0Sstevel@tonic-gate 	samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr;
2803*0Sstevel@tonic-gate 	samsg->sadb_msg_version = PF_KEY_V2;
2804*0Sstevel@tonic-gate 	samsg->sadb_msg_type = SADB_REGISTER;
2805*0Sstevel@tonic-gate 	samsg->sadb_msg_errno = 0;
2806*0Sstevel@tonic-gate 	samsg->sadb_msg_satype = SADB_SATYPE_ESP;
2807*0Sstevel@tonic-gate 	samsg->sadb_msg_len = SADB_8TO64(allocsize);
2808*0Sstevel@tonic-gate 	samsg->sadb_msg_reserved = 0;
2809*0Sstevel@tonic-gate 	/*
2810*0Sstevel@tonic-gate 	 * Assume caller has sufficient sequence/pid number info.  If it's one
2811*0Sstevel@tonic-gate 	 * from me over a new alg., I could give two hoots about sequence.
2812*0Sstevel@tonic-gate 	 */
2813*0Sstevel@tonic-gate 	samsg->sadb_msg_seq = sequence;
2814*0Sstevel@tonic-gate 	samsg->sadb_msg_pid = pid;
2815*0Sstevel@tonic-gate 
2816*0Sstevel@tonic-gate 	if (sasupp_auth != NULL) {
2817*0Sstevel@tonic-gate 		sasupp_auth->sadb_supported_len =
2818*0Sstevel@tonic-gate 		    SADB_8TO64(sizeof (*sasupp_auth) +
2819*0Sstevel@tonic-gate 			sizeof (*saalg) * current_aalgs);
2820*0Sstevel@tonic-gate 		sasupp_auth->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
2821*0Sstevel@tonic-gate 		sasupp_auth->sadb_supported_reserved = 0;
2822*0Sstevel@tonic-gate 	}
2823*0Sstevel@tonic-gate 
2824*0Sstevel@tonic-gate /* EXPORT DELETE START */
2825*0Sstevel@tonic-gate 	if (sasupp_encr != NULL) {
2826*0Sstevel@tonic-gate 		sasupp_encr->sadb_supported_len =
2827*0Sstevel@tonic-gate 		    SADB_8TO64(sizeof (*sasupp_encr) +
2828*0Sstevel@tonic-gate 			sizeof (*saalg) * current_ealgs);
2829*0Sstevel@tonic-gate 		sasupp_encr->sadb_supported_exttype =
2830*0Sstevel@tonic-gate 		    SADB_EXT_SUPPORTED_ENCRYPT;
2831*0Sstevel@tonic-gate 		sasupp_encr->sadb_supported_reserved = 0;
2832*0Sstevel@tonic-gate 	}
2833*0Sstevel@tonic-gate /* EXPORT DELETE END */
2834*0Sstevel@tonic-gate 
2835*0Sstevel@tonic-gate 	if (esp_pfkey_q != NULL)
2836*0Sstevel@tonic-gate 		putnext(esp_pfkey_q, keysock_out_mp);
2837*0Sstevel@tonic-gate 	else {
2838*0Sstevel@tonic-gate 		freemsg(keysock_out_mp);
2839*0Sstevel@tonic-gate 		return (B_FALSE);
2840*0Sstevel@tonic-gate 	}
2841*0Sstevel@tonic-gate 
2842*0Sstevel@tonic-gate 	return (B_TRUE);
2843*0Sstevel@tonic-gate }
2844*0Sstevel@tonic-gate 
2845*0Sstevel@tonic-gate /*
2846*0Sstevel@tonic-gate  * Invoked when the algorithm table changes. Causes SADB_REGISTER
2847*0Sstevel@tonic-gate  * messages continaining the current list of algorithms to be
2848*0Sstevel@tonic-gate  * sent up to the ESP listeners.
2849*0Sstevel@tonic-gate  */
2850*0Sstevel@tonic-gate void
2851*0Sstevel@tonic-gate ipsecesp_algs_changed(void)
2852*0Sstevel@tonic-gate {
2853*0Sstevel@tonic-gate 	/*
2854*0Sstevel@tonic-gate 	 * Time to send a PF_KEY SADB_REGISTER message to ESP listeners
2855*0Sstevel@tonic-gate 	 * everywhere.  (The function itself checks for NULL esp_pfkey_q.)
2856*0Sstevel@tonic-gate 	 */
2857*0Sstevel@tonic-gate 	(void) esp_register_out(0, 0, 0);
2858*0Sstevel@tonic-gate }
2859*0Sstevel@tonic-gate 
2860*0Sstevel@tonic-gate /*
2861*0Sstevel@tonic-gate  * taskq_dispatch handler.
2862*0Sstevel@tonic-gate  */
2863*0Sstevel@tonic-gate static void
2864*0Sstevel@tonic-gate inbound_task(void *arg)
2865*0Sstevel@tonic-gate {
2866*0Sstevel@tonic-gate 	esph_t *esph;
2867*0Sstevel@tonic-gate 	mblk_t *mp = (mblk_t *)arg;
2868*0Sstevel@tonic-gate 	ipsec_in_t *ii = (ipsec_in_t *)mp->b_rptr;
2869*0Sstevel@tonic-gate 	int ipsec_rc;
2870*0Sstevel@tonic-gate 
2871*0Sstevel@tonic-gate 	esp2dbg(("in ESP inbound_task"));
2872*0Sstevel@tonic-gate 
2873*0Sstevel@tonic-gate 	esph = ipsec_inbound_esp_sa(mp);
2874*0Sstevel@tonic-gate 	if (esph == NULL)
2875*0Sstevel@tonic-gate 		return;
2876*0Sstevel@tonic-gate 	ASSERT(ii->ipsec_in_esp_sa != NULL);
2877*0Sstevel@tonic-gate 	ipsec_rc = ii->ipsec_in_esp_sa->ipsa_input_func(mp, esph);
2878*0Sstevel@tonic-gate 	if (ipsec_rc != IPSEC_STATUS_SUCCESS)
2879*0Sstevel@tonic-gate 		return;
2880*0Sstevel@tonic-gate 	ip_fanout_proto_again(mp, NULL, NULL, NULL);
2881*0Sstevel@tonic-gate }
2882*0Sstevel@tonic-gate 
2883*0Sstevel@tonic-gate /*
2884*0Sstevel@tonic-gate  * Now that weak-key passed, actually ADD the security association, and
2885*0Sstevel@tonic-gate  * send back a reply ADD message.
2886*0Sstevel@tonic-gate  */
2887*0Sstevel@tonic-gate static int
2888*0Sstevel@tonic-gate esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi)
2889*0Sstevel@tonic-gate {
2890*0Sstevel@tonic-gate 	isaf_t *primary, *secondary, *inbound;
2891*0Sstevel@tonic-gate 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
2892*0Sstevel@tonic-gate 	sadb_address_t *dstext =
2893*0Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
2894*0Sstevel@tonic-gate 	struct sockaddr_in *dst;
2895*0Sstevel@tonic-gate 	struct sockaddr_in6 *dst6;
2896*0Sstevel@tonic-gate 	boolean_t is_ipv4, clone = B_FALSE, is_inbound = B_FALSE;
2897*0Sstevel@tonic-gate 	uint32_t *dstaddr;
2898*0Sstevel@tonic-gate 	ipsa_t *larval = NULL;
2899*0Sstevel@tonic-gate 	ipsacq_t *acqrec;
2900*0Sstevel@tonic-gate 	iacqf_t *acq_bucket;
2901*0Sstevel@tonic-gate 	mblk_t *acq_msgs = NULL;
2902*0Sstevel@tonic-gate 	int rc;
2903*0Sstevel@tonic-gate 	sadb_t *sp;
2904*0Sstevel@tonic-gate 	int outhash;
2905*0Sstevel@tonic-gate 	mblk_t *lpkt;
2906*0Sstevel@tonic-gate 
2907*0Sstevel@tonic-gate /* EXPORT DELETE START */
2908*0Sstevel@tonic-gate #if 0
2909*0Sstevel@tonic-gate 	/*
2910*0Sstevel@tonic-gate 	 * Gross hack for export control.  Since esp_encr_keycheck
2911*0Sstevel@tonic-gate 	 * is gone, I have to somehow enforce that exportable ESP source
2912*0Sstevel@tonic-gate 	 * can't have encryption.
2913*0Sstevel@tonic-gate 	 */
2914*0Sstevel@tonic-gate /* EXPORT DELETE END */
2915*0Sstevel@tonic-gate 	if (assoc->sadb_sa_encrypt != SADB_EALG_NULL) {
2916*0Sstevel@tonic-gate 		samsg->sadb_x_msg_diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG;
2917*0Sstevel@tonic-gate 		return (EINVAL);
2918*0Sstevel@tonic-gate 	}
2919*0Sstevel@tonic-gate /* EXPORT DELETE START */
2920*0Sstevel@tonic-gate #endif
2921*0Sstevel@tonic-gate /* EXPORT DELETE END */
2922*0Sstevel@tonic-gate 
2923*0Sstevel@tonic-gate 	/*
2924*0Sstevel@tonic-gate 	 * Locate the appropriate table(s).
2925*0Sstevel@tonic-gate 	 */
2926*0Sstevel@tonic-gate 
2927*0Sstevel@tonic-gate 	dst = (struct sockaddr_in *)(dstext + 1);
2928*0Sstevel@tonic-gate 	dst6 = (struct sockaddr_in6 *)dst;
2929*0Sstevel@tonic-gate 	is_ipv4 = (dst->sin_family == AF_INET);
2930*0Sstevel@tonic-gate 	if (is_ipv4) {
2931*0Sstevel@tonic-gate 		sp = &esp_sadb.s_v4;
2932*0Sstevel@tonic-gate 		dstaddr = (uint32_t *)(&dst->sin_addr);
2933*0Sstevel@tonic-gate 		outhash = OUTBOUND_HASH_V4(*(ipaddr_t *)dstaddr);
2934*0Sstevel@tonic-gate 	} else {
2935*0Sstevel@tonic-gate 		sp = &esp_sadb.s_v6;
2936*0Sstevel@tonic-gate 		dstaddr = (uint32_t *)(&dst6->sin6_addr);
2937*0Sstevel@tonic-gate 		outhash = OUTBOUND_HASH_V6(*(in6_addr_t *)dstaddr);
2938*0Sstevel@tonic-gate 	}
2939*0Sstevel@tonic-gate 	inbound = &sp->sdb_if[INBOUND_HASH(assoc->sadb_sa_spi)];
2940*0Sstevel@tonic-gate 	switch (ksi->ks_in_dsttype) {
2941*0Sstevel@tonic-gate 	case KS_IN_ADDR_MBCAST:
2942*0Sstevel@tonic-gate 		clone = B_TRUE;	/* All mcast SAs can be bidirectional */
2943*0Sstevel@tonic-gate 		/* FALLTHRU */
2944*0Sstevel@tonic-gate 	case KS_IN_ADDR_ME:
2945*0Sstevel@tonic-gate 		primary = inbound;
2946*0Sstevel@tonic-gate 		secondary = &sp->sdb_of[outhash];
2947*0Sstevel@tonic-gate 		/*
2948*0Sstevel@tonic-gate 		 * If the source address is either one of mine, or unspecified
2949*0Sstevel@tonic-gate 		 * (which is best summed up by saying "not 'not mine'"),
2950*0Sstevel@tonic-gate 		 * then the association is potentially bi-directional,
2951*0Sstevel@tonic-gate 		 * in that it can be used for inbound traffic and outbound
2952*0Sstevel@tonic-gate 		 * traffic.  The best example of such an SA is a multicast
2953*0Sstevel@tonic-gate 		 * SA (which allows me to receive the outbound traffic).
2954*0Sstevel@tonic-gate 		 */
2955*0Sstevel@tonic-gate 		if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME)
2956*0Sstevel@tonic-gate 			clone = B_TRUE;
2957*0Sstevel@tonic-gate 		is_inbound = B_TRUE;
2958*0Sstevel@tonic-gate 		break;
2959*0Sstevel@tonic-gate 	case KS_IN_ADDR_NOTME:
2960*0Sstevel@tonic-gate 		primary = &sp->sdb_of[outhash];
2961*0Sstevel@tonic-gate 		secondary = inbound;
2962*0Sstevel@tonic-gate 		/*
2963*0Sstevel@tonic-gate 		 * If the source address literally not mine (either
2964*0Sstevel@tonic-gate 		 * unspecified or not mine), then this SA may have an
2965*0Sstevel@tonic-gate 		 * address that WILL be mine after some configuration.
2966*0Sstevel@tonic-gate 		 * We pay the price for this by making it a bi-directional
2967*0Sstevel@tonic-gate 		 * SA.
2968*0Sstevel@tonic-gate 		 */
2969*0Sstevel@tonic-gate 		if (ksi->ks_in_srctype != KS_IN_ADDR_ME)
2970*0Sstevel@tonic-gate 			clone = B_TRUE;
2971*0Sstevel@tonic-gate 		break;
2972*0Sstevel@tonic-gate 	default:
2973*0Sstevel@tonic-gate 		samsg->sadb_x_msg_diagnostic = SADB_X_DIAGNOSTIC_BAD_DST;
2974*0Sstevel@tonic-gate 		return (EINVAL);
2975*0Sstevel@tonic-gate 	}
2976*0Sstevel@tonic-gate 
2977*0Sstevel@tonic-gate 	/*
2978*0Sstevel@tonic-gate 	 * Find a ACQUIRE list entry if possible.  If we've added an SA that
2979*0Sstevel@tonic-gate 	 * suits the needs of an ACQUIRE list entry, we can eliminate the
2980*0Sstevel@tonic-gate 	 * ACQUIRE list entry and transmit the enqueued packets.  Use the
2981*0Sstevel@tonic-gate 	 * high-bit of the sequence number to queue it.  Key off destination
2982*0Sstevel@tonic-gate 	 * addr, and change acqrec's state.
2983*0Sstevel@tonic-gate 	 */
2984*0Sstevel@tonic-gate 
2985*0Sstevel@tonic-gate 	if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) {
2986*0Sstevel@tonic-gate 		acq_bucket = &sp->sdb_acq[outhash];
2987*0Sstevel@tonic-gate 		mutex_enter(&acq_bucket->iacqf_lock);
2988*0Sstevel@tonic-gate 		for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL;
2989*0Sstevel@tonic-gate 		    acqrec = acqrec->ipsacq_next) {
2990*0Sstevel@tonic-gate 			mutex_enter(&acqrec->ipsacq_lock);
2991*0Sstevel@tonic-gate 			/*
2992*0Sstevel@tonic-gate 			 * Q:  I only check sequence.  Should I check dst?
2993*0Sstevel@tonic-gate 			 * A: Yes, check dest because those are the packets
2994*0Sstevel@tonic-gate 			 *    that are queued up.
2995*0Sstevel@tonic-gate 			 */
2996*0Sstevel@tonic-gate 			if (acqrec->ipsacq_seq == samsg->sadb_msg_seq &&
2997*0Sstevel@tonic-gate 			    IPSA_ARE_ADDR_EQUAL(dstaddr,
2998*0Sstevel@tonic-gate 				acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam))
2999*0Sstevel@tonic-gate 				break;
3000*0Sstevel@tonic-gate 			mutex_exit(&acqrec->ipsacq_lock);
3001*0Sstevel@tonic-gate 		}
3002*0Sstevel@tonic-gate 		if (acqrec != NULL) {
3003*0Sstevel@tonic-gate 			/*
3004*0Sstevel@tonic-gate 			 * AHA!  I found an ACQUIRE record for this SA.
3005*0Sstevel@tonic-gate 			 * Grab the msg list, and free the acquire record.
3006*0Sstevel@tonic-gate 			 * I already am holding the lock for this record,
3007*0Sstevel@tonic-gate 			 * so all I have to do is free it.
3008*0Sstevel@tonic-gate 			 */
3009*0Sstevel@tonic-gate 			acq_msgs = acqrec->ipsacq_mp;
3010*0Sstevel@tonic-gate 			acqrec->ipsacq_mp = NULL;
3011*0Sstevel@tonic-gate 			mutex_exit(&acqrec->ipsacq_lock);
3012*0Sstevel@tonic-gate 			sadb_destroy_acquire(acqrec);
3013*0Sstevel@tonic-gate 		}
3014*0Sstevel@tonic-gate 		mutex_exit(&acq_bucket->iacqf_lock);
3015*0Sstevel@tonic-gate 	}
3016*0Sstevel@tonic-gate 
3017*0Sstevel@tonic-gate 	/*
3018*0Sstevel@tonic-gate 	 * Find PF_KEY message, and see if I'm an update.  If so, find entry
3019*0Sstevel@tonic-gate 	 * in larval list (if there).
3020*0Sstevel@tonic-gate 	 */
3021*0Sstevel@tonic-gate 
3022*0Sstevel@tonic-gate 	if (samsg->sadb_msg_type == SADB_UPDATE) {
3023*0Sstevel@tonic-gate 		mutex_enter(&inbound->isaf_lock);
3024*0Sstevel@tonic-gate 		larval = ipsec_getassocbyspi(inbound, assoc->sadb_sa_spi,
3025*0Sstevel@tonic-gate 		    ALL_ZEROES_PTR, dstaddr, dst->sin_family);
3026*0Sstevel@tonic-gate 		mutex_exit(&inbound->isaf_lock);
3027*0Sstevel@tonic-gate 
3028*0Sstevel@tonic-gate 		if (larval == NULL) {
3029*0Sstevel@tonic-gate 			esp0dbg(("Larval update, but larval disappeared.\n"));
3030*0Sstevel@tonic-gate 			return (ESRCH);
3031*0Sstevel@tonic-gate 		} /* Else sadb_common_add unlinks it for me! */
3032*0Sstevel@tonic-gate 	}
3033*0Sstevel@tonic-gate 
3034*0Sstevel@tonic-gate 	lpkt = NULL;
3035*0Sstevel@tonic-gate 	if (larval != NULL)
3036*0Sstevel@tonic-gate 		lpkt = sadb_clear_lpkt(larval);
3037*0Sstevel@tonic-gate 
3038*0Sstevel@tonic-gate 	rc = sadb_common_add(esp_sadb.s_ip_q, esp_pfkey_q, mp, samsg, ksi,
3039*0Sstevel@tonic-gate 	    primary, secondary, larval, clone, is_inbound);
3040*0Sstevel@tonic-gate 
3041*0Sstevel@tonic-gate 	if (rc == 0 && lpkt != NULL) {
3042*0Sstevel@tonic-gate 		rc = !taskq_dispatch(esp_taskq, inbound_task,
3043*0Sstevel@tonic-gate 			    (void *) lpkt, TQ_NOSLEEP);
3044*0Sstevel@tonic-gate 	}
3045*0Sstevel@tonic-gate 
3046*0Sstevel@tonic-gate 	if (rc != 0) {
3047*0Sstevel@tonic-gate 		ip_drop_packet(lpkt, B_TRUE, NULL, NULL,
3048*0Sstevel@tonic-gate 		    &ipdrops_sadb_inlarval_timeout, &esp_dropper);
3049*0Sstevel@tonic-gate 	}
3050*0Sstevel@tonic-gate 
3051*0Sstevel@tonic-gate 	/*
3052*0Sstevel@tonic-gate 	 * How much more stack will I create with all of these
3053*0Sstevel@tonic-gate 	 * esp_outbound() calls?
3054*0Sstevel@tonic-gate 	 */
3055*0Sstevel@tonic-gate 
3056*0Sstevel@tonic-gate 	while (acq_msgs != NULL) {
3057*0Sstevel@tonic-gate 		mblk_t *mp = acq_msgs;
3058*0Sstevel@tonic-gate 
3059*0Sstevel@tonic-gate 		acq_msgs = acq_msgs->b_next;
3060*0Sstevel@tonic-gate 		mp->b_next = NULL;
3061*0Sstevel@tonic-gate 		if (rc == 0) {
3062*0Sstevel@tonic-gate 			if (ipsec_outbound_sa(mp, IPPROTO_ESP)) {
3063*0Sstevel@tonic-gate 				((ipsec_out_t *)(mp->b_rptr))->
3064*0Sstevel@tonic-gate 				    ipsec_out_esp_done = B_TRUE;
3065*0Sstevel@tonic-gate 				if (esp_outbound(mp) == IPSEC_STATUS_SUCCESS) {
3066*0Sstevel@tonic-gate 					ipha_t *ipha = (ipha_t *)
3067*0Sstevel@tonic-gate 					    mp->b_cont->b_rptr;
3068*0Sstevel@tonic-gate 
3069*0Sstevel@tonic-gate 					/* do AH processing if needed */
3070*0Sstevel@tonic-gate 					if (!esp_do_outbound_ah(mp))
3071*0Sstevel@tonic-gate 						continue;
3072*0Sstevel@tonic-gate 
3073*0Sstevel@tonic-gate 					/* finish IPsec processing */
3074*0Sstevel@tonic-gate 					if (is_ipv4) {
3075*0Sstevel@tonic-gate 						ip_wput_ipsec_out(NULL, mp,
3076*0Sstevel@tonic-gate 						    ipha, NULL, NULL);
3077*0Sstevel@tonic-gate 					} else {
3078*0Sstevel@tonic-gate 						ip6_t *ip6h = (ip6_t *)ipha;
3079*0Sstevel@tonic-gate 						ip_wput_ipsec_out_v6(NULL,
3080*0Sstevel@tonic-gate 						    mp, ip6h, NULL, NULL);
3081*0Sstevel@tonic-gate 					}
3082*0Sstevel@tonic-gate 				}
3083*0Sstevel@tonic-gate 				continue;
3084*0Sstevel@tonic-gate 			}
3085*0Sstevel@tonic-gate 		}
3086*0Sstevel@tonic-gate 		ESP_BUMP_STAT(out_discards);
3087*0Sstevel@tonic-gate 		ip_drop_packet(mp, B_FALSE, NULL, NULL,
3088*0Sstevel@tonic-gate 		    &ipdrops_sadb_acquire_timeout, &esp_dropper);
3089*0Sstevel@tonic-gate 	}
3090*0Sstevel@tonic-gate 
3091*0Sstevel@tonic-gate 	return (rc);
3092*0Sstevel@tonic-gate }
3093*0Sstevel@tonic-gate 
3094*0Sstevel@tonic-gate /*
3095*0Sstevel@tonic-gate  * Add new ESP security association.  This may become a generic AH/ESP
3096*0Sstevel@tonic-gate  * routine eventually.
3097*0Sstevel@tonic-gate  */
3098*0Sstevel@tonic-gate static int
3099*0Sstevel@tonic-gate esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic)
3100*0Sstevel@tonic-gate {
3101*0Sstevel@tonic-gate 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
3102*0Sstevel@tonic-gate 	sadb_address_t *srcext =
3103*0Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
3104*0Sstevel@tonic-gate 	sadb_address_t *dstext =
3105*0Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
3106*0Sstevel@tonic-gate 	sadb_address_t *nttext_loc =
3107*0Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_LOC];
3108*0Sstevel@tonic-gate 	sadb_address_t *nttext_rem =
3109*0Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_REM];
3110*0Sstevel@tonic-gate 	sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
3111*0Sstevel@tonic-gate 	sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
3112*0Sstevel@tonic-gate 	struct sockaddr_in *src, *dst;
3113*0Sstevel@tonic-gate 	struct sockaddr_in *natt_loc, *natt_rem;
3114*0Sstevel@tonic-gate 	struct sockaddr_in6 *natt_loc6, *natt_rem6;
3115*0Sstevel@tonic-gate 
3116*0Sstevel@tonic-gate 	sadb_lifetime_t *soft =
3117*0Sstevel@tonic-gate 	    (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
3118*0Sstevel@tonic-gate 	sadb_lifetime_t *hard =
3119*0Sstevel@tonic-gate 	    (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
3120*0Sstevel@tonic-gate 
3121*0Sstevel@tonic-gate 	/* I need certain extensions present for an ADD message. */
3122*0Sstevel@tonic-gate 	if (srcext == NULL) {
3123*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
3124*0Sstevel@tonic-gate 		return (EINVAL);
3125*0Sstevel@tonic-gate 	}
3126*0Sstevel@tonic-gate 	if (dstext == NULL) {
3127*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
3128*0Sstevel@tonic-gate 		return (EINVAL);
3129*0Sstevel@tonic-gate 	}
3130*0Sstevel@tonic-gate 	if (assoc == NULL) {
3131*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
3132*0Sstevel@tonic-gate 		return (EINVAL);
3133*0Sstevel@tonic-gate 	}
3134*0Sstevel@tonic-gate 	if (ekey == NULL && assoc->sadb_sa_encrypt != SADB_EALG_NULL) {
3135*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_EKEY;
3136*0Sstevel@tonic-gate 		return (EINVAL);
3137*0Sstevel@tonic-gate 	}
3138*0Sstevel@tonic-gate 
3139*0Sstevel@tonic-gate 	src = (struct sockaddr_in *)(srcext + 1);
3140*0Sstevel@tonic-gate 	dst = (struct sockaddr_in *)(dstext + 1);
3141*0Sstevel@tonic-gate 	natt_loc = (struct sockaddr_in *)(nttext_loc + 1);
3142*0Sstevel@tonic-gate 	natt_loc6 = (struct sockaddr_in6 *)(nttext_loc + 1);
3143*0Sstevel@tonic-gate 	natt_rem = (struct sockaddr_in *)(nttext_rem + 1);
3144*0Sstevel@tonic-gate 	natt_rem6 = (struct sockaddr_in6 *)(nttext_rem + 1);
3145*0Sstevel@tonic-gate 
3146*0Sstevel@tonic-gate 	/* Sundry ADD-specific reality checks. */
3147*0Sstevel@tonic-gate 	/* XXX STATS :  Logging/stats here? */
3148*0Sstevel@tonic-gate 	if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) {
3149*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
3150*0Sstevel@tonic-gate 		return (EINVAL);
3151*0Sstevel@tonic-gate 	}
3152*0Sstevel@tonic-gate 	if (assoc->sadb_sa_encrypt == SADB_EALG_NONE) {
3153*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG;
3154*0Sstevel@tonic-gate 		return (EINVAL);
3155*0Sstevel@tonic-gate 	}
3156*0Sstevel@tonic-gate 
3157*0Sstevel@tonic-gate 	if (assoc->sadb_sa_encrypt == SADB_EALG_NULL &&
3158*0Sstevel@tonic-gate 	    assoc->sadb_sa_auth == SADB_AALG_NONE) {
3159*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
3160*0Sstevel@tonic-gate 		return (EINVAL);
3161*0Sstevel@tonic-gate 	}
3162*0Sstevel@tonic-gate 
3163*0Sstevel@tonic-gate 	if (assoc->sadb_sa_flags & ~(SADB_SAFLAGS_NOREPLAY |
3164*0Sstevel@tonic-gate 	    SADB_X_SAFLAGS_NATT_LOC | SADB_X_SAFLAGS_NATT_REM)) {
3165*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS;
3166*0Sstevel@tonic-gate 		return (EINVAL);
3167*0Sstevel@tonic-gate 	}
3168*0Sstevel@tonic-gate 
3169*0Sstevel@tonic-gate 	if ((*diagnostic = sadb_hardsoftchk(hard, soft)) != 0) {
3170*0Sstevel@tonic-gate 		return (EINVAL);
3171*0Sstevel@tonic-gate 	}
3172*0Sstevel@tonic-gate 	if (src->sin_family != dst->sin_family) {
3173*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
3174*0Sstevel@tonic-gate 		return (EINVAL);
3175*0Sstevel@tonic-gate 	}
3176*0Sstevel@tonic-gate 
3177*0Sstevel@tonic-gate 
3178*0Sstevel@tonic-gate 	if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_LOC) {
3179*0Sstevel@tonic-gate 		if (nttext_loc == NULL) {
3180*0Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_LOC;
3181*0Sstevel@tonic-gate 			return (EINVAL);
3182*0Sstevel@tonic-gate 		}
3183*0Sstevel@tonic-gate 
3184*0Sstevel@tonic-gate 		if (natt_loc->sin_family == AF_INET6 &&
3185*0Sstevel@tonic-gate 		    !IN6_IS_ADDR_V4MAPPED(&natt_loc6->sin6_addr)) {
3186*0Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC;
3187*0Sstevel@tonic-gate 			return (EINVAL);
3188*0Sstevel@tonic-gate 		}
3189*0Sstevel@tonic-gate 	}
3190*0Sstevel@tonic-gate 
3191*0Sstevel@tonic-gate 	if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_REM) {
3192*0Sstevel@tonic-gate 		if (nttext_rem == NULL) {
3193*0Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_REM;
3194*0Sstevel@tonic-gate 			return (EINVAL);
3195*0Sstevel@tonic-gate 		}
3196*0Sstevel@tonic-gate 		if (natt_rem->sin_family == AF_INET6 &&
3197*0Sstevel@tonic-gate 		    !IN6_IS_ADDR_V4MAPPED(&natt_rem6->sin6_addr)) {
3198*0Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM;
3199*0Sstevel@tonic-gate 			return (EINVAL);
3200*0Sstevel@tonic-gate 		}
3201*0Sstevel@tonic-gate 	}
3202*0Sstevel@tonic-gate 
3203*0Sstevel@tonic-gate 
3204*0Sstevel@tonic-gate 	/* Stuff I don't support, for now.  XXX Diagnostic? */
3205*0Sstevel@tonic-gate 	if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL ||
3206*0Sstevel@tonic-gate 	    ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL)
3207*0Sstevel@tonic-gate 		return (EOPNOTSUPP);
3208*0Sstevel@tonic-gate 
3209*0Sstevel@tonic-gate 	/*
3210*0Sstevel@tonic-gate 	 * XXX Policy :  I'm not checking identities or sensitivity
3211*0Sstevel@tonic-gate 	 * labels at this time, but if I did, I'd do them here, before I sent
3212*0Sstevel@tonic-gate 	 * the weak key check up to the algorithm.
3213*0Sstevel@tonic-gate 	 */
3214*0Sstevel@tonic-gate 
3215*0Sstevel@tonic-gate 	mutex_enter(&alg_lock);
3216*0Sstevel@tonic-gate 
3217*0Sstevel@tonic-gate 	/*
3218*0Sstevel@tonic-gate 	 * First locate the authentication algorithm.
3219*0Sstevel@tonic-gate 	 */
3220*0Sstevel@tonic-gate 	if (akey != NULL) {
3221*0Sstevel@tonic-gate 		ipsec_alginfo_t *aalg;
3222*0Sstevel@tonic-gate 
3223*0Sstevel@tonic-gate 		aalg = ipsec_alglists[IPSEC_ALG_AUTH][assoc->sadb_sa_auth];
3224*0Sstevel@tonic-gate 		if (aalg == NULL || !ALG_VALID(aalg)) {
3225*0Sstevel@tonic-gate 			mutex_exit(&alg_lock);
3226*0Sstevel@tonic-gate 			esp1dbg(("Couldn't find auth alg #%d.\n",
3227*0Sstevel@tonic-gate 			    assoc->sadb_sa_auth));
3228*0Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
3229*0Sstevel@tonic-gate 			return (EINVAL);
3230*0Sstevel@tonic-gate 		}
3231*0Sstevel@tonic-gate 		ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
3232*0Sstevel@tonic-gate 
3233*0Sstevel@tonic-gate 		/* sanity check key sizes */
3234*0Sstevel@tonic-gate 		if (!ipsec_valid_key_size(akey->sadb_key_bits, aalg)) {
3235*0Sstevel@tonic-gate 			mutex_exit(&alg_lock);
3236*0Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS;
3237*0Sstevel@tonic-gate 			return (EINVAL);
3238*0Sstevel@tonic-gate 		}
3239*0Sstevel@tonic-gate 
3240*0Sstevel@tonic-gate 		/* check key and fix parity if needed */
3241*0Sstevel@tonic-gate 		if (ipsec_check_key(aalg->alg_mech_type, akey, B_TRUE,
3242*0Sstevel@tonic-gate 		    diagnostic) != 0) {
3243*0Sstevel@tonic-gate 			mutex_exit(&alg_lock);
3244*0Sstevel@tonic-gate 			return (EINVAL);
3245*0Sstevel@tonic-gate 		}
3246*0Sstevel@tonic-gate 	}
3247*0Sstevel@tonic-gate 
3248*0Sstevel@tonic-gate /* EXPORT DELETE START */
3249*0Sstevel@tonic-gate 	/*
3250*0Sstevel@tonic-gate 	 * Then locate the encryption algorithm.
3251*0Sstevel@tonic-gate 	 */
3252*0Sstevel@tonic-gate 	if (ekey != NULL) {
3253*0Sstevel@tonic-gate 		ipsec_alginfo_t *ealg;
3254*0Sstevel@tonic-gate 
3255*0Sstevel@tonic-gate 		ealg = ipsec_alglists[IPSEC_ALG_ENCR][assoc->sadb_sa_encrypt];
3256*0Sstevel@tonic-gate 		if (ealg == NULL || !ALG_VALID(ealg)) {
3257*0Sstevel@tonic-gate 			mutex_exit(&alg_lock);
3258*0Sstevel@tonic-gate 			esp1dbg(("Couldn't find encr alg #%d.\n",
3259*0Sstevel@tonic-gate 			    assoc->sadb_sa_encrypt));
3260*0Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG;
3261*0Sstevel@tonic-gate 			return (EINVAL);
3262*0Sstevel@tonic-gate 		}
3263*0Sstevel@tonic-gate 		ASSERT(ealg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
3264*0Sstevel@tonic-gate 
3265*0Sstevel@tonic-gate 		/* sanity check key sizes */
3266*0Sstevel@tonic-gate 		if (!ipsec_valid_key_size(ekey->sadb_key_bits, ealg)) {
3267*0Sstevel@tonic-gate 			mutex_exit(&alg_lock);
3268*0Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_BAD_EKEYBITS;
3269*0Sstevel@tonic-gate 			return (EINVAL);
3270*0Sstevel@tonic-gate 		}
3271*0Sstevel@tonic-gate 
3272*0Sstevel@tonic-gate 		/* check key */
3273*0Sstevel@tonic-gate 		if (ipsec_check_key(ealg->alg_mech_type, ekey, B_FALSE,
3274*0Sstevel@tonic-gate 		    diagnostic) != 0) {
3275*0Sstevel@tonic-gate 			mutex_exit(&alg_lock);
3276*0Sstevel@tonic-gate 			return (EINVAL);
3277*0Sstevel@tonic-gate 		}
3278*0Sstevel@tonic-gate 	}
3279*0Sstevel@tonic-gate /* EXPORT DELETE END */
3280*0Sstevel@tonic-gate 	mutex_exit(&alg_lock);
3281*0Sstevel@tonic-gate 
3282*0Sstevel@tonic-gate 	return (esp_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi));
3283*0Sstevel@tonic-gate }
3284*0Sstevel@tonic-gate 
3285*0Sstevel@tonic-gate /*
3286*0Sstevel@tonic-gate  * Update a security association.  Updates come in two varieties.  The first
3287*0Sstevel@tonic-gate  * is an update of lifetimes on a non-larval SA.  The second is an update of
3288*0Sstevel@tonic-gate  * a larval SA, which ends up looking a lot more like an add.
3289*0Sstevel@tonic-gate  */
3290*0Sstevel@tonic-gate static int
3291*0Sstevel@tonic-gate esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic)
3292*0Sstevel@tonic-gate {
3293*0Sstevel@tonic-gate 	sadb_address_t *dstext =
3294*0Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
3295*0Sstevel@tonic-gate 	struct sockaddr_in *sin;
3296*0Sstevel@tonic-gate 
3297*0Sstevel@tonic-gate 	if (dstext == NULL) {
3298*0Sstevel@tonic-gate 		*diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
3299*0Sstevel@tonic-gate 		return (EINVAL);
3300*0Sstevel@tonic-gate 	}
3301*0Sstevel@tonic-gate 
3302*0Sstevel@tonic-gate 	sin = (struct sockaddr_in *)(dstext + 1);
3303*0Sstevel@tonic-gate 	return (sadb_update_sa(mp, ksi,
3304*0Sstevel@tonic-gate 	    (sin->sin_family == AF_INET6) ? &esp_sadb.s_v6 : &esp_sadb.s_v4,
3305*0Sstevel@tonic-gate 	    diagnostic, esp_pfkey_q, esp_add_sa));
3306*0Sstevel@tonic-gate }
3307*0Sstevel@tonic-gate 
3308*0Sstevel@tonic-gate /*
3309*0Sstevel@tonic-gate  * Delete a security association.  This is REALLY likely to be code common to
3310*0Sstevel@tonic-gate  * both AH and ESP.  Find the association, then unlink it.
3311*0Sstevel@tonic-gate  */
3312*0Sstevel@tonic-gate static int
3313*0Sstevel@tonic-gate esp_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic)
3314*0Sstevel@tonic-gate {
3315*0Sstevel@tonic-gate 	sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
3316*0Sstevel@tonic-gate 	sadb_address_t *dstext =
3317*0Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
3318*0Sstevel@tonic-gate 	sadb_address_t *srcext =
3319*0Sstevel@tonic-gate 	    (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
3320*0Sstevel@tonic-gate 	struct sockaddr_in *sin;
3321*0Sstevel@tonic-gate 
3322*0Sstevel@tonic-gate 	if (assoc == NULL) {
3323*0Sstevel@tonic-gate 		if (dstext != NULL) {
3324*0Sstevel@tonic-gate 			sin = (struct sockaddr_in *)(dstext + 1);
3325*0Sstevel@tonic-gate 		} else if (srcext != NULL) {
3326*0Sstevel@tonic-gate 			sin = (struct sockaddr_in *)(srcext + 1);
3327*0Sstevel@tonic-gate 		} else {
3328*0Sstevel@tonic-gate 			*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
3329*0Sstevel@tonic-gate 			return (EINVAL);
3330*0Sstevel@tonic-gate 		}
3331*0Sstevel@tonic-gate 		return sadb_purge_sa(mp, ksi,
3332*0Sstevel@tonic-gate 		    (sin->sin_family == AF_INET6) ? &esp_sadb.s_v6 :
3333*0Sstevel@tonic-gate 		    &esp_sadb.s_v4,
3334*0Sstevel@tonic-gate 		    diagnostic, esp_pfkey_q, esp_sadb.s_ip_q);
3335*0Sstevel@tonic-gate 	}
3336*0Sstevel@tonic-gate 
3337*0Sstevel@tonic-gate 	return (sadb_del_sa(mp, ksi, &esp_sadb, diagnostic, esp_pfkey_q));
3338*0Sstevel@tonic-gate }
3339*0Sstevel@tonic-gate 
3340*0Sstevel@tonic-gate /*
3341*0Sstevel@tonic-gate  * Convert the entire contents of all of ESP's SA tables into PF_KEY SADB_DUMP
3342*0Sstevel@tonic-gate  * messages.
3343*0Sstevel@tonic-gate  */
3344*0Sstevel@tonic-gate static void
3345*0Sstevel@tonic-gate esp_dump(mblk_t *mp, keysock_in_t *ksi)
3346*0Sstevel@tonic-gate {
3347*0Sstevel@tonic-gate 	int error;
3348*0Sstevel@tonic-gate 	sadb_msg_t *samsg;
3349*0Sstevel@tonic-gate 
3350*0Sstevel@tonic-gate 	/*
3351*0Sstevel@tonic-gate 	 * Dump each fanout, bailing if error is non-zero.
3352*0Sstevel@tonic-gate 	 */
3353*0Sstevel@tonic-gate 
3354*0Sstevel@tonic-gate 	error = sadb_dump(esp_pfkey_q, mp, ksi->ks_in_serial, &esp_sadb.s_v4);
3355*0Sstevel@tonic-gate 	if (error != 0)
3356*0Sstevel@tonic-gate 		goto bail;
3357*0Sstevel@tonic-gate 
3358*0Sstevel@tonic-gate 	error = sadb_dump(esp_pfkey_q, mp, ksi->ks_in_serial, &esp_sadb.s_v6);
3359*0Sstevel@tonic-gate bail:
3360*0Sstevel@tonic-gate 	ASSERT(mp->b_cont != NULL);
3361*0Sstevel@tonic-gate 	samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
3362*0Sstevel@tonic-gate 	samsg->sadb_msg_errno = (uint8_t)error;
3363*0Sstevel@tonic-gate 	sadb_pfkey_echo(esp_pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi,
3364*0Sstevel@tonic-gate 	    NULL);
3365*0Sstevel@tonic-gate }
3366*0Sstevel@tonic-gate 
3367*0Sstevel@tonic-gate /*
3368*0Sstevel@tonic-gate  * ESP parsing of PF_KEY messages.  Keysock did most of the really silly
3369*0Sstevel@tonic-gate  * error cases.  What I receive is a fully-formed, syntactically legal
3370*0Sstevel@tonic-gate  * PF_KEY message.  I then need to check semantics...
3371*0Sstevel@tonic-gate  *
3372*0Sstevel@tonic-gate  * This code may become common to AH and ESP.  Stay tuned.
3373*0Sstevel@tonic-gate  *
3374*0Sstevel@tonic-gate  * I also make the assumption that db_ref's are cool.  If this assumption
3375*0Sstevel@tonic-gate  * is wrong, this means that someone other than keysock or me has been
3376*0Sstevel@tonic-gate  * mucking with PF_KEY messages.
3377*0Sstevel@tonic-gate  */
3378*0Sstevel@tonic-gate static void
3379*0Sstevel@tonic-gate esp_parse_pfkey(mblk_t *mp)
3380*0Sstevel@tonic-gate {
3381*0Sstevel@tonic-gate 	mblk_t *msg = mp->b_cont;
3382*0Sstevel@tonic-gate 	sadb_msg_t *samsg;
3383*0Sstevel@tonic-gate 	keysock_in_t *ksi;
3384*0Sstevel@tonic-gate 	int error;
3385*0Sstevel@tonic-gate 	int diagnostic = SADB_X_DIAGNOSTIC_NONE;
3386*0Sstevel@tonic-gate 
3387*0Sstevel@tonic-gate 	ASSERT(msg != NULL);
3388*0Sstevel@tonic-gate 	samsg = (sadb_msg_t *)msg->b_rptr;
3389*0Sstevel@tonic-gate 	ksi = (keysock_in_t *)mp->b_rptr;
3390*0Sstevel@tonic-gate 
3391*0Sstevel@tonic-gate 	/*
3392*0Sstevel@tonic-gate 	 * If applicable, convert unspecified AF_INET6 to unspecified
3393*0Sstevel@tonic-gate 	 * AF_INET.
3394*0Sstevel@tonic-gate 	 */
3395*0Sstevel@tonic-gate 	sadb_srcaddrfix(ksi);
3396*0Sstevel@tonic-gate 
3397*0Sstevel@tonic-gate 	switch (samsg->sadb_msg_type) {
3398*0Sstevel@tonic-gate 	case SADB_ADD:
3399*0Sstevel@tonic-gate 		error = esp_add_sa(mp, ksi, &diagnostic);
3400*0Sstevel@tonic-gate 		if (error != 0) {
3401*0Sstevel@tonic-gate 			sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic,
3402*0Sstevel@tonic-gate 			    ksi->ks_in_serial);
3403*0Sstevel@tonic-gate 		}
3404*0Sstevel@tonic-gate 		/* else esp_add_sa() took care of things. */
3405*0Sstevel@tonic-gate 		break;
3406*0Sstevel@tonic-gate 	case SADB_DELETE:
3407*0Sstevel@tonic-gate 		error = esp_del_sa(mp, ksi, &diagnostic);
3408*0Sstevel@tonic-gate 		if (error != 0) {
3409*0Sstevel@tonic-gate 			sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic,
3410*0Sstevel@tonic-gate 			    ksi->ks_in_serial);
3411*0Sstevel@tonic-gate 		}
3412*0Sstevel@tonic-gate 		/* Else esp_del_sa() took care of things. */
3413*0Sstevel@tonic-gate 		break;
3414*0Sstevel@tonic-gate 	case SADB_GET:
3415*0Sstevel@tonic-gate 		error = sadb_get_sa(mp, ksi, &esp_sadb, &diagnostic,
3416*0Sstevel@tonic-gate 		    esp_pfkey_q);
3417*0Sstevel@tonic-gate 		if (error != 0) {
3418*0Sstevel@tonic-gate 			sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic,
3419*0Sstevel@tonic-gate 			    ksi->ks_in_serial);
3420*0Sstevel@tonic-gate 		}
3421*0Sstevel@tonic-gate 		/* Else sadb_get_sa() took care of things. */
3422*0Sstevel@tonic-gate 		break;
3423*0Sstevel@tonic-gate 	case SADB_FLUSH:
3424*0Sstevel@tonic-gate 		sadbp_flush(&esp_sadb);
3425*0Sstevel@tonic-gate 		sadb_pfkey_echo(esp_pfkey_q, mp, samsg, ksi, NULL);
3426*0Sstevel@tonic-gate 		break;
3427*0Sstevel@tonic-gate 	case SADB_REGISTER:
3428*0Sstevel@tonic-gate 		/*
3429*0Sstevel@tonic-gate 		 * Hmmm, let's do it!  Check for extensions (there should
3430*0Sstevel@tonic-gate 		 * be none), extract the fields, call esp_register_out(),
3431*0Sstevel@tonic-gate 		 * then either free or report an error.
3432*0Sstevel@tonic-gate 		 *
3433*0Sstevel@tonic-gate 		 * Keysock takes care of the PF_KEY bookkeeping for this.
3434*0Sstevel@tonic-gate 		 */
3435*0Sstevel@tonic-gate 		if (esp_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid,
3436*0Sstevel@tonic-gate 		    ksi->ks_in_serial)) {
3437*0Sstevel@tonic-gate 			freemsg(mp);
3438*0Sstevel@tonic-gate 		} else {
3439*0Sstevel@tonic-gate 			/*
3440*0Sstevel@tonic-gate 			 * Only way this path hits is if there is a memory
3441*0Sstevel@tonic-gate 			 * failure.  It will not return B_FALSE because of
3442*0Sstevel@tonic-gate 			 * lack of esp_pfkey_q if I am in wput().
3443*0Sstevel@tonic-gate 			 */
3444*0Sstevel@tonic-gate 			sadb_pfkey_error(esp_pfkey_q, mp, ENOMEM, diagnostic,
3445*0Sstevel@tonic-gate 			    ksi->ks_in_serial);
3446*0Sstevel@tonic-gate 		}
3447*0Sstevel@tonic-gate 		break;
3448*0Sstevel@tonic-gate 	case SADB_UPDATE:
3449*0Sstevel@tonic-gate 		/*
3450*0Sstevel@tonic-gate 		 * Find a larval, if not there, find a full one and get
3451*0Sstevel@tonic-gate 		 * strict.
3452*0Sstevel@tonic-gate 		 */
3453*0Sstevel@tonic-gate 		error = esp_update_sa(mp, ksi, &diagnostic);
3454*0Sstevel@tonic-gate 		if (error != 0) {
3455*0Sstevel@tonic-gate 			sadb_pfkey_error(esp_pfkey_q, mp, error, diagnostic,
3456*0Sstevel@tonic-gate 			    ksi->ks_in_serial);
3457*0Sstevel@tonic-gate 		}
3458*0Sstevel@tonic-gate 		/* else esp_update_sa() took care of things. */
3459*0Sstevel@tonic-gate 		break;
3460*0Sstevel@tonic-gate 	case SADB_GETSPI:
3461*0Sstevel@tonic-gate 		/*
3462*0Sstevel@tonic-gate 		 * Reserve a new larval entry.
3463*0Sstevel@tonic-gate 		 */
3464*0Sstevel@tonic-gate 		esp_getspi(mp, ksi);
3465*0Sstevel@tonic-gate 		break;
3466*0Sstevel@tonic-gate 	case SADB_ACQUIRE:
3467*0Sstevel@tonic-gate 		/*
3468*0Sstevel@tonic-gate 		 * Find larval and/or ACQUIRE record and kill it (them), I'm
3469*0Sstevel@tonic-gate 		 * most likely an error.  Inbound ACQUIRE messages should only
3470*0Sstevel@tonic-gate 		 * have the base header.
3471*0Sstevel@tonic-gate 		 */
3472*0Sstevel@tonic-gate 		sadb_in_acquire(samsg, &esp_sadb, esp_pfkey_q);
3473*0Sstevel@tonic-gate 		freemsg(mp);
3474*0Sstevel@tonic-gate 		break;
3475*0Sstevel@tonic-gate 	case SADB_DUMP:
3476*0Sstevel@tonic-gate 		/*
3477*0Sstevel@tonic-gate 		 * Dump all entries.
3478*0Sstevel@tonic-gate 		 */
3479*0Sstevel@tonic-gate 		esp_dump(mp, ksi);
3480*0Sstevel@tonic-gate 		/* esp_dump will take care of the return message, etc. */
3481*0Sstevel@tonic-gate 		break;
3482*0Sstevel@tonic-gate 	case SADB_EXPIRE:
3483*0Sstevel@tonic-gate 		/* Should never reach me. */
3484*0Sstevel@tonic-gate 		sadb_pfkey_error(esp_pfkey_q, mp, EOPNOTSUPP, diagnostic,
3485*0Sstevel@tonic-gate 		    ksi->ks_in_serial);
3486*0Sstevel@tonic-gate 		break;
3487*0Sstevel@tonic-gate 	default:
3488*0Sstevel@tonic-gate 		sadb_pfkey_error(esp_pfkey_q, mp, EINVAL,
3489*0Sstevel@tonic-gate 		    SADB_X_DIAGNOSTIC_UNKNOWN_MSG, ksi->ks_in_serial);
3490*0Sstevel@tonic-gate 		break;
3491*0Sstevel@tonic-gate 	}
3492*0Sstevel@tonic-gate }
3493*0Sstevel@tonic-gate 
3494*0Sstevel@tonic-gate /*
3495*0Sstevel@tonic-gate  * Handle case where PF_KEY says it can't find a keysock for one of my
3496*0Sstevel@tonic-gate  * ACQUIRE messages.
3497*0Sstevel@tonic-gate  */
3498*0Sstevel@tonic-gate static void
3499*0Sstevel@tonic-gate esp_keysock_no_socket(mblk_t *mp)
3500*0Sstevel@tonic-gate {
3501*0Sstevel@tonic-gate 	sadb_msg_t *samsg;
3502*0Sstevel@tonic-gate 	keysock_out_err_t *kse = (keysock_out_err_t *)mp->b_rptr;
3503*0Sstevel@tonic-gate 
3504*0Sstevel@tonic-gate 	if (mp->b_cont == NULL) {
3505*0Sstevel@tonic-gate 		freemsg(mp);
3506*0Sstevel@tonic-gate 		return;
3507*0Sstevel@tonic-gate 	}
3508*0Sstevel@tonic-gate 	samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
3509*0Sstevel@tonic-gate 
3510*0Sstevel@tonic-gate 	/*
3511*0Sstevel@tonic-gate 	 * If keysock can't find any registered, delete the acquire record
3512*0Sstevel@tonic-gate 	 * immediately, and handle errors.
3513*0Sstevel@tonic-gate 	 */
3514*0Sstevel@tonic-gate 	if (samsg->sadb_msg_type == SADB_ACQUIRE) {
3515*0Sstevel@tonic-gate 		samsg->sadb_msg_errno = kse->ks_err_errno;
3516*0Sstevel@tonic-gate 		samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg));
3517*0Sstevel@tonic-gate 		/*
3518*0Sstevel@tonic-gate 		 * Use the write-side of the esp_pfkey_q, in case there is
3519*0Sstevel@tonic-gate 		 * no esp_sadb.s_ip_q.
3520*0Sstevel@tonic-gate 		 */
3521*0Sstevel@tonic-gate 		sadb_in_acquire(samsg, &esp_sadb, WR(esp_pfkey_q));
3522*0Sstevel@tonic-gate 	}
3523*0Sstevel@tonic-gate 
3524*0Sstevel@tonic-gate 	freemsg(mp);
3525*0Sstevel@tonic-gate }
3526*0Sstevel@tonic-gate 
3527*0Sstevel@tonic-gate /*
3528*0Sstevel@tonic-gate  * First-cut reality check for an inbound PF_KEY message.
3529*0Sstevel@tonic-gate  */
3530*0Sstevel@tonic-gate static boolean_t
3531*0Sstevel@tonic-gate esp_pfkey_reality_failures(mblk_t *mp, keysock_in_t *ksi)
3532*0Sstevel@tonic-gate {
3533*0Sstevel@tonic-gate 	int diagnostic;
3534*0Sstevel@tonic-gate 
3535*0Sstevel@tonic-gate 	if (ksi->ks_in_extv[SADB_EXT_PROPOSAL] != NULL) {
3536*0Sstevel@tonic-gate 		diagnostic = SADB_X_DIAGNOSTIC_PROP_PRESENT;
3537*0Sstevel@tonic-gate 		goto badmsg;
3538*0Sstevel@tonic-gate 	}
3539*0Sstevel@tonic-gate 	if (ksi->ks_in_extv[SADB_EXT_SUPPORTED_AUTH] != NULL ||
3540*0Sstevel@tonic-gate 	    ksi->ks_in_extv[SADB_EXT_SUPPORTED_ENCRYPT] != NULL) {
3541*0Sstevel@tonic-gate 		diagnostic = SADB_X_DIAGNOSTIC_SUPP_PRESENT;
3542*0Sstevel@tonic-gate 		goto badmsg;
3543*0Sstevel@tonic-gate 	}
3544*0Sstevel@tonic-gate 	if (ksi->ks_in_srctype == KS_IN_ADDR_MBCAST) {
3545*0Sstevel@tonic-gate 		diagnostic = SADB_X_DIAGNOSTIC_BAD_SRC;
3546*0Sstevel@tonic-gate 		goto badmsg;
3547*0Sstevel@tonic-gate 	}
3548*0Sstevel@tonic-gate 	if (ksi->ks_in_dsttype == KS_IN_ADDR_UNSPEC) {
3549*0Sstevel@tonic-gate 		diagnostic = SADB_X_DIAGNOSTIC_BAD_DST;
3550*0Sstevel@tonic-gate 		goto badmsg;
3551*0Sstevel@tonic-gate 	}
3552*0Sstevel@tonic-gate 
3553*0Sstevel@tonic-gate 	return (B_FALSE);	/* False ==> no failures */
3554*0Sstevel@tonic-gate 
3555*0Sstevel@tonic-gate badmsg:
3556*0Sstevel@tonic-gate 	sadb_pfkey_error(esp_pfkey_q, mp, EINVAL, diagnostic,
3557*0Sstevel@tonic-gate 	    ksi->ks_in_serial);
3558*0Sstevel@tonic-gate 	return (B_TRUE);	/* True ==> failures */
3559*0Sstevel@tonic-gate }
3560*0Sstevel@tonic-gate 
3561*0Sstevel@tonic-gate /*
3562*0Sstevel@tonic-gate  * ESP module write put routine.
3563*0Sstevel@tonic-gate  */
3564*0Sstevel@tonic-gate static void
3565*0Sstevel@tonic-gate ipsecesp_wput(queue_t *q, mblk_t *mp)
3566*0Sstevel@tonic-gate {
3567*0Sstevel@tonic-gate 	ipsec_info_t *ii;
3568*0Sstevel@tonic-gate 	keysock_in_t *ksi;
3569*0Sstevel@tonic-gate 	int rc;
3570*0Sstevel@tonic-gate 	struct iocblk *iocp;
3571*0Sstevel@tonic-gate 
3572*0Sstevel@tonic-gate 	esp3dbg(("In esp_wput().\n"));
3573*0Sstevel@tonic-gate 
3574*0Sstevel@tonic-gate 	/* NOTE: Each case must take care of freeing or passing mp. */
3575*0Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
3576*0Sstevel@tonic-gate 	case M_CTL:
3577*0Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) < sizeof (ipsec_info_t)) {
3578*0Sstevel@tonic-gate 			/* Not big enough message. */
3579*0Sstevel@tonic-gate 			freemsg(mp);
3580*0Sstevel@tonic-gate 			break;
3581*0Sstevel@tonic-gate 		}
3582*0Sstevel@tonic-gate 		ii = (ipsec_info_t *)mp->b_rptr;
3583*0Sstevel@tonic-gate 
3584*0Sstevel@tonic-gate 		switch (ii->ipsec_info_type) {
3585*0Sstevel@tonic-gate 		case KEYSOCK_OUT_ERR:
3586*0Sstevel@tonic-gate 			esp1dbg(("Got KEYSOCK_OUT_ERR message.\n"));
3587*0Sstevel@tonic-gate 			esp_keysock_no_socket(mp);
3588*0Sstevel@tonic-gate 			break;
3589*0Sstevel@tonic-gate 		case KEYSOCK_IN:
3590*0Sstevel@tonic-gate 			ESP_BUMP_STAT(keysock_in);
3591*0Sstevel@tonic-gate 			esp3dbg(("Got KEYSOCK_IN message.\n"));
3592*0Sstevel@tonic-gate 			ksi = (keysock_in_t *)ii;
3593*0Sstevel@tonic-gate 			/*
3594*0Sstevel@tonic-gate 			 * Some common reality checks.
3595*0Sstevel@tonic-gate 			 */
3596*0Sstevel@tonic-gate 
3597*0Sstevel@tonic-gate 			if (esp_pfkey_reality_failures(mp, ksi))
3598*0Sstevel@tonic-gate 				return;
3599*0Sstevel@tonic-gate 
3600*0Sstevel@tonic-gate 			/*
3601*0Sstevel@tonic-gate 			 * Use 'q' instead of esp_sadb.s_ip_q, since
3602*0Sstevel@tonic-gate 			 * it's the write side already, and it'll go
3603*0Sstevel@tonic-gate 			 * down to IP.  Use esp_pfkey_q because we
3604*0Sstevel@tonic-gate 			 * wouldn't get here if that weren't set, and
3605*0Sstevel@tonic-gate 			 * the RD(q) has been done already.
3606*0Sstevel@tonic-gate 			 */
3607*0Sstevel@tonic-gate 			if (ksi->ks_in_srctype == KS_IN_ADDR_UNKNOWN) {
3608*0Sstevel@tonic-gate 				rc = sadb_addrcheck(q, esp_pfkey_q, mp,
3609*0Sstevel@tonic-gate 				    ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC],
3610*0Sstevel@tonic-gate 				    ksi->ks_in_serial);
3611*0Sstevel@tonic-gate 				if (rc == KS_IN_ADDR_UNKNOWN)
3612*0Sstevel@tonic-gate 					return;
3613*0Sstevel@tonic-gate 				else
3614*0Sstevel@tonic-gate 					ksi->ks_in_srctype = rc;
3615*0Sstevel@tonic-gate 			}
3616*0Sstevel@tonic-gate 			if (ksi->ks_in_dsttype == KS_IN_ADDR_UNKNOWN) {
3617*0Sstevel@tonic-gate 				rc = sadb_addrcheck(q, esp_pfkey_q, mp,
3618*0Sstevel@tonic-gate 				    ksi->ks_in_extv[SADB_EXT_ADDRESS_DST],
3619*0Sstevel@tonic-gate 				    ksi->ks_in_serial);
3620*0Sstevel@tonic-gate 				if (rc == KS_IN_ADDR_UNKNOWN)
3621*0Sstevel@tonic-gate 					return;
3622*0Sstevel@tonic-gate 				else
3623*0Sstevel@tonic-gate 					ksi->ks_in_dsttype = rc;
3624*0Sstevel@tonic-gate 			}
3625*0Sstevel@tonic-gate 			/*
3626*0Sstevel@tonic-gate 			 * XXX Proxy may be a different address family.
3627*0Sstevel@tonic-gate 			 */
3628*0Sstevel@tonic-gate 			if (ksi->ks_in_proxytype == KS_IN_ADDR_UNKNOWN) {
3629*0Sstevel@tonic-gate 				rc = sadb_addrcheck(q, esp_pfkey_q, mp,
3630*0Sstevel@tonic-gate 				    ksi->ks_in_extv[SADB_EXT_ADDRESS_PROXY],
3631*0Sstevel@tonic-gate 				    ksi->ks_in_serial);
3632*0Sstevel@tonic-gate 				if (rc == KS_IN_ADDR_UNKNOWN)
3633*0Sstevel@tonic-gate 					return;
3634*0Sstevel@tonic-gate 				else
3635*0Sstevel@tonic-gate 					ksi->ks_in_proxytype = rc;
3636*0Sstevel@tonic-gate 			}
3637*0Sstevel@tonic-gate 			esp_parse_pfkey(mp);
3638*0Sstevel@tonic-gate 			break;
3639*0Sstevel@tonic-gate 		case KEYSOCK_HELLO:
3640*0Sstevel@tonic-gate 			sadb_keysock_hello(&esp_pfkey_q, q, mp,
3641*0Sstevel@tonic-gate 			    esp_ager, &esp_event, SADB_SATYPE_ESP);
3642*0Sstevel@tonic-gate 			break;
3643*0Sstevel@tonic-gate 		default:
3644*0Sstevel@tonic-gate 			esp2dbg(("Got M_CTL from above of 0x%x.\n",
3645*0Sstevel@tonic-gate 			    ii->ipsec_info_type));
3646*0Sstevel@tonic-gate 			freemsg(mp);
3647*0Sstevel@tonic-gate 			break;
3648*0Sstevel@tonic-gate 		}
3649*0Sstevel@tonic-gate 		break;
3650*0Sstevel@tonic-gate 	case M_IOCTL:
3651*0Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
3652*0Sstevel@tonic-gate 		switch (iocp->ioc_cmd) {
3653*0Sstevel@tonic-gate 		case ND_SET:
3654*0Sstevel@tonic-gate 		case ND_GET:
3655*0Sstevel@tonic-gate 			if (nd_getset(q, ipsecesp_g_nd, mp)) {
3656*0Sstevel@tonic-gate 				qreply(q, mp);
3657*0Sstevel@tonic-gate 				return;
3658*0Sstevel@tonic-gate 			} else {
3659*0Sstevel@tonic-gate 				iocp->ioc_error = ENOENT;
3660*0Sstevel@tonic-gate 			}
3661*0Sstevel@tonic-gate 			/* FALLTHRU */
3662*0Sstevel@tonic-gate 		default:
3663*0Sstevel@tonic-gate 			/* We really don't support any other ioctls, do we? */
3664*0Sstevel@tonic-gate 
3665*0Sstevel@tonic-gate 			/* Return EINVAL */
3666*0Sstevel@tonic-gate 			if (iocp->ioc_error != ENOENT)
3667*0Sstevel@tonic-gate 				iocp->ioc_error = EINVAL;
3668*0Sstevel@tonic-gate 			iocp->ioc_count = 0;
3669*0Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
3670*0Sstevel@tonic-gate 			qreply(q, mp);
3671*0Sstevel@tonic-gate 			return;
3672*0Sstevel@tonic-gate 		}
3673*0Sstevel@tonic-gate 	default:
3674*0Sstevel@tonic-gate 		esp3dbg(("Got default message, type %d, passing to IP.\n",
3675*0Sstevel@tonic-gate 		    mp->b_datap->db_type));
3676*0Sstevel@tonic-gate 		putnext(q, mp);
3677*0Sstevel@tonic-gate 	}
3678*0Sstevel@tonic-gate }
3679*0Sstevel@tonic-gate 
3680*0Sstevel@tonic-gate /* EXPORT DELETE START */
3681*0Sstevel@tonic-gate /*
3682*0Sstevel@tonic-gate  * Process an outbound ESP packet that can be accelerated by a IPsec
3683*0Sstevel@tonic-gate  * hardware acceleration capable Provider.
3684*0Sstevel@tonic-gate  * The caller already inserted and initialized the ESP header.
3685*0Sstevel@tonic-gate  * This function allocates a tagging M_CTL, and adds room at the end
3686*0Sstevel@tonic-gate  * of the packet to hold the ICV if authentication is needed.
3687*0Sstevel@tonic-gate  *
3688*0Sstevel@tonic-gate  * On success returns B_TRUE, on failure returns B_FALSE and frees the
3689*0Sstevel@tonic-gate  * mblk chain ipsec_out.
3690*0Sstevel@tonic-gate  */
3691*0Sstevel@tonic-gate static ipsec_status_t
3692*0Sstevel@tonic-gate esp_outbound_accelerated(mblk_t *ipsec_out, uint_t icv_len)
3693*0Sstevel@tonic-gate {
3694*0Sstevel@tonic-gate 	ipsec_out_t *io;
3695*0Sstevel@tonic-gate 	mblk_t *lastmp;
3696*0Sstevel@tonic-gate 
3697*0Sstevel@tonic-gate 	ESP_BUMP_STAT(out_accelerated);
3698*0Sstevel@tonic-gate 
3699*0Sstevel@tonic-gate 	io = (ipsec_out_t *)ipsec_out->b_rptr;
3700*0Sstevel@tonic-gate 
3701*0Sstevel@tonic-gate 	/* mark packet as being accelerated in IPSEC_OUT */
3702*0Sstevel@tonic-gate 	ASSERT(io->ipsec_out_accelerated == B_FALSE);
3703*0Sstevel@tonic-gate 	io->ipsec_out_accelerated = B_TRUE;
3704*0Sstevel@tonic-gate 
3705*0Sstevel@tonic-gate 	/*
3706*0Sstevel@tonic-gate 	 * add room at the end of the packet for the ICV if needed
3707*0Sstevel@tonic-gate 	 */
3708*0Sstevel@tonic-gate 	if (icv_len > 0) {
3709*0Sstevel@tonic-gate 		/* go to last mblk */
3710*0Sstevel@tonic-gate 		lastmp = ipsec_out;	/* For following while loop. */
3711*0Sstevel@tonic-gate 		do {
3712*0Sstevel@tonic-gate 			lastmp = lastmp->b_cont;
3713*0Sstevel@tonic-gate 		} while (lastmp->b_cont != NULL);
3714*0Sstevel@tonic-gate 
3715*0Sstevel@tonic-gate 		/* if not enough available room, allocate new mblk */
3716*0Sstevel@tonic-gate 		if ((lastmp->b_wptr + icv_len) > lastmp->b_datap->db_lim) {
3717*0Sstevel@tonic-gate 			lastmp->b_cont = allocb(icv_len, BPRI_HI);
3718*0Sstevel@tonic-gate 			if (lastmp->b_cont == NULL) {
3719*0Sstevel@tonic-gate 				ESP_BUMP_STAT(out_discards);
3720*0Sstevel@tonic-gate 				ip_drop_packet(ipsec_out, B_FALSE, NULL, NULL,
3721*0Sstevel@tonic-gate 				    &ipdrops_esp_nomem, &esp_dropper);
3722*0Sstevel@tonic-gate 				return (IPSEC_STATUS_FAILED);
3723*0Sstevel@tonic-gate 			}
3724*0Sstevel@tonic-gate 			lastmp = lastmp->b_cont;
3725*0Sstevel@tonic-gate 		}
3726*0Sstevel@tonic-gate 		lastmp->b_wptr += icv_len;
3727*0Sstevel@tonic-gate 	}
3728*0Sstevel@tonic-gate 
3729*0Sstevel@tonic-gate 	return (IPSEC_STATUS_SUCCESS);
3730*0Sstevel@tonic-gate }
3731*0Sstevel@tonic-gate 
3732*0Sstevel@tonic-gate /*
3733*0Sstevel@tonic-gate  * Process an inbound accelerated ESP packet.
3734*0Sstevel@tonic-gate  * On success returns B_TRUE, on failure returns B_FALSE and frees the
3735*0Sstevel@tonic-gate  * mblk chain ipsec_in.
3736*0Sstevel@tonic-gate  */
3737*0Sstevel@tonic-gate static ipsec_status_t
3738*0Sstevel@tonic-gate esp_inbound_accelerated(mblk_t *ipsec_in, mblk_t *data_mp, boolean_t isv4,
3739*0Sstevel@tonic-gate     ipsa_t *assoc)
3740*0Sstevel@tonic-gate {
3741*0Sstevel@tonic-gate 	ipsec_in_t *ii;
3742*0Sstevel@tonic-gate 	mblk_t *hada_mp;
3743*0Sstevel@tonic-gate 	uint32_t icv_len = 0;
3744*0Sstevel@tonic-gate 	da_ipsec_t *hada;
3745*0Sstevel@tonic-gate 	ipha_t *ipha;
3746*0Sstevel@tonic-gate 	ip6_t *ip6h;
3747*0Sstevel@tonic-gate 	kstat_named_t *counter;
3748*0Sstevel@tonic-gate 
3749*0Sstevel@tonic-gate 	ESP_BUMP_STAT(in_accelerated);
3750*0Sstevel@tonic-gate 
3751*0Sstevel@tonic-gate 	ii = (ipsec_in_t *)ipsec_in->b_rptr;
3752*0Sstevel@tonic-gate 	hada_mp = ii->ipsec_in_da;
3753*0Sstevel@tonic-gate 	ASSERT(hada_mp != NULL);
3754*0Sstevel@tonic-gate 	hada = (da_ipsec_t *)hada_mp->b_rptr;
3755*0Sstevel@tonic-gate 
3756*0Sstevel@tonic-gate 	/*
3757*0Sstevel@tonic-gate 	 * We only support one level of decapsulation in hardware, so
3758*0Sstevel@tonic-gate 	 * nuke the pointer.
3759*0Sstevel@tonic-gate 	 */
3760*0Sstevel@tonic-gate 	ii->ipsec_in_da = NULL;
3761*0Sstevel@tonic-gate 	ii->ipsec_in_accelerated = B_FALSE;
3762*0Sstevel@tonic-gate 
3763*0Sstevel@tonic-gate 	if (assoc->ipsa_auth_alg != IPSA_AALG_NONE) {
3764*0Sstevel@tonic-gate 		/*
3765*0Sstevel@tonic-gate 		 * ESP with authentication. We expect the Provider to have
3766*0Sstevel@tonic-gate 		 * computed the ICV and placed it in the hardware acceleration
3767*0Sstevel@tonic-gate 		 * data attributes.
3768*0Sstevel@tonic-gate 		 *
3769*0Sstevel@tonic-gate 		 * Extract ICV length from attributes M_CTL and sanity check
3770*0Sstevel@tonic-gate 		 * its value. We allow the mblk to be smaller than da_ipsec_t
3771*0Sstevel@tonic-gate 		 * for a small ICV, as long as the entire ICV fits within the
3772*0Sstevel@tonic-gate 		 * mblk.
3773*0Sstevel@tonic-gate 		 *
3774*0Sstevel@tonic-gate 		 * Also ensures that the ICV length computed by Provider
3775*0Sstevel@tonic-gate 		 * corresponds to the ICV length of the agorithm specified by
3776*0Sstevel@tonic-gate 		 * the SA.
3777*0Sstevel@tonic-gate 		 */
3778*0Sstevel@tonic-gate 		icv_len = hada->da_icv_len;
3779*0Sstevel@tonic-gate 		if ((icv_len != assoc->ipsa_mac_len) ||
3780*0Sstevel@tonic-gate 		    (icv_len > DA_ICV_MAX_LEN) || (MBLKL(hada_mp) <
3781*0Sstevel@tonic-gate 			(sizeof (da_ipsec_t) - DA_ICV_MAX_LEN + icv_len))) {
3782*0Sstevel@tonic-gate 			esp0dbg(("esp_inbound_accelerated: "
3783*0Sstevel@tonic-gate 			    "ICV len (%u) incorrect or mblk too small (%u)\n",
3784*0Sstevel@tonic-gate 			    icv_len, (uint32_t)(MBLKL(hada_mp))));
3785*0Sstevel@tonic-gate 			counter = &ipdrops_esp_bad_auth;
3786*0Sstevel@tonic-gate 			goto esp_in_discard;
3787*0Sstevel@tonic-gate 		}
3788*0Sstevel@tonic-gate 	}
3789*0Sstevel@tonic-gate 
3790*0Sstevel@tonic-gate 	/* get pointers to IP header */
3791*0Sstevel@tonic-gate 	if (isv4) {
3792*0Sstevel@tonic-gate 		ipha = (ipha_t *)data_mp->b_rptr;
3793*0Sstevel@tonic-gate 	} else {
3794*0Sstevel@tonic-gate 		ip6h = (ip6_t *)data_mp->b_rptr;
3795*0Sstevel@tonic-gate 	}
3796*0Sstevel@tonic-gate 
3797*0Sstevel@tonic-gate 	/*
3798*0Sstevel@tonic-gate 	 * Compare ICV in ESP packet vs ICV computed by adapter.
3799*0Sstevel@tonic-gate 	 * We also remove the ICV from the end of the packet since
3800*0Sstevel@tonic-gate 	 * it will no longer be needed.
3801*0Sstevel@tonic-gate 	 *
3802*0Sstevel@tonic-gate 	 * Assume that esp_inbound() already ensured that the pkt
3803*0Sstevel@tonic-gate 	 * was in one mblk.
3804*0Sstevel@tonic-gate 	 */
3805*0Sstevel@tonic-gate 	ASSERT(data_mp->b_cont == NULL);
3806*0Sstevel@tonic-gate 	data_mp->b_wptr -= icv_len;
3807*0Sstevel@tonic-gate 	/* adjust IP header */
3808*0Sstevel@tonic-gate 	if (isv4)
3809*0Sstevel@tonic-gate 		ipha->ipha_length = htons(ntohs(ipha->ipha_length) - icv_len);
3810*0Sstevel@tonic-gate 	else
3811*0Sstevel@tonic-gate 		ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - icv_len);
3812*0Sstevel@tonic-gate 	if (icv_len && bcmp(hada->da_icv, data_mp->b_wptr, icv_len)) {
3813*0Sstevel@tonic-gate 		int af;
3814*0Sstevel@tonic-gate 		void *addr;
3815*0Sstevel@tonic-gate 
3816*0Sstevel@tonic-gate 		if (isv4) {
3817*0Sstevel@tonic-gate 			addr = &ipha->ipha_dst;
3818*0Sstevel@tonic-gate 			af = AF_INET;
3819*0Sstevel@tonic-gate 		} else {
3820*0Sstevel@tonic-gate 			addr = &ip6h->ip6_dst;
3821*0Sstevel@tonic-gate 			af = AF_INET6;
3822*0Sstevel@tonic-gate 		}
3823*0Sstevel@tonic-gate 
3824*0Sstevel@tonic-gate 		/*
3825*0Sstevel@tonic-gate 		 * Log the event. Don't print to the console, block
3826*0Sstevel@tonic-gate 		 * potential denial-of-service attack.
3827*0Sstevel@tonic-gate 		 */
3828*0Sstevel@tonic-gate 		ESP_BUMP_STAT(bad_auth);
3829*0Sstevel@tonic-gate 		ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
3830*0Sstevel@tonic-gate 		    "ESP Authentication failed spi %x, dst_addr %s",
3831*0Sstevel@tonic-gate 		    assoc->ipsa_spi, addr, af);
3832*0Sstevel@tonic-gate 		counter = &ipdrops_esp_bad_auth;
3833*0Sstevel@tonic-gate 		goto esp_in_discard;
3834*0Sstevel@tonic-gate 	}
3835*0Sstevel@tonic-gate 
3836*0Sstevel@tonic-gate 	esp3dbg(("esp_inbound_accelerated: ESP authentication succeeded, "
3837*0Sstevel@tonic-gate 	    "checking replay\n"));
3838*0Sstevel@tonic-gate 
3839*0Sstevel@tonic-gate 	ipsec_in->b_cont = data_mp;
3840*0Sstevel@tonic-gate 
3841*0Sstevel@tonic-gate 	/*
3842*0Sstevel@tonic-gate 	 * Remove ESP header and padding from packet.
3843*0Sstevel@tonic-gate 	 */
3844*0Sstevel@tonic-gate 	if (!esp_strip_header(data_mp, ii->ipsec_in_v4, assoc->ipsa_iv_len,
3845*0Sstevel@tonic-gate 		&counter)) {
3846*0Sstevel@tonic-gate 		esp1dbg(("esp_inbound_accelerated: "
3847*0Sstevel@tonic-gate 		    "esp_strip_header() failed\n"));
3848*0Sstevel@tonic-gate 		goto esp_in_discard;
3849*0Sstevel@tonic-gate 	}
3850*0Sstevel@tonic-gate 
3851*0Sstevel@tonic-gate 	freeb(hada_mp);
3852*0Sstevel@tonic-gate 
3853*0Sstevel@tonic-gate 	/*
3854*0Sstevel@tonic-gate 	 * Account for usage..
3855*0Sstevel@tonic-gate 	 */
3856*0Sstevel@tonic-gate 	if (!esp_age_bytes(assoc, msgdsize(data_mp), B_TRUE)) {
3857*0Sstevel@tonic-gate 		/* The ipsa has hit hard expiration, LOG and AUDIT. */
3858*0Sstevel@tonic-gate 		ESP_BUMP_STAT(bytes_expired);
3859*0Sstevel@tonic-gate 		IP_ESP_BUMP_STAT(in_discards);
3860*0Sstevel@tonic-gate 		ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
3861*0Sstevel@tonic-gate 		    "ESP association 0x%x, dst %s had bytes expire.\n",
3862*0Sstevel@tonic-gate 		    assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam);
3863*0Sstevel@tonic-gate 		ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL,
3864*0Sstevel@tonic-gate 		    &ipdrops_esp_bytes_expire, &esp_dropper);
3865*0Sstevel@tonic-gate 		return (IPSEC_STATUS_FAILED);
3866*0Sstevel@tonic-gate 	}
3867*0Sstevel@tonic-gate 
3868*0Sstevel@tonic-gate 	/* done processing the packet */
3869*0Sstevel@tonic-gate 	return (IPSEC_STATUS_SUCCESS);
3870*0Sstevel@tonic-gate 
3871*0Sstevel@tonic-gate esp_in_discard:
3872*0Sstevel@tonic-gate 	IP_ESP_BUMP_STAT(in_discards);
3873*0Sstevel@tonic-gate 	freeb(hada_mp);
3874*0Sstevel@tonic-gate 
3875*0Sstevel@tonic-gate 	ipsec_in->b_cont = data_mp;	/* For ip_drop_packet()'s sake... */
3876*0Sstevel@tonic-gate 	ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, counter, &esp_dropper);
3877*0Sstevel@tonic-gate 
3878*0Sstevel@tonic-gate 	return (IPSEC_STATUS_FAILED);
3879*0Sstevel@tonic-gate }
3880*0Sstevel@tonic-gate /* EXPORT DELETE END */
3881*0Sstevel@tonic-gate 
3882*0Sstevel@tonic-gate /*
3883*0Sstevel@tonic-gate  * Wrapper to allow IP to trigger an ESP association failure message
3884*0Sstevel@tonic-gate  * during inbound SA selection.
3885*0Sstevel@tonic-gate  */
3886*0Sstevel@tonic-gate void
3887*0Sstevel@tonic-gate ipsecesp_in_assocfailure(mblk_t *mp, char level, ushort_t sl, char *fmt,
3888*0Sstevel@tonic-gate     uint32_t spi, void *addr, int af)
3889*0Sstevel@tonic-gate {
3890*0Sstevel@tonic-gate 	if (ipsecesp_log_unknown_spi) {
3891*0Sstevel@tonic-gate 		ipsec_assocfailure(info.mi_idnum, 0, level, sl, fmt, spi,
3892*0Sstevel@tonic-gate 		    addr, af);
3893*0Sstevel@tonic-gate 	}
3894*0Sstevel@tonic-gate 
3895*0Sstevel@tonic-gate 	ip_drop_packet(mp, B_TRUE, NULL, NULL, &ipdrops_esp_no_sa,
3896*0Sstevel@tonic-gate 	    &esp_dropper);
3897*0Sstevel@tonic-gate }
3898*0Sstevel@tonic-gate 
3899*0Sstevel@tonic-gate /*
3900*0Sstevel@tonic-gate  * Initialize the ESP input and output processing functions.
3901*0Sstevel@tonic-gate  */
3902*0Sstevel@tonic-gate void
3903*0Sstevel@tonic-gate ipsecesp_init_funcs(ipsa_t *sa)
3904*0Sstevel@tonic-gate {
3905*0Sstevel@tonic-gate 	if (sa->ipsa_output_func == NULL)
3906*0Sstevel@tonic-gate 		sa->ipsa_output_func = esp_outbound;
3907*0Sstevel@tonic-gate 	if (sa->ipsa_input_func == NULL)
3908*0Sstevel@tonic-gate 		sa->ipsa_input_func = esp_inbound;
3909*0Sstevel@tonic-gate }
3910