Home | History | Annotate | Download | only in ip
      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