xref: /illumos-gate/usr/src/uts/common/inet/ip/ip_arp.c (revision 8a06b3d6)
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 /*
231f19738eSmeem  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24bd670b35SErik Nordmark  */
25bd670b35SErik Nordmark 
26bd670b35SErik Nordmark #include <inet/ip_arp.h>
27bd670b35SErik Nordmark #include <inet/ip_ndp.h>
28bd670b35SErik Nordmark #include <net/if_arp.h>
29bd670b35SErik Nordmark #include <netinet/if_ether.h>
30bd670b35SErik Nordmark #include <sys/strsubr.h>
31bd670b35SErik Nordmark #include <inet/ip6.h>
32bd670b35SErik Nordmark #include <inet/ip.h>
33bd670b35SErik Nordmark #include <inet/ip_ire.h>
34bd670b35SErik Nordmark #include <inet/ip_if.h>
35bd670b35SErik Nordmark #include <sys/dlpi.h>
36bd670b35SErik Nordmark #include <sys/sunddi.h>
37bd670b35SErik Nordmark #include <sys/strsun.h>
38bd670b35SErik Nordmark #include <sys/sdt.h>
39bd670b35SErik Nordmark #include <inet/mi.h>
40bd670b35SErik Nordmark #include <inet/arp.h>
41bd670b35SErik Nordmark #include <inet/ipdrop.h>
42bd670b35SErik Nordmark #include <sys/sockio.h>
43bd670b35SErik Nordmark #include <inet/ip_impl.h>
44bd670b35SErik Nordmark #include <sys/policy.h>
45bd670b35SErik Nordmark 
46bd670b35SErik Nordmark #define	ARL_LL_ADDR_OFFSET(arl)	(((arl)->arl_sap_length) < 0 ? \
47bd670b35SErik Nordmark 	(sizeof (dl_unitdata_req_t)) : \
48bd670b35SErik Nordmark 	((sizeof (dl_unitdata_req_t)) + (ABS((arl)->arl_sap_length))))
49bd670b35SErik Nordmark 
50bd670b35SErik Nordmark /*
51bd670b35SErik Nordmark  * MAC-specific intelligence.  Shouldn't be needed, but the DL_INFO_ACK
52bd670b35SErik Nordmark  * doesn't quite do it for us.
53bd670b35SErik Nordmark  */
54bd670b35SErik Nordmark typedef struct arp_m_s {
55bd670b35SErik Nordmark 	t_uscalar_t	arp_mac_type;
56bd670b35SErik Nordmark 	uint32_t	arp_mac_arp_hw_type;
57bd670b35SErik Nordmark 	t_scalar_t	arp_mac_sap_length;
58bd670b35SErik Nordmark 	uint32_t	arp_mac_hw_addr_length;
59bd670b35SErik Nordmark } arp_m_t;
60bd670b35SErik Nordmark 
615e1743f0SToomas Soome static int arp_close(queue_t *, int, cred_t *);
62*8a06b3d6SToomas Soome static int arp_rput(queue_t *, mblk_t *);
63*8a06b3d6SToomas Soome static int arp_wput(queue_t *, mblk_t *);
64bd670b35SErik Nordmark static arp_m_t	*arp_m_lookup(t_uscalar_t mac_type);
65bd670b35SErik Nordmark static void arp_notify(ipaddr_t, mblk_t *, uint32_t, ip_recv_attr_t *,
66bd670b35SErik Nordmark 	ncec_t *);
67bd670b35SErik Nordmark static int arp_output(ill_t *, uint32_t, const uchar_t *, const uchar_t *,
68bd670b35SErik Nordmark 	const uchar_t *, const uchar_t *, uchar_t *);
69bd670b35SErik Nordmark static int  arp_modclose(arl_t *);
70bd670b35SErik Nordmark static void  arp_mod_close_tail(arl_t *);
71bd670b35SErik Nordmark static mblk_t *arl_unbind(arl_t *);
72bd670b35SErik Nordmark static void arp_process_packet(ill_t *, mblk_t *);
73bd670b35SErik Nordmark static void arp_excl(ipsq_t *, queue_t *, mblk_t *, void *);
74bd670b35SErik Nordmark static void arp_drop_packet(const char *str, mblk_t *, ill_t *);
75bd670b35SErik Nordmark static int arp_open(queue_t *, dev_t *, int, int, cred_t *);
76bd670b35SErik Nordmark static int ip_sioctl_ifunitsel_arp(queue_t *, int *);
77bd670b35SErik Nordmark static int ip_sioctl_slifname_arp(queue_t *, void *);
78bd670b35SErik Nordmark static void arp_dlpi_send(arl_t *, mblk_t *);
79bd670b35SErik Nordmark static void arl_defaults_common(arl_t *, mblk_t *);
80bd670b35SErik Nordmark static int arp_modopen(queue_t *, dev_t *, int, int, cred_t *);
81bd670b35SErik Nordmark static void arp_ifname_notify(arl_t *);
82bd670b35SErik Nordmark static void arp_rput_dlpi_writer(ipsq_t *, queue_t *, mblk_t *, void *);
83bd670b35SErik Nordmark static arl_t *ill_to_arl(ill_t *);
84bd670b35SErik Nordmark 
85bd670b35SErik Nordmark #define	DL_PRIM(mp)	(((union DL_primitives *)(mp)->b_rptr)->dl_primitive)
86bd670b35SErik Nordmark #define	IS_DLPI_DATA(mp)						\
87bd670b35SErik Nordmark 	((DB_TYPE(mp) == M_PROTO) &&					\
88bd670b35SErik Nordmark 	MBLKL(mp) >= sizeof (dl_unitdata_ind_t) &&			\
89bd670b35SErik Nordmark 	(DL_PRIM(mp) == DL_UNITDATA_IND))
90bd670b35SErik Nordmark 
91bd670b35SErik Nordmark #define	AR_NOTFOUND	1	/* No matching ace found in cache */
92bd670b35SErik Nordmark #define	AR_MERGED	2	/* Matching ace updated (RFC 826 Merge_flag) */
93bd670b35SErik Nordmark #define	AR_LOOPBACK	3	/* Our own arp packet was received */
94bd670b35SErik Nordmark #define	AR_BOGON	4	/* Another host has our IP addr. */
95bd670b35SErik Nordmark #define	AR_FAILED	5	/* Duplicate Address Detection has failed */
96bd670b35SErik Nordmark #define	AR_CHANGED	6	/* Address has changed; tell IP (and merged) */
97bd670b35SErik Nordmark 
98bd670b35SErik Nordmark boolean_t arp_no_defense;
99bd670b35SErik Nordmark 
100bd670b35SErik Nordmark struct module_info arp_mod_info = {
101937e6fcdSNitin Hande 	IP_MOD_ID, "arp", 1, INFPSZ, 65536, 1024
102bd670b35SErik Nordmark };
103bd670b35SErik Nordmark static struct qinit rinit_arp = {
104*8a06b3d6SToomas Soome 	arp_rput, NULL, arp_open, arp_close, NULL, &arp_mod_info
105bd670b35SErik Nordmark };
106bd670b35SErik Nordmark static struct qinit winit_arp = {
107*8a06b3d6SToomas Soome 	arp_wput, NULL, arp_open, arp_close, NULL, &arp_mod_info
108bd670b35SErik Nordmark };
109bd670b35SErik Nordmark struct streamtab arpinfo = {
110bd670b35SErik Nordmark 	&rinit_arp, &winit_arp
111bd670b35SErik Nordmark };
112bd670b35SErik Nordmark #define	ARH_FIXED_LEN	8
113bd670b35SErik Nordmark #define	AR_LL_HDR_SLACK	32
114bd670b35SErik Nordmark 
115bd670b35SErik Nordmark /*
116bd670b35SErik Nordmark  * pfhooks for ARP.
117bd670b35SErik Nordmark  */
118bd670b35SErik Nordmark #define	ARP_HOOK_IN(_hook, _event, _ilp, _hdr, _fm, _m, ipst)		\
119bd670b35SErik Nordmark 									\
120*8a06b3d6SToomas Soome 	if ((_hook).he_interested) {					\
121*8a06b3d6SToomas Soome 		hook_pkt_event_t info;					\
122bd670b35SErik Nordmark 									\
123bd670b35SErik Nordmark 		info.hpe_protocol = ipst->ips_arp_net_data;		\
124*8a06b3d6SToomas Soome 		info.hpe_ifp = _ilp;					\
125*8a06b3d6SToomas Soome 		info.hpe_ofp = 0;					\
126*8a06b3d6SToomas Soome 		info.hpe_hdr = _hdr;					\
127*8a06b3d6SToomas Soome 		info.hpe_mp = &(_fm);					\
128*8a06b3d6SToomas Soome 		info.hpe_mb = _m;					\
129bd670b35SErik Nordmark 		if (hook_run(ipst->ips_arp_net_data->netd_hooks,	\
130bd670b35SErik Nordmark 		    _event, (hook_data_t)&info) != 0) {			\
131*8a06b3d6SToomas Soome 			if (_fm != NULL) {				\
132*8a06b3d6SToomas Soome 				freemsg(_fm);				\
133*8a06b3d6SToomas Soome 				_fm = NULL;				\
134*8a06b3d6SToomas Soome 			}						\
135*8a06b3d6SToomas Soome 			_hdr = NULL;					\
136*8a06b3d6SToomas Soome 			_m = NULL;					\
137*8a06b3d6SToomas Soome 		} else {						\
138*8a06b3d6SToomas Soome 			_hdr = info.hpe_hdr;				\
139*8a06b3d6SToomas Soome 			_m = info.hpe_mb;				\
140*8a06b3d6SToomas Soome 		}							\
141bd670b35SErik Nordmark 	}
142bd670b35SErik Nordmark 
143bd670b35SErik Nordmark #define	ARP_HOOK_OUT(_hook, _event, _olp, _hdr, _fm, _m, ipst)		\
144bd670b35SErik Nordmark 									\
145*8a06b3d6SToomas Soome 	if ((_hook).he_interested) {					\
146*8a06b3d6SToomas Soome 		hook_pkt_event_t info;					\
147bd670b35SErik Nordmark 									\
148bd670b35SErik Nordmark 		info.hpe_protocol = ipst->ips_arp_net_data;		\
149*8a06b3d6SToomas Soome 		info.hpe_ifp = 0;					\
150*8a06b3d6SToomas Soome 		info.hpe_ofp = _olp;					\
151*8a06b3d6SToomas Soome 		info.hpe_hdr = _hdr;					\
152*8a06b3d6SToomas Soome 		info.hpe_mp = &(_fm);					\
153*8a06b3d6SToomas Soome 		info.hpe_mb = _m;					\
154bd670b35SErik Nordmark 		if (hook_run(ipst->ips_arp_net_data->netd_hooks,	\
155bd670b35SErik Nordmark 		    _event, (hook_data_t)&info) != 0) {			\
156*8a06b3d6SToomas Soome 			if (_fm != NULL) {				\
157*8a06b3d6SToomas Soome 				freemsg(_fm);				\
158*8a06b3d6SToomas Soome 				_fm = NULL;				\
159*8a06b3d6SToomas Soome 			}						\
160*8a06b3d6SToomas Soome 			_hdr = NULL;					\
161*8a06b3d6SToomas Soome 			_m = NULL;					\
162*8a06b3d6SToomas Soome 		} else {						\
163*8a06b3d6SToomas Soome 			_hdr = info.hpe_hdr;				\
164*8a06b3d6SToomas Soome 			_m = info.hpe_mb;				\
165*8a06b3d6SToomas Soome 		}							\
166bd670b35SErik Nordmark 	}
167bd670b35SErik Nordmark 
168bd670b35SErik Nordmark static arp_m_t	arp_m_tbl[] = {
169bd670b35SErik Nordmark 	{ DL_CSMACD,	ARPHRD_ETHER,	-2,	6},	/* 802.3 */
170bd670b35SErik Nordmark 	{ DL_TPB,	ARPHRD_IEEE802,	-2,	6},	/* 802.4 */
171bd670b35SErik Nordmark 	{ DL_TPR,	ARPHRD_IEEE802,	-2,	6},	/* 802.5 */
172bd670b35SErik Nordmark 	{ DL_METRO,	ARPHRD_IEEE802,	-2,	6},	/* 802.6 */
173bd670b35SErik Nordmark 	{ DL_ETHER,	ARPHRD_ETHER,	-2,	6},	/* Ethernet */
174bd670b35SErik Nordmark 	{ DL_FDDI,	ARPHRD_ETHER,	-2,	6},	/* FDDI */
175bd670b35SErik Nordmark 	{ DL_IB,	ARPHRD_IB,	-2,	20},	/* Infiniband */
176bd670b35SErik Nordmark 	{ DL_OTHER,	ARPHRD_ETHER,	-2,	6}	/* unknown */
177bd670b35SErik Nordmark };
178bd670b35SErik Nordmark 
179bd670b35SErik Nordmark static void
arl_refhold_locked(arl_t * arl)180bd670b35SErik Nordmark arl_refhold_locked(arl_t *arl)
181bd670b35SErik Nordmark {
182bd670b35SErik Nordmark 	ASSERT(MUTEX_HELD(&arl->arl_lock));
183bd670b35SErik Nordmark 	arl->arl_refcnt++;
184bd670b35SErik Nordmark 	ASSERT(arl->arl_refcnt != 0);
185bd670b35SErik Nordmark }
186bd670b35SErik Nordmark 
187bd670b35SErik Nordmark static void
arl_refrele(arl_t * arl)188bd670b35SErik Nordmark arl_refrele(arl_t *arl)
189bd670b35SErik Nordmark {
190bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
191bd670b35SErik Nordmark 	ASSERT(arl->arl_refcnt != 0);
192bd670b35SErik Nordmark 	arl->arl_refcnt--;
193bd670b35SErik Nordmark 	if (arl->arl_refcnt > 1) {
194bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
195bd670b35SErik Nordmark 		return;
196bd670b35SErik Nordmark 	}
197bd670b35SErik Nordmark 
198bd670b35SErik Nordmark 	/* ill_close or arp_unbind_complete may be waiting */
199bd670b35SErik Nordmark 	cv_broadcast(&arl->arl_cv);
200bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
201bd670b35SErik Nordmark }
202bd670b35SErik Nordmark 
203bd670b35SErik Nordmark /*
204bd670b35SErik Nordmark  * wake up any pending ip ioctls.
205bd670b35SErik Nordmark  */
206bd670b35SErik Nordmark static void
arp_cmd_done(ill_t * ill,int err,t_uscalar_t lastprim)207bd670b35SErik Nordmark arp_cmd_done(ill_t *ill, int err, t_uscalar_t lastprim)
208bd670b35SErik Nordmark {
209bd670b35SErik Nordmark 	if (lastprim == DL_UNBIND_REQ && ill->ill_replumbing)
210bd670b35SErik Nordmark 		arp_replumb_done(ill, 0);
211bd670b35SErik Nordmark 	else
212bd670b35SErik Nordmark 		arp_bringup_done(ill, err);
213bd670b35SErik Nordmark }
214bd670b35SErik Nordmark 
215bd670b35SErik Nordmark static int
ip_nce_resolve_all(ill_t * ill,uchar_t * src_haddr,uint32_t hlen,const in_addr_t * src_paddr,ncec_t ** sncec,int op)216bd670b35SErik Nordmark ip_nce_resolve_all(ill_t *ill, uchar_t *src_haddr, uint32_t hlen,
217bd670b35SErik Nordmark     const in_addr_t *src_paddr, ncec_t **sncec, int op)
218bd670b35SErik Nordmark {
219bd670b35SErik Nordmark 	int retv;
220bd670b35SErik Nordmark 	ncec_t *ncec;
221bd670b35SErik Nordmark 	boolean_t ll_changed;
222bd670b35SErik Nordmark 	uchar_t *lladdr = NULL;
223bd670b35SErik Nordmark 	int new_state;
224bd670b35SErik Nordmark 
225bd670b35SErik Nordmark 	ASSERT(ill != NULL);
226bd670b35SErik Nordmark 
227bd670b35SErik Nordmark 	ncec = ncec_lookup_illgrp_v4(ill, src_paddr);
228bd670b35SErik Nordmark 	*sncec = ncec;
229bd670b35SErik Nordmark 
230bd670b35SErik Nordmark 	if (ncec == NULL) {
231bd670b35SErik Nordmark 		retv = AR_NOTFOUND;
232bd670b35SErik Nordmark 		goto done;
233bd670b35SErik Nordmark 	}
234bd670b35SErik Nordmark 
235bd670b35SErik Nordmark 	mutex_enter(&ncec->ncec_lock);
236bd670b35SErik Nordmark 	/*
237bd670b35SErik Nordmark 	 * IP addr and hardware address match what we already
238bd670b35SErik Nordmark 	 * have, then this is a broadcast packet emitted by one of our
239bd670b35SErik Nordmark 	 * interfaces, reflected by the switch and received on another
240bd670b35SErik Nordmark 	 * interface.  We return AR_LOOPBACK.
241bd670b35SErik Nordmark 	 */
242bd670b35SErik Nordmark 	lladdr = ncec->ncec_lladdr;
243bd670b35SErik Nordmark 	if (NCE_MYADDR(ncec) && hlen == ncec->ncec_ill->ill_phys_addr_length &&
244bd670b35SErik Nordmark 	    bcmp(lladdr, src_haddr, hlen) == 0) {
245bd670b35SErik Nordmark 		mutex_exit(&ncec->ncec_lock);
246bd670b35SErik Nordmark 		retv = AR_LOOPBACK;
247bd670b35SErik Nordmark 		goto done;
248bd670b35SErik Nordmark 	}
249bd670b35SErik Nordmark 	/*
250bd670b35SErik Nordmark 	 * If the entry is unverified, then we've just verified that
251bd670b35SErik Nordmark 	 * someone else already owns this address, because this is a
252bd670b35SErik Nordmark 	 * message with the same protocol address but different
253bd670b35SErik Nordmark 	 * hardware address.
254bd670b35SErik Nordmark 	 */
255bd670b35SErik Nordmark 	if (ncec->ncec_flags & NCE_F_UNVERIFIED) {
256bd670b35SErik Nordmark 		mutex_exit(&ncec->ncec_lock);
257bd670b35SErik Nordmark 		ncec_delete(ncec);
258bd670b35SErik Nordmark 		ncec_refrele(ncec);
259bd670b35SErik Nordmark 		*sncec = NULL;
260bd670b35SErik Nordmark 		retv = AR_FAILED;
261bd670b35SErik Nordmark 		goto done;
262bd670b35SErik Nordmark 	}
263bd670b35SErik Nordmark 
264bd670b35SErik Nordmark 	/*
265bd670b35SErik Nordmark 	 * If the IP address matches ours and we're authoritative for
266bd670b35SErik Nordmark 	 * this entry, then some other node is using our IP addr, so
267bd670b35SErik Nordmark 	 * return AR_BOGON.  Also reset the transmit count to zero so
268bd670b35SErik Nordmark 	 * that, if we're currently in initial announcement mode, we
269bd670b35SErik Nordmark 	 * switch back to the lazier defense mode.  Knowing that
270bd670b35SErik Nordmark 	 * there's at least one duplicate out there, we ought not
271bd670b35SErik Nordmark 	 * blindly announce.
272bd670b35SErik Nordmark 	 *
273bd670b35SErik Nordmark 	 * NCE_F_AUTHORITY is set in one of two ways:
274bd670b35SErik Nordmark 	 * 1. /sbin/arp told us so, via the "permanent" flag.
275bd670b35SErik Nordmark 	 * 2. This is one of my addresses.
276bd670b35SErik Nordmark 	 */
277bd670b35SErik Nordmark 	if (ncec->ncec_flags & NCE_F_AUTHORITY) {
278bd670b35SErik Nordmark 		ncec->ncec_unsolicit_count = 0;
279bd670b35SErik Nordmark 		mutex_exit(&ncec->ncec_lock);
280bd670b35SErik Nordmark 		retv = AR_BOGON;
281bd670b35SErik Nordmark 		goto done;
282bd670b35SErik Nordmark 	}
283bd670b35SErik Nordmark 
284bd670b35SErik Nordmark 	/*
285bd670b35SErik Nordmark 	 * No address conflict was detected, and we are getting
286bd670b35SErik Nordmark 	 * ready to update the ncec's hwaddr. The nce MUST NOT be on an
287bd670b35SErik Nordmark 	 * under interface, because all dynamic nce's are created on the
288bd670b35SErik Nordmark 	 * native interface (in the non-IPMP case) or on the IPMP
289bd670b35SErik Nordmark 	 * meta-interface (in the IPMP case)
290bd670b35SErik Nordmark 	 */
291bd670b35SErik Nordmark 	ASSERT(!IS_UNDER_IPMP(ncec->ncec_ill));
292bd670b35SErik Nordmark 
293bd670b35SErik Nordmark 	/*
294bd670b35SErik Nordmark 	 * update ncec with src_haddr, hlen.
295bd670b35SErik Nordmark 	 *
296bd670b35SErik Nordmark 	 * We are trying to resolve this ncec_addr/src_paddr and we
297bd670b35SErik Nordmark 	 * got a REQUEST/RESPONSE from the ncec_addr/src_paddr.
298bd670b35SErik Nordmark 	 * So the new_state is at least "STALE". If, in addition,
299bd670b35SErik Nordmark 	 * this a solicited, unicast ARP_RESPONSE, we can transition
300bd670b35SErik Nordmark 	 * to REACHABLE.
301bd670b35SErik Nordmark 	 */
302bd670b35SErik Nordmark 	new_state = ND_STALE;
303bd670b35SErik Nordmark 	ip1dbg(("got info for ncec %p from addr %x\n",
304bd670b35SErik Nordmark 	    (void *)ncec, *src_paddr));
305bd670b35SErik Nordmark 	retv = AR_MERGED;
306bd670b35SErik Nordmark 	if (ncec->ncec_state == ND_INCOMPLETE ||
307bd670b35SErik Nordmark 	    ncec->ncec_state == ND_INITIAL) {
308bd670b35SErik Nordmark 		ll_changed = B_TRUE;
309bd670b35SErik Nordmark 	} else {
310bd670b35SErik Nordmark 		ll_changed = nce_cmp_ll_addr(ncec, src_haddr, hlen);
311bd670b35SErik Nordmark 		if (!ll_changed)
312bd670b35SErik Nordmark 			new_state = ND_UNCHANGED;
313bd670b35SErik Nordmark 		else
314bd670b35SErik Nordmark 			retv = AR_CHANGED;
315bd670b35SErik Nordmark 	}
316bd670b35SErik Nordmark 	/*
317bd670b35SErik Nordmark 	 * We don't have the equivalent of the IPv6 'S' flag indicating
318bd670b35SErik Nordmark 	 * a solicited response, so we assume that if we are in
319bd670b35SErik Nordmark 	 * INCOMPLETE, or got back an unchanged lladdr in PROBE state,
320bd670b35SErik Nordmark 	 * and this is an ARP_RESPONSE, it must be a
321bd670b35SErik Nordmark 	 * solicited response allowing us to transtion to REACHABLE.
322bd670b35SErik Nordmark 	 */
323bd670b35SErik Nordmark 	if (op == ARP_RESPONSE) {
324bd670b35SErik Nordmark 		switch (ncec->ncec_state) {
325bd670b35SErik Nordmark 		case ND_PROBE:
326bd670b35SErik Nordmark 			new_state = (ll_changed ? ND_STALE : ND_REACHABLE);
327bd670b35SErik Nordmark 			break;
328bd670b35SErik Nordmark 		case ND_INCOMPLETE:
329bd670b35SErik Nordmark 			new_state = ND_REACHABLE;
330bd670b35SErik Nordmark 			break;
331bd670b35SErik Nordmark 		}
332bd670b35SErik Nordmark 	}
333bd670b35SErik Nordmark 	/*
334bd670b35SErik Nordmark 	 * Call nce_update() to refresh fastpath information on any
335bd670b35SErik Nordmark 	 * dependent nce_t entries.
336bd670b35SErik Nordmark 	 */
337bd670b35SErik Nordmark 	nce_update(ncec, new_state, (ll_changed ? src_haddr : NULL));
338bd670b35SErik Nordmark 	mutex_exit(&ncec->ncec_lock);
339bd670b35SErik Nordmark 	nce_resolv_ok(ncec);
340bd670b35SErik Nordmark done:
341bd670b35SErik Nordmark 	return (retv);
342bd670b35SErik Nordmark }
343bd670b35SErik Nordmark 
344bd670b35SErik Nordmark /* Find an entry for a particular MAC type in the arp_m_tbl. */
345bd670b35SErik Nordmark static arp_m_t	*
arp_m_lookup(t_uscalar_t mac_type)346bd670b35SErik Nordmark arp_m_lookup(t_uscalar_t mac_type)
347bd670b35SErik Nordmark {
348bd670b35SErik Nordmark 	arp_m_t	*arm;
349bd670b35SErik Nordmark 
350bd670b35SErik Nordmark 	for (arm = arp_m_tbl; arm < A_END(arp_m_tbl); arm++) {
351bd670b35SErik Nordmark 		if (arm->arp_mac_type == mac_type)
352bd670b35SErik Nordmark 			return (arm);
353bd670b35SErik Nordmark 	}
354bd670b35SErik Nordmark 	return (NULL);
355bd670b35SErik Nordmark }
356bd670b35SErik Nordmark 
357a6911619SDarren Reed uint32_t
arp_hw_type(t_uscalar_t mactype)358bd670b35SErik Nordmark arp_hw_type(t_uscalar_t mactype)
359bd670b35SErik Nordmark {
360bd670b35SErik Nordmark 	arp_m_t *arm;
361bd670b35SErik Nordmark 
362bd670b35SErik Nordmark 	if ((arm = arp_m_lookup(mactype)) == NULL)
363bd670b35SErik Nordmark 		arm = arp_m_lookup(DL_OTHER);
364bd670b35SErik Nordmark 	return (arm->arp_mac_arp_hw_type);
365bd670b35SErik Nordmark }
366bd670b35SErik Nordmark 
367bd670b35SErik Nordmark /*
368bd670b35SErik Nordmark  * Called when an DLPI control message has been acked; send down the next
369bd670b35SErik Nordmark  * queued message (if any).
370bd670b35SErik Nordmark  * The DLPI messages of interest being bind, attach and unbind since
371bd670b35SErik Nordmark  * these are the only ones sent by ARP via arp_dlpi_send.
372bd670b35SErik Nordmark  */
373bd670b35SErik Nordmark static void
arp_dlpi_done(arl_t * arl,ill_t * ill)374bd670b35SErik Nordmark arp_dlpi_done(arl_t *arl, ill_t *ill)
375bd670b35SErik Nordmark {
376bd670b35SErik Nordmark 	mblk_t *mp;
377bd670b35SErik Nordmark 	int err;
378bd670b35SErik Nordmark 	t_uscalar_t prim;
379bd670b35SErik Nordmark 
380bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
381bd670b35SErik Nordmark 	prim = arl->arl_dlpi_pending;
382bd670b35SErik Nordmark 
383bd670b35SErik Nordmark 	if ((mp = arl->arl_dlpi_deferred) == NULL) {
384bd670b35SErik Nordmark 		arl->arl_dlpi_pending = DL_PRIM_INVAL;
385bd670b35SErik Nordmark 		if (arl->arl_state_flags & ARL_LL_DOWN)
386bd670b35SErik Nordmark 			err = ENETDOWN;
387bd670b35SErik Nordmark 		else
388bd670b35SErik Nordmark 			err = 0;
389bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
390bd670b35SErik Nordmark 
391bd670b35SErik Nordmark 		mutex_enter(&ill->ill_lock);
392bd670b35SErik Nordmark 		ill->ill_arl_dlpi_pending = 0;
393bd670b35SErik Nordmark 		mutex_exit(&ill->ill_lock);
394bd670b35SErik Nordmark 		arp_cmd_done(ill, err, prim);
395bd670b35SErik Nordmark 		return;
396bd670b35SErik Nordmark 	}
397bd670b35SErik Nordmark 
398bd670b35SErik Nordmark 	arl->arl_dlpi_deferred = mp->b_next;
399bd670b35SErik Nordmark 	mp->b_next = NULL;
400bd670b35SErik Nordmark 
401bd670b35SErik Nordmark 	ASSERT(DB_TYPE(mp) == M_PROTO || DB_TYPE(mp) == M_PCPROTO);
402bd670b35SErik Nordmark 
403bd670b35SErik Nordmark 	arl->arl_dlpi_pending = DL_PRIM(mp);
404bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
405bd670b35SErik Nordmark 
406bd670b35SErik Nordmark 	mutex_enter(&ill->ill_lock);
407bd670b35SErik Nordmark 	ill->ill_arl_dlpi_pending = 1;
408bd670b35SErik Nordmark 	mutex_exit(&ill->ill_lock);
409bd670b35SErik Nordmark 
410bd670b35SErik Nordmark 	putnext(arl->arl_wq, mp);
411bd670b35SErik Nordmark }
412bd670b35SErik Nordmark 
413bd670b35SErik Nordmark /*
414bd670b35SErik Nordmark  * This routine is called during module initialization when the DL_INFO_ACK
415bd670b35SErik Nordmark  * comes back from the device.	We set up defaults for all the device dependent
416bd670b35SErik Nordmark  * doo-dads we are going to need.  This will leave us ready to roll if we are
417bd670b35SErik Nordmark  * attempting auto-configuration.  Alternatively, these defaults can be
418bd670b35SErik Nordmark  * overridden by initialization procedures possessing higher intelligence.
419bd670b35SErik Nordmark  *
420bd670b35SErik Nordmark  * Caller will free the mp.
421bd670b35SErik Nordmark  */
422bd670b35SErik Nordmark static void
arp_ll_set_defaults(arl_t * arl,mblk_t * mp)423bd670b35SErik Nordmark arp_ll_set_defaults(arl_t *arl, mblk_t *mp)
424bd670b35SErik Nordmark {
425bd670b35SErik Nordmark 	arp_m_t		*arm;
426bd670b35SErik Nordmark 	dl_info_ack_t	*dlia = (dl_info_ack_t *)mp->b_rptr;
427bd670b35SErik Nordmark 
428bd670b35SErik Nordmark 	if ((arm = arp_m_lookup(dlia->dl_mac_type)) == NULL)
429bd670b35SErik Nordmark 		arm = arp_m_lookup(DL_OTHER);
430bd670b35SErik Nordmark 	ASSERT(arm != NULL);
431bd670b35SErik Nordmark 
432bd670b35SErik Nordmark 	/*
433bd670b35SErik Nordmark 	 * We initialize based on parameters in the (currently) not too
434bd670b35SErik Nordmark 	 * exhaustive arp_m_tbl.
435bd670b35SErik Nordmark 	 */
436bd670b35SErik Nordmark 	if (dlia->dl_version == DL_VERSION_2) {
437bd670b35SErik Nordmark 		arl->arl_sap_length = dlia->dl_sap_length;
438bd670b35SErik Nordmark 		arl->arl_phys_addr_length = dlia->dl_brdcst_addr_length;
439bd670b35SErik Nordmark 		if (dlia->dl_provider_style == DL_STYLE2)
440bd670b35SErik Nordmark 			arl->arl_needs_attach = 1;
441bd670b35SErik Nordmark 	} else {
442bd670b35SErik Nordmark 		arl->arl_sap_length = arm->arp_mac_sap_length;
443bd670b35SErik Nordmark 		arl->arl_phys_addr_length = arm->arp_mac_hw_addr_length;
444bd670b35SErik Nordmark 	}
445bd670b35SErik Nordmark 	/*
446bd670b35SErik Nordmark 	 * Note: the arp_hw_type in the arp header may be derived from
447bd670b35SErik Nordmark 	 * the ill_mac_type and arp_m_lookup().
448bd670b35SErik Nordmark 	 */
449bd670b35SErik Nordmark 	arl->arl_sap = ETHERTYPE_ARP;
450bd670b35SErik Nordmark 	arl_defaults_common(arl, mp);
451bd670b35SErik Nordmark }
452bd670b35SErik Nordmark 
453*8a06b3d6SToomas Soome static int
arp_wput(queue_t * q,mblk_t * mp)454bd670b35SErik Nordmark arp_wput(queue_t *q, mblk_t *mp)
455bd670b35SErik Nordmark {
456bd670b35SErik Nordmark 	int err = EINVAL;
457bd670b35SErik Nordmark 	struct iocblk *ioc;
458bd670b35SErik Nordmark 	mblk_t *mp1;
459bd670b35SErik Nordmark 
460bd670b35SErik Nordmark 	switch (DB_TYPE(mp)) {
461bd670b35SErik Nordmark 	case M_IOCTL:
462bd670b35SErik Nordmark 		ASSERT(q->q_next != NULL);
463bd670b35SErik Nordmark 		ioc = (struct iocblk *)mp->b_rptr;
464bd670b35SErik Nordmark 		if (ioc->ioc_cmd != SIOCSLIFNAME &&
465bd670b35SErik Nordmark 		    ioc->ioc_cmd != IF_UNITSEL) {
466bd670b35SErik Nordmark 			DTRACE_PROBE4(arl__dlpi, char *, "arp_wput",
467bd670b35SErik Nordmark 			    char *, "<some ioctl>", char *, "-",
468bd670b35SErik Nordmark 			    arl_t *, (arl_t *)q->q_ptr);
469bd670b35SErik Nordmark 			putnext(q, mp);
470*8a06b3d6SToomas Soome 			break;
471bd670b35SErik Nordmark 		}
472bd670b35SErik Nordmark 		if ((mp1 = mp->b_cont) == 0)
473bd670b35SErik Nordmark 			err = EINVAL;
474bd670b35SErik Nordmark 		else if (ioc->ioc_cmd == SIOCSLIFNAME)
475bd670b35SErik Nordmark 			err = ip_sioctl_slifname_arp(q, mp1->b_rptr);
476bd670b35SErik Nordmark 		else if (ioc->ioc_cmd == IF_UNITSEL)
477bd670b35SErik Nordmark 			err = ip_sioctl_ifunitsel_arp(q, (int *)mp1->b_rptr);
478bd670b35SErik Nordmark 		if (err == 0)
479bd670b35SErik Nordmark 			miocack(q, mp, 0, 0);
480bd670b35SErik Nordmark 		else
481bd670b35SErik Nordmark 			miocnak(q, mp, 0, err);
482*8a06b3d6SToomas Soome 		break;
483bd670b35SErik Nordmark 	default:
484bd670b35SErik Nordmark 		DTRACE_PROBE4(arl__dlpi, char *, "arp_wput default",
485bd670b35SErik Nordmark 		    char *, "default mblk", char *, "-",
486bd670b35SErik Nordmark 		    arl_t *, (arl_t *)q->q_ptr);
487bd670b35SErik Nordmark 		putnext(q, mp);
488*8a06b3d6SToomas Soome 		break;
489bd670b35SErik Nordmark 	}
490*8a06b3d6SToomas Soome 	return (0);
491bd670b35SErik Nordmark }
492bd670b35SErik Nordmark 
493bd670b35SErik Nordmark /*
494bd670b35SErik Nordmark  * similar to ill_dlpi_pending(): verify that the received DLPI response
495bd670b35SErik Nordmark  * matches the one that is pending for the arl.
496bd670b35SErik Nordmark  */
497bd670b35SErik Nordmark static boolean_t
arl_dlpi_pending(arl_t * arl,t_uscalar_t prim)498bd670b35SErik Nordmark arl_dlpi_pending(arl_t *arl, t_uscalar_t prim)
499bd670b35SErik Nordmark {
500bd670b35SErik Nordmark 	t_uscalar_t pending;
501bd670b35SErik Nordmark 
502bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
503bd670b35SErik Nordmark 	if (arl->arl_dlpi_pending == prim) {
504bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
505bd670b35SErik Nordmark 		return (B_TRUE);
506bd670b35SErik Nordmark 	}
507bd670b35SErik Nordmark 
508bd670b35SErik Nordmark 	if (arl->arl_state_flags & ARL_CONDEMNED) {
509bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
510bd670b35SErik Nordmark 		return (B_FALSE);
511bd670b35SErik Nordmark 	}
512bd670b35SErik Nordmark 	pending = arl->arl_dlpi_pending;
513bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
514bd670b35SErik Nordmark 
515bd670b35SErik Nordmark 	if (pending == DL_PRIM_INVAL) {
516bd670b35SErik Nordmark 		ip0dbg(("arl_dlpi_pending unsolicited ack for %s on %s",
517bd670b35SErik Nordmark 		    dl_primstr(prim), arl->arl_name));
518bd670b35SErik Nordmark 	} else {
519bd670b35SErik Nordmark 		ip0dbg(("arl_dlpi_pending ack for %s on %s expect %s",
520bd670b35SErik Nordmark 		    dl_primstr(prim), arl->arl_name, dl_primstr(pending)));
521bd670b35SErik Nordmark 	}
522bd670b35SErik Nordmark 	return (B_FALSE);
523bd670b35SErik Nordmark }
524bd670b35SErik Nordmark 
525bd670b35SErik Nordmark /* DLPI messages, other than DL_UNITDATA_IND are handled here. */
526bd670b35SErik Nordmark static void
arp_rput_dlpi(queue_t * q,mblk_t * mp)527bd670b35SErik Nordmark arp_rput_dlpi(queue_t *q, mblk_t *mp)
528bd670b35SErik Nordmark {
529bd670b35SErik Nordmark 	arl_t		*arl = (arl_t *)q->q_ptr;
530bd670b35SErik Nordmark 	union DL_primitives *dlp;
531bd670b35SErik Nordmark 	t_uscalar_t	prim;
532bd670b35SErik Nordmark 	t_uscalar_t	reqprim = DL_PRIM_INVAL;
533bd670b35SErik Nordmark 	ill_t		*ill;
534bd670b35SErik Nordmark 
535bd670b35SErik Nordmark 	if ((mp->b_wptr - mp->b_rptr) < sizeof (dlp->dl_primitive)) {
536bd670b35SErik Nordmark 		putnext(q, mp);
537bd670b35SErik Nordmark 		return;
538bd670b35SErik Nordmark 	}
539bd670b35SErik Nordmark 	dlp = (union DL_primitives *)mp->b_rptr;
540bd670b35SErik Nordmark 	prim = dlp->dl_primitive;
541bd670b35SErik Nordmark 
542bd670b35SErik Nordmark 	/*
543bd670b35SErik Nordmark 	 * If we received an ACK but didn't send a request for it, then it
544bd670b35SErik Nordmark 	 * can't be part of any pending operation; discard up-front.
545bd670b35SErik Nordmark 	 */
546bd670b35SErik Nordmark 	switch (prim) {
547bd670b35SErik Nordmark 	case DL_ERROR_ACK:
548bd670b35SErik Nordmark 		/*
549bd670b35SErik Nordmark 		 * ce is confused about how DLPI works, so we have to interpret
550bd670b35SErik Nordmark 		 * an "error" on DL_NOTIFY_ACK (which we never could have sent)
551bd670b35SErik Nordmark 		 * as really meaning an error on DL_NOTIFY_REQ.
552bd670b35SErik Nordmark 		 *
553bd670b35SErik Nordmark 		 * Note that supporting DL_NOTIFY_REQ is optional, so printing
554bd670b35SErik Nordmark 		 * out an error message on the console isn't warranted except
555bd670b35SErik Nordmark 		 * for debug.
556bd670b35SErik Nordmark 		 */
557bd670b35SErik Nordmark 		if (dlp->error_ack.dl_error_primitive == DL_NOTIFY_ACK ||
558bd670b35SErik Nordmark 		    dlp->error_ack.dl_error_primitive == DL_NOTIFY_REQ) {
559bd670b35SErik Nordmark 			reqprim = DL_NOTIFY_REQ;
560bd670b35SErik Nordmark 		} else {
561bd670b35SErik Nordmark 			reqprim = dlp->error_ack.dl_error_primitive;
562bd670b35SErik Nordmark 		}
563bd670b35SErik Nordmark 		break;
564bd670b35SErik Nordmark 	case DL_INFO_ACK:
565bd670b35SErik Nordmark 		reqprim = DL_INFO_REQ;
566bd670b35SErik Nordmark 		break;
567bd670b35SErik Nordmark 	case DL_OK_ACK:
568bd670b35SErik Nordmark 		reqprim = dlp->ok_ack.dl_correct_primitive;
569bd670b35SErik Nordmark 		break;
570bd670b35SErik Nordmark 	case DL_BIND_ACK:
571bd670b35SErik Nordmark 		reqprim = DL_BIND_REQ;
572bd670b35SErik Nordmark 		break;
573bd670b35SErik Nordmark 	default:
574bd670b35SErik Nordmark 		DTRACE_PROBE2(rput_dl_badprim, arl_t *, arl,
575bd670b35SErik Nordmark 		    union DL_primitives *, dlp);
576bd670b35SErik Nordmark 		putnext(q, mp);
577bd670b35SErik Nordmark 		return;
578bd670b35SErik Nordmark 	}
579bd670b35SErik Nordmark 	if (reqprim == DL_PRIM_INVAL || !arl_dlpi_pending(arl, reqprim)) {
580bd670b35SErik Nordmark 		freemsg(mp);
581bd670b35SErik Nordmark 		return;
582bd670b35SErik Nordmark 	}
583bd670b35SErik Nordmark 	DTRACE_PROBE4(arl__dlpi, char *, "arp_rput_dlpi received",
584bd670b35SErik Nordmark 	    char *, dl_primstr(prim), char *, dl_primstr(reqprim),
585bd670b35SErik Nordmark 	    arl_t *, arl);
586bd670b35SErik Nordmark 
587bd670b35SErik Nordmark 	ASSERT(prim != DL_NOTIFY_IND);
588bd670b35SErik Nordmark 
589bd670b35SErik Nordmark 	ill = arl_to_ill(arl);
590bd670b35SErik Nordmark 
591bd670b35SErik Nordmark 	switch (reqprim) {
592bd670b35SErik Nordmark 	case DL_INFO_REQ:
593bd670b35SErik Nordmark 		/*
594bd670b35SErik Nordmark 		 * ill has not been set up yet for this case. This is the
595bd670b35SErik Nordmark 		 * DL_INFO_ACK for the first DL_INFO_REQ sent from
596bd670b35SErik Nordmark 		 * arp_modopen(). There should be no other arl_dlpi_deferred
597bd670b35SErik Nordmark 		 * messages pending. We initialize the arl here.
598bd670b35SErik Nordmark 		 */
599bd670b35SErik Nordmark 		ASSERT(!arl->arl_dlpi_style_set);
600bd670b35SErik Nordmark 		ASSERT(arl->arl_dlpi_pending == DL_INFO_REQ);
601bd670b35SErik Nordmark 		ASSERT(arl->arl_dlpi_deferred == NULL);
602bd670b35SErik Nordmark 		arl->arl_dlpi_pending = DL_PRIM_INVAL;
603bd670b35SErik Nordmark 		arp_ll_set_defaults(arl, mp);
604bd670b35SErik Nordmark 		freemsg(mp);
605bd670b35SErik Nordmark 		return;
606bd670b35SErik Nordmark 	case DL_UNBIND_REQ:
607bd670b35SErik Nordmark 		mutex_enter(&arl->arl_lock);
608bd670b35SErik Nordmark 		arl->arl_state_flags &= ~ARL_DL_UNBIND_IN_PROGRESS;
609bd670b35SErik Nordmark 		/*
610bd670b35SErik Nordmark 		 * This is not an error, so we don't set ARL_LL_DOWN
611bd670b35SErik Nordmark 		 */
612bd670b35SErik Nordmark 		arl->arl_state_flags &= ~ARL_LL_UP;
613bd670b35SErik Nordmark 		arl->arl_state_flags |= ARL_LL_UNBOUND;
614bd670b35SErik Nordmark 		if (arl->arl_state_flags & ARL_CONDEMNED) {
615bd670b35SErik Nordmark 			/*
616bd670b35SErik Nordmark 			 * if this is part of the unplumb the arl may
617bd670b35SErik Nordmark 			 * vaporize any moment after we cv_signal the
618bd670b35SErik Nordmark 			 * arl_cv so we reset arl_dlpi_pending here.
619bd670b35SErik Nordmark 			 * All other cases (including replumb) will
620bd670b35SErik Nordmark 			 * have the arl_dlpi_pending reset in
621bd670b35SErik Nordmark 			 * arp_dlpi_done.
622bd670b35SErik Nordmark 			 */
623bd670b35SErik Nordmark 			arl->arl_dlpi_pending = DL_PRIM_INVAL;
624bd670b35SErik Nordmark 		}
625bd670b35SErik Nordmark 		cv_signal(&arl->arl_cv);
626bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
627bd670b35SErik Nordmark 		break;
628bd670b35SErik Nordmark 	}
629bd670b35SErik Nordmark 	if (ill != NULL) {
630bd670b35SErik Nordmark 		/*
631bd670b35SErik Nordmark 		 * ill ref obtained by arl_to_ill()  will be released
632bd670b35SErik Nordmark 		 * by qwriter_ip()
633bd670b35SErik Nordmark 		 */
634bd670b35SErik Nordmark 		qwriter_ip(ill, ill->ill_wq, mp, arp_rput_dlpi_writer,
635bd670b35SErik Nordmark 		    CUR_OP, B_TRUE);
636bd670b35SErik Nordmark 		return;
637bd670b35SErik Nordmark 	}
638bd670b35SErik Nordmark 	freemsg(mp);
639bd670b35SErik Nordmark }
640bd670b35SErik Nordmark 
641bd670b35SErik Nordmark /*
642bd670b35SErik Nordmark  * Handling of DLPI messages that require exclusive access to the ipsq.
643bd670b35SErik Nordmark  */
644bd670b35SErik Nordmark /* ARGSUSED */
645bd670b35SErik Nordmark static void
arp_rput_dlpi_writer(ipsq_t * ipsq,queue_t * q,mblk_t * mp,void * dummy_arg)646bd670b35SErik Nordmark arp_rput_dlpi_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *dummy_arg)
647bd670b35SErik Nordmark {
648bd670b35SErik Nordmark 	union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
649bd670b35SErik Nordmark 	ill_t		*ill = (ill_t *)q->q_ptr;
650bd670b35SErik Nordmark 	arl_t		*arl = ill_to_arl(ill);
651bd670b35SErik Nordmark 
652bd670b35SErik Nordmark 	if (arl == NULL) {
653bd670b35SErik Nordmark 		/*
654bd670b35SErik Nordmark 		 * happens as a result arp_modclose triggering unbind.
655bd670b35SErik Nordmark 		 * arp_rput_dlpi will cv_signal the arl_cv and the modclose
656bd670b35SErik Nordmark 		 * will complete, but when it does ipsq_exit, the waiting
657bd670b35SErik Nordmark 		 * qwriter_ip gets into the ipsq but will find the arl null.
658bd670b35SErik Nordmark 		 * There should be no deferred messages in this case, so
659bd670b35SErik Nordmark 		 * just complete and exit.
660bd670b35SErik Nordmark 		 */
661bd670b35SErik Nordmark 		arp_cmd_done(ill, 0, DL_UNBIND_REQ);
662bd670b35SErik Nordmark 		freemsg(mp);
663bd670b35SErik Nordmark 		return;
664bd670b35SErik Nordmark 	}
665bd670b35SErik Nordmark 	switch (dlp->dl_primitive) {
666bd670b35SErik Nordmark 	case DL_ERROR_ACK:
667bd670b35SErik Nordmark 		switch (dlp->error_ack.dl_error_primitive) {
668bd670b35SErik Nordmark 		case DL_UNBIND_REQ:
669bd670b35SErik Nordmark 			mutex_enter(&arl->arl_lock);
670bd670b35SErik Nordmark 			arl->arl_state_flags &= ~ARL_DL_UNBIND_IN_PROGRESS;
671bd670b35SErik Nordmark 			arl->arl_state_flags &= ~ARL_LL_UP;
672bd670b35SErik Nordmark 			arl->arl_state_flags |= ARL_LL_UNBOUND;
673bd670b35SErik Nordmark 			arl->arl_state_flags |= ARL_LL_DOWN;
674bd670b35SErik Nordmark 			cv_signal(&arl->arl_cv);
675bd670b35SErik Nordmark 			mutex_exit(&arl->arl_lock);
676bd670b35SErik Nordmark 			break;
677bd670b35SErik Nordmark 		case DL_BIND_REQ:
678bd670b35SErik Nordmark 			mutex_enter(&arl->arl_lock);
679bd670b35SErik Nordmark 			arl->arl_state_flags &= ~ARL_LL_UP;
680bd670b35SErik Nordmark 			arl->arl_state_flags |= ARL_LL_DOWN;
681bd670b35SErik Nordmark 			arl->arl_state_flags |= ARL_LL_UNBOUND;
682bd670b35SErik Nordmark 			cv_signal(&arl->arl_cv);
683bd670b35SErik Nordmark 			mutex_exit(&arl->arl_lock);
684bd670b35SErik Nordmark 			break;
685bd670b35SErik Nordmark 		case DL_ATTACH_REQ:
686bd670b35SErik Nordmark 			break;
687bd670b35SErik Nordmark 		default:
688bd670b35SErik Nordmark 			/* If it's anything else, we didn't send it. */
689bd670b35SErik Nordmark 			arl_refrele(arl);
690bd670b35SErik Nordmark 			putnext(q, mp);
691bd670b35SErik Nordmark 			return;
692bd670b35SErik Nordmark 		}
693bd670b35SErik Nordmark 		break;
694bd670b35SErik Nordmark 	case DL_OK_ACK:
695bd670b35SErik Nordmark 		DTRACE_PROBE4(arl__dlpi, char *, "arp_rput_dlpi_writer ok",
696bd670b35SErik Nordmark 		    char *, dl_primstr(dlp->ok_ack.dl_correct_primitive),
697bd670b35SErik Nordmark 		    char *, dl_primstr(dlp->ok_ack.dl_correct_primitive),
698bd670b35SErik Nordmark 		    arl_t *, arl);
699bd670b35SErik Nordmark 		mutex_enter(&arl->arl_lock);
700bd670b35SErik Nordmark 		switch (dlp->ok_ack.dl_correct_primitive) {
701bd670b35SErik Nordmark 		case DL_UNBIND_REQ:
702bd670b35SErik Nordmark 		case DL_ATTACH_REQ:
703bd670b35SErik Nordmark 			break;
704bd670b35SErik Nordmark 		default:
705bd670b35SErik Nordmark 			ip0dbg(("Dropping unrecognized DL_OK_ACK for %s",
706bd670b35SErik Nordmark 			    dl_primstr(dlp->ok_ack.dl_correct_primitive)));
707bd670b35SErik Nordmark 			mutex_exit(&arl->arl_lock);
708bd670b35SErik Nordmark 			arl_refrele(arl);
709bd670b35SErik Nordmark 			freemsg(mp);
710bd670b35SErik Nordmark 			return;
711bd670b35SErik Nordmark 		}
712bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
713bd670b35SErik Nordmark 		break;
714bd670b35SErik Nordmark 	case DL_BIND_ACK:
715bd670b35SErik Nordmark 		DTRACE_PROBE2(rput_dl_bind, arl_t *, arl,
716bd670b35SErik Nordmark 		    dl_bind_ack_t *, &dlp->bind_ack);
717bd670b35SErik Nordmark 
718bd670b35SErik Nordmark 		mutex_enter(&arl->arl_lock);
719bd670b35SErik Nordmark 		ASSERT(arl->arl_state_flags & ARL_LL_BIND_PENDING);
720bd670b35SErik Nordmark 		arl->arl_state_flags &=
721bd670b35SErik Nordmark 		    ~(ARL_LL_BIND_PENDING|ARL_LL_DOWN|ARL_LL_UNBOUND);
722bd670b35SErik Nordmark 		arl->arl_state_flags |= ARL_LL_UP;
723bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
724bd670b35SErik Nordmark 		break;
725bd670b35SErik Nordmark 	case DL_UDERROR_IND:
726bd670b35SErik Nordmark 		DTRACE_PROBE2(rput_dl_uderror, arl_t *, arl,
727bd670b35SErik Nordmark 		    dl_uderror_ind_t *, &dlp->uderror_ind);
728bd670b35SErik Nordmark 		arl_refrele(arl);
729bd670b35SErik Nordmark 		putnext(q, mp);
730bd670b35SErik Nordmark 		return;
731bd670b35SErik Nordmark 	default:
732bd670b35SErik Nordmark 		DTRACE_PROBE2(rput_dl_badprim, arl_t *, arl,
733bd670b35SErik Nordmark 		    union DL_primitives *, dlp);
734bd670b35SErik Nordmark 		arl_refrele(arl);
735bd670b35SErik Nordmark 		putnext(q, mp);
736bd670b35SErik Nordmark 		return;
737bd670b35SErik Nordmark 	}
738bd670b35SErik Nordmark 	arp_dlpi_done(arl, ill);
739bd670b35SErik Nordmark 	arl_refrele(arl);
740bd670b35SErik Nordmark 	freemsg(mp);
741bd670b35SErik Nordmark }
742bd670b35SErik Nordmark 
743*8a06b3d6SToomas Soome int
arp_rput(queue_t * q,mblk_t * mp)744bd670b35SErik Nordmark arp_rput(queue_t *q, mblk_t *mp)
745bd670b35SErik Nordmark {
746bd670b35SErik Nordmark 	arl_t		*arl = q->q_ptr;
747bd670b35SErik Nordmark 	boolean_t	need_refrele = B_FALSE;
748bd670b35SErik Nordmark 
749bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
750bd670b35SErik Nordmark 	if (((arl->arl_state_flags &
751bd670b35SErik Nordmark 	    (ARL_CONDEMNED | ARL_LL_REPLUMBING)) != 0)) {
752bd670b35SErik Nordmark 		/*
753bd670b35SErik Nordmark 		 * Only allow high priority DLPI messages during unplumb or
754bd670b35SErik Nordmark 		 * replumb, and we don't take an arl_refcnt for that case.
755bd670b35SErik Nordmark 		 */
756bd670b35SErik Nordmark 		if (DB_TYPE(mp) != M_PCPROTO) {
757bd670b35SErik Nordmark 			mutex_exit(&arl->arl_lock);
758bd670b35SErik Nordmark 			freemsg(mp);
759*8a06b3d6SToomas Soome 			return (0);
760bd670b35SErik Nordmark 		}
761bd670b35SErik Nordmark 	} else {
762bd670b35SErik Nordmark 		arl_refhold_locked(arl);
763bd670b35SErik Nordmark 		need_refrele = B_TRUE;
764bd670b35SErik Nordmark 	}
765bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
766bd670b35SErik Nordmark 
767bd670b35SErik Nordmark 	switch (DB_TYPE(mp)) {
768bd670b35SErik Nordmark 	case M_PCPROTO:
769bd670b35SErik Nordmark 	case M_PROTO: {
770bd670b35SErik Nordmark 		ill_t *ill;
771bd670b35SErik Nordmark 
772bd670b35SErik Nordmark 		/*
773bd670b35SErik Nordmark 		 * could be one of
774bd670b35SErik Nordmark 		 * (i)   real message from the wire, (DLPI_DATA)
775bd670b35SErik Nordmark 		 * (ii)  DLPI message
776bd670b35SErik Nordmark 		 * Take a ref on the ill associated with this arl to
777bd670b35SErik Nordmark 		 * prevent the ill from being unplumbed until this thread
778bd670b35SErik Nordmark 		 * is done.
779bd670b35SErik Nordmark 		 */
780bd670b35SErik Nordmark 		if (IS_DLPI_DATA(mp)) {
781bd670b35SErik Nordmark 			ill = arl_to_ill(arl);
782bd670b35SErik Nordmark 			if (ill == NULL) {
783bd670b35SErik Nordmark 				arp_drop_packet("No ill", mp, ill);
784bd670b35SErik Nordmark 				break;
785bd670b35SErik Nordmark 			}
786bd670b35SErik Nordmark 			arp_process_packet(ill, mp);
787bd670b35SErik Nordmark 			ill_refrele(ill);
788bd670b35SErik Nordmark 			break;
789bd670b35SErik Nordmark 		}
790bd670b35SErik Nordmark 		/* Miscellaneous DLPI messages get shuffled off. */
791bd670b35SErik Nordmark 		arp_rput_dlpi(q, mp);
792bd670b35SErik Nordmark 		break;
793bd670b35SErik Nordmark 	}
794bd670b35SErik Nordmark 	case M_ERROR:
795bd670b35SErik Nordmark 	case M_HANGUP:
796bd670b35SErik Nordmark 		if (mp->b_rptr < mp->b_wptr)
797bd670b35SErik Nordmark 			arl->arl_error = (int)(*mp->b_rptr & 0xFF);
798bd670b35SErik Nordmark 		if (arl->arl_error == 0)
799bd670b35SErik Nordmark 			arl->arl_error = ENXIO;
800bd670b35SErik Nordmark 		freemsg(mp);
801bd670b35SErik Nordmark 		break;
802bd670b35SErik Nordmark 	default:
803bd670b35SErik Nordmark 		ip1dbg(("arp_rput other db type %x\n", DB_TYPE(mp)));
804bd670b35SErik Nordmark 		putnext(q, mp);
805bd670b35SErik Nordmark 		break;
806bd670b35SErik Nordmark 	}
807bd670b35SErik Nordmark 	if (need_refrele)
808bd670b35SErik Nordmark 		arl_refrele(arl);
809*8a06b3d6SToomas Soome 	return (0);
810bd670b35SErik Nordmark }
811bd670b35SErik Nordmark 
812bd670b35SErik Nordmark static void
arp_process_packet(ill_t * ill,mblk_t * mp)813bd670b35SErik Nordmark arp_process_packet(ill_t *ill, mblk_t *mp)
814bd670b35SErik Nordmark {
815*8a06b3d6SToomas Soome 	mblk_t		*mp1;
816bd670b35SErik Nordmark 	arh_t		*arh;
817bd670b35SErik Nordmark 	in_addr_t	src_paddr, dst_paddr;
818bd670b35SErik Nordmark 	uint32_t	hlen, plen;
819bd670b35SErik Nordmark 	boolean_t	is_probe;
820bd670b35SErik Nordmark 	int		op;
821bd670b35SErik Nordmark 	ncec_t		*dst_ncec, *src_ncec = NULL;
822bd670b35SErik Nordmark 	uchar_t		*src_haddr, *arhp, *dst_haddr, *dp, *sp;
823bd670b35SErik Nordmark 	int		err;
824bd670b35SErik Nordmark 	ip_stack_t	*ipst;
825bd670b35SErik Nordmark 	boolean_t	need_ill_refrele = B_FALSE;
826bd670b35SErik Nordmark 	nce_t		*nce;
827bd670b35SErik Nordmark 	uchar_t		*src_lladdr;
828bd670b35SErik Nordmark 	dl_unitdata_ind_t *dlui;
829bd670b35SErik Nordmark 	ip_recv_attr_t	iras;
830bd670b35SErik Nordmark 
831bd670b35SErik Nordmark 	ASSERT(ill != NULL);
832bd670b35SErik Nordmark 	if (ill->ill_flags & ILLF_NOARP) {
833bd670b35SErik Nordmark 		arp_drop_packet("Interface does not support ARP", mp, ill);
834bd670b35SErik Nordmark 		return;
835bd670b35SErik Nordmark 	}
836bd670b35SErik Nordmark 	ipst = ill->ill_ipst;
837bd670b35SErik Nordmark 	/*
838bd670b35SErik Nordmark 	 * What we should have at this point is a DL_UNITDATA_IND message
839bd670b35SErik Nordmark 	 * followed by an ARP packet.  We do some initial checks and then
840bd670b35SErik Nordmark 	 * get to work.
841bd670b35SErik Nordmark 	 */
842bd670b35SErik Nordmark 	dlui = (dl_unitdata_ind_t *)mp->b_rptr;
843bd670b35SErik Nordmark 	if (dlui->dl_group_address == 1) {
844bd670b35SErik Nordmark 		/*
845bd670b35SErik Nordmark 		 * multicast or broadcast  packet. Only accept on the ipmp
846bd670b35SErik Nordmark 		 * nominated interface for multicasts ('cast_ill').
847bd670b35SErik Nordmark 		 * If we have no cast_ill we are liberal and accept everything.
848bd670b35SErik Nordmark 		 */
849bd670b35SErik Nordmark 		if (IS_UNDER_IPMP(ill)) {
850bd670b35SErik Nordmark 			/* For an under ill_grp can change under lock */
851bd670b35SErik Nordmark 			rw_enter(&ipst->ips_ill_g_lock, RW_READER);
852bd670b35SErik Nordmark 			if (!ill->ill_nom_cast && ill->ill_grp != NULL &&
853bd670b35SErik Nordmark 			    ill->ill_grp->ig_cast_ill != NULL) {
854bd670b35SErik Nordmark 				rw_exit(&ipst->ips_ill_g_lock);
855bd670b35SErik Nordmark 				arp_drop_packet("Interface is not nominated "
856bd670b35SErik Nordmark 				    "for multicast sends and receives",
857bd670b35SErik Nordmark 				    mp, ill);
858bd670b35SErik Nordmark 				return;
859bd670b35SErik Nordmark 			}
860bd670b35SErik Nordmark 			rw_exit(&ipst->ips_ill_g_lock);
861bd670b35SErik Nordmark 		}
862bd670b35SErik Nordmark 	}
863bd670b35SErik Nordmark 	mp1 = mp->b_cont;
864bd670b35SErik Nordmark 	if (mp1 == NULL) {
865bd670b35SErik Nordmark 		arp_drop_packet("Missing ARP packet", mp, ill);
866bd670b35SErik Nordmark 		return;
867bd670b35SErik Nordmark 	}
868bd670b35SErik Nordmark 	if (mp1->b_cont != NULL) {
869bd670b35SErik Nordmark 		/* No fooling around with funny messages. */
870bd670b35SErik Nordmark 		if (!pullupmsg(mp1, -1)) {
871bd670b35SErik Nordmark 			arp_drop_packet("Funny message: pullup failed",
872bd670b35SErik Nordmark 			    mp, ill);
873bd670b35SErik Nordmark 			return;
874bd670b35SErik Nordmark 		}
875bd670b35SErik Nordmark 	}
876bd670b35SErik Nordmark 	arh = (arh_t *)mp1->b_rptr;
877bd670b35SErik Nordmark 	hlen = arh->arh_hlen;
878bd670b35SErik Nordmark 	plen = arh->arh_plen;
879bd670b35SErik Nordmark 	if (MBLKL(mp1) < ARH_FIXED_LEN + 2 * hlen + 2 * plen) {
880bd670b35SErik Nordmark 		arp_drop_packet("mblk len too small", mp, ill);
881bd670b35SErik Nordmark 		return;
882bd670b35SErik Nordmark 	}
883bd670b35SErik Nordmark 	/*
884bd670b35SErik Nordmark 	 * hlen 0 is used for RFC 1868 UnARP.
885bd670b35SErik Nordmark 	 *
886bd670b35SErik Nordmark 	 * Note that the rest of the code checks that hlen is what we expect
887bd670b35SErik Nordmark 	 * for this hardware address type, so might as well discard packets
888bd670b35SErik Nordmark 	 * here that don't match.
889bd670b35SErik Nordmark 	 */
890bd670b35SErik Nordmark 	if ((hlen > 0 && hlen != ill->ill_phys_addr_length) || plen == 0) {
891bd670b35SErik Nordmark 		DTRACE_PROBE2(rput_bogus, ill_t *, ill, mblk_t *, mp1);
892bd670b35SErik Nordmark 		arp_drop_packet("Bogus hlen or plen", mp, ill);
893bd670b35SErik Nordmark 		return;
894bd670b35SErik Nordmark 	}
895bd670b35SErik Nordmark 	/*
896bd670b35SErik Nordmark 	 * Historically, Solaris has been lenient about hardware type numbers.
897bd670b35SErik Nordmark 	 * We should check here, but don't.
898bd670b35SErik Nordmark 	 */
899bd670b35SErik Nordmark 	DTRACE_PROBE3(arp__physical__in__start, ill_t *, ill, arh_t *, arh,
900bd670b35SErik Nordmark 	    mblk_t *, mp);
901bd670b35SErik Nordmark 	/*
902bd670b35SErik Nordmark 	 * If ill is in an ipmp group, it will be the under ill. If we want
903bd670b35SErik Nordmark 	 * to report the packet as coming up the IPMP interface, we should
904bd670b35SErik Nordmark 	 * convert it to the ipmp ill.
905bd670b35SErik Nordmark 	 */
906bd670b35SErik Nordmark 	ARP_HOOK_IN(ipst->ips_arp_physical_in_event, ipst->ips_arp_physical_in,
907bd670b35SErik Nordmark 	    ill->ill_phyint->phyint_ifindex, arh, mp, mp1, ipst);
908bd670b35SErik Nordmark 	DTRACE_PROBE1(arp__physical__in__end, mblk_t *, mp);
909bd670b35SErik Nordmark 	if (mp == NULL)
910bd670b35SErik Nordmark 		return;
911bd670b35SErik Nordmark 	arhp = (uchar_t *)arh + ARH_FIXED_LEN;
912bd670b35SErik Nordmark 	src_haddr = arhp;			/* ar$sha */
913bd670b35SErik Nordmark 	arhp += hlen;
914bd670b35SErik Nordmark 	bcopy(arhp, &src_paddr, IP_ADDR_LEN);	/* ar$spa */
915bd670b35SErik Nordmark 	sp = arhp;
916bd670b35SErik Nordmark 	arhp += IP_ADDR_LEN;
917bd670b35SErik Nordmark 	dst_haddr = arhp;			/* ar$dha */
918bd670b35SErik Nordmark 	arhp += hlen;
919bd670b35SErik Nordmark 	bcopy(arhp, &dst_paddr, IP_ADDR_LEN);	/* ar$tpa */
920bd670b35SErik Nordmark 	dp = arhp;
921bd670b35SErik Nordmark 	op = BE16_TO_U16(arh->arh_operation);
922bd670b35SErik Nordmark 
923bd670b35SErik Nordmark 	DTRACE_PROBE2(ip__arp__input, (in_addr_t), src_paddr,
924bd670b35SErik Nordmark 	    (in_addr_t), dst_paddr);
925bd670b35SErik Nordmark 
926bd670b35SErik Nordmark 	/* Determine if this is just a probe */
927bd670b35SErik Nordmark 	is_probe = (src_paddr == INADDR_ANY);
928bd670b35SErik Nordmark 
92901685f97SSowmini Varadhan 	/*
93001685f97SSowmini Varadhan 	 * The following test for loopback is faster than
93101685f97SSowmini Varadhan 	 * IP_LOOPBACK_ADDR(), because it avoids any bitwise
93201685f97SSowmini Varadhan 	 * operations.
93301685f97SSowmini Varadhan 	 * Note that these addresses are always in network byte order
93401685f97SSowmini Varadhan 	 */
93501685f97SSowmini Varadhan 	if ((*(uint8_t *)&src_paddr) == IN_LOOPBACKNET ||
93601685f97SSowmini Varadhan 	    (*(uint8_t *)&dst_paddr) == IN_LOOPBACKNET ||
937c13c3653SSowmini Varadhan 	    CLASSD(src_paddr) || CLASSD(dst_paddr)) {
93801685f97SSowmini Varadhan 		arp_drop_packet("Martian IP addr", mp, ill);
93901685f97SSowmini Varadhan 		return;
94001685f97SSowmini Varadhan 	}
94101685f97SSowmini Varadhan 
942bd670b35SErik Nordmark 	/*
943bd670b35SErik Nordmark 	 * ira_ill is the only field used down the arp_notify path.
944bd670b35SErik Nordmark 	 */
945bd670b35SErik Nordmark 	bzero(&iras, sizeof (iras));
946bd670b35SErik Nordmark 	iras.ira_ill = iras.ira_rill = ill;
947bd670b35SErik Nordmark 	/*
948bd670b35SErik Nordmark 	 * RFC 826: first check if the <protocol, sender protocol address> is
949bd670b35SErik Nordmark 	 * in the cache, if there is a sender protocol address.  Note that this
950bd670b35SErik Nordmark 	 * step also handles resolutions based on source.
951bd670b35SErik Nordmark 	 */
952bd670b35SErik Nordmark 	/* Note: after here we need to freeb(mp) and freemsg(mp1) separately */
953bd670b35SErik Nordmark 	mp->b_cont = NULL;
954bd670b35SErik Nordmark 	if (is_probe) {
955bd670b35SErik Nordmark 		err = AR_NOTFOUND;
956bd670b35SErik Nordmark 	} else {
957bd670b35SErik Nordmark 		if (plen != 4) {
958bd670b35SErik Nordmark 			arp_drop_packet("bad protocol len", mp, ill);
959bd670b35SErik Nordmark 			return;
960bd670b35SErik Nordmark 		}
961bd670b35SErik Nordmark 		err = ip_nce_resolve_all(ill, src_haddr, hlen, &src_paddr,
962bd670b35SErik Nordmark 		    &src_ncec, op);
963bd670b35SErik Nordmark 		switch (err) {
964bd670b35SErik Nordmark 		case AR_BOGON:
965bd670b35SErik Nordmark 			ASSERT(src_ncec != NULL);
966bd670b35SErik Nordmark 			arp_notify(src_paddr, mp1, AR_CN_BOGON,
967bd670b35SErik Nordmark 			    &iras, src_ncec);
968bd670b35SErik Nordmark 			break;
969bd670b35SErik Nordmark 		case AR_FAILED:
970bd670b35SErik Nordmark 			arp_notify(src_paddr, mp1, AR_CN_FAILED, &iras,
971bd670b35SErik Nordmark 			    src_ncec);
972bd670b35SErik Nordmark 			break;
973bd670b35SErik Nordmark 		case AR_LOOPBACK:
974bd670b35SErik Nordmark 			DTRACE_PROBE2(rput_loopback, ill_t *, ill, arh_t *,
975bd670b35SErik Nordmark 			    arh);
976bd670b35SErik Nordmark 			freemsg(mp1);
977bd670b35SErik Nordmark 			break;
978bd670b35SErik Nordmark 		default:
979bd670b35SErik Nordmark 			goto update;
980bd670b35SErik Nordmark 		}
981bd670b35SErik Nordmark 		freemsg(mp);
982bd670b35SErik Nordmark 		if (src_ncec != NULL)
983bd670b35SErik Nordmark 			ncec_refrele(src_ncec);
984bd670b35SErik Nordmark 		return;
985bd670b35SErik Nordmark 	}
986bd670b35SErik Nordmark update:
987bd670b35SErik Nordmark 	/*
988bd670b35SErik Nordmark 	 * Now look up the destination address.  By RFC 826, we ignore the
989bd670b35SErik Nordmark 	 * packet at this step if the target isn't one of our addresses (i.e.,
990bd670b35SErik Nordmark 	 * one we have been asked to PUBLISH).  This is true even if the
991bd670b35SErik Nordmark 	 * target is something we're trying to resolve and the packet
992bd670b35SErik Nordmark 	 * is a response.
993bd670b35SErik Nordmark 	 */
994bd670b35SErik Nordmark 	dst_ncec = ncec_lookup_illgrp_v4(ill, &dst_paddr);
995bd670b35SErik Nordmark 	if (dst_ncec == NULL || !NCE_PUBLISH(dst_ncec)) {
996bd670b35SErik Nordmark 		/*
997bd670b35SErik Nordmark 		 * Let the client know if the source mapping has changed, even
998bd670b35SErik Nordmark 		 * if the destination provides no useful information for the
999bd670b35SErik Nordmark 		 * client.
1000bd670b35SErik Nordmark 		 */
1001bd670b35SErik Nordmark 		if (err == AR_CHANGED) {
1002bd670b35SErik Nordmark 			arp_notify(src_paddr, mp1, AR_CN_ANNOUNCE, &iras,
1003bd670b35SErik Nordmark 			    NULL);
1004bd670b35SErik Nordmark 			freemsg(mp);
1005bd670b35SErik Nordmark 		} else {
1006bd670b35SErik Nordmark 			freemsg(mp);
1007bd670b35SErik Nordmark 			arp_drop_packet("Target is not interesting", mp1, ill);
1008bd670b35SErik Nordmark 		}
1009bd670b35SErik Nordmark 		if (dst_ncec != NULL)
1010bd670b35SErik Nordmark 			ncec_refrele(dst_ncec);
1011bd670b35SErik Nordmark 		if (src_ncec != NULL)
1012bd670b35SErik Nordmark 			ncec_refrele(src_ncec);
1013bd670b35SErik Nordmark 		return;
1014bd670b35SErik Nordmark 	}
1015bd670b35SErik Nordmark 
1016bd670b35SErik Nordmark 	if (dst_ncec->ncec_flags & NCE_F_UNVERIFIED) {
1017bd670b35SErik Nordmark 		/*
1018bd670b35SErik Nordmark 		 * Check for a reflection.  Some misbehaving bridges will
1019bd670b35SErik Nordmark 		 * reflect our own transmitted packets back to us.
1020bd670b35SErik Nordmark 		 */
1021bd670b35SErik Nordmark 		ASSERT(NCE_PUBLISH(dst_ncec));
1022bd670b35SErik Nordmark 		if (hlen != dst_ncec->ncec_ill->ill_phys_addr_length) {
1023bd670b35SErik Nordmark 			ncec_refrele(dst_ncec);
1024bd670b35SErik Nordmark 			if (src_ncec != NULL)
1025bd670b35SErik Nordmark 				ncec_refrele(src_ncec);
1026bd670b35SErik Nordmark 			freemsg(mp);
1027bd670b35SErik Nordmark 			arp_drop_packet("bad arh_len", mp1, ill);
1028bd670b35SErik Nordmark 			return;
1029bd670b35SErik Nordmark 		}
1030bd670b35SErik Nordmark 		if (!nce_cmp_ll_addr(dst_ncec, src_haddr, hlen)) {
1031bd670b35SErik Nordmark 			DTRACE_PROBE3(rput_probe_reflected, ill_t *, ill,
1032bd670b35SErik Nordmark 			    arh_t *, arh, ncec_t *, dst_ncec);
1033bd670b35SErik Nordmark 			ncec_refrele(dst_ncec);
1034bd670b35SErik Nordmark 			if (src_ncec != NULL)
1035bd670b35SErik Nordmark 				ncec_refrele(src_ncec);
1036bd670b35SErik Nordmark 			freemsg(mp);
1037bd670b35SErik Nordmark 			arp_drop_packet("Reflected probe", mp1, ill);
1038bd670b35SErik Nordmark 			return;
1039bd670b35SErik Nordmark 		}
1040bd670b35SErik Nordmark 		/*
1041bd670b35SErik Nordmark 		 * Responses targeting our HW address that are not responses to
1042bd670b35SErik Nordmark 		 * our DAD probe must be ignored as they are related to requests
1043bd670b35SErik Nordmark 		 * sent before DAD was restarted.
1044bd670b35SErik Nordmark 		 */
1045bd670b35SErik Nordmark 		if (op == ARP_RESPONSE &&
1046bd670b35SErik Nordmark 		    (nce_cmp_ll_addr(dst_ncec, dst_haddr, hlen) == 0)) {
1047bd670b35SErik Nordmark 			ncec_refrele(dst_ncec);
1048bd670b35SErik Nordmark 			if (src_ncec != NULL)
1049bd670b35SErik Nordmark 				ncec_refrele(src_ncec);
1050bd670b35SErik Nordmark 			freemsg(mp);
1051bd670b35SErik Nordmark 			arp_drop_packet(
1052bd670b35SErik Nordmark 			    "Response to request that was sent before DAD",
1053bd670b35SErik Nordmark 			    mp1, ill);
1054bd670b35SErik Nordmark 			return;
1055bd670b35SErik Nordmark 		}
1056bd670b35SErik Nordmark 		/*
1057bd670b35SErik Nordmark 		 * Responses targeted to HW addresses which are not ours but
1058bd670b35SErik Nordmark 		 * sent to our unverified proto address are also conflicts.
1059bd670b35SErik Nordmark 		 * These may be reported by a proxy rather than the interface
1060bd670b35SErik Nordmark 		 * with the conflicting address, dst_paddr is in conflict
1061bd670b35SErik Nordmark 		 * rather than src_paddr. To ensure IP can locate the correct
1062bd670b35SErik Nordmark 		 * ipif to take down, it is necessary to copy dst_paddr to
1063bd670b35SErik Nordmark 		 * the src_paddr field before sending it to IP. The same is
1064bd670b35SErik Nordmark 		 * required for probes, where src_paddr will be INADDR_ANY.
1065bd670b35SErik Nordmark 		 */
1066bd670b35SErik Nordmark 		if (is_probe || op == ARP_RESPONSE) {
1067bd670b35SErik Nordmark 			bcopy(dp, sp, plen);
1068bd670b35SErik Nordmark 			arp_notify(src_paddr, mp1, AR_CN_FAILED, &iras,
1069bd670b35SErik Nordmark 			    NULL);
1070bd670b35SErik Nordmark 			ncec_delete(dst_ncec);
1071bd670b35SErik Nordmark 		} else if (err == AR_CHANGED) {
1072bd670b35SErik Nordmark 			arp_notify(src_paddr, mp1, AR_CN_ANNOUNCE, &iras,
1073bd670b35SErik Nordmark 			    NULL);
1074bd670b35SErik Nordmark 		} else {
1075bd670b35SErik Nordmark 			DTRACE_PROBE3(rput_request_unverified,
1076bd670b35SErik Nordmark 			    ill_t *, ill, arh_t *, arh, ncec_t *, dst_ncec);
1077bd670b35SErik Nordmark 			arp_drop_packet("Unverified request", mp1, ill);
1078bd670b35SErik Nordmark 		}
1079bd670b35SErik Nordmark 		freemsg(mp);
1080bd670b35SErik Nordmark 		ncec_refrele(dst_ncec);
1081bd670b35SErik Nordmark 		if (src_ncec != NULL)
1082bd670b35SErik Nordmark 			ncec_refrele(src_ncec);
1083bd670b35SErik Nordmark 		return;
1084bd670b35SErik Nordmark 	}
1085bd670b35SErik Nordmark 	/*
1086bd670b35SErik Nordmark 	 * If it's a request, then we reply to this, and if we think the
1087bd670b35SErik Nordmark 	 * sender's unknown, then we create an entry to avoid unnecessary ARPs.
1088bd670b35SErik Nordmark 	 * The design assumption is that someone ARPing us is likely to send us
1089bd670b35SErik Nordmark 	 * a packet soon, and that we'll want to reply to it.
1090bd670b35SErik Nordmark 	 */
1091bd670b35SErik Nordmark 	if (op == ARP_REQUEST) {
1092bd670b35SErik Nordmark 		const uchar_t *nce_hwaddr;
1093bd670b35SErik Nordmark 		struct in_addr nce_paddr;
1094bd670b35SErik Nordmark 		clock_t now;
1095bd670b35SErik Nordmark 		ill_t *under_ill = ill;
1096bd670b35SErik Nordmark 		boolean_t send_unicast = B_TRUE;
1097bd670b35SErik Nordmark 
1098bd670b35SErik Nordmark 		ASSERT(NCE_PUBLISH(dst_ncec));
1099bd670b35SErik Nordmark 
1100bd670b35SErik Nordmark 		if ((dst_ncec->ncec_flags & (NCE_F_BCAST|NCE_F_MCAST)) != 0) {
1101bd670b35SErik Nordmark 			/*
1102bd670b35SErik Nordmark 			 * Ignore senders who are deliberately or accidentally
1103bd670b35SErik Nordmark 			 * confused.
1104bd670b35SErik Nordmark 			 */
1105bd670b35SErik Nordmark 			goto bail;
1106bd670b35SErik Nordmark 		}
1107bd670b35SErik Nordmark 
1108bd670b35SErik Nordmark 		if (!is_probe && err == AR_NOTFOUND) {
1109bd670b35SErik Nordmark 			ASSERT(src_ncec == NULL);
1110bd670b35SErik Nordmark 
1111bd670b35SErik Nordmark 			if (IS_UNDER_IPMP(under_ill)) {
1112bd670b35SErik Nordmark 				/*
1113bd670b35SErik Nordmark 				 * create the ncec for the sender on ipmp_ill.
1114bd670b35SErik Nordmark 				 * We pass in the ipmp_ill itself to avoid
1115bd670b35SErik Nordmark 				 * creating an nce_t on the under_ill.
1116bd670b35SErik Nordmark 				 */
1117bd670b35SErik Nordmark 				ill = ipmp_ill_hold_ipmp_ill(under_ill);
1118bd670b35SErik Nordmark 				if (ill == NULL)
1119bd670b35SErik Nordmark 					ill = under_ill;
1120bd670b35SErik Nordmark 				else
1121bd670b35SErik Nordmark 					need_ill_refrele = B_TRUE;
1122bd670b35SErik Nordmark 			}
1123bd670b35SErik Nordmark 
1124bd670b35SErik Nordmark 			err = nce_lookup_then_add_v4(ill, src_haddr, hlen,
1125bd670b35SErik Nordmark 			    &src_paddr, 0, ND_STALE, &nce);
1126bd670b35SErik Nordmark 
1127bd670b35SErik Nordmark 			switch (err) {
1128bd670b35SErik Nordmark 			case 0:
1129bd670b35SErik Nordmark 			case EEXIST:
1130bd670b35SErik Nordmark 				ip1dbg(("added ncec %p in state %d ill %s\n",
1131bd670b35SErik Nordmark 				    (void *)src_ncec, src_ncec->ncec_state,
1132bd670b35SErik Nordmark 				    ill->ill_name));
1133bd670b35SErik Nordmark 				src_ncec = nce->nce_common;
1134bd670b35SErik Nordmark 				break;
1135bd670b35SErik Nordmark 			default:
1136bd670b35SErik Nordmark 				/*
1137bd670b35SErik Nordmark 				 * Either no memory, or the outgoing interface
1138bd670b35SErik Nordmark 				 * is in the process of down/unplumb. In the
1139bd670b35SErik Nordmark 				 * latter case, we will fail the send anyway,
1140bd670b35SErik Nordmark 				 * and in the former case, we should try to send
1141bd670b35SErik Nordmark 				 * the ARP response.
1142bd670b35SErik Nordmark 				 */
1143bd670b35SErik Nordmark 				src_lladdr = src_haddr;
1144bd670b35SErik Nordmark 				goto send_response;
1145bd670b35SErik Nordmark 			}
1146bd670b35SErik Nordmark 			ncec_refhold(src_ncec);
1147bd670b35SErik Nordmark 			nce_refrele(nce);
1148bd670b35SErik Nordmark 			/* set up cleanup interval on ncec */
1149bd670b35SErik Nordmark 		}
1150bd670b35SErik Nordmark 
1151bd670b35SErik Nordmark 		/*
1152bd670b35SErik Nordmark 		 * This implements periodic address defense based on a modified
1153bd670b35SErik Nordmark 		 * version of the RFC 3927 requirements.  Instead of sending a
1154bd670b35SErik Nordmark 		 * broadcasted reply every time, as demanded by the RFC, we
1155bd670b35SErik Nordmark 		 * send at most one broadcast reply per arp_broadcast_interval.
1156bd670b35SErik Nordmark 		 */
1157bd670b35SErik Nordmark 		now = ddi_get_lbolt();
1158bd670b35SErik Nordmark 		if ((now - dst_ncec->ncec_last_time_defended) >
1159bd670b35SErik Nordmark 		    MSEC_TO_TICK(ipst->ips_ipv4_dad_announce_interval)) {
1160bd670b35SErik Nordmark 			dst_ncec->ncec_last_time_defended = now;
1161bd670b35SErik Nordmark 			/*
1162bd670b35SErik Nordmark 			 * If this is one of the long-suffering entries,
1163bd670b35SErik Nordmark 			 * pull it out now.  It no longer needs separate
1164bd670b35SErik Nordmark 			 * defense, because we're now doing that with this
1165bd670b35SErik Nordmark 			 * broadcasted reply.
1166bd670b35SErik Nordmark 			 */
1167bd670b35SErik Nordmark 			dst_ncec->ncec_flags &= ~NCE_F_DELAYED;
1168bd670b35SErik Nordmark 			send_unicast = B_FALSE;
1169bd670b35SErik Nordmark 		}
1170bd670b35SErik Nordmark 		if (src_ncec != NULL && send_unicast) {
1171bd670b35SErik Nordmark 			src_lladdr = src_ncec->ncec_lladdr;
1172bd670b35SErik Nordmark 		} else {
1173bd670b35SErik Nordmark 			src_lladdr = under_ill->ill_bcast_mp->b_rptr +
1174bd670b35SErik Nordmark 			    NCE_LL_ADDR_OFFSET(under_ill);
1175bd670b35SErik Nordmark 		}
1176bd670b35SErik Nordmark send_response:
1177bd670b35SErik Nordmark 		nce_hwaddr = dst_ncec->ncec_lladdr;
1178bd670b35SErik Nordmark 		IN6_V4MAPPED_TO_INADDR(&dst_ncec->ncec_addr, &nce_paddr);
1179bd670b35SErik Nordmark 
1180bd670b35SErik Nordmark 		(void) arp_output(under_ill, ARP_RESPONSE,
1181bd670b35SErik Nordmark 		    nce_hwaddr, (uchar_t *)&nce_paddr, src_haddr,
1182bd670b35SErik Nordmark 		    (uchar_t *)&src_paddr, src_lladdr);
1183bd670b35SErik Nordmark 	}
1184bd670b35SErik Nordmark bail:
1185bd670b35SErik Nordmark 	if (dst_ncec != NULL) {
1186bd670b35SErik Nordmark 		ncec_refrele(dst_ncec);
1187bd670b35SErik Nordmark 	}
1188bd670b35SErik Nordmark 	if (src_ncec != NULL) {
1189bd670b35SErik Nordmark 		ncec_refrele(src_ncec);
1190bd670b35SErik Nordmark 	}
1191bd670b35SErik Nordmark 	if (err == AR_CHANGED) {
1192bd670b35SErik Nordmark 		mp->b_cont = NULL;
1193bd670b35SErik Nordmark 		arp_notify(src_paddr, mp1, AR_CN_ANNOUNCE, &iras, NULL);
1194bd670b35SErik Nordmark 		mp1 = NULL;
1195bd670b35SErik Nordmark 	}
1196bd670b35SErik Nordmark 	if (need_ill_refrele)
1197bd670b35SErik Nordmark 		ill_refrele(ill);
1198bd670b35SErik Nordmark done:
1199bd670b35SErik Nordmark 	freemsg(mp);
1200bd670b35SErik Nordmark 	freemsg(mp1);
1201bd670b35SErik Nordmark }
1202bd670b35SErik Nordmark 
1203bd670b35SErik Nordmark /*
1204bd670b35SErik Nordmark  * Basic initialization of the arl_t and the arl_common structure shared with
1205bd670b35SErik Nordmark  * the ill_t that is done after SLIFNAME/IF_UNITSEL.
1206bd670b35SErik Nordmark  */
1207bd670b35SErik Nordmark static int
arl_ill_init(arl_t * arl,char * ill_name)1208bd670b35SErik Nordmark arl_ill_init(arl_t *arl, char *ill_name)
1209bd670b35SErik Nordmark {
1210bd670b35SErik Nordmark 	ill_t *ill;
1211bd670b35SErik Nordmark 	arl_ill_common_t *ai;
1212bd670b35SErik Nordmark 
1213bd670b35SErik Nordmark 	ill = ill_lookup_on_name(ill_name, B_FALSE, B_FALSE, B_FALSE,
1214bd670b35SErik Nordmark 	    arl->arl_ipst);
1215bd670b35SErik Nordmark 
1216bd670b35SErik Nordmark 	if (ill == NULL)
1217bd670b35SErik Nordmark 		return (ENXIO);
1218bd670b35SErik Nordmark 
1219bd670b35SErik Nordmark 	/*
1220bd670b35SErik Nordmark 	 * By the time we set up the arl, we expect the ETHERTYPE_IP
1221bd670b35SErik Nordmark 	 * stream to be fully bound and attached. So we copy/verify
1222bd670b35SErik Nordmark 	 * relevant information as possible from/against the ill.
1223bd670b35SErik Nordmark 	 *
1224bd670b35SErik Nordmark 	 * The following should have been set up in arp_ll_set_defaults()
1225bd670b35SErik Nordmark 	 * after the first DL_INFO_ACK was received.
1226bd670b35SErik Nordmark 	 */
1227bd670b35SErik Nordmark 	ASSERT(arl->arl_phys_addr_length == ill->ill_phys_addr_length);
1228bd670b35SErik Nordmark 	ASSERT(arl->arl_sap == ETHERTYPE_ARP);
1229bd670b35SErik Nordmark 	ASSERT(arl->arl_mactype == ill->ill_mactype);
1230bd670b35SErik Nordmark 	ASSERT(arl->arl_sap_length == ill->ill_sap_length);
1231bd670b35SErik Nordmark 
1232bd670b35SErik Nordmark 	ai =  kmem_zalloc(sizeof (*ai), KM_SLEEP);
1233bd670b35SErik Nordmark 	mutex_enter(&ill->ill_lock);
1234bd670b35SErik Nordmark 	/* First ensure that the ill is not CONDEMNED.  */
1235bd670b35SErik Nordmark 	if (ill->ill_state_flags & ILL_CONDEMNED) {
1236bd670b35SErik Nordmark 		mutex_exit(&ill->ill_lock);
1237bd670b35SErik Nordmark 		ill_refrele(ill);
1238bd670b35SErik Nordmark 		kmem_free(ai, sizeof (*ai));
1239bd670b35SErik Nordmark 		return (ENXIO);
1240bd670b35SErik Nordmark 	}
1241bd670b35SErik Nordmark 	if (ill->ill_common != NULL || arl->arl_common != NULL) {
1242bd670b35SErik Nordmark 		mutex_exit(&ill->ill_lock);
1243bd670b35SErik Nordmark 		ip0dbg(("%s: PPA already exists", ill->ill_name));
1244bd670b35SErik Nordmark 		ill_refrele(ill);
1245bd670b35SErik Nordmark 		kmem_free(ai, sizeof (*ai));
1246bd670b35SErik Nordmark 		return (EEXIST);
1247bd670b35SErik Nordmark 	}
1248bd670b35SErik Nordmark 	mutex_init(&ai->ai_lock, NULL, MUTEX_DEFAULT, NULL);
1249bd670b35SErik Nordmark 	ai->ai_arl = arl;
1250bd670b35SErik Nordmark 	ai->ai_ill = ill;
1251bd670b35SErik Nordmark 	ill->ill_common = ai;
1252bd670b35SErik Nordmark 	arl->arl_common = ai;
1253bd670b35SErik Nordmark 	mutex_exit(&ill->ill_lock);
1254bd670b35SErik Nordmark 	(void) strlcpy(arl->arl_name, ill->ill_name, LIFNAMSIZ);
1255bd670b35SErik Nordmark 	arl->arl_name_length = ill->ill_name_length;
1256bd670b35SErik Nordmark 	ill_refrele(ill);
1257bd670b35SErik Nordmark 	arp_ifname_notify(arl);
1258bd670b35SErik Nordmark 	return (0);
1259bd670b35SErik Nordmark }
1260bd670b35SErik Nordmark 
1261bd670b35SErik Nordmark /* Allocate and do common initializations for DLPI messages. */
1262bd670b35SErik Nordmark static mblk_t *
ip_ar_dlpi_comm(t_uscalar_t prim,size_t size)1263bd670b35SErik Nordmark ip_ar_dlpi_comm(t_uscalar_t prim, size_t size)
1264bd670b35SErik Nordmark {
1265bd670b35SErik Nordmark 	mblk_t  *mp;
1266bd670b35SErik Nordmark 
1267bd670b35SErik Nordmark 	if ((mp = allocb(size, BPRI_HI)) == NULL)
1268bd670b35SErik Nordmark 		return (NULL);
1269bd670b35SErik Nordmark 
1270bd670b35SErik Nordmark 	/*
1271bd670b35SErik Nordmark 	 * DLPIv2 says that DL_INFO_REQ and DL_TOKEN_REQ (the latter
1272bd670b35SErik Nordmark 	 * of which we don't seem to use) are sent with M_PCPROTO, and
1273bd670b35SErik Nordmark 	 * that other DLPI are M_PROTO.
1274bd670b35SErik Nordmark 	 */
1275bd670b35SErik Nordmark 	DB_TYPE(mp) = (prim == DL_INFO_REQ) ? M_PCPROTO : M_PROTO;
1276bd670b35SErik Nordmark 
1277bd670b35SErik Nordmark 	mp->b_wptr = mp->b_rptr + size;
1278bd670b35SErik Nordmark 	bzero(mp->b_rptr, size);
1279bd670b35SErik Nordmark 	DL_PRIM(mp) = prim;
1280bd670b35SErik Nordmark 	return (mp);
1281bd670b35SErik Nordmark }
1282bd670b35SErik Nordmark 
1283bd670b35SErik Nordmark 
1284bd670b35SErik Nordmark int
ip_sioctl_ifunitsel_arp(queue_t * q,int * ppa)1285bd670b35SErik Nordmark ip_sioctl_ifunitsel_arp(queue_t *q, int *ppa)
1286bd670b35SErik Nordmark {
1287bd670b35SErik Nordmark 	arl_t *arl;
1288bd670b35SErik Nordmark 	char *cp, ill_name[LIFNAMSIZ];
1289bd670b35SErik Nordmark 
1290bd670b35SErik Nordmark 	if (q->q_next == NULL)
1291bd670b35SErik Nordmark 		return (EINVAL);
1292bd670b35SErik Nordmark 
1293bd670b35SErik Nordmark 	do {
1294bd670b35SErik Nordmark 		q = q->q_next;
1295bd670b35SErik Nordmark 	} while (q->q_next != NULL);
1296bd670b35SErik Nordmark 	cp = q->q_qinfo->qi_minfo->mi_idname;
1297bd670b35SErik Nordmark 
1298bd670b35SErik Nordmark 	arl = (arl_t *)q->q_ptr;
1299bd670b35SErik Nordmark 	(void) snprintf(ill_name, sizeof (ill_name), "%s%d", cp, *ppa);
1300bd670b35SErik Nordmark 	arl->arl_ppa = *ppa;
1301bd670b35SErik Nordmark 	return (arl_ill_init(arl, ill_name));
1302bd670b35SErik Nordmark }
1303bd670b35SErik Nordmark 
1304bd670b35SErik Nordmark int
ip_sioctl_slifname_arp(queue_t * q,void * lifreq)1305bd670b35SErik Nordmark ip_sioctl_slifname_arp(queue_t *q, void *lifreq)
1306bd670b35SErik Nordmark {
1307bd670b35SErik Nordmark 	arl_t *arl;
1308bd670b35SErik Nordmark 	struct lifreq *lifr = lifreq;
1309bd670b35SErik Nordmark 
1310bd670b35SErik Nordmark 	/* ioctl not valid when IP opened as a device */
1311bd670b35SErik Nordmark 	if (q->q_next == NULL)
1312bd670b35SErik Nordmark 		return (EINVAL);
1313bd670b35SErik Nordmark 
1314bd670b35SErik Nordmark 	arl = (arl_t *)q->q_ptr;
1315bd670b35SErik Nordmark 	arl->arl_ppa = lifr->lifr_ppa;
1316bd670b35SErik Nordmark 	return (arl_ill_init(arl, lifr->lifr_name));
1317bd670b35SErik Nordmark }
1318bd670b35SErik Nordmark 
1319bd670b35SErik Nordmark arl_t *
ill_to_arl(ill_t * ill)1320bd670b35SErik Nordmark ill_to_arl(ill_t *ill)
1321bd670b35SErik Nordmark {
1322bd670b35SErik Nordmark 	arl_ill_common_t *ai = ill->ill_common;
1323bd670b35SErik Nordmark 	arl_t *arl = NULL;
1324bd670b35SErik Nordmark 
1325bd670b35SErik Nordmark 	if (ai == NULL)
1326bd670b35SErik Nordmark 		return (NULL);
1327bd670b35SErik Nordmark 	/*
1328bd670b35SErik Nordmark 	 * Find the arl_t that corresponds to this ill_t from the shared
1329bd670b35SErik Nordmark 	 * ill_common structure. We can safely access the ai here as it
1330bd670b35SErik Nordmark 	 * will only be freed in arp_modclose() after we have become
1331bd670b35SErik Nordmark 	 * single-threaded.
1332bd670b35SErik Nordmark 	 */
1333bd670b35SErik Nordmark 	mutex_enter(&ai->ai_lock);
1334bd670b35SErik Nordmark 	if ((arl = ai->ai_arl) != NULL) {
1335bd670b35SErik Nordmark 		mutex_enter(&arl->arl_lock);
1336bd670b35SErik Nordmark 		if (!(arl->arl_state_flags & ARL_CONDEMNED)) {
1337bd670b35SErik Nordmark 			arl_refhold_locked(arl);
1338bd670b35SErik Nordmark 			mutex_exit(&arl->arl_lock);
1339bd670b35SErik Nordmark 		} else {
1340bd670b35SErik Nordmark 			mutex_exit(&arl->arl_lock);
1341bd670b35SErik Nordmark 			arl = NULL;
1342bd670b35SErik Nordmark 		}
1343bd670b35SErik Nordmark 	}
1344bd670b35SErik Nordmark 	mutex_exit(&ai->ai_lock);
1345bd670b35SErik Nordmark 	return (arl);
1346bd670b35SErik Nordmark }
1347bd670b35SErik Nordmark 
1348bd670b35SErik Nordmark ill_t *
arl_to_ill(arl_t * arl)1349bd670b35SErik Nordmark arl_to_ill(arl_t *arl)
1350bd670b35SErik Nordmark {
1351bd670b35SErik Nordmark 	arl_ill_common_t *ai = arl->arl_common;
1352bd670b35SErik Nordmark 	ill_t *ill = NULL;
1353bd670b35SErik Nordmark 
1354bd670b35SErik Nordmark 	if (ai == NULL) {
1355bd670b35SErik Nordmark 		/*
1356bd670b35SErik Nordmark 		 * happens when the arp stream is just being opened, and
1357bd670b35SErik Nordmark 		 * arl_ill_init has not been executed yet.
1358bd670b35SErik Nordmark 		 */
1359bd670b35SErik Nordmark 		return (NULL);
1360bd670b35SErik Nordmark 	}
1361bd670b35SErik Nordmark 	/*
1362bd670b35SErik Nordmark 	 * Find the ill_t that corresponds to this arl_t from the shared
1363bd670b35SErik Nordmark 	 * arl_common structure. We can safely access the ai here as it
1364bd670b35SErik Nordmark 	 * will only be freed in arp_modclose() after we have become
1365bd670b35SErik Nordmark 	 * single-threaded.
1366bd670b35SErik Nordmark 	 */
1367bd670b35SErik Nordmark 	mutex_enter(&ai->ai_lock);
1368bd670b35SErik Nordmark 	if ((ill = ai->ai_ill) != NULL) {
1369bd670b35SErik Nordmark 		mutex_enter(&ill->ill_lock);
1370bd670b35SErik Nordmark 		if (!ILL_IS_CONDEMNED(ill)) {
1371bd670b35SErik Nordmark 			ill_refhold_locked(ill);
1372bd670b35SErik Nordmark 			mutex_exit(&ill->ill_lock);
1373bd670b35SErik Nordmark 		} else {
1374bd670b35SErik Nordmark 			mutex_exit(&ill->ill_lock);
1375bd670b35SErik Nordmark 			ill = NULL;
1376bd670b35SErik Nordmark 		}
1377bd670b35SErik Nordmark 	}
1378bd670b35SErik Nordmark 	mutex_exit(&ai->ai_lock);
1379bd670b35SErik Nordmark 	return (ill);
1380bd670b35SErik Nordmark }
1381bd670b35SErik Nordmark 
1382bd670b35SErik Nordmark int
arp_ll_up(ill_t * ill)1383bd670b35SErik Nordmark arp_ll_up(ill_t *ill)
1384bd670b35SErik Nordmark {
1385bd670b35SErik Nordmark 	mblk_t	*attach_mp = NULL;
1386bd670b35SErik Nordmark 	mblk_t	*bind_mp = NULL;
1387bd670b35SErik Nordmark 	mblk_t	*unbind_mp = NULL;
1388*8a06b3d6SToomas Soome 	arl_t	*arl;
1389bd670b35SErik Nordmark 
1390bd670b35SErik Nordmark 	ASSERT(IAM_WRITER_ILL(ill));
1391bd670b35SErik Nordmark 	arl = ill_to_arl(ill);
1392bd670b35SErik Nordmark 
1393bd670b35SErik Nordmark 	DTRACE_PROBE2(ill__downup, char *, "arp_ll_up", ill_t *, ill);
1394bd670b35SErik Nordmark 	if (arl == NULL)
1395bd670b35SErik Nordmark 		return (ENXIO);
1396bd670b35SErik Nordmark 	DTRACE_PROBE2(arl__downup, char *, "arp_ll_up", arl_t *, arl);
1397bd670b35SErik Nordmark 	if ((arl->arl_state_flags & ARL_LL_UP) != 0) {
1398bd670b35SErik Nordmark 		arl_refrele(arl);
1399bd670b35SErik Nordmark 		return (0);
1400bd670b35SErik Nordmark 	}
1401bd670b35SErik Nordmark 	if (arl->arl_needs_attach) { /* DL_STYLE2 */
1402bd670b35SErik Nordmark 		attach_mp =
1403bd670b35SErik Nordmark 		    ip_ar_dlpi_comm(DL_ATTACH_REQ, sizeof (dl_attach_req_t));
1404bd670b35SErik Nordmark 		if (attach_mp == NULL)
1405bd670b35SErik Nordmark 			goto bad;
1406bd670b35SErik Nordmark 		((dl_attach_req_t *)attach_mp->b_rptr)->dl_ppa = arl->arl_ppa;
1407bd670b35SErik Nordmark 	}
1408bd670b35SErik Nordmark 
1409bd670b35SErik Nordmark 	/* Allocate and initialize a bind message. */
1410bd670b35SErik Nordmark 	bind_mp = ip_ar_dlpi_comm(DL_BIND_REQ, sizeof (dl_bind_req_t));
1411bd670b35SErik Nordmark 	if (bind_mp == NULL)
1412bd670b35SErik Nordmark 		goto bad;
1413bd670b35SErik Nordmark 	((dl_bind_req_t *)bind_mp->b_rptr)->dl_sap = ETHERTYPE_ARP;
1414bd670b35SErik Nordmark 	((dl_bind_req_t *)bind_mp->b_rptr)->dl_service_mode = DL_CLDLS;
1415bd670b35SErik Nordmark 
1416bd670b35SErik Nordmark 	unbind_mp = ip_ar_dlpi_comm(DL_UNBIND_REQ, sizeof (dl_unbind_req_t));
1417bd670b35SErik Nordmark 	if (unbind_mp == NULL)
1418bd670b35SErik Nordmark 		goto bad;
1419bd670b35SErik Nordmark 	if (arl->arl_needs_attach) {
1420bd670b35SErik Nordmark 		arp_dlpi_send(arl, attach_mp);
1421bd670b35SErik Nordmark 	}
1422bd670b35SErik Nordmark 	arl->arl_unbind_mp = unbind_mp;
1423bd670b35SErik Nordmark 
1424bd670b35SErik Nordmark 	arl->arl_state_flags |= ARL_LL_BIND_PENDING;
1425bd670b35SErik Nordmark 	arp_dlpi_send(arl, bind_mp);
1426bd670b35SErik Nordmark 	arl_refrele(arl);
1427bd670b35SErik Nordmark 	return (EINPROGRESS);
1428bd670b35SErik Nordmark 
1429bd670b35SErik Nordmark bad:
1430bd670b35SErik Nordmark 	freemsg(attach_mp);
1431bd670b35SErik Nordmark 	freemsg(bind_mp);
1432bd670b35SErik Nordmark 	freemsg(unbind_mp);
1433bd670b35SErik Nordmark 	arl_refrele(arl);
1434bd670b35SErik Nordmark 	return (ENOMEM);
1435bd670b35SErik Nordmark }
1436bd670b35SErik Nordmark 
1437bd670b35SErik Nordmark /*
1438bd670b35SErik Nordmark  * consumes/frees mp
1439bd670b35SErik Nordmark  */
1440bd670b35SErik Nordmark static void
arp_notify(in_addr_t src,mblk_t * mp,uint32_t arcn_code,ip_recv_attr_t * ira,ncec_t * ncec)1441bd670b35SErik Nordmark arp_notify(in_addr_t src, mblk_t *mp, uint32_t arcn_code,
1442bd670b35SErik Nordmark     ip_recv_attr_t *ira, ncec_t *ncec)
1443bd670b35SErik Nordmark {
1444bd670b35SErik Nordmark 	char		hbuf[MAC_STR_LEN];
1445bd670b35SErik Nordmark 	char		sbuf[INET_ADDRSTRLEN];
1446bd670b35SErik Nordmark 	ill_t		*ill = ira->ira_ill;
1447bd670b35SErik Nordmark 	ip_stack_t	*ipst = ill->ill_ipst;
1448bd670b35SErik Nordmark 	arh_t		*arh = (arh_t *)mp->b_rptr;
1449bd670b35SErik Nordmark 
1450bd670b35SErik Nordmark 	switch (arcn_code) {
1451bd670b35SErik Nordmark 	case AR_CN_BOGON:
1452bd670b35SErik Nordmark 		/*
1453bd670b35SErik Nordmark 		 * Someone is sending ARP packets with a source protocol
1454bd670b35SErik Nordmark 		 * address that we have published and for which we believe our
1455bd670b35SErik Nordmark 		 * entry is authoritative and verified to be unique on
1456bd670b35SErik Nordmark 		 * the network.
1457bd670b35SErik Nordmark 		 *
1458bd670b35SErik Nordmark 		 * arp_process_packet() sends AR_CN_FAILED for the case when
1459bd670b35SErik Nordmark 		 * a DAD probe is received and the hardware address of a
1460bd670b35SErik Nordmark 		 * non-authoritative entry has changed. Thus, AR_CN_BOGON
1461bd670b35SErik Nordmark 		 * indicates a real conflict, and we have to do resolution.
1462bd670b35SErik Nordmark 		 *
1463bd670b35SErik Nordmark 		 * We back away quickly from the address if it's from DHCP or
1464bd670b35SErik Nordmark 		 * otherwise temporary and hasn't been used recently (or at
1465bd670b35SErik Nordmark 		 * all).  We'd like to include "deprecated" addresses here as
1466bd670b35SErik Nordmark 		 * well (as there's no real reason to defend something we're
1467bd670b35SErik Nordmark 		 * discarding), but IPMP "reuses" this flag to mean something
1468bd670b35SErik Nordmark 		 * other than the standard meaning.
1469bd670b35SErik Nordmark 		 */
1470bd670b35SErik Nordmark 		if (ip_nce_conflict(mp, ira, ncec)) {
1471bd670b35SErik Nordmark 			(void) mac_colon_addr((uint8_t *)(arh + 1),
1472bd670b35SErik Nordmark 			    arh->arh_hlen, hbuf, sizeof (hbuf));
1473bd670b35SErik Nordmark 			(void) ip_dot_addr(src, sbuf);
1474bd670b35SErik Nordmark 			cmn_err(CE_WARN,
1475bd670b35SErik Nordmark 			    "proxy ARP problem?  Node '%s' is using %s on %s",
1476bd670b35SErik Nordmark 			    hbuf, sbuf, ill->ill_name);
1477bd670b35SErik Nordmark 			if (!arp_no_defense)
1478bd670b35SErik Nordmark 				(void) arp_announce(ncec);
1479bd670b35SErik Nordmark 			/*
1480bd670b35SErik Nordmark 			 * ncec_last_time_defended has been adjusted in
1481bd670b35SErik Nordmark 			 * ip_nce_conflict.
1482bd670b35SErik Nordmark 			 */
1483bd670b35SErik Nordmark 		} else {
1484bd670b35SErik Nordmark 			ncec_delete(ncec);
1485bd670b35SErik Nordmark 		}
1486bd670b35SErik Nordmark 		freemsg(mp);
1487bd670b35SErik Nordmark 		break;
1488bd670b35SErik Nordmark 	case AR_CN_ANNOUNCE: {
1489bd670b35SErik Nordmark 		nce_hw_map_t hwm;
1490bd670b35SErik Nordmark 		/*
1491bd670b35SErik Nordmark 		 * ARP gives us a copy of any packet where it thinks
1492bd670b35SErik Nordmark 		 * the address has changed, so that we can update our
1493bd670b35SErik Nordmark 		 * caches.  We're responsible for caching known answers
1494bd670b35SErik Nordmark 		 * in the current design.  We check whether the
1495bd670b35SErik Nordmark 		 * hardware address really has changed in all of our
1496bd670b35SErik Nordmark 		 * entries that have cached this mapping, and if so, we
1497bd670b35SErik Nordmark 		 * blow them away.  This way we will immediately pick
1498bd670b35SErik Nordmark 		 * up the rare case of a host changing hardware
1499bd670b35SErik Nordmark 		 * address.
1500bd670b35SErik Nordmark 		 */
1501bd670b35SErik Nordmark 		if (src == 0) {
1502bd670b35SErik Nordmark 			freemsg(mp);
1503bd670b35SErik Nordmark 			break;
1504bd670b35SErik Nordmark 		}
1505bd670b35SErik Nordmark 		hwm.hwm_addr = src;
1506bd670b35SErik Nordmark 		hwm.hwm_hwlen = arh->arh_hlen;
1507bd670b35SErik Nordmark 		hwm.hwm_hwaddr = (uchar_t *)(arh + 1);
1508bd670b35SErik Nordmark 		hwm.hwm_flags = 0;
1509bd670b35SErik Nordmark 		ncec_walk_common(ipst->ips_ndp4, NULL,
1510*8a06b3d6SToomas Soome 		    nce_update_hw_changed, &hwm, B_TRUE);
1511bd670b35SErik Nordmark 		freemsg(mp);
1512bd670b35SErik Nordmark 		break;
1513bd670b35SErik Nordmark 	}
1514bd670b35SErik Nordmark 	case AR_CN_FAILED:
1515bd670b35SErik Nordmark 		if (arp_no_defense) {
1516bd670b35SErik Nordmark 			(void) mac_colon_addr((uint8_t *)(arh + 1),
1517bd670b35SErik Nordmark 			    arh->arh_hlen, hbuf, sizeof (hbuf));
1518bd670b35SErik Nordmark 			(void) ip_dot_addr(src, sbuf);
1519bd670b35SErik Nordmark 
1520bd670b35SErik Nordmark 			cmn_err(CE_WARN,
1521bd670b35SErik Nordmark 			    "node %s is using our IP address %s on %s",
1522bd670b35SErik Nordmark 			    hbuf, sbuf, ill->ill_name);
1523bd670b35SErik Nordmark 			freemsg(mp);
1524bd670b35SErik Nordmark 			break;
1525bd670b35SErik Nordmark 		}
1526bd670b35SErik Nordmark 		/*
1527bd670b35SErik Nordmark 		 * mp will be freed by arp_excl.
1528bd670b35SErik Nordmark 		 */
1529bd670b35SErik Nordmark 		ill_refhold(ill);
1530bd670b35SErik Nordmark 		qwriter_ip(ill, ill->ill_rq, mp, arp_excl, NEW_OP, B_FALSE);
1531bd670b35SErik Nordmark 		return;
1532bd670b35SErik Nordmark 	default:
1533bd670b35SErik Nordmark 		ASSERT(0);
1534bd670b35SErik Nordmark 		freemsg(mp);
1535bd670b35SErik Nordmark 		break;
1536bd670b35SErik Nordmark 	}
1537bd670b35SErik Nordmark }
1538bd670b35SErik Nordmark 
1539bd670b35SErik Nordmark /*
1540bd670b35SErik Nordmark  * arp_output is called to transmit an ARP Request or Response. The mapping
1541bd670b35SErik Nordmark  * to RFC 826 variables is:
1542bd670b35SErik Nordmark  *   haddr1 == ar$sha
1543bd670b35SErik Nordmark  *   paddr1 == ar$spa
1544bd670b35SErik Nordmark  *   haddr2 == ar$tha
1545bd670b35SErik Nordmark  *   paddr2 == ar$tpa
1546bd670b35SErik Nordmark  * The ARP frame is sent to the ether_dst in dst_lladdr.
1547bd670b35SErik Nordmark  */
1548bd670b35SErik Nordmark static int
arp_output(ill_t * ill,uint32_t operation,const uchar_t * haddr1,const uchar_t * paddr1,const uchar_t * haddr2,const uchar_t * paddr2,uchar_t * dst_lladdr)1549bd670b35SErik Nordmark arp_output(ill_t *ill, uint32_t operation,
1550bd670b35SErik Nordmark     const uchar_t *haddr1, const uchar_t *paddr1, const uchar_t *haddr2,
1551bd670b35SErik Nordmark     const uchar_t *paddr2, uchar_t *dst_lladdr)
1552bd670b35SErik Nordmark {
1553bd670b35SErik Nordmark 	arh_t	*arh;
1554bd670b35SErik Nordmark 	uint8_t	*cp;
1555bd670b35SErik Nordmark 	uint_t	hlen;
1556bd670b35SErik Nordmark 	uint32_t plen = IPV4_ADDR_LEN; /* ar$pln from RFC 826 */
1557bd670b35SErik Nordmark 	uint32_t proto = IP_ARP_PROTO_TYPE;
1558bd670b35SErik Nordmark 	mblk_t *mp;
1559bd670b35SErik Nordmark 	arl_t *arl;
1560bd670b35SErik Nordmark 
1561bd670b35SErik Nordmark 	ASSERT(dst_lladdr != NULL);
1562bd670b35SErik Nordmark 	hlen = ill->ill_phys_addr_length; /* ar$hln from RFC 826 */
1563bd670b35SErik Nordmark 	mp = ill_dlur_gen(dst_lladdr, hlen, ETHERTYPE_ARP, ill->ill_sap_length);
1564bd670b35SErik Nordmark 
1565bd670b35SErik Nordmark 	if (mp == NULL)
1566bd670b35SErik Nordmark 		return (ENOMEM);
1567bd670b35SErik Nordmark 
1568bd670b35SErik Nordmark 	/* IFF_NOARP flag is set or link down: do not send arp messages */
1569bd670b35SErik Nordmark 	if ((ill->ill_flags & ILLF_NOARP) || !ill->ill_dl_up) {
1570bd670b35SErik Nordmark 		freemsg(mp);
1571bd670b35SErik Nordmark 		return (ENXIO);
1572bd670b35SErik Nordmark 	}
1573bd670b35SErik Nordmark 
1574bd670b35SErik Nordmark 	mp->b_cont = allocb(AR_LL_HDR_SLACK + ARH_FIXED_LEN + (hlen * 4) +
1575bd670b35SErik Nordmark 	    plen + plen, BPRI_MED);
1576bd670b35SErik Nordmark 	if (mp->b_cont == NULL) {
1577bd670b35SErik Nordmark 		freeb(mp);
1578bd670b35SErik Nordmark 		return (ENOMEM);
1579bd670b35SErik Nordmark 	}
1580bd670b35SErik Nordmark 
1581bd670b35SErik Nordmark 	/* Fill in the ARP header. */
1582bd670b35SErik Nordmark 	cp = mp->b_cont->b_rptr + (AR_LL_HDR_SLACK + hlen + hlen);
1583bd670b35SErik Nordmark 	mp->b_cont->b_rptr = cp;
1584bd670b35SErik Nordmark 	arh = (arh_t *)cp;
1585bd670b35SErik Nordmark 	U16_TO_BE16(arp_hw_type(ill->ill_mactype), arh->arh_hardware);
1586bd670b35SErik Nordmark 	U16_TO_BE16(proto, arh->arh_proto);
1587bd670b35SErik Nordmark 	arh->arh_hlen = (uint8_t)hlen;
1588bd670b35SErik Nordmark 	arh->arh_plen = (uint8_t)plen;
1589bd670b35SErik Nordmark 	U16_TO_BE16(operation, arh->arh_operation);
1590bd670b35SErik Nordmark 	cp += ARH_FIXED_LEN;
1591bd670b35SErik Nordmark 	bcopy(haddr1, cp, hlen);
1592bd670b35SErik Nordmark 	cp += hlen;
1593bd670b35SErik Nordmark 	if (paddr1 == NULL)
1594bd670b35SErik Nordmark 		bzero(cp, plen);
1595bd670b35SErik Nordmark 	else
1596bd670b35SErik Nordmark 		bcopy(paddr1, cp, plen);
1597bd670b35SErik Nordmark 	cp += plen;
1598bd670b35SErik Nordmark 	if (haddr2 == NULL)
1599bd670b35SErik Nordmark 		bzero(cp, hlen);
1600bd670b35SErik Nordmark 	else
1601bd670b35SErik Nordmark 		bcopy(haddr2, cp, hlen);
1602bd670b35SErik Nordmark 	cp += hlen;
1603bd670b35SErik Nordmark 	bcopy(paddr2, cp, plen);
1604bd670b35SErik Nordmark 	cp += plen;
1605bd670b35SErik Nordmark 	mp->b_cont->b_wptr = cp;
1606bd670b35SErik Nordmark 
1607bd670b35SErik Nordmark 	DTRACE_PROBE3(arp__physical__out__start,
1608bd670b35SErik Nordmark 	    ill_t *, ill, arh_t *, arh, mblk_t *, mp);
1609bd670b35SErik Nordmark 	ARP_HOOK_OUT(ill->ill_ipst->ips_arp_physical_out_event,
1610bd670b35SErik Nordmark 	    ill->ill_ipst->ips_arp_physical_out,
1611bd670b35SErik Nordmark 	    ill->ill_phyint->phyint_ifindex, arh, mp, mp->b_cont,
1612bd670b35SErik Nordmark 	    ill->ill_ipst);
1613bd670b35SErik Nordmark 	DTRACE_PROBE1(arp__physical__out__end, mblk_t *, mp);
1614bd670b35SErik Nordmark 	if (mp == NULL)
1615bd670b35SErik Nordmark 		return (0);
1616bd670b35SErik Nordmark 
1617bd670b35SErik Nordmark 	/* Ship it out. */
1618bd670b35SErik Nordmark 	arl = ill_to_arl(ill);
1619bd670b35SErik Nordmark 	if (arl == NULL) {
1620bd670b35SErik Nordmark 		freemsg(mp);
1621bd670b35SErik Nordmark 		return (0);
1622bd670b35SErik Nordmark 	}
1623bd670b35SErik Nordmark 	if (canputnext(arl->arl_wq))
1624bd670b35SErik Nordmark 		putnext(arl->arl_wq, mp);
1625bd670b35SErik Nordmark 	else
1626bd670b35SErik Nordmark 		freemsg(mp);
1627bd670b35SErik Nordmark 	arl_refrele(arl);
1628bd670b35SErik Nordmark 	return (0);
1629bd670b35SErik Nordmark }
1630bd670b35SErik Nordmark 
1631bd670b35SErik Nordmark /*
1632bd670b35SErik Nordmark  * Process resolve requests.
1633bd670b35SErik Nordmark  * If we are not yet reachable then we check and decrease ncec_rcnt; otherwise
1634bd670b35SErik Nordmark  * we leave it alone (the caller will check and manage ncec_pcnt in those
1635bd670b35SErik Nordmark  * cases.)
1636bd670b35SErik Nordmark  */
1637bd670b35SErik Nordmark int
arp_request(ncec_t * ncec,in_addr_t sender,ill_t * ill)1638bd670b35SErik Nordmark arp_request(ncec_t *ncec, in_addr_t sender, ill_t *ill)
1639bd670b35SErik Nordmark {
1640bd670b35SErik Nordmark 	int err;
1641bd670b35SErik Nordmark 	const uchar_t *target_hwaddr;
1642bd670b35SErik Nordmark 	struct in_addr nce_paddr;
1643bd670b35SErik Nordmark 	uchar_t *dst_lladdr;
1644bd670b35SErik Nordmark 	boolean_t use_rcnt = !NCE_ISREACHABLE(ncec);
1645bd670b35SErik Nordmark 
1646bd670b35SErik Nordmark 	ASSERT(MUTEX_HELD(&ncec->ncec_lock));
1647bd670b35SErik Nordmark 	ASSERT(!IS_IPMP(ill));
1648bd670b35SErik Nordmark 
1649bd670b35SErik Nordmark 	if (use_rcnt && ncec->ncec_rcnt == 0) {
1650bd670b35SErik Nordmark 		/* not allowed any more retransmits. */
1651bd670b35SErik Nordmark 		return (0);
1652bd670b35SErik Nordmark 	}
1653bd670b35SErik Nordmark 
1654bd670b35SErik Nordmark 	if ((ill->ill_flags & ILLF_NOARP) != 0)
1655bd670b35SErik Nordmark 		return (0);
1656bd670b35SErik Nordmark 
1657bd670b35SErik Nordmark 	IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &nce_paddr);
1658bd670b35SErik Nordmark 
1659bd670b35SErik Nordmark 	target_hwaddr =
1660bd670b35SErik Nordmark 	    ill->ill_bcast_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill);
1661bd670b35SErik Nordmark 
1662bd670b35SErik Nordmark 	if (NCE_ISREACHABLE(ncec)) {
1663bd670b35SErik Nordmark 		dst_lladdr =  ncec->ncec_lladdr;
1664bd670b35SErik Nordmark 	} else {
1665bd670b35SErik Nordmark 		dst_lladdr =  ill->ill_bcast_mp->b_rptr +
1666bd670b35SErik Nordmark 		    NCE_LL_ADDR_OFFSET(ill);
1667bd670b35SErik Nordmark 	}
1668bd670b35SErik Nordmark 
1669bd670b35SErik Nordmark 	mutex_exit(&ncec->ncec_lock);
1670bd670b35SErik Nordmark 	err = arp_output(ill, ARP_REQUEST,
1671bd670b35SErik Nordmark 	    ill->ill_phys_addr, (uchar_t *)&sender, target_hwaddr,
1672bd670b35SErik Nordmark 	    (uchar_t *)&nce_paddr, dst_lladdr);
1673bd670b35SErik Nordmark 	mutex_enter(&ncec->ncec_lock);
1674bd670b35SErik Nordmark 
1675bd670b35SErik Nordmark 	if (err != 0) {
1676bd670b35SErik Nordmark 		/*
1677bd670b35SErik Nordmark 		 * Some transient error such as ENOMEM or a down link was
1678bd670b35SErik Nordmark 		 * encountered. If the link has been taken down permanently,
1679bd670b35SErik Nordmark 		 * the ncec will eventually be cleaned up (ipif_down_tail()
1680bd670b35SErik Nordmark 		 * will call ipif_nce_down() and flush the ncec), to terminate
1681bd670b35SErik Nordmark 		 * recurring attempts to send ARP requests. In all other cases,
1682bd670b35SErik Nordmark 		 * allow the caller another chance at success next time.
1683bd670b35SErik Nordmark 		 */
1684bd670b35SErik Nordmark 		return (ncec->ncec_ill->ill_reachable_retrans_time);
1685bd670b35SErik Nordmark 	}
1686bd670b35SErik Nordmark 
1687bd670b35SErik Nordmark 	if (use_rcnt)
1688bd670b35SErik Nordmark 		ncec->ncec_rcnt--;
1689bd670b35SErik Nordmark 
1690bd670b35SErik Nordmark 	return (ncec->ncec_ill->ill_reachable_retrans_time);
1691bd670b35SErik Nordmark }
1692bd670b35SErik Nordmark 
1693bd670b35SErik Nordmark /* return B_TRUE if dropped */
1694bd670b35SErik Nordmark boolean_t
arp_announce(ncec_t * ncec)1695bd670b35SErik Nordmark arp_announce(ncec_t *ncec)
1696bd670b35SErik Nordmark {
1697bd670b35SErik Nordmark 	ill_t *ill;
1698bd670b35SErik Nordmark 	int err;
1699bd670b35SErik Nordmark 	uchar_t *sphys_addr, *bcast_addr;
1700bd670b35SErik Nordmark 	struct in_addr ncec_addr;
1701bd670b35SErik Nordmark 	boolean_t need_refrele = B_FALSE;
1702bd670b35SErik Nordmark 
1703bd670b35SErik Nordmark 	ASSERT((ncec->ncec_flags & NCE_F_BCAST) == 0);
1704bd670b35SErik Nordmark 	ASSERT((ncec->ncec_flags & NCE_F_MCAST) == 0);
1705bd670b35SErik Nordmark 
1706bd670b35SErik Nordmark 	if (IS_IPMP(ncec->ncec_ill)) {
1707bd670b35SErik Nordmark 		/* sent on the cast_ill */
17081f19738eSmeem 		ill = ipmp_ill_hold_xmit_ill(ncec->ncec_ill, B_FALSE);
1709bd670b35SErik Nordmark 		if (ill == NULL)
1710bd670b35SErik Nordmark 			return (B_TRUE);
1711bd670b35SErik Nordmark 		need_refrele = B_TRUE;
1712bd670b35SErik Nordmark 	} else {
1713bd670b35SErik Nordmark 		ill = ncec->ncec_ill;
1714bd670b35SErik Nordmark 	}
1715bd670b35SErik Nordmark 
1716bd670b35SErik Nordmark 	/*
1717bd670b35SErik Nordmark 	 * broadcast an announce to ill_bcast address.
1718bd670b35SErik Nordmark 	 */
1719bd670b35SErik Nordmark 	IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &ncec_addr);
1720bd670b35SErik Nordmark 
1721bd670b35SErik Nordmark 	sphys_addr = ncec->ncec_lladdr;
1722bd670b35SErik Nordmark 	bcast_addr = ill->ill_bcast_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill);
1723bd670b35SErik Nordmark 
1724bd670b35SErik Nordmark 	err = arp_output(ill, ARP_REQUEST,
1725bd670b35SErik Nordmark 	    sphys_addr, (uchar_t *)&ncec_addr, bcast_addr,
1726bd670b35SErik Nordmark 	    (uchar_t *)&ncec_addr, bcast_addr);
1727bd670b35SErik Nordmark 
1728bd670b35SErik Nordmark 	if (need_refrele)
1729bd670b35SErik Nordmark 		ill_refrele(ill);
1730bd670b35SErik Nordmark 	return (err != 0);
1731bd670b35SErik Nordmark }
1732bd670b35SErik Nordmark 
1733bd670b35SErik Nordmark /* return B_TRUE if dropped */
1734bd670b35SErik Nordmark boolean_t
arp_probe(ncec_t * ncec)1735bd670b35SErik Nordmark arp_probe(ncec_t *ncec)
1736bd670b35SErik Nordmark {
1737bd670b35SErik Nordmark 	ill_t *ill;
1738bd670b35SErik Nordmark 	int err;
1739bd670b35SErik Nordmark 	struct in_addr ncec_addr;
1740bd670b35SErik Nordmark 	uchar_t *sphys_addr, *dst_lladdr;
1741bd670b35SErik Nordmark 
1742bd670b35SErik Nordmark 	if (IS_IPMP(ncec->ncec_ill)) {
17431f19738eSmeem 		ill = ipmp_ill_hold_xmit_ill(ncec->ncec_ill, B_FALSE);
1744bd670b35SErik Nordmark 		if (ill == NULL)
1745bd670b35SErik Nordmark 			return (B_TRUE);
1746bd670b35SErik Nordmark 	} else {
1747bd670b35SErik Nordmark 		ill = ncec->ncec_ill;
1748bd670b35SErik Nordmark 	}
1749bd670b35SErik Nordmark 
1750bd670b35SErik Nordmark 	IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &ncec_addr);
1751bd670b35SErik Nordmark 
1752bd670b35SErik Nordmark 	sphys_addr = ncec->ncec_lladdr;
1753bd670b35SErik Nordmark 	dst_lladdr = ill->ill_bcast_mp->b_rptr + NCE_LL_ADDR_OFFSET(ill);
1754bd670b35SErik Nordmark 	err = arp_output(ill, ARP_REQUEST,
1755bd670b35SErik Nordmark 	    sphys_addr, NULL, NULL, (uchar_t *)&ncec_addr, dst_lladdr);
1756bd670b35SErik Nordmark 
1757bd670b35SErik Nordmark 	if (IS_IPMP(ncec->ncec_ill))
1758bd670b35SErik Nordmark 		ill_refrele(ill);
1759bd670b35SErik Nordmark 	return (err != 0);
1760bd670b35SErik Nordmark }
1761bd670b35SErik Nordmark 
1762bd670b35SErik Nordmark static mblk_t *
arl_unbind(arl_t * arl)1763bd670b35SErik Nordmark arl_unbind(arl_t *arl)
1764bd670b35SErik Nordmark {
1765bd670b35SErik Nordmark 	mblk_t *mp;
1766bd670b35SErik Nordmark 
1767bd670b35SErik Nordmark 	if ((mp = arl->arl_unbind_mp) != NULL) {
1768bd670b35SErik Nordmark 		arl->arl_unbind_mp = NULL;
1769bd670b35SErik Nordmark 		arl->arl_state_flags |= ARL_DL_UNBIND_IN_PROGRESS;
1770bd670b35SErik Nordmark 	}
1771bd670b35SErik Nordmark 	return (mp);
1772bd670b35SErik Nordmark }
1773bd670b35SErik Nordmark 
1774bd670b35SErik Nordmark int
arp_ll_down(ill_t * ill)1775bd670b35SErik Nordmark arp_ll_down(ill_t *ill)
1776bd670b35SErik Nordmark {
1777*8a06b3d6SToomas Soome 	arl_t	*arl;
1778bd670b35SErik Nordmark 	mblk_t *unbind_mp;
1779bd670b35SErik Nordmark 	int err = 0;
1780bd670b35SErik Nordmark 	boolean_t replumb = (ill->ill_replumbing == 1);
1781bd670b35SErik Nordmark 
1782bd670b35SErik Nordmark 	DTRACE_PROBE2(ill__downup, char *, "arp_ll_down", ill_t *, ill);
1783bd670b35SErik Nordmark 	if ((arl = ill_to_arl(ill)) == NULL)
1784bd670b35SErik Nordmark 		return (ENXIO);
1785bd670b35SErik Nordmark 	DTRACE_PROBE2(arl__downup, char *, "arp_ll_down", arl_t *, arl);
1786bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
1787bd670b35SErik Nordmark 	unbind_mp = arl_unbind(arl);
1788bd670b35SErik Nordmark 	if (unbind_mp != NULL) {
1789bd670b35SErik Nordmark 		ASSERT(arl->arl_state_flags & ARL_DL_UNBIND_IN_PROGRESS);
1790bd670b35SErik Nordmark 		DTRACE_PROBE2(arp__unbinding, mblk_t *, unbind_mp,
1791bd670b35SErik Nordmark 		    arl_t *, arl);
1792bd670b35SErik Nordmark 		err = EINPROGRESS;
1793bd670b35SErik Nordmark 		if (replumb)
1794bd670b35SErik Nordmark 			arl->arl_state_flags |= ARL_LL_REPLUMBING;
1795bd670b35SErik Nordmark 	}
1796bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
1797bd670b35SErik Nordmark 	if (unbind_mp != NULL)
1798bd670b35SErik Nordmark 		arp_dlpi_send(arl, unbind_mp);
1799bd670b35SErik Nordmark 	arl_refrele(arl);
1800bd670b35SErik Nordmark 	return (err);
1801bd670b35SErik Nordmark }
1802bd670b35SErik Nordmark 
1803bd670b35SErik Nordmark /* ARGSUSED */
1804bd670b35SErik Nordmark int
arp_close(queue_t * q,int flags __unused,cred_t * credp __unused)18055e1743f0SToomas Soome arp_close(queue_t *q, int flags __unused, cred_t *credp __unused)
1806bd670b35SErik Nordmark {
1807bd670b35SErik Nordmark 	if (WR(q)->q_next != NULL) {
1808bd670b35SErik Nordmark 		/* This is a module close */
1809bd670b35SErik Nordmark 		return (arp_modclose(q->q_ptr));
1810bd670b35SErik Nordmark 	}
1811bd670b35SErik Nordmark 	qprocsoff(q);
1812bd670b35SErik Nordmark 	q->q_ptr = WR(q)->q_ptr = NULL;
1813bd670b35SErik Nordmark 	return (0);
1814bd670b35SErik Nordmark }
1815bd670b35SErik Nordmark 
1816bd670b35SErik Nordmark static int
arp_modclose(arl_t * arl)1817bd670b35SErik Nordmark arp_modclose(arl_t *arl)
1818bd670b35SErik Nordmark {
1819bd670b35SErik Nordmark 	arl_ill_common_t *ai = arl->arl_common;
1820bd670b35SErik Nordmark 	ill_t		*ill;
1821bd670b35SErik Nordmark 	queue_t		*q = arl->arl_rq;
1822bd670b35SErik Nordmark 	mblk_t		*mp, *nextmp;
1823bd670b35SErik Nordmark 	ipsq_t		*ipsq = NULL;
1824bd670b35SErik Nordmark 
1825bd670b35SErik Nordmark 	ill = arl_to_ill(arl);
1826bd670b35SErik Nordmark 	if (ill != NULL) {
1827bd670b35SErik Nordmark 		if (!ill_waiter_inc(ill)) {
1828bd670b35SErik Nordmark 			ill_refrele(ill);
1829bd670b35SErik Nordmark 		} else {
1830bd670b35SErik Nordmark 			ill_refrele(ill);
1831bd670b35SErik Nordmark 			if (ipsq_enter(ill, B_FALSE, NEW_OP))
1832bd670b35SErik Nordmark 				ipsq = ill->ill_phyint->phyint_ipsq;
1833bd670b35SErik Nordmark 			ill_waiter_dcr(ill);
1834bd670b35SErik Nordmark 		}
1835bd670b35SErik Nordmark 		if (ipsq == NULL) {
1836bd670b35SErik Nordmark 			/*
1837bd670b35SErik Nordmark 			 * could not enter the ipsq because ill is already
1838bd670b35SErik Nordmark 			 * marked CONDEMNED.
1839bd670b35SErik Nordmark 			 */
1840bd670b35SErik Nordmark 			ill = NULL;
1841bd670b35SErik Nordmark 		}
1842bd670b35SErik Nordmark 	}
1843bd670b35SErik Nordmark 	if (ai != NULL && ipsq == NULL) {
1844bd670b35SErik Nordmark 		/*
1845bd670b35SErik Nordmark 		 * Either we did not get an ill because it was marked CONDEMNED
1846bd670b35SErik Nordmark 		 * or we could not enter the ipsq because it was unplumbing.
1847bd670b35SErik Nordmark 		 * In both cases, wait for the ill to complete ip_modclose().
1848bd670b35SErik Nordmark 		 *
1849bd670b35SErik Nordmark 		 * If the arp_modclose happened even before SLIFNAME, the ai
1850bd670b35SErik Nordmark 		 * itself would be NULL, in which case we can complete the close
1851bd670b35SErik Nordmark 		 * without waiting.
1852bd670b35SErik Nordmark 		 */
1853bd670b35SErik Nordmark 		mutex_enter(&ai->ai_lock);
1854bd670b35SErik Nordmark 		while (ai->ai_ill != NULL)
1855bd670b35SErik Nordmark 			cv_wait(&ai->ai_ill_unplumb_done, &ai->ai_lock);
1856bd670b35SErik Nordmark 		mutex_exit(&ai->ai_lock);
1857bd670b35SErik Nordmark 	}
1858bd670b35SErik Nordmark 	ASSERT(ill == NULL || IAM_WRITER_ILL(ill));
1859bd670b35SErik Nordmark 
1860bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
1861bd670b35SErik Nordmark 	/*
1862bd670b35SErik Nordmark 	 * If the ill had completed unplumbing before arp_modclose(), there
1863bd670b35SErik Nordmark 	 * would be no ill (and therefore, no ipsq) to serialize arp_modclose()
1864bd670b35SErik Nordmark 	 * so that we need to explicitly check for ARL_CONDEMNED and back off
1865bd670b35SErik Nordmark 	 * if it is set.
1866bd670b35SErik Nordmark 	 */
1867bd670b35SErik Nordmark 	if ((arl->arl_state_flags & ARL_CONDEMNED) != 0) {
1868bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
1869bd670b35SErik Nordmark 		ASSERT(ipsq == NULL);
1870bd670b35SErik Nordmark 		return (0);
1871bd670b35SErik Nordmark 	}
1872bd670b35SErik Nordmark 	arl->arl_state_flags |= ARL_CONDEMNED;
1873bd670b35SErik Nordmark 
1874bd670b35SErik Nordmark 	/*
1875bd670b35SErik Nordmark 	 * send out all pending dlpi messages, don't wait for the ack (which
1876bd670b35SErik Nordmark 	 * will be ignored in arp_rput when CONDEMNED is set)
1877bd670b35SErik Nordmark 	 *
1878bd670b35SErik Nordmark 	 * We have to check for pending DL_UNBIND_REQ because, in the case
1879bd670b35SErik Nordmark 	 * that ip_modclose() executed before arp_modclose(), the call to
1880bd670b35SErik Nordmark 	 * ill_delete_tail->ipif_arp_down() would have triggered a
1881bd670b35SErik Nordmark 	 * DL_UNBIND_REQ. When arp_modclose() executes ipsq_enter() will fail
1882bd670b35SErik Nordmark 	 * (since ip_modclose() is in the ipsq) but the DL_UNBIND_ACK may not
1883bd670b35SErik Nordmark 	 * have been processed yet. In this scenario, we cannot reset
1884bd670b35SErik Nordmark 	 * arl_dlpi_pending, because the setting/clearing of arl_state_flags
1885bd670b35SErik Nordmark 	 * related to unbind, and the associated cv_waits must be allowed to
1886bd670b35SErik Nordmark 	 * continue.
1887bd670b35SErik Nordmark 	 */
1888bd670b35SErik Nordmark 	if (arl->arl_dlpi_pending != DL_UNBIND_REQ)
1889bd670b35SErik Nordmark 		arl->arl_dlpi_pending = DL_PRIM_INVAL;
1890bd670b35SErik Nordmark 	mp = arl->arl_dlpi_deferred;
1891bd670b35SErik Nordmark 	arl->arl_dlpi_deferred = NULL;
1892bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
1893bd670b35SErik Nordmark 
1894bd670b35SErik Nordmark 	for (; mp != NULL; mp = nextmp) {
1895bd670b35SErik Nordmark 		nextmp = mp->b_next;
1896bd670b35SErik Nordmark 		mp->b_next = NULL;
1897bd670b35SErik Nordmark 		putnext(arl->arl_wq, mp);
1898bd670b35SErik Nordmark 	}
1899bd670b35SErik Nordmark 
1900bd670b35SErik Nordmark 	/* Wait for data paths to quiesce */
1901bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
1902bd670b35SErik Nordmark 	while (arl->arl_refcnt != 0)
1903bd670b35SErik Nordmark 		cv_wait(&arl->arl_cv, &arl->arl_lock);
1904bd670b35SErik Nordmark 
1905bd670b35SErik Nordmark 	/*
1906bd670b35SErik Nordmark 	 * unbind, so that nothing else can come up from driver.
1907bd670b35SErik Nordmark 	 */
1908bd670b35SErik Nordmark 	mp = arl_unbind(arl);
1909bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
1910bd670b35SErik Nordmark 	if (mp != NULL)
1911bd670b35SErik Nordmark 		arp_dlpi_send(arl, mp);
1912bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
1913bd670b35SErik Nordmark 
1914bd670b35SErik Nordmark 	/* wait for unbind ack  */
1915bd670b35SErik Nordmark 	while (arl->arl_state_flags & ARL_DL_UNBIND_IN_PROGRESS)
1916bd670b35SErik Nordmark 		cv_wait(&arl->arl_cv, &arl->arl_lock);
1917bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
1918bd670b35SErik Nordmark 
1919bd670b35SErik Nordmark 	qprocsoff(q);
1920bd670b35SErik Nordmark 
1921bd670b35SErik Nordmark 	if (ill != NULL) {
1922bd670b35SErik Nordmark 		mutex_enter(&ill->ill_lock);
1923bd670b35SErik Nordmark 		ill->ill_arl_dlpi_pending = 0;
1924bd670b35SErik Nordmark 		mutex_exit(&ill->ill_lock);
1925bd670b35SErik Nordmark 	}
1926bd670b35SErik Nordmark 
1927bd670b35SErik Nordmark 	if (ai != NULL) {
1928bd670b35SErik Nordmark 		mutex_enter(&ai->ai_lock);
1929bd670b35SErik Nordmark 		ai->ai_arl = NULL;
1930bd670b35SErik Nordmark 		if (ai->ai_ill == NULL) {
1931bd670b35SErik Nordmark 			mutex_destroy(&ai->ai_lock);
1932bd670b35SErik Nordmark 			kmem_free(ai, sizeof (*ai));
1933bd670b35SErik Nordmark 		} else {
1934bd670b35SErik Nordmark 			mutex_exit(&ai->ai_lock);
1935bd670b35SErik Nordmark 		}
1936bd670b35SErik Nordmark 	}
1937bd670b35SErik Nordmark 
1938bd670b35SErik Nordmark 	/* free up the rest */
1939bd670b35SErik Nordmark 	arp_mod_close_tail(arl);
1940bd670b35SErik Nordmark 
1941bd670b35SErik Nordmark 	q->q_ptr = WR(q)->q_ptr = NULL;
1942bd670b35SErik Nordmark 
1943bd670b35SErik Nordmark 	if (ipsq != NULL)
1944bd670b35SErik Nordmark 		ipsq_exit(ipsq);
1945bd670b35SErik Nordmark 
1946bd670b35SErik Nordmark 	return (0);
1947bd670b35SErik Nordmark }
1948bd670b35SErik Nordmark 
1949bd670b35SErik Nordmark static void
arp_mod_close_tail(arl_t * arl)1950bd670b35SErik Nordmark arp_mod_close_tail(arl_t *arl)
1951bd670b35SErik Nordmark {
1952bd670b35SErik Nordmark 	ip_stack_t	*ipst = arl->arl_ipst;
1953bd670b35SErik Nordmark 	mblk_t		**mpp;
1954bd670b35SErik Nordmark 
1955bd670b35SErik Nordmark 	mutex_enter(&ipst->ips_ip_mi_lock);
1956bd670b35SErik Nordmark 	mi_close_unlink(&ipst->ips_arp_g_head, (IDP)arl);
1957bd670b35SErik Nordmark 	mutex_exit(&ipst->ips_ip_mi_lock);
1958bd670b35SErik Nordmark 
1959bd670b35SErik Nordmark 	/*
1960bd670b35SErik Nordmark 	 * credp could be null if the open didn't succeed and ip_modopen
1961bd670b35SErik Nordmark 	 * itself calls ip_close.
1962bd670b35SErik Nordmark 	 */
1963bd670b35SErik Nordmark 	if (arl->arl_credp != NULL)
1964bd670b35SErik Nordmark 		crfree(arl->arl_credp);
1965bd670b35SErik Nordmark 
1966bd670b35SErik Nordmark 	/* Free all retained control messages. */
1967bd670b35SErik Nordmark 	mpp = &arl->arl_first_mp_to_free;
1968bd670b35SErik Nordmark 	do {
1969bd670b35SErik Nordmark 		while (mpp[0]) {
1970bd670b35SErik Nordmark 			mblk_t  *mp;
1971bd670b35SErik Nordmark 			mblk_t  *mp1;
1972bd670b35SErik Nordmark 
1973bd670b35SErik Nordmark 			mp = mpp[0];
1974bd670b35SErik Nordmark 			mpp[0] = mp->b_next;
1975bd670b35SErik Nordmark 			for (mp1 = mp; mp1 != NULL; mp1 = mp1->b_cont) {
1976bd670b35SErik Nordmark 				mp1->b_next = NULL;
1977bd670b35SErik Nordmark 				mp1->b_prev = NULL;
1978bd670b35SErik Nordmark 			}
1979bd670b35SErik Nordmark 			freemsg(mp);
1980bd670b35SErik Nordmark 		}
1981bd670b35SErik Nordmark 	} while (mpp++ != &arl->arl_last_mp_to_free);
1982bd670b35SErik Nordmark 
1983bd670b35SErik Nordmark 	netstack_rele(ipst->ips_netstack);
1984bd670b35SErik Nordmark 	mi_free(arl->arl_name);
1985bd670b35SErik Nordmark 	mi_close_free((IDP)arl);
1986bd670b35SErik Nordmark }
1987bd670b35SErik Nordmark 
1988bd670b35SErik Nordmark /*
1989bd670b35SErik Nordmark  * DAD failed. Tear down ipifs with the specified srce address. Note that
1990bd670b35SErik Nordmark  * tearing down the ipif also meas deleting the ncec through ipif_down,
1991bd670b35SErik Nordmark  * so it is not possible to use nce_timer for recovery. Instead we start
1992bd670b35SErik Nordmark  * a timer on the ipif. Caller has to free the mp.
1993bd670b35SErik Nordmark  */
1994bd670b35SErik Nordmark void
arp_failure(mblk_t * mp,ip_recv_attr_t * ira)1995bd670b35SErik Nordmark arp_failure(mblk_t *mp, ip_recv_attr_t *ira)
1996bd670b35SErik Nordmark {
1997bd670b35SErik Nordmark 	ill_t *ill = ira->ira_ill;
1998bd670b35SErik Nordmark 
1999bd670b35SErik Nordmark 	if ((mp = copymsg(mp)) != NULL) {
2000bd670b35SErik Nordmark 		ill_refhold(ill);
2001bd670b35SErik Nordmark 		qwriter_ip(ill, ill->ill_rq, mp, arp_excl, NEW_OP, B_FALSE);
2002bd670b35SErik Nordmark 	}
2003bd670b35SErik Nordmark }
2004bd670b35SErik Nordmark 
2005bd670b35SErik Nordmark /*
2006bd670b35SErik Nordmark  * This is for exclusive changes due to ARP.  Tear down an interface due
2007bd670b35SErik Nordmark  * to AR_CN_FAILED and AR_CN_BOGON.
2008bd670b35SErik Nordmark  */
2009bd670b35SErik Nordmark /* ARGSUSED */
2010bd670b35SErik Nordmark static void
arp_excl(ipsq_t * ipsq,queue_t * rq,mblk_t * mp,void * dummy_arg)2011bd670b35SErik Nordmark arp_excl(ipsq_t *ipsq, queue_t *rq, mblk_t *mp, void *dummy_arg)
2012bd670b35SErik Nordmark {
2013bd670b35SErik Nordmark 	ill_t	*ill = rq->q_ptr;
2014bd670b35SErik Nordmark 	arh_t *arh;
2015bd670b35SErik Nordmark 	ipaddr_t src;
2016bd670b35SErik Nordmark 	ipif_t	*ipif;
2017bd670b35SErik Nordmark 	ip_stack_t *ipst = ill->ill_ipst;
2018bd670b35SErik Nordmark 	uchar_t	*haddr;
2019bd670b35SErik Nordmark 	uint_t	haddrlen;
2020bd670b35SErik Nordmark 
2021bd670b35SErik Nordmark 	/* first try src = ar$spa */
2022bd670b35SErik Nordmark 	arh = (arh_t *)mp->b_rptr;
2023bd670b35SErik Nordmark 	bcopy((char *)&arh[1] + arh->arh_hlen, &src, IP_ADDR_LEN);
2024bd670b35SErik Nordmark 
2025bd670b35SErik Nordmark 	haddrlen = arh->arh_hlen;
2026bd670b35SErik Nordmark 	haddr = (uint8_t *)(arh + 1);
2027bd670b35SErik Nordmark 
2028bd670b35SErik Nordmark 	if (haddrlen == ill->ill_phys_addr_length) {
2029bd670b35SErik Nordmark 		/*
2030bd670b35SErik Nordmark 		 * Ignore conflicts generated by misbehaving switches that
2031bd670b35SErik Nordmark 		 * just reflect our own messages back to us.  For IPMP, we may
2032bd670b35SErik Nordmark 		 * see reflections across any ill in the illgrp.
2033bd670b35SErik Nordmark 		 */
2034bd670b35SErik Nordmark 		/* For an under ill_grp can change under lock */
2035bd670b35SErik Nordmark 		rw_enter(&ipst->ips_ill_g_lock, RW_READER);
2036bd670b35SErik Nordmark 		if (bcmp(haddr, ill->ill_phys_addr, haddrlen) == 0 ||
2037bd670b35SErik Nordmark 		    IS_UNDER_IPMP(ill) && ill->ill_grp != NULL &&
2038bd670b35SErik Nordmark 		    ipmp_illgrp_find_ill(ill->ill_grp, haddr,
2039bd670b35SErik Nordmark 		    haddrlen) != NULL) {
2040bd670b35SErik Nordmark 			rw_exit(&ipst->ips_ill_g_lock);
2041bd670b35SErik Nordmark 			goto ignore_conflict;
2042bd670b35SErik Nordmark 		}
2043bd670b35SErik Nordmark 		rw_exit(&ipst->ips_ill_g_lock);
2044bd670b35SErik Nordmark 	}
2045bd670b35SErik Nordmark 
2046bd670b35SErik Nordmark 	/*
2047bd670b35SErik Nordmark 	 * Look up the appropriate ipif.
2048bd670b35SErik Nordmark 	 */
2049bd670b35SErik Nordmark 	ipif = ipif_lookup_addr(src, ill, ALL_ZONES, ipst);
2050bd670b35SErik Nordmark 	if (ipif == NULL)
2051bd670b35SErik Nordmark 		goto ignore_conflict;
2052bd670b35SErik Nordmark 
2053bd670b35SErik Nordmark 	/* Reload the ill to match the ipif */
2054bd670b35SErik Nordmark 	ill = ipif->ipif_ill;
2055bd670b35SErik Nordmark 
2056bd670b35SErik Nordmark 	/* If it's already duplicate or ineligible, then don't do anything. */
2057bd670b35SErik Nordmark 	if (ipif->ipif_flags & (IPIF_POINTOPOINT|IPIF_DUPLICATE)) {
2058bd670b35SErik Nordmark 		ipif_refrele(ipif);
2059bd670b35SErik Nordmark 		goto ignore_conflict;
2060bd670b35SErik Nordmark 	}
2061bd670b35SErik Nordmark 
2062bd670b35SErik Nordmark 	/*
2063bd670b35SErik Nordmark 	 * If we failed on a recovery probe, then restart the timer to
2064bd670b35SErik Nordmark 	 * try again later.
2065bd670b35SErik Nordmark 	 */
2066bd670b35SErik Nordmark 	if (!ipif->ipif_was_dup) {
2067bd670b35SErik Nordmark 		char hbuf[MAC_STR_LEN];
2068bd670b35SErik Nordmark 		char sbuf[INET_ADDRSTRLEN];
2069bd670b35SErik Nordmark 		char ibuf[LIFNAMSIZ];
2070bd670b35SErik Nordmark 
2071bd670b35SErik Nordmark 		(void) mac_colon_addr(haddr, haddrlen, hbuf, sizeof (hbuf));
2072bd670b35SErik Nordmark 		(void) ip_dot_addr(src, sbuf);
2073bd670b35SErik Nordmark 		ipif_get_name(ipif, ibuf, sizeof (ibuf));
2074bd670b35SErik Nordmark 
2075bd670b35SErik Nordmark 		cmn_err(CE_WARN, "%s has duplicate address %s (in use by %s);"
2076bd670b35SErik Nordmark 		    " disabled", ibuf, sbuf, hbuf);
2077bd670b35SErik Nordmark 	}
2078bd670b35SErik Nordmark 	mutex_enter(&ill->ill_lock);
2079bd670b35SErik Nordmark 	ASSERT(!(ipif->ipif_flags & IPIF_DUPLICATE));
2080bd670b35SErik Nordmark 	ipif->ipif_flags |= IPIF_DUPLICATE;
2081bd670b35SErik Nordmark 	ill->ill_ipif_dup_count++;
2082bd670b35SErik Nordmark 	mutex_exit(&ill->ill_lock);
2083bd670b35SErik Nordmark 	(void) ipif_down(ipif, NULL, NULL);
2084bd670b35SErik Nordmark 	(void) ipif_down_tail(ipif);
2085bd670b35SErik Nordmark 	mutex_enter(&ill->ill_lock);
2086bd670b35SErik Nordmark 	if (!(ipif->ipif_flags & (IPIF_DHCPRUNNING|IPIF_TEMPORARY)) &&
2087bd670b35SErik Nordmark 	    ill->ill_net_type == IRE_IF_RESOLVER &&
2088bd670b35SErik Nordmark 	    !(ipif->ipif_state_flags & IPIF_CONDEMNED) &&
2089bd670b35SErik Nordmark 	    ipst->ips_ip_dup_recovery > 0) {
2090bd670b35SErik Nordmark 		ASSERT(ipif->ipif_recovery_id == 0);
2091bd670b35SErik Nordmark 		ipif->ipif_recovery_id = timeout(ipif_dup_recovery,
2092bd670b35SErik Nordmark 		    ipif, MSEC_TO_TICK(ipst->ips_ip_dup_recovery));
2093bd670b35SErik Nordmark 	}
2094bd670b35SErik Nordmark 	mutex_exit(&ill->ill_lock);
2095bd670b35SErik Nordmark 	ipif_refrele(ipif);
2096bd670b35SErik Nordmark 
2097bd670b35SErik Nordmark ignore_conflict:
2098bd670b35SErik Nordmark 	freemsg(mp);
2099bd670b35SErik Nordmark }
2100bd670b35SErik Nordmark 
2101bd670b35SErik Nordmark /*
2102bd670b35SErik Nordmark  * This is a place for a dtrace hook.
2103bd670b35SErik Nordmark  * Note that mp can be either the DL_UNITDATA_IND with a b_cont payload,
2104bd670b35SErik Nordmark  * or just the ARP packet payload as an M_DATA.
2105bd670b35SErik Nordmark  */
2106bd670b35SErik Nordmark /* ARGSUSED */
2107bd670b35SErik Nordmark static void
arp_drop_packet(const char * str,mblk_t * mp,ill_t * ill)2108bd670b35SErik Nordmark arp_drop_packet(const char *str, mblk_t *mp, ill_t *ill)
2109bd670b35SErik Nordmark {
2110bd670b35SErik Nordmark 	freemsg(mp);
2111bd670b35SErik Nordmark }
2112bd670b35SErik Nordmark 
2113bd670b35SErik Nordmark static boolean_t
arp_over_driver(queue_t * q)2114bd670b35SErik Nordmark arp_over_driver(queue_t *q)
2115bd670b35SErik Nordmark {
2116bd670b35SErik Nordmark 	queue_t *qnext = STREAM(q)->sd_wrq->q_next;
2117bd670b35SErik Nordmark 
2118bd670b35SErik Nordmark 	/*
2119bd670b35SErik Nordmark 	 * check if first module below stream head is IP or UDP.
2120bd670b35SErik Nordmark 	 */
2121bd670b35SErik Nordmark 	ASSERT(qnext != NULL);
2122bd670b35SErik Nordmark 	if (strcmp(Q2NAME(qnext), "ip") != 0 &&
2123bd670b35SErik Nordmark 	    strcmp(Q2NAME(qnext), "udp") != 0) {
2124bd670b35SErik Nordmark 		/*
2125bd670b35SErik Nordmark 		 * module below is not ip or udp, so arp has been pushed
2126bd670b35SErik Nordmark 		 * on the driver.
2127bd670b35SErik Nordmark 		 */
2128bd670b35SErik Nordmark 		return (B_TRUE);
2129bd670b35SErik Nordmark 	}
2130bd670b35SErik Nordmark 	return (B_FALSE);
2131bd670b35SErik Nordmark }
2132bd670b35SErik Nordmark 
2133bd670b35SErik Nordmark static int
arp_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)2134bd670b35SErik Nordmark arp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
2135bd670b35SErik Nordmark {
2136bd670b35SErik Nordmark 	int err;
2137bd670b35SErik Nordmark 
2138bd670b35SErik Nordmark 	ASSERT(sflag & MODOPEN);
2139bd670b35SErik Nordmark 	if (!arp_over_driver(q)) {
2140bd670b35SErik Nordmark 		q->q_qinfo = dummymodinfo.st_rdinit;
2141bd670b35SErik Nordmark 		WR(q)->q_qinfo = dummymodinfo.st_wrinit;
2142bd670b35SErik Nordmark 		return ((*dummymodinfo.st_rdinit->qi_qopen)(q, devp, flag,
2143bd670b35SErik Nordmark 		    sflag, credp));
2144bd670b35SErik Nordmark 	}
2145bd670b35SErik Nordmark 	err = arp_modopen(q, devp, flag, sflag, credp);
2146bd670b35SErik Nordmark 	return (err);
2147bd670b35SErik Nordmark }
2148bd670b35SErik Nordmark 
2149bd670b35SErik Nordmark /*
2150bd670b35SErik Nordmark  * In most cases we must be a writer on the IP stream before coming to
2151bd670b35SErik Nordmark  * arp_dlpi_send(), to serialize DLPI sends to the driver. The exceptions
2152bd670b35SErik Nordmark  * when we are not a writer are very early duing initialization (in
2153bd670b35SErik Nordmark  * arl_init, before the arl has done a SLIFNAME, so that we don't yet know
2154bd670b35SErik Nordmark  * the associated ill) or during arp_mod_close, when we could not enter the
2155bd670b35SErik Nordmark  * ipsq because the ill has already unplumbed.
2156bd670b35SErik Nordmark  */
2157bd670b35SErik Nordmark static void
arp_dlpi_send(arl_t * arl,mblk_t * mp)2158bd670b35SErik Nordmark arp_dlpi_send(arl_t *arl, mblk_t *mp)
2159bd670b35SErik Nordmark {
2160bd670b35SErik Nordmark 	mblk_t **mpp;
2161bd670b35SErik Nordmark 	t_uscalar_t prim;
2162bd670b35SErik Nordmark 	arl_ill_common_t *ai;
2163bd670b35SErik Nordmark 
2164bd670b35SErik Nordmark 	ASSERT(DB_TYPE(mp) == M_PROTO || DB_TYPE(mp) == M_PCPROTO);
2165bd670b35SErik Nordmark 
2166bd670b35SErik Nordmark #ifdef DEBUG
2167bd670b35SErik Nordmark 	ai = arl->arl_common;
2168bd670b35SErik Nordmark 	if (ai != NULL) {
2169bd670b35SErik Nordmark 		mutex_enter(&ai->ai_lock);
2170bd670b35SErik Nordmark 		if (ai->ai_ill != NULL)
2171bd670b35SErik Nordmark 			ASSERT(IAM_WRITER_ILL(ai->ai_ill));
2172bd670b35SErik Nordmark 		mutex_exit(&ai->ai_lock);
2173bd670b35SErik Nordmark 	}
2174bd670b35SErik Nordmark #endif /* DEBUG */
2175bd670b35SErik Nordmark 
2176bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
2177bd670b35SErik Nordmark 	if (arl->arl_dlpi_pending != DL_PRIM_INVAL) {
2178bd670b35SErik Nordmark 		/* Must queue message. Tail insertion */
2179bd670b35SErik Nordmark 		mpp = &arl->arl_dlpi_deferred;
2180bd670b35SErik Nordmark 		while (*mpp != NULL)
2181bd670b35SErik Nordmark 			mpp = &((*mpp)->b_next);
2182bd670b35SErik Nordmark 
2183bd670b35SErik Nordmark 		*mpp = mp;
2184bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
2185bd670b35SErik Nordmark 		return;
2186bd670b35SErik Nordmark 	}
2187bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
2188bd670b35SErik Nordmark 	if ((prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive)
2189bd670b35SErik Nordmark 	    == DL_BIND_REQ) {
2190bd670b35SErik Nordmark 		ASSERT((arl->arl_state_flags & ARL_DL_UNBIND_IN_PROGRESS) == 0);
2191bd670b35SErik Nordmark 	}
2192bd670b35SErik Nordmark 	/*
2193bd670b35SErik Nordmark 	 * No need to take the arl_lock to examine ARL_CONDEMNED at this point
2194bd670b35SErik Nordmark 	 * because the only thread that can see ARL_CONDEMNED here is the
2195bd670b35SErik Nordmark 	 * closing arp_modclose() thread which sets the flag after becoming a
2196bd670b35SErik Nordmark 	 * writer on the ipsq. Threads from IP must have finished and
2197bd670b35SErik Nordmark 	 * cannot be active now.
2198bd670b35SErik Nordmark 	 */
2199bd670b35SErik Nordmark 	if (!(arl->arl_state_flags & ARL_CONDEMNED) ||
2200bd670b35SErik Nordmark 	    (prim == DL_UNBIND_REQ)) {
2201bd670b35SErik Nordmark 		if (prim != DL_NOTIFY_CONF) {
2202bd670b35SErik Nordmark 			ill_t *ill = arl_to_ill(arl);
2203bd670b35SErik Nordmark 
2204bd670b35SErik Nordmark 			arl->arl_dlpi_pending = prim;
2205bd670b35SErik Nordmark 			if (ill != NULL) {
2206bd670b35SErik Nordmark 				mutex_enter(&ill->ill_lock);
2207bd670b35SErik Nordmark 				ill->ill_arl_dlpi_pending = 1;
2208bd670b35SErik Nordmark 				mutex_exit(&ill->ill_lock);
2209bd670b35SErik Nordmark 				ill_refrele(ill);
2210bd670b35SErik Nordmark 			}
2211bd670b35SErik Nordmark 		}
2212bd670b35SErik Nordmark 	}
2213bd670b35SErik Nordmark 	DTRACE_PROBE4(arl__dlpi, char *, "arp_dlpi_send",
2214bd670b35SErik Nordmark 	    char *, dl_primstr(prim), char *, "-",  arl_t *, arl);
2215bd670b35SErik Nordmark 	putnext(arl->arl_wq, mp);
2216bd670b35SErik Nordmark }
2217bd670b35SErik Nordmark 
2218bd670b35SErik Nordmark static void
arl_defaults_common(arl_t * arl,mblk_t * mp)2219bd670b35SErik Nordmark arl_defaults_common(arl_t *arl, mblk_t *mp)
2220bd670b35SErik Nordmark {
2221bd670b35SErik Nordmark 	dl_info_ack_t	*dlia = (dl_info_ack_t *)mp->b_rptr;
2222bd670b35SErik Nordmark 	/*
2223bd670b35SErik Nordmark 	 * Till the ill is fully up  the ill is not globally visible.
2224bd670b35SErik Nordmark 	 * So no need for a lock.
2225bd670b35SErik Nordmark 	 */
2226bd670b35SErik Nordmark 	arl->arl_mactype = dlia->dl_mac_type;
2227bd670b35SErik Nordmark 	arl->arl_sap_length = dlia->dl_sap_length;
2228bd670b35SErik Nordmark 
2229bd670b35SErik Nordmark 	if (!arl->arl_dlpi_style_set) {
2230bd670b35SErik Nordmark 		if (dlia->dl_provider_style == DL_STYLE2)
2231bd670b35SErik Nordmark 			arl->arl_needs_attach = 1;
2232bd670b35SErik Nordmark 		mutex_enter(&arl->arl_lock);
2233bd670b35SErik Nordmark 		ASSERT(arl->arl_dlpi_style_set == 0);
2234bd670b35SErik Nordmark 		arl->arl_dlpi_style_set = 1;
2235bd670b35SErik Nordmark 		arl->arl_state_flags &= ~ARL_LL_SUBNET_PENDING;
2236bd670b35SErik Nordmark 		cv_broadcast(&arl->arl_cv);
2237bd670b35SErik Nordmark 		mutex_exit(&arl->arl_lock);
2238bd670b35SErik Nordmark 	}
2239bd670b35SErik Nordmark }
2240bd670b35SErik Nordmark 
2241bd670b35SErik Nordmark int
arl_init(queue_t * q,arl_t * arl)2242bd670b35SErik Nordmark arl_init(queue_t *q, arl_t *arl)
2243bd670b35SErik Nordmark {
2244bd670b35SErik Nordmark 	mblk_t *info_mp;
2245bd670b35SErik Nordmark 	dl_info_req_t   *dlir;
2246bd670b35SErik Nordmark 
2247bd670b35SErik Nordmark 	/* subset of ill_init */
2248bd670b35SErik Nordmark 	mutex_init(&arl->arl_lock, NULL, MUTEX_DEFAULT, 0);
2249bd670b35SErik Nordmark 
2250bd670b35SErik Nordmark 	arl->arl_rq = q;
2251bd670b35SErik Nordmark 	arl->arl_wq = WR(q);
2252bd670b35SErik Nordmark 
2253bd670b35SErik Nordmark 	info_mp = allocb(MAX(sizeof (dl_info_req_t), sizeof (dl_info_ack_t)),
2254bd670b35SErik Nordmark 	    BPRI_HI);
2255bd670b35SErik Nordmark 	if (info_mp == NULL)
2256bd670b35SErik Nordmark 		return (ENOMEM);
2257bd670b35SErik Nordmark 	/*
2258bd670b35SErik Nordmark 	 * allocate sufficient space to contain device name.
2259bd670b35SErik Nordmark 	 */
2260bd670b35SErik Nordmark 	arl->arl_name = (char *)(mi_zalloc(2 * LIFNAMSIZ));
2261bd670b35SErik Nordmark 	arl->arl_ppa = UINT_MAX;
2262bd670b35SErik Nordmark 	arl->arl_state_flags |= (ARL_LL_SUBNET_PENDING | ARL_LL_UNBOUND);
2263bd670b35SErik Nordmark 
2264bd670b35SErik Nordmark 	/* Send down the Info Request to the driver. */
2265bd670b35SErik Nordmark 	info_mp->b_datap->db_type = M_PCPROTO;
2266bd670b35SErik Nordmark 	dlir = (dl_info_req_t *)info_mp->b_rptr;
2267bd670b35SErik Nordmark 	info_mp->b_wptr = (uchar_t *)&dlir[1];
2268bd670b35SErik Nordmark 	dlir->dl_primitive = DL_INFO_REQ;
2269bd670b35SErik Nordmark 	arl->arl_dlpi_pending = DL_PRIM_INVAL;
2270bd670b35SErik Nordmark 	qprocson(q);
2271bd670b35SErik Nordmark 
2272bd670b35SErik Nordmark 	arp_dlpi_send(arl, info_mp);
2273bd670b35SErik Nordmark 	return (0);
2274bd670b35SErik Nordmark }
2275bd670b35SErik Nordmark 
2276bd670b35SErik Nordmark int
arl_wait_for_info_ack(arl_t * arl)2277bd670b35SErik Nordmark arl_wait_for_info_ack(arl_t *arl)
2278bd670b35SErik Nordmark {
2279bd670b35SErik Nordmark 	int err;
2280bd670b35SErik Nordmark 
2281bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
2282bd670b35SErik Nordmark 	while (arl->arl_state_flags & ARL_LL_SUBNET_PENDING) {
2283bd670b35SErik Nordmark 		/*
2284bd670b35SErik Nordmark 		 * Return value of 0 indicates a pending signal.
2285bd670b35SErik Nordmark 		 */
2286bd670b35SErik Nordmark 		err = cv_wait_sig(&arl->arl_cv, &arl->arl_lock);
2287bd670b35SErik Nordmark 		if (err == 0) {
2288bd670b35SErik Nordmark 			mutex_exit(&arl->arl_lock);
2289bd670b35SErik Nordmark 			return (EINTR);
2290bd670b35SErik Nordmark 		}
2291bd670b35SErik Nordmark 	}
2292bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
2293bd670b35SErik Nordmark 	/*
2294bd670b35SErik Nordmark 	 * ip_rput_other could have set an error  in ill_error on
2295bd670b35SErik Nordmark 	 * receipt of M_ERROR.
2296bd670b35SErik Nordmark 	 */
2297bd670b35SErik Nordmark 	return (arl->arl_error);
2298bd670b35SErik Nordmark }
2299bd670b35SErik Nordmark 
2300bd670b35SErik Nordmark void
arl_set_muxid(ill_t * ill,int muxid)2301bd670b35SErik Nordmark arl_set_muxid(ill_t *ill, int muxid)
2302bd670b35SErik Nordmark {
2303bd670b35SErik Nordmark 	arl_t *arl;
2304bd670b35SErik Nordmark 
2305bd670b35SErik Nordmark 	arl = ill_to_arl(ill);
2306bd670b35SErik Nordmark 	if (arl != NULL) {
2307bd670b35SErik Nordmark 		arl->arl_muxid = muxid;
2308bd670b35SErik Nordmark 		arl_refrele(arl);
2309bd670b35SErik Nordmark 	}
2310bd670b35SErik Nordmark }
2311bd670b35SErik Nordmark 
2312bd670b35SErik Nordmark int
arl_get_muxid(ill_t * ill)2313bd670b35SErik Nordmark arl_get_muxid(ill_t *ill)
2314bd670b35SErik Nordmark {
2315bd670b35SErik Nordmark 	arl_t *arl;
2316bd670b35SErik Nordmark 	int muxid = 0;
2317bd670b35SErik Nordmark 
2318bd670b35SErik Nordmark 	arl = ill_to_arl(ill);
2319bd670b35SErik Nordmark 	if (arl != NULL) {
2320bd670b35SErik Nordmark 		muxid = arl->arl_muxid;
2321bd670b35SErik Nordmark 		arl_refrele(arl);
2322bd670b35SErik Nordmark 	}
2323bd670b35SErik Nordmark 	return (muxid);
2324bd670b35SErik Nordmark }
2325bd670b35SErik Nordmark 
2326bd670b35SErik Nordmark static int
arp_modopen(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)2327bd670b35SErik Nordmark arp_modopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
2328bd670b35SErik Nordmark {
2329bd670b35SErik Nordmark 	int	err;
2330bd670b35SErik Nordmark 	zoneid_t zoneid;
2331bd670b35SErik Nordmark 	netstack_t *ns;
2332bd670b35SErik Nordmark 	ip_stack_t *ipst;
2333bd670b35SErik Nordmark 	arl_t	*arl = NULL;
2334bd670b35SErik Nordmark 
2335bd670b35SErik Nordmark 	/*
2336bd670b35SErik Nordmark 	 * Prevent unprivileged processes from pushing IP so that
2337bd670b35SErik Nordmark 	 * they can't send raw IP.
2338bd670b35SErik Nordmark 	 */
2339bd670b35SErik Nordmark 	if (secpolicy_net_rawaccess(credp) != 0)
2340bd670b35SErik Nordmark 		return (EPERM);
2341bd670b35SErik Nordmark 
2342bd670b35SErik Nordmark 	ns = netstack_find_by_cred(credp);
2343bd670b35SErik Nordmark 	ASSERT(ns != NULL);
2344bd670b35SErik Nordmark 	ipst = ns->netstack_ip;
2345bd670b35SErik Nordmark 	ASSERT(ipst != NULL);
2346bd670b35SErik Nordmark 
2347bd670b35SErik Nordmark 	/*
2348bd670b35SErik Nordmark 	 * For exclusive stacks we set the zoneid to zero
2349bd670b35SErik Nordmark 	 * to make IP operate as if in the global zone.
2350bd670b35SErik Nordmark 	 */
2351bd670b35SErik Nordmark 	if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
2352bd670b35SErik Nordmark 		zoneid = GLOBAL_ZONEID;
2353bd670b35SErik Nordmark 	else
2354bd670b35SErik Nordmark 		zoneid = crgetzoneid(credp);
2355bd670b35SErik Nordmark 
2356bd670b35SErik Nordmark 	arl = (arl_t *)mi_open_alloc_sleep(sizeof (arl_t));
2357bd670b35SErik Nordmark 	q->q_ptr = WR(q)->q_ptr = arl;
2358bd670b35SErik Nordmark 	arl->arl_ipst = ipst;
2359bd670b35SErik Nordmark 	arl->arl_zoneid = zoneid;
2360bd670b35SErik Nordmark 	err = arl_init(q, arl);
2361bd670b35SErik Nordmark 
2362bd670b35SErik Nordmark 	if (err != 0) {
2363bd670b35SErik Nordmark 		mi_free(arl->arl_name);
2364bd670b35SErik Nordmark 		mi_free(arl);
2365bd670b35SErik Nordmark 		netstack_rele(ipst->ips_netstack);
2366bd670b35SErik Nordmark 		q->q_ptr = NULL;
2367bd670b35SErik Nordmark 		WR(q)->q_ptr = NULL;
2368bd670b35SErik Nordmark 		return (err);
2369bd670b35SErik Nordmark 	}
2370bd670b35SErik Nordmark 
2371bd670b35SErik Nordmark 	/*
2372bd670b35SErik Nordmark 	 * Wait for the DL_INFO_ACK if a DL_INFO_REQ was sent.
2373bd670b35SErik Nordmark 	 */
2374bd670b35SErik Nordmark 	err = arl_wait_for_info_ack(arl);
2375bd670b35SErik Nordmark 	if (err == 0)
2376bd670b35SErik Nordmark 		arl->arl_credp = credp;
2377bd670b35SErik Nordmark 	else
2378bd670b35SErik Nordmark 		goto fail;
2379bd670b35SErik Nordmark 
2380bd670b35SErik Nordmark 	crhold(credp);
2381bd670b35SErik Nordmark 
2382bd670b35SErik Nordmark 	mutex_enter(&ipst->ips_ip_mi_lock);
2383bd670b35SErik Nordmark 	err = mi_open_link(&ipst->ips_arp_g_head, (IDP)q->q_ptr, devp, flag,
2384bd670b35SErik Nordmark 	    sflag, credp);
2385bd670b35SErik Nordmark 	mutex_exit(&ipst->ips_ip_mi_lock);
2386bd670b35SErik Nordmark fail:
2387bd670b35SErik Nordmark 	if (err) {
23885e1743f0SToomas Soome 		(void) arp_close(q, 0, credp);
2389bd670b35SErik Nordmark 		return (err);
2390bd670b35SErik Nordmark 	}
2391bd670b35SErik Nordmark 	return (0);
2392bd670b35SErik Nordmark }
2393bd670b35SErik Nordmark 
2394bd670b35SErik Nordmark /*
2395bd670b35SErik Nordmark  * Notify any downstream modules (esp softmac and hitbox) of the name
2396bd670b35SErik Nordmark  * of this interface using an M_CTL.
2397bd670b35SErik Nordmark  */
2398bd670b35SErik Nordmark static void
arp_ifname_notify(arl_t * arl)2399bd670b35SErik Nordmark arp_ifname_notify(arl_t *arl)
2400bd670b35SErik Nordmark {
2401bd670b35SErik Nordmark 	mblk_t *mp1, *mp2;
2402bd670b35SErik Nordmark 	struct iocblk *iocp;
2403bd670b35SErik Nordmark 	struct lifreq *lifr;
2404bd670b35SErik Nordmark 
2405bd670b35SErik Nordmark 	if ((mp1 = mkiocb(SIOCSLIFNAME)) == NULL)
2406bd670b35SErik Nordmark 		return;
2407bd670b35SErik Nordmark 	if ((mp2 = allocb(sizeof (struct lifreq), BPRI_HI)) == NULL) {
2408bd670b35SErik Nordmark 		freemsg(mp1);
2409bd670b35SErik Nordmark 		return;
2410bd670b35SErik Nordmark 	}
2411bd670b35SErik Nordmark 
2412bd670b35SErik Nordmark 	lifr = (struct lifreq *)mp2->b_rptr;
2413bd670b35SErik Nordmark 	mp2->b_wptr += sizeof (struct lifreq);
2414bd670b35SErik Nordmark 	bzero(lifr, sizeof (struct lifreq));
2415bd670b35SErik Nordmark 
2416bd670b35SErik Nordmark 	(void) strncpy(lifr->lifr_name, arl->arl_name, LIFNAMSIZ);
2417bd670b35SErik Nordmark 	lifr->lifr_ppa = arl->arl_ppa;
2418bd670b35SErik Nordmark 	lifr->lifr_flags = ILLF_IPV4;
2419bd670b35SErik Nordmark 
2420bd670b35SErik Nordmark 	/* Use M_CTL to avoid confusing anyone else who might be listening. */
2421bd670b35SErik Nordmark 	DB_TYPE(mp1) = M_CTL;
2422bd670b35SErik Nordmark 	mp1->b_cont = mp2;
2423bd670b35SErik Nordmark 	iocp = (struct iocblk *)mp1->b_rptr;
2424bd670b35SErik Nordmark 	iocp->ioc_count = msgsize(mp1->b_cont);
2425bd670b35SErik Nordmark 	DTRACE_PROBE4(arl__dlpi, char *, "arp_ifname_notify",
2426bd670b35SErik Nordmark 	    char *, "SIOCSLIFNAME", char *, "-",  arl_t *, arl);
2427bd670b35SErik Nordmark 	putnext(arl->arl_wq, mp1);
2428bd670b35SErik Nordmark }
2429bd670b35SErik Nordmark 
2430bd670b35SErik Nordmark void
arp_send_replumb_conf(ill_t * ill)2431bd670b35SErik Nordmark arp_send_replumb_conf(ill_t *ill)
2432bd670b35SErik Nordmark {
2433bd670b35SErik Nordmark 	mblk_t *mp;
2434bd670b35SErik Nordmark 	arl_t *arl = ill_to_arl(ill);
2435bd670b35SErik Nordmark 
2436bd670b35SErik Nordmark 	if (arl == NULL)
2437bd670b35SErik Nordmark 		return;
2438bd670b35SErik Nordmark 	/*
2439bd670b35SErik Nordmark 	 * arl_got_replumb and arl_got_unbind to be cleared after we complete
2440bd670b35SErik Nordmark 	 * arp_cmd_done.
2441bd670b35SErik Nordmark 	 */
2442bd670b35SErik Nordmark 	mp = mexchange(NULL, NULL, sizeof (dl_notify_conf_t), M_PROTO,
2443bd670b35SErik Nordmark 	    DL_NOTIFY_CONF);
2444bd670b35SErik Nordmark 	((dl_notify_conf_t *)(mp->b_rptr))->dl_notification =
2445bd670b35SErik Nordmark 	    DL_NOTE_REPLUMB_DONE;
2446bd670b35SErik Nordmark 	arp_dlpi_send(arl, mp);
2447bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
2448bd670b35SErik Nordmark 	arl->arl_state_flags &= ~ARL_LL_REPLUMBING;
2449bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
2450bd670b35SErik Nordmark 	arl_refrele(arl);
2451bd670b35SErik Nordmark }
2452bd670b35SErik Nordmark 
2453bd670b35SErik Nordmark /*
2454bd670b35SErik Nordmark  * The unplumb code paths call arp_unbind_complete() to make sure that it is
2455bd670b35SErik Nordmark  * safe to tear down the ill. We wait for DL_UNBIND_ACK to complete, and also
2456bd670b35SErik Nordmark  * for the arl_refcnt to fall to one so that, when we return from
2457bd670b35SErik Nordmark  * arp_unbind_complete(), we know for certain that there are no threads in
2458bd670b35SErik Nordmark  * arp_rput() that might access the arl_ill.
2459bd670b35SErik Nordmark  */
2460bd670b35SErik Nordmark void
arp_unbind_complete(ill_t * ill)2461bd670b35SErik Nordmark arp_unbind_complete(ill_t *ill)
2462bd670b35SErik Nordmark {
2463bd670b35SErik Nordmark 	arl_t *arl = ill_to_arl(ill);
2464bd670b35SErik Nordmark 
2465bd670b35SErik Nordmark 	if (arl == NULL)
2466bd670b35SErik Nordmark 		return;
2467bd670b35SErik Nordmark 	mutex_enter(&arl->arl_lock);
2468bd670b35SErik Nordmark 	/*
2469bd670b35SErik Nordmark 	 * wait for unbind ack and arl_refcnt to drop to 1. Note that the
2470bd670b35SErik Nordmark 	 * quiescent arl_refcnt for this function is 1 (and not 0) because
2471bd670b35SErik Nordmark 	 * ill_to_arl() will itself return after taking a ref on the arl_t.
2472bd670b35SErik Nordmark 	 */
2473bd670b35SErik Nordmark 	while (arl->arl_state_flags & ARL_DL_UNBIND_IN_PROGRESS)
2474bd670b35SErik Nordmark 		cv_wait(&arl->arl_cv, &arl->arl_lock);
2475bd670b35SErik Nordmark 	while (arl->arl_refcnt != 1)
2476bd670b35SErik Nordmark 		cv_wait(&arl->arl_cv, &arl->arl_lock);
2477bd670b35SErik Nordmark 	mutex_exit(&arl->arl_lock);
2478bd670b35SErik Nordmark 	arl_refrele(arl);
2479bd670b35SErik Nordmark }
2480