1bd670b35SErik Nordmark /* 2bd670b35SErik Nordmark * CDDL HEADER START 3bd670b35SErik Nordmark * 4bd670b35SErik Nordmark * The contents of this file are subject to the terms of the 5bd670b35SErik Nordmark * Common Development and Distribution License (the "License"). 6bd670b35SErik Nordmark * You may not use this file except in compliance with the License. 7bd670b35SErik Nordmark * 8bd670b35SErik Nordmark * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9bd670b35SErik Nordmark * or http://www.opensolaris.org/os/licensing. 10bd670b35SErik Nordmark * See the License for the specific language governing permissions 11bd670b35SErik Nordmark * and limitations under the License. 12bd670b35SErik Nordmark * 13bd670b35SErik Nordmark * When distributing Covered Code, include this CDDL HEADER in each 14bd670b35SErik Nordmark * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15bd670b35SErik Nordmark * If applicable, add the following below this CDDL HEADER, with the 16bd670b35SErik Nordmark * fields enclosed by brackets "[]" replaced with your own identifying 17bd670b35SErik Nordmark * information: Portions Copyright [yyyy] [name of copyright owner] 18bd670b35SErik Nordmark * 19bd670b35SErik Nordmark * CDDL HEADER END 20bd670b35SErik Nordmark */ 21bd670b35SErik Nordmark 22bd670b35SErik Nordmark /* 239cd928feSAlan Maguire * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24bd670b35SErik Nordmark */ 25bd670b35SErik Nordmark /* Copyright (c) 1990 Mentat Inc. */ 26bd670b35SErik Nordmark 27*77dabb95SDan McDonald /* 28*77dabb95SDan McDonald * Copyright 2019 Joyent, Inc. 29*77dabb95SDan McDonald */ 30*77dabb95SDan McDonald 31bd670b35SErik Nordmark #include <sys/types.h> 32bd670b35SErik Nordmark #include <sys/stream.h> 33bd670b35SErik Nordmark #include <sys/strsun.h> 34bd670b35SErik Nordmark #include <sys/zone.h> 35bd670b35SErik Nordmark #include <sys/ddi.h> 36bd670b35SErik Nordmark #include <sys/sunddi.h> 37bd670b35SErik Nordmark #include <sys/cmn_err.h> 38bd670b35SErik Nordmark #include <sys/debug.h> 39bd670b35SErik Nordmark #include <sys/atomic.h> 40bd670b35SErik Nordmark 41bd670b35SErik Nordmark #include <sys/systm.h> 42bd670b35SErik Nordmark #include <sys/param.h> 43bd670b35SErik Nordmark #include <sys/kmem.h> 44bd670b35SErik Nordmark #include <sys/sdt.h> 45bd670b35SErik Nordmark #include <sys/socket.h> 46bd670b35SErik Nordmark #include <sys/mac.h> 47bd670b35SErik Nordmark #include <net/if.h> 48bd670b35SErik Nordmark #include <net/if_arp.h> 49bd670b35SErik Nordmark #include <net/route.h> 50bd670b35SErik Nordmark #include <sys/sockio.h> 51bd670b35SErik Nordmark #include <netinet/in.h> 52bd670b35SErik Nordmark #include <net/if_dl.h> 53bd670b35SErik Nordmark 54bd670b35SErik Nordmark #include <inet/common.h> 55bd670b35SErik Nordmark #include <inet/mi.h> 56bd670b35SErik Nordmark #include <inet/mib2.h> 57bd670b35SErik Nordmark #include <inet/nd.h> 58bd670b35SErik Nordmark #include <inet/arp.h> 59bd670b35SErik Nordmark #include <inet/snmpcom.h> 60bd670b35SErik Nordmark #include <inet/kstatcom.h> 61bd670b35SErik Nordmark 62bd670b35SErik Nordmark #include <netinet/igmp_var.h> 63bd670b35SErik Nordmark #include <netinet/ip6.h> 64bd670b35SErik Nordmark #include <netinet/icmp6.h> 65bd670b35SErik Nordmark #include <netinet/sctp.h> 66bd670b35SErik Nordmark 67bd670b35SErik Nordmark #include <inet/ip.h> 68bd670b35SErik Nordmark #include <inet/ip_impl.h> 69bd670b35SErik Nordmark #include <inet/ip6.h> 70bd670b35SErik Nordmark #include <inet/ip6_asp.h> 71bd670b35SErik Nordmark #include <inet/tcp.h> 72bd670b35SErik Nordmark #include <inet/ip_multi.h> 73bd670b35SErik Nordmark #include <inet/ip_if.h> 74bd670b35SErik Nordmark #include <inet/ip_ire.h> 75bd670b35SErik Nordmark #include <inet/ip_ftable.h> 76bd670b35SErik Nordmark #include <inet/ip_rts.h> 77bd670b35SErik Nordmark #include <inet/optcom.h> 78bd670b35SErik Nordmark #include <inet/ip_ndp.h> 79bd670b35SErik Nordmark #include <inet/ip_listutils.h> 80bd670b35SErik Nordmark #include <netinet/igmp.h> 81bd670b35SErik Nordmark #include <netinet/ip_mroute.h> 82bd670b35SErik Nordmark #include <inet/ipp_common.h> 83bd670b35SErik Nordmark 84bd670b35SErik Nordmark #include <net/pfkeyv2.h> 85bd670b35SErik Nordmark #include <inet/sadb.h> 86bd670b35SErik Nordmark #include <inet/ipsec_impl.h> 87bd670b35SErik Nordmark #include <inet/ipdrop.h> 88bd670b35SErik Nordmark #include <inet/ip_netinfo.h> 89bd670b35SErik Nordmark #include <sys/squeue_impl.h> 90bd670b35SErik Nordmark #include <sys/squeue.h> 91bd670b35SErik Nordmark 92bd670b35SErik Nordmark #include <inet/ipclassifier.h> 93bd670b35SErik Nordmark #include <inet/sctp_ip.h> 94bd670b35SErik Nordmark #include <inet/sctp/sctp_impl.h> 95bd670b35SErik Nordmark #include <inet/udp_impl.h> 96bd670b35SErik Nordmark #include <sys/sunddi.h> 97bd670b35SErik Nordmark 98bd670b35SErik Nordmark #include <sys/tsol/label.h> 99bd670b35SErik Nordmark #include <sys/tsol/tnet.h> 100bd670b35SErik Nordmark 101bd670b35SErik Nordmark /* 102bd670b35SErik Nordmark * Release a reference on ip_xmit_attr. 103bd670b35SErik Nordmark * The reference is acquired by conn_get_ixa() 104*77dabb95SDan McDonald * 105*77dabb95SDan McDonald * This macro has a lowercase function-call version for callers outside 106*77dabb95SDan McDonald * this file. 107bd670b35SErik Nordmark */ 108bd670b35SErik Nordmark #define IXA_REFRELE(ixa) \ 109bd670b35SErik Nordmark { \ 1101a5e258fSJosef 'Jeff' Sipek if (atomic_dec_32_nv(&(ixa)->ixa_refcnt) == 0) \ 111bd670b35SErik Nordmark ixa_inactive(ixa); \ 112bd670b35SErik Nordmark } 113bd670b35SErik Nordmark 114bd670b35SErik Nordmark #define IXA_REFHOLD(ixa) \ 115bd670b35SErik Nordmark { \ 116*77dabb95SDan McDonald ASSERT3U((ixa)->ixa_refcnt, !=, 0); \ 1171a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&(ixa)->ixa_refcnt); \ 118bd670b35SErik Nordmark } 119bd670b35SErik Nordmark 120bd670b35SErik Nordmark /* 121bd670b35SErik Nordmark * When we need to handle a transmit side asynchronous operation, then we need 122bd670b35SErik Nordmark * to save sufficient information so that we can call the fragment and postfrag 123bd670b35SErik Nordmark * functions. That information is captured in an mblk containing this structure. 124bd670b35SErik Nordmark * 125bd670b35SErik Nordmark * Since this is currently only used for IPsec, we include information for 126bd670b35SErik Nordmark * the kernel crypto framework. 127bd670b35SErik Nordmark */ 128bd670b35SErik Nordmark typedef struct ixamblk_s { 129bd670b35SErik Nordmark boolean_t ixm_inbound; /* B_FALSE */ 130bd670b35SErik Nordmark iaflags_t ixm_flags; /* ixa_flags */ 131bd670b35SErik Nordmark netstackid_t ixm_stackid; /* Verify it didn't go away */ 132bd670b35SErik Nordmark uint_t ixm_ifindex; /* Used to find the nce */ 133bd670b35SErik Nordmark in6_addr_t ixm_nceaddr_v6; /* Used to find nce */ 134bd670b35SErik Nordmark #define ixm_nceaddr_v4 V4_PART_OF_V6(ixm_nceaddr_v6) 135bd670b35SErik Nordmark uint32_t ixm_fragsize; 136bd670b35SErik Nordmark uint_t ixm_pktlen; 137bd670b35SErik Nordmark uint16_t ixm_ip_hdr_length; /* Points to ULP header */ 138bd670b35SErik Nordmark uint8_t ixm_protocol; /* Protocol number for ULP cksum */ 139bd670b35SErik Nordmark pfirepostfrag_t ixm_postfragfn; 140bd670b35SErik Nordmark 141bd670b35SErik Nordmark zoneid_t ixm_zoneid; /* Needed for ipobs */ 142bd670b35SErik Nordmark zoneid_t ixm_no_loop_zoneid; /* IXAF_NO_LOOP_ZONEID_SET */ 143bd670b35SErik Nordmark 144bd670b35SErik Nordmark uint_t ixm_scopeid; /* For IPv6 link-locals */ 145bd670b35SErik Nordmark 146bd670b35SErik Nordmark uint32_t ixm_ident; /* For IPv6 fragment header */ 147bd670b35SErik Nordmark uint32_t ixm_xmit_hint; 148bd670b35SErik Nordmark 1499cd928feSAlan Maguire uint64_t ixm_conn_id; /* Used by DTrace */ 150bd670b35SErik Nordmark cred_t *ixm_cred; /* For getpeerucred - refhold if set */ 151bd670b35SErik Nordmark pid_t ixm_cpid; /* For getpeerucred */ 152bd670b35SErik Nordmark 153bd670b35SErik Nordmark ts_label_t *ixm_tsl; /* Refhold if set. */ 154bd670b35SErik Nordmark 155bd670b35SErik Nordmark /* 156bd670b35SErik Nordmark * When the pointers below are set they have a refhold on the struct. 157bd670b35SErik Nordmark */ 158bd670b35SErik Nordmark ipsec_latch_t *ixm_ipsec_latch; 159bd670b35SErik Nordmark struct ipsa_s *ixm_ipsec_ah_sa; /* SA for AH */ 160bd670b35SErik Nordmark struct ipsa_s *ixm_ipsec_esp_sa; /* SA for ESP */ 161bd670b35SErik Nordmark struct ipsec_policy_s *ixm_ipsec_policy; /* why are we here? */ 162bd670b35SErik Nordmark struct ipsec_action_s *ixm_ipsec_action; /* For reflected packets */ 163bd670b35SErik Nordmark 164bd670b35SErik Nordmark ipsa_ref_t ixm_ipsec_ref[2]; /* Soft reference to SA */ 165bd670b35SErik Nordmark 166bd670b35SErik Nordmark /* Need these while waiting for SA */ 167bd670b35SErik Nordmark uint16_t ixm_ipsec_src_port; /* Source port number of d-gram. */ 168bd670b35SErik Nordmark uint16_t ixm_ipsec_dst_port; /* Destination port number of d-gram. */ 169bd670b35SErik Nordmark uint8_t ixm_ipsec_icmp_type; /* ICMP type of d-gram */ 170bd670b35SErik Nordmark uint8_t ixm_ipsec_icmp_code; /* ICMP code of d-gram */ 171bd670b35SErik Nordmark 172bd670b35SErik Nordmark sa_family_t ixm_ipsec_inaf; /* Inner address family */ 173bd670b35SErik Nordmark uint32_t ixm_ipsec_insrc[IXA_MAX_ADDRLEN]; /* Inner src address */ 174bd670b35SErik Nordmark uint32_t ixm_ipsec_indst[IXA_MAX_ADDRLEN]; /* Inner dest address */ 175bd670b35SErik Nordmark uint8_t ixm_ipsec_insrcpfx; /* Inner source prefix */ 176bd670b35SErik Nordmark uint8_t ixm_ipsec_indstpfx; /* Inner destination prefix */ 177bd670b35SErik Nordmark 178bd670b35SErik Nordmark uint8_t ixm_ipsec_proto; /* IP protocol number for d-gram. */ 179bd670b35SErik Nordmark } ixamblk_t; 180bd670b35SErik Nordmark 181bd670b35SErik Nordmark 182bd670b35SErik Nordmark /* 183bd670b35SErik Nordmark * When we need to handle a receive side asynchronous operation, then we need 184bd670b35SErik Nordmark * to save sufficient information so that we can call ip_fanout. 185bd670b35SErik Nordmark * That information is captured in an mblk containing this structure. 186bd670b35SErik Nordmark * 187bd670b35SErik Nordmark * Since this is currently only used for IPsec, we include information for 188bd670b35SErik Nordmark * the kernel crypto framework. 189bd670b35SErik Nordmark */ 190bd670b35SErik Nordmark typedef struct iramblk_s { 191bd670b35SErik Nordmark boolean_t irm_inbound; /* B_TRUE */ 192bd670b35SErik Nordmark iaflags_t irm_flags; /* ira_flags */ 193bd670b35SErik Nordmark netstackid_t irm_stackid; /* Verify it didn't go away */ 194bd670b35SErik Nordmark uint_t irm_ifindex; /* To find ira_ill */ 195bd670b35SErik Nordmark 196bd670b35SErik Nordmark uint_t irm_rifindex; /* ira_rifindex */ 197bd670b35SErik Nordmark uint_t irm_ruifindex; /* ira_ruifindex */ 198bd670b35SErik Nordmark uint_t irm_pktlen; 199bd670b35SErik Nordmark uint16_t irm_ip_hdr_length; /* Points to ULP header */ 200bd670b35SErik Nordmark uint8_t irm_protocol; /* Protocol number for ULP cksum */ 201bd670b35SErik Nordmark zoneid_t irm_zoneid; /* ALL_ZONES unless local delivery */ 202bd670b35SErik Nordmark 203bd670b35SErik Nordmark squeue_t *irm_sqp; 204bd670b35SErik Nordmark ill_rx_ring_t *irm_ring; 205bd670b35SErik Nordmark 206bd670b35SErik Nordmark ipaddr_t irm_mroute_tunnel; /* IRAF_MROUTE_TUNNEL_SET */ 207bd670b35SErik Nordmark zoneid_t irm_no_loop_zoneid; /* IRAF_NO_LOOP_ZONEID_SET */ 208bd670b35SErik Nordmark uint32_t irm_esp_udp_ports; /* IRAF_ESP_UDP_PORTS */ 209bd670b35SErik Nordmark 210bd670b35SErik Nordmark char irm_l2src[IRA_L2SRC_SIZE]; /* If IRAF_L2SRC_SET */ 211bd670b35SErik Nordmark 212bd670b35SErik Nordmark cred_t *irm_cred; /* For getpeerucred - refhold if set */ 213bd670b35SErik Nordmark pid_t irm_cpid; /* For getpeerucred */ 214bd670b35SErik Nordmark 215bd670b35SErik Nordmark ts_label_t *irm_tsl; /* Refhold if set. */ 216bd670b35SErik Nordmark 217bd670b35SErik Nordmark /* 218bd670b35SErik Nordmark * When set these correspond to a refhold on the object. 219bd670b35SErik Nordmark */ 220bd670b35SErik Nordmark struct ipsa_s *irm_ipsec_ah_sa; /* SA for AH */ 221bd670b35SErik Nordmark struct ipsa_s *irm_ipsec_esp_sa; /* SA for ESP */ 222bd670b35SErik Nordmark struct ipsec_action_s *irm_ipsec_action; /* For reflected packets */ 223bd670b35SErik Nordmark } iramblk_t; 224bd670b35SErik Nordmark 225bd670b35SErik Nordmark 226bd670b35SErik Nordmark /* 227bd670b35SErik Nordmark * Take the information in ip_xmit_attr_t and stick it in an mblk 228bd670b35SErik Nordmark * that can later be passed to ip_xmit_attr_from_mblk to recreate the 229bd670b35SErik Nordmark * ip_xmit_attr_t. 230bd670b35SErik Nordmark * 231bd670b35SErik Nordmark * Returns NULL on memory allocation failure. 232bd670b35SErik Nordmark */ 233bd670b35SErik Nordmark mblk_t * 234bd670b35SErik Nordmark ip_xmit_attr_to_mblk(ip_xmit_attr_t *ixa) 235bd670b35SErik Nordmark { 236bd670b35SErik Nordmark mblk_t *ixamp; 237bd670b35SErik Nordmark ixamblk_t *ixm; 238bd670b35SErik Nordmark nce_t *nce = ixa->ixa_nce; 239bd670b35SErik Nordmark 240bd670b35SErik Nordmark ASSERT(nce != NULL); 241bd670b35SErik Nordmark ixamp = allocb(sizeof (*ixm), BPRI_MED); 242bd670b35SErik Nordmark if (ixamp == NULL) 243bd670b35SErik Nordmark return (NULL); 244bd670b35SErik Nordmark 245bd670b35SErik Nordmark ixamp->b_datap->db_type = M_BREAK; 246bd670b35SErik Nordmark ixamp->b_wptr += sizeof (*ixm); 247bd670b35SErik Nordmark ixm = (ixamblk_t *)ixamp->b_rptr; 248bd670b35SErik Nordmark 249bd670b35SErik Nordmark bzero(ixm, sizeof (*ixm)); 250bd670b35SErik Nordmark ixm->ixm_inbound = B_FALSE; 251bd670b35SErik Nordmark ixm->ixm_flags = ixa->ixa_flags; 252bd670b35SErik Nordmark ixm->ixm_stackid = ixa->ixa_ipst->ips_netstack->netstack_stackid; 253bd670b35SErik Nordmark ixm->ixm_ifindex = nce->nce_ill->ill_phyint->phyint_ifindex; 254bd670b35SErik Nordmark ixm->ixm_nceaddr_v6 = nce->nce_addr; 255bd670b35SErik Nordmark ixm->ixm_fragsize = ixa->ixa_fragsize; 256bd670b35SErik Nordmark ixm->ixm_pktlen = ixa->ixa_pktlen; 257bd670b35SErik Nordmark ixm->ixm_ip_hdr_length = ixa->ixa_ip_hdr_length; 258bd670b35SErik Nordmark ixm->ixm_protocol = ixa->ixa_protocol; 259bd670b35SErik Nordmark ixm->ixm_postfragfn = ixa->ixa_postfragfn; 260bd670b35SErik Nordmark ixm->ixm_zoneid = ixa->ixa_zoneid; 261bd670b35SErik Nordmark ixm->ixm_no_loop_zoneid = ixa->ixa_no_loop_zoneid; 262bd670b35SErik Nordmark ixm->ixm_scopeid = ixa->ixa_scopeid; 263bd670b35SErik Nordmark ixm->ixm_ident = ixa->ixa_ident; 264bd670b35SErik Nordmark ixm->ixm_xmit_hint = ixa->ixa_xmit_hint; 265bd670b35SErik Nordmark 266bd670b35SErik Nordmark if (ixa->ixa_tsl != NULL) { 267bd670b35SErik Nordmark ixm->ixm_tsl = ixa->ixa_tsl; 268bd670b35SErik Nordmark label_hold(ixm->ixm_tsl); 269bd670b35SErik Nordmark } 270bd670b35SErik Nordmark if (ixa->ixa_cred != NULL) { 271bd670b35SErik Nordmark ixm->ixm_cred = ixa->ixa_cred; 272bd670b35SErik Nordmark crhold(ixa->ixa_cred); 273bd670b35SErik Nordmark } 274bd670b35SErik Nordmark ixm->ixm_cpid = ixa->ixa_cpid; 2759cd928feSAlan Maguire ixm->ixm_conn_id = ixa->ixa_conn_id; 276bd670b35SErik Nordmark 277bd670b35SErik Nordmark if (ixa->ixa_flags & IXAF_IPSEC_SECURE) { 278bd670b35SErik Nordmark if (ixa->ixa_ipsec_ah_sa != NULL) { 279bd670b35SErik Nordmark ixm->ixm_ipsec_ah_sa = ixa->ixa_ipsec_ah_sa; 280bd670b35SErik Nordmark IPSA_REFHOLD(ixa->ixa_ipsec_ah_sa); 281bd670b35SErik Nordmark } 282bd670b35SErik Nordmark if (ixa->ixa_ipsec_esp_sa != NULL) { 283bd670b35SErik Nordmark ixm->ixm_ipsec_esp_sa = ixa->ixa_ipsec_esp_sa; 284bd670b35SErik Nordmark IPSA_REFHOLD(ixa->ixa_ipsec_esp_sa); 285bd670b35SErik Nordmark } 286bd670b35SErik Nordmark if (ixa->ixa_ipsec_policy != NULL) { 287bd670b35SErik Nordmark ixm->ixm_ipsec_policy = ixa->ixa_ipsec_policy; 288bd670b35SErik Nordmark IPPOL_REFHOLD(ixa->ixa_ipsec_policy); 289bd670b35SErik Nordmark } 290bd670b35SErik Nordmark if (ixa->ixa_ipsec_action != NULL) { 291bd670b35SErik Nordmark ixm->ixm_ipsec_action = ixa->ixa_ipsec_action; 292bd670b35SErik Nordmark IPACT_REFHOLD(ixa->ixa_ipsec_action); 293bd670b35SErik Nordmark } 294bd670b35SErik Nordmark if (ixa->ixa_ipsec_latch != NULL) { 295bd670b35SErik Nordmark ixm->ixm_ipsec_latch = ixa->ixa_ipsec_latch; 296bd670b35SErik Nordmark IPLATCH_REFHOLD(ixa->ixa_ipsec_latch); 297bd670b35SErik Nordmark } 298bd670b35SErik Nordmark ixm->ixm_ipsec_ref[0] = ixa->ixa_ipsec_ref[0]; 299bd670b35SErik Nordmark ixm->ixm_ipsec_ref[1] = ixa->ixa_ipsec_ref[1]; 300bd670b35SErik Nordmark ixm->ixm_ipsec_src_port = ixa->ixa_ipsec_src_port; 301bd670b35SErik Nordmark ixm->ixm_ipsec_dst_port = ixa->ixa_ipsec_dst_port; 302bd670b35SErik Nordmark ixm->ixm_ipsec_icmp_type = ixa->ixa_ipsec_icmp_type; 303bd670b35SErik Nordmark ixm->ixm_ipsec_icmp_code = ixa->ixa_ipsec_icmp_code; 304bd670b35SErik Nordmark ixm->ixm_ipsec_inaf = ixa->ixa_ipsec_inaf; 305bd670b35SErik Nordmark ixm->ixm_ipsec_insrc[0] = ixa->ixa_ipsec_insrc[0]; 306bd670b35SErik Nordmark ixm->ixm_ipsec_insrc[1] = ixa->ixa_ipsec_insrc[1]; 307bd670b35SErik Nordmark ixm->ixm_ipsec_insrc[2] = ixa->ixa_ipsec_insrc[2]; 308bd670b35SErik Nordmark ixm->ixm_ipsec_insrc[3] = ixa->ixa_ipsec_insrc[3]; 309bd670b35SErik Nordmark ixm->ixm_ipsec_indst[0] = ixa->ixa_ipsec_indst[0]; 310bd670b35SErik Nordmark ixm->ixm_ipsec_indst[1] = ixa->ixa_ipsec_indst[1]; 311bd670b35SErik Nordmark ixm->ixm_ipsec_indst[2] = ixa->ixa_ipsec_indst[2]; 312bd670b35SErik Nordmark ixm->ixm_ipsec_indst[3] = ixa->ixa_ipsec_indst[3]; 313bd670b35SErik Nordmark ixm->ixm_ipsec_insrcpfx = ixa->ixa_ipsec_insrcpfx; 314bd670b35SErik Nordmark ixm->ixm_ipsec_indstpfx = ixa->ixa_ipsec_indstpfx; 315bd670b35SErik Nordmark ixm->ixm_ipsec_proto = ixa->ixa_ipsec_proto; 316bd670b35SErik Nordmark } 317bd670b35SErik Nordmark return (ixamp); 318bd670b35SErik Nordmark } 319bd670b35SErik Nordmark 320bd670b35SErik Nordmark /* 321bd670b35SErik Nordmark * Extract the ip_xmit_attr_t from the mblk, checking that the 322bd670b35SErik Nordmark * ip_stack_t, ill_t, and nce_t still exist. Returns B_FALSE if that is 323bd670b35SErik Nordmark * not the case. 324bd670b35SErik Nordmark * 325bd670b35SErik Nordmark * Otherwise ixa is updated. 326bd670b35SErik Nordmark * Caller needs to release references on the ixa by calling ixa_refrele() 327bd670b35SErik Nordmark * which will imediately call ixa_inactive to release the references. 328bd670b35SErik Nordmark */ 329bd670b35SErik Nordmark boolean_t 330bd670b35SErik Nordmark ip_xmit_attr_from_mblk(mblk_t *ixamp, ip_xmit_attr_t *ixa) 331bd670b35SErik Nordmark { 332bd670b35SErik Nordmark ixamblk_t *ixm; 333bd670b35SErik Nordmark netstack_t *ns; 334bd670b35SErik Nordmark ip_stack_t *ipst; 335bd670b35SErik Nordmark ill_t *ill; 336bd670b35SErik Nordmark nce_t *nce; 337bd670b35SErik Nordmark 338bd670b35SErik Nordmark /* We assume the caller hasn't initialized ixa */ 339bd670b35SErik Nordmark bzero(ixa, sizeof (*ixa)); 340bd670b35SErik Nordmark 341bd670b35SErik Nordmark ASSERT(DB_TYPE(ixamp) == M_BREAK); 342bd670b35SErik Nordmark ASSERT(ixamp->b_cont == NULL); 343bd670b35SErik Nordmark 344bd670b35SErik Nordmark ixm = (ixamblk_t *)ixamp->b_rptr; 345bd670b35SErik Nordmark ASSERT(!ixm->ixm_inbound); 346bd670b35SErik Nordmark 347bd670b35SErik Nordmark /* Verify the netstack is still around */ 348bd670b35SErik Nordmark ns = netstack_find_by_stackid(ixm->ixm_stackid); 349bd670b35SErik Nordmark if (ns == NULL) { 350bd670b35SErik Nordmark /* Disappeared on us */ 351bd670b35SErik Nordmark (void) ip_xmit_attr_free_mblk(ixamp); 352bd670b35SErik Nordmark return (B_FALSE); 353bd670b35SErik Nordmark } 354bd670b35SErik Nordmark ipst = ns->netstack_ip; 355bd670b35SErik Nordmark 356bd670b35SErik Nordmark /* Verify the ill is still around */ 357bd670b35SErik Nordmark ill = ill_lookup_on_ifindex(ixm->ixm_ifindex, 358bd670b35SErik Nordmark !(ixm->ixm_flags & IXAF_IS_IPV4), ipst); 359bd670b35SErik Nordmark 360bd670b35SErik Nordmark /* We have the ill, hence the netstack can't go away */ 361bd670b35SErik Nordmark netstack_rele(ns); 362bd670b35SErik Nordmark if (ill == NULL) { 363bd670b35SErik Nordmark /* Disappeared on us */ 364bd670b35SErik Nordmark (void) ip_xmit_attr_free_mblk(ixamp); 365bd670b35SErik Nordmark return (B_FALSE); 366bd670b35SErik Nordmark } 367bd670b35SErik Nordmark /* 368bd670b35SErik Nordmark * Find the nce. We don't load-spread (only lookup nce's on the ill) 369bd670b35SErik Nordmark * because we want to find the same nce as the one we had when 370bd670b35SErik Nordmark * ip_xmit_attr_to_mblk was called. 371bd670b35SErik Nordmark */ 372bd670b35SErik Nordmark if (ixm->ixm_flags & IXAF_IS_IPV4) { 373bd670b35SErik Nordmark nce = nce_lookup_v4(ill, &ixm->ixm_nceaddr_v4); 374bd670b35SErik Nordmark } else { 375bd670b35SErik Nordmark nce = nce_lookup_v6(ill, &ixm->ixm_nceaddr_v6); 376bd670b35SErik Nordmark } 377bd670b35SErik Nordmark 378bd670b35SErik Nordmark /* We have the nce, hence the ill can't go away */ 379bd670b35SErik Nordmark ill_refrele(ill); 380bd670b35SErik Nordmark if (nce == NULL) { 381bd670b35SErik Nordmark /* 382bd670b35SErik Nordmark * Since this is unusual and we don't know what type of 383bd670b35SErik Nordmark * nce it was, we drop the packet. 384bd670b35SErik Nordmark */ 385bd670b35SErik Nordmark (void) ip_xmit_attr_free_mblk(ixamp); 386bd670b35SErik Nordmark return (B_FALSE); 387bd670b35SErik Nordmark } 388bd670b35SErik Nordmark 389bd670b35SErik Nordmark ixa->ixa_flags = ixm->ixm_flags; 390bd670b35SErik Nordmark ixa->ixa_refcnt = 1; 391bd670b35SErik Nordmark ixa->ixa_ipst = ipst; 392bd670b35SErik Nordmark ixa->ixa_fragsize = ixm->ixm_fragsize; 393bd670b35SErik Nordmark ixa->ixa_pktlen = ixm->ixm_pktlen; 394bd670b35SErik Nordmark ixa->ixa_ip_hdr_length = ixm->ixm_ip_hdr_length; 395bd670b35SErik Nordmark ixa->ixa_protocol = ixm->ixm_protocol; 396bd670b35SErik Nordmark ixa->ixa_nce = nce; 397bd670b35SErik Nordmark ixa->ixa_postfragfn = ixm->ixm_postfragfn; 398bd670b35SErik Nordmark ixa->ixa_zoneid = ixm->ixm_zoneid; 399bd670b35SErik Nordmark ixa->ixa_no_loop_zoneid = ixm->ixm_no_loop_zoneid; 400bd670b35SErik Nordmark ixa->ixa_scopeid = ixm->ixm_scopeid; 401bd670b35SErik Nordmark ixa->ixa_ident = ixm->ixm_ident; 402bd670b35SErik Nordmark ixa->ixa_xmit_hint = ixm->ixm_xmit_hint; 403bd670b35SErik Nordmark 404bd670b35SErik Nordmark if (ixm->ixm_tsl != NULL) { 405bd670b35SErik Nordmark ixa->ixa_tsl = ixm->ixm_tsl; 406bd670b35SErik Nordmark ixa->ixa_free_flags |= IXA_FREE_TSL; 407be4c8f74SErik Nordmark ixm->ixm_tsl = NULL; 408bd670b35SErik Nordmark } 409bd670b35SErik Nordmark if (ixm->ixm_cred != NULL) { 410bd670b35SErik Nordmark ixa->ixa_cred = ixm->ixm_cred; 411bd670b35SErik Nordmark ixa->ixa_free_flags |= IXA_FREE_CRED; 412be4c8f74SErik Nordmark ixm->ixm_cred = NULL; 413bd670b35SErik Nordmark } 414bd670b35SErik Nordmark ixa->ixa_cpid = ixm->ixm_cpid; 4159cd928feSAlan Maguire ixa->ixa_conn_id = ixm->ixm_conn_id; 416bd670b35SErik Nordmark 417bd670b35SErik Nordmark ixa->ixa_ipsec_ah_sa = ixm->ixm_ipsec_ah_sa; 418bd670b35SErik Nordmark ixa->ixa_ipsec_esp_sa = ixm->ixm_ipsec_esp_sa; 419bd670b35SErik Nordmark ixa->ixa_ipsec_policy = ixm->ixm_ipsec_policy; 420bd670b35SErik Nordmark ixa->ixa_ipsec_action = ixm->ixm_ipsec_action; 421bd670b35SErik Nordmark ixa->ixa_ipsec_latch = ixm->ixm_ipsec_latch; 422bd670b35SErik Nordmark 423bd670b35SErik Nordmark ixa->ixa_ipsec_ref[0] = ixm->ixm_ipsec_ref[0]; 424bd670b35SErik Nordmark ixa->ixa_ipsec_ref[1] = ixm->ixm_ipsec_ref[1]; 425bd670b35SErik Nordmark ixa->ixa_ipsec_src_port = ixm->ixm_ipsec_src_port; 426bd670b35SErik Nordmark ixa->ixa_ipsec_dst_port = ixm->ixm_ipsec_dst_port; 427bd670b35SErik Nordmark ixa->ixa_ipsec_icmp_type = ixm->ixm_ipsec_icmp_type; 428bd670b35SErik Nordmark ixa->ixa_ipsec_icmp_code = ixm->ixm_ipsec_icmp_code; 429bd670b35SErik Nordmark ixa->ixa_ipsec_inaf = ixm->ixm_ipsec_inaf; 430bd670b35SErik Nordmark ixa->ixa_ipsec_insrc[0] = ixm->ixm_ipsec_insrc[0]; 431bd670b35SErik Nordmark ixa->ixa_ipsec_insrc[1] = ixm->ixm_ipsec_insrc[1]; 432bd670b35SErik Nordmark ixa->ixa_ipsec_insrc[2] = ixm->ixm_ipsec_insrc[2]; 433bd670b35SErik Nordmark ixa->ixa_ipsec_insrc[3] = ixm->ixm_ipsec_insrc[3]; 434bd670b35SErik Nordmark ixa->ixa_ipsec_indst[0] = ixm->ixm_ipsec_indst[0]; 435bd670b35SErik Nordmark ixa->ixa_ipsec_indst[1] = ixm->ixm_ipsec_indst[1]; 436bd670b35SErik Nordmark ixa->ixa_ipsec_indst[2] = ixm->ixm_ipsec_indst[2]; 437bd670b35SErik Nordmark ixa->ixa_ipsec_indst[3] = ixm->ixm_ipsec_indst[3]; 438bd670b35SErik Nordmark ixa->ixa_ipsec_insrcpfx = ixm->ixm_ipsec_insrcpfx; 439bd670b35SErik Nordmark ixa->ixa_ipsec_indstpfx = ixm->ixm_ipsec_indstpfx; 440bd670b35SErik Nordmark ixa->ixa_ipsec_proto = ixm->ixm_ipsec_proto; 441bd670b35SErik Nordmark 442bd670b35SErik Nordmark freeb(ixamp); 443bd670b35SErik Nordmark return (B_TRUE); 444bd670b35SErik Nordmark } 445bd670b35SErik Nordmark 446bd670b35SErik Nordmark /* 447bd670b35SErik Nordmark * Free the ixm mblk and any references it holds 448bd670b35SErik Nordmark * Returns b_cont. 449bd670b35SErik Nordmark */ 450bd670b35SErik Nordmark mblk_t * 451bd670b35SErik Nordmark ip_xmit_attr_free_mblk(mblk_t *ixamp) 452bd670b35SErik Nordmark { 453bd670b35SErik Nordmark ixamblk_t *ixm; 454bd670b35SErik Nordmark mblk_t *mp; 455bd670b35SErik Nordmark 456bd670b35SErik Nordmark /* Consume mp */ 457bd670b35SErik Nordmark ASSERT(DB_TYPE(ixamp) == M_BREAK); 458bd670b35SErik Nordmark mp = ixamp->b_cont; 459bd670b35SErik Nordmark 460bd670b35SErik Nordmark ixm = (ixamblk_t *)ixamp->b_rptr; 461bd670b35SErik Nordmark ASSERT(!ixm->ixm_inbound); 462bd670b35SErik Nordmark 463bd670b35SErik Nordmark if (ixm->ixm_ipsec_ah_sa != NULL) { 464bd670b35SErik Nordmark IPSA_REFRELE(ixm->ixm_ipsec_ah_sa); 465bd670b35SErik Nordmark ixm->ixm_ipsec_ah_sa = NULL; 466bd670b35SErik Nordmark } 467bd670b35SErik Nordmark if (ixm->ixm_ipsec_esp_sa != NULL) { 468bd670b35SErik Nordmark IPSA_REFRELE(ixm->ixm_ipsec_esp_sa); 469bd670b35SErik Nordmark ixm->ixm_ipsec_esp_sa = NULL; 470bd670b35SErik Nordmark } 471bd670b35SErik Nordmark if (ixm->ixm_ipsec_policy != NULL) { 472bd670b35SErik Nordmark IPPOL_REFRELE(ixm->ixm_ipsec_policy); 473bd670b35SErik Nordmark ixm->ixm_ipsec_policy = NULL; 474bd670b35SErik Nordmark } 475bd670b35SErik Nordmark if (ixm->ixm_ipsec_action != NULL) { 476bd670b35SErik Nordmark IPACT_REFRELE(ixm->ixm_ipsec_action); 477bd670b35SErik Nordmark ixm->ixm_ipsec_action = NULL; 478bd670b35SErik Nordmark } 479bd670b35SErik Nordmark if (ixm->ixm_ipsec_latch) { 480bd670b35SErik Nordmark IPLATCH_REFRELE(ixm->ixm_ipsec_latch); 481bd670b35SErik Nordmark ixm->ixm_ipsec_latch = NULL; 482bd670b35SErik Nordmark } 483bd670b35SErik Nordmark 484bd670b35SErik Nordmark if (ixm->ixm_tsl != NULL) { 485bd670b35SErik Nordmark label_rele(ixm->ixm_tsl); 486bd670b35SErik Nordmark ixm->ixm_tsl = NULL; 487bd670b35SErik Nordmark } 488bd670b35SErik Nordmark if (ixm->ixm_cred != NULL) { 489bd670b35SErik Nordmark crfree(ixm->ixm_cred); 490bd670b35SErik Nordmark ixm->ixm_cred = NULL; 491bd670b35SErik Nordmark } 492bd670b35SErik Nordmark freeb(ixamp); 493bd670b35SErik Nordmark return (mp); 494bd670b35SErik Nordmark } 495bd670b35SErik Nordmark 496bd670b35SErik Nordmark /* 497bd670b35SErik Nordmark * Take the information in ip_recv_attr_t and stick it in an mblk 498bd670b35SErik Nordmark * that can later be passed to ip_recv_attr_from_mblk to recreate the 499bd670b35SErik Nordmark * ip_recv_attr_t. 500bd670b35SErik Nordmark * 501bd670b35SErik Nordmark * Returns NULL on memory allocation failure. 502bd670b35SErik Nordmark */ 503bd670b35SErik Nordmark mblk_t * 504bd670b35SErik Nordmark ip_recv_attr_to_mblk(ip_recv_attr_t *ira) 505bd670b35SErik Nordmark { 506bd670b35SErik Nordmark mblk_t *iramp; 507bd670b35SErik Nordmark iramblk_t *irm; 508bd670b35SErik Nordmark ill_t *ill = ira->ira_ill; 509bd670b35SErik Nordmark 510bd670b35SErik Nordmark ASSERT(ira->ira_ill != NULL || ira->ira_ruifindex != 0); 511bd670b35SErik Nordmark 512bd670b35SErik Nordmark iramp = allocb(sizeof (*irm), BPRI_MED); 513bd670b35SErik Nordmark if (iramp == NULL) 514bd670b35SErik Nordmark return (NULL); 515bd670b35SErik Nordmark 516bd670b35SErik Nordmark iramp->b_datap->db_type = M_BREAK; 517bd670b35SErik Nordmark iramp->b_wptr += sizeof (*irm); 518bd670b35SErik Nordmark irm = (iramblk_t *)iramp->b_rptr; 519bd670b35SErik Nordmark 520bd670b35SErik Nordmark bzero(irm, sizeof (*irm)); 521bd670b35SErik Nordmark irm->irm_inbound = B_TRUE; 522bd670b35SErik Nordmark irm->irm_flags = ira->ira_flags; 523bd670b35SErik Nordmark if (ill != NULL) { 524bd670b35SErik Nordmark /* Internal to IP - preserve ip_stack_t, ill and rill */ 525bd670b35SErik Nordmark irm->irm_stackid = 526bd670b35SErik Nordmark ill->ill_ipst->ips_netstack->netstack_stackid; 527bd670b35SErik Nordmark irm->irm_ifindex = ira->ira_ill->ill_phyint->phyint_ifindex; 528bd670b35SErik Nordmark ASSERT(ira->ira_rill->ill_phyint->phyint_ifindex == 529bd670b35SErik Nordmark ira->ira_rifindex); 530bd670b35SErik Nordmark } else { 531bd670b35SErik Nordmark /* Let ip_recv_attr_from_stackid know there isn't one */ 532bd670b35SErik Nordmark irm->irm_stackid = -1; 533bd670b35SErik Nordmark } 534bd670b35SErik Nordmark irm->irm_rifindex = ira->ira_rifindex; 535bd670b35SErik Nordmark irm->irm_ruifindex = ira->ira_ruifindex; 536bd670b35SErik Nordmark irm->irm_pktlen = ira->ira_pktlen; 537bd670b35SErik Nordmark irm->irm_ip_hdr_length = ira->ira_ip_hdr_length; 538bd670b35SErik Nordmark irm->irm_protocol = ira->ira_protocol; 539bd670b35SErik Nordmark 540bd670b35SErik Nordmark irm->irm_sqp = ira->ira_sqp; 541bd670b35SErik Nordmark irm->irm_ring = ira->ira_ring; 542bd670b35SErik Nordmark 543bd670b35SErik Nordmark irm->irm_zoneid = ira->ira_zoneid; 544bd670b35SErik Nordmark irm->irm_mroute_tunnel = ira->ira_mroute_tunnel; 545bd670b35SErik Nordmark irm->irm_no_loop_zoneid = ira->ira_no_loop_zoneid; 546bd670b35SErik Nordmark irm->irm_esp_udp_ports = ira->ira_esp_udp_ports; 547bd670b35SErik Nordmark 548bd670b35SErik Nordmark if (ira->ira_tsl != NULL) { 549bd670b35SErik Nordmark irm->irm_tsl = ira->ira_tsl; 550bd670b35SErik Nordmark label_hold(irm->irm_tsl); 551bd670b35SErik Nordmark } 552bd670b35SErik Nordmark if (ira->ira_cred != NULL) { 553bd670b35SErik Nordmark irm->irm_cred = ira->ira_cred; 554bd670b35SErik Nordmark crhold(ira->ira_cred); 555bd670b35SErik Nordmark } 556bd670b35SErik Nordmark irm->irm_cpid = ira->ira_cpid; 557bd670b35SErik Nordmark 558bd670b35SErik Nordmark if (ira->ira_flags & IRAF_L2SRC_SET) 559bd670b35SErik Nordmark bcopy(ira->ira_l2src, irm->irm_l2src, IRA_L2SRC_SIZE); 560bd670b35SErik Nordmark 561bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IPSEC_SECURE) { 562bd670b35SErik Nordmark if (ira->ira_ipsec_ah_sa != NULL) { 563bd670b35SErik Nordmark irm->irm_ipsec_ah_sa = ira->ira_ipsec_ah_sa; 564bd670b35SErik Nordmark IPSA_REFHOLD(ira->ira_ipsec_ah_sa); 565bd670b35SErik Nordmark } 566bd670b35SErik Nordmark if (ira->ira_ipsec_esp_sa != NULL) { 567bd670b35SErik Nordmark irm->irm_ipsec_esp_sa = ira->ira_ipsec_esp_sa; 568bd670b35SErik Nordmark IPSA_REFHOLD(ira->ira_ipsec_esp_sa); 569bd670b35SErik Nordmark } 570bd670b35SErik Nordmark if (ira->ira_ipsec_action != NULL) { 571bd670b35SErik Nordmark irm->irm_ipsec_action = ira->ira_ipsec_action; 572bd670b35SErik Nordmark IPACT_REFHOLD(ira->ira_ipsec_action); 573bd670b35SErik Nordmark } 574bd670b35SErik Nordmark } 575bd670b35SErik Nordmark return (iramp); 576bd670b35SErik Nordmark } 577bd670b35SErik Nordmark 578bd670b35SErik Nordmark /* 579bd670b35SErik Nordmark * Extract the ip_recv_attr_t from the mblk. If we are used inside IP 580bd670b35SErik Nordmark * then irm_stackid is not -1, in which case we check that the 581bd670b35SErik Nordmark * ip_stack_t and ill_t still exist. Returns B_FALSE if that is 582bd670b35SErik Nordmark * not the case. 583bd670b35SErik Nordmark * If irm_stackid is zero then we are used by an ULP (e.g., squeue_enter) 584bd670b35SErik Nordmark * and we just proceed with ira_ill and ira_rill as NULL. 585bd670b35SErik Nordmark * 586bd670b35SErik Nordmark * The caller needs to release any references on the pointers inside the ire 587bd670b35SErik Nordmark * by calling ira_cleanup. 588bd670b35SErik Nordmark */ 589bd670b35SErik Nordmark boolean_t 590bd670b35SErik Nordmark ip_recv_attr_from_mblk(mblk_t *iramp, ip_recv_attr_t *ira) 591bd670b35SErik Nordmark { 592bd670b35SErik Nordmark iramblk_t *irm; 593bd670b35SErik Nordmark netstack_t *ns; 594bd670b35SErik Nordmark ip_stack_t *ipst = NULL; 595bd670b35SErik Nordmark ill_t *ill = NULL, *rill = NULL; 596bd670b35SErik Nordmark 597bd670b35SErik Nordmark /* We assume the caller hasn't initialized ira */ 598bd670b35SErik Nordmark bzero(ira, sizeof (*ira)); 599bd670b35SErik Nordmark 600bd670b35SErik Nordmark ASSERT(DB_TYPE(iramp) == M_BREAK); 601bd670b35SErik Nordmark ASSERT(iramp->b_cont == NULL); 602bd670b35SErik Nordmark 603bd670b35SErik Nordmark irm = (iramblk_t *)iramp->b_rptr; 604bd670b35SErik Nordmark ASSERT(irm->irm_inbound); 605bd670b35SErik Nordmark 606bd670b35SErik Nordmark if (irm->irm_stackid != -1) { 607bd670b35SErik Nordmark /* Verify the netstack is still around */ 608bd670b35SErik Nordmark ns = netstack_find_by_stackid(irm->irm_stackid); 609bd670b35SErik Nordmark if (ns == NULL) { 610bd670b35SErik Nordmark /* Disappeared on us */ 611bd670b35SErik Nordmark (void) ip_recv_attr_free_mblk(iramp); 612bd670b35SErik Nordmark return (B_FALSE); 613bd670b35SErik Nordmark } 614bd670b35SErik Nordmark ipst = ns->netstack_ip; 615bd670b35SErik Nordmark 616bd670b35SErik Nordmark /* Verify the ill is still around */ 617bd670b35SErik Nordmark ill = ill_lookup_on_ifindex(irm->irm_ifindex, 618bd670b35SErik Nordmark !(irm->irm_flags & IRAF_IS_IPV4), ipst); 619bd670b35SErik Nordmark 620bd670b35SErik Nordmark if (irm->irm_ifindex == irm->irm_rifindex) { 621bd670b35SErik Nordmark rill = ill; 622bd670b35SErik Nordmark } else { 623bd670b35SErik Nordmark rill = ill_lookup_on_ifindex(irm->irm_rifindex, 624bd670b35SErik Nordmark !(irm->irm_flags & IRAF_IS_IPV4), ipst); 625bd670b35SErik Nordmark } 626bd670b35SErik Nordmark 627bd670b35SErik Nordmark /* We have the ill, hence the netstack can't go away */ 628bd670b35SErik Nordmark netstack_rele(ns); 629bd670b35SErik Nordmark if (ill == NULL || rill == NULL) { 630bd670b35SErik Nordmark /* Disappeared on us */ 631bd670b35SErik Nordmark if (ill != NULL) 632bd670b35SErik Nordmark ill_refrele(ill); 633bd670b35SErik Nordmark if (rill != NULL && rill != ill) 634bd670b35SErik Nordmark ill_refrele(rill); 635bd670b35SErik Nordmark (void) ip_recv_attr_free_mblk(iramp); 636bd670b35SErik Nordmark return (B_FALSE); 637bd670b35SErik Nordmark } 638bd670b35SErik Nordmark } 639bd670b35SErik Nordmark 640bd670b35SErik Nordmark ira->ira_flags = irm->irm_flags; 641bd670b35SErik Nordmark /* Caller must ill_refele(ira_ill) by using ira_cleanup() */ 642bd670b35SErik Nordmark ira->ira_ill = ill; 643bd670b35SErik Nordmark ira->ira_rill = rill; 644bd670b35SErik Nordmark 645bd670b35SErik Nordmark ira->ira_rifindex = irm->irm_rifindex; 646bd670b35SErik Nordmark ira->ira_ruifindex = irm->irm_ruifindex; 647bd670b35SErik Nordmark ira->ira_pktlen = irm->irm_pktlen; 648bd670b35SErik Nordmark ira->ira_ip_hdr_length = irm->irm_ip_hdr_length; 649bd670b35SErik Nordmark ira->ira_protocol = irm->irm_protocol; 650bd670b35SErik Nordmark 651bd670b35SErik Nordmark ira->ira_sqp = irm->irm_sqp; 652bd670b35SErik Nordmark /* The rest of IP assumes that the rings never go away. */ 653bd670b35SErik Nordmark ira->ira_ring = irm->irm_ring; 654bd670b35SErik Nordmark 655bd670b35SErik Nordmark ira->ira_zoneid = irm->irm_zoneid; 656bd670b35SErik Nordmark ira->ira_mroute_tunnel = irm->irm_mroute_tunnel; 657bd670b35SErik Nordmark ira->ira_no_loop_zoneid = irm->irm_no_loop_zoneid; 658bd670b35SErik Nordmark ira->ira_esp_udp_ports = irm->irm_esp_udp_ports; 659bd670b35SErik Nordmark 660bd670b35SErik Nordmark if (irm->irm_tsl != NULL) { 661bd670b35SErik Nordmark ira->ira_tsl = irm->irm_tsl; 662bd670b35SErik Nordmark ira->ira_free_flags |= IRA_FREE_TSL; 663be4c8f74SErik Nordmark irm->irm_tsl = NULL; 664bd670b35SErik Nordmark } 665bd670b35SErik Nordmark if (irm->irm_cred != NULL) { 666bd670b35SErik Nordmark ira->ira_cred = irm->irm_cred; 667bd670b35SErik Nordmark ira->ira_free_flags |= IRA_FREE_CRED; 668be4c8f74SErik Nordmark irm->irm_cred = NULL; 669bd670b35SErik Nordmark } 670bd670b35SErik Nordmark ira->ira_cpid = irm->irm_cpid; 671bd670b35SErik Nordmark 672bd670b35SErik Nordmark if (ira->ira_flags & IRAF_L2SRC_SET) 673bd670b35SErik Nordmark bcopy(irm->irm_l2src, ira->ira_l2src, IRA_L2SRC_SIZE); 674bd670b35SErik Nordmark 675bd670b35SErik Nordmark ira->ira_ipsec_ah_sa = irm->irm_ipsec_ah_sa; 676bd670b35SErik Nordmark ira->ira_ipsec_esp_sa = irm->irm_ipsec_esp_sa; 677bd670b35SErik Nordmark ira->ira_ipsec_action = irm->irm_ipsec_action; 678bd670b35SErik Nordmark 679bd670b35SErik Nordmark freeb(iramp); 680bd670b35SErik Nordmark return (B_TRUE); 681bd670b35SErik Nordmark } 682bd670b35SErik Nordmark 683bd670b35SErik Nordmark /* 684bd670b35SErik Nordmark * Free the irm mblk and any references it holds 685bd670b35SErik Nordmark * Returns b_cont. 686bd670b35SErik Nordmark */ 687bd670b35SErik Nordmark mblk_t * 688bd670b35SErik Nordmark ip_recv_attr_free_mblk(mblk_t *iramp) 689bd670b35SErik Nordmark { 690bd670b35SErik Nordmark iramblk_t *irm; 691bd670b35SErik Nordmark mblk_t *mp; 692bd670b35SErik Nordmark 693bd670b35SErik Nordmark /* Consume mp */ 694bd670b35SErik Nordmark ASSERT(DB_TYPE(iramp) == M_BREAK); 695bd670b35SErik Nordmark mp = iramp->b_cont; 696bd670b35SErik Nordmark 697bd670b35SErik Nordmark irm = (iramblk_t *)iramp->b_rptr; 698bd670b35SErik Nordmark ASSERT(irm->irm_inbound); 699bd670b35SErik Nordmark 700bd670b35SErik Nordmark if (irm->irm_ipsec_ah_sa != NULL) { 701bd670b35SErik Nordmark IPSA_REFRELE(irm->irm_ipsec_ah_sa); 702bd670b35SErik Nordmark irm->irm_ipsec_ah_sa = NULL; 703bd670b35SErik Nordmark } 704bd670b35SErik Nordmark if (irm->irm_ipsec_esp_sa != NULL) { 705bd670b35SErik Nordmark IPSA_REFRELE(irm->irm_ipsec_esp_sa); 706bd670b35SErik Nordmark irm->irm_ipsec_esp_sa = NULL; 707bd670b35SErik Nordmark } 708bd670b35SErik Nordmark if (irm->irm_ipsec_action != NULL) { 709bd670b35SErik Nordmark IPACT_REFRELE(irm->irm_ipsec_action); 710bd670b35SErik Nordmark irm->irm_ipsec_action = NULL; 711bd670b35SErik Nordmark } 712bd670b35SErik Nordmark if (irm->irm_tsl != NULL) { 713bd670b35SErik Nordmark label_rele(irm->irm_tsl); 714bd670b35SErik Nordmark irm->irm_tsl = NULL; 715bd670b35SErik Nordmark } 716bd670b35SErik Nordmark if (irm->irm_cred != NULL) { 717bd670b35SErik Nordmark crfree(irm->irm_cred); 718bd670b35SErik Nordmark irm->irm_cred = NULL; 719bd670b35SErik Nordmark } 720bd670b35SErik Nordmark 721bd670b35SErik Nordmark freeb(iramp); 722bd670b35SErik Nordmark return (mp); 723bd670b35SErik Nordmark } 724bd670b35SErik Nordmark 725bd670b35SErik Nordmark /* 726bd670b35SErik Nordmark * Returns true if the mblk contains an ip_recv_attr_t 727bd670b35SErik Nordmark * For now we just check db_type. 728bd670b35SErik Nordmark */ 729bd670b35SErik Nordmark boolean_t 730bd670b35SErik Nordmark ip_recv_attr_is_mblk(mblk_t *mp) 731bd670b35SErik Nordmark { 732bd670b35SErik Nordmark /* 733bd670b35SErik Nordmark * Need to handle the various forms of tcp_timermp which are tagged 734bd670b35SErik Nordmark * with b_wptr and might have a NULL b_datap. 735bd670b35SErik Nordmark */ 736bd670b35SErik Nordmark if (mp->b_wptr == NULL || mp->b_wptr == (uchar_t *)-1) 737bd670b35SErik Nordmark return (B_FALSE); 738bd670b35SErik Nordmark 739bd670b35SErik Nordmark #ifdef DEBUG 740bd670b35SErik Nordmark iramblk_t *irm; 741bd670b35SErik Nordmark 742bd670b35SErik Nordmark if (DB_TYPE(mp) != M_BREAK) 743bd670b35SErik Nordmark return (B_FALSE); 744bd670b35SErik Nordmark 745bd670b35SErik Nordmark irm = (iramblk_t *)mp->b_rptr; 746bd670b35SErik Nordmark ASSERT(irm->irm_inbound); 747bd670b35SErik Nordmark return (B_TRUE); 748bd670b35SErik Nordmark #else 749bd670b35SErik Nordmark return (DB_TYPE(mp) == M_BREAK); 750bd670b35SErik Nordmark #endif 751bd670b35SErik Nordmark } 752bd670b35SErik Nordmark 753bd670b35SErik Nordmark static ip_xmit_attr_t * 754bd670b35SErik Nordmark conn_get_ixa_impl(conn_t *connp, boolean_t replace, int kmflag) 755bd670b35SErik Nordmark { 756*77dabb95SDan McDonald ip_xmit_attr_t *oldixa; /* Already attached to conn_t */ 757*77dabb95SDan McDonald ip_xmit_attr_t *ixa; /* New one, which we return. */ 758*77dabb95SDan McDonald 759*77dabb95SDan McDonald /* 760*77dabb95SDan McDonald * NOTE: If the marked-below common case isn't, move the 761*77dabb95SDan McDonald * kmem_alloc() up here and put a free in what was marked as the 762*77dabb95SDan McDonald * (not really) common case instead. 763*77dabb95SDan McDonald */ 764bd670b35SErik Nordmark 765bd670b35SErik Nordmark mutex_enter(&connp->conn_lock); 766*77dabb95SDan McDonald oldixa = connp->conn_ixa; 767bd670b35SErik Nordmark 768*77dabb95SDan McDonald /* At least one reference for the conn_t */ 769*77dabb95SDan McDonald ASSERT3U(oldixa->ixa_refcnt, >=, 1); 770*77dabb95SDan McDonald if (atomic_inc_32_nv(&oldixa->ixa_refcnt) == 2) { 771*77dabb95SDan McDonald /* No other thread using conn_ixa (common case) */ 772bd670b35SErik Nordmark mutex_exit(&connp->conn_lock); 773*77dabb95SDan McDonald return (oldixa); 774bd670b35SErik Nordmark } 775*77dabb95SDan McDonald /* Do allocation inside-the-conn_lock because it's less common. */ 776bd670b35SErik Nordmark ixa = kmem_alloc(sizeof (*ixa), kmflag); 777bd670b35SErik Nordmark if (ixa == NULL) { 778bd670b35SErik Nordmark mutex_exit(&connp->conn_lock); 779*77dabb95SDan McDonald IXA_REFRELE(oldixa); 780bd670b35SErik Nordmark return (NULL); 781bd670b35SErik Nordmark } 782*77dabb95SDan McDonald ixa_safe_copy(oldixa, ixa); 783bd670b35SErik Nordmark 784bd670b35SErik Nordmark /* Make sure we drop conn_lock before any refrele */ 785bd670b35SErik Nordmark if (replace) { 786bd670b35SErik Nordmark ixa->ixa_refcnt++; /* No atomic needed - not visible */ 787bd670b35SErik Nordmark connp->conn_ixa = ixa; 788bd670b35SErik Nordmark mutex_exit(&connp->conn_lock); 789bd670b35SErik Nordmark IXA_REFRELE(oldixa); /* Undo refcnt from conn_t */ 790bd670b35SErik Nordmark } else { 791bd670b35SErik Nordmark mutex_exit(&connp->conn_lock); 792bd670b35SErik Nordmark } 793bd670b35SErik Nordmark IXA_REFRELE(oldixa); /* Undo above atomic_add_32_nv */ 794bd670b35SErik Nordmark 795bd670b35SErik Nordmark return (ixa); 796bd670b35SErik Nordmark } 797bd670b35SErik Nordmark 798bd670b35SErik Nordmark /* 799bd670b35SErik Nordmark * Return an ip_xmit_attr_t to use with a conn_t that ensures that only 800bd670b35SErik Nordmark * the caller can access the ip_xmit_attr_t. 801bd670b35SErik Nordmark * 802bd670b35SErik Nordmark * If nobody else is using conn_ixa we return it. 803bd670b35SErik Nordmark * Otherwise we make a "safe" copy of conn_ixa 804bd670b35SErik Nordmark * and return it. The "safe" copy has the pointers set to NULL 805bd670b35SErik Nordmark * (since the pointers might be changed by another thread using 806bd670b35SErik Nordmark * conn_ixa). The caller needs to check for NULL pointers to see 807bd670b35SErik Nordmark * if ip_set_destination needs to be called to re-establish the pointers. 808bd670b35SErik Nordmark * 809bd670b35SErik Nordmark * If 'replace' is set then we replace conn_ixa with the new ip_xmit_attr_t. 810bd670b35SErik Nordmark * That is used when we connect() the ULP. 811bd670b35SErik Nordmark */ 812bd670b35SErik Nordmark ip_xmit_attr_t * 813bd670b35SErik Nordmark conn_get_ixa(conn_t *connp, boolean_t replace) 814bd670b35SErik Nordmark { 815bd670b35SErik Nordmark return (conn_get_ixa_impl(connp, replace, KM_NOSLEEP)); 816bd670b35SErik Nordmark } 817bd670b35SErik Nordmark 818bd670b35SErik Nordmark /* 819bd670b35SErik Nordmark * Used only when the option is to have the kernel hang due to not 820bd670b35SErik Nordmark * cleaning up ixa references on ills etc. 821bd670b35SErik Nordmark */ 822bd670b35SErik Nordmark ip_xmit_attr_t * 823bd670b35SErik Nordmark conn_get_ixa_tryhard(conn_t *connp, boolean_t replace) 824bd670b35SErik Nordmark { 825bd670b35SErik Nordmark return (conn_get_ixa_impl(connp, replace, KM_SLEEP)); 826bd670b35SErik Nordmark } 827bd670b35SErik Nordmark 828bd670b35SErik Nordmark /* 829bd670b35SErik Nordmark * Replace conn_ixa with the ixa argument. 830bd670b35SErik Nordmark * 831bd670b35SErik Nordmark * The caller must hold conn_lock. 832bd670b35SErik Nordmark * 833bd670b35SErik Nordmark * We return the old ixa; the caller must ixa_refrele that after conn_lock 834bd670b35SErik Nordmark * has been dropped. 835bd670b35SErik Nordmark */ 836bd670b35SErik Nordmark ip_xmit_attr_t * 837bd670b35SErik Nordmark conn_replace_ixa(conn_t *connp, ip_xmit_attr_t *ixa) 838bd670b35SErik Nordmark { 839bd670b35SErik Nordmark ip_xmit_attr_t *oldixa; 840bd670b35SErik Nordmark 841bd670b35SErik Nordmark ASSERT(MUTEX_HELD(&connp->conn_lock)); 842bd670b35SErik Nordmark 843bd670b35SErik Nordmark oldixa = connp->conn_ixa; 844bd670b35SErik Nordmark IXA_REFHOLD(ixa); 8459cd928feSAlan Maguire ixa->ixa_conn_id = oldixa->ixa_conn_id; 846bd670b35SErik Nordmark connp->conn_ixa = ixa; 847bd670b35SErik Nordmark return (oldixa); 848bd670b35SErik Nordmark } 849bd670b35SErik Nordmark 850bd670b35SErik Nordmark /* 851bd670b35SErik Nordmark * Return a ip_xmit_attr_t to use with a conn_t that is based on but 852bd670b35SErik Nordmark * separate from conn_ixa. 853bd670b35SErik Nordmark * 854bd670b35SErik Nordmark * This "safe" copy has the pointers set to NULL 855bd670b35SErik Nordmark * (since the pointers might be changed by another thread using 856bd670b35SErik Nordmark * conn_ixa). The caller needs to check for NULL pointers to see 857bd670b35SErik Nordmark * if ip_set_destination needs to be called to re-establish the pointers. 858bd670b35SErik Nordmark */ 859bd670b35SErik Nordmark ip_xmit_attr_t * 860bd670b35SErik Nordmark conn_get_ixa_exclusive(conn_t *connp) 861bd670b35SErik Nordmark { 862*77dabb95SDan McDonald ip_xmit_attr_t *oldixa; 863bd670b35SErik Nordmark ip_xmit_attr_t *ixa; 864bd670b35SErik Nordmark 865*77dabb95SDan McDonald ixa = kmem_alloc(sizeof (*ixa), KM_NOSLEEP | KM_NORMALPRI); 866*77dabb95SDan McDonald if (ixa == NULL) 867bd670b35SErik Nordmark return (NULL); 868*77dabb95SDan McDonald 869*77dabb95SDan McDonald mutex_enter(&connp->conn_lock); 870*77dabb95SDan McDonald 871*77dabb95SDan McDonald oldixa = connp->conn_ixa; 872*77dabb95SDan McDonald IXA_REFHOLD(oldixa); 873*77dabb95SDan McDonald 874*77dabb95SDan McDonald ixa_safe_copy(oldixa, ixa); 875bd670b35SErik Nordmark mutex_exit(&connp->conn_lock); 876*77dabb95SDan McDonald IXA_REFRELE(oldixa); 877bd670b35SErik Nordmark return (ixa); 878bd670b35SErik Nordmark } 879bd670b35SErik Nordmark 880bd670b35SErik Nordmark void 881bd670b35SErik Nordmark ixa_safe_copy(ip_xmit_attr_t *src, ip_xmit_attr_t *ixa) 882bd670b35SErik Nordmark { 883bd670b35SErik Nordmark bcopy(src, ixa, sizeof (*ixa)); 884bd670b35SErik Nordmark ixa->ixa_refcnt = 1; 885bd670b35SErik Nordmark /* 886bd670b35SErik Nordmark * Clear any pointers that have references and might be changed 887bd670b35SErik Nordmark * by ip_set_destination or the ULP 888bd670b35SErik Nordmark */ 889bd670b35SErik Nordmark ixa->ixa_ire = NULL; 890bd670b35SErik Nordmark ixa->ixa_nce = NULL; 891bd670b35SErik Nordmark ixa->ixa_dce = NULL; 892bd670b35SErik Nordmark ixa->ixa_ire_generation = IRE_GENERATION_VERIFY; 893bd670b35SErik Nordmark ixa->ixa_dce_generation = DCE_GENERATION_VERIFY; 894bd670b35SErik Nordmark #ifdef DEBUG 895bd670b35SErik Nordmark ixa->ixa_curthread = NULL; 896bd670b35SErik Nordmark #endif 897bd670b35SErik Nordmark /* Clear all the IPsec pointers and the flag as well. */ 898bd670b35SErik Nordmark ixa->ixa_flags &= ~IXAF_IPSEC_SECURE; 899bd670b35SErik Nordmark 900bd670b35SErik Nordmark ixa->ixa_ipsec_latch = NULL; 901bd670b35SErik Nordmark ixa->ixa_ipsec_ah_sa = NULL; 902bd670b35SErik Nordmark ixa->ixa_ipsec_esp_sa = NULL; 903bd670b35SErik Nordmark ixa->ixa_ipsec_policy = NULL; 904bd670b35SErik Nordmark ixa->ixa_ipsec_action = NULL; 905bd670b35SErik Nordmark 906bd670b35SErik Nordmark /* 907bd670b35SErik Nordmark * We leave ixa_tsl unchanged, but if it has a refhold we need 908bd670b35SErik Nordmark * to get an extra refhold. 909bd670b35SErik Nordmark */ 910bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_TSL) 911bd670b35SErik Nordmark label_hold(ixa->ixa_tsl); 912bd670b35SErik Nordmark 913bd670b35SErik Nordmark /* 914bd670b35SErik Nordmark * We leave ixa_cred unchanged, but if it has a refhold we need 915bd670b35SErik Nordmark * to get an extra refhold. 916bd670b35SErik Nordmark */ 917bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_CRED) 918bd670b35SErik Nordmark crhold(ixa->ixa_cred); 919925ef79cSKeith M Wesolowski 920925ef79cSKeith M Wesolowski /* 921925ef79cSKeith M Wesolowski * There is no cleanup in progress on this new copy. 922925ef79cSKeith M Wesolowski */ 923925ef79cSKeith M Wesolowski ixa->ixa_tcpcleanup = IXATC_IDLE; 924bd670b35SErik Nordmark } 925bd670b35SErik Nordmark 926bd670b35SErik Nordmark /* 927bd670b35SErik Nordmark * Duplicate an ip_xmit_attr_t. 928bd670b35SErik Nordmark * Assumes that the caller controls the ixa, hence we do not need to use 929bd670b35SErik Nordmark * a safe copy. We just have to increase the refcnt on any pointers. 930bd670b35SErik Nordmark */ 931bd670b35SErik Nordmark ip_xmit_attr_t * 932bd670b35SErik Nordmark ip_xmit_attr_duplicate(ip_xmit_attr_t *src_ixa) 933bd670b35SErik Nordmark { 934bd670b35SErik Nordmark ip_xmit_attr_t *ixa; 935bd670b35SErik Nordmark 936bd670b35SErik Nordmark ixa = kmem_alloc(sizeof (*ixa), KM_NOSLEEP); 937bd670b35SErik Nordmark if (ixa == NULL) 938bd670b35SErik Nordmark return (NULL); 939bd670b35SErik Nordmark bcopy(src_ixa, ixa, sizeof (*ixa)); 940bd670b35SErik Nordmark ixa->ixa_refcnt = 1; 941bd670b35SErik Nordmark 942bd670b35SErik Nordmark if (ixa->ixa_ire != NULL) 943bd670b35SErik Nordmark ire_refhold_notr(ixa->ixa_ire); 944bd670b35SErik Nordmark if (ixa->ixa_nce != NULL) 945bd670b35SErik Nordmark nce_refhold(ixa->ixa_nce); 946bd670b35SErik Nordmark if (ixa->ixa_dce != NULL) 947bd670b35SErik Nordmark dce_refhold_notr(ixa->ixa_dce); 948bd670b35SErik Nordmark 949bd670b35SErik Nordmark #ifdef DEBUG 950bd670b35SErik Nordmark ixa->ixa_curthread = NULL; 951bd670b35SErik Nordmark #endif 952bd670b35SErik Nordmark 953bd670b35SErik Nordmark if (ixa->ixa_ipsec_latch != NULL) 954bd670b35SErik Nordmark IPLATCH_REFHOLD(ixa->ixa_ipsec_latch); 955bd670b35SErik Nordmark if (ixa->ixa_ipsec_ah_sa != NULL) 956bd670b35SErik Nordmark IPSA_REFHOLD(ixa->ixa_ipsec_ah_sa); 957bd670b35SErik Nordmark if (ixa->ixa_ipsec_esp_sa != NULL) 958bd670b35SErik Nordmark IPSA_REFHOLD(ixa->ixa_ipsec_esp_sa); 959bd670b35SErik Nordmark if (ixa->ixa_ipsec_policy != NULL) 960bd670b35SErik Nordmark IPPOL_REFHOLD(ixa->ixa_ipsec_policy); 961bd670b35SErik Nordmark if (ixa->ixa_ipsec_action != NULL) 962bd670b35SErik Nordmark IPACT_REFHOLD(ixa->ixa_ipsec_action); 963bd670b35SErik Nordmark 964bd670b35SErik Nordmark if (ixa->ixa_tsl != NULL) { 965bd670b35SErik Nordmark label_hold(ixa->ixa_tsl); 966bd670b35SErik Nordmark ixa->ixa_free_flags |= IXA_FREE_TSL; 967bd670b35SErik Nordmark } 968bd670b35SErik Nordmark if (ixa->ixa_cred != NULL) { 969bd670b35SErik Nordmark crhold(ixa->ixa_cred); 970bd670b35SErik Nordmark ixa->ixa_free_flags |= IXA_FREE_CRED; 971bd670b35SErik Nordmark } 972bd670b35SErik Nordmark return (ixa); 973bd670b35SErik Nordmark } 974bd670b35SErik Nordmark 975bd670b35SErik Nordmark /* 976bd670b35SErik Nordmark * Used to replace the ixa_label field. 977bd670b35SErik Nordmark * The caller should have a reference on the label, which we transfer to 978bd670b35SErik Nordmark * the attributes so that when the attribute is freed/cleaned up 979bd670b35SErik Nordmark * we will release that reference. 980bd670b35SErik Nordmark */ 981bd670b35SErik Nordmark void 982bd670b35SErik Nordmark ip_xmit_attr_replace_tsl(ip_xmit_attr_t *ixa, ts_label_t *tsl) 983bd670b35SErik Nordmark { 984bd670b35SErik Nordmark ASSERT(tsl != NULL); 985bd670b35SErik Nordmark 986bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_TSL) { 987bd670b35SErik Nordmark ASSERT(ixa->ixa_tsl != NULL); 988bd670b35SErik Nordmark label_rele(ixa->ixa_tsl); 989bd670b35SErik Nordmark } else { 990bd670b35SErik Nordmark ixa->ixa_free_flags |= IXA_FREE_TSL; 991bd670b35SErik Nordmark } 992bd670b35SErik Nordmark ixa->ixa_tsl = tsl; 993bd670b35SErik Nordmark } 994bd670b35SErik Nordmark 995bd670b35SErik Nordmark /* 996bd670b35SErik Nordmark * Replace the ip_recv_attr_t's label. 997bd670b35SErik Nordmark * Due to kernel RPC's use of db_credp we also need to replace ira_cred; 998bd670b35SErik Nordmark * TCP/UDP uses ira_cred to set db_credp for non-socket users. 999bd670b35SErik Nordmark * This can fail (and return B_FALSE) due to lack of memory. 1000bd670b35SErik Nordmark */ 1001bd670b35SErik Nordmark boolean_t 1002bd670b35SErik Nordmark ip_recv_attr_replace_label(ip_recv_attr_t *ira, ts_label_t *tsl) 1003bd670b35SErik Nordmark { 1004bd670b35SErik Nordmark cred_t *newcr; 1005bd670b35SErik Nordmark 1006bd670b35SErik Nordmark if (ira->ira_free_flags & IRA_FREE_TSL) { 1007bd670b35SErik Nordmark ASSERT(ira->ira_tsl != NULL); 1008bd670b35SErik Nordmark label_rele(ira->ira_tsl); 1009bd670b35SErik Nordmark } 1010bd670b35SErik Nordmark label_hold(tsl); 1011bd670b35SErik Nordmark ira->ira_tsl = tsl; 1012bd670b35SErik Nordmark ira->ira_free_flags |= IRA_FREE_TSL; 1013bd670b35SErik Nordmark 1014bd670b35SErik Nordmark /* 1015bd670b35SErik Nordmark * Reset zoneid if we have a shared address. That allows 1016bd670b35SErik Nordmark * ip_fanout_tx_v4/v6 to determine the zoneid again. 1017bd670b35SErik Nordmark */ 1018bd670b35SErik Nordmark if (ira->ira_flags & IRAF_TX_SHARED_ADDR) 1019bd670b35SErik Nordmark ira->ira_zoneid = ALL_ZONES; 1020bd670b35SErik Nordmark 1021bd670b35SErik Nordmark /* We update ira_cred for RPC */ 1022bd670b35SErik Nordmark newcr = copycred_from_tslabel(ira->ira_cred, ira->ira_tsl, KM_NOSLEEP); 1023bd670b35SErik Nordmark if (newcr == NULL) 1024bd670b35SErik Nordmark return (B_FALSE); 1025bd670b35SErik Nordmark if (ira->ira_free_flags & IRA_FREE_CRED) 1026bd670b35SErik Nordmark crfree(ira->ira_cred); 1027bd670b35SErik Nordmark ira->ira_cred = newcr; 1028bd670b35SErik Nordmark ira->ira_free_flags |= IRA_FREE_CRED; 1029bd670b35SErik Nordmark return (B_TRUE); 1030bd670b35SErik Nordmark } 1031bd670b35SErik Nordmark 1032bd670b35SErik Nordmark /* 1033bd670b35SErik Nordmark * This needs to be called after ip_set_destination/tsol_check_dest might 1034bd670b35SErik Nordmark * have changed ixa_tsl to be specific for a destination, and we now want to 1035bd670b35SErik Nordmark * send to a different destination. 1036bd670b35SErik Nordmark * We have to restart with crgetlabel() since ip_set_destination/ 1037bd670b35SErik Nordmark * tsol_check_dest will start with ixa_tsl. 1038bd670b35SErik Nordmark */ 1039bd670b35SErik Nordmark void 1040bd670b35SErik Nordmark ip_xmit_attr_restore_tsl(ip_xmit_attr_t *ixa, cred_t *cr) 1041bd670b35SErik Nordmark { 1042bd670b35SErik Nordmark if (!is_system_labeled()) 1043bd670b35SErik Nordmark return; 1044bd670b35SErik Nordmark 1045bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_TSL) { 1046bd670b35SErik Nordmark ASSERT(ixa->ixa_tsl != NULL); 1047bd670b35SErik Nordmark label_rele(ixa->ixa_tsl); 1048bd670b35SErik Nordmark ixa->ixa_free_flags &= ~IXA_FREE_TSL; 1049bd670b35SErik Nordmark } 1050bd670b35SErik Nordmark ixa->ixa_tsl = crgetlabel(cr); 1051bd670b35SErik Nordmark } 1052bd670b35SErik Nordmark 1053bd670b35SErik Nordmark void 1054bd670b35SErik Nordmark ixa_refrele(ip_xmit_attr_t *ixa) 1055bd670b35SErik Nordmark { 1056bd670b35SErik Nordmark IXA_REFRELE(ixa); 1057bd670b35SErik Nordmark } 1058bd670b35SErik Nordmark 1059bd670b35SErik Nordmark void 1060bd670b35SErik Nordmark ixa_inactive(ip_xmit_attr_t *ixa) 1061bd670b35SErik Nordmark { 1062bd670b35SErik Nordmark ASSERT(ixa->ixa_refcnt == 0); 1063bd670b35SErik Nordmark 1064bd670b35SErik Nordmark ixa_cleanup(ixa); 1065bd670b35SErik Nordmark kmem_free(ixa, sizeof (*ixa)); 1066bd670b35SErik Nordmark } 1067bd670b35SErik Nordmark 1068bd670b35SErik Nordmark /* 1069bd670b35SErik Nordmark * Release any references contained in the ixa. 1070bd670b35SErik Nordmark * Also clear any fields that are not controlled by ixa_flags. 1071bd670b35SErik Nordmark */ 1072bd670b35SErik Nordmark void 1073bd670b35SErik Nordmark ixa_cleanup(ip_xmit_attr_t *ixa) 1074bd670b35SErik Nordmark { 1075bd670b35SErik Nordmark if (ixa->ixa_ire != NULL) { 1076bd670b35SErik Nordmark ire_refrele_notr(ixa->ixa_ire); 1077bd670b35SErik Nordmark ixa->ixa_ire = NULL; 1078bd670b35SErik Nordmark } 1079bd670b35SErik Nordmark if (ixa->ixa_dce != NULL) { 1080bd670b35SErik Nordmark dce_refrele_notr(ixa->ixa_dce); 1081bd670b35SErik Nordmark ixa->ixa_dce = NULL; 1082bd670b35SErik Nordmark } 1083bd670b35SErik Nordmark if (ixa->ixa_nce != NULL) { 1084bd670b35SErik Nordmark nce_refrele(ixa->ixa_nce); 1085bd670b35SErik Nordmark ixa->ixa_nce = NULL; 1086bd670b35SErik Nordmark } 1087bd670b35SErik Nordmark ixa->ixa_ire_generation = IRE_GENERATION_VERIFY; 1088bd670b35SErik Nordmark ixa->ixa_dce_generation = DCE_GENERATION_VERIFY; 1089bd670b35SErik Nordmark if (ixa->ixa_flags & IXAF_IPSEC_SECURE) { 1090bd670b35SErik Nordmark ipsec_out_release_refs(ixa); 1091bd670b35SErik Nordmark } 1092bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_TSL) { 1093bd670b35SErik Nordmark ASSERT(ixa->ixa_tsl != NULL); 1094bd670b35SErik Nordmark label_rele(ixa->ixa_tsl); 1095bd670b35SErik Nordmark ixa->ixa_free_flags &= ~IXA_FREE_TSL; 1096bd670b35SErik Nordmark } 109776a1033eSErik Nordmark ixa->ixa_tsl = NULL; 1098bd670b35SErik Nordmark if (ixa->ixa_free_flags & IXA_FREE_CRED) { 1099bd670b35SErik Nordmark ASSERT(ixa->ixa_cred != NULL); 1100bd670b35SErik Nordmark crfree(ixa->ixa_cred); 1101bd670b35SErik Nordmark ixa->ixa_free_flags &= ~IXA_FREE_CRED; 1102bd670b35SErik Nordmark } 110376a1033eSErik Nordmark ixa->ixa_cred = NULL; 1104bd670b35SErik Nordmark ixa->ixa_src_preferences = 0; 1105bd670b35SErik Nordmark ixa->ixa_ifindex = 0; 1106bd670b35SErik Nordmark ixa->ixa_multicast_ifindex = 0; 1107bd670b35SErik Nordmark ixa->ixa_multicast_ifaddr = INADDR_ANY; 1108bd670b35SErik Nordmark } 1109bd670b35SErik Nordmark 1110bd670b35SErik Nordmark /* 1111bd670b35SErik Nordmark * Release any references contained in the ira. 1112bd670b35SErik Nordmark * Callers which use ip_recv_attr_from_mblk() would pass B_TRUE as the second 1113bd670b35SErik Nordmark * argument. 1114bd670b35SErik Nordmark */ 1115bd670b35SErik Nordmark void 1116bd670b35SErik Nordmark ira_cleanup(ip_recv_attr_t *ira, boolean_t refrele_ill) 1117bd670b35SErik Nordmark { 1118bd670b35SErik Nordmark if (ira->ira_ill != NULL) { 1119bd670b35SErik Nordmark if (ira->ira_rill != ira->ira_ill) { 1120bd670b35SErik Nordmark /* Caused by async processing */ 1121bd670b35SErik Nordmark ill_refrele(ira->ira_rill); 1122bd670b35SErik Nordmark } 1123bd670b35SErik Nordmark if (refrele_ill) 1124bd670b35SErik Nordmark ill_refrele(ira->ira_ill); 1125bd670b35SErik Nordmark } 1126bd670b35SErik Nordmark if (ira->ira_flags & IRAF_IPSEC_SECURE) { 1127bd670b35SErik Nordmark ipsec_in_release_refs(ira); 1128bd670b35SErik Nordmark } 1129bd670b35SErik Nordmark if (ira->ira_free_flags & IRA_FREE_TSL) { 1130bd670b35SErik Nordmark ASSERT(ira->ira_tsl != NULL); 1131bd670b35SErik Nordmark label_rele(ira->ira_tsl); 1132bd670b35SErik Nordmark ira->ira_free_flags &= ~IRA_FREE_TSL; 1133bd670b35SErik Nordmark } 1134be4c8f74SErik Nordmark ira->ira_tsl = NULL; 1135bd670b35SErik Nordmark if (ira->ira_free_flags & IRA_FREE_CRED) { 1136bd670b35SErik Nordmark ASSERT(ira->ira_cred != NULL); 1137bd670b35SErik Nordmark crfree(ira->ira_cred); 1138bd670b35SErik Nordmark ira->ira_free_flags &= ~IRA_FREE_CRED; 1139bd670b35SErik Nordmark } 1140be4c8f74SErik Nordmark ira->ira_cred = NULL; 1141bd670b35SErik Nordmark } 1142bd670b35SErik Nordmark 1143bd670b35SErik Nordmark /* 1144bd670b35SErik Nordmark * Function to help release any IRE, NCE, or DCEs that 1145bd670b35SErik Nordmark * have been deleted and are marked as condemned. 1146bd670b35SErik Nordmark * The caller is responsible for any serialization which is different 1147bd670b35SErik Nordmark * for TCP, SCTP, and others. 1148bd670b35SErik Nordmark */ 1149bd670b35SErik Nordmark static void 1150bd670b35SErik Nordmark ixa_cleanup_stale(ip_xmit_attr_t *ixa) 1151bd670b35SErik Nordmark { 1152bd670b35SErik Nordmark ire_t *ire; 1153bd670b35SErik Nordmark nce_t *nce; 1154bd670b35SErik Nordmark dce_t *dce; 1155bd670b35SErik Nordmark 1156bd670b35SErik Nordmark ire = ixa->ixa_ire; 1157bd670b35SErik Nordmark nce = ixa->ixa_nce; 1158bd670b35SErik Nordmark dce = ixa->ixa_dce; 1159bd670b35SErik Nordmark 1160bd670b35SErik Nordmark if (ire != NULL && IRE_IS_CONDEMNED(ire)) { 1161bd670b35SErik Nordmark ire_refrele_notr(ire); 1162bd670b35SErik Nordmark ire = ire_blackhole(ixa->ixa_ipst, 1163bd670b35SErik Nordmark !(ixa->ixa_flags & IXAF_IS_IPV4)); 1164bd670b35SErik Nordmark ASSERT(ire != NULL); 1165bd670b35SErik Nordmark #ifdef DEBUG 1166bd670b35SErik Nordmark ire_refhold_notr(ire); 1167bd670b35SErik Nordmark ire_refrele(ire); 1168bd670b35SErik Nordmark #endif 1169bd670b35SErik Nordmark ixa->ixa_ire = ire; 1170bd670b35SErik Nordmark ixa->ixa_ire_generation = IRE_GENERATION_VERIFY; 1171bd670b35SErik Nordmark } 1172bd670b35SErik Nordmark if (nce != NULL && nce->nce_is_condemned) { 1173bd670b35SErik Nordmark /* Can make it NULL as long as we set IRE_GENERATION_VERIFY */ 1174bd670b35SErik Nordmark nce_refrele(nce); 1175bd670b35SErik Nordmark ixa->ixa_nce = NULL; 1176bd670b35SErik Nordmark ixa->ixa_ire_generation = IRE_GENERATION_VERIFY; 1177bd670b35SErik Nordmark } 1178bd670b35SErik Nordmark if (dce != NULL && DCE_IS_CONDEMNED(dce)) { 1179bd670b35SErik Nordmark dce_refrele_notr(dce); 1180bd670b35SErik Nordmark dce = dce_get_default(ixa->ixa_ipst); 1181bd670b35SErik Nordmark ASSERT(dce != NULL); 1182bd670b35SErik Nordmark #ifdef DEBUG 1183bd670b35SErik Nordmark dce_refhold_notr(dce); 1184bd670b35SErik Nordmark dce_refrele(dce); 1185bd670b35SErik Nordmark #endif 1186bd670b35SErik Nordmark ixa->ixa_dce = dce; 1187bd670b35SErik Nordmark ixa->ixa_dce_generation = DCE_GENERATION_VERIFY; 1188bd670b35SErik Nordmark } 1189bd670b35SErik Nordmark } 1190bd670b35SErik Nordmark 11917c6d7024SJerry Jelinek static mblk_t * 11927c6d7024SJerry Jelinek tcp_ixa_cleanup_getmblk(conn_t *connp) 11937c6d7024SJerry Jelinek { 11947c6d7024SJerry Jelinek tcp_stack_t *tcps = connp->conn_netstack->netstack_tcp; 11957c6d7024SJerry Jelinek int need_retry; 11967c6d7024SJerry Jelinek mblk_t *mp; 11977c6d7024SJerry Jelinek 11987c6d7024SJerry Jelinek mutex_enter(&tcps->tcps_ixa_cleanup_lock); 11997c6d7024SJerry Jelinek 12007c6d7024SJerry Jelinek /* 12017c6d7024SJerry Jelinek * It's possible that someone else came in and started cleaning up 12027c6d7024SJerry Jelinek * another connection between the time we verified this one is not being 12037c6d7024SJerry Jelinek * cleaned up and the time we actually get the shared mblk. If that's 12047c6d7024SJerry Jelinek * the case, we've dropped the lock, and some other thread may have 12057c6d7024SJerry Jelinek * cleaned up this connection again, and is still waiting for 12067c6d7024SJerry Jelinek * notification of that cleanup's completion. Therefore we need to 12077c6d7024SJerry Jelinek * recheck. 12087c6d7024SJerry Jelinek */ 12097c6d7024SJerry Jelinek do { 12107c6d7024SJerry Jelinek need_retry = 0; 12117c6d7024SJerry Jelinek while (connp->conn_ixa->ixa_tcpcleanup != IXATC_IDLE) { 12127c6d7024SJerry Jelinek cv_wait(&tcps->tcps_ixa_cleanup_done_cv, 12137c6d7024SJerry Jelinek &tcps->tcps_ixa_cleanup_lock); 12147c6d7024SJerry Jelinek } 12157c6d7024SJerry Jelinek 12167c6d7024SJerry Jelinek while ((mp = tcps->tcps_ixa_cleanup_mp) == NULL) { 12177c6d7024SJerry Jelinek /* 12187c6d7024SJerry Jelinek * Multiple concurrent cleanups; need to have the last 12197c6d7024SJerry Jelinek * one run since it could be an unplumb. 12207c6d7024SJerry Jelinek */ 12217c6d7024SJerry Jelinek need_retry = 1; 12227c6d7024SJerry Jelinek cv_wait(&tcps->tcps_ixa_cleanup_ready_cv, 12237c6d7024SJerry Jelinek &tcps->tcps_ixa_cleanup_lock); 12247c6d7024SJerry Jelinek } 12257c6d7024SJerry Jelinek } while (need_retry); 12267c6d7024SJerry Jelinek 12277c6d7024SJerry Jelinek /* 12287c6d7024SJerry Jelinek * We now have the lock and the mblk; now make sure that no one else can 12297c6d7024SJerry Jelinek * try to clean up this connection or enqueue it for cleanup, clear the 12307c6d7024SJerry Jelinek * mblk pointer for this stack, drop the lock, and return the mblk. 12317c6d7024SJerry Jelinek */ 12327c6d7024SJerry Jelinek ASSERT(MUTEX_HELD(&tcps->tcps_ixa_cleanup_lock)); 12337c6d7024SJerry Jelinek ASSERT(connp->conn_ixa->ixa_tcpcleanup == IXATC_IDLE); 12347c6d7024SJerry Jelinek ASSERT(tcps->tcps_ixa_cleanup_mp == mp); 12357c6d7024SJerry Jelinek ASSERT(mp != NULL); 12367c6d7024SJerry Jelinek 12377c6d7024SJerry Jelinek connp->conn_ixa->ixa_tcpcleanup = IXATC_INPROGRESS; 12387c6d7024SJerry Jelinek tcps->tcps_ixa_cleanup_mp = NULL; 12397c6d7024SJerry Jelinek mutex_exit(&tcps->tcps_ixa_cleanup_lock); 12407c6d7024SJerry Jelinek 12417c6d7024SJerry Jelinek return (mp); 12427c6d7024SJerry Jelinek } 12437c6d7024SJerry Jelinek 1244bd670b35SErik Nordmark /* 1245bd670b35SErik Nordmark * Used to run ixa_cleanup_stale inside the tcp squeue. 1246bd670b35SErik Nordmark * When done we hand the mp back by assigning it to tcps_ixa_cleanup_mp 1247bd670b35SErik Nordmark * and waking up the caller. 1248bd670b35SErik Nordmark */ 1249bd670b35SErik Nordmark /* ARGSUSED2 */ 1250bd670b35SErik Nordmark static void 1251bd670b35SErik Nordmark tcp_ixa_cleanup(void *arg, mblk_t *mp, void *arg2, 1252bd670b35SErik Nordmark ip_recv_attr_t *dummy) 1253bd670b35SErik Nordmark { 1254bd670b35SErik Nordmark conn_t *connp = (conn_t *)arg; 1255bd670b35SErik Nordmark tcp_stack_t *tcps; 1256bd670b35SErik Nordmark 1257bd670b35SErik Nordmark tcps = connp->conn_netstack->netstack_tcp; 1258bd670b35SErik Nordmark 1259bd670b35SErik Nordmark ixa_cleanup_stale(connp->conn_ixa); 1260bd670b35SErik Nordmark 1261bd670b35SErik Nordmark mutex_enter(&tcps->tcps_ixa_cleanup_lock); 1262bd670b35SErik Nordmark ASSERT(tcps->tcps_ixa_cleanup_mp == NULL); 12637c6d7024SJerry Jelinek connp->conn_ixa->ixa_tcpcleanup = IXATC_COMPLETE; 1264bd670b35SErik Nordmark tcps->tcps_ixa_cleanup_mp = mp; 12657c6d7024SJerry Jelinek cv_signal(&tcps->tcps_ixa_cleanup_ready_cv); 12667c6d7024SJerry Jelinek /* 12677c6d7024SJerry Jelinek * It is possible for any number of threads to be waiting for cleanup of 12687c6d7024SJerry Jelinek * different connections. Absent a per-connection (or per-IXA) CV, we 12697c6d7024SJerry Jelinek * need to wake them all up even though only one can be waiting on this 12707c6d7024SJerry Jelinek * particular cleanup. 12717c6d7024SJerry Jelinek */ 12727c6d7024SJerry Jelinek cv_broadcast(&tcps->tcps_ixa_cleanup_done_cv); 1273bd670b35SErik Nordmark mutex_exit(&tcps->tcps_ixa_cleanup_lock); 1274bd670b35SErik Nordmark } 1275bd670b35SErik Nordmark 12767c6d7024SJerry Jelinek static void 12777c6d7024SJerry Jelinek tcp_ixa_cleanup_wait_and_finish(conn_t *connp) 12787c6d7024SJerry Jelinek { 12797c6d7024SJerry Jelinek tcp_stack_t *tcps = connp->conn_netstack->netstack_tcp; 12807c6d7024SJerry Jelinek 12817c6d7024SJerry Jelinek mutex_enter(&tcps->tcps_ixa_cleanup_lock); 12827c6d7024SJerry Jelinek 12837c6d7024SJerry Jelinek ASSERT(connp->conn_ixa->ixa_tcpcleanup != IXATC_IDLE); 12847c6d7024SJerry Jelinek 12857c6d7024SJerry Jelinek while (connp->conn_ixa->ixa_tcpcleanup == IXATC_INPROGRESS) { 12867c6d7024SJerry Jelinek cv_wait(&tcps->tcps_ixa_cleanup_done_cv, 12877c6d7024SJerry Jelinek &tcps->tcps_ixa_cleanup_lock); 12887c6d7024SJerry Jelinek } 12897c6d7024SJerry Jelinek 12907c6d7024SJerry Jelinek ASSERT(connp->conn_ixa->ixa_tcpcleanup == IXATC_COMPLETE); 12917c6d7024SJerry Jelinek connp->conn_ixa->ixa_tcpcleanup = IXATC_IDLE; 12927c6d7024SJerry Jelinek cv_broadcast(&tcps->tcps_ixa_cleanup_done_cv); 12937c6d7024SJerry Jelinek 12947c6d7024SJerry Jelinek mutex_exit(&tcps->tcps_ixa_cleanup_lock); 12957c6d7024SJerry Jelinek } 1296bd670b35SErik Nordmark 1297bd670b35SErik Nordmark /* 1298bd670b35SErik Nordmark * ipcl_walk() function to help release any IRE, NCE, or DCEs that 1299bd670b35SErik Nordmark * have been deleted and are marked as condemned. 1300bd670b35SErik Nordmark * Note that we can't cleanup the pointers since there can be threads 1301bd670b35SErik Nordmark * in conn_ip_output() sending while we are called. 1302bd670b35SErik Nordmark */ 1303bd670b35SErik Nordmark void 1304bd670b35SErik Nordmark conn_ixa_cleanup(conn_t *connp, void *arg) 1305bd670b35SErik Nordmark { 1306bd670b35SErik Nordmark boolean_t tryhard = (boolean_t)arg; 1307bd670b35SErik Nordmark 1308bd670b35SErik Nordmark if (IPCL_IS_TCP(connp)) { 1309bd670b35SErik Nordmark mblk_t *mp; 1310bd670b35SErik Nordmark 13117c6d7024SJerry Jelinek mp = tcp_ixa_cleanup_getmblk(connp); 1312bd670b35SErik Nordmark 1313bd670b35SErik Nordmark if (connp->conn_sqp->sq_run == curthread) { 1314bd670b35SErik Nordmark /* Already on squeue */ 1315bd670b35SErik Nordmark tcp_ixa_cleanup(connp, mp, NULL, NULL); 1316bd670b35SErik Nordmark } else { 1317bd670b35SErik Nordmark CONN_INC_REF(connp); 1318bd670b35SErik Nordmark SQUEUE_ENTER_ONE(connp->conn_sqp, mp, tcp_ixa_cleanup, 1319bd670b35SErik Nordmark connp, NULL, SQ_PROCESS, SQTAG_TCP_IXA_CLEANUP); 1320bd670b35SErik Nordmark } 13217c6d7024SJerry Jelinek tcp_ixa_cleanup_wait_and_finish(connp); 1322bd670b35SErik Nordmark } else if (IPCL_IS_SCTP(connp)) { 1323bd670b35SErik Nordmark sctp_t *sctp; 1324bd670b35SErik Nordmark sctp_faddr_t *fp; 1325bd670b35SErik Nordmark 1326bd670b35SErik Nordmark sctp = CONN2SCTP(connp); 1327bd670b35SErik Nordmark RUN_SCTP(sctp); 1328bd670b35SErik Nordmark ixa_cleanup_stale(connp->conn_ixa); 13296be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) 13306be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India ixa_cleanup_stale(fp->sf_ixa); 1331bd670b35SErik Nordmark WAKE_SCTP(sctp); 1332bd670b35SErik Nordmark } else { 1333bd670b35SErik Nordmark ip_xmit_attr_t *ixa; 1334bd670b35SErik Nordmark 1335bd670b35SErik Nordmark /* 1336bd670b35SErik Nordmark * If there is a different thread using conn_ixa then we get a 1337bd670b35SErik Nordmark * new copy and cut the old one loose from conn_ixa. Otherwise 1338bd670b35SErik Nordmark * we use conn_ixa and prevent any other thread from 1339bd670b35SErik Nordmark * using/changing it. Anybody using conn_ixa (e.g., a thread in 1340bd670b35SErik Nordmark * conn_ip_output) will do an ixa_refrele which will remove any 1341bd670b35SErik Nordmark * references on the ire etc. 1342bd670b35SErik Nordmark * 1343bd670b35SErik Nordmark * Once we are done other threads can use conn_ixa since the 1344bd670b35SErik Nordmark * refcnt will be back at one. 1345bd670b35SErik Nordmark * 1346bd670b35SErik Nordmark * We are called either because an ill is going away, or 1347bd670b35SErik Nordmark * due to memory reclaim. In the former case we wait for 1348bd670b35SErik Nordmark * memory since we must remove the refcnts on the ill. 1349bd670b35SErik Nordmark */ 1350bd670b35SErik Nordmark if (tryhard) { 1351bd670b35SErik Nordmark ixa = conn_get_ixa_tryhard(connp, B_TRUE); 1352bd670b35SErik Nordmark ASSERT(ixa != NULL); 1353bd670b35SErik Nordmark } else { 1354bd670b35SErik Nordmark ixa = conn_get_ixa(connp, B_TRUE); 1355bd670b35SErik Nordmark if (ixa == NULL) { 1356bd670b35SErik Nordmark /* 1357bd670b35SErik Nordmark * Somebody else was using it and kmem_alloc 1358bd670b35SErik Nordmark * failed! Next memory reclaim will try to 1359bd670b35SErik Nordmark * clean up. 1360bd670b35SErik Nordmark */ 1361bd670b35SErik Nordmark DTRACE_PROBE1(conn__ixa__cleanup__bail, 1362bd670b35SErik Nordmark conn_t *, connp); 1363bd670b35SErik Nordmark return; 1364bd670b35SErik Nordmark } 1365bd670b35SErik Nordmark } 1366bd670b35SErik Nordmark ixa_cleanup_stale(ixa); 1367*77dabb95SDan McDonald IXA_REFRELE(ixa); 1368bd670b35SErik Nordmark } 1369bd670b35SErik Nordmark } 1370bd670b35SErik Nordmark 1371bd670b35SErik Nordmark /* 1372bd670b35SErik Nordmark * ixa needs to be an exclusive copy so that no one changes the cookie 1373bd670b35SErik Nordmark * or the ixa_nce. 1374bd670b35SErik Nordmark */ 1375bd670b35SErik Nordmark boolean_t 1376bd670b35SErik Nordmark ixa_check_drain_insert(conn_t *connp, ip_xmit_attr_t *ixa) 1377bd670b35SErik Nordmark { 1378bd670b35SErik Nordmark uintptr_t cookie = ixa->ixa_cookie; 1379bd670b35SErik Nordmark ill_dld_direct_t *idd; 1380bd670b35SErik Nordmark idl_tx_list_t *idl_txl; 1381bd670b35SErik Nordmark ill_t *ill = ixa->ixa_nce->nce_ill; 1382bd670b35SErik Nordmark boolean_t inserted = B_FALSE; 1383bd670b35SErik Nordmark 1384bd670b35SErik Nordmark idd = &(ill)->ill_dld_capab->idc_direct; 1385bd670b35SErik Nordmark idl_txl = &ixa->ixa_ipst->ips_idl_tx_list[IDLHASHINDEX(cookie)]; 1386bd670b35SErik Nordmark mutex_enter(&idl_txl->txl_lock); 13873344d750Smeem 13883344d750Smeem /* 13893344d750Smeem * If `cookie' is zero, ip_xmit() -> canputnext() failed -- i.e., flow 13903344d750Smeem * control is asserted on an ill that does not support direct calls. 13913344d750Smeem * Jump to insert. 13923344d750Smeem */ 13933344d750Smeem if (cookie == 0) 13943344d750Smeem goto tryinsert; 13953344d750Smeem 13963344d750Smeem ASSERT(ILL_DIRECT_CAPABLE(ill)); 13973344d750Smeem 13983344d750Smeem if (idd->idd_tx_fctl_df(idd->idd_tx_fctl_dh, cookie) == 0) { 13993344d750Smeem DTRACE_PROBE1(ill__tx__not__blocked, uintptr_t, cookie); 1400bd670b35SErik Nordmark } else if (idl_txl->txl_cookie != NULL && 1401bd670b35SErik Nordmark idl_txl->txl_cookie != ixa->ixa_cookie) { 14023344d750Smeem DTRACE_PROBE2(ill__tx__cookie__collision, uintptr_t, cookie, 1403bd670b35SErik Nordmark uintptr_t, idl_txl->txl_cookie); 14043344d750Smeem /* TODO: bump kstat for cookie collision */ 1405bd670b35SErik Nordmark } else { 14063344d750Smeem /* 14073344d750Smeem * Check/set conn_blocked under conn_lock. Note that txl_lock 14083344d750Smeem * will not suffice since two separate UDP threads may be 14093344d750Smeem * racing to send to different destinations that are 14103344d750Smeem * associated with different cookies and thus may not be 14113344d750Smeem * holding the same txl_lock. Further, since a given conn_t 14123344d750Smeem * can only be on a single drain list, the conn_t will be 14133344d750Smeem * enqueued on whichever thread wins this race. 14143344d750Smeem */ 14153344d750Smeem tryinsert: mutex_enter(&connp->conn_lock); 14163344d750Smeem if (connp->conn_blocked) { 14173344d750Smeem DTRACE_PROBE1(ill__tx__conn__already__blocked, 14183344d750Smeem conn_t *, connp); 14193344d750Smeem mutex_exit(&connp->conn_lock); 14203344d750Smeem } else { 14213344d750Smeem connp->conn_blocked = B_TRUE; 14223344d750Smeem mutex_exit(&connp->conn_lock); 1423bd670b35SErik Nordmark idl_txl->txl_cookie = cookie; 1424bd670b35SErik Nordmark conn_drain_insert(connp, idl_txl); 1425bd670b35SErik Nordmark if (!IPCL_IS_NONSTR(connp)) 1426bd670b35SErik Nordmark noenable(connp->conn_wq); 1427bd670b35SErik Nordmark inserted = B_TRUE; 1428bd670b35SErik Nordmark } 14293344d750Smeem } 1430bd670b35SErik Nordmark mutex_exit(&idl_txl->txl_lock); 1431bd670b35SErik Nordmark return (inserted); 1432bd670b35SErik Nordmark } 1433