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