10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51659Smarkfen * Common Development and Distribution License (the "License"). 61659Smarkfen * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 221659Smarkfen * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/types.h> 290Sstevel@tonic-gate #include <sys/stream.h> 300Sstevel@tonic-gate #include <sys/sunddi.h> 31*3055Sdanmcd #include <sys/ddi.h> 320Sstevel@tonic-gate #include <sys/strlog.h> 330Sstevel@tonic-gate 340Sstevel@tonic-gate #include <inet/common.h> 350Sstevel@tonic-gate #include <inet/mib2.h> 360Sstevel@tonic-gate #include <inet/ip.h> 370Sstevel@tonic-gate #include <inet/ip6.h> 380Sstevel@tonic-gate #include <inet/ipdrop.h> 390Sstevel@tonic-gate 400Sstevel@tonic-gate #include <net/pfkeyv2.h> 410Sstevel@tonic-gate #include <inet/ipsec_info.h> 420Sstevel@tonic-gate #include <inet/sadb.h> 430Sstevel@tonic-gate #include <inet/ipsec_impl.h> 440Sstevel@tonic-gate #include <inet/ipsecesp.h> 450Sstevel@tonic-gate #include <inet/ipsecah.h> 460Sstevel@tonic-gate #include <sys/kstat.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate /* stats */ 490Sstevel@tonic-gate static kstat_t *ipsec_ksp; 500Sstevel@tonic-gate ipsec_kstats_t *ipsec_kstats; 510Sstevel@tonic-gate 520Sstevel@tonic-gate /* The IPsec SADBs for AH and ESP */ 530Sstevel@tonic-gate sadbp_t ah_sadb, esp_sadb; 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* Packet dropper for IP IPsec processing failures */ 560Sstevel@tonic-gate extern ipdropper_t ip_dropper; 570Sstevel@tonic-gate 580Sstevel@tonic-gate void 590Sstevel@tonic-gate ipsec_kstat_init(void) 600Sstevel@tonic-gate { 610Sstevel@tonic-gate ipsec_ksp = kstat_create("ip", 0, "ipsec_stat", "net", 620Sstevel@tonic-gate KSTAT_TYPE_NAMED, sizeof (*ipsec_kstats) / sizeof (kstat_named_t), 630Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT); 640Sstevel@tonic-gate 650Sstevel@tonic-gate ASSERT(ipsec_ksp != NULL); 660Sstevel@tonic-gate 670Sstevel@tonic-gate ipsec_kstats = ipsec_ksp->ks_data; 680Sstevel@tonic-gate 690Sstevel@tonic-gate #define KI(x) kstat_named_init(&ipsec_kstats->x, #x, KSTAT_DATA_UINT64) 700Sstevel@tonic-gate KI(esp_stat_in_requests); 710Sstevel@tonic-gate KI(esp_stat_in_discards); 720Sstevel@tonic-gate KI(esp_stat_lookup_failure); 730Sstevel@tonic-gate KI(ah_stat_in_requests); 740Sstevel@tonic-gate KI(ah_stat_in_discards); 750Sstevel@tonic-gate KI(ah_stat_lookup_failure); 761659Smarkfen KI(sadb_acquire_maxpackets); 771659Smarkfen KI(sadb_acquire_qhiwater); 780Sstevel@tonic-gate #undef KI 790Sstevel@tonic-gate 800Sstevel@tonic-gate kstat_install(ipsec_ksp); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate 830Sstevel@tonic-gate void 840Sstevel@tonic-gate ipsec_kstat_destroy(void) 850Sstevel@tonic-gate { 860Sstevel@tonic-gate kstat_delete(ipsec_ksp); 870Sstevel@tonic-gate } 880Sstevel@tonic-gate 890Sstevel@tonic-gate /* 900Sstevel@tonic-gate * Returns B_TRUE if the identities in the SA match the identities 910Sstevel@tonic-gate * in the "latch" structure. 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate 940Sstevel@tonic-gate static boolean_t 950Sstevel@tonic-gate ipsec_match_outbound_ids(ipsec_latch_t *ipl, ipsa_t *sa) 960Sstevel@tonic-gate { 970Sstevel@tonic-gate ASSERT(ipl->ipl_ids_latched == B_TRUE); 980Sstevel@tonic-gate return ipsid_equal(ipl->ipl_local_cid, sa->ipsa_src_cid) && 990Sstevel@tonic-gate ipsid_equal(ipl->ipl_remote_cid, sa->ipsa_dst_cid); 1000Sstevel@tonic-gate } 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate /* 1030Sstevel@tonic-gate * Look up a security association based on the unique ID generated by IP and 104*3055Sdanmcd * transport or tunnel information, such as ports and upper-layer protocol, 105*3055Sdanmcd * and the inner and outer address(es). Used for uniqueness testing and 106*3055Sdanmcd * outbound packets. The outer source address may be ignored. 1070Sstevel@tonic-gate * 1080Sstevel@tonic-gate * I expect an SA hash bucket, and that its per-bucket mutex is held. 1090Sstevel@tonic-gate * The SA ptr I return will have its reference count incremented by one. 1100Sstevel@tonic-gate */ 1110Sstevel@tonic-gate ipsa_t * 1120Sstevel@tonic-gate ipsec_getassocbyconn(isaf_t *bucket, ipsec_out_t *io, uint32_t *src, 1130Sstevel@tonic-gate uint32_t *dst, sa_family_t af, uint8_t protocol) 1140Sstevel@tonic-gate { 1150Sstevel@tonic-gate ipsa_t *retval, *candidate; 1160Sstevel@tonic-gate ipsec_action_t *candact; 1170Sstevel@tonic-gate boolean_t need_unique; 118*3055Sdanmcd boolean_t tunnel_mode = io->ipsec_out_tunnel; 1190Sstevel@tonic-gate uint64_t unique_id; 1200Sstevel@tonic-gate uint32_t old_flags, excludeflags; 1210Sstevel@tonic-gate ipsec_policy_t *pp = io->ipsec_out_policy; 1220Sstevel@tonic-gate ipsec_action_t *actlist = io->ipsec_out_act; 1230Sstevel@tonic-gate ipsec_action_t *act; 1240Sstevel@tonic-gate ipsec_latch_t *ipl = io->ipsec_out_latch; 1250Sstevel@tonic-gate ipsa_ref_t *ipr = NULL; 126*3055Sdanmcd sa_family_t inaf = io->ipsec_out_inaf; 127*3055Sdanmcd uint32_t *insrc = io->ipsec_out_insrc; 128*3055Sdanmcd uint32_t *indst = io->ipsec_out_indst; 129*3055Sdanmcd uint8_t insrcpfx = io->ipsec_out_insrcpfx; 130*3055Sdanmcd uint8_t indstpfx = io->ipsec_out_indstpfx; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bucket->isaf_lock)); 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate /* 135*3055Sdanmcd * Caller must set ipsec_out_t structure such that we know 136*3055Sdanmcd * whether this is tunnel mode or transport mode based on 137*3055Sdanmcd * io->ipsec_out_tunnel. If this flag is set, we assume that 138*3055Sdanmcd * there are valid inner src and destination addresses to compare. 139*3055Sdanmcd */ 140*3055Sdanmcd 141*3055Sdanmcd /* 1420Sstevel@tonic-gate * Fast path: do we have a latch structure, is it for this bucket, 1430Sstevel@tonic-gate * and does the generation number match? If so, refhold and return. 1440Sstevel@tonic-gate */ 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate if (ipl != NULL) { 1470Sstevel@tonic-gate ASSERT((protocol == IPPROTO_AH) || (protocol == IPPROTO_ESP)); 1480Sstevel@tonic-gate ipr = &ipl->ipl_ref[protocol - IPPROTO_ESP]; 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate retval = ipr->ipsr_sa; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate /* 1530Sstevel@tonic-gate * NOTE: The isaf_gen check (incremented upon 1540Sstevel@tonic-gate * sadb_unlinkassoc()) protects against retval being a freed 1550Sstevel@tonic-gate * SA. (We're exploiting short-circuit evaluation.) 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate if ((bucket == ipr->ipsr_bucket) && 1580Sstevel@tonic-gate (bucket->isaf_gen == ipr->ipsr_gen) && 1590Sstevel@tonic-gate (retval->ipsa_state != IPSA_STATE_DEAD) && 1600Sstevel@tonic-gate !(retval->ipsa_flags & IPSA_F_CINVALID)) { 1610Sstevel@tonic-gate IPSA_REFHOLD(retval); 1620Sstevel@tonic-gate return (retval); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate ASSERT((pp != NULL) || (actlist != NULL)); 1670Sstevel@tonic-gate if (actlist == NULL) 1680Sstevel@tonic-gate actlist = pp->ipsp_act; 1690Sstevel@tonic-gate ASSERT(actlist != NULL); 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate need_unique = actlist->ipa_want_unique; 1720Sstevel@tonic-gate unique_id = SA_FORM_UNIQUE_ID(io); 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate /* 1750Sstevel@tonic-gate * Precompute mask for SA flags comparison: If we need a 1760Sstevel@tonic-gate * unique SA and an SA has already been used, or if the SA has 1770Sstevel@tonic-gate * a unique value which doesn't match, we aren't interested in 1780Sstevel@tonic-gate * the SA.. 1790Sstevel@tonic-gate */ 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate excludeflags = IPSA_F_UNIQUE; 1820Sstevel@tonic-gate if (need_unique) 1830Sstevel@tonic-gate excludeflags |= IPSA_F_USED; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * Walk the hash bucket, matching on: 1870Sstevel@tonic-gate * 1880Sstevel@tonic-gate * - unique_id 1890Sstevel@tonic-gate * - destination 1900Sstevel@tonic-gate * - source 1910Sstevel@tonic-gate * - algorithms 192*3055Sdanmcd * - inner dst 193*3055Sdanmcd * - inner src 1940Sstevel@tonic-gate * - <MORE TBD> 1950Sstevel@tonic-gate * 1960Sstevel@tonic-gate * Make sure that wildcard sources are inserted at the end of the hash 1970Sstevel@tonic-gate * bucket. 1980Sstevel@tonic-gate * 1990Sstevel@tonic-gate * DEFINITIONS: A _shared_ SA is one with unique_id == 0 and USED. 2000Sstevel@tonic-gate * An _unused_ SA is one with unique_id == 0 and not USED. 2010Sstevel@tonic-gate * A _unique_ SA is one with unique_id != 0 and USED. 2020Sstevel@tonic-gate * An SA with unique_id != 0 and not USED never happens. 2030Sstevel@tonic-gate */ 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate candidate = NULL; 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate for (retval = bucket->isaf_ipsa; retval != NULL; 2080Sstevel@tonic-gate retval = retval->ipsa_next) { 2090Sstevel@tonic-gate ASSERT((candidate == NULL) || 2100Sstevel@tonic-gate MUTEX_HELD(&candidate->ipsa_lock)); 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate /* 2130Sstevel@tonic-gate * Q: Should I lock this SA? 2140Sstevel@tonic-gate * A: For now, yes. I change and use too many fields in here 2150Sstevel@tonic-gate * (e.g. unique_id) that I may be racing with other threads. 2160Sstevel@tonic-gate * Also, the refcnt needs to be bumped up. 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate mutex_enter(&retval->ipsa_lock); 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate /* My apologies for the use of goto instead of continue. */ 222*3055Sdanmcd 223*3055Sdanmcd /* Outer destination address */ 2240Sstevel@tonic-gate if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af)) 2250Sstevel@tonic-gate goto next_ipsa; /* Destination mismatch. */ 226*3055Sdanmcd 227*3055Sdanmcd /* Outer source address */ 2280Sstevel@tonic-gate if (!IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) && 2290Sstevel@tonic-gate !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) 2300Sstevel@tonic-gate goto next_ipsa; /* Specific source and not matched. */ 2310Sstevel@tonic-gate 232*3055Sdanmcd if (tunnel_mode) { 233*3055Sdanmcd /* Check tunnel mode */ 234*3055Sdanmcd if (!(retval->ipsa_flags & IPSA_F_TUNNEL)) 235*3055Sdanmcd goto next_ipsa; /* Not tunnel mode SA */ 236*3055Sdanmcd 237*3055Sdanmcd /* Inner destination address */ 238*3055Sdanmcd if (!IPSA_IS_ADDR_UNSPEC(retval->ipsa_innerdst, inaf)) { 239*3055Sdanmcd if (!ip_addr_match((uint8_t *)indst, 240*3055Sdanmcd min(indstpfx, retval->ipsa_innerdstpfx), 241*3055Sdanmcd (in6_addr_t *)retval->ipsa_innerdst)) 242*3055Sdanmcd goto next_ipsa; /* not matched. */ 243*3055Sdanmcd } 244*3055Sdanmcd 245*3055Sdanmcd /* Inner source address */ 246*3055Sdanmcd if (!IPSA_IS_ADDR_UNSPEC(retval->ipsa_innersrc, inaf)) { 247*3055Sdanmcd if (!ip_addr_match((uint8_t *)insrc, 248*3055Sdanmcd min(insrcpfx, retval->ipsa_innersrcpfx), 249*3055Sdanmcd (in6_addr_t *)retval->ipsa_innersrc)) 250*3055Sdanmcd goto next_ipsa; /* not matched. */ 251*3055Sdanmcd } 252*3055Sdanmcd } else { 253*3055Sdanmcd /* Check transport mode */ 254*3055Sdanmcd if (retval->ipsa_flags & IPSA_F_TUNNEL) 255*3055Sdanmcd goto next_ipsa; /* Not transport mode SA */ 256*3055Sdanmcd 257*3055Sdanmcd /* 258*3055Sdanmcd * TODO - If we ever do RFC 3884's dream of transport- 259*3055Sdanmcd * mode SAs with inner IP address selectors, we need 260*3055Sdanmcd * to put some code here. 261*3055Sdanmcd */ 262*3055Sdanmcd } 263*3055Sdanmcd 2640Sstevel@tonic-gate /* 2650Sstevel@tonic-gate * XXX should be able to use cached/latched action 2660Sstevel@tonic-gate * to dodge this loop 2670Sstevel@tonic-gate */ 2680Sstevel@tonic-gate for (act = actlist; act != NULL; act = act->ipa_next) { 2690Sstevel@tonic-gate ipsec_act_t *ap = &act->ipa_act; 2700Sstevel@tonic-gate if (ap->ipa_type != IPSEC_POLICY_APPLY) 2710Sstevel@tonic-gate continue; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* 2740Sstevel@tonic-gate * XXX ugly. should be better way to do this test 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate if (protocol == IPPROTO_AH) { 2770Sstevel@tonic-gate if (!(ap->ipa_apply.ipp_use_ah)) 2780Sstevel@tonic-gate continue; 2790Sstevel@tonic-gate if (ap->ipa_apply.ipp_auth_alg != 2800Sstevel@tonic-gate retval->ipsa_auth_alg) 2810Sstevel@tonic-gate continue; 2820Sstevel@tonic-gate if (ap->ipa_apply.ipp_ah_minbits > 2830Sstevel@tonic-gate retval->ipsa_authkeybits) 2840Sstevel@tonic-gate continue; 2850Sstevel@tonic-gate } else { 2860Sstevel@tonic-gate if (!(ap->ipa_apply.ipp_use_esp)) 2870Sstevel@tonic-gate continue; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate if ((ap->ipa_apply.ipp_encr_alg != 2900Sstevel@tonic-gate retval->ipsa_encr_alg)) 2910Sstevel@tonic-gate continue; 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate if (ap->ipa_apply.ipp_espe_minbits > 2940Sstevel@tonic-gate retval->ipsa_encrkeybits) 2950Sstevel@tonic-gate continue; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate if (ap->ipa_apply.ipp_esp_auth_alg != 0) { 2980Sstevel@tonic-gate if (ap->ipa_apply.ipp_esp_auth_alg != 2990Sstevel@tonic-gate retval->ipsa_auth_alg) 3000Sstevel@tonic-gate continue; 3010Sstevel@tonic-gate if (ap->ipa_apply.ipp_espa_minbits > 3020Sstevel@tonic-gate retval->ipsa_authkeybits) 3030Sstevel@tonic-gate continue; 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate /* 3080Sstevel@tonic-gate * Check key mgmt proto, cookie 3090Sstevel@tonic-gate */ 3100Sstevel@tonic-gate if ((ap->ipa_apply.ipp_km_proto != 0) && 3110Sstevel@tonic-gate (retval->ipsa_kmp != 0) && 3120Sstevel@tonic-gate (ap->ipa_apply.ipp_km_proto != retval->ipsa_kmp)) 3130Sstevel@tonic-gate continue; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate if ((ap->ipa_apply.ipp_km_cookie != 0) && 3160Sstevel@tonic-gate (retval->ipsa_kmc != 0) && 3170Sstevel@tonic-gate (ap->ipa_apply.ipp_km_cookie != retval->ipsa_kmc)) 3180Sstevel@tonic-gate continue; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate break; 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate if (act == NULL) 3230Sstevel@tonic-gate goto next_ipsa; /* nothing matched */ 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate /* 3260Sstevel@tonic-gate * Do identities match? 3270Sstevel@tonic-gate */ 3280Sstevel@tonic-gate if (ipl && ipl->ipl_ids_latched && 3290Sstevel@tonic-gate !ipsec_match_outbound_ids(ipl, retval)) 3300Sstevel@tonic-gate goto next_ipsa; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * At this point, we know that we have at least a match on: 3340Sstevel@tonic-gate * 3350Sstevel@tonic-gate * - dest 3360Sstevel@tonic-gate * - source (if source is specified, i.e. non-zeroes) 337*3055Sdanmcd * - inner dest (if specified) 338*3055Sdanmcd * - inner source (if specified) 3390Sstevel@tonic-gate * - auth alg (if auth alg is specified, i.e. non-zero) 3400Sstevel@tonic-gate * - encrypt. alg (if encrypt. alg is specified, i.e. non-zero) 3410Sstevel@tonic-gate * and we know that the SA keylengths are appropriate. 3420Sstevel@tonic-gate * 3430Sstevel@tonic-gate * (Keep in mind known-src SAs are hit before zero-src SAs, 3440Sstevel@tonic-gate * thanks to sadb_insertassoc().) 3450Sstevel@tonic-gate * If we need a unique asssociation, optimally we have 3460Sstevel@tonic-gate * ipsa_unique_id == unique_id, otherwise NOT USED 3470Sstevel@tonic-gate * is held in reserve (stored in candidate). 3480Sstevel@tonic-gate * 3490Sstevel@tonic-gate * For those stored in candidate, take best-match (i.e. given 3500Sstevel@tonic-gate * a choice, candidate should have non-zero ipsa_src). 3510Sstevel@tonic-gate */ 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate /* 3540Sstevel@tonic-gate * If SA has a unique value which matches, we're all set... 3550Sstevel@tonic-gate * "key management knows best" 3560Sstevel@tonic-gate */ 3570Sstevel@tonic-gate if ((retval->ipsa_flags & IPSA_F_UNIQUE) && 3580Sstevel@tonic-gate ((unique_id & retval->ipsa_unique_mask) == 3590Sstevel@tonic-gate retval->ipsa_unique_id)) 3600Sstevel@tonic-gate break; 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * If we need a unique SA and this SA has already been used, 3640Sstevel@tonic-gate * or if the SA has a unique value which doesn't match, 3650Sstevel@tonic-gate * this isn't for us. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate if (retval->ipsa_flags & excludeflags) 3690Sstevel@tonic-gate goto next_ipsa; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate /* 3730Sstevel@tonic-gate * I found a candidate.. 3740Sstevel@tonic-gate */ 3750Sstevel@tonic-gate if (candidate == NULL) { 3760Sstevel@tonic-gate /* 3770Sstevel@tonic-gate * and didn't already have one.. 3780Sstevel@tonic-gate */ 3790Sstevel@tonic-gate candidate = retval; 3800Sstevel@tonic-gate candact = act; 3810Sstevel@tonic-gate continue; 3820Sstevel@tonic-gate } else { 3830Sstevel@tonic-gate /* 3840Sstevel@tonic-gate * If candidate's source address is zero and 3850Sstevel@tonic-gate * the current match (i.e. retval) address is 3860Sstevel@tonic-gate * not zero, we have a better candidate.. 3870Sstevel@tonic-gate */ 3880Sstevel@tonic-gate if (IPSA_IS_ADDR_UNSPEC(candidate->ipsa_srcaddr, af) && 3890Sstevel@tonic-gate !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) { 3900Sstevel@tonic-gate mutex_exit(&candidate->ipsa_lock); 3910Sstevel@tonic-gate candidate = retval; 3920Sstevel@tonic-gate candact = act; 3930Sstevel@tonic-gate continue; 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate next_ipsa: 3970Sstevel@tonic-gate mutex_exit(&retval->ipsa_lock); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate ASSERT((retval == NULL) || MUTEX_HELD(&retval->ipsa_lock)); 4000Sstevel@tonic-gate ASSERT((candidate == NULL) || MUTEX_HELD(&candidate->ipsa_lock)); 4010Sstevel@tonic-gate ASSERT((retval == NULL) || (act != NULL)); 4020Sstevel@tonic-gate ASSERT((candidate == NULL) || (candact != NULL)); 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate /* Let caller react to a lookup failure when it gets NULL. */ 4050Sstevel@tonic-gate if (retval == NULL && candidate == NULL) 4060Sstevel@tonic-gate return (NULL); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate if (retval == NULL) { 4090Sstevel@tonic-gate ASSERT(MUTEX_HELD(&candidate->ipsa_lock)); 4100Sstevel@tonic-gate retval = candidate; 4110Sstevel@tonic-gate act = candact; 4120Sstevel@tonic-gate } else if (candidate != NULL) { 4130Sstevel@tonic-gate mutex_exit(&candidate->ipsa_lock); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate ASSERT(MUTEX_HELD(&retval->ipsa_lock)); 4160Sstevel@tonic-gate ASSERT(act != NULL); 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate /* 4190Sstevel@tonic-gate * Even though I hold the mutex, since the reference counter is an 4200Sstevel@tonic-gate * atomic operation, I really have to use the IPSA_REFHOLD macro. 4210Sstevel@tonic-gate */ 4220Sstevel@tonic-gate IPSA_REFHOLD(retval); 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate /* 4250Sstevel@tonic-gate * This association is no longer unused. 4260Sstevel@tonic-gate */ 4270Sstevel@tonic-gate old_flags = retval->ipsa_flags; 4280Sstevel@tonic-gate retval->ipsa_flags |= IPSA_F_USED; 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate /* 4310Sstevel@tonic-gate * Cache a reference to this SA for the fast path. 4320Sstevel@tonic-gate */ 4330Sstevel@tonic-gate if (ipr != NULL) { 4340Sstevel@tonic-gate ipr->ipsr_bucket = bucket; 4350Sstevel@tonic-gate ipr->ipsr_gen = bucket->isaf_gen; 4360Sstevel@tonic-gate ipr->ipsr_sa = retval; 4370Sstevel@tonic-gate /* I'm now caching, so the cache-invalid flag goes away! */ 4380Sstevel@tonic-gate retval->ipsa_flags &= ~IPSA_F_CINVALID; 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate /* 4410Sstevel@tonic-gate * Latch various things while we're here.. 4420Sstevel@tonic-gate */ 4430Sstevel@tonic-gate if (ipl != NULL) { 4440Sstevel@tonic-gate if (!ipl->ipl_ids_latched) { 4450Sstevel@tonic-gate ipsec_latch_ids(ipl, 4460Sstevel@tonic-gate retval->ipsa_src_cid, retval->ipsa_dst_cid); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate if (!ipl->ipl_out_action_latched) { 4490Sstevel@tonic-gate IPACT_REFHOLD(act); 4500Sstevel@tonic-gate ipl->ipl_out_action = act; 4510Sstevel@tonic-gate ipl->ipl_out_action_latched = B_TRUE; 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* 4560Sstevel@tonic-gate * Set the uniqueness only first time. 4570Sstevel@tonic-gate */ 4580Sstevel@tonic-gate if (need_unique && !(old_flags & IPSA_F_USED)) { 4590Sstevel@tonic-gate if (retval->ipsa_unique_id == 0) { 4600Sstevel@tonic-gate ASSERT((retval->ipsa_flags & IPSA_F_UNIQUE) == 0); 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * From now on, only this src, dst[ports, addr], 4630Sstevel@tonic-gate * proto, should use it. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate retval->ipsa_flags |= IPSA_F_UNIQUE; 4660Sstevel@tonic-gate retval->ipsa_unique_id = unique_id; 4670Sstevel@tonic-gate retval->ipsa_unique_mask = SA_UNIQUE_MASK( 4680Sstevel@tonic-gate io->ipsec_out_src_port, io->ipsec_out_dst_port, 469*3055Sdanmcd protocol, 0); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate /* 4730Sstevel@tonic-gate * Set the source address and adjust the hash 4740Sstevel@tonic-gate * buckets only if src_addr is zero. 4750Sstevel@tonic-gate */ 4760Sstevel@tonic-gate if (IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) { 4770Sstevel@tonic-gate /* 4780Sstevel@tonic-gate * sadb_unlinkassoc() will decrement the refcnt. Bump 4790Sstevel@tonic-gate * up when we have the lock so that we don't have to 4800Sstevel@tonic-gate * acquire locks when we come back from 4810Sstevel@tonic-gate * sadb_insertassoc(). 4820Sstevel@tonic-gate * 4830Sstevel@tonic-gate * We don't need to bump the bucket's gen since 4840Sstevel@tonic-gate * we aren't moving to a new bucket. 4850Sstevel@tonic-gate */ 4860Sstevel@tonic-gate IPSA_REFHOLD(retval); 4870Sstevel@tonic-gate IPSA_COPY_ADDR(retval->ipsa_srcaddr, src, af); 4880Sstevel@tonic-gate mutex_exit(&retval->ipsa_lock); 4890Sstevel@tonic-gate sadb_unlinkassoc(retval); 4900Sstevel@tonic-gate /* 4910Sstevel@tonic-gate * Since the bucket lock is held, we know 4920Sstevel@tonic-gate * sadb_insertassoc() will succeed. 4930Sstevel@tonic-gate */ 4940Sstevel@tonic-gate #ifdef DEBUG 4950Sstevel@tonic-gate if (sadb_insertassoc(retval, bucket) != 0) { 4960Sstevel@tonic-gate cmn_err(CE_PANIC, 4970Sstevel@tonic-gate "sadb_insertassoc() failed in " 4980Sstevel@tonic-gate "ipsec_getassocbyconn().\n"); 4990Sstevel@tonic-gate } 5000Sstevel@tonic-gate #else /* non-DEBUG */ 5010Sstevel@tonic-gate (void) sadb_insertassoc(retval, bucket); 5020Sstevel@tonic-gate #endif /* DEBUG */ 5030Sstevel@tonic-gate return (retval); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate mutex_exit(&retval->ipsa_lock); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate return (retval); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * Look up a security association based on the security parameters index (SPI) 5130Sstevel@tonic-gate * and address(es). This is used for inbound packets and general SA lookups 5140Sstevel@tonic-gate * (even in outbound SA tables). The source address may be ignored. Return 5150Sstevel@tonic-gate * NULL if no association is available. If an SA is found, return it, with 5160Sstevel@tonic-gate * its refcnt incremented. The caller must REFRELE after using the SA. 5170Sstevel@tonic-gate * The hash bucket must be locked down before calling. 5180Sstevel@tonic-gate */ 5190Sstevel@tonic-gate ipsa_t * 5200Sstevel@tonic-gate ipsec_getassocbyspi(isaf_t *bucket, uint32_t spi, uint32_t *src, uint32_t *dst, 5210Sstevel@tonic-gate sa_family_t af) 5220Sstevel@tonic-gate { 5230Sstevel@tonic-gate ipsa_t *retval; 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bucket->isaf_lock)); 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate /* 5280Sstevel@tonic-gate * Walk the hash bucket, matching exactly on SPI, then destination, 5290Sstevel@tonic-gate * then source. 5300Sstevel@tonic-gate * 5310Sstevel@tonic-gate * Per-SA locking doesn't need to happen, because I'm only matching 5320Sstevel@tonic-gate * on addresses. Addresses are only changed during insertion/deletion 5330Sstevel@tonic-gate * from the hash bucket. Since the hash bucket lock is held, we don't 5340Sstevel@tonic-gate * need to worry about addresses changing. 5350Sstevel@tonic-gate */ 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate for (retval = bucket->isaf_ipsa; retval != NULL; 5380Sstevel@tonic-gate retval = retval->ipsa_next) { 5390Sstevel@tonic-gate if (retval->ipsa_spi != spi) 5400Sstevel@tonic-gate continue; 5410Sstevel@tonic-gate if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af)) 5420Sstevel@tonic-gate continue; 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* 5450Sstevel@tonic-gate * Assume that wildcard source addresses are inserted at the 5460Sstevel@tonic-gate * end of the hash bucket. (See sadb_insertassoc().) 5470Sstevel@tonic-gate * The following check for source addresses is a weak form 5480Sstevel@tonic-gate * of access control/source identity verification. If an 5490Sstevel@tonic-gate * SA has a source address, I only match an all-zeroes 5500Sstevel@tonic-gate * source address, or that particular one. If the SA has 5510Sstevel@tonic-gate * an all-zeroes source, then I match regardless. 5520Sstevel@tonic-gate * 5530Sstevel@tonic-gate * There is a weakness here in that a packet with all-zeroes 5540Sstevel@tonic-gate * for an address will match regardless of the source address 5550Sstevel@tonic-gate * stored in the packet. 556691Ssommerfe * 557691Ssommerfe * Note that port-level packet selectors, if present, 558691Ssommerfe * are checked in ipsec_check_ipsecin_unique(). 5590Sstevel@tonic-gate */ 5600Sstevel@tonic-gate if (IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) || 5610Sstevel@tonic-gate IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af) || 5620Sstevel@tonic-gate IPSA_IS_ADDR_UNSPEC(src, af)) 5630Sstevel@tonic-gate break; 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate if (retval != NULL) { 5670Sstevel@tonic-gate /* 5680Sstevel@tonic-gate * Just refhold the return value. The caller will then 5690Sstevel@tonic-gate * make the appropriate calls to set the USED flag. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate IPSA_REFHOLD(retval); 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate return (retval); 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate boolean_t 5780Sstevel@tonic-gate ipsec_outbound_sa(mblk_t *mp, uint_t proto) 5790Sstevel@tonic-gate { 5800Sstevel@tonic-gate mblk_t *data_mp; 5810Sstevel@tonic-gate ipsec_out_t *io; 5820Sstevel@tonic-gate ipaddr_t dst; 5830Sstevel@tonic-gate uint32_t *dst_ptr, *src_ptr; 5840Sstevel@tonic-gate isaf_t *bucket; 5850Sstevel@tonic-gate ipsa_t *assoc; 5860Sstevel@tonic-gate ip6_pkt_t ipp; 5870Sstevel@tonic-gate in6_addr_t dst6; 5880Sstevel@tonic-gate ipsa_t **sa; 5890Sstevel@tonic-gate sadbp_t *sadbp; 590564Ssommerfe sadb_t *sp; 5910Sstevel@tonic-gate sa_family_t af; 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate data_mp = mp->b_cont; 5940Sstevel@tonic-gate io = (ipsec_out_t *)mp->b_rptr; 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate if (proto == IPPROTO_ESP) { 5970Sstevel@tonic-gate sa = &io->ipsec_out_esp_sa; 5980Sstevel@tonic-gate sadbp = &esp_sadb; 5990Sstevel@tonic-gate } else { 6000Sstevel@tonic-gate ASSERT(proto == IPPROTO_AH); 6010Sstevel@tonic-gate sa = &io->ipsec_out_ah_sa; 6020Sstevel@tonic-gate sadbp = &ah_sadb; 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate ASSERT(*sa == NULL); 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate if (io->ipsec_out_v4) { 6080Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION); 6110Sstevel@tonic-gate dst = ip_get_dst(ipha); 612564Ssommerfe sp = &sadbp->s_v4; 6130Sstevel@tonic-gate af = AF_INET; 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate /* 6160Sstevel@tonic-gate * NOTE:Getting the outbound association is considerably 6170Sstevel@tonic-gate * painful. ipsec_getassocbyconn() will require more 6180Sstevel@tonic-gate * parameters as policy implementations mature. 6190Sstevel@tonic-gate */ 620564Ssommerfe bucket = OUTBOUND_BUCKET_V4(sp, dst); 6210Sstevel@tonic-gate src_ptr = (uint32_t *)&ipha->ipha_src; 6220Sstevel@tonic-gate dst_ptr = (uint32_t *)&dst; 6230Sstevel@tonic-gate } else { 6240Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)data_mp->b_rptr; 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION); 6270Sstevel@tonic-gate dst6 = ip_get_dst_v6(ip6h, NULL); 6280Sstevel@tonic-gate af = AF_INET6; 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate bzero(&ipp, sizeof (ipp)); 631564Ssommerfe sp = &sadbp->s_v6; 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate /* Same NOTE: applies here! */ 634564Ssommerfe bucket = OUTBOUND_BUCKET_V6(sp, dst6); 6350Sstevel@tonic-gate src_ptr = (uint32_t *)&ip6h->ip6_src; 6360Sstevel@tonic-gate dst_ptr = (uint32_t *)&dst6; 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 6400Sstevel@tonic-gate assoc = ipsec_getassocbyconn(bucket, io, src_ptr, dst_ptr, af, proto); 6410Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate if (assoc == NULL) 6440Sstevel@tonic-gate return (B_FALSE); 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate if (assoc->ipsa_state == IPSA_STATE_DEAD) { 6470Sstevel@tonic-gate IPSA_REFRELE(assoc); 6480Sstevel@tonic-gate return (B_FALSE); 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate ASSERT(assoc->ipsa_state != IPSA_STATE_LARVAL); 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate *sa = assoc; 6540Sstevel@tonic-gate return (B_TRUE); 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate /* 6580Sstevel@tonic-gate * Inbound IPsec SA selection. 6590Sstevel@tonic-gate */ 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate ah_t * 6620Sstevel@tonic-gate ipsec_inbound_ah_sa(mblk_t *mp) 6630Sstevel@tonic-gate { 6640Sstevel@tonic-gate mblk_t *ipsec_in; 6650Sstevel@tonic-gate ipha_t *ipha; 6660Sstevel@tonic-gate ipsa_t *assoc; 6670Sstevel@tonic-gate ah_t *ah; 6680Sstevel@tonic-gate isaf_t *hptr; 6690Sstevel@tonic-gate ipsec_in_t *ii; 6700Sstevel@tonic-gate boolean_t isv6; 6710Sstevel@tonic-gate ip6_t *ip6h; 6720Sstevel@tonic-gate int ah_offset; 6730Sstevel@tonic-gate uint32_t *src_ptr, *dst_ptr; 6740Sstevel@tonic-gate int pullup_len; 675564Ssommerfe sadb_t *sp; 6760Sstevel@tonic-gate sa_family_t af; 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate IP_AH_BUMP_STAT(in_requests); 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate ASSERT(mp->b_datap->db_type == M_CTL); 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate ipsec_in = mp; 6830Sstevel@tonic-gate ii = (ipsec_in_t *)ipsec_in->b_rptr; 6840Sstevel@tonic-gate mp = mp->b_cont; 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate ASSERT(mp->b_datap->db_type == M_DATA); 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate isv6 = !ii->ipsec_in_v4; 6890Sstevel@tonic-gate if (isv6) { 6900Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 6910Sstevel@tonic-gate ah_offset = ipsec_ah_get_hdr_size_v6(mp, B_TRUE); 6920Sstevel@tonic-gate } else { 6930Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 6940Sstevel@tonic-gate ASSERT(ipha->ipha_protocol == IPPROTO_AH); 6950Sstevel@tonic-gate ah_offset = ipha->ipha_version_and_hdr_length - 6960Sstevel@tonic-gate (uint8_t)((IP_VERSION << 4)); 6970Sstevel@tonic-gate ah_offset <<= 2; 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * We assume that the IP header is pulled up until 7020Sstevel@tonic-gate * the options. We need to see whether we have the 7030Sstevel@tonic-gate * AH header in the same mblk or not. 7040Sstevel@tonic-gate */ 7050Sstevel@tonic-gate pullup_len = ah_offset + sizeof (ah_t); 7060Sstevel@tonic-gate if (mp->b_rptr + pullup_len > mp->b_wptr) { 7070Sstevel@tonic-gate if (!pullupmsg(mp, pullup_len)) { 7081659Smarkfen ipsec_rl_strlog(ip_mod_info.mi_idnum, 0, 0, 7091659Smarkfen SL_WARN | SL_ERROR, 7100Sstevel@tonic-gate "ipsec_inbound_ah_sa: Small AH header\n"); 7110Sstevel@tonic-gate IP_AH_BUMP_STAT(in_discards); 7120Sstevel@tonic-gate ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, 7130Sstevel@tonic-gate &ipdrops_ah_bad_length, &ip_dropper); 7140Sstevel@tonic-gate return (NULL); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate if (isv6) 7170Sstevel@tonic-gate ip6h = (ip6_t *)mp->b_rptr; 7180Sstevel@tonic-gate else 7190Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate ah = (ah_t *)(mp->b_rptr + ah_offset); 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate if (isv6) { 7250Sstevel@tonic-gate src_ptr = (uint32_t *)&ip6h->ip6_src; 7260Sstevel@tonic-gate dst_ptr = (uint32_t *)&ip6h->ip6_dst; 727564Ssommerfe sp = &ah_sadb.s_v6; 7280Sstevel@tonic-gate af = AF_INET6; 7290Sstevel@tonic-gate } else { 7300Sstevel@tonic-gate src_ptr = (uint32_t *)&ipha->ipha_src; 7310Sstevel@tonic-gate dst_ptr = (uint32_t *)&ipha->ipha_dst; 732564Ssommerfe sp = &ah_sadb.s_v4; 7330Sstevel@tonic-gate af = AF_INET; 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate 736564Ssommerfe hptr = INBOUND_BUCKET(sp, ah->ah_spi); 7370Sstevel@tonic-gate mutex_enter(&hptr->isaf_lock); 7380Sstevel@tonic-gate assoc = ipsec_getassocbyspi(hptr, ah->ah_spi, src_ptr, dst_ptr, af); 7390Sstevel@tonic-gate mutex_exit(&hptr->isaf_lock); 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate if (assoc == NULL || assoc->ipsa_state == IPSA_STATE_DEAD) { 7420Sstevel@tonic-gate IP_AH_BUMP_STAT(lookup_failure); 7430Sstevel@tonic-gate IP_AH_BUMP_STAT(in_discards); 7440Sstevel@tonic-gate ipsecah_in_assocfailure(ipsec_in, 0, 7450Sstevel@tonic-gate SL_ERROR | SL_CONSOLE | SL_WARN, 7460Sstevel@tonic-gate "ipsec_inbound_ah_sa: No association found for " 7470Sstevel@tonic-gate "spi 0x%x, dst addr %s\n", 7480Sstevel@tonic-gate ah->ah_spi, dst_ptr, af); 7490Sstevel@tonic-gate if (assoc != NULL) { 7500Sstevel@tonic-gate IPSA_REFRELE(assoc); 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate return (NULL); 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate if (assoc->ipsa_state == IPSA_STATE_LARVAL) { 7560Sstevel@tonic-gate /* Not fully baked; swap the packet under a rock until then */ 7570Sstevel@tonic-gate sadb_set_lpkt(assoc, ipsec_in); 7580Sstevel@tonic-gate IPSA_REFRELE(assoc); 7590Sstevel@tonic-gate return (NULL); 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate /* 7630Sstevel@tonic-gate * Save a reference to the association so that it can 7640Sstevel@tonic-gate * be retrieved after execution. We free any AH SA reference 7650Sstevel@tonic-gate * already there (innermost SA "wins". The reference to 7660Sstevel@tonic-gate * the SA will also be used later when doing the policy checks. 7670Sstevel@tonic-gate */ 7680Sstevel@tonic-gate if (ii->ipsec_in_ah_sa != NULL) { 7690Sstevel@tonic-gate IPSA_REFRELE(ii->ipsec_in_ah_sa); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate ii->ipsec_in_ah_sa = assoc; 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate return (ah); 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate esph_t * 7770Sstevel@tonic-gate ipsec_inbound_esp_sa(mblk_t *ipsec_in_mp) 7780Sstevel@tonic-gate { 7790Sstevel@tonic-gate mblk_t *data_mp, *placeholder; 7800Sstevel@tonic-gate uint32_t *src_ptr, *dst_ptr; 7810Sstevel@tonic-gate ipsec_in_t *ii; 7820Sstevel@tonic-gate ipha_t *ipha; 7830Sstevel@tonic-gate ip6_t *ip6h; 7840Sstevel@tonic-gate esph_t *esph; 7850Sstevel@tonic-gate ipsa_t *ipsa; 7860Sstevel@tonic-gate isaf_t *bucket; 7870Sstevel@tonic-gate uint_t preamble; 7880Sstevel@tonic-gate sa_family_t af; 7890Sstevel@tonic-gate boolean_t isv6; 790564Ssommerfe sadb_t *sp; 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_requests); 7930Sstevel@tonic-gate ASSERT(ipsec_in_mp->b_datap->db_type == M_CTL); 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate /* We have IPSEC_IN already! */ 7960Sstevel@tonic-gate ii = (ipsec_in_t *)ipsec_in_mp->b_rptr; 7970Sstevel@tonic-gate data_mp = ipsec_in_mp->b_cont; 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate ASSERT(ii->ipsec_in_type == IPSEC_IN); 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate isv6 = !ii->ipsec_in_v4; 8020Sstevel@tonic-gate if (isv6) { 8030Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 8040Sstevel@tonic-gate } else { 8050Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate /* 8090Sstevel@tonic-gate * Put all data into one mblk if it's not there already. 8100Sstevel@tonic-gate * XXX This is probably bad long-term. Figure out better ways of doing 8110Sstevel@tonic-gate * this. Much of the inbound path depends on all of the data being 8120Sstevel@tonic-gate * in one mblk. 8130Sstevel@tonic-gate * 8140Sstevel@tonic-gate * XXX Jumbogram issues will have to be dealt with here. 8150Sstevel@tonic-gate * If the plen is 0, we'll have to scan for a HBH header with the 8160Sstevel@tonic-gate * actual packet length. 8170Sstevel@tonic-gate */ 8180Sstevel@tonic-gate if (data_mp->b_datap->db_ref > 1 || 8190Sstevel@tonic-gate (data_mp->b_wptr - data_mp->b_rptr) < 8200Sstevel@tonic-gate (isv6 ? (ntohs(ip6h->ip6_plen) + sizeof (ip6_t)) 8210Sstevel@tonic-gate : ntohs(ipha->ipha_length))) { 8220Sstevel@tonic-gate placeholder = msgpullup(data_mp, -1); 8230Sstevel@tonic-gate if (placeholder == NULL) { 8240Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 8250Sstevel@tonic-gate /* 8260Sstevel@tonic-gate * TODO: Extract inbound interface from the IPSEC_IN 8270Sstevel@tonic-gate * message's ii->ipsec_in_rill_index. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, 8300Sstevel@tonic-gate &ipdrops_esp_nomem, &ip_dropper); 8310Sstevel@tonic-gate return (NULL); 8320Sstevel@tonic-gate } else { 8330Sstevel@tonic-gate /* Reset packet with new pulled up mblk. */ 8340Sstevel@tonic-gate freemsg(data_mp); 8350Sstevel@tonic-gate data_mp = placeholder; 8360Sstevel@tonic-gate ipsec_in_mp->b_cont = data_mp; 8370Sstevel@tonic-gate } 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate /* 8410Sstevel@tonic-gate * Find the ESP header, point the address pointers at the appropriate 8420Sstevel@tonic-gate * IPv4/IPv6 places. 8430Sstevel@tonic-gate */ 8440Sstevel@tonic-gate if (isv6) { 8450Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 8460Sstevel@tonic-gate src_ptr = (uint32_t *)&ip6h->ip6_src; 8470Sstevel@tonic-gate dst_ptr = (uint32_t *)&ip6h->ip6_dst; 8480Sstevel@tonic-gate if (ip6h->ip6_nxt != IPPROTO_ESP) { 8490Sstevel@tonic-gate /* There are options that need to be processed. */ 8500Sstevel@tonic-gate preamble = ip_hdr_length_v6(data_mp, ip6h); 8510Sstevel@tonic-gate } else { 8520Sstevel@tonic-gate preamble = sizeof (ip6_t); 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate 855564Ssommerfe sp = &esp_sadb.s_v6; 8560Sstevel@tonic-gate af = AF_INET6; 8570Sstevel@tonic-gate } else { 8580Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; 8590Sstevel@tonic-gate src_ptr = (uint32_t *)&ipha->ipha_src; 8600Sstevel@tonic-gate dst_ptr = (uint32_t *)&ipha->ipha_dst; 8610Sstevel@tonic-gate preamble = IPH_HDR_LENGTH(ipha); 8620Sstevel@tonic-gate 863564Ssommerfe sp = &esp_sadb.s_v4; 8640Sstevel@tonic-gate af = AF_INET; 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate esph = (esph_t *)(data_mp->b_rptr + preamble); 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate /* Since hash is common on inbound (SPI value), hash here. */ 870564Ssommerfe bucket = INBOUND_BUCKET(sp, esph->esph_spi); 8710Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 8720Sstevel@tonic-gate ipsa = ipsec_getassocbyspi(bucket, esph->esph_spi, src_ptr, dst_ptr, 8730Sstevel@tonic-gate af); 8740Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate if (ipsa == NULL || ipsa->ipsa_state == IPSA_STATE_DEAD) { 8770Sstevel@tonic-gate /* This is a loggable error! AUDIT ME! */ 8780Sstevel@tonic-gate IP_ESP_BUMP_STAT(lookup_failure); 8790Sstevel@tonic-gate IP_ESP_BUMP_STAT(in_discards); 8800Sstevel@tonic-gate ipsecesp_in_assocfailure(ipsec_in_mp, 0, 8810Sstevel@tonic-gate SL_ERROR | SL_CONSOLE | SL_WARN, 8820Sstevel@tonic-gate "ipsec_inbound_esp_sa: No association found for " 8830Sstevel@tonic-gate "spi 0x%x, dst addr %s\n", 8840Sstevel@tonic-gate esph->esph_spi, dst_ptr, af); 8850Sstevel@tonic-gate if (ipsa != NULL) { 8860Sstevel@tonic-gate IPSA_REFRELE(ipsa); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate return (NULL); 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate if (ipsa->ipsa_state == IPSA_STATE_LARVAL) { 8920Sstevel@tonic-gate /* Not fully baked; swap the packet under a rock until then */ 8930Sstevel@tonic-gate sadb_set_lpkt(ipsa, ipsec_in_mp); 8940Sstevel@tonic-gate IPSA_REFRELE(ipsa); 8950Sstevel@tonic-gate return (NULL); 8960Sstevel@tonic-gate } 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate /* 8990Sstevel@tonic-gate * Save a reference to the association so that it can 9000Sstevel@tonic-gate * be retrieved after execution. We free any AH SA reference 9010Sstevel@tonic-gate * already there (innermost SA "wins". The reference to 9020Sstevel@tonic-gate * the SA will also be used later when doing the policy checks. 9030Sstevel@tonic-gate */ 9040Sstevel@tonic-gate if (ii->ipsec_in_esp_sa != NULL) { 9050Sstevel@tonic-gate IPSA_REFRELE(ii->ipsec_in_esp_sa); 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate ii->ipsec_in_esp_sa = ipsa; 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate return (esph); 9100Sstevel@tonic-gate } 911