Unleashed v1.4
[unleashed.git] / kernel / net / ip / ip_sadb.c
blobcc158a2a19d7fbfd5a0d755d5e969d02b4840d14
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/stream.h>
28 #include <sys/strsubr.h>
29 #include <sys/sunddi.h>
30 #include <sys/ddi.h>
31 #include <sys/strlog.h>
33 #include <inet/common.h>
34 #include <inet/mib2.h>
35 #include <inet/ip.h>
36 #include <inet/ip6.h>
38 #include <net/pfkeyv2.h>
39 #include <inet/sadb.h>
40 #include <inet/ipsec_impl.h>
41 #include <inet/ipdrop.h>
42 #include <inet/ipsecesp.h>
43 #include <inet/ipsecah.h>
44 #include <sys/kstat.h>
47 * Returns B_TRUE if the identities in the SA match the identities
48 * in the "latch" structure.
51 static boolean_t
52 ipsec_match_outbound_ids(ipsec_latch_t *ipl, ipsa_t *sa)
54 ASSERT(ipl->ipl_ids_latched == B_TRUE);
55 return ipsid_equal(ipl->ipl_local_cid, sa->ipsa_src_cid) &&
56 ipsid_equal(ipl->ipl_remote_cid, sa->ipsa_dst_cid);
60 * Look up a security association based on the unique ID generated by IP and
61 * transport or tunnel information, such as ports and upper-layer protocol,
62 * and the inner and outer address(es). Used for uniqueness testing and
63 * outbound packets. The outer source address may be ignored.
65 * I expect an SA hash bucket, and that its per-bucket mutex is held.
66 * The SA ptr I return will have its reference count incremented by one.
68 ipsa_t *
69 ipsec_getassocbyconn(isaf_t *bucket, ip_xmit_attr_t *ixa, uint32_t *src,
70 uint32_t *dst, sa_family_t af, uint8_t protocol)
72 ipsa_t *retval, *candidate;
73 ipsec_action_t *candact;
74 boolean_t need_unique;
75 boolean_t tunnel_mode = (ixa->ixa_flags & IXAF_IPSEC_TUNNEL);
76 uint64_t unique_id;
77 uint32_t old_flags, excludeflags;
78 ipsec_policy_t *pp = ixa->ixa_ipsec_policy;
79 ipsec_action_t *actlist = ixa->ixa_ipsec_action;
80 ipsec_action_t *act;
81 ipsec_latch_t *ipl = ixa->ixa_ipsec_latch;
82 ipsa_ref_t *ipr = NULL;
83 sa_family_t inaf = ixa->ixa_ipsec_inaf;
84 uint32_t *insrc = ixa->ixa_ipsec_insrc;
85 uint32_t *indst = ixa->ixa_ipsec_indst;
86 uint8_t insrcpfx = ixa->ixa_ipsec_insrcpfx;
87 uint8_t indstpfx = ixa->ixa_ipsec_indstpfx;
89 ASSERT(MUTEX_HELD(&bucket->isaf_lock));
92 * Caller must set ip_xmit_attr_t structure such that we know
93 * whether this is tunnel mode or transport mode based on
94 * IXAF_IPSEC_TUNNEL. If this flag is set, we assume that
95 * there are valid inner src and destination addresses to compare.
99 * Fast path: do we have a latch structure, is it for this bucket,
100 * and does the generation number match? If so, refhold and return.
103 if (ipl != NULL) {
104 ASSERT((protocol == IPPROTO_AH) || (protocol == IPPROTO_ESP));
105 ipr = &ixa->ixa_ipsec_ref[protocol - IPPROTO_ESP];
107 retval = ipr->ipsr_sa;
110 * NOTE: The isaf_gen check (incremented upon
111 * sadb_unlinkassoc()) protects against retval being a freed
112 * SA. (We're exploiting short-circuit evaluation.)
114 if ((bucket == ipr->ipsr_bucket) &&
115 (bucket->isaf_gen == ipr->ipsr_gen) &&
116 (retval->ipsa_state != IPSA_STATE_DEAD) &&
117 !(retval->ipsa_flags & IPSA_F_CINVALID)) {
118 IPSA_REFHOLD(retval);
119 return (retval);
123 ASSERT((pp != NULL) || (actlist != NULL));
124 if (actlist == NULL)
125 actlist = pp->ipsp_act;
126 ASSERT(actlist != NULL);
128 need_unique = actlist->ipa_want_unique;
129 unique_id = SA_FORM_UNIQUE_ID(ixa);
132 * Precompute mask for SA flags comparison: If we need a
133 * unique SA and an SA has already been used, or if the SA has
134 * a unique value which doesn't match, we aren't interested in
135 * the SA..
138 excludeflags = IPSA_F_UNIQUE;
139 if (need_unique)
140 excludeflags |= IPSA_F_USED;
143 * Walk the hash bucket, matching on:
145 * - unique_id
146 * - destination
147 * - source
148 * - algorithms
149 * - inner dst
150 * - inner src
151 * - <MORE TBD>
153 * Make sure that wildcard sources are inserted at the end of the hash
154 * bucket.
156 * DEFINITIONS: A _shared_ SA is one with unique_id == 0 and USED.
157 * An _unused_ SA is one with unique_id == 0 and not USED.
158 * A _unique_ SA is one with unique_id != 0 and USED.
159 * An SA with unique_id != 0 and not USED never happens.
162 candidate = NULL;
164 for (retval = bucket->isaf_ipsa; retval != NULL;
165 retval = retval->ipsa_next) {
166 ASSERT((candidate == NULL) ||
167 MUTEX_HELD(&candidate->ipsa_lock));
170 * Q: Should I lock this SA?
171 * A: For now, yes. I change and use too many fields in here
172 * (e.g. unique_id) that I may be racing with other threads.
173 * Also, the refcnt needs to be bumped up.
176 mutex_enter(&retval->ipsa_lock);
178 /* My apologies for the use of goto instead of continue. */
180 /* Outer destination address */
181 if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af))
182 goto next_ipsa; /* Destination mismatch. */
184 /* Outer source address */
185 if (!IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) &&
186 !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af))
187 goto next_ipsa; /* Specific source and not matched. */
189 if (tunnel_mode) {
190 /* Check tunnel mode */
191 if (!(retval->ipsa_flags & IPSA_F_TUNNEL))
192 goto next_ipsa; /* Not tunnel mode SA */
194 /* Inner destination address */
195 if (!IPSA_IS_ADDR_UNSPEC(retval->ipsa_innerdst, inaf)) {
196 if (!ip_addr_match((uint8_t *)indst,
197 min(indstpfx, retval->ipsa_innerdstpfx),
198 (in6_addr_t *)retval->ipsa_innerdst))
199 goto next_ipsa; /* not matched. */
202 /* Inner source address */
203 if (!IPSA_IS_ADDR_UNSPEC(retval->ipsa_innersrc, inaf)) {
204 if (!ip_addr_match((uint8_t *)insrc,
205 min(insrcpfx, retval->ipsa_innersrcpfx),
206 (in6_addr_t *)retval->ipsa_innersrc))
207 goto next_ipsa; /* not matched. */
209 } else {
210 /* Check transport mode */
211 if (retval->ipsa_flags & IPSA_F_TUNNEL)
212 goto next_ipsa; /* Not transport mode SA */
215 * TODO - If we ever do RFC 3884's dream of transport-
216 * mode SAs with inner IP address selectors, we need
217 * to put some code here.
222 * XXX should be able to use cached/latched action
223 * to dodge this loop
225 for (act = actlist; act != NULL; act = act->ipa_next) {
226 ipsec_act_t *ap = &act->ipa_act;
227 if (ap->ipa_type != IPSEC_POLICY_APPLY)
228 continue;
231 * XXX ugly. should be better way to do this test
233 if (protocol == IPPROTO_AH) {
234 if (!(ap->ipa_apply.ipp_use_ah))
235 continue;
236 if (ap->ipa_apply.ipp_auth_alg !=
237 retval->ipsa_auth_alg)
238 continue;
239 if (ap->ipa_apply.ipp_ah_minbits >
240 retval->ipsa_authkeybits)
241 continue;
242 } else {
243 if (!(ap->ipa_apply.ipp_use_esp))
244 continue;
246 if ((ap->ipa_apply.ipp_encr_alg !=
247 retval->ipsa_encr_alg))
248 continue;
250 if (ap->ipa_apply.ipp_espe_minbits >
251 retval->ipsa_encrkeybits)
252 continue;
254 if (ap->ipa_apply.ipp_esp_auth_alg != 0) {
255 if (ap->ipa_apply.ipp_esp_auth_alg !=
256 retval->ipsa_auth_alg)
257 continue;
258 if (ap->ipa_apply.ipp_espa_minbits >
259 retval->ipsa_authkeybits)
260 continue;
265 * Check key mgmt proto, cookie
267 if ((ap->ipa_apply.ipp_km_proto != 0) &&
268 (retval->ipsa_kmp != 0) &&
269 (ap->ipa_apply.ipp_km_proto != retval->ipsa_kmp))
270 continue;
272 if ((ap->ipa_apply.ipp_km_cookie != 0) &&
273 (retval->ipsa_kmc != 0) &&
274 (ap->ipa_apply.ipp_km_cookie != retval->ipsa_kmc))
275 continue;
277 break;
279 if (act == NULL)
280 goto next_ipsa; /* nothing matched */
283 * Do identities match?
285 if (ipl && ipl->ipl_ids_latched &&
286 !ipsec_match_outbound_ids(ipl, retval))
287 goto next_ipsa;
290 * At this point, we know that we have at least a match on:
292 * - dest
293 * - source (if source is specified, i.e. non-zeroes)
294 * - inner dest (if specified)
295 * - inner source (if specified)
296 * - auth alg (if auth alg is specified, i.e. non-zero)
297 * - encrypt. alg (if encrypt. alg is specified, i.e. non-zero)
298 * and we know that the SA keylengths are appropriate.
300 * (Keep in mind known-src SAs are hit before zero-src SAs,
301 * thanks to sadb_insertassoc().)
302 * If we need a unique asssociation, optimally we have
303 * ipsa_unique_id == unique_id, otherwise NOT USED
304 * is held in reserve (stored in candidate).
306 * For those stored in candidate, take best-match (i.e. given
307 * a choice, candidate should have non-zero ipsa_src).
311 * If SA has a unique value which matches, we're all set...
312 * "key management knows best"
314 if ((retval->ipsa_flags & IPSA_F_UNIQUE) &&
315 ((unique_id & retval->ipsa_unique_mask) ==
316 retval->ipsa_unique_id))
317 break;
320 * If we need a unique SA and this SA has already been used,
321 * or if the SA has a unique value which doesn't match,
322 * this isn't for us.
325 if (retval->ipsa_flags & excludeflags)
326 goto next_ipsa;
330 * I found a candidate..
332 if (candidate == NULL) {
334 * and didn't already have one..
336 candidate = retval;
337 candact = act;
338 continue;
339 } else {
341 * If candidate's source address is zero and
342 * the current match (i.e. retval) address is
343 * not zero, we have a better candidate..
345 if (IPSA_IS_ADDR_UNSPEC(candidate->ipsa_srcaddr, af) &&
346 !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) {
347 mutex_exit(&candidate->ipsa_lock);
348 candidate = retval;
349 candact = act;
350 continue;
353 next_ipsa:
354 mutex_exit(&retval->ipsa_lock);
356 ASSERT((retval == NULL) || MUTEX_HELD(&retval->ipsa_lock));
357 ASSERT((candidate == NULL) || MUTEX_HELD(&candidate->ipsa_lock));
358 ASSERT((retval == NULL) || (act != NULL));
359 ASSERT((candidate == NULL) || (candact != NULL));
361 /* Let caller react to a lookup failure when it gets NULL. */
362 if (retval == NULL && candidate == NULL)
363 return (NULL);
365 if (retval == NULL) {
366 ASSERT(MUTEX_HELD(&candidate->ipsa_lock));
367 retval = candidate;
368 act = candact;
369 } else if (candidate != NULL) {
370 mutex_exit(&candidate->ipsa_lock);
372 ASSERT(MUTEX_HELD(&retval->ipsa_lock));
373 ASSERT(act != NULL);
376 * Even though I hold the mutex, since the reference counter is an
377 * atomic operation, I really have to use the IPSA_REFHOLD macro.
379 IPSA_REFHOLD(retval);
382 * This association is no longer unused.
384 old_flags = retval->ipsa_flags;
385 retval->ipsa_flags |= IPSA_F_USED;
388 * Cache a reference to this SA for the fast path.
390 if (ipr != NULL) {
391 ipr->ipsr_bucket = bucket;
392 ipr->ipsr_gen = bucket->isaf_gen;
393 ipr->ipsr_sa = retval;
394 /* I'm now caching, so the cache-invalid flag goes away! */
395 retval->ipsa_flags &= ~IPSA_F_CINVALID;
398 * Latch various things while we're here..
400 if (ipl != NULL) {
401 if (!ipl->ipl_ids_latched) {
402 ipsec_latch_ids(ipl,
403 retval->ipsa_src_cid, retval->ipsa_dst_cid);
405 if (ixa->ixa_ipsec_action == NULL) {
406 IPACT_REFHOLD(act);
407 ixa->ixa_ipsec_action = act;
412 * Set the uniqueness only first time.
414 if (need_unique && !(old_flags & IPSA_F_USED)) {
415 if (retval->ipsa_unique_id == 0) {
416 ASSERT((retval->ipsa_flags & IPSA_F_UNIQUE) == 0);
418 * From now on, only this src, dst[ports, addr],
419 * proto, should use it.
421 retval->ipsa_flags |= IPSA_F_UNIQUE;
422 retval->ipsa_unique_id = unique_id;
423 retval->ipsa_unique_mask = SA_UNIQUE_MASK(
424 ixa->ixa_ipsec_src_port, ixa->ixa_ipsec_dst_port,
425 protocol, 0);
429 * Set the source address and adjust the hash
430 * buckets only if src_addr is zero.
432 if (IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) {
434 * sadb_unlinkassoc() will decrement the refcnt. Bump
435 * up when we have the lock so that we don't have to
436 * acquire locks when we come back from
437 * sadb_insertassoc().
439 * We don't need to bump the bucket's gen since
440 * we aren't moving to a new bucket.
442 IPSA_REFHOLD(retval);
443 IPSA_COPY_ADDR(retval->ipsa_srcaddr, src, af);
444 mutex_exit(&retval->ipsa_lock);
445 sadb_unlinkassoc(retval);
447 * Since the bucket lock is held, we know
448 * sadb_insertassoc() will succeed.
450 #ifdef DEBUG
451 if (sadb_insertassoc(retval, bucket) != 0) {
452 cmn_err(CE_PANIC,
453 "sadb_insertassoc() failed in "
454 "ipsec_getassocbyconn().\n");
456 #else /* non-DEBUG */
457 (void) sadb_insertassoc(retval, bucket);
458 #endif /* DEBUG */
459 return (retval);
462 mutex_exit(&retval->ipsa_lock);
464 return (retval);
468 * Look up a security association based on the security parameters index (SPI)
469 * and address(es). This is used for inbound packets and general SA lookups
470 * (even in outbound SA tables). The source address may be ignored. Return
471 * NULL if no association is available. If an SA is found, return it, with
472 * its refcnt incremented. The caller must REFRELE after using the SA.
473 * The hash bucket must be locked down before calling.
475 ipsa_t *
476 ipsec_getassocbyspi(isaf_t *bucket, uint32_t spi, uint32_t *src, uint32_t *dst,
477 sa_family_t af)
479 ipsa_t *retval;
481 ASSERT(MUTEX_HELD(&bucket->isaf_lock));
484 * Walk the hash bucket, matching exactly on SPI, then destination,
485 * then source.
487 * Per-SA locking doesn't need to happen, because I'm only matching
488 * on addresses. Addresses are only changed during insertion/deletion
489 * from the hash bucket. Since the hash bucket lock is held, we don't
490 * need to worry about addresses changing.
493 for (retval = bucket->isaf_ipsa; retval != NULL;
494 retval = retval->ipsa_next) {
495 if (retval->ipsa_spi != spi)
496 continue;
497 if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af))
498 continue;
501 * Assume that wildcard source addresses are inserted at the
502 * end of the hash bucket. (See sadb_insertassoc().)
503 * The following check for source addresses is a weak form
504 * of access control/source identity verification. If an
505 * SA has a source address, I only match an all-zeroes
506 * source address, or that particular one. If the SA has
507 * an all-zeroes source, then I match regardless.
509 * There is a weakness here in that a packet with all-zeroes
510 * for an address will match regardless of the source address
511 * stored in the packet.
513 * Note that port-level packet selectors, if present,
514 * are checked in ipsec_check_ipsecin_unique().
516 if (IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) ||
517 IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af) ||
518 IPSA_IS_ADDR_UNSPEC(src, af))
519 break;
522 if (retval != NULL) {
524 * Just refhold the return value. The caller will then
525 * make the appropriate calls to set the USED flag.
527 IPSA_REFHOLD(retval);
530 return (retval);
533 boolean_t
534 ipsec_outbound_sa(mblk_t *data_mp, ip_xmit_attr_t *ixa, uint_t proto)
536 ipaddr_t dst;
537 uint32_t *dst_ptr, *src_ptr;
538 isaf_t *bucket;
539 ipsa_t *assoc;
540 ip_pkt_t ipp;
541 in6_addr_t dst6;
542 ipsa_t **sa;
543 sadbp_t *sadbp;
544 sadb_t *sp;
545 sa_family_t af;
546 ip_stack_t *ipst = ixa->ixa_ipst;
547 netstack_t *ns = ipst->ips_netstack;
549 ASSERT(ixa->ixa_flags & IXAF_IPSEC_SECURE);
551 if (proto == IPPROTO_ESP) {
552 ipsecesp_stack_t *espstack;
554 espstack = ns->netstack_ipsecesp;
555 sa = &ixa->ixa_ipsec_esp_sa;
556 sadbp = &espstack->esp_sadb;
557 } else {
558 ipsecah_stack_t *ahstack;
560 ASSERT(proto == IPPROTO_AH);
561 ahstack = ns->netstack_ipsecah;
562 sa = &ixa->ixa_ipsec_ah_sa;
563 sadbp = &ahstack->ah_sadb;
566 ASSERT(*sa == NULL);
568 if (ixa->ixa_flags & IXAF_IS_IPV4) {
569 ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
571 ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION);
572 dst = ip_get_dst(ipha);
573 sp = &sadbp->s_v4;
574 af = AF_INET;
577 * NOTE:Getting the outbound association is considerably
578 * painful. ipsec_getassocbyconn() will require more
579 * parameters as policy implementations mature.
581 bucket = OUTBOUND_BUCKET_V4(sp, dst);
582 src_ptr = (uint32_t *)&ipha->ipha_src;
583 dst_ptr = (uint32_t *)&dst;
584 } else {
585 ip6_t *ip6h = (ip6_t *)data_mp->b_rptr;
587 ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
588 dst6 = ip_get_dst_v6(ip6h, data_mp, NULL);
589 af = AF_INET6;
591 bzero(&ipp, sizeof (ipp));
592 sp = &sadbp->s_v6;
594 /* Same NOTE: applies here! */
595 bucket = OUTBOUND_BUCKET_V6(sp, dst6);
596 src_ptr = (uint32_t *)&ip6h->ip6_src;
597 dst_ptr = (uint32_t *)&dst6;
600 mutex_enter(&bucket->isaf_lock);
601 assoc = ipsec_getassocbyconn(bucket, ixa, src_ptr, dst_ptr, af,
602 proto);
603 mutex_exit(&bucket->isaf_lock);
605 if (assoc == NULL)
606 return (B_FALSE);
608 if (assoc->ipsa_state == IPSA_STATE_DEAD) {
609 IPSA_REFRELE(assoc);
610 return (B_FALSE);
613 ASSERT(assoc->ipsa_state != IPSA_STATE_LARVAL);
615 *sa = assoc;
616 return (B_TRUE);
620 * Inbound IPsec SA selection.
621 * Can return a pulled up mblk.
622 * When it returns non-NULL ahp is updated
624 mblk_t *
625 ipsec_inbound_ah_sa(mblk_t *mp, ip_recv_attr_t *ira, ah_t **ahp)
627 ipha_t *ipha;
628 ipsa_t *assoc;
629 ah_t *ah;
630 isaf_t *hptr;
631 boolean_t isv6;
632 ip6_t *ip6h;
633 int ah_offset;
634 uint32_t *src_ptr, *dst_ptr;
635 int pullup_len;
636 sadb_t *sp;
637 sa_family_t af;
638 netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
639 ipsec_stack_t *ipss = ns->netstack_ipsec;
640 ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
642 IP_AH_BUMP_STAT(ipss, in_requests);
644 isv6 = !(ira->ira_flags & IRAF_IS_IPV4);
645 if (isv6) {
646 ip6h = (ip6_t *)mp->b_rptr;
647 ah_offset = ipsec_ah_get_hdr_size_v6(mp, B_TRUE);
648 } else {
649 ipha = (ipha_t *)mp->b_rptr;
650 ASSERT(ipha->ipha_protocol == IPPROTO_AH);
651 ah_offset = ipha->ipha_version_and_hdr_length -
652 (uint8_t)((IP_VERSION << 4));
653 ah_offset <<= 2;
657 * We assume that the IP header is pulled up until
658 * the options. We need to see whether we have the
659 * AH header in the same mblk or not.
661 pullup_len = ah_offset + sizeof (ah_t);
662 if (mp->b_rptr + pullup_len > mp->b_wptr) {
663 if (!pullupmsg(mp, pullup_len)) {
664 ipsec_rl_strlog(ns, ip_mod_info.mi_idnum, 0, 0,
665 SL_WARN | SL_ERROR,
666 "ipsec_inbound_ah_sa: Small AH header\n");
667 IP_AH_BUMP_STAT(ipss, in_discards);
668 ip_drop_packet(mp, B_TRUE, ira->ira_ill,
669 DROPPER(ipss, ipds_ah_bad_length),
670 &ipss->ipsec_dropper);
671 return (NULL);
673 if (isv6)
674 ip6h = (ip6_t *)mp->b_rptr;
675 else
676 ipha = (ipha_t *)mp->b_rptr;
679 ah = (ah_t *)(mp->b_rptr + ah_offset);
681 if (isv6) {
682 src_ptr = (uint32_t *)&ip6h->ip6_src;
683 dst_ptr = (uint32_t *)&ip6h->ip6_dst;
684 sp = &ahstack->ah_sadb.s_v6;
685 af = AF_INET6;
686 } else {
687 src_ptr = (uint32_t *)&ipha->ipha_src;
688 dst_ptr = (uint32_t *)&ipha->ipha_dst;
689 sp = &ahstack->ah_sadb.s_v4;
690 af = AF_INET;
693 hptr = INBOUND_BUCKET(sp, ah->ah_spi);
694 mutex_enter(&hptr->isaf_lock);
695 assoc = ipsec_getassocbyspi(hptr, ah->ah_spi, src_ptr, dst_ptr, af);
696 mutex_exit(&hptr->isaf_lock);
698 if (assoc == NULL || assoc->ipsa_state == IPSA_STATE_DEAD ||
699 assoc->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) {
700 IP_AH_BUMP_STAT(ipss, lookup_failure);
701 IP_AH_BUMP_STAT(ipss, in_discards);
702 ipsecah_in_assocfailure(mp, 0,
703 SL_ERROR | SL_CONSOLE | SL_WARN,
704 "ipsec_inbound_ah_sa: No association found for "
705 "spi 0x%x, dst addr %s\n",
706 ah->ah_spi, dst_ptr, af, ira);
707 if (assoc != NULL) {
708 IPSA_REFRELE(assoc);
710 return (NULL);
713 if (assoc->ipsa_state == IPSA_STATE_LARVAL) {
714 /* Not fully baked; swap the packet under a rock until then */
716 mp = sadb_set_lpkt(assoc, mp, ira);
717 if (mp == NULL) {
718 IPSA_REFRELE(assoc);
719 return (NULL);
721 /* Looks like the SA is no longer LARVAL. */
724 /* Are the IPsec fields initialized at all? */
725 if (!(ira->ira_flags & IRAF_IPSEC_SECURE)) {
726 ira->ira_ipsec_action = NULL;
727 ira->ira_ipsec_ah_sa = NULL;
728 ira->ira_ipsec_esp_sa = NULL;
732 * Save a reference to the association so that it can
733 * be retrieved after execution. We free any AH SA reference
734 * already there (innermost SA "wins". The reference to
735 * the SA will also be used later when doing the policy checks.
737 if (ira->ira_ipsec_ah_sa != NULL) {
738 IPSA_REFRELE(ira->ira_ipsec_ah_sa);
740 ira->ira_flags |= IRAF_IPSEC_SECURE;
741 ira->ira_ipsec_ah_sa = assoc;
743 *ahp = ah;
744 return (mp);
748 * Can return a pulled up mblk.
749 * When it returns non-NULL esphp is updated
751 mblk_t *
752 ipsec_inbound_esp_sa(mblk_t *data_mp, ip_recv_attr_t *ira, esph_t **esphp)
754 mblk_t *placeholder;
755 uint32_t *src_ptr, *dst_ptr;
756 ipha_t *ipha;
757 ip6_t *ip6h;
758 esph_t *esph;
759 ipsa_t *ipsa;
760 isaf_t *bucket;
761 uint_t preamble;
762 sa_family_t af;
763 boolean_t isv6;
764 sadb_t *sp;
765 netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
766 ipsec_stack_t *ipss = ns->netstack_ipsec;
767 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
769 IP_ESP_BUMP_STAT(ipss, in_requests);
771 isv6 = !(ira->ira_flags & IRAF_IS_IPV4);
772 if (isv6) {
773 ip6h = (ip6_t *)data_mp->b_rptr;
774 } else {
775 ipha = (ipha_t *)data_mp->b_rptr;
779 * Put all data into one mblk if it's not there already.
780 * XXX This is probably bad long-term. Figure out better ways of doing
781 * this. Much of the inbound path depends on all of the data being
782 * in one mblk.
784 * XXX Jumbogram issues will have to be dealt with here.
785 * If the plen is 0, we'll have to scan for a HBH header with the
786 * actual packet length.
788 if (data_mp->b_datap->db_ref > 1 ||
789 (data_mp->b_wptr - data_mp->b_rptr) < ira->ira_pktlen) {
790 placeholder = msgpullup(data_mp, -1);
791 if (placeholder == NULL) {
792 IP_ESP_BUMP_STAT(ipss, in_discards);
793 ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
794 DROPPER(ipss, ipds_esp_nomem),
795 &ipss->ipsec_dropper);
796 return (NULL);
797 } else {
798 /* Reset packet with new pulled up mblk. */
799 freemsg(data_mp);
800 data_mp = placeholder;
805 * Find the ESP header, point the address pointers at the appropriate
806 * IPv4/IPv6 places.
808 if (isv6) {
809 ip6h = (ip6_t *)data_mp->b_rptr;
810 src_ptr = (uint32_t *)&ip6h->ip6_src;
811 dst_ptr = (uint32_t *)&ip6h->ip6_dst;
812 if (ip6h->ip6_nxt != IPPROTO_ESP) {
813 /* There are options that need to be processed. */
814 preamble = ip_hdr_length_v6(data_mp, ip6h);
815 } else {
816 preamble = sizeof (ip6_t);
819 sp = &espstack->esp_sadb.s_v6;
820 af = AF_INET6;
821 } else {
822 ipha = (ipha_t *)data_mp->b_rptr;
823 src_ptr = (uint32_t *)&ipha->ipha_src;
824 dst_ptr = (uint32_t *)&ipha->ipha_dst;
825 preamble = IPH_HDR_LENGTH(ipha);
827 sp = &espstack->esp_sadb.s_v4;
828 af = AF_INET;
831 esph = (esph_t *)(data_mp->b_rptr + preamble);
833 /* Since hash is common on inbound (SPI value), hash here. */
834 bucket = INBOUND_BUCKET(sp, esph->esph_spi);
835 mutex_enter(&bucket->isaf_lock);
836 ipsa = ipsec_getassocbyspi(bucket, esph->esph_spi, src_ptr, dst_ptr,
837 af);
838 mutex_exit(&bucket->isaf_lock);
840 if (ipsa == NULL || ipsa->ipsa_state == IPSA_STATE_DEAD ||
841 ipsa->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) {
842 /* This is a loggable error! AUDIT ME! */
843 IP_ESP_BUMP_STAT(ipss, lookup_failure);
844 IP_ESP_BUMP_STAT(ipss, in_discards);
845 ipsecesp_in_assocfailure(data_mp, 0,
846 SL_ERROR | SL_CONSOLE | SL_WARN,
847 "ipsec_inbound_esp_sa: No association found for "
848 "spi 0x%x, dst addr %s\n",
849 esph->esph_spi, dst_ptr, af, ira);
850 if (ipsa != NULL) {
851 IPSA_REFRELE(ipsa);
853 return (NULL);
856 if (ipsa->ipsa_state == IPSA_STATE_LARVAL) {
857 /* Not fully baked; swap the packet under a rock until then */
859 data_mp = sadb_set_lpkt(ipsa, data_mp, ira);
860 if (data_mp == NULL) {
861 IPSA_REFRELE(ipsa);
862 return (NULL);
864 /* Looks like the SA is no longer LARVAL. */
867 /* Are the IPsec fields initialized at all? */
868 if (!(ira->ira_flags & IRAF_IPSEC_SECURE)) {
869 ira->ira_ipsec_action = NULL;
870 ira->ira_ipsec_ah_sa = NULL;
871 ira->ira_ipsec_esp_sa = NULL;
875 * Save a reference to the association so that it can
876 * be retrieved after execution. We free any AH SA reference
877 * already there (innermost SA "wins". The reference to
878 * the SA will also be used later when doing the policy checks.
880 if (ira->ira_ipsec_esp_sa != NULL) {
881 IPSA_REFRELE(ira->ira_ipsec_esp_sa);
883 ira->ira_flags |= IRAF_IPSEC_SECURE;
884 ira->ira_ipsec_esp_sa = ipsa;
886 *esphp = esph;
887 return (data_mp);