xref: /titanic_50/usr/src/uts/common/inet/ip/ip_sadb.c (revision afd1ac7b1c9a8cdf273c865aa5e9a14620341443)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/stream.h>
31 #include <sys/sunddi.h>
32 #include <sys/strlog.h>
33 
34 #include <inet/common.h>
35 #include <inet/mib2.h>
36 #include <inet/ip.h>
37 #include <inet/ip6.h>
38 #include <inet/ipdrop.h>
39 
40 #include <net/pfkeyv2.h>
41 #include <inet/ipsec_info.h>
42 #include <inet/sadb.h>
43 #include <inet/ipsec_impl.h>
44 #include <inet/ipsecesp.h>
45 #include <inet/ipsecah.h>
46 #include <sys/kstat.h>
47 
48 /* stats */
49 static kstat_t *ipsec_ksp;
50 ipsec_kstats_t *ipsec_kstats;
51 
52 /* The IPsec SADBs for AH and ESP */
53 sadbp_t ah_sadb, esp_sadb;
54 
55 /* Packet dropper for IP IPsec processing failures */
56 extern ipdropper_t ip_dropper;
57 
58 void
59 ipsec_kstat_init(void)
60 {
61 	ipsec_ksp = kstat_create("ip", 0, "ipsec_stat", "net",
62 	    KSTAT_TYPE_NAMED, sizeof (*ipsec_kstats) / sizeof (kstat_named_t),
63 	    KSTAT_FLAG_PERSISTENT);
64 
65 	ASSERT(ipsec_ksp != NULL);
66 
67 	ipsec_kstats = ipsec_ksp->ks_data;
68 
69 #define	KI(x) kstat_named_init(&ipsec_kstats->x, #x, KSTAT_DATA_UINT64)
70 	KI(esp_stat_in_requests);
71 	KI(esp_stat_in_discards);
72 	KI(esp_stat_lookup_failure);
73 	KI(ah_stat_in_requests);
74 	KI(ah_stat_in_discards);
75 	KI(ah_stat_lookup_failure);
76 #undef KI
77 
78 	kstat_install(ipsec_ksp);
79 }
80 
81 void
82 ipsec_kstat_destroy(void)
83 {
84 	kstat_delete(ipsec_ksp);
85 }
86 
87 /*
88  * Returns B_TRUE if the identities in the SA match the identities
89  * in the "latch" structure.
90  */
91 
92 static boolean_t
93 ipsec_match_outbound_ids(ipsec_latch_t *ipl, ipsa_t *sa)
94 {
95 	ASSERT(ipl->ipl_ids_latched == B_TRUE);
96 	return ipsid_equal(ipl->ipl_local_cid, sa->ipsa_src_cid) &&
97 	    ipsid_equal(ipl->ipl_remote_cid, sa->ipsa_dst_cid);
98 }
99 
100 /*
101  * Look up a security association based on the unique ID generated by IP and
102  * transport information, such as ports and upper-layer protocol, and the
103  * address(es).	 Used for uniqueness testing and outbound packets.  The
104  * source address may be ignored.
105  *
106  * I expect an SA hash bucket, and that its per-bucket mutex is held.
107  * The SA ptr I return will have its reference count incremented by one.
108  */
109 ipsa_t *
110 ipsec_getassocbyconn(isaf_t *bucket, ipsec_out_t *io, uint32_t *src,
111     uint32_t *dst, sa_family_t af, uint8_t protocol)
112 {
113 	ipsa_t *retval, *candidate;
114 	ipsec_action_t *candact;
115 	boolean_t need_unique;
116 	uint64_t unique_id;
117 	uint32_t old_flags, excludeflags;
118 	ipsec_policy_t *pp = io->ipsec_out_policy;
119 	ipsec_action_t *actlist = io->ipsec_out_act;
120 	ipsec_action_t *act;
121 	ipsec_latch_t *ipl = io->ipsec_out_latch;
122 	ipsa_ref_t *ipr = NULL;
123 
124 	ASSERT(MUTEX_HELD(&bucket->isaf_lock));
125 
126 	/*
127 	 * Fast path: do we have a latch structure, is it for this bucket,
128 	 * and does the generation number match?  If so, refhold and return.
129 	 */
130 
131 	if (ipl != NULL) {
132 		ASSERT((protocol == IPPROTO_AH) || (protocol == IPPROTO_ESP));
133 		ipr = &ipl->ipl_ref[protocol - IPPROTO_ESP];
134 
135 		retval = ipr->ipsr_sa;
136 
137 		/*
138 		 * NOTE: The isaf_gen check (incremented upon
139 		 * sadb_unlinkassoc()) protects against retval being a freed
140 		 * SA.  (We're exploiting short-circuit evaluation.)
141 		 */
142 		if ((bucket == ipr->ipsr_bucket) &&
143 		    (bucket->isaf_gen == ipr->ipsr_gen) &&
144 		    (retval->ipsa_state != IPSA_STATE_DEAD) &&
145 		    !(retval->ipsa_flags & IPSA_F_CINVALID)) {
146 			IPSA_REFHOLD(retval);
147 			return (retval);
148 		}
149 	}
150 
151 	ASSERT((pp != NULL) || (actlist != NULL));
152 	if (actlist == NULL)
153 		actlist = pp->ipsp_act;
154 	ASSERT(actlist != NULL);
155 
156 	need_unique = actlist->ipa_want_unique;
157 	unique_id = SA_FORM_UNIQUE_ID(io);
158 
159 	/*
160 	 * Precompute mask for SA flags comparison: If we need a
161 	 * unique SA and an SA has already been used, or if the SA has
162 	 * a unique value which doesn't match, we aren't interested in
163 	 * the SA..
164 	 */
165 
166 	excludeflags = IPSA_F_UNIQUE;
167 	if (need_unique)
168 		excludeflags |= IPSA_F_USED;
169 
170 	/*
171 	 * Walk the hash bucket, matching on:
172 	 *
173 	 * - unique_id
174 	 * - destination
175 	 * - source
176 	 * - algorithms
177 	 * - <MORE TBD>
178 	 *
179 	 * Make sure that wildcard sources are inserted at the end of the hash
180 	 * bucket.
181 	 *
182 	 * DEFINITIONS:	A _shared_ SA is one with unique_id == 0 and USED.
183 	 *		An _unused_ SA is one with unique_id == 0 and not USED.
184 	 *		A _unique_ SA is one with unique_id != 0 and USED.
185 	 *		An SA with unique_id != 0 and not USED never happens.
186 	 */
187 
188 	candidate = NULL;
189 
190 	for (retval = bucket->isaf_ipsa; retval != NULL;
191 	    retval = retval->ipsa_next) {
192 		ASSERT((candidate == NULL) ||
193 		    MUTEX_HELD(&candidate->ipsa_lock));
194 
195 		/*
196 		 * Q: Should I lock this SA?
197 		 * A: For now, yes.  I change and use too many fields in here
198 		 *    (e.g. unique_id) that I may be racing with other threads.
199 		 *    Also, the refcnt needs to be bumped up.
200 		 */
201 
202 		mutex_enter(&retval->ipsa_lock);
203 
204 		/* My apologies for the use of goto instead of continue. */
205 		if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af))
206 			goto next_ipsa;	/* Destination mismatch. */
207 		if (!IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) &&
208 		    !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af))
209 			goto next_ipsa;	/* Specific source and not matched. */
210 
211 		/*
212 		 * XXX should be able to use cached/latched action
213 		 * to dodge this loop
214 		 */
215 		for (act = actlist; act != NULL; act = act->ipa_next) {
216 			ipsec_act_t *ap = &act->ipa_act;
217 			if (ap->ipa_type != IPSEC_POLICY_APPLY)
218 				continue;
219 
220 			/*
221 			 * XXX ugly.  should be better way to do this test
222 			 */
223 			if (protocol == IPPROTO_AH) {
224 				if (!(ap->ipa_apply.ipp_use_ah))
225 					continue;
226 				if (ap->ipa_apply.ipp_auth_alg !=
227 				    retval->ipsa_auth_alg)
228 					continue;
229 				if (ap->ipa_apply.ipp_ah_minbits >
230 					retval->ipsa_authkeybits)
231 					continue;
232 			} else {
233 				if (!(ap->ipa_apply.ipp_use_esp))
234 					continue;
235 
236 				if ((ap->ipa_apply.ipp_encr_alg !=
237 				    retval->ipsa_encr_alg))
238 					continue;
239 
240 				if (ap->ipa_apply.ipp_espe_minbits >
241 				    retval->ipsa_encrkeybits)
242 					continue;
243 
244 				if (ap->ipa_apply.ipp_esp_auth_alg != 0) {
245 					if (ap->ipa_apply.ipp_esp_auth_alg !=
246 					    retval->ipsa_auth_alg)
247 						continue;
248 					if (ap->ipa_apply.ipp_espa_minbits >
249 					    retval->ipsa_authkeybits)
250 						continue;
251 				}
252 			}
253 
254 			/*
255 			 * Check key mgmt proto, cookie
256 			 */
257 			if ((ap->ipa_apply.ipp_km_proto != 0) &&
258 			    (retval->ipsa_kmp != 0) &&
259 			    (ap->ipa_apply.ipp_km_proto != retval->ipsa_kmp))
260 				continue;
261 
262 			if ((ap->ipa_apply.ipp_km_cookie != 0) &&
263 			    (retval->ipsa_kmc != 0) &&
264 			    (ap->ipa_apply.ipp_km_cookie != retval->ipsa_kmc))
265 				continue;
266 
267 			break;
268 		}
269 		if (act == NULL)
270 			goto next_ipsa;	/* nothing matched */
271 
272 		/*
273 		 * Do identities match?
274 		 */
275 		if (ipl && ipl->ipl_ids_latched &&
276 		    !ipsec_match_outbound_ids(ipl, retval))
277 			goto next_ipsa;
278 
279 		/*
280 		 * At this point, we know that we have at least a match on:
281 		 *
282 		 * - dest
283 		 * - source (if source is specified, i.e. non-zeroes)
284 		 * - auth alg (if auth alg is specified, i.e. non-zero)
285 		 * - encrypt. alg (if encrypt. alg is specified, i.e. non-zero)
286 		 * and we know that the SA keylengths are appropriate.
287 		 *
288 		 * (Keep in mind known-src SAs are hit before zero-src SAs,
289 		 * thanks to sadb_insertassoc().)
290 		 * If we need a unique asssociation, optimally we have
291 		 * ipsa_unique_id == unique_id, otherwise NOT USED
292 		 * is held in reserve (stored in candidate).
293 		 *
294 		 * For those stored in candidate, take best-match (i.e. given
295 		 * a choice, candidate should have non-zero ipsa_src).
296 		 */
297 
298 		/*
299 		 * If SA has a unique value which matches, we're all set...
300 		 * "key management knows best"
301 		 */
302 		if ((retval->ipsa_flags & IPSA_F_UNIQUE) &&
303 		    ((unique_id & retval->ipsa_unique_mask) ==
304 			retval->ipsa_unique_id))
305 			break;
306 
307 		/*
308 		 * If we need a unique SA and this SA has already been used,
309 		 * or if the SA has a unique value which doesn't match,
310 		 * this isn't for us.
311 		 */
312 
313 		if (retval->ipsa_flags & excludeflags)
314 			goto next_ipsa;
315 
316 
317 		/*
318 		 * I found a candidate..
319 		 */
320 		if (candidate == NULL) {
321 			/*
322 			 * and didn't already have one..
323 			 */
324 			candidate = retval;
325 			candact = act;
326 			continue;
327 		} else {
328 			/*
329 			 * If candidate's source address is zero and
330 			 * the current match (i.e. retval) address is
331 			 * not zero, we have a better candidate..
332 			 */
333 			if (IPSA_IS_ADDR_UNSPEC(candidate->ipsa_srcaddr, af) &&
334 			    !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) {
335 				mutex_exit(&candidate->ipsa_lock);
336 				candidate = retval;
337 				candact = act;
338 				continue;
339 			}
340 		}
341 next_ipsa:
342 		mutex_exit(&retval->ipsa_lock);
343 	}
344 	ASSERT((retval == NULL) || MUTEX_HELD(&retval->ipsa_lock));
345 	ASSERT((candidate == NULL) || MUTEX_HELD(&candidate->ipsa_lock));
346 	ASSERT((retval == NULL) || (act != NULL));
347 	ASSERT((candidate == NULL) || (candact != NULL));
348 
349 	/* Let caller react to a lookup failure when it gets NULL. */
350 	if (retval == NULL && candidate == NULL)
351 		return (NULL);
352 
353 	if (retval == NULL) {
354 		ASSERT(MUTEX_HELD(&candidate->ipsa_lock));
355 		retval = candidate;
356 		act = candact;
357 	} else if (candidate != NULL) {
358 		mutex_exit(&candidate->ipsa_lock);
359 	}
360 	ASSERT(MUTEX_HELD(&retval->ipsa_lock));
361 	ASSERT(act != NULL);
362 
363 	/*
364 	 * Even though I hold the mutex, since the reference counter is an
365 	 * atomic operation, I really have to use the IPSA_REFHOLD macro.
366 	 */
367 	IPSA_REFHOLD(retval);
368 
369 	/*
370 	 * This association is no longer unused.
371 	 */
372 	old_flags = retval->ipsa_flags;
373 	retval->ipsa_flags |= IPSA_F_USED;
374 
375 	/*
376 	 * Cache a reference to this SA for the fast path.
377 	 */
378 	if (ipr != NULL) {
379 		ipr->ipsr_bucket = bucket;
380 		ipr->ipsr_gen = bucket->isaf_gen;
381 		ipr->ipsr_sa = retval;
382 		/* I'm now caching, so the cache-invalid flag goes away! */
383 		retval->ipsa_flags &= ~IPSA_F_CINVALID;
384 	}
385 	/*
386 	 * Latch various things while we're here..
387 	 */
388 	if (ipl != NULL) {
389 		if (!ipl->ipl_ids_latched) {
390 			ipsec_latch_ids(ipl,
391 			    retval->ipsa_src_cid, retval->ipsa_dst_cid);
392 		}
393 		if (!ipl->ipl_out_action_latched) {
394 			IPACT_REFHOLD(act);
395 			ipl->ipl_out_action = act;
396 			ipl->ipl_out_action_latched = B_TRUE;
397 		}
398 	}
399 
400 	/*
401 	 * Set the uniqueness only first time.
402 	 */
403 	if (need_unique && !(old_flags & IPSA_F_USED)) {
404 		if (retval->ipsa_unique_id == 0) {
405 			ASSERT((retval->ipsa_flags & IPSA_F_UNIQUE) == 0);
406 			/*
407 			 * From now on, only this src, dst[ports, addr],
408 			 * proto, should use it.
409 			 */
410 			retval->ipsa_flags |= IPSA_F_UNIQUE;
411 			retval->ipsa_unique_id = unique_id;
412 			retval->ipsa_unique_mask = SA_UNIQUE_MASK(
413 			    io->ipsec_out_src_port, io->ipsec_out_dst_port,
414 			    protocol);
415 		}
416 
417 		/*
418 		 * Set the source address and adjust the hash
419 		 * buckets only if src_addr is zero.
420 		 */
421 		if (IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) {
422 			/*
423 			 * sadb_unlinkassoc() will decrement the refcnt.  Bump
424 			 * up when we have the lock so that we don't have to
425 			 * acquire locks when we come back from
426 			 * sadb_insertassoc().
427 			 *
428 			 * We don't need to bump the bucket's gen since
429 			 * we aren't moving to a new bucket.
430 			 */
431 			IPSA_REFHOLD(retval);
432 			IPSA_COPY_ADDR(retval->ipsa_srcaddr, src, af);
433 			mutex_exit(&retval->ipsa_lock);
434 			sadb_unlinkassoc(retval);
435 			/*
436 			 * Since the bucket lock is held, we know
437 			 * sadb_insertassoc() will succeed.
438 			 */
439 #ifdef DEBUG
440 			if (sadb_insertassoc(retval, bucket) != 0) {
441 				cmn_err(CE_PANIC,
442 				    "sadb_insertassoc() failed in "
443 				    "ipsec_getassocbyconn().\n");
444 			}
445 #else	/* non-DEBUG */
446 			(void) sadb_insertassoc(retval, bucket);
447 #endif	/* DEBUG */
448 			return (retval);
449 		}
450 	}
451 	mutex_exit(&retval->ipsa_lock);
452 
453 	return (retval);
454 }
455 
456 /*
457  * Look up a security association based on the security parameters index (SPI)
458  * and address(es).  This is used for inbound packets and general SA lookups
459  * (even in outbound SA tables).  The source address may be ignored.  Return
460  * NULL if no association is available.	 If an SA is found, return it, with
461  * its refcnt incremented.  The caller must REFRELE after using the SA.
462  * The hash bucket must be locked down before calling.
463  */
464 ipsa_t *
465 ipsec_getassocbyspi(isaf_t *bucket, uint32_t spi, uint32_t *src, uint32_t *dst,
466     sa_family_t af)
467 {
468 	ipsa_t *retval;
469 
470 	ASSERT(MUTEX_HELD(&bucket->isaf_lock));
471 
472 	/*
473 	 * Walk the hash bucket, matching exactly on SPI, then destination,
474 	 * then source.
475 	 *
476 	 * Per-SA locking doesn't need to happen, because I'm only matching
477 	 * on addresses.  Addresses are only changed during insertion/deletion
478 	 * from the hash bucket.  Since the hash bucket lock is held, we don't
479 	 * need to worry about addresses changing.
480 	 */
481 
482 	for (retval = bucket->isaf_ipsa; retval != NULL;
483 	    retval = retval->ipsa_next) {
484 		if (retval->ipsa_spi != spi)
485 			continue;
486 		if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af))
487 			continue;
488 
489 		/*
490 		 * Assume that wildcard source addresses are inserted at the
491 		 * end of the hash bucket.  (See sadb_insertassoc().)
492 		 * The following check for source addresses is a weak form
493 		 * of access control/source identity verification.  If an
494 		 * SA has a source address, I only match an all-zeroes
495 		 * source address, or that particular one.  If the SA has
496 		 * an all-zeroes source, then I match regardless.
497 		 *
498 		 * There is a weakness here in that a packet with all-zeroes
499 		 * for an address will match regardless of the source address
500 		 * stored in the packet.
501 		 *
502 		 * Note that port-level packet selectors, if present,
503 		 * are checked in ipsec_check_ipsecin_unique().
504 		 */
505 		if (IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) ||
506 		    IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af) ||
507 		    IPSA_IS_ADDR_UNSPEC(src, af))
508 			break;
509 	}
510 
511 	if (retval != NULL) {
512 		/*
513 		 * Just refhold the return value.  The caller will then
514 		 * make the appropriate calls to set the USED flag.
515 		 */
516 		IPSA_REFHOLD(retval);
517 	}
518 
519 	return (retval);
520 }
521 
522 boolean_t
523 ipsec_outbound_sa(mblk_t *mp, uint_t proto)
524 {
525 	mblk_t *data_mp;
526 	ipsec_out_t *io;
527 	ipaddr_t dst;
528 	uint32_t *dst_ptr, *src_ptr;
529 	isaf_t *bucket;
530 	ipsa_t *assoc;
531 	ip6_pkt_t ipp;
532 	in6_addr_t dst6;
533 	ipsa_t **sa;
534 	sadbp_t *sadbp;
535 	sadb_t *sp;
536 	sa_family_t af;
537 
538 	data_mp = mp->b_cont;
539 	io = (ipsec_out_t *)mp->b_rptr;
540 
541 	if (proto == IPPROTO_ESP) {
542 		sa = &io->ipsec_out_esp_sa;
543 		sadbp = &esp_sadb;
544 	} else {
545 		ASSERT(proto == IPPROTO_AH);
546 		sa = &io->ipsec_out_ah_sa;
547 		sadbp = &ah_sadb;
548 	}
549 
550 	ASSERT(*sa == NULL);
551 
552 	if (io->ipsec_out_v4) {
553 		ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
554 
555 		ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION);
556 		dst = ip_get_dst(ipha);
557 		sp = &sadbp->s_v4;
558 		af = AF_INET;
559 
560 		/*
561 		 * NOTE:Getting the outbound association is considerably
562 		 *	painful.  ipsec_getassocbyconn() will require more
563 		 *	parameters as policy implementations mature.
564 		 */
565 		bucket = OUTBOUND_BUCKET_V4(sp, dst);
566 		src_ptr = (uint32_t *)&ipha->ipha_src;
567 		dst_ptr = (uint32_t *)&dst;
568 	} else {
569 		ip6_t *ip6h = (ip6_t *)data_mp->b_rptr;
570 
571 		ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
572 		dst6 = ip_get_dst_v6(ip6h, NULL);
573 		af = AF_INET6;
574 
575 		bzero(&ipp, sizeof (ipp));
576 		sp = &sadbp->s_v6;
577 
578 		/* Same NOTE: applies here! */
579 		bucket = OUTBOUND_BUCKET_V6(sp, dst6);
580 		src_ptr = (uint32_t *)&ip6h->ip6_src;
581 		dst_ptr = (uint32_t *)&dst6;
582 	}
583 
584 	mutex_enter(&bucket->isaf_lock);
585 	assoc = ipsec_getassocbyconn(bucket, io, src_ptr, dst_ptr, af, proto);
586 	mutex_exit(&bucket->isaf_lock);
587 
588 	if (assoc == NULL)
589 		return (B_FALSE);
590 
591 	if (assoc->ipsa_state == IPSA_STATE_DEAD) {
592 		IPSA_REFRELE(assoc);
593 		return (B_FALSE);
594 	}
595 
596 	ASSERT(assoc->ipsa_state != IPSA_STATE_LARVAL);
597 
598 	*sa = assoc;
599 	return (B_TRUE);
600 }
601 
602 /*
603  * Inbound IPsec SA selection.
604  */
605 
606 ah_t *
607 ipsec_inbound_ah_sa(mblk_t *mp)
608 {
609 	mblk_t *ipsec_in;
610 	ipha_t *ipha;
611 	ipsa_t 	*assoc;
612 	ah_t *ah;
613 	isaf_t *hptr;
614 	ipsec_in_t *ii;
615 	boolean_t isv6;
616 	ip6_t *ip6h;
617 	int ah_offset;
618 	uint32_t *src_ptr, *dst_ptr;
619 	int pullup_len;
620 	sadb_t *sp;
621 	sa_family_t af;
622 
623 	IP_AH_BUMP_STAT(in_requests);
624 
625 	ASSERT(mp->b_datap->db_type == M_CTL);
626 
627 	ipsec_in = mp;
628 	ii = (ipsec_in_t *)ipsec_in->b_rptr;
629 	mp = mp->b_cont;
630 
631 	ASSERT(mp->b_datap->db_type == M_DATA);
632 
633 	isv6 = !ii->ipsec_in_v4;
634 	if (isv6) {
635 		ip6h = (ip6_t *)mp->b_rptr;
636 		ah_offset = ipsec_ah_get_hdr_size_v6(mp, B_TRUE);
637 	} else {
638 		ipha = (ipha_t *)mp->b_rptr;
639 		ASSERT(ipha->ipha_protocol == IPPROTO_AH);
640 		ah_offset = ipha->ipha_version_and_hdr_length -
641 		    (uint8_t)((IP_VERSION << 4));
642 		ah_offset <<= 2;
643 	}
644 
645 	/*
646 	 * We assume that the IP header is pulled up until
647 	 * the options. We need to see whether we have the
648 	 * AH header in the same mblk or not.
649 	 */
650 	pullup_len = ah_offset + sizeof (ah_t);
651 	if (mp->b_rptr + pullup_len > mp->b_wptr) {
652 		if (!pullupmsg(mp, pullup_len)) {
653 			ipsecah_rl_strlog(0,  SL_WARN | SL_ERROR,
654 			    "ipsec_inbound_ah_sa: Small AH header\n");
655 			IP_AH_BUMP_STAT(in_discards);
656 			ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL,
657 			    &ipdrops_ah_bad_length, &ip_dropper);
658 			return (NULL);
659 		}
660 		if (isv6)
661 			ip6h = (ip6_t *)mp->b_rptr;
662 		else
663 			ipha = (ipha_t *)mp->b_rptr;
664 	}
665 
666 	ah = (ah_t *)(mp->b_rptr + ah_offset);
667 
668 	if (isv6) {
669 		src_ptr = (uint32_t *)&ip6h->ip6_src;
670 		dst_ptr = (uint32_t *)&ip6h->ip6_dst;
671 		sp = &ah_sadb.s_v6;
672 		af = AF_INET6;
673 	} else {
674 		src_ptr = (uint32_t *)&ipha->ipha_src;
675 		dst_ptr = (uint32_t *)&ipha->ipha_dst;
676 		sp = &ah_sadb.s_v4;
677 		af = AF_INET;
678 	}
679 
680 	hptr = INBOUND_BUCKET(sp, ah->ah_spi);
681 	mutex_enter(&hptr->isaf_lock);
682 	assoc = ipsec_getassocbyspi(hptr, ah->ah_spi, src_ptr, dst_ptr, af);
683 	mutex_exit(&hptr->isaf_lock);
684 
685 	if (assoc == NULL || assoc->ipsa_state == IPSA_STATE_DEAD) {
686 		IP_AH_BUMP_STAT(lookup_failure);
687 		IP_AH_BUMP_STAT(in_discards);
688 		ipsecah_in_assocfailure(ipsec_in, 0,
689 		    SL_ERROR | SL_CONSOLE | SL_WARN,
690 		    "ipsec_inbound_ah_sa: No association found for "
691 		    "spi 0x%x, dst addr %s\n",
692 		    ah->ah_spi, dst_ptr, af);
693 		if (assoc != NULL) {
694 			IPSA_REFRELE(assoc);
695 		}
696 		return (NULL);
697 	}
698 
699 	if (assoc->ipsa_state == IPSA_STATE_LARVAL) {
700 		/* Not fully baked; swap the packet under a rock until then */
701 		sadb_set_lpkt(assoc, ipsec_in);
702 		IPSA_REFRELE(assoc);
703 		return (NULL);
704 	}
705 
706 	/*
707 	 * Save a reference to the association so that it can
708 	 * be retrieved after execution. We free any AH SA reference
709 	 * already there (innermost SA "wins". The reference to
710 	 * the SA will also be used later when doing the policy checks.
711 	 */
712 	if (ii->ipsec_in_ah_sa != NULL) {
713 		IPSA_REFRELE(ii->ipsec_in_ah_sa);
714 	}
715 	ii->ipsec_in_ah_sa = assoc;
716 
717 	return (ah);
718 }
719 
720 esph_t *
721 ipsec_inbound_esp_sa(mblk_t *ipsec_in_mp)
722 {
723 	mblk_t *data_mp, *placeholder;
724 	uint32_t *src_ptr, *dst_ptr;
725 	ipsec_in_t *ii;
726 	ipha_t *ipha;
727 	ip6_t *ip6h;
728 	esph_t *esph;
729 	ipsa_t *ipsa;
730 	isaf_t *bucket;
731 	uint_t preamble;
732 	sa_family_t af;
733 	boolean_t isv6;
734 	sadb_t *sp;
735 
736 	IP_ESP_BUMP_STAT(in_requests);
737 	ASSERT(ipsec_in_mp->b_datap->db_type == M_CTL);
738 
739 	/* We have IPSEC_IN already! */
740 	ii = (ipsec_in_t *)ipsec_in_mp->b_rptr;
741 	data_mp = ipsec_in_mp->b_cont;
742 
743 	ASSERT(ii->ipsec_in_type == IPSEC_IN);
744 
745 	isv6 = !ii->ipsec_in_v4;
746 	if (isv6) {
747 		ip6h = (ip6_t *)data_mp->b_rptr;
748 	} else {
749 		ipha = (ipha_t *)data_mp->b_rptr;
750 	}
751 
752 	/*
753 	 * Put all data into one mblk if it's not there already.
754 	 * XXX This is probably bad long-term.  Figure out better ways of doing
755 	 * this.  Much of the inbound path depends on all of the data being
756 	 * in one mblk.
757 	 *
758 	 * XXX Jumbogram issues will have to be dealt with here.
759 	 * If the plen is 0, we'll have to scan for a HBH header with the
760 	 * actual packet length.
761 	 */
762 	if (data_mp->b_datap->db_ref > 1 ||
763 	    (data_mp->b_wptr - data_mp->b_rptr) <
764 	    (isv6 ? (ntohs(ip6h->ip6_plen) + sizeof (ip6_t))
765 		: ntohs(ipha->ipha_length))) {
766 		placeholder = msgpullup(data_mp, -1);
767 		if (placeholder == NULL) {
768 			IP_ESP_BUMP_STAT(in_discards);
769 			/*
770 			 * TODO: Extract inbound interface from the IPSEC_IN
771 			 * message's ii->ipsec_in_rill_index.
772 			 */
773 			ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL,
774 			    &ipdrops_esp_nomem, &ip_dropper);
775 			return (NULL);
776 		} else {
777 			/* Reset packet with new pulled up mblk. */
778 			freemsg(data_mp);
779 			data_mp = placeholder;
780 			ipsec_in_mp->b_cont = data_mp;
781 		}
782 	}
783 
784 	/*
785 	 * Find the ESP header, point the address pointers at the appropriate
786 	 * IPv4/IPv6 places.
787 	 */
788 	if (isv6) {
789 		ip6h = (ip6_t *)data_mp->b_rptr;
790 		src_ptr = (uint32_t *)&ip6h->ip6_src;
791 		dst_ptr = (uint32_t *)&ip6h->ip6_dst;
792 		if (ip6h->ip6_nxt != IPPROTO_ESP) {
793 			/* There are options that need to be processed. */
794 			preamble = ip_hdr_length_v6(data_mp, ip6h);
795 		} else {
796 			preamble = sizeof (ip6_t);
797 		}
798 
799 		sp = &esp_sadb.s_v6;
800 		af = AF_INET6;
801 	} else {
802 		ipha = (ipha_t *)data_mp->b_rptr;
803 		src_ptr = (uint32_t *)&ipha->ipha_src;
804 		dst_ptr = (uint32_t *)&ipha->ipha_dst;
805 		preamble = IPH_HDR_LENGTH(ipha);
806 
807 		sp = &esp_sadb.s_v4;
808 		af = AF_INET;
809 	}
810 
811 	esph = (esph_t *)(data_mp->b_rptr + preamble);
812 
813 	/* Since hash is common on inbound (SPI value), hash here. */
814 	bucket = INBOUND_BUCKET(sp, esph->esph_spi);
815 	mutex_enter(&bucket->isaf_lock);
816 	ipsa = ipsec_getassocbyspi(bucket, esph->esph_spi, src_ptr, dst_ptr,
817 	    af);
818 	mutex_exit(&bucket->isaf_lock);
819 
820 	if (ipsa == NULL || ipsa->ipsa_state == IPSA_STATE_DEAD) {
821 		/*  This is a loggable error!  AUDIT ME! */
822 		IP_ESP_BUMP_STAT(lookup_failure);
823 		IP_ESP_BUMP_STAT(in_discards);
824 		ipsecesp_in_assocfailure(ipsec_in_mp, 0,
825 		    SL_ERROR | SL_CONSOLE | SL_WARN,
826 		    "ipsec_inbound_esp_sa: No association found for "
827 		    "spi 0x%x, dst addr %s\n",
828 		    esph->esph_spi, dst_ptr, af);
829 		if (ipsa != NULL) {
830 			IPSA_REFRELE(ipsa);
831 		}
832 		return (NULL);
833 	}
834 
835 	if (ipsa->ipsa_state == IPSA_STATE_LARVAL) {
836 		/* Not fully baked; swap the packet under a rock until then */
837 		sadb_set_lpkt(ipsa, ipsec_in_mp);
838 		IPSA_REFRELE(ipsa);
839 		return (NULL);
840 	}
841 
842 	/*
843 	 * Save a reference to the association so that it can
844 	 * be retrieved after execution. We free any AH SA reference
845 	 * already there (innermost SA "wins". The reference to
846 	 * the SA will also be used later when doing the policy checks.
847 	 */
848 	if (ii->ipsec_in_esp_sa != NULL) {
849 		IPSA_REFRELE(ii->ipsec_in_esp_sa);
850 	}
851 	ii->ipsec_in_esp_sa = ipsa;
852 
853 	return (esph);
854 }
855