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 /*
22930af642SDan 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>
287c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
29de8c4a14SErik Nordmark #include <sys/strsubr.h>
3038d95a78Smarkfen #include <sys/errno.h>
317c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
327c478bd9Sstevel@tonic-gate #include <sys/debug.h>
337c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
347c478bd9Sstevel@tonic-gate #include <sys/stream.h>
357c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
397c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
407c478bd9Sstevel@tonic-gate #include <sys/socket.h>
417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
437c478bd9Sstevel@tonic-gate #include <sys/crypto/api.h>
447c478bd9Sstevel@tonic-gate #include <sys/zone.h>
457c478bd9Sstevel@tonic-gate #include <netinet/in.h>
467c478bd9Sstevel@tonic-gate #include <net/if.h>
477c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h>
48628b0c67SMark Fenwick #include <net/pfpolicy.h>
497c478bd9Sstevel@tonic-gate #include <inet/common.h>
507c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
517c478bd9Sstevel@tonic-gate #include <inet/ip.h>
528810c16bSdanmcd #include <inet/ip_ire.h>
537c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
547c478bd9Sstevel@tonic-gate #include <inet/ipsec_info.h>
557c478bd9Sstevel@tonic-gate #include <inet/tcp.h>
567c478bd9Sstevel@tonic-gate #include <inet/sadb.h>
57f4b3ec61Sdh155122 #include <inet/ipsec_impl.h>
587c478bd9Sstevel@tonic-gate #include <inet/ipsecah.h>
597c478bd9Sstevel@tonic-gate #include <inet/ipsecesp.h>
607c478bd9Sstevel@tonic-gate #include <sys/random.h>
617c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
625d3b8cb7SBill Sommerfeld #include <sys/strsun.h>
635d3b8cb7SBill Sommerfeld #include <sys/strsubr.h>
647c478bd9Sstevel@tonic-gate #include <inet/ip_if.h>
657c478bd9Sstevel@tonic-gate #include <inet/ipdrop.h>
667c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
677c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h>
685d3b8cb7SBill Sommerfeld #include <sys/tsol/tnet.h>
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate * This source file contains Security Association Database (SADB) common
727c478bd9Sstevel@tonic-gate * routines. They are linked in with the AH module. Since AH has no chance
737c478bd9Sstevel@tonic-gate * of falling under export control, it was safe to link it in there.
747c478bd9Sstevel@tonic-gate */
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate static mblk_t *sadb_extended_acquire(ipsec_selector_t *, ipsec_policy_t *,
775d3b8cb7SBill Sommerfeld ipsec_action_t *, boolean_t, uint32_t, uint32_t, sadb_sens_t *,
785d3b8cb7SBill Sommerfeld netstack_t *);
79bd670b35SErik Nordmark static ipsa_t *sadb_torch_assoc(isaf_t *, ipsa_t *);
80f4b3ec61Sdh155122 static void sadb_destroy_acqlist(iacqf_t **, uint_t, boolean_t,
81f4b3ec61Sdh155122 netstack_t *);
82f4b3ec61Sdh155122 static void sadb_destroy(sadb_t *, netstack_t *);
838810c16bSdanmcd static mblk_t *sadb_sa2msg(ipsa_t *, sadb_msg_t *);
84bd670b35SErik Nordmark static ts_label_t *sadb_label_from_sens(sadb_sens_t *, uint64_t *);
85bd670b35SErik Nordmark static sadb_sens_t *sadb_make_sens_ext(ts_label_t *tsl, int *len);
867c478bd9Sstevel@tonic-gate
878810c16bSdanmcd static time_t sadb_add_time(time_t, uint64_t);
8838d95a78Smarkfen static void lifetime_fuzz(ipsa_t *);
8938d95a78Smarkfen static void age_pair_peer_list(templist_t *, sadb_t *, boolean_t);
905d3b8cb7SBill Sommerfeld static int get_ipsa_pair(ipsa_query_t *, ipsap_t *, int *);
915d3b8cb7SBill Sommerfeld static void init_ipsa_pair(ipsap_t *);
925d3b8cb7SBill Sommerfeld static void destroy_ipsa_pair(ipsap_t *);
935d3b8cb7SBill Sommerfeld static int update_pairing(ipsap_t *, ipsa_query_t *, keysock_in_t *, int *);
949c2c14abSThejaswini Singarajipura static void ipsa_set_replay(ipsa_t *ipsa, uint32_t offset);
959c2c14abSThejaswini Singarajipura
96bffb04cfSmarkfen /*
97bffb04cfSmarkfen * ipsacq_maxpackets is defined here to make it tunable
98bffb04cfSmarkfen * from /etc/system.
99bffb04cfSmarkfen */
100bffb04cfSmarkfen extern uint64_t ipsacq_maxpackets;
101bffb04cfSmarkfen
1027c478bd9Sstevel@tonic-gate #define SET_EXPIRE(sa, delta, exp) { \
1037c478bd9Sstevel@tonic-gate if (((sa)->ipsa_ ## delta) != 0) { \
1047c478bd9Sstevel@tonic-gate (sa)->ipsa_ ## exp = sadb_add_time((sa)->ipsa_addtime, \
1057c478bd9Sstevel@tonic-gate (sa)->ipsa_ ## delta); \
1067c478bd9Sstevel@tonic-gate } \
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate #define UPDATE_EXPIRE(sa, delta, exp) { \
1107c478bd9Sstevel@tonic-gate if (((sa)->ipsa_ ## delta) != 0) { \
1117c478bd9Sstevel@tonic-gate time_t tmp = sadb_add_time((sa)->ipsa_usetime, \
1127c478bd9Sstevel@tonic-gate (sa)->ipsa_ ## delta); \
1137c478bd9Sstevel@tonic-gate if (((sa)->ipsa_ ## exp) == 0) \
1147c478bd9Sstevel@tonic-gate (sa)->ipsa_ ## exp = tmp; \
1157c478bd9Sstevel@tonic-gate else \
1167c478bd9Sstevel@tonic-gate (sa)->ipsa_ ## exp = \
1177c478bd9Sstevel@tonic-gate MIN((sa)->ipsa_ ## exp, tmp); \
1187c478bd9Sstevel@tonic-gate } \
1197c478bd9Sstevel@tonic-gate }
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate /* wrap the macro so we can pass it as a function pointer */
1237c478bd9Sstevel@tonic-gate void
sadb_sa_refrele(void * target)1247c478bd9Sstevel@tonic-gate sadb_sa_refrele(void *target)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate IPSA_REFRELE(((ipsa_t *)target));
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate * We presume that sizeof (long) == sizeof (time_t) and that time_t is
1317c478bd9Sstevel@tonic-gate * a signed type.
1327c478bd9Sstevel@tonic-gate */
1337c478bd9Sstevel@tonic-gate #define TIME_MAX LONG_MAX
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate /*
1367c478bd9Sstevel@tonic-gate * PF_KEY gives us lifetimes in uint64_t seconds. We presume that
1377c478bd9Sstevel@tonic-gate * time_t is defined to be a signed type with the same range as
1387c478bd9Sstevel@tonic-gate * "long". On ILP32 systems, we thus run the risk of wrapping around
1397c478bd9Sstevel@tonic-gate * at end of time, as well as "overwrapping" the clock back around
1407c478bd9Sstevel@tonic-gate * into a seemingly valid but incorrect future date earlier than the
1417c478bd9Sstevel@tonic-gate * desired expiration.
1427c478bd9Sstevel@tonic-gate *
1437c478bd9Sstevel@tonic-gate * In order to avoid odd behavior (either negative lifetimes or loss
1447c478bd9Sstevel@tonic-gate * of high order bits) when someone asks for bizarrely long SA
1457c478bd9Sstevel@tonic-gate * lifetimes, we do a saturating add for expire times.
1467c478bd9Sstevel@tonic-gate *
1477c478bd9Sstevel@tonic-gate * We presume that ILP32 systems will be past end of support life when
1487c478bd9Sstevel@tonic-gate * the 32-bit time_t overflows (a dangerous assumption, mind you..).
1497c478bd9Sstevel@tonic-gate *
1507c478bd9Sstevel@tonic-gate * On LP64, 2^64 seconds are about 5.8e11 years, at which point we
1517c478bd9Sstevel@tonic-gate * will hopefully have figured out clever ways to avoid the use of
1527c478bd9Sstevel@tonic-gate * fixed-sized integers in computation.
1537c478bd9Sstevel@tonic-gate */
1547c478bd9Sstevel@tonic-gate static time_t
sadb_add_time(time_t base,uint64_t delta)1557c478bd9Sstevel@tonic-gate sadb_add_time(time_t base, uint64_t delta)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate time_t sum;
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate * Clip delta to the maximum possible time_t value to
1617c478bd9Sstevel@tonic-gate * prevent "overwrapping" back into a shorter-than-desired
1627c478bd9Sstevel@tonic-gate * future time.
1637c478bd9Sstevel@tonic-gate */
1647c478bd9Sstevel@tonic-gate if (delta > TIME_MAX)
1657c478bd9Sstevel@tonic-gate delta = TIME_MAX;
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate * This sum may still overflow.
1687c478bd9Sstevel@tonic-gate */
1697c478bd9Sstevel@tonic-gate sum = base + delta;
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate * .. so if the result is less than the base, we overflowed.
1737c478bd9Sstevel@tonic-gate */
1747c478bd9Sstevel@tonic-gate if (sum < base)
1757c478bd9Sstevel@tonic-gate sum = TIME_MAX;
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate return (sum);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate * Callers of this function have already created a working security
1827c478bd9Sstevel@tonic-gate * association, and have found the appropriate table & hash chain. All this
1837c478bd9Sstevel@tonic-gate * function does is check duplicates, and insert the SA. The caller needs to
1847c478bd9Sstevel@tonic-gate * hold the hash bucket lock and increment the refcnt before insertion.
1857c478bd9Sstevel@tonic-gate *
1867c478bd9Sstevel@tonic-gate * Return 0 if success, EEXIST if collision.
1877c478bd9Sstevel@tonic-gate */
188437220cdSdanmcd #define SA_UNIQUE_MATCH(sa1, sa2) \
189437220cdSdanmcd (((sa1)->ipsa_unique_id & (sa1)->ipsa_unique_mask) == \
190437220cdSdanmcd ((sa2)->ipsa_unique_id & (sa2)->ipsa_unique_mask))
191437220cdSdanmcd
1927c478bd9Sstevel@tonic-gate int
sadb_insertassoc(ipsa_t * ipsa,isaf_t * bucket)1937c478bd9Sstevel@tonic-gate sadb_insertassoc(ipsa_t *ipsa, isaf_t *bucket)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate ipsa_t **ptpn = NULL;
1967c478bd9Sstevel@tonic-gate ipsa_t *walker;
1977c478bd9Sstevel@tonic-gate boolean_t unspecsrc;
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&bucket->isaf_lock));
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate unspecsrc = IPSA_IS_ADDR_UNSPEC(ipsa->ipsa_srcaddr, ipsa->ipsa_addrfam);
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate walker = bucket->isaf_ipsa;
2047c478bd9Sstevel@tonic-gate ASSERT(walker == NULL || ipsa->ipsa_addrfam == walker->ipsa_addrfam);
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate /*
2077c478bd9Sstevel@tonic-gate * Find insertion point (pointed to with **ptpn). Insert at the head
2087c478bd9Sstevel@tonic-gate * of the list unless there's an unspecified source address, then
2097c478bd9Sstevel@tonic-gate * insert it after the last SA with a specified source address.
2107c478bd9Sstevel@tonic-gate *
2117c478bd9Sstevel@tonic-gate * BTW, you'll have to walk the whole chain, matching on {DST, SPI}
2127c478bd9Sstevel@tonic-gate * checking for collisions.
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate while (walker != NULL) {
2167c478bd9Sstevel@tonic-gate if (IPSA_ARE_ADDR_EQUAL(walker->ipsa_dstaddr,
2177c478bd9Sstevel@tonic-gate ipsa->ipsa_dstaddr, ipsa->ipsa_addrfam)) {
2187c478bd9Sstevel@tonic-gate if (walker->ipsa_spi == ipsa->ipsa_spi)
2197c478bd9Sstevel@tonic-gate return (EEXIST);
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate mutex_enter(&walker->ipsa_lock);
2227c478bd9Sstevel@tonic-gate if (ipsa->ipsa_state == IPSA_STATE_MATURE &&
2237c478bd9Sstevel@tonic-gate (walker->ipsa_flags & IPSA_F_USED) &&
224437220cdSdanmcd SA_UNIQUE_MATCH(walker, ipsa)) {
2257c478bd9Sstevel@tonic-gate walker->ipsa_flags |= IPSA_F_CINVALID;
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate mutex_exit(&walker->ipsa_lock);
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate if (ptpn == NULL && unspecsrc) {
2317c478bd9Sstevel@tonic-gate if (IPSA_IS_ADDR_UNSPEC(walker->ipsa_srcaddr,
2327c478bd9Sstevel@tonic-gate walker->ipsa_addrfam))
2337c478bd9Sstevel@tonic-gate ptpn = walker->ipsa_ptpn;
2347c478bd9Sstevel@tonic-gate else if (walker->ipsa_next == NULL)
2357c478bd9Sstevel@tonic-gate ptpn = &walker->ipsa_next;
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate walker = walker->ipsa_next;
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate if (ptpn == NULL)
2427c478bd9Sstevel@tonic-gate ptpn = &bucket->isaf_ipsa;
2437c478bd9Sstevel@tonic-gate ipsa->ipsa_next = *ptpn;
2447c478bd9Sstevel@tonic-gate ipsa->ipsa_ptpn = ptpn;
2457c478bd9Sstevel@tonic-gate if (ipsa->ipsa_next != NULL)
2467c478bd9Sstevel@tonic-gate ipsa->ipsa_next->ipsa_ptpn = &ipsa->ipsa_next;
2477c478bd9Sstevel@tonic-gate *ptpn = ipsa;
2487c478bd9Sstevel@tonic-gate ipsa->ipsa_linklock = &bucket->isaf_lock;
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate return (0);
2517c478bd9Sstevel@tonic-gate }
252437220cdSdanmcd #undef SA_UNIQUE_MATCH
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate * Free a security association. Its reference count is 0, which means
2567c478bd9Sstevel@tonic-gate * I must free it. The SA must be unlocked and must not be linked into
2577c478bd9Sstevel@tonic-gate * any fanout list.
2587c478bd9Sstevel@tonic-gate */
2597c478bd9Sstevel@tonic-gate static void
sadb_freeassoc(ipsa_t * ipsa)2607c478bd9Sstevel@tonic-gate sadb_freeassoc(ipsa_t *ipsa)
2617c478bd9Sstevel@tonic-gate {
262f4b3ec61Sdh155122 ipsec_stack_t *ipss = ipsa->ipsa_netstack->netstack_ipsec;
263bd670b35SErik Nordmark mblk_t *asyncmp, *mp;
264f4b3ec61Sdh155122
265f4b3ec61Sdh155122 ASSERT(ipss != NULL);
2660c0328cdSBill Sommerfeld ASSERT(MUTEX_NOT_HELD(&ipsa->ipsa_lock));
2677c478bd9Sstevel@tonic-gate ASSERT(ipsa->ipsa_refcnt == 0);
2687c478bd9Sstevel@tonic-gate ASSERT(ipsa->ipsa_next == NULL);
2697c478bd9Sstevel@tonic-gate ASSERT(ipsa->ipsa_ptpn == NULL);
2707c478bd9Sstevel@tonic-gate
271bd670b35SErik Nordmark
272bd670b35SErik Nordmark asyncmp = sadb_clear_lpkt(ipsa);
273bd670b35SErik Nordmark if (asyncmp != NULL) {
274bd670b35SErik Nordmark mp = ip_recv_attr_free_mblk(asyncmp);
275bd670b35SErik Nordmark ip_drop_packet(mp, B_TRUE, NULL,
276f4b3ec61Sdh155122 DROPPER(ipss, ipds_sadb_inlarval_timeout),
277f4b3ec61Sdh155122 &ipss->ipsec_sadb_dropper);
278bd670b35SErik Nordmark }
279bd670b35SErik Nordmark mutex_enter(&ipsa->ipsa_lock);
2805d3b8cb7SBill Sommerfeld
281bd670b35SErik Nordmark if (ipsa->ipsa_tsl != NULL) {
282bd670b35SErik Nordmark label_rele(ipsa->ipsa_tsl);
283bd670b35SErik Nordmark ipsa->ipsa_tsl = NULL;
2845d3b8cb7SBill Sommerfeld }
2855d3b8cb7SBill Sommerfeld
286bd670b35SErik Nordmark if (ipsa->ipsa_otsl != NULL) {
287bd670b35SErik Nordmark label_rele(ipsa->ipsa_otsl);
288bd670b35SErik Nordmark ipsa->ipsa_otsl = NULL;
2895d3b8cb7SBill Sommerfeld }
2905d3b8cb7SBill Sommerfeld
2917c478bd9Sstevel@tonic-gate ipsec_destroy_ctx_tmpl(ipsa, IPSEC_ALG_AUTH);
2927c478bd9Sstevel@tonic-gate ipsec_destroy_ctx_tmpl(ipsa, IPSEC_ALG_ENCR);
2937c478bd9Sstevel@tonic-gate mutex_exit(&ipsa->ipsa_lock);
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate /* bzero() these fields for paranoia's sake. */
2967c478bd9Sstevel@tonic-gate if (ipsa->ipsa_authkey != NULL) {
2977c478bd9Sstevel@tonic-gate bzero(ipsa->ipsa_authkey, ipsa->ipsa_authkeylen);
2987c478bd9Sstevel@tonic-gate kmem_free(ipsa->ipsa_authkey, ipsa->ipsa_authkeylen);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate if (ipsa->ipsa_encrkey != NULL) {
3017c478bd9Sstevel@tonic-gate bzero(ipsa->ipsa_encrkey, ipsa->ipsa_encrkeylen);
3027c478bd9Sstevel@tonic-gate kmem_free(ipsa->ipsa_encrkey, ipsa->ipsa_encrkeylen);
3037c478bd9Sstevel@tonic-gate }
304628b0c67SMark Fenwick if (ipsa->ipsa_nonce_buf != NULL) {
305628b0c67SMark Fenwick bzero(ipsa->ipsa_nonce_buf, sizeof (ipsec_nonce_t));
306628b0c67SMark Fenwick kmem_free(ipsa->ipsa_nonce_buf, sizeof (ipsec_nonce_t));
307628b0c67SMark Fenwick }
3087c478bd9Sstevel@tonic-gate if (ipsa->ipsa_src_cid != NULL) {
3097c478bd9Sstevel@tonic-gate IPSID_REFRELE(ipsa->ipsa_src_cid);
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate if (ipsa->ipsa_dst_cid != NULL) {
3127c478bd9Sstevel@tonic-gate IPSID_REFRELE(ipsa->ipsa_dst_cid);
3137c478bd9Sstevel@tonic-gate }
314628b0c67SMark Fenwick if (ipsa->ipsa_emech.cm_param != NULL)
315628b0c67SMark Fenwick kmem_free(ipsa->ipsa_emech.cm_param,
316628b0c67SMark Fenwick ipsa->ipsa_emech.cm_param_len);
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate mutex_destroy(&ipsa->ipsa_lock);
3197c478bd9Sstevel@tonic-gate kmem_free(ipsa, sizeof (*ipsa));
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate * Unlink a security association from a hash bucket. Assume the hash bucket
3247c478bd9Sstevel@tonic-gate * lock is held, but the association's lock is not.
3257c478bd9Sstevel@tonic-gate *
3267c478bd9Sstevel@tonic-gate * Note that we do not bump the bucket's generation number here because
3277c478bd9Sstevel@tonic-gate * we might not be making a visible change to the set of visible SA's.
3287c478bd9Sstevel@tonic-gate * All callers MUST bump the bucket's generation number before they unlock
3297c478bd9Sstevel@tonic-gate * the bucket if they use sadb_unlinkassoc to permanetly remove an SA which
3307c478bd9Sstevel@tonic-gate * was present in the bucket at the time it was locked.
3317c478bd9Sstevel@tonic-gate */
3327c478bd9Sstevel@tonic-gate void
sadb_unlinkassoc(ipsa_t * ipsa)3337c478bd9Sstevel@tonic-gate sadb_unlinkassoc(ipsa_t *ipsa)
3347c478bd9Sstevel@tonic-gate {
3357c478bd9Sstevel@tonic-gate ASSERT(ipsa->ipsa_linklock != NULL);
3367c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(ipsa->ipsa_linklock));
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate /* These fields are protected by the link lock. */
3397c478bd9Sstevel@tonic-gate *(ipsa->ipsa_ptpn) = ipsa->ipsa_next;
3407c478bd9Sstevel@tonic-gate if (ipsa->ipsa_next != NULL) {
3417c478bd9Sstevel@tonic-gate ipsa->ipsa_next->ipsa_ptpn = ipsa->ipsa_ptpn;
3427c478bd9Sstevel@tonic-gate ipsa->ipsa_next = NULL;
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate ipsa->ipsa_ptpn = NULL;
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate /* This may destroy the SA. */
3487c478bd9Sstevel@tonic-gate IPSA_REFRELE(ipsa);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate
3519c2c14abSThejaswini Singarajipura void
sadb_delete_cluster(ipsa_t * assoc)3529c2c14abSThejaswini Singarajipura sadb_delete_cluster(ipsa_t *assoc)
3539c2c14abSThejaswini Singarajipura {
3549c2c14abSThejaswini Singarajipura uint8_t protocol;
3559c2c14abSThejaswini Singarajipura
3569c2c14abSThejaswini Singarajipura if (cl_inet_deletespi &&
3579c2c14abSThejaswini Singarajipura ((assoc->ipsa_state == IPSA_STATE_LARVAL) ||
3589c2c14abSThejaswini Singarajipura (assoc->ipsa_state == IPSA_STATE_MATURE))) {
3599c2c14abSThejaswini Singarajipura protocol = (assoc->ipsa_type == SADB_SATYPE_AH) ?
3609c2c14abSThejaswini Singarajipura IPPROTO_AH : IPPROTO_ESP;
3618e4b770fSLu Huafeng cl_inet_deletespi(assoc->ipsa_netstack->netstack_stackid,
3628e4b770fSLu Huafeng protocol, assoc->ipsa_spi, NULL);
3639c2c14abSThejaswini Singarajipura }
3649c2c14abSThejaswini Singarajipura }
3659c2c14abSThejaswini Singarajipura
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate * Create a larval security association with the specified SPI. All other
3687c478bd9Sstevel@tonic-gate * fields are zeroed.
3697c478bd9Sstevel@tonic-gate */
3707c478bd9Sstevel@tonic-gate static ipsa_t *
sadb_makelarvalassoc(uint32_t spi,uint32_t * src,uint32_t * dst,int addrfam,netstack_t * ns)371f4b3ec61Sdh155122 sadb_makelarvalassoc(uint32_t spi, uint32_t *src, uint32_t *dst, int addrfam,
372f4b3ec61Sdh155122 netstack_t *ns)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate ipsa_t *newbie;
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate * Allocate...
3787c478bd9Sstevel@tonic-gate */
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate newbie = (ipsa_t *)kmem_zalloc(sizeof (ipsa_t), KM_NOSLEEP);
3817c478bd9Sstevel@tonic-gate if (newbie == NULL) {
3827c478bd9Sstevel@tonic-gate /* Can't make new larval SA. */
3837c478bd9Sstevel@tonic-gate return (NULL);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate /* Assigned requested SPI, assume caller does SPI allocation magic. */
3877c478bd9Sstevel@tonic-gate newbie->ipsa_spi = spi;
388f4b3ec61Sdh155122 newbie->ipsa_netstack = ns; /* No netstack_hold */
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate * Copy addresses...
3927c478bd9Sstevel@tonic-gate */
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate IPSA_COPY_ADDR(newbie->ipsa_srcaddr, src, addrfam);
3957c478bd9Sstevel@tonic-gate IPSA_COPY_ADDR(newbie->ipsa_dstaddr, dst, addrfam);
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate newbie->ipsa_addrfam = addrfam;
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate * Set common initialization values, including refcnt.
4017c478bd9Sstevel@tonic-gate */
4027c478bd9Sstevel@tonic-gate mutex_init(&newbie->ipsa_lock, NULL, MUTEX_DEFAULT, NULL);
4037c478bd9Sstevel@tonic-gate newbie->ipsa_state = IPSA_STATE_LARVAL;
4047c478bd9Sstevel@tonic-gate newbie->ipsa_refcnt = 1;
4057c478bd9Sstevel@tonic-gate newbie->ipsa_freefunc = sadb_freeassoc;
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate * There aren't a lot of other common initialization values, as
4097c478bd9Sstevel@tonic-gate * they are copied in from the PF_KEY message.
4107c478bd9Sstevel@tonic-gate */
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate return (newbie);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate * Call me to initialize a security association fanout.
4177c478bd9Sstevel@tonic-gate */
418fb87b5d2Ssommerfe static int
sadb_init_fanout(isaf_t ** tablep,uint_t size,int kmflag)419fb87b5d2Ssommerfe sadb_init_fanout(isaf_t **tablep, uint_t size, int kmflag)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate isaf_t *table;
4227c478bd9Sstevel@tonic-gate int i;
4237c478bd9Sstevel@tonic-gate
424fb87b5d2Ssommerfe table = (isaf_t *)kmem_alloc(size * sizeof (*table), kmflag);
4257c478bd9Sstevel@tonic-gate *tablep = table;
4267c478bd9Sstevel@tonic-gate
427fb87b5d2Ssommerfe if (table == NULL)
428fb87b5d2Ssommerfe return (ENOMEM);
429fb87b5d2Ssommerfe
430fb87b5d2Ssommerfe for (i = 0; i < size; i++) {
4317c478bd9Sstevel@tonic-gate mutex_init(&(table[i].isaf_lock), NULL, MUTEX_DEFAULT, NULL);
4327c478bd9Sstevel@tonic-gate table[i].isaf_ipsa = NULL;
4337c478bd9Sstevel@tonic-gate table[i].isaf_gen = 0;
4347c478bd9Sstevel@tonic-gate }
435fb87b5d2Ssommerfe
436fb87b5d2Ssommerfe return (0);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate
439fb87b5d2Ssommerfe /*
440fb87b5d2Ssommerfe * Call me to initialize an acquire fanout
441fb87b5d2Ssommerfe */
442fb87b5d2Ssommerfe static int
sadb_init_acfanout(iacqf_t ** tablep,uint_t size,int kmflag)443fb87b5d2Ssommerfe sadb_init_acfanout(iacqf_t **tablep, uint_t size, int kmflag)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate iacqf_t *table;
4467c478bd9Sstevel@tonic-gate int i;
4477c478bd9Sstevel@tonic-gate
448fb87b5d2Ssommerfe table = (iacqf_t *)kmem_alloc(size * sizeof (*table), kmflag);
4497c478bd9Sstevel@tonic-gate *tablep = table;
4507c478bd9Sstevel@tonic-gate
451fb87b5d2Ssommerfe if (table == NULL)
452fb87b5d2Ssommerfe return (ENOMEM);
453fb87b5d2Ssommerfe
454fb87b5d2Ssommerfe for (i = 0; i < size; i++) {
4557c478bd9Sstevel@tonic-gate mutex_init(&(table[i].iacqf_lock), NULL, MUTEX_DEFAULT, NULL);
4567c478bd9Sstevel@tonic-gate table[i].iacqf_ipsacq = NULL;
4577c478bd9Sstevel@tonic-gate }
458fb87b5d2Ssommerfe
459fb87b5d2Ssommerfe return (0);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate
4627c478bd9Sstevel@tonic-gate /*
463fb87b5d2Ssommerfe * Attempt to initialize an SADB instance. On failure, return ENOMEM;
464fb87b5d2Ssommerfe * caller must clean up partial allocations.
4657c478bd9Sstevel@tonic-gate */
466fb87b5d2Ssommerfe static int
sadb_init_trial(sadb_t * sp,uint_t size,int kmflag)467fb87b5d2Ssommerfe sadb_init_trial(sadb_t *sp, uint_t size, int kmflag)
4687c478bd9Sstevel@tonic-gate {
469fb87b5d2Ssommerfe ASSERT(sp->sdb_of == NULL);
470fb87b5d2Ssommerfe ASSERT(sp->sdb_if == NULL);
471fb87b5d2Ssommerfe ASSERT(sp->sdb_acq == NULL);
472fb87b5d2Ssommerfe
473fb87b5d2Ssommerfe sp->sdb_hashsize = size;
474fb87b5d2Ssommerfe if (sadb_init_fanout(&sp->sdb_of, size, kmflag) != 0)
475fb87b5d2Ssommerfe return (ENOMEM);
476fb87b5d2Ssommerfe if (sadb_init_fanout(&sp->sdb_if, size, kmflag) != 0)
477fb87b5d2Ssommerfe return (ENOMEM);
478fb87b5d2Ssommerfe if (sadb_init_acfanout(&sp->sdb_acq, size, kmflag) != 0)
479fb87b5d2Ssommerfe return (ENOMEM);
480fb87b5d2Ssommerfe
481fb87b5d2Ssommerfe return (0);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate /*
485fb87b5d2Ssommerfe * Call me to initialize an SADB instance; fall back to default size on failure.
486fb87b5d2Ssommerfe */
487fb87b5d2Ssommerfe static void
sadb_init(const char * name,sadb_t * sp,uint_t size,uint_t ver,netstack_t * ns)488f4b3ec61Sdh155122 sadb_init(const char *name, sadb_t *sp, uint_t size, uint_t ver,
489f4b3ec61Sdh155122 netstack_t *ns)
490fb87b5d2Ssommerfe {
491fb87b5d2Ssommerfe ASSERT(sp->sdb_of == NULL);
492fb87b5d2Ssommerfe ASSERT(sp->sdb_if == NULL);
493fb87b5d2Ssommerfe ASSERT(sp->sdb_acq == NULL);
494fb87b5d2Ssommerfe
495fb87b5d2Ssommerfe if (size < IPSEC_DEFAULT_HASH_SIZE)
496fb87b5d2Ssommerfe size = IPSEC_DEFAULT_HASH_SIZE;
497fb87b5d2Ssommerfe
498fb87b5d2Ssommerfe if (sadb_init_trial(sp, size, KM_NOSLEEP) != 0) {
499fb87b5d2Ssommerfe
500fb87b5d2Ssommerfe cmn_err(CE_WARN,
501fb87b5d2Ssommerfe "Unable to allocate %u entry IPv%u %s SADB hash table",
502fb87b5d2Ssommerfe size, ver, name);
503fb87b5d2Ssommerfe
504f4b3ec61Sdh155122 sadb_destroy(sp, ns);
505fb87b5d2Ssommerfe size = IPSEC_DEFAULT_HASH_SIZE;
506fb87b5d2Ssommerfe cmn_err(CE_WARN, "Falling back to %d entries", size);
507fb87b5d2Ssommerfe (void) sadb_init_trial(sp, size, KM_SLEEP);
508fb87b5d2Ssommerfe }
509fb87b5d2Ssommerfe }
510fb87b5d2Ssommerfe
511fb87b5d2Ssommerfe
512fb87b5d2Ssommerfe /*
5137c478bd9Sstevel@tonic-gate * Initialize an SADB-pair.
5147c478bd9Sstevel@tonic-gate */
5157c478bd9Sstevel@tonic-gate void
sadbp_init(const char * name,sadbp_t * sp,int type,int size,netstack_t * ns)516f4b3ec61Sdh155122 sadbp_init(const char *name, sadbp_t *sp, int type, int size, netstack_t *ns)
5177c478bd9Sstevel@tonic-gate {
518f4b3ec61Sdh155122 sadb_init(name, &sp->s_v4, size, 4, ns);
519f4b3ec61Sdh155122 sadb_init(name, &sp->s_v6, size, 6, ns);
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate sp->s_satype = type;
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate ASSERT((type == SADB_SATYPE_AH) || (type == SADB_SATYPE_ESP));
524f4b3ec61Sdh155122 if (type == SADB_SATYPE_AH) {
525f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec;
526f4b3ec61Sdh155122
527f4b3ec61Sdh155122 ip_drop_register(&ipss->ipsec_sadb_dropper, "IPsec SADB");
52872bd9b6bSdanmcd sp->s_addflags = AH_ADD_SETTABLE_FLAGS;
52972bd9b6bSdanmcd sp->s_updateflags = AH_UPDATE_SETTABLE_FLAGS;
53072bd9b6bSdanmcd } else {
53172bd9b6bSdanmcd sp->s_addflags = ESP_ADD_SETTABLE_FLAGS;
53272bd9b6bSdanmcd sp->s_updateflags = ESP_UPDATE_SETTABLE_FLAGS;
533f4b3ec61Sdh155122 }
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate /*
5377c478bd9Sstevel@tonic-gate * Deliver a single SADB_DUMP message representing a single SA. This is
5387c478bd9Sstevel@tonic-gate * called many times by sadb_dump().
5397c478bd9Sstevel@tonic-gate *
5407c478bd9Sstevel@tonic-gate * If the return value of this is ENOBUFS (not the same as ENOMEM), then
5417c478bd9Sstevel@tonic-gate * the caller should take that as a hint that dupb() on the "original answer"
5427c478bd9Sstevel@tonic-gate * failed, and that perhaps the caller should try again with a copyb()ed
5437c478bd9Sstevel@tonic-gate * "original answer".
5447c478bd9Sstevel@tonic-gate */
5457c478bd9Sstevel@tonic-gate static int
sadb_dump_deliver(queue_t * pfkey_q,mblk_t * original_answer,ipsa_t * ipsa,sadb_msg_t * samsg)5467c478bd9Sstevel@tonic-gate sadb_dump_deliver(queue_t *pfkey_q, mblk_t *original_answer, ipsa_t *ipsa,
5477c478bd9Sstevel@tonic-gate sadb_msg_t *samsg)
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate mblk_t *answer;
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate answer = dupb(original_answer);
5527c478bd9Sstevel@tonic-gate if (answer == NULL)
5537c478bd9Sstevel@tonic-gate return (ENOBUFS);
5547c478bd9Sstevel@tonic-gate answer->b_cont = sadb_sa2msg(ipsa, samsg);
5557c478bd9Sstevel@tonic-gate if (answer->b_cont == NULL) {
5567c478bd9Sstevel@tonic-gate freeb(answer);
5577c478bd9Sstevel@tonic-gate return (ENOMEM);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate /* Just do a putnext, and let keysock deal with flow control. */
5617c478bd9Sstevel@tonic-gate putnext(pfkey_q, answer);
5627c478bd9Sstevel@tonic-gate return (0);
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate /*
5667c478bd9Sstevel@tonic-gate * Common function to allocate and prepare a keysock_out_t M_CTL message.
5677c478bd9Sstevel@tonic-gate */
5687c478bd9Sstevel@tonic-gate mblk_t *
sadb_keysock_out(minor_t serial)5697c478bd9Sstevel@tonic-gate sadb_keysock_out(minor_t serial)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate mblk_t *mp;
5727c478bd9Sstevel@tonic-gate keysock_out_t *kso;
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate mp = allocb(sizeof (ipsec_info_t), BPRI_HI);
5757c478bd9Sstevel@tonic-gate if (mp != NULL) {
5767c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_CTL;
5777c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (ipsec_info_t);
5787c478bd9Sstevel@tonic-gate kso = (keysock_out_t *)mp->b_rptr;
5797c478bd9Sstevel@tonic-gate kso->ks_out_type = KEYSOCK_OUT;
5807c478bd9Sstevel@tonic-gate kso->ks_out_len = sizeof (*kso);
5817c478bd9Sstevel@tonic-gate kso->ks_out_serial = serial;
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate return (mp);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate * Perform an SADB_DUMP, spewing out every SA in an array of SA fanouts
5897c478bd9Sstevel@tonic-gate * to keysock.
5907c478bd9Sstevel@tonic-gate */
5917c478bd9Sstevel@tonic-gate static int
sadb_dump_fanout(queue_t * pfkey_q,mblk_t * mp,minor_t serial,isaf_t * fanout,int num_entries,boolean_t do_peers,time_t active_time)5927c478bd9Sstevel@tonic-gate sadb_dump_fanout(queue_t *pfkey_q, mblk_t *mp, minor_t serial, isaf_t *fanout,
5939c2c14abSThejaswini Singarajipura int num_entries, boolean_t do_peers, time_t active_time)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate int i, error = 0;
5967c478bd9Sstevel@tonic-gate mblk_t *original_answer;
5977c478bd9Sstevel@tonic-gate ipsa_t *walker;
5987c478bd9Sstevel@tonic-gate sadb_msg_t *samsg;
5999c2c14abSThejaswini Singarajipura time_t current;
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate /*
6027c478bd9Sstevel@tonic-gate * For each IPSA hash bucket do:
6037c478bd9Sstevel@tonic-gate * - Hold the mutex
6047c478bd9Sstevel@tonic-gate * - Walk each entry, doing an sadb_dump_deliver() on it.
6057c478bd9Sstevel@tonic-gate */
6067c478bd9Sstevel@tonic-gate ASSERT(mp->b_cont != NULL);
6077c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate original_answer = sadb_keysock_out(serial);
6107c478bd9Sstevel@tonic-gate if (original_answer == NULL)
6117c478bd9Sstevel@tonic-gate return (ENOMEM);
6127c478bd9Sstevel@tonic-gate
6139c2c14abSThejaswini Singarajipura current = gethrestime_sec();
6147c478bd9Sstevel@tonic-gate for (i = 0; i < num_entries; i++) {
6157c478bd9Sstevel@tonic-gate mutex_enter(&fanout[i].isaf_lock);
6167c478bd9Sstevel@tonic-gate for (walker = fanout[i].isaf_ipsa; walker != NULL;
6177c478bd9Sstevel@tonic-gate walker = walker->ipsa_next) {
6187c478bd9Sstevel@tonic-gate if (!do_peers && walker->ipsa_haspeer)
6197c478bd9Sstevel@tonic-gate continue;
6209c2c14abSThejaswini Singarajipura if ((active_time != 0) &&
6219c2c14abSThejaswini Singarajipura ((current - walker->ipsa_lastuse) > active_time))
6229c2c14abSThejaswini Singarajipura continue;
6237c478bd9Sstevel@tonic-gate error = sadb_dump_deliver(pfkey_q, original_answer,
6247c478bd9Sstevel@tonic-gate walker, samsg);
6257c478bd9Sstevel@tonic-gate if (error == ENOBUFS) {
6267c478bd9Sstevel@tonic-gate mblk_t *new_original_answer;
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate /* Ran out of dupb's. Try a copyb. */
6297c478bd9Sstevel@tonic-gate new_original_answer = copyb(original_answer);
6307c478bd9Sstevel@tonic-gate if (new_original_answer == NULL) {
6317c478bd9Sstevel@tonic-gate error = ENOMEM;
6327c478bd9Sstevel@tonic-gate } else {
6337c478bd9Sstevel@tonic-gate freeb(original_answer);
6347c478bd9Sstevel@tonic-gate original_answer = new_original_answer;
6357c478bd9Sstevel@tonic-gate error = sadb_dump_deliver(pfkey_q,
6367c478bd9Sstevel@tonic-gate original_answer, walker, samsg);
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate if (error != 0)
6407c478bd9Sstevel@tonic-gate break; /* out of for loop. */
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate mutex_exit(&fanout[i].isaf_lock);
6437c478bd9Sstevel@tonic-gate if (error != 0)
6447c478bd9Sstevel@tonic-gate break; /* out of for loop. */
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate freeb(original_answer);
6487c478bd9Sstevel@tonic-gate return (error);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate * Dump an entire SADB; outbound first, then inbound.
6537c478bd9Sstevel@tonic-gate */
6547c478bd9Sstevel@tonic-gate
6557c478bd9Sstevel@tonic-gate int
sadb_dump(queue_t * pfkey_q,mblk_t * mp,keysock_in_t * ksi,sadb_t * sp)6569c2c14abSThejaswini Singarajipura sadb_dump(queue_t *pfkey_q, mblk_t *mp, keysock_in_t *ksi, sadb_t *sp)
6577c478bd9Sstevel@tonic-gate {
6587c478bd9Sstevel@tonic-gate int error;
6599c2c14abSThejaswini Singarajipura time_t active_time = 0;
6609c2c14abSThejaswini Singarajipura sadb_x_edump_t *edump =
6619c2c14abSThejaswini Singarajipura (sadb_x_edump_t *)ksi->ks_in_extv[SADB_X_EXT_EDUMP];
6629c2c14abSThejaswini Singarajipura
6639c2c14abSThejaswini Singarajipura if (edump != NULL) {
6649c2c14abSThejaswini Singarajipura active_time = edump->sadb_x_edump_timeout;
6659c2c14abSThejaswini Singarajipura }
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate /* Dump outbound */
6689c2c14abSThejaswini Singarajipura error = sadb_dump_fanout(pfkey_q, mp, ksi->ks_in_serial, sp->sdb_of,
6699c2c14abSThejaswini Singarajipura sp->sdb_hashsize, B_TRUE, active_time);
6707c478bd9Sstevel@tonic-gate if (error)
6717c478bd9Sstevel@tonic-gate return (error);
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate /* Dump inbound */
6749c2c14abSThejaswini Singarajipura return sadb_dump_fanout(pfkey_q, mp, ksi->ks_in_serial, sp->sdb_if,
6759c2c14abSThejaswini Singarajipura sp->sdb_hashsize, B_FALSE, active_time);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate /*
6797c478bd9Sstevel@tonic-gate * Generic sadb table walker.
6807c478bd9Sstevel@tonic-gate *
6817c478bd9Sstevel@tonic-gate * Call "walkfn" for each SA in each bucket in "table"; pass the
6827c478bd9Sstevel@tonic-gate * bucket, the entry and "cookie" to the callback function.
6837c478bd9Sstevel@tonic-gate * Take care to ensure that walkfn can delete the SA without screwing
6847c478bd9Sstevel@tonic-gate * up our traverse.
6857c478bd9Sstevel@tonic-gate *
6867c478bd9Sstevel@tonic-gate * The bucket is locked for the duration of the callback, both so that the
6877c478bd9Sstevel@tonic-gate * callback can just call sadb_unlinkassoc() when it wants to delete something,
6887c478bd9Sstevel@tonic-gate * and so that no new entries are added while we're walking the list.
6897c478bd9Sstevel@tonic-gate */
6907c478bd9Sstevel@tonic-gate static void
sadb_walker(isaf_t * table,uint_t numentries,void (* walkfn)(isaf_t * head,ipsa_t * entry,void * cookie),void * cookie)6917c478bd9Sstevel@tonic-gate sadb_walker(isaf_t *table, uint_t numentries,
6927c478bd9Sstevel@tonic-gate void (*walkfn)(isaf_t *head, ipsa_t *entry, void *cookie),
6937c478bd9Sstevel@tonic-gate void *cookie)
6947c478bd9Sstevel@tonic-gate {
6957c478bd9Sstevel@tonic-gate int i;
6967c478bd9Sstevel@tonic-gate for (i = 0; i < numentries; i++) {
6977c478bd9Sstevel@tonic-gate ipsa_t *entry, *next;
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate mutex_enter(&table[i].isaf_lock);
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate for (entry = table[i].isaf_ipsa; entry != NULL;
7027c478bd9Sstevel@tonic-gate entry = next) {
7037c478bd9Sstevel@tonic-gate next = entry->ipsa_next;
7047c478bd9Sstevel@tonic-gate (*walkfn)(&table[i], entry, cookie);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate mutex_exit(&table[i].isaf_lock);
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate * Call me to free up a security association fanout. Use the forever
7127c478bd9Sstevel@tonic-gate * variable to indicate freeing up the SAs (forever == B_FALSE, e.g.
7137c478bd9Sstevel@tonic-gate * an SADB_FLUSH message), or destroying everything (forever == B_TRUE,
7147c478bd9Sstevel@tonic-gate * when a module is unloaded).
7157c478bd9Sstevel@tonic-gate */
7167c478bd9Sstevel@tonic-gate static void
sadb_destroyer(isaf_t ** tablep,uint_t numentries,boolean_t forever,boolean_t inbound)7179c2c14abSThejaswini Singarajipura sadb_destroyer(isaf_t **tablep, uint_t numentries, boolean_t forever,
7189c2c14abSThejaswini Singarajipura boolean_t inbound)
7197c478bd9Sstevel@tonic-gate {
7207c478bd9Sstevel@tonic-gate int i;
721fb87b5d2Ssommerfe isaf_t *table = *tablep;
7229c2c14abSThejaswini Singarajipura uint8_t protocol;
7238e4b770fSLu Huafeng ipsa_t *sa;
7248e4b770fSLu Huafeng netstackid_t sid;
725fb87b5d2Ssommerfe
726fb87b5d2Ssommerfe if (table == NULL)
727fb87b5d2Ssommerfe return;
7287c478bd9Sstevel@tonic-gate
7297c478bd9Sstevel@tonic-gate for (i = 0; i < numentries; i++) {
7307c478bd9Sstevel@tonic-gate mutex_enter(&table[i].isaf_lock);
7318e4b770fSLu Huafeng while ((sa = table[i].isaf_ipsa) != NULL) {
7329c2c14abSThejaswini Singarajipura if (inbound && cl_inet_deletespi &&
7338e4b770fSLu Huafeng (sa->ipsa_state != IPSA_STATE_ACTIVE_ELSEWHERE) &&
7348e4b770fSLu Huafeng (sa->ipsa_state != IPSA_STATE_IDLE)) {
7358e4b770fSLu Huafeng protocol = (sa->ipsa_type == SADB_SATYPE_AH) ?
7368e4b770fSLu Huafeng IPPROTO_AH : IPPROTO_ESP;
7378e4b770fSLu Huafeng sid = sa->ipsa_netstack->netstack_stackid;
7388e4b770fSLu Huafeng cl_inet_deletespi(sid, protocol, sa->ipsa_spi,
7398e4b770fSLu Huafeng NULL);
7409c2c14abSThejaswini Singarajipura }
7418e4b770fSLu Huafeng sadb_unlinkassoc(sa);
7429c2c14abSThejaswini Singarajipura }
7437c478bd9Sstevel@tonic-gate table[i].isaf_gen++;
7447c478bd9Sstevel@tonic-gate mutex_exit(&table[i].isaf_lock);
7457c478bd9Sstevel@tonic-gate if (forever)
7467c478bd9Sstevel@tonic-gate mutex_destroy(&(table[i].isaf_lock));
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate
749fb87b5d2Ssommerfe if (forever) {
750fb87b5d2Ssommerfe *tablep = NULL;
7517c478bd9Sstevel@tonic-gate kmem_free(table, numentries * sizeof (*table));
7527c478bd9Sstevel@tonic-gate }
753fb87b5d2Ssommerfe }
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate /*
7567c478bd9Sstevel@tonic-gate * Entry points to sadb_destroyer().
7577c478bd9Sstevel@tonic-gate */
7587c478bd9Sstevel@tonic-gate static void
sadb_flush(sadb_t * sp,netstack_t * ns)759f4b3ec61Sdh155122 sadb_flush(sadb_t *sp, netstack_t *ns)
7607c478bd9Sstevel@tonic-gate {
7617c478bd9Sstevel@tonic-gate /*
7627c478bd9Sstevel@tonic-gate * Flush out each bucket, one at a time. Were it not for keysock's
7637c478bd9Sstevel@tonic-gate * enforcement, there would be a subtlety where I could add on the
7647c478bd9Sstevel@tonic-gate * heels of a flush. With keysock's enforcement, however, this
7657c478bd9Sstevel@tonic-gate * makes ESP's job easy.
7667c478bd9Sstevel@tonic-gate */
7679c2c14abSThejaswini Singarajipura sadb_destroyer(&sp->sdb_of, sp->sdb_hashsize, B_FALSE, B_FALSE);
7689c2c14abSThejaswini Singarajipura sadb_destroyer(&sp->sdb_if, sp->sdb_hashsize, B_FALSE, B_TRUE);
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate /* For each acquire, destroy it; leave the bucket mutex alone. */
771f4b3ec61Sdh155122 sadb_destroy_acqlist(&sp->sdb_acq, sp->sdb_hashsize, B_FALSE, ns);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate
7747c478bd9Sstevel@tonic-gate static void
sadb_destroy(sadb_t * sp,netstack_t * ns)775f4b3ec61Sdh155122 sadb_destroy(sadb_t *sp, netstack_t *ns)
7767c478bd9Sstevel@tonic-gate {
7779c2c14abSThejaswini Singarajipura sadb_destroyer(&sp->sdb_of, sp->sdb_hashsize, B_TRUE, B_FALSE);
7789c2c14abSThejaswini Singarajipura sadb_destroyer(&sp->sdb_if, sp->sdb_hashsize, B_TRUE, B_TRUE);
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate /* For each acquire, destroy it, including the bucket mutex. */
781f4b3ec61Sdh155122 sadb_destroy_acqlist(&sp->sdb_acq, sp->sdb_hashsize, B_TRUE, ns);
782fb87b5d2Ssommerfe
783fb87b5d2Ssommerfe ASSERT(sp->sdb_of == NULL);
784fb87b5d2Ssommerfe ASSERT(sp->sdb_if == NULL);
785fb87b5d2Ssommerfe ASSERT(sp->sdb_acq == NULL);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate void
sadbp_flush(sadbp_t * spp,netstack_t * ns)789f4b3ec61Sdh155122 sadbp_flush(sadbp_t *spp, netstack_t *ns)
7907c478bd9Sstevel@tonic-gate {
791f4b3ec61Sdh155122 sadb_flush(&spp->s_v4, ns);
792f4b3ec61Sdh155122 sadb_flush(&spp->s_v6, ns);
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate void
sadbp_destroy(sadbp_t * spp,netstack_t * ns)796f4b3ec61Sdh155122 sadbp_destroy(sadbp_t *spp, netstack_t *ns)
7977c478bd9Sstevel@tonic-gate {
798f4b3ec61Sdh155122 sadb_destroy(&spp->s_v4, ns);
799f4b3ec61Sdh155122 sadb_destroy(&spp->s_v6, ns);
8007c478bd9Sstevel@tonic-gate
801f4b3ec61Sdh155122 if (spp->s_satype == SADB_SATYPE_AH) {
802f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec;
803f4b3ec61Sdh155122
804f4b3ec61Sdh155122 ip_drop_unregister(&ipss->ipsec_sadb_dropper);
805f4b3ec61Sdh155122 }
8067c478bd9Sstevel@tonic-gate }
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate * Check hard vs. soft lifetimes. If there's a reality mismatch (e.g.
8117c478bd9Sstevel@tonic-gate * soft lifetimes > hard lifetimes) return an appropriate diagnostic for
8127c478bd9Sstevel@tonic-gate * EINVAL.
8137c478bd9Sstevel@tonic-gate */
8147c478bd9Sstevel@tonic-gate int
sadb_hardsoftchk(sadb_lifetime_t * hard,sadb_lifetime_t * soft,sadb_lifetime_t * idle)8159c2c14abSThejaswini Singarajipura sadb_hardsoftchk(sadb_lifetime_t *hard, sadb_lifetime_t *soft,
8169c2c14abSThejaswini Singarajipura sadb_lifetime_t *idle)
8177c478bd9Sstevel@tonic-gate {
8187c478bd9Sstevel@tonic-gate if (hard == NULL || soft == NULL)
8197c478bd9Sstevel@tonic-gate return (0);
8207c478bd9Sstevel@tonic-gate
8217c478bd9Sstevel@tonic-gate if (hard->sadb_lifetime_allocations != 0 &&
8227c478bd9Sstevel@tonic-gate soft->sadb_lifetime_allocations != 0 &&
8237c478bd9Sstevel@tonic-gate hard->sadb_lifetime_allocations < soft->sadb_lifetime_allocations)
8247c478bd9Sstevel@tonic-gate return (SADB_X_DIAGNOSTIC_ALLOC_HSERR);
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate if (hard->sadb_lifetime_bytes != 0 &&
8277c478bd9Sstevel@tonic-gate soft->sadb_lifetime_bytes != 0 &&
8287c478bd9Sstevel@tonic-gate hard->sadb_lifetime_bytes < soft->sadb_lifetime_bytes)
8297c478bd9Sstevel@tonic-gate return (SADB_X_DIAGNOSTIC_BYTES_HSERR);
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate if (hard->sadb_lifetime_addtime != 0 &&
8327c478bd9Sstevel@tonic-gate soft->sadb_lifetime_addtime != 0 &&
8337c478bd9Sstevel@tonic-gate hard->sadb_lifetime_addtime < soft->sadb_lifetime_addtime)
8347c478bd9Sstevel@tonic-gate return (SADB_X_DIAGNOSTIC_ADDTIME_HSERR);
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate if (hard->sadb_lifetime_usetime != 0 &&
8377c478bd9Sstevel@tonic-gate soft->sadb_lifetime_usetime != 0 &&
8387c478bd9Sstevel@tonic-gate hard->sadb_lifetime_usetime < soft->sadb_lifetime_usetime)
8397c478bd9Sstevel@tonic-gate return (SADB_X_DIAGNOSTIC_USETIME_HSERR);
8407c478bd9Sstevel@tonic-gate
8419c2c14abSThejaswini Singarajipura if (idle != NULL) {
8429c2c14abSThejaswini Singarajipura if (hard->sadb_lifetime_addtime != 0 &&
8439c2c14abSThejaswini Singarajipura idle->sadb_lifetime_addtime != 0 &&
8449c2c14abSThejaswini Singarajipura hard->sadb_lifetime_addtime < idle->sadb_lifetime_addtime)
8459c2c14abSThejaswini Singarajipura return (SADB_X_DIAGNOSTIC_ADDTIME_HSERR);
8469c2c14abSThejaswini Singarajipura
8479c2c14abSThejaswini Singarajipura if (soft->sadb_lifetime_addtime != 0 &&
8489c2c14abSThejaswini Singarajipura idle->sadb_lifetime_addtime != 0 &&
8499c2c14abSThejaswini Singarajipura soft->sadb_lifetime_addtime < idle->sadb_lifetime_addtime)
8509c2c14abSThejaswini Singarajipura return (SADB_X_DIAGNOSTIC_ADDTIME_HSERR);
8519c2c14abSThejaswini Singarajipura
8529c2c14abSThejaswini Singarajipura if (hard->sadb_lifetime_usetime != 0 &&
8539c2c14abSThejaswini Singarajipura idle->sadb_lifetime_usetime != 0 &&
8549c2c14abSThejaswini Singarajipura hard->sadb_lifetime_usetime < idle->sadb_lifetime_usetime)
8559c2c14abSThejaswini Singarajipura return (SADB_X_DIAGNOSTIC_USETIME_HSERR);
8569c2c14abSThejaswini Singarajipura
8579c2c14abSThejaswini Singarajipura if (soft->sadb_lifetime_usetime != 0 &&
8589c2c14abSThejaswini Singarajipura idle->sadb_lifetime_usetime != 0 &&
8599c2c14abSThejaswini Singarajipura soft->sadb_lifetime_usetime < idle->sadb_lifetime_usetime)
8609c2c14abSThejaswini Singarajipura return (SADB_X_DIAGNOSTIC_USETIME_HSERR);
8619c2c14abSThejaswini Singarajipura }
8629c2c14abSThejaswini Singarajipura
8637c478bd9Sstevel@tonic-gate return (0);
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate /*
8675d3b8cb7SBill Sommerfeld * Sanity check sensitivity labels.
8685d3b8cb7SBill Sommerfeld *
8695d3b8cb7SBill Sommerfeld * For now, just reject labels on unlabeled systems.
8705d3b8cb7SBill Sommerfeld */
8715d3b8cb7SBill Sommerfeld int
sadb_labelchk(keysock_in_t * ksi)8725d3b8cb7SBill Sommerfeld sadb_labelchk(keysock_in_t *ksi)
8735d3b8cb7SBill Sommerfeld {
8745d3b8cb7SBill Sommerfeld if (!is_system_labeled()) {
8755d3b8cb7SBill Sommerfeld if (ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL)
8765d3b8cb7SBill Sommerfeld return (SADB_X_DIAGNOSTIC_BAD_LABEL);
8775d3b8cb7SBill Sommerfeld
8785d3b8cb7SBill Sommerfeld if (ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS] != NULL)
8795d3b8cb7SBill Sommerfeld return (SADB_X_DIAGNOSTIC_BAD_LABEL);
8805d3b8cb7SBill Sommerfeld }
8815d3b8cb7SBill Sommerfeld
8825d3b8cb7SBill Sommerfeld return (0);
8835d3b8cb7SBill Sommerfeld }
8845d3b8cb7SBill Sommerfeld
8855d3b8cb7SBill Sommerfeld /*
8867c478bd9Sstevel@tonic-gate * Clone a security association for the purposes of inserting a single SA
88738d95a78Smarkfen * into inbound and outbound tables respectively. This function should only
88838d95a78Smarkfen * be called from sadb_common_add().
8897c478bd9Sstevel@tonic-gate */
8907c478bd9Sstevel@tonic-gate static ipsa_t *
sadb_cloneassoc(ipsa_t * ipsa)8917c478bd9Sstevel@tonic-gate sadb_cloneassoc(ipsa_t *ipsa)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate ipsa_t *newbie;
8947c478bd9Sstevel@tonic-gate boolean_t error = B_FALSE;
8957c478bd9Sstevel@tonic-gate
8960c0328cdSBill Sommerfeld ASSERT(MUTEX_NOT_HELD(&(ipsa->ipsa_lock)));
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate newbie = kmem_alloc(sizeof (ipsa_t), KM_NOSLEEP);
8997c478bd9Sstevel@tonic-gate if (newbie == NULL)
9007c478bd9Sstevel@tonic-gate return (NULL);
9017c478bd9Sstevel@tonic-gate
9027c478bd9Sstevel@tonic-gate /* Copy over what we can. */
9037c478bd9Sstevel@tonic-gate *newbie = *ipsa;
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate /* bzero and initialize locks, in case *_init() allocates... */
9067c478bd9Sstevel@tonic-gate mutex_init(&newbie->ipsa_lock, NULL, MUTEX_DEFAULT, NULL);
9077c478bd9Sstevel@tonic-gate
908bd670b35SErik Nordmark if (newbie->ipsa_tsl != NULL)
909bd670b35SErik Nordmark label_hold(newbie->ipsa_tsl);
9105d3b8cb7SBill Sommerfeld
911bd670b35SErik Nordmark if (newbie->ipsa_otsl != NULL)
912bd670b35SErik Nordmark label_hold(newbie->ipsa_otsl);
9135d3b8cb7SBill Sommerfeld
9147c478bd9Sstevel@tonic-gate /*
9157c478bd9Sstevel@tonic-gate * While somewhat dain-bramaged, the most graceful way to
9167c478bd9Sstevel@tonic-gate * recover from errors is to keep plowing through the
9177c478bd9Sstevel@tonic-gate * allocations, and getting what I can. It's easier to call
9187c478bd9Sstevel@tonic-gate * sadb_freeassoc() on the stillborn clone when all the
9197c478bd9Sstevel@tonic-gate * pointers aren't pointing to the parent's data.
9207c478bd9Sstevel@tonic-gate */
9217c478bd9Sstevel@tonic-gate
9227c478bd9Sstevel@tonic-gate if (ipsa->ipsa_authkey != NULL) {
9237c478bd9Sstevel@tonic-gate newbie->ipsa_authkey = kmem_alloc(newbie->ipsa_authkeylen,
9247c478bd9Sstevel@tonic-gate KM_NOSLEEP);
9257c478bd9Sstevel@tonic-gate if (newbie->ipsa_authkey == NULL) {
9267c478bd9Sstevel@tonic-gate error = B_TRUE;
9277c478bd9Sstevel@tonic-gate } else {
9287c478bd9Sstevel@tonic-gate bcopy(ipsa->ipsa_authkey, newbie->ipsa_authkey,
9297c478bd9Sstevel@tonic-gate newbie->ipsa_authkeylen);
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate newbie->ipsa_kcfauthkey.ck_data =
9327c478bd9Sstevel@tonic-gate newbie->ipsa_authkey;
9337c478bd9Sstevel@tonic-gate }
9347c478bd9Sstevel@tonic-gate
9357c478bd9Sstevel@tonic-gate if (newbie->ipsa_amech.cm_param != NULL) {
9367c478bd9Sstevel@tonic-gate newbie->ipsa_amech.cm_param =
9377c478bd9Sstevel@tonic-gate (char *)&newbie->ipsa_mac_len;
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate if (ipsa->ipsa_encrkey != NULL) {
9427c478bd9Sstevel@tonic-gate newbie->ipsa_encrkey = kmem_alloc(newbie->ipsa_encrkeylen,
9437c478bd9Sstevel@tonic-gate KM_NOSLEEP);
9447c478bd9Sstevel@tonic-gate if (newbie->ipsa_encrkey == NULL) {
9457c478bd9Sstevel@tonic-gate error = B_TRUE;
9467c478bd9Sstevel@tonic-gate } else {
9477c478bd9Sstevel@tonic-gate bcopy(ipsa->ipsa_encrkey, newbie->ipsa_encrkey,
9487c478bd9Sstevel@tonic-gate newbie->ipsa_encrkeylen);
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate newbie->ipsa_kcfencrkey.ck_data =
9517c478bd9Sstevel@tonic-gate newbie->ipsa_encrkey;
9527c478bd9Sstevel@tonic-gate }
9537c478bd9Sstevel@tonic-gate }
9547c478bd9Sstevel@tonic-gate
9557c478bd9Sstevel@tonic-gate newbie->ipsa_authtmpl = NULL;
9567c478bd9Sstevel@tonic-gate newbie->ipsa_encrtmpl = NULL;
95738d95a78Smarkfen newbie->ipsa_haspeer = B_TRUE;
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate if (ipsa->ipsa_src_cid != NULL) {
9607c478bd9Sstevel@tonic-gate newbie->ipsa_src_cid = ipsa->ipsa_src_cid;
9617c478bd9Sstevel@tonic-gate IPSID_REFHOLD(ipsa->ipsa_src_cid);
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate if (ipsa->ipsa_dst_cid != NULL) {
9657c478bd9Sstevel@tonic-gate newbie->ipsa_dst_cid = ipsa->ipsa_dst_cid;
9667c478bd9Sstevel@tonic-gate IPSID_REFHOLD(ipsa->ipsa_dst_cid);
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate if (error) {
9707c478bd9Sstevel@tonic-gate sadb_freeassoc(newbie);
9717c478bd9Sstevel@tonic-gate return (NULL);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate return (newbie);
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate
9777c478bd9Sstevel@tonic-gate /*
9787c478bd9Sstevel@tonic-gate * Initialize a SADB address extension at the address specified by addrext.
9797c478bd9Sstevel@tonic-gate * Return a pointer to the end of the new address extension.
9807c478bd9Sstevel@tonic-gate */
9817c478bd9Sstevel@tonic-gate static uint8_t *
sadb_make_addr_ext(uint8_t * start,uint8_t * end,uint16_t exttype,sa_family_t af,uint32_t * addr,uint16_t port,uint8_t proto,int prefix)9827c478bd9Sstevel@tonic-gate sadb_make_addr_ext(uint8_t *start, uint8_t *end, uint16_t exttype,
9838810c16bSdanmcd sa_family_t af, uint32_t *addr, uint16_t port, uint8_t proto, int prefix)
9847c478bd9Sstevel@tonic-gate {
9857c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
9867c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6;
9877c478bd9Sstevel@tonic-gate uint8_t *cur = start;
9887c478bd9Sstevel@tonic-gate int addrext_len;
9897c478bd9Sstevel@tonic-gate int sin_len;
9907c478bd9Sstevel@tonic-gate sadb_address_t *addrext = (sadb_address_t *)cur;
9917c478bd9Sstevel@tonic-gate
9927c478bd9Sstevel@tonic-gate if (cur == NULL)
9937c478bd9Sstevel@tonic-gate return (NULL);
9947c478bd9Sstevel@tonic-gate
9957c478bd9Sstevel@tonic-gate cur += sizeof (*addrext);
9967c478bd9Sstevel@tonic-gate if (cur > end)
9977c478bd9Sstevel@tonic-gate return (NULL);
9987c478bd9Sstevel@tonic-gate
9997c478bd9Sstevel@tonic-gate addrext->sadb_address_proto = proto;
10008810c16bSdanmcd addrext->sadb_address_prefixlen = prefix;
10017c478bd9Sstevel@tonic-gate addrext->sadb_address_reserved = 0;
10027c478bd9Sstevel@tonic-gate addrext->sadb_address_exttype = exttype;
10037c478bd9Sstevel@tonic-gate
10047c478bd9Sstevel@tonic-gate switch (af) {
10057c478bd9Sstevel@tonic-gate case AF_INET:
10067c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)cur;
10077c478bd9Sstevel@tonic-gate sin_len = sizeof (*sin);
10087c478bd9Sstevel@tonic-gate cur += sin_len;
10097c478bd9Sstevel@tonic-gate if (cur > end)
10107c478bd9Sstevel@tonic-gate return (NULL);
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate sin->sin_family = af;
10137c478bd9Sstevel@tonic-gate bzero(sin->sin_zero, sizeof (sin->sin_zero));
10147c478bd9Sstevel@tonic-gate sin->sin_port = port;
10157c478bd9Sstevel@tonic-gate IPSA_COPY_ADDR(&sin->sin_addr, addr, af);
10167c478bd9Sstevel@tonic-gate break;
10177c478bd9Sstevel@tonic-gate case AF_INET6:
10187c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cur;
10197c478bd9Sstevel@tonic-gate sin_len = sizeof (*sin6);
10207c478bd9Sstevel@tonic-gate cur += sin_len;
10217c478bd9Sstevel@tonic-gate if (cur > end)
10227c478bd9Sstevel@tonic-gate return (NULL);
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (*sin6));
10257c478bd9Sstevel@tonic-gate sin6->sin6_family = af;
10267c478bd9Sstevel@tonic-gate sin6->sin6_port = port;
10277c478bd9Sstevel@tonic-gate IPSA_COPY_ADDR(&sin6->sin6_addr, addr, af);
10287c478bd9Sstevel@tonic-gate break;
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate addrext_len = roundup(cur - start, sizeof (uint64_t));
10327c478bd9Sstevel@tonic-gate addrext->sadb_address_len = SADB_8TO64(addrext_len);
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate cur = start + addrext_len;
10357c478bd9Sstevel@tonic-gate if (cur > end)
10367c478bd9Sstevel@tonic-gate cur = NULL;
10377c478bd9Sstevel@tonic-gate
10387c478bd9Sstevel@tonic-gate return (cur);
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate
10417c478bd9Sstevel@tonic-gate /*
10427c478bd9Sstevel@tonic-gate * Construct a key management cookie extension.
10437c478bd9Sstevel@tonic-gate */
10447c478bd9Sstevel@tonic-gate
10457c478bd9Sstevel@tonic-gate static uint8_t *
sadb_make_kmc_ext(uint8_t * cur,uint8_t * end,uint32_t kmp,uint32_t kmc)10467c478bd9Sstevel@tonic-gate sadb_make_kmc_ext(uint8_t *cur, uint8_t *end, uint32_t kmp, uint32_t kmc)
10477c478bd9Sstevel@tonic-gate {
10487c478bd9Sstevel@tonic-gate sadb_x_kmc_t *kmcext = (sadb_x_kmc_t *)cur;
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate if (cur == NULL)
10517c478bd9Sstevel@tonic-gate return (NULL);
10527c478bd9Sstevel@tonic-gate
10537c478bd9Sstevel@tonic-gate cur += sizeof (*kmcext);
10547c478bd9Sstevel@tonic-gate
10557c478bd9Sstevel@tonic-gate if (cur > end)
10567c478bd9Sstevel@tonic-gate return (NULL);
10577c478bd9Sstevel@tonic-gate
10587c478bd9Sstevel@tonic-gate kmcext->sadb_x_kmc_len = SADB_8TO64(sizeof (*kmcext));
10597c478bd9Sstevel@tonic-gate kmcext->sadb_x_kmc_exttype = SADB_X_EXT_KM_COOKIE;
10607c478bd9Sstevel@tonic-gate kmcext->sadb_x_kmc_proto = kmp;
10617c478bd9Sstevel@tonic-gate kmcext->sadb_x_kmc_cookie = kmc;
10627c478bd9Sstevel@tonic-gate kmcext->sadb_x_kmc_reserved = 0;
10637c478bd9Sstevel@tonic-gate
10647c478bd9Sstevel@tonic-gate return (cur);
10657c478bd9Sstevel@tonic-gate }
10667c478bd9Sstevel@tonic-gate
10677c478bd9Sstevel@tonic-gate /*
10687c478bd9Sstevel@tonic-gate * Given an original message header with sufficient space following it, and an
10697c478bd9Sstevel@tonic-gate * SA, construct a full PF_KEY message with all of the relevant extensions.
10707c478bd9Sstevel@tonic-gate * This is mostly used for SADB_GET, and SADB_DUMP.
10717c478bd9Sstevel@tonic-gate */
10728810c16bSdanmcd static mblk_t *
sadb_sa2msg(ipsa_t * ipsa,sadb_msg_t * samsg)10737c478bd9Sstevel@tonic-gate sadb_sa2msg(ipsa_t *ipsa, sadb_msg_t *samsg)
10747c478bd9Sstevel@tonic-gate {
10757c478bd9Sstevel@tonic-gate int alloclen, addrsize, paddrsize, authsize, encrsize;
10765d3b8cb7SBill Sommerfeld int srcidsize, dstidsize, senslen, osenslen;
10777c478bd9Sstevel@tonic-gate sa_family_t fam, pfam; /* Address family for SADB_EXT_ADDRESS */
10787c478bd9Sstevel@tonic-gate /* src/dst and proxy sockaddrs. */
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate * The following are pointers into the PF_KEY message this PF_KEY
10817c478bd9Sstevel@tonic-gate * message creates.
10827c478bd9Sstevel@tonic-gate */
10837c478bd9Sstevel@tonic-gate sadb_msg_t *newsamsg;
10847c478bd9Sstevel@tonic-gate sadb_sa_t *assoc;
10857c478bd9Sstevel@tonic-gate sadb_lifetime_t *lt;
10867c478bd9Sstevel@tonic-gate sadb_key_t *key;
10877c478bd9Sstevel@tonic-gate sadb_ident_t *ident;
10887c478bd9Sstevel@tonic-gate sadb_sens_t *sens;
10897c478bd9Sstevel@tonic-gate sadb_ext_t *walker; /* For when we need a generic ext. pointer. */
10909c2c14abSThejaswini Singarajipura sadb_x_replay_ctr_t *repl_ctr;
109138d95a78Smarkfen sadb_x_pair_t *pair_ext;
109238d95a78Smarkfen
10937c478bd9Sstevel@tonic-gate mblk_t *mp;
10947c478bd9Sstevel@tonic-gate uint8_t *cur, *end;
10957c478bd9Sstevel@tonic-gate /* These indicate the presence of the above extension fields. */
10965d3b8cb7SBill Sommerfeld boolean_t soft = B_FALSE, hard = B_FALSE;
10975d3b8cb7SBill Sommerfeld boolean_t isrc = B_FALSE, idst = B_FALSE;
10985d3b8cb7SBill Sommerfeld boolean_t auth = B_FALSE, encr = B_FALSE;
10995d3b8cb7SBill Sommerfeld boolean_t sensinteg = B_FALSE, osensinteg = B_FALSE;
11005d3b8cb7SBill Sommerfeld boolean_t srcid = B_FALSE, dstid = B_FALSE;
11019c2c14abSThejaswini Singarajipura boolean_t idle;
110238d95a78Smarkfen boolean_t paired;
110338d95a78Smarkfen uint32_t otherspi;
11047c478bd9Sstevel@tonic-gate
11057c478bd9Sstevel@tonic-gate /* First off, figure out the allocation length for this message. */
11067c478bd9Sstevel@tonic-gate /*
11077c478bd9Sstevel@tonic-gate * Constant stuff. This includes base, SA, address (src, dst),
11087c478bd9Sstevel@tonic-gate * and lifetime (current).
11097c478bd9Sstevel@tonic-gate */
11107c478bd9Sstevel@tonic-gate alloclen = sizeof (sadb_msg_t) + sizeof (sadb_sa_t) +
11117c478bd9Sstevel@tonic-gate sizeof (sadb_lifetime_t);
11127c478bd9Sstevel@tonic-gate
11137c478bd9Sstevel@tonic-gate fam = ipsa->ipsa_addrfam;
11147c478bd9Sstevel@tonic-gate switch (fam) {
11157c478bd9Sstevel@tonic-gate case AF_INET:
11167c478bd9Sstevel@tonic-gate addrsize = roundup(sizeof (struct sockaddr_in) +
11177c478bd9Sstevel@tonic-gate sizeof (sadb_address_t), sizeof (uint64_t));
11187c478bd9Sstevel@tonic-gate break;
11197c478bd9Sstevel@tonic-gate case AF_INET6:
11207c478bd9Sstevel@tonic-gate addrsize = roundup(sizeof (struct sockaddr_in6) +
11217c478bd9Sstevel@tonic-gate sizeof (sadb_address_t), sizeof (uint64_t));
11227c478bd9Sstevel@tonic-gate break;
11237c478bd9Sstevel@tonic-gate default:
11247c478bd9Sstevel@tonic-gate return (NULL);
11257c478bd9Sstevel@tonic-gate }
11267c478bd9Sstevel@tonic-gate /*
11277c478bd9Sstevel@tonic-gate * Allocate TWO address extensions, for source and destination.
11287c478bd9Sstevel@tonic-gate * (Thus, the * 2.)
11297c478bd9Sstevel@tonic-gate */
11307c478bd9Sstevel@tonic-gate alloclen += addrsize * 2;
11317c478bd9Sstevel@tonic-gate if (ipsa->ipsa_flags & IPSA_F_NATT_REM)
11327c478bd9Sstevel@tonic-gate alloclen += addrsize;
11337c478bd9Sstevel@tonic-gate if (ipsa->ipsa_flags & IPSA_F_NATT_LOC)
11347c478bd9Sstevel@tonic-gate alloclen += addrsize;
11357c478bd9Sstevel@tonic-gate
113638d95a78Smarkfen if (ipsa->ipsa_flags & IPSA_F_PAIRED) {
113738d95a78Smarkfen paired = B_TRUE;
113838d95a78Smarkfen alloclen += sizeof (sadb_x_pair_t);
113938d95a78Smarkfen otherspi = ipsa->ipsa_otherspi;
114038d95a78Smarkfen } else {
114138d95a78Smarkfen paired = B_FALSE;
114238d95a78Smarkfen }
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate /* How 'bout other lifetimes? */
11457c478bd9Sstevel@tonic-gate if (ipsa->ipsa_softaddlt != 0 || ipsa->ipsa_softuselt != 0 ||
11467c478bd9Sstevel@tonic-gate ipsa->ipsa_softbyteslt != 0 || ipsa->ipsa_softalloc != 0) {
11477c478bd9Sstevel@tonic-gate alloclen += sizeof (sadb_lifetime_t);
11487c478bd9Sstevel@tonic-gate soft = B_TRUE;
11497c478bd9Sstevel@tonic-gate }
11507c478bd9Sstevel@tonic-gate
11517c478bd9Sstevel@tonic-gate if (ipsa->ipsa_hardaddlt != 0 || ipsa->ipsa_harduselt != 0 ||
11527c478bd9Sstevel@tonic-gate ipsa->ipsa_hardbyteslt != 0 || ipsa->ipsa_hardalloc != 0) {
11537c478bd9Sstevel@tonic-gate alloclen += sizeof (sadb_lifetime_t);
11547c478bd9Sstevel@tonic-gate hard = B_TRUE;
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate
11579c2c14abSThejaswini Singarajipura if (ipsa->ipsa_idleaddlt != 0 || ipsa->ipsa_idleuselt != 0) {
11589c2c14abSThejaswini Singarajipura alloclen += sizeof (sadb_lifetime_t);
11599c2c14abSThejaswini Singarajipura idle = B_TRUE;
11609c2c14abSThejaswini Singarajipura } else {
11619c2c14abSThejaswini Singarajipura idle = B_FALSE;
11629c2c14abSThejaswini Singarajipura }
11639c2c14abSThejaswini Singarajipura
11648810c16bSdanmcd /* Inner addresses. */
11655d3b8cb7SBill Sommerfeld if (ipsa->ipsa_innerfam != 0) {
11668810c16bSdanmcd pfam = ipsa->ipsa_innerfam;
11677c478bd9Sstevel@tonic-gate switch (pfam) {
11687c478bd9Sstevel@tonic-gate case AF_INET6:
11697c478bd9Sstevel@tonic-gate paddrsize = roundup(sizeof (struct sockaddr_in6) +
11707c478bd9Sstevel@tonic-gate sizeof (sadb_address_t), sizeof (uint64_t));
11717c478bd9Sstevel@tonic-gate break;
11727c478bd9Sstevel@tonic-gate case AF_INET:
11737c478bd9Sstevel@tonic-gate paddrsize = roundup(sizeof (struct sockaddr_in) +
11747c478bd9Sstevel@tonic-gate sizeof (sadb_address_t), sizeof (uint64_t));
11757c478bd9Sstevel@tonic-gate break;
11767c478bd9Sstevel@tonic-gate default:
11777c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC,
11787c478bd9Sstevel@tonic-gate "IPsec SADB: Proxy length failure.\n");
11797c478bd9Sstevel@tonic-gate break;
11807c478bd9Sstevel@tonic-gate }
11818810c16bSdanmcd isrc = B_TRUE;
11828810c16bSdanmcd idst = B_TRUE;
11838810c16bSdanmcd alloclen += 2 * paddrsize;
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate
11867c478bd9Sstevel@tonic-gate /* For the following fields, assume that length != 0 ==> stuff */
11877c478bd9Sstevel@tonic-gate if (ipsa->ipsa_authkeylen != 0) {
11887c478bd9Sstevel@tonic-gate authsize = roundup(sizeof (sadb_key_t) + ipsa->ipsa_authkeylen,
11897c478bd9Sstevel@tonic-gate sizeof (uint64_t));
11907c478bd9Sstevel@tonic-gate alloclen += authsize;
11917c478bd9Sstevel@tonic-gate auth = B_TRUE;
11927c478bd9Sstevel@tonic-gate }
11937c478bd9Sstevel@tonic-gate
11947c478bd9Sstevel@tonic-gate if (ipsa->ipsa_encrkeylen != 0) {
1195628b0c67SMark Fenwick encrsize = roundup(sizeof (sadb_key_t) + ipsa->ipsa_encrkeylen +
1196628b0c67SMark Fenwick ipsa->ipsa_nonce_len, sizeof (uint64_t));
11977c478bd9Sstevel@tonic-gate alloclen += encrsize;
11987c478bd9Sstevel@tonic-gate encr = B_TRUE;
11997c478bd9Sstevel@tonic-gate } else {
12007c478bd9Sstevel@tonic-gate encr = B_FALSE;
12017c478bd9Sstevel@tonic-gate }
12027c478bd9Sstevel@tonic-gate
1203bd670b35SErik Nordmark if (ipsa->ipsa_tsl != NULL) {
1204bd670b35SErik Nordmark senslen = sadb_sens_len_from_label(ipsa->ipsa_tsl);
12055d3b8cb7SBill Sommerfeld alloclen += senslen;
12067c478bd9Sstevel@tonic-gate sensinteg = B_TRUE;
12075d3b8cb7SBill Sommerfeld }
12085d3b8cb7SBill Sommerfeld
1209bd670b35SErik Nordmark if (ipsa->ipsa_otsl != NULL) {
1210bd670b35SErik Nordmark osenslen = sadb_sens_len_from_label(ipsa->ipsa_otsl);
12115d3b8cb7SBill Sommerfeld alloclen += osenslen;
12125d3b8cb7SBill Sommerfeld osensinteg = B_TRUE;
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate
12157c478bd9Sstevel@tonic-gate /*
12167c478bd9Sstevel@tonic-gate * Must use strlen() here for lengths. Identities use NULL
12177c478bd9Sstevel@tonic-gate * pointers to indicate their nonexistence.
12187c478bd9Sstevel@tonic-gate */
12197c478bd9Sstevel@tonic-gate if (ipsa->ipsa_src_cid != NULL) {
12207c478bd9Sstevel@tonic-gate srcidsize = roundup(sizeof (sadb_ident_t) +
12217c478bd9Sstevel@tonic-gate strlen(ipsa->ipsa_src_cid->ipsid_cid) + 1,
12227c478bd9Sstevel@tonic-gate sizeof (uint64_t));
12237c478bd9Sstevel@tonic-gate alloclen += srcidsize;
12247c478bd9Sstevel@tonic-gate srcid = B_TRUE;
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate
12277c478bd9Sstevel@tonic-gate if (ipsa->ipsa_dst_cid != NULL) {
12287c478bd9Sstevel@tonic-gate dstidsize = roundup(sizeof (sadb_ident_t) +
12297c478bd9Sstevel@tonic-gate strlen(ipsa->ipsa_dst_cid->ipsid_cid) + 1,
12307c478bd9Sstevel@tonic-gate sizeof (uint64_t));
12317c478bd9Sstevel@tonic-gate alloclen += dstidsize;
12327c478bd9Sstevel@tonic-gate dstid = B_TRUE;
12337c478bd9Sstevel@tonic-gate }
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate if ((ipsa->ipsa_kmp != 0) || (ipsa->ipsa_kmc != 0))
12367c478bd9Sstevel@tonic-gate alloclen += sizeof (sadb_x_kmc_t);
12377c478bd9Sstevel@tonic-gate
12389c2c14abSThejaswini Singarajipura if (ipsa->ipsa_replay != 0) {
12399c2c14abSThejaswini Singarajipura alloclen += sizeof (sadb_x_replay_ctr_t);
12409c2c14abSThejaswini Singarajipura }
12419c2c14abSThejaswini Singarajipura
12427c478bd9Sstevel@tonic-gate /* Make sure the allocation length is a multiple of 8 bytes. */
12437c478bd9Sstevel@tonic-gate ASSERT((alloclen & 0x7) == 0);
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate /* XXX Possibly make it esballoc, with a bzero-ing free_ftn. */
12467c478bd9Sstevel@tonic-gate mp = allocb(alloclen, BPRI_HI);
12477c478bd9Sstevel@tonic-gate if (mp == NULL)
12487c478bd9Sstevel@tonic-gate return (NULL);
12495d3b8cb7SBill Sommerfeld bzero(mp->b_rptr, alloclen);
12507c478bd9Sstevel@tonic-gate
12517c478bd9Sstevel@tonic-gate mp->b_wptr += alloclen;
12527c478bd9Sstevel@tonic-gate end = mp->b_wptr;
12537c478bd9Sstevel@tonic-gate newsamsg = (sadb_msg_t *)mp->b_rptr;
12547c478bd9Sstevel@tonic-gate *newsamsg = *samsg;
12557c478bd9Sstevel@tonic-gate newsamsg->sadb_msg_len = (uint16_t)SADB_8TO64(alloclen);
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate mutex_enter(&ipsa->ipsa_lock); /* Since I'm grabbing SA fields... */
12587c478bd9Sstevel@tonic-gate
12597c478bd9Sstevel@tonic-gate newsamsg->sadb_msg_satype = ipsa->ipsa_type;
12607c478bd9Sstevel@tonic-gate
12617c478bd9Sstevel@tonic-gate assoc = (sadb_sa_t *)(newsamsg + 1);
12627c478bd9Sstevel@tonic-gate assoc->sadb_sa_len = SADB_8TO64(sizeof (*assoc));
12637c478bd9Sstevel@tonic-gate assoc->sadb_sa_exttype = SADB_EXT_SA;
12647c478bd9Sstevel@tonic-gate assoc->sadb_sa_spi = ipsa->ipsa_spi;
12657c478bd9Sstevel@tonic-gate assoc->sadb_sa_replay = ipsa->ipsa_replay_wsize;
12667c478bd9Sstevel@tonic-gate assoc->sadb_sa_state = ipsa->ipsa_state;
12677c478bd9Sstevel@tonic-gate assoc->sadb_sa_auth = ipsa->ipsa_auth_alg;
12687c478bd9Sstevel@tonic-gate assoc->sadb_sa_encrypt = ipsa->ipsa_encr_alg;
12697c478bd9Sstevel@tonic-gate assoc->sadb_sa_flags = ipsa->ipsa_flags;
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate lt = (sadb_lifetime_t *)(assoc + 1);
12727c478bd9Sstevel@tonic-gate lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt));
12737c478bd9Sstevel@tonic-gate lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
1274437220cdSdanmcd /* We do not support the concept. */
1275437220cdSdanmcd lt->sadb_lifetime_allocations = 0;
12767c478bd9Sstevel@tonic-gate lt->sadb_lifetime_bytes = ipsa->ipsa_bytes;
12777c478bd9Sstevel@tonic-gate lt->sadb_lifetime_addtime = ipsa->ipsa_addtime;
12787c478bd9Sstevel@tonic-gate lt->sadb_lifetime_usetime = ipsa->ipsa_usetime;
12797c478bd9Sstevel@tonic-gate
12807c478bd9Sstevel@tonic-gate if (hard) {
12817c478bd9Sstevel@tonic-gate lt++;
12827c478bd9Sstevel@tonic-gate lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt));
12837c478bd9Sstevel@tonic-gate lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
12847c478bd9Sstevel@tonic-gate lt->sadb_lifetime_allocations = ipsa->ipsa_hardalloc;
12857c478bd9Sstevel@tonic-gate lt->sadb_lifetime_bytes = ipsa->ipsa_hardbyteslt;
12867c478bd9Sstevel@tonic-gate lt->sadb_lifetime_addtime = ipsa->ipsa_hardaddlt;
12877c478bd9Sstevel@tonic-gate lt->sadb_lifetime_usetime = ipsa->ipsa_harduselt;
12887c478bd9Sstevel@tonic-gate }
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate if (soft) {
12917c478bd9Sstevel@tonic-gate lt++;
12927c478bd9Sstevel@tonic-gate lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt));
12937c478bd9Sstevel@tonic-gate lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
12947c478bd9Sstevel@tonic-gate lt->sadb_lifetime_allocations = ipsa->ipsa_softalloc;
12957c478bd9Sstevel@tonic-gate lt->sadb_lifetime_bytes = ipsa->ipsa_softbyteslt;
12967c478bd9Sstevel@tonic-gate lt->sadb_lifetime_addtime = ipsa->ipsa_softaddlt;
12977c478bd9Sstevel@tonic-gate lt->sadb_lifetime_usetime = ipsa->ipsa_softuselt;
12987c478bd9Sstevel@tonic-gate }
12997c478bd9Sstevel@tonic-gate
13009c2c14abSThejaswini Singarajipura if (idle) {
13019c2c14abSThejaswini Singarajipura lt++;
13029c2c14abSThejaswini Singarajipura lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt));
13039c2c14abSThejaswini Singarajipura lt->sadb_lifetime_exttype = SADB_X_EXT_LIFETIME_IDLE;
13049c2c14abSThejaswini Singarajipura lt->sadb_lifetime_addtime = ipsa->ipsa_idleaddlt;
13059c2c14abSThejaswini Singarajipura lt->sadb_lifetime_usetime = ipsa->ipsa_idleuselt;
13069c2c14abSThejaswini Singarajipura }
13079c2c14abSThejaswini Singarajipura
13087c478bd9Sstevel@tonic-gate cur = (uint8_t *)(lt + 1);
13097c478bd9Sstevel@tonic-gate
13108810c16bSdanmcd /* NOTE: Don't fill in ports here if we are a tunnel-mode SA. */
13117c478bd9Sstevel@tonic-gate cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_SRC, fam,
13128810c16bSdanmcd ipsa->ipsa_srcaddr, (!isrc && !idst) ? SA_SRCPORT(ipsa) : 0,
13138810c16bSdanmcd SA_PROTO(ipsa), 0);
13147c478bd9Sstevel@tonic-gate if (cur == NULL) {
13157c478bd9Sstevel@tonic-gate freemsg(mp);
13167c478bd9Sstevel@tonic-gate mp = NULL;
13177c478bd9Sstevel@tonic-gate goto bail;
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate
13207c478bd9Sstevel@tonic-gate cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_DST, fam,
13218810c16bSdanmcd ipsa->ipsa_dstaddr, (!isrc && !idst) ? SA_DSTPORT(ipsa) : 0,
13228810c16bSdanmcd SA_PROTO(ipsa), 0);
13237c478bd9Sstevel@tonic-gate if (cur == NULL) {
13247c478bd9Sstevel@tonic-gate freemsg(mp);
13257c478bd9Sstevel@tonic-gate mp = NULL;
13267c478bd9Sstevel@tonic-gate goto bail;
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate if (ipsa->ipsa_flags & IPSA_F_NATT_LOC) {
13307c478bd9Sstevel@tonic-gate cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_NATT_LOC,
1331437220cdSdanmcd fam, &ipsa->ipsa_natt_addr_loc, ipsa->ipsa_local_nat_port,
1332437220cdSdanmcd IPPROTO_UDP, 0);
13337c478bd9Sstevel@tonic-gate if (cur == NULL) {
13347c478bd9Sstevel@tonic-gate freemsg(mp);
13357c478bd9Sstevel@tonic-gate mp = NULL;
13367c478bd9Sstevel@tonic-gate goto bail;
13377c478bd9Sstevel@tonic-gate }
13387c478bd9Sstevel@tonic-gate }
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate if (ipsa->ipsa_flags & IPSA_F_NATT_REM) {
13417c478bd9Sstevel@tonic-gate cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_NATT_REM,
1342437220cdSdanmcd fam, &ipsa->ipsa_natt_addr_rem, ipsa->ipsa_remote_nat_port,
13438810c16bSdanmcd IPPROTO_UDP, 0);
13447c478bd9Sstevel@tonic-gate if (cur == NULL) {
13457c478bd9Sstevel@tonic-gate freemsg(mp);
13467c478bd9Sstevel@tonic-gate mp = NULL;
13477c478bd9Sstevel@tonic-gate goto bail;
13487c478bd9Sstevel@tonic-gate }
13497c478bd9Sstevel@tonic-gate }
13507c478bd9Sstevel@tonic-gate
13518810c16bSdanmcd /* If we are a tunnel-mode SA, fill in the inner-selectors. */
13528810c16bSdanmcd if (isrc) {
13538810c16bSdanmcd cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_SRC,
13548810c16bSdanmcd pfam, ipsa->ipsa_innersrc, SA_SRCPORT(ipsa),
13558810c16bSdanmcd SA_IPROTO(ipsa), ipsa->ipsa_innersrcpfx);
13568810c16bSdanmcd if (cur == NULL) {
13578810c16bSdanmcd freemsg(mp);
13588810c16bSdanmcd mp = NULL;
13598810c16bSdanmcd goto bail;
13608810c16bSdanmcd }
13618810c16bSdanmcd }
13628810c16bSdanmcd
13638810c16bSdanmcd if (idst) {
13648810c16bSdanmcd cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_DST,
13658810c16bSdanmcd pfam, ipsa->ipsa_innerdst, SA_DSTPORT(ipsa),
13668810c16bSdanmcd SA_IPROTO(ipsa), ipsa->ipsa_innerdstpfx);
13677c478bd9Sstevel@tonic-gate if (cur == NULL) {
13687c478bd9Sstevel@tonic-gate freemsg(mp);
13697c478bd9Sstevel@tonic-gate mp = NULL;
13707c478bd9Sstevel@tonic-gate goto bail;
13717c478bd9Sstevel@tonic-gate }
13727c478bd9Sstevel@tonic-gate }
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate if ((ipsa->ipsa_kmp != 0) || (ipsa->ipsa_kmc != 0)) {
13757c478bd9Sstevel@tonic-gate cur = sadb_make_kmc_ext(cur, end,
13767c478bd9Sstevel@tonic-gate ipsa->ipsa_kmp, ipsa->ipsa_kmc);
13777c478bd9Sstevel@tonic-gate if (cur == NULL) {
13787c478bd9Sstevel@tonic-gate freemsg(mp);
13797c478bd9Sstevel@tonic-gate mp = NULL;
13807c478bd9Sstevel@tonic-gate goto bail;
13817c478bd9Sstevel@tonic-gate }
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate
13847c478bd9Sstevel@tonic-gate walker = (sadb_ext_t *)cur;
13857c478bd9Sstevel@tonic-gate if (auth) {
13867c478bd9Sstevel@tonic-gate key = (sadb_key_t *)walker;
13877c478bd9Sstevel@tonic-gate key->sadb_key_len = SADB_8TO64(authsize);
13887c478bd9Sstevel@tonic-gate key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
13897c478bd9Sstevel@tonic-gate key->sadb_key_bits = ipsa->ipsa_authkeybits;
13907c478bd9Sstevel@tonic-gate key->sadb_key_reserved = 0;
13917c478bd9Sstevel@tonic-gate bcopy(ipsa->ipsa_authkey, key + 1, ipsa->ipsa_authkeylen);
13927c478bd9Sstevel@tonic-gate walker = (sadb_ext_t *)((uint64_t *)walker +
13937c478bd9Sstevel@tonic-gate walker->sadb_ext_len);
13947c478bd9Sstevel@tonic-gate }
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate if (encr) {
1397628b0c67SMark Fenwick uint8_t *buf_ptr;
13987c478bd9Sstevel@tonic-gate key = (sadb_key_t *)walker;
13997c478bd9Sstevel@tonic-gate key->sadb_key_len = SADB_8TO64(encrsize);
14007c478bd9Sstevel@tonic-gate key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
14017c478bd9Sstevel@tonic-gate key->sadb_key_bits = ipsa->ipsa_encrkeybits;
1402628b0c67SMark Fenwick key->sadb_key_reserved = ipsa->ipsa_saltbits;
1403628b0c67SMark Fenwick buf_ptr = (uint8_t *)(key + 1);
1404628b0c67SMark Fenwick bcopy(ipsa->ipsa_encrkey, buf_ptr, ipsa->ipsa_encrkeylen);
1405628b0c67SMark Fenwick if (ipsa->ipsa_salt != NULL) {
1406628b0c67SMark Fenwick buf_ptr += ipsa->ipsa_encrkeylen;
1407628b0c67SMark Fenwick bcopy(ipsa->ipsa_salt, buf_ptr, ipsa->ipsa_saltlen);
1408628b0c67SMark Fenwick }
14097c478bd9Sstevel@tonic-gate walker = (sadb_ext_t *)((uint64_t *)walker +
14107c478bd9Sstevel@tonic-gate walker->sadb_ext_len);
14117c478bd9Sstevel@tonic-gate }
14127c478bd9Sstevel@tonic-gate
14137c478bd9Sstevel@tonic-gate if (srcid) {
14147c478bd9Sstevel@tonic-gate ident = (sadb_ident_t *)walker;
14157c478bd9Sstevel@tonic-gate ident->sadb_ident_len = SADB_8TO64(srcidsize);
14167c478bd9Sstevel@tonic-gate ident->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
14177c478bd9Sstevel@tonic-gate ident->sadb_ident_type = ipsa->ipsa_src_cid->ipsid_type;
14187c478bd9Sstevel@tonic-gate ident->sadb_ident_id = 0;
14197c478bd9Sstevel@tonic-gate ident->sadb_ident_reserved = 0;
14207c478bd9Sstevel@tonic-gate (void) strcpy((char *)(ident + 1),
14217c478bd9Sstevel@tonic-gate ipsa->ipsa_src_cid->ipsid_cid);
14227c478bd9Sstevel@tonic-gate walker = (sadb_ext_t *)((uint64_t *)walker +
14237c478bd9Sstevel@tonic-gate walker->sadb_ext_len);
14247c478bd9Sstevel@tonic-gate }
14257c478bd9Sstevel@tonic-gate
14267c478bd9Sstevel@tonic-gate if (dstid) {
14277c478bd9Sstevel@tonic-gate ident = (sadb_ident_t *)walker;
14287c478bd9Sstevel@tonic-gate ident->sadb_ident_len = SADB_8TO64(dstidsize);
14297c478bd9Sstevel@tonic-gate ident->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
14307c478bd9Sstevel@tonic-gate ident->sadb_ident_type = ipsa->ipsa_dst_cid->ipsid_type;
14317c478bd9Sstevel@tonic-gate ident->sadb_ident_id = 0;
14327c478bd9Sstevel@tonic-gate ident->sadb_ident_reserved = 0;
14337c478bd9Sstevel@tonic-gate (void) strcpy((char *)(ident + 1),
14347c478bd9Sstevel@tonic-gate ipsa->ipsa_dst_cid->ipsid_cid);
14357c478bd9Sstevel@tonic-gate walker = (sadb_ext_t *)((uint64_t *)walker +
14367c478bd9Sstevel@tonic-gate walker->sadb_ext_len);
14377c478bd9Sstevel@tonic-gate }
14387c478bd9Sstevel@tonic-gate
14397c478bd9Sstevel@tonic-gate if (sensinteg) {
14407c478bd9Sstevel@tonic-gate sens = (sadb_sens_t *)walker;
1441bd670b35SErik Nordmark sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY,
1442bd670b35SErik Nordmark ipsa->ipsa_tsl, senslen);
14435d3b8cb7SBill Sommerfeld
14445d3b8cb7SBill Sommerfeld walker = (sadb_ext_t *)((uint64_t *)walker +
14455d3b8cb7SBill Sommerfeld walker->sadb_ext_len);
14467c478bd9Sstevel@tonic-gate }
14475d3b8cb7SBill Sommerfeld
14485d3b8cb7SBill Sommerfeld if (osensinteg) {
14495d3b8cb7SBill Sommerfeld sens = (sadb_sens_t *)walker;
14505d3b8cb7SBill Sommerfeld
1451bd670b35SErik Nordmark sadb_sens_from_label(sens, SADB_X_EXT_OUTER_SENS,
1452bd670b35SErik Nordmark ipsa->ipsa_otsl, osenslen);
14535d3b8cb7SBill Sommerfeld if (ipsa->ipsa_mac_exempt)
14545d3b8cb7SBill Sommerfeld sens->sadb_x_sens_flags = SADB_X_SENS_IMPLICIT;
14555d3b8cb7SBill Sommerfeld
14567c478bd9Sstevel@tonic-gate walker = (sadb_ext_t *)((uint64_t *)walker +
14577c478bd9Sstevel@tonic-gate walker->sadb_ext_len);
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate
146038d95a78Smarkfen if (paired) {
146138d95a78Smarkfen pair_ext = (sadb_x_pair_t *)walker;
146238d95a78Smarkfen
146338d95a78Smarkfen pair_ext->sadb_x_pair_len = SADB_8TO64(sizeof (sadb_x_pair_t));
146438d95a78Smarkfen pair_ext->sadb_x_pair_exttype = SADB_X_EXT_PAIR;
146538d95a78Smarkfen pair_ext->sadb_x_pair_spi = otherspi;
146638d95a78Smarkfen
146738d95a78Smarkfen walker = (sadb_ext_t *)((uint64_t *)walker +
146838d95a78Smarkfen walker->sadb_ext_len);
146938d95a78Smarkfen }
147038d95a78Smarkfen
14719c2c14abSThejaswini Singarajipura if (ipsa->ipsa_replay != 0) {
14729c2c14abSThejaswini Singarajipura repl_ctr = (sadb_x_replay_ctr_t *)walker;
14739c2c14abSThejaswini Singarajipura repl_ctr->sadb_x_rc_len = SADB_8TO64(sizeof (*repl_ctr));
14749c2c14abSThejaswini Singarajipura repl_ctr->sadb_x_rc_exttype = SADB_X_EXT_REPLAY_VALUE;
14759c2c14abSThejaswini Singarajipura repl_ctr->sadb_x_rc_replay32 = ipsa->ipsa_replay;
14769c2c14abSThejaswini Singarajipura repl_ctr->sadb_x_rc_replay64 = 0;
14779c2c14abSThejaswini Singarajipura walker = (sadb_ext_t *)(repl_ctr + 1);
14789c2c14abSThejaswini Singarajipura }
14799c2c14abSThejaswini Singarajipura
14807c478bd9Sstevel@tonic-gate bail:
14817c478bd9Sstevel@tonic-gate /* Pardon any delays... */
14827c478bd9Sstevel@tonic-gate mutex_exit(&ipsa->ipsa_lock);
14837c478bd9Sstevel@tonic-gate
14847c478bd9Sstevel@tonic-gate return (mp);
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate
14877c478bd9Sstevel@tonic-gate /*
14887c478bd9Sstevel@tonic-gate * Strip out key headers or unmarked headers (SADB_EXT_KEY_*, SADB_EXT_UNKNOWN)
14897c478bd9Sstevel@tonic-gate * and adjust base message accordingly.
14907c478bd9Sstevel@tonic-gate *
14917c478bd9Sstevel@tonic-gate * Assume message is pulled up in one piece of contiguous memory.
14927c478bd9Sstevel@tonic-gate *
14937c478bd9Sstevel@tonic-gate * Say if we start off with:
14947c478bd9Sstevel@tonic-gate *
14957c478bd9Sstevel@tonic-gate * +------+----+-------------+-----------+---------------+---------------+
14967c478bd9Sstevel@tonic-gate * | base | SA | source addr | dest addr | rsrvd. or key | soft lifetime |
14977c478bd9Sstevel@tonic-gate * +------+----+-------------+-----------+---------------+---------------+
14987c478bd9Sstevel@tonic-gate *
14997c478bd9Sstevel@tonic-gate * we will end up with
15007c478bd9Sstevel@tonic-gate *
15017c478bd9Sstevel@tonic-gate * +------+----+-------------+-----------+---------------+
15027c478bd9Sstevel@tonic-gate * | base | SA | source addr | dest addr | soft lifetime |
15037c478bd9Sstevel@tonic-gate * +------+----+-------------+-----------+---------------+
15047c478bd9Sstevel@tonic-gate */
15057c478bd9Sstevel@tonic-gate static void
sadb_strip(sadb_msg_t * samsg)15067c478bd9Sstevel@tonic-gate sadb_strip(sadb_msg_t *samsg)
15077c478bd9Sstevel@tonic-gate {
15087c478bd9Sstevel@tonic-gate sadb_ext_t *ext;
15097c478bd9Sstevel@tonic-gate uint8_t *target = NULL;
15107c478bd9Sstevel@tonic-gate uint8_t *msgend;
15117c478bd9Sstevel@tonic-gate int sofar = SADB_8TO64(sizeof (*samsg));
15127c478bd9Sstevel@tonic-gate int copylen;
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate ext = (sadb_ext_t *)(samsg + 1);
15157c478bd9Sstevel@tonic-gate msgend = (uint8_t *)samsg;
15167c478bd9Sstevel@tonic-gate msgend += SADB_64TO8(samsg->sadb_msg_len);
15177c478bd9Sstevel@tonic-gate while ((uint8_t *)ext < msgend) {
15187c478bd9Sstevel@tonic-gate if (ext->sadb_ext_type == SADB_EXT_RESERVED ||
15197c478bd9Sstevel@tonic-gate ext->sadb_ext_type == SADB_EXT_KEY_AUTH ||
15209c2c14abSThejaswini Singarajipura ext->sadb_ext_type == SADB_X_EXT_EDUMP ||
15217c478bd9Sstevel@tonic-gate ext->sadb_ext_type == SADB_EXT_KEY_ENCRYPT) {
15227c478bd9Sstevel@tonic-gate /*
15237c478bd9Sstevel@tonic-gate * Aha! I found a header to be erased.
15247c478bd9Sstevel@tonic-gate */
15257c478bd9Sstevel@tonic-gate
15267c478bd9Sstevel@tonic-gate if (target != NULL) {
15277c478bd9Sstevel@tonic-gate /*
15287c478bd9Sstevel@tonic-gate * If I had a previous header to be erased,
15297c478bd9Sstevel@tonic-gate * copy over it. I can get away with just
15307c478bd9Sstevel@tonic-gate * copying backwards because the target will
15317c478bd9Sstevel@tonic-gate * always be 8 bytes behind the source.
15327c478bd9Sstevel@tonic-gate */
15337c478bd9Sstevel@tonic-gate copylen = ((uint8_t *)ext) - (target +
15347c478bd9Sstevel@tonic-gate SADB_64TO8(
15357c478bd9Sstevel@tonic-gate ((sadb_ext_t *)target)->sadb_ext_len));
15367c478bd9Sstevel@tonic-gate ovbcopy(((uint8_t *)ext - copylen), target,
15377c478bd9Sstevel@tonic-gate copylen);
15387c478bd9Sstevel@tonic-gate target += copylen;
15397c478bd9Sstevel@tonic-gate ((sadb_ext_t *)target)->sadb_ext_len =
15407c478bd9Sstevel@tonic-gate SADB_8TO64(((uint8_t *)ext) - target +
15417c478bd9Sstevel@tonic-gate SADB_64TO8(ext->sadb_ext_len));
15427c478bd9Sstevel@tonic-gate } else {
15437c478bd9Sstevel@tonic-gate target = (uint8_t *)ext;
15447c478bd9Sstevel@tonic-gate }
15457c478bd9Sstevel@tonic-gate } else {
15467c478bd9Sstevel@tonic-gate sofar += ext->sadb_ext_len;
15477c478bd9Sstevel@tonic-gate }
15487c478bd9Sstevel@tonic-gate
15497c478bd9Sstevel@tonic-gate ext = (sadb_ext_t *)(((uint64_t *)ext) + ext->sadb_ext_len);
15507c478bd9Sstevel@tonic-gate }
15517c478bd9Sstevel@tonic-gate
15527c478bd9Sstevel@tonic-gate ASSERT((uint8_t *)ext == msgend);
15537c478bd9Sstevel@tonic-gate
15547c478bd9Sstevel@tonic-gate if (target != NULL) {
15557c478bd9Sstevel@tonic-gate copylen = ((uint8_t *)ext) - (target +
15567c478bd9Sstevel@tonic-gate SADB_64TO8(((sadb_ext_t *)target)->sadb_ext_len));
15577c478bd9Sstevel@tonic-gate if (copylen != 0)
15587c478bd9Sstevel@tonic-gate ovbcopy(((uint8_t *)ext - copylen), target, copylen);
15597c478bd9Sstevel@tonic-gate }
15607c478bd9Sstevel@tonic-gate
15617c478bd9Sstevel@tonic-gate /* Adjust samsg. */
15627c478bd9Sstevel@tonic-gate samsg->sadb_msg_len = (uint16_t)sofar;
15637c478bd9Sstevel@tonic-gate
15647c478bd9Sstevel@tonic-gate /* Assume all of the rest is cleared by caller in sadb_pfkey_echo(). */
15657c478bd9Sstevel@tonic-gate }
15667c478bd9Sstevel@tonic-gate
15677c478bd9Sstevel@tonic-gate /*
15687c478bd9Sstevel@tonic-gate * AH needs to send an error to PF_KEY. Assume mp points to an M_CTL
15697c478bd9Sstevel@tonic-gate * followed by an M_DATA with a PF_KEY message in it. The serial of
15707c478bd9Sstevel@tonic-gate * the sending keysock instance is included.
15717c478bd9Sstevel@tonic-gate */
15727c478bd9Sstevel@tonic-gate void
sadb_pfkey_error(queue_t * pfkey_q,mblk_t * mp,int error,int diagnostic,uint_t serial)15737c478bd9Sstevel@tonic-gate sadb_pfkey_error(queue_t *pfkey_q, mblk_t *mp, int error, int diagnostic,
15747c478bd9Sstevel@tonic-gate uint_t serial)
15757c478bd9Sstevel@tonic-gate {
15767c478bd9Sstevel@tonic-gate mblk_t *msg = mp->b_cont;
15777c478bd9Sstevel@tonic-gate sadb_msg_t *samsg;
15787c478bd9Sstevel@tonic-gate keysock_out_t *kso;
15797c478bd9Sstevel@tonic-gate
15807c478bd9Sstevel@tonic-gate /*
15817c478bd9Sstevel@tonic-gate * Enough functions call this to merit a NULL queue check.
15827c478bd9Sstevel@tonic-gate */
15837c478bd9Sstevel@tonic-gate if (pfkey_q == NULL) {
15847c478bd9Sstevel@tonic-gate freemsg(mp);
15857c478bd9Sstevel@tonic-gate return;
15867c478bd9Sstevel@tonic-gate }
15877c478bd9Sstevel@tonic-gate
15887c478bd9Sstevel@tonic-gate ASSERT(msg != NULL);
15897c478bd9Sstevel@tonic-gate ASSERT((mp->b_wptr - mp->b_rptr) == sizeof (ipsec_info_t));
15907c478bd9Sstevel@tonic-gate ASSERT((msg->b_wptr - msg->b_rptr) >= sizeof (sadb_msg_t));
15917c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)msg->b_rptr;
15927c478bd9Sstevel@tonic-gate kso = (keysock_out_t *)mp->b_rptr;
15937c478bd9Sstevel@tonic-gate
15947c478bd9Sstevel@tonic-gate kso->ks_out_type = KEYSOCK_OUT;
15957c478bd9Sstevel@tonic-gate kso->ks_out_len = sizeof (*kso);
15967c478bd9Sstevel@tonic-gate kso->ks_out_serial = serial;
15977c478bd9Sstevel@tonic-gate
15987c478bd9Sstevel@tonic-gate /*
15997c478bd9Sstevel@tonic-gate * Only send the base message up in the event of an error.
16007c478bd9Sstevel@tonic-gate * Don't worry about bzero()-ing, because it was probably bogus
16017c478bd9Sstevel@tonic-gate * anyway.
16027c478bd9Sstevel@tonic-gate */
16037c478bd9Sstevel@tonic-gate msg->b_wptr = msg->b_rptr + sizeof (*samsg);
16047c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)msg->b_rptr;
16057c478bd9Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg));
16067c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)error;
16077c478bd9Sstevel@tonic-gate if (diagnostic != SADB_X_DIAGNOSTIC_PRESET)
16087c478bd9Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = (uint16_t)diagnostic;
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate putnext(pfkey_q, mp);
16117c478bd9Sstevel@tonic-gate }
16127c478bd9Sstevel@tonic-gate
16137c478bd9Sstevel@tonic-gate /*
16147c478bd9Sstevel@tonic-gate * Send a successful return packet back to keysock via the queue in pfkey_q.
16157c478bd9Sstevel@tonic-gate *
16167c478bd9Sstevel@tonic-gate * Often, an SA is associated with the reply message, it's passed in if needed,
16177c478bd9Sstevel@tonic-gate * and NULL if not. BTW, that ipsa will have its refcnt appropriately held,
16187c478bd9Sstevel@tonic-gate * and the caller will release said refcnt.
16197c478bd9Sstevel@tonic-gate */
16207c478bd9Sstevel@tonic-gate void
sadb_pfkey_echo(queue_t * pfkey_q,mblk_t * mp,sadb_msg_t * samsg,keysock_in_t * ksi,ipsa_t * ipsa)16217c478bd9Sstevel@tonic-gate sadb_pfkey_echo(queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
16227c478bd9Sstevel@tonic-gate keysock_in_t *ksi, ipsa_t *ipsa)
16237c478bd9Sstevel@tonic-gate {
16247c478bd9Sstevel@tonic-gate keysock_out_t *kso;
16257c478bd9Sstevel@tonic-gate mblk_t *mp1;
16267c478bd9Sstevel@tonic-gate sadb_msg_t *newsamsg;
16277c478bd9Sstevel@tonic-gate uint8_t *oldend;
16287c478bd9Sstevel@tonic-gate
16297c478bd9Sstevel@tonic-gate ASSERT((mp->b_cont != NULL) &&
16307c478bd9Sstevel@tonic-gate ((void *)samsg == (void *)mp->b_cont->b_rptr) &&
16317c478bd9Sstevel@tonic-gate ((void *)mp->b_rptr == (void *)ksi));
16327c478bd9Sstevel@tonic-gate
16337c478bd9Sstevel@tonic-gate switch (samsg->sadb_msg_type) {
16347c478bd9Sstevel@tonic-gate case SADB_ADD:
16357c478bd9Sstevel@tonic-gate case SADB_UPDATE:
163638d95a78Smarkfen case SADB_X_UPDATEPAIR:
16379c2c14abSThejaswini Singarajipura case SADB_X_DELPAIR_STATE:
16387c478bd9Sstevel@tonic-gate case SADB_FLUSH:
16397c478bd9Sstevel@tonic-gate case SADB_DUMP:
16407c478bd9Sstevel@tonic-gate /*
16417c478bd9Sstevel@tonic-gate * I have all of the message already. I just need to strip
16427c478bd9Sstevel@tonic-gate * out the keying material and echo the message back.
16437c478bd9Sstevel@tonic-gate *
16447c478bd9Sstevel@tonic-gate * NOTE: for SADB_DUMP, the function sadb_dump() did the
16457c478bd9Sstevel@tonic-gate * work. When DUMP reaches here, it should only be a base
16467c478bd9Sstevel@tonic-gate * message.
16477c478bd9Sstevel@tonic-gate */
16487c478bd9Sstevel@tonic-gate justecho:
16497c478bd9Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_KEY_AUTH] != NULL ||
16509c2c14abSThejaswini Singarajipura ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT] != NULL ||
16519c2c14abSThejaswini Singarajipura ksi->ks_in_extv[SADB_X_EXT_EDUMP] != NULL) {
16527c478bd9Sstevel@tonic-gate sadb_strip(samsg);
16537c478bd9Sstevel@tonic-gate /* Assume PF_KEY message is contiguous. */
16547c478bd9Sstevel@tonic-gate ASSERT(mp->b_cont->b_cont == NULL);
16557c478bd9Sstevel@tonic-gate oldend = mp->b_cont->b_wptr;
16567c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr = mp->b_cont->b_rptr +
16577c478bd9Sstevel@tonic-gate SADB_64TO8(samsg->sadb_msg_len);
16587c478bd9Sstevel@tonic-gate bzero(mp->b_cont->b_wptr, oldend - mp->b_cont->b_wptr);
16597c478bd9Sstevel@tonic-gate }
16607c478bd9Sstevel@tonic-gate break;
16617c478bd9Sstevel@tonic-gate case SADB_GET:
16627c478bd9Sstevel@tonic-gate /*
16637c478bd9Sstevel@tonic-gate * Do a lot of work here, because of the ipsa I just found.
16648810c16bSdanmcd * First construct the new PF_KEY message, then abandon
16658810c16bSdanmcd * the old one.
16667c478bd9Sstevel@tonic-gate */
16677c478bd9Sstevel@tonic-gate mp1 = sadb_sa2msg(ipsa, samsg);
16687c478bd9Sstevel@tonic-gate if (mp1 == NULL) {
16697c478bd9Sstevel@tonic-gate sadb_pfkey_error(pfkey_q, mp, ENOMEM,
16707c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_NONE, ksi->ks_in_serial);
16717c478bd9Sstevel@tonic-gate return;
16727c478bd9Sstevel@tonic-gate }
16737c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
16747c478bd9Sstevel@tonic-gate mp->b_cont = mp1;
16757c478bd9Sstevel@tonic-gate break;
16767c478bd9Sstevel@tonic-gate case SADB_DELETE:
167738d95a78Smarkfen case SADB_X_DELPAIR:
16787c478bd9Sstevel@tonic-gate if (ipsa == NULL)
16797c478bd9Sstevel@tonic-gate goto justecho;
16807c478bd9Sstevel@tonic-gate /*
16817c478bd9Sstevel@tonic-gate * Because listening KMds may require more info, treat
16827c478bd9Sstevel@tonic-gate * DELETE like a special case of GET.
16837c478bd9Sstevel@tonic-gate */
16847c478bd9Sstevel@tonic-gate mp1 = sadb_sa2msg(ipsa, samsg);
16857c478bd9Sstevel@tonic-gate if (mp1 == NULL) {
16867c478bd9Sstevel@tonic-gate sadb_pfkey_error(pfkey_q, mp, ENOMEM,
16877c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_NONE, ksi->ks_in_serial);
16887c478bd9Sstevel@tonic-gate return;
16897c478bd9Sstevel@tonic-gate }
16907c478bd9Sstevel@tonic-gate newsamsg = (sadb_msg_t *)mp1->b_rptr;
16917c478bd9Sstevel@tonic-gate sadb_strip(newsamsg);
16927c478bd9Sstevel@tonic-gate oldend = mp1->b_wptr;
16937c478bd9Sstevel@tonic-gate mp1->b_wptr = mp1->b_rptr + SADB_64TO8(newsamsg->sadb_msg_len);
16947c478bd9Sstevel@tonic-gate bzero(mp1->b_wptr, oldend - mp1->b_wptr);
16957c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
16967c478bd9Sstevel@tonic-gate mp->b_cont = mp1;
16977c478bd9Sstevel@tonic-gate break;
16987c478bd9Sstevel@tonic-gate default:
16997c478bd9Sstevel@tonic-gate if (mp != NULL)
17007c478bd9Sstevel@tonic-gate freemsg(mp);
17017c478bd9Sstevel@tonic-gate return;
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate
17047c478bd9Sstevel@tonic-gate /* ksi is now null and void. */
17057c478bd9Sstevel@tonic-gate kso = (keysock_out_t *)ksi;
17067c478bd9Sstevel@tonic-gate kso->ks_out_type = KEYSOCK_OUT;
17077c478bd9Sstevel@tonic-gate kso->ks_out_len = sizeof (*kso);
17087c478bd9Sstevel@tonic-gate kso->ks_out_serial = ksi->ks_in_serial;
17097c478bd9Sstevel@tonic-gate /* We're ready to send... */
17107c478bd9Sstevel@tonic-gate putnext(pfkey_q, mp);
17117c478bd9Sstevel@tonic-gate }
17127c478bd9Sstevel@tonic-gate
17137c478bd9Sstevel@tonic-gate /*
17147c478bd9Sstevel@tonic-gate * Set up a global pfkey_q instance for AH, ESP, or some other consumer.
17157c478bd9Sstevel@tonic-gate */
17167c478bd9Sstevel@tonic-gate void
sadb_keysock_hello(queue_t ** pfkey_qp,queue_t * q,mblk_t * mp,void (* ager)(void *),void * agerarg,timeout_id_t * top,int satype)17177c478bd9Sstevel@tonic-gate sadb_keysock_hello(queue_t **pfkey_qp, queue_t *q, mblk_t *mp,
1718f4b3ec61Sdh155122 void (*ager)(void *), void *agerarg, timeout_id_t *top, int satype)
17197c478bd9Sstevel@tonic-gate {
17207c478bd9Sstevel@tonic-gate keysock_hello_ack_t *kha;
17217c478bd9Sstevel@tonic-gate queue_t *oldq;
17227c478bd9Sstevel@tonic-gate
17237c478bd9Sstevel@tonic-gate ASSERT(OTHERQ(q) != NULL);
17247c478bd9Sstevel@tonic-gate
17257c478bd9Sstevel@tonic-gate /*
17267c478bd9Sstevel@tonic-gate * First, check atomically that I'm the first and only keysock
17277c478bd9Sstevel@tonic-gate * instance.
17287c478bd9Sstevel@tonic-gate *
17297c478bd9Sstevel@tonic-gate * Use OTHERQ(q), because qreply(q, mp) == putnext(OTHERQ(q), mp),
17307c478bd9Sstevel@tonic-gate * and I want this module to say putnext(*_pfkey_q, mp) for PF_KEY
17317c478bd9Sstevel@tonic-gate * messages.
17327c478bd9Sstevel@tonic-gate */
17337c478bd9Sstevel@tonic-gate
1734*75d94465SJosef 'Jeff' Sipek oldq = atomic_cas_ptr((void **)pfkey_qp, NULL, OTHERQ(q));
17357c478bd9Sstevel@tonic-gate if (oldq != NULL) {
17367c478bd9Sstevel@tonic-gate ASSERT(oldq != q);
17377c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Danger! Multiple keysocks on top of %s.\n",
17387c478bd9Sstevel@tonic-gate (satype == SADB_SATYPE_ESP)? "ESP" : "AH or other");
17397c478bd9Sstevel@tonic-gate freemsg(mp);
17407c478bd9Sstevel@tonic-gate return;
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate
17437c478bd9Sstevel@tonic-gate kha = (keysock_hello_ack_t *)mp->b_rptr;
17447c478bd9Sstevel@tonic-gate kha->ks_hello_len = sizeof (keysock_hello_ack_t);
17457c478bd9Sstevel@tonic-gate kha->ks_hello_type = KEYSOCK_HELLO_ACK;
17467c478bd9Sstevel@tonic-gate kha->ks_hello_satype = (uint8_t)satype;
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate /*
1749*75d94465SJosef 'Jeff' Sipek * If we made it past the atomic_cas_ptr, then we have "exclusive"
1750*75d94465SJosef 'Jeff' Sipek * access to the timeout handle. Fire it off after the default ager
17510e9b5742SDan McDonald * interval.
17527c478bd9Sstevel@tonic-gate */
17530e9b5742SDan McDonald *top = qtimeout(*pfkey_qp, ager, agerarg,
17540e9b5742SDan McDonald drv_usectohz(SADB_AGE_INTERVAL_DEFAULT * 1000));
17557c478bd9Sstevel@tonic-gate
17567c478bd9Sstevel@tonic-gate putnext(*pfkey_qp, mp);
17577c478bd9Sstevel@tonic-gate }
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate /*
17608810c16bSdanmcd * Normalize IPv4-mapped IPv6 addresses (and prefixes) as appropriate.
17617c478bd9Sstevel@tonic-gate *
17628810c16bSdanmcd * Check addresses themselves for wildcard or multicast.
17638810c16bSdanmcd * Check ire table for local/non-local/broadcast.
17647c478bd9Sstevel@tonic-gate */
17657c478bd9Sstevel@tonic-gate int
sadb_addrcheck(queue_t * pfkey_q,mblk_t * mp,sadb_ext_t * ext,uint_t serial,netstack_t * ns)1766f4b3ec61Sdh155122 sadb_addrcheck(queue_t *pfkey_q, mblk_t *mp, sadb_ext_t *ext, uint_t serial,
1767f4b3ec61Sdh155122 netstack_t *ns)
17687c478bd9Sstevel@tonic-gate {
17697c478bd9Sstevel@tonic-gate sadb_address_t *addr = (sadb_address_t *)ext;
17707c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
17717c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6;
17728810c16bSdanmcd int diagnostic, type;
17738810c16bSdanmcd boolean_t normalized = B_FALSE;
17747c478bd9Sstevel@tonic-gate
17757c478bd9Sstevel@tonic-gate ASSERT(ext != NULL);
17767c478bd9Sstevel@tonic-gate ASSERT((ext->sadb_ext_type == SADB_EXT_ADDRESS_SRC) ||
17777c478bd9Sstevel@tonic-gate (ext->sadb_ext_type == SADB_EXT_ADDRESS_DST) ||
17788810c16bSdanmcd (ext->sadb_ext_type == SADB_X_EXT_ADDRESS_INNER_SRC) ||
17798810c16bSdanmcd (ext->sadb_ext_type == SADB_X_EXT_ADDRESS_INNER_DST) ||
17808810c16bSdanmcd (ext->sadb_ext_type == SADB_X_EXT_ADDRESS_NATT_LOC) ||
17818810c16bSdanmcd (ext->sadb_ext_type == SADB_X_EXT_ADDRESS_NATT_REM));
17827c478bd9Sstevel@tonic-gate
17837c478bd9Sstevel@tonic-gate /* Assign both sockaddrs, the compiler will do the right thing. */
17847c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)(addr + 1);
17857c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)(addr + 1);
17867c478bd9Sstevel@tonic-gate
17878810c16bSdanmcd if (sin6->sin6_family == AF_INET6) {
17888810c16bSdanmcd if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
17897c478bd9Sstevel@tonic-gate /*
17908810c16bSdanmcd * Convert to an AF_INET sockaddr. This means the
17918810c16bSdanmcd * return messages will have the extra space, but have
17928810c16bSdanmcd * AF_INET sockaddrs instead of AF_INET6.
17937c478bd9Sstevel@tonic-gate *
17947c478bd9Sstevel@tonic-gate * Yes, RFC 2367 isn't clear on what to do here w.r.t.
17957c478bd9Sstevel@tonic-gate * mapped addresses, but since AF_INET6 ::ffff:<v4> is
17967c478bd9Sstevel@tonic-gate * equal to AF_INET <v4>, it shouldnt be a huge
17977c478bd9Sstevel@tonic-gate * problem.
17987c478bd9Sstevel@tonic-gate */
17997c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET;
18008810c16bSdanmcd IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr,
18018810c16bSdanmcd &sin->sin_addr);
18027c478bd9Sstevel@tonic-gate bzero(&sin->sin_zero, sizeof (sin->sin_zero));
18038810c16bSdanmcd normalized = B_TRUE;
18047c478bd9Sstevel@tonic-gate }
18058810c16bSdanmcd } else if (sin->sin_family != AF_INET) {
18067c478bd9Sstevel@tonic-gate switch (ext->sadb_ext_type) {
18077c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_SRC:
18087c478bd9Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_BAD_SRC_AF;
18097c478bd9Sstevel@tonic-gate break;
18107c478bd9Sstevel@tonic-gate case SADB_EXT_ADDRESS_DST:
18117c478bd9Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_BAD_DST_AF;
18127c478bd9Sstevel@tonic-gate break;
18138810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_SRC:
18147c478bd9Sstevel@tonic-gate diagnostic = SADB_X_DIAGNOSTIC_BAD_PROXY_AF;
18157c478bd9Sstevel@tonic-gate break;
18168810c16bSdanmcd case SADB_X_EXT_ADDRESS_INNER_DST:
18178810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_BAD_INNER_DST_AF;
18188810c16bSdanmcd break;
18198810c16bSdanmcd case SADB_X_EXT_ADDRESS_NATT_LOC:
18208810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_BAD_NATT_LOC_AF;
18218810c16bSdanmcd break;
18228810c16bSdanmcd case SADB_X_EXT_ADDRESS_NATT_REM:
18238810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_BAD_NATT_REM_AF;
18248810c16bSdanmcd break;
18257c478bd9Sstevel@tonic-gate /* There is no default, see above ASSERT. */
18267c478bd9Sstevel@tonic-gate }
18278810c16bSdanmcd bail:
18288810c16bSdanmcd if (pfkey_q != NULL) {
18298810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL, diagnostic,
18308810c16bSdanmcd serial);
18318810c16bSdanmcd } else {
18328810c16bSdanmcd /*
18338810c16bSdanmcd * Scribble in sadb_msg that we got passed in.
18348810c16bSdanmcd * Overload "mp" to be an sadb_msg pointer.
18358810c16bSdanmcd */
18368810c16bSdanmcd sadb_msg_t *samsg = (sadb_msg_t *)mp;
18377c478bd9Sstevel@tonic-gate
18388810c16bSdanmcd samsg->sadb_msg_errno = EINVAL;
18398810c16bSdanmcd samsg->sadb_x_msg_diagnostic = diagnostic;
18408810c16bSdanmcd }
18417c478bd9Sstevel@tonic-gate return (KS_IN_ADDR_UNKNOWN);
18427c478bd9Sstevel@tonic-gate }
18437c478bd9Sstevel@tonic-gate
18448810c16bSdanmcd if (ext->sadb_ext_type == SADB_X_EXT_ADDRESS_INNER_SRC ||
18458810c16bSdanmcd ext->sadb_ext_type == SADB_X_EXT_ADDRESS_INNER_DST) {
18468810c16bSdanmcd /*
18478810c16bSdanmcd * We need only check for prefix issues.
18488810c16bSdanmcd */
18498810c16bSdanmcd
18508810c16bSdanmcd /* Set diagnostic now, in case we need it later. */
18518810c16bSdanmcd diagnostic =
18528810c16bSdanmcd (ext->sadb_ext_type == SADB_X_EXT_ADDRESS_INNER_SRC) ?
18538810c16bSdanmcd SADB_X_DIAGNOSTIC_PREFIX_INNER_SRC :
18548810c16bSdanmcd SADB_X_DIAGNOSTIC_PREFIX_INNER_DST;
18558810c16bSdanmcd
18568810c16bSdanmcd if (normalized)
18578810c16bSdanmcd addr->sadb_address_prefixlen -= 96;
18588810c16bSdanmcd
18598810c16bSdanmcd /*
18608810c16bSdanmcd * Verify and mask out inner-addresses based on prefix length.
18618810c16bSdanmcd */
18628810c16bSdanmcd if (sin->sin_family == AF_INET) {
18638810c16bSdanmcd if (addr->sadb_address_prefixlen > 32)
18648810c16bSdanmcd goto bail;
18658810c16bSdanmcd sin->sin_addr.s_addr &=
18668810c16bSdanmcd ip_plen_to_mask(addr->sadb_address_prefixlen);
18678810c16bSdanmcd } else {
18688810c16bSdanmcd in6_addr_t mask;
18698810c16bSdanmcd
18708810c16bSdanmcd ASSERT(sin->sin_family == AF_INET6);
18718810c16bSdanmcd /*
18728810c16bSdanmcd * ip_plen_to_mask_v6() returns NULL if the value in
18738810c16bSdanmcd * question is out of range.
18748810c16bSdanmcd */
18758810c16bSdanmcd if (ip_plen_to_mask_v6(addr->sadb_address_prefixlen,
18768810c16bSdanmcd &mask) == NULL)
18778810c16bSdanmcd goto bail;
18788810c16bSdanmcd sin6->sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
18798810c16bSdanmcd sin6->sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
18808810c16bSdanmcd sin6->sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
18818810c16bSdanmcd sin6->sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
18828810c16bSdanmcd }
18838810c16bSdanmcd
18848810c16bSdanmcd /* We don't care in these cases. */
18858810c16bSdanmcd return (KS_IN_ADDR_DONTCARE);
18868810c16bSdanmcd }
18878810c16bSdanmcd
18888810c16bSdanmcd if (sin->sin_family == AF_INET6) {
18898810c16bSdanmcd /* Check the easy ones now. */
18908810c16bSdanmcd if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
18918810c16bSdanmcd return (KS_IN_ADDR_MBCAST);
18928810c16bSdanmcd if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
18938810c16bSdanmcd return (KS_IN_ADDR_UNSPEC);
18948810c16bSdanmcd /*
18958810c16bSdanmcd * At this point, we're a unicast IPv6 address.
18968810c16bSdanmcd *
18978810c16bSdanmcd * XXX Zones alert -> me/notme decision needs to be tempered
18988810c16bSdanmcd * by what zone we're in when we go to zone-aware IPsec.
18998810c16bSdanmcd */
1900bd670b35SErik Nordmark if (ip_type_v6(&sin6->sin6_addr, ns->netstack_ip) ==
1901bd670b35SErik Nordmark IRE_LOCAL) {
19028810c16bSdanmcd /* Hey hey, it's local. */
19038810c16bSdanmcd return (KS_IN_ADDR_ME);
19048810c16bSdanmcd }
19058810c16bSdanmcd } else {
19068810c16bSdanmcd ASSERT(sin->sin_family == AF_INET);
19078810c16bSdanmcd if (sin->sin_addr.s_addr == INADDR_ANY)
19088810c16bSdanmcd return (KS_IN_ADDR_UNSPEC);
19098810c16bSdanmcd if (CLASSD(sin->sin_addr.s_addr))
19108810c16bSdanmcd return (KS_IN_ADDR_MBCAST);
19118810c16bSdanmcd /*
19128810c16bSdanmcd * At this point we're a unicast or broadcast IPv4 address.
19138810c16bSdanmcd *
1914bd670b35SErik Nordmark * Check if the address is IRE_BROADCAST or IRE_LOCAL.
19158810c16bSdanmcd *
19168810c16bSdanmcd * XXX Zones alert -> me/notme decision needs to be tempered
19178810c16bSdanmcd * by what zone we're in when we go to zone-aware IPsec.
19188810c16bSdanmcd */
1919bd670b35SErik Nordmark type = ip_type_v4(sin->sin_addr.s_addr, ns->netstack_ip);
1920bd670b35SErik Nordmark switch (type) {
1921bd670b35SErik Nordmark case IRE_LOCAL:
1922bd670b35SErik Nordmark return (KS_IN_ADDR_ME);
1923bd670b35SErik Nordmark case IRE_BROADCAST:
1924bd670b35SErik Nordmark return (KS_IN_ADDR_MBCAST);
19258810c16bSdanmcd }
19268810c16bSdanmcd }
19278810c16bSdanmcd
19288810c16bSdanmcd return (KS_IN_ADDR_NOTME);
19297c478bd9Sstevel@tonic-gate }
19307c478bd9Sstevel@tonic-gate
19317c478bd9Sstevel@tonic-gate /*
19328810c16bSdanmcd * Address normalizations and reality checks for inbound PF_KEY messages.
19338810c16bSdanmcd *
19347c478bd9Sstevel@tonic-gate * For the case of src == unspecified AF_INET6, and dst == AF_INET, convert
19358810c16bSdanmcd * the source to AF_INET. Do the same for the inner sources.
19367c478bd9Sstevel@tonic-gate */
19378810c16bSdanmcd boolean_t
sadb_addrfix(keysock_in_t * ksi,queue_t * pfkey_q,mblk_t * mp,netstack_t * ns)1938f4b3ec61Sdh155122 sadb_addrfix(keysock_in_t *ksi, queue_t *pfkey_q, mblk_t *mp, netstack_t *ns)
19397c478bd9Sstevel@tonic-gate {
19408810c16bSdanmcd struct sockaddr_in *src, *isrc;
19418810c16bSdanmcd struct sockaddr_in6 *dst, *idst;
19427c478bd9Sstevel@tonic-gate sadb_address_t *srcext, *dstext;
194307b56925Ssommerfe uint16_t sport;
19448810c16bSdanmcd sadb_ext_t **extv = ksi->ks_in_extv;
19458810c16bSdanmcd int rc;
19467c478bd9Sstevel@tonic-gate
19478810c16bSdanmcd if (extv[SADB_EXT_ADDRESS_SRC] != NULL) {
19488810c16bSdanmcd rc = sadb_addrcheck(pfkey_q, mp, extv[SADB_EXT_ADDRESS_SRC],
1949f4b3ec61Sdh155122 ksi->ks_in_serial, ns);
19508810c16bSdanmcd if (rc == KS_IN_ADDR_UNKNOWN)
19518810c16bSdanmcd return (B_FALSE);
19528810c16bSdanmcd if (rc == KS_IN_ADDR_MBCAST) {
19538810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
19548810c16bSdanmcd SADB_X_DIAGNOSTIC_BAD_SRC, ksi->ks_in_serial);
19558810c16bSdanmcd return (B_FALSE);
19568810c16bSdanmcd }
19578810c16bSdanmcd ksi->ks_in_srctype = rc;
19588810c16bSdanmcd }
19597c478bd9Sstevel@tonic-gate
19608810c16bSdanmcd if (extv[SADB_EXT_ADDRESS_DST] != NULL) {
19618810c16bSdanmcd rc = sadb_addrcheck(pfkey_q, mp, extv[SADB_EXT_ADDRESS_DST],
1962f4b3ec61Sdh155122 ksi->ks_in_serial, ns);
19638810c16bSdanmcd if (rc == KS_IN_ADDR_UNKNOWN)
19648810c16bSdanmcd return (B_FALSE);
19658810c16bSdanmcd if (rc == KS_IN_ADDR_UNSPEC) {
19668810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
19678810c16bSdanmcd SADB_X_DIAGNOSTIC_BAD_DST, ksi->ks_in_serial);
19688810c16bSdanmcd return (B_FALSE);
19698810c16bSdanmcd }
19708810c16bSdanmcd ksi->ks_in_dsttype = rc;
19718810c16bSdanmcd }
19727c478bd9Sstevel@tonic-gate
19737c478bd9Sstevel@tonic-gate /*
19748810c16bSdanmcd * NAT-Traversal addrs are simple enough to not require all of
19758810c16bSdanmcd * the checks in sadb_addrcheck(). Just normalize or reject if not
19768810c16bSdanmcd * AF_INET.
19777c478bd9Sstevel@tonic-gate */
19788810c16bSdanmcd if (extv[SADB_X_EXT_ADDRESS_NATT_LOC] != NULL) {
19798810c16bSdanmcd rc = sadb_addrcheck(pfkey_q, mp,
1980f4b3ec61Sdh155122 extv[SADB_X_EXT_ADDRESS_NATT_LOC], ksi->ks_in_serial, ns);
19818810c16bSdanmcd
19828810c16bSdanmcd /*
1983437220cdSdanmcd * Local NAT-T addresses never use an IRE_LOCAL, so it should
1984437220cdSdanmcd * always be NOTME, or UNSPEC (to handle both tunnel mode
1985437220cdSdanmcd * AND local-port flexibility).
19868810c16bSdanmcd */
1987437220cdSdanmcd if (rc != KS_IN_ADDR_NOTME && rc != KS_IN_ADDR_UNSPEC) {
19888810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
19898810c16bSdanmcd SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC,
19908810c16bSdanmcd ksi->ks_in_serial);
19918810c16bSdanmcd return (B_FALSE);
19928810c16bSdanmcd }
19938810c16bSdanmcd src = (struct sockaddr_in *)
19948810c16bSdanmcd (((sadb_address_t *)extv[SADB_X_EXT_ADDRESS_NATT_LOC]) + 1);
19958810c16bSdanmcd if (src->sin_family != AF_INET) {
19968810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
19978810c16bSdanmcd SADB_X_DIAGNOSTIC_BAD_NATT_LOC_AF,
19988810c16bSdanmcd ksi->ks_in_serial);
19998810c16bSdanmcd return (B_FALSE);
20008810c16bSdanmcd }
20018810c16bSdanmcd }
20028810c16bSdanmcd
20038810c16bSdanmcd if (extv[SADB_X_EXT_ADDRESS_NATT_REM] != NULL) {
20048810c16bSdanmcd rc = sadb_addrcheck(pfkey_q, mp,
2005f4b3ec61Sdh155122 extv[SADB_X_EXT_ADDRESS_NATT_REM], ksi->ks_in_serial, ns);
20068810c16bSdanmcd
20078810c16bSdanmcd /*
2008437220cdSdanmcd * Remote NAT-T addresses never use an IRE_LOCAL, so it should
20098810c16bSdanmcd * always be NOTME, or UNSPEC if it's a tunnel-mode SA.
20108810c16bSdanmcd */
20118810c16bSdanmcd if (rc != KS_IN_ADDR_NOTME &&
20128810c16bSdanmcd !(extv[SADB_X_EXT_ADDRESS_INNER_SRC] != NULL &&
20138810c16bSdanmcd rc == KS_IN_ADDR_UNSPEC)) {
20148810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
20158810c16bSdanmcd SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM,
20168810c16bSdanmcd ksi->ks_in_serial);
20178810c16bSdanmcd return (B_FALSE);
20188810c16bSdanmcd }
20198810c16bSdanmcd src = (struct sockaddr_in *)
20208810c16bSdanmcd (((sadb_address_t *)extv[SADB_X_EXT_ADDRESS_NATT_REM]) + 1);
20218810c16bSdanmcd if (src->sin_family != AF_INET) {
20228810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
20238810c16bSdanmcd SADB_X_DIAGNOSTIC_BAD_NATT_REM_AF,
20248810c16bSdanmcd ksi->ks_in_serial);
20258810c16bSdanmcd return (B_FALSE);
20268810c16bSdanmcd }
20278810c16bSdanmcd }
20288810c16bSdanmcd
20298810c16bSdanmcd if (extv[SADB_X_EXT_ADDRESS_INNER_SRC] != NULL) {
20308810c16bSdanmcd if (extv[SADB_X_EXT_ADDRESS_INNER_DST] == NULL) {
20318810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
20328810c16bSdanmcd SADB_X_DIAGNOSTIC_MISSING_INNER_DST,
20338810c16bSdanmcd ksi->ks_in_serial);
20348810c16bSdanmcd return (B_FALSE);
20358810c16bSdanmcd }
20368810c16bSdanmcd
20378810c16bSdanmcd if (sadb_addrcheck(pfkey_q, mp,
2038f4b3ec61Sdh155122 extv[SADB_X_EXT_ADDRESS_INNER_DST], ksi->ks_in_serial, ns)
20398810c16bSdanmcd == KS_IN_ADDR_UNKNOWN ||
20408810c16bSdanmcd sadb_addrcheck(pfkey_q, mp,
2041f4b3ec61Sdh155122 extv[SADB_X_EXT_ADDRESS_INNER_SRC], ksi->ks_in_serial, ns)
20428810c16bSdanmcd == KS_IN_ADDR_UNKNOWN)
20438810c16bSdanmcd return (B_FALSE);
20448810c16bSdanmcd
20458810c16bSdanmcd isrc = (struct sockaddr_in *)
20468810c16bSdanmcd (((sadb_address_t *)extv[SADB_X_EXT_ADDRESS_INNER_SRC]) +
20478810c16bSdanmcd 1);
20488810c16bSdanmcd idst = (struct sockaddr_in6 *)
20498810c16bSdanmcd (((sadb_address_t *)extv[SADB_X_EXT_ADDRESS_INNER_DST]) +
20508810c16bSdanmcd 1);
20518810c16bSdanmcd if (isrc->sin_family != idst->sin6_family) {
20528810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
20538810c16bSdanmcd SADB_X_DIAGNOSTIC_INNER_AF_MISMATCH,
20548810c16bSdanmcd ksi->ks_in_serial);
20558810c16bSdanmcd return (B_FALSE);
20568810c16bSdanmcd }
20578810c16bSdanmcd } else if (extv[SADB_X_EXT_ADDRESS_INNER_DST] != NULL) {
20588810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
20598810c16bSdanmcd SADB_X_DIAGNOSTIC_MISSING_INNER_SRC,
20608810c16bSdanmcd ksi->ks_in_serial);
20618810c16bSdanmcd return (B_FALSE);
20628810c16bSdanmcd } else {
20638810c16bSdanmcd isrc = NULL; /* For inner/outer port check below. */
20648810c16bSdanmcd }
20658810c16bSdanmcd
20668810c16bSdanmcd dstext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_DST];
20678810c16bSdanmcd srcext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_SRC];
20688810c16bSdanmcd
20698810c16bSdanmcd if (dstext == NULL || srcext == NULL)
20708810c16bSdanmcd return (B_TRUE);
20718810c16bSdanmcd
20728810c16bSdanmcd dst = (struct sockaddr_in6 *)(dstext + 1);
20738810c16bSdanmcd src = (struct sockaddr_in *)(srcext + 1);
20748810c16bSdanmcd
20758810c16bSdanmcd if (isrc != NULL &&
20768810c16bSdanmcd (isrc->sin_port != 0 || idst->sin6_port != 0) &&
20778810c16bSdanmcd (src->sin_port != 0 || dst->sin6_port != 0)) {
20788810c16bSdanmcd /* Can't set inner and outer ports in one SA. */
20798810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
20808810c16bSdanmcd SADB_X_DIAGNOSTIC_DUAL_PORT_SETS,
20818810c16bSdanmcd ksi->ks_in_serial);
20828810c16bSdanmcd return (B_FALSE);
20838810c16bSdanmcd }
20848810c16bSdanmcd
20858810c16bSdanmcd if (dst->sin6_family == src->sin_family)
20868810c16bSdanmcd return (B_TRUE);
20878810c16bSdanmcd
20888810c16bSdanmcd if (srcext->sadb_address_proto != dstext->sadb_address_proto) {
20898810c16bSdanmcd if (srcext->sadb_address_proto == 0) {
20908810c16bSdanmcd srcext->sadb_address_proto = dstext->sadb_address_proto;
20918810c16bSdanmcd } else if (dstext->sadb_address_proto == 0) {
20928810c16bSdanmcd dstext->sadb_address_proto = srcext->sadb_address_proto;
20938810c16bSdanmcd } else {
20948810c16bSdanmcd /* Inequal protocols, neither were 0. Report error. */
20958810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
20968810c16bSdanmcd SADB_X_DIAGNOSTIC_PROTO_MISMATCH,
20978810c16bSdanmcd ksi->ks_in_serial);
20988810c16bSdanmcd return (B_FALSE);
20998810c16bSdanmcd }
21008810c16bSdanmcd }
21018810c16bSdanmcd
21028810c16bSdanmcd /*
21038810c16bSdanmcd * With the exception of an unspec IPv6 source and an IPv4
21048810c16bSdanmcd * destination, address families MUST me matched.
21058810c16bSdanmcd */
21068810c16bSdanmcd if (src->sin_family == AF_INET ||
21078810c16bSdanmcd ksi->ks_in_srctype != KS_IN_ADDR_UNSPEC) {
21088810c16bSdanmcd sadb_pfkey_error(pfkey_q, mp, EINVAL,
21098810c16bSdanmcd SADB_X_DIAGNOSTIC_AF_MISMATCH, ksi->ks_in_serial);
21108810c16bSdanmcd return (B_FALSE);
21118810c16bSdanmcd }
21127c478bd9Sstevel@tonic-gate
211307b56925Ssommerfe /*
211407b56925Ssommerfe * Convert "src" to AF_INET INADDR_ANY. We rely on sin_port being
211507b56925Ssommerfe * in the same place for sockaddr_in and sockaddr_in6.
211607b56925Ssommerfe */
211707b56925Ssommerfe sport = src->sin_port;
21187c478bd9Sstevel@tonic-gate bzero(src, sizeof (*src));
21197c478bd9Sstevel@tonic-gate src->sin_family = AF_INET;
212007b56925Ssommerfe src->sin_port = sport;
21218810c16bSdanmcd
21228810c16bSdanmcd return (B_TRUE);
21237c478bd9Sstevel@tonic-gate }
21247c478bd9Sstevel@tonic-gate
21257c478bd9Sstevel@tonic-gate /*
21267c478bd9Sstevel@tonic-gate * Set the results in "addrtype", given an IRE as requested by
21277c478bd9Sstevel@tonic-gate * sadb_addrcheck().
21287c478bd9Sstevel@tonic-gate */
21297c478bd9Sstevel@tonic-gate int
sadb_addrset(ire_t * ire)21307c478bd9Sstevel@tonic-gate sadb_addrset(ire_t *ire)
21317c478bd9Sstevel@tonic-gate {
21327c478bd9Sstevel@tonic-gate if ((ire->ire_type & IRE_BROADCAST) ||
21337c478bd9Sstevel@tonic-gate (ire->ire_ipversion == IPV4_VERSION && CLASSD(ire->ire_addr)) ||
21347c478bd9Sstevel@tonic-gate (ire->ire_ipversion == IPV6_VERSION &&
21357c478bd9Sstevel@tonic-gate IN6_IS_ADDR_MULTICAST(&(ire->ire_addr_v6))))
21367c478bd9Sstevel@tonic-gate return (KS_IN_ADDR_MBCAST);
21377c478bd9Sstevel@tonic-gate if (ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK))
21387c478bd9Sstevel@tonic-gate return (KS_IN_ADDR_ME);
21397c478bd9Sstevel@tonic-gate return (KS_IN_ADDR_NOTME);
21407c478bd9Sstevel@tonic-gate }
21417c478bd9Sstevel@tonic-gate
21425d3b8cb7SBill Sommerfeld /*
21435d3b8cb7SBill Sommerfeld * Match primitives..
21445d3b8cb7SBill Sommerfeld * !!! TODO: short term: inner selectors
21455d3b8cb7SBill Sommerfeld * ipv6 scope id (ifindex)
21465d3b8cb7SBill Sommerfeld * longer term: zone id. sensitivity label. uid.
21475d3b8cb7SBill Sommerfeld */
21485d3b8cb7SBill Sommerfeld boolean_t
sadb_match_spi(ipsa_query_t * sq,ipsa_t * sa)21495d3b8cb7SBill Sommerfeld sadb_match_spi(ipsa_query_t *sq, ipsa_t *sa)
21505d3b8cb7SBill Sommerfeld {
21515d3b8cb7SBill Sommerfeld return (sq->spi == sa->ipsa_spi);
21525d3b8cb7SBill Sommerfeld }
21535d3b8cb7SBill Sommerfeld
21545d3b8cb7SBill Sommerfeld boolean_t
sadb_match_dst_v6(ipsa_query_t * sq,ipsa_t * sa)21555d3b8cb7SBill Sommerfeld sadb_match_dst_v6(ipsa_query_t *sq, ipsa_t *sa)
21565d3b8cb7SBill Sommerfeld {
21575d3b8cb7SBill Sommerfeld return (IPSA_ARE_ADDR_EQUAL(sa->ipsa_dstaddr, sq->dstaddr, AF_INET6));
21585d3b8cb7SBill Sommerfeld }
21595d3b8cb7SBill Sommerfeld
21605d3b8cb7SBill Sommerfeld boolean_t
sadb_match_src_v6(ipsa_query_t * sq,ipsa_t * sa)21615d3b8cb7SBill Sommerfeld sadb_match_src_v6(ipsa_query_t *sq, ipsa_t *sa)
21625d3b8cb7SBill Sommerfeld {
21635d3b8cb7SBill Sommerfeld return (IPSA_ARE_ADDR_EQUAL(sa->ipsa_srcaddr, sq->srcaddr, AF_INET6));
21645d3b8cb7SBill Sommerfeld }
21655d3b8cb7SBill Sommerfeld
21665d3b8cb7SBill Sommerfeld boolean_t
sadb_match_dst_v4(ipsa_query_t * sq,ipsa_t * sa)21675d3b8cb7SBill Sommerfeld sadb_match_dst_v4(ipsa_query_t *sq, ipsa_t *sa)
21685d3b8cb7SBill Sommerfeld {
21695d3b8cb7SBill Sommerfeld return (sq->dstaddr[0] == sa->ipsa_dstaddr[0]);
21705d3b8cb7SBill Sommerfeld }
21715d3b8cb7SBill Sommerfeld
21725d3b8cb7SBill Sommerfeld boolean_t
sadb_match_src_v4(ipsa_query_t * sq,ipsa_t * sa)21735d3b8cb7SBill Sommerfeld sadb_match_src_v4(ipsa_query_t *sq, ipsa_t *sa)
21745d3b8cb7SBill Sommerfeld {
21755d3b8cb7SBill Sommerfeld return (sq->srcaddr[0] == sa->ipsa_srcaddr[0]);
21765d3b8cb7SBill Sommerfeld }
21775d3b8cb7SBill Sommerfeld
21785d3b8cb7SBill Sommerfeld boolean_t
sadb_match_dstid(ipsa_query_t * sq,ipsa_t * sa)21795d3b8cb7SBill Sommerfeld sadb_match_dstid(ipsa_query_t *sq, ipsa_t *sa)
21805d3b8cb7SBill Sommerfeld {
21815d3b8cb7SBill Sommerfeld return ((sa->ipsa_dst_cid != NULL) &&
21825d3b8cb7SBill Sommerfeld (sq->didtype == sa->ipsa_dst_cid->ipsid_type) &&
21835d3b8cb7SBill Sommerfeld (strcmp(sq->didstr, sa->ipsa_dst_cid->ipsid_cid) == 0));
21845d3b8cb7SBill Sommerfeld
21855d3b8cb7SBill Sommerfeld }
21865d3b8cb7SBill Sommerfeld boolean_t
sadb_match_srcid(ipsa_query_t * sq,ipsa_t * sa)21875d3b8cb7SBill Sommerfeld sadb_match_srcid(ipsa_query_t *sq, ipsa_t *sa)
21885d3b8cb7SBill Sommerfeld {
21895d3b8cb7SBill Sommerfeld return ((sa->ipsa_src_cid != NULL) &&
21905d3b8cb7SBill Sommerfeld (sq->sidtype == sa->ipsa_src_cid->ipsid_type) &&
21915d3b8cb7SBill Sommerfeld (strcmp(sq->sidstr, sa->ipsa_src_cid->ipsid_cid) == 0));
21925d3b8cb7SBill Sommerfeld }
21935d3b8cb7SBill Sommerfeld
21945d3b8cb7SBill Sommerfeld boolean_t
sadb_match_kmc(ipsa_query_t * sq,ipsa_t * sa)21955d3b8cb7SBill Sommerfeld sadb_match_kmc(ipsa_query_t *sq, ipsa_t *sa)
21965d3b8cb7SBill Sommerfeld {
21975d3b8cb7SBill Sommerfeld #define M(a, b) (((a) == 0) || ((b) == 0) || ((a) == (b)))
21985d3b8cb7SBill Sommerfeld
21995d3b8cb7SBill Sommerfeld return (M(sq->kmc, sa->ipsa_kmc) && M(sq->kmp, sa->ipsa_kmp));
22005d3b8cb7SBill Sommerfeld
22015d3b8cb7SBill Sommerfeld #undef M
22025d3b8cb7SBill Sommerfeld }
22035d3b8cb7SBill Sommerfeld
22045d3b8cb7SBill Sommerfeld /*
22055d3b8cb7SBill Sommerfeld * Common function which extracts several PF_KEY extensions for ease of
22065d3b8cb7SBill Sommerfeld * SADB matching.
22075d3b8cb7SBill Sommerfeld *
22085d3b8cb7SBill Sommerfeld * XXX TODO: weed out ipsa_query_t fields not used during matching
22095d3b8cb7SBill Sommerfeld * or afterwards?
22105d3b8cb7SBill Sommerfeld */
22115d3b8cb7SBill Sommerfeld int
sadb_form_query(keysock_in_t * ksi,uint32_t req,uint32_t match,ipsa_query_t * sq,int * diagnostic)22125d3b8cb7SBill Sommerfeld sadb_form_query(keysock_in_t *ksi, uint32_t req, uint32_t match,
22135d3b8cb7SBill Sommerfeld ipsa_query_t *sq, int *diagnostic)
22145d3b8cb7SBill Sommerfeld {
22155d3b8cb7SBill Sommerfeld int i;
22165d3b8cb7SBill Sommerfeld ipsa_match_fn_t *mfpp = &(sq->matchers[0]);
22175d3b8cb7SBill Sommerfeld
22185d3b8cb7SBill Sommerfeld for (i = 0; i < IPSA_NMATCH; i++)
22195d3b8cb7SBill Sommerfeld sq->matchers[i] = NULL;
22205d3b8cb7SBill Sommerfeld
22215d3b8cb7SBill Sommerfeld ASSERT((req & ~match) == 0);
22225d3b8cb7SBill Sommerfeld
22235d3b8cb7SBill Sommerfeld sq->req = req;
22245d3b8cb7SBill Sommerfeld sq->dstext = (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
22255d3b8cb7SBill Sommerfeld sq->srcext = (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
22265d3b8cb7SBill Sommerfeld sq->assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
22275d3b8cb7SBill Sommerfeld
22285d3b8cb7SBill Sommerfeld if ((req & IPSA_Q_DST) && (sq->dstext == NULL)) {
22295d3b8cb7SBill Sommerfeld *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
22305d3b8cb7SBill Sommerfeld return (EINVAL);
22315d3b8cb7SBill Sommerfeld }
22325d3b8cb7SBill Sommerfeld if ((req & IPSA_Q_SRC) && (sq->srcext == NULL)) {
22335d3b8cb7SBill Sommerfeld *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
22345d3b8cb7SBill Sommerfeld return (EINVAL);
22355d3b8cb7SBill Sommerfeld }
22365d3b8cb7SBill Sommerfeld if ((req & IPSA_Q_SA) && (sq->assoc == NULL)) {
22375d3b8cb7SBill Sommerfeld *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
22385d3b8cb7SBill Sommerfeld return (EINVAL);
22395d3b8cb7SBill Sommerfeld }
22405d3b8cb7SBill Sommerfeld
22415d3b8cb7SBill Sommerfeld if (match & IPSA_Q_SA) {
22425d3b8cb7SBill Sommerfeld *mfpp++ = sadb_match_spi;
22435d3b8cb7SBill Sommerfeld sq->spi = sq->assoc->sadb_sa_spi;
22445d3b8cb7SBill Sommerfeld }
22455d3b8cb7SBill Sommerfeld
22465d3b8cb7SBill Sommerfeld if (sq->dstext != NULL)
22475d3b8cb7SBill Sommerfeld sq->dst = (struct sockaddr_in *)(sq->dstext + 1);
22485d3b8cb7SBill Sommerfeld else {
22495d3b8cb7SBill Sommerfeld sq->dst = NULL;
22505d3b8cb7SBill Sommerfeld sq->dst6 = NULL;
22515d3b8cb7SBill Sommerfeld sq->dstaddr = NULL;
22525d3b8cb7SBill Sommerfeld }
22535d3b8cb7SBill Sommerfeld
22545d3b8cb7SBill Sommerfeld if (sq->srcext != NULL)
22555d3b8cb7SBill Sommerfeld sq->src = (struct sockaddr_in *)(sq->srcext + 1);
22565d3b8cb7SBill Sommerfeld else {
22575d3b8cb7SBill Sommerfeld sq->src = NULL;
22585d3b8cb7SBill Sommerfeld sq->src6 = NULL;
22595d3b8cb7SBill Sommerfeld sq->srcaddr = NULL;
22605d3b8cb7SBill Sommerfeld }
22615d3b8cb7SBill Sommerfeld
22625d3b8cb7SBill Sommerfeld if (sq->dst != NULL)
22635d3b8cb7SBill Sommerfeld sq->af = sq->dst->sin_family;
22645d3b8cb7SBill Sommerfeld else if (sq->src != NULL)
22655d3b8cb7SBill Sommerfeld sq->af = sq->src->sin_family;
22665d3b8cb7SBill Sommerfeld else
22675d3b8cb7SBill Sommerfeld sq->af = AF_INET;
22685d3b8cb7SBill Sommerfeld
22695d3b8cb7SBill Sommerfeld if (sq->af == AF_INET6) {
22705d3b8cb7SBill Sommerfeld if ((match & IPSA_Q_DST) && (sq->dstext != NULL)) {
22715d3b8cb7SBill Sommerfeld *mfpp++ = sadb_match_dst_v6;
22725d3b8cb7SBill Sommerfeld sq->dst6 = (struct sockaddr_in6 *)sq->dst;
22735d3b8cb7SBill Sommerfeld sq->dstaddr = (uint32_t *)&(sq->dst6->sin6_addr);
22745d3b8cb7SBill Sommerfeld } else {
22755d3b8cb7SBill Sommerfeld match &= ~IPSA_Q_DST;
22765d3b8cb7SBill Sommerfeld sq->dstaddr = ALL_ZEROES_PTR;
22775d3b8cb7SBill Sommerfeld }
22785d3b8cb7SBill Sommerfeld
22795d3b8cb7SBill Sommerfeld if ((match & IPSA_Q_SRC) && (sq->srcext != NULL)) {
22805d3b8cb7SBill Sommerfeld sq->src6 = (struct sockaddr_in6 *)(sq->srcext + 1);
22815d3b8cb7SBill Sommerfeld sq->srcaddr = (uint32_t *)&sq->src6->sin6_addr;
22825d3b8cb7SBill Sommerfeld if (sq->src6->sin6_family != AF_INET6) {
22835d3b8cb7SBill Sommerfeld *diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
22845d3b8cb7SBill Sommerfeld return (EINVAL);
22855d3b8cb7SBill Sommerfeld }
22865d3b8cb7SBill Sommerfeld *mfpp++ = sadb_match_src_v6;
22875d3b8cb7SBill Sommerfeld } else {
22885d3b8cb7SBill Sommerfeld match &= ~IPSA_Q_SRC;
22895d3b8cb7SBill Sommerfeld sq->srcaddr = ALL_ZEROES_PTR;
22905d3b8cb7SBill Sommerfeld }
22915d3b8cb7SBill Sommerfeld } else {
22925d3b8cb7SBill Sommerfeld sq->src6 = sq->dst6 = NULL;
22935d3b8cb7SBill Sommerfeld if ((match & IPSA_Q_DST) && (sq->dstext != NULL)) {
22945d3b8cb7SBill Sommerfeld *mfpp++ = sadb_match_dst_v4;
22955d3b8cb7SBill Sommerfeld sq->dstaddr = (uint32_t *)&sq->dst->sin_addr;
22965d3b8cb7SBill Sommerfeld } else {
22975d3b8cb7SBill Sommerfeld match &= ~IPSA_Q_DST;
22985d3b8cb7SBill Sommerfeld sq->dstaddr = ALL_ZEROES_PTR;
22995d3b8cb7SBill Sommerfeld }
23005d3b8cb7SBill Sommerfeld if ((match & IPSA_Q_SRC) && (sq->srcext != NULL)) {
23015d3b8cb7SBill Sommerfeld sq->srcaddr = (uint32_t *)&sq->src->sin_addr;
23025d3b8cb7SBill Sommerfeld if (sq->src->sin_family != AF_INET) {
23035d3b8cb7SBill Sommerfeld *diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
23045d3b8cb7SBill Sommerfeld return (EINVAL);
23055d3b8cb7SBill Sommerfeld }
23065d3b8cb7SBill Sommerfeld *mfpp++ = sadb_match_src_v4;
23075d3b8cb7SBill Sommerfeld } else {
23085d3b8cb7SBill Sommerfeld match &= ~IPSA_Q_SRC;
23095d3b8cb7SBill Sommerfeld sq->srcaddr = ALL_ZEROES_PTR;
23105d3b8cb7SBill Sommerfeld }
23115d3b8cb7SBill Sommerfeld }
23125d3b8cb7SBill Sommerfeld
23135d3b8cb7SBill Sommerfeld sq->dstid = (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_DST];
23145d3b8cb7SBill Sommerfeld if ((match & IPSA_Q_DSTID) && (sq->dstid != NULL)) {
23155d3b8cb7SBill Sommerfeld sq->didstr = (char *)(sq->dstid + 1);
23165d3b8cb7SBill Sommerfeld sq->didtype = sq->dstid->sadb_ident_type;
23175d3b8cb7SBill Sommerfeld *mfpp++ = sadb_match_dstid;
23185d3b8cb7SBill Sommerfeld }
23195d3b8cb7SBill Sommerfeld
23205d3b8cb7SBill Sommerfeld sq->srcid = (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_SRC];
23215d3b8cb7SBill Sommerfeld
23225d3b8cb7SBill Sommerfeld if ((match & IPSA_Q_SRCID) && (sq->srcid != NULL)) {
23235d3b8cb7SBill Sommerfeld sq->sidstr = (char *)(sq->srcid + 1);
23245d3b8cb7SBill Sommerfeld sq->sidtype = sq->srcid->sadb_ident_type;
23255d3b8cb7SBill Sommerfeld *mfpp++ = sadb_match_srcid;
23265d3b8cb7SBill Sommerfeld }
23275d3b8cb7SBill Sommerfeld
23285d3b8cb7SBill Sommerfeld sq->kmcext = (sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
23295d3b8cb7SBill Sommerfeld sq->kmc = 0;
23305d3b8cb7SBill Sommerfeld sq->kmp = 0;
23315d3b8cb7SBill Sommerfeld
23325d3b8cb7SBill Sommerfeld if ((match & IPSA_Q_KMC) && (sq->kmcext)) {
23335d3b8cb7SBill Sommerfeld sq->kmc = sq->kmcext->sadb_x_kmc_cookie;
23345d3b8cb7SBill Sommerfeld sq->kmp = sq->kmcext->sadb_x_kmc_proto;
23355d3b8cb7SBill Sommerfeld *mfpp++ = sadb_match_kmc;
23365d3b8cb7SBill Sommerfeld }
23375d3b8cb7SBill Sommerfeld
23385d3b8cb7SBill Sommerfeld if (match & (IPSA_Q_INBOUND|IPSA_Q_OUTBOUND)) {
23395d3b8cb7SBill Sommerfeld if (sq->af == AF_INET6)
23405d3b8cb7SBill Sommerfeld sq->sp = &sq->spp->s_v6;
23415d3b8cb7SBill Sommerfeld else
23425d3b8cb7SBill Sommerfeld sq->sp = &sq->spp->s_v4;
23435d3b8cb7SBill Sommerfeld } else {
23445d3b8cb7SBill Sommerfeld sq->sp = NULL;
23455d3b8cb7SBill Sommerfeld }
23465d3b8cb7SBill Sommerfeld
23475d3b8cb7SBill Sommerfeld if (match & IPSA_Q_INBOUND) {
23485d3b8cb7SBill Sommerfeld sq->inhash = INBOUND_HASH(sq->sp, sq->assoc->sadb_sa_spi);
23495d3b8cb7SBill Sommerfeld sq->inbound = &sq->sp->sdb_if[sq->inhash];
23505d3b8cb7SBill Sommerfeld } else {
23515d3b8cb7SBill Sommerfeld sq->inhash = 0;
23525d3b8cb7SBill Sommerfeld sq->inbound = NULL;
23535d3b8cb7SBill Sommerfeld }
23545d3b8cb7SBill Sommerfeld
23555d3b8cb7SBill Sommerfeld if (match & IPSA_Q_OUTBOUND) {
23565d3b8cb7SBill Sommerfeld if (sq->af == AF_INET6) {
23575d3b8cb7SBill Sommerfeld sq->outhash = OUTBOUND_HASH_V6(sq->sp, *(sq->dstaddr));
23585d3b8cb7SBill Sommerfeld } else {
23595d3b8cb7SBill Sommerfeld sq->outhash = OUTBOUND_HASH_V4(sq->sp, *(sq->dstaddr));
23605d3b8cb7SBill Sommerfeld }
23615d3b8cb7SBill Sommerfeld sq->outbound = &sq->sp->sdb_of[sq->outhash];
23625d3b8cb7SBill Sommerfeld } else {
23635d3b8cb7SBill Sommerfeld sq->outhash = 0;
23645d3b8cb7SBill Sommerfeld sq->outbound = NULL;
23655d3b8cb7SBill Sommerfeld }
23665d3b8cb7SBill Sommerfeld sq->match = match;
23675d3b8cb7SBill Sommerfeld return (0);
23685d3b8cb7SBill Sommerfeld }
23695d3b8cb7SBill Sommerfeld
23705d3b8cb7SBill Sommerfeld /*
23715d3b8cb7SBill Sommerfeld * Match an initialized query structure with a security association;
23725d3b8cb7SBill Sommerfeld * return B_TRUE on a match, B_FALSE on a miss.
23735d3b8cb7SBill Sommerfeld * Applies match functions set up by sadb_form_query() until one returns false.
23745d3b8cb7SBill Sommerfeld */
23755d3b8cb7SBill Sommerfeld boolean_t
sadb_match_query(ipsa_query_t * sq,ipsa_t * sa)23765d3b8cb7SBill Sommerfeld sadb_match_query(ipsa_query_t *sq, ipsa_t *sa)
23775d3b8cb7SBill Sommerfeld {
23785d3b8cb7SBill Sommerfeld ipsa_match_fn_t *mfpp = &(sq->matchers[0]);
23795d3b8cb7SBill Sommerfeld ipsa_match_fn_t mfp;
23805d3b8cb7SBill Sommerfeld
23815d3b8cb7SBill Sommerfeld for (mfp = *mfpp++; mfp != NULL; mfp = *mfpp++) {
23825d3b8cb7SBill Sommerfeld if (!mfp(sq, sa))
23835d3b8cb7SBill Sommerfeld return (B_FALSE);
23845d3b8cb7SBill Sommerfeld }
23855d3b8cb7SBill Sommerfeld return (B_TRUE);
23865d3b8cb7SBill Sommerfeld }
23877c478bd9Sstevel@tonic-gate
23887c478bd9Sstevel@tonic-gate /*
23897c478bd9Sstevel@tonic-gate * Walker callback function to delete sa's based on src/dst address.
23907c478bd9Sstevel@tonic-gate * Assumes that we're called with *head locked, no other locks held;
23917c478bd9Sstevel@tonic-gate * Conveniently, and not coincidentally, this is both what sadb_walker
23927c478bd9Sstevel@tonic-gate * gives us and also what sadb_unlinkassoc expects.
23937c478bd9Sstevel@tonic-gate */
23947c478bd9Sstevel@tonic-gate struct sadb_purge_state
23957c478bd9Sstevel@tonic-gate {
23965d3b8cb7SBill Sommerfeld ipsa_query_t sq;
23977c478bd9Sstevel@tonic-gate boolean_t inbnd;
23989c2c14abSThejaswini Singarajipura uint8_t sadb_sa_state;
23997c478bd9Sstevel@tonic-gate };
24007c478bd9Sstevel@tonic-gate
24017c478bd9Sstevel@tonic-gate static void
sadb_purge_cb(isaf_t * head,ipsa_t * entry,void * cookie)24027c478bd9Sstevel@tonic-gate sadb_purge_cb(isaf_t *head, ipsa_t *entry, void *cookie)
24037c478bd9Sstevel@tonic-gate {
24047c478bd9Sstevel@tonic-gate struct sadb_purge_state *ps = (struct sadb_purge_state *)cookie;
24057c478bd9Sstevel@tonic-gate
24067c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&head->isaf_lock));
24077c478bd9Sstevel@tonic-gate
24087c478bd9Sstevel@tonic-gate mutex_enter(&entry->ipsa_lock);
24097c478bd9Sstevel@tonic-gate
24105d3b8cb7SBill Sommerfeld if (entry->ipsa_state == IPSA_STATE_LARVAL ||
24115d3b8cb7SBill Sommerfeld !sadb_match_query(&ps->sq, entry)) {
24127c478bd9Sstevel@tonic-gate mutex_exit(&entry->ipsa_lock);
24137c478bd9Sstevel@tonic-gate return;
24147c478bd9Sstevel@tonic-gate }
24157c478bd9Sstevel@tonic-gate
24169c2c14abSThejaswini Singarajipura if (ps->inbnd) {
24179c2c14abSThejaswini Singarajipura sadb_delete_cluster(entry);
24189c2c14abSThejaswini Singarajipura }
24197c478bd9Sstevel@tonic-gate entry->ipsa_state = IPSA_STATE_DEAD;
2420bd670b35SErik Nordmark (void) sadb_torch_assoc(head, entry);
24217c478bd9Sstevel@tonic-gate }
24227c478bd9Sstevel@tonic-gate
24237c478bd9Sstevel@tonic-gate /*
24247c478bd9Sstevel@tonic-gate * Common code to purge an SA with a matching src or dst address.
24257c478bd9Sstevel@tonic-gate * Don't kill larval SA's in such a purge.
24267c478bd9Sstevel@tonic-gate */
24277c478bd9Sstevel@tonic-gate int
sadb_purge_sa(mblk_t * mp,keysock_in_t * ksi,sadb_t * sp,int * diagnostic,queue_t * pfkey_q)24285d3b8cb7SBill Sommerfeld sadb_purge_sa(mblk_t *mp, keysock_in_t *ksi, sadb_t *sp,
2429bd670b35SErik Nordmark int *diagnostic, queue_t *pfkey_q)
24307c478bd9Sstevel@tonic-gate {
24317c478bd9Sstevel@tonic-gate struct sadb_purge_state ps;
24325d3b8cb7SBill Sommerfeld int error = sadb_form_query(ksi, 0,
24335d3b8cb7SBill Sommerfeld IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SRCID|IPSA_Q_DSTID|IPSA_Q_KMC,
24345d3b8cb7SBill Sommerfeld &ps.sq, diagnostic);
24357c478bd9Sstevel@tonic-gate
24365d3b8cb7SBill Sommerfeld if (error != 0)
24375d3b8cb7SBill Sommerfeld return (error);
24387c478bd9Sstevel@tonic-gate
24397c478bd9Sstevel@tonic-gate /*
24407c478bd9Sstevel@tonic-gate * This is simple, crude, and effective.
24417c478bd9Sstevel@tonic-gate * Unimplemented optimizations (TBD):
24427c478bd9Sstevel@tonic-gate * - we can limit how many places we search based on where we
24437c478bd9Sstevel@tonic-gate * think the SA is filed.
24447c478bd9Sstevel@tonic-gate * - if we get a dst address, we can hash based on dst addr to find
24457c478bd9Sstevel@tonic-gate * the correct bucket in the outbound table.
24467c478bd9Sstevel@tonic-gate */
24477c478bd9Sstevel@tonic-gate ps.inbnd = B_TRUE;
2448fb87b5d2Ssommerfe sadb_walker(sp->sdb_if, sp->sdb_hashsize, sadb_purge_cb, &ps);
24497c478bd9Sstevel@tonic-gate ps.inbnd = B_FALSE;
2450fb87b5d2Ssommerfe sadb_walker(sp->sdb_of, sp->sdb_hashsize, sadb_purge_cb, &ps);
24517c478bd9Sstevel@tonic-gate
24527c478bd9Sstevel@tonic-gate ASSERT(mp->b_cont != NULL);
24537c478bd9Sstevel@tonic-gate sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi,
24547c478bd9Sstevel@tonic-gate NULL);
24557c478bd9Sstevel@tonic-gate return (0);
24567c478bd9Sstevel@tonic-gate }
24577c478bd9Sstevel@tonic-gate
24589c2c14abSThejaswini Singarajipura static void
sadb_delpair_state_one(isaf_t * head,ipsa_t * entry,void * cookie)24595d3b8cb7SBill Sommerfeld sadb_delpair_state_one(isaf_t *head, ipsa_t *entry, void *cookie)
24609c2c14abSThejaswini Singarajipura {
24619c2c14abSThejaswini Singarajipura struct sadb_purge_state *ps = (struct sadb_purge_state *)cookie;
24629c2c14abSThejaswini Singarajipura isaf_t *inbound_bucket;
24639c2c14abSThejaswini Singarajipura ipsa_t *peer_assoc;
24645d3b8cb7SBill Sommerfeld ipsa_query_t *sq = &ps->sq;
24659c2c14abSThejaswini Singarajipura
24669c2c14abSThejaswini Singarajipura ASSERT(MUTEX_HELD(&head->isaf_lock));
24679c2c14abSThejaswini Singarajipura
24689c2c14abSThejaswini Singarajipura mutex_enter(&entry->ipsa_lock);
24699c2c14abSThejaswini Singarajipura
24709c2c14abSThejaswini Singarajipura if ((entry->ipsa_state != ps->sadb_sa_state) ||
24715d3b8cb7SBill Sommerfeld ((sq->srcaddr != NULL) &&
24725d3b8cb7SBill Sommerfeld !IPSA_ARE_ADDR_EQUAL(entry->ipsa_srcaddr, sq->srcaddr, sq->af))) {
24739c2c14abSThejaswini Singarajipura mutex_exit(&entry->ipsa_lock);
24749c2c14abSThejaswini Singarajipura return;
24759c2c14abSThejaswini Singarajipura }
24769c2c14abSThejaswini Singarajipura
24779c2c14abSThejaswini Singarajipura /*
24789c2c14abSThejaswini Singarajipura * The isaf_t *, which is passed in , is always an outbound bucket,
24799c2c14abSThejaswini Singarajipura * and we are preserving the outbound-then-inbound hash-bucket lock
24809c2c14abSThejaswini Singarajipura * ordering. The sadb_walker() which triggers this function is called
24819c2c14abSThejaswini Singarajipura * only on the outbound fanout, and the corresponding inbound bucket
24829c2c14abSThejaswini Singarajipura * lock is safe to acquire here.
24839c2c14abSThejaswini Singarajipura */
24849c2c14abSThejaswini Singarajipura
24859c2c14abSThejaswini Singarajipura if (entry->ipsa_haspeer) {
24865d3b8cb7SBill Sommerfeld inbound_bucket = INBOUND_BUCKET(sq->sp, entry->ipsa_spi);
24879c2c14abSThejaswini Singarajipura mutex_enter(&inbound_bucket->isaf_lock);
24889c2c14abSThejaswini Singarajipura peer_assoc = ipsec_getassocbyspi(inbound_bucket,
24899c2c14abSThejaswini Singarajipura entry->ipsa_spi, entry->ipsa_srcaddr,
24909c2c14abSThejaswini Singarajipura entry->ipsa_dstaddr, entry->ipsa_addrfam);
24919c2c14abSThejaswini Singarajipura } else {
24925d3b8cb7SBill Sommerfeld inbound_bucket = INBOUND_BUCKET(sq->sp, entry->ipsa_otherspi);
24939c2c14abSThejaswini Singarajipura mutex_enter(&inbound_bucket->isaf_lock);
24949c2c14abSThejaswini Singarajipura peer_assoc = ipsec_getassocbyspi(inbound_bucket,
24959c2c14abSThejaswini Singarajipura entry->ipsa_otherspi, entry->ipsa_dstaddr,
24969c2c14abSThejaswini Singarajipura entry->ipsa_srcaddr, entry->ipsa_addrfam);
24979c2c14abSThejaswini Singarajipura }
24989c2c14abSThejaswini Singarajipura
24999c2c14abSThejaswini Singarajipura entry->ipsa_state = IPSA_STATE_DEAD;
2500bd670b35SErik Nordmark (void) sadb_torch_assoc(head, entry);
25019c2c14abSThejaswini Singarajipura if (peer_assoc != NULL) {
25029c2c14abSThejaswini Singarajipura mutex_enter(&peer_assoc->ipsa_lock);
25039c2c14abSThejaswini Singarajipura peer_assoc->ipsa_state = IPSA_STATE_DEAD;
2504bd670b35SErik Nordmark (void) sadb_torch_assoc(inbound_bucket, peer_assoc);
25059c2c14abSThejaswini Singarajipura }
25069c2c14abSThejaswini Singarajipura mutex_exit(&inbound_bucket->isaf_lock);
25079c2c14abSThejaswini Singarajipura }
25089c2c14abSThejaswini Singarajipura
25095d3b8cb7SBill Sommerfeld static int
sadb_delpair_state(mblk_t * mp,keysock_in_t * ksi,sadbp_t * spp,int * diagnostic,queue_t * pfkey_q)25105d3b8cb7SBill Sommerfeld sadb_delpair_state(mblk_t *mp, keysock_in_t *ksi, sadbp_t *spp,
25115d3b8cb7SBill Sommerfeld int *diagnostic, queue_t *pfkey_q)
25127c478bd9Sstevel@tonic-gate {
25137c478bd9Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
25149c2c14abSThejaswini Singarajipura struct sadb_purge_state ps;
25155d3b8cb7SBill Sommerfeld int error;
25169c2c14abSThejaswini Singarajipura
25175d3b8cb7SBill Sommerfeld ps.sq.spp = spp; /* XXX param */
25185d3b8cb7SBill Sommerfeld
25195d3b8cb7SBill Sommerfeld error = sadb_form_query(ksi, IPSA_Q_DST|IPSA_Q_SRC,
25205d3b8cb7SBill Sommerfeld IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SRCID|IPSA_Q_DSTID|IPSA_Q_KMC,
25215d3b8cb7SBill Sommerfeld &ps.sq, diagnostic);
25225d3b8cb7SBill Sommerfeld if (error != 0)
25235d3b8cb7SBill Sommerfeld return (error);
25245d3b8cb7SBill Sommerfeld
25259c2c14abSThejaswini Singarajipura ps.inbnd = B_FALSE;
25269c2c14abSThejaswini Singarajipura ps.sadb_sa_state = assoc->sadb_sa_state;
25275d3b8cb7SBill Sommerfeld sadb_walker(ps.sq.sp->sdb_of, ps.sq.sp->sdb_hashsize,
25285d3b8cb7SBill Sommerfeld sadb_delpair_state_one, &ps);
25299c2c14abSThejaswini Singarajipura
25309c2c14abSThejaswini Singarajipura ASSERT(mp->b_cont != NULL);
25319c2c14abSThejaswini Singarajipura sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
25329c2c14abSThejaswini Singarajipura ksi, NULL);
25339c2c14abSThejaswini Singarajipura return (0);
25349c2c14abSThejaswini Singarajipura }
25359c2c14abSThejaswini Singarajipura
25365d3b8cb7SBill Sommerfeld /*
25375d3b8cb7SBill Sommerfeld * Common code to delete/get an SA.
25385d3b8cb7SBill Sommerfeld */
25395d3b8cb7SBill Sommerfeld int
sadb_delget_sa(mblk_t * mp,keysock_in_t * ksi,sadbp_t * spp,int * diagnostic,queue_t * pfkey_q,uint8_t sadb_msg_type)25405d3b8cb7SBill Sommerfeld sadb_delget_sa(mblk_t *mp, keysock_in_t *ksi, sadbp_t *spp,
25415d3b8cb7SBill Sommerfeld int *diagnostic, queue_t *pfkey_q, uint8_t sadb_msg_type)
25425d3b8cb7SBill Sommerfeld {
25435d3b8cb7SBill Sommerfeld ipsa_query_t sq;
25445d3b8cb7SBill Sommerfeld ipsa_t *echo_target = NULL;
25455d3b8cb7SBill Sommerfeld ipsap_t ipsapp;
25465d3b8cb7SBill Sommerfeld uint_t error = 0;
25475d3b8cb7SBill Sommerfeld
25485d3b8cb7SBill Sommerfeld if (sadb_msg_type == SADB_X_DELPAIR_STATE)
25495d3b8cb7SBill Sommerfeld return (sadb_delpair_state(mp, ksi, spp, diagnostic, pfkey_q));
25505d3b8cb7SBill Sommerfeld
25515d3b8cb7SBill Sommerfeld sq.spp = spp; /* XXX param */
25525d3b8cb7SBill Sommerfeld error = sadb_form_query(ksi, IPSA_Q_DST|IPSA_Q_SA,
25535d3b8cb7SBill Sommerfeld IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SA|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
25545d3b8cb7SBill Sommerfeld &sq, diagnostic);
25555d3b8cb7SBill Sommerfeld if (error != 0)
25565d3b8cb7SBill Sommerfeld return (error);
25575d3b8cb7SBill Sommerfeld
25585d3b8cb7SBill Sommerfeld error = get_ipsa_pair(&sq, &ipsapp, diagnostic);
25595d3b8cb7SBill Sommerfeld if (error != 0) {
25605d3b8cb7SBill Sommerfeld return (error);
25619c2c14abSThejaswini Singarajipura }
25629c2c14abSThejaswini Singarajipura
25635d3b8cb7SBill Sommerfeld echo_target = ipsapp.ipsap_sa_ptr;
256438d95a78Smarkfen if (echo_target == NULL)
25655d3b8cb7SBill Sommerfeld echo_target = ipsapp.ipsap_psa_ptr;
256638d95a78Smarkfen
256738d95a78Smarkfen if (sadb_msg_type == SADB_DELETE || sadb_msg_type == SADB_X_DELPAIR) {
256838d95a78Smarkfen /*
256938d95a78Smarkfen * Bucket locks will be required if SA is actually unlinked.
257038d95a78Smarkfen * get_ipsa_pair() returns valid hash bucket pointers even
2571a1ba8781SMark Fenwick * if it can't find a pair SA pointer. To prevent a potential
2572a1ba8781SMark Fenwick * deadlock, always lock the outbound bucket before the inbound.
257338d95a78Smarkfen */
25745d3b8cb7SBill Sommerfeld if (ipsapp.in_inbound_table) {
25755d3b8cb7SBill Sommerfeld mutex_enter(&ipsapp.ipsap_pbucket->isaf_lock);
25765d3b8cb7SBill Sommerfeld mutex_enter(&ipsapp.ipsap_bucket->isaf_lock);
2577a1ba8781SMark Fenwick } else {
25785d3b8cb7SBill Sommerfeld mutex_enter(&ipsapp.ipsap_bucket->isaf_lock);
25795d3b8cb7SBill Sommerfeld mutex_enter(&ipsapp.ipsap_pbucket->isaf_lock);
2580a1ba8781SMark Fenwick }
258138d95a78Smarkfen
25825d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_sa_ptr != NULL) {
25835d3b8cb7SBill Sommerfeld mutex_enter(&ipsapp.ipsap_sa_ptr->ipsa_lock);
25845d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_sa_ptr->ipsa_flags & IPSA_F_INBOUND) {
25855d3b8cb7SBill Sommerfeld sadb_delete_cluster(ipsapp.ipsap_sa_ptr);
25869c2c14abSThejaswini Singarajipura }
25875d3b8cb7SBill Sommerfeld ipsapp.ipsap_sa_ptr->ipsa_state = IPSA_STATE_DEAD;
25885d3b8cb7SBill Sommerfeld (void) sadb_torch_assoc(ipsapp.ipsap_bucket,
2589bd670b35SErik Nordmark ipsapp.ipsap_sa_ptr);
259038d95a78Smarkfen /*
259138d95a78Smarkfen * sadb_torch_assoc() releases the ipsa_lock
259238d95a78Smarkfen * and calls sadb_unlinkassoc() which does a
259338d95a78Smarkfen * IPSA_REFRELE.
259438d95a78Smarkfen */
259538d95a78Smarkfen }
25965d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_psa_ptr != NULL) {
25975d3b8cb7SBill Sommerfeld mutex_enter(&ipsapp.ipsap_psa_ptr->ipsa_lock);
2598fc809ee9SPaul Wernau if (sadb_msg_type == SADB_X_DELPAIR ||
25995d3b8cb7SBill Sommerfeld ipsapp.ipsap_psa_ptr->ipsa_haspeer) {
26005d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_psa_ptr->ipsa_flags &
26019c2c14abSThejaswini Singarajipura IPSA_F_INBOUND) {
26025d3b8cb7SBill Sommerfeld sadb_delete_cluster
26035d3b8cb7SBill Sommerfeld (ipsapp.ipsap_psa_ptr);
26049c2c14abSThejaswini Singarajipura }
26055d3b8cb7SBill Sommerfeld ipsapp.ipsap_psa_ptr->ipsa_state =
260638d95a78Smarkfen IPSA_STATE_DEAD;
26075d3b8cb7SBill Sommerfeld (void) sadb_torch_assoc(ipsapp.ipsap_pbucket,
2608bd670b35SErik Nordmark ipsapp.ipsap_psa_ptr);
260938d95a78Smarkfen } else {
261038d95a78Smarkfen /*
261138d95a78Smarkfen * Only half of the "pair" has been deleted.
261238d95a78Smarkfen * Update the remaining SA and remove references
261338d95a78Smarkfen * to its pair SA, which is now gone.
261438d95a78Smarkfen */
26155d3b8cb7SBill Sommerfeld ipsapp.ipsap_psa_ptr->ipsa_otherspi = 0;
26165d3b8cb7SBill Sommerfeld ipsapp.ipsap_psa_ptr->ipsa_flags &=
261738d95a78Smarkfen ~IPSA_F_PAIRED;
26185d3b8cb7SBill Sommerfeld mutex_exit(&ipsapp.ipsap_psa_ptr->ipsa_lock);
261938d95a78Smarkfen }
262038d95a78Smarkfen } else if (sadb_msg_type == SADB_X_DELPAIR) {
262138d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
262238d95a78Smarkfen error = ESRCH;
262338d95a78Smarkfen }
26245d3b8cb7SBill Sommerfeld mutex_exit(&ipsapp.ipsap_bucket->isaf_lock);
26255d3b8cb7SBill Sommerfeld mutex_exit(&ipsapp.ipsap_pbucket->isaf_lock);
262638d95a78Smarkfen }
262738d95a78Smarkfen
262838d95a78Smarkfen ASSERT(mp->b_cont != NULL);
262938d95a78Smarkfen
263038d95a78Smarkfen if (error == 0)
263138d95a78Smarkfen sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)
263238d95a78Smarkfen mp->b_cont->b_rptr, ksi, echo_target);
263338d95a78Smarkfen
26345d3b8cb7SBill Sommerfeld destroy_ipsa_pair(&ipsapp);
263538d95a78Smarkfen
263638d95a78Smarkfen return (error);
263738d95a78Smarkfen }
263838d95a78Smarkfen
263938d95a78Smarkfen /*
264038d95a78Smarkfen * This function takes a sadb_sa_t and finds the ipsa_t structure
264138d95a78Smarkfen * and the isaf_t (hash bucket) that its stored under. If the security
264238d95a78Smarkfen * association has a peer, the ipsa_t structure and bucket for that security
264338d95a78Smarkfen * association are also searched for. The "pair" of ipsa_t's and isaf_t's
264438d95a78Smarkfen * are returned as a ipsap_t.
264538d95a78Smarkfen *
2646a1ba8781SMark Fenwick * The hash buckets are returned for convenience, if the calling function
2647a1ba8781SMark Fenwick * needs to use the hash bucket locks, say to remove the SA's, it should
2648a1ba8781SMark Fenwick * take care to observe the convention of locking outbound bucket then
2649a1ba8781SMark Fenwick * inbound bucket. The flag in_inbound_table provides direction.
2650a1ba8781SMark Fenwick *
265138d95a78Smarkfen * Note that a "pair" is defined as one (but not both) of the following:
265238d95a78Smarkfen *
265338d95a78Smarkfen * A security association which has a soft reference to another security
265438d95a78Smarkfen * association via its SPI.
265538d95a78Smarkfen *
265638d95a78Smarkfen * A security association that is not obviously "inbound" or "outbound" so
265738d95a78Smarkfen * it appears in both hash tables, the "peer" being the same security
265838d95a78Smarkfen * association in the other hash table.
265938d95a78Smarkfen *
266038d95a78Smarkfen * This function will return NULL if the ipsa_t can't be found in the
266138d95a78Smarkfen * inbound or outbound hash tables (not found). If only one ipsa_t is
266238d95a78Smarkfen * found, the pair ipsa_t will be NULL. Both isaf_t values are valid
266338d95a78Smarkfen * provided at least one ipsa_t is found.
266438d95a78Smarkfen */
26655d3b8cb7SBill Sommerfeld static int
get_ipsa_pair(ipsa_query_t * sq,ipsap_t * ipsapp,int * diagnostic)26665d3b8cb7SBill Sommerfeld get_ipsa_pair(ipsa_query_t *sq, ipsap_t *ipsapp, int *diagnostic)
266738d95a78Smarkfen {
266838d95a78Smarkfen uint32_t pair_srcaddr[IPSA_MAX_ADDRLEN];
266938d95a78Smarkfen uint32_t pair_dstaddr[IPSA_MAX_ADDRLEN];
267038d95a78Smarkfen uint32_t pair_spi;
267138d95a78Smarkfen
26725d3b8cb7SBill Sommerfeld init_ipsa_pair(ipsapp);
267338d95a78Smarkfen
2674a1ba8781SMark Fenwick ipsapp->in_inbound_table = B_FALSE;
2675a1ba8781SMark Fenwick
26767c478bd9Sstevel@tonic-gate /* Lock down both buckets. */
26775d3b8cb7SBill Sommerfeld mutex_enter(&sq->outbound->isaf_lock);
26785d3b8cb7SBill Sommerfeld mutex_enter(&sq->inbound->isaf_lock);
26797c478bd9Sstevel@tonic-gate
26805d3b8cb7SBill Sommerfeld if (sq->assoc->sadb_sa_flags & IPSA_F_INBOUND) {
26815d3b8cb7SBill Sommerfeld ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(sq->inbound,
26825d3b8cb7SBill Sommerfeld sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr, sq->af);
268338d95a78Smarkfen if (ipsapp->ipsap_sa_ptr != NULL) {
26845d3b8cb7SBill Sommerfeld ipsapp->ipsap_bucket = sq->inbound;
26855d3b8cb7SBill Sommerfeld ipsapp->ipsap_pbucket = sq->outbound;
2686a1ba8781SMark Fenwick ipsapp->in_inbound_table = B_TRUE;
26877c478bd9Sstevel@tonic-gate } else {
26885d3b8cb7SBill Sommerfeld ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(sq->outbound,
26895d3b8cb7SBill Sommerfeld sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr,
26905d3b8cb7SBill Sommerfeld sq->af);
26915d3b8cb7SBill Sommerfeld ipsapp->ipsap_bucket = sq->outbound;
26925d3b8cb7SBill Sommerfeld ipsapp->ipsap_pbucket = sq->inbound;
26937c478bd9Sstevel@tonic-gate }
269438d95a78Smarkfen } else {
269538d95a78Smarkfen /* IPSA_F_OUTBOUND is set *or* no directions flags set. */
269638d95a78Smarkfen ipsapp->ipsap_sa_ptr =
26975d3b8cb7SBill Sommerfeld ipsec_getassocbyspi(sq->outbound,
26985d3b8cb7SBill Sommerfeld sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr, sq->af);
269938d95a78Smarkfen if (ipsapp->ipsap_sa_ptr != NULL) {
27005d3b8cb7SBill Sommerfeld ipsapp->ipsap_bucket = sq->outbound;
27015d3b8cb7SBill Sommerfeld ipsapp->ipsap_pbucket = sq->inbound;
270238d95a78Smarkfen } else {
27035d3b8cb7SBill Sommerfeld ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(sq->inbound,
27045d3b8cb7SBill Sommerfeld sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr,
27055d3b8cb7SBill Sommerfeld sq->af);
27065d3b8cb7SBill Sommerfeld ipsapp->ipsap_bucket = sq->inbound;
27075d3b8cb7SBill Sommerfeld ipsapp->ipsap_pbucket = sq->outbound;
270838d95a78Smarkfen if (ipsapp->ipsap_sa_ptr != NULL)
2709a1ba8781SMark Fenwick ipsapp->in_inbound_table = B_TRUE;
27107c478bd9Sstevel@tonic-gate }
27117c478bd9Sstevel@tonic-gate }
27127c478bd9Sstevel@tonic-gate
271338d95a78Smarkfen if (ipsapp->ipsap_sa_ptr == NULL) {
27145d3b8cb7SBill Sommerfeld mutex_exit(&sq->outbound->isaf_lock);
27155d3b8cb7SBill Sommerfeld mutex_exit(&sq->inbound->isaf_lock);
27165d3b8cb7SBill Sommerfeld *diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
27175d3b8cb7SBill Sommerfeld return (ESRCH);
271838d95a78Smarkfen }
27197c478bd9Sstevel@tonic-gate
272038d95a78Smarkfen if ((ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) &&
2721a1ba8781SMark Fenwick ipsapp->in_inbound_table) {
27225d3b8cb7SBill Sommerfeld mutex_exit(&sq->outbound->isaf_lock);
27235d3b8cb7SBill Sommerfeld mutex_exit(&sq->inbound->isaf_lock);
27245d3b8cb7SBill Sommerfeld return (0);
272538d95a78Smarkfen }
27267c478bd9Sstevel@tonic-gate
272738d95a78Smarkfen mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
272838d95a78Smarkfen if (ipsapp->ipsap_sa_ptr->ipsa_haspeer) {
27297c478bd9Sstevel@tonic-gate /*
273038d95a78Smarkfen * haspeer implies no sa_pairing, look for same spi
273138d95a78Smarkfen * in other hashtable.
27327c478bd9Sstevel@tonic-gate */
273338d95a78Smarkfen ipsapp->ipsap_psa_ptr =
273438d95a78Smarkfen ipsec_getassocbyspi(ipsapp->ipsap_pbucket,
27355d3b8cb7SBill Sommerfeld sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr, sq->af);
273638d95a78Smarkfen mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
27375d3b8cb7SBill Sommerfeld mutex_exit(&sq->outbound->isaf_lock);
27385d3b8cb7SBill Sommerfeld mutex_exit(&sq->inbound->isaf_lock);
27395d3b8cb7SBill Sommerfeld return (0);
27407c478bd9Sstevel@tonic-gate }
274138d95a78Smarkfen pair_spi = ipsapp->ipsap_sa_ptr->ipsa_otherspi;
274238d95a78Smarkfen IPSA_COPY_ADDR(&pair_srcaddr,
27435d3b8cb7SBill Sommerfeld ipsapp->ipsap_sa_ptr->ipsa_srcaddr, sq->af);
274438d95a78Smarkfen IPSA_COPY_ADDR(&pair_dstaddr,
27455d3b8cb7SBill Sommerfeld ipsapp->ipsap_sa_ptr->ipsa_dstaddr, sq->af);
274638d95a78Smarkfen mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
27475d3b8cb7SBill Sommerfeld mutex_exit(&sq->inbound->isaf_lock);
27485d3b8cb7SBill Sommerfeld mutex_exit(&sq->outbound->isaf_lock);
274938d95a78Smarkfen
275038d95a78Smarkfen if (pair_spi == 0) {
275138d95a78Smarkfen ASSERT(ipsapp->ipsap_bucket != NULL);
275238d95a78Smarkfen ASSERT(ipsapp->ipsap_pbucket != NULL);
27535d3b8cb7SBill Sommerfeld return (0);
27547c478bd9Sstevel@tonic-gate }
27557c478bd9Sstevel@tonic-gate
275638d95a78Smarkfen /* found sa in outbound sadb, peer should be inbound */
275738d95a78Smarkfen
2758a1ba8781SMark Fenwick if (ipsapp->in_inbound_table) {
275938d95a78Smarkfen /* Found SA in inbound table, pair will be in outbound. */
27605d3b8cb7SBill Sommerfeld if (sq->af == AF_INET6) {
27615d3b8cb7SBill Sommerfeld ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V6(sq->sp,
276238d95a78Smarkfen *(uint32_t *)pair_srcaddr);
276338d95a78Smarkfen } else {
27645d3b8cb7SBill Sommerfeld ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V4(sq->sp,
276538d95a78Smarkfen *(uint32_t *)pair_srcaddr);
276638d95a78Smarkfen }
276738d95a78Smarkfen } else {
27685d3b8cb7SBill Sommerfeld ipsapp->ipsap_pbucket = INBOUND_BUCKET(sq->sp, pair_spi);
276938d95a78Smarkfen }
277038d95a78Smarkfen mutex_enter(&ipsapp->ipsap_pbucket->isaf_lock);
277138d95a78Smarkfen ipsapp->ipsap_psa_ptr = ipsec_getassocbyspi(ipsapp->ipsap_pbucket,
27725d3b8cb7SBill Sommerfeld pair_spi, pair_dstaddr, pair_srcaddr, sq->af);
277338d95a78Smarkfen mutex_exit(&ipsapp->ipsap_pbucket->isaf_lock);
277438d95a78Smarkfen ASSERT(ipsapp->ipsap_bucket != NULL);
277538d95a78Smarkfen ASSERT(ipsapp->ipsap_pbucket != NULL);
27765d3b8cb7SBill Sommerfeld return (0);
27777c478bd9Sstevel@tonic-gate }
27787c478bd9Sstevel@tonic-gate
27797c478bd9Sstevel@tonic-gate /*
27808810c16bSdanmcd * Perform NAT-traversal cached checksum offset calculations here.
27817c478bd9Sstevel@tonic-gate */
27828810c16bSdanmcd static void
sadb_nat_calculations(ipsa_t * newbie,sadb_address_t * natt_loc_ext,sadb_address_t * natt_rem_ext,uint32_t * src_addr_ptr,uint32_t * dst_addr_ptr)27838810c16bSdanmcd sadb_nat_calculations(ipsa_t *newbie, sadb_address_t *natt_loc_ext,
27848810c16bSdanmcd sadb_address_t *natt_rem_ext, uint32_t *src_addr_ptr,
27858810c16bSdanmcd uint32_t *dst_addr_ptr)
27867c478bd9Sstevel@tonic-gate {
27878810c16bSdanmcd struct sockaddr_in *natt_loc, *natt_rem;
27887c478bd9Sstevel@tonic-gate uint32_t *natt_loc_ptr = NULL, *natt_rem_ptr = NULL;
27897c478bd9Sstevel@tonic-gate uint32_t running_sum = 0;
27907c478bd9Sstevel@tonic-gate
27917c478bd9Sstevel@tonic-gate #define DOWN_SUM(x) (x) = ((x) & 0xFFFF) + ((x) >> 16)
27927c478bd9Sstevel@tonic-gate
27937c478bd9Sstevel@tonic-gate if (natt_rem_ext != NULL) {
27947c478bd9Sstevel@tonic-gate uint32_t l_src;
27957c478bd9Sstevel@tonic-gate uint32_t l_rem;
27967c478bd9Sstevel@tonic-gate
27977c478bd9Sstevel@tonic-gate natt_rem = (struct sockaddr_in *)(natt_rem_ext + 1);
27987c478bd9Sstevel@tonic-gate
27998810c16bSdanmcd /* Ensured by sadb_addrfix(). */
28008810c16bSdanmcd ASSERT(natt_rem->sin_family == AF_INET);
28018810c16bSdanmcd
28027c478bd9Sstevel@tonic-gate natt_rem_ptr = (uint32_t *)(&natt_rem->sin_addr);
2803437220cdSdanmcd newbie->ipsa_remote_nat_port = natt_rem->sin_port;
28047c478bd9Sstevel@tonic-gate l_src = *src_addr_ptr;
28057c478bd9Sstevel@tonic-gate l_rem = *natt_rem_ptr;
28067c478bd9Sstevel@tonic-gate
28078810c16bSdanmcd /* Instead of IPSA_COPY_ADDR(), just copy first 32 bits. */
2808437220cdSdanmcd newbie->ipsa_natt_addr_rem = *natt_rem_ptr;
28097c478bd9Sstevel@tonic-gate
28107c478bd9Sstevel@tonic-gate l_src = ntohl(l_src);
28117c478bd9Sstevel@tonic-gate DOWN_SUM(l_src);
28127c478bd9Sstevel@tonic-gate DOWN_SUM(l_src);
28137c478bd9Sstevel@tonic-gate l_rem = ntohl(l_rem);
28147c478bd9Sstevel@tonic-gate DOWN_SUM(l_rem);
28157c478bd9Sstevel@tonic-gate DOWN_SUM(l_rem);
28167c478bd9Sstevel@tonic-gate
28177c478bd9Sstevel@tonic-gate /*
28187c478bd9Sstevel@tonic-gate * We're 1's complement for checksums, so check for wraparound
28197c478bd9Sstevel@tonic-gate * here.
28207c478bd9Sstevel@tonic-gate */
28217c478bd9Sstevel@tonic-gate if (l_rem > l_src)
28227c478bd9Sstevel@tonic-gate l_src--;
28237c478bd9Sstevel@tonic-gate
28247c478bd9Sstevel@tonic-gate running_sum += l_src - l_rem;
28257c478bd9Sstevel@tonic-gate
28267c478bd9Sstevel@tonic-gate DOWN_SUM(running_sum);
28277c478bd9Sstevel@tonic-gate DOWN_SUM(running_sum);
28287c478bd9Sstevel@tonic-gate }
28297c478bd9Sstevel@tonic-gate
28307c478bd9Sstevel@tonic-gate if (natt_loc_ext != NULL) {
28317c478bd9Sstevel@tonic-gate natt_loc = (struct sockaddr_in *)(natt_loc_ext + 1);
28327c478bd9Sstevel@tonic-gate
28338810c16bSdanmcd /* Ensured by sadb_addrfix(). */
28348810c16bSdanmcd ASSERT(natt_loc->sin_family == AF_INET);
28358810c16bSdanmcd
2836437220cdSdanmcd natt_loc_ptr = (uint32_t *)(&natt_loc->sin_addr);
2837437220cdSdanmcd newbie->ipsa_local_nat_port = natt_loc->sin_port;
28387c478bd9Sstevel@tonic-gate
28398810c16bSdanmcd /* Instead of IPSA_COPY_ADDR(), just copy first 32 bits. */
2840437220cdSdanmcd newbie->ipsa_natt_addr_loc = *natt_loc_ptr;
28417c478bd9Sstevel@tonic-gate
2842437220cdSdanmcd /*
2843437220cdSdanmcd * NAT-T port agility means we may have natt_loc_ext, but
2844437220cdSdanmcd * only for a local-port change.
2845437220cdSdanmcd */
2846437220cdSdanmcd if (natt_loc->sin_addr.s_addr != INADDR_ANY) {
2847437220cdSdanmcd uint32_t l_dst = ntohl(*dst_addr_ptr);
2848437220cdSdanmcd uint32_t l_loc = ntohl(*natt_loc_ptr);
2849437220cdSdanmcd
28507c478bd9Sstevel@tonic-gate DOWN_SUM(l_loc);
28517c478bd9Sstevel@tonic-gate DOWN_SUM(l_loc);
28527c478bd9Sstevel@tonic-gate DOWN_SUM(l_dst);
28537c478bd9Sstevel@tonic-gate DOWN_SUM(l_dst);
28547c478bd9Sstevel@tonic-gate
28557c478bd9Sstevel@tonic-gate /*
2856437220cdSdanmcd * We're 1's complement for checksums, so check for
2857437220cdSdanmcd * wraparound here.
28587c478bd9Sstevel@tonic-gate */
28597c478bd9Sstevel@tonic-gate if (l_loc > l_dst)
28607c478bd9Sstevel@tonic-gate l_dst--;
28617c478bd9Sstevel@tonic-gate
28627c478bd9Sstevel@tonic-gate running_sum += l_dst - l_loc;
28637c478bd9Sstevel@tonic-gate DOWN_SUM(running_sum);
28647c478bd9Sstevel@tonic-gate DOWN_SUM(running_sum);
28657c478bd9Sstevel@tonic-gate }
2866437220cdSdanmcd }
28677c478bd9Sstevel@tonic-gate
28687c478bd9Sstevel@tonic-gate newbie->ipsa_inbound_cksum = running_sum;
28697c478bd9Sstevel@tonic-gate #undef DOWN_SUM
28708810c16bSdanmcd }
28718810c16bSdanmcd
28728810c16bSdanmcd /*
28738810c16bSdanmcd * This function is called from consumers that need to insert a fully-grown
28748810c16bSdanmcd * security association into its tables. This function takes into account that
28758810c16bSdanmcd * SAs can be "inbound", "outbound", or "both". The "primary" and "secondary"
28768810c16bSdanmcd * hash bucket parameters are set in order of what the SA will be most of the
28778810c16bSdanmcd * time. (For example, an SA with an unspecified source, and a multicast
28788810c16bSdanmcd * destination will primarily be an outbound SA. OTOH, if that destination
28798810c16bSdanmcd * is unicast for this node, then the SA will primarily be inbound.)
28808810c16bSdanmcd *
28818810c16bSdanmcd * It takes a lot of parameters because even if clone is B_FALSE, this needs
28828810c16bSdanmcd * to check both buckets for purposes of collision.
28838810c16bSdanmcd *
28848810c16bSdanmcd * Return 0 upon success. Return various errnos (ENOMEM, EEXIST) for
28858810c16bSdanmcd * various error conditions. We may need to set samsg->sadb_x_msg_diagnostic
28868810c16bSdanmcd * with additional diagnostic information because there is at least one EINVAL
28878810c16bSdanmcd * case here.
28888810c16bSdanmcd */
28898810c16bSdanmcd int
sadb_common_add(queue_t * pfkey_q,mblk_t * mp,sadb_msg_t * samsg,keysock_in_t * ksi,isaf_t * primary,isaf_t * secondary,ipsa_t * newbie,boolean_t clone,boolean_t is_inbound,int * diagnostic,netstack_t * ns,sadbp_t * spp)2890bd670b35SErik Nordmark sadb_common_add(queue_t *pfkey_q, mblk_t *mp, sadb_msg_t *samsg,
28918810c16bSdanmcd keysock_in_t *ksi, isaf_t *primary, isaf_t *secondary,
2892f4b3ec61Sdh155122 ipsa_t *newbie, boolean_t clone, boolean_t is_inbound, int *diagnostic,
289338d95a78Smarkfen netstack_t *ns, sadbp_t *spp)
28948810c16bSdanmcd {
28958810c16bSdanmcd ipsa_t *newbie_clone = NULL, *scratch;
28965d3b8cb7SBill Sommerfeld ipsap_t ipsapp;
28978810c16bSdanmcd sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
28988810c16bSdanmcd sadb_address_t *srcext =
28998810c16bSdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
29008810c16bSdanmcd sadb_address_t *dstext =
29018810c16bSdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
29028810c16bSdanmcd sadb_address_t *isrcext =
29038810c16bSdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_SRC];
29048810c16bSdanmcd sadb_address_t *idstext =
29058810c16bSdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_DST];
29068810c16bSdanmcd sadb_x_kmc_t *kmcext =
29078810c16bSdanmcd (sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
29088810c16bSdanmcd sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
29098810c16bSdanmcd sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
29105d3b8cb7SBill Sommerfeld sadb_sens_t *sens =
29115d3b8cb7SBill Sommerfeld (sadb_sens_t *)ksi->ks_in_extv[SADB_EXT_SENSITIVITY];
29125d3b8cb7SBill Sommerfeld sadb_sens_t *osens =
29135d3b8cb7SBill Sommerfeld (sadb_sens_t *)ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS];
291438d95a78Smarkfen sadb_x_pair_t *pair_ext =
291538d95a78Smarkfen (sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
29169c2c14abSThejaswini Singarajipura sadb_x_replay_ctr_t *replayext =
29179c2c14abSThejaswini Singarajipura (sadb_x_replay_ctr_t *)ksi->ks_in_extv[SADB_X_EXT_REPLAY_VALUE];
29189c2c14abSThejaswini Singarajipura uint8_t protocol =
29199c2c14abSThejaswini Singarajipura (samsg->sadb_msg_satype == SADB_SATYPE_AH) ? IPPROTO_AH:IPPROTO_ESP;
2920628b0c67SMark Fenwick int salt_offset;
2921628b0c67SMark Fenwick uint8_t *buf_ptr;
29228810c16bSdanmcd struct sockaddr_in *src, *dst, *isrc, *idst;
29238810c16bSdanmcd struct sockaddr_in6 *src6, *dst6, *isrc6, *idst6;
29248810c16bSdanmcd sadb_lifetime_t *soft =
29258810c16bSdanmcd (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
29268810c16bSdanmcd sadb_lifetime_t *hard =
29278810c16bSdanmcd (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
29289c2c14abSThejaswini Singarajipura sadb_lifetime_t *idle =
29299c2c14abSThejaswini Singarajipura (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE];
29308810c16bSdanmcd sa_family_t af;
29318810c16bSdanmcd int error = 0;
29328810c16bSdanmcd boolean_t isupdate = (newbie != NULL);
29338810c16bSdanmcd uint32_t *src_addr_ptr, *dst_addr_ptr, *isrc_addr_ptr, *idst_addr_ptr;
2934f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec;
29355d3b8cb7SBill Sommerfeld ip_stack_t *ipst = ns->netstack_ip;
2936628b0c67SMark Fenwick ipsec_alginfo_t *alg;
29379c2c14abSThejaswini Singarajipura int rcode;
2938bd670b35SErik Nordmark boolean_t async = B_FALSE;
29398810c16bSdanmcd
29405d3b8cb7SBill Sommerfeld init_ipsa_pair(&ipsapp);
29415d3b8cb7SBill Sommerfeld
294238d95a78Smarkfen if (srcext == NULL) {
294338d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
294438d95a78Smarkfen return (EINVAL);
294538d95a78Smarkfen }
294638d95a78Smarkfen if (dstext == NULL) {
294738d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
294838d95a78Smarkfen return (EINVAL);
294938d95a78Smarkfen }
295038d95a78Smarkfen if (assoc == NULL) {
295138d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
295238d95a78Smarkfen return (EINVAL);
295338d95a78Smarkfen }
295438d95a78Smarkfen
29558810c16bSdanmcd src = (struct sockaddr_in *)(srcext + 1);
29568810c16bSdanmcd src6 = (struct sockaddr_in6 *)(srcext + 1);
29578810c16bSdanmcd dst = (struct sockaddr_in *)(dstext + 1);
29588810c16bSdanmcd dst6 = (struct sockaddr_in6 *)(dstext + 1);
29598810c16bSdanmcd if (isrcext != NULL) {
29608810c16bSdanmcd isrc = (struct sockaddr_in *)(isrcext + 1);
29618810c16bSdanmcd isrc6 = (struct sockaddr_in6 *)(isrcext + 1);
29628810c16bSdanmcd ASSERT(idstext != NULL);
29638810c16bSdanmcd idst = (struct sockaddr_in *)(idstext + 1);
29648810c16bSdanmcd idst6 = (struct sockaddr_in6 *)(idstext + 1);
29658810c16bSdanmcd } else {
29668810c16bSdanmcd isrc = NULL;
29678810c16bSdanmcd isrc6 = NULL;
29688810c16bSdanmcd }
29698810c16bSdanmcd
29708810c16bSdanmcd af = src->sin_family;
29718810c16bSdanmcd
29728810c16bSdanmcd if (af == AF_INET) {
29738810c16bSdanmcd src_addr_ptr = (uint32_t *)&src->sin_addr;
29748810c16bSdanmcd dst_addr_ptr = (uint32_t *)&dst->sin_addr;
29758810c16bSdanmcd } else {
29768810c16bSdanmcd ASSERT(af == AF_INET6);
29778810c16bSdanmcd src_addr_ptr = (uint32_t *)&src6->sin6_addr;
29788810c16bSdanmcd dst_addr_ptr = (uint32_t *)&dst6->sin6_addr;
29798810c16bSdanmcd }
29808810c16bSdanmcd
29819c2c14abSThejaswini Singarajipura if (!isupdate && (clone == B_TRUE || is_inbound == B_TRUE) &&
29829c2c14abSThejaswini Singarajipura cl_inet_checkspi &&
29839c2c14abSThejaswini Singarajipura (assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE_ELSEWHERE)) {
29848e4b770fSLu Huafeng rcode = cl_inet_checkspi(ns->netstack_stackid, protocol,
29858e4b770fSLu Huafeng assoc->sadb_sa_spi, NULL);
29869c2c14abSThejaswini Singarajipura if (rcode == -1) {
29879c2c14abSThejaswini Singarajipura return (EEXIST);
29889c2c14abSThejaswini Singarajipura }
29899c2c14abSThejaswini Singarajipura }
29909c2c14abSThejaswini Singarajipura
299138d95a78Smarkfen /*
299238d95a78Smarkfen * Check to see if the new SA will be cloned AND paired. The
299338d95a78Smarkfen * reason a SA will be cloned is the source or destination addresses
299438d95a78Smarkfen * are not specific enough to determine if the SA goes in the outbound
299538d95a78Smarkfen * or the inbound hash table, so its cloned and put in both. If
299638d95a78Smarkfen * the SA is paired, it's soft linked to another SA for the other
299738d95a78Smarkfen * direction. Keeping track and looking up SA's that are direction
299838d95a78Smarkfen * unspecific and linked is too hard.
299938d95a78Smarkfen */
300038d95a78Smarkfen if (clone && (pair_ext != NULL)) {
300138d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
300238d95a78Smarkfen return (EINVAL);
300338d95a78Smarkfen }
300438d95a78Smarkfen
30058810c16bSdanmcd if (!isupdate) {
30068810c16bSdanmcd newbie = sadb_makelarvalassoc(assoc->sadb_sa_spi,
3007f4b3ec61Sdh155122 src_addr_ptr, dst_addr_ptr, af, ns);
30088810c16bSdanmcd if (newbie == NULL)
30098810c16bSdanmcd return (ENOMEM);
30108810c16bSdanmcd }
30118810c16bSdanmcd
30128810c16bSdanmcd mutex_enter(&newbie->ipsa_lock);
30138810c16bSdanmcd
30148810c16bSdanmcd if (isrc != NULL) {
30158810c16bSdanmcd if (isrc->sin_family == AF_INET) {
30168810c16bSdanmcd if (srcext->sadb_address_proto != IPPROTO_ENCAP) {
30178810c16bSdanmcd if (srcext->sadb_address_proto != 0) {
30188810c16bSdanmcd /*
30198810c16bSdanmcd * Mismatched outer-packet protocol
30208810c16bSdanmcd * and inner-packet address family.
30218810c16bSdanmcd */
30228810c16bSdanmcd mutex_exit(&newbie->ipsa_lock);
30238810c16bSdanmcd error = EPROTOTYPE;
3024a1ba8781SMark Fenwick *diagnostic =
3025a1ba8781SMark Fenwick SADB_X_DIAGNOSTIC_INNER_AF_MISMATCH;
30268810c16bSdanmcd goto error;
30278810c16bSdanmcd } else {
30288810c16bSdanmcd /* Fill in with explicit protocol. */
30298810c16bSdanmcd srcext->sadb_address_proto =
30308810c16bSdanmcd IPPROTO_ENCAP;
30318810c16bSdanmcd dstext->sadb_address_proto =
30328810c16bSdanmcd IPPROTO_ENCAP;
30338810c16bSdanmcd }
30348810c16bSdanmcd }
30358810c16bSdanmcd isrc_addr_ptr = (uint32_t *)&isrc->sin_addr;
30368810c16bSdanmcd idst_addr_ptr = (uint32_t *)&idst->sin_addr;
30378810c16bSdanmcd } else {
30388810c16bSdanmcd ASSERT(isrc->sin_family == AF_INET6);
30398810c16bSdanmcd if (srcext->sadb_address_proto != IPPROTO_IPV6) {
30408810c16bSdanmcd if (srcext->sadb_address_proto != 0) {
30418810c16bSdanmcd /*
30428810c16bSdanmcd * Mismatched outer-packet protocol
30438810c16bSdanmcd * and inner-packet address family.
30448810c16bSdanmcd */
30458810c16bSdanmcd mutex_exit(&newbie->ipsa_lock);
30468810c16bSdanmcd error = EPROTOTYPE;
3047a1ba8781SMark Fenwick *diagnostic =
3048a1ba8781SMark Fenwick SADB_X_DIAGNOSTIC_INNER_AF_MISMATCH;
30498810c16bSdanmcd goto error;
30508810c16bSdanmcd } else {
30518810c16bSdanmcd /* Fill in with explicit protocol. */
30528810c16bSdanmcd srcext->sadb_address_proto =
30538810c16bSdanmcd IPPROTO_IPV6;
30548810c16bSdanmcd dstext->sadb_address_proto =
30558810c16bSdanmcd IPPROTO_IPV6;
30568810c16bSdanmcd }
30578810c16bSdanmcd }
30588810c16bSdanmcd isrc_addr_ptr = (uint32_t *)&isrc6->sin6_addr;
30598810c16bSdanmcd idst_addr_ptr = (uint32_t *)&idst6->sin6_addr;
30608810c16bSdanmcd }
30618810c16bSdanmcd newbie->ipsa_innerfam = isrc->sin_family;
30628810c16bSdanmcd
30638810c16bSdanmcd IPSA_COPY_ADDR(newbie->ipsa_innersrc, isrc_addr_ptr,
30648810c16bSdanmcd newbie->ipsa_innerfam);
30658810c16bSdanmcd IPSA_COPY_ADDR(newbie->ipsa_innerdst, idst_addr_ptr,
30668810c16bSdanmcd newbie->ipsa_innerfam);
30678810c16bSdanmcd newbie->ipsa_innersrcpfx = isrcext->sadb_address_prefixlen;
30688810c16bSdanmcd newbie->ipsa_innerdstpfx = idstext->sadb_address_prefixlen;
30698810c16bSdanmcd
30708810c16bSdanmcd /* Unique value uses inner-ports for Tunnel Mode... */
30718810c16bSdanmcd newbie->ipsa_unique_id = SA_UNIQUE_ID(isrc->sin_port,
30728810c16bSdanmcd idst->sin_port, dstext->sadb_address_proto,
30738810c16bSdanmcd idstext->sadb_address_proto);
30748810c16bSdanmcd newbie->ipsa_unique_mask = SA_UNIQUE_MASK(isrc->sin_port,
30758810c16bSdanmcd idst->sin_port, dstext->sadb_address_proto,
30768810c16bSdanmcd idstext->sadb_address_proto);
30778810c16bSdanmcd } else {
30788810c16bSdanmcd /* ... and outer-ports for Transport Mode. */
30798810c16bSdanmcd newbie->ipsa_unique_id = SA_UNIQUE_ID(src->sin_port,
30808810c16bSdanmcd dst->sin_port, dstext->sadb_address_proto, 0);
30818810c16bSdanmcd newbie->ipsa_unique_mask = SA_UNIQUE_MASK(src->sin_port,
30828810c16bSdanmcd dst->sin_port, dstext->sadb_address_proto, 0);
30838810c16bSdanmcd }
30848810c16bSdanmcd if (newbie->ipsa_unique_mask != (uint64_t)0)
30858810c16bSdanmcd newbie->ipsa_flags |= IPSA_F_UNIQUE;
30868810c16bSdanmcd
30878810c16bSdanmcd sadb_nat_calculations(newbie,
30888810c16bSdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_LOC],
30898810c16bSdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_REM],
30908810c16bSdanmcd src_addr_ptr, dst_addr_ptr);
30917c478bd9Sstevel@tonic-gate
30927c478bd9Sstevel@tonic-gate newbie->ipsa_type = samsg->sadb_msg_satype;
3093a1ba8781SMark Fenwick
30949c2c14abSThejaswini Singarajipura ASSERT((assoc->sadb_sa_state == SADB_SASTATE_MATURE) ||
30959c2c14abSThejaswini Singarajipura (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE));
30967c478bd9Sstevel@tonic-gate newbie->ipsa_auth_alg = assoc->sadb_sa_auth;
30977c478bd9Sstevel@tonic-gate newbie->ipsa_encr_alg = assoc->sadb_sa_encrypt;
309838d95a78Smarkfen
30998810c16bSdanmcd newbie->ipsa_flags |= assoc->sadb_sa_flags;
3100a1ba8781SMark Fenwick if (newbie->ipsa_flags & SADB_X_SAFLAGS_NATT_LOC &&
3101a1ba8781SMark Fenwick ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_LOC] == NULL) {
31028810c16bSdanmcd mutex_exit(&newbie->ipsa_lock);
3103a1ba8781SMark Fenwick *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_LOC;
3104a1ba8781SMark Fenwick error = EINVAL;
3105a1ba8781SMark Fenwick goto error;
3106a1ba8781SMark Fenwick }
3107a1ba8781SMark Fenwick if (newbie->ipsa_flags & SADB_X_SAFLAGS_NATT_REM &&
3108a1ba8781SMark Fenwick ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_REM] == NULL) {
3109a1ba8781SMark Fenwick mutex_exit(&newbie->ipsa_lock);
3110a1ba8781SMark Fenwick *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_REM;
3111a1ba8781SMark Fenwick error = EINVAL;
3112a1ba8781SMark Fenwick goto error;
3113a1ba8781SMark Fenwick }
3114a1ba8781SMark Fenwick if (newbie->ipsa_flags & SADB_X_SAFLAGS_TUNNEL &&
3115a1ba8781SMark Fenwick ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_SRC] == NULL) {
3116a1ba8781SMark Fenwick mutex_exit(&newbie->ipsa_lock);
3117a1ba8781SMark Fenwick *diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_SRC;
31188810c16bSdanmcd error = EINVAL;
31198810c16bSdanmcd goto error;
31208810c16bSdanmcd }
31217c478bd9Sstevel@tonic-gate /*
31227c478bd9Sstevel@tonic-gate * If unspecified source address, force replay_wsize to 0.
31237c478bd9Sstevel@tonic-gate * This is because an SA that has multiple sources of secure
31247c478bd9Sstevel@tonic-gate * traffic cannot enforce a replay counter w/o synchronizing the
31257c478bd9Sstevel@tonic-gate * senders.
31267c478bd9Sstevel@tonic-gate */
31277c478bd9Sstevel@tonic-gate if (ksi->ks_in_srctype != KS_IN_ADDR_UNSPEC)
31287c478bd9Sstevel@tonic-gate newbie->ipsa_replay_wsize = assoc->sadb_sa_replay;
31297c478bd9Sstevel@tonic-gate else
31307c478bd9Sstevel@tonic-gate newbie->ipsa_replay_wsize = 0;
31317c478bd9Sstevel@tonic-gate
3132437220cdSdanmcd newbie->ipsa_addtime = gethrestime_sec();
31337c478bd9Sstevel@tonic-gate
31347c478bd9Sstevel@tonic-gate if (kmcext != NULL) {
31357c478bd9Sstevel@tonic-gate newbie->ipsa_kmp = kmcext->sadb_x_kmc_proto;
31367c478bd9Sstevel@tonic-gate newbie->ipsa_kmc = kmcext->sadb_x_kmc_cookie;
31377c478bd9Sstevel@tonic-gate }
31387c478bd9Sstevel@tonic-gate
31397c478bd9Sstevel@tonic-gate /*
31407c478bd9Sstevel@tonic-gate * XXX CURRENT lifetime checks MAY BE needed for an UPDATE.
31417c478bd9Sstevel@tonic-gate * The spec says that one can update current lifetimes, but
31427c478bd9Sstevel@tonic-gate * that seems impractical, especially in the larval-to-mature
31437c478bd9Sstevel@tonic-gate * update that this function performs.
31447c478bd9Sstevel@tonic-gate */
31457c478bd9Sstevel@tonic-gate if (soft != NULL) {
31467c478bd9Sstevel@tonic-gate newbie->ipsa_softaddlt = soft->sadb_lifetime_addtime;
31477c478bd9Sstevel@tonic-gate newbie->ipsa_softuselt = soft->sadb_lifetime_usetime;
31487c478bd9Sstevel@tonic-gate newbie->ipsa_softbyteslt = soft->sadb_lifetime_bytes;
31497c478bd9Sstevel@tonic-gate newbie->ipsa_softalloc = soft->sadb_lifetime_allocations;
31507c478bd9Sstevel@tonic-gate SET_EXPIRE(newbie, softaddlt, softexpiretime);
31517c478bd9Sstevel@tonic-gate }
31527c478bd9Sstevel@tonic-gate if (hard != NULL) {
31537c478bd9Sstevel@tonic-gate newbie->ipsa_hardaddlt = hard->sadb_lifetime_addtime;
31547c478bd9Sstevel@tonic-gate newbie->ipsa_harduselt = hard->sadb_lifetime_usetime;
31557c478bd9Sstevel@tonic-gate newbie->ipsa_hardbyteslt = hard->sadb_lifetime_bytes;
31567c478bd9Sstevel@tonic-gate newbie->ipsa_hardalloc = hard->sadb_lifetime_allocations;
31577c478bd9Sstevel@tonic-gate SET_EXPIRE(newbie, hardaddlt, hardexpiretime);
31587c478bd9Sstevel@tonic-gate }
31599c2c14abSThejaswini Singarajipura if (idle != NULL) {
31609c2c14abSThejaswini Singarajipura newbie->ipsa_idleaddlt = idle->sadb_lifetime_addtime;
31619c2c14abSThejaswini Singarajipura newbie->ipsa_idleuselt = idle->sadb_lifetime_usetime;
31629c2c14abSThejaswini Singarajipura newbie->ipsa_idleexpiretime = newbie->ipsa_addtime +
31639c2c14abSThejaswini Singarajipura newbie->ipsa_idleaddlt;
31649c2c14abSThejaswini Singarajipura newbie->ipsa_idletime = newbie->ipsa_idleaddlt;
31659c2c14abSThejaswini Singarajipura }
31667c478bd9Sstevel@tonic-gate
31677c478bd9Sstevel@tonic-gate newbie->ipsa_authtmpl = NULL;
31687c478bd9Sstevel@tonic-gate newbie->ipsa_encrtmpl = NULL;
31697c478bd9Sstevel@tonic-gate
3170bd670b35SErik Nordmark #ifdef IPSEC_LATENCY_TEST
3171bd670b35SErik Nordmark if (akey != NULL && newbie->ipsa_auth_alg != SADB_AALG_NONE) {
3172bd670b35SErik Nordmark #else
31737c478bd9Sstevel@tonic-gate if (akey != NULL) {
3174bd670b35SErik Nordmark #endif
3175bd670b35SErik Nordmark async = (ipss->ipsec_algs_exec_mode[IPSEC_ALG_AUTH] ==
3176bd670b35SErik Nordmark IPSEC_ALGS_EXEC_ASYNC);
3177bd670b35SErik Nordmark
31787c478bd9Sstevel@tonic-gate newbie->ipsa_authkeybits = akey->sadb_key_bits;
31797c478bd9Sstevel@tonic-gate newbie->ipsa_authkeylen = SADB_1TO8(akey->sadb_key_bits);
31807c478bd9Sstevel@tonic-gate /* In case we have to round up to the next byte... */
31817c478bd9Sstevel@tonic-gate if ((akey->sadb_key_bits & 0x7) != 0)
31827c478bd9Sstevel@tonic-gate newbie->ipsa_authkeylen++;
31837c478bd9Sstevel@tonic-gate newbie->ipsa_authkey = kmem_alloc(newbie->ipsa_authkeylen,
31847c478bd9Sstevel@tonic-gate KM_NOSLEEP);
31857c478bd9Sstevel@tonic-gate if (newbie->ipsa_authkey == NULL) {
31867c478bd9Sstevel@tonic-gate error = ENOMEM;
31877c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsa_lock);
31887c478bd9Sstevel@tonic-gate goto error;
31897c478bd9Sstevel@tonic-gate }
31907c478bd9Sstevel@tonic-gate bcopy(akey + 1, newbie->ipsa_authkey, newbie->ipsa_authkeylen);
31917c478bd9Sstevel@tonic-gate bzero(akey + 1, newbie->ipsa_authkeylen);
31927c478bd9Sstevel@tonic-gate
31937c478bd9Sstevel@tonic-gate /*
31947c478bd9Sstevel@tonic-gate * Pre-initialize the kernel crypto framework key
31957c478bd9Sstevel@tonic-gate * structure.
31967c478bd9Sstevel@tonic-gate */
31977c478bd9Sstevel@tonic-gate newbie->ipsa_kcfauthkey.ck_format = CRYPTO_KEY_RAW;
31987c478bd9Sstevel@tonic-gate newbie->ipsa_kcfauthkey.ck_length = newbie->ipsa_authkeybits;
31997c478bd9Sstevel@tonic-gate newbie->ipsa_kcfauthkey.ck_data = newbie->ipsa_authkey;
32007c478bd9Sstevel@tonic-gate
3201f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_alg_lock);
3202628b0c67SMark Fenwick alg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
3203628b0c67SMark Fenwick [newbie->ipsa_auth_alg];
3204628b0c67SMark Fenwick if (alg != NULL && ALG_VALID(alg)) {
3205628b0c67SMark Fenwick newbie->ipsa_amech.cm_type = alg->alg_mech_type;
3206628b0c67SMark Fenwick newbie->ipsa_amech.cm_param =
3207628b0c67SMark Fenwick (char *)&newbie->ipsa_mac_len;
3208628b0c67SMark Fenwick newbie->ipsa_amech.cm_param_len = sizeof (size_t);
3209628b0c67SMark Fenwick newbie->ipsa_mac_len = (size_t)alg->alg_datalen;
3210628b0c67SMark Fenwick } else {
3211628b0c67SMark Fenwick newbie->ipsa_amech.cm_type = CRYPTO_MECHANISM_INVALID;
3212628b0c67SMark Fenwick }
32137c478bd9Sstevel@tonic-gate error = ipsec_create_ctx_tmpl(newbie, IPSEC_ALG_AUTH);
3214f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock);
32157c478bd9Sstevel@tonic-gate if (error != 0) {
32167c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsa_lock);
3217a1ba8781SMark Fenwick /*
3218a1ba8781SMark Fenwick * An error here indicates that alg is the wrong type
3219a1ba8781SMark Fenwick * (IE: not authentication) or its not in the alg tables
3220a1ba8781SMark Fenwick * created by ipsecalgs(1m), or Kcf does not like the
3221a1ba8781SMark Fenwick * parameters passed in with this algorithm, which is
3222a1ba8781SMark Fenwick * probably a coding error!
3223a1ba8781SMark Fenwick */
3224a1ba8781SMark Fenwick *diagnostic = SADB_X_DIAGNOSTIC_BAD_CTX;
3225628b0c67SMark Fenwick
32267c478bd9Sstevel@tonic-gate goto error;
32277c478bd9Sstevel@tonic-gate }
32287c478bd9Sstevel@tonic-gate }
32297c478bd9Sstevel@tonic-gate
32307c478bd9Sstevel@tonic-gate if (ekey != NULL) {
3231628b0c67SMark Fenwick mutex_enter(&ipss->ipsec_alg_lock);
3232bd670b35SErik Nordmark async = async || (ipss->ipsec_algs_exec_mode[IPSEC_ALG_ENCR] ==
3233bd670b35SErik Nordmark IPSEC_ALGS_EXEC_ASYNC);
3234628b0c67SMark Fenwick alg = ipss->ipsec_alglists[IPSEC_ALG_ENCR]
3235628b0c67SMark Fenwick [newbie->ipsa_encr_alg];
3236628b0c67SMark Fenwick
3237628b0c67SMark Fenwick if (alg != NULL && ALG_VALID(alg)) {
3238628b0c67SMark Fenwick newbie->ipsa_emech.cm_type = alg->alg_mech_type;
3239628b0c67SMark Fenwick newbie->ipsa_datalen = alg->alg_datalen;
3240628b0c67SMark Fenwick if (alg->alg_flags & ALG_FLAG_COUNTERMODE)
3241628b0c67SMark Fenwick newbie->ipsa_flags |= IPSA_F_COUNTERMODE;
3242628b0c67SMark Fenwick
3243628b0c67SMark Fenwick if (alg->alg_flags & ALG_FLAG_COMBINED) {
3244628b0c67SMark Fenwick newbie->ipsa_flags |= IPSA_F_COMBINED;
3245628b0c67SMark Fenwick newbie->ipsa_mac_len = alg->alg_icvlen;
3246628b0c67SMark Fenwick }
3247628b0c67SMark Fenwick
3248628b0c67SMark Fenwick if (alg->alg_flags & ALG_FLAG_CCM)
3249628b0c67SMark Fenwick newbie->ipsa_noncefunc = ccm_params_init;
3250628b0c67SMark Fenwick else if (alg->alg_flags & ALG_FLAG_GCM)
3251628b0c67SMark Fenwick newbie->ipsa_noncefunc = gcm_params_init;
3252628b0c67SMark Fenwick else newbie->ipsa_noncefunc = cbc_params_init;
3253628b0c67SMark Fenwick
3254628b0c67SMark Fenwick newbie->ipsa_saltlen = alg->alg_saltlen;
3255628b0c67SMark Fenwick newbie->ipsa_saltbits = SADB_8TO1(newbie->ipsa_saltlen);
3256628b0c67SMark Fenwick newbie->ipsa_iv_len = alg->alg_ivlen;
3257628b0c67SMark Fenwick newbie->ipsa_nonce_len = newbie->ipsa_saltlen +
3258628b0c67SMark Fenwick newbie->ipsa_iv_len;
3259628b0c67SMark Fenwick newbie->ipsa_emech.cm_param = NULL;
3260628b0c67SMark Fenwick newbie->ipsa_emech.cm_param_len = 0;
3261628b0c67SMark Fenwick } else {
3262628b0c67SMark Fenwick newbie->ipsa_emech.cm_type = CRYPTO_MECHANISM_INVALID;
3263628b0c67SMark Fenwick }
3264628b0c67SMark Fenwick mutex_exit(&ipss->ipsec_alg_lock);
3265628b0c67SMark Fenwick
3266628b0c67SMark Fenwick /*
3267628b0c67SMark Fenwick * The byte stream following the sadb_key_t is made up of:
3268628b0c67SMark Fenwick * key bytes, [salt bytes], [IV initial value]
3269628b0c67SMark Fenwick * All of these have variable length. The IV is typically
3270628b0c67SMark Fenwick * randomly generated by this function and not passed in.
3271628b0c67SMark Fenwick * By supporting the injection of a known IV, the whole
3272628b0c67SMark Fenwick * IPsec subsystem and the underlying crypto subsystem
3273628b0c67SMark Fenwick * can be tested with known test vectors.
3274628b0c67SMark Fenwick *
3275628b0c67SMark Fenwick * The keying material has been checked by ext_check()
3276628b0c67SMark Fenwick * and ipsec_valid_key_size(), after removing salt/IV
3277628b0c67SMark Fenwick * bits, whats left is the encryption key. If this is too
3278628b0c67SMark Fenwick * short, ipsec_create_ctx_tmpl() will fail and the SA
3279628b0c67SMark Fenwick * won't get created.
3280628b0c67SMark Fenwick *
3281628b0c67SMark Fenwick * set ipsa_encrkeylen to length of key only.
3282628b0c67SMark Fenwick */
32837c478bd9Sstevel@tonic-gate newbie->ipsa_encrkeybits = ekey->sadb_key_bits;
3284628b0c67SMark Fenwick newbie->ipsa_encrkeybits -= ekey->sadb_key_reserved;
3285628b0c67SMark Fenwick newbie->ipsa_encrkeybits -= newbie->ipsa_saltbits;
3286628b0c67SMark Fenwick newbie->ipsa_encrkeylen = SADB_1TO8(newbie->ipsa_encrkeybits);
3287628b0c67SMark Fenwick
32887c478bd9Sstevel@tonic-gate /* In case we have to round up to the next byte... */
32897c478bd9Sstevel@tonic-gate if ((ekey->sadb_key_bits & 0x7) != 0)
32907c478bd9Sstevel@tonic-gate newbie->ipsa_encrkeylen++;
3291628b0c67SMark Fenwick
32927c478bd9Sstevel@tonic-gate newbie->ipsa_encrkey = kmem_alloc(newbie->ipsa_encrkeylen,
32937c478bd9Sstevel@tonic-gate KM_NOSLEEP);
32947c478bd9Sstevel@tonic-gate if (newbie->ipsa_encrkey == NULL) {
32957c478bd9Sstevel@tonic-gate error = ENOMEM;
32967c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsa_lock);
32977c478bd9Sstevel@tonic-gate goto error;
32987c478bd9Sstevel@tonic-gate }
3299628b0c67SMark Fenwick
3300628b0c67SMark Fenwick buf_ptr = (uint8_t *)(ekey + 1);
3301628b0c67SMark Fenwick bcopy(buf_ptr, newbie->ipsa_encrkey, newbie->ipsa_encrkeylen);
3302628b0c67SMark Fenwick
3303628b0c67SMark Fenwick if (newbie->ipsa_flags & IPSA_F_COMBINED) {
3304628b0c67SMark Fenwick /*
3305628b0c67SMark Fenwick * Combined mode algs need a nonce. Copy the salt and
3306628b0c67SMark Fenwick * IV into a buffer. The ipsa_nonce is a pointer into
3307628b0c67SMark Fenwick * this buffer, some bytes at the start of the buffer
3308628b0c67SMark Fenwick * may be unused, depends on the salt length. The IV
3309628b0c67SMark Fenwick * is 64 bit aligned so it can be incremented as a
3310628b0c67SMark Fenwick * uint64_t. Zero out key in samsg_t before freeing.
3311628b0c67SMark Fenwick */
3312628b0c67SMark Fenwick
3313628b0c67SMark Fenwick newbie->ipsa_nonce_buf = kmem_alloc(
3314628b0c67SMark Fenwick sizeof (ipsec_nonce_t), KM_NOSLEEP);
3315628b0c67SMark Fenwick if (newbie->ipsa_nonce_buf == NULL) {
3316628b0c67SMark Fenwick error = ENOMEM;
3317628b0c67SMark Fenwick mutex_exit(&newbie->ipsa_lock);
3318628b0c67SMark Fenwick goto error;
3319628b0c67SMark Fenwick }
3320628b0c67SMark Fenwick /*
3321628b0c67SMark Fenwick * Initialize nonce and salt pointers to point
3322628b0c67SMark Fenwick * to the nonce buffer. This is just in case we get
3323628b0c67SMark Fenwick * bad data, the pointers will be valid, the data
3324628b0c67SMark Fenwick * won't be.
3325628b0c67SMark Fenwick *
3326628b0c67SMark Fenwick * See sadb.h for layout of nonce.
3327628b0c67SMark Fenwick */
3328628b0c67SMark Fenwick newbie->ipsa_iv = &newbie->ipsa_nonce_buf->iv;
3329628b0c67SMark Fenwick newbie->ipsa_salt = (uint8_t *)newbie->ipsa_nonce_buf;
3330628b0c67SMark Fenwick newbie->ipsa_nonce = newbie->ipsa_salt;
3331628b0c67SMark Fenwick if (newbie->ipsa_saltlen != 0) {
3332628b0c67SMark Fenwick salt_offset = MAXSALTSIZE -
3333628b0c67SMark Fenwick newbie->ipsa_saltlen;
3334628b0c67SMark Fenwick newbie->ipsa_salt = (uint8_t *)
3335628b0c67SMark Fenwick &newbie->ipsa_nonce_buf->salt[salt_offset];
3336628b0c67SMark Fenwick newbie->ipsa_nonce = newbie->ipsa_salt;
3337628b0c67SMark Fenwick buf_ptr += newbie->ipsa_encrkeylen;
3338628b0c67SMark Fenwick bcopy(buf_ptr, newbie->ipsa_salt,
3339628b0c67SMark Fenwick newbie->ipsa_saltlen);
3340628b0c67SMark Fenwick }
3341628b0c67SMark Fenwick /*
3342628b0c67SMark Fenwick * The IV for CCM/GCM mode increments, it should not
3343628b0c67SMark Fenwick * repeat. Get a random value for the IV, make a
3344628b0c67SMark Fenwick * copy, the SA will expire when/if the IV ever
3345628b0c67SMark Fenwick * wraps back to the initial value. If an Initial IV
3346628b0c67SMark Fenwick * is passed in via PF_KEY, save this in the SA.
3347628b0c67SMark Fenwick * Initialising IV for inbound is pointless as its
3348628b0c67SMark Fenwick * taken from the inbound packet.
3349628b0c67SMark Fenwick */
3350628b0c67SMark Fenwick if (!is_inbound) {
3351628b0c67SMark Fenwick if (ekey->sadb_key_reserved != 0) {
3352628b0c67SMark Fenwick buf_ptr += newbie->ipsa_saltlen;
3353628b0c67SMark Fenwick bcopy(buf_ptr, (uint8_t *)newbie->
3354628b0c67SMark Fenwick ipsa_iv, SADB_1TO8(ekey->
3355628b0c67SMark Fenwick sadb_key_reserved));
3356628b0c67SMark Fenwick } else {
3357628b0c67SMark Fenwick (void) random_get_pseudo_bytes(
3358628b0c67SMark Fenwick (uint8_t *)newbie->ipsa_iv,
3359628b0c67SMark Fenwick newbie->ipsa_iv_len);
3360628b0c67SMark Fenwick }
3361628b0c67SMark Fenwick newbie->ipsa_iv_softexpire =
3362628b0c67SMark Fenwick (*newbie->ipsa_iv) << 9;
3363628b0c67SMark Fenwick newbie->ipsa_iv_hardexpire = *newbie->ipsa_iv;
3364628b0c67SMark Fenwick }
3365628b0c67SMark Fenwick }
3366628b0c67SMark Fenwick bzero((ekey + 1), SADB_1TO8(ekey->sadb_key_bits));
33677c478bd9Sstevel@tonic-gate
33687c478bd9Sstevel@tonic-gate /*
33697c478bd9Sstevel@tonic-gate * Pre-initialize the kernel crypto framework key
33707c478bd9Sstevel@tonic-gate * structure.
33717c478bd9Sstevel@tonic-gate */
33727c478bd9Sstevel@tonic-gate newbie->ipsa_kcfencrkey.ck_format = CRYPTO_KEY_RAW;
33737c478bd9Sstevel@tonic-gate newbie->ipsa_kcfencrkey.ck_length = newbie->ipsa_encrkeybits;
33747c478bd9Sstevel@tonic-gate newbie->ipsa_kcfencrkey.ck_data = newbie->ipsa_encrkey;
33757c478bd9Sstevel@tonic-gate
3376f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_alg_lock);
33777c478bd9Sstevel@tonic-gate error = ipsec_create_ctx_tmpl(newbie, IPSEC_ALG_ENCR);
3378f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock);
33797c478bd9Sstevel@tonic-gate if (error != 0) {
33807c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsa_lock);
3381a1ba8781SMark Fenwick /* See above for error explanation. */
3382a1ba8781SMark Fenwick *diagnostic = SADB_X_DIAGNOSTIC_BAD_CTX;
33837c478bd9Sstevel@tonic-gate goto error;
33847c478bd9Sstevel@tonic-gate }
33857c478bd9Sstevel@tonic-gate }
33867c478bd9Sstevel@tonic-gate
3387bd670b35SErik Nordmark if (async)
3388bd670b35SErik Nordmark newbie->ipsa_flags |= IPSA_F_ASYNC;
3389bd670b35SErik Nordmark
33907c478bd9Sstevel@tonic-gate /*
33917c478bd9Sstevel@tonic-gate * Ptrs to processing functions.
33927c478bd9Sstevel@tonic-gate */
33937c478bd9Sstevel@tonic-gate if (newbie->ipsa_type == SADB_SATYPE_ESP)
33947c478bd9Sstevel@tonic-gate ipsecesp_init_funcs(newbie);
33957c478bd9Sstevel@tonic-gate else
33967c478bd9Sstevel@tonic-gate ipsecah_init_funcs(newbie);
33977c478bd9Sstevel@tonic-gate ASSERT(newbie->ipsa_output_func != NULL &&
33987c478bd9Sstevel@tonic-gate newbie->ipsa_input_func != NULL);
33997c478bd9Sstevel@tonic-gate
34007c478bd9Sstevel@tonic-gate /*
34017c478bd9Sstevel@tonic-gate * Certificate ID stuff.
34027c478bd9Sstevel@tonic-gate */
34037c478bd9Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_IDENTITY_SRC] != NULL) {
34047c478bd9Sstevel@tonic-gate sadb_ident_t *id =
34057c478bd9Sstevel@tonic-gate (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_SRC];
34067c478bd9Sstevel@tonic-gate
34077c478bd9Sstevel@tonic-gate /*
34087c478bd9Sstevel@tonic-gate * Can assume strlen() will return okay because ext_check() in
34097c478bd9Sstevel@tonic-gate * keysock.c prepares the string for us.
34107c478bd9Sstevel@tonic-gate */
34117c478bd9Sstevel@tonic-gate newbie->ipsa_src_cid = ipsid_lookup(id->sadb_ident_type,
3412f4b3ec61Sdh155122 (char *)(id+1), ns);
34137c478bd9Sstevel@tonic-gate if (newbie->ipsa_src_cid == NULL) {
34147c478bd9Sstevel@tonic-gate error = ENOMEM;
34157c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsa_lock);
34167c478bd9Sstevel@tonic-gate goto error;
34177c478bd9Sstevel@tonic-gate }
34187c478bd9Sstevel@tonic-gate }
34197c478bd9Sstevel@tonic-gate
34207c478bd9Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_IDENTITY_DST] != NULL) {
34217c478bd9Sstevel@tonic-gate sadb_ident_t *id =
34227c478bd9Sstevel@tonic-gate (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_DST];
34237c478bd9Sstevel@tonic-gate
34247c478bd9Sstevel@tonic-gate /*
34257c478bd9Sstevel@tonic-gate * Can assume strlen() will return okay because ext_check() in
34267c478bd9Sstevel@tonic-gate * keysock.c prepares the string for us.
34277c478bd9Sstevel@tonic-gate */
34287c478bd9Sstevel@tonic-gate newbie->ipsa_dst_cid = ipsid_lookup(id->sadb_ident_type,
3429f4b3ec61Sdh155122 (char *)(id+1), ns);
34307c478bd9Sstevel@tonic-gate if (newbie->ipsa_dst_cid == NULL) {
34317c478bd9Sstevel@tonic-gate error = ENOMEM;
34327c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsa_lock);
34337c478bd9Sstevel@tonic-gate goto error;
34347c478bd9Sstevel@tonic-gate }
34357c478bd9Sstevel@tonic-gate }
34367c478bd9Sstevel@tonic-gate
34375d3b8cb7SBill Sommerfeld /*
34385d3b8cb7SBill Sommerfeld * sensitivity label handling code:
34395d3b8cb7SBill Sommerfeld * Convert sens + bitmap into cred_t, and associate it
34405d3b8cb7SBill Sommerfeld * with the new SA.
34415d3b8cb7SBill Sommerfeld */
34427c478bd9Sstevel@tonic-gate if (sens != NULL) {
34437c478bd9Sstevel@tonic-gate uint64_t *bitmap = (uint64_t *)(sens + 1);
34447c478bd9Sstevel@tonic-gate
3445bd670b35SErik Nordmark newbie->ipsa_tsl = sadb_label_from_sens(sens, bitmap);
34465d3b8cb7SBill Sommerfeld }
34475d3b8cb7SBill Sommerfeld
34485d3b8cb7SBill Sommerfeld /*
34495d3b8cb7SBill Sommerfeld * Likewise for outer sensitivity.
34505d3b8cb7SBill Sommerfeld */
34515d3b8cb7SBill Sommerfeld if (osens != NULL) {
34525d3b8cb7SBill Sommerfeld uint64_t *bitmap = (uint64_t *)(osens + 1);
3453bd670b35SErik Nordmark ts_label_t *tsl, *effective_tsl;
34545d3b8cb7SBill Sommerfeld uint32_t *peer_addr_ptr;
3455bd670b35SErik Nordmark zoneid_t zoneid = GLOBAL_ZONEID;
3456bd670b35SErik Nordmark zone_t *zone;
34575d3b8cb7SBill Sommerfeld
34585d3b8cb7SBill Sommerfeld peer_addr_ptr = is_inbound ? src_addr_ptr : dst_addr_ptr;
34595d3b8cb7SBill Sommerfeld
3460bd670b35SErik Nordmark tsl = sadb_label_from_sens(osens, bitmap);
34615d3b8cb7SBill Sommerfeld newbie->ipsa_mac_exempt = CONN_MAC_DEFAULT;
34625d3b8cb7SBill Sommerfeld
34635d3b8cb7SBill Sommerfeld if (osens->sadb_x_sens_flags & SADB_X_SENS_IMPLICIT) {
34645d3b8cb7SBill Sommerfeld newbie->ipsa_mac_exempt = CONN_MAC_IMPLICIT;
34655d3b8cb7SBill Sommerfeld }
34665d3b8cb7SBill Sommerfeld
3467bd670b35SErik Nordmark error = tsol_check_dest(tsl, peer_addr_ptr,
34685d3b8cb7SBill Sommerfeld (af == AF_INET6)?IPV6_VERSION:IPV4_VERSION,
3469bd670b35SErik Nordmark newbie->ipsa_mac_exempt, B_TRUE, &effective_tsl);
34705d3b8cb7SBill Sommerfeld if (error != 0) {
3471bd670b35SErik Nordmark label_rele(tsl);
34727c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsa_lock);
34737c478bd9Sstevel@tonic-gate goto error;
34747c478bd9Sstevel@tonic-gate }
34755d3b8cb7SBill Sommerfeld
3476bd670b35SErik Nordmark if (effective_tsl != NULL) {
3477bd670b35SErik Nordmark label_rele(tsl);
3478bd670b35SErik Nordmark tsl = effective_tsl;
34797c478bd9Sstevel@tonic-gate }
34805d3b8cb7SBill Sommerfeld
3481bd670b35SErik Nordmark newbie->ipsa_otsl = tsl;
3482bd670b35SErik Nordmark
3483bd670b35SErik Nordmark zone = zone_find_by_label(tsl);
3484bd670b35SErik Nordmark if (zone != NULL) {
3485bd670b35SErik Nordmark zoneid = zone->zone_id;
3486bd670b35SErik Nordmark zone_rele(zone);
3487bd670b35SErik Nordmark }
3488bd670b35SErik Nordmark /*
3489bd670b35SErik Nordmark * For exclusive stacks we set the zoneid to zero to operate
3490bd670b35SErik Nordmark * as if in the global zone for tsol_compute_label_v4/v6
3491bd670b35SErik Nordmark */
3492bd670b35SErik Nordmark if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
3493bd670b35SErik Nordmark zoneid = GLOBAL_ZONEID;
34945d3b8cb7SBill Sommerfeld
34955d3b8cb7SBill Sommerfeld if (af == AF_INET6) {
3496bd670b35SErik Nordmark error = tsol_compute_label_v6(tsl, zoneid,
3497eb035775SBill Sommerfeld (in6_addr_t *)peer_addr_ptr,
34985d3b8cb7SBill Sommerfeld newbie->ipsa_opt_storage, ipst);
34995d3b8cb7SBill Sommerfeld } else {
3500bd670b35SErik Nordmark error = tsol_compute_label_v4(tsl, zoneid,
3501bd670b35SErik Nordmark *peer_addr_ptr, newbie->ipsa_opt_storage, ipst);
35027c478bd9Sstevel@tonic-gate }
3503eb035775SBill Sommerfeld if (error != 0) {
3504eb035775SBill Sommerfeld mutex_exit(&newbie->ipsa_lock);
3505eb035775SBill Sommerfeld goto error;
3506eb035775SBill Sommerfeld }
35077c478bd9Sstevel@tonic-gate }
35087c478bd9Sstevel@tonic-gate
35097c478bd9Sstevel@tonic-gate
35109c2c14abSThejaswini Singarajipura if (replayext != NULL) {
35119c2c14abSThejaswini Singarajipura if ((replayext->sadb_x_rc_replay32 == 0) &&
35129c2c14abSThejaswini Singarajipura (replayext->sadb_x_rc_replay64 != 0)) {
35139c2c14abSThejaswini Singarajipura error = EOPNOTSUPP;
3514a1ba8781SMark Fenwick *diagnostic = SADB_X_DIAGNOSTIC_INVALID_REPLAY;
35159c2c14abSThejaswini Singarajipura mutex_exit(&newbie->ipsa_lock);
35169c2c14abSThejaswini Singarajipura goto error;
35179c2c14abSThejaswini Singarajipura }
35189c2c14abSThejaswini Singarajipura newbie->ipsa_replay = replayext->sadb_x_rc_replay32;
35199c2c14abSThejaswini Singarajipura }
35209c2c14abSThejaswini Singarajipura
35217c478bd9Sstevel@tonic-gate /* now that the SA has been updated, set its new state */
35227c478bd9Sstevel@tonic-gate newbie->ipsa_state = assoc->sadb_sa_state;
35237c478bd9Sstevel@tonic-gate
352438d95a78Smarkfen if (clone) {
352538d95a78Smarkfen newbie->ipsa_haspeer = B_TRUE;
352638d95a78Smarkfen } else {
352738d95a78Smarkfen if (!is_inbound) {
352838d95a78Smarkfen lifetime_fuzz(newbie);
352938d95a78Smarkfen }
353038d95a78Smarkfen }
35317c478bd9Sstevel@tonic-gate /*
35327c478bd9Sstevel@tonic-gate * The less locks I hold when doing an insertion and possible cloning,
35337c478bd9Sstevel@tonic-gate * the better!
35347c478bd9Sstevel@tonic-gate */
35357c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsa_lock);
35367c478bd9Sstevel@tonic-gate
35377c478bd9Sstevel@tonic-gate if (clone) {
35387c478bd9Sstevel@tonic-gate newbie_clone = sadb_cloneassoc(newbie);
35397c478bd9Sstevel@tonic-gate
35407c478bd9Sstevel@tonic-gate if (newbie_clone == NULL) {
35417c478bd9Sstevel@tonic-gate error = ENOMEM;
35427c478bd9Sstevel@tonic-gate goto error;
35437c478bd9Sstevel@tonic-gate }
35447c478bd9Sstevel@tonic-gate }
35457c478bd9Sstevel@tonic-gate
35467c478bd9Sstevel@tonic-gate /*
35477c478bd9Sstevel@tonic-gate * Enter the bucket locks. The order of entry is outbound,
35487c478bd9Sstevel@tonic-gate * inbound. We map "primary" and "secondary" into outbound and inbound
35497c478bd9Sstevel@tonic-gate * based on the destination address type. If the destination address
35507c478bd9Sstevel@tonic-gate * type is for a node that isn't mine (or potentially mine), the
35517c478bd9Sstevel@tonic-gate * "primary" bucket is the outbound one.
35527c478bd9Sstevel@tonic-gate */
355338d95a78Smarkfen if (!is_inbound) {
35547c478bd9Sstevel@tonic-gate /* primary == outbound */
35557c478bd9Sstevel@tonic-gate mutex_enter(&primary->isaf_lock);
35567c478bd9Sstevel@tonic-gate mutex_enter(&secondary->isaf_lock);
35577c478bd9Sstevel@tonic-gate } else {
35587c478bd9Sstevel@tonic-gate /* primary == inbound */
35597c478bd9Sstevel@tonic-gate mutex_enter(&secondary->isaf_lock);
35607c478bd9Sstevel@tonic-gate mutex_enter(&primary->isaf_lock);
35617c478bd9Sstevel@tonic-gate }
35627c478bd9Sstevel@tonic-gate
35637c478bd9Sstevel@tonic-gate /*
35647c478bd9Sstevel@tonic-gate * sadb_insertassoc() doesn't increment the reference
35657c478bd9Sstevel@tonic-gate * count. We therefore have to increment the
35667c478bd9Sstevel@tonic-gate * reference count one more time to reflect the
35677c478bd9Sstevel@tonic-gate * pointers of the table that reference this SA.
35687c478bd9Sstevel@tonic-gate */
35697c478bd9Sstevel@tonic-gate IPSA_REFHOLD(newbie);
35707c478bd9Sstevel@tonic-gate
35717c478bd9Sstevel@tonic-gate if (isupdate) {
35727c478bd9Sstevel@tonic-gate /*
35737c478bd9Sstevel@tonic-gate * Unlink from larval holding cell in the "inbound" fanout.
35747c478bd9Sstevel@tonic-gate */
35757c478bd9Sstevel@tonic-gate ASSERT(newbie->ipsa_linklock == &primary->isaf_lock ||
35767c478bd9Sstevel@tonic-gate newbie->ipsa_linklock == &secondary->isaf_lock);
35777c478bd9Sstevel@tonic-gate sadb_unlinkassoc(newbie);
35787c478bd9Sstevel@tonic-gate }
35797c478bd9Sstevel@tonic-gate
35807c478bd9Sstevel@tonic-gate mutex_enter(&newbie->ipsa_lock);
35817c478bd9Sstevel@tonic-gate error = sadb_insertassoc(newbie, primary);
35827c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsa_lock);
35837c478bd9Sstevel@tonic-gate
35847c478bd9Sstevel@tonic-gate if (error != 0) {
35857c478bd9Sstevel@tonic-gate /*
35867c478bd9Sstevel@tonic-gate * Since sadb_insertassoc() failed, we must decrement the
35877c478bd9Sstevel@tonic-gate * refcount again so the cleanup code will actually free
35887c478bd9Sstevel@tonic-gate * the offending SA.
35897c478bd9Sstevel@tonic-gate */
35907c478bd9Sstevel@tonic-gate IPSA_REFRELE(newbie);
35917c478bd9Sstevel@tonic-gate goto error_unlock;
35927c478bd9Sstevel@tonic-gate }
35937c478bd9Sstevel@tonic-gate
35947c478bd9Sstevel@tonic-gate if (newbie_clone != NULL) {
35957c478bd9Sstevel@tonic-gate mutex_enter(&newbie_clone->ipsa_lock);
35967c478bd9Sstevel@tonic-gate error = sadb_insertassoc(newbie_clone, secondary);
35977c478bd9Sstevel@tonic-gate mutex_exit(&newbie_clone->ipsa_lock);
35987c478bd9Sstevel@tonic-gate if (error != 0) {
35997c478bd9Sstevel@tonic-gate /* Collision in secondary table. */
36007c478bd9Sstevel@tonic-gate sadb_unlinkassoc(newbie); /* This does REFRELE. */
36017c478bd9Sstevel@tonic-gate goto error_unlock;
36027c478bd9Sstevel@tonic-gate }
36037c478bd9Sstevel@tonic-gate IPSA_REFHOLD(newbie_clone);
36047c478bd9Sstevel@tonic-gate } else {
36057c478bd9Sstevel@tonic-gate ASSERT(primary != secondary);
36067c478bd9Sstevel@tonic-gate scratch = ipsec_getassocbyspi(secondary, newbie->ipsa_spi,
36077c478bd9Sstevel@tonic-gate ALL_ZEROES_PTR, newbie->ipsa_dstaddr, af);
36087c478bd9Sstevel@tonic-gate if (scratch != NULL) {
36097c478bd9Sstevel@tonic-gate /* Collision in secondary table. */
36107c478bd9Sstevel@tonic-gate sadb_unlinkassoc(newbie); /* This does REFRELE. */
36117c478bd9Sstevel@tonic-gate /* Set the error, since ipsec_getassocbyspi() can't. */
36127c478bd9Sstevel@tonic-gate error = EEXIST;
36137c478bd9Sstevel@tonic-gate goto error_unlock;
36147c478bd9Sstevel@tonic-gate }
36157c478bd9Sstevel@tonic-gate }
36167c478bd9Sstevel@tonic-gate
36177c478bd9Sstevel@tonic-gate /* OKAY! So let's do some reality check assertions. */
36187c478bd9Sstevel@tonic-gate
36190c0328cdSBill Sommerfeld ASSERT(MUTEX_NOT_HELD(&newbie->ipsa_lock));
36200c0328cdSBill Sommerfeld ASSERT(newbie_clone == NULL ||
36210c0328cdSBill Sommerfeld (MUTEX_NOT_HELD(&newbie_clone->ipsa_lock)));
36227c478bd9Sstevel@tonic-gate
36237c478bd9Sstevel@tonic-gate error_unlock:
36247c478bd9Sstevel@tonic-gate
36257c478bd9Sstevel@tonic-gate /*
36267c478bd9Sstevel@tonic-gate * We can exit the locks in any order. Only entrance needs to
36277c478bd9Sstevel@tonic-gate * follow any protocol.
36287c478bd9Sstevel@tonic-gate */
36297c478bd9Sstevel@tonic-gate mutex_exit(&secondary->isaf_lock);
36307c478bd9Sstevel@tonic-gate mutex_exit(&primary->isaf_lock);
36317c478bd9Sstevel@tonic-gate
363238d95a78Smarkfen if (pair_ext != NULL && error == 0) {
363338d95a78Smarkfen /* update pair_spi if it exists. */
36345d3b8cb7SBill Sommerfeld ipsa_query_t sq;
36355d3b8cb7SBill Sommerfeld
36365d3b8cb7SBill Sommerfeld sq.spp = spp; /* XXX param */
36375d3b8cb7SBill Sommerfeld error = sadb_form_query(ksi, IPSA_Q_DST, IPSA_Q_SRC|IPSA_Q_DST|
36385d3b8cb7SBill Sommerfeld IPSA_Q_SA|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND, &sq, diagnostic);
36395d3b8cb7SBill Sommerfeld if (error)
36405d3b8cb7SBill Sommerfeld return (error);
36415d3b8cb7SBill Sommerfeld
36425d3b8cb7SBill Sommerfeld error = get_ipsa_pair(&sq, &ipsapp, diagnostic);
36435d3b8cb7SBill Sommerfeld
36445d3b8cb7SBill Sommerfeld if (error != 0)
36455d3b8cb7SBill Sommerfeld goto error;
36465d3b8cb7SBill Sommerfeld
36475d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_psa_ptr != NULL) {
364838d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_PAIR_ALREADY;
364938d95a78Smarkfen error = EINVAL;
365038d95a78Smarkfen } else {
365138d95a78Smarkfen /* update_pairing() sets diagnostic */
36525d3b8cb7SBill Sommerfeld error = update_pairing(&ipsapp, &sq, ksi, diagnostic);
365338d95a78Smarkfen }
365438d95a78Smarkfen }
36557c478bd9Sstevel@tonic-gate /* Common error point for this routine. */
36567c478bd9Sstevel@tonic-gate error:
36577c478bd9Sstevel@tonic-gate if (newbie != NULL) {
365838d95a78Smarkfen if (error != 0) {
365938d95a78Smarkfen /* This SA is broken, let the reaper clean up. */
366038d95a78Smarkfen mutex_enter(&newbie->ipsa_lock);
366138d95a78Smarkfen newbie->ipsa_state = IPSA_STATE_DEAD;
366238d95a78Smarkfen newbie->ipsa_hardexpiretime = 1;
366338d95a78Smarkfen mutex_exit(&newbie->ipsa_lock);
366438d95a78Smarkfen }
36657c478bd9Sstevel@tonic-gate IPSA_REFRELE(newbie);
36667c478bd9Sstevel@tonic-gate }
36677c478bd9Sstevel@tonic-gate if (newbie_clone != NULL) {
36687c478bd9Sstevel@tonic-gate IPSA_REFRELE(newbie_clone);
36697c478bd9Sstevel@tonic-gate }
36707c478bd9Sstevel@tonic-gate
36717c478bd9Sstevel@tonic-gate if (error == 0) {
36727c478bd9Sstevel@tonic-gate /*
36737c478bd9Sstevel@tonic-gate * Construct favorable PF_KEY return message and send to
367438d95a78Smarkfen * keysock. Update the flags in the original keysock message
367538d95a78Smarkfen * to reflect the actual flags in the new SA.
367638d95a78Smarkfen * (Q: Do I need to pass "newbie"? If I do,
36777c478bd9Sstevel@tonic-gate * make sure to REFHOLD, call, then REFRELE.)
36787c478bd9Sstevel@tonic-gate */
367938d95a78Smarkfen assoc->sadb_sa_flags = newbie->ipsa_flags;
36807c478bd9Sstevel@tonic-gate sadb_pfkey_echo(pfkey_q, mp, samsg, ksi, NULL);
36817c478bd9Sstevel@tonic-gate }
36827c478bd9Sstevel@tonic-gate
36835d3b8cb7SBill Sommerfeld destroy_ipsa_pair(&ipsapp);
36847c478bd9Sstevel@tonic-gate return (error);
36857c478bd9Sstevel@tonic-gate }
36867c478bd9Sstevel@tonic-gate
36877c478bd9Sstevel@tonic-gate /*
36887c478bd9Sstevel@tonic-gate * Set the time of first use for a security association. Update any
36897c478bd9Sstevel@tonic-gate * expiration times as a result.
36907c478bd9Sstevel@tonic-gate */
36917c478bd9Sstevel@tonic-gate void
36927c478bd9Sstevel@tonic-gate sadb_set_usetime(ipsa_t *assoc)
36937c478bd9Sstevel@tonic-gate {
3694437220cdSdanmcd time_t snapshot = gethrestime_sec();
3695437220cdSdanmcd
36967c478bd9Sstevel@tonic-gate mutex_enter(&assoc->ipsa_lock);
3697437220cdSdanmcd assoc->ipsa_lastuse = snapshot;
36989c2c14abSThejaswini Singarajipura assoc->ipsa_idleexpiretime = snapshot + assoc->ipsa_idletime;
36999c2c14abSThejaswini Singarajipura
37007c478bd9Sstevel@tonic-gate /*
37017c478bd9Sstevel@tonic-gate * Caller does check usetime before calling me usually, and
37027c478bd9Sstevel@tonic-gate * double-checking is better than a mutex_enter/exit hit.
37037c478bd9Sstevel@tonic-gate */
37047c478bd9Sstevel@tonic-gate if (assoc->ipsa_usetime == 0) {
37057c478bd9Sstevel@tonic-gate /*
37067c478bd9Sstevel@tonic-gate * This is redundant for outbound SA's, as
37077c478bd9Sstevel@tonic-gate * ipsec_getassocbyconn() sets the IPSA_F_USED flag already.
37087c478bd9Sstevel@tonic-gate * Inbound SAs, however, have no such protection.
37097c478bd9Sstevel@tonic-gate */
37107c478bd9Sstevel@tonic-gate assoc->ipsa_flags |= IPSA_F_USED;
3711437220cdSdanmcd assoc->ipsa_usetime = snapshot;
37127c478bd9Sstevel@tonic-gate
37137c478bd9Sstevel@tonic-gate /*
37147c478bd9Sstevel@tonic-gate * After setting the use time, see if we have a use lifetime
37157c478bd9Sstevel@tonic-gate * that would cause the actual SA expiration time to shorten.
37167c478bd9Sstevel@tonic-gate */
37177c478bd9Sstevel@tonic-gate UPDATE_EXPIRE(assoc, softuselt, softexpiretime);
37187c478bd9Sstevel@tonic-gate UPDATE_EXPIRE(assoc, harduselt, hardexpiretime);
37197c478bd9Sstevel@tonic-gate }
37207c478bd9Sstevel@tonic-gate mutex_exit(&assoc->ipsa_lock);
37217c478bd9Sstevel@tonic-gate }
37227c478bd9Sstevel@tonic-gate
37237c478bd9Sstevel@tonic-gate /*
37247c478bd9Sstevel@tonic-gate * Send up a PF_KEY expire message for this association.
37257c478bd9Sstevel@tonic-gate */
37267c478bd9Sstevel@tonic-gate static void
37277c478bd9Sstevel@tonic-gate sadb_expire_assoc(queue_t *pfkey_q, ipsa_t *assoc)
37287c478bd9Sstevel@tonic-gate {
37297c478bd9Sstevel@tonic-gate mblk_t *mp, *mp1;
37307c478bd9Sstevel@tonic-gate int alloclen, af;
37317c478bd9Sstevel@tonic-gate sadb_msg_t *samsg;
37327c478bd9Sstevel@tonic-gate sadb_lifetime_t *current, *expire;
37337c478bd9Sstevel@tonic-gate sadb_sa_t *saext;
37347c478bd9Sstevel@tonic-gate uint8_t *end;
37358810c16bSdanmcd boolean_t tunnel_mode;
37367c478bd9Sstevel@tonic-gate
37377c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&assoc->ipsa_lock));
37387c478bd9Sstevel@tonic-gate
37397c478bd9Sstevel@tonic-gate /* Don't bother sending if there's no queue. */
37407c478bd9Sstevel@tonic-gate if (pfkey_q == NULL)
37417c478bd9Sstevel@tonic-gate return;
37427c478bd9Sstevel@tonic-gate
37437c478bd9Sstevel@tonic-gate mp = sadb_keysock_out(0);
37447c478bd9Sstevel@tonic-gate if (mp == NULL) {
37457c478bd9Sstevel@tonic-gate /* cmn_err(CE_WARN, */
37467c478bd9Sstevel@tonic-gate /* "sadb_expire_assoc: Can't allocate KEYSOCK_OUT.\n"); */
37477c478bd9Sstevel@tonic-gate return;
37487c478bd9Sstevel@tonic-gate }
37497c478bd9Sstevel@tonic-gate
37507c478bd9Sstevel@tonic-gate alloclen = sizeof (*samsg) + sizeof (*current) + sizeof (*expire) +
37517c478bd9Sstevel@tonic-gate 2 * sizeof (sadb_address_t) + sizeof (*saext);
37527c478bd9Sstevel@tonic-gate
37537c478bd9Sstevel@tonic-gate af = assoc->ipsa_addrfam;
37547c478bd9Sstevel@tonic-gate switch (af) {
37557c478bd9Sstevel@tonic-gate case AF_INET:
37567c478bd9Sstevel@tonic-gate alloclen += 2 * sizeof (struct sockaddr_in);
37577c478bd9Sstevel@tonic-gate break;
37587c478bd9Sstevel@tonic-gate case AF_INET6:
37597c478bd9Sstevel@tonic-gate alloclen += 2 * sizeof (struct sockaddr_in6);
37607c478bd9Sstevel@tonic-gate break;
37617c478bd9Sstevel@tonic-gate default:
37627c478bd9Sstevel@tonic-gate /* Won't happen unless there's a kernel bug. */
37637c478bd9Sstevel@tonic-gate freeb(mp);
37647c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
37657c478bd9Sstevel@tonic-gate "sadb_expire_assoc: Unknown address length.\n");
37667c478bd9Sstevel@tonic-gate return;
37677c478bd9Sstevel@tonic-gate }
37687c478bd9Sstevel@tonic-gate
37698810c16bSdanmcd tunnel_mode = (assoc->ipsa_flags & IPSA_F_TUNNEL);
37708810c16bSdanmcd if (tunnel_mode) {
37718810c16bSdanmcd alloclen += 2 * sizeof (sadb_address_t);
37728810c16bSdanmcd switch (assoc->ipsa_innerfam) {
37738810c16bSdanmcd case AF_INET:
37748810c16bSdanmcd alloclen += 2 * sizeof (struct sockaddr_in);
37758810c16bSdanmcd break;
37768810c16bSdanmcd case AF_INET6:
37778810c16bSdanmcd alloclen += 2 * sizeof (struct sockaddr_in6);
37788810c16bSdanmcd break;
37798810c16bSdanmcd default:
37808810c16bSdanmcd /* Won't happen unless there's a kernel bug. */
37818810c16bSdanmcd freeb(mp);
37828810c16bSdanmcd cmn_err(CE_WARN, "sadb_expire_assoc: "
37838810c16bSdanmcd "Unknown inner address length.\n");
37848810c16bSdanmcd return;
37858810c16bSdanmcd }
37868810c16bSdanmcd }
37878810c16bSdanmcd
37887c478bd9Sstevel@tonic-gate mp->b_cont = allocb(alloclen, BPRI_HI);
37897c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) {
37907c478bd9Sstevel@tonic-gate freeb(mp);
37917c478bd9Sstevel@tonic-gate /* cmn_err(CE_WARN, */
37927c478bd9Sstevel@tonic-gate /* "sadb_expire_assoc: Can't allocate message.\n"); */
37937c478bd9Sstevel@tonic-gate return;
37947c478bd9Sstevel@tonic-gate }
37957c478bd9Sstevel@tonic-gate
37967c478bd9Sstevel@tonic-gate mp1 = mp;
37977c478bd9Sstevel@tonic-gate mp = mp->b_cont;
37987c478bd9Sstevel@tonic-gate end = mp->b_wptr + alloclen;
37997c478bd9Sstevel@tonic-gate
38007c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_wptr;
38017c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (*samsg);
38027c478bd9Sstevel@tonic-gate samsg->sadb_msg_version = PF_KEY_V2;
38037c478bd9Sstevel@tonic-gate samsg->sadb_msg_type = SADB_EXPIRE;
38047c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = 0;
38057c478bd9Sstevel@tonic-gate samsg->sadb_msg_satype = assoc->ipsa_type;
38067c478bd9Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(alloclen);
38077c478bd9Sstevel@tonic-gate samsg->sadb_msg_reserved = 0;
38087c478bd9Sstevel@tonic-gate samsg->sadb_msg_seq = 0;
38097c478bd9Sstevel@tonic-gate samsg->sadb_msg_pid = 0;
38107c478bd9Sstevel@tonic-gate
38117c478bd9Sstevel@tonic-gate saext = (sadb_sa_t *)mp->b_wptr;
38127c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (*saext);
38137c478bd9Sstevel@tonic-gate saext->sadb_sa_len = SADB_8TO64(sizeof (*saext));
38147c478bd9Sstevel@tonic-gate saext->sadb_sa_exttype = SADB_EXT_SA;
38157c478bd9Sstevel@tonic-gate saext->sadb_sa_spi = assoc->ipsa_spi;
38167c478bd9Sstevel@tonic-gate saext->sadb_sa_replay = assoc->ipsa_replay_wsize;
38177c478bd9Sstevel@tonic-gate saext->sadb_sa_state = assoc->ipsa_state;
38187c478bd9Sstevel@tonic-gate saext->sadb_sa_auth = assoc->ipsa_auth_alg;
38197c478bd9Sstevel@tonic-gate saext->sadb_sa_encrypt = assoc->ipsa_encr_alg;
38207c478bd9Sstevel@tonic-gate saext->sadb_sa_flags = assoc->ipsa_flags;
38217c478bd9Sstevel@tonic-gate
38227c478bd9Sstevel@tonic-gate current = (sadb_lifetime_t *)mp->b_wptr;
38237c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (sadb_lifetime_t);
38247c478bd9Sstevel@tonic-gate current->sadb_lifetime_len = SADB_8TO64(sizeof (*current));
38257c478bd9Sstevel@tonic-gate current->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
3826437220cdSdanmcd /* We do not support the concept. */
3827437220cdSdanmcd current->sadb_lifetime_allocations = 0;
38287c478bd9Sstevel@tonic-gate current->sadb_lifetime_bytes = assoc->ipsa_bytes;
38297c478bd9Sstevel@tonic-gate current->sadb_lifetime_addtime = assoc->ipsa_addtime;
38307c478bd9Sstevel@tonic-gate current->sadb_lifetime_usetime = assoc->ipsa_usetime;
38317c478bd9Sstevel@tonic-gate
38327c478bd9Sstevel@tonic-gate expire = (sadb_lifetime_t *)mp->b_wptr;
38337c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (*expire);
38347c478bd9Sstevel@tonic-gate expire->sadb_lifetime_len = SADB_8TO64(sizeof (*expire));
38357c478bd9Sstevel@tonic-gate
38367c478bd9Sstevel@tonic-gate if (assoc->ipsa_state == IPSA_STATE_DEAD) {
38377c478bd9Sstevel@tonic-gate expire->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
38387c478bd9Sstevel@tonic-gate expire->sadb_lifetime_allocations = assoc->ipsa_hardalloc;
38397c478bd9Sstevel@tonic-gate expire->sadb_lifetime_bytes = assoc->ipsa_hardbyteslt;
38407c478bd9Sstevel@tonic-gate expire->sadb_lifetime_addtime = assoc->ipsa_hardaddlt;
38417c478bd9Sstevel@tonic-gate expire->sadb_lifetime_usetime = assoc->ipsa_harduselt;
38429c2c14abSThejaswini Singarajipura } else if (assoc->ipsa_state == IPSA_STATE_DYING) {
38437c478bd9Sstevel@tonic-gate expire->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
38447c478bd9Sstevel@tonic-gate expire->sadb_lifetime_allocations = assoc->ipsa_softalloc;
38457c478bd9Sstevel@tonic-gate expire->sadb_lifetime_bytes = assoc->ipsa_softbyteslt;
38467c478bd9Sstevel@tonic-gate expire->sadb_lifetime_addtime = assoc->ipsa_softaddlt;
38477c478bd9Sstevel@tonic-gate expire->sadb_lifetime_usetime = assoc->ipsa_softuselt;
38489c2c14abSThejaswini Singarajipura } else {
38499c2c14abSThejaswini Singarajipura ASSERT(assoc->ipsa_state == IPSA_STATE_MATURE);
38509c2c14abSThejaswini Singarajipura expire->sadb_lifetime_exttype = SADB_X_EXT_LIFETIME_IDLE;
38519c2c14abSThejaswini Singarajipura expire->sadb_lifetime_allocations = 0;
38529c2c14abSThejaswini Singarajipura expire->sadb_lifetime_bytes = 0;
38539c2c14abSThejaswini Singarajipura expire->sadb_lifetime_addtime = assoc->ipsa_idleaddlt;
38549c2c14abSThejaswini Singarajipura expire->sadb_lifetime_usetime = assoc->ipsa_idleuselt;
38557c478bd9Sstevel@tonic-gate }
38567c478bd9Sstevel@tonic-gate
38577c478bd9Sstevel@tonic-gate mp->b_wptr = sadb_make_addr_ext(mp->b_wptr, end, SADB_EXT_ADDRESS_SRC,
38588810c16bSdanmcd af, assoc->ipsa_srcaddr, tunnel_mode ? 0 : SA_SRCPORT(assoc),
38598810c16bSdanmcd SA_PROTO(assoc), 0);
38607c478bd9Sstevel@tonic-gate ASSERT(mp->b_wptr != NULL);
38617c478bd9Sstevel@tonic-gate
38627c478bd9Sstevel@tonic-gate mp->b_wptr = sadb_make_addr_ext(mp->b_wptr, end, SADB_EXT_ADDRESS_DST,
38638810c16bSdanmcd af, assoc->ipsa_dstaddr, tunnel_mode ? 0 : SA_DSTPORT(assoc),
38648810c16bSdanmcd SA_PROTO(assoc), 0);
38657c478bd9Sstevel@tonic-gate ASSERT(mp->b_wptr != NULL);
38667c478bd9Sstevel@tonic-gate
38678810c16bSdanmcd if (tunnel_mode) {
38688810c16bSdanmcd mp->b_wptr = sadb_make_addr_ext(mp->b_wptr, end,
38698810c16bSdanmcd SADB_X_EXT_ADDRESS_INNER_SRC, assoc->ipsa_innerfam,
38708810c16bSdanmcd assoc->ipsa_innersrc, SA_SRCPORT(assoc), SA_IPROTO(assoc),
38718810c16bSdanmcd assoc->ipsa_innersrcpfx);
38728810c16bSdanmcd ASSERT(mp->b_wptr != NULL);
38738810c16bSdanmcd mp->b_wptr = sadb_make_addr_ext(mp->b_wptr, end,
38748810c16bSdanmcd SADB_X_EXT_ADDRESS_INNER_DST, assoc->ipsa_innerfam,
38758810c16bSdanmcd assoc->ipsa_innerdst, SA_DSTPORT(assoc), SA_IPROTO(assoc),
38768810c16bSdanmcd assoc->ipsa_innerdstpfx);
38778810c16bSdanmcd ASSERT(mp->b_wptr != NULL);
38788810c16bSdanmcd }
38798810c16bSdanmcd
38807c478bd9Sstevel@tonic-gate /* Can just putnext, we're ready to go! */
38817c478bd9Sstevel@tonic-gate putnext(pfkey_q, mp1);
38827c478bd9Sstevel@tonic-gate }
38837c478bd9Sstevel@tonic-gate
38847c478bd9Sstevel@tonic-gate /*
38857c478bd9Sstevel@tonic-gate * "Age" the SA with the number of bytes that was used to protect traffic.
38867c478bd9Sstevel@tonic-gate * Send an SADB_EXPIRE message if appropriate. Return B_TRUE if there was
38877c478bd9Sstevel@tonic-gate * enough "charge" left in the SA to protect the data. Return B_FALSE
38887c478bd9Sstevel@tonic-gate * otherwise. (If B_FALSE is returned, the association either was, or became
38897c478bd9Sstevel@tonic-gate * DEAD.)
38907c478bd9Sstevel@tonic-gate */
38917c478bd9Sstevel@tonic-gate boolean_t
38927c478bd9Sstevel@tonic-gate sadb_age_bytes(queue_t *pfkey_q, ipsa_t *assoc, uint64_t bytes,
38937c478bd9Sstevel@tonic-gate boolean_t sendmsg)
38947c478bd9Sstevel@tonic-gate {
38957c478bd9Sstevel@tonic-gate boolean_t rc = B_TRUE;
38967c478bd9Sstevel@tonic-gate uint64_t newtotal;
38977c478bd9Sstevel@tonic-gate
38987c478bd9Sstevel@tonic-gate mutex_enter(&assoc->ipsa_lock);
38997c478bd9Sstevel@tonic-gate newtotal = assoc->ipsa_bytes + bytes;
39007c478bd9Sstevel@tonic-gate if (assoc->ipsa_hardbyteslt != 0 &&
39017c478bd9Sstevel@tonic-gate newtotal >= assoc->ipsa_hardbyteslt) {
39029c2c14abSThejaswini Singarajipura if (assoc->ipsa_state != IPSA_STATE_DEAD) {
39039c2c14abSThejaswini Singarajipura sadb_delete_cluster(assoc);
39047c478bd9Sstevel@tonic-gate /*
39057c478bd9Sstevel@tonic-gate * Send EXPIRE message to PF_KEY. May wish to pawn
39067c478bd9Sstevel@tonic-gate * this off on another non-interrupt thread. Also
39077c478bd9Sstevel@tonic-gate * unlink this SA immediately.
39087c478bd9Sstevel@tonic-gate */
39097c478bd9Sstevel@tonic-gate assoc->ipsa_state = IPSA_STATE_DEAD;
39107c478bd9Sstevel@tonic-gate if (sendmsg)
39117c478bd9Sstevel@tonic-gate sadb_expire_assoc(pfkey_q, assoc);
39127c478bd9Sstevel@tonic-gate /*
39137c478bd9Sstevel@tonic-gate * Set non-zero expiration time so sadb_age_assoc()
39147c478bd9Sstevel@tonic-gate * will work when reaping.
39157c478bd9Sstevel@tonic-gate */
39167c478bd9Sstevel@tonic-gate assoc->ipsa_hardexpiretime = (time_t)1;
39177c478bd9Sstevel@tonic-gate } /* Else someone beat me to it! */
39187c478bd9Sstevel@tonic-gate rc = B_FALSE;
39197c478bd9Sstevel@tonic-gate } else if (assoc->ipsa_softbyteslt != 0 &&
39207c478bd9Sstevel@tonic-gate (newtotal >= assoc->ipsa_softbyteslt)) {
39217c478bd9Sstevel@tonic-gate if (assoc->ipsa_state < IPSA_STATE_DYING) {
39227c478bd9Sstevel@tonic-gate /*
39237c478bd9Sstevel@tonic-gate * Send EXPIRE message to PF_KEY. May wish to pawn
39247c478bd9Sstevel@tonic-gate * this off on another non-interrupt thread.
39257c478bd9Sstevel@tonic-gate */
39267c478bd9Sstevel@tonic-gate assoc->ipsa_state = IPSA_STATE_DYING;
392750283218Smarkfen assoc->ipsa_bytes = newtotal;
39287c478bd9Sstevel@tonic-gate if (sendmsg)
39297c478bd9Sstevel@tonic-gate sadb_expire_assoc(pfkey_q, assoc);
39307c478bd9Sstevel@tonic-gate } /* Else someone beat me to it! */
39317c478bd9Sstevel@tonic-gate }
39327c478bd9Sstevel@tonic-gate if (rc == B_TRUE)
39337c478bd9Sstevel@tonic-gate assoc->ipsa_bytes = newtotal;
39347c478bd9Sstevel@tonic-gate mutex_exit(&assoc->ipsa_lock);
39357c478bd9Sstevel@tonic-gate return (rc);
39367c478bd9Sstevel@tonic-gate }
39377c478bd9Sstevel@tonic-gate
39387c478bd9Sstevel@tonic-gate /*
39397c478bd9Sstevel@tonic-gate * "Torch" an individual SA. Returns NULL, so it can be tail-called from
39407c478bd9Sstevel@tonic-gate * sadb_age_assoc().
39417c478bd9Sstevel@tonic-gate */
39427c478bd9Sstevel@tonic-gate static ipsa_t *
3943bd670b35SErik Nordmark sadb_torch_assoc(isaf_t *head, ipsa_t *sa)
39447c478bd9Sstevel@tonic-gate {
39457c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&head->isaf_lock));
39467c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sa->ipsa_lock));
39477c478bd9Sstevel@tonic-gate ASSERT(sa->ipsa_state == IPSA_STATE_DEAD);
39487c478bd9Sstevel@tonic-gate
39497c478bd9Sstevel@tonic-gate /*
39507c478bd9Sstevel@tonic-gate * Force cached SAs to be revalidated..
39517c478bd9Sstevel@tonic-gate */
39527c478bd9Sstevel@tonic-gate head->isaf_gen++;
39537c478bd9Sstevel@tonic-gate
39547c478bd9Sstevel@tonic-gate mutex_exit(&sa->ipsa_lock);
39557c478bd9Sstevel@tonic-gate sadb_unlinkassoc(sa);
39567c478bd9Sstevel@tonic-gate
39577c478bd9Sstevel@tonic-gate return (NULL);
39587c478bd9Sstevel@tonic-gate }
39597c478bd9Sstevel@tonic-gate
39607c478bd9Sstevel@tonic-gate /*
3961437220cdSdanmcd * Do various SA-is-idle activities depending on delta (the number of idle
3962437220cdSdanmcd * seconds on the SA) and/or other properties of the SA.
3963437220cdSdanmcd *
3964437220cdSdanmcd * Return B_TRUE if I've sent a packet, because I have to drop the
3965437220cdSdanmcd * association's mutex before sending a packet out the wire.
3966437220cdSdanmcd */
3967437220cdSdanmcd /* ARGSUSED */
3968437220cdSdanmcd static boolean_t
3969437220cdSdanmcd sadb_idle_activities(ipsa_t *assoc, time_t delta, boolean_t inbound)
3970437220cdSdanmcd {
3971437220cdSdanmcd ipsecesp_stack_t *espstack = assoc->ipsa_netstack->netstack_ipsecesp;
3972437220cdSdanmcd int nat_t_interval = espstack->ipsecesp_nat_keepalive_interval;
3973437220cdSdanmcd
3974437220cdSdanmcd ASSERT(MUTEX_HELD(&assoc->ipsa_lock));
3975437220cdSdanmcd
3976437220cdSdanmcd if (!inbound && (assoc->ipsa_flags & IPSA_F_NATT_LOC) &&
3977437220cdSdanmcd delta >= nat_t_interval &&
3978437220cdSdanmcd gethrestime_sec() - assoc->ipsa_last_nat_t_ka >= nat_t_interval) {
3979437220cdSdanmcd ASSERT(assoc->ipsa_type == SADB_SATYPE_ESP);
3980437220cdSdanmcd assoc->ipsa_last_nat_t_ka = gethrestime_sec();
3981437220cdSdanmcd mutex_exit(&assoc->ipsa_lock);
3982437220cdSdanmcd ipsecesp_send_keepalive(assoc);
3983437220cdSdanmcd return (B_TRUE);
3984437220cdSdanmcd }
3985437220cdSdanmcd return (B_FALSE);
3986437220cdSdanmcd }
3987437220cdSdanmcd
3988437220cdSdanmcd /*
398938d95a78Smarkfen * Return "assoc" if haspeer is true and I send an expire. This allows
39907c478bd9Sstevel@tonic-gate * the consumers' aging functions to tidy up an expired SA's peer.
39917c478bd9Sstevel@tonic-gate */
39927c478bd9Sstevel@tonic-gate static ipsa_t *
39937c478bd9Sstevel@tonic-gate sadb_age_assoc(isaf_t *head, queue_t *pfkey_q, ipsa_t *assoc,
3994bd670b35SErik Nordmark time_t current, int reap_delay, boolean_t inbound)
39957c478bd9Sstevel@tonic-gate {
39967c478bd9Sstevel@tonic-gate ipsa_t *retval = NULL;
3997437220cdSdanmcd boolean_t dropped_mutex = B_FALSE;
39987c478bd9Sstevel@tonic-gate
39997c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&head->isaf_lock));
40007c478bd9Sstevel@tonic-gate
40017c478bd9Sstevel@tonic-gate mutex_enter(&assoc->ipsa_lock);
40027c478bd9Sstevel@tonic-gate
40039c2c14abSThejaswini Singarajipura if (((assoc->ipsa_state == IPSA_STATE_LARVAL) ||
40049c2c14abSThejaswini Singarajipura ((assoc->ipsa_state == IPSA_STATE_IDLE) ||
40059c2c14abSThejaswini Singarajipura (assoc->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) &&
40069c2c14abSThejaswini Singarajipura (assoc->ipsa_hardexpiretime != 0))) &&
40077c478bd9Sstevel@tonic-gate (assoc->ipsa_hardexpiretime <= current)) {
40087c478bd9Sstevel@tonic-gate assoc->ipsa_state = IPSA_STATE_DEAD;
4009bd670b35SErik Nordmark return (sadb_torch_assoc(head, assoc));
40107c478bd9Sstevel@tonic-gate }
40117c478bd9Sstevel@tonic-gate
40127c478bd9Sstevel@tonic-gate /*
40137c478bd9Sstevel@tonic-gate * Check lifetimes. Fortunately, SA setup is done
40147c478bd9Sstevel@tonic-gate * such that there are only two times to look at,
40157c478bd9Sstevel@tonic-gate * softexpiretime, and hardexpiretime.
40167c478bd9Sstevel@tonic-gate *
40177c478bd9Sstevel@tonic-gate * Check hard first.
40187c478bd9Sstevel@tonic-gate */
40197c478bd9Sstevel@tonic-gate
40207c478bd9Sstevel@tonic-gate if (assoc->ipsa_hardexpiretime != 0 &&
40217c478bd9Sstevel@tonic-gate assoc->ipsa_hardexpiretime <= current) {
40227c478bd9Sstevel@tonic-gate if (assoc->ipsa_state == IPSA_STATE_DEAD)
4023bd670b35SErik Nordmark return (sadb_torch_assoc(head, assoc));
40247c478bd9Sstevel@tonic-gate
40259c2c14abSThejaswini Singarajipura if (inbound) {
40269c2c14abSThejaswini Singarajipura sadb_delete_cluster(assoc);
40279c2c14abSThejaswini Singarajipura }
40289c2c14abSThejaswini Singarajipura
40297c478bd9Sstevel@tonic-gate /*
40307c478bd9Sstevel@tonic-gate * Send SADB_EXPIRE with hard lifetime, delay for unlinking.
40317c478bd9Sstevel@tonic-gate */
40327c478bd9Sstevel@tonic-gate assoc->ipsa_state = IPSA_STATE_DEAD;
403338d95a78Smarkfen if (assoc->ipsa_haspeer || assoc->ipsa_otherspi != 0) {
40347c478bd9Sstevel@tonic-gate /*
403538d95a78Smarkfen * If the SA is paired or peered with another, put
403638d95a78Smarkfen * a copy on a list which can be processed later, the
403738d95a78Smarkfen * pair/peer SA needs to be updated so the both die
403838d95a78Smarkfen * at the same time.
403938d95a78Smarkfen *
404038d95a78Smarkfen * If I return assoc, I have to bump up its reference
404138d95a78Smarkfen * count to keep with the ipsa_t reference count
404238d95a78Smarkfen * semantics.
40437c478bd9Sstevel@tonic-gate */
40447c478bd9Sstevel@tonic-gate IPSA_REFHOLD(assoc);
40457c478bd9Sstevel@tonic-gate retval = assoc;
40467c478bd9Sstevel@tonic-gate }
40477c478bd9Sstevel@tonic-gate sadb_expire_assoc(pfkey_q, assoc);
40487c478bd9Sstevel@tonic-gate assoc->ipsa_hardexpiretime = current + reap_delay;
40497c478bd9Sstevel@tonic-gate } else if (assoc->ipsa_softexpiretime != 0 &&
40507c478bd9Sstevel@tonic-gate assoc->ipsa_softexpiretime <= current &&
40517c478bd9Sstevel@tonic-gate assoc->ipsa_state < IPSA_STATE_DYING) {
40527c478bd9Sstevel@tonic-gate /*
40537c478bd9Sstevel@tonic-gate * Send EXPIRE message to PF_KEY. May wish to pawn
40547c478bd9Sstevel@tonic-gate * this off on another non-interrupt thread.
40557c478bd9Sstevel@tonic-gate */
40567c478bd9Sstevel@tonic-gate assoc->ipsa_state = IPSA_STATE_DYING;
40577c478bd9Sstevel@tonic-gate if (assoc->ipsa_haspeer) {
40587c478bd9Sstevel@tonic-gate /*
405938d95a78Smarkfen * If the SA has a peer, update the peer's state
406038d95a78Smarkfen * on SOFT_EXPIRE, this is mostly to prevent two
406138d95a78Smarkfen * expire messages from effectively the same SA.
406238d95a78Smarkfen *
406338d95a78Smarkfen * Don't care about paired SA's, then can (and should)
406438d95a78Smarkfen * be able to soft expire at different times.
406538d95a78Smarkfen *
40667c478bd9Sstevel@tonic-gate * If I return assoc, I have to bump up its
40677c478bd9Sstevel@tonic-gate * reference count to keep with the ipsa_t reference
40687c478bd9Sstevel@tonic-gate * count semantics.
40697c478bd9Sstevel@tonic-gate */
40707c478bd9Sstevel@tonic-gate IPSA_REFHOLD(assoc);
40717c478bd9Sstevel@tonic-gate retval = assoc;
40727c478bd9Sstevel@tonic-gate }
40737c478bd9Sstevel@tonic-gate sadb_expire_assoc(pfkey_q, assoc);
40749c2c14abSThejaswini Singarajipura } else if (assoc->ipsa_idletime != 0 &&
40759c2c14abSThejaswini Singarajipura assoc->ipsa_idleexpiretime <= current) {
40769c2c14abSThejaswini Singarajipura if (assoc->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) {
40779c2c14abSThejaswini Singarajipura assoc->ipsa_state = IPSA_STATE_IDLE;
40789c2c14abSThejaswini Singarajipura }
40799c2c14abSThejaswini Singarajipura
40809c2c14abSThejaswini Singarajipura /*
40819c2c14abSThejaswini Singarajipura * Need to handle Mature case
40829c2c14abSThejaswini Singarajipura */
4083a14de6c8SDan McDonald if (assoc->ipsa_state == IPSA_STATE_MATURE) {
40849c2c14abSThejaswini Singarajipura sadb_expire_assoc(pfkey_q, assoc);
40859c2c14abSThejaswini Singarajipura }
4086437220cdSdanmcd } else {
4087437220cdSdanmcd /* Check idle time activities. */
4088437220cdSdanmcd dropped_mutex = sadb_idle_activities(assoc,
4089437220cdSdanmcd current - assoc->ipsa_lastuse, inbound);
40907c478bd9Sstevel@tonic-gate }
40917c478bd9Sstevel@tonic-gate
4092437220cdSdanmcd if (!dropped_mutex)
40937c478bd9Sstevel@tonic-gate mutex_exit(&assoc->ipsa_lock);
40947c478bd9Sstevel@tonic-gate return (retval);
40957c478bd9Sstevel@tonic-gate }
40967c478bd9Sstevel@tonic-gate
40977c478bd9Sstevel@tonic-gate /*
40987c478bd9Sstevel@tonic-gate * Called by a consumer protocol to do ther dirty work of reaping dead
40997c478bd9Sstevel@tonic-gate * Security Associations.
410038d95a78Smarkfen *
410138d95a78Smarkfen * NOTE: sadb_age_assoc() marks expired SA's as DEAD but only removed
410238d95a78Smarkfen * SA's that are already marked DEAD, so expired SA's are only reaped
410338d95a78Smarkfen * the second time sadb_ager() runs.
41047c478bd9Sstevel@tonic-gate */
41057c478bd9Sstevel@tonic-gate void
4106bd670b35SErik Nordmark sadb_ager(sadb_t *sp, queue_t *pfkey_q, int reap_delay, netstack_t *ns)
41077c478bd9Sstevel@tonic-gate {
41087c478bd9Sstevel@tonic-gate int i;
41097c478bd9Sstevel@tonic-gate isaf_t *bucket;
41107c478bd9Sstevel@tonic-gate ipsa_t *assoc, *spare;
41117c478bd9Sstevel@tonic-gate iacqf_t *acqlist;
41127c478bd9Sstevel@tonic-gate ipsacq_t *acqrec, *spareacq;
411338d95a78Smarkfen templist_t *haspeerlist, *newbie;
4114437220cdSdanmcd /* Snapshot current time now. */
4115437220cdSdanmcd time_t current = gethrestime_sec();
411638d95a78Smarkfen haspeerlist = NULL;
41177c478bd9Sstevel@tonic-gate
41187c478bd9Sstevel@tonic-gate /*
41197c478bd9Sstevel@tonic-gate * Do my dirty work. This includes aging real entries, aging
41207c478bd9Sstevel@tonic-gate * larvals, and aging outstanding ACQUIREs.
41217c478bd9Sstevel@tonic-gate *
41227c478bd9Sstevel@tonic-gate * I hope I don't tie up resources for too long.
41237c478bd9Sstevel@tonic-gate */
41247c478bd9Sstevel@tonic-gate
41257c478bd9Sstevel@tonic-gate /* Age acquires. */
41267c478bd9Sstevel@tonic-gate
4127fb87b5d2Ssommerfe for (i = 0; i < sp->sdb_hashsize; i++) {
41287c478bd9Sstevel@tonic-gate acqlist = &sp->sdb_acq[i];
41297c478bd9Sstevel@tonic-gate mutex_enter(&acqlist->iacqf_lock);
41307c478bd9Sstevel@tonic-gate for (acqrec = acqlist->iacqf_ipsacq; acqrec != NULL;
41317c478bd9Sstevel@tonic-gate acqrec = spareacq) {
41327c478bd9Sstevel@tonic-gate spareacq = acqrec->ipsacq_next;
41337c478bd9Sstevel@tonic-gate if (current > acqrec->ipsacq_expire)
4134f4b3ec61Sdh155122 sadb_destroy_acquire(acqrec, ns);
41357c478bd9Sstevel@tonic-gate }
41367c478bd9Sstevel@tonic-gate mutex_exit(&acqlist->iacqf_lock);
41377c478bd9Sstevel@tonic-gate }
41387c478bd9Sstevel@tonic-gate
41397c478bd9Sstevel@tonic-gate /* Age inbound associations. */
4140fb87b5d2Ssommerfe for (i = 0; i < sp->sdb_hashsize; i++) {
41417c478bd9Sstevel@tonic-gate bucket = &(sp->sdb_if[i]);
41427c478bd9Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock);
41437c478bd9Sstevel@tonic-gate for (assoc = bucket->isaf_ipsa; assoc != NULL;
41447c478bd9Sstevel@tonic-gate assoc = spare) {
41457c478bd9Sstevel@tonic-gate spare = assoc->ipsa_next;
41467c478bd9Sstevel@tonic-gate if (sadb_age_assoc(bucket, pfkey_q, assoc, current,
4147bd670b35SErik Nordmark reap_delay, B_TRUE) != NULL) {
41487c478bd9Sstevel@tonic-gate /*
414938d95a78Smarkfen * Put SA's which have a peer or SA's which
415038d95a78Smarkfen * are paired on a list for processing after
415138d95a78Smarkfen * all the hash tables have been walked.
415238d95a78Smarkfen *
41537c478bd9Sstevel@tonic-gate * sadb_age_assoc() increments the refcnt,
41547c478bd9Sstevel@tonic-gate * effectively doing an IPSA_REFHOLD().
41557c478bd9Sstevel@tonic-gate */
41567c478bd9Sstevel@tonic-gate newbie = kmem_alloc(sizeof (*newbie),
41577c478bd9Sstevel@tonic-gate KM_NOSLEEP);
41587c478bd9Sstevel@tonic-gate if (newbie == NULL) {
41597c478bd9Sstevel@tonic-gate /*
41607c478bd9Sstevel@tonic-gate * Don't forget to REFRELE().
41617c478bd9Sstevel@tonic-gate */
41627c478bd9Sstevel@tonic-gate IPSA_REFRELE(assoc);
41637c478bd9Sstevel@tonic-gate continue; /* for loop... */
41647c478bd9Sstevel@tonic-gate }
41657c478bd9Sstevel@tonic-gate newbie->next = haspeerlist;
41667c478bd9Sstevel@tonic-gate newbie->ipsa = assoc;
41677c478bd9Sstevel@tonic-gate haspeerlist = newbie;
41687c478bd9Sstevel@tonic-gate }
41697c478bd9Sstevel@tonic-gate }
41707c478bd9Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock);
41717c478bd9Sstevel@tonic-gate }
41727c478bd9Sstevel@tonic-gate
417338d95a78Smarkfen age_pair_peer_list(haspeerlist, sp, B_FALSE);
417438d95a78Smarkfen haspeerlist = NULL;
41757c478bd9Sstevel@tonic-gate
41767c478bd9Sstevel@tonic-gate /* Age outbound associations. */
4177fb87b5d2Ssommerfe for (i = 0; i < sp->sdb_hashsize; i++) {
41787c478bd9Sstevel@tonic-gate bucket = &(sp->sdb_of[i]);
41797c478bd9Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock);
41807c478bd9Sstevel@tonic-gate for (assoc = bucket->isaf_ipsa; assoc != NULL;
41817c478bd9Sstevel@tonic-gate assoc = spare) {
41827c478bd9Sstevel@tonic-gate spare = assoc->ipsa_next;
41837c478bd9Sstevel@tonic-gate if (sadb_age_assoc(bucket, pfkey_q, assoc, current,
4184bd670b35SErik Nordmark reap_delay, B_FALSE) != NULL) {
41857c478bd9Sstevel@tonic-gate /*
41867c478bd9Sstevel@tonic-gate * sadb_age_assoc() increments the refcnt,
41877c478bd9Sstevel@tonic-gate * effectively doing an IPSA_REFHOLD().
41887c478bd9Sstevel@tonic-gate */
41897c478bd9Sstevel@tonic-gate newbie = kmem_alloc(sizeof (*newbie),
41907c478bd9Sstevel@tonic-gate KM_NOSLEEP);
41917c478bd9Sstevel@tonic-gate if (newbie == NULL) {
41927c478bd9Sstevel@tonic-gate /*
41937c478bd9Sstevel@tonic-gate * Don't forget to REFRELE().
41947c478bd9Sstevel@tonic-gate */
41957c478bd9Sstevel@tonic-gate IPSA_REFRELE(assoc);
41967c478bd9Sstevel@tonic-gate continue; /* for loop... */
41977c478bd9Sstevel@tonic-gate }
41987c478bd9Sstevel@tonic-gate newbie->next = haspeerlist;
41997c478bd9Sstevel@tonic-gate newbie->ipsa = assoc;
42007c478bd9Sstevel@tonic-gate haspeerlist = newbie;
42017c478bd9Sstevel@tonic-gate }
42027c478bd9Sstevel@tonic-gate }
42037c478bd9Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock);
42047c478bd9Sstevel@tonic-gate }
420538d95a78Smarkfen
420638d95a78Smarkfen age_pair_peer_list(haspeerlist, sp, B_TRUE);
420738d95a78Smarkfen
42087c478bd9Sstevel@tonic-gate /*
42097c478bd9Sstevel@tonic-gate * Run a GC pass to clean out dead identities.
42107c478bd9Sstevel@tonic-gate */
4211f4b3ec61Sdh155122 ipsid_gc(ns);
42127c478bd9Sstevel@tonic-gate }
42137c478bd9Sstevel@tonic-gate
42147c478bd9Sstevel@tonic-gate /*
42157c478bd9Sstevel@tonic-gate * Figure out when to reschedule the ager.
42167c478bd9Sstevel@tonic-gate */
42177c478bd9Sstevel@tonic-gate timeout_id_t
42187c478bd9Sstevel@tonic-gate sadb_retimeout(hrtime_t begin, queue_t *pfkey_q, void (*ager)(void *),
4219f4b3ec61Sdh155122 void *agerarg, uint_t *intp, uint_t intmax, short mid)
42207c478bd9Sstevel@tonic-gate {
42217c478bd9Sstevel@tonic-gate hrtime_t end = gethrtime();
4222cf0ee00aSDan McDonald uint_t interval = *intp; /* "interval" is in ms. */
42237c478bd9Sstevel@tonic-gate
42247c478bd9Sstevel@tonic-gate /*
42257c478bd9Sstevel@tonic-gate * See how long this took. If it took too long, increase the
42267c478bd9Sstevel@tonic-gate * aging interval.
42277c478bd9Sstevel@tonic-gate */
4228cf0ee00aSDan McDonald if ((end - begin) > MSEC2NSEC(interval)) {
42297c478bd9Sstevel@tonic-gate if (interval >= intmax) {
42307c478bd9Sstevel@tonic-gate /* XXX Rate limit this? Or recommend flush? */
42317c478bd9Sstevel@tonic-gate (void) strlog(mid, 0, 0, SL_ERROR | SL_WARN,
42327c478bd9Sstevel@tonic-gate "Too many SA's to age out in %d msec.\n",
42337c478bd9Sstevel@tonic-gate intmax);
42347c478bd9Sstevel@tonic-gate } else {
42357c478bd9Sstevel@tonic-gate /* Double by shifting by one bit. */
42367c478bd9Sstevel@tonic-gate interval <<= 1;
42377c478bd9Sstevel@tonic-gate interval = min(interval, intmax);
42387c478bd9Sstevel@tonic-gate }
4239cf0ee00aSDan McDonald } else if ((end - begin) <= (MSEC2NSEC(interval) / 2) &&
42407c478bd9Sstevel@tonic-gate interval > SADB_AGE_INTERVAL_DEFAULT) {
42417c478bd9Sstevel@tonic-gate /*
42427c478bd9Sstevel@tonic-gate * If I took less than half of the interval, then I should
42437c478bd9Sstevel@tonic-gate * ratchet the interval back down. Never automatically
42447c478bd9Sstevel@tonic-gate * shift below the default aging interval.
42457c478bd9Sstevel@tonic-gate *
42467c478bd9Sstevel@tonic-gate * NOTE:This even overrides manual setting of the age
42470e9b5742SDan McDonald * interval using NDD to lower the setting past the
42480e9b5742SDan McDonald * default. In other words, if you set the interval
42490e9b5742SDan McDonald * lower than the default, and your SADB gets too big,
42500e9b5742SDan McDonald * the interval will only self-lower back to the default.
42517c478bd9Sstevel@tonic-gate */
42527c478bd9Sstevel@tonic-gate /* Halve by shifting one bit. */
42537c478bd9Sstevel@tonic-gate interval >>= 1;
42547c478bd9Sstevel@tonic-gate interval = max(interval, SADB_AGE_INTERVAL_DEFAULT);
42557c478bd9Sstevel@tonic-gate }
42567c478bd9Sstevel@tonic-gate *intp = interval;
4257f4b3ec61Sdh155122 return (qtimeout(pfkey_q, ager, agerarg,
4258cf0ee00aSDan McDonald drv_usectohz(interval * (MICROSEC / MILLISEC))));
42597c478bd9Sstevel@tonic-gate }
42607c478bd9Sstevel@tonic-gate
42617c478bd9Sstevel@tonic-gate
42627c478bd9Sstevel@tonic-gate /*
42637c478bd9Sstevel@tonic-gate * Update the lifetime values of an SA. This is the path an SADB_UPDATE
42647c478bd9Sstevel@tonic-gate * message takes when updating a MATURE or DYING SA.
42657c478bd9Sstevel@tonic-gate */
42667c478bd9Sstevel@tonic-gate static void
42677c478bd9Sstevel@tonic-gate sadb_update_lifetimes(ipsa_t *assoc, sadb_lifetime_t *hard,
42689c2c14abSThejaswini Singarajipura sadb_lifetime_t *soft, sadb_lifetime_t *idle, boolean_t outbound)
42697c478bd9Sstevel@tonic-gate {
42707c478bd9Sstevel@tonic-gate mutex_enter(&assoc->ipsa_lock);
42717c478bd9Sstevel@tonic-gate
42727c478bd9Sstevel@tonic-gate /*
42737c478bd9Sstevel@tonic-gate * XXX RFC 2367 mentions how an SADB_EXT_LIFETIME_CURRENT can be
42747c478bd9Sstevel@tonic-gate * passed in during an update message. We currently don't handle
42757c478bd9Sstevel@tonic-gate * these.
42767c478bd9Sstevel@tonic-gate */
42777c478bd9Sstevel@tonic-gate
42787c478bd9Sstevel@tonic-gate if (hard != NULL) {
42797c478bd9Sstevel@tonic-gate if (hard->sadb_lifetime_bytes != 0)
42807c478bd9Sstevel@tonic-gate assoc->ipsa_hardbyteslt = hard->sadb_lifetime_bytes;
42817c478bd9Sstevel@tonic-gate if (hard->sadb_lifetime_usetime != 0)
42827c478bd9Sstevel@tonic-gate assoc->ipsa_harduselt = hard->sadb_lifetime_usetime;
42837c478bd9Sstevel@tonic-gate if (hard->sadb_lifetime_addtime != 0)
42847c478bd9Sstevel@tonic-gate assoc->ipsa_hardaddlt = hard->sadb_lifetime_addtime;
42857c478bd9Sstevel@tonic-gate if (assoc->ipsa_hardaddlt != 0) {
42867c478bd9Sstevel@tonic-gate assoc->ipsa_hardexpiretime =
42877c478bd9Sstevel@tonic-gate assoc->ipsa_addtime + assoc->ipsa_hardaddlt;
42887c478bd9Sstevel@tonic-gate }
428938d95a78Smarkfen if (assoc->ipsa_harduselt != 0 &&
429038d95a78Smarkfen assoc->ipsa_flags & IPSA_F_USED) {
429138d95a78Smarkfen UPDATE_EXPIRE(assoc, harduselt, hardexpiretime);
42927c478bd9Sstevel@tonic-gate }
42937c478bd9Sstevel@tonic-gate if (hard->sadb_lifetime_allocations != 0)
42947c478bd9Sstevel@tonic-gate assoc->ipsa_hardalloc = hard->sadb_lifetime_allocations;
42957c478bd9Sstevel@tonic-gate }
42967c478bd9Sstevel@tonic-gate
42977c478bd9Sstevel@tonic-gate if (soft != NULL) {
429838d95a78Smarkfen if (soft->sadb_lifetime_bytes != 0) {
429938d95a78Smarkfen if (soft->sadb_lifetime_bytes >
430038d95a78Smarkfen assoc->ipsa_hardbyteslt) {
430138d95a78Smarkfen assoc->ipsa_softbyteslt =
430238d95a78Smarkfen assoc->ipsa_hardbyteslt;
430338d95a78Smarkfen } else {
430438d95a78Smarkfen assoc->ipsa_softbyteslt =
430538d95a78Smarkfen soft->sadb_lifetime_bytes;
430638d95a78Smarkfen }
430738d95a78Smarkfen }
430838d95a78Smarkfen if (soft->sadb_lifetime_usetime != 0) {
430938d95a78Smarkfen if (soft->sadb_lifetime_usetime >
431038d95a78Smarkfen assoc->ipsa_harduselt) {
431138d95a78Smarkfen assoc->ipsa_softuselt =
431238d95a78Smarkfen assoc->ipsa_harduselt;
431338d95a78Smarkfen } else {
431438d95a78Smarkfen assoc->ipsa_softuselt =
431538d95a78Smarkfen soft->sadb_lifetime_usetime;
431638d95a78Smarkfen }
431738d95a78Smarkfen }
431838d95a78Smarkfen if (soft->sadb_lifetime_addtime != 0) {
431938d95a78Smarkfen if (soft->sadb_lifetime_addtime >
432038d95a78Smarkfen assoc->ipsa_hardexpiretime) {
432138d95a78Smarkfen assoc->ipsa_softexpiretime =
432238d95a78Smarkfen assoc->ipsa_hardexpiretime;
432338d95a78Smarkfen } else {
432438d95a78Smarkfen assoc->ipsa_softaddlt =
432538d95a78Smarkfen soft->sadb_lifetime_addtime;
432638d95a78Smarkfen }
432738d95a78Smarkfen }
43287c478bd9Sstevel@tonic-gate if (assoc->ipsa_softaddlt != 0) {
43297c478bd9Sstevel@tonic-gate assoc->ipsa_softexpiretime =
43307c478bd9Sstevel@tonic-gate assoc->ipsa_addtime + assoc->ipsa_softaddlt;
43317c478bd9Sstevel@tonic-gate }
433238d95a78Smarkfen if (assoc->ipsa_softuselt != 0 &&
433338d95a78Smarkfen assoc->ipsa_flags & IPSA_F_USED) {
433438d95a78Smarkfen UPDATE_EXPIRE(assoc, softuselt, softexpiretime);
43357c478bd9Sstevel@tonic-gate }
433638d95a78Smarkfen if (outbound && assoc->ipsa_softexpiretime != 0) {
433738d95a78Smarkfen if (assoc->ipsa_state == IPSA_STATE_MATURE)
433838d95a78Smarkfen lifetime_fuzz(assoc);
43397c478bd9Sstevel@tonic-gate }
43407c478bd9Sstevel@tonic-gate
43417c478bd9Sstevel@tonic-gate if (soft->sadb_lifetime_allocations != 0)
43427c478bd9Sstevel@tonic-gate assoc->ipsa_softalloc = soft->sadb_lifetime_allocations;
43437c478bd9Sstevel@tonic-gate }
43449c2c14abSThejaswini Singarajipura
43459c2c14abSThejaswini Singarajipura if (idle != NULL) {
43469c2c14abSThejaswini Singarajipura time_t current = gethrestime_sec();
43479c2c14abSThejaswini Singarajipura if ((assoc->ipsa_idleexpiretime <= current) &&
43489c2c14abSThejaswini Singarajipura (assoc->ipsa_idleaddlt == idle->sadb_lifetime_addtime)) {
43499c2c14abSThejaswini Singarajipura assoc->ipsa_idleexpiretime =
43509c2c14abSThejaswini Singarajipura current + assoc->ipsa_idleaddlt;
43519c2c14abSThejaswini Singarajipura }
43529c2c14abSThejaswini Singarajipura if (idle->sadb_lifetime_addtime != 0)
43539c2c14abSThejaswini Singarajipura assoc->ipsa_idleaddlt = idle->sadb_lifetime_addtime;
43549c2c14abSThejaswini Singarajipura if (idle->sadb_lifetime_usetime != 0)
43559c2c14abSThejaswini Singarajipura assoc->ipsa_idleuselt = idle->sadb_lifetime_usetime;
43569c2c14abSThejaswini Singarajipura if (assoc->ipsa_idleaddlt != 0) {
43579c2c14abSThejaswini Singarajipura assoc->ipsa_idleexpiretime =
43589c2c14abSThejaswini Singarajipura current + idle->sadb_lifetime_addtime;
43599c2c14abSThejaswini Singarajipura assoc->ipsa_idletime = idle->sadb_lifetime_addtime;
43609c2c14abSThejaswini Singarajipura }
43619c2c14abSThejaswini Singarajipura if (assoc->ipsa_idleuselt != 0) {
43629c2c14abSThejaswini Singarajipura if (assoc->ipsa_idletime != 0) {
43639c2c14abSThejaswini Singarajipura assoc->ipsa_idletime = min(assoc->ipsa_idletime,
43649c2c14abSThejaswini Singarajipura assoc->ipsa_idleuselt);
43659c2c14abSThejaswini Singarajipura assoc->ipsa_idleexpiretime =
43669c2c14abSThejaswini Singarajipura current + assoc->ipsa_idletime;
43679c2c14abSThejaswini Singarajipura } else {
43689c2c14abSThejaswini Singarajipura assoc->ipsa_idleexpiretime =
43699c2c14abSThejaswini Singarajipura current + assoc->ipsa_idleuselt;
43709c2c14abSThejaswini Singarajipura assoc->ipsa_idletime = assoc->ipsa_idleuselt;
43719c2c14abSThejaswini Singarajipura }
43729c2c14abSThejaswini Singarajipura }
43739c2c14abSThejaswini Singarajipura }
43747c478bd9Sstevel@tonic-gate mutex_exit(&assoc->ipsa_lock);
43757c478bd9Sstevel@tonic-gate }
43767c478bd9Sstevel@tonic-gate
43779c2c14abSThejaswini Singarajipura static int
43789c2c14abSThejaswini Singarajipura sadb_update_state(ipsa_t *assoc, uint_t new_state, mblk_t **ipkt_lst)
43799c2c14abSThejaswini Singarajipura {
43809c2c14abSThejaswini Singarajipura int rcode = 0;
43819c2c14abSThejaswini Singarajipura time_t current = gethrestime_sec();
43829c2c14abSThejaswini Singarajipura
43839c2c14abSThejaswini Singarajipura mutex_enter(&assoc->ipsa_lock);
43849c2c14abSThejaswini Singarajipura
43859c2c14abSThejaswini Singarajipura switch (new_state) {
43869c2c14abSThejaswini Singarajipura case SADB_X_SASTATE_ACTIVE_ELSEWHERE:
43879c2c14abSThejaswini Singarajipura if (assoc->ipsa_state == SADB_X_SASTATE_IDLE) {
43889c2c14abSThejaswini Singarajipura assoc->ipsa_state = IPSA_STATE_ACTIVE_ELSEWHERE;
43899c2c14abSThejaswini Singarajipura assoc->ipsa_idleexpiretime =
43909c2c14abSThejaswini Singarajipura current + assoc->ipsa_idletime;
43919c2c14abSThejaswini Singarajipura }
43929c2c14abSThejaswini Singarajipura break;
43939c2c14abSThejaswini Singarajipura case SADB_X_SASTATE_IDLE:
43949c2c14abSThejaswini Singarajipura if (assoc->ipsa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE) {
43959c2c14abSThejaswini Singarajipura assoc->ipsa_state = IPSA_STATE_IDLE;
43969c2c14abSThejaswini Singarajipura assoc->ipsa_idleexpiretime =
43979c2c14abSThejaswini Singarajipura current + assoc->ipsa_idletime;
43989c2c14abSThejaswini Singarajipura } else {
43999c2c14abSThejaswini Singarajipura rcode = EINVAL;
44009c2c14abSThejaswini Singarajipura }
44019c2c14abSThejaswini Singarajipura break;
44029c2c14abSThejaswini Singarajipura
44039c2c14abSThejaswini Singarajipura case SADB_X_SASTATE_ACTIVE:
44049c2c14abSThejaswini Singarajipura if (assoc->ipsa_state != SADB_X_SASTATE_IDLE) {
44059c2c14abSThejaswini Singarajipura rcode = EINVAL;
44069c2c14abSThejaswini Singarajipura break;
44079c2c14abSThejaswini Singarajipura }
44089c2c14abSThejaswini Singarajipura assoc->ipsa_state = IPSA_STATE_MATURE;
44099c2c14abSThejaswini Singarajipura assoc->ipsa_idleexpiretime = current + assoc->ipsa_idletime;
44109c2c14abSThejaswini Singarajipura
44119c2c14abSThejaswini Singarajipura if (ipkt_lst == NULL) {
44129c2c14abSThejaswini Singarajipura break;
44139c2c14abSThejaswini Singarajipura }
44149c2c14abSThejaswini Singarajipura
44159c2c14abSThejaswini Singarajipura if (assoc->ipsa_bpkt_head != NULL) {
44169c2c14abSThejaswini Singarajipura *ipkt_lst = assoc->ipsa_bpkt_head;
44179c2c14abSThejaswini Singarajipura assoc->ipsa_bpkt_head = assoc->ipsa_bpkt_tail = NULL;
44189c2c14abSThejaswini Singarajipura assoc->ipsa_mblkcnt = 0;
44199c2c14abSThejaswini Singarajipura } else {
44209c2c14abSThejaswini Singarajipura *ipkt_lst = NULL;
44219c2c14abSThejaswini Singarajipura }
44229c2c14abSThejaswini Singarajipura break;
44239c2c14abSThejaswini Singarajipura default:
44249c2c14abSThejaswini Singarajipura rcode = EINVAL;
44259c2c14abSThejaswini Singarajipura break;
44269c2c14abSThejaswini Singarajipura }
44279c2c14abSThejaswini Singarajipura
44289c2c14abSThejaswini Singarajipura mutex_exit(&assoc->ipsa_lock);
44299c2c14abSThejaswini Singarajipura return (rcode);
44309c2c14abSThejaswini Singarajipura }
44319c2c14abSThejaswini Singarajipura
44327c478bd9Sstevel@tonic-gate /*
44335d3b8cb7SBill Sommerfeld * Check a proposed KMC update for sanity.
44345d3b8cb7SBill Sommerfeld */
44355d3b8cb7SBill Sommerfeld static int
44365d3b8cb7SBill Sommerfeld sadb_check_kmc(ipsa_query_t *sq, ipsa_t *sa, int *diagnostic)
44375d3b8cb7SBill Sommerfeld {
44385d3b8cb7SBill Sommerfeld uint32_t kmp = sq->kmp;
44395d3b8cb7SBill Sommerfeld uint32_t kmc = sq->kmc;
44405d3b8cb7SBill Sommerfeld
44415d3b8cb7SBill Sommerfeld if (sa == NULL)
44425d3b8cb7SBill Sommerfeld return (0);
44435d3b8cb7SBill Sommerfeld
44445d3b8cb7SBill Sommerfeld if (sa->ipsa_state == IPSA_STATE_DEAD)
44455d3b8cb7SBill Sommerfeld return (ESRCH); /* DEAD == Not there, in this case. */
44465d3b8cb7SBill Sommerfeld
44475d3b8cb7SBill Sommerfeld if ((kmp != 0) && ((sa->ipsa_kmp != 0) || (sa->ipsa_kmp != kmp))) {
44485d3b8cb7SBill Sommerfeld *diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMP;
44495d3b8cb7SBill Sommerfeld return (EINVAL);
44505d3b8cb7SBill Sommerfeld }
44515d3b8cb7SBill Sommerfeld
44525d3b8cb7SBill Sommerfeld if ((kmc != 0) && ((sa->ipsa_kmc != 0) || (sa->ipsa_kmc != kmc))) {
44535d3b8cb7SBill Sommerfeld *diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMC;
44545d3b8cb7SBill Sommerfeld return (EINVAL);
44555d3b8cb7SBill Sommerfeld }
44565d3b8cb7SBill Sommerfeld
44575d3b8cb7SBill Sommerfeld return (0);
44585d3b8cb7SBill Sommerfeld }
44595d3b8cb7SBill Sommerfeld
44605d3b8cb7SBill Sommerfeld /*
44615d3b8cb7SBill Sommerfeld * Actually update the KMC info.
44625d3b8cb7SBill Sommerfeld */
44635d3b8cb7SBill Sommerfeld static void
44645d3b8cb7SBill Sommerfeld sadb_update_kmc(ipsa_query_t *sq, ipsa_t *sa)
44655d3b8cb7SBill Sommerfeld {
44665d3b8cb7SBill Sommerfeld uint32_t kmp = sq->kmp;
44675d3b8cb7SBill Sommerfeld uint32_t kmc = sq->kmc;
44685d3b8cb7SBill Sommerfeld
44695d3b8cb7SBill Sommerfeld if (kmp != 0)
44705d3b8cb7SBill Sommerfeld sa->ipsa_kmp = kmp;
44715d3b8cb7SBill Sommerfeld if (kmc != 0)
44725d3b8cb7SBill Sommerfeld sa->ipsa_kmc = kmc;
44735d3b8cb7SBill Sommerfeld }
44745d3b8cb7SBill Sommerfeld
44755d3b8cb7SBill Sommerfeld /*
44767c478bd9Sstevel@tonic-gate * Common code to update an SA.
44777c478bd9Sstevel@tonic-gate */
44787c478bd9Sstevel@tonic-gate
44797c478bd9Sstevel@tonic-gate int
44809c2c14abSThejaswini Singarajipura sadb_update_sa(mblk_t *mp, keysock_in_t *ksi, mblk_t **ipkt_lst,
448138d95a78Smarkfen sadbp_t *spp, int *diagnostic, queue_t *pfkey_q,
4482f4b3ec61Sdh155122 int (*add_sa_func)(mblk_t *, keysock_in_t *, int *, netstack_t *),
448338d95a78Smarkfen netstack_t *ns, uint8_t sadb_msg_type)
44847c478bd9Sstevel@tonic-gate {
44857c478bd9Sstevel@tonic-gate sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
44867c478bd9Sstevel@tonic-gate sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
44879c2c14abSThejaswini Singarajipura sadb_x_replay_ctr_t *replext =
44889c2c14abSThejaswini Singarajipura (sadb_x_replay_ctr_t *)ksi->ks_in_extv[SADB_X_EXT_REPLAY_VALUE];
44897c478bd9Sstevel@tonic-gate sadb_lifetime_t *soft =
44907c478bd9Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT];
44917c478bd9Sstevel@tonic-gate sadb_lifetime_t *hard =
44927c478bd9Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD];
44939c2c14abSThejaswini Singarajipura sadb_lifetime_t *idle =
44949c2c14abSThejaswini Singarajipura (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE];
449538d95a78Smarkfen sadb_x_pair_t *pair_ext =
449638d95a78Smarkfen (sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
449738d95a78Smarkfen ipsa_t *echo_target = NULL;
44985d3b8cb7SBill Sommerfeld ipsap_t ipsapp;
44995d3b8cb7SBill Sommerfeld ipsa_query_t sq;
45009c2c14abSThejaswini Singarajipura time_t current = gethrestime_sec();
45017c478bd9Sstevel@tonic-gate
45025d3b8cb7SBill Sommerfeld sq.spp = spp; /* XXX param */
45035d3b8cb7SBill Sommerfeld int error = sadb_form_query(ksi, IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SA,
45045d3b8cb7SBill Sommerfeld IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SA|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
45055d3b8cb7SBill Sommerfeld &sq, diagnostic);
450638d95a78Smarkfen
45075d3b8cb7SBill Sommerfeld if (error != 0)
45085d3b8cb7SBill Sommerfeld return (error);
45097c478bd9Sstevel@tonic-gate
45105d3b8cb7SBill Sommerfeld error = get_ipsa_pair(&sq, &ipsapp, diagnostic);
45115d3b8cb7SBill Sommerfeld if (error != 0)
45125d3b8cb7SBill Sommerfeld return (error);
45137c478bd9Sstevel@tonic-gate
45145d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_psa_ptr == NULL && ipsapp.ipsap_sa_ptr != NULL) {
45155d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) {
45167c478bd9Sstevel@tonic-gate /*
45177c478bd9Sstevel@tonic-gate * REFRELE the target and let the add_sa_func()
45187c478bd9Sstevel@tonic-gate * deal with updating a larval SA.
45197c478bd9Sstevel@tonic-gate */
45205d3b8cb7SBill Sommerfeld destroy_ipsa_pair(&ipsapp);
4521f4b3ec61Sdh155122 return (add_sa_func(mp, ksi, diagnostic, ns));
45227c478bd9Sstevel@tonic-gate }
45237c478bd9Sstevel@tonic-gate }
45247c478bd9Sstevel@tonic-gate
4525a1ba8781SMark Fenwick /*
4526a1ba8781SMark Fenwick * At this point we have an UPDATE to a MATURE SA. There should
4527a1ba8781SMark Fenwick * not be any keying material present.
4528a1ba8781SMark Fenwick */
4529a1ba8781SMark Fenwick if (akey != NULL) {
4530a1ba8781SMark Fenwick *diagnostic = SADB_X_DIAGNOSTIC_AKEY_PRESENT;
4531a1ba8781SMark Fenwick error = EINVAL;
4532a1ba8781SMark Fenwick goto bail;
4533a1ba8781SMark Fenwick }
4534a1ba8781SMark Fenwick if (ekey != NULL) {
4535a1ba8781SMark Fenwick *diagnostic = SADB_X_DIAGNOSTIC_EKEY_PRESENT;
4536a1ba8781SMark Fenwick error = EINVAL;
4537a1ba8781SMark Fenwick goto bail;
4538a1ba8781SMark Fenwick }
4539a1ba8781SMark Fenwick
45405d3b8cb7SBill Sommerfeld if (sq.assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE) {
45415d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_sa_ptr != NULL &&
45425d3b8cb7SBill Sommerfeld ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_IDLE) {
45435d3b8cb7SBill Sommerfeld if ((error = sadb_update_state(ipsapp.ipsap_sa_ptr,
45445d3b8cb7SBill Sommerfeld sq.assoc->sadb_sa_state, NULL)) != 0) {
45459c2c14abSThejaswini Singarajipura *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
45469c2c14abSThejaswini Singarajipura goto bail;
45479c2c14abSThejaswini Singarajipura }
45489c2c14abSThejaswini Singarajipura }
45495d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_psa_ptr != NULL &&
45505d3b8cb7SBill Sommerfeld ipsapp.ipsap_psa_ptr->ipsa_state == IPSA_STATE_IDLE) {
45515d3b8cb7SBill Sommerfeld if ((error = sadb_update_state(ipsapp.ipsap_psa_ptr,
45525d3b8cb7SBill Sommerfeld sq.assoc->sadb_sa_state, NULL)) != 0) {
45539c2c14abSThejaswini Singarajipura *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
45549c2c14abSThejaswini Singarajipura goto bail;
45559c2c14abSThejaswini Singarajipura }
45569c2c14abSThejaswini Singarajipura }
45579c2c14abSThejaswini Singarajipura }
45585d3b8cb7SBill Sommerfeld if (sq.assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE) {
45595d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_sa_ptr != NULL) {
45605d3b8cb7SBill Sommerfeld error = sadb_update_state(ipsapp.ipsap_sa_ptr,
45615d3b8cb7SBill Sommerfeld sq.assoc->sadb_sa_state,
45625d3b8cb7SBill Sommerfeld (ipsapp.ipsap_sa_ptr->ipsa_flags &
45639c2c14abSThejaswini Singarajipura IPSA_F_INBOUND) ? ipkt_lst : NULL);
45649c2c14abSThejaswini Singarajipura if (error) {
45659c2c14abSThejaswini Singarajipura *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
45669c2c14abSThejaswini Singarajipura goto bail;
45679c2c14abSThejaswini Singarajipura }
45689c2c14abSThejaswini Singarajipura }
45695d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_psa_ptr != NULL) {
45705d3b8cb7SBill Sommerfeld error = sadb_update_state(ipsapp.ipsap_psa_ptr,
45715d3b8cb7SBill Sommerfeld sq.assoc->sadb_sa_state,
45725d3b8cb7SBill Sommerfeld (ipsapp.ipsap_psa_ptr->ipsa_flags &
45739c2c14abSThejaswini Singarajipura IPSA_F_INBOUND) ? ipkt_lst : NULL);
45749c2c14abSThejaswini Singarajipura if (error) {
45759c2c14abSThejaswini Singarajipura *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
45769c2c14abSThejaswini Singarajipura goto bail;
45779c2c14abSThejaswini Singarajipura }
45789c2c14abSThejaswini Singarajipura }
45799c2c14abSThejaswini Singarajipura sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
45809c2c14abSThejaswini Singarajipura ksi, echo_target);
45819c2c14abSThejaswini Singarajipura goto bail;
45829c2c14abSThejaswini Singarajipura }
45839c2c14abSThejaswini Singarajipura
45847c478bd9Sstevel@tonic-gate /*
45857c478bd9Sstevel@tonic-gate * Reality checks for updates of active associations.
45867c478bd9Sstevel@tonic-gate * Sundry first-pass UPDATE-specific reality checks.
45877c478bd9Sstevel@tonic-gate * Have to do the checks here, because it's after the add_sa code.
45887c478bd9Sstevel@tonic-gate * XXX STATS : logging/stats here?
45897c478bd9Sstevel@tonic-gate */
45907c478bd9Sstevel@tonic-gate
45915d3b8cb7SBill Sommerfeld if (!((sq.assoc->sadb_sa_state == SADB_SASTATE_MATURE) ||
45925d3b8cb7SBill Sommerfeld (sq.assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE))) {
45937c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
45947c478bd9Sstevel@tonic-gate error = EINVAL;
45957c478bd9Sstevel@tonic-gate goto bail;
45967c478bd9Sstevel@tonic-gate }
45975d3b8cb7SBill Sommerfeld if (sq.assoc->sadb_sa_flags & ~spp->s_updateflags) {
45987c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS;
45997c478bd9Sstevel@tonic-gate error = EINVAL;
46007c478bd9Sstevel@tonic-gate goto bail;
46017c478bd9Sstevel@tonic-gate }
46027c478bd9Sstevel@tonic-gate if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL) {
4603a1ba8781SMark Fenwick *diagnostic = SADB_X_DIAGNOSTIC_MISSING_LIFETIME;
46047c478bd9Sstevel@tonic-gate error = EOPNOTSUPP;
46057c478bd9Sstevel@tonic-gate goto bail;
46067c478bd9Sstevel@tonic-gate }
46079c2c14abSThejaswini Singarajipura
46089c2c14abSThejaswini Singarajipura if ((*diagnostic = sadb_hardsoftchk(hard, soft, idle)) != 0) {
46097c478bd9Sstevel@tonic-gate error = EINVAL;
46107c478bd9Sstevel@tonic-gate goto bail;
46117c478bd9Sstevel@tonic-gate }
46127c478bd9Sstevel@tonic-gate
46135d3b8cb7SBill Sommerfeld if ((*diagnostic = sadb_labelchk(ksi)) != 0)
46145d3b8cb7SBill Sommerfeld return (EINVAL);
46155d3b8cb7SBill Sommerfeld
46165d3b8cb7SBill Sommerfeld error = sadb_check_kmc(&sq, ipsapp.ipsap_sa_ptr, diagnostic);
46175d3b8cb7SBill Sommerfeld if (error != 0)
46187c478bd9Sstevel@tonic-gate goto bail;
46195d3b8cb7SBill Sommerfeld
46205d3b8cb7SBill Sommerfeld error = sadb_check_kmc(&sq, ipsapp.ipsap_psa_ptr, diagnostic);
46215d3b8cb7SBill Sommerfeld if (error != 0)
46227c478bd9Sstevel@tonic-gate goto bail;
46235d3b8cb7SBill Sommerfeld
46245d3b8cb7SBill Sommerfeld
46255d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_sa_ptr != NULL) {
46269c2c14abSThejaswini Singarajipura /*
46279c2c14abSThejaswini Singarajipura * Do not allow replay value change for MATURE or LARVAL SA.
46289c2c14abSThejaswini Singarajipura */
46299c2c14abSThejaswini Singarajipura
46309c2c14abSThejaswini Singarajipura if ((replext != NULL) &&
46315d3b8cb7SBill Sommerfeld ((ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) ||
46325d3b8cb7SBill Sommerfeld (ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_MATURE))) {
46339c2c14abSThejaswini Singarajipura *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
46349c2c14abSThejaswini Singarajipura error = EINVAL;
46359c2c14abSThejaswini Singarajipura goto bail;
46369c2c14abSThejaswini Singarajipura }
46377c478bd9Sstevel@tonic-gate }
46387c478bd9Sstevel@tonic-gate
46397c478bd9Sstevel@tonic-gate
46405d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_sa_ptr != NULL) {
46415d3b8cb7SBill Sommerfeld sadb_update_lifetimes(ipsapp.ipsap_sa_ptr, hard, soft,
46429c2c14abSThejaswini Singarajipura idle, B_TRUE);
46435d3b8cb7SBill Sommerfeld sadb_update_kmc(&sq, ipsapp.ipsap_sa_ptr);
46449c2c14abSThejaswini Singarajipura if ((replext != NULL) &&
46455d3b8cb7SBill Sommerfeld (ipsapp.ipsap_sa_ptr->ipsa_replay_wsize != 0)) {
46469c2c14abSThejaswini Singarajipura /*
46479c2c14abSThejaswini Singarajipura * If an inbound SA, update the replay counter
46489c2c14abSThejaswini Singarajipura * and check off all the other sequence number
46499c2c14abSThejaswini Singarajipura */
46509c2c14abSThejaswini Singarajipura if (ksi->ks_in_dsttype == KS_IN_ADDR_ME) {
46515d3b8cb7SBill Sommerfeld if (!sadb_replay_check(ipsapp.ipsap_sa_ptr,
46529c2c14abSThejaswini Singarajipura replext->sadb_x_rc_replay32)) {
4653a1ba8781SMark Fenwick *diagnostic =
4654a1ba8781SMark Fenwick SADB_X_DIAGNOSTIC_INVALID_REPLAY;
46559c2c14abSThejaswini Singarajipura error = EINVAL;
46569c2c14abSThejaswini Singarajipura goto bail;
46579c2c14abSThejaswini Singarajipura }
46585d3b8cb7SBill Sommerfeld mutex_enter(&ipsapp.ipsap_sa_ptr->ipsa_lock);
46595d3b8cb7SBill Sommerfeld ipsapp.ipsap_sa_ptr->ipsa_idleexpiretime =
46609c2c14abSThejaswini Singarajipura current +
46615d3b8cb7SBill Sommerfeld ipsapp.ipsap_sa_ptr->ipsa_idletime;
46625d3b8cb7SBill Sommerfeld mutex_exit(&ipsapp.ipsap_sa_ptr->ipsa_lock);
46639c2c14abSThejaswini Singarajipura } else {
46645d3b8cb7SBill Sommerfeld mutex_enter(&ipsapp.ipsap_sa_ptr->ipsa_lock);
46655d3b8cb7SBill Sommerfeld ipsapp.ipsap_sa_ptr->ipsa_replay =
46669c2c14abSThejaswini Singarajipura replext->sadb_x_rc_replay32;
46675d3b8cb7SBill Sommerfeld ipsapp.ipsap_sa_ptr->ipsa_idleexpiretime =
46689c2c14abSThejaswini Singarajipura current +
46695d3b8cb7SBill Sommerfeld ipsapp.ipsap_sa_ptr->ipsa_idletime;
46705d3b8cb7SBill Sommerfeld mutex_exit(&ipsapp.ipsap_sa_ptr->ipsa_lock);
46719c2c14abSThejaswini Singarajipura }
46729c2c14abSThejaswini Singarajipura }
46737c478bd9Sstevel@tonic-gate }
46747c478bd9Sstevel@tonic-gate
467538d95a78Smarkfen if (sadb_msg_type == SADB_X_UPDATEPAIR) {
46765d3b8cb7SBill Sommerfeld if (ipsapp.ipsap_psa_ptr != NULL) {
46775d3b8cb7SBill Sommerfeld sadb_update_lifetimes(ipsapp.ipsap_psa_ptr, hard, soft,
46789c2c14abSThejaswini Singarajipura idle, B_FALSE);
46795d3b8cb7SBill Sommerfeld sadb_update_kmc(&sq, ipsapp.ipsap_psa_ptr);
468038d95a78Smarkfen } else {
468138d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
468238d95a78Smarkfen error = ESRCH;
468338d95a78Smarkfen goto bail;
468438d95a78Smarkfen }
46857c478bd9Sstevel@tonic-gate }
46867c478bd9Sstevel@tonic-gate
468738d95a78Smarkfen if (pair_ext != NULL)
46885d3b8cb7SBill Sommerfeld error = update_pairing(&ipsapp, &sq, ksi, diagnostic);
468938d95a78Smarkfen
469038d95a78Smarkfen if (error == 0)
46917c478bd9Sstevel@tonic-gate sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
469238d95a78Smarkfen ksi, echo_target);
46937c478bd9Sstevel@tonic-gate bail:
469438d95a78Smarkfen
46955d3b8cb7SBill Sommerfeld destroy_ipsa_pair(&ipsapp);
469638d95a78Smarkfen
469738d95a78Smarkfen return (error);
46987c478bd9Sstevel@tonic-gate }
46997c478bd9Sstevel@tonic-gate
470038d95a78Smarkfen
47015d3b8cb7SBill Sommerfeld static int
47025d3b8cb7SBill Sommerfeld update_pairing(ipsap_t *ipsapp, ipsa_query_t *sq, keysock_in_t *ksi,
47035d3b8cb7SBill Sommerfeld int *diagnostic)
470438d95a78Smarkfen {
470538d95a78Smarkfen sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
470638d95a78Smarkfen sadb_x_pair_t *pair_ext =
470738d95a78Smarkfen (sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
470838d95a78Smarkfen int error = 0;
47095d3b8cb7SBill Sommerfeld ipsap_t oipsapp;
471038d95a78Smarkfen boolean_t undo_pair = B_FALSE;
471138d95a78Smarkfen uint32_t ipsa_flags;
471238d95a78Smarkfen
471338d95a78Smarkfen if (pair_ext->sadb_x_pair_spi == 0 || pair_ext->sadb_x_pair_spi ==
471438d95a78Smarkfen assoc->sadb_sa_spi) {
471538d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
471638d95a78Smarkfen return (EINVAL);
471738d95a78Smarkfen }
471838d95a78Smarkfen
471938d95a78Smarkfen /*
472038d95a78Smarkfen * Assume for now that the spi value provided in the SADB_UPDATE
472138d95a78Smarkfen * message was valid, update the SA with its pair spi value.
472238d95a78Smarkfen * If the spi turns out to be bogus or the SA no longer exists
472338d95a78Smarkfen * then this will be detected when the reverse update is made
472438d95a78Smarkfen * below.
472538d95a78Smarkfen */
472638d95a78Smarkfen mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
472738d95a78Smarkfen ipsapp->ipsap_sa_ptr->ipsa_flags |= IPSA_F_PAIRED;
472838d95a78Smarkfen ipsapp->ipsap_sa_ptr->ipsa_otherspi = pair_ext->sadb_x_pair_spi;
472938d95a78Smarkfen mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
473038d95a78Smarkfen
473138d95a78Smarkfen /*
473238d95a78Smarkfen * After updating the ipsa_otherspi element of the SA, get_ipsa_pair()
473338d95a78Smarkfen * should now return pointers to the SA *AND* its pair, if this is not
473438d95a78Smarkfen * the case, the "otherspi" either did not exist or was deleted. Also
473538d95a78Smarkfen * check that "otherspi" is not already paired. If everything looks
473638d95a78Smarkfen * good, complete the update. IPSA_REFRELE the first pair_pointer
473738d95a78Smarkfen * after this update to ensure its not deleted until we are done.
473838d95a78Smarkfen */
47395d3b8cb7SBill Sommerfeld error = get_ipsa_pair(sq, &oipsapp, diagnostic);
47405d3b8cb7SBill Sommerfeld if (error != 0) {
474138d95a78Smarkfen /*
474238d95a78Smarkfen * This should never happen, calling function still has
474338d95a78Smarkfen * IPSA_REFHELD on the SA we just updated.
474438d95a78Smarkfen */
47455d3b8cb7SBill Sommerfeld return (error); /* XXX EINVAL instead of ESRCH? */
474638d95a78Smarkfen }
474738d95a78Smarkfen
47485d3b8cb7SBill Sommerfeld if (oipsapp.ipsap_psa_ptr == NULL) {
474938d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
4750a1ba8781SMark Fenwick error = EINVAL;
475138d95a78Smarkfen undo_pair = B_TRUE;
475238d95a78Smarkfen } else {
47535d3b8cb7SBill Sommerfeld ipsa_flags = oipsapp.ipsap_psa_ptr->ipsa_flags;
47545d3b8cb7SBill Sommerfeld if ((oipsapp.ipsap_psa_ptr->ipsa_state == IPSA_STATE_DEAD) ||
47555d3b8cb7SBill Sommerfeld (oipsapp.ipsap_psa_ptr->ipsa_state == IPSA_STATE_DYING)) {
475638d95a78Smarkfen /* Its dead Jim! */
475738d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
475838d95a78Smarkfen undo_pair = B_TRUE;
475938d95a78Smarkfen } else if ((ipsa_flags & (IPSA_F_OUTBOUND | IPSA_F_INBOUND)) ==
476038d95a78Smarkfen (IPSA_F_OUTBOUND | IPSA_F_INBOUND)) {
476138d95a78Smarkfen /* This SA is in both hashtables. */
476238d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
476338d95a78Smarkfen undo_pair = B_TRUE;
476438d95a78Smarkfen } else if (ipsa_flags & IPSA_F_PAIRED) {
476538d95a78Smarkfen /* This SA is already paired with another. */
476638d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_PAIR_ALREADY;
476738d95a78Smarkfen undo_pair = B_TRUE;
476838d95a78Smarkfen }
476938d95a78Smarkfen }
477038d95a78Smarkfen
477138d95a78Smarkfen if (undo_pair) {
477238d95a78Smarkfen /* The pair SA does not exist. */
477338d95a78Smarkfen mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
477438d95a78Smarkfen ipsapp->ipsap_sa_ptr->ipsa_flags &= ~IPSA_F_PAIRED;
477538d95a78Smarkfen ipsapp->ipsap_sa_ptr->ipsa_otherspi = 0;
477638d95a78Smarkfen mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
477738d95a78Smarkfen } else {
47785d3b8cb7SBill Sommerfeld mutex_enter(&oipsapp.ipsap_psa_ptr->ipsa_lock);
47795d3b8cb7SBill Sommerfeld oipsapp.ipsap_psa_ptr->ipsa_otherspi = assoc->sadb_sa_spi;
47805d3b8cb7SBill Sommerfeld oipsapp.ipsap_psa_ptr->ipsa_flags |= IPSA_F_PAIRED;
47815d3b8cb7SBill Sommerfeld mutex_exit(&oipsapp.ipsap_psa_ptr->ipsa_lock);
478238d95a78Smarkfen }
478338d95a78Smarkfen
47845d3b8cb7SBill Sommerfeld destroy_ipsa_pair(&oipsapp);
47857c478bd9Sstevel@tonic-gate return (error);
47867c478bd9Sstevel@tonic-gate }
47877c478bd9Sstevel@tonic-gate
47887c478bd9Sstevel@tonic-gate /*
47897c478bd9Sstevel@tonic-gate * The following functions deal with ACQUIRE LISTS. An ACQUIRE list is
47907c478bd9Sstevel@tonic-gate * a list of outstanding SADB_ACQUIRE messages. If ipsec_getassocbyconn() fails
47917c478bd9Sstevel@tonic-gate * for an outbound datagram, that datagram is queued up on an ACQUIRE record,
47927c478bd9Sstevel@tonic-gate * and an SADB_ACQUIRE message is sent up. Presumably, a user-space key
47937c478bd9Sstevel@tonic-gate * management daemon will process the ACQUIRE, use a SADB_GETSPI to reserve
47947c478bd9Sstevel@tonic-gate * an SPI value and a larval SA, then SADB_UPDATE the larval SA, and ADD the
47957c478bd9Sstevel@tonic-gate * other direction's SA.
47967c478bd9Sstevel@tonic-gate */
47977c478bd9Sstevel@tonic-gate
47987c478bd9Sstevel@tonic-gate /*
47997c478bd9Sstevel@tonic-gate * Check the ACQUIRE lists. If there's an existing ACQUIRE record,
48007c478bd9Sstevel@tonic-gate * grab it, lock it, and return it. Otherwise return NULL.
48015d3b8cb7SBill Sommerfeld *
48025d3b8cb7SBill Sommerfeld * XXX MLS number of arguments getting unwieldy here
48037c478bd9Sstevel@tonic-gate */
48047c478bd9Sstevel@tonic-gate static ipsacq_t *
48057c478bd9Sstevel@tonic-gate sadb_checkacquire(iacqf_t *bucket, ipsec_action_t *ap, ipsec_policy_t *pp,
48068810c16bSdanmcd uint32_t *src, uint32_t *dst, uint32_t *isrc, uint32_t *idst,
4807bd670b35SErik Nordmark uint64_t unique_id, ts_label_t *tsl)
48087c478bd9Sstevel@tonic-gate {
48097c478bd9Sstevel@tonic-gate ipsacq_t *walker;
48107c478bd9Sstevel@tonic-gate sa_family_t fam;
48118810c16bSdanmcd uint32_t blank_address[4] = {0, 0, 0, 0};
48128810c16bSdanmcd
48138810c16bSdanmcd if (isrc == NULL) {
48148810c16bSdanmcd ASSERT(idst == NULL);
48158810c16bSdanmcd isrc = idst = blank_address;
48168810c16bSdanmcd }
48177c478bd9Sstevel@tonic-gate
48187c478bd9Sstevel@tonic-gate /*
48197c478bd9Sstevel@tonic-gate * Scan list for duplicates. Check for UNIQUE, src/dest, policy.
48207c478bd9Sstevel@tonic-gate *
48217c478bd9Sstevel@tonic-gate * XXX May need search for duplicates based on other things too!
48227c478bd9Sstevel@tonic-gate */
48237c478bd9Sstevel@tonic-gate for (walker = bucket->iacqf_ipsacq; walker != NULL;
48247c478bd9Sstevel@tonic-gate walker = walker->ipsacq_next) {
48257c478bd9Sstevel@tonic-gate mutex_enter(&walker->ipsacq_lock);
48267c478bd9Sstevel@tonic-gate fam = walker->ipsacq_addrfam;
48277c478bd9Sstevel@tonic-gate if (IPSA_ARE_ADDR_EQUAL(dst, walker->ipsacq_dstaddr, fam) &&
48287c478bd9Sstevel@tonic-gate IPSA_ARE_ADDR_EQUAL(src, walker->ipsacq_srcaddr, fam) &&
48298810c16bSdanmcd ip_addr_match((uint8_t *)isrc, walker->ipsacq_innersrcpfx,
48308810c16bSdanmcd (in6_addr_t *)walker->ipsacq_innersrc) &&
48318810c16bSdanmcd ip_addr_match((uint8_t *)idst, walker->ipsacq_innerdstpfx,
48328810c16bSdanmcd (in6_addr_t *)walker->ipsacq_innerdst) &&
48337c478bd9Sstevel@tonic-gate (ap == walker->ipsacq_act) &&
48347c478bd9Sstevel@tonic-gate (pp == walker->ipsacq_policy) &&
48357c478bd9Sstevel@tonic-gate /* XXX do deep compares of ap/pp? */
48365d3b8cb7SBill Sommerfeld (unique_id == walker->ipsacq_unique_id) &&
4837bd670b35SErik Nordmark (ipsec_label_match(tsl, walker->ipsacq_tsl)))
48387c478bd9Sstevel@tonic-gate break; /* everything matched */
48397c478bd9Sstevel@tonic-gate mutex_exit(&walker->ipsacq_lock);
48407c478bd9Sstevel@tonic-gate }
48417c478bd9Sstevel@tonic-gate
48427c478bd9Sstevel@tonic-gate return (walker);
48437c478bd9Sstevel@tonic-gate }
48447c478bd9Sstevel@tonic-gate
48457c478bd9Sstevel@tonic-gate /*
48467c478bd9Sstevel@tonic-gate * For this mblk, insert a new acquire record. Assume bucket contains addrs
48477c478bd9Sstevel@tonic-gate * of all of the same length. Give up (and drop) if memory
48487c478bd9Sstevel@tonic-gate * cannot be allocated for a new one; otherwise, invoke callback to
48497c478bd9Sstevel@tonic-gate * send the acquire up..
48507c478bd9Sstevel@tonic-gate *
48517c478bd9Sstevel@tonic-gate * In cases where we need both AH and ESP, add the SA to the ESP ACQUIRE
4852bd670b35SErik Nordmark * list. The ah_add_sa_finish() routines can look at the packet's attached
4853bd670b35SErik Nordmark * attributes and handle this case specially.
48547c478bd9Sstevel@tonic-gate */
48557c478bd9Sstevel@tonic-gate void
4856bd670b35SErik Nordmark sadb_acquire(mblk_t *datamp, ip_xmit_attr_t *ixa, boolean_t need_ah,
4857bd670b35SErik Nordmark boolean_t need_esp)
48587c478bd9Sstevel@tonic-gate {
4859bd670b35SErik Nordmark mblk_t *asyncmp;
48607c478bd9Sstevel@tonic-gate sadbp_t *spp;
48617c478bd9Sstevel@tonic-gate sadb_t *sp;
48627c478bd9Sstevel@tonic-gate ipsacq_t *newbie;
48637c478bd9Sstevel@tonic-gate iacqf_t *bucket;
48647c478bd9Sstevel@tonic-gate mblk_t *extended;
48657c478bd9Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)datamp->b_rptr;
48667c478bd9Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)datamp->b_rptr;
48678810c16bSdanmcd uint32_t *src, *dst, *isrc, *idst;
4868bd670b35SErik Nordmark ipsec_policy_t *pp = ixa->ixa_ipsec_policy;
4869bd670b35SErik Nordmark ipsec_action_t *ap = ixa->ixa_ipsec_action;
48707c478bd9Sstevel@tonic-gate sa_family_t af;
48717c478bd9Sstevel@tonic-gate int hashoffset;
48727c478bd9Sstevel@tonic-gate uint32_t seq;
48737c478bd9Sstevel@tonic-gate uint64_t unique_id = 0;
48747c478bd9Sstevel@tonic-gate ipsec_selector_t sel;
4875bd670b35SErik Nordmark boolean_t tunnel_mode = (ixa->ixa_flags & IXAF_IPSEC_TUNNEL) != 0;
4876bd670b35SErik Nordmark ts_label_t *tsl = NULL;
4877bd670b35SErik Nordmark netstack_t *ns = ixa->ixa_ipst->ips_netstack;
4878f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec;
48795d3b8cb7SBill Sommerfeld sadb_sens_t *sens = NULL;
48805d3b8cb7SBill Sommerfeld int sens_len;
48817c478bd9Sstevel@tonic-gate
48827c478bd9Sstevel@tonic-gate ASSERT((pp != NULL) || (ap != NULL));
48837c478bd9Sstevel@tonic-gate
48847c478bd9Sstevel@tonic-gate ASSERT(need_ah != NULL || need_esp != NULL);
48855d3b8cb7SBill Sommerfeld
48867c478bd9Sstevel@tonic-gate /* Assign sadb pointers */
4887f4b3ec61Sdh155122 if (need_esp) { /* ESP for AH+ESP */
4888f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
4889f4b3ec61Sdh155122
4890f4b3ec61Sdh155122 spp = &espstack->esp_sadb;
4891f4b3ec61Sdh155122 } else {
4892f4b3ec61Sdh155122 ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
4893f4b3ec61Sdh155122
4894f4b3ec61Sdh155122 spp = &ahstack->ah_sadb;
4895f4b3ec61Sdh155122 }
4896bd670b35SErik Nordmark sp = (ixa->ixa_flags & IXAF_IS_IPV4) ? &spp->s_v4 : &spp->s_v6;
48975d3b8cb7SBill Sommerfeld
48985d3b8cb7SBill Sommerfeld if (is_system_labeled())
4899bd670b35SErik Nordmark tsl = ixa->ixa_tsl;
49005d3b8cb7SBill Sommerfeld
49017c478bd9Sstevel@tonic-gate if (ap == NULL)
49027c478bd9Sstevel@tonic-gate ap = pp->ipsp_act;
49037c478bd9Sstevel@tonic-gate
49047c478bd9Sstevel@tonic-gate ASSERT(ap != NULL);
49057c478bd9Sstevel@tonic-gate
49068810c16bSdanmcd if (ap->ipa_act.ipa_apply.ipp_use_unique || tunnel_mode)
4907bd670b35SErik Nordmark unique_id = SA_FORM_UNIQUE_ID(ixa);
49087c478bd9Sstevel@tonic-gate
49097c478bd9Sstevel@tonic-gate /*
49107c478bd9Sstevel@tonic-gate * Set up an ACQUIRE record.
49117c478bd9Sstevel@tonic-gate *
49127c478bd9Sstevel@tonic-gate * Immediately, make sure the ACQUIRE sequence number doesn't slip
49137c478bd9Sstevel@tonic-gate * below the lowest point allowed in the kernel. (In other words,
49147c478bd9Sstevel@tonic-gate * make sure the high bit on the sequence number is set.)
49157c478bd9Sstevel@tonic-gate */
49167c478bd9Sstevel@tonic-gate
4917f4b3ec61Sdh155122 seq = keysock_next_seq(ns) | IACQF_LOWEST_SEQ;
49187c478bd9Sstevel@tonic-gate
49197c478bd9Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IP_VERSION) {
49207c478bd9Sstevel@tonic-gate src = (uint32_t *)&ipha->ipha_src;
49217c478bd9Sstevel@tonic-gate dst = (uint32_t *)&ipha->ipha_dst;
49227c478bd9Sstevel@tonic-gate af = AF_INET;
4923fb87b5d2Ssommerfe hashoffset = OUTBOUND_HASH_V4(sp, ipha->ipha_dst);
4924bd670b35SErik Nordmark ASSERT(ixa->ixa_flags & IXAF_IS_IPV4);
49257c478bd9Sstevel@tonic-gate } else {
49267c478bd9Sstevel@tonic-gate ASSERT(IPH_HDR_VERSION(ipha) == IPV6_VERSION);
49277c478bd9Sstevel@tonic-gate src = (uint32_t *)&ip6h->ip6_src;
49287c478bd9Sstevel@tonic-gate dst = (uint32_t *)&ip6h->ip6_dst;
49297c478bd9Sstevel@tonic-gate af = AF_INET6;
4930fb87b5d2Ssommerfe hashoffset = OUTBOUND_HASH_V6(sp, ip6h->ip6_dst);
4931bd670b35SErik Nordmark ASSERT(!(ixa->ixa_flags & IXAF_IS_IPV4));
49327c478bd9Sstevel@tonic-gate }
49337c478bd9Sstevel@tonic-gate
49348810c16bSdanmcd if (tunnel_mode) {
49357807385bSDan McDonald if (pp == NULL) {
49367807385bSDan McDonald /*
49377807385bSDan McDonald * Tunnel mode with no policy pointer means this is a
49387807385bSDan McDonald * reflected ICMP (like a ECHO REQUEST) that came in
49397807385bSDan McDonald * with self-encapsulated protection. Until we better
49407807385bSDan McDonald * support this, drop the packet.
49417807385bSDan McDonald */
4942bd670b35SErik Nordmark ip_drop_packet(datamp, B_FALSE, NULL,
49437807385bSDan McDonald DROPPER(ipss, ipds_spd_got_selfencap),
49447807385bSDan McDonald &ipss->ipsec_spd_dropper);
49457807385bSDan McDonald return;
49467807385bSDan McDonald }
49478810c16bSdanmcd /* Snag inner addresses. */
4948bd670b35SErik Nordmark isrc = ixa->ixa_ipsec_insrc;
4949bd670b35SErik Nordmark idst = ixa->ixa_ipsec_indst;
49508810c16bSdanmcd } else {
49518810c16bSdanmcd isrc = idst = NULL;
49528810c16bSdanmcd }
49538810c16bSdanmcd
49547c478bd9Sstevel@tonic-gate /*
49557c478bd9Sstevel@tonic-gate * Check buckets to see if there is an existing entry. If so,
49567c478bd9Sstevel@tonic-gate * grab it. sadb_checkacquire locks newbie if found.
49577c478bd9Sstevel@tonic-gate */
49587c478bd9Sstevel@tonic-gate bucket = &(sp->sdb_acq[hashoffset]);
49597c478bd9Sstevel@tonic-gate mutex_enter(&bucket->iacqf_lock);
49608810c16bSdanmcd newbie = sadb_checkacquire(bucket, ap, pp, src, dst, isrc, idst,
4961bd670b35SErik Nordmark unique_id, tsl);
49627c478bd9Sstevel@tonic-gate
49637c478bd9Sstevel@tonic-gate if (newbie == NULL) {
49647c478bd9Sstevel@tonic-gate /*
49657c478bd9Sstevel@tonic-gate * Otherwise, allocate a new one.
49667c478bd9Sstevel@tonic-gate */
49677c478bd9Sstevel@tonic-gate newbie = kmem_zalloc(sizeof (*newbie), KM_NOSLEEP);
49687c478bd9Sstevel@tonic-gate if (newbie == NULL) {
49697c478bd9Sstevel@tonic-gate mutex_exit(&bucket->iacqf_lock);
4970bd670b35SErik Nordmark ip_drop_packet(datamp, B_FALSE, NULL,
4971f4b3ec61Sdh155122 DROPPER(ipss, ipds_sadb_acquire_nomem),
4972f4b3ec61Sdh155122 &ipss->ipsec_sadb_dropper);
49737c478bd9Sstevel@tonic-gate return;
49747c478bd9Sstevel@tonic-gate }
49757c478bd9Sstevel@tonic-gate newbie->ipsacq_policy = pp;
49767c478bd9Sstevel@tonic-gate if (pp != NULL) {
49777c478bd9Sstevel@tonic-gate IPPOL_REFHOLD(pp);
49787c478bd9Sstevel@tonic-gate }
49797c478bd9Sstevel@tonic-gate IPACT_REFHOLD(ap);
49807c478bd9Sstevel@tonic-gate newbie->ipsacq_act = ap;
49817c478bd9Sstevel@tonic-gate newbie->ipsacq_linklock = &bucket->iacqf_lock;
49827c478bd9Sstevel@tonic-gate newbie->ipsacq_next = bucket->iacqf_ipsacq;
49837c478bd9Sstevel@tonic-gate newbie->ipsacq_ptpn = &bucket->iacqf_ipsacq;
49847c478bd9Sstevel@tonic-gate if (newbie->ipsacq_next != NULL)
49857c478bd9Sstevel@tonic-gate newbie->ipsacq_next->ipsacq_ptpn = &newbie->ipsacq_next;
49865d3b8cb7SBill Sommerfeld
49877c478bd9Sstevel@tonic-gate bucket->iacqf_ipsacq = newbie;
49887c478bd9Sstevel@tonic-gate mutex_init(&newbie->ipsacq_lock, NULL, MUTEX_DEFAULT, NULL);
49897c478bd9Sstevel@tonic-gate mutex_enter(&newbie->ipsacq_lock);
49907c478bd9Sstevel@tonic-gate }
49917c478bd9Sstevel@tonic-gate
49925d3b8cb7SBill Sommerfeld /*
49935d3b8cb7SBill Sommerfeld * XXX MLS does it actually help us to drop the bucket lock here?
49945d3b8cb7SBill Sommerfeld * we have inserted a half-built, locked acquire record into the
49955d3b8cb7SBill Sommerfeld * bucket. any competing thread will now be able to lock the bucket
49965d3b8cb7SBill Sommerfeld * to scan it, but will immediately pile up on the new acquire
49975d3b8cb7SBill Sommerfeld * record's lock; I don't think we gain anything here other than to
49985d3b8cb7SBill Sommerfeld * disperse blame for lock contention.
49995d3b8cb7SBill Sommerfeld *
50005d3b8cb7SBill Sommerfeld * we might be able to dispense with acquire record locks entirely..
50015d3b8cb7SBill Sommerfeld * just use the bucket locks..
50025d3b8cb7SBill Sommerfeld */
50035d3b8cb7SBill Sommerfeld
50047c478bd9Sstevel@tonic-gate mutex_exit(&bucket->iacqf_lock);
50057c478bd9Sstevel@tonic-gate
50067c478bd9Sstevel@tonic-gate /*
50077c478bd9Sstevel@tonic-gate * This assert looks silly for now, but we may need to enter newbie's
50087c478bd9Sstevel@tonic-gate * mutex during a search.
50097c478bd9Sstevel@tonic-gate */
50107c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&newbie->ipsacq_lock));
50117c478bd9Sstevel@tonic-gate
5012bd670b35SErik Nordmark /*
5013bd670b35SErik Nordmark * Make the ip_xmit_attr_t into something we can queue.
5014bd670b35SErik Nordmark * If no memory it frees datamp.
5015bd670b35SErik Nordmark */
5016bd670b35SErik Nordmark asyncmp = ip_xmit_attr_to_mblk(ixa);
5017bd670b35SErik Nordmark if (asyncmp != NULL)
5018bd670b35SErik Nordmark linkb(asyncmp, datamp);
5019bd670b35SErik Nordmark
50207c478bd9Sstevel@tonic-gate /* Queue up packet. Use b_next. */
5021bd670b35SErik Nordmark
5022bd670b35SErik Nordmark if (asyncmp == NULL) {
5023bd670b35SErik Nordmark /* Statistics for allocation failure */
5024bd670b35SErik Nordmark if (ixa->ixa_flags & IXAF_IS_IPV4) {
5025bd670b35SErik Nordmark BUMP_MIB(&ixa->ixa_ipst->ips_ip_mib,
5026bd670b35SErik Nordmark ipIfStatsOutDiscards);
5027bd670b35SErik Nordmark } else {
5028bd670b35SErik Nordmark BUMP_MIB(&ixa->ixa_ipst->ips_ip6_mib,
5029bd670b35SErik Nordmark ipIfStatsOutDiscards);
5030bd670b35SErik Nordmark }
5031bd670b35SErik Nordmark ip_drop_output("No memory for asyncmp", datamp, NULL);
5032bd670b35SErik Nordmark freemsg(datamp);
5033bd670b35SErik Nordmark } else if (newbie->ipsacq_numpackets == 0) {
50347c478bd9Sstevel@tonic-gate /* First one. */
5035bd670b35SErik Nordmark newbie->ipsacq_mp = asyncmp;
50367c478bd9Sstevel@tonic-gate newbie->ipsacq_numpackets = 1;
5037437220cdSdanmcd newbie->ipsacq_expire = gethrestime_sec();
50387c478bd9Sstevel@tonic-gate /*
50397c478bd9Sstevel@tonic-gate * Extended ACQUIRE with both AH+ESP will use ESP's timeout
50407c478bd9Sstevel@tonic-gate * value.
50417c478bd9Sstevel@tonic-gate */
50427c478bd9Sstevel@tonic-gate newbie->ipsacq_expire += *spp->s_acquire_timeout;
50437c478bd9Sstevel@tonic-gate newbie->ipsacq_seq = seq;
50447c478bd9Sstevel@tonic-gate newbie->ipsacq_addrfam = af;
50457c478bd9Sstevel@tonic-gate
5046bd670b35SErik Nordmark newbie->ipsacq_srcport = ixa->ixa_ipsec_src_port;
5047bd670b35SErik Nordmark newbie->ipsacq_dstport = ixa->ixa_ipsec_dst_port;
5048bd670b35SErik Nordmark newbie->ipsacq_icmp_type = ixa->ixa_ipsec_icmp_type;
5049bd670b35SErik Nordmark newbie->ipsacq_icmp_code = ixa->ixa_ipsec_icmp_code;
50508810c16bSdanmcd if (tunnel_mode) {
5051bd670b35SErik Nordmark newbie->ipsacq_inneraddrfam = ixa->ixa_ipsec_inaf;
5052bd670b35SErik Nordmark newbie->ipsacq_proto = ixa->ixa_ipsec_inaf == AF_INET6 ?
50538810c16bSdanmcd IPPROTO_IPV6 : IPPROTO_ENCAP;
5054bd670b35SErik Nordmark newbie->ipsacq_innersrcpfx = ixa->ixa_ipsec_insrcpfx;
5055bd670b35SErik Nordmark newbie->ipsacq_innerdstpfx = ixa->ixa_ipsec_indstpfx;
50568810c16bSdanmcd IPSA_COPY_ADDR(newbie->ipsacq_innersrc,
5057bd670b35SErik Nordmark ixa->ixa_ipsec_insrc, ixa->ixa_ipsec_inaf);
50588810c16bSdanmcd IPSA_COPY_ADDR(newbie->ipsacq_innerdst,
5059bd670b35SErik Nordmark ixa->ixa_ipsec_indst, ixa->ixa_ipsec_inaf);
50608810c16bSdanmcd } else {
5061bd670b35SErik Nordmark newbie->ipsacq_proto = ixa->ixa_ipsec_proto;
50628810c16bSdanmcd }
50637c478bd9Sstevel@tonic-gate newbie->ipsacq_unique_id = unique_id;
50645d3b8cb7SBill Sommerfeld
5065bd670b35SErik Nordmark if (ixa->ixa_tsl != NULL) {
5066bd670b35SErik Nordmark label_hold(ixa->ixa_tsl);
5067bd670b35SErik Nordmark newbie->ipsacq_tsl = ixa->ixa_tsl;
50685d3b8cb7SBill Sommerfeld }
50697c478bd9Sstevel@tonic-gate } else {
50707c478bd9Sstevel@tonic-gate /* Scan to the end of the list & insert. */
50717c478bd9Sstevel@tonic-gate mblk_t *lastone = newbie->ipsacq_mp;
50727c478bd9Sstevel@tonic-gate
50737c478bd9Sstevel@tonic-gate while (lastone->b_next != NULL)
50747c478bd9Sstevel@tonic-gate lastone = lastone->b_next;
5075bd670b35SErik Nordmark lastone->b_next = asyncmp;
5076bffb04cfSmarkfen if (newbie->ipsacq_numpackets++ == ipsacq_maxpackets) {
5077bffb04cfSmarkfen newbie->ipsacq_numpackets = ipsacq_maxpackets;
50787c478bd9Sstevel@tonic-gate lastone = newbie->ipsacq_mp;
50797c478bd9Sstevel@tonic-gate newbie->ipsacq_mp = lastone->b_next;
50807c478bd9Sstevel@tonic-gate lastone->b_next = NULL;
5081bd670b35SErik Nordmark
5082bd670b35SErik Nordmark /* Freeing the async message */
5083bd670b35SErik Nordmark lastone = ip_xmit_attr_free_mblk(lastone);
5084bd670b35SErik Nordmark ip_drop_packet(lastone, B_FALSE, NULL,
5085f4b3ec61Sdh155122 DROPPER(ipss, ipds_sadb_acquire_toofull),
5086f4b3ec61Sdh155122 &ipss->ipsec_sadb_dropper);
5087bffb04cfSmarkfen } else {
5088f4b3ec61Sdh155122 IP_ACQUIRE_STAT(ipss, qhiwater,
5089f4b3ec61Sdh155122 newbie->ipsacq_numpackets);
50907c478bd9Sstevel@tonic-gate }
50917c478bd9Sstevel@tonic-gate }
50927c478bd9Sstevel@tonic-gate
50937c478bd9Sstevel@tonic-gate /*
50947c478bd9Sstevel@tonic-gate * Reset addresses. Set them to the most recently added mblk chain,
50957c478bd9Sstevel@tonic-gate * so that the address pointers in the acquire record will point
50967c478bd9Sstevel@tonic-gate * at an mblk still attached to the acquire list.
50977c478bd9Sstevel@tonic-gate */
50987c478bd9Sstevel@tonic-gate
50997c478bd9Sstevel@tonic-gate newbie->ipsacq_srcaddr = src;
51007c478bd9Sstevel@tonic-gate newbie->ipsacq_dstaddr = dst;
51017c478bd9Sstevel@tonic-gate
51027c478bd9Sstevel@tonic-gate /*
51037c478bd9Sstevel@tonic-gate * If the acquire record has more than one queued packet, we've
51047c478bd9Sstevel@tonic-gate * already sent an ACQUIRE, and don't need to repeat ourself.
51057c478bd9Sstevel@tonic-gate */
51067c478bd9Sstevel@tonic-gate if (newbie->ipsacq_seq != seq || newbie->ipsacq_numpackets > 1) {
51077c478bd9Sstevel@tonic-gate /* I have an acquire outstanding already! */
51087c478bd9Sstevel@tonic-gate mutex_exit(&newbie->ipsacq_lock);
51097c478bd9Sstevel@tonic-gate return;
51107c478bd9Sstevel@tonic-gate }
51117c478bd9Sstevel@tonic-gate
51125d3b8cb7SBill Sommerfeld if (!keysock_extended_reg(ns))
51135d3b8cb7SBill Sommerfeld goto punt_extended;
51147c478bd9Sstevel@tonic-gate /*
51157c478bd9Sstevel@tonic-gate * Construct an extended ACQUIRE. There are logging
51167c478bd9Sstevel@tonic-gate * opportunities here in failure cases.
51177c478bd9Sstevel@tonic-gate */
5118188e1664SErik Nordmark bzero(&sel, sizeof (sel));
5119bd670b35SErik Nordmark sel.ips_isv4 = (ixa->ixa_flags & IXAF_IS_IPV4) != 0;
51208810c16bSdanmcd if (tunnel_mode) {
5121bd670b35SErik Nordmark sel.ips_protocol = (ixa->ixa_ipsec_inaf == AF_INET) ?
51228810c16bSdanmcd IPPROTO_ENCAP : IPPROTO_IPV6;
51238810c16bSdanmcd } else {
5124bd670b35SErik Nordmark sel.ips_protocol = ixa->ixa_ipsec_proto;
5125bd670b35SErik Nordmark sel.ips_local_port = ixa->ixa_ipsec_src_port;
5126bd670b35SErik Nordmark sel.ips_remote_port = ixa->ixa_ipsec_dst_port;
51278810c16bSdanmcd }
5128bd670b35SErik Nordmark sel.ips_icmp_type = ixa->ixa_ipsec_icmp_type;
5129bd670b35SErik Nordmark sel.ips_icmp_code = ixa->ixa_ipsec_icmp_code;
51308810c16bSdanmcd sel.ips_is_icmp_inv_acq = 0;
51318810c16bSdanmcd if (af == AF_INET) {
51328810c16bSdanmcd sel.ips_local_addr_v4 = ipha->ipha_src;
51338810c16bSdanmcd sel.ips_remote_addr_v4 = ipha->ipha_dst;
51348810c16bSdanmcd } else {
51358810c16bSdanmcd sel.ips_local_addr_v6 = ip6h->ip6_src;
51368810c16bSdanmcd sel.ips_remote_addr_v6 = ip6h->ip6_dst;
51378810c16bSdanmcd }
51388810c16bSdanmcd
51397c478bd9Sstevel@tonic-gate extended = sadb_keysock_out(0);
51405d3b8cb7SBill Sommerfeld if (extended == NULL)
51415d3b8cb7SBill Sommerfeld goto punt_extended;
51425d3b8cb7SBill Sommerfeld
5143bd670b35SErik Nordmark if (ixa->ixa_tsl != NULL) {
51445d3b8cb7SBill Sommerfeld /*
51455d3b8cb7SBill Sommerfeld * XXX MLS correct condition here?
51465d3b8cb7SBill Sommerfeld * XXX MLS other credential attributes in acquire?
51475d3b8cb7SBill Sommerfeld * XXX malloc failure? don't fall back to original?
51485d3b8cb7SBill Sommerfeld */
5149bd670b35SErik Nordmark sens = sadb_make_sens_ext(ixa->ixa_tsl, &sens_len);
51505d3b8cb7SBill Sommerfeld
51515d3b8cb7SBill Sommerfeld if (sens == NULL) {
51525d3b8cb7SBill Sommerfeld freeb(extended);
51535d3b8cb7SBill Sommerfeld goto punt_extended;
51545d3b8cb7SBill Sommerfeld }
51555d3b8cb7SBill Sommerfeld }
51565d3b8cb7SBill Sommerfeld
51575d3b8cb7SBill Sommerfeld extended->b_cont = sadb_extended_acquire(&sel, pp, ap, tunnel_mode,
51585d3b8cb7SBill Sommerfeld seq, 0, sens, ns);
51595d3b8cb7SBill Sommerfeld
51605d3b8cb7SBill Sommerfeld if (sens != NULL)
51615d3b8cb7SBill Sommerfeld kmem_free(sens, sens_len);
51625d3b8cb7SBill Sommerfeld
51637c478bd9Sstevel@tonic-gate if (extended->b_cont == NULL) {
51647c478bd9Sstevel@tonic-gate freeb(extended);
51655d3b8cb7SBill Sommerfeld goto punt_extended;
51667c478bd9Sstevel@tonic-gate }
51677c478bd9Sstevel@tonic-gate
51687c478bd9Sstevel@tonic-gate /*
51697c478bd9Sstevel@tonic-gate * Send an ACQUIRE message (and possible an extended ACQUIRE) based on
51707c478bd9Sstevel@tonic-gate * this new record. The send-acquire callback assumes that acqrec is
51717c478bd9Sstevel@tonic-gate * already locked.
51727c478bd9Sstevel@tonic-gate */
5173f4b3ec61Sdh155122 (*spp->s_acqfn)(newbie, extended, ns);
51745d3b8cb7SBill Sommerfeld return;
51755d3b8cb7SBill Sommerfeld
51765d3b8cb7SBill Sommerfeld punt_extended:
51775d3b8cb7SBill Sommerfeld (*spp->s_acqfn)(newbie, NULL, ns);
51787c478bd9Sstevel@tonic-gate }
51797c478bd9Sstevel@tonic-gate
51807c478bd9Sstevel@tonic-gate /*
51817c478bd9Sstevel@tonic-gate * Unlink and free an acquire record.
51827c478bd9Sstevel@tonic-gate */
51837c478bd9Sstevel@tonic-gate void
5184f4b3ec61Sdh155122 sadb_destroy_acquire(ipsacq_t *acqrec, netstack_t *ns)
51857c478bd9Sstevel@tonic-gate {
51867c478bd9Sstevel@tonic-gate mblk_t *mp;
5187f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec;
51887c478bd9Sstevel@tonic-gate
51897c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(acqrec->ipsacq_linklock));
51907c478bd9Sstevel@tonic-gate
51917c478bd9Sstevel@tonic-gate if (acqrec->ipsacq_policy != NULL) {
5192bd670b35SErik Nordmark IPPOL_REFRELE(acqrec->ipsacq_policy);
51937c478bd9Sstevel@tonic-gate }
51947c478bd9Sstevel@tonic-gate if (acqrec->ipsacq_act != NULL) {
51957c478bd9Sstevel@tonic-gate IPACT_REFRELE(acqrec->ipsacq_act);
51967c478bd9Sstevel@tonic-gate }
51977c478bd9Sstevel@tonic-gate
51987c478bd9Sstevel@tonic-gate /* Unlink */
51997c478bd9Sstevel@tonic-gate *(acqrec->ipsacq_ptpn) = acqrec->ipsacq_next;
52007c478bd9Sstevel@tonic-gate if (acqrec->ipsacq_next != NULL)
52017c478bd9Sstevel@tonic-gate acqrec->ipsacq_next->ipsacq_ptpn = acqrec->ipsacq_ptpn;
52027c478bd9Sstevel@tonic-gate
5203bd670b35SErik Nordmark if (acqrec->ipsacq_tsl != NULL) {
5204bd670b35SErik Nordmark label_rele(acqrec->ipsacq_tsl);
5205bd670b35SErik Nordmark acqrec->ipsacq_tsl = NULL;
52065d3b8cb7SBill Sommerfeld }
52075d3b8cb7SBill Sommerfeld
52087c478bd9Sstevel@tonic-gate /*
52097c478bd9Sstevel@tonic-gate * Free hanging mp's.
52107c478bd9Sstevel@tonic-gate *
52117c478bd9Sstevel@tonic-gate * XXX Instead of freemsg(), perhaps use IPSEC_REQ_FAILED.
52127c478bd9Sstevel@tonic-gate */
52137c478bd9Sstevel@tonic-gate
52147c478bd9Sstevel@tonic-gate mutex_enter(&acqrec->ipsacq_lock);
52157c478bd9Sstevel@tonic-gate while (acqrec->ipsacq_mp != NULL) {
52167c478bd9Sstevel@tonic-gate mp = acqrec->ipsacq_mp;
52177c478bd9Sstevel@tonic-gate acqrec->ipsacq_mp = mp->b_next;
52187c478bd9Sstevel@tonic-gate mp->b_next = NULL;
5219bd670b35SErik Nordmark /* Freeing the async message */
5220bd670b35SErik Nordmark mp = ip_xmit_attr_free_mblk(mp);
5221bd670b35SErik Nordmark ip_drop_packet(mp, B_FALSE, NULL,
5222f4b3ec61Sdh155122 DROPPER(ipss, ipds_sadb_acquire_timeout),
5223f4b3ec61Sdh155122 &ipss->ipsec_sadb_dropper);
52247c478bd9Sstevel@tonic-gate }
52257c478bd9Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock);
52267c478bd9Sstevel@tonic-gate
52277c478bd9Sstevel@tonic-gate /* Free */
52287c478bd9Sstevel@tonic-gate mutex_destroy(&acqrec->ipsacq_lock);
52297c478bd9Sstevel@tonic-gate kmem_free(acqrec, sizeof (*acqrec));
52307c478bd9Sstevel@tonic-gate }
52317c478bd9Sstevel@tonic-gate
52327c478bd9Sstevel@tonic-gate /*
52337c478bd9Sstevel@tonic-gate * Destroy an acquire list fanout.
52347c478bd9Sstevel@tonic-gate */
5235fb87b5d2Ssommerfe static void
5236f4b3ec61Sdh155122 sadb_destroy_acqlist(iacqf_t **listp, uint_t numentries, boolean_t forever,
5237f4b3ec61Sdh155122 netstack_t *ns)
52387c478bd9Sstevel@tonic-gate {
52397c478bd9Sstevel@tonic-gate int i;
5240fb87b5d2Ssommerfe iacqf_t *list = *listp;
5241fb87b5d2Ssommerfe
5242fb87b5d2Ssommerfe if (list == NULL)
5243fb87b5d2Ssommerfe return;
52447c478bd9Sstevel@tonic-gate
52457c478bd9Sstevel@tonic-gate for (i = 0; i < numentries; i++) {
52467c478bd9Sstevel@tonic-gate mutex_enter(&(list[i].iacqf_lock));
52477c478bd9Sstevel@tonic-gate while (list[i].iacqf_ipsacq != NULL)
5248f4b3ec61Sdh155122 sadb_destroy_acquire(list[i].iacqf_ipsacq, ns);
52497c478bd9Sstevel@tonic-gate mutex_exit(&(list[i].iacqf_lock));
52507c478bd9Sstevel@tonic-gate if (forever)
52517c478bd9Sstevel@tonic-gate mutex_destroy(&(list[i].iacqf_lock));
52527c478bd9Sstevel@tonic-gate }
52537c478bd9Sstevel@tonic-gate
5254fb87b5d2Ssommerfe if (forever) {
5255fb87b5d2Ssommerfe *listp = NULL;
52567c478bd9Sstevel@tonic-gate kmem_free(list, numentries * sizeof (*list));
52577c478bd9Sstevel@tonic-gate }
5258fb87b5d2Ssommerfe }
52597c478bd9Sstevel@tonic-gate
52607845d282Sdanmcd /*
52617845d282Sdanmcd * Create an algorithm descriptor for an extended ACQUIRE. Filter crypto
52627845d282Sdanmcd * framework's view of reality vs. IPsec's. EF's wins, BTW.
52637845d282Sdanmcd */
52647c478bd9Sstevel@tonic-gate static uint8_t *
52657c478bd9Sstevel@tonic-gate sadb_new_algdesc(uint8_t *start, uint8_t *limit,
52667c478bd9Sstevel@tonic-gate sadb_x_ecomb_t *ecomb, uint8_t satype, uint8_t algtype,
5267f4b3ec61Sdh155122 uint8_t alg, uint16_t minbits, uint16_t maxbits, ipsec_stack_t *ipss)
52687c478bd9Sstevel@tonic-gate {
52697c478bd9Sstevel@tonic-gate uint8_t *cur = start;
52707845d282Sdanmcd ipsec_alginfo_t *algp;
52717c478bd9Sstevel@tonic-gate sadb_x_algdesc_t *algdesc = (sadb_x_algdesc_t *)cur;
52727845d282Sdanmcd
52737c478bd9Sstevel@tonic-gate cur += sizeof (*algdesc);
52747c478bd9Sstevel@tonic-gate if (cur >= limit)
52757c478bd9Sstevel@tonic-gate return (NULL);
52767c478bd9Sstevel@tonic-gate
52777c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_numalgs++;
52787c478bd9Sstevel@tonic-gate
52797845d282Sdanmcd /*
52807845d282Sdanmcd * Normalize vs. crypto framework's limits. This way, you can specify
52817845d282Sdanmcd * a stronger policy, and when the framework loads a stronger version,
52827845d282Sdanmcd * you can just keep plowing w/o rewhacking your SPD.
52837845d282Sdanmcd */
5284f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_alg_lock);
5285f4b3ec61Sdh155122 algp = ipss->ipsec_alglists[(algtype == SADB_X_ALGTYPE_AUTH) ?
52867845d282Sdanmcd IPSEC_ALG_AUTH : IPSEC_ALG_ENCR][alg];
528710b3fbf5Sdanmcd if (algp == NULL) {
528810b3fbf5Sdanmcd mutex_exit(&ipss->ipsec_alg_lock);
528910b3fbf5Sdanmcd return (NULL); /* Algorithm doesn't exist. Fail gracefully. */
529010b3fbf5Sdanmcd }
52917845d282Sdanmcd if (minbits < algp->alg_ef_minbits)
52927845d282Sdanmcd minbits = algp->alg_ef_minbits;
52937845d282Sdanmcd if (maxbits > algp->alg_ef_maxbits)
52947845d282Sdanmcd maxbits = algp->alg_ef_maxbits;
5295f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock);
52967845d282Sdanmcd
5297628b0c67SMark Fenwick algdesc->sadb_x_algdesc_reserved = SADB_8TO1(algp->alg_saltlen);
52987c478bd9Sstevel@tonic-gate algdesc->sadb_x_algdesc_satype = satype;
52997c478bd9Sstevel@tonic-gate algdesc->sadb_x_algdesc_algtype = algtype;
53007c478bd9Sstevel@tonic-gate algdesc->sadb_x_algdesc_alg = alg;
53017c478bd9Sstevel@tonic-gate algdesc->sadb_x_algdesc_minbits = minbits;
53027c478bd9Sstevel@tonic-gate algdesc->sadb_x_algdesc_maxbits = maxbits;
5303628b0c67SMark Fenwick
53047c478bd9Sstevel@tonic-gate return (cur);
53057c478bd9Sstevel@tonic-gate }
53067c478bd9Sstevel@tonic-gate
53077c478bd9Sstevel@tonic-gate /*
53087c478bd9Sstevel@tonic-gate * Convert the given ipsec_action_t into an ecomb starting at *ecomb
53097c478bd9Sstevel@tonic-gate * which must fit before *limit
53107c478bd9Sstevel@tonic-gate *
53117c478bd9Sstevel@tonic-gate * return NULL if we ran out of room or a pointer to the end of the ecomb.
53127c478bd9Sstevel@tonic-gate */
53137c478bd9Sstevel@tonic-gate static uint8_t *
5314f4b3ec61Sdh155122 sadb_action_to_ecomb(uint8_t *start, uint8_t *limit, ipsec_action_t *act,
5315f4b3ec61Sdh155122 netstack_t *ns)
53167c478bd9Sstevel@tonic-gate {
53177c478bd9Sstevel@tonic-gate uint8_t *cur = start;
53187c478bd9Sstevel@tonic-gate sadb_x_ecomb_t *ecomb = (sadb_x_ecomb_t *)cur;
53197c478bd9Sstevel@tonic-gate ipsec_prot_t *ipp;
5320f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec;
53217c478bd9Sstevel@tonic-gate
53227c478bd9Sstevel@tonic-gate cur += sizeof (*ecomb);
53237c478bd9Sstevel@tonic-gate if (cur >= limit)
53247c478bd9Sstevel@tonic-gate return (NULL);
53257c478bd9Sstevel@tonic-gate
53267c478bd9Sstevel@tonic-gate ASSERT(act->ipa_act.ipa_type == IPSEC_ACT_APPLY);
53277c478bd9Sstevel@tonic-gate
53287c478bd9Sstevel@tonic-gate ipp = &act->ipa_act.ipa_apply;
53297c478bd9Sstevel@tonic-gate
53307c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_numalgs = 0;
53317c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_reserved = 0;
53327c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_reserved2 = 0;
53337c478bd9Sstevel@tonic-gate /*
53347c478bd9Sstevel@tonic-gate * No limits on allocations, since we really don't support that
53357c478bd9Sstevel@tonic-gate * concept currently.
53367c478bd9Sstevel@tonic-gate */
53377c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_allocations = 0;
53387c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_allocations = 0;
53397c478bd9Sstevel@tonic-gate
53407c478bd9Sstevel@tonic-gate /*
53417c478bd9Sstevel@tonic-gate * XXX TBD: Policy or global parameters will eventually be
53427c478bd9Sstevel@tonic-gate * able to fill in some of these.
53437c478bd9Sstevel@tonic-gate */
53447c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_flags = 0;
53457c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_bytes = 0;
53467c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_bytes = 0;
53477c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_addtime = 0;
53487c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_addtime = 0;
53497c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_soft_usetime = 0;
53507c478bd9Sstevel@tonic-gate ecomb->sadb_x_ecomb_hard_usetime = 0;
53517c478bd9Sstevel@tonic-gate
53527c478bd9Sstevel@tonic-gate if (ipp->ipp_use_ah) {
53537c478bd9Sstevel@tonic-gate cur = sadb_new_algdesc(cur, limit, ecomb,
53547c478bd9Sstevel@tonic-gate SADB_SATYPE_AH, SADB_X_ALGTYPE_AUTH, ipp->ipp_auth_alg,
5355f4b3ec61Sdh155122 ipp->ipp_ah_minbits, ipp->ipp_ah_maxbits, ipss);
53567c478bd9Sstevel@tonic-gate if (cur == NULL)
53577c478bd9Sstevel@tonic-gate return (NULL);
5358f4b3ec61Sdh155122 ipsecah_fill_defs(ecomb, ns);
53597c478bd9Sstevel@tonic-gate }
53607c478bd9Sstevel@tonic-gate
53617c478bd9Sstevel@tonic-gate if (ipp->ipp_use_esp) {
53627c478bd9Sstevel@tonic-gate if (ipp->ipp_use_espa) {
53637c478bd9Sstevel@tonic-gate cur = sadb_new_algdesc(cur, limit, ecomb,
53647c478bd9Sstevel@tonic-gate SADB_SATYPE_ESP, SADB_X_ALGTYPE_AUTH,
53657c478bd9Sstevel@tonic-gate ipp->ipp_esp_auth_alg,
53667c478bd9Sstevel@tonic-gate ipp->ipp_espa_minbits,
5367f4b3ec61Sdh155122 ipp->ipp_espa_maxbits, ipss);
53687c478bd9Sstevel@tonic-gate if (cur == NULL)
53697c478bd9Sstevel@tonic-gate return (NULL);
53707c478bd9Sstevel@tonic-gate }
53717c478bd9Sstevel@tonic-gate
53727c478bd9Sstevel@tonic-gate cur = sadb_new_algdesc(cur, limit, ecomb,
53737c478bd9Sstevel@tonic-gate SADB_SATYPE_ESP, SADB_X_ALGTYPE_CRYPT,
53747c478bd9Sstevel@tonic-gate ipp->ipp_encr_alg,
53757c478bd9Sstevel@tonic-gate ipp->ipp_espe_minbits,
5376f4b3ec61Sdh155122 ipp->ipp_espe_maxbits, ipss);
53777c478bd9Sstevel@tonic-gate if (cur == NULL)
53787c478bd9Sstevel@tonic-gate return (NULL);
53797c478bd9Sstevel@tonic-gate /* Fill in lifetimes if and only if AH didn't already... */
53807c478bd9Sstevel@tonic-gate if (!ipp->ipp_use_ah)
5381f4b3ec61Sdh155122 ipsecesp_fill_defs(ecomb, ns);
53827c478bd9Sstevel@tonic-gate }
53837c478bd9Sstevel@tonic-gate
53847c478bd9Sstevel@tonic-gate return (cur);
53857c478bd9Sstevel@tonic-gate }
53867c478bd9Sstevel@tonic-gate
53875d3b8cb7SBill Sommerfeld #include <sys/tsol/label_macro.h> /* XXX should not need this */
53885d3b8cb7SBill Sommerfeld
53895d3b8cb7SBill Sommerfeld /*
53905d3b8cb7SBill Sommerfeld * From a cred_t, construct a sensitivity label extension
53915d3b8cb7SBill Sommerfeld *
53925d3b8cb7SBill Sommerfeld * We send up a fixed-size sensitivity label bitmap, and are perhaps
53935d3b8cb7SBill Sommerfeld * overly chummy with the underlying data structures here.
53945d3b8cb7SBill Sommerfeld */
53955d3b8cb7SBill Sommerfeld
53965d3b8cb7SBill Sommerfeld /* ARGSUSED */
53975d3b8cb7SBill Sommerfeld int
5398bd670b35SErik Nordmark sadb_sens_len_from_label(ts_label_t *tsl)
53995d3b8cb7SBill Sommerfeld {
54005d3b8cb7SBill Sommerfeld int baselen = sizeof (sadb_sens_t) + _C_LEN * 4;
54015d3b8cb7SBill Sommerfeld return (roundup(baselen, sizeof (uint64_t)));
54025d3b8cb7SBill Sommerfeld }
54035d3b8cb7SBill Sommerfeld
54045d3b8cb7SBill Sommerfeld void
5405bd670b35SErik Nordmark sadb_sens_from_label(sadb_sens_t *sens, int exttype, ts_label_t *tsl,
5406bd670b35SErik Nordmark int senslen)
54075d3b8cb7SBill Sommerfeld {
54085d3b8cb7SBill Sommerfeld uint8_t *bitmap;
54095d3b8cb7SBill Sommerfeld bslabel_t *sl;
54105d3b8cb7SBill Sommerfeld
54115d3b8cb7SBill Sommerfeld /* LINTED */
54125d3b8cb7SBill Sommerfeld ASSERT((_C_LEN & 1) == 0);
54135d3b8cb7SBill Sommerfeld ASSERT((senslen & 7) == 0);
54145d3b8cb7SBill Sommerfeld
54155d3b8cb7SBill Sommerfeld sl = label2bslabel(tsl);
54165d3b8cb7SBill Sommerfeld
54175d3b8cb7SBill Sommerfeld sens->sadb_sens_exttype = exttype;
54185d3b8cb7SBill Sommerfeld sens->sadb_sens_len = SADB_8TO64(senslen);
54195d3b8cb7SBill Sommerfeld
54205d3b8cb7SBill Sommerfeld sens->sadb_sens_dpd = tsl->tsl_doi;
54215d3b8cb7SBill Sommerfeld sens->sadb_sens_sens_level = LCLASS(sl);
54225d3b8cb7SBill Sommerfeld sens->sadb_sens_integ_level = 0; /* TBD */
54235d3b8cb7SBill Sommerfeld sens->sadb_sens_sens_len = _C_LEN >> 1;
54245d3b8cb7SBill Sommerfeld sens->sadb_sens_integ_len = 0; /* TBD */
54255d3b8cb7SBill Sommerfeld sens->sadb_x_sens_flags = 0;
54265d3b8cb7SBill Sommerfeld
54275d3b8cb7SBill Sommerfeld bitmap = (uint8_t *)(sens + 1);
54285d3b8cb7SBill Sommerfeld bcopy(&(((_bslabel_impl_t *)sl)->compartments), bitmap, _C_LEN * 4);
54295d3b8cb7SBill Sommerfeld }
54305d3b8cb7SBill Sommerfeld
54315d3b8cb7SBill Sommerfeld static sadb_sens_t *
5432bd670b35SErik Nordmark sadb_make_sens_ext(ts_label_t *tsl, int *len)
54335d3b8cb7SBill Sommerfeld {
54345d3b8cb7SBill Sommerfeld /* XXX allocation failure? */
5435bd670b35SErik Nordmark int sens_len = sadb_sens_len_from_label(tsl);
54365d3b8cb7SBill Sommerfeld
54375d3b8cb7SBill Sommerfeld sadb_sens_t *sens = kmem_alloc(sens_len, KM_SLEEP);
54385d3b8cb7SBill Sommerfeld
5439bd670b35SErik Nordmark sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY, tsl, sens_len);
54405d3b8cb7SBill Sommerfeld
54415d3b8cb7SBill Sommerfeld *len = sens_len;
54425d3b8cb7SBill Sommerfeld
54435d3b8cb7SBill Sommerfeld return (sens);
54445d3b8cb7SBill Sommerfeld }
54455d3b8cb7SBill Sommerfeld
54465d3b8cb7SBill Sommerfeld /*
54475d3b8cb7SBill Sommerfeld * Okay, how do we report errors/invalid labels from this?
54485d3b8cb7SBill Sommerfeld * With a special designated "not a label" cred_t ?
54495d3b8cb7SBill Sommerfeld */
54505d3b8cb7SBill Sommerfeld /* ARGSUSED */
5451bd670b35SErik Nordmark ts_label_t *
5452bd670b35SErik Nordmark sadb_label_from_sens(sadb_sens_t *sens, uint64_t *bitmap)
54535d3b8cb7SBill Sommerfeld {
54545d3b8cb7SBill Sommerfeld int bitmap_len = SADB_64TO8(sens->sadb_sens_sens_len);
54555d3b8cb7SBill Sommerfeld bslabel_t sl;
5456bd670b35SErik Nordmark ts_label_t *tsl;
54575d3b8cb7SBill Sommerfeld
54585d3b8cb7SBill Sommerfeld if (sens->sadb_sens_integ_level != 0)
54595d3b8cb7SBill Sommerfeld return (NULL);
54605d3b8cb7SBill Sommerfeld if (sens->sadb_sens_integ_len != 0)
54615d3b8cb7SBill Sommerfeld return (NULL);
54625d3b8cb7SBill Sommerfeld if (bitmap_len > _C_LEN * 4)
54635d3b8cb7SBill Sommerfeld return (NULL);
54645d3b8cb7SBill Sommerfeld
54655d3b8cb7SBill Sommerfeld bsllow(&sl);
54665d3b8cb7SBill Sommerfeld LCLASS_SET((_bslabel_impl_t *)&sl, sens->sadb_sens_sens_level);
54675d3b8cb7SBill Sommerfeld bcopy(bitmap, &((_bslabel_impl_t *)&sl)->compartments,
54685d3b8cb7SBill Sommerfeld bitmap_len);
54695d3b8cb7SBill Sommerfeld
5470bd670b35SErik Nordmark tsl = labelalloc(&sl, sens->sadb_sens_dpd, KM_NOSLEEP);
5471bd670b35SErik Nordmark if (tsl == NULL)
5472bd670b35SErik Nordmark return (NULL);
54735d3b8cb7SBill Sommerfeld
54745d3b8cb7SBill Sommerfeld if (sens->sadb_x_sens_flags & SADB_X_SENS_UNLABELED)
5475bd670b35SErik Nordmark tsl->tsl_flags |= TSLF_UNLABELED;
5476bd670b35SErik Nordmark return (tsl);
54775d3b8cb7SBill Sommerfeld }
54785d3b8cb7SBill Sommerfeld
54795d3b8cb7SBill Sommerfeld /* End XXX label-library-leakage */
54805d3b8cb7SBill Sommerfeld
54817c478bd9Sstevel@tonic-gate /*
54827c478bd9Sstevel@tonic-gate * Construct an extended ACQUIRE message based on a selector and the resulting
54837c478bd9Sstevel@tonic-gate * IPsec action.
54847c478bd9Sstevel@tonic-gate *
54857c478bd9Sstevel@tonic-gate * NOTE: This is used by both inverse ACQUIRE and actual ACQUIRE
54867c478bd9Sstevel@tonic-gate * generation. As a consequence, expect this function to evolve
54877c478bd9Sstevel@tonic-gate * rapidly.
54887c478bd9Sstevel@tonic-gate */
54897c478bd9Sstevel@tonic-gate static mblk_t *
54907c478bd9Sstevel@tonic-gate sadb_extended_acquire(ipsec_selector_t *sel, ipsec_policy_t *pol,
5491f4b3ec61Sdh155122 ipsec_action_t *act, boolean_t tunnel_mode, uint32_t seq, uint32_t pid,
54925d3b8cb7SBill Sommerfeld sadb_sens_t *sens, netstack_t *ns)
54937c478bd9Sstevel@tonic-gate {
54947c478bd9Sstevel@tonic-gate mblk_t *mp;
54957c478bd9Sstevel@tonic-gate sadb_msg_t *samsg;
54967c478bd9Sstevel@tonic-gate uint8_t *start, *cur, *end;
54977c478bd9Sstevel@tonic-gate uint32_t *saddrptr, *daddrptr;
54987c478bd9Sstevel@tonic-gate sa_family_t af;
54997c478bd9Sstevel@tonic-gate sadb_prop_t *eprop;
55007c478bd9Sstevel@tonic-gate ipsec_action_t *ap, *an;
55018810c16bSdanmcd ipsec_selkey_t *ipsl;
55028810c16bSdanmcd uint8_t proto, pfxlen;
55037c478bd9Sstevel@tonic-gate uint16_t lport, rport;
55047c478bd9Sstevel@tonic-gate uint32_t kmp, kmc;
55057c478bd9Sstevel@tonic-gate
55067c478bd9Sstevel@tonic-gate /*
55077c478bd9Sstevel@tonic-gate * Find the action we want sooner rather than later..
55087c478bd9Sstevel@tonic-gate */
55097c478bd9Sstevel@tonic-gate an = NULL;
55107c478bd9Sstevel@tonic-gate if (pol == NULL) {
55117c478bd9Sstevel@tonic-gate ap = act;
55127c478bd9Sstevel@tonic-gate } else {
55137c478bd9Sstevel@tonic-gate ap = pol->ipsp_act;
55147c478bd9Sstevel@tonic-gate
55157c478bd9Sstevel@tonic-gate if (ap != NULL)
55167c478bd9Sstevel@tonic-gate an = ap->ipa_next;
55177c478bd9Sstevel@tonic-gate }
55187c478bd9Sstevel@tonic-gate
55197c478bd9Sstevel@tonic-gate /*
55207c478bd9Sstevel@tonic-gate * Just take a swag for the allocation for now. We can always
55217c478bd9Sstevel@tonic-gate * alter it later.
55227c478bd9Sstevel@tonic-gate */
55230358d3a6Sdanmcd #define SADB_EXTENDED_ACQUIRE_SIZE 4096
55247c478bd9Sstevel@tonic-gate mp = allocb(SADB_EXTENDED_ACQUIRE_SIZE, BPRI_HI);
55257c478bd9Sstevel@tonic-gate if (mp == NULL)
55267c478bd9Sstevel@tonic-gate return (NULL);
55277c478bd9Sstevel@tonic-gate
55287c478bd9Sstevel@tonic-gate start = mp->b_rptr;
55297c478bd9Sstevel@tonic-gate end = start + SADB_EXTENDED_ACQUIRE_SIZE;
55307c478bd9Sstevel@tonic-gate
55317c478bd9Sstevel@tonic-gate cur = start;
55327c478bd9Sstevel@tonic-gate
55337c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)cur;
55347c478bd9Sstevel@tonic-gate cur += sizeof (*samsg);
55357c478bd9Sstevel@tonic-gate
55367c478bd9Sstevel@tonic-gate samsg->sadb_msg_version = PF_KEY_V2;
55377c478bd9Sstevel@tonic-gate samsg->sadb_msg_type = SADB_ACQUIRE;
55387c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = 0;
55397c478bd9Sstevel@tonic-gate samsg->sadb_msg_reserved = 0;
55407c478bd9Sstevel@tonic-gate samsg->sadb_msg_satype = 0;
55417c478bd9Sstevel@tonic-gate samsg->sadb_msg_seq = seq;
55427c478bd9Sstevel@tonic-gate samsg->sadb_msg_pid = pid;
55437c478bd9Sstevel@tonic-gate
55448810c16bSdanmcd if (tunnel_mode) {
55457c478bd9Sstevel@tonic-gate /*
55468810c16bSdanmcd * Form inner address extensions based NOT on the inner
55478810c16bSdanmcd * selectors (i.e. the packet data), but on the policy's
55488810c16bSdanmcd * selector key (i.e. the policy's selector information).
55498810c16bSdanmcd *
55508810c16bSdanmcd * NOTE: The position of IPv4 and IPv6 addresses is the
55518810c16bSdanmcd * same in ipsec_selkey_t (unless the compiler does very
55528810c16bSdanmcd * strange things with unions, consult your local C language
55538810c16bSdanmcd * lawyer for details).
55547c478bd9Sstevel@tonic-gate */
55557807385bSDan McDonald ASSERT(pol != NULL);
55567807385bSDan McDonald
55578810c16bSdanmcd ipsl = &(pol->ipsp_sel->ipsl_key);
55588810c16bSdanmcd if (ipsl->ipsl_valid & IPSL_IPV4) {
55598810c16bSdanmcd af = AF_INET;
55608810c16bSdanmcd ASSERT(sel->ips_protocol == IPPROTO_ENCAP);
55618810c16bSdanmcd ASSERT(!(ipsl->ipsl_valid & IPSL_IPV6));
55628810c16bSdanmcd } else {
55638810c16bSdanmcd af = AF_INET6;
55648810c16bSdanmcd ASSERT(sel->ips_protocol == IPPROTO_IPV6);
55658810c16bSdanmcd ASSERT(ipsl->ipsl_valid & IPSL_IPV6);
55668810c16bSdanmcd }
55677c478bd9Sstevel@tonic-gate
55688810c16bSdanmcd if (ipsl->ipsl_valid & IPSL_LOCAL_ADDR) {
55698810c16bSdanmcd saddrptr = (uint32_t *)(&ipsl->ipsl_local);
55708810c16bSdanmcd pfxlen = ipsl->ipsl_local_pfxlen;
55718810c16bSdanmcd } else {
55728810c16bSdanmcd saddrptr = (uint32_t *)(&ipv6_all_zeros);
55738810c16bSdanmcd pfxlen = 0;
55748810c16bSdanmcd }
55758810c16bSdanmcd /* XXX What about ICMP type/code? */
55768810c16bSdanmcd lport = (ipsl->ipsl_valid & IPSL_LOCAL_PORT) ?
55778810c16bSdanmcd ipsl->ipsl_lport : 0;
55788810c16bSdanmcd proto = (ipsl->ipsl_valid & IPSL_PROTOCOL) ?
55798810c16bSdanmcd ipsl->ipsl_proto : 0;
55808810c16bSdanmcd
55818810c16bSdanmcd cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_SRC,
55828810c16bSdanmcd af, saddrptr, lport, proto, pfxlen);
55838810c16bSdanmcd if (cur == NULL) {
55848810c16bSdanmcd freeb(mp);
55858810c16bSdanmcd return (NULL);
55868810c16bSdanmcd }
55878810c16bSdanmcd
55888810c16bSdanmcd if (ipsl->ipsl_valid & IPSL_REMOTE_ADDR) {
55898810c16bSdanmcd daddrptr = (uint32_t *)(&ipsl->ipsl_remote);
55908810c16bSdanmcd pfxlen = ipsl->ipsl_remote_pfxlen;
55918810c16bSdanmcd } else {
55928810c16bSdanmcd daddrptr = (uint32_t *)(&ipv6_all_zeros);
55938810c16bSdanmcd pfxlen = 0;
55948810c16bSdanmcd }
55958810c16bSdanmcd /* XXX What about ICMP type/code? */
55968810c16bSdanmcd rport = (ipsl->ipsl_valid & IPSL_REMOTE_PORT) ?
55978810c16bSdanmcd ipsl->ipsl_rport : 0;
55988810c16bSdanmcd
55998810c16bSdanmcd cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_DST,
56008810c16bSdanmcd af, daddrptr, rport, proto, pfxlen);
56018810c16bSdanmcd if (cur == NULL) {
56028810c16bSdanmcd freeb(mp);
56038810c16bSdanmcd return (NULL);
56048810c16bSdanmcd }
56058810c16bSdanmcd /*
56068810c16bSdanmcd * TODO - if we go to 3408's dream of transport mode IP-in-IP
56078810c16bSdanmcd * _with_ inner-packet address selectors, we'll need to further
56088810c16bSdanmcd * distinguish tunnel mode here. For now, having inner
56098810c16bSdanmcd * addresses and/or ports is sufficient.
56108810c16bSdanmcd *
56118810c16bSdanmcd * Meanwhile, whack proto/ports to reflect IP-in-IP for the
56128810c16bSdanmcd * outer addresses.
56138810c16bSdanmcd */
56148810c16bSdanmcd proto = sel->ips_protocol; /* Either _ENCAP or _IPV6 */
56158810c16bSdanmcd lport = rport = 0;
56168810c16bSdanmcd } else if ((ap != NULL) && (!ap->ipa_want_unique)) {
56177c478bd9Sstevel@tonic-gate proto = 0;
56187c478bd9Sstevel@tonic-gate lport = 0;
56197c478bd9Sstevel@tonic-gate rport = 0;
56207c478bd9Sstevel@tonic-gate if (pol != NULL) {
56218810c16bSdanmcd ipsl = &(pol->ipsp_sel->ipsl_key);
56228810c16bSdanmcd if (ipsl->ipsl_valid & IPSL_PROTOCOL)
56238810c16bSdanmcd proto = ipsl->ipsl_proto;
56248810c16bSdanmcd if (ipsl->ipsl_valid & IPSL_REMOTE_PORT)
56258810c16bSdanmcd rport = ipsl->ipsl_rport;
56268810c16bSdanmcd if (ipsl->ipsl_valid & IPSL_LOCAL_PORT)
56278810c16bSdanmcd lport = ipsl->ipsl_lport;
56287c478bd9Sstevel@tonic-gate }
56298810c16bSdanmcd } else {
56308810c16bSdanmcd proto = sel->ips_protocol;
56318810c16bSdanmcd lport = sel->ips_local_port;
56328810c16bSdanmcd rport = sel->ips_remote_port;
56337c478bd9Sstevel@tonic-gate }
56347c478bd9Sstevel@tonic-gate
56358810c16bSdanmcd af = sel->ips_isv4 ? AF_INET : AF_INET6;
56368810c16bSdanmcd
56378810c16bSdanmcd /*
56388810c16bSdanmcd * NOTE: The position of IPv4 and IPv6 addresses is the same in
56398810c16bSdanmcd * ipsec_selector_t.
56408810c16bSdanmcd */
56417c478bd9Sstevel@tonic-gate cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_SRC, af,
56428810c16bSdanmcd (uint32_t *)(&sel->ips_local_addr_v6), lport, proto, 0);
56437c478bd9Sstevel@tonic-gate
56447c478bd9Sstevel@tonic-gate if (cur == NULL) {
56457c478bd9Sstevel@tonic-gate freeb(mp);
56467c478bd9Sstevel@tonic-gate return (NULL);
56477c478bd9Sstevel@tonic-gate }
56487c478bd9Sstevel@tonic-gate
56497c478bd9Sstevel@tonic-gate cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_DST, af,
56508810c16bSdanmcd (uint32_t *)(&sel->ips_remote_addr_v6), rport, proto, 0);
56517c478bd9Sstevel@tonic-gate
56527c478bd9Sstevel@tonic-gate if (cur == NULL) {
56537c478bd9Sstevel@tonic-gate freeb(mp);
56547c478bd9Sstevel@tonic-gate return (NULL);
56557c478bd9Sstevel@tonic-gate }
56567c478bd9Sstevel@tonic-gate
56575d3b8cb7SBill Sommerfeld if (sens != NULL) {
56585d3b8cb7SBill Sommerfeld uint8_t *sensext = cur;
56595d3b8cb7SBill Sommerfeld int senslen = SADB_64TO8(sens->sadb_sens_len);
56605d3b8cb7SBill Sommerfeld
56615d3b8cb7SBill Sommerfeld cur += senslen;
56625d3b8cb7SBill Sommerfeld if (cur > end) {
56635d3b8cb7SBill Sommerfeld freeb(mp);
56645d3b8cb7SBill Sommerfeld return (NULL);
56655d3b8cb7SBill Sommerfeld }
56665d3b8cb7SBill Sommerfeld bcopy(sens, sensext, senslen);
56675d3b8cb7SBill Sommerfeld }
56685d3b8cb7SBill Sommerfeld
56697c478bd9Sstevel@tonic-gate /*
56707c478bd9Sstevel@tonic-gate * This section will change a lot as policy evolves.
56717c478bd9Sstevel@tonic-gate * For now, it'll be relatively simple.
56727c478bd9Sstevel@tonic-gate */
56737c478bd9Sstevel@tonic-gate eprop = (sadb_prop_t *)cur;
56747c478bd9Sstevel@tonic-gate cur += sizeof (*eprop);
56757c478bd9Sstevel@tonic-gate if (cur > end) {
56767c478bd9Sstevel@tonic-gate /* no space left */
56777c478bd9Sstevel@tonic-gate freeb(mp);
56787c478bd9Sstevel@tonic-gate return (NULL);
56797c478bd9Sstevel@tonic-gate }
56807c478bd9Sstevel@tonic-gate
56817c478bd9Sstevel@tonic-gate eprop->sadb_prop_exttype = SADB_X_EXT_EPROP;
56827c478bd9Sstevel@tonic-gate eprop->sadb_x_prop_ereserved = 0;
56837c478bd9Sstevel@tonic-gate eprop->sadb_x_prop_numecombs = 0;
56847c478bd9Sstevel@tonic-gate eprop->sadb_prop_replay = 32; /* default */
56857c478bd9Sstevel@tonic-gate
56867c478bd9Sstevel@tonic-gate kmc = kmp = 0;
56877c478bd9Sstevel@tonic-gate
56887c478bd9Sstevel@tonic-gate for (; ap != NULL; ap = an) {
56897c478bd9Sstevel@tonic-gate an = (pol != NULL) ? ap->ipa_next : NULL;
56907c478bd9Sstevel@tonic-gate
56917c478bd9Sstevel@tonic-gate /*
56927c478bd9Sstevel@tonic-gate * Skip non-IPsec policies
56937c478bd9Sstevel@tonic-gate */
56947c478bd9Sstevel@tonic-gate if (ap->ipa_act.ipa_type != IPSEC_ACT_APPLY)
56957c478bd9Sstevel@tonic-gate continue;
56967c478bd9Sstevel@tonic-gate
56977c478bd9Sstevel@tonic-gate if (ap->ipa_act.ipa_apply.ipp_km_proto)
56987c478bd9Sstevel@tonic-gate kmp = ap->ipa_act.ipa_apply.ipp_km_proto;
56997c478bd9Sstevel@tonic-gate if (ap->ipa_act.ipa_apply.ipp_km_cookie)
57007c478bd9Sstevel@tonic-gate kmc = ap->ipa_act.ipa_apply.ipp_km_cookie;
57017c478bd9Sstevel@tonic-gate if (ap->ipa_act.ipa_apply.ipp_replay_depth) {
57027c478bd9Sstevel@tonic-gate eprop->sadb_prop_replay =
57037c478bd9Sstevel@tonic-gate ap->ipa_act.ipa_apply.ipp_replay_depth;
57047c478bd9Sstevel@tonic-gate }
57057c478bd9Sstevel@tonic-gate
5706f4b3ec61Sdh155122 cur = sadb_action_to_ecomb(cur, end, ap, ns);
57077c478bd9Sstevel@tonic-gate if (cur == NULL) { /* no space */
57087c478bd9Sstevel@tonic-gate freeb(mp);
57097c478bd9Sstevel@tonic-gate return (NULL);
57107c478bd9Sstevel@tonic-gate }
57117c478bd9Sstevel@tonic-gate eprop->sadb_x_prop_numecombs++;
57127c478bd9Sstevel@tonic-gate }
57137c478bd9Sstevel@tonic-gate
57147c478bd9Sstevel@tonic-gate if (eprop->sadb_x_prop_numecombs == 0) {
57157c478bd9Sstevel@tonic-gate /*
57167c478bd9Sstevel@tonic-gate * This will happen if we fail to find a policy
57177c478bd9Sstevel@tonic-gate * allowing for IPsec processing.
57187c478bd9Sstevel@tonic-gate * Construct an error message.
57197c478bd9Sstevel@tonic-gate */
57207c478bd9Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg));
57217c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = ENOENT;
57227c478bd9Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = 0;
57237c478bd9Sstevel@tonic-gate return (mp);
57247c478bd9Sstevel@tonic-gate }
57257c478bd9Sstevel@tonic-gate
57267c478bd9Sstevel@tonic-gate if ((kmp != 0) || (kmc != 0)) {
57277c478bd9Sstevel@tonic-gate cur = sadb_make_kmc_ext(cur, end, kmp, kmc);
57287c478bd9Sstevel@tonic-gate if (cur == NULL) {
57297c478bd9Sstevel@tonic-gate freeb(mp);
57307c478bd9Sstevel@tonic-gate return (NULL);
57317c478bd9Sstevel@tonic-gate }
57327c478bd9Sstevel@tonic-gate }
57337c478bd9Sstevel@tonic-gate
57347c478bd9Sstevel@tonic-gate eprop->sadb_prop_len = SADB_8TO64(cur - (uint8_t *)eprop);
57357c478bd9Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(cur - start);
57367c478bd9Sstevel@tonic-gate mp->b_wptr = cur;
57377c478bd9Sstevel@tonic-gate
57387c478bd9Sstevel@tonic-gate return (mp);
57397c478bd9Sstevel@tonic-gate }
57407c478bd9Sstevel@tonic-gate
57417c478bd9Sstevel@tonic-gate /*
57428810c16bSdanmcd * Generic setup of an RFC 2367 ACQUIRE message. Caller sets satype.
57438810c16bSdanmcd *
57448810c16bSdanmcd * NOTE: This function acquires alg_lock as a side-effect if-and-only-if we
57458810c16bSdanmcd * succeed (i.e. return non-NULL). Caller MUST release it. This is to
57468810c16bSdanmcd * maximize code consolidation while preventing algorithm changes from messing
57478810c16bSdanmcd * with the callers finishing touches on the ACQUIRE itself.
57487c478bd9Sstevel@tonic-gate */
57498810c16bSdanmcd mblk_t *
5750f4b3ec61Sdh155122 sadb_setup_acquire(ipsacq_t *acqrec, uint8_t satype, ipsec_stack_t *ipss)
57517c478bd9Sstevel@tonic-gate {
57528810c16bSdanmcd uint_t allocsize;
57538810c16bSdanmcd mblk_t *pfkeymp, *msgmp;
57547c478bd9Sstevel@tonic-gate sa_family_t af;
57558810c16bSdanmcd uint8_t *cur, *end;
57568810c16bSdanmcd sadb_msg_t *samsg;
57577c478bd9Sstevel@tonic-gate uint16_t sport_typecode;
57587c478bd9Sstevel@tonic-gate uint16_t dport_typecode;
57597c478bd9Sstevel@tonic-gate uint8_t check_proto;
57608810c16bSdanmcd boolean_t tunnel_mode = (acqrec->ipsacq_inneraddrfam != 0);
57617c478bd9Sstevel@tonic-gate
57628810c16bSdanmcd ASSERT(MUTEX_HELD(&acqrec->ipsacq_lock));
57638810c16bSdanmcd
57648810c16bSdanmcd pfkeymp = sadb_keysock_out(0);
57658810c16bSdanmcd if (pfkeymp == NULL)
57667c478bd9Sstevel@tonic-gate return (NULL);
57677c478bd9Sstevel@tonic-gate
57688810c16bSdanmcd /*
57698810c16bSdanmcd * First, allocate a basic ACQUIRE message
57708810c16bSdanmcd */
57718810c16bSdanmcd allocsize = sizeof (sadb_msg_t) + sizeof (sadb_address_t) +
57728810c16bSdanmcd sizeof (sadb_address_t) + sizeof (sadb_prop_t);
57738810c16bSdanmcd
57748810c16bSdanmcd /* Make sure there's enough to cover both AF_INET and AF_INET6. */
57758810c16bSdanmcd allocsize += 2 * sizeof (struct sockaddr_in6);
57768810c16bSdanmcd
5777f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_alg_lock);
57788810c16bSdanmcd /* NOTE: The lock is now held through to this function's return. */
5779f4b3ec61Sdh155122 allocsize += ipss->ipsec_nalgs[IPSEC_ALG_AUTH] *
5780f4b3ec61Sdh155122 ipss->ipsec_nalgs[IPSEC_ALG_ENCR] * sizeof (sadb_comb_t);
57818810c16bSdanmcd
57828810c16bSdanmcd if (tunnel_mode) {
57838810c16bSdanmcd /* Tunnel mode! */
57848810c16bSdanmcd allocsize += 2 * sizeof (sadb_address_t);
57858810c16bSdanmcd /* Enough to cover both AF_INET and AF_INET6. */
57868810c16bSdanmcd allocsize += 2 * sizeof (struct sockaddr_in6);
57878810c16bSdanmcd }
57888810c16bSdanmcd
57898810c16bSdanmcd msgmp = allocb(allocsize, BPRI_HI);
57908810c16bSdanmcd if (msgmp == NULL) {
57918810c16bSdanmcd freeb(pfkeymp);
5792f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock);
57938810c16bSdanmcd return (NULL);
57948810c16bSdanmcd }
57958810c16bSdanmcd
57968810c16bSdanmcd pfkeymp->b_cont = msgmp;
57978810c16bSdanmcd cur = msgmp->b_rptr;
57988810c16bSdanmcd end = cur + allocsize;
57998810c16bSdanmcd samsg = (sadb_msg_t *)cur;
58008810c16bSdanmcd cur += sizeof (sadb_msg_t);
58018810c16bSdanmcd
58027c478bd9Sstevel@tonic-gate af = acqrec->ipsacq_addrfam;
58037c478bd9Sstevel@tonic-gate switch (af) {
58047c478bd9Sstevel@tonic-gate case AF_INET:
58057c478bd9Sstevel@tonic-gate check_proto = IPPROTO_ICMP;
58067c478bd9Sstevel@tonic-gate break;
58077c478bd9Sstevel@tonic-gate case AF_INET6:
58087c478bd9Sstevel@tonic-gate check_proto = IPPROTO_ICMPV6;
58097c478bd9Sstevel@tonic-gate break;
58107c478bd9Sstevel@tonic-gate default:
58117c478bd9Sstevel@tonic-gate /* This should never happen unless we have kernel bugs. */
58127c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
58137c478bd9Sstevel@tonic-gate "sadb_setup_acquire: corrupt ACQUIRE record.\n");
58147c478bd9Sstevel@tonic-gate ASSERT(0);
5815f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock);
58167c478bd9Sstevel@tonic-gate return (NULL);
58177c478bd9Sstevel@tonic-gate }
58187c478bd9Sstevel@tonic-gate
58197c478bd9Sstevel@tonic-gate samsg->sadb_msg_version = PF_KEY_V2;
58207c478bd9Sstevel@tonic-gate samsg->sadb_msg_type = SADB_ACQUIRE;
58218810c16bSdanmcd samsg->sadb_msg_satype = satype;
58227c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = 0;
58237c478bd9Sstevel@tonic-gate samsg->sadb_msg_pid = 0;
58247c478bd9Sstevel@tonic-gate samsg->sadb_msg_reserved = 0;
58257c478bd9Sstevel@tonic-gate samsg->sadb_msg_seq = acqrec->ipsacq_seq;
58267c478bd9Sstevel@tonic-gate
58277c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&acqrec->ipsacq_lock));
58287c478bd9Sstevel@tonic-gate
58298810c16bSdanmcd if ((acqrec->ipsacq_proto == check_proto) || tunnel_mode) {
58307c478bd9Sstevel@tonic-gate sport_typecode = dport_typecode = 0;
58317c478bd9Sstevel@tonic-gate } else {
58327c478bd9Sstevel@tonic-gate sport_typecode = acqrec->ipsacq_srcport;
58337c478bd9Sstevel@tonic-gate dport_typecode = acqrec->ipsacq_dstport;
58347c478bd9Sstevel@tonic-gate }
58357c478bd9Sstevel@tonic-gate
58367c478bd9Sstevel@tonic-gate cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_SRC, af,
58378810c16bSdanmcd acqrec->ipsacq_srcaddr, sport_typecode, acqrec->ipsacq_proto, 0);
58387c478bd9Sstevel@tonic-gate
58397c478bd9Sstevel@tonic-gate cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_DST, af,
58408810c16bSdanmcd acqrec->ipsacq_dstaddr, dport_typecode, acqrec->ipsacq_proto, 0);
58418810c16bSdanmcd
58428810c16bSdanmcd if (tunnel_mode) {
58438810c16bSdanmcd sport_typecode = acqrec->ipsacq_srcport;
58448810c16bSdanmcd dport_typecode = acqrec->ipsacq_dstport;
58458810c16bSdanmcd cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_SRC,
58468810c16bSdanmcd acqrec->ipsacq_inneraddrfam, acqrec->ipsacq_innersrc,
58478810c16bSdanmcd sport_typecode, acqrec->ipsacq_inner_proto,
58488810c16bSdanmcd acqrec->ipsacq_innersrcpfx);
58498810c16bSdanmcd cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_DST,
58508810c16bSdanmcd acqrec->ipsacq_inneraddrfam, acqrec->ipsacq_innerdst,
58518810c16bSdanmcd dport_typecode, acqrec->ipsacq_inner_proto,
58528810c16bSdanmcd acqrec->ipsacq_innerdstpfx);
58538810c16bSdanmcd }
58548810c16bSdanmcd
58558810c16bSdanmcd /* XXX Insert identity information here. */
58568810c16bSdanmcd
58578810c16bSdanmcd /* XXXMLS Insert sensitivity information here. */
58587c478bd9Sstevel@tonic-gate
58597c478bd9Sstevel@tonic-gate if (cur != NULL)
58608810c16bSdanmcd samsg->sadb_msg_len = SADB_8TO64(cur - msgmp->b_rptr);
58618810c16bSdanmcd else
5862f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock);
58637c478bd9Sstevel@tonic-gate
58648810c16bSdanmcd return (pfkeymp);
58657c478bd9Sstevel@tonic-gate }
58667c478bd9Sstevel@tonic-gate
58677c478bd9Sstevel@tonic-gate /*
58687c478bd9Sstevel@tonic-gate * Given an SADB_GETSPI message, find an appropriately ranged SA and
58697c478bd9Sstevel@tonic-gate * allocate an SA. If there are message improprieties, return (ipsa_t *)-1.
58707c478bd9Sstevel@tonic-gate * If there was a memory allocation error, return NULL. (Assume NULL !=
58717c478bd9Sstevel@tonic-gate * (ipsa_t *)-1).
58727c478bd9Sstevel@tonic-gate *
58737c478bd9Sstevel@tonic-gate * master_spi is passed in host order.
58747c478bd9Sstevel@tonic-gate */
58757c478bd9Sstevel@tonic-gate ipsa_t *
5876f4b3ec61Sdh155122 sadb_getspi(keysock_in_t *ksi, uint32_t master_spi, int *diagnostic,
58779c2c14abSThejaswini Singarajipura netstack_t *ns, uint_t sa_type)
58787c478bd9Sstevel@tonic-gate {
58797c478bd9Sstevel@tonic-gate sadb_address_t *src =
58807c478bd9Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC],
58817c478bd9Sstevel@tonic-gate *dst = (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
58827c478bd9Sstevel@tonic-gate sadb_spirange_t *range =
58837c478bd9Sstevel@tonic-gate (sadb_spirange_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE];
58847c478bd9Sstevel@tonic-gate struct sockaddr_in *ssa, *dsa;
58857c478bd9Sstevel@tonic-gate struct sockaddr_in6 *ssa6, *dsa6;
58867c478bd9Sstevel@tonic-gate uint32_t *srcaddr, *dstaddr;
58877c478bd9Sstevel@tonic-gate sa_family_t af;
58887c478bd9Sstevel@tonic-gate uint32_t add, min, max;
58899c2c14abSThejaswini Singarajipura uint8_t protocol =
58909c2c14abSThejaswini Singarajipura (sa_type == SADB_SATYPE_AH) ? IPPROTO_AH : IPPROTO_ESP;
58917c478bd9Sstevel@tonic-gate
58927c478bd9Sstevel@tonic-gate if (src == NULL) {
58937c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
58947c478bd9Sstevel@tonic-gate return ((ipsa_t *)-1);
58957c478bd9Sstevel@tonic-gate }
58967c478bd9Sstevel@tonic-gate if (dst == NULL) {
58977c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
58987c478bd9Sstevel@tonic-gate return ((ipsa_t *)-1);
58997c478bd9Sstevel@tonic-gate }
59007c478bd9Sstevel@tonic-gate if (range == NULL) {
59017c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_RANGE;
59027c478bd9Sstevel@tonic-gate return ((ipsa_t *)-1);
59037c478bd9Sstevel@tonic-gate }
59047c478bd9Sstevel@tonic-gate
59057c478bd9Sstevel@tonic-gate min = ntohl(range->sadb_spirange_min);
59067c478bd9Sstevel@tonic-gate max = ntohl(range->sadb_spirange_max);
59077c478bd9Sstevel@tonic-gate dsa = (struct sockaddr_in *)(dst + 1);
59087c478bd9Sstevel@tonic-gate dsa6 = (struct sockaddr_in6 *)dsa;
59097c478bd9Sstevel@tonic-gate
59107c478bd9Sstevel@tonic-gate ssa = (struct sockaddr_in *)(src + 1);
59117c478bd9Sstevel@tonic-gate ssa6 = (struct sockaddr_in6 *)ssa;
59128810c16bSdanmcd ASSERT(dsa->sin_family == ssa->sin_family);
59137c478bd9Sstevel@tonic-gate
59147c478bd9Sstevel@tonic-gate srcaddr = ALL_ZEROES_PTR;
59157c478bd9Sstevel@tonic-gate af = dsa->sin_family;
59167c478bd9Sstevel@tonic-gate switch (af) {
59177c478bd9Sstevel@tonic-gate case AF_INET:
59187c478bd9Sstevel@tonic-gate if (src != NULL)
59197c478bd9Sstevel@tonic-gate srcaddr = (uint32_t *)(&ssa->sin_addr);
59207c478bd9Sstevel@tonic-gate dstaddr = (uint32_t *)(&dsa->sin_addr);
59217c478bd9Sstevel@tonic-gate break;
59227c478bd9Sstevel@tonic-gate case AF_INET6:
59237c478bd9Sstevel@tonic-gate if (src != NULL)
59247c478bd9Sstevel@tonic-gate srcaddr = (uint32_t *)(&ssa6->sin6_addr);
59257c478bd9Sstevel@tonic-gate dstaddr = (uint32_t *)(&dsa6->sin6_addr);
59267c478bd9Sstevel@tonic-gate break;
59277c478bd9Sstevel@tonic-gate default:
59287c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_DST_AF;
59297c478bd9Sstevel@tonic-gate return ((ipsa_t *)-1);
59307c478bd9Sstevel@tonic-gate }
59317c478bd9Sstevel@tonic-gate
59327c478bd9Sstevel@tonic-gate if (master_spi < min || master_spi > max) {
59337c478bd9Sstevel@tonic-gate /* Return a random value in the range. */
59349c2c14abSThejaswini Singarajipura if (cl_inet_getspi) {
59358e4b770fSLu Huafeng cl_inet_getspi(ns->netstack_stackid, protocol,
59368e4b770fSLu Huafeng (uint8_t *)&add, sizeof (add), NULL);
59379c2c14abSThejaswini Singarajipura } else {
59389c2c14abSThejaswini Singarajipura (void) random_get_pseudo_bytes((uint8_t *)&add,
59399c2c14abSThejaswini Singarajipura sizeof (add));
59409c2c14abSThejaswini Singarajipura }
59417c478bd9Sstevel@tonic-gate master_spi = min + (add % (max - min + 1));
59427c478bd9Sstevel@tonic-gate }
59437c478bd9Sstevel@tonic-gate
59447c478bd9Sstevel@tonic-gate /*
59457c478bd9Sstevel@tonic-gate * Since master_spi is passed in host order, we need to htonl() it
59467c478bd9Sstevel@tonic-gate * for the purposes of creating a new SA.
59477c478bd9Sstevel@tonic-gate */
5948f4b3ec61Sdh155122 return (sadb_makelarvalassoc(htonl(master_spi), srcaddr, dstaddr, af,
5949f4b3ec61Sdh155122 ns));
59507c478bd9Sstevel@tonic-gate }
59517c478bd9Sstevel@tonic-gate
59527c478bd9Sstevel@tonic-gate /*
59537c478bd9Sstevel@tonic-gate *
59547c478bd9Sstevel@tonic-gate * Locate an ACQUIRE and nuke it. If I have an samsg that's larger than the
59557c478bd9Sstevel@tonic-gate * base header, just ignore it. Otherwise, lock down the whole ACQUIRE list
59567c478bd9Sstevel@tonic-gate * and scan for the sequence number in question. I may wish to accept an
59577c478bd9Sstevel@tonic-gate * address pair with it, for easier searching.
59587c478bd9Sstevel@tonic-gate *
59597c478bd9Sstevel@tonic-gate * Caller frees the message, so we don't have to here.
59607c478bd9Sstevel@tonic-gate *
5961bd670b35SErik Nordmark * NOTE: The pfkey_q parameter may be used in the future for ACQUIRE
59627c478bd9Sstevel@tonic-gate * failures.
59637c478bd9Sstevel@tonic-gate */
59647c478bd9Sstevel@tonic-gate /* ARGSUSED */
59657c478bd9Sstevel@tonic-gate void
5966bd670b35SErik Nordmark sadb_in_acquire(sadb_msg_t *samsg, sadbp_t *sp, queue_t *pfkey_q,
5967bd670b35SErik Nordmark netstack_t *ns)
59687c478bd9Sstevel@tonic-gate {
59697c478bd9Sstevel@tonic-gate int i;
59707c478bd9Sstevel@tonic-gate ipsacq_t *acqrec;
59717c478bd9Sstevel@tonic-gate iacqf_t *bucket;
59727c478bd9Sstevel@tonic-gate
59737c478bd9Sstevel@tonic-gate /*
59747c478bd9Sstevel@tonic-gate * I only accept the base header for this!
59757c478bd9Sstevel@tonic-gate * Though to be honest, requiring the dst address would help
59767c478bd9Sstevel@tonic-gate * immensely.
59777c478bd9Sstevel@tonic-gate *
59787c478bd9Sstevel@tonic-gate * XXX There are already cases where I can get the dst address.
59797c478bd9Sstevel@tonic-gate */
59807c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_len > SADB_8TO64(sizeof (*samsg)))
59817c478bd9Sstevel@tonic-gate return;
59827c478bd9Sstevel@tonic-gate
59837c478bd9Sstevel@tonic-gate /*
59847c478bd9Sstevel@tonic-gate * Using the samsg->sadb_msg_seq, find the ACQUIRE record, delete it,
59857c478bd9Sstevel@tonic-gate * (and in the future send a message to IP with the appropriate error
59867c478bd9Sstevel@tonic-gate * number).
59877c478bd9Sstevel@tonic-gate *
59887c478bd9Sstevel@tonic-gate * Q: Do I want to reject if pid != 0?
59897c478bd9Sstevel@tonic-gate */
59907c478bd9Sstevel@tonic-gate
5991fb87b5d2Ssommerfe for (i = 0; i < sp->s_v4.sdb_hashsize; i++) {
59927c478bd9Sstevel@tonic-gate bucket = &sp->s_v4.sdb_acq[i];
59937c478bd9Sstevel@tonic-gate mutex_enter(&bucket->iacqf_lock);
59947c478bd9Sstevel@tonic-gate for (acqrec = bucket->iacqf_ipsacq; acqrec != NULL;
59957c478bd9Sstevel@tonic-gate acqrec = acqrec->ipsacq_next) {
59967c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_seq == acqrec->ipsacq_seq)
59977c478bd9Sstevel@tonic-gate break; /* for acqrec... loop. */
59987c478bd9Sstevel@tonic-gate }
59997c478bd9Sstevel@tonic-gate if (acqrec != NULL)
60007c478bd9Sstevel@tonic-gate break; /* for i = 0... loop. */
60017c478bd9Sstevel@tonic-gate
60027c478bd9Sstevel@tonic-gate mutex_exit(&bucket->iacqf_lock);
6003fb87b5d2Ssommerfe }
60047c478bd9Sstevel@tonic-gate
6005fb87b5d2Ssommerfe if (acqrec == NULL) {
6006fb87b5d2Ssommerfe for (i = 0; i < sp->s_v6.sdb_hashsize; i++) {
60077c478bd9Sstevel@tonic-gate bucket = &sp->s_v6.sdb_acq[i];
60087c478bd9Sstevel@tonic-gate mutex_enter(&bucket->iacqf_lock);
60097c478bd9Sstevel@tonic-gate for (acqrec = bucket->iacqf_ipsacq; acqrec != NULL;
60107c478bd9Sstevel@tonic-gate acqrec = acqrec->ipsacq_next) {
60117c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_seq == acqrec->ipsacq_seq)
60127c478bd9Sstevel@tonic-gate break; /* for acqrec... loop. */
60137c478bd9Sstevel@tonic-gate }
60147c478bd9Sstevel@tonic-gate if (acqrec != NULL)
60157c478bd9Sstevel@tonic-gate break; /* for i = 0... loop. */
60167c478bd9Sstevel@tonic-gate
60177c478bd9Sstevel@tonic-gate mutex_exit(&bucket->iacqf_lock);
60187c478bd9Sstevel@tonic-gate }
6019fb87b5d2Ssommerfe }
6020fb87b5d2Ssommerfe
60217c478bd9Sstevel@tonic-gate
60227c478bd9Sstevel@tonic-gate if (acqrec == NULL)
60237c478bd9Sstevel@tonic-gate return;
60247c478bd9Sstevel@tonic-gate
60257c478bd9Sstevel@tonic-gate /*
60267c478bd9Sstevel@tonic-gate * What do I do with the errno and IP? I may need mp's services a
60277c478bd9Sstevel@tonic-gate * little more. See sadb_destroy_acquire() for future directions
60287c478bd9Sstevel@tonic-gate * beyond free the mblk chain on the acquire record.
60297c478bd9Sstevel@tonic-gate */
60307c478bd9Sstevel@tonic-gate
60317c478bd9Sstevel@tonic-gate ASSERT(&bucket->iacqf_lock == acqrec->ipsacq_linklock);
6032f4b3ec61Sdh155122 sadb_destroy_acquire(acqrec, ns);
60337c478bd9Sstevel@tonic-gate /* Have to exit mutex here, because of breaking out of for loop. */
60347c478bd9Sstevel@tonic-gate mutex_exit(&bucket->iacqf_lock);
60357c478bd9Sstevel@tonic-gate }
60367c478bd9Sstevel@tonic-gate
60377c478bd9Sstevel@tonic-gate /*
60387c478bd9Sstevel@tonic-gate * The following functions work with the replay windows of an SA. They assume
60397c478bd9Sstevel@tonic-gate * the ipsa->ipsa_replay_arr is an array of uint64_t, and that the bit vector
60407c478bd9Sstevel@tonic-gate * represents the highest sequence number packet received, and back
60417c478bd9Sstevel@tonic-gate * (ipsa->ipsa_replay_wsize) packets.
60427c478bd9Sstevel@tonic-gate */
60437c478bd9Sstevel@tonic-gate
60447c478bd9Sstevel@tonic-gate /*
60457c478bd9Sstevel@tonic-gate * Is the replay bit set?
60467c478bd9Sstevel@tonic-gate */
60477c478bd9Sstevel@tonic-gate static boolean_t
60487c478bd9Sstevel@tonic-gate ipsa_is_replay_set(ipsa_t *ipsa, uint32_t offset)
60497c478bd9Sstevel@tonic-gate {
60507c478bd9Sstevel@tonic-gate uint64_t bit = (uint64_t)1 << (uint64_t)(offset & 63);
60517c478bd9Sstevel@tonic-gate
60527c478bd9Sstevel@tonic-gate return ((bit & ipsa->ipsa_replay_arr[offset >> 6]) ? B_TRUE : B_FALSE);
60537c478bd9Sstevel@tonic-gate }
60547c478bd9Sstevel@tonic-gate
60557c478bd9Sstevel@tonic-gate /*
60567c478bd9Sstevel@tonic-gate * Shift the bits of the replay window over.
60577c478bd9Sstevel@tonic-gate */
60587c478bd9Sstevel@tonic-gate static void
60597c478bd9Sstevel@tonic-gate ipsa_shift_replay(ipsa_t *ipsa, uint32_t shift)
60607c478bd9Sstevel@tonic-gate {
60617c478bd9Sstevel@tonic-gate int i;
60627c478bd9Sstevel@tonic-gate int jump = ((shift - 1) >> 6) + 1;
60637c478bd9Sstevel@tonic-gate
60647c478bd9Sstevel@tonic-gate if (shift == 0)
60657c478bd9Sstevel@tonic-gate return;
60667c478bd9Sstevel@tonic-gate
60677c478bd9Sstevel@tonic-gate for (i = (ipsa->ipsa_replay_wsize - 1) >> 6; i >= 0; i--) {
60687c478bd9Sstevel@tonic-gate if (i + jump <= (ipsa->ipsa_replay_wsize - 1) >> 6) {
60697c478bd9Sstevel@tonic-gate ipsa->ipsa_replay_arr[i + jump] |=
60707c478bd9Sstevel@tonic-gate ipsa->ipsa_replay_arr[i] >> (64 - (shift & 63));
60717c478bd9Sstevel@tonic-gate }
60727c478bd9Sstevel@tonic-gate ipsa->ipsa_replay_arr[i] <<= shift;
60737c478bd9Sstevel@tonic-gate }
60747c478bd9Sstevel@tonic-gate }
60757c478bd9Sstevel@tonic-gate
60767c478bd9Sstevel@tonic-gate /*
60777c478bd9Sstevel@tonic-gate * Set a bit in the bit vector.
60787c478bd9Sstevel@tonic-gate */
60797c478bd9Sstevel@tonic-gate static void
60807c478bd9Sstevel@tonic-gate ipsa_set_replay(ipsa_t *ipsa, uint32_t offset)
60817c478bd9Sstevel@tonic-gate {
60827c478bd9Sstevel@tonic-gate uint64_t bit = (uint64_t)1 << (uint64_t)(offset & 63);
60837c478bd9Sstevel@tonic-gate
60847c478bd9Sstevel@tonic-gate ipsa->ipsa_replay_arr[offset >> 6] |= bit;
60857c478bd9Sstevel@tonic-gate }
60867c478bd9Sstevel@tonic-gate
60877c478bd9Sstevel@tonic-gate #define SADB_MAX_REPLAY_VALUE 0xffffffff
60887c478bd9Sstevel@tonic-gate
60897c478bd9Sstevel@tonic-gate /*
60907c478bd9Sstevel@tonic-gate * Assume caller has NOT done ntohl() already on seq. Check to see
60917c478bd9Sstevel@tonic-gate * if replay sequence number "seq" has been seen already.
60927c478bd9Sstevel@tonic-gate */
60937c478bd9Sstevel@tonic-gate boolean_t
60947c478bd9Sstevel@tonic-gate sadb_replay_check(ipsa_t *ipsa, uint32_t seq)
60957c478bd9Sstevel@tonic-gate {
60967c478bd9Sstevel@tonic-gate boolean_t rc;
60977c478bd9Sstevel@tonic-gate uint32_t diff;
60987c478bd9Sstevel@tonic-gate
60997c478bd9Sstevel@tonic-gate if (ipsa->ipsa_replay_wsize == 0)
61007c478bd9Sstevel@tonic-gate return (B_TRUE);
61017c478bd9Sstevel@tonic-gate
61027c478bd9Sstevel@tonic-gate /*
61037c478bd9Sstevel@tonic-gate * NOTE: I've already checked for 0 on the wire in sadb_replay_peek().
61047c478bd9Sstevel@tonic-gate */
61057c478bd9Sstevel@tonic-gate
61067c478bd9Sstevel@tonic-gate /* Convert sequence number into host order before holding the mutex. */
61077c478bd9Sstevel@tonic-gate seq = ntohl(seq);
61087c478bd9Sstevel@tonic-gate
61097c478bd9Sstevel@tonic-gate mutex_enter(&ipsa->ipsa_lock);
61107c478bd9Sstevel@tonic-gate
61117c478bd9Sstevel@tonic-gate /* Initialize inbound SA's ipsa_replay field to last one received. */
61127c478bd9Sstevel@tonic-gate if (ipsa->ipsa_replay == 0)
61137c478bd9Sstevel@tonic-gate ipsa->ipsa_replay = 1;
61147c478bd9Sstevel@tonic-gate
61157c478bd9Sstevel@tonic-gate if (seq > ipsa->ipsa_replay) {
61167c478bd9Sstevel@tonic-gate /*
61177c478bd9Sstevel@tonic-gate * I have received a new "highest value received". Shift
61187c478bd9Sstevel@tonic-gate * the replay window over.
61197c478bd9Sstevel@tonic-gate */
61207c478bd9Sstevel@tonic-gate diff = seq - ipsa->ipsa_replay;
61217c478bd9Sstevel@tonic-gate if (diff < ipsa->ipsa_replay_wsize) {
61227c478bd9Sstevel@tonic-gate /* In replay window, shift bits over. */
61237c478bd9Sstevel@tonic-gate ipsa_shift_replay(ipsa, diff);
61247c478bd9Sstevel@tonic-gate } else {
61257c478bd9Sstevel@tonic-gate /* WAY FAR AHEAD, clear bits and start again. */
61267c478bd9Sstevel@tonic-gate bzero(ipsa->ipsa_replay_arr,
61277c478bd9Sstevel@tonic-gate sizeof (ipsa->ipsa_replay_arr));
61287c478bd9Sstevel@tonic-gate }
61297c478bd9Sstevel@tonic-gate ipsa_set_replay(ipsa, 0);
61307c478bd9Sstevel@tonic-gate ipsa->ipsa_replay = seq;
61317c478bd9Sstevel@tonic-gate rc = B_TRUE;
61327c478bd9Sstevel@tonic-gate goto done;
61337c478bd9Sstevel@tonic-gate }
61347c478bd9Sstevel@tonic-gate diff = ipsa->ipsa_replay - seq;
61357c478bd9Sstevel@tonic-gate if (diff >= ipsa->ipsa_replay_wsize || ipsa_is_replay_set(ipsa, diff)) {
61367c478bd9Sstevel@tonic-gate rc = B_FALSE;
61377c478bd9Sstevel@tonic-gate goto done;
61387c478bd9Sstevel@tonic-gate }
61397c478bd9Sstevel@tonic-gate /* Set this packet as seen. */
61407c478bd9Sstevel@tonic-gate ipsa_set_replay(ipsa, diff);
61417c478bd9Sstevel@tonic-gate
61427c478bd9Sstevel@tonic-gate rc = B_TRUE;
61437c478bd9Sstevel@tonic-gate done:
61447c478bd9Sstevel@tonic-gate mutex_exit(&ipsa->ipsa_lock);
61457c478bd9Sstevel@tonic-gate return (rc);
61467c478bd9Sstevel@tonic-gate }
61477c478bd9Sstevel@tonic-gate
61487c478bd9Sstevel@tonic-gate /*
61497c478bd9Sstevel@tonic-gate * "Peek" and see if we should even bother going through the effort of
61507c478bd9Sstevel@tonic-gate * running an authentication check on the sequence number passed in.
61517c478bd9Sstevel@tonic-gate * this takes into account packets that are below the replay window,
61527c478bd9Sstevel@tonic-gate * and collisions with already replayed packets. Return B_TRUE if it
61538810c16bSdanmcd * is okay to proceed, B_FALSE if this packet should be dropped immediately.
61547c478bd9Sstevel@tonic-gate * Assume same byte-ordering as sadb_replay_check.
61557c478bd9Sstevel@tonic-gate */
61567c478bd9Sstevel@tonic-gate boolean_t
61577c478bd9Sstevel@tonic-gate sadb_replay_peek(ipsa_t *ipsa, uint32_t seq)
61587c478bd9Sstevel@tonic-gate {
61597c478bd9Sstevel@tonic-gate boolean_t rc = B_FALSE;
61607c478bd9Sstevel@tonic-gate uint32_t diff;
61617c478bd9Sstevel@tonic-gate
61627c478bd9Sstevel@tonic-gate if (ipsa->ipsa_replay_wsize == 0)
61637c478bd9Sstevel@tonic-gate return (B_TRUE);
61647c478bd9Sstevel@tonic-gate
61657c478bd9Sstevel@tonic-gate /*
61667c478bd9Sstevel@tonic-gate * 0 is 0, regardless of byte order... :)
61677c478bd9Sstevel@tonic-gate *
61687c478bd9Sstevel@tonic-gate * If I get 0 on the wire (and there is a replay window) then the
61697c478bd9Sstevel@tonic-gate * sender most likely wrapped. This ipsa may need to be marked or
61707c478bd9Sstevel@tonic-gate * something.
61717c478bd9Sstevel@tonic-gate */
61727c478bd9Sstevel@tonic-gate if (seq == 0)
61737c478bd9Sstevel@tonic-gate return (B_FALSE);
61747c478bd9Sstevel@tonic-gate
61757c478bd9Sstevel@tonic-gate seq = ntohl(seq);
61767c478bd9Sstevel@tonic-gate mutex_enter(&ipsa->ipsa_lock);
61777c478bd9Sstevel@tonic-gate if (seq < ipsa->ipsa_replay - ipsa->ipsa_replay_wsize &&
61787c478bd9Sstevel@tonic-gate ipsa->ipsa_replay >= ipsa->ipsa_replay_wsize)
61797c478bd9Sstevel@tonic-gate goto done;
61807c478bd9Sstevel@tonic-gate
61817c478bd9Sstevel@tonic-gate /*
61827c478bd9Sstevel@tonic-gate * If I've hit 0xffffffff, then quite honestly, I don't need to
61837c478bd9Sstevel@tonic-gate * bother with formalities. I'm not accepting any more packets
61847c478bd9Sstevel@tonic-gate * on this SA.
61857c478bd9Sstevel@tonic-gate */
61867c478bd9Sstevel@tonic-gate if (ipsa->ipsa_replay == SADB_MAX_REPLAY_VALUE) {
61877c478bd9Sstevel@tonic-gate /*
61887c478bd9Sstevel@tonic-gate * Since we're already holding the lock, update the
61897c478bd9Sstevel@tonic-gate * expire time ala. sadb_replay_delete() and return.
61907c478bd9Sstevel@tonic-gate */
61917c478bd9Sstevel@tonic-gate ipsa->ipsa_hardexpiretime = (time_t)1;
61927c478bd9Sstevel@tonic-gate goto done;
61937c478bd9Sstevel@tonic-gate }
61947c478bd9Sstevel@tonic-gate
61957c478bd9Sstevel@tonic-gate if (seq <= ipsa->ipsa_replay) {
61967c478bd9Sstevel@tonic-gate /*
61977c478bd9Sstevel@tonic-gate * This seq is in the replay window. I'm not below it,
61987c478bd9Sstevel@tonic-gate * because I already checked for that above!
61997c478bd9Sstevel@tonic-gate */
62007c478bd9Sstevel@tonic-gate diff = ipsa->ipsa_replay - seq;
62017c478bd9Sstevel@tonic-gate if (ipsa_is_replay_set(ipsa, diff))
62027c478bd9Sstevel@tonic-gate goto done;
62037c478bd9Sstevel@tonic-gate }
62047c478bd9Sstevel@tonic-gate /* Else return B_TRUE, I'm going to advance the window. */
62057c478bd9Sstevel@tonic-gate
62067c478bd9Sstevel@tonic-gate rc = B_TRUE;
62077c478bd9Sstevel@tonic-gate done:
62087c478bd9Sstevel@tonic-gate mutex_exit(&ipsa->ipsa_lock);
62097c478bd9Sstevel@tonic-gate return (rc);
62107c478bd9Sstevel@tonic-gate }
62117c478bd9Sstevel@tonic-gate
62127c478bd9Sstevel@tonic-gate /*
62137c478bd9Sstevel@tonic-gate * Delete a single SA.
62147c478bd9Sstevel@tonic-gate *
62157c478bd9Sstevel@tonic-gate * For now, use the quick-and-dirty trick of making the association's
62167c478bd9Sstevel@tonic-gate * hard-expire lifetime (time_t)1, ensuring deletion by the *_ager().
62177c478bd9Sstevel@tonic-gate */
62187c478bd9Sstevel@tonic-gate void
62197c478bd9Sstevel@tonic-gate sadb_replay_delete(ipsa_t *assoc)
62207c478bd9Sstevel@tonic-gate {
62217c478bd9Sstevel@tonic-gate mutex_enter(&assoc->ipsa_lock);
62227c478bd9Sstevel@tonic-gate assoc->ipsa_hardexpiretime = (time_t)1;
62237c478bd9Sstevel@tonic-gate mutex_exit(&assoc->ipsa_lock);
62247c478bd9Sstevel@tonic-gate }
62257c478bd9Sstevel@tonic-gate
62267c478bd9Sstevel@tonic-gate /*
62277c478bd9Sstevel@tonic-gate * Special front-end to ipsec_rl_strlog() dealing with SA failure.
62287c478bd9Sstevel@tonic-gate * this is designed to take only a format string with "* %x * %s *", so
62297c478bd9Sstevel@tonic-gate * that "spi" is printed first, then "addr" is converted using inet_pton().
62307c478bd9Sstevel@tonic-gate *
62317c478bd9Sstevel@tonic-gate * This is abstracted out to save the stack space for only when inet_pton()
62327c478bd9Sstevel@tonic-gate * is called. Make sure "spi" is in network order; it usually is when this
62337c478bd9Sstevel@tonic-gate * would get called.
62347c478bd9Sstevel@tonic-gate */
62357c478bd9Sstevel@tonic-gate void
62367c478bd9Sstevel@tonic-gate ipsec_assocfailure(short mid, short sid, char level, ushort_t sl, char *fmt,
6237f4b3ec61Sdh155122 uint32_t spi, void *addr, int af, netstack_t *ns)
62387c478bd9Sstevel@tonic-gate {
62397c478bd9Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN];
62407c478bd9Sstevel@tonic-gate
62417c478bd9Sstevel@tonic-gate ASSERT(af == AF_INET6 || af == AF_INET);
62427c478bd9Sstevel@tonic-gate
6243f4b3ec61Sdh155122 ipsec_rl_strlog(ns, mid, sid, level, sl, fmt, ntohl(spi),
62447c478bd9Sstevel@tonic-gate inet_ntop(af, addr, buf, sizeof (buf)));
62457c478bd9Sstevel@tonic-gate }
62467c478bd9Sstevel@tonic-gate
62477c478bd9Sstevel@tonic-gate /*
62487c478bd9Sstevel@tonic-gate * Fills in a reference to the policy, if any, from the conn, in *ppp
62497c478bd9Sstevel@tonic-gate */
62507c478bd9Sstevel@tonic-gate static void
62518810c16bSdanmcd ipsec_conn_pol(ipsec_selector_t *sel, conn_t *connp, ipsec_policy_t **ppp)
62527c478bd9Sstevel@tonic-gate {
62537c478bd9Sstevel@tonic-gate ipsec_policy_t *pp;
62547c478bd9Sstevel@tonic-gate ipsec_latch_t *ipl = connp->conn_latch;
62557c478bd9Sstevel@tonic-gate
6256bd670b35SErik Nordmark if ((ipl != NULL) && (connp->conn_ixa->ixa_ipsec_policy != NULL)) {
6257bd670b35SErik Nordmark pp = connp->conn_ixa->ixa_ipsec_policy;
62587c478bd9Sstevel@tonic-gate IPPOL_REFHOLD(pp);
62597c478bd9Sstevel@tonic-gate } else {
6260bd670b35SErik Nordmark pp = ipsec_find_policy(IPSEC_TYPE_OUTBOUND, connp, sel,
6261f4b3ec61Sdh155122 connp->conn_netstack);
62627c478bd9Sstevel@tonic-gate }
62637c478bd9Sstevel@tonic-gate *ppp = pp;
62647c478bd9Sstevel@tonic-gate }
62657c478bd9Sstevel@tonic-gate
62667c478bd9Sstevel@tonic-gate /*
62677c478bd9Sstevel@tonic-gate * The following functions scan through active conn_t structures
62687c478bd9Sstevel@tonic-gate * and return a reference to the best-matching policy it can find.
62697c478bd9Sstevel@tonic-gate * Caller must release the reference.
62707c478bd9Sstevel@tonic-gate */
62717c478bd9Sstevel@tonic-gate static void
6272f4b3ec61Sdh155122 ipsec_udp_pol(ipsec_selector_t *sel, ipsec_policy_t **ppp, ip_stack_t *ipst)
62737c478bd9Sstevel@tonic-gate {
62747c478bd9Sstevel@tonic-gate connf_t *connfp;
62757c478bd9Sstevel@tonic-gate conn_t *connp = NULL;
62767c478bd9Sstevel@tonic-gate ipsec_selector_t portonly;
62777c478bd9Sstevel@tonic-gate
62787c478bd9Sstevel@tonic-gate bzero((void *)&portonly, sizeof (portonly));
62797c478bd9Sstevel@tonic-gate
62807c478bd9Sstevel@tonic-gate if (sel->ips_local_port == 0)
62817c478bd9Sstevel@tonic-gate return;
62827c478bd9Sstevel@tonic-gate
6283f4b3ec61Sdh155122 connfp = &ipst->ips_ipcl_udp_fanout[IPCL_UDP_HASH(sel->ips_local_port,
6284f4b3ec61Sdh155122 ipst)];
62857c478bd9Sstevel@tonic-gate mutex_enter(&connfp->connf_lock);
62867c478bd9Sstevel@tonic-gate
62877c478bd9Sstevel@tonic-gate if (sel->ips_isv4) {
62887c478bd9Sstevel@tonic-gate connp = connfp->connf_head;
62897c478bd9Sstevel@tonic-gate while (connp != NULL) {
62907c478bd9Sstevel@tonic-gate if (IPCL_UDP_MATCH(connp, sel->ips_local_port,
62917c478bd9Sstevel@tonic-gate sel->ips_local_addr_v4, sel->ips_remote_port,
62927c478bd9Sstevel@tonic-gate sel->ips_remote_addr_v4))
62937c478bd9Sstevel@tonic-gate break;
62947c478bd9Sstevel@tonic-gate connp = connp->conn_next;
62957c478bd9Sstevel@tonic-gate }
62967c478bd9Sstevel@tonic-gate
62977c478bd9Sstevel@tonic-gate if (connp == NULL) {
62987c478bd9Sstevel@tonic-gate /* Try port-only match in IPv6. */
62997c478bd9Sstevel@tonic-gate portonly.ips_local_port = sel->ips_local_port;
63007c478bd9Sstevel@tonic-gate sel = &portonly;
63017c478bd9Sstevel@tonic-gate }
63027c478bd9Sstevel@tonic-gate }
63037c478bd9Sstevel@tonic-gate
63047c478bd9Sstevel@tonic-gate if (connp == NULL) {
63057c478bd9Sstevel@tonic-gate connp = connfp->connf_head;
63067c478bd9Sstevel@tonic-gate while (connp != NULL) {
63077c478bd9Sstevel@tonic-gate if (IPCL_UDP_MATCH_V6(connp, sel->ips_local_port,
63087c478bd9Sstevel@tonic-gate sel->ips_local_addr_v6, sel->ips_remote_port,
63097c478bd9Sstevel@tonic-gate sel->ips_remote_addr_v6))
63107c478bd9Sstevel@tonic-gate break;
63117c478bd9Sstevel@tonic-gate connp = connp->conn_next;
63127c478bd9Sstevel@tonic-gate }
63137c478bd9Sstevel@tonic-gate
63147c478bd9Sstevel@tonic-gate if (connp == NULL) {
63157c478bd9Sstevel@tonic-gate mutex_exit(&connfp->connf_lock);
63167c478bd9Sstevel@tonic-gate return;
63177c478bd9Sstevel@tonic-gate }
63187c478bd9Sstevel@tonic-gate }
63197c478bd9Sstevel@tonic-gate
63207c478bd9Sstevel@tonic-gate CONN_INC_REF(connp);
63217c478bd9Sstevel@tonic-gate mutex_exit(&connfp->connf_lock);
63227c478bd9Sstevel@tonic-gate
63238810c16bSdanmcd ipsec_conn_pol(sel, connp, ppp);
6324bd670b35SErik Nordmark CONN_DEC_REF(connp);
63257c478bd9Sstevel@tonic-gate }
63267c478bd9Sstevel@tonic-gate
63277c478bd9Sstevel@tonic-gate static conn_t *
6328f4b3ec61Sdh155122 ipsec_find_listen_conn(uint16_t *pptr, ipsec_selector_t *sel, ip_stack_t *ipst)
63297c478bd9Sstevel@tonic-gate {
63307c478bd9Sstevel@tonic-gate connf_t *connfp;
63317c478bd9Sstevel@tonic-gate conn_t *connp = NULL;
63327c478bd9Sstevel@tonic-gate const in6_addr_t *v6addrmatch = &sel->ips_local_addr_v6;
63337c478bd9Sstevel@tonic-gate
63347c478bd9Sstevel@tonic-gate if (sel->ips_local_port == 0)
63357c478bd9Sstevel@tonic-gate return (NULL);
63367c478bd9Sstevel@tonic-gate
6337437220cdSdanmcd connfp = &ipst->ips_ipcl_bind_fanout[
6338437220cdSdanmcd IPCL_BIND_HASH(sel->ips_local_port, ipst)];
63397c478bd9Sstevel@tonic-gate mutex_enter(&connfp->connf_lock);
63407c478bd9Sstevel@tonic-gate
63417c478bd9Sstevel@tonic-gate if (sel->ips_isv4) {
63427c478bd9Sstevel@tonic-gate connp = connfp->connf_head;
63437c478bd9Sstevel@tonic-gate while (connp != NULL) {
63447c478bd9Sstevel@tonic-gate if (IPCL_BIND_MATCH(connp, IPPROTO_TCP,
63457c478bd9Sstevel@tonic-gate sel->ips_local_addr_v4, pptr[1]))
63467c478bd9Sstevel@tonic-gate break;
63477c478bd9Sstevel@tonic-gate connp = connp->conn_next;
63487c478bd9Sstevel@tonic-gate }
63497c478bd9Sstevel@tonic-gate
63507c478bd9Sstevel@tonic-gate if (connp == NULL) {
63517c478bd9Sstevel@tonic-gate /* Match to all-zeroes. */
63527c478bd9Sstevel@tonic-gate v6addrmatch = &ipv6_all_zeros;
63537c478bd9Sstevel@tonic-gate }
63547c478bd9Sstevel@tonic-gate }
63557c478bd9Sstevel@tonic-gate
63567c478bd9Sstevel@tonic-gate if (connp == NULL) {
63577c478bd9Sstevel@tonic-gate connp = connfp->connf_head;
63587c478bd9Sstevel@tonic-gate while (connp != NULL) {
63597c478bd9Sstevel@tonic-gate if (IPCL_BIND_MATCH_V6(connp, IPPROTO_TCP,
63607c478bd9Sstevel@tonic-gate *v6addrmatch, pptr[1]))
63617c478bd9Sstevel@tonic-gate break;
63627c478bd9Sstevel@tonic-gate connp = connp->conn_next;
63637c478bd9Sstevel@tonic-gate }
63647c478bd9Sstevel@tonic-gate
63657c478bd9Sstevel@tonic-gate if (connp == NULL) {
63667c478bd9Sstevel@tonic-gate mutex_exit(&connfp->connf_lock);
63677c478bd9Sstevel@tonic-gate return (NULL);
63687c478bd9Sstevel@tonic-gate }
63697c478bd9Sstevel@tonic-gate }
63707c478bd9Sstevel@tonic-gate
63717c478bd9Sstevel@tonic-gate CONN_INC_REF(connp);
63727c478bd9Sstevel@tonic-gate mutex_exit(&connfp->connf_lock);
63737c478bd9Sstevel@tonic-gate return (connp);
63747c478bd9Sstevel@tonic-gate }
63757c478bd9Sstevel@tonic-gate
63767c478bd9Sstevel@tonic-gate static void
6377f4b3ec61Sdh155122 ipsec_tcp_pol(ipsec_selector_t *sel, ipsec_policy_t **ppp, ip_stack_t *ipst)
63787c478bd9Sstevel@tonic-gate {
63797c478bd9Sstevel@tonic-gate connf_t *connfp;
63807c478bd9Sstevel@tonic-gate conn_t *connp;
63817c478bd9Sstevel@tonic-gate uint32_t ports;
63827c478bd9Sstevel@tonic-gate uint16_t *pptr = (uint16_t *)&ports;
63837c478bd9Sstevel@tonic-gate
63847c478bd9Sstevel@tonic-gate /*
63857c478bd9Sstevel@tonic-gate * Find TCP state in the following order:
63867c478bd9Sstevel@tonic-gate * 1.) Connected conns.
63877c478bd9Sstevel@tonic-gate * 2.) Listeners.
63887c478bd9Sstevel@tonic-gate *
63897c478bd9Sstevel@tonic-gate * Even though #2 will be the common case for inbound traffic, only
63907c478bd9Sstevel@tonic-gate * following this order insures correctness.
63917c478bd9Sstevel@tonic-gate */
63927c478bd9Sstevel@tonic-gate
63937c478bd9Sstevel@tonic-gate if (sel->ips_local_port == 0)
63947c478bd9Sstevel@tonic-gate return;
63957c478bd9Sstevel@tonic-gate
63967c478bd9Sstevel@tonic-gate /*
63977c478bd9Sstevel@tonic-gate * 0 should be fport, 1 should be lport. SRC is the local one here.
63987c478bd9Sstevel@tonic-gate * See ipsec_construct_inverse_acquire() for details.
63997c478bd9Sstevel@tonic-gate */
64007c478bd9Sstevel@tonic-gate pptr[0] = sel->ips_remote_port;
64017c478bd9Sstevel@tonic-gate pptr[1] = sel->ips_local_port;
64027c478bd9Sstevel@tonic-gate
6403f4b3ec61Sdh155122 connfp = &ipst->ips_ipcl_conn_fanout[
6404f4b3ec61Sdh155122 IPCL_CONN_HASH(sel->ips_remote_addr_v4, ports, ipst)];
64057c478bd9Sstevel@tonic-gate mutex_enter(&connfp->connf_lock);
64067c478bd9Sstevel@tonic-gate connp = connfp->connf_head;
64077c478bd9Sstevel@tonic-gate
64087c478bd9Sstevel@tonic-gate if (sel->ips_isv4) {
64097c478bd9Sstevel@tonic-gate while (connp != NULL) {
64107c478bd9Sstevel@tonic-gate if (IPCL_CONN_MATCH(connp, IPPROTO_TCP,
64117c478bd9Sstevel@tonic-gate sel->ips_remote_addr_v4, sel->ips_local_addr_v4,
64127c478bd9Sstevel@tonic-gate ports))
64137c478bd9Sstevel@tonic-gate break;
64147c478bd9Sstevel@tonic-gate connp = connp->conn_next;
64157c478bd9Sstevel@tonic-gate }
64167c478bd9Sstevel@tonic-gate } else {
64177c478bd9Sstevel@tonic-gate while (connp != NULL) {
64187c478bd9Sstevel@tonic-gate if (IPCL_CONN_MATCH_V6(connp, IPPROTO_TCP,
64197c478bd9Sstevel@tonic-gate sel->ips_remote_addr_v6, sel->ips_local_addr_v6,
64207c478bd9Sstevel@tonic-gate ports))
64217c478bd9Sstevel@tonic-gate break;
64227c478bd9Sstevel@tonic-gate connp = connp->conn_next;
64237c478bd9Sstevel@tonic-gate }
64247c478bd9Sstevel@tonic-gate }
64257c478bd9Sstevel@tonic-gate
64267c478bd9Sstevel@tonic-gate if (connp != NULL) {
64277c478bd9Sstevel@tonic-gate CONN_INC_REF(connp);
64287c478bd9Sstevel@tonic-gate mutex_exit(&connfp->connf_lock);
64297c478bd9Sstevel@tonic-gate } else {
64307c478bd9Sstevel@tonic-gate mutex_exit(&connfp->connf_lock);
64317c478bd9Sstevel@tonic-gate
64327c478bd9Sstevel@tonic-gate /* Try the listen hash. */
6433f4b3ec61Sdh155122 if ((connp = ipsec_find_listen_conn(pptr, sel, ipst)) == NULL)
64347c478bd9Sstevel@tonic-gate return;
64357c478bd9Sstevel@tonic-gate }
64367c478bd9Sstevel@tonic-gate
64378810c16bSdanmcd ipsec_conn_pol(sel, connp, ppp);
6438bd670b35SErik Nordmark CONN_DEC_REF(connp);
64397c478bd9Sstevel@tonic-gate }
64407c478bd9Sstevel@tonic-gate
64417c478bd9Sstevel@tonic-gate static void
6442f4b3ec61Sdh155122 ipsec_sctp_pol(ipsec_selector_t *sel, ipsec_policy_t **ppp,
6443f4b3ec61Sdh155122 ip_stack_t *ipst)
64447c478bd9Sstevel@tonic-gate {
64457c478bd9Sstevel@tonic-gate conn_t *connp;
64467c478bd9Sstevel@tonic-gate uint32_t ports;
64477c478bd9Sstevel@tonic-gate uint16_t *pptr = (uint16_t *)&ports;
64487c478bd9Sstevel@tonic-gate
64497c478bd9Sstevel@tonic-gate /*
64507c478bd9Sstevel@tonic-gate * Find SCP state in the following order:
64517c478bd9Sstevel@tonic-gate * 1.) Connected conns.
64527c478bd9Sstevel@tonic-gate * 2.) Listeners.
64537c478bd9Sstevel@tonic-gate *
64547c478bd9Sstevel@tonic-gate * Even though #2 will be the common case for inbound traffic, only
64557c478bd9Sstevel@tonic-gate * following this order insures correctness.
64567c478bd9Sstevel@tonic-gate */
64577c478bd9Sstevel@tonic-gate
64587c478bd9Sstevel@tonic-gate if (sel->ips_local_port == 0)
64597c478bd9Sstevel@tonic-gate return;
64607c478bd9Sstevel@tonic-gate
64617c478bd9Sstevel@tonic-gate /*
64627c478bd9Sstevel@tonic-gate * 0 should be fport, 1 should be lport. SRC is the local one here.
64637c478bd9Sstevel@tonic-gate * See ipsec_construct_inverse_acquire() for details.
64647c478bd9Sstevel@tonic-gate */
64657c478bd9Sstevel@tonic-gate pptr[0] = sel->ips_remote_port;
64667c478bd9Sstevel@tonic-gate pptr[1] = sel->ips_local_port;
64677c478bd9Sstevel@tonic-gate
6468bd670b35SErik Nordmark /*
6469bd670b35SErik Nordmark * For labeled systems, there's no need to check the
6470bd670b35SErik Nordmark * label here. It's known to be good as we checked
6471bd670b35SErik Nordmark * before allowing the connection to become bound.
6472bd670b35SErik Nordmark */
64737c478bd9Sstevel@tonic-gate if (sel->ips_isv4) {
64747c478bd9Sstevel@tonic-gate in6_addr_t src, dst;
64757c478bd9Sstevel@tonic-gate
64767c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sel->ips_remote_addr_v4, &dst);
64777c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sel->ips_local_addr_v4, &src);
6478e35d2278Svi117747 connp = sctp_find_conn(&dst, &src, ports, ALL_ZONES,
6479bd670b35SErik Nordmark 0, ipst->ips_netstack->netstack_sctp);
64807c478bd9Sstevel@tonic-gate } else {
64817c478bd9Sstevel@tonic-gate connp = sctp_find_conn(&sel->ips_remote_addr_v6,
6482e35d2278Svi117747 &sel->ips_local_addr_v6, ports, ALL_ZONES,
6483bd670b35SErik Nordmark 0, ipst->ips_netstack->netstack_sctp);
64847c478bd9Sstevel@tonic-gate }
64857c478bd9Sstevel@tonic-gate if (connp == NULL)
64867c478bd9Sstevel@tonic-gate return;
64878810c16bSdanmcd ipsec_conn_pol(sel, connp, ppp);
6488bd670b35SErik Nordmark CONN_DEC_REF(connp);
64898810c16bSdanmcd }
64908810c16bSdanmcd
64918810c16bSdanmcd /*
64928810c16bSdanmcd * Fill in a query for the SPD (in "sel") using two PF_KEY address extensions.
64938810c16bSdanmcd * Returns 0 or errno, and always sets *diagnostic to something appropriate
64948810c16bSdanmcd * to PF_KEY.
64958810c16bSdanmcd *
64968810c16bSdanmcd * NOTE: For right now, this function (and ipsec_selector_t for that matter),
64978810c16bSdanmcd * ignore prefix lengths in the address extension. Since we match on first-
64988810c16bSdanmcd * entered policies, this shouldn't matter. Also, since we normalize prefix-
64998810c16bSdanmcd * set addresses to mask out the lower bits, we should get a suitable search
65008810c16bSdanmcd * key for the SPD anyway. This is the function to change if the assumption
65018810c16bSdanmcd * about suitable search keys is wrong.
65028810c16bSdanmcd */
65038810c16bSdanmcd static int
65048810c16bSdanmcd ipsec_get_inverse_acquire_sel(ipsec_selector_t *sel, sadb_address_t *srcext,
65058810c16bSdanmcd sadb_address_t *dstext, int *diagnostic)
65068810c16bSdanmcd {
65078810c16bSdanmcd struct sockaddr_in *src, *dst;
65088810c16bSdanmcd struct sockaddr_in6 *src6, *dst6;
65098810c16bSdanmcd
65108810c16bSdanmcd *diagnostic = 0;
65118810c16bSdanmcd
65128810c16bSdanmcd bzero(sel, sizeof (*sel));
65138810c16bSdanmcd sel->ips_protocol = srcext->sadb_address_proto;
65148810c16bSdanmcd dst = (struct sockaddr_in *)(dstext + 1);
65158810c16bSdanmcd if (dst->sin_family == AF_INET6) {
65168810c16bSdanmcd dst6 = (struct sockaddr_in6 *)dst;
65178810c16bSdanmcd src6 = (struct sockaddr_in6 *)(srcext + 1);
65188810c16bSdanmcd if (src6->sin6_family != AF_INET6) {
65198810c16bSdanmcd *diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
65208810c16bSdanmcd return (EINVAL);
65218810c16bSdanmcd }
65228810c16bSdanmcd sel->ips_remote_addr_v6 = dst6->sin6_addr;
65238810c16bSdanmcd sel->ips_local_addr_v6 = src6->sin6_addr;
65248810c16bSdanmcd if (sel->ips_protocol == IPPROTO_ICMPV6) {
65258810c16bSdanmcd sel->ips_is_icmp_inv_acq = 1;
65268810c16bSdanmcd } else {
65278810c16bSdanmcd sel->ips_remote_port = dst6->sin6_port;
65288810c16bSdanmcd sel->ips_local_port = src6->sin6_port;
65298810c16bSdanmcd }
65308810c16bSdanmcd sel->ips_isv4 = B_FALSE;
65318810c16bSdanmcd } else {
65328810c16bSdanmcd src = (struct sockaddr_in *)(srcext + 1);
65338810c16bSdanmcd if (src->sin_family != AF_INET) {
65348810c16bSdanmcd *diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
65358810c16bSdanmcd return (EINVAL);
65368810c16bSdanmcd }
65378810c16bSdanmcd sel->ips_remote_addr_v4 = dst->sin_addr.s_addr;
65388810c16bSdanmcd sel->ips_local_addr_v4 = src->sin_addr.s_addr;
65398810c16bSdanmcd if (sel->ips_protocol == IPPROTO_ICMP) {
65408810c16bSdanmcd sel->ips_is_icmp_inv_acq = 1;
65418810c16bSdanmcd } else {
65428810c16bSdanmcd sel->ips_remote_port = dst->sin_port;
65438810c16bSdanmcd sel->ips_local_port = src->sin_port;
65448810c16bSdanmcd }
65458810c16bSdanmcd sel->ips_isv4 = B_TRUE;
65468810c16bSdanmcd }
65478810c16bSdanmcd return (0);
65488810c16bSdanmcd }
65498810c16bSdanmcd
65508810c16bSdanmcd /*
65518810c16bSdanmcd * We have encapsulation.
65528810c16bSdanmcd * - Lookup tun_t by address and look for an associated
65538810c16bSdanmcd * tunnel policy
65548810c16bSdanmcd * - If there are inner selectors
65558810c16bSdanmcd * - check ITPF_P_TUNNEL and ITPF_P_ACTIVE
65568810c16bSdanmcd * - Look up tunnel policy based on selectors
65578810c16bSdanmcd * - Else
65588810c16bSdanmcd * - Sanity check the negotation
65598810c16bSdanmcd * - If appropriate, fall through to global policy
65608810c16bSdanmcd */
65618810c16bSdanmcd static int
65628810c16bSdanmcd ipsec_tun_pol(ipsec_selector_t *sel, ipsec_policy_t **ppp,
65638810c16bSdanmcd sadb_address_t *innsrcext, sadb_address_t *inndstext, ipsec_tun_pol_t *itp,
6564bd670b35SErik Nordmark int *diagnostic)
65658810c16bSdanmcd {
65668810c16bSdanmcd int err;
65678810c16bSdanmcd ipsec_policy_head_t *polhead;
65688810c16bSdanmcd
6569051c7f8aSDan McDonald *diagnostic = 0;
6570051c7f8aSDan McDonald
65718810c16bSdanmcd /* Check for inner selectors and act appropriately */
65728810c16bSdanmcd
65738810c16bSdanmcd if (innsrcext != NULL) {
65748810c16bSdanmcd /* Inner selectors present */
65758810c16bSdanmcd ASSERT(inndstext != NULL);
65768810c16bSdanmcd if ((itp == NULL) ||
65778810c16bSdanmcd (itp->itp_flags & (ITPF_P_ACTIVE | ITPF_P_TUNNEL)) !=
65788810c16bSdanmcd (ITPF_P_ACTIVE | ITPF_P_TUNNEL)) {
65798810c16bSdanmcd /*
65808810c16bSdanmcd * If inner packet selectors, we must have negotiate
65818810c16bSdanmcd * tunnel and active policy. If the tunnel has
65828810c16bSdanmcd * transport-mode policy set on it, or has no policy,
65838810c16bSdanmcd * fail.
65848810c16bSdanmcd */
65858810c16bSdanmcd return (ENOENT);
65868810c16bSdanmcd } else {
65878810c16bSdanmcd /*
65888810c16bSdanmcd * Reset "sel" to indicate inner selectors. Pass
65898810c16bSdanmcd * inner PF_KEY address extensions for this to happen.
65908810c16bSdanmcd */
65912b24ab6bSSebastien Roy if ((err = ipsec_get_inverse_acquire_sel(sel,
65922b24ab6bSSebastien Roy innsrcext, inndstext, diagnostic)) != 0)
65938810c16bSdanmcd return (err);
65948810c16bSdanmcd /*
65958810c16bSdanmcd * Now look for a tunnel policy based on those inner
65968810c16bSdanmcd * selectors. (Common code is below.)
65978810c16bSdanmcd */
65988810c16bSdanmcd }
65998810c16bSdanmcd } else {
66008810c16bSdanmcd /* No inner selectors present */
66018810c16bSdanmcd if ((itp == NULL) || !(itp->itp_flags & ITPF_P_ACTIVE)) {
66028810c16bSdanmcd /*
66038810c16bSdanmcd * Transport mode negotiation with no tunnel policy
66048810c16bSdanmcd * configured - return to indicate a global policy
66058810c16bSdanmcd * check is needed.
66068810c16bSdanmcd */
66078810c16bSdanmcd return (0);
66088810c16bSdanmcd } else if (itp->itp_flags & ITPF_P_TUNNEL) {
66098810c16bSdanmcd /* Tunnel mode set with no inner selectors. */
66108810c16bSdanmcd return (ENOENT);
66118810c16bSdanmcd }
66128810c16bSdanmcd /*
66138810c16bSdanmcd * Else, this is a tunnel policy configured with ifconfig(1m)
66148810c16bSdanmcd * or "negotiate transport" with ipsecconf(1m). We have an
66158810c16bSdanmcd * itp with policy set based on any match, so don't bother
66168810c16bSdanmcd * changing fields in "sel".
66178810c16bSdanmcd */
66188810c16bSdanmcd }
66198810c16bSdanmcd
66208810c16bSdanmcd ASSERT(itp != NULL);
66218810c16bSdanmcd polhead = itp->itp_policy;
66228810c16bSdanmcd ASSERT(polhead != NULL);
66238810c16bSdanmcd rw_enter(&polhead->iph_lock, RW_READER);
6624bd670b35SErik Nordmark *ppp = ipsec_find_policy_head(NULL, polhead, IPSEC_TYPE_INBOUND, sel);
66258810c16bSdanmcd rw_exit(&polhead->iph_lock);
66268810c16bSdanmcd
66278810c16bSdanmcd /*
66288810c16bSdanmcd * Don't default to global if we didn't find a matching policy entry.
66298810c16bSdanmcd * Instead, send ENOENT, just like if we hit a transport-mode tunnel.
66308810c16bSdanmcd */
66318810c16bSdanmcd if (*ppp == NULL)
66328810c16bSdanmcd return (ENOENT);
66338810c16bSdanmcd
66348810c16bSdanmcd return (0);
66357c478bd9Sstevel@tonic-gate }
66367c478bd9Sstevel@tonic-gate
6637bd670b35SErik Nordmark /*
6638bd670b35SErik Nordmark * For sctp conn_faddr is the primary address, hence this is of limited
6639bd670b35SErik Nordmark * use for sctp.
6640bd670b35SErik Nordmark */
66417c478bd9Sstevel@tonic-gate static void
6642f4b3ec61Sdh155122 ipsec_oth_pol(ipsec_selector_t *sel, ipsec_policy_t **ppp,
6643f4b3ec61Sdh155122 ip_stack_t *ipst)
66447c478bd9Sstevel@tonic-gate {
66457c478bd9Sstevel@tonic-gate boolean_t isv4 = sel->ips_isv4;
66467c478bd9Sstevel@tonic-gate connf_t *connfp;
66477c478bd9Sstevel@tonic-gate conn_t *connp;
66487c478bd9Sstevel@tonic-gate
66497c478bd9Sstevel@tonic-gate if (isv4) {
6650bd670b35SErik Nordmark connfp = &ipst->ips_ipcl_proto_fanout_v4[sel->ips_protocol];
66517c478bd9Sstevel@tonic-gate } else {
6652f4b3ec61Sdh155122 connfp = &ipst->ips_ipcl_proto_fanout_v6[sel->ips_protocol];
66537c478bd9Sstevel@tonic-gate }
66547c478bd9Sstevel@tonic-gate
66557c478bd9Sstevel@tonic-gate mutex_enter(&connfp->connf_lock);
66567c478bd9Sstevel@tonic-gate for (connp = connfp->connf_head; connp != NULL;
66577c478bd9Sstevel@tonic-gate connp = connp->conn_next) {
6658bd670b35SErik Nordmark if (isv4) {
6659bd670b35SErik Nordmark if ((connp->conn_laddr_v4 == INADDR_ANY ||
6660bd670b35SErik Nordmark connp->conn_laddr_v4 == sel->ips_local_addr_v4) &&
6661bd670b35SErik Nordmark (connp->conn_faddr_v4 == INADDR_ANY ||
6662bd670b35SErik Nordmark connp->conn_faddr_v4 == sel->ips_remote_addr_v4))
6663bd670b35SErik Nordmark break;
6664bd670b35SErik Nordmark } else {
6665bd670b35SErik Nordmark if ((IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6) ||
6666bd670b35SErik Nordmark IN6_ARE_ADDR_EQUAL(&connp->conn_laddr_v6,
66677c478bd9Sstevel@tonic-gate &sel->ips_local_addr_v6)) &&
6668bd670b35SErik Nordmark (IN6_IS_ADDR_UNSPECIFIED(&connp->conn_faddr_v6) ||
6669bd670b35SErik Nordmark IN6_ARE_ADDR_EQUAL(&connp->conn_faddr_v6,
6670bd670b35SErik Nordmark &sel->ips_remote_addr_v6)))
66717c478bd9Sstevel@tonic-gate break;
66727c478bd9Sstevel@tonic-gate }
66737c478bd9Sstevel@tonic-gate }
66747c478bd9Sstevel@tonic-gate if (connp == NULL) {
66757c478bd9Sstevel@tonic-gate mutex_exit(&connfp->connf_lock);
66767c478bd9Sstevel@tonic-gate return;
66777c478bd9Sstevel@tonic-gate }
66787c478bd9Sstevel@tonic-gate
66797c478bd9Sstevel@tonic-gate CONN_INC_REF(connp);
66807c478bd9Sstevel@tonic-gate mutex_exit(&connfp->connf_lock);
66817c478bd9Sstevel@tonic-gate
66828810c16bSdanmcd ipsec_conn_pol(sel, connp, ppp);
6683bd670b35SErik Nordmark CONN_DEC_REF(connp);
66847c478bd9Sstevel@tonic-gate }
66857c478bd9Sstevel@tonic-gate
66867c478bd9Sstevel@tonic-gate /*
66877c478bd9Sstevel@tonic-gate * Construct an inverse ACQUIRE reply based on:
66887c478bd9Sstevel@tonic-gate *
66897c478bd9Sstevel@tonic-gate * 1.) Current global policy.
66907c478bd9Sstevel@tonic-gate * 2.) An conn_t match depending on what all was passed in the extv[].
66918810c16bSdanmcd * 3.) A tunnel's policy head.
66927c478bd9Sstevel@tonic-gate * ...
66937c478bd9Sstevel@tonic-gate * N.) Other stuff TBD (e.g. identities)
66947c478bd9Sstevel@tonic-gate *
66957c478bd9Sstevel@tonic-gate * If there is an error, set sadb_msg_errno and sadb_x_msg_diagnostic
66967c478bd9Sstevel@tonic-gate * in this function so the caller can extract them where appropriately.
66977c478bd9Sstevel@tonic-gate *
66987c478bd9Sstevel@tonic-gate * The SRC address is the local one - just like an outbound ACQUIRE message.
66995d3b8cb7SBill Sommerfeld *
67005d3b8cb7SBill Sommerfeld * XXX MLS: key management supplies a label which we just reflect back up
67015d3b8cb7SBill Sommerfeld * again. clearly we need to involve the label in the rest of the checks.
67027c478bd9Sstevel@tonic-gate */
67037c478bd9Sstevel@tonic-gate mblk_t *
6704f4b3ec61Sdh155122 ipsec_construct_inverse_acquire(sadb_msg_t *samsg, sadb_ext_t *extv[],
6705f4b3ec61Sdh155122 netstack_t *ns)
67067c478bd9Sstevel@tonic-gate {
67077c478bd9Sstevel@tonic-gate int err;
67087c478bd9Sstevel@tonic-gate int diagnostic;
67097c478bd9Sstevel@tonic-gate sadb_address_t *srcext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_SRC],
67108810c16bSdanmcd *dstext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_DST],
67118810c16bSdanmcd *innsrcext = (sadb_address_t *)extv[SADB_X_EXT_ADDRESS_INNER_SRC],
67128810c16bSdanmcd *inndstext = (sadb_address_t *)extv[SADB_X_EXT_ADDRESS_INNER_DST];
67135d3b8cb7SBill Sommerfeld sadb_sens_t *sens = (sadb_sens_t *)extv[SADB_EXT_SENSITIVITY];
67148810c16bSdanmcd struct sockaddr_in6 *src, *dst;
67158810c16bSdanmcd struct sockaddr_in6 *isrc, *idst;
67168810c16bSdanmcd ipsec_tun_pol_t *itp = NULL;
67178810c16bSdanmcd ipsec_policy_t *pp = NULL;
67188810c16bSdanmcd ipsec_selector_t sel, isel;
6719051c7f8aSDan McDonald mblk_t *retmp = NULL;
6720f4b3ec61Sdh155122 ip_stack_t *ipst = ns->netstack_ip;
67217c478bd9Sstevel@tonic-gate
67225d3b8cb7SBill Sommerfeld
67238810c16bSdanmcd /* Normalize addresses */
6724f4b3ec61Sdh155122 if (sadb_addrcheck(NULL, (mblk_t *)samsg, (sadb_ext_t *)srcext, 0, ns)
6725f4b3ec61Sdh155122 == KS_IN_ADDR_UNKNOWN) {
67267c478bd9Sstevel@tonic-gate err = EINVAL;
67278810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_BAD_SRC;
67287c478bd9Sstevel@tonic-gate goto bail;
67297c478bd9Sstevel@tonic-gate }
67308810c16bSdanmcd src = (struct sockaddr_in6 *)(srcext + 1);
6731f4b3ec61Sdh155122 if (sadb_addrcheck(NULL, (mblk_t *)samsg, (sadb_ext_t *)dstext, 0, ns)
6732f4b3ec61Sdh155122 == KS_IN_ADDR_UNKNOWN) {
67337c478bd9Sstevel@tonic-gate err = EINVAL;
67348810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_BAD_DST;
67357c478bd9Sstevel@tonic-gate goto bail;
67367c478bd9Sstevel@tonic-gate }
67378810c16bSdanmcd dst = (struct sockaddr_in6 *)(dstext + 1);
67388810c16bSdanmcd if (src->sin6_family != dst->sin6_family) {
67398810c16bSdanmcd err = EINVAL;
67408810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
67418810c16bSdanmcd goto bail;
67427c478bd9Sstevel@tonic-gate }
67438810c16bSdanmcd
67448810c16bSdanmcd /* Check for tunnel mode and act appropriately */
67458810c16bSdanmcd if (innsrcext != NULL) {
67468810c16bSdanmcd if (inndstext == NULL) {
67478810c16bSdanmcd err = EINVAL;
67488810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_DST;
67498810c16bSdanmcd goto bail;
67508810c16bSdanmcd }
67518810c16bSdanmcd if (sadb_addrcheck(NULL, (mblk_t *)samsg,
6752f4b3ec61Sdh155122 (sadb_ext_t *)innsrcext, 0, ns) == KS_IN_ADDR_UNKNOWN) {
67538810c16bSdanmcd err = EINVAL;
67548810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_INNER_SRC;
67558810c16bSdanmcd goto bail;
67568810c16bSdanmcd }
67578810c16bSdanmcd isrc = (struct sockaddr_in6 *)(innsrcext + 1);
67588810c16bSdanmcd if (sadb_addrcheck(NULL, (mblk_t *)samsg,
6759f4b3ec61Sdh155122 (sadb_ext_t *)inndstext, 0, ns) == KS_IN_ADDR_UNKNOWN) {
67608810c16bSdanmcd err = EINVAL;
67618810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_INNER_DST;
67628810c16bSdanmcd goto bail;
67638810c16bSdanmcd }
67648810c16bSdanmcd idst = (struct sockaddr_in6 *)(inndstext + 1);
67658810c16bSdanmcd if (isrc->sin6_family != idst->sin6_family) {
67668810c16bSdanmcd err = EINVAL;
67678810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_INNER_AF_MISMATCH;
67688810c16bSdanmcd goto bail;
67698810c16bSdanmcd }
67708810c16bSdanmcd if (isrc->sin6_family != AF_INET &&
67718810c16bSdanmcd isrc->sin6_family != AF_INET6) {
67728810c16bSdanmcd err = EINVAL;
67738810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_BAD_INNER_SRC_AF;
67748810c16bSdanmcd goto bail;
67758810c16bSdanmcd }
67768810c16bSdanmcd } else if (inndstext != NULL) {
67778810c16bSdanmcd err = EINVAL;
67788810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_SRC;
67798810c16bSdanmcd goto bail;
67808810c16bSdanmcd }
67818810c16bSdanmcd
67828810c16bSdanmcd /* Get selectors first, based on outer addresses */
67838810c16bSdanmcd err = ipsec_get_inverse_acquire_sel(&sel, srcext, dstext, &diagnostic);
67848810c16bSdanmcd if (err != 0)
67858810c16bSdanmcd goto bail;
67868810c16bSdanmcd
67878810c16bSdanmcd /* Check for tunnel mode mismatches. */
67888810c16bSdanmcd if (innsrcext != NULL &&
67898810c16bSdanmcd ((isrc->sin6_family == AF_INET &&
67908810c16bSdanmcd sel.ips_protocol != IPPROTO_ENCAP && sel.ips_protocol != 0) ||
67918810c16bSdanmcd (isrc->sin6_family == AF_INET6 &&
6792437220cdSdanmcd sel.ips_protocol != IPPROTO_IPV6 && sel.ips_protocol != 0))) {
67938810c16bSdanmcd err = EPROTOTYPE;
67948810c16bSdanmcd goto bail;
67957c478bd9Sstevel@tonic-gate }
67967c478bd9Sstevel@tonic-gate
67977c478bd9Sstevel@tonic-gate /*
67987c478bd9Sstevel@tonic-gate * Okay, we have the addresses and other selector information.
67997c478bd9Sstevel@tonic-gate * Let's first find a conn...
68007c478bd9Sstevel@tonic-gate */
68018810c16bSdanmcd pp = NULL;
68027c478bd9Sstevel@tonic-gate switch (sel.ips_protocol) {
68037c478bd9Sstevel@tonic-gate case IPPROTO_TCP:
6804f4b3ec61Sdh155122 ipsec_tcp_pol(&sel, &pp, ipst);
68057c478bd9Sstevel@tonic-gate break;
68067c478bd9Sstevel@tonic-gate case IPPROTO_UDP:
6807f4b3ec61Sdh155122 ipsec_udp_pol(&sel, &pp, ipst);
68087c478bd9Sstevel@tonic-gate break;
68097c478bd9Sstevel@tonic-gate case IPPROTO_SCTP:
6810f4b3ec61Sdh155122 ipsec_sctp_pol(&sel, &pp, ipst);
68118810c16bSdanmcd break;
68128810c16bSdanmcd case IPPROTO_ENCAP:
68138810c16bSdanmcd case IPPROTO_IPV6:
68148810c16bSdanmcd /*
68158810c16bSdanmcd * Assume sel.ips_remote_addr_* has the right address at
68168810c16bSdanmcd * that exact position.
68178810c16bSdanmcd */
68182b24ab6bSSebastien Roy itp = itp_get_byaddr((uint32_t *)(&sel.ips_local_addr_v6),
68192b24ab6bSSebastien Roy (uint32_t *)(&sel.ips_remote_addr_v6), src->sin6_family,
68202b24ab6bSSebastien Roy ipst);
68212b24ab6bSSebastien Roy
68228810c16bSdanmcd if (innsrcext == NULL) {
68238810c16bSdanmcd /*
68248810c16bSdanmcd * Transport-mode tunnel, make sure we fake out isel
68258810c16bSdanmcd * to contain something based on the outer protocol.
68268810c16bSdanmcd */
68278810c16bSdanmcd bzero(&isel, sizeof (isel));
68288810c16bSdanmcd isel.ips_isv4 = (sel.ips_protocol == IPPROTO_ENCAP);
68298810c16bSdanmcd } /* Else isel is initialized by ipsec_tun_pol(). */
68308810c16bSdanmcd err = ipsec_tun_pol(&isel, &pp, innsrcext, inndstext, itp,
6831bd670b35SErik Nordmark &diagnostic);
68328810c16bSdanmcd /*
68338810c16bSdanmcd * NOTE: isel isn't used for now, but in RFC 430x IPsec, it
68348810c16bSdanmcd * may be.
68358810c16bSdanmcd */
68368810c16bSdanmcd if (err != 0)
68378810c16bSdanmcd goto bail;
68387c478bd9Sstevel@tonic-gate break;
68397c478bd9Sstevel@tonic-gate default:
6840f4b3ec61Sdh155122 ipsec_oth_pol(&sel, &pp, ipst);
68417c478bd9Sstevel@tonic-gate break;
68427c478bd9Sstevel@tonic-gate }
68437c478bd9Sstevel@tonic-gate
68447c478bd9Sstevel@tonic-gate /*
68458810c16bSdanmcd * If we didn't find a matching conn_t or other policy head, take a
68468810c16bSdanmcd * look in the global policy.
68477c478bd9Sstevel@tonic-gate */
68488810c16bSdanmcd if (pp == NULL) {
6849bd670b35SErik Nordmark pp = ipsec_find_policy(IPSEC_TYPE_OUTBOUND, NULL, &sel, ns);
68507c478bd9Sstevel@tonic-gate if (pp == NULL) {
68517c478bd9Sstevel@tonic-gate /* There's no global policy. */
68527c478bd9Sstevel@tonic-gate err = ENOENT;
68537c478bd9Sstevel@tonic-gate diagnostic = 0;
68547c478bd9Sstevel@tonic-gate goto bail;
68557c478bd9Sstevel@tonic-gate }
68567c478bd9Sstevel@tonic-gate }
68577c478bd9Sstevel@tonic-gate
68587c478bd9Sstevel@tonic-gate /*
68597c478bd9Sstevel@tonic-gate * Now that we have a policy entry/widget, construct an ACQUIRE
68607c478bd9Sstevel@tonic-gate * message based on that, fix fields where appropriate,
68617c478bd9Sstevel@tonic-gate * and return the message.
68627c478bd9Sstevel@tonic-gate */
68638810c16bSdanmcd retmp = sadb_extended_acquire(&sel, pp, NULL,
68648810c16bSdanmcd (itp != NULL && (itp->itp_flags & ITPF_P_TUNNEL)),
68655d3b8cb7SBill Sommerfeld samsg->sadb_msg_seq, samsg->sadb_msg_pid, sens, ns);
68667c478bd9Sstevel@tonic-gate if (pp != NULL) {
6867bd670b35SErik Nordmark IPPOL_REFRELE(pp);
68687c478bd9Sstevel@tonic-gate }
6869051c7f8aSDan McDonald ASSERT(err == 0 && diagnostic == 0);
6870051c7f8aSDan McDonald if (retmp == NULL)
6871051c7f8aSDan McDonald err = ENOMEM;
6872051c7f8aSDan McDonald bail:
68732b24ab6bSSebastien Roy if (itp != NULL) {
68742b24ab6bSSebastien Roy ITP_REFRELE(itp, ns);
68752b24ab6bSSebastien Roy }
68767c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)err;
68777c478bd9Sstevel@tonic-gate samsg->sadb_x_msg_diagnostic = (uint16_t)diagnostic;
6878051c7f8aSDan McDonald return (retmp);
68797c478bd9Sstevel@tonic-gate }
68807c478bd9Sstevel@tonic-gate
68817c478bd9Sstevel@tonic-gate /*
6882a14de6c8SDan McDonald * ipsa_lpkt is a one-element queue, only manipulated by the next two
6883a14de6c8SDan McDonald * functions. They have to hold the ipsa_lock because of potential races
6884a14de6c8SDan McDonald * between key management using SADB_UPDATE, and inbound packets that may
6885a14de6c8SDan McDonald * queue up on the larval SA (hence the 'l' in "lpkt").
68867c478bd9Sstevel@tonic-gate */
68877c478bd9Sstevel@tonic-gate
68887c478bd9Sstevel@tonic-gate /*
6889930af642SDan McDonald * sadb_set_lpkt:
6890930af642SDan McDonald *
6891930af642SDan McDonald * Returns the passed-in packet if the SA is no longer larval.
6892930af642SDan McDonald *
6893930af642SDan McDonald * Returns NULL if the SA is larval, and needs to be swapped into the SA for
6894930af642SDan McDonald * processing after an SADB_UPDATE.
68957c478bd9Sstevel@tonic-gate */
6896930af642SDan McDonald mblk_t *
6897bd670b35SErik Nordmark sadb_set_lpkt(ipsa_t *ipsa, mblk_t *npkt, ip_recv_attr_t *ira)
68987c478bd9Sstevel@tonic-gate {
68997c478bd9Sstevel@tonic-gate mblk_t *opkt;
69007c478bd9Sstevel@tonic-gate
6901a14de6c8SDan McDonald mutex_enter(&ipsa->ipsa_lock);
6902930af642SDan McDonald opkt = ipsa->ipsa_lpkt;
6903930af642SDan McDonald if (ipsa->ipsa_state == IPSA_STATE_LARVAL) {
6904930af642SDan McDonald /*
6905930af642SDan McDonald * Consume npkt and place it in the LARVAL SA's inbound
6906930af642SDan McDonald * packet slot.
6907930af642SDan McDonald */
6908bd670b35SErik Nordmark mblk_t *attrmp;
6909bd670b35SErik Nordmark
6910bd670b35SErik Nordmark attrmp = ip_recv_attr_to_mblk(ira);
6911bd670b35SErik Nordmark if (attrmp == NULL) {
6912bd670b35SErik Nordmark ill_t *ill = ira->ira_ill;
6913bd670b35SErik Nordmark
6914bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
6915bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", npkt, ill);
6916bd670b35SErik Nordmark freemsg(npkt);
6917bd670b35SErik Nordmark opkt = NULL;
6918bd670b35SErik Nordmark } else {
6919bd670b35SErik Nordmark ASSERT(attrmp->b_cont == NULL);
6920bd670b35SErik Nordmark attrmp->b_cont = npkt;
6921930af642SDan McDonald ipsa->ipsa_lpkt = attrmp;
6922bd670b35SErik Nordmark }
6923930af642SDan McDonald npkt = NULL;
6924a14de6c8SDan McDonald } else {
6925930af642SDan McDonald /*
6926930af642SDan McDonald * If not larval, we lost the race. NOTE: ipsa_lpkt may still
6927930af642SDan McDonald * have been non-NULL in the non-larval case, because of
6928930af642SDan McDonald * inbound packets arriving prior to sadb_common_add()
6929930af642SDan McDonald * transferring the SA completely out of larval state, but
6930930af642SDan McDonald * after lpkt was grabbed by the AH/ESP-specific add routines.
6931930af642SDan McDonald * We should clear the old ipsa_lpkt in this case to make sure
6932930af642SDan McDonald * that it doesn't linger on the now-MATURE IPsec SA, or get
6933930af642SDan McDonald * picked up as an out-of-order packet.
6934930af642SDan McDonald */
6935930af642SDan McDonald ipsa->ipsa_lpkt = NULL;
6936a14de6c8SDan McDonald }
6937a14de6c8SDan McDonald mutex_exit(&ipsa->ipsa_lock);
69387c478bd9Sstevel@tonic-gate
6939bd670b35SErik Nordmark if (opkt != NULL) {
6940930af642SDan McDonald ipsec_stack_t *ipss;
6941930af642SDan McDonald
6942930af642SDan McDonald ipss = ira->ira_ill->ill_ipst->ips_netstack->netstack_ipsec;
6943bd670b35SErik Nordmark opkt = ip_recv_attr_free_mblk(opkt);
6944bd670b35SErik Nordmark ip_drop_packet(opkt, B_TRUE, ira->ira_ill,
6945f4b3ec61Sdh155122 DROPPER(ipss, ipds_sadb_inlarval_replace),
6946f4b3ec61Sdh155122 &ipss->ipsec_sadb_dropper);
6947bd670b35SErik Nordmark }
6948930af642SDan McDonald return (npkt);
69497c478bd9Sstevel@tonic-gate }
69507c478bd9Sstevel@tonic-gate
69517c478bd9Sstevel@tonic-gate /*
69527c478bd9Sstevel@tonic-gate * sadb_clear_lpkt: Atomically clear ipsa->ipsa_lpkt and return the
69537c478bd9Sstevel@tonic-gate * previous value.
69547c478bd9Sstevel@tonic-gate */
69557c478bd9Sstevel@tonic-gate mblk_t *
69567c478bd9Sstevel@tonic-gate sadb_clear_lpkt(ipsa_t *ipsa)
69577c478bd9Sstevel@tonic-gate {
69587c478bd9Sstevel@tonic-gate mblk_t *opkt;
69597c478bd9Sstevel@tonic-gate
6960a14de6c8SDan McDonald mutex_enter(&ipsa->ipsa_lock);
69617c478bd9Sstevel@tonic-gate opkt = ipsa->ipsa_lpkt;
6962a14de6c8SDan McDonald ipsa->ipsa_lpkt = NULL;
6963a14de6c8SDan McDonald mutex_exit(&ipsa->ipsa_lock);
69647c478bd9Sstevel@tonic-gate return (opkt);
69657c478bd9Sstevel@tonic-gate }
69667c478bd9Sstevel@tonic-gate
6967d74f5ecaSDan McDonald /*
6968d74f5ecaSDan McDonald * Buffer a packet that's in IDLE state as set by Solaris Clustering.
6969d74f5ecaSDan McDonald */
69709c2c14abSThejaswini Singarajipura void
6971bd670b35SErik Nordmark sadb_buf_pkt(ipsa_t *ipsa, mblk_t *bpkt, ip_recv_attr_t *ira)
69729c2c14abSThejaswini Singarajipura {
6973bd670b35SErik Nordmark netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
69749c2c14abSThejaswini Singarajipura ipsec_stack_t *ipss = ns->netstack_ipsec;
6975d74f5ecaSDan McDonald in6_addr_t *srcaddr = (in6_addr_t *)(&ipsa->ipsa_srcaddr);
6976d74f5ecaSDan McDonald in6_addr_t *dstaddr = (in6_addr_t *)(&ipsa->ipsa_dstaddr);
6977bd670b35SErik Nordmark mblk_t *mp;
69789c2c14abSThejaswini Singarajipura
69799c2c14abSThejaswini Singarajipura ASSERT(ipsa->ipsa_state == IPSA_STATE_IDLE);
6980d74f5ecaSDan McDonald
6981d74f5ecaSDan McDonald if (cl_inet_idlesa == NULL) {
6982bd670b35SErik Nordmark ip_drop_packet(bpkt, B_TRUE, ira->ira_ill,
6983d74f5ecaSDan McDonald DROPPER(ipss, ipds_sadb_inidle_overflow),
6984d74f5ecaSDan McDonald &ipss->ipsec_sadb_dropper);
6985d74f5ecaSDan McDonald return;
6986d74f5ecaSDan McDonald }
6987d74f5ecaSDan McDonald
69888e4b770fSLu Huafeng cl_inet_idlesa(ns->netstack_stackid,
69898e4b770fSLu Huafeng (ipsa->ipsa_type == SADB_SATYPE_AH) ? IPPROTO_AH : IPPROTO_ESP,
69908e4b770fSLu Huafeng ipsa->ipsa_spi, ipsa->ipsa_addrfam, *srcaddr, *dstaddr, NULL);
6991d74f5ecaSDan McDonald
6992bd670b35SErik Nordmark mp = ip_recv_attr_to_mblk(ira);
6993bd670b35SErik Nordmark if (mp == NULL) {
6994bd670b35SErik Nordmark ip_drop_packet(bpkt, B_TRUE, ira->ira_ill,
6995bd670b35SErik Nordmark DROPPER(ipss, ipds_sadb_inidle_overflow),
6996bd670b35SErik Nordmark &ipss->ipsec_sadb_dropper);
6997bd670b35SErik Nordmark return;
6998bd670b35SErik Nordmark }
6999bd670b35SErik Nordmark linkb(mp, bpkt);
700073184bc7SDan McDonald
70019c2c14abSThejaswini Singarajipura mutex_enter(&ipsa->ipsa_lock);
70029c2c14abSThejaswini Singarajipura ipsa->ipsa_mblkcnt++;
70039c2c14abSThejaswini Singarajipura if (ipsa->ipsa_bpkt_head == NULL) {
70049c2c14abSThejaswini Singarajipura ipsa->ipsa_bpkt_head = ipsa->ipsa_bpkt_tail = bpkt;
70059c2c14abSThejaswini Singarajipura } else {
70069c2c14abSThejaswini Singarajipura ipsa->ipsa_bpkt_tail->b_next = bpkt;
70079c2c14abSThejaswini Singarajipura ipsa->ipsa_bpkt_tail = bpkt;
70089c2c14abSThejaswini Singarajipura if (ipsa->ipsa_mblkcnt > SADB_MAX_IDLEPKTS) {
70099c2c14abSThejaswini Singarajipura mblk_t *tmp;
7010bd670b35SErik Nordmark
70119c2c14abSThejaswini Singarajipura tmp = ipsa->ipsa_bpkt_head;
70129c2c14abSThejaswini Singarajipura ipsa->ipsa_bpkt_head = ipsa->ipsa_bpkt_head->b_next;
7013bd670b35SErik Nordmark tmp = ip_recv_attr_free_mblk(tmp);
7014bd670b35SErik Nordmark ip_drop_packet(tmp, B_TRUE, NULL,
70159c2c14abSThejaswini Singarajipura DROPPER(ipss, ipds_sadb_inidle_overflow),
70169c2c14abSThejaswini Singarajipura &ipss->ipsec_sadb_dropper);
70179c2c14abSThejaswini Singarajipura ipsa->ipsa_mblkcnt --;
70189c2c14abSThejaswini Singarajipura }
70199c2c14abSThejaswini Singarajipura }
70209c2c14abSThejaswini Singarajipura mutex_exit(&ipsa->ipsa_lock);
70219c2c14abSThejaswini Singarajipura }
70229c2c14abSThejaswini Singarajipura
70239c2c14abSThejaswini Singarajipura /*
70249c2c14abSThejaswini Singarajipura * Stub function that taskq_dispatch() invokes to take the mblk (in arg)
70259c2c14abSThejaswini Singarajipura * and put into STREAMS again.
70269c2c14abSThejaswini Singarajipura */
70279c2c14abSThejaswini Singarajipura void
70289c2c14abSThejaswini Singarajipura sadb_clear_buf_pkt(void *ipkt)
70299c2c14abSThejaswini Singarajipura {
70309c2c14abSThejaswini Singarajipura mblk_t *tmp, *buf_pkt;
7031bd670b35SErik Nordmark ip_recv_attr_t iras;
70329c2c14abSThejaswini Singarajipura
70339c2c14abSThejaswini Singarajipura buf_pkt = (mblk_t *)ipkt;
70349c2c14abSThejaswini Singarajipura
70359c2c14abSThejaswini Singarajipura while (buf_pkt != NULL) {
7036bd670b35SErik Nordmark mblk_t *data_mp;
7037bd670b35SErik Nordmark
70389c2c14abSThejaswini Singarajipura tmp = buf_pkt->b_next;
70399c2c14abSThejaswini Singarajipura buf_pkt->b_next = NULL;
7040bd670b35SErik Nordmark
7041bd670b35SErik Nordmark data_mp = buf_pkt->b_cont;
7042bd670b35SErik Nordmark buf_pkt->b_cont = NULL;
7043bd670b35SErik Nordmark if (!ip_recv_attr_from_mblk(buf_pkt, &iras)) {
7044bd670b35SErik Nordmark /* The ill or ip_stack_t disappeared on us. */
7045bd670b35SErik Nordmark ip_drop_input("ip_recv_attr_from_mblk", data_mp, NULL);
7046bd670b35SErik Nordmark freemsg(data_mp);
7047bd670b35SErik Nordmark } else {
7048bd670b35SErik Nordmark ip_input_post_ipsec(data_mp, &iras);
7049bd670b35SErik Nordmark }
7050bd670b35SErik Nordmark ira_cleanup(&iras, B_TRUE);
70519c2c14abSThejaswini Singarajipura buf_pkt = tmp;
70529c2c14abSThejaswini Singarajipura }
70539c2c14abSThejaswini Singarajipura }
70547c478bd9Sstevel@tonic-gate /*
70557c478bd9Sstevel@tonic-gate * Walker callback used by sadb_alg_update() to free/create crypto
70567c478bd9Sstevel@tonic-gate * context template when a crypto software provider is removed or
70577c478bd9Sstevel@tonic-gate * added.
70587c478bd9Sstevel@tonic-gate */
70597c478bd9Sstevel@tonic-gate
70607c478bd9Sstevel@tonic-gate struct sadb_update_alg_state {
70617c478bd9Sstevel@tonic-gate ipsec_algtype_t alg_type;
70627c478bd9Sstevel@tonic-gate uint8_t alg_id;
70637c478bd9Sstevel@tonic-gate boolean_t is_added;
7064bd670b35SErik Nordmark boolean_t async_auth;
7065bd670b35SErik Nordmark boolean_t async_encr;
70667c478bd9Sstevel@tonic-gate };
70677c478bd9Sstevel@tonic-gate
70687c478bd9Sstevel@tonic-gate static void
70697c478bd9Sstevel@tonic-gate sadb_alg_update_cb(isaf_t *head, ipsa_t *entry, void *cookie)
70707c478bd9Sstevel@tonic-gate {
70717c478bd9Sstevel@tonic-gate struct sadb_update_alg_state *update_state =
70727c478bd9Sstevel@tonic-gate (struct sadb_update_alg_state *)cookie;
70737c478bd9Sstevel@tonic-gate crypto_ctx_template_t *ctx_tmpl = NULL;
70747c478bd9Sstevel@tonic-gate
70757c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&head->isaf_lock));
70767c478bd9Sstevel@tonic-gate
70777c478bd9Sstevel@tonic-gate if (entry->ipsa_state == IPSA_STATE_LARVAL)
70787c478bd9Sstevel@tonic-gate return;
70797c478bd9Sstevel@tonic-gate
70807c478bd9Sstevel@tonic-gate mutex_enter(&entry->ipsa_lock);
70817c478bd9Sstevel@tonic-gate
7082bd670b35SErik Nordmark if ((entry->ipsa_encr_alg != SADB_EALG_NONE && entry->ipsa_encr_alg !=
7083bd670b35SErik Nordmark SADB_EALG_NULL && update_state->async_encr) ||
7084bd670b35SErik Nordmark (entry->ipsa_auth_alg != SADB_AALG_NONE &&
7085bd670b35SErik Nordmark update_state->async_auth)) {
7086bd670b35SErik Nordmark entry->ipsa_flags |= IPSA_F_ASYNC;
7087bd670b35SErik Nordmark } else {
7088bd670b35SErik Nordmark entry->ipsa_flags &= ~IPSA_F_ASYNC;
7089bd670b35SErik Nordmark }
7090bd670b35SErik Nordmark
70917c478bd9Sstevel@tonic-gate switch (update_state->alg_type) {
70927c478bd9Sstevel@tonic-gate case IPSEC_ALG_AUTH:
70937c478bd9Sstevel@tonic-gate if (entry->ipsa_auth_alg == update_state->alg_id)
70947c478bd9Sstevel@tonic-gate ctx_tmpl = &entry->ipsa_authtmpl;
70957c478bd9Sstevel@tonic-gate break;
70967c478bd9Sstevel@tonic-gate case IPSEC_ALG_ENCR:
70977c478bd9Sstevel@tonic-gate if (entry->ipsa_encr_alg == update_state->alg_id)
70987c478bd9Sstevel@tonic-gate ctx_tmpl = &entry->ipsa_encrtmpl;
70997c478bd9Sstevel@tonic-gate break;
71007c478bd9Sstevel@tonic-gate default:
71017c478bd9Sstevel@tonic-gate ctx_tmpl = NULL;
71027c478bd9Sstevel@tonic-gate }
71037c478bd9Sstevel@tonic-gate
71047c478bd9Sstevel@tonic-gate if (ctx_tmpl == NULL) {
71057c478bd9Sstevel@tonic-gate mutex_exit(&entry->ipsa_lock);
71067c478bd9Sstevel@tonic-gate return;
71077c478bd9Sstevel@tonic-gate }
71087c478bd9Sstevel@tonic-gate
71097c478bd9Sstevel@tonic-gate /*
71107c478bd9Sstevel@tonic-gate * The context template of the SA may be affected by the change
71117c478bd9Sstevel@tonic-gate * of crypto provider.
71127c478bd9Sstevel@tonic-gate */
71137c478bd9Sstevel@tonic-gate if (update_state->is_added) {
71147c478bd9Sstevel@tonic-gate /* create the context template if not already done */
71157c478bd9Sstevel@tonic-gate if (*ctx_tmpl == NULL) {
71167c478bd9Sstevel@tonic-gate (void) ipsec_create_ctx_tmpl(entry,
71177c478bd9Sstevel@tonic-gate update_state->alg_type);
71187c478bd9Sstevel@tonic-gate }
71197c478bd9Sstevel@tonic-gate } else {
71207c478bd9Sstevel@tonic-gate /*
71217c478bd9Sstevel@tonic-gate * The crypto provider was removed. If the context template
71227c478bd9Sstevel@tonic-gate * exists but it is no longer valid, free it.
71237c478bd9Sstevel@tonic-gate */
71247c478bd9Sstevel@tonic-gate if (*ctx_tmpl != NULL)
71257c478bd9Sstevel@tonic-gate ipsec_destroy_ctx_tmpl(entry, update_state->alg_type);
71267c478bd9Sstevel@tonic-gate }
71277c478bd9Sstevel@tonic-gate
71287c478bd9Sstevel@tonic-gate mutex_exit(&entry->ipsa_lock);
71297c478bd9Sstevel@tonic-gate }
71307c478bd9Sstevel@tonic-gate
71317c478bd9Sstevel@tonic-gate /*
7132bd670b35SErik Nordmark * Invoked by IP when an software crypto provider has been updated, or if
7133bd670b35SErik Nordmark * the crypto synchrony changes. The type and id of the corresponding
7134bd670b35SErik Nordmark * algorithm is passed as argument. The type is set to ALL in the case of
7135bd670b35SErik Nordmark * a synchrony change.
7136bd670b35SErik Nordmark *
71377c478bd9Sstevel@tonic-gate * is_added is B_TRUE if the provider was added, B_FALSE if it was
71387c478bd9Sstevel@tonic-gate * removed. The function updates the SADB and free/creates the
71397c478bd9Sstevel@tonic-gate * context templates associated with SAs if needed.
71407c478bd9Sstevel@tonic-gate */
71417c478bd9Sstevel@tonic-gate
7142fb87b5d2Ssommerfe #define SADB_ALG_UPDATE_WALK(sadb, table) \
7143fb87b5d2Ssommerfe sadb_walker((sadb).table, (sadb).sdb_hashsize, sadb_alg_update_cb, \
7144fb87b5d2Ssommerfe &update_state)
71457c478bd9Sstevel@tonic-gate
71467c478bd9Sstevel@tonic-gate void
7147f4b3ec61Sdh155122 sadb_alg_update(ipsec_algtype_t alg_type, uint8_t alg_id, boolean_t is_added,
7148f4b3ec61Sdh155122 netstack_t *ns)
71497c478bd9Sstevel@tonic-gate {
71507c478bd9Sstevel@tonic-gate struct sadb_update_alg_state update_state;
7151f4b3ec61Sdh155122 ipsecah_stack_t *ahstack = ns->netstack_ipsecah;
7152f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
7153bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec;
71547c478bd9Sstevel@tonic-gate
71557c478bd9Sstevel@tonic-gate update_state.alg_type = alg_type;
71567c478bd9Sstevel@tonic-gate update_state.alg_id = alg_id;
71577c478bd9Sstevel@tonic-gate update_state.is_added = is_added;
7158bd670b35SErik Nordmark update_state.async_auth = ipss->ipsec_algs_exec_mode[IPSEC_ALG_AUTH] ==
7159bd670b35SErik Nordmark IPSEC_ALGS_EXEC_ASYNC;
7160bd670b35SErik Nordmark update_state.async_encr = ipss->ipsec_algs_exec_mode[IPSEC_ALG_ENCR] ==
7161bd670b35SErik Nordmark IPSEC_ALGS_EXEC_ASYNC;
71627c478bd9Sstevel@tonic-gate
7163bd670b35SErik Nordmark if (alg_type == IPSEC_ALG_AUTH || alg_type == IPSEC_ALG_ALL) {
71647c478bd9Sstevel@tonic-gate /* walk the AH tables only for auth. algorithm changes */
7165f4b3ec61Sdh155122 SADB_ALG_UPDATE_WALK(ahstack->ah_sadb.s_v4, sdb_of);
7166f4b3ec61Sdh155122 SADB_ALG_UPDATE_WALK(ahstack->ah_sadb.s_v4, sdb_if);
7167f4b3ec61Sdh155122 SADB_ALG_UPDATE_WALK(ahstack->ah_sadb.s_v6, sdb_of);
7168f4b3ec61Sdh155122 SADB_ALG_UPDATE_WALK(ahstack->ah_sadb.s_v6, sdb_if);
71697c478bd9Sstevel@tonic-gate }
71707c478bd9Sstevel@tonic-gate
71717c478bd9Sstevel@tonic-gate /* walk the ESP tables */
7172f4b3ec61Sdh155122 SADB_ALG_UPDATE_WALK(espstack->esp_sadb.s_v4, sdb_of);
7173f4b3ec61Sdh155122 SADB_ALG_UPDATE_WALK(espstack->esp_sadb.s_v4, sdb_if);
7174f4b3ec61Sdh155122 SADB_ALG_UPDATE_WALK(espstack->esp_sadb.s_v6, sdb_of);
7175f4b3ec61Sdh155122 SADB_ALG_UPDATE_WALK(espstack->esp_sadb.s_v6, sdb_if);
71767c478bd9Sstevel@tonic-gate }
71777c478bd9Sstevel@tonic-gate
71787c478bd9Sstevel@tonic-gate /*
71797c478bd9Sstevel@tonic-gate * Creates a context template for the specified SA. This function
71807c478bd9Sstevel@tonic-gate * is called when an SA is created and when a context template needs
71817c478bd9Sstevel@tonic-gate * to be created due to a change of software provider.
71827c478bd9Sstevel@tonic-gate */
71837c478bd9Sstevel@tonic-gate int
71847c478bd9Sstevel@tonic-gate ipsec_create_ctx_tmpl(ipsa_t *sa, ipsec_algtype_t alg_type)
71857c478bd9Sstevel@tonic-gate {
71867c478bd9Sstevel@tonic-gate ipsec_alginfo_t *alg;
71877c478bd9Sstevel@tonic-gate crypto_mechanism_t mech;
71887c478bd9Sstevel@tonic-gate crypto_key_t *key;
71897c478bd9Sstevel@tonic-gate crypto_ctx_template_t *sa_tmpl;
71907c478bd9Sstevel@tonic-gate int rv;
7191f4b3ec61Sdh155122 ipsec_stack_t *ipss = sa->ipsa_netstack->netstack_ipsec;
71927c478bd9Sstevel@tonic-gate
7193f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
71947c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sa->ipsa_lock));
71957c478bd9Sstevel@tonic-gate
71967c478bd9Sstevel@tonic-gate /* get pointers to the algorithm info, context template, and key */
71977c478bd9Sstevel@tonic-gate switch (alg_type) {
71987c478bd9Sstevel@tonic-gate case IPSEC_ALG_AUTH:
71997c478bd9Sstevel@tonic-gate key = &sa->ipsa_kcfauthkey;
72007c478bd9Sstevel@tonic-gate sa_tmpl = &sa->ipsa_authtmpl;
7201f4b3ec61Sdh155122 alg = ipss->ipsec_alglists[alg_type][sa->ipsa_auth_alg];
72027c478bd9Sstevel@tonic-gate break;
72037c478bd9Sstevel@tonic-gate case IPSEC_ALG_ENCR:
72047c478bd9Sstevel@tonic-gate key = &sa->ipsa_kcfencrkey;
72057c478bd9Sstevel@tonic-gate sa_tmpl = &sa->ipsa_encrtmpl;
7206f4b3ec61Sdh155122 alg = ipss->ipsec_alglists[alg_type][sa->ipsa_encr_alg];
72077c478bd9Sstevel@tonic-gate break;
72087c478bd9Sstevel@tonic-gate default:
72097c478bd9Sstevel@tonic-gate alg = NULL;
72107c478bd9Sstevel@tonic-gate }
72117c478bd9Sstevel@tonic-gate
72127c478bd9Sstevel@tonic-gate if (alg == NULL || !ALG_VALID(alg))
72137c478bd9Sstevel@tonic-gate return (EINVAL);
72147c478bd9Sstevel@tonic-gate
72157c478bd9Sstevel@tonic-gate /* initialize the mech info structure for the framework */
72167c478bd9Sstevel@tonic-gate ASSERT(alg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
72177c478bd9Sstevel@tonic-gate mech.cm_type = alg->alg_mech_type;
72187c478bd9Sstevel@tonic-gate mech.cm_param = NULL;
72197c478bd9Sstevel@tonic-gate mech.cm_param_len = 0;
72207c478bd9Sstevel@tonic-gate
72217c478bd9Sstevel@tonic-gate /* create a new context template */
72227c478bd9Sstevel@tonic-gate rv = crypto_create_ctx_template(&mech, key, sa_tmpl, KM_NOSLEEP);
72237c478bd9Sstevel@tonic-gate
72247c478bd9Sstevel@tonic-gate /*
72257c478bd9Sstevel@tonic-gate * CRYPTO_MECH_NOT_SUPPORTED can be returned if only hardware
72267c478bd9Sstevel@tonic-gate * providers are available for that mechanism. In that case
72277c478bd9Sstevel@tonic-gate * we don't fail, and will generate the context template from
72287c478bd9Sstevel@tonic-gate * the framework callback when a software provider for that
72297c478bd9Sstevel@tonic-gate * mechanism registers.
72307c478bd9Sstevel@tonic-gate *
72317c478bd9Sstevel@tonic-gate * The context template is assigned the special value
72327c478bd9Sstevel@tonic-gate * IPSEC_CTX_TMPL_ALLOC if the allocation failed due to a
72337c478bd9Sstevel@tonic-gate * lack of memory. No attempt will be made to use
72347c478bd9Sstevel@tonic-gate * the context template if it is set to this value.
72357c478bd9Sstevel@tonic-gate */
72367c478bd9Sstevel@tonic-gate if (rv == CRYPTO_HOST_MEMORY) {
72377c478bd9Sstevel@tonic-gate *sa_tmpl = IPSEC_CTX_TMPL_ALLOC;
72387c478bd9Sstevel@tonic-gate } else if (rv != CRYPTO_SUCCESS) {
72397c478bd9Sstevel@tonic-gate *sa_tmpl = NULL;
72407c478bd9Sstevel@tonic-gate if (rv != CRYPTO_MECH_NOT_SUPPORTED)
72417c478bd9Sstevel@tonic-gate return (EINVAL);
72427c478bd9Sstevel@tonic-gate }
72437c478bd9Sstevel@tonic-gate
72447c478bd9Sstevel@tonic-gate return (0);
72457c478bd9Sstevel@tonic-gate }
72467c478bd9Sstevel@tonic-gate
72477c478bd9Sstevel@tonic-gate /*
72487c478bd9Sstevel@tonic-gate * Destroy the context template of the specified algorithm type
72497c478bd9Sstevel@tonic-gate * of the specified SA. Must be called while holding the SA lock.
72507c478bd9Sstevel@tonic-gate */
72517c478bd9Sstevel@tonic-gate void
72527c478bd9Sstevel@tonic-gate ipsec_destroy_ctx_tmpl(ipsa_t *sa, ipsec_algtype_t alg_type)
72537c478bd9Sstevel@tonic-gate {
72547c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&sa->ipsa_lock));
72557c478bd9Sstevel@tonic-gate
72567c478bd9Sstevel@tonic-gate if (alg_type == IPSEC_ALG_AUTH) {
72577c478bd9Sstevel@tonic-gate if (sa->ipsa_authtmpl == IPSEC_CTX_TMPL_ALLOC)
72587c478bd9Sstevel@tonic-gate sa->ipsa_authtmpl = NULL;
72597c478bd9Sstevel@tonic-gate else if (sa->ipsa_authtmpl != NULL) {
72607c478bd9Sstevel@tonic-gate crypto_destroy_ctx_template(sa->ipsa_authtmpl);
72617c478bd9Sstevel@tonic-gate sa->ipsa_authtmpl = NULL;
72627c478bd9Sstevel@tonic-gate }
72637c478bd9Sstevel@tonic-gate } else {
72647c478bd9Sstevel@tonic-gate ASSERT(alg_type == IPSEC_ALG_ENCR);
72657c478bd9Sstevel@tonic-gate if (sa->ipsa_encrtmpl == IPSEC_CTX_TMPL_ALLOC)
72667c478bd9Sstevel@tonic-gate sa->ipsa_encrtmpl = NULL;
72677c478bd9Sstevel@tonic-gate else if (sa->ipsa_encrtmpl != NULL) {
72687c478bd9Sstevel@tonic-gate crypto_destroy_ctx_template(sa->ipsa_encrtmpl);
72697c478bd9Sstevel@tonic-gate sa->ipsa_encrtmpl = NULL;
72707c478bd9Sstevel@tonic-gate }
72717c478bd9Sstevel@tonic-gate }
72727c478bd9Sstevel@tonic-gate }
72737c478bd9Sstevel@tonic-gate
72747c478bd9Sstevel@tonic-gate /*
72757c478bd9Sstevel@tonic-gate * Use the kernel crypto framework to check the validity of a key received
72767c478bd9Sstevel@tonic-gate * via keysock. Returns 0 if the key is OK, -1 otherwise.
72777c478bd9Sstevel@tonic-gate */
72787c478bd9Sstevel@tonic-gate int
72797c478bd9Sstevel@tonic-gate ipsec_check_key(crypto_mech_type_t mech_type, sadb_key_t *sadb_key,
72807c478bd9Sstevel@tonic-gate boolean_t is_auth, int *diag)
72817c478bd9Sstevel@tonic-gate {
72827c478bd9Sstevel@tonic-gate crypto_mechanism_t mech;
72837c478bd9Sstevel@tonic-gate crypto_key_t crypto_key;
72847c478bd9Sstevel@tonic-gate int crypto_rc;
72857c478bd9Sstevel@tonic-gate
72867c478bd9Sstevel@tonic-gate mech.cm_type = mech_type;
72877c478bd9Sstevel@tonic-gate mech.cm_param = NULL;
72887c478bd9Sstevel@tonic-gate mech.cm_param_len = 0;
72897c478bd9Sstevel@tonic-gate
72907c478bd9Sstevel@tonic-gate crypto_key.ck_format = CRYPTO_KEY_RAW;
72917c478bd9Sstevel@tonic-gate crypto_key.ck_data = sadb_key + 1;
72927c478bd9Sstevel@tonic-gate crypto_key.ck_length = sadb_key->sadb_key_bits;
72937c478bd9Sstevel@tonic-gate
72947c478bd9Sstevel@tonic-gate crypto_rc = crypto_key_check(&mech, &crypto_key);
72957c478bd9Sstevel@tonic-gate
72967c478bd9Sstevel@tonic-gate switch (crypto_rc) {
72977c478bd9Sstevel@tonic-gate case CRYPTO_SUCCESS:
72987c478bd9Sstevel@tonic-gate return (0);
72997c478bd9Sstevel@tonic-gate case CRYPTO_MECHANISM_INVALID:
73007c478bd9Sstevel@tonic-gate case CRYPTO_MECH_NOT_SUPPORTED:
73017c478bd9Sstevel@tonic-gate *diag = is_auth ? SADB_X_DIAGNOSTIC_BAD_AALG :
73027c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_BAD_EALG;
73037c478bd9Sstevel@tonic-gate break;
73047c478bd9Sstevel@tonic-gate case CRYPTO_KEY_SIZE_RANGE:
73057c478bd9Sstevel@tonic-gate *diag = is_auth ? SADB_X_DIAGNOSTIC_BAD_AKEYBITS :
73067c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_BAD_EKEYBITS;
73077c478bd9Sstevel@tonic-gate break;
73087c478bd9Sstevel@tonic-gate case CRYPTO_WEAK_KEY:
73097c478bd9Sstevel@tonic-gate *diag = is_auth ? SADB_X_DIAGNOSTIC_WEAK_AKEY :
73107c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_WEAK_EKEY;
73117c478bd9Sstevel@tonic-gate break;
73127c478bd9Sstevel@tonic-gate }
73137c478bd9Sstevel@tonic-gate
73147c478bd9Sstevel@tonic-gate return (-1);
73157c478bd9Sstevel@tonic-gate }
73165d3b8cb7SBill Sommerfeld
73175d3b8cb7SBill Sommerfeld /*
73185d3b8cb7SBill Sommerfeld * Whack options in the outer IP header when ipsec changes the outer label
73195d3b8cb7SBill Sommerfeld *
73205d3b8cb7SBill Sommerfeld * This is inelegant and really could use refactoring.
73215d3b8cb7SBill Sommerfeld */
7322bd670b35SErik Nordmark mblk_t *
7323bd670b35SErik Nordmark sadb_whack_label_v4(mblk_t *mp, ipsa_t *assoc, kstat_named_t *counter,
7324bd670b35SErik Nordmark ipdropper_t *dropper)
73255d3b8cb7SBill Sommerfeld {
73265d3b8cb7SBill Sommerfeld int delta;
73275d3b8cb7SBill Sommerfeld int plen;
73285d3b8cb7SBill Sommerfeld dblk_t *db;
73295d3b8cb7SBill Sommerfeld int hlen;
73305d3b8cb7SBill Sommerfeld uint8_t *opt_storage = assoc->ipsa_opt_storage;
73315d3b8cb7SBill Sommerfeld ipha_t *ipha = (ipha_t *)mp->b_rptr;
73325d3b8cb7SBill Sommerfeld
73335d3b8cb7SBill Sommerfeld plen = ntohs(ipha->ipha_length);
73345d3b8cb7SBill Sommerfeld
73355d3b8cb7SBill Sommerfeld delta = tsol_remove_secopt(ipha, MBLKL(mp));
73365d3b8cb7SBill Sommerfeld mp->b_wptr += delta;
73375d3b8cb7SBill Sommerfeld plen += delta;
73385d3b8cb7SBill Sommerfeld
73395d3b8cb7SBill Sommerfeld /* XXX XXX code copied from tsol_check_label */
73405d3b8cb7SBill Sommerfeld
73415d3b8cb7SBill Sommerfeld /* Make sure we have room for the worst-case addition */
73425d3b8cb7SBill Sommerfeld hlen = IPH_HDR_LENGTH(ipha) + opt_storage[IPOPT_OLEN];
73435d3b8cb7SBill Sommerfeld hlen = (hlen + 3) & ~3;
73445d3b8cb7SBill Sommerfeld if (hlen > IP_MAX_HDR_LENGTH)
73455d3b8cb7SBill Sommerfeld hlen = IP_MAX_HDR_LENGTH;
73465d3b8cb7SBill Sommerfeld hlen -= IPH_HDR_LENGTH(ipha);
73475d3b8cb7SBill Sommerfeld
73485d3b8cb7SBill Sommerfeld db = mp->b_datap;
73495d3b8cb7SBill Sommerfeld if ((db->db_ref != 1) || (mp->b_wptr + hlen > db->db_lim)) {
73505d3b8cb7SBill Sommerfeld int copylen;
73515d3b8cb7SBill Sommerfeld mblk_t *new_mp;
73525d3b8cb7SBill Sommerfeld
73535d3b8cb7SBill Sommerfeld /* allocate enough to be meaningful, but not *too* much */
73545d3b8cb7SBill Sommerfeld copylen = MBLKL(mp);
73555d3b8cb7SBill Sommerfeld if (copylen > 256)
73565d3b8cb7SBill Sommerfeld copylen = 256;
73575d3b8cb7SBill Sommerfeld new_mp = allocb_tmpl(hlen + copylen +
73585d3b8cb7SBill Sommerfeld (mp->b_rptr - mp->b_datap->db_base), mp);
73595d3b8cb7SBill Sommerfeld
7360bd670b35SErik Nordmark if (new_mp == NULL) {
7361bd670b35SErik Nordmark ip_drop_packet(mp, B_FALSE, NULL, counter, dropper);
7362bd670b35SErik Nordmark return (NULL);
7363bd670b35SErik Nordmark }
73645d3b8cb7SBill Sommerfeld
73655d3b8cb7SBill Sommerfeld /* keep the bias */
73665d3b8cb7SBill Sommerfeld new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
73675d3b8cb7SBill Sommerfeld new_mp->b_wptr = new_mp->b_rptr + copylen;
73685d3b8cb7SBill Sommerfeld bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
73695d3b8cb7SBill Sommerfeld new_mp->b_cont = mp;
73705d3b8cb7SBill Sommerfeld if ((mp->b_rptr += copylen) >= mp->b_wptr) {
73715d3b8cb7SBill Sommerfeld new_mp->b_cont = mp->b_cont;
73725d3b8cb7SBill Sommerfeld freeb(mp);
73735d3b8cb7SBill Sommerfeld }
7374bd670b35SErik Nordmark mp = new_mp;
73755d3b8cb7SBill Sommerfeld ipha = (ipha_t *)mp->b_rptr;
73765d3b8cb7SBill Sommerfeld }
73775d3b8cb7SBill Sommerfeld
73785d3b8cb7SBill Sommerfeld delta = tsol_prepend_option(assoc->ipsa_opt_storage, ipha, MBLKL(mp));
73795d3b8cb7SBill Sommerfeld
73805d3b8cb7SBill Sommerfeld ASSERT(delta != -1);
73815d3b8cb7SBill Sommerfeld
73825d3b8cb7SBill Sommerfeld plen += delta;
73835d3b8cb7SBill Sommerfeld mp->b_wptr += delta;
73845d3b8cb7SBill Sommerfeld
73855d3b8cb7SBill Sommerfeld /*
73865d3b8cb7SBill Sommerfeld * Paranoia
73875d3b8cb7SBill Sommerfeld */
73885d3b8cb7SBill Sommerfeld db = mp->b_datap;
73895d3b8cb7SBill Sommerfeld
73905d3b8cb7SBill Sommerfeld ASSERT3P(mp->b_wptr, <=, db->db_lim);
73915d3b8cb7SBill Sommerfeld ASSERT3P(mp->b_rptr, <=, db->db_lim);
73925d3b8cb7SBill Sommerfeld
73935d3b8cb7SBill Sommerfeld ASSERT3P(mp->b_wptr, >=, db->db_base);
73945d3b8cb7SBill Sommerfeld ASSERT3P(mp->b_rptr, >=, db->db_base);
73955d3b8cb7SBill Sommerfeld /* End paranoia */
73965d3b8cb7SBill Sommerfeld
73975d3b8cb7SBill Sommerfeld ipha->ipha_length = htons(plen);
73985d3b8cb7SBill Sommerfeld
7399bd670b35SErik Nordmark return (mp);
74005d3b8cb7SBill Sommerfeld }
74015d3b8cb7SBill Sommerfeld
7402bd670b35SErik Nordmark mblk_t *
7403bd670b35SErik Nordmark sadb_whack_label_v6(mblk_t *mp, ipsa_t *assoc, kstat_named_t *counter,
7404bd670b35SErik Nordmark ipdropper_t *dropper)
74055d3b8cb7SBill Sommerfeld {
74065d3b8cb7SBill Sommerfeld int delta;
74075d3b8cb7SBill Sommerfeld int plen;
74085d3b8cb7SBill Sommerfeld dblk_t *db;
74095d3b8cb7SBill Sommerfeld int hlen;
74105d3b8cb7SBill Sommerfeld uint8_t *opt_storage = assoc->ipsa_opt_storage;
74115d3b8cb7SBill Sommerfeld uint_t sec_opt_len; /* label option length not including type, len */
74125d3b8cb7SBill Sommerfeld ip6_t *ip6h = (ip6_t *)mp->b_rptr;
74135d3b8cb7SBill Sommerfeld
74145d3b8cb7SBill Sommerfeld plen = ntohs(ip6h->ip6_plen);
74155d3b8cb7SBill Sommerfeld
74165d3b8cb7SBill Sommerfeld delta = tsol_remove_secopt_v6(ip6h, MBLKL(mp));
74175d3b8cb7SBill Sommerfeld mp->b_wptr += delta;
74185d3b8cb7SBill Sommerfeld plen += delta;
74195d3b8cb7SBill Sommerfeld
74205d3b8cb7SBill Sommerfeld /* XXX XXX code copied from tsol_check_label_v6 */
74215d3b8cb7SBill Sommerfeld /*
74225d3b8cb7SBill Sommerfeld * Make sure we have room for the worst-case addition. Add 2 bytes for
74235d3b8cb7SBill Sommerfeld * the hop-by-hop ext header's next header and length fields. Add
74245d3b8cb7SBill Sommerfeld * another 2 bytes for the label option type, len and then round
74255d3b8cb7SBill Sommerfeld * up to the next 8-byte multiple.
74265d3b8cb7SBill Sommerfeld */
74275d3b8cb7SBill Sommerfeld sec_opt_len = opt_storage[1];
74285d3b8cb7SBill Sommerfeld
74295d3b8cb7SBill Sommerfeld db = mp->b_datap;
74305d3b8cb7SBill Sommerfeld hlen = (4 + sec_opt_len + 7) & ~7;
74315d3b8cb7SBill Sommerfeld
74325d3b8cb7SBill Sommerfeld if ((db->db_ref != 1) || (mp->b_wptr + hlen > db->db_lim)) {
74335d3b8cb7SBill Sommerfeld int copylen;
74345d3b8cb7SBill Sommerfeld mblk_t *new_mp;
74355d3b8cb7SBill Sommerfeld uint16_t hdr_len;
74365d3b8cb7SBill Sommerfeld
74375d3b8cb7SBill Sommerfeld hdr_len = ip_hdr_length_v6(mp, ip6h);
74385d3b8cb7SBill Sommerfeld /*
74395d3b8cb7SBill Sommerfeld * Allocate enough to be meaningful, but not *too* much.
74405d3b8cb7SBill Sommerfeld * Also all the IPv6 extension headers must be in the same mblk
74415d3b8cb7SBill Sommerfeld */
74425d3b8cb7SBill Sommerfeld copylen = MBLKL(mp);
74435d3b8cb7SBill Sommerfeld if (copylen > 256)
74445d3b8cb7SBill Sommerfeld copylen = 256;
74455d3b8cb7SBill Sommerfeld if (copylen < hdr_len)
74465d3b8cb7SBill Sommerfeld copylen = hdr_len;
74475d3b8cb7SBill Sommerfeld new_mp = allocb_tmpl(hlen + copylen +
74485d3b8cb7SBill Sommerfeld (mp->b_rptr - mp->b_datap->db_base), mp);
7449bd670b35SErik Nordmark if (new_mp == NULL) {
7450bd670b35SErik Nordmark ip_drop_packet(mp, B_FALSE, NULL, counter, dropper);
7451bd670b35SErik Nordmark return (NULL);
7452bd670b35SErik Nordmark }
74535d3b8cb7SBill Sommerfeld
74545d3b8cb7SBill Sommerfeld /* keep the bias */
74555d3b8cb7SBill Sommerfeld new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
74565d3b8cb7SBill Sommerfeld new_mp->b_wptr = new_mp->b_rptr + copylen;
74575d3b8cb7SBill Sommerfeld bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
74585d3b8cb7SBill Sommerfeld new_mp->b_cont = mp;
74595d3b8cb7SBill Sommerfeld if ((mp->b_rptr += copylen) >= mp->b_wptr) {
74605d3b8cb7SBill Sommerfeld new_mp->b_cont = mp->b_cont;
74615d3b8cb7SBill Sommerfeld freeb(mp);
74625d3b8cb7SBill Sommerfeld }
7463bd670b35SErik Nordmark mp = new_mp;
74645d3b8cb7SBill Sommerfeld ip6h = (ip6_t *)mp->b_rptr;
74655d3b8cb7SBill Sommerfeld }
74665d3b8cb7SBill Sommerfeld
74675d3b8cb7SBill Sommerfeld delta = tsol_prepend_option_v6(assoc->ipsa_opt_storage,
74685d3b8cb7SBill Sommerfeld ip6h, MBLKL(mp));
74695d3b8cb7SBill Sommerfeld
74705d3b8cb7SBill Sommerfeld ASSERT(delta != -1);
74715d3b8cb7SBill Sommerfeld
74725d3b8cb7SBill Sommerfeld plen += delta;
74735d3b8cb7SBill Sommerfeld mp->b_wptr += delta;
74745d3b8cb7SBill Sommerfeld
74755d3b8cb7SBill Sommerfeld /*
74765d3b8cb7SBill Sommerfeld * Paranoia
74775d3b8cb7SBill Sommerfeld */
74785d3b8cb7SBill Sommerfeld db = mp->b_datap;
74795d3b8cb7SBill Sommerfeld
74805d3b8cb7SBill Sommerfeld ASSERT3P(mp->b_wptr, <=, db->db_lim);
74815d3b8cb7SBill Sommerfeld ASSERT3P(mp->b_rptr, <=, db->db_lim);
74825d3b8cb7SBill Sommerfeld
74835d3b8cb7SBill Sommerfeld ASSERT3P(mp->b_wptr, >=, db->db_base);
74845d3b8cb7SBill Sommerfeld ASSERT3P(mp->b_rptr, >=, db->db_base);
74855d3b8cb7SBill Sommerfeld /* End paranoia */
74865d3b8cb7SBill Sommerfeld
74875d3b8cb7SBill Sommerfeld ip6h->ip6_plen = htons(plen);
74885d3b8cb7SBill Sommerfeld
7489bd670b35SErik Nordmark return (mp);
74905d3b8cb7SBill Sommerfeld }
74915d3b8cb7SBill Sommerfeld
7492bd670b35SErik Nordmark /* Whack the labels and update ip_xmit_attr_t as needed */
7493bd670b35SErik Nordmark mblk_t *
7494bd670b35SErik Nordmark sadb_whack_label(mblk_t *mp, ipsa_t *assoc, ip_xmit_attr_t *ixa,
7495bd670b35SErik Nordmark kstat_named_t *counter, ipdropper_t *dropper)
7496bd670b35SErik Nordmark {
7497bd670b35SErik Nordmark int adjust;
7498bd670b35SErik Nordmark int iplen;
74995d3b8cb7SBill Sommerfeld
7500bd670b35SErik Nordmark if (ixa->ixa_flags & IXAF_IS_IPV4) {
7501bd670b35SErik Nordmark ipha_t *ipha = (ipha_t *)mp->b_rptr;
7502bd670b35SErik Nordmark
7503bd670b35SErik Nordmark ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION);
7504bd670b35SErik Nordmark iplen = ntohs(ipha->ipha_length);
7505bd670b35SErik Nordmark mp = sadb_whack_label_v4(mp, assoc, counter, dropper);
7506bd670b35SErik Nordmark if (mp == NULL)
7507bd670b35SErik Nordmark return (NULL);
7508bd670b35SErik Nordmark
7509bd670b35SErik Nordmark ipha = (ipha_t *)mp->b_rptr;
7510bd670b35SErik Nordmark ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION);
7511bd670b35SErik Nordmark adjust = (int)ntohs(ipha->ipha_length) - iplen;
7512bd670b35SErik Nordmark } else {
7513bd670b35SErik Nordmark ip6_t *ip6h = (ip6_t *)mp->b_rptr;
7514bd670b35SErik Nordmark
7515bd670b35SErik Nordmark ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
7516bd670b35SErik Nordmark iplen = ntohs(ip6h->ip6_plen);
7517bd670b35SErik Nordmark mp = sadb_whack_label_v6(mp, assoc, counter, dropper);
7518bd670b35SErik Nordmark if (mp == NULL)
7519bd670b35SErik Nordmark return (NULL);
7520bd670b35SErik Nordmark
7521bd670b35SErik Nordmark ip6h = (ip6_t *)mp->b_rptr;
7522bd670b35SErik Nordmark ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
7523bd670b35SErik Nordmark adjust = (int)ntohs(ip6h->ip6_plen) - iplen;
7524bd670b35SErik Nordmark }
7525bd670b35SErik Nordmark ixa->ixa_pktlen += adjust;
7526bd670b35SErik Nordmark ixa->ixa_ip_hdr_length += adjust;
7527bd670b35SErik Nordmark return (mp);
7528bd670b35SErik Nordmark }
75295d3b8cb7SBill Sommerfeld
753038d95a78Smarkfen /*
753138d95a78Smarkfen * If this is an outgoing SA then add some fuzz to the
753238d95a78Smarkfen * SOFT EXPIRE time. The reason for this is to stop
753338d95a78Smarkfen * peers trying to renegotiate SOFT expiring SA's at
753438d95a78Smarkfen * the same time. The amount of fuzz needs to be at
75350e9b5742SDan McDonald * least 8 seconds which is the typical interval
753638d95a78Smarkfen * sadb_ager(), although this is only a guide as it
753738d95a78Smarkfen * selftunes.
753838d95a78Smarkfen */
75395d3b8cb7SBill Sommerfeld static void
754038d95a78Smarkfen lifetime_fuzz(ipsa_t *assoc)
754138d95a78Smarkfen {
754238d95a78Smarkfen uint8_t rnd;
754338d95a78Smarkfen
754438d95a78Smarkfen if (assoc->ipsa_softaddlt == 0)
754538d95a78Smarkfen return;
754638d95a78Smarkfen
754738d95a78Smarkfen (void) random_get_pseudo_bytes(&rnd, sizeof (rnd));
75480e9b5742SDan McDonald rnd = (rnd & 0xF) + 8;
754938d95a78Smarkfen assoc->ipsa_softexpiretime -= rnd;
755038d95a78Smarkfen assoc->ipsa_softaddlt -= rnd;
755138d95a78Smarkfen }
75525d3b8cb7SBill Sommerfeld
75535d3b8cb7SBill Sommerfeld static void
755438d95a78Smarkfen destroy_ipsa_pair(ipsap_t *ipsapp)
755538d95a78Smarkfen {
755638d95a78Smarkfen /*
755738d95a78Smarkfen * Because of the multi-line macro nature of IPSA_REFRELE, keep
755838d95a78Smarkfen * them in { }.
755938d95a78Smarkfen */
756038d95a78Smarkfen if (ipsapp->ipsap_sa_ptr != NULL) {
756138d95a78Smarkfen IPSA_REFRELE(ipsapp->ipsap_sa_ptr);
756238d95a78Smarkfen }
756338d95a78Smarkfen if (ipsapp->ipsap_psa_ptr != NULL) {
756438d95a78Smarkfen IPSA_REFRELE(ipsapp->ipsap_psa_ptr);
756538d95a78Smarkfen }
75665d3b8cb7SBill Sommerfeld init_ipsa_pair(ipsapp);
75675d3b8cb7SBill Sommerfeld }
756838d95a78Smarkfen
75695d3b8cb7SBill Sommerfeld static void
75705d3b8cb7SBill Sommerfeld init_ipsa_pair(ipsap_t *ipsapp)
75715d3b8cb7SBill Sommerfeld {
75725d3b8cb7SBill Sommerfeld ipsapp->ipsap_bucket = NULL;
75735d3b8cb7SBill Sommerfeld ipsapp->ipsap_sa_ptr = NULL;
75745d3b8cb7SBill Sommerfeld ipsapp->ipsap_pbucket = NULL;
75755d3b8cb7SBill Sommerfeld ipsapp->ipsap_psa_ptr = NULL;
757638d95a78Smarkfen }
757738d95a78Smarkfen
757838d95a78Smarkfen /*
757938d95a78Smarkfen * The sadb_ager() function walks through the hash tables of SA's and ages
758038d95a78Smarkfen * them, if the SA expires as a result, its marked as DEAD and will be reaped
758138d95a78Smarkfen * the next time sadb_ager() runs. SA's which are paired or have a peer (same
758238d95a78Smarkfen * SA appears in both the inbound and outbound tables because its not possible
758338d95a78Smarkfen * to determine its direction) are placed on a list when they expire. This is
758438d95a78Smarkfen * to ensure that pair/peer SA's are reaped at the same time, even if they
758538d95a78Smarkfen * expire at different times.
758638d95a78Smarkfen *
758738d95a78Smarkfen * This function is called twice by sadb_ager(), one after processing the
758838d95a78Smarkfen * inbound table, then again after processing the outbound table.
758938d95a78Smarkfen */
759038d95a78Smarkfen void
759138d95a78Smarkfen age_pair_peer_list(templist_t *haspeerlist, sadb_t *sp, boolean_t outbound)
759238d95a78Smarkfen {
759338d95a78Smarkfen templist_t *listptr;
759438d95a78Smarkfen int outhash;
759538d95a78Smarkfen isaf_t *bucket;
759638d95a78Smarkfen boolean_t haspeer;
759738d95a78Smarkfen ipsa_t *peer_assoc, *dying;
759838d95a78Smarkfen /*
759938d95a78Smarkfen * Haspeer cases will contain both IPv4 and IPv6. This code
760038d95a78Smarkfen * is address independent.
760138d95a78Smarkfen */
760238d95a78Smarkfen while (haspeerlist != NULL) {
760338d95a78Smarkfen /* "dying" contains the SA that has a peer. */
760438d95a78Smarkfen dying = haspeerlist->ipsa;
760538d95a78Smarkfen haspeer = (dying->ipsa_haspeer);
760638d95a78Smarkfen listptr = haspeerlist;
760738d95a78Smarkfen haspeerlist = listptr->next;
760838d95a78Smarkfen kmem_free(listptr, sizeof (*listptr));
760938d95a78Smarkfen /*
761038d95a78Smarkfen * Pick peer bucket based on addrfam.
761138d95a78Smarkfen */
761238d95a78Smarkfen if (outbound) {
761338d95a78Smarkfen if (haspeer)
761438d95a78Smarkfen bucket = INBOUND_BUCKET(sp, dying->ipsa_spi);
761538d95a78Smarkfen else
761638d95a78Smarkfen bucket = INBOUND_BUCKET(sp,
761738d95a78Smarkfen dying->ipsa_otherspi);
761838d95a78Smarkfen } else { /* inbound */
761938d95a78Smarkfen if (haspeer) {
762038d95a78Smarkfen if (dying->ipsa_addrfam == AF_INET6) {
762138d95a78Smarkfen outhash = OUTBOUND_HASH_V6(sp,
762238d95a78Smarkfen *((in6_addr_t *)&dying->
762338d95a78Smarkfen ipsa_dstaddr));
762438d95a78Smarkfen } else {
762538d95a78Smarkfen outhash = OUTBOUND_HASH_V4(sp,
762638d95a78Smarkfen *((ipaddr_t *)&dying->
762738d95a78Smarkfen ipsa_dstaddr));
762838d95a78Smarkfen }
762938d95a78Smarkfen } else if (dying->ipsa_addrfam == AF_INET6) {
763038d95a78Smarkfen outhash = OUTBOUND_HASH_V6(sp,
763138d95a78Smarkfen *((in6_addr_t *)&dying->
763238d95a78Smarkfen ipsa_srcaddr));
763338d95a78Smarkfen } else {
763438d95a78Smarkfen outhash = OUTBOUND_HASH_V4(sp,
763538d95a78Smarkfen *((ipaddr_t *)&dying->
763638d95a78Smarkfen ipsa_srcaddr));
763738d95a78Smarkfen }
763838d95a78Smarkfen bucket = &(sp->sdb_of[outhash]);
763938d95a78Smarkfen }
764038d95a78Smarkfen
764138d95a78Smarkfen mutex_enter(&bucket->isaf_lock);
764238d95a78Smarkfen /*
764338d95a78Smarkfen * "haspeer" SA's have the same src/dst address ordering,
764438d95a78Smarkfen * "paired" SA's have the src/dst addresses reversed.
764538d95a78Smarkfen */
764638d95a78Smarkfen if (haspeer) {
764738d95a78Smarkfen peer_assoc = ipsec_getassocbyspi(bucket,
764838d95a78Smarkfen dying->ipsa_spi, dying->ipsa_srcaddr,
764938d95a78Smarkfen dying->ipsa_dstaddr, dying->ipsa_addrfam);
765038d95a78Smarkfen } else {
765138d95a78Smarkfen peer_assoc = ipsec_getassocbyspi(bucket,
765238d95a78Smarkfen dying->ipsa_otherspi, dying->ipsa_dstaddr,
765338d95a78Smarkfen dying->ipsa_srcaddr, dying->ipsa_addrfam);
765438d95a78Smarkfen }
765538d95a78Smarkfen
765638d95a78Smarkfen mutex_exit(&bucket->isaf_lock);
765738d95a78Smarkfen if (peer_assoc != NULL) {
765838d95a78Smarkfen mutex_enter(&peer_assoc->ipsa_lock);
765938d95a78Smarkfen mutex_enter(&dying->ipsa_lock);
766038d95a78Smarkfen if (!haspeer) {
766138d95a78Smarkfen /*
766238d95a78Smarkfen * Only SA's which have a "peer" or are
766338d95a78Smarkfen * "paired" end up on this list, so this
766438d95a78Smarkfen * must be a "paired" SA, update the flags
766538d95a78Smarkfen * to break the pair.
766638d95a78Smarkfen */
766738d95a78Smarkfen peer_assoc->ipsa_otherspi = 0;
766838d95a78Smarkfen peer_assoc->ipsa_flags &= ~IPSA_F_PAIRED;
766938d95a78Smarkfen dying->ipsa_otherspi = 0;
767038d95a78Smarkfen dying->ipsa_flags &= ~IPSA_F_PAIRED;
767138d95a78Smarkfen }
767238d95a78Smarkfen if (haspeer || outbound) {
767338d95a78Smarkfen /*
767438d95a78Smarkfen * Update the state of the "inbound" SA when
767538d95a78Smarkfen * the "outbound" SA has expired. Don't update
767638d95a78Smarkfen * the "outbound" SA when the "inbound" SA
767738d95a78Smarkfen * SA expires because setting the hard_addtime
767838d95a78Smarkfen * below will cause this to happen.
767938d95a78Smarkfen */
768038d95a78Smarkfen peer_assoc->ipsa_state = dying->ipsa_state;
768138d95a78Smarkfen }
768238d95a78Smarkfen if (dying->ipsa_state == IPSA_STATE_DEAD)
768338d95a78Smarkfen peer_assoc->ipsa_hardexpiretime = 1;
768438d95a78Smarkfen
768538d95a78Smarkfen mutex_exit(&dying->ipsa_lock);
768638d95a78Smarkfen mutex_exit(&peer_assoc->ipsa_lock);
768738d95a78Smarkfen IPSA_REFRELE(peer_assoc);
768838d95a78Smarkfen }
768938d95a78Smarkfen IPSA_REFRELE(dying);
769038d95a78Smarkfen }
769138d95a78Smarkfen }
7692628b0c67SMark Fenwick
7693628b0c67SMark Fenwick /*
7694628b0c67SMark Fenwick * Ensure that the IV used for CCM mode never repeats. The IV should
7695628b0c67SMark Fenwick * only be updated by this function. Also check to see if the IV
7696628b0c67SMark Fenwick * is about to wrap and generate a SOFT Expire. This function is only
7697628b0c67SMark Fenwick * called for outgoing packets, the IV for incomming packets is taken
7698628b0c67SMark Fenwick * from the wire. If the outgoing SA needs to be expired, update
7699628b0c67SMark Fenwick * the matching incomming SA.
7700628b0c67SMark Fenwick */
7701628b0c67SMark Fenwick boolean_t
7702628b0c67SMark Fenwick update_iv(uint8_t *iv_ptr, queue_t *pfkey_q, ipsa_t *assoc,
7703628b0c67SMark Fenwick ipsecesp_stack_t *espstack)
7704628b0c67SMark Fenwick {
7705628b0c67SMark Fenwick boolean_t rc = B_TRUE;
7706628b0c67SMark Fenwick isaf_t *inbound_bucket;
7707628b0c67SMark Fenwick sadb_t *sp;
7708628b0c67SMark Fenwick ipsa_t *pair_sa = NULL;
7709628b0c67SMark Fenwick int sa_new_state = 0;
7710628b0c67SMark Fenwick
7711628b0c67SMark Fenwick /* For non counter modes, the IV is random data. */
7712628b0c67SMark Fenwick if (!(assoc->ipsa_flags & IPSA_F_COUNTERMODE)) {
7713628b0c67SMark Fenwick (void) random_get_pseudo_bytes(iv_ptr, assoc->ipsa_iv_len);
7714628b0c67SMark Fenwick return (rc);
7715628b0c67SMark Fenwick }
7716628b0c67SMark Fenwick
7717628b0c67SMark Fenwick mutex_enter(&assoc->ipsa_lock);
7718628b0c67SMark Fenwick
7719628b0c67SMark Fenwick (*assoc->ipsa_iv)++;
7720628b0c67SMark Fenwick
7721628b0c67SMark Fenwick if (*assoc->ipsa_iv == assoc->ipsa_iv_hardexpire) {
7722628b0c67SMark Fenwick sa_new_state = IPSA_STATE_DEAD;
7723628b0c67SMark Fenwick rc = B_FALSE;
7724628b0c67SMark Fenwick } else if (*assoc->ipsa_iv == assoc->ipsa_iv_softexpire) {
7725628b0c67SMark Fenwick if (assoc->ipsa_state != IPSA_STATE_DYING) {
7726628b0c67SMark Fenwick /*
7727628b0c67SMark Fenwick * This SA may have already been expired when its
7728628b0c67SMark Fenwick * PAIR_SA expired.
7729628b0c67SMark Fenwick */
7730628b0c67SMark Fenwick sa_new_state = IPSA_STATE_DYING;
7731628b0c67SMark Fenwick }
7732628b0c67SMark Fenwick }
7733628b0c67SMark Fenwick if (sa_new_state) {
7734628b0c67SMark Fenwick /*
7735628b0c67SMark Fenwick * If there is a state change, we need to update this SA
7736628b0c67SMark Fenwick * and its "pair", we can find the bucket for the "pair" SA
7737628b0c67SMark Fenwick * while holding the ipsa_t mutex, but we won't actually
7738628b0c67SMark Fenwick * update anything untill the ipsa_t mutex has been released
7739628b0c67SMark Fenwick * for _this_ SA.
7740628b0c67SMark Fenwick */
7741628b0c67SMark Fenwick assoc->ipsa_state = sa_new_state;
7742628b0c67SMark Fenwick if (assoc->ipsa_addrfam == AF_INET6) {
7743628b0c67SMark Fenwick sp = &espstack->esp_sadb.s_v6;
7744628b0c67SMark Fenwick } else {
7745628b0c67SMark Fenwick sp = &espstack->esp_sadb.s_v4;
7746628b0c67SMark Fenwick }
7747628b0c67SMark Fenwick inbound_bucket = INBOUND_BUCKET(sp, assoc->ipsa_otherspi);
7748628b0c67SMark Fenwick sadb_expire_assoc(pfkey_q, assoc);
7749628b0c67SMark Fenwick }
7750628b0c67SMark Fenwick if (rc == B_TRUE)
7751628b0c67SMark Fenwick bcopy(assoc->ipsa_iv, iv_ptr, assoc->ipsa_iv_len);
7752628b0c67SMark Fenwick
7753628b0c67SMark Fenwick mutex_exit(&assoc->ipsa_lock);
7754628b0c67SMark Fenwick
7755628b0c67SMark Fenwick if (sa_new_state) {
7756628b0c67SMark Fenwick /* Find the inbound SA, need to lock hash bucket. */
7757628b0c67SMark Fenwick mutex_enter(&inbound_bucket->isaf_lock);
7758628b0c67SMark Fenwick pair_sa = ipsec_getassocbyspi(inbound_bucket,
7759628b0c67SMark Fenwick assoc->ipsa_otherspi, assoc->ipsa_dstaddr,
7760628b0c67SMark Fenwick assoc->ipsa_srcaddr, assoc->ipsa_addrfam);
7761628b0c67SMark Fenwick mutex_exit(&inbound_bucket->isaf_lock);
7762628b0c67SMark Fenwick if (pair_sa != NULL) {
7763628b0c67SMark Fenwick mutex_enter(&pair_sa->ipsa_lock);
7764628b0c67SMark Fenwick pair_sa->ipsa_state = sa_new_state;
7765628b0c67SMark Fenwick mutex_exit(&pair_sa->ipsa_lock);
7766628b0c67SMark Fenwick IPSA_REFRELE(pair_sa);
7767628b0c67SMark Fenwick }
7768628b0c67SMark Fenwick }
7769628b0c67SMark Fenwick
7770628b0c67SMark Fenwick return (rc);
7771628b0c67SMark Fenwick }
7772628b0c67SMark Fenwick
7773628b0c67SMark Fenwick void
7774628b0c67SMark Fenwick ccm_params_init(ipsa_t *assoc, uchar_t *esph, uint_t data_len, uchar_t *iv_ptr,
7775628b0c67SMark Fenwick ipsa_cm_mech_t *cm_mech, crypto_data_t *crypto_data)
7776628b0c67SMark Fenwick {
7777628b0c67SMark Fenwick uchar_t *nonce;
7778628b0c67SMark Fenwick crypto_mechanism_t *combined_mech;
7779628b0c67SMark Fenwick CK_AES_CCM_PARAMS *params;
7780628b0c67SMark Fenwick
7781628b0c67SMark Fenwick combined_mech = (crypto_mechanism_t *)cm_mech;
7782628b0c67SMark Fenwick params = (CK_AES_CCM_PARAMS *)(combined_mech + 1);
7783628b0c67SMark Fenwick nonce = (uchar_t *)(params + 1);
7784628b0c67SMark Fenwick params->ulMACSize = assoc->ipsa_mac_len;
7785628b0c67SMark Fenwick params->ulNonceSize = assoc->ipsa_nonce_len;
7786628b0c67SMark Fenwick params->ulAuthDataSize = sizeof (esph_t);
7787628b0c67SMark Fenwick params->ulDataSize = data_len;
7788628b0c67SMark Fenwick params->nonce = nonce;
7789628b0c67SMark Fenwick params->authData = esph;
7790628b0c67SMark Fenwick
7791628b0c67SMark Fenwick cm_mech->combined_mech.cm_type = assoc->ipsa_emech.cm_type;
7792628b0c67SMark Fenwick cm_mech->combined_mech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
7793628b0c67SMark Fenwick cm_mech->combined_mech.cm_param = (caddr_t)params;
7794628b0c67SMark Fenwick /* See gcm_params_init() for comments. */
7795628b0c67SMark Fenwick bcopy(assoc->ipsa_nonce, nonce, assoc->ipsa_saltlen);
7796628b0c67SMark Fenwick nonce += assoc->ipsa_saltlen;
7797628b0c67SMark Fenwick bcopy(iv_ptr, nonce, assoc->ipsa_iv_len);
7798628b0c67SMark Fenwick crypto_data->cd_miscdata = NULL;
7799628b0c67SMark Fenwick }
7800628b0c67SMark Fenwick
7801628b0c67SMark Fenwick /* ARGSUSED */
7802628b0c67SMark Fenwick void
7803628b0c67SMark Fenwick cbc_params_init(ipsa_t *assoc, uchar_t *esph, uint_t data_len, uchar_t *iv_ptr,
7804628b0c67SMark Fenwick ipsa_cm_mech_t *cm_mech, crypto_data_t *crypto_data)
7805628b0c67SMark Fenwick {
7806628b0c67SMark Fenwick cm_mech->combined_mech.cm_type = assoc->ipsa_emech.cm_type;
7807628b0c67SMark Fenwick cm_mech->combined_mech.cm_param_len = 0;
7808628b0c67SMark Fenwick cm_mech->combined_mech.cm_param = NULL;
7809628b0c67SMark Fenwick crypto_data->cd_miscdata = (char *)iv_ptr;
7810628b0c67SMark Fenwick }
7811628b0c67SMark Fenwick
7812628b0c67SMark Fenwick /* ARGSUSED */
7813628b0c67SMark Fenwick void
7814628b0c67SMark Fenwick gcm_params_init(ipsa_t *assoc, uchar_t *esph, uint_t data_len, uchar_t *iv_ptr,
7815628b0c67SMark Fenwick ipsa_cm_mech_t *cm_mech, crypto_data_t *crypto_data)
7816628b0c67SMark Fenwick {
7817628b0c67SMark Fenwick uchar_t *nonce;
7818628b0c67SMark Fenwick crypto_mechanism_t *combined_mech;
7819628b0c67SMark Fenwick CK_AES_GCM_PARAMS *params;
7820628b0c67SMark Fenwick
7821628b0c67SMark Fenwick combined_mech = (crypto_mechanism_t *)cm_mech;
7822628b0c67SMark Fenwick params = (CK_AES_GCM_PARAMS *)(combined_mech + 1);
7823628b0c67SMark Fenwick nonce = (uchar_t *)(params + 1);
7824628b0c67SMark Fenwick
7825628b0c67SMark Fenwick params->pIv = nonce;
7826628b0c67SMark Fenwick params->ulIvLen = assoc->ipsa_nonce_len;
7827628b0c67SMark Fenwick params->ulIvBits = SADB_8TO1(assoc->ipsa_nonce_len);
7828628b0c67SMark Fenwick params->pAAD = esph;
7829628b0c67SMark Fenwick params->ulAADLen = sizeof (esph_t);
7830628b0c67SMark Fenwick params->ulTagBits = SADB_8TO1(assoc->ipsa_mac_len);
7831628b0c67SMark Fenwick
7832628b0c67SMark Fenwick cm_mech->combined_mech.cm_type = assoc->ipsa_emech.cm_type;
7833628b0c67SMark Fenwick cm_mech->combined_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
7834628b0c67SMark Fenwick cm_mech->combined_mech.cm_param = (caddr_t)params;
7835628b0c67SMark Fenwick /*
7836628b0c67SMark Fenwick * Create the nonce, which is made up of the salt and the IV.
7837628b0c67SMark Fenwick * Copy the salt from the SA and the IV from the packet.
7838628b0c67SMark Fenwick * For inbound packets we copy the IV from the packet because it
7839628b0c67SMark Fenwick * was set by the sending system, for outbound packets we copy the IV
7840628b0c67SMark Fenwick * from the packet because the IV in the SA may be changed by another
7841628b0c67SMark Fenwick * thread, the IV in the packet was created while holding a mutex.
7842628b0c67SMark Fenwick */
7843628b0c67SMark Fenwick bcopy(assoc->ipsa_nonce, nonce, assoc->ipsa_saltlen);
7844628b0c67SMark Fenwick nonce += assoc->ipsa_saltlen;
7845628b0c67SMark Fenwick bcopy(iv_ptr, nonce, assoc->ipsa_iv_len);
7846628b0c67SMark Fenwick crypto_data->cd_miscdata = NULL;
7847628b0c67SMark Fenwick }
7848