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