xref: /onnv-gate/usr/src/uts/common/inet/ip/ip_attr.c (revision 13009:29fc56bd19a6)
111042SErik.Nordmark@Sun.COM /*
211042SErik.Nordmark@Sun.COM  * CDDL HEADER START
311042SErik.Nordmark@Sun.COM  *
411042SErik.Nordmark@Sun.COM  * The contents of this file are subject to the terms of the
511042SErik.Nordmark@Sun.COM  * Common Development and Distribution License (the "License").
611042SErik.Nordmark@Sun.COM  * You may not use this file except in compliance with the License.
711042SErik.Nordmark@Sun.COM  *
811042SErik.Nordmark@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911042SErik.Nordmark@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011042SErik.Nordmark@Sun.COM  * See the License for the specific language governing permissions
1111042SErik.Nordmark@Sun.COM  * and limitations under the License.
1211042SErik.Nordmark@Sun.COM  *
1311042SErik.Nordmark@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411042SErik.Nordmark@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511042SErik.Nordmark@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611042SErik.Nordmark@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711042SErik.Nordmark@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811042SErik.Nordmark@Sun.COM  *
1911042SErik.Nordmark@Sun.COM  * CDDL HEADER END
2011042SErik.Nordmark@Sun.COM  */
2111042SErik.Nordmark@Sun.COM 
2211042SErik.Nordmark@Sun.COM /*
2312507SAlan.Maguire@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2411042SErik.Nordmark@Sun.COM  */
2511042SErik.Nordmark@Sun.COM /* Copyright (c) 1990 Mentat Inc. */
2611042SErik.Nordmark@Sun.COM 
2711042SErik.Nordmark@Sun.COM #include <sys/types.h>
2811042SErik.Nordmark@Sun.COM #include <sys/stream.h>
2911042SErik.Nordmark@Sun.COM #include <sys/strsun.h>
3011042SErik.Nordmark@Sun.COM #include <sys/zone.h>
3111042SErik.Nordmark@Sun.COM #include <sys/ddi.h>
3211042SErik.Nordmark@Sun.COM #include <sys/sunddi.h>
3311042SErik.Nordmark@Sun.COM #include <sys/cmn_err.h>
3411042SErik.Nordmark@Sun.COM #include <sys/debug.h>
3511042SErik.Nordmark@Sun.COM #include <sys/atomic.h>
3611042SErik.Nordmark@Sun.COM 
3711042SErik.Nordmark@Sun.COM #include <sys/systm.h>
3811042SErik.Nordmark@Sun.COM #include <sys/param.h>
3911042SErik.Nordmark@Sun.COM #include <sys/kmem.h>
4011042SErik.Nordmark@Sun.COM #include <sys/sdt.h>
4111042SErik.Nordmark@Sun.COM #include <sys/socket.h>
4211042SErik.Nordmark@Sun.COM #include <sys/mac.h>
4311042SErik.Nordmark@Sun.COM #include <net/if.h>
4411042SErik.Nordmark@Sun.COM #include <net/if_arp.h>
4511042SErik.Nordmark@Sun.COM #include <net/route.h>
4611042SErik.Nordmark@Sun.COM #include <sys/sockio.h>
4711042SErik.Nordmark@Sun.COM #include <netinet/in.h>
4811042SErik.Nordmark@Sun.COM #include <net/if_dl.h>
4911042SErik.Nordmark@Sun.COM 
5011042SErik.Nordmark@Sun.COM #include <inet/common.h>
5111042SErik.Nordmark@Sun.COM #include <inet/mi.h>
5211042SErik.Nordmark@Sun.COM #include <inet/mib2.h>
5311042SErik.Nordmark@Sun.COM #include <inet/nd.h>
5411042SErik.Nordmark@Sun.COM #include <inet/arp.h>
5511042SErik.Nordmark@Sun.COM #include <inet/snmpcom.h>
5611042SErik.Nordmark@Sun.COM #include <inet/kstatcom.h>
5711042SErik.Nordmark@Sun.COM 
5811042SErik.Nordmark@Sun.COM #include <netinet/igmp_var.h>
5911042SErik.Nordmark@Sun.COM #include <netinet/ip6.h>
6011042SErik.Nordmark@Sun.COM #include <netinet/icmp6.h>
6111042SErik.Nordmark@Sun.COM #include <netinet/sctp.h>
6211042SErik.Nordmark@Sun.COM 
6311042SErik.Nordmark@Sun.COM #include <inet/ip.h>
6411042SErik.Nordmark@Sun.COM #include <inet/ip_impl.h>
6511042SErik.Nordmark@Sun.COM #include <inet/ip6.h>
6611042SErik.Nordmark@Sun.COM #include <inet/ip6_asp.h>
6711042SErik.Nordmark@Sun.COM #include <inet/tcp.h>
6811042SErik.Nordmark@Sun.COM #include <inet/ip_multi.h>
6911042SErik.Nordmark@Sun.COM #include <inet/ip_if.h>
7011042SErik.Nordmark@Sun.COM #include <inet/ip_ire.h>
7111042SErik.Nordmark@Sun.COM #include <inet/ip_ftable.h>
7211042SErik.Nordmark@Sun.COM #include <inet/ip_rts.h>
7311042SErik.Nordmark@Sun.COM #include <inet/optcom.h>
7411042SErik.Nordmark@Sun.COM #include <inet/ip_ndp.h>
7511042SErik.Nordmark@Sun.COM #include <inet/ip_listutils.h>
7611042SErik.Nordmark@Sun.COM #include <netinet/igmp.h>
7711042SErik.Nordmark@Sun.COM #include <netinet/ip_mroute.h>
7811042SErik.Nordmark@Sun.COM #include <inet/ipp_common.h>
7911042SErik.Nordmark@Sun.COM 
8011042SErik.Nordmark@Sun.COM #include <net/pfkeyv2.h>
8111042SErik.Nordmark@Sun.COM #include <inet/sadb.h>
8211042SErik.Nordmark@Sun.COM #include <inet/ipsec_impl.h>
8311042SErik.Nordmark@Sun.COM #include <inet/ipdrop.h>
8411042SErik.Nordmark@Sun.COM #include <inet/ip_netinfo.h>
8511042SErik.Nordmark@Sun.COM #include <sys/squeue_impl.h>
8611042SErik.Nordmark@Sun.COM #include <sys/squeue.h>
8711042SErik.Nordmark@Sun.COM 
8811042SErik.Nordmark@Sun.COM #include <inet/ipclassifier.h>
8911042SErik.Nordmark@Sun.COM #include <inet/sctp_ip.h>
9011042SErik.Nordmark@Sun.COM #include <inet/sctp/sctp_impl.h>
9111042SErik.Nordmark@Sun.COM #include <inet/udp_impl.h>
9211042SErik.Nordmark@Sun.COM #include <sys/sunddi.h>
9311042SErik.Nordmark@Sun.COM 
9411042SErik.Nordmark@Sun.COM #include <sys/tsol/label.h>
9511042SErik.Nordmark@Sun.COM #include <sys/tsol/tnet.h>
9611042SErik.Nordmark@Sun.COM 
9711042SErik.Nordmark@Sun.COM /*
9811042SErik.Nordmark@Sun.COM  * Release a reference on ip_xmit_attr.
9911042SErik.Nordmark@Sun.COM  * The reference is acquired by conn_get_ixa()
10011042SErik.Nordmark@Sun.COM  */
10111042SErik.Nordmark@Sun.COM #define	IXA_REFRELE(ixa)					\
10211042SErik.Nordmark@Sun.COM {								\
10311042SErik.Nordmark@Sun.COM 	if (atomic_add_32_nv(&(ixa)->ixa_refcnt, -1) == 0)	\
10411042SErik.Nordmark@Sun.COM 		ixa_inactive(ixa);				\
10511042SErik.Nordmark@Sun.COM }
10611042SErik.Nordmark@Sun.COM 
10711042SErik.Nordmark@Sun.COM #define	IXA_REFHOLD(ixa)					\
10811042SErik.Nordmark@Sun.COM {								\
10911042SErik.Nordmark@Sun.COM 	ASSERT((ixa)->ixa_refcnt != 0);				\
11011042SErik.Nordmark@Sun.COM 	atomic_add_32(&(ixa)->ixa_refcnt, 1);			\
11111042SErik.Nordmark@Sun.COM }
11211042SErik.Nordmark@Sun.COM 
11311042SErik.Nordmark@Sun.COM /*
11411042SErik.Nordmark@Sun.COM  * When we need to handle a transmit side asynchronous operation, then we need
11511042SErik.Nordmark@Sun.COM  * to save sufficient information so that we can call the fragment and postfrag
11611042SErik.Nordmark@Sun.COM  * functions. That information is captured in an mblk containing this structure.
11711042SErik.Nordmark@Sun.COM  *
11811042SErik.Nordmark@Sun.COM  * Since this is currently only used for IPsec, we include information for
11911042SErik.Nordmark@Sun.COM  * the kernel crypto framework.
12011042SErik.Nordmark@Sun.COM  */
12111042SErik.Nordmark@Sun.COM typedef struct ixamblk_s {
12211042SErik.Nordmark@Sun.COM 	boolean_t	ixm_inbound;	/* B_FALSE */
12311042SErik.Nordmark@Sun.COM 	iaflags_t	ixm_flags;	/* ixa_flags */
12411042SErik.Nordmark@Sun.COM 	netstackid_t	ixm_stackid;	/* Verify it didn't go away */
12511042SErik.Nordmark@Sun.COM 	uint_t		ixm_ifindex;	/* Used to find the nce */
12611042SErik.Nordmark@Sun.COM 	in6_addr_t	ixm_nceaddr_v6;	/* Used to find nce */
12711042SErik.Nordmark@Sun.COM #define	ixm_nceaddr_v4	V4_PART_OF_V6(ixm_nceaddr_v6)
12811042SErik.Nordmark@Sun.COM 	uint32_t	ixm_fragsize;
12911042SErik.Nordmark@Sun.COM 	uint_t		ixm_pktlen;
13011042SErik.Nordmark@Sun.COM 	uint16_t	ixm_ip_hdr_length; /* Points to ULP header */
13111042SErik.Nordmark@Sun.COM 	uint8_t		ixm_protocol;	/* Protocol number for ULP cksum */
13211042SErik.Nordmark@Sun.COM 	pfirepostfrag_t	ixm_postfragfn;
13311042SErik.Nordmark@Sun.COM 
13411042SErik.Nordmark@Sun.COM 	zoneid_t	ixm_zoneid;		/* Needed for ipobs */
13511042SErik.Nordmark@Sun.COM 	zoneid_t	ixm_no_loop_zoneid;	/* IXAF_NO_LOOP_ZONEID_SET */
13611042SErik.Nordmark@Sun.COM 
13711042SErik.Nordmark@Sun.COM 	uint_t		ixm_scopeid;		/* For IPv6 link-locals */
13811042SErik.Nordmark@Sun.COM 
13911042SErik.Nordmark@Sun.COM 	uint32_t	ixm_ident;		/* For IPv6 fragment header */
14011042SErik.Nordmark@Sun.COM 	uint32_t	ixm_xmit_hint;
14111042SErik.Nordmark@Sun.COM 
14212507SAlan.Maguire@Sun.COM 	uint64_t	ixm_conn_id;		/* Used by DTrace */
14311042SErik.Nordmark@Sun.COM 	cred_t		*ixm_cred;	/* For getpeerucred - refhold if set */
14411042SErik.Nordmark@Sun.COM 	pid_t		ixm_cpid;	/* For getpeerucred */
14511042SErik.Nordmark@Sun.COM 
14611042SErik.Nordmark@Sun.COM 	ts_label_t	*ixm_tsl;	/* Refhold if set. */
14711042SErik.Nordmark@Sun.COM 
14811042SErik.Nordmark@Sun.COM 	/*
14911042SErik.Nordmark@Sun.COM 	 * When the pointers below are set they have a refhold on the struct.
15011042SErik.Nordmark@Sun.COM 	 */
15111042SErik.Nordmark@Sun.COM 	ipsec_latch_t		*ixm_ipsec_latch;
15211042SErik.Nordmark@Sun.COM 	struct ipsa_s		*ixm_ipsec_ah_sa;	/* SA for AH */
15311042SErik.Nordmark@Sun.COM 	struct ipsa_s		*ixm_ipsec_esp_sa;	/* SA for ESP */
15411042SErik.Nordmark@Sun.COM 	struct ipsec_policy_s 	*ixm_ipsec_policy;	/* why are we here? */
15511042SErik.Nordmark@Sun.COM 	struct ipsec_action_s	*ixm_ipsec_action; /* For reflected packets */
15611042SErik.Nordmark@Sun.COM 
15711042SErik.Nordmark@Sun.COM 	ipsa_ref_t		ixm_ipsec_ref[2]; /* Soft reference to SA */
15811042SErik.Nordmark@Sun.COM 
15911042SErik.Nordmark@Sun.COM 	/* Need these while waiting for SA */
16011042SErik.Nordmark@Sun.COM 	uint16_t ixm_ipsec_src_port;	/* Source port number of d-gram. */
16111042SErik.Nordmark@Sun.COM 	uint16_t ixm_ipsec_dst_port;	/* Destination port number of d-gram. */
16211042SErik.Nordmark@Sun.COM 	uint8_t  ixm_ipsec_icmp_type;	/* ICMP type of d-gram */
16311042SErik.Nordmark@Sun.COM 	uint8_t  ixm_ipsec_icmp_code;	/* ICMP code of d-gram */
16411042SErik.Nordmark@Sun.COM 
16511042SErik.Nordmark@Sun.COM 	sa_family_t ixm_ipsec_inaf;	/* Inner address family */
16611042SErik.Nordmark@Sun.COM 	uint32_t ixm_ipsec_insrc[IXA_MAX_ADDRLEN];	/* Inner src address */
16711042SErik.Nordmark@Sun.COM 	uint32_t ixm_ipsec_indst[IXA_MAX_ADDRLEN];	/* Inner dest address */
16811042SErik.Nordmark@Sun.COM 	uint8_t  ixm_ipsec_insrcpfx;	/* Inner source prefix */
16911042SErik.Nordmark@Sun.COM 	uint8_t  ixm_ipsec_indstpfx;	/* Inner destination prefix */
17011042SErik.Nordmark@Sun.COM 
17111042SErik.Nordmark@Sun.COM 	uint8_t ixm_ipsec_proto;	/* IP protocol number for d-gram. */
17211042SErik.Nordmark@Sun.COM } ixamblk_t;
17311042SErik.Nordmark@Sun.COM 
17411042SErik.Nordmark@Sun.COM 
17511042SErik.Nordmark@Sun.COM /*
17611042SErik.Nordmark@Sun.COM  * When we need to handle a receive side asynchronous operation, then we need
17711042SErik.Nordmark@Sun.COM  * to save sufficient information so that we can call ip_fanout.
17811042SErik.Nordmark@Sun.COM  * That information is captured in an mblk containing this structure.
17911042SErik.Nordmark@Sun.COM  *
18011042SErik.Nordmark@Sun.COM  * Since this is currently only used for IPsec, we include information for
18111042SErik.Nordmark@Sun.COM  * the kernel crypto framework.
18211042SErik.Nordmark@Sun.COM  */
18311042SErik.Nordmark@Sun.COM typedef struct iramblk_s {
18411042SErik.Nordmark@Sun.COM 	boolean_t	irm_inbound;	/* B_TRUE */
18511042SErik.Nordmark@Sun.COM 	iaflags_t	irm_flags;	/* ira_flags */
18611042SErik.Nordmark@Sun.COM 	netstackid_t	irm_stackid;	/* Verify it didn't go away */
18711042SErik.Nordmark@Sun.COM 	uint_t		irm_ifindex;	/* To find ira_ill */
18811042SErik.Nordmark@Sun.COM 
18911042SErik.Nordmark@Sun.COM 	uint_t		irm_rifindex;	/* ira_rifindex */
19011042SErik.Nordmark@Sun.COM 	uint_t		irm_ruifindex;	/* ira_ruifindex */
19111042SErik.Nordmark@Sun.COM 	uint_t		irm_pktlen;
19211042SErik.Nordmark@Sun.COM 	uint16_t	irm_ip_hdr_length; /* Points to ULP header */
19311042SErik.Nordmark@Sun.COM 	uint8_t		irm_protocol;	/* Protocol number for ULP cksum */
19411042SErik.Nordmark@Sun.COM 	zoneid_t	irm_zoneid;	/* ALL_ZONES unless local delivery */
19511042SErik.Nordmark@Sun.COM 
19611042SErik.Nordmark@Sun.COM 	squeue_t	*irm_sqp;
19711042SErik.Nordmark@Sun.COM 	ill_rx_ring_t	*irm_ring;
19811042SErik.Nordmark@Sun.COM 
19911042SErik.Nordmark@Sun.COM 	ipaddr_t	irm_mroute_tunnel;	/* IRAF_MROUTE_TUNNEL_SET */
20011042SErik.Nordmark@Sun.COM 	zoneid_t	irm_no_loop_zoneid;	/* IRAF_NO_LOOP_ZONEID_SET */
20111042SErik.Nordmark@Sun.COM 	uint32_t	irm_esp_udp_ports;	/* IRAF_ESP_UDP_PORTS */
20211042SErik.Nordmark@Sun.COM 
20311042SErik.Nordmark@Sun.COM 	char		irm_l2src[IRA_L2SRC_SIZE];	/* If IRAF_L2SRC_SET */
20411042SErik.Nordmark@Sun.COM 
20511042SErik.Nordmark@Sun.COM 	cred_t		*irm_cred;	/* For getpeerucred - refhold if set */
20611042SErik.Nordmark@Sun.COM 	pid_t		irm_cpid;	/* For getpeerucred */
20711042SErik.Nordmark@Sun.COM 
20811042SErik.Nordmark@Sun.COM 	ts_label_t	*irm_tsl;	/* Refhold if set. */
20911042SErik.Nordmark@Sun.COM 
21011042SErik.Nordmark@Sun.COM 	/*
21111042SErik.Nordmark@Sun.COM 	 * When set these correspond to a refhold on the object.
21211042SErik.Nordmark@Sun.COM 	 */
21311042SErik.Nordmark@Sun.COM 	struct ipsa_s		*irm_ipsec_ah_sa;	/* SA for AH */
21411042SErik.Nordmark@Sun.COM 	struct ipsa_s		*irm_ipsec_esp_sa;	/* SA for ESP */
21511042SErik.Nordmark@Sun.COM 	struct ipsec_action_s	*irm_ipsec_action; /* For reflected packets */
21611042SErik.Nordmark@Sun.COM } iramblk_t;
21711042SErik.Nordmark@Sun.COM 
21811042SErik.Nordmark@Sun.COM 
21911042SErik.Nordmark@Sun.COM /*
22011042SErik.Nordmark@Sun.COM  * Take the information in ip_xmit_attr_t and stick it in an mblk
22111042SErik.Nordmark@Sun.COM  * that can later be passed to ip_xmit_attr_from_mblk to recreate the
22211042SErik.Nordmark@Sun.COM  * ip_xmit_attr_t.
22311042SErik.Nordmark@Sun.COM  *
22411042SErik.Nordmark@Sun.COM  * Returns NULL on memory allocation failure.
22511042SErik.Nordmark@Sun.COM  */
22611042SErik.Nordmark@Sun.COM mblk_t *
ip_xmit_attr_to_mblk(ip_xmit_attr_t * ixa)22711042SErik.Nordmark@Sun.COM ip_xmit_attr_to_mblk(ip_xmit_attr_t *ixa)
22811042SErik.Nordmark@Sun.COM {
22911042SErik.Nordmark@Sun.COM 	mblk_t		*ixamp;
23011042SErik.Nordmark@Sun.COM 	ixamblk_t	*ixm;
23111042SErik.Nordmark@Sun.COM 	nce_t		*nce = ixa->ixa_nce;
23211042SErik.Nordmark@Sun.COM 
23311042SErik.Nordmark@Sun.COM 	ASSERT(nce != NULL);
23411042SErik.Nordmark@Sun.COM 	ixamp = allocb(sizeof (*ixm), BPRI_MED);
23511042SErik.Nordmark@Sun.COM 	if (ixamp == NULL)
23611042SErik.Nordmark@Sun.COM 		return (NULL);
23711042SErik.Nordmark@Sun.COM 
23811042SErik.Nordmark@Sun.COM 	ixamp->b_datap->db_type = M_BREAK;
23911042SErik.Nordmark@Sun.COM 	ixamp->b_wptr += sizeof (*ixm);
24011042SErik.Nordmark@Sun.COM 	ixm = (ixamblk_t *)ixamp->b_rptr;
24111042SErik.Nordmark@Sun.COM 
24211042SErik.Nordmark@Sun.COM 	bzero(ixm, sizeof (*ixm));
24311042SErik.Nordmark@Sun.COM 	ixm->ixm_inbound = B_FALSE;
24411042SErik.Nordmark@Sun.COM 	ixm->ixm_flags = ixa->ixa_flags;
24511042SErik.Nordmark@Sun.COM 	ixm->ixm_stackid = ixa->ixa_ipst->ips_netstack->netstack_stackid;
24611042SErik.Nordmark@Sun.COM 	ixm->ixm_ifindex = nce->nce_ill->ill_phyint->phyint_ifindex;
24711042SErik.Nordmark@Sun.COM 	ixm->ixm_nceaddr_v6 = nce->nce_addr;
24811042SErik.Nordmark@Sun.COM 	ixm->ixm_fragsize = ixa->ixa_fragsize;
24911042SErik.Nordmark@Sun.COM 	ixm->ixm_pktlen = ixa->ixa_pktlen;
25011042SErik.Nordmark@Sun.COM 	ixm->ixm_ip_hdr_length = ixa->ixa_ip_hdr_length;
25111042SErik.Nordmark@Sun.COM 	ixm->ixm_protocol = ixa->ixa_protocol;
25211042SErik.Nordmark@Sun.COM 	ixm->ixm_postfragfn = ixa->ixa_postfragfn;
25311042SErik.Nordmark@Sun.COM 	ixm->ixm_zoneid = ixa->ixa_zoneid;
25411042SErik.Nordmark@Sun.COM 	ixm->ixm_no_loop_zoneid = ixa->ixa_no_loop_zoneid;
25511042SErik.Nordmark@Sun.COM 	ixm->ixm_scopeid = ixa->ixa_scopeid;
25611042SErik.Nordmark@Sun.COM 	ixm->ixm_ident = ixa->ixa_ident;
25711042SErik.Nordmark@Sun.COM 	ixm->ixm_xmit_hint = ixa->ixa_xmit_hint;
25811042SErik.Nordmark@Sun.COM 
25911042SErik.Nordmark@Sun.COM 	if (ixa->ixa_tsl != NULL) {
26011042SErik.Nordmark@Sun.COM 		ixm->ixm_tsl = ixa->ixa_tsl;
26111042SErik.Nordmark@Sun.COM 		label_hold(ixm->ixm_tsl);
26211042SErik.Nordmark@Sun.COM 	}
26311042SErik.Nordmark@Sun.COM 	if (ixa->ixa_cred != NULL) {
26411042SErik.Nordmark@Sun.COM 		ixm->ixm_cred = ixa->ixa_cred;
26511042SErik.Nordmark@Sun.COM 		crhold(ixa->ixa_cred);
26611042SErik.Nordmark@Sun.COM 	}
26711042SErik.Nordmark@Sun.COM 	ixm->ixm_cpid = ixa->ixa_cpid;
26812507SAlan.Maguire@Sun.COM 	ixm->ixm_conn_id = ixa->ixa_conn_id;
26911042SErik.Nordmark@Sun.COM 
27011042SErik.Nordmark@Sun.COM 	if (ixa->ixa_flags & IXAF_IPSEC_SECURE) {
27111042SErik.Nordmark@Sun.COM 		if (ixa->ixa_ipsec_ah_sa != NULL) {
27211042SErik.Nordmark@Sun.COM 			ixm->ixm_ipsec_ah_sa = ixa->ixa_ipsec_ah_sa;
27311042SErik.Nordmark@Sun.COM 			IPSA_REFHOLD(ixa->ixa_ipsec_ah_sa);
27411042SErik.Nordmark@Sun.COM 		}
27511042SErik.Nordmark@Sun.COM 		if (ixa->ixa_ipsec_esp_sa != NULL) {
27611042SErik.Nordmark@Sun.COM 			ixm->ixm_ipsec_esp_sa = ixa->ixa_ipsec_esp_sa;
27711042SErik.Nordmark@Sun.COM 			IPSA_REFHOLD(ixa->ixa_ipsec_esp_sa);
27811042SErik.Nordmark@Sun.COM 		}
27911042SErik.Nordmark@Sun.COM 		if (ixa->ixa_ipsec_policy != NULL) {
28011042SErik.Nordmark@Sun.COM 			ixm->ixm_ipsec_policy = ixa->ixa_ipsec_policy;
28111042SErik.Nordmark@Sun.COM 			IPPOL_REFHOLD(ixa->ixa_ipsec_policy);
28211042SErik.Nordmark@Sun.COM 		}
28311042SErik.Nordmark@Sun.COM 		if (ixa->ixa_ipsec_action != NULL) {
28411042SErik.Nordmark@Sun.COM 			ixm->ixm_ipsec_action = ixa->ixa_ipsec_action;
28511042SErik.Nordmark@Sun.COM 			IPACT_REFHOLD(ixa->ixa_ipsec_action);
28611042SErik.Nordmark@Sun.COM 		}
28711042SErik.Nordmark@Sun.COM 		if (ixa->ixa_ipsec_latch != NULL) {
28811042SErik.Nordmark@Sun.COM 			ixm->ixm_ipsec_latch = ixa->ixa_ipsec_latch;
28911042SErik.Nordmark@Sun.COM 			IPLATCH_REFHOLD(ixa->ixa_ipsec_latch);
29011042SErik.Nordmark@Sun.COM 		}
29111042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_ref[0] = ixa->ixa_ipsec_ref[0];
29211042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_ref[1] = ixa->ixa_ipsec_ref[1];
29311042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_src_port = ixa->ixa_ipsec_src_port;
29411042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_dst_port = ixa->ixa_ipsec_dst_port;
29511042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_icmp_type = ixa->ixa_ipsec_icmp_type;
29611042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_icmp_code = ixa->ixa_ipsec_icmp_code;
29711042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_inaf = ixa->ixa_ipsec_inaf;
29811042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_insrc[0] = ixa->ixa_ipsec_insrc[0];
29911042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_insrc[1] = ixa->ixa_ipsec_insrc[1];
30011042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_insrc[2] = ixa->ixa_ipsec_insrc[2];
30111042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_insrc[3] = ixa->ixa_ipsec_insrc[3];
30211042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_indst[0] = ixa->ixa_ipsec_indst[0];
30311042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_indst[1] = ixa->ixa_ipsec_indst[1];
30411042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_indst[2] = ixa->ixa_ipsec_indst[2];
30511042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_indst[3] = ixa->ixa_ipsec_indst[3];
30611042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_insrcpfx = ixa->ixa_ipsec_insrcpfx;
30711042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_indstpfx = ixa->ixa_ipsec_indstpfx;
30811042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_proto = ixa->ixa_ipsec_proto;
30911042SErik.Nordmark@Sun.COM 	}
31011042SErik.Nordmark@Sun.COM 	return (ixamp);
31111042SErik.Nordmark@Sun.COM }
31211042SErik.Nordmark@Sun.COM 
31311042SErik.Nordmark@Sun.COM /*
31411042SErik.Nordmark@Sun.COM  * Extract the ip_xmit_attr_t from the mblk, checking that the
31511042SErik.Nordmark@Sun.COM  * ip_stack_t, ill_t, and nce_t still exist. Returns B_FALSE if that is
31611042SErik.Nordmark@Sun.COM  * not the case.
31711042SErik.Nordmark@Sun.COM  *
31811042SErik.Nordmark@Sun.COM  * Otherwise ixa is updated.
31911042SErik.Nordmark@Sun.COM  * Caller needs to release references on the ixa by calling ixa_refrele()
32011042SErik.Nordmark@Sun.COM  * which will imediately call ixa_inactive to release the references.
32111042SErik.Nordmark@Sun.COM  */
32211042SErik.Nordmark@Sun.COM boolean_t
ip_xmit_attr_from_mblk(mblk_t * ixamp,ip_xmit_attr_t * ixa)32311042SErik.Nordmark@Sun.COM ip_xmit_attr_from_mblk(mblk_t *ixamp, ip_xmit_attr_t *ixa)
32411042SErik.Nordmark@Sun.COM {
32511042SErik.Nordmark@Sun.COM 	ixamblk_t	*ixm;
32611042SErik.Nordmark@Sun.COM 	netstack_t	*ns;
32711042SErik.Nordmark@Sun.COM 	ip_stack_t	*ipst;
32811042SErik.Nordmark@Sun.COM 	ill_t		*ill;
32911042SErik.Nordmark@Sun.COM 	nce_t		*nce;
33011042SErik.Nordmark@Sun.COM 
33111042SErik.Nordmark@Sun.COM 	/* We assume the caller hasn't initialized ixa */
33211042SErik.Nordmark@Sun.COM 	bzero(ixa, sizeof (*ixa));
33311042SErik.Nordmark@Sun.COM 
33411042SErik.Nordmark@Sun.COM 	ASSERT(DB_TYPE(ixamp) == M_BREAK);
33511042SErik.Nordmark@Sun.COM 	ASSERT(ixamp->b_cont == NULL);
33611042SErik.Nordmark@Sun.COM 
33711042SErik.Nordmark@Sun.COM 	ixm = (ixamblk_t *)ixamp->b_rptr;
33811042SErik.Nordmark@Sun.COM 	ASSERT(!ixm->ixm_inbound);
33911042SErik.Nordmark@Sun.COM 
34011042SErik.Nordmark@Sun.COM 	/* Verify the netstack is still around */
34111042SErik.Nordmark@Sun.COM 	ns = netstack_find_by_stackid(ixm->ixm_stackid);
34211042SErik.Nordmark@Sun.COM 	if (ns == NULL) {
34311042SErik.Nordmark@Sun.COM 		/* Disappeared on us */
34411042SErik.Nordmark@Sun.COM 		(void) ip_xmit_attr_free_mblk(ixamp);
34511042SErik.Nordmark@Sun.COM 		return (B_FALSE);
34611042SErik.Nordmark@Sun.COM 	}
34711042SErik.Nordmark@Sun.COM 	ipst = ns->netstack_ip;
34811042SErik.Nordmark@Sun.COM 
34911042SErik.Nordmark@Sun.COM 	/* Verify the ill is still around */
35011042SErik.Nordmark@Sun.COM 	ill = ill_lookup_on_ifindex(ixm->ixm_ifindex,
35111042SErik.Nordmark@Sun.COM 	    !(ixm->ixm_flags & IXAF_IS_IPV4), ipst);
35211042SErik.Nordmark@Sun.COM 
35311042SErik.Nordmark@Sun.COM 	/* We have the ill, hence the netstack can't go away */
35411042SErik.Nordmark@Sun.COM 	netstack_rele(ns);
35511042SErik.Nordmark@Sun.COM 	if (ill == NULL) {
35611042SErik.Nordmark@Sun.COM 		/* Disappeared on us */
35711042SErik.Nordmark@Sun.COM 		(void) ip_xmit_attr_free_mblk(ixamp);
35811042SErik.Nordmark@Sun.COM 		return (B_FALSE);
35911042SErik.Nordmark@Sun.COM 	}
36011042SErik.Nordmark@Sun.COM 	/*
36111042SErik.Nordmark@Sun.COM 	 * Find the nce. We don't load-spread (only lookup nce's on the ill)
36211042SErik.Nordmark@Sun.COM 	 * because we want to find the same nce as the one we had when
36311042SErik.Nordmark@Sun.COM 	 * ip_xmit_attr_to_mblk was called.
36411042SErik.Nordmark@Sun.COM 	 */
36511042SErik.Nordmark@Sun.COM 	if (ixm->ixm_flags & IXAF_IS_IPV4) {
36611042SErik.Nordmark@Sun.COM 		nce = nce_lookup_v4(ill, &ixm->ixm_nceaddr_v4);
36711042SErik.Nordmark@Sun.COM 	} else {
36811042SErik.Nordmark@Sun.COM 		nce = nce_lookup_v6(ill, &ixm->ixm_nceaddr_v6);
36911042SErik.Nordmark@Sun.COM 	}
37011042SErik.Nordmark@Sun.COM 
37111042SErik.Nordmark@Sun.COM 	/* We have the nce, hence the ill can't go away */
37211042SErik.Nordmark@Sun.COM 	ill_refrele(ill);
37311042SErik.Nordmark@Sun.COM 	if (nce == NULL) {
37411042SErik.Nordmark@Sun.COM 		/*
37511042SErik.Nordmark@Sun.COM 		 * Since this is unusual and we don't know what type of
37611042SErik.Nordmark@Sun.COM 		 * nce it was, we drop the packet.
37711042SErik.Nordmark@Sun.COM 		 */
37811042SErik.Nordmark@Sun.COM 		(void) ip_xmit_attr_free_mblk(ixamp);
37911042SErik.Nordmark@Sun.COM 		return (B_FALSE);
38011042SErik.Nordmark@Sun.COM 	}
38111042SErik.Nordmark@Sun.COM 
38211042SErik.Nordmark@Sun.COM 	ixa->ixa_flags = ixm->ixm_flags;
38311042SErik.Nordmark@Sun.COM 	ixa->ixa_refcnt = 1;
38411042SErik.Nordmark@Sun.COM 	ixa->ixa_ipst = ipst;
38511042SErik.Nordmark@Sun.COM 	ixa->ixa_fragsize = ixm->ixm_fragsize;
38611042SErik.Nordmark@Sun.COM 	ixa->ixa_pktlen =  ixm->ixm_pktlen;
38711042SErik.Nordmark@Sun.COM 	ixa->ixa_ip_hdr_length = ixm->ixm_ip_hdr_length;
38811042SErik.Nordmark@Sun.COM 	ixa->ixa_protocol = ixm->ixm_protocol;
38911042SErik.Nordmark@Sun.COM 	ixa->ixa_nce = nce;
39011042SErik.Nordmark@Sun.COM 	ixa->ixa_postfragfn = ixm->ixm_postfragfn;
39111042SErik.Nordmark@Sun.COM 	ixa->ixa_zoneid = ixm->ixm_zoneid;
39211042SErik.Nordmark@Sun.COM 	ixa->ixa_no_loop_zoneid = ixm->ixm_no_loop_zoneid;
39311042SErik.Nordmark@Sun.COM 	ixa->ixa_scopeid = ixm->ixm_scopeid;
39411042SErik.Nordmark@Sun.COM 	ixa->ixa_ident = ixm->ixm_ident;
39511042SErik.Nordmark@Sun.COM 	ixa->ixa_xmit_hint = ixm->ixm_xmit_hint;
39611042SErik.Nordmark@Sun.COM 
39711042SErik.Nordmark@Sun.COM 	if (ixm->ixm_tsl != NULL) {
39811042SErik.Nordmark@Sun.COM 		ixa->ixa_tsl = ixm->ixm_tsl;
39911042SErik.Nordmark@Sun.COM 		ixa->ixa_free_flags |= IXA_FREE_TSL;
40011849SErik.Nordmark@Sun.COM 		ixm->ixm_tsl = NULL;
40111042SErik.Nordmark@Sun.COM 	}
40211042SErik.Nordmark@Sun.COM 	if (ixm->ixm_cred != NULL) {
40311042SErik.Nordmark@Sun.COM 		ixa->ixa_cred = ixm->ixm_cred;
40411042SErik.Nordmark@Sun.COM 		ixa->ixa_free_flags |= IXA_FREE_CRED;
40511849SErik.Nordmark@Sun.COM 		ixm->ixm_cred = NULL;
40611042SErik.Nordmark@Sun.COM 	}
40711042SErik.Nordmark@Sun.COM 	ixa->ixa_cpid = ixm->ixm_cpid;
40812507SAlan.Maguire@Sun.COM 	ixa->ixa_conn_id = ixm->ixm_conn_id;
40911042SErik.Nordmark@Sun.COM 
41011042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_ah_sa = ixm->ixm_ipsec_ah_sa;
41111042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_esp_sa = ixm->ixm_ipsec_esp_sa;
41211042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_policy = ixm->ixm_ipsec_policy;
41311042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_action = ixm->ixm_ipsec_action;
41411042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_latch = ixm->ixm_ipsec_latch;
41511042SErik.Nordmark@Sun.COM 
41611042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_ref[0] = ixm->ixm_ipsec_ref[0];
41711042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_ref[1] = ixm->ixm_ipsec_ref[1];
41811042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_src_port = ixm->ixm_ipsec_src_port;
41911042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_dst_port = ixm->ixm_ipsec_dst_port;
42011042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_icmp_type = ixm->ixm_ipsec_icmp_type;
42111042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_icmp_code = ixm->ixm_ipsec_icmp_code;
42211042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_inaf = ixm->ixm_ipsec_inaf;
42311042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_insrc[0] = ixm->ixm_ipsec_insrc[0];
42411042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_insrc[1] = ixm->ixm_ipsec_insrc[1];
42511042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_insrc[2] = ixm->ixm_ipsec_insrc[2];
42611042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_insrc[3] = ixm->ixm_ipsec_insrc[3];
42711042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_indst[0] = ixm->ixm_ipsec_indst[0];
42811042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_indst[1] = ixm->ixm_ipsec_indst[1];
42911042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_indst[2] = ixm->ixm_ipsec_indst[2];
43011042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_indst[3] = ixm->ixm_ipsec_indst[3];
43111042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_insrcpfx = ixm->ixm_ipsec_insrcpfx;
43211042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_indstpfx = ixm->ixm_ipsec_indstpfx;
43311042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_proto = ixm->ixm_ipsec_proto;
43411042SErik.Nordmark@Sun.COM 
43511042SErik.Nordmark@Sun.COM 	freeb(ixamp);
43611042SErik.Nordmark@Sun.COM 	return (B_TRUE);
43711042SErik.Nordmark@Sun.COM }
43811042SErik.Nordmark@Sun.COM 
43911042SErik.Nordmark@Sun.COM /*
44011042SErik.Nordmark@Sun.COM  * Free the ixm mblk and any references it holds
44111042SErik.Nordmark@Sun.COM  * Returns b_cont.
44211042SErik.Nordmark@Sun.COM  */
44311042SErik.Nordmark@Sun.COM mblk_t *
ip_xmit_attr_free_mblk(mblk_t * ixamp)44411042SErik.Nordmark@Sun.COM ip_xmit_attr_free_mblk(mblk_t *ixamp)
44511042SErik.Nordmark@Sun.COM {
44611042SErik.Nordmark@Sun.COM 	ixamblk_t	*ixm;
44711042SErik.Nordmark@Sun.COM 	mblk_t		*mp;
44811042SErik.Nordmark@Sun.COM 
44911042SErik.Nordmark@Sun.COM 	/* Consume mp */
45011042SErik.Nordmark@Sun.COM 	ASSERT(DB_TYPE(ixamp) == M_BREAK);
45111042SErik.Nordmark@Sun.COM 	mp = ixamp->b_cont;
45211042SErik.Nordmark@Sun.COM 
45311042SErik.Nordmark@Sun.COM 	ixm = (ixamblk_t *)ixamp->b_rptr;
45411042SErik.Nordmark@Sun.COM 	ASSERT(!ixm->ixm_inbound);
45511042SErik.Nordmark@Sun.COM 
45611042SErik.Nordmark@Sun.COM 	if (ixm->ixm_ipsec_ah_sa != NULL) {
45711042SErik.Nordmark@Sun.COM 		IPSA_REFRELE(ixm->ixm_ipsec_ah_sa);
45811042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_ah_sa = NULL;
45911042SErik.Nordmark@Sun.COM 	}
46011042SErik.Nordmark@Sun.COM 	if (ixm->ixm_ipsec_esp_sa != NULL) {
46111042SErik.Nordmark@Sun.COM 		IPSA_REFRELE(ixm->ixm_ipsec_esp_sa);
46211042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_esp_sa = NULL;
46311042SErik.Nordmark@Sun.COM 	}
46411042SErik.Nordmark@Sun.COM 	if (ixm->ixm_ipsec_policy != NULL) {
46511042SErik.Nordmark@Sun.COM 		IPPOL_REFRELE(ixm->ixm_ipsec_policy);
46611042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_policy = NULL;
46711042SErik.Nordmark@Sun.COM 	}
46811042SErik.Nordmark@Sun.COM 	if (ixm->ixm_ipsec_action != NULL) {
46911042SErik.Nordmark@Sun.COM 		IPACT_REFRELE(ixm->ixm_ipsec_action);
47011042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_action = NULL;
47111042SErik.Nordmark@Sun.COM 	}
47211042SErik.Nordmark@Sun.COM 	if (ixm->ixm_ipsec_latch) {
47311042SErik.Nordmark@Sun.COM 		IPLATCH_REFRELE(ixm->ixm_ipsec_latch);
47411042SErik.Nordmark@Sun.COM 		ixm->ixm_ipsec_latch = NULL;
47511042SErik.Nordmark@Sun.COM 	}
47611042SErik.Nordmark@Sun.COM 
47711042SErik.Nordmark@Sun.COM 	if (ixm->ixm_tsl != NULL) {
47811042SErik.Nordmark@Sun.COM 		label_rele(ixm->ixm_tsl);
47911042SErik.Nordmark@Sun.COM 		ixm->ixm_tsl = NULL;
48011042SErik.Nordmark@Sun.COM 	}
48111042SErik.Nordmark@Sun.COM 	if (ixm->ixm_cred != NULL) {
48211042SErik.Nordmark@Sun.COM 		crfree(ixm->ixm_cred);
48311042SErik.Nordmark@Sun.COM 		ixm->ixm_cred = NULL;
48411042SErik.Nordmark@Sun.COM 	}
48511042SErik.Nordmark@Sun.COM 	freeb(ixamp);
48611042SErik.Nordmark@Sun.COM 	return (mp);
48711042SErik.Nordmark@Sun.COM }
48811042SErik.Nordmark@Sun.COM 
48911042SErik.Nordmark@Sun.COM /*
49011042SErik.Nordmark@Sun.COM  * Take the information in ip_recv_attr_t and stick it in an mblk
49111042SErik.Nordmark@Sun.COM  * that can later be passed to ip_recv_attr_from_mblk to recreate the
49211042SErik.Nordmark@Sun.COM  * ip_recv_attr_t.
49311042SErik.Nordmark@Sun.COM  *
49411042SErik.Nordmark@Sun.COM  * Returns NULL on memory allocation failure.
49511042SErik.Nordmark@Sun.COM  */
49611042SErik.Nordmark@Sun.COM mblk_t *
ip_recv_attr_to_mblk(ip_recv_attr_t * ira)49711042SErik.Nordmark@Sun.COM ip_recv_attr_to_mblk(ip_recv_attr_t *ira)
49811042SErik.Nordmark@Sun.COM {
49911042SErik.Nordmark@Sun.COM 	mblk_t		*iramp;
50011042SErik.Nordmark@Sun.COM 	iramblk_t	*irm;
50111042SErik.Nordmark@Sun.COM 	ill_t		*ill = ira->ira_ill;
50211042SErik.Nordmark@Sun.COM 
50311042SErik.Nordmark@Sun.COM 	ASSERT(ira->ira_ill != NULL || ira->ira_ruifindex != 0);
50411042SErik.Nordmark@Sun.COM 
50511042SErik.Nordmark@Sun.COM 	iramp = allocb(sizeof (*irm), BPRI_MED);
50611042SErik.Nordmark@Sun.COM 	if (iramp == NULL)
50711042SErik.Nordmark@Sun.COM 		return (NULL);
50811042SErik.Nordmark@Sun.COM 
50911042SErik.Nordmark@Sun.COM 	iramp->b_datap->db_type = M_BREAK;
51011042SErik.Nordmark@Sun.COM 	iramp->b_wptr += sizeof (*irm);
51111042SErik.Nordmark@Sun.COM 	irm = (iramblk_t *)iramp->b_rptr;
51211042SErik.Nordmark@Sun.COM 
51311042SErik.Nordmark@Sun.COM 	bzero(irm, sizeof (*irm));
51411042SErik.Nordmark@Sun.COM 	irm->irm_inbound = B_TRUE;
51511042SErik.Nordmark@Sun.COM 	irm->irm_flags = ira->ira_flags;
51611042SErik.Nordmark@Sun.COM 	if (ill != NULL) {
51711042SErik.Nordmark@Sun.COM 		/* Internal to IP - preserve ip_stack_t, ill and rill */
51811042SErik.Nordmark@Sun.COM 		irm->irm_stackid =
51911042SErik.Nordmark@Sun.COM 		    ill->ill_ipst->ips_netstack->netstack_stackid;
52011042SErik.Nordmark@Sun.COM 		irm->irm_ifindex = ira->ira_ill->ill_phyint->phyint_ifindex;
52111042SErik.Nordmark@Sun.COM 		ASSERT(ira->ira_rill->ill_phyint->phyint_ifindex ==
52211042SErik.Nordmark@Sun.COM 		    ira->ira_rifindex);
52311042SErik.Nordmark@Sun.COM 	} else {
52411042SErik.Nordmark@Sun.COM 		/* Let ip_recv_attr_from_stackid know there isn't one */
52511042SErik.Nordmark@Sun.COM 		irm->irm_stackid = -1;
52611042SErik.Nordmark@Sun.COM 	}
52711042SErik.Nordmark@Sun.COM 	irm->irm_rifindex = ira->ira_rifindex;
52811042SErik.Nordmark@Sun.COM 	irm->irm_ruifindex = ira->ira_ruifindex;
52911042SErik.Nordmark@Sun.COM 	irm->irm_pktlen = ira->ira_pktlen;
53011042SErik.Nordmark@Sun.COM 	irm->irm_ip_hdr_length = ira->ira_ip_hdr_length;
53111042SErik.Nordmark@Sun.COM 	irm->irm_protocol = ira->ira_protocol;
53211042SErik.Nordmark@Sun.COM 
53311042SErik.Nordmark@Sun.COM 	irm->irm_sqp = ira->ira_sqp;
53411042SErik.Nordmark@Sun.COM 	irm->irm_ring = ira->ira_ring;
53511042SErik.Nordmark@Sun.COM 
53611042SErik.Nordmark@Sun.COM 	irm->irm_zoneid = ira->ira_zoneid;
53711042SErik.Nordmark@Sun.COM 	irm->irm_mroute_tunnel = ira->ira_mroute_tunnel;
53811042SErik.Nordmark@Sun.COM 	irm->irm_no_loop_zoneid = ira->ira_no_loop_zoneid;
53911042SErik.Nordmark@Sun.COM 	irm->irm_esp_udp_ports = ira->ira_esp_udp_ports;
54011042SErik.Nordmark@Sun.COM 
54111042SErik.Nordmark@Sun.COM 	if (ira->ira_tsl != NULL) {
54211042SErik.Nordmark@Sun.COM 		irm->irm_tsl = ira->ira_tsl;
54311042SErik.Nordmark@Sun.COM 		label_hold(irm->irm_tsl);
54411042SErik.Nordmark@Sun.COM 	}
54511042SErik.Nordmark@Sun.COM 	if (ira->ira_cred != NULL) {
54611042SErik.Nordmark@Sun.COM 		irm->irm_cred = ira->ira_cred;
54711042SErik.Nordmark@Sun.COM 		crhold(ira->ira_cred);
54811042SErik.Nordmark@Sun.COM 	}
54911042SErik.Nordmark@Sun.COM 	irm->irm_cpid = ira->ira_cpid;
55011042SErik.Nordmark@Sun.COM 
55111042SErik.Nordmark@Sun.COM 	if (ira->ira_flags & IRAF_L2SRC_SET)
55211042SErik.Nordmark@Sun.COM 		bcopy(ira->ira_l2src, irm->irm_l2src, IRA_L2SRC_SIZE);
55311042SErik.Nordmark@Sun.COM 
55411042SErik.Nordmark@Sun.COM 	if (ira->ira_flags & IRAF_IPSEC_SECURE) {
55511042SErik.Nordmark@Sun.COM 		if (ira->ira_ipsec_ah_sa != NULL) {
55611042SErik.Nordmark@Sun.COM 			irm->irm_ipsec_ah_sa = ira->ira_ipsec_ah_sa;
55711042SErik.Nordmark@Sun.COM 			IPSA_REFHOLD(ira->ira_ipsec_ah_sa);
55811042SErik.Nordmark@Sun.COM 		}
55911042SErik.Nordmark@Sun.COM 		if (ira->ira_ipsec_esp_sa != NULL) {
56011042SErik.Nordmark@Sun.COM 			irm->irm_ipsec_esp_sa = ira->ira_ipsec_esp_sa;
56111042SErik.Nordmark@Sun.COM 			IPSA_REFHOLD(ira->ira_ipsec_esp_sa);
56211042SErik.Nordmark@Sun.COM 		}
56311042SErik.Nordmark@Sun.COM 		if (ira->ira_ipsec_action != NULL) {
56411042SErik.Nordmark@Sun.COM 			irm->irm_ipsec_action = ira->ira_ipsec_action;
56511042SErik.Nordmark@Sun.COM 			IPACT_REFHOLD(ira->ira_ipsec_action);
56611042SErik.Nordmark@Sun.COM 		}
56711042SErik.Nordmark@Sun.COM 	}
56811042SErik.Nordmark@Sun.COM 	return (iramp);
56911042SErik.Nordmark@Sun.COM }
57011042SErik.Nordmark@Sun.COM 
57111042SErik.Nordmark@Sun.COM /*
57211042SErik.Nordmark@Sun.COM  * Extract the ip_recv_attr_t from the mblk. If we are used inside IP
57311042SErik.Nordmark@Sun.COM  * then irm_stackid is not -1, in which case we check that the
57411042SErik.Nordmark@Sun.COM  * ip_stack_t and ill_t still exist. Returns B_FALSE if that is
57511042SErik.Nordmark@Sun.COM  * not the case.
57611042SErik.Nordmark@Sun.COM  * If irm_stackid is zero then we are used by an ULP (e.g., squeue_enter)
57711042SErik.Nordmark@Sun.COM  * and we just proceed with ira_ill and ira_rill as NULL.
57811042SErik.Nordmark@Sun.COM  *
57911042SErik.Nordmark@Sun.COM  * The caller needs to release any references on the pointers inside the ire
58011042SErik.Nordmark@Sun.COM  * by calling ira_cleanup.
58111042SErik.Nordmark@Sun.COM  */
58211042SErik.Nordmark@Sun.COM boolean_t
ip_recv_attr_from_mblk(mblk_t * iramp,ip_recv_attr_t * ira)58311042SErik.Nordmark@Sun.COM ip_recv_attr_from_mblk(mblk_t *iramp, ip_recv_attr_t *ira)
58411042SErik.Nordmark@Sun.COM {
58511042SErik.Nordmark@Sun.COM 	iramblk_t	*irm;
58611042SErik.Nordmark@Sun.COM 	netstack_t	*ns;
58711042SErik.Nordmark@Sun.COM 	ip_stack_t	*ipst = NULL;
58811042SErik.Nordmark@Sun.COM 	ill_t		*ill = NULL, *rill = NULL;
58911042SErik.Nordmark@Sun.COM 
59011042SErik.Nordmark@Sun.COM 	/* We assume the caller hasn't initialized ira */
59111042SErik.Nordmark@Sun.COM 	bzero(ira, sizeof (*ira));
59211042SErik.Nordmark@Sun.COM 
59311042SErik.Nordmark@Sun.COM 	ASSERT(DB_TYPE(iramp) == M_BREAK);
59411042SErik.Nordmark@Sun.COM 	ASSERT(iramp->b_cont == NULL);
59511042SErik.Nordmark@Sun.COM 
59611042SErik.Nordmark@Sun.COM 	irm = (iramblk_t *)iramp->b_rptr;
59711042SErik.Nordmark@Sun.COM 	ASSERT(irm->irm_inbound);
59811042SErik.Nordmark@Sun.COM 
59911042SErik.Nordmark@Sun.COM 	if (irm->irm_stackid != -1) {
60011042SErik.Nordmark@Sun.COM 		/* Verify the netstack is still around */
60111042SErik.Nordmark@Sun.COM 		ns = netstack_find_by_stackid(irm->irm_stackid);
60211042SErik.Nordmark@Sun.COM 		if (ns == NULL) {
60311042SErik.Nordmark@Sun.COM 			/* Disappeared on us */
60411042SErik.Nordmark@Sun.COM 			(void) ip_recv_attr_free_mblk(iramp);
60511042SErik.Nordmark@Sun.COM 			return (B_FALSE);
60611042SErik.Nordmark@Sun.COM 		}
60711042SErik.Nordmark@Sun.COM 		ipst = ns->netstack_ip;
60811042SErik.Nordmark@Sun.COM 
60911042SErik.Nordmark@Sun.COM 		/* Verify the ill is still around */
61011042SErik.Nordmark@Sun.COM 		ill = ill_lookup_on_ifindex(irm->irm_ifindex,
61111042SErik.Nordmark@Sun.COM 		    !(irm->irm_flags & IRAF_IS_IPV4), ipst);
61211042SErik.Nordmark@Sun.COM 
61311042SErik.Nordmark@Sun.COM 		if (irm->irm_ifindex == irm->irm_rifindex) {
61411042SErik.Nordmark@Sun.COM 			rill = ill;
61511042SErik.Nordmark@Sun.COM 		} else {
61611042SErik.Nordmark@Sun.COM 			rill = ill_lookup_on_ifindex(irm->irm_rifindex,
61711042SErik.Nordmark@Sun.COM 			    !(irm->irm_flags & IRAF_IS_IPV4), ipst);
61811042SErik.Nordmark@Sun.COM 		}
61911042SErik.Nordmark@Sun.COM 
62011042SErik.Nordmark@Sun.COM 		/* We have the ill, hence the netstack can't go away */
62111042SErik.Nordmark@Sun.COM 		netstack_rele(ns);
62211042SErik.Nordmark@Sun.COM 		if (ill == NULL || rill == NULL) {
62311042SErik.Nordmark@Sun.COM 			/* Disappeared on us */
62411042SErik.Nordmark@Sun.COM 			if (ill != NULL)
62511042SErik.Nordmark@Sun.COM 				ill_refrele(ill);
62611042SErik.Nordmark@Sun.COM 			if (rill != NULL && rill != ill)
62711042SErik.Nordmark@Sun.COM 				ill_refrele(rill);
62811042SErik.Nordmark@Sun.COM 			(void) ip_recv_attr_free_mblk(iramp);
62911042SErik.Nordmark@Sun.COM 			return (B_FALSE);
63011042SErik.Nordmark@Sun.COM 		}
63111042SErik.Nordmark@Sun.COM 	}
63211042SErik.Nordmark@Sun.COM 
63311042SErik.Nordmark@Sun.COM 	ira->ira_flags = irm->irm_flags;
63411042SErik.Nordmark@Sun.COM 	/* Caller must ill_refele(ira_ill) by using ira_cleanup() */
63511042SErik.Nordmark@Sun.COM 	ira->ira_ill = ill;
63611042SErik.Nordmark@Sun.COM 	ira->ira_rill = rill;
63711042SErik.Nordmark@Sun.COM 
63811042SErik.Nordmark@Sun.COM 	ira->ira_rifindex = irm->irm_rifindex;
63911042SErik.Nordmark@Sun.COM 	ira->ira_ruifindex = irm->irm_ruifindex;
64011042SErik.Nordmark@Sun.COM 	ira->ira_pktlen = irm->irm_pktlen;
64111042SErik.Nordmark@Sun.COM 	ira->ira_ip_hdr_length = irm->irm_ip_hdr_length;
64211042SErik.Nordmark@Sun.COM 	ira->ira_protocol = irm->irm_protocol;
64311042SErik.Nordmark@Sun.COM 
64411042SErik.Nordmark@Sun.COM 	ira->ira_sqp = irm->irm_sqp;
64511042SErik.Nordmark@Sun.COM 	/* The rest of IP assumes that the rings never go away. */
64611042SErik.Nordmark@Sun.COM 	ira->ira_ring = irm->irm_ring;
64711042SErik.Nordmark@Sun.COM 
64811042SErik.Nordmark@Sun.COM 	ira->ira_zoneid = irm->irm_zoneid;
64911042SErik.Nordmark@Sun.COM 	ira->ira_mroute_tunnel = irm->irm_mroute_tunnel;
65011042SErik.Nordmark@Sun.COM 	ira->ira_no_loop_zoneid = irm->irm_no_loop_zoneid;
65111042SErik.Nordmark@Sun.COM 	ira->ira_esp_udp_ports = irm->irm_esp_udp_ports;
65211042SErik.Nordmark@Sun.COM 
65311042SErik.Nordmark@Sun.COM 	if (irm->irm_tsl != NULL) {
65411042SErik.Nordmark@Sun.COM 		ira->ira_tsl = irm->irm_tsl;
65511042SErik.Nordmark@Sun.COM 		ira->ira_free_flags |= IRA_FREE_TSL;
65611849SErik.Nordmark@Sun.COM 		irm->irm_tsl = NULL;
65711042SErik.Nordmark@Sun.COM 	}
65811042SErik.Nordmark@Sun.COM 	if (irm->irm_cred != NULL) {
65911042SErik.Nordmark@Sun.COM 		ira->ira_cred = irm->irm_cred;
66011042SErik.Nordmark@Sun.COM 		ira->ira_free_flags |= IRA_FREE_CRED;
66111849SErik.Nordmark@Sun.COM 		irm->irm_cred = NULL;
66211042SErik.Nordmark@Sun.COM 	}
66311042SErik.Nordmark@Sun.COM 	ira->ira_cpid = irm->irm_cpid;
66411042SErik.Nordmark@Sun.COM 
66511042SErik.Nordmark@Sun.COM 	if (ira->ira_flags & IRAF_L2SRC_SET)
66611042SErik.Nordmark@Sun.COM 		bcopy(irm->irm_l2src, ira->ira_l2src, IRA_L2SRC_SIZE);
66711042SErik.Nordmark@Sun.COM 
66811042SErik.Nordmark@Sun.COM 	ira->ira_ipsec_ah_sa = irm->irm_ipsec_ah_sa;
66911042SErik.Nordmark@Sun.COM 	ira->ira_ipsec_esp_sa = irm->irm_ipsec_esp_sa;
67011042SErik.Nordmark@Sun.COM 	ira->ira_ipsec_action = irm->irm_ipsec_action;
67111042SErik.Nordmark@Sun.COM 
67211042SErik.Nordmark@Sun.COM 	freeb(iramp);
67311042SErik.Nordmark@Sun.COM 	return (B_TRUE);
67411042SErik.Nordmark@Sun.COM }
67511042SErik.Nordmark@Sun.COM 
67611042SErik.Nordmark@Sun.COM /*
67711042SErik.Nordmark@Sun.COM  * Free the irm mblk and any references it holds
67811042SErik.Nordmark@Sun.COM  * Returns b_cont.
67911042SErik.Nordmark@Sun.COM  */
68011042SErik.Nordmark@Sun.COM mblk_t *
ip_recv_attr_free_mblk(mblk_t * iramp)68111042SErik.Nordmark@Sun.COM ip_recv_attr_free_mblk(mblk_t *iramp)
68211042SErik.Nordmark@Sun.COM {
68311042SErik.Nordmark@Sun.COM 	iramblk_t	*irm;
68411042SErik.Nordmark@Sun.COM 	mblk_t		*mp;
68511042SErik.Nordmark@Sun.COM 
68611042SErik.Nordmark@Sun.COM 	/* Consume mp */
68711042SErik.Nordmark@Sun.COM 	ASSERT(DB_TYPE(iramp) == M_BREAK);
68811042SErik.Nordmark@Sun.COM 	mp = iramp->b_cont;
68911042SErik.Nordmark@Sun.COM 
69011042SErik.Nordmark@Sun.COM 	irm = (iramblk_t *)iramp->b_rptr;
69111042SErik.Nordmark@Sun.COM 	ASSERT(irm->irm_inbound);
69211042SErik.Nordmark@Sun.COM 
69311042SErik.Nordmark@Sun.COM 	if (irm->irm_ipsec_ah_sa != NULL) {
69411042SErik.Nordmark@Sun.COM 		IPSA_REFRELE(irm->irm_ipsec_ah_sa);
69511042SErik.Nordmark@Sun.COM 		irm->irm_ipsec_ah_sa = NULL;
69611042SErik.Nordmark@Sun.COM 	}
69711042SErik.Nordmark@Sun.COM 	if (irm->irm_ipsec_esp_sa != NULL) {
69811042SErik.Nordmark@Sun.COM 		IPSA_REFRELE(irm->irm_ipsec_esp_sa);
69911042SErik.Nordmark@Sun.COM 		irm->irm_ipsec_esp_sa = NULL;
70011042SErik.Nordmark@Sun.COM 	}
70111042SErik.Nordmark@Sun.COM 	if (irm->irm_ipsec_action != NULL) {
70211042SErik.Nordmark@Sun.COM 		IPACT_REFRELE(irm->irm_ipsec_action);
70311042SErik.Nordmark@Sun.COM 		irm->irm_ipsec_action = NULL;
70411042SErik.Nordmark@Sun.COM 	}
70511042SErik.Nordmark@Sun.COM 	if (irm->irm_tsl != NULL) {
70611042SErik.Nordmark@Sun.COM 		label_rele(irm->irm_tsl);
70711042SErik.Nordmark@Sun.COM 		irm->irm_tsl = NULL;
70811042SErik.Nordmark@Sun.COM 	}
70911042SErik.Nordmark@Sun.COM 	if (irm->irm_cred != NULL) {
71011042SErik.Nordmark@Sun.COM 		crfree(irm->irm_cred);
71111042SErik.Nordmark@Sun.COM 		irm->irm_cred = NULL;
71211042SErik.Nordmark@Sun.COM 	}
71311042SErik.Nordmark@Sun.COM 
71411042SErik.Nordmark@Sun.COM 	freeb(iramp);
71511042SErik.Nordmark@Sun.COM 	return (mp);
71611042SErik.Nordmark@Sun.COM }
71711042SErik.Nordmark@Sun.COM 
71811042SErik.Nordmark@Sun.COM /*
71911042SErik.Nordmark@Sun.COM  * Returns true if the mblk contains an ip_recv_attr_t
72011042SErik.Nordmark@Sun.COM  * For now we just check db_type.
72111042SErik.Nordmark@Sun.COM  */
72211042SErik.Nordmark@Sun.COM boolean_t
ip_recv_attr_is_mblk(mblk_t * mp)72311042SErik.Nordmark@Sun.COM ip_recv_attr_is_mblk(mblk_t *mp)
72411042SErik.Nordmark@Sun.COM {
72511042SErik.Nordmark@Sun.COM 	/*
72611042SErik.Nordmark@Sun.COM 	 * Need to handle the various forms of tcp_timermp which are tagged
72711042SErik.Nordmark@Sun.COM 	 * with b_wptr and might have a NULL b_datap.
72811042SErik.Nordmark@Sun.COM 	 */
72911042SErik.Nordmark@Sun.COM 	if (mp->b_wptr == NULL || mp->b_wptr == (uchar_t *)-1)
73011042SErik.Nordmark@Sun.COM 		return (B_FALSE);
73111042SErik.Nordmark@Sun.COM 
73211042SErik.Nordmark@Sun.COM #ifdef	DEBUG
73311042SErik.Nordmark@Sun.COM 	iramblk_t	*irm;
73411042SErik.Nordmark@Sun.COM 
73511042SErik.Nordmark@Sun.COM 	if (DB_TYPE(mp) != M_BREAK)
73611042SErik.Nordmark@Sun.COM 		return (B_FALSE);
73711042SErik.Nordmark@Sun.COM 
73811042SErik.Nordmark@Sun.COM 	irm = (iramblk_t *)mp->b_rptr;
73911042SErik.Nordmark@Sun.COM 	ASSERT(irm->irm_inbound);
74011042SErik.Nordmark@Sun.COM 	return (B_TRUE);
74111042SErik.Nordmark@Sun.COM #else
74211042SErik.Nordmark@Sun.COM 	return (DB_TYPE(mp) == M_BREAK);
74311042SErik.Nordmark@Sun.COM #endif
74411042SErik.Nordmark@Sun.COM }
74511042SErik.Nordmark@Sun.COM 
74611042SErik.Nordmark@Sun.COM static ip_xmit_attr_t *
conn_get_ixa_impl(conn_t * connp,boolean_t replace,int kmflag)74711042SErik.Nordmark@Sun.COM conn_get_ixa_impl(conn_t *connp, boolean_t replace, int kmflag)
74811042SErik.Nordmark@Sun.COM {
74911042SErik.Nordmark@Sun.COM 	ip_xmit_attr_t	*ixa;
75011042SErik.Nordmark@Sun.COM 	ip_xmit_attr_t	*oldixa;
75111042SErik.Nordmark@Sun.COM 
75211042SErik.Nordmark@Sun.COM 	mutex_enter(&connp->conn_lock);
75311042SErik.Nordmark@Sun.COM 	ixa = connp->conn_ixa;
75411042SErik.Nordmark@Sun.COM 
75511042SErik.Nordmark@Sun.COM 	/* At least one references for the conn_t */
75611042SErik.Nordmark@Sun.COM 	ASSERT(ixa->ixa_refcnt >= 1);
75711042SErik.Nordmark@Sun.COM 	if (atomic_add_32_nv(&ixa->ixa_refcnt, 1) == 2) {
75811042SErik.Nordmark@Sun.COM 		/* No other thread using conn_ixa */
75911042SErik.Nordmark@Sun.COM 		mutex_exit(&connp->conn_lock);
76011042SErik.Nordmark@Sun.COM 		return (ixa);
76111042SErik.Nordmark@Sun.COM 	}
76211042SErik.Nordmark@Sun.COM 	ixa = kmem_alloc(sizeof (*ixa), kmflag);
76311042SErik.Nordmark@Sun.COM 	if (ixa == NULL) {
76411042SErik.Nordmark@Sun.COM 		mutex_exit(&connp->conn_lock);
76511042SErik.Nordmark@Sun.COM 		ixa_refrele(connp->conn_ixa);
76611042SErik.Nordmark@Sun.COM 		return (NULL);
76711042SErik.Nordmark@Sun.COM 	}
76811042SErik.Nordmark@Sun.COM 	ixa_safe_copy(connp->conn_ixa, ixa);
76911042SErik.Nordmark@Sun.COM 
77011042SErik.Nordmark@Sun.COM 	/* Make sure we drop conn_lock before any refrele */
77111042SErik.Nordmark@Sun.COM 	if (replace) {
77211042SErik.Nordmark@Sun.COM 		ixa->ixa_refcnt++;	/* No atomic needed - not visible */
77311042SErik.Nordmark@Sun.COM 		oldixa = connp->conn_ixa;
77411042SErik.Nordmark@Sun.COM 		connp->conn_ixa = ixa;
77511042SErik.Nordmark@Sun.COM 		mutex_exit(&connp->conn_lock);
77611042SErik.Nordmark@Sun.COM 		IXA_REFRELE(oldixa);	/* Undo refcnt from conn_t */
77711042SErik.Nordmark@Sun.COM 	} else {
77811042SErik.Nordmark@Sun.COM 		oldixa = connp->conn_ixa;
77911042SErik.Nordmark@Sun.COM 		mutex_exit(&connp->conn_lock);
78011042SErik.Nordmark@Sun.COM 	}
78111042SErik.Nordmark@Sun.COM 	IXA_REFRELE(oldixa);	/* Undo above atomic_add_32_nv */
78211042SErik.Nordmark@Sun.COM 
78311042SErik.Nordmark@Sun.COM 	return (ixa);
78411042SErik.Nordmark@Sun.COM }
78511042SErik.Nordmark@Sun.COM 
78611042SErik.Nordmark@Sun.COM /*
78711042SErik.Nordmark@Sun.COM  * Return an ip_xmit_attr_t to use with a conn_t that ensures that only
78811042SErik.Nordmark@Sun.COM  * the caller can access the ip_xmit_attr_t.
78911042SErik.Nordmark@Sun.COM  *
79011042SErik.Nordmark@Sun.COM  * If nobody else is using conn_ixa we return it.
79111042SErik.Nordmark@Sun.COM  * Otherwise we make a "safe" copy of conn_ixa
79211042SErik.Nordmark@Sun.COM  * and return it. The "safe" copy has the pointers set to NULL
79311042SErik.Nordmark@Sun.COM  * (since the pointers might be changed by another thread using
79411042SErik.Nordmark@Sun.COM  * conn_ixa). The caller needs to check for NULL pointers to see
79511042SErik.Nordmark@Sun.COM  * if ip_set_destination needs to be called to re-establish the pointers.
79611042SErik.Nordmark@Sun.COM  *
79711042SErik.Nordmark@Sun.COM  * If 'replace' is set then we replace conn_ixa with the new ip_xmit_attr_t.
79811042SErik.Nordmark@Sun.COM  * That is used when we connect() the ULP.
79911042SErik.Nordmark@Sun.COM  */
80011042SErik.Nordmark@Sun.COM ip_xmit_attr_t *
conn_get_ixa(conn_t * connp,boolean_t replace)80111042SErik.Nordmark@Sun.COM conn_get_ixa(conn_t *connp, boolean_t replace)
80211042SErik.Nordmark@Sun.COM {
80311042SErik.Nordmark@Sun.COM 	return (conn_get_ixa_impl(connp, replace, KM_NOSLEEP));
80411042SErik.Nordmark@Sun.COM }
80511042SErik.Nordmark@Sun.COM 
80611042SErik.Nordmark@Sun.COM /*
80711042SErik.Nordmark@Sun.COM  * Used only when the option is to have the kernel hang due to not
80811042SErik.Nordmark@Sun.COM  * cleaning up ixa references on ills etc.
80911042SErik.Nordmark@Sun.COM  */
81011042SErik.Nordmark@Sun.COM ip_xmit_attr_t *
conn_get_ixa_tryhard(conn_t * connp,boolean_t replace)81111042SErik.Nordmark@Sun.COM conn_get_ixa_tryhard(conn_t *connp, boolean_t replace)
81211042SErik.Nordmark@Sun.COM {
81311042SErik.Nordmark@Sun.COM 	return (conn_get_ixa_impl(connp, replace, KM_SLEEP));
81411042SErik.Nordmark@Sun.COM }
81511042SErik.Nordmark@Sun.COM 
81611042SErik.Nordmark@Sun.COM /*
81711042SErik.Nordmark@Sun.COM  * Replace conn_ixa with the ixa argument.
81811042SErik.Nordmark@Sun.COM  *
81911042SErik.Nordmark@Sun.COM  * The caller must hold conn_lock.
82011042SErik.Nordmark@Sun.COM  *
82111042SErik.Nordmark@Sun.COM  * We return the old ixa; the caller must ixa_refrele that after conn_lock
82211042SErik.Nordmark@Sun.COM  * has been dropped.
82311042SErik.Nordmark@Sun.COM  */
82411042SErik.Nordmark@Sun.COM ip_xmit_attr_t *
conn_replace_ixa(conn_t * connp,ip_xmit_attr_t * ixa)82511042SErik.Nordmark@Sun.COM conn_replace_ixa(conn_t *connp, ip_xmit_attr_t *ixa)
82611042SErik.Nordmark@Sun.COM {
82711042SErik.Nordmark@Sun.COM 	ip_xmit_attr_t	*oldixa;
82811042SErik.Nordmark@Sun.COM 
82911042SErik.Nordmark@Sun.COM 	ASSERT(MUTEX_HELD(&connp->conn_lock));
83011042SErik.Nordmark@Sun.COM 
83111042SErik.Nordmark@Sun.COM 	oldixa = connp->conn_ixa;
83211042SErik.Nordmark@Sun.COM 	IXA_REFHOLD(ixa);
83312507SAlan.Maguire@Sun.COM 	ixa->ixa_conn_id = oldixa->ixa_conn_id;
83411042SErik.Nordmark@Sun.COM 	connp->conn_ixa = ixa;
83511042SErik.Nordmark@Sun.COM 	return (oldixa);
83611042SErik.Nordmark@Sun.COM }
83711042SErik.Nordmark@Sun.COM 
83811042SErik.Nordmark@Sun.COM /*
83911042SErik.Nordmark@Sun.COM  * Return a ip_xmit_attr_t to use with a conn_t that is based on but
84011042SErik.Nordmark@Sun.COM  * separate from conn_ixa.
84111042SErik.Nordmark@Sun.COM  *
84211042SErik.Nordmark@Sun.COM  * This "safe" copy has the pointers set to NULL
84311042SErik.Nordmark@Sun.COM  * (since the pointers might be changed by another thread using
84411042SErik.Nordmark@Sun.COM  * conn_ixa). The caller needs to check for NULL pointers to see
84511042SErik.Nordmark@Sun.COM  * if ip_set_destination needs to be called to re-establish the pointers.
84611042SErik.Nordmark@Sun.COM  */
84711042SErik.Nordmark@Sun.COM ip_xmit_attr_t *
conn_get_ixa_exclusive(conn_t * connp)84811042SErik.Nordmark@Sun.COM conn_get_ixa_exclusive(conn_t *connp)
84911042SErik.Nordmark@Sun.COM {
85011042SErik.Nordmark@Sun.COM 	ip_xmit_attr_t *ixa;
85111042SErik.Nordmark@Sun.COM 
85211042SErik.Nordmark@Sun.COM 	mutex_enter(&connp->conn_lock);
85311042SErik.Nordmark@Sun.COM 	ixa = connp->conn_ixa;
85411042SErik.Nordmark@Sun.COM 
85511042SErik.Nordmark@Sun.COM 	/* At least one references for the conn_t */
85611042SErik.Nordmark@Sun.COM 	ASSERT(ixa->ixa_refcnt >= 1);
85711042SErik.Nordmark@Sun.COM 
85811042SErik.Nordmark@Sun.COM 	/* Make sure conn_ixa doesn't disappear while we copy it */
85911042SErik.Nordmark@Sun.COM 	atomic_add_32(&ixa->ixa_refcnt, 1);
86011042SErik.Nordmark@Sun.COM 
86111042SErik.Nordmark@Sun.COM 	ixa = kmem_alloc(sizeof (*ixa), KM_NOSLEEP);
86211042SErik.Nordmark@Sun.COM 	if (ixa == NULL) {
86311042SErik.Nordmark@Sun.COM 		mutex_exit(&connp->conn_lock);
86411042SErik.Nordmark@Sun.COM 		ixa_refrele(connp->conn_ixa);
86511042SErik.Nordmark@Sun.COM 		return (NULL);
86611042SErik.Nordmark@Sun.COM 	}
86711042SErik.Nordmark@Sun.COM 	ixa_safe_copy(connp->conn_ixa, ixa);
86811042SErik.Nordmark@Sun.COM 	mutex_exit(&connp->conn_lock);
86911042SErik.Nordmark@Sun.COM 	IXA_REFRELE(connp->conn_ixa);
87011042SErik.Nordmark@Sun.COM 	return (ixa);
87111042SErik.Nordmark@Sun.COM }
87211042SErik.Nordmark@Sun.COM 
87311042SErik.Nordmark@Sun.COM void
ixa_safe_copy(ip_xmit_attr_t * src,ip_xmit_attr_t * ixa)87411042SErik.Nordmark@Sun.COM ixa_safe_copy(ip_xmit_attr_t *src, ip_xmit_attr_t *ixa)
87511042SErik.Nordmark@Sun.COM {
87611042SErik.Nordmark@Sun.COM 	bcopy(src, ixa, sizeof (*ixa));
87711042SErik.Nordmark@Sun.COM 	ixa->ixa_refcnt = 1;
87811042SErik.Nordmark@Sun.COM 	/*
87911042SErik.Nordmark@Sun.COM 	 * Clear any pointers that have references and might be changed
88011042SErik.Nordmark@Sun.COM 	 * by ip_set_destination or the ULP
88111042SErik.Nordmark@Sun.COM 	 */
88211042SErik.Nordmark@Sun.COM 	ixa->ixa_ire = NULL;
88311042SErik.Nordmark@Sun.COM 	ixa->ixa_nce = NULL;
88411042SErik.Nordmark@Sun.COM 	ixa->ixa_dce = NULL;
88511042SErik.Nordmark@Sun.COM 	ixa->ixa_ire_generation = IRE_GENERATION_VERIFY;
88611042SErik.Nordmark@Sun.COM 	ixa->ixa_dce_generation = DCE_GENERATION_VERIFY;
88711042SErik.Nordmark@Sun.COM #ifdef DEBUG
88811042SErik.Nordmark@Sun.COM 	ixa->ixa_curthread = NULL;
88911042SErik.Nordmark@Sun.COM #endif
89011042SErik.Nordmark@Sun.COM 	/* Clear all the IPsec pointers and the flag as well. */
89111042SErik.Nordmark@Sun.COM 	ixa->ixa_flags &= ~IXAF_IPSEC_SECURE;
89211042SErik.Nordmark@Sun.COM 
89311042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_latch = NULL;
89411042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_ah_sa = NULL;
89511042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_esp_sa = NULL;
89611042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_policy = NULL;
89711042SErik.Nordmark@Sun.COM 	ixa->ixa_ipsec_action = NULL;
89811042SErik.Nordmark@Sun.COM 
89911042SErik.Nordmark@Sun.COM 	/*
90011042SErik.Nordmark@Sun.COM 	 * We leave ixa_tsl unchanged, but if it has a refhold we need
90111042SErik.Nordmark@Sun.COM 	 * to get an extra refhold.
90211042SErik.Nordmark@Sun.COM 	 */
90311042SErik.Nordmark@Sun.COM 	if (ixa->ixa_free_flags & IXA_FREE_TSL)
90411042SErik.Nordmark@Sun.COM 		label_hold(ixa->ixa_tsl);
90511042SErik.Nordmark@Sun.COM 
90611042SErik.Nordmark@Sun.COM 	/*
90711042SErik.Nordmark@Sun.COM 	 * We leave ixa_cred unchanged, but if it has a refhold we need
90811042SErik.Nordmark@Sun.COM 	 * to get an extra refhold.
90911042SErik.Nordmark@Sun.COM 	 */
91011042SErik.Nordmark@Sun.COM 	if (ixa->ixa_free_flags & IXA_FREE_CRED)
91111042SErik.Nordmark@Sun.COM 		crhold(ixa->ixa_cred);
91211042SErik.Nordmark@Sun.COM }
91311042SErik.Nordmark@Sun.COM 
91411042SErik.Nordmark@Sun.COM /*
91511042SErik.Nordmark@Sun.COM  * Duplicate an ip_xmit_attr_t.
91611042SErik.Nordmark@Sun.COM  * Assumes that the caller controls the ixa, hence we do not need to use
91711042SErik.Nordmark@Sun.COM  * a safe copy. We just have to increase the refcnt on any pointers.
91811042SErik.Nordmark@Sun.COM  */
91911042SErik.Nordmark@Sun.COM ip_xmit_attr_t *
ip_xmit_attr_duplicate(ip_xmit_attr_t * src_ixa)92011042SErik.Nordmark@Sun.COM ip_xmit_attr_duplicate(ip_xmit_attr_t *src_ixa)
92111042SErik.Nordmark@Sun.COM {
92211042SErik.Nordmark@Sun.COM 	ip_xmit_attr_t *ixa;
92311042SErik.Nordmark@Sun.COM 
92411042SErik.Nordmark@Sun.COM 	ixa = kmem_alloc(sizeof (*ixa), KM_NOSLEEP);
92511042SErik.Nordmark@Sun.COM 	if (ixa == NULL)
92611042SErik.Nordmark@Sun.COM 		return (NULL);
92711042SErik.Nordmark@Sun.COM 	bcopy(src_ixa, ixa, sizeof (*ixa));
92811042SErik.Nordmark@Sun.COM 	ixa->ixa_refcnt = 1;
92911042SErik.Nordmark@Sun.COM 
93011042SErik.Nordmark@Sun.COM 	if (ixa->ixa_ire != NULL)
93111042SErik.Nordmark@Sun.COM 		ire_refhold_notr(ixa->ixa_ire);
93211042SErik.Nordmark@Sun.COM 	if (ixa->ixa_nce != NULL)
93311042SErik.Nordmark@Sun.COM 		nce_refhold(ixa->ixa_nce);
93411042SErik.Nordmark@Sun.COM 	if (ixa->ixa_dce != NULL)
93511042SErik.Nordmark@Sun.COM 		dce_refhold_notr(ixa->ixa_dce);
93611042SErik.Nordmark@Sun.COM 
93711042SErik.Nordmark@Sun.COM #ifdef DEBUG
93811042SErik.Nordmark@Sun.COM 	ixa->ixa_curthread = NULL;
93911042SErik.Nordmark@Sun.COM #endif
94011042SErik.Nordmark@Sun.COM 
94111042SErik.Nordmark@Sun.COM 	if (ixa->ixa_ipsec_latch != NULL)
94211042SErik.Nordmark@Sun.COM 		IPLATCH_REFHOLD(ixa->ixa_ipsec_latch);
94311042SErik.Nordmark@Sun.COM 	if (ixa->ixa_ipsec_ah_sa != NULL)
94411042SErik.Nordmark@Sun.COM 		IPSA_REFHOLD(ixa->ixa_ipsec_ah_sa);
94511042SErik.Nordmark@Sun.COM 	if (ixa->ixa_ipsec_esp_sa != NULL)
94611042SErik.Nordmark@Sun.COM 		IPSA_REFHOLD(ixa->ixa_ipsec_esp_sa);
94711042SErik.Nordmark@Sun.COM 	if (ixa->ixa_ipsec_policy != NULL)
94811042SErik.Nordmark@Sun.COM 		IPPOL_REFHOLD(ixa->ixa_ipsec_policy);
94911042SErik.Nordmark@Sun.COM 	if (ixa->ixa_ipsec_action != NULL)
95011042SErik.Nordmark@Sun.COM 		IPACT_REFHOLD(ixa->ixa_ipsec_action);
95111042SErik.Nordmark@Sun.COM 
95211042SErik.Nordmark@Sun.COM 	if (ixa->ixa_tsl != NULL) {
95311042SErik.Nordmark@Sun.COM 		label_hold(ixa->ixa_tsl);
95411042SErik.Nordmark@Sun.COM 		ixa->ixa_free_flags |= IXA_FREE_TSL;
95511042SErik.Nordmark@Sun.COM 	}
95611042SErik.Nordmark@Sun.COM 	if (ixa->ixa_cred != NULL) {
95711042SErik.Nordmark@Sun.COM 		crhold(ixa->ixa_cred);
95811042SErik.Nordmark@Sun.COM 		ixa->ixa_free_flags |= IXA_FREE_CRED;
95911042SErik.Nordmark@Sun.COM 	}
96011042SErik.Nordmark@Sun.COM 	return (ixa);
96111042SErik.Nordmark@Sun.COM }
96211042SErik.Nordmark@Sun.COM 
96311042SErik.Nordmark@Sun.COM /*
96411042SErik.Nordmark@Sun.COM  * Used to replace the ixa_label field.
96511042SErik.Nordmark@Sun.COM  * The caller should have a reference on the label, which we transfer to
96611042SErik.Nordmark@Sun.COM  * the attributes so that when the attribute is freed/cleaned up
96711042SErik.Nordmark@Sun.COM  * we will release that reference.
96811042SErik.Nordmark@Sun.COM  */
96911042SErik.Nordmark@Sun.COM void
ip_xmit_attr_replace_tsl(ip_xmit_attr_t * ixa,ts_label_t * tsl)97011042SErik.Nordmark@Sun.COM ip_xmit_attr_replace_tsl(ip_xmit_attr_t *ixa, ts_label_t *tsl)
97111042SErik.Nordmark@Sun.COM {
97211042SErik.Nordmark@Sun.COM 	ASSERT(tsl != NULL);
97311042SErik.Nordmark@Sun.COM 
97411042SErik.Nordmark@Sun.COM 	if (ixa->ixa_free_flags & IXA_FREE_TSL) {
97511042SErik.Nordmark@Sun.COM 		ASSERT(ixa->ixa_tsl != NULL);
97611042SErik.Nordmark@Sun.COM 		label_rele(ixa->ixa_tsl);
97711042SErik.Nordmark@Sun.COM 	} else {
97811042SErik.Nordmark@Sun.COM 		ixa->ixa_free_flags |= IXA_FREE_TSL;
97911042SErik.Nordmark@Sun.COM 	}
98011042SErik.Nordmark@Sun.COM 	ixa->ixa_tsl = tsl;
98111042SErik.Nordmark@Sun.COM }
98211042SErik.Nordmark@Sun.COM 
98311042SErik.Nordmark@Sun.COM /*
98411042SErik.Nordmark@Sun.COM  * Replace the ip_recv_attr_t's label.
98511042SErik.Nordmark@Sun.COM  * Due to kernel RPC's use of db_credp we also need to replace ira_cred;
98611042SErik.Nordmark@Sun.COM  * TCP/UDP uses ira_cred to set db_credp for non-socket users.
98711042SErik.Nordmark@Sun.COM  * This can fail (and return B_FALSE) due to lack of memory.
98811042SErik.Nordmark@Sun.COM  */
98911042SErik.Nordmark@Sun.COM boolean_t
ip_recv_attr_replace_label(ip_recv_attr_t * ira,ts_label_t * tsl)99011042SErik.Nordmark@Sun.COM ip_recv_attr_replace_label(ip_recv_attr_t *ira, ts_label_t *tsl)
99111042SErik.Nordmark@Sun.COM {
99211042SErik.Nordmark@Sun.COM 	cred_t	*newcr;
99311042SErik.Nordmark@Sun.COM 
99411042SErik.Nordmark@Sun.COM 	if (ira->ira_free_flags & IRA_FREE_TSL) {
99511042SErik.Nordmark@Sun.COM 		ASSERT(ira->ira_tsl != NULL);
99611042SErik.Nordmark@Sun.COM 		label_rele(ira->ira_tsl);
99711042SErik.Nordmark@Sun.COM 	}
99811042SErik.Nordmark@Sun.COM 	label_hold(tsl);
99911042SErik.Nordmark@Sun.COM 	ira->ira_tsl = tsl;
100011042SErik.Nordmark@Sun.COM 	ira->ira_free_flags |= IRA_FREE_TSL;
100111042SErik.Nordmark@Sun.COM 
100211042SErik.Nordmark@Sun.COM 	/*
100311042SErik.Nordmark@Sun.COM 	 * Reset zoneid if we have a shared address. That allows
100411042SErik.Nordmark@Sun.COM 	 * ip_fanout_tx_v4/v6 to determine the zoneid again.
100511042SErik.Nordmark@Sun.COM 	 */
100611042SErik.Nordmark@Sun.COM 	if (ira->ira_flags & IRAF_TX_SHARED_ADDR)
100711042SErik.Nordmark@Sun.COM 		ira->ira_zoneid = ALL_ZONES;
100811042SErik.Nordmark@Sun.COM 
100911042SErik.Nordmark@Sun.COM 	/* We update ira_cred for RPC */
101011042SErik.Nordmark@Sun.COM 	newcr = copycred_from_tslabel(ira->ira_cred, ira->ira_tsl, KM_NOSLEEP);
101111042SErik.Nordmark@Sun.COM 	if (newcr == NULL)
101211042SErik.Nordmark@Sun.COM 		return (B_FALSE);
101311042SErik.Nordmark@Sun.COM 	if (ira->ira_free_flags & IRA_FREE_CRED)
101411042SErik.Nordmark@Sun.COM 		crfree(ira->ira_cred);
101511042SErik.Nordmark@Sun.COM 	ira->ira_cred = newcr;
101611042SErik.Nordmark@Sun.COM 	ira->ira_free_flags |= IRA_FREE_CRED;
101711042SErik.Nordmark@Sun.COM 	return (B_TRUE);
101811042SErik.Nordmark@Sun.COM }
101911042SErik.Nordmark@Sun.COM 
102011042SErik.Nordmark@Sun.COM /*
102111042SErik.Nordmark@Sun.COM  * This needs to be called after ip_set_destination/tsol_check_dest might
102211042SErik.Nordmark@Sun.COM  * have changed ixa_tsl to be specific for a destination, and we now want to
102311042SErik.Nordmark@Sun.COM  * send to a different destination.
102411042SErik.Nordmark@Sun.COM  * We have to restart with crgetlabel() since ip_set_destination/
102511042SErik.Nordmark@Sun.COM  * tsol_check_dest will start with ixa_tsl.
102611042SErik.Nordmark@Sun.COM  */
102711042SErik.Nordmark@Sun.COM void
ip_xmit_attr_restore_tsl(ip_xmit_attr_t * ixa,cred_t * cr)102811042SErik.Nordmark@Sun.COM ip_xmit_attr_restore_tsl(ip_xmit_attr_t *ixa, cred_t *cr)
102911042SErik.Nordmark@Sun.COM {
103011042SErik.Nordmark@Sun.COM 	if (!is_system_labeled())
103111042SErik.Nordmark@Sun.COM 		return;
103211042SErik.Nordmark@Sun.COM 
103311042SErik.Nordmark@Sun.COM 	if (ixa->ixa_free_flags & IXA_FREE_TSL) {
103411042SErik.Nordmark@Sun.COM 		ASSERT(ixa->ixa_tsl != NULL);
103511042SErik.Nordmark@Sun.COM 		label_rele(ixa->ixa_tsl);
103611042SErik.Nordmark@Sun.COM 		ixa->ixa_free_flags &= ~IXA_FREE_TSL;
103711042SErik.Nordmark@Sun.COM 	}
103811042SErik.Nordmark@Sun.COM 	ixa->ixa_tsl = crgetlabel(cr);
103911042SErik.Nordmark@Sun.COM }
104011042SErik.Nordmark@Sun.COM 
104111042SErik.Nordmark@Sun.COM void
ixa_refrele(ip_xmit_attr_t * ixa)104211042SErik.Nordmark@Sun.COM ixa_refrele(ip_xmit_attr_t *ixa)
104311042SErik.Nordmark@Sun.COM {
104411042SErik.Nordmark@Sun.COM 	IXA_REFRELE(ixa);
104511042SErik.Nordmark@Sun.COM }
104611042SErik.Nordmark@Sun.COM 
104711042SErik.Nordmark@Sun.COM void
ixa_inactive(ip_xmit_attr_t * ixa)104811042SErik.Nordmark@Sun.COM ixa_inactive(ip_xmit_attr_t *ixa)
104911042SErik.Nordmark@Sun.COM {
105011042SErik.Nordmark@Sun.COM 	ASSERT(ixa->ixa_refcnt == 0);
105111042SErik.Nordmark@Sun.COM 
105211042SErik.Nordmark@Sun.COM 	ixa_cleanup(ixa);
105311042SErik.Nordmark@Sun.COM 	kmem_free(ixa, sizeof (*ixa));
105411042SErik.Nordmark@Sun.COM }
105511042SErik.Nordmark@Sun.COM 
105611042SErik.Nordmark@Sun.COM /*
105711042SErik.Nordmark@Sun.COM  * Release any references contained in the ixa.
105811042SErik.Nordmark@Sun.COM  * Also clear any fields that are not controlled by ixa_flags.
105911042SErik.Nordmark@Sun.COM  */
106011042SErik.Nordmark@Sun.COM void
ixa_cleanup(ip_xmit_attr_t * ixa)106111042SErik.Nordmark@Sun.COM ixa_cleanup(ip_xmit_attr_t *ixa)
106211042SErik.Nordmark@Sun.COM {
106311042SErik.Nordmark@Sun.COM 	if (ixa->ixa_ire != NULL) {
106411042SErik.Nordmark@Sun.COM 		ire_refrele_notr(ixa->ixa_ire);
106511042SErik.Nordmark@Sun.COM 		ixa->ixa_ire = NULL;
106611042SErik.Nordmark@Sun.COM 	}
106711042SErik.Nordmark@Sun.COM 	if (ixa->ixa_dce != NULL) {
106811042SErik.Nordmark@Sun.COM 		dce_refrele_notr(ixa->ixa_dce);
106911042SErik.Nordmark@Sun.COM 		ixa->ixa_dce = NULL;
107011042SErik.Nordmark@Sun.COM 	}
107111042SErik.Nordmark@Sun.COM 	if (ixa->ixa_nce != NULL) {
107211042SErik.Nordmark@Sun.COM 		nce_refrele(ixa->ixa_nce);
107311042SErik.Nordmark@Sun.COM 		ixa->ixa_nce = NULL;
107411042SErik.Nordmark@Sun.COM 	}
107511042SErik.Nordmark@Sun.COM 	ixa->ixa_ire_generation = IRE_GENERATION_VERIFY;
107611042SErik.Nordmark@Sun.COM 	ixa->ixa_dce_generation = DCE_GENERATION_VERIFY;
107711042SErik.Nordmark@Sun.COM 	if (ixa->ixa_flags & IXAF_IPSEC_SECURE) {
107811042SErik.Nordmark@Sun.COM 		ipsec_out_release_refs(ixa);
107911042SErik.Nordmark@Sun.COM 	}
108011042SErik.Nordmark@Sun.COM 	if (ixa->ixa_free_flags & IXA_FREE_TSL) {
108111042SErik.Nordmark@Sun.COM 		ASSERT(ixa->ixa_tsl != NULL);
108211042SErik.Nordmark@Sun.COM 		label_rele(ixa->ixa_tsl);
108311042SErik.Nordmark@Sun.COM 		ixa->ixa_free_flags &= ~IXA_FREE_TSL;
108411042SErik.Nordmark@Sun.COM 	}
108511680SErik.Nordmark@Sun.COM 	ixa->ixa_tsl = NULL;
108611042SErik.Nordmark@Sun.COM 	if (ixa->ixa_free_flags & IXA_FREE_CRED) {
108711042SErik.Nordmark@Sun.COM 		ASSERT(ixa->ixa_cred != NULL);
108811042SErik.Nordmark@Sun.COM 		crfree(ixa->ixa_cred);
108911042SErik.Nordmark@Sun.COM 		ixa->ixa_free_flags &= ~IXA_FREE_CRED;
109011042SErik.Nordmark@Sun.COM 	}
109111680SErik.Nordmark@Sun.COM 	ixa->ixa_cred = NULL;
109211042SErik.Nordmark@Sun.COM 	ixa->ixa_src_preferences = 0;
109311042SErik.Nordmark@Sun.COM 	ixa->ixa_ifindex = 0;
109411042SErik.Nordmark@Sun.COM 	ixa->ixa_multicast_ifindex = 0;
109511042SErik.Nordmark@Sun.COM 	ixa->ixa_multicast_ifaddr = INADDR_ANY;
109611042SErik.Nordmark@Sun.COM }
109711042SErik.Nordmark@Sun.COM 
109811042SErik.Nordmark@Sun.COM /*
109911042SErik.Nordmark@Sun.COM  * Release any references contained in the ira.
110011042SErik.Nordmark@Sun.COM  * Callers which use ip_recv_attr_from_mblk() would pass B_TRUE as the second
110111042SErik.Nordmark@Sun.COM  * argument.
110211042SErik.Nordmark@Sun.COM  */
110311042SErik.Nordmark@Sun.COM void
ira_cleanup(ip_recv_attr_t * ira,boolean_t refrele_ill)110411042SErik.Nordmark@Sun.COM ira_cleanup(ip_recv_attr_t *ira, boolean_t refrele_ill)
110511042SErik.Nordmark@Sun.COM {
110611042SErik.Nordmark@Sun.COM 	if (ira->ira_ill != NULL) {
110711042SErik.Nordmark@Sun.COM 		if (ira->ira_rill != ira->ira_ill) {
110811042SErik.Nordmark@Sun.COM 			/* Caused by async processing */
110911042SErik.Nordmark@Sun.COM 			ill_refrele(ira->ira_rill);
111011042SErik.Nordmark@Sun.COM 		}
111111042SErik.Nordmark@Sun.COM 		if (refrele_ill)
111211042SErik.Nordmark@Sun.COM 			ill_refrele(ira->ira_ill);
111311042SErik.Nordmark@Sun.COM 	}
111411042SErik.Nordmark@Sun.COM 	if (ira->ira_flags & IRAF_IPSEC_SECURE) {
111511042SErik.Nordmark@Sun.COM 		ipsec_in_release_refs(ira);
111611042SErik.Nordmark@Sun.COM 	}
111711042SErik.Nordmark@Sun.COM 	if (ira->ira_free_flags & IRA_FREE_TSL) {
111811042SErik.Nordmark@Sun.COM 		ASSERT(ira->ira_tsl != NULL);
111911042SErik.Nordmark@Sun.COM 		label_rele(ira->ira_tsl);
112011042SErik.Nordmark@Sun.COM 		ira->ira_free_flags &= ~IRA_FREE_TSL;
112111042SErik.Nordmark@Sun.COM 	}
112211849SErik.Nordmark@Sun.COM 	ira->ira_tsl = NULL;
112311042SErik.Nordmark@Sun.COM 	if (ira->ira_free_flags & IRA_FREE_CRED) {
112411042SErik.Nordmark@Sun.COM 		ASSERT(ira->ira_cred != NULL);
112511042SErik.Nordmark@Sun.COM 		crfree(ira->ira_cred);
112611042SErik.Nordmark@Sun.COM 		ira->ira_free_flags &= ~IRA_FREE_CRED;
112711042SErik.Nordmark@Sun.COM 	}
112811849SErik.Nordmark@Sun.COM 	ira->ira_cred = NULL;
112911042SErik.Nordmark@Sun.COM }
113011042SErik.Nordmark@Sun.COM 
113111042SErik.Nordmark@Sun.COM /*
113211042SErik.Nordmark@Sun.COM  * Function to help release any IRE, NCE, or DCEs that
113311042SErik.Nordmark@Sun.COM  * have been deleted and are marked as condemned.
113411042SErik.Nordmark@Sun.COM  * The caller is responsible for any serialization which is different
113511042SErik.Nordmark@Sun.COM  * for TCP, SCTP, and others.
113611042SErik.Nordmark@Sun.COM  */
113711042SErik.Nordmark@Sun.COM static void
ixa_cleanup_stale(ip_xmit_attr_t * ixa)113811042SErik.Nordmark@Sun.COM ixa_cleanup_stale(ip_xmit_attr_t *ixa)
113911042SErik.Nordmark@Sun.COM {
114011042SErik.Nordmark@Sun.COM 	ire_t		*ire;
114111042SErik.Nordmark@Sun.COM 	nce_t		*nce;
114211042SErik.Nordmark@Sun.COM 	dce_t		*dce;
114311042SErik.Nordmark@Sun.COM 
114411042SErik.Nordmark@Sun.COM 	ire = ixa->ixa_ire;
114511042SErik.Nordmark@Sun.COM 	nce = ixa->ixa_nce;
114611042SErik.Nordmark@Sun.COM 	dce = ixa->ixa_dce;
114711042SErik.Nordmark@Sun.COM 
114811042SErik.Nordmark@Sun.COM 	if (ire != NULL && IRE_IS_CONDEMNED(ire)) {
114911042SErik.Nordmark@Sun.COM 		ire_refrele_notr(ire);
115011042SErik.Nordmark@Sun.COM 		ire = ire_blackhole(ixa->ixa_ipst,
115111042SErik.Nordmark@Sun.COM 		    !(ixa->ixa_flags & IXAF_IS_IPV4));
115211042SErik.Nordmark@Sun.COM 		ASSERT(ire != NULL);
115311042SErik.Nordmark@Sun.COM #ifdef DEBUG
115411042SErik.Nordmark@Sun.COM 		ire_refhold_notr(ire);
115511042SErik.Nordmark@Sun.COM 		ire_refrele(ire);
115611042SErik.Nordmark@Sun.COM #endif
115711042SErik.Nordmark@Sun.COM 		ixa->ixa_ire = ire;
115811042SErik.Nordmark@Sun.COM 		ixa->ixa_ire_generation = IRE_GENERATION_VERIFY;
115911042SErik.Nordmark@Sun.COM 	}
116011042SErik.Nordmark@Sun.COM 	if (nce != NULL && nce->nce_is_condemned) {
116111042SErik.Nordmark@Sun.COM 		/* Can make it NULL as long as we set IRE_GENERATION_VERIFY */
116211042SErik.Nordmark@Sun.COM 		nce_refrele(nce);
116311042SErik.Nordmark@Sun.COM 		ixa->ixa_nce = NULL;
116411042SErik.Nordmark@Sun.COM 		ixa->ixa_ire_generation = IRE_GENERATION_VERIFY;
116511042SErik.Nordmark@Sun.COM 	}
116611042SErik.Nordmark@Sun.COM 	if (dce != NULL && DCE_IS_CONDEMNED(dce)) {
116711042SErik.Nordmark@Sun.COM 		dce_refrele_notr(dce);
116811042SErik.Nordmark@Sun.COM 		dce = dce_get_default(ixa->ixa_ipst);
116911042SErik.Nordmark@Sun.COM 		ASSERT(dce != NULL);
117011042SErik.Nordmark@Sun.COM #ifdef DEBUG
117111042SErik.Nordmark@Sun.COM 		dce_refhold_notr(dce);
117211042SErik.Nordmark@Sun.COM 		dce_refrele(dce);
117311042SErik.Nordmark@Sun.COM #endif
117411042SErik.Nordmark@Sun.COM 		ixa->ixa_dce = dce;
117511042SErik.Nordmark@Sun.COM 		ixa->ixa_dce_generation = DCE_GENERATION_VERIFY;
117611042SErik.Nordmark@Sun.COM 	}
117711042SErik.Nordmark@Sun.COM }
117811042SErik.Nordmark@Sun.COM 
117911042SErik.Nordmark@Sun.COM /*
118011042SErik.Nordmark@Sun.COM  * Used to run ixa_cleanup_stale inside the tcp squeue.
118111042SErik.Nordmark@Sun.COM  * When done we hand the mp back by assigning it to tcps_ixa_cleanup_mp
118211042SErik.Nordmark@Sun.COM  * and waking up the caller.
118311042SErik.Nordmark@Sun.COM  */
118411042SErik.Nordmark@Sun.COM /* ARGSUSED2 */
118511042SErik.Nordmark@Sun.COM static void
tcp_ixa_cleanup(void * arg,mblk_t * mp,void * arg2,ip_recv_attr_t * dummy)118611042SErik.Nordmark@Sun.COM tcp_ixa_cleanup(void *arg, mblk_t *mp, void *arg2,
118711042SErik.Nordmark@Sun.COM     ip_recv_attr_t *dummy)
118811042SErik.Nordmark@Sun.COM {
118911042SErik.Nordmark@Sun.COM 	conn_t	*connp = (conn_t *)arg;
119011042SErik.Nordmark@Sun.COM 	tcp_stack_t	*tcps;
119111042SErik.Nordmark@Sun.COM 
119211042SErik.Nordmark@Sun.COM 	tcps = connp->conn_netstack->netstack_tcp;
119311042SErik.Nordmark@Sun.COM 
119411042SErik.Nordmark@Sun.COM 	ixa_cleanup_stale(connp->conn_ixa);
119511042SErik.Nordmark@Sun.COM 
119611042SErik.Nordmark@Sun.COM 	mutex_enter(&tcps->tcps_ixa_cleanup_lock);
119711042SErik.Nordmark@Sun.COM 	ASSERT(tcps->tcps_ixa_cleanup_mp == NULL);
119811042SErik.Nordmark@Sun.COM 	tcps->tcps_ixa_cleanup_mp = mp;
119911042SErik.Nordmark@Sun.COM 	cv_signal(&tcps->tcps_ixa_cleanup_cv);
120011042SErik.Nordmark@Sun.COM 	mutex_exit(&tcps->tcps_ixa_cleanup_lock);
120111042SErik.Nordmark@Sun.COM }
120211042SErik.Nordmark@Sun.COM 
120311042SErik.Nordmark@Sun.COM 
120411042SErik.Nordmark@Sun.COM /*
120511042SErik.Nordmark@Sun.COM  * ipcl_walk() function to help release any IRE, NCE, or DCEs that
120611042SErik.Nordmark@Sun.COM  * have been deleted and are marked as condemned.
120711042SErik.Nordmark@Sun.COM  * Note that we can't cleanup the pointers since there can be threads
120811042SErik.Nordmark@Sun.COM  * in conn_ip_output() sending while we are called.
120911042SErik.Nordmark@Sun.COM  */
121011042SErik.Nordmark@Sun.COM void
conn_ixa_cleanup(conn_t * connp,void * arg)121111042SErik.Nordmark@Sun.COM conn_ixa_cleanup(conn_t *connp, void *arg)
121211042SErik.Nordmark@Sun.COM {
121311042SErik.Nordmark@Sun.COM 	boolean_t tryhard = (boolean_t)arg;
121411042SErik.Nordmark@Sun.COM 
121511042SErik.Nordmark@Sun.COM 	if (IPCL_IS_TCP(connp)) {
121611042SErik.Nordmark@Sun.COM 		mblk_t		*mp;
121711042SErik.Nordmark@Sun.COM 		tcp_stack_t	*tcps;
121811042SErik.Nordmark@Sun.COM 
121911042SErik.Nordmark@Sun.COM 		tcps = connp->conn_netstack->netstack_tcp;
122011042SErik.Nordmark@Sun.COM 
122111042SErik.Nordmark@Sun.COM 		mutex_enter(&tcps->tcps_ixa_cleanup_lock);
122211042SErik.Nordmark@Sun.COM 		while ((mp = tcps->tcps_ixa_cleanup_mp) == NULL) {
122311042SErik.Nordmark@Sun.COM 			/*
122411042SErik.Nordmark@Sun.COM 			 * Multiple concurrent cleanups; need to have the last
122511042SErik.Nordmark@Sun.COM 			 * one run since it could be an unplumb.
122611042SErik.Nordmark@Sun.COM 			 */
122711042SErik.Nordmark@Sun.COM 			cv_wait(&tcps->tcps_ixa_cleanup_cv,
122811042SErik.Nordmark@Sun.COM 			    &tcps->tcps_ixa_cleanup_lock);
122911042SErik.Nordmark@Sun.COM 		}
123011042SErik.Nordmark@Sun.COM 		tcps->tcps_ixa_cleanup_mp = NULL;
123111042SErik.Nordmark@Sun.COM 		mutex_exit(&tcps->tcps_ixa_cleanup_lock);
123211042SErik.Nordmark@Sun.COM 
123311042SErik.Nordmark@Sun.COM 		if (connp->conn_sqp->sq_run == curthread) {
123411042SErik.Nordmark@Sun.COM 			/* Already on squeue */
123511042SErik.Nordmark@Sun.COM 			tcp_ixa_cleanup(connp, mp, NULL, NULL);
123611042SErik.Nordmark@Sun.COM 		} else {
123711042SErik.Nordmark@Sun.COM 			CONN_INC_REF(connp);
123811042SErik.Nordmark@Sun.COM 			SQUEUE_ENTER_ONE(connp->conn_sqp, mp, tcp_ixa_cleanup,
123911042SErik.Nordmark@Sun.COM 			    connp, NULL, SQ_PROCESS, SQTAG_TCP_IXA_CLEANUP);
124011042SErik.Nordmark@Sun.COM 
124111042SErik.Nordmark@Sun.COM 			/* Wait until tcp_ixa_cleanup has run */
124211042SErik.Nordmark@Sun.COM 			mutex_enter(&tcps->tcps_ixa_cleanup_lock);
124311042SErik.Nordmark@Sun.COM 			while (tcps->tcps_ixa_cleanup_mp == NULL) {
124411042SErik.Nordmark@Sun.COM 				cv_wait(&tcps->tcps_ixa_cleanup_cv,
124511042SErik.Nordmark@Sun.COM 				    &tcps->tcps_ixa_cleanup_lock);
124611042SErik.Nordmark@Sun.COM 			}
124711042SErik.Nordmark@Sun.COM 			mutex_exit(&tcps->tcps_ixa_cleanup_lock);
124811042SErik.Nordmark@Sun.COM 		}
124911042SErik.Nordmark@Sun.COM 	} else if (IPCL_IS_SCTP(connp)) {
125011042SErik.Nordmark@Sun.COM 		sctp_t	*sctp;
125111042SErik.Nordmark@Sun.COM 		sctp_faddr_t *fp;
125211042SErik.Nordmark@Sun.COM 
125311042SErik.Nordmark@Sun.COM 		sctp = CONN2SCTP(connp);
125411042SErik.Nordmark@Sun.COM 		RUN_SCTP(sctp);
125511042SErik.Nordmark@Sun.COM 		ixa_cleanup_stale(connp->conn_ixa);
1256*13009SChandrasekar.Marimuthu@Sun.COM 		for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next)
1257*13009SChandrasekar.Marimuthu@Sun.COM 			ixa_cleanup_stale(fp->sf_ixa);
125811042SErik.Nordmark@Sun.COM 		WAKE_SCTP(sctp);
125911042SErik.Nordmark@Sun.COM 	} else {
126011042SErik.Nordmark@Sun.COM 		ip_xmit_attr_t	*ixa;
126111042SErik.Nordmark@Sun.COM 
126211042SErik.Nordmark@Sun.COM 		/*
126311042SErik.Nordmark@Sun.COM 		 * If there is a different thread using conn_ixa then we get a
126411042SErik.Nordmark@Sun.COM 		 * new copy and cut the old one loose from conn_ixa. Otherwise
126511042SErik.Nordmark@Sun.COM 		 * we use conn_ixa and prevent any other thread from
126611042SErik.Nordmark@Sun.COM 		 * using/changing it. Anybody using conn_ixa (e.g., a thread in
126711042SErik.Nordmark@Sun.COM 		 * conn_ip_output) will do an ixa_refrele which will remove any
126811042SErik.Nordmark@Sun.COM 		 * references on the ire etc.
126911042SErik.Nordmark@Sun.COM 		 *
127011042SErik.Nordmark@Sun.COM 		 * Once we are done other threads can use conn_ixa since the
127111042SErik.Nordmark@Sun.COM 		 * refcnt will be back at one.
127211042SErik.Nordmark@Sun.COM 		 *
127311042SErik.Nordmark@Sun.COM 		 * We are called either because an ill is going away, or
127411042SErik.Nordmark@Sun.COM 		 * due to memory reclaim. In the former case we wait for
127511042SErik.Nordmark@Sun.COM 		 * memory since we must remove the refcnts on the ill.
127611042SErik.Nordmark@Sun.COM 		 */
127711042SErik.Nordmark@Sun.COM 		if (tryhard) {
127811042SErik.Nordmark@Sun.COM 			ixa = conn_get_ixa_tryhard(connp, B_TRUE);
127911042SErik.Nordmark@Sun.COM 			ASSERT(ixa != NULL);
128011042SErik.Nordmark@Sun.COM 		} else {
128111042SErik.Nordmark@Sun.COM 			ixa = conn_get_ixa(connp, B_TRUE);
128211042SErik.Nordmark@Sun.COM 			if (ixa == NULL) {
128311042SErik.Nordmark@Sun.COM 				/*
128411042SErik.Nordmark@Sun.COM 				 * Somebody else was using it and kmem_alloc
128511042SErik.Nordmark@Sun.COM 				 * failed! Next memory reclaim will try to
128611042SErik.Nordmark@Sun.COM 				 * clean up.
128711042SErik.Nordmark@Sun.COM 				 */
128811042SErik.Nordmark@Sun.COM 				DTRACE_PROBE1(conn__ixa__cleanup__bail,
128911042SErik.Nordmark@Sun.COM 				    conn_t *, connp);
129011042SErik.Nordmark@Sun.COM 				return;
129111042SErik.Nordmark@Sun.COM 			}
129211042SErik.Nordmark@Sun.COM 		}
129311042SErik.Nordmark@Sun.COM 		ixa_cleanup_stale(ixa);
129411042SErik.Nordmark@Sun.COM 		ixa_refrele(ixa);
129511042SErik.Nordmark@Sun.COM 	}
129611042SErik.Nordmark@Sun.COM }
129711042SErik.Nordmark@Sun.COM 
129811042SErik.Nordmark@Sun.COM /*
129911042SErik.Nordmark@Sun.COM  * ixa needs to be an exclusive copy so that no one changes the cookie
130011042SErik.Nordmark@Sun.COM  * or the ixa_nce.
130111042SErik.Nordmark@Sun.COM  */
130211042SErik.Nordmark@Sun.COM boolean_t
ixa_check_drain_insert(conn_t * connp,ip_xmit_attr_t * ixa)130311042SErik.Nordmark@Sun.COM ixa_check_drain_insert(conn_t *connp, ip_xmit_attr_t *ixa)
130411042SErik.Nordmark@Sun.COM {
130511042SErik.Nordmark@Sun.COM 	uintptr_t cookie = ixa->ixa_cookie;
130611042SErik.Nordmark@Sun.COM 	ill_dld_direct_t *idd;
130711042SErik.Nordmark@Sun.COM 	idl_tx_list_t *idl_txl;
130811042SErik.Nordmark@Sun.COM 	ill_t *ill = ixa->ixa_nce->nce_ill;
130911042SErik.Nordmark@Sun.COM 	boolean_t inserted = B_FALSE;
131011042SErik.Nordmark@Sun.COM 
131111042SErik.Nordmark@Sun.COM 	idd = &(ill)->ill_dld_capab->idc_direct;
131211042SErik.Nordmark@Sun.COM 	idl_txl = &ixa->ixa_ipst->ips_idl_tx_list[IDLHASHINDEX(cookie)];
131312020SPeter.Memishian@Sun.COM 	mutex_enter(&idl_txl->txl_lock);
131412020SPeter.Memishian@Sun.COM 
131512020SPeter.Memishian@Sun.COM 	/*
131612020SPeter.Memishian@Sun.COM 	 * If `cookie' is zero, ip_xmit() -> canputnext() failed -- i.e., flow
131712020SPeter.Memishian@Sun.COM 	 * control is asserted on an ill that does not support direct calls.
131812020SPeter.Memishian@Sun.COM 	 * Jump to insert.
131912020SPeter.Memishian@Sun.COM 	 */
132012020SPeter.Memishian@Sun.COM 	if (cookie == 0)
132112020SPeter.Memishian@Sun.COM 		goto tryinsert;
132212020SPeter.Memishian@Sun.COM 
132311042SErik.Nordmark@Sun.COM 	ASSERT(ILL_DIRECT_CAPABLE(ill));
132412020SPeter.Memishian@Sun.COM 
132512020SPeter.Memishian@Sun.COM 	if (idd->idd_tx_fctl_df(idd->idd_tx_fctl_dh, cookie) == 0) {
132612020SPeter.Memishian@Sun.COM 		DTRACE_PROBE1(ill__tx__not__blocked, uintptr_t, cookie);
132711042SErik.Nordmark@Sun.COM 	} else if (idl_txl->txl_cookie != NULL &&
132811042SErik.Nordmark@Sun.COM 	    idl_txl->txl_cookie != ixa->ixa_cookie) {
132912020SPeter.Memishian@Sun.COM 		DTRACE_PROBE2(ill__tx__cookie__collision, uintptr_t, cookie,
133011042SErik.Nordmark@Sun.COM 		    uintptr_t, idl_txl->txl_cookie);
133112020SPeter.Memishian@Sun.COM 		/* TODO: bump kstat for cookie collision */
133211042SErik.Nordmark@Sun.COM 	} else {
133312020SPeter.Memishian@Sun.COM 		/*
133412020SPeter.Memishian@Sun.COM 		 * Check/set conn_blocked under conn_lock.  Note that txl_lock
133512020SPeter.Memishian@Sun.COM 		 * will not suffice since two separate UDP threads may be
133612020SPeter.Memishian@Sun.COM 		 * racing to send to different destinations that are
133712020SPeter.Memishian@Sun.COM 		 * associated with different cookies and thus may not be
133812020SPeter.Memishian@Sun.COM 		 * holding the same txl_lock.  Further, since a given conn_t
133912020SPeter.Memishian@Sun.COM 		 * can only be on a single drain list, the conn_t will be
134012020SPeter.Memishian@Sun.COM 		 * enqueued on whichever thread wins this race.
134112020SPeter.Memishian@Sun.COM 		 */
134212020SPeter.Memishian@Sun.COM tryinsert:	mutex_enter(&connp->conn_lock);
134312020SPeter.Memishian@Sun.COM 		if (connp->conn_blocked) {
134412020SPeter.Memishian@Sun.COM 			DTRACE_PROBE1(ill__tx__conn__already__blocked,
134512020SPeter.Memishian@Sun.COM 			    conn_t *, connp);
134612020SPeter.Memishian@Sun.COM 			mutex_exit(&connp->conn_lock);
134712020SPeter.Memishian@Sun.COM 		} else {
134812020SPeter.Memishian@Sun.COM 			connp->conn_blocked = B_TRUE;
134912020SPeter.Memishian@Sun.COM 			mutex_exit(&connp->conn_lock);
135012020SPeter.Memishian@Sun.COM 			idl_txl->txl_cookie = cookie;
135112020SPeter.Memishian@Sun.COM 			conn_drain_insert(connp, idl_txl);
135212020SPeter.Memishian@Sun.COM 			if (!IPCL_IS_NONSTR(connp))
135312020SPeter.Memishian@Sun.COM 				noenable(connp->conn_wq);
135412020SPeter.Memishian@Sun.COM 			inserted = B_TRUE;
135512020SPeter.Memishian@Sun.COM 		}
135611042SErik.Nordmark@Sun.COM 	}
135711042SErik.Nordmark@Sun.COM 	mutex_exit(&idl_txl->txl_lock);
135811042SErik.Nordmark@Sun.COM 	return (inserted);
135911042SErik.Nordmark@Sun.COM }
1360