xref: /illumos-gate/usr/src/uts/common/inet/ip/ip_sadb.c (revision 930af642)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5bffb04cfSmarkfen  * Common Development and Distribution License (the "License").
6bffb04cfSmarkfen  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*930af642SDan McDonald  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/stream.h>
285d3b8cb7SBill Sommerfeld #include <sys/strsubr.h>
297c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
308810c16bSdanmcd #include <sys/ddi.h>
317c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <inet/common.h>
347c478bd9Sstevel@tonic-gate #include <inet/mib2.h>
357c478bd9Sstevel@tonic-gate #include <inet/ip.h>
367c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h>
397c478bd9Sstevel@tonic-gate #include <inet/sadb.h>
407c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h>
41f4b3ec61Sdh #include <inet/ipdrop.h>
427c478bd9Sstevel@tonic-gate #include <inet/ipsecesp.h>
437c478bd9Sstevel@tonic-gate #include <inet/ipsecah.h>
447c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * Returns B_TRUE if the identities in the SA match the identities
487c478bd9Sstevel@tonic-gate  * in the "latch" structure.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static boolean_t
ipsec_match_outbound_ids(ipsec_latch_t * ipl,ipsa_t * sa)527c478bd9Sstevel@tonic-gate ipsec_match_outbound_ids(ipsec_latch_t *ipl, ipsa_t *sa)
537c478bd9Sstevel@tonic-gate {
547c478bd9Sstevel@tonic-gate 	ASSERT(ipl->ipl_ids_latched == B_TRUE);
557c478bd9Sstevel@tonic-gate 	return ipsid_equal(ipl->ipl_local_cid, sa->ipsa_src_cid) &&
567c478bd9Sstevel@tonic-gate 	    ipsid_equal(ipl->ipl_remote_cid, sa->ipsa_dst_cid);
577c478bd9Sstevel@tonic-gate }
587c478bd9Sstevel@tonic-gate 
59bd670b35SErik Nordmark /* l1 is packet label; l2 is SA label */
605d3b8cb7SBill Sommerfeld boolean_t
ipsec_label_match(ts_label_t * l1,ts_label_t * l2)61bd670b35SErik Nordmark ipsec_label_match(ts_label_t *l1, ts_label_t *l2)
625d3b8cb7SBill Sommerfeld {
635d3b8cb7SBill Sommerfeld 	if (!is_system_labeled())
645d3b8cb7SBill Sommerfeld 		return (B_TRUE);
655d3b8cb7SBill Sommerfeld 
665d3b8cb7SBill Sommerfeld 	/*
67bd670b35SErik Nordmark 	 * Check for NULL label.  Unlabeled SA (l2) always matches;
685d3b8cb7SBill Sommerfeld 	 * unlabeled user with labeled  SA always fails
695d3b8cb7SBill Sommerfeld 	 */
70bd670b35SErik Nordmark 	if (l2 == NULL)
715d3b8cb7SBill Sommerfeld 		return (B_TRUE);
725d3b8cb7SBill Sommerfeld 
735d3b8cb7SBill Sommerfeld 	if (l1 == NULL)
745d3b8cb7SBill Sommerfeld 		return (B_FALSE);
755d3b8cb7SBill Sommerfeld 
765d3b8cb7SBill Sommerfeld 	/* Simple IPsec MLS policy: labels must be equal */
775d3b8cb7SBill Sommerfeld 	/* In future will need bit in policy saying whether this is the case */
785d3b8cb7SBill Sommerfeld 
795d3b8cb7SBill Sommerfeld 	/*
805d3b8cb7SBill Sommerfeld 	 * label_equal() checks DOI and label contents.  We should be
815d3b8cb7SBill Sommerfeld 	 * good to go with this check.
825d3b8cb7SBill Sommerfeld 	 */
835d3b8cb7SBill Sommerfeld 	return (label_equal(l1, l2));
845d3b8cb7SBill Sommerfeld }
855d3b8cb7SBill Sommerfeld 
865d3b8cb7SBill Sommerfeld 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * Look up a security association based on the unique ID generated by IP and
898810c16bSdanmcd  * transport or tunnel information, such as ports and upper-layer protocol,
908810c16bSdanmcd  * and the inner and outer address(es).	 Used for uniqueness testing and
918810c16bSdanmcd  * outbound packets.  The outer source address may be ignored.
927c478bd9Sstevel@tonic-gate  *
937c478bd9Sstevel@tonic-gate  * I expect an SA hash bucket, and that its per-bucket mutex is held.
947c478bd9Sstevel@tonic-gate  * The SA ptr I return will have its reference count incremented by one.
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate ipsa_t *
ipsec_getassocbyconn(isaf_t * bucket,ip_xmit_attr_t * ixa,uint32_t * src,uint32_t * dst,sa_family_t af,uint8_t protocol,ts_label_t * tsl)97bd670b35SErik Nordmark ipsec_getassocbyconn(isaf_t *bucket, ip_xmit_attr_t *ixa, uint32_t *src,
98bd670b35SErik Nordmark     uint32_t *dst, sa_family_t af, uint8_t protocol, ts_label_t *tsl)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate 	ipsa_t *retval, *candidate;
1017c478bd9Sstevel@tonic-gate 	ipsec_action_t *candact;
1027c478bd9Sstevel@tonic-gate 	boolean_t need_unique;
103bd670b35SErik Nordmark 	boolean_t tunnel_mode = (ixa->ixa_flags & IXAF_IPSEC_TUNNEL);
1047c478bd9Sstevel@tonic-gate 	uint64_t unique_id;
1057c478bd9Sstevel@tonic-gate 	uint32_t old_flags, excludeflags;
106bd670b35SErik Nordmark 	ipsec_policy_t *pp = ixa->ixa_ipsec_policy;
107bd670b35SErik Nordmark 	ipsec_action_t *actlist = ixa->ixa_ipsec_action;
1087c478bd9Sstevel@tonic-gate 	ipsec_action_t *act;
109bd670b35SErik Nordmark 	ipsec_latch_t *ipl = ixa->ixa_ipsec_latch;
1107c478bd9Sstevel@tonic-gate 	ipsa_ref_t *ipr = NULL;
111bd670b35SErik Nordmark 	sa_family_t inaf = ixa->ixa_ipsec_inaf;
112bd670b35SErik Nordmark 	uint32_t *insrc = ixa->ixa_ipsec_insrc;
113bd670b35SErik Nordmark 	uint32_t *indst = ixa->ixa_ipsec_indst;
114bd670b35SErik Nordmark 	uint8_t insrcpfx = ixa->ixa_ipsec_insrcpfx;
115bd670b35SErik Nordmark 	uint8_t indstpfx = ixa->ixa_ipsec_indstpfx;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&bucket->isaf_lock));
1187c478bd9Sstevel@tonic-gate 
1198810c16bSdanmcd 	/*
120bd670b35SErik Nordmark 	 * Caller must set ip_xmit_attr_t structure such that we know
1218810c16bSdanmcd 	 * whether this is tunnel mode or transport mode based on
122bd670b35SErik Nordmark 	 * IXAF_IPSEC_TUNNEL.  If this flag is set, we assume that
1238810c16bSdanmcd 	 * there are valid inner src and destination addresses to compare.
1248810c16bSdanmcd 	 */
1258810c16bSdanmcd 
1267c478bd9Sstevel@tonic-gate 	/*
1277c478bd9Sstevel@tonic-gate 	 * Fast path: do we have a latch structure, is it for this bucket,
1287c478bd9Sstevel@tonic-gate 	 * and does the generation number match?  If so, refhold and return.
1297c478bd9Sstevel@tonic-gate 	 */
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	if (ipl != NULL) {
1327c478bd9Sstevel@tonic-gate 		ASSERT((protocol == IPPROTO_AH) || (protocol == IPPROTO_ESP));
133bd670b35SErik Nordmark 		ipr = &ixa->ixa_ipsec_ref[protocol - IPPROTO_ESP];
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 		retval = ipr->ipsr_sa;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 		/*
1387c478bd9Sstevel@tonic-gate 		 * NOTE: The isaf_gen check (incremented upon
1397c478bd9Sstevel@tonic-gate 		 * sadb_unlinkassoc()) protects against retval being a freed
1407c478bd9Sstevel@tonic-gate 		 * SA.  (We're exploiting short-circuit evaluation.)
1417c478bd9Sstevel@tonic-gate 		 */
1427c478bd9Sstevel@tonic-gate 		if ((bucket == ipr->ipsr_bucket) &&
1437c478bd9Sstevel@tonic-gate 		    (bucket->isaf_gen == ipr->ipsr_gen) &&
1447c478bd9Sstevel@tonic-gate 		    (retval->ipsa_state != IPSA_STATE_DEAD) &&
1457c478bd9Sstevel@tonic-gate 		    !(retval->ipsa_flags & IPSA_F_CINVALID)) {
1467c478bd9Sstevel@tonic-gate 			IPSA_REFHOLD(retval);
1477c478bd9Sstevel@tonic-gate 			return (retval);
1487c478bd9Sstevel@tonic-gate 		}
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	ASSERT((pp != NULL) || (actlist != NULL));
1527c478bd9Sstevel@tonic-gate 	if (actlist == NULL)
1537c478bd9Sstevel@tonic-gate 		actlist = pp->ipsp_act;
1547c478bd9Sstevel@tonic-gate 	ASSERT(actlist != NULL);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	need_unique = actlist->ipa_want_unique;
157bd670b35SErik Nordmark 	unique_id = SA_FORM_UNIQUE_ID(ixa);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/*
1607c478bd9Sstevel@tonic-gate 	 * Precompute mask for SA flags comparison: If we need a
1617c478bd9Sstevel@tonic-gate 	 * unique SA and an SA has already been used, or if the SA has
1627c478bd9Sstevel@tonic-gate 	 * a unique value which doesn't match, we aren't interested in
1637c478bd9Sstevel@tonic-gate 	 * the SA..
1647c478bd9Sstevel@tonic-gate 	 */
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	excludeflags = IPSA_F_UNIQUE;
1677c478bd9Sstevel@tonic-gate 	if (need_unique)
1687c478bd9Sstevel@tonic-gate 		excludeflags |= IPSA_F_USED;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/*
1717c478bd9Sstevel@tonic-gate 	 * Walk the hash bucket, matching on:
1727c478bd9Sstevel@tonic-gate 	 *
1737c478bd9Sstevel@tonic-gate 	 * - unique_id
1747c478bd9Sstevel@tonic-gate 	 * - destination
1757c478bd9Sstevel@tonic-gate 	 * - source
1767c478bd9Sstevel@tonic-gate 	 * - algorithms
1778810c16bSdanmcd 	 * - inner dst
1788810c16bSdanmcd 	 * - inner src
1797c478bd9Sstevel@tonic-gate 	 * - <MORE TBD>
1807c478bd9Sstevel@tonic-gate 	 *
1817c478bd9Sstevel@tonic-gate 	 * Make sure that wildcard sources are inserted at the end of the hash
1827c478bd9Sstevel@tonic-gate 	 * bucket.
1837c478bd9Sstevel@tonic-gate 	 *
1847c478bd9Sstevel@tonic-gate 	 * DEFINITIONS:	A _shared_ SA is one with unique_id == 0 and USED.
1857c478bd9Sstevel@tonic-gate 	 *		An _unused_ SA is one with unique_id == 0 and not USED.
1867c478bd9Sstevel@tonic-gate 	 *		A _unique_ SA is one with unique_id != 0 and USED.
1877c478bd9Sstevel@tonic-gate 	 *		An SA with unique_id != 0 and not USED never happens.
1887c478bd9Sstevel@tonic-gate 	 */
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	candidate = NULL;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	for (retval = bucket->isaf_ipsa; retval != NULL;
1937c478bd9Sstevel@tonic-gate 	    retval = retval->ipsa_next) {
1947c478bd9Sstevel@tonic-gate 		ASSERT((candidate == NULL) ||
1957c478bd9Sstevel@tonic-gate 		    MUTEX_HELD(&candidate->ipsa_lock));
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		/*
1987c478bd9Sstevel@tonic-gate 		 * Q: Should I lock this SA?
1997c478bd9Sstevel@tonic-gate 		 * A: For now, yes.  I change and use too many fields in here
2007c478bd9Sstevel@tonic-gate 		 *    (e.g. unique_id) that I may be racing with other threads.
2017c478bd9Sstevel@tonic-gate 		 *    Also, the refcnt needs to be bumped up.
2027c478bd9Sstevel@tonic-gate 		 */
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 		mutex_enter(&retval->ipsa_lock);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 		/* My apologies for the use of goto instead of continue. */
2078810c16bSdanmcd 
2088810c16bSdanmcd 		/* Outer destination address */
2097c478bd9Sstevel@tonic-gate 		if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af))
2107c478bd9Sstevel@tonic-gate 			goto next_ipsa;	/* Destination mismatch. */
2118810c16bSdanmcd 
2128810c16bSdanmcd 		/* Outer source address */
2137c478bd9Sstevel@tonic-gate 		if (!IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) &&
2147c478bd9Sstevel@tonic-gate 		    !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af))
2157c478bd9Sstevel@tonic-gate 			goto next_ipsa;	/* Specific source and not matched. */
2167c478bd9Sstevel@tonic-gate 
2178810c16bSdanmcd 		if (tunnel_mode) {
2188810c16bSdanmcd 			/* Check tunnel mode */
2198810c16bSdanmcd 			if (!(retval->ipsa_flags & IPSA_F_TUNNEL))
2208810c16bSdanmcd 				goto next_ipsa; /* Not tunnel mode SA */
2218810c16bSdanmcd 
2228810c16bSdanmcd 			/* Inner destination address */
2238810c16bSdanmcd 			if (!IPSA_IS_ADDR_UNSPEC(retval->ipsa_innerdst, inaf)) {
2248810c16bSdanmcd 				if (!ip_addr_match((uint8_t *)indst,
2258810c16bSdanmcd 				    min(indstpfx, retval->ipsa_innerdstpfx),
2268810c16bSdanmcd 				    (in6_addr_t *)retval->ipsa_innerdst))
2278810c16bSdanmcd 					goto next_ipsa; /* not matched. */
2288810c16bSdanmcd 			}
2298810c16bSdanmcd 
2308810c16bSdanmcd 			/* Inner source address */
2318810c16bSdanmcd 			if (!IPSA_IS_ADDR_UNSPEC(retval->ipsa_innersrc, inaf)) {
2328810c16bSdanmcd 				if (!ip_addr_match((uint8_t *)insrc,
2338810c16bSdanmcd 				    min(insrcpfx, retval->ipsa_innersrcpfx),
2348810c16bSdanmcd 				    (in6_addr_t *)retval->ipsa_innersrc))
2358810c16bSdanmcd 					goto next_ipsa; /* not matched. */
2368810c16bSdanmcd 			}
2378810c16bSdanmcd 		} else {
2388810c16bSdanmcd 			/* Check transport mode */
2398810c16bSdanmcd 			if (retval->ipsa_flags & IPSA_F_TUNNEL)
2408810c16bSdanmcd 				goto next_ipsa; /* Not transport mode SA */
2418810c16bSdanmcd 
2428810c16bSdanmcd 			/*
2438810c16bSdanmcd 			 * TODO - If we ever do RFC 3884's dream of transport-
2448810c16bSdanmcd 			 * mode SAs with inner IP address selectors, we need
2458810c16bSdanmcd 			 * to put some code here.
2468810c16bSdanmcd 			 */
2478810c16bSdanmcd 		}
2488810c16bSdanmcd 
2497c478bd9Sstevel@tonic-gate 		/*
2507c478bd9Sstevel@tonic-gate 		 * XXX should be able to use cached/latched action
2517c478bd9Sstevel@tonic-gate 		 * to dodge this loop
2527c478bd9Sstevel@tonic-gate 		 */
2537c478bd9Sstevel@tonic-gate 		for (act = actlist; act != NULL; act = act->ipa_next) {
2547c478bd9Sstevel@tonic-gate 			ipsec_act_t *ap = &act->ipa_act;
2557c478bd9Sstevel@tonic-gate 			if (ap->ipa_type != IPSEC_POLICY_APPLY)
2567c478bd9Sstevel@tonic-gate 				continue;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 			/*
2597c478bd9Sstevel@tonic-gate 			 * XXX ugly.  should be better way to do this test
2607c478bd9Sstevel@tonic-gate 			 */
2617c478bd9Sstevel@tonic-gate 			if (protocol == IPPROTO_AH) {
2627c478bd9Sstevel@tonic-gate 				if (!(ap->ipa_apply.ipp_use_ah))
2637c478bd9Sstevel@tonic-gate 					continue;
2647c478bd9Sstevel@tonic-gate 				if (ap->ipa_apply.ipp_auth_alg !=
2657c478bd9Sstevel@tonic-gate 				    retval->ipsa_auth_alg)
2667c478bd9Sstevel@tonic-gate 					continue;
2677c478bd9Sstevel@tonic-gate 				if (ap->ipa_apply.ipp_ah_minbits >
2689c2c14abSThejaswini Singarajipura 				    retval->ipsa_authkeybits)
2697c478bd9Sstevel@tonic-gate 					continue;
2707c478bd9Sstevel@tonic-gate 			} else {
2717c478bd9Sstevel@tonic-gate 				if (!(ap->ipa_apply.ipp_use_esp))
2727c478bd9Sstevel@tonic-gate 					continue;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 				if ((ap->ipa_apply.ipp_encr_alg !=
2757c478bd9Sstevel@tonic-gate 				    retval->ipsa_encr_alg))
2767c478bd9Sstevel@tonic-gate 					continue;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 				if (ap->ipa_apply.ipp_espe_minbits >
2797c478bd9Sstevel@tonic-gate 				    retval->ipsa_encrkeybits)
2807c478bd9Sstevel@tonic-gate 					continue;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 				if (ap->ipa_apply.ipp_esp_auth_alg != 0) {
2837c478bd9Sstevel@tonic-gate 					if (ap->ipa_apply.ipp_esp_auth_alg !=
2847c478bd9Sstevel@tonic-gate 					    retval->ipsa_auth_alg)
2857c478bd9Sstevel@tonic-gate 						continue;
2867c478bd9Sstevel@tonic-gate 					if (ap->ipa_apply.ipp_espa_minbits >
2877c478bd9Sstevel@tonic-gate 					    retval->ipsa_authkeybits)
2887c478bd9Sstevel@tonic-gate 						continue;
2897c478bd9Sstevel@tonic-gate 				}
2907c478bd9Sstevel@tonic-gate 			}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 			/*
2937c478bd9Sstevel@tonic-gate 			 * Check key mgmt proto, cookie
2947c478bd9Sstevel@tonic-gate 			 */
2957c478bd9Sstevel@tonic-gate 			if ((ap->ipa_apply.ipp_km_proto != 0) &&
2967c478bd9Sstevel@tonic-gate 			    (retval->ipsa_kmp != 0) &&
2977c478bd9Sstevel@tonic-gate 			    (ap->ipa_apply.ipp_km_proto != retval->ipsa_kmp))
2987c478bd9Sstevel@tonic-gate 				continue;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 			if ((ap->ipa_apply.ipp_km_cookie != 0) &&
3017c478bd9Sstevel@tonic-gate 			    (retval->ipsa_kmc != 0) &&
3027c478bd9Sstevel@tonic-gate 			    (ap->ipa_apply.ipp_km_cookie != retval->ipsa_kmc))
3037c478bd9Sstevel@tonic-gate 				continue;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 			break;
3067c478bd9Sstevel@tonic-gate 		}
3077c478bd9Sstevel@tonic-gate 		if (act == NULL)
3087c478bd9Sstevel@tonic-gate 			goto next_ipsa;	/* nothing matched */
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 		/*
3117c478bd9Sstevel@tonic-gate 		 * Do identities match?
3127c478bd9Sstevel@tonic-gate 		 */
3137c478bd9Sstevel@tonic-gate 		if (ipl && ipl->ipl_ids_latched &&
3147c478bd9Sstevel@tonic-gate 		    !ipsec_match_outbound_ids(ipl, retval))
3157c478bd9Sstevel@tonic-gate 			goto next_ipsa;
3167c478bd9Sstevel@tonic-gate 
3175d3b8cb7SBill Sommerfeld 		/*
3185d3b8cb7SBill Sommerfeld 		 * Do labels match?
3195d3b8cb7SBill Sommerfeld 		 */
320bd670b35SErik Nordmark 		if (!ipsec_label_match(tsl, retval->ipsa_tsl))
3215d3b8cb7SBill Sommerfeld 			goto next_ipsa;
3225d3b8cb7SBill Sommerfeld 
3237c478bd9Sstevel@tonic-gate 		/*
3247c478bd9Sstevel@tonic-gate 		 * At this point, we know that we have at least a match on:
3257c478bd9Sstevel@tonic-gate 		 *
3267c478bd9Sstevel@tonic-gate 		 * - dest
3277c478bd9Sstevel@tonic-gate 		 * - source (if source is specified, i.e. non-zeroes)
3288810c16bSdanmcd 		 * - inner dest (if specified)
3298810c16bSdanmcd 		 * - inner source (if specified)
3307c478bd9Sstevel@tonic-gate 		 * - auth alg (if auth alg is specified, i.e. non-zero)
3317c478bd9Sstevel@tonic-gate 		 * - encrypt. alg (if encrypt. alg is specified, i.e. non-zero)
3327c478bd9Sstevel@tonic-gate 		 * and we know that the SA keylengths are appropriate.
3337c478bd9Sstevel@tonic-gate 		 *
3347c478bd9Sstevel@tonic-gate 		 * (Keep in mind known-src SAs are hit before zero-src SAs,
3357c478bd9Sstevel@tonic-gate 		 * thanks to sadb_insertassoc().)
3367c478bd9Sstevel@tonic-gate 		 * If we need a unique asssociation, optimally we have
3377c478bd9Sstevel@tonic-gate 		 * ipsa_unique_id == unique_id, otherwise NOT USED
3387c478bd9Sstevel@tonic-gate 		 * is held in reserve (stored in candidate).
3397c478bd9Sstevel@tonic-gate 		 *
3407c478bd9Sstevel@tonic-gate 		 * For those stored in candidate, take best-match (i.e. given
3417c478bd9Sstevel@tonic-gate 		 * a choice, candidate should have non-zero ipsa_src).
3427c478bd9Sstevel@tonic-gate 		 */
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 		/*
3457c478bd9Sstevel@tonic-gate 		 * If SA has a unique value which matches, we're all set...
3467c478bd9Sstevel@tonic-gate 		 * "key management knows best"
3477c478bd9Sstevel@tonic-gate 		 */
3487c478bd9Sstevel@tonic-gate 		if ((retval->ipsa_flags & IPSA_F_UNIQUE) &&
3497c478bd9Sstevel@tonic-gate 		    ((unique_id & retval->ipsa_unique_mask) ==
3509c2c14abSThejaswini Singarajipura 		    retval->ipsa_unique_id))
3517c478bd9Sstevel@tonic-gate 			break;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 		/*
3547c478bd9Sstevel@tonic-gate 		 * If we need a unique SA and this SA has already been used,
3557c478bd9Sstevel@tonic-gate 		 * or if the SA has a unique value which doesn't match,
3567c478bd9Sstevel@tonic-gate 		 * this isn't for us.
3577c478bd9Sstevel@tonic-gate 		 */
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		if (retval->ipsa_flags & excludeflags)
3607c478bd9Sstevel@tonic-gate 			goto next_ipsa;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 		/*
3647c478bd9Sstevel@tonic-gate 		 * I found a candidate..
3657c478bd9Sstevel@tonic-gate 		 */
3667c478bd9Sstevel@tonic-gate 		if (candidate == NULL) {
3677c478bd9Sstevel@tonic-gate 			/*
3687c478bd9Sstevel@tonic-gate 			 * and didn't already have one..
3697c478bd9Sstevel@tonic-gate 			 */
3707c478bd9Sstevel@tonic-gate 			candidate = retval;
3717c478bd9Sstevel@tonic-gate 			candact = act;
3727c478bd9Sstevel@tonic-gate 			continue;
3737c478bd9Sstevel@tonic-gate 		} else {
3747c478bd9Sstevel@tonic-gate 			/*
3757c478bd9Sstevel@tonic-gate 			 * If candidate's source address is zero and
3767c478bd9Sstevel@tonic-gate 			 * the current match (i.e. retval) address is
3777c478bd9Sstevel@tonic-gate 			 * not zero, we have a better candidate..
3787c478bd9Sstevel@tonic-gate 			 */
3797c478bd9Sstevel@tonic-gate 			if (IPSA_IS_ADDR_UNSPEC(candidate->ipsa_srcaddr, af) &&
3807c478bd9Sstevel@tonic-gate 			    !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) {
3817c478bd9Sstevel@tonic-gate 				mutex_exit(&candidate->ipsa_lock);
3827c478bd9Sstevel@tonic-gate 				candidate = retval;
3837c478bd9Sstevel@tonic-gate 				candact = act;
3847c478bd9Sstevel@tonic-gate 				continue;
3857c478bd9Sstevel@tonic-gate 			}
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate next_ipsa:
3887c478bd9Sstevel@tonic-gate 		mutex_exit(&retval->ipsa_lock);
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 	ASSERT((retval == NULL) || MUTEX_HELD(&retval->ipsa_lock));
3917c478bd9Sstevel@tonic-gate 	ASSERT((candidate == NULL) || MUTEX_HELD(&candidate->ipsa_lock));
3927c478bd9Sstevel@tonic-gate 	ASSERT((retval == NULL) || (act != NULL));
3937c478bd9Sstevel@tonic-gate 	ASSERT((candidate == NULL) || (candact != NULL));
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/* Let caller react to a lookup failure when it gets NULL. */
3967c478bd9Sstevel@tonic-gate 	if (retval == NULL && candidate == NULL)
3977c478bd9Sstevel@tonic-gate 		return (NULL);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (retval == NULL) {
4007c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&candidate->ipsa_lock));
4017c478bd9Sstevel@tonic-gate 		retval = candidate;
4027c478bd9Sstevel@tonic-gate 		act = candact;
4037c478bd9Sstevel@tonic-gate 	} else if (candidate != NULL) {
4047c478bd9Sstevel@tonic-gate 		mutex_exit(&candidate->ipsa_lock);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&retval->ipsa_lock));
4077c478bd9Sstevel@tonic-gate 	ASSERT(act != NULL);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/*
4107c478bd9Sstevel@tonic-gate 	 * Even though I hold the mutex, since the reference counter is an
4117c478bd9Sstevel@tonic-gate 	 * atomic operation, I really have to use the IPSA_REFHOLD macro.
4127c478bd9Sstevel@tonic-gate 	 */
4137c478bd9Sstevel@tonic-gate 	IPSA_REFHOLD(retval);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/*
4167c478bd9Sstevel@tonic-gate 	 * This association is no longer unused.
4177c478bd9Sstevel@tonic-gate 	 */
4187c478bd9Sstevel@tonic-gate 	old_flags = retval->ipsa_flags;
4197c478bd9Sstevel@tonic-gate 	retval->ipsa_flags |= IPSA_F_USED;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/*
4227c478bd9Sstevel@tonic-gate 	 * Cache a reference to this SA for the fast path.
4237c478bd9Sstevel@tonic-gate 	 */
4247c478bd9Sstevel@tonic-gate 	if (ipr != NULL) {
4257c478bd9Sstevel@tonic-gate 		ipr->ipsr_bucket = bucket;
4267c478bd9Sstevel@tonic-gate 		ipr->ipsr_gen = bucket->isaf_gen;
4277c478bd9Sstevel@tonic-gate 		ipr->ipsr_sa = retval;
4287c478bd9Sstevel@tonic-gate 		/* I'm now caching, so the cache-invalid flag goes away! */
4297c478bd9Sstevel@tonic-gate 		retval->ipsa_flags &= ~IPSA_F_CINVALID;
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 	/*
4327c478bd9Sstevel@tonic-gate 	 * Latch various things while we're here..
4337c478bd9Sstevel@tonic-gate 	 */
4347c478bd9Sstevel@tonic-gate 	if (ipl != NULL) {
4357c478bd9Sstevel@tonic-gate 		if (!ipl->ipl_ids_latched) {
4367c478bd9Sstevel@tonic-gate 			ipsec_latch_ids(ipl,
4377c478bd9Sstevel@tonic-gate 			    retval->ipsa_src_cid, retval->ipsa_dst_cid);
4387c478bd9Sstevel@tonic-gate 		}
439bd670b35SErik Nordmark 		if (ixa->ixa_ipsec_action == NULL) {
4407c478bd9Sstevel@tonic-gate 			IPACT_REFHOLD(act);
441bd670b35SErik Nordmark 			ixa->ixa_ipsec_action = act;
4427c478bd9Sstevel@tonic-gate 		}
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/*
4467c478bd9Sstevel@tonic-gate 	 * Set the uniqueness only first time.
4477c478bd9Sstevel@tonic-gate 	 */
4487c478bd9Sstevel@tonic-gate 	if (need_unique && !(old_flags & IPSA_F_USED)) {
4497c478bd9Sstevel@tonic-gate 		if (retval->ipsa_unique_id == 0) {
4507c478bd9Sstevel@tonic-gate 			ASSERT((retval->ipsa_flags & IPSA_F_UNIQUE) == 0);
4517c478bd9Sstevel@tonic-gate 			/*
4527c478bd9Sstevel@tonic-gate 			 * From now on, only this src, dst[ports, addr],
4537c478bd9Sstevel@tonic-gate 			 * proto, should use it.
4547c478bd9Sstevel@tonic-gate 			 */
4557c478bd9Sstevel@tonic-gate 			retval->ipsa_flags |= IPSA_F_UNIQUE;
4567c478bd9Sstevel@tonic-gate 			retval->ipsa_unique_id = unique_id;
4577c478bd9Sstevel@tonic-gate 			retval->ipsa_unique_mask = SA_UNIQUE_MASK(
458bd670b35SErik Nordmark 			    ixa->ixa_ipsec_src_port, ixa->ixa_ipsec_dst_port,
4598810c16bSdanmcd 			    protocol, 0);
4607c478bd9Sstevel@tonic-gate 		}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 		/*
4637c478bd9Sstevel@tonic-gate 		 * Set the source address and adjust the hash
4647c478bd9Sstevel@tonic-gate 		 * buckets only if src_addr is zero.
4657c478bd9Sstevel@tonic-gate 		 */
4667c478bd9Sstevel@tonic-gate 		if (IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) {
4677c478bd9Sstevel@tonic-gate 			/*
4687c478bd9Sstevel@tonic-gate 			 * sadb_unlinkassoc() will decrement the refcnt.  Bump
4697c478bd9Sstevel@tonic-gate 			 * up when we have the lock so that we don't have to
4707c478bd9Sstevel@tonic-gate 			 * acquire locks when we come back from
4717c478bd9Sstevel@tonic-gate 			 * sadb_insertassoc().
4727c478bd9Sstevel@tonic-gate 			 *
4737c478bd9Sstevel@tonic-gate 			 * We don't need to bump the bucket's gen since
4747c478bd9Sstevel@tonic-gate 			 * we aren't moving to a new bucket.
4757c478bd9Sstevel@tonic-gate 			 */
4767c478bd9Sstevel@tonic-gate 			IPSA_REFHOLD(retval);
4777c478bd9Sstevel@tonic-gate 			IPSA_COPY_ADDR(retval->ipsa_srcaddr, src, af);
4787c478bd9Sstevel@tonic-gate 			mutex_exit(&retval->ipsa_lock);
4797c478bd9Sstevel@tonic-gate 			sadb_unlinkassoc(retval);
4807c478bd9Sstevel@tonic-gate 			/*
4817c478bd9Sstevel@tonic-gate 			 * Since the bucket lock is held, we know
4827c478bd9Sstevel@tonic-gate 			 * sadb_insertassoc() will succeed.
4837c478bd9Sstevel@tonic-gate 			 */
4847c478bd9Sstevel@tonic-gate #ifdef DEBUG
4857c478bd9Sstevel@tonic-gate 			if (sadb_insertassoc(retval, bucket) != 0) {
4867c478bd9Sstevel@tonic-gate 				cmn_err(CE_PANIC,
4877c478bd9Sstevel@tonic-gate 				    "sadb_insertassoc() failed in "
4887c478bd9Sstevel@tonic-gate 				    "ipsec_getassocbyconn().\n");
4897c478bd9Sstevel@tonic-gate 			}
4907c478bd9Sstevel@tonic-gate #else	/* non-DEBUG */
4917c478bd9Sstevel@tonic-gate 			(void) sadb_insertassoc(retval, bucket);
4927c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
4937c478bd9Sstevel@tonic-gate 			return (retval);
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 	mutex_exit(&retval->ipsa_lock);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	return (retval);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate  * Look up a security association based on the security parameters index (SPI)
5037c478bd9Sstevel@tonic-gate  * and address(es).  This is used for inbound packets and general SA lookups
5047c478bd9Sstevel@tonic-gate  * (even in outbound SA tables).  The source address may be ignored.  Return
5057c478bd9Sstevel@tonic-gate  * NULL if no association is available.	 If an SA is found, return it, with
5067c478bd9Sstevel@tonic-gate  * its refcnt incremented.  The caller must REFRELE after using the SA.
5077c478bd9Sstevel@tonic-gate  * The hash bucket must be locked down before calling.
5087c478bd9Sstevel@tonic-gate  */
5097c478bd9Sstevel@tonic-gate ipsa_t *
ipsec_getassocbyspi(isaf_t * bucket,uint32_t spi,uint32_t * src,uint32_t * dst,sa_family_t af)5107c478bd9Sstevel@tonic-gate ipsec_getassocbyspi(isaf_t *bucket, uint32_t spi, uint32_t *src, uint32_t *dst,
5117c478bd9Sstevel@tonic-gate     sa_family_t af)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 	ipsa_t *retval;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&bucket->isaf_lock));
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	/*
5187c478bd9Sstevel@tonic-gate 	 * Walk the hash bucket, matching exactly on SPI, then destination,
5197c478bd9Sstevel@tonic-gate 	 * then source.
5207c478bd9Sstevel@tonic-gate 	 *
5217c478bd9Sstevel@tonic-gate 	 * Per-SA locking doesn't need to happen, because I'm only matching
5227c478bd9Sstevel@tonic-gate 	 * on addresses.  Addresses are only changed during insertion/deletion
5237c478bd9Sstevel@tonic-gate 	 * from the hash bucket.  Since the hash bucket lock is held, we don't
5247c478bd9Sstevel@tonic-gate 	 * need to worry about addresses changing.
5257c478bd9Sstevel@tonic-gate 	 */
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	for (retval = bucket->isaf_ipsa; retval != NULL;
5287c478bd9Sstevel@tonic-gate 	    retval = retval->ipsa_next) {
5297c478bd9Sstevel@tonic-gate 		if (retval->ipsa_spi != spi)
5307c478bd9Sstevel@tonic-gate 			continue;
5317c478bd9Sstevel@tonic-gate 		if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af))
5327c478bd9Sstevel@tonic-gate 			continue;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 		/*
5357c478bd9Sstevel@tonic-gate 		 * Assume that wildcard source addresses are inserted at the
5367c478bd9Sstevel@tonic-gate 		 * end of the hash bucket.  (See sadb_insertassoc().)
5377c478bd9Sstevel@tonic-gate 		 * The following check for source addresses is a weak form
5387c478bd9Sstevel@tonic-gate 		 * of access control/source identity verification.  If an
5397c478bd9Sstevel@tonic-gate 		 * SA has a source address, I only match an all-zeroes
5407c478bd9Sstevel@tonic-gate 		 * source address, or that particular one.  If the SA has
5417c478bd9Sstevel@tonic-gate 		 * an all-zeroes source, then I match regardless.
5427c478bd9Sstevel@tonic-gate 		 *
5437c478bd9Sstevel@tonic-gate 		 * There is a weakness here in that a packet with all-zeroes
5447c478bd9Sstevel@tonic-gate 		 * for an address will match regardless of the source address
5457c478bd9Sstevel@tonic-gate 		 * stored in the packet.
54607b56925Ssommerfe 		 *
54707b56925Ssommerfe 		 * Note that port-level packet selectors, if present,
54807b56925Ssommerfe 		 * are checked in ipsec_check_ipsecin_unique().
5497c478bd9Sstevel@tonic-gate 		 */
5507c478bd9Sstevel@tonic-gate 		if (IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) ||
5517c478bd9Sstevel@tonic-gate 		    IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af) ||
5527c478bd9Sstevel@tonic-gate 		    IPSA_IS_ADDR_UNSPEC(src, af))
5537c478bd9Sstevel@tonic-gate 			break;
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if (retval != NULL) {
5577c478bd9Sstevel@tonic-gate 		/*
5587c478bd9Sstevel@tonic-gate 		 * Just refhold the return value.  The caller will then
5597c478bd9Sstevel@tonic-gate 		 * make the appropriate calls to set the USED flag.
5607c478bd9Sstevel@tonic-gate 		 */
5617c478bd9Sstevel@tonic-gate 		IPSA_REFHOLD(retval);
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	return (retval);
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate boolean_t
ipsec_outbound_sa(mblk_t * data_mp,ip_xmit_attr_t * ixa,uint_t proto)568bd670b35SErik Nordmark ipsec_outbound_sa(mblk_t *data_mp, ip_xmit_attr_t *ixa, uint_t proto)
5697c478bd9Sstevel@tonic-gate {
5707c478bd9Sstevel@tonic-gate 	ipaddr_t dst;
5717c478bd9Sstevel@tonic-gate 	uint32_t *dst_ptr, *src_ptr;
5727c478bd9Sstevel@tonic-gate 	isaf_t *bucket;
5737c478bd9Sstevel@tonic-gate 	ipsa_t *assoc;
574bd670b35SErik Nordmark 	ip_pkt_t ipp;
5757c478bd9Sstevel@tonic-gate 	in6_addr_t dst6;
5767c478bd9Sstevel@tonic-gate 	ipsa_t **sa;
5777c478bd9Sstevel@tonic-gate 	sadbp_t *sadbp;
578fb87b5d2Ssommerfe 	sadb_t *sp;
5797c478bd9Sstevel@tonic-gate 	sa_family_t af;
580bd670b35SErik Nordmark 	ip_stack_t	*ipst = ixa->ixa_ipst;
581bd670b35SErik Nordmark 	netstack_t	*ns = ipst->ips_netstack;
5827c478bd9Sstevel@tonic-gate 
583bd670b35SErik Nordmark 	ASSERT(ixa->ixa_flags & IXAF_IPSEC_SECURE);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if (proto == IPPROTO_ESP) {
586f4b3ec61Sdh 		ipsecesp_stack_t	*espstack;
587f4b3ec61Sdh 
588f4b3ec61Sdh 		espstack = ns->netstack_ipsecesp;
589bd670b35SErik Nordmark 		sa = &ixa->ixa_ipsec_esp_sa;
590f4b3ec61Sdh 		sadbp = &espstack->esp_sadb;
5917c478bd9Sstevel@tonic-gate 	} else {
592f4b3ec61Sdh 		ipsecah_stack_t	*ahstack;
593f4b3ec61Sdh 
5947c478bd9Sstevel@tonic-gate 		ASSERT(proto == IPPROTO_AH);
595f4b3ec61Sdh 		ahstack = ns->netstack_ipsecah;
596bd670b35SErik Nordmark 		sa = &ixa->ixa_ipsec_ah_sa;
597f4b3ec61Sdh 		sadbp = &ahstack->ah_sadb;
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	ASSERT(*sa == NULL);
6017c478bd9Sstevel@tonic-gate 
602bd670b35SErik Nordmark 	if (ixa->ixa_flags & IXAF_IS_IPV4) {
6037c478bd9Sstevel@tonic-gate 		ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 		ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION);
6067c478bd9Sstevel@tonic-gate 		dst = ip_get_dst(ipha);
607fb87b5d2Ssommerfe 		sp = &sadbp->s_v4;
6087c478bd9Sstevel@tonic-gate 		af = AF_INET;
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 		/*
6117c478bd9Sstevel@tonic-gate 		 * NOTE:Getting the outbound association is considerably
6127c478bd9Sstevel@tonic-gate 		 *	painful.  ipsec_getassocbyconn() will require more
6137c478bd9Sstevel@tonic-gate 		 *	parameters as policy implementations mature.
6147c478bd9Sstevel@tonic-gate 		 */
615fb87b5d2Ssommerfe 		bucket = OUTBOUND_BUCKET_V4(sp, dst);
6167c478bd9Sstevel@tonic-gate 		src_ptr = (uint32_t *)&ipha->ipha_src;
6177c478bd9Sstevel@tonic-gate 		dst_ptr = (uint32_t *)&dst;
6187c478bd9Sstevel@tonic-gate 	} else {
6197c478bd9Sstevel@tonic-gate 		ip6_t *ip6h = (ip6_t *)data_mp->b_rptr;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 		ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
6223062294fSDan McDonald 		dst6 = ip_get_dst_v6(ip6h, data_mp, NULL);
6237c478bd9Sstevel@tonic-gate 		af = AF_INET6;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		bzero(&ipp, sizeof (ipp));
626fb87b5d2Ssommerfe 		sp = &sadbp->s_v6;
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 		/* Same NOTE: applies here! */
629fb87b5d2Ssommerfe 		bucket = OUTBOUND_BUCKET_V6(sp, dst6);
6307c478bd9Sstevel@tonic-gate 		src_ptr = (uint32_t *)&ip6h->ip6_src;
6317c478bd9Sstevel@tonic-gate 		dst_ptr = (uint32_t *)&dst6;
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	mutex_enter(&bucket->isaf_lock);
635bd670b35SErik Nordmark 	assoc = ipsec_getassocbyconn(bucket, ixa, src_ptr, dst_ptr, af,
636bd670b35SErik Nordmark 	    proto, ixa->ixa_tsl);
6377c478bd9Sstevel@tonic-gate 	mutex_exit(&bucket->isaf_lock);
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	if (assoc == NULL)
6407c478bd9Sstevel@tonic-gate 		return (B_FALSE);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	if (assoc->ipsa_state == IPSA_STATE_DEAD) {
6437c478bd9Sstevel@tonic-gate 		IPSA_REFRELE(assoc);
6447c478bd9Sstevel@tonic-gate 		return (B_FALSE);
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	ASSERT(assoc->ipsa_state != IPSA_STATE_LARVAL);
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	*sa = assoc;
6507c478bd9Sstevel@tonic-gate 	return (B_TRUE);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate /*
6547c478bd9Sstevel@tonic-gate  * Inbound IPsec SA selection.
655bd670b35SErik Nordmark  * Can return a pulled up mblk.
656bd670b35SErik Nordmark  * When it returns non-NULL ahp is updated
6577c478bd9Sstevel@tonic-gate  */
658bd670b35SErik Nordmark mblk_t *
ipsec_inbound_ah_sa(mblk_t * mp,ip_recv_attr_t * ira,ah_t ** ahp)659bd670b35SErik Nordmark ipsec_inbound_ah_sa(mblk_t *mp, ip_recv_attr_t *ira, ah_t **ahp)
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate 	ipha_t *ipha;
6627c478bd9Sstevel@tonic-gate 	ipsa_t 	*assoc;
6637c478bd9Sstevel@tonic-gate 	ah_t *ah;
6647c478bd9Sstevel@tonic-gate 	isaf_t *hptr;
6657c478bd9Sstevel@tonic-gate 	boolean_t isv6;
6667c478bd9Sstevel@tonic-gate 	ip6_t *ip6h;
6677c478bd9Sstevel@tonic-gate 	int ah_offset;
6687c478bd9Sstevel@tonic-gate 	uint32_t *src_ptr, *dst_ptr;
6697c478bd9Sstevel@tonic-gate 	int pullup_len;
670fb87b5d2Ssommerfe 	sadb_t *sp;
6717c478bd9Sstevel@tonic-gate 	sa_family_t af;
672bd670b35SErik Nordmark 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
673f4b3ec61Sdh 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
674f4b3ec61Sdh 	ipsecah_stack_t	*ahstack = ns->netstack_ipsecah;
6757c478bd9Sstevel@tonic-gate 
676f4b3ec61Sdh 	IP_AH_BUMP_STAT(ipss, in_requests);
6777c478bd9Sstevel@tonic-gate 
678bd670b35SErik Nordmark 	isv6 = !(ira->ira_flags & IRAF_IS_IPV4);
6797c478bd9Sstevel@tonic-gate 	if (isv6) {
6807c478bd9Sstevel@tonic-gate 		ip6h = (ip6_t *)mp->b_rptr;
6817c478bd9Sstevel@tonic-gate 		ah_offset = ipsec_ah_get_hdr_size_v6(mp, B_TRUE);
6827c478bd9Sstevel@tonic-gate 	} else {
6837c478bd9Sstevel@tonic-gate 		ipha = (ipha_t *)mp->b_rptr;
6847c478bd9Sstevel@tonic-gate 		ASSERT(ipha->ipha_protocol == IPPROTO_AH);
6857c478bd9Sstevel@tonic-gate 		ah_offset = ipha->ipha_version_and_hdr_length -
6867c478bd9Sstevel@tonic-gate 		    (uint8_t)((IP_VERSION << 4));
6877c478bd9Sstevel@tonic-gate 		ah_offset <<= 2;
6887c478bd9Sstevel@tonic-gate 	}
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	/*
6917c478bd9Sstevel@tonic-gate 	 * We assume that the IP header is pulled up until
6927c478bd9Sstevel@tonic-gate 	 * the options. We need to see whether we have the
6937c478bd9Sstevel@tonic-gate 	 * AH header in the same mblk or not.
6947c478bd9Sstevel@tonic-gate 	 */
6957c478bd9Sstevel@tonic-gate 	pullup_len = ah_offset + sizeof (ah_t);
6967c478bd9Sstevel@tonic-gate 	if (mp->b_rptr + pullup_len > mp->b_wptr) {
6977c478bd9Sstevel@tonic-gate 		if (!pullupmsg(mp, pullup_len)) {
698f4b3ec61Sdh 			ipsec_rl_strlog(ns, ip_mod_info.mi_idnum, 0, 0,
699bffb04cfSmarkfen 			    SL_WARN | SL_ERROR,
7007c478bd9Sstevel@tonic-gate 			    "ipsec_inbound_ah_sa: Small AH header\n");
701f4b3ec61Sdh 			IP_AH_BUMP_STAT(ipss, in_discards);
702bd670b35SErik Nordmark 			ip_drop_packet(mp, B_TRUE, ira->ira_ill,
703f4b3ec61Sdh 			    DROPPER(ipss, ipds_ah_bad_length),
704f4b3ec61Sdh 			    &ipss->ipsec_dropper);
7057c478bd9Sstevel@tonic-gate 			return (NULL);
7067c478bd9Sstevel@tonic-gate 		}
7077c478bd9Sstevel@tonic-gate 		if (isv6)
7087c478bd9Sstevel@tonic-gate 			ip6h = (ip6_t *)mp->b_rptr;
7097c478bd9Sstevel@tonic-gate 		else
7107c478bd9Sstevel@tonic-gate 			ipha = (ipha_t *)mp->b_rptr;
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	ah = (ah_t *)(mp->b_rptr + ah_offset);
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	if (isv6) {
7167c478bd9Sstevel@tonic-gate 		src_ptr = (uint32_t *)&ip6h->ip6_src;
7177c478bd9Sstevel@tonic-gate 		dst_ptr = (uint32_t *)&ip6h->ip6_dst;
718f4b3ec61Sdh 		sp = &ahstack->ah_sadb.s_v6;
7197c478bd9Sstevel@tonic-gate 		af = AF_INET6;
7207c478bd9Sstevel@tonic-gate 	} else {
7217c478bd9Sstevel@tonic-gate 		src_ptr = (uint32_t *)&ipha->ipha_src;
7227c478bd9Sstevel@tonic-gate 		dst_ptr = (uint32_t *)&ipha->ipha_dst;
723f4b3ec61Sdh 		sp = &ahstack->ah_sadb.s_v4;
7247c478bd9Sstevel@tonic-gate 		af = AF_INET;
7257c478bd9Sstevel@tonic-gate 	}
7267c478bd9Sstevel@tonic-gate 
727fb87b5d2Ssommerfe 	hptr = INBOUND_BUCKET(sp, ah->ah_spi);
7287c478bd9Sstevel@tonic-gate 	mutex_enter(&hptr->isaf_lock);
7297c478bd9Sstevel@tonic-gate 	assoc = ipsec_getassocbyspi(hptr, ah->ah_spi, src_ptr, dst_ptr, af);
7307c478bd9Sstevel@tonic-gate 	mutex_exit(&hptr->isaf_lock);
7317c478bd9Sstevel@tonic-gate 
7329c2c14abSThejaswini Singarajipura 	if (assoc == NULL || assoc->ipsa_state == IPSA_STATE_DEAD ||
7339c2c14abSThejaswini Singarajipura 	    assoc->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) {
734f4b3ec61Sdh 		IP_AH_BUMP_STAT(ipss, lookup_failure);
735f4b3ec61Sdh 		IP_AH_BUMP_STAT(ipss, in_discards);
736bd670b35SErik Nordmark 		ipsecah_in_assocfailure(mp, 0,
7377c478bd9Sstevel@tonic-gate 		    SL_ERROR | SL_CONSOLE | SL_WARN,
7387c478bd9Sstevel@tonic-gate 		    "ipsec_inbound_ah_sa: No association found for "
7397c478bd9Sstevel@tonic-gate 		    "spi 0x%x, dst addr %s\n",
740bd670b35SErik Nordmark 		    ah->ah_spi, dst_ptr, af, ira);
7417c478bd9Sstevel@tonic-gate 		if (assoc != NULL) {
7427c478bd9Sstevel@tonic-gate 			IPSA_REFRELE(assoc);
7437c478bd9Sstevel@tonic-gate 		}
7447c478bd9Sstevel@tonic-gate 		return (NULL);
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 
747*930af642SDan McDonald 	if (assoc->ipsa_state == IPSA_STATE_LARVAL) {
7487c478bd9Sstevel@tonic-gate 		/* Not fully baked; swap the packet under a rock until then */
749*930af642SDan McDonald 
750*930af642SDan McDonald 		mp = sadb_set_lpkt(assoc, mp, ira);
751*930af642SDan McDonald 		if (mp == NULL) {
752*930af642SDan McDonald 			IPSA_REFRELE(assoc);
753*930af642SDan McDonald 			return (NULL);
754*930af642SDan McDonald 		}
755*930af642SDan McDonald 		/* Looks like the SA is no longer LARVAL. */
7567c478bd9Sstevel@tonic-gate 	}
7577c478bd9Sstevel@tonic-gate 
758bd670b35SErik Nordmark 	/* Are the IPsec fields initialized at all? */
759bd670b35SErik Nordmark 	if (!(ira->ira_flags & IRAF_IPSEC_SECURE)) {
760bd670b35SErik Nordmark 		ira->ira_ipsec_action = NULL;
761bd670b35SErik Nordmark 		ira->ira_ipsec_ah_sa = NULL;
762bd670b35SErik Nordmark 		ira->ira_ipsec_esp_sa = NULL;
763bd670b35SErik Nordmark 	}
764bd670b35SErik Nordmark 
7657c478bd9Sstevel@tonic-gate 	/*
7667c478bd9Sstevel@tonic-gate 	 * Save a reference to the association so that it can
7677c478bd9Sstevel@tonic-gate 	 * be retrieved after execution. We free any AH SA reference
7687c478bd9Sstevel@tonic-gate 	 * already there (innermost SA "wins". The reference to
7697c478bd9Sstevel@tonic-gate 	 * the SA will also be used later when doing the policy checks.
7707c478bd9Sstevel@tonic-gate 	 */
771bd670b35SErik Nordmark 	if (ira->ira_ipsec_ah_sa != NULL) {
772bd670b35SErik Nordmark 		IPSA_REFRELE(ira->ira_ipsec_ah_sa);
7737c478bd9Sstevel@tonic-gate 	}
774bd670b35SErik Nordmark 	ira->ira_flags |= IRAF_IPSEC_SECURE;
775bd670b35SErik Nordmark 	ira->ira_ipsec_ah_sa = assoc;
7767c478bd9Sstevel@tonic-gate 
777bd670b35SErik Nordmark 	*ahp = ah;
778bd670b35SErik Nordmark 	return (mp);
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate 
781bd670b35SErik Nordmark /*
782bd670b35SErik Nordmark  * Can return a pulled up mblk.
783bd670b35SErik Nordmark  * When it returns non-NULL esphp is updated
784bd670b35SErik Nordmark  */
785bd670b35SErik Nordmark mblk_t *
ipsec_inbound_esp_sa(mblk_t * data_mp,ip_recv_attr_t * ira,esph_t ** esphp)786bd670b35SErik Nordmark ipsec_inbound_esp_sa(mblk_t *data_mp, ip_recv_attr_t *ira, esph_t **esphp)
7877c478bd9Sstevel@tonic-gate {
788bd670b35SErik Nordmark 	mblk_t *placeholder;
7897c478bd9Sstevel@tonic-gate 	uint32_t *src_ptr, *dst_ptr;
7907c478bd9Sstevel@tonic-gate 	ipha_t *ipha;
7917c478bd9Sstevel@tonic-gate 	ip6_t *ip6h;
7927c478bd9Sstevel@tonic-gate 	esph_t *esph;
7937c478bd9Sstevel@tonic-gate 	ipsa_t *ipsa;
7947c478bd9Sstevel@tonic-gate 	isaf_t *bucket;
7957c478bd9Sstevel@tonic-gate 	uint_t preamble;
7967c478bd9Sstevel@tonic-gate 	sa_family_t af;
7977c478bd9Sstevel@tonic-gate 	boolean_t isv6;
798fb87b5d2Ssommerfe 	sadb_t *sp;
799bd670b35SErik Nordmark 	netstack_t	*ns = ira->ira_ill->ill_ipst->ips_netstack;
800f4b3ec61Sdh 	ipsec_stack_t	*ipss = ns->netstack_ipsec;
801f4b3ec61Sdh 	ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
8027c478bd9Sstevel@tonic-gate 
803f4b3ec61Sdh 	IP_ESP_BUMP_STAT(ipss, in_requests);
8047c478bd9Sstevel@tonic-gate 
805bd670b35SErik Nordmark 	isv6 = !(ira->ira_flags & IRAF_IS_IPV4);
8067c478bd9Sstevel@tonic-gate 	if (isv6) {
8077c478bd9Sstevel@tonic-gate 		ip6h = (ip6_t *)data_mp->b_rptr;
8087c478bd9Sstevel@tonic-gate 	} else {
8097c478bd9Sstevel@tonic-gate 		ipha = (ipha_t *)data_mp->b_rptr;
8107c478bd9Sstevel@tonic-gate 	}
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	/*
8137c478bd9Sstevel@tonic-gate 	 * Put all data into one mblk if it's not there already.
8147c478bd9Sstevel@tonic-gate 	 * XXX This is probably bad long-term.  Figure out better ways of doing
8157c478bd9Sstevel@tonic-gate 	 * this.  Much of the inbound path depends on all of the data being
8167c478bd9Sstevel@tonic-gate 	 * in one mblk.
8177c478bd9Sstevel@tonic-gate 	 *
8187c478bd9Sstevel@tonic-gate 	 * XXX Jumbogram issues will have to be dealt with here.
8197c478bd9Sstevel@tonic-gate 	 * If the plen is 0, we'll have to scan for a HBH header with the
8207c478bd9Sstevel@tonic-gate 	 * actual packet length.
8217c478bd9Sstevel@tonic-gate 	 */
8227c478bd9Sstevel@tonic-gate 	if (data_mp->b_datap->db_ref > 1 ||
823bd670b35SErik Nordmark 	    (data_mp->b_wptr - data_mp->b_rptr) < ira->ira_pktlen) {
8247c478bd9Sstevel@tonic-gate 		placeholder = msgpullup(data_mp, -1);
8257c478bd9Sstevel@tonic-gate 		if (placeholder == NULL) {
826f4b3ec61Sdh 			IP_ESP_BUMP_STAT(ipss, in_discards);
827bd670b35SErik Nordmark 			ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
828f4b3ec61Sdh 			    DROPPER(ipss, ipds_esp_nomem),
829f4b3ec61Sdh 			    &ipss->ipsec_dropper);
8307c478bd9Sstevel@tonic-gate 			return (NULL);
8317c478bd9Sstevel@tonic-gate 		} else {
8327c478bd9Sstevel@tonic-gate 			/* Reset packet with new pulled up mblk. */
8337c478bd9Sstevel@tonic-gate 			freemsg(data_mp);
8347c478bd9Sstevel@tonic-gate 			data_mp = placeholder;
8357c478bd9Sstevel@tonic-gate 		}
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	/*
8397c478bd9Sstevel@tonic-gate 	 * Find the ESP header, point the address pointers at the appropriate
8407c478bd9Sstevel@tonic-gate 	 * IPv4/IPv6 places.
8417c478bd9Sstevel@tonic-gate 	 */
8427c478bd9Sstevel@tonic-gate 	if (isv6) {
8437c478bd9Sstevel@tonic-gate 		ip6h = (ip6_t *)data_mp->b_rptr;
8447c478bd9Sstevel@tonic-gate 		src_ptr = (uint32_t *)&ip6h->ip6_src;
8457c478bd9Sstevel@tonic-gate 		dst_ptr = (uint32_t *)&ip6h->ip6_dst;
8467c478bd9Sstevel@tonic-gate 		if (ip6h->ip6_nxt != IPPROTO_ESP) {
8477c478bd9Sstevel@tonic-gate 			/* There are options that need to be processed. */
8487c478bd9Sstevel@tonic-gate 			preamble = ip_hdr_length_v6(data_mp, ip6h);
8497c478bd9Sstevel@tonic-gate 		} else {
8507c478bd9Sstevel@tonic-gate 			preamble = sizeof (ip6_t);
8517c478bd9Sstevel@tonic-gate 		}
8527c478bd9Sstevel@tonic-gate 
853f4b3ec61Sdh 		sp = &espstack->esp_sadb.s_v6;
8547c478bd9Sstevel@tonic-gate 		af = AF_INET6;
8557c478bd9Sstevel@tonic-gate 	} else {
8567c478bd9Sstevel@tonic-gate 		ipha = (ipha_t *)data_mp->b_rptr;
8577c478bd9Sstevel@tonic-gate 		src_ptr = (uint32_t *)&ipha->ipha_src;
8587c478bd9Sstevel@tonic-gate 		dst_ptr = (uint32_t *)&ipha->ipha_dst;
8597c478bd9Sstevel@tonic-gate 		preamble = IPH_HDR_LENGTH(ipha);
8607c478bd9Sstevel@tonic-gate 
861f4b3ec61Sdh 		sp = &espstack->esp_sadb.s_v4;
8627c478bd9Sstevel@tonic-gate 		af = AF_INET;
8637c478bd9Sstevel@tonic-gate 	}
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	esph = (esph_t *)(data_mp->b_rptr + preamble);
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	/* Since hash is common on inbound (SPI value), hash here. */
868fb87b5d2Ssommerfe 	bucket = INBOUND_BUCKET(sp, esph->esph_spi);
8697c478bd9Sstevel@tonic-gate 	mutex_enter(&bucket->isaf_lock);
8707c478bd9Sstevel@tonic-gate 	ipsa = ipsec_getassocbyspi(bucket, esph->esph_spi, src_ptr, dst_ptr,
8717c478bd9Sstevel@tonic-gate 	    af);
8727c478bd9Sstevel@tonic-gate 	mutex_exit(&bucket->isaf_lock);
8737c478bd9Sstevel@tonic-gate 
8749c2c14abSThejaswini Singarajipura 	if (ipsa == NULL || ipsa->ipsa_state == IPSA_STATE_DEAD ||
8759c2c14abSThejaswini Singarajipura 	    ipsa->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) {
8767c478bd9Sstevel@tonic-gate 		/*  This is a loggable error!  AUDIT ME! */
877f4b3ec61Sdh 		IP_ESP_BUMP_STAT(ipss, lookup_failure);
878f4b3ec61Sdh 		IP_ESP_BUMP_STAT(ipss, in_discards);
879bd670b35SErik Nordmark 		ipsecesp_in_assocfailure(data_mp, 0,
8807c478bd9Sstevel@tonic-gate 		    SL_ERROR | SL_CONSOLE | SL_WARN,
8817c478bd9Sstevel@tonic-gate 		    "ipsec_inbound_esp_sa: No association found for "
8827c478bd9Sstevel@tonic-gate 		    "spi 0x%x, dst addr %s\n",
883bd670b35SErik Nordmark 		    esph->esph_spi, dst_ptr, af, ira);
8847c478bd9Sstevel@tonic-gate 		if (ipsa != NULL) {
8857c478bd9Sstevel@tonic-gate 			IPSA_REFRELE(ipsa);
8867c478bd9Sstevel@tonic-gate 		}
8877c478bd9Sstevel@tonic-gate 		return (NULL);
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 
890*930af642SDan McDonald 	if (ipsa->ipsa_state == IPSA_STATE_LARVAL) {
8917c478bd9Sstevel@tonic-gate 		/* Not fully baked; swap the packet under a rock until then */
892*930af642SDan McDonald 
893*930af642SDan McDonald 		data_mp = sadb_set_lpkt(ipsa, data_mp, ira);
894*930af642SDan McDonald 		if (data_mp == NULL) {
895*930af642SDan McDonald 			IPSA_REFRELE(ipsa);
896*930af642SDan McDonald 			return (NULL);
897*930af642SDan McDonald 		}
898*930af642SDan McDonald 		/* Looks like the SA is no longer LARVAL. */
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 
901bd670b35SErik Nordmark 	/* Are the IPsec fields initialized at all? */
902bd670b35SErik Nordmark 	if (!(ira->ira_flags & IRAF_IPSEC_SECURE)) {
903bd670b35SErik Nordmark 		ira->ira_ipsec_action = NULL;
904bd670b35SErik Nordmark 		ira->ira_ipsec_ah_sa = NULL;
905bd670b35SErik Nordmark 		ira->ira_ipsec_esp_sa = NULL;
906bd670b35SErik Nordmark 	}
907bd670b35SErik Nordmark 
9087c478bd9Sstevel@tonic-gate 	/*
9097c478bd9Sstevel@tonic-gate 	 * Save a reference to the association so that it can
9107c478bd9Sstevel@tonic-gate 	 * be retrieved after execution. We free any AH SA reference
9117c478bd9Sstevel@tonic-gate 	 * already there (innermost SA "wins". The reference to
9127c478bd9Sstevel@tonic-gate 	 * the SA will also be used later when doing the policy checks.
9137c478bd9Sstevel@tonic-gate 	 */
914bd670b35SErik Nordmark 	if (ira->ira_ipsec_esp_sa != NULL) {
915bd670b35SErik Nordmark 		IPSA_REFRELE(ira->ira_ipsec_esp_sa);
9167c478bd9Sstevel@tonic-gate 	}
917bd670b35SErik Nordmark 	ira->ira_flags |= IRAF_IPSEC_SECURE;
918bd670b35SErik Nordmark 	ira->ira_ipsec_esp_sa = ipsa;
9197c478bd9Sstevel@tonic-gate 
920bd670b35SErik Nordmark 	*esphp = esph;
921bd670b35SErik Nordmark 	return (data_mp);
9227c478bd9Sstevel@tonic-gate }
923