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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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