xref: /titanic_51/usr/src/uts/common/inet/ip/ip_attr.c (revision 77dabb95057c6ac2d639808648bf928ca53585f4)
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