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