xref: /illumos-gate/usr/src/uts/common/io/dls/dls.c (revision 115f9ea8)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56b6515e2Sericheng  * Common Development and Distribution License (the "License").
66b6515e2Sericheng  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22ae6aa22aSVenugopal Iyer  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24cabb4db9SDan McDonald  * Copyright 2012, Nexenta Systems, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27cba073b1SRobert Mustacchi /*
289e4af98fSRobert Mustacchi  * Copyright 2019 Joyent, Inc.
29cba073b1SRobert Mustacchi  */
30cba073b1SRobert Mustacchi 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * Data-Link Services Module
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include	<sys/strsun.h>
367c478bd9Sstevel@tonic-gate #include	<sys/vlan.h>
37da14cebeSEric Cheng #include	<sys/dld_impl.h>
383bdd2dd4SMichael Lim #include	<sys/mac_client_priv.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate int
dls_open(dls_link_t * dlp,dls_dl_handle_t ddh,dld_str_t * dsp)41da14cebeSEric Cheng dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
427c478bd9Sstevel@tonic-gate {
43d62bc4baSyz 	zoneid_t	zid = getzoneid();
44d62bc4baSyz 	boolean_t	local;
453bdd2dd4SMichael Lim 	int		err;
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate 	/*
48da14cebeSEric Cheng 	 * Check whether this client belongs to the zone of this dlp. Note that
49da14cebeSEric Cheng 	 * a global zone client is allowed to open a local zone dlp.
507c478bd9Sstevel@tonic-gate 	 */
51da14cebeSEric Cheng 	if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid)
52d62bc4baSyz 		return (ENOENT);
537c478bd9Sstevel@tonic-gate 
545d460eafSCathy Zhou 	/*
555d460eafSCathy Zhou 	 * mac_start() is required for non-legacy MACs to show accurate
565d460eafSCathy Zhou 	 * kstats even before the interface is brought up. For legacy
575d460eafSCathy Zhou 	 * drivers, this is not needed. Further, calling mac_start() for
585d460eafSCathy Zhou 	 * legacy drivers would make the shared-lower-stream to stay in
595d460eafSCathy Zhou 	 * the DL_IDLE state, which in turn causes performance regression.
605d460eafSCathy Zhou 	 */
615d460eafSCathy Zhou 	if (!mac_capab_get(dlp->dl_mh, MAC_CAPAB_LEGACY, NULL) &&
625d460eafSCathy Zhou 	    ((err = mac_start(dlp->dl_mh)) != 0)) {
633bdd2dd4SMichael Lim 		return (err);
645d460eafSCathy Zhou 	}
653bdd2dd4SMichael Lim 
66da14cebeSEric Cheng 	local = (zid == dlp->dl_zid);
67da14cebeSEric Cheng 	dlp->dl_zone_ref += (local ? 1 : 0);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	/*
707c478bd9Sstevel@tonic-gate 	 * Cache a copy of the MAC interface handle, a pointer to the
71da14cebeSEric Cheng 	 * immutable MAC info.
727c478bd9Sstevel@tonic-gate 	 */
73da14cebeSEric Cheng 	dsp->ds_dlp = dlp;
74da14cebeSEric Cheng 	dsp->ds_mh = dlp->dl_mh;
75da14cebeSEric Cheng 	dsp->ds_mch = dlp->dl_mch;
76da14cebeSEric Cheng 	dsp->ds_mip = dlp->dl_mip;
77da14cebeSEric Cheng 	dsp->ds_ddh = ddh;
78da14cebeSEric Cheng 	dsp->ds_local = local;
797c478bd9Sstevel@tonic-gate 
80da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
817c478bd9Sstevel@tonic-gate 	return (0);
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate void
dls_close(dld_str_t * dsp)85da14cebeSEric Cheng dls_close(dld_str_t *dsp)
867c478bd9Sstevel@tonic-gate {
87da14cebeSEric Cheng 	dls_link_t		*dlp = dsp->ds_dlp;
887c478bd9Sstevel@tonic-gate 	dls_multicst_addr_t	*p;
897c478bd9Sstevel@tonic-gate 	dls_multicst_addr_t	*nextp;
90d62bc4baSyz 
91da14cebeSEric Cheng 	ASSERT(dsp->ds_datathr_cnt == 0);
92da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
937c478bd9Sstevel@tonic-gate 
94da14cebeSEric Cheng 	if (dsp->ds_local)
95da14cebeSEric Cheng 		dlp->dl_zone_ref--;
96da14cebeSEric Cheng 	dsp->ds_local = B_FALSE;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	/*
99da14cebeSEric Cheng 	 * Walk the list of multicast addresses, disabling each at the MAC.
100da14cebeSEric Cheng 	 * Note that we must remove multicast address before
101da14cebeSEric Cheng 	 * mac_unicast_remove() (called by dls_active_clear()) because
102da14cebeSEric Cheng 	 * mac_multicast_remove() relies on the unicast flows on the mac
103da14cebeSEric Cheng 	 * client.
1047c478bd9Sstevel@tonic-gate 	 */
105da14cebeSEric Cheng 	for (p = dsp->ds_dmap; p != NULL; p = nextp) {
106da14cebeSEric Cheng 		(void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
1077c478bd9Sstevel@tonic-gate 		nextp = p->dma_nextp;
1087c478bd9Sstevel@tonic-gate 		kmem_free(p, sizeof (dls_multicst_addr_t));
1097c478bd9Sstevel@tonic-gate 	}
110da14cebeSEric Cheng 	dsp->ds_dmap = NULL;
1117c478bd9Sstevel@tonic-gate 
1125d460eafSCathy Zhou 	dls_active_clear(dsp, B_TRUE);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	/*
115da14cebeSEric Cheng 	 * If the dld_str_t is bound then unbind it.
1167c478bd9Sstevel@tonic-gate 	 */
117da14cebeSEric Cheng 	if (dsp->ds_dlstate == DL_IDLE) {
1185ecc58b1SGirish Moodalbail 		dls_unbind(dsp);
119da14cebeSEric Cheng 		dsp->ds_dlstate = DL_UNBOUND;
120da14cebeSEric Cheng 	}
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	/*
123da14cebeSEric Cheng 	 * If the MAC has been set in promiscuous mode then disable it.
124da14cebeSEric Cheng 	 * This needs to be done before resetting ds_rx.
1257c478bd9Sstevel@tonic-gate 	 */
126cabb4db9SDan McDonald 	(void) dls_promisc(dsp, 0);
1274b46d1efSkrgopi 
1287c478bd9Sstevel@tonic-gate 	/*
129da14cebeSEric Cheng 	 * At this point we have cutoff inbound packet flow from the mac
130da14cebeSEric Cheng 	 * for this 'dsp'. The dls_link_remove above cut off packets meant
131da14cebeSEric Cheng 	 * for us and waited for upcalls to finish. Similarly the dls_promisc
132da14cebeSEric Cheng 	 * reset above waited for promisc callbacks to finish. Now we can
133da14cebeSEric Cheng 	 * safely reset ds_rx to NULL
1347c478bd9Sstevel@tonic-gate 	 */
135da14cebeSEric Cheng 	dsp->ds_rx = NULL;
136da14cebeSEric Cheng 	dsp->ds_rx_arg = NULL;
137d62bc4baSyz 
138da14cebeSEric Cheng 	dsp->ds_dlp = NULL;
139d62bc4baSyz 
1405d460eafSCathy Zhou 	if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
1415d460eafSCathy Zhou 		mac_stop(dsp->ds_mh);
1423bdd2dd4SMichael Lim 
1437c478bd9Sstevel@tonic-gate 	/*
144da14cebeSEric Cheng 	 * Release our reference to the dls_link_t allowing that to be
145da14cebeSEric Cheng 	 * destroyed if there are no more dls_impl_t.
1467c478bd9Sstevel@tonic-gate 	 */
147da14cebeSEric Cheng 	dls_link_rele(dlp);
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate int
dls_bind(dld_str_t * dsp,uint32_t sap)151da14cebeSEric Cheng dls_bind(dld_str_t *dsp, uint32_t sap)
1527c478bd9Sstevel@tonic-gate {
153ba2e4443Sseb 	uint32_t	dls_sap;
1547c478bd9Sstevel@tonic-gate 
155da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
156da14cebeSEric Cheng 
1577c478bd9Sstevel@tonic-gate 	/*
1587c478bd9Sstevel@tonic-gate 	 * Check to see the value is legal for the media type.
1597c478bd9Sstevel@tonic-gate 	 */
160da14cebeSEric Cheng 	if (!mac_sap_verify(dsp->ds_mh, sap, &dls_sap))
1617c478bd9Sstevel@tonic-gate 		return (EINVAL);
162da14cebeSEric Cheng 
163da14cebeSEric Cheng 	if (dsp->ds_promisc & DLS_PROMISC_SAP)
164ba2e4443Sseb 		dls_sap = DLS_SAP_PROMISC;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/*
167da14cebeSEric Cheng 	 * Set up the dld_str_t to mark it as able to receive packets.
1687c478bd9Sstevel@tonic-gate 	 */
169da14cebeSEric Cheng 	dsp->ds_sap = sap;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	/*
172da14cebeSEric Cheng 	 * The MAC layer does the VLAN demultiplexing and will only pass up
173da14cebeSEric Cheng 	 * untagged packets to non-promiscuous primary MAC clients. In order to
17484de666eSRyan Zezeski 	 * support binding to the VLAN SAP, which is required by DLPI, DLS
175da14cebeSEric Cheng 	 * needs to get a copy of all tagged packets when the client binds to
176da14cebeSEric Cheng 	 * the VLAN SAP. We do this by registering a separate promiscuous
17784de666eSRyan Zezeski 	 * callback for each DLS client binding to that SAP.
1787c478bd9Sstevel@tonic-gate 	 *
179da14cebeSEric Cheng 	 * Note: even though there are two promiscuous handles in dld_str_t,
180da14cebeSEric Cheng 	 * ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle
18184de666eSRyan Zezeski 	 * to receive VLAN traffic when promiscuous mode is not on. Only one of
18284de666eSRyan Zezeski 	 * them can be non-NULL at the same time, to avoid receiving duplicate
18384de666eSRyan Zezeski 	 * copies of packets.
184da14cebeSEric Cheng 	 */
185da14cebeSEric Cheng 	if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) {
186da14cebeSEric Cheng 		int err;
187da14cebeSEric Cheng 
188da14cebeSEric Cheng 		if (dsp->ds_vlan_mph != NULL)
189da14cebeSEric Cheng 			return (EINVAL);
190da14cebeSEric Cheng 		err = mac_promisc_add(dsp->ds_mch,
191da14cebeSEric Cheng 		    MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
192da14cebeSEric Cheng 		    &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
1938d4cf8d8S 
1948d4cf8d8S 		if (err == 0 && dsp->ds_nonip &&
1958d4cf8d8S 		    dsp->ds_dlp->dl_nonip_cnt++ == 0)
1968d4cf8d8S 			mac_rx_bypass_disable(dsp->ds_mch);
1978d4cf8d8S 
198da14cebeSEric Cheng 		return (err);
199da14cebeSEric Cheng 	}
2007c478bd9Sstevel@tonic-gate 
201da14cebeSEric Cheng 	/*
202da14cebeSEric Cheng 	 * Now bind the dld_str_t by adding it into the hash table in the
203da14cebeSEric Cheng 	 * dls_link_t.
204da14cebeSEric Cheng 	 */
205da14cebeSEric Cheng 	dls_link_add(dsp->ds_dlp, dls_sap, dsp);
2068d4cf8d8S 	if (dsp->ds_nonip && dsp->ds_dlp->dl_nonip_cnt++ == 0)
2078d4cf8d8S 		mac_rx_bypass_disable(dsp->ds_mch);
2088d4cf8d8S 
2097c478bd9Sstevel@tonic-gate 	return (0);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2125ecc58b1SGirish Moodalbail void
dls_unbind(dld_str_t * dsp)213da14cebeSEric Cheng dls_unbind(dld_str_t *dsp)
2147c478bd9Sstevel@tonic-gate {
215da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
2167c478bd9Sstevel@tonic-gate 
2178d4cf8d8S 	if (dsp->ds_nonip && --dsp->ds_dlp->dl_nonip_cnt == 0)
2188d4cf8d8S 		mac_rx_bypass_enable(dsp->ds_mch);
2198d4cf8d8S 
2207c478bd9Sstevel@tonic-gate 	/*
2219e4af98fSRobert Mustacchi 	 * A VLAN SAP does not actually add itself to the STREAM head today.
2229e4af98fSRobert Mustacchi 	 * While we initially set up a VLAN handle below, it's possible that
2239e4af98fSRobert Mustacchi 	 * something else will have come in and clobbered it.
2247c478bd9Sstevel@tonic-gate 	 */
2259e4af98fSRobert Mustacchi 	if (dsp->ds_sap == ETHERTYPE_VLAN) {
2269e4af98fSRobert Mustacchi 		if (dsp->ds_vlan_mph != NULL) {
2279e4af98fSRobert Mustacchi 			mac_promisc_remove(dsp->ds_vlan_mph);
2289e4af98fSRobert Mustacchi 			dsp->ds_vlan_mph = NULL;
2299e4af98fSRobert Mustacchi 		}
2305ecc58b1SGirish Moodalbail 		return;
231da14cebeSEric Cheng 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/*
234da14cebeSEric Cheng 	 * Unbind the dld_str_t by removing it from the hash table in the
235da14cebeSEric Cheng 	 * dls_link_t.
2367c478bd9Sstevel@tonic-gate 	 */
237da14cebeSEric Cheng 	dls_link_remove(dsp->ds_dlp, dsp);
238da14cebeSEric Cheng 	dsp->ds_sap = 0;
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate 
241cabb4db9SDan McDonald /*
242cabb4db9SDan McDonald  * In order to prevent promiscuous-mode processing with dsp->ds_promisc
243cabb4db9SDan McDonald  * set to inaccurate values, this function sets dsp->ds_promisc with new
244cabb4db9SDan McDonald  * flags.  For enabling (mac_promisc_add), the flags are set prior to the
245cabb4db9SDan McDonald  * actual enabling.  For disabling (mac_promisc_remove), the flags are set
246cabb4db9SDan McDonald  * after the actual disabling.
247cabb4db9SDan McDonald  */
2487c478bd9Sstevel@tonic-gate int
dls_promisc(dld_str_t * dsp,uint32_t new_flags)249cabb4db9SDan McDonald dls_promisc(dld_str_t *dsp, uint32_t new_flags)
2507c478bd9Sstevel@tonic-gate {
251cabb4db9SDan McDonald 	int err = 0;
252cabb4db9SDan McDonald 	uint32_t old_flags = dsp->ds_promisc;
253*115f9ea8SRobert Mustacchi 	const uint32_t option_flags = DLS_PROMISC_RX_ONLY;
254*115f9ea8SRobert Mustacchi 	uint32_t old_type = old_flags & ~option_flags;
255*115f9ea8SRobert Mustacchi 	uint32_t new_type = new_flags & ~option_flags;
256cba073b1SRobert Mustacchi 	mac_client_promisc_type_t mptype = MAC_CLIENT_PROMISC_ALL;
257*115f9ea8SRobert Mustacchi 	uint16_t mac_flags = 0;
2587c478bd9Sstevel@tonic-gate 
259da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
260cabb4db9SDan McDonald 	ASSERT(!(new_flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
261*115f9ea8SRobert Mustacchi 	    DLS_PROMISC_PHYS | option_flags)));
2627c478bd9Sstevel@tonic-gate 
263cba073b1SRobert Mustacchi 	/*
264cba073b1SRobert Mustacchi 	 * If the user has only requested DLS_PROMISC_MULTI then we need to make
265cba073b1SRobert Mustacchi 	 * sure that they don't see all packets.
266cba073b1SRobert Mustacchi 	 */
267*115f9ea8SRobert Mustacchi 	if (new_type == DLS_PROMISC_MULTI)
268cba073b1SRobert Mustacchi 		mptype = MAC_CLIENT_PROMISC_MULTI;
269cba073b1SRobert Mustacchi 
270*115f9ea8SRobert Mustacchi 	/*
271*115f9ea8SRobert Mustacchi 	 * Look at new flags and figure out the correct mac promisc flags.
272*115f9ea8SRobert Mustacchi 	 * If we've only requested DLS_PROMISC_SAP and not _MULTI or _PHYS,
273*115f9ea8SRobert Mustacchi 	 * don't turn on physical promisc mode.
274*115f9ea8SRobert Mustacchi 	 */
275*115f9ea8SRobert Mustacchi 	if (new_flags & DLS_PROMISC_RX_ONLY)
276*115f9ea8SRobert Mustacchi 		mac_flags |= MAC_PROMISC_FLAGS_NO_TX_LOOP;
277*115f9ea8SRobert Mustacchi 	if (new_type == DLS_PROMISC_SAP)
278*115f9ea8SRobert Mustacchi 		mac_flags |= MAC_PROMISC_FLAGS_NO_PHYS;
279*115f9ea8SRobert Mustacchi 
280*115f9ea8SRobert Mustacchi 	/*
281*115f9ea8SRobert Mustacchi 	 * There are three cases we care about here with respect to MAC. Going
282*115f9ea8SRobert Mustacchi 	 * from nothing to something, something to nothing, something to
283*115f9ea8SRobert Mustacchi 	 * something where we need to change how we're getting stuff from mac.
284*115f9ea8SRobert Mustacchi 	 * In the last case, as long as they're not equal, we need to assume
285*115f9ea8SRobert Mustacchi 	 * something has changed and do something about it.
286*115f9ea8SRobert Mustacchi 	 */
287*115f9ea8SRobert Mustacchi 	if (old_type == 0 && new_type == 0) {
288da14cebeSEric Cheng 		/*
289*115f9ea8SRobert Mustacchi 		 * If there are only option flags in the old and new flags
290*115f9ea8SRobert Mustacchi 		 * then there is no need to talk to MAC. Just update the flags.
291da14cebeSEric Cheng 		 */
292cabb4db9SDan McDonald 		dsp->ds_promisc = new_flags;
293*115f9ea8SRobert Mustacchi 	} else if (old_type == 0 && new_type != 0) {
294*115f9ea8SRobert Mustacchi 		dsp->ds_promisc = new_flags;
295cba073b1SRobert Mustacchi 		err = mac_promisc_add(dsp->ds_mch, mptype,
296*115f9ea8SRobert Mustacchi 		    dls_rx_promisc, dsp, &dsp->ds_mph, mac_flags);
297cabb4db9SDan McDonald 		if (err != 0) {
298cabb4db9SDan McDonald 			dsp->ds_promisc = old_flags;
299da14cebeSEric Cheng 			return (err);
300cabb4db9SDan McDonald 		}
301da14cebeSEric Cheng 
302da14cebeSEric Cheng 		/* Remove vlan promisc handle to avoid sending dup copy up */
303da14cebeSEric Cheng 		if (dsp->ds_vlan_mph != NULL) {
3045ecc58b1SGirish Moodalbail 			mac_promisc_remove(dsp->ds_vlan_mph);
305da14cebeSEric Cheng 			dsp->ds_vlan_mph = NULL;
30698b1442aSmeem 		}
307*115f9ea8SRobert Mustacchi 	} else if (old_type != 0 && new_type == 0) {
308da14cebeSEric Cheng 		ASSERT(dsp->ds_mph != NULL);
3095ecc58b1SGirish Moodalbail 
3105ecc58b1SGirish Moodalbail 		mac_promisc_remove(dsp->ds_mph);
311cabb4db9SDan McDonald 		dsp->ds_promisc = new_flags;
312da14cebeSEric Cheng 		dsp->ds_mph = NULL;
313da14cebeSEric Cheng 
314da14cebeSEric Cheng 		if (dsp->ds_sap == ETHERTYPE_VLAN &&
315da14cebeSEric Cheng 		    dsp->ds_dlstate != DL_UNBOUND) {
316da14cebeSEric Cheng 			if (dsp->ds_vlan_mph != NULL)
317da14cebeSEric Cheng 				return (EINVAL);
318da14cebeSEric Cheng 			err = mac_promisc_add(dsp->ds_mch,
319da14cebeSEric Cheng 			    MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
320da14cebeSEric Cheng 			    &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
32198b1442aSmeem 		}
322*115f9ea8SRobert Mustacchi 	} else if (new_flags != old_flags) {
323da14cebeSEric Cheng 		ASSERT(dsp->ds_mph != NULL);
3245ecc58b1SGirish Moodalbail 		mac_promisc_remove(dsp->ds_mph);
325cabb4db9SDan McDonald 		/* Honors both after-remove and before-add semantics! */
326cabb4db9SDan McDonald 		dsp->ds_promisc = new_flags;
327cba073b1SRobert Mustacchi 		err = mac_promisc_add(dsp->ds_mch, mptype,
328*115f9ea8SRobert Mustacchi 		    dls_rx_promisc, dsp, &dsp->ds_mph, mac_flags);
329cabb4db9SDan McDonald 		if (err != 0)
330cabb4db9SDan McDonald 			dsp->ds_promisc = old_flags;
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	return (err);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate int
dls_multicst_add(dld_str_t * dsp,const uint8_t * addr)337da14cebeSEric Cheng dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	int			err;
3407c478bd9Sstevel@tonic-gate 	dls_multicst_addr_t	**pp;
3417c478bd9Sstevel@tonic-gate 	dls_multicst_addr_t	*p;
3427c478bd9Sstevel@tonic-gate 	uint_t			addr_length;
3437c478bd9Sstevel@tonic-gate 
344da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
345da14cebeSEric Cheng 
3467c478bd9Sstevel@tonic-gate 	/*
3477c478bd9Sstevel@tonic-gate 	 * Check whether the address is in the list of enabled addresses for
348da14cebeSEric Cheng 	 * this dld_str_t.
349da14cebeSEric Cheng 	 */
350da14cebeSEric Cheng 	addr_length = dsp->ds_mip->mi_addr_length;
351da14cebeSEric Cheng 
352da14cebeSEric Cheng 	/*
353da14cebeSEric Cheng 	 * Protect against concurrent access of ds_dmap by data threads using
354da14cebeSEric Cheng 	 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
355da14cebeSEric Cheng 	 * remove operations. Dropping the ds_rw_lock across mac calls is thus
356da14cebeSEric Cheng 	 * ok and is also required by the locking protocol.
3577c478bd9Sstevel@tonic-gate 	 */
358da14cebeSEric Cheng 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
359da14cebeSEric Cheng 	for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
3607c478bd9Sstevel@tonic-gate 		if (bcmp(addr, p->dma_addr, addr_length) == 0) {
3617c478bd9Sstevel@tonic-gate 			/*
3627c478bd9Sstevel@tonic-gate 			 * It is there so there's nothing to do.
3637c478bd9Sstevel@tonic-gate 			 */
3647c478bd9Sstevel@tonic-gate 			err = 0;
3657c478bd9Sstevel@tonic-gate 			goto done;
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	/*
370da14cebeSEric Cheng 	 * Allocate a new list item and add it to the list.
3717c478bd9Sstevel@tonic-gate 	 */
372da14cebeSEric Cheng 	p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP);
373da14cebeSEric Cheng 	bcopy(addr, p->dma_addr, addr_length);
374da14cebeSEric Cheng 	*pp = p;
375da14cebeSEric Cheng 	rw_exit(&dsp->ds_rw_lock);
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	/*
3787c478bd9Sstevel@tonic-gate 	 * Enable the address at the MAC.
3797c478bd9Sstevel@tonic-gate 	 */
380da14cebeSEric Cheng 	err = mac_multicast_add(dsp->ds_mch, addr);
381da14cebeSEric Cheng 	if (err == 0)
382da14cebeSEric Cheng 		return (0);
3837c478bd9Sstevel@tonic-gate 
384da14cebeSEric Cheng 	/* Undo the operation as it has failed */
385da14cebeSEric Cheng 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
386da14cebeSEric Cheng 	ASSERT(*pp == p && p->dma_nextp == NULL);
387da14cebeSEric Cheng 	*pp = NULL;
388da14cebeSEric Cheng 	kmem_free(p, sizeof (dls_multicst_addr_t));
3897c478bd9Sstevel@tonic-gate done:
390da14cebeSEric Cheng 	rw_exit(&dsp->ds_rw_lock);
3917c478bd9Sstevel@tonic-gate 	return (err);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate int
dls_multicst_remove(dld_str_t * dsp,const uint8_t * addr)395da14cebeSEric Cheng dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr)
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate 	dls_multicst_addr_t	**pp;
3987c478bd9Sstevel@tonic-gate 	dls_multicst_addr_t	*p;
3997c478bd9Sstevel@tonic-gate 	uint_t			addr_length;
4007c478bd9Sstevel@tonic-gate 
401da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
402da14cebeSEric Cheng 
4037c478bd9Sstevel@tonic-gate 	/*
4047c478bd9Sstevel@tonic-gate 	 * Find the address in the list of enabled addresses for this
405da14cebeSEric Cheng 	 * dld_str_t.
4067c478bd9Sstevel@tonic-gate 	 */
407da14cebeSEric Cheng 	addr_length = dsp->ds_mip->mi_addr_length;
408da14cebeSEric Cheng 
409da14cebeSEric Cheng 	/*
410da14cebeSEric Cheng 	 * Protect against concurrent access to ds_dmap by data threads using
411da14cebeSEric Cheng 	 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
412da14cebeSEric Cheng 	 * remove operations. Dropping the ds_rw_lock across mac calls is thus
413da14cebeSEric Cheng 	 * ok and is also required by the locking protocol.
414da14cebeSEric Cheng 	 */
415da14cebeSEric Cheng 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
416da14cebeSEric Cheng 	for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
4177c478bd9Sstevel@tonic-gate 		if (bcmp(addr, p->dma_addr, addr_length) == 0)
4187c478bd9Sstevel@tonic-gate 			break;
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/*
4227c478bd9Sstevel@tonic-gate 	 * If we walked to the end of the list then the given address is
423da14cebeSEric Cheng 	 * not currently enabled for this dld_str_t.
4247c478bd9Sstevel@tonic-gate 	 */
4257c478bd9Sstevel@tonic-gate 	if (p == NULL) {
426da14cebeSEric Cheng 		rw_exit(&dsp->ds_rw_lock);
427da14cebeSEric Cheng 		return (ENOENT);
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/*
431da14cebeSEric Cheng 	 * Remove the address from the list.
4327c478bd9Sstevel@tonic-gate 	 */
433da14cebeSEric Cheng 	*pp = p->dma_nextp;
434da14cebeSEric Cheng 	rw_exit(&dsp->ds_rw_lock);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	/*
437da14cebeSEric Cheng 	 * Disable the address at the MAC.
4387c478bd9Sstevel@tonic-gate 	 */
439da14cebeSEric Cheng 	mac_multicast_remove(dsp->ds_mch, addr);
4407c478bd9Sstevel@tonic-gate 	kmem_free(p, sizeof (dls_multicst_addr_t));
441da14cebeSEric Cheng 	return (0);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate mblk_t *
dls_header(dld_str_t * dsp,const uint8_t * addr,uint16_t sap,uint_t pri,mblk_t ** payloadp)445da14cebeSEric Cheng dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri,
446605445d5Sdg     mblk_t **payloadp)
4477c478bd9Sstevel@tonic-gate {
448605445d5Sdg 	uint16_t vid;
449605445d5Sdg 	size_t extra_len;
450605445d5Sdg 	uint16_t mac_sap;
451605445d5Sdg 	mblk_t *mp, *payload;
452da14cebeSEric Cheng 	boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
453ba2e4443Sseb 	struct ether_vlan_header *evhp;
454ba2e4443Sseb 
455da14cebeSEric Cheng 	vid = mac_client_vid(dsp->ds_mch);
456605445d5Sdg 	payload = (payloadp == NULL) ? NULL : (*payloadp);
457605445d5Sdg 
458605445d5Sdg 	/*
459e75f0919SSebastien Roy 	 * In the case of Ethernet, we need to tell mac_header() if we need
460e75f0919SSebastien Roy 	 * extra room beyond the Ethernet header for a VLAN header.  We'll
461e75f0919SSebastien Roy 	 * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener
462e75f0919SSebastien Roy 	 * (because such streams will be handling VLAN headers on their own)
463e75f0919SSebastien Roy 	 * and one of the following conditions is satisfied:
464605445d5Sdg 	 *
465e75f0919SSebastien Roy 	 * - This is a VLAN stream
466e75f0919SSebastien Roy 	 * - This is a physical stream, the priority is not 0, and user
467e75f0919SSebastien Roy 	 *   priority tagging is allowed.
468605445d5Sdg 	 */
469605445d5Sdg 	if (is_ethernet && sap != ETHERTYPE_VLAN &&
470e75f0919SSebastien Roy 	    (vid != VLAN_ID_NONE ||
471e75f0919SSebastien Roy 	    (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) {
472ba2e4443Sseb 		extra_len = sizeof (struct ether_vlan_header) -
473ba2e4443Sseb 		    sizeof (struct ether_header);
474605445d5Sdg 		mac_sap = ETHERTYPE_VLAN;
475ba2e4443Sseb 	} else {
476ba2e4443Sseb 		extra_len = 0;
477ba2e4443Sseb 		mac_sap = sap;
478ba2e4443Sseb 	}
479ba2e4443Sseb 
480da14cebeSEric Cheng 	mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len);
481605445d5Sdg 	if (mp == NULL)
482605445d5Sdg 		return (NULL);
483605445d5Sdg 
484e75f0919SSebastien Roy 	if ((vid == VLAN_ID_NONE && (pri == 0 ||
485e75f0919SSebastien Roy 	    dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet)
486ba2e4443Sseb 		return (mp);
4877c478bd9Sstevel@tonic-gate 
488605445d5Sdg 	/*
489605445d5Sdg 	 * Fill in the tag information.
490605445d5Sdg 	 */
491ba2e4443Sseb 	ASSERT(MBLKL(mp) == sizeof (struct ether_header));
492605445d5Sdg 	if (extra_len != 0) {
493605445d5Sdg 		mp->b_wptr += extra_len;
494605445d5Sdg 		evhp = (struct ether_vlan_header *)mp->b_rptr;
495605445d5Sdg 		evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
496605445d5Sdg 		evhp->ether_type = htons(sap);
497605445d5Sdg 	} else {
498605445d5Sdg 		/*
499605445d5Sdg 		 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
500605445d5Sdg 		 * in the payload. Update the priority.
501605445d5Sdg 		 */
502605445d5Sdg 		struct ether_vlan_extinfo *extinfo;
503605445d5Sdg 		size_t len = sizeof (struct ether_vlan_extinfo);
504605445d5Sdg 
505605445d5Sdg 		ASSERT(sap == ETHERTYPE_VLAN);
506605445d5Sdg 		ASSERT(payload != NULL);
507605445d5Sdg 
508605445d5Sdg 		if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
509605445d5Sdg 			mblk_t *newmp;
510605445d5Sdg 
511605445d5Sdg 			/*
512605445d5Sdg 			 * Because some DLS consumers only check the db_ref
513605445d5Sdg 			 * count of the first mblk, we pullup 'payload' into
514605445d5Sdg 			 * a single mblk.
515605445d5Sdg 			 */
516605445d5Sdg 			newmp = msgpullup(payload, -1);
517605445d5Sdg 			if ((newmp == NULL) || (MBLKL(newmp) < len)) {
518605445d5Sdg 				freemsg(newmp);
519605445d5Sdg 				freemsg(mp);
520605445d5Sdg 				return (NULL);
521605445d5Sdg 			} else {
522605445d5Sdg 				freemsg(payload);
523605445d5Sdg 				*payloadp = payload = newmp;
524605445d5Sdg 			}
525605445d5Sdg 		}
526605445d5Sdg 
527605445d5Sdg 		extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
528605445d5Sdg 		extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
529605445d5Sdg 		    VLAN_ID(ntohs(extinfo->ether_tci))));
530605445d5Sdg 	}
531ba2e4443Sseb 	return (mp);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate void
dls_rx_set(dld_str_t * dsp,dls_rx_t rx,void * arg)535da14cebeSEric Cheng dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg)
5367c478bd9Sstevel@tonic-gate {
537da14cebeSEric Cheng 	mutex_enter(&dsp->ds_lock);
538da14cebeSEric Cheng 	dsp->ds_rx = rx;
539da14cebeSEric Cheng 	dsp->ds_rx_arg = arg;
540da14cebeSEric Cheng 	mutex_exit(&dsp->ds_lock);
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
543da14cebeSEric Cheng static boolean_t
dls_accept_common(dld_str_t * dsp,mac_header_info_t * mhip,dls_rx_t * ds_rx,void ** ds_rx_arg,boolean_t promisc,boolean_t promisc_loopback)544da14cebeSEric Cheng dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
545da14cebeSEric Cheng     void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	dls_multicst_addr_t	*dmap;
548da14cebeSEric Cheng 	size_t			addr_length = dsp->ds_mip->mi_addr_length;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	/*
551da14cebeSEric Cheng 	 * We must not accept packets if the dld_str_t is not marked as bound
5527c478bd9Sstevel@tonic-gate 	 * or is being removed.
5537c478bd9Sstevel@tonic-gate 	 */
554da14cebeSEric Cheng 	if (dsp->ds_dlstate != DL_IDLE)
5557c478bd9Sstevel@tonic-gate 		goto refuse;
5567c478bd9Sstevel@tonic-gate 
557da14cebeSEric Cheng 	if (dsp->ds_promisc != 0) {
558da14cebeSEric Cheng 		/*
559da14cebeSEric Cheng 		 * Filter out packets that arrived from the data path
560cba073b1SRobert Mustacchi 		 * (i_dls_link_rx) when promisc mode is on. We need to correlate
561cba073b1SRobert Mustacchi 		 * the ds_promisc flags with the mac header destination type. If
562cba073b1SRobert Mustacchi 		 * only DLS_PROMISC_MULTI is enabled, we need to only reject
563cba073b1SRobert Mustacchi 		 * multicast packets as those are the only ones which filter up
564cba073b1SRobert Mustacchi 		 * the promiscuous path. If we have DLS_PROMISC_PHYS or
565cba073b1SRobert Mustacchi 		 * DLS_PROMISC_SAP set, then we know that we'll be seeing
566cba073b1SRobert Mustacchi 		 * everything, so we should drop it now.
567da14cebeSEric Cheng 		 */
568cba073b1SRobert Mustacchi 		if (!promisc && !(dsp->ds_promisc == DLS_PROMISC_MULTI &&
569cba073b1SRobert Mustacchi 		    mhip->mhi_dsttype != MAC_ADDRTYPE_MULTICAST))
570da14cebeSEric Cheng 			goto refuse;
571da14cebeSEric Cheng 		/*
572da14cebeSEric Cheng 		 * If the dls_impl_t is in 'all physical' mode then
573da14cebeSEric Cheng 		 * always accept.
574da14cebeSEric Cheng 		 */
575da14cebeSEric Cheng 		if (dsp->ds_promisc & DLS_PROMISC_PHYS)
576da14cebeSEric Cheng 			goto accept;
5777c478bd9Sstevel@tonic-gate 
578da14cebeSEric Cheng 		/*
579da14cebeSEric Cheng 		 * Loopback packets i.e. packets sent out by DLS on a given
580da14cebeSEric Cheng 		 * mac end point, will be accepted back by DLS on loopback
581da14cebeSEric Cheng 		 * from the mac, only in the 'all physical' mode which has been
582da14cebeSEric Cheng 		 * covered by the previous check above
583da14cebeSEric Cheng 		 */
584da14cebeSEric Cheng 		if (promisc_loopback)
585da14cebeSEric Cheng 			goto refuse;
586da14cebeSEric Cheng 	}
587d62bc4baSyz 
588ba2e4443Sseb 	switch (mhip->mhi_dsttype) {
589ba2e4443Sseb 	case MAC_ADDRTYPE_UNICAST:
590da14cebeSEric Cheng 	case MAC_ADDRTYPE_BROADCAST:
591ba2e4443Sseb 		/*
592da14cebeSEric Cheng 		 * We can accept unicast and broadcast packets because
593da14cebeSEric Cheng 		 * filtering is already done by the mac layer.
594ba2e4443Sseb 		 */
595da14cebeSEric Cheng 		goto accept;
596ba2e4443Sseb 	case MAC_ADDRTYPE_MULTICAST:
597ba2e4443Sseb 		/*
598da14cebeSEric Cheng 		 * Additional filtering is needed for multicast addresses
599da14cebeSEric Cheng 		 * because different streams may be interested in different
600da14cebeSEric Cheng 		 * addresses.
601ba2e4443Sseb 		 */
602da14cebeSEric Cheng 		if (dsp->ds_promisc & DLS_PROMISC_MULTI)
6037c478bd9Sstevel@tonic-gate 			goto accept;
604da14cebeSEric Cheng 
605da14cebeSEric Cheng 		rw_enter(&dsp->ds_rw_lock, RW_READER);
606da14cebeSEric Cheng 		for (dmap = dsp->ds_dmap; dmap != NULL;
607ba2e4443Sseb 		    dmap = dmap->dma_nextp) {
608ba2e4443Sseb 			if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
609ba2e4443Sseb 			    addr_length) == 0) {
610da14cebeSEric Cheng 				rw_exit(&dsp->ds_rw_lock);
611ba2e4443Sseb 				goto accept;
612ba2e4443Sseb 			}
613ba2e4443Sseb 		}
614da14cebeSEric Cheng 		rw_exit(&dsp->ds_rw_lock);
615ba2e4443Sseb 		break;
6167c478bd9Sstevel@tonic-gate 	}
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate refuse:
6197c478bd9Sstevel@tonic-gate 	return (B_FALSE);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate accept:
622cd93090eSericheng 	/*
623da14cebeSEric Cheng 	 * the returned ds_rx and ds_rx_arg will always be in sync.
624cd93090eSericheng 	 */
625da14cebeSEric Cheng 	mutex_enter(&dsp->ds_lock);
626da14cebeSEric Cheng 	*ds_rx = dsp->ds_rx;
627da14cebeSEric Cheng 	*ds_rx_arg = dsp->ds_rx_arg;
628da14cebeSEric Cheng 	mutex_exit(&dsp->ds_lock);
629da14cebeSEric Cheng 
6307c478bd9Sstevel@tonic-gate 	return (B_TRUE);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
633605445d5Sdg /* ARGSUSED */
6347c478bd9Sstevel@tonic-gate boolean_t
dls_accept(dld_str_t * dsp,mac_header_info_t * mhip,dls_rx_t * ds_rx,void ** ds_rx_arg)635da14cebeSEric Cheng dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
636da14cebeSEric Cheng     void **ds_rx_arg)
6377c478bd9Sstevel@tonic-gate {
638da14cebeSEric Cheng 	return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE,
639da14cebeSEric Cheng 	    B_FALSE));
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate 
642d62bc4baSyz boolean_t
dls_accept_promisc(dld_str_t * dsp,mac_header_info_t * mhip,dls_rx_t * ds_rx,void ** ds_rx_arg,boolean_t loopback)643da14cebeSEric Cheng dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
644da14cebeSEric Cheng     void **ds_rx_arg, boolean_t loopback)
645da14cebeSEric Cheng {
646da14cebeSEric Cheng 	return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE,
647da14cebeSEric Cheng 	    loopback));
648da14cebeSEric Cheng }
649da14cebeSEric Cheng 
650da14cebeSEric Cheng int
dls_mac_active_set(dls_link_t * dlp)651d62bc4baSyz dls_mac_active_set(dls_link_t *dlp)
652d62bc4baSyz {
653da14cebeSEric Cheng 	int err = 0;
654d62bc4baSyz 
655d62bc4baSyz 	/*
656da14cebeSEric Cheng 	 * First client; add the primary unicast address.
657d62bc4baSyz 	 */
658da14cebeSEric Cheng 	if (dlp->dl_nactive == 0) {
659da14cebeSEric Cheng 		/*
660da14cebeSEric Cheng 		 * First client; add the primary unicast address.
661da14cebeSEric Cheng 		 */
662da14cebeSEric Cheng 		mac_diag_t diag;
663da14cebeSEric Cheng 
664da14cebeSEric Cheng 		/* request the primary MAC address */
6654c91d6c6SVenugopal Iyer 		if ((err = mac_unicast_add(dlp->dl_mch, NULL,
6664c91d6c6SVenugopal Iyer 		    MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE |
66784de666eSRyan Zezeski 		    MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah,
66884de666eSRyan Zezeski 		    VLAN_ID_NONE, &diag)) != 0) {
669da14cebeSEric Cheng 			return (err);
670da14cebeSEric Cheng 		}
671da14cebeSEric Cheng 
672da14cebeSEric Cheng 		/*
673da14cebeSEric Cheng 		 * Set the function to start receiving packets.
674da14cebeSEric Cheng 		 */
675da14cebeSEric Cheng 		mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp);
676d62bc4baSyz 	}
677d62bc4baSyz 	dlp->dl_nactive++;
678da14cebeSEric Cheng 	return (0);
679d62bc4baSyz }
680d62bc4baSyz 
681d62bc4baSyz void
dls_mac_active_clear(dls_link_t * dlp)682d62bc4baSyz dls_mac_active_clear(dls_link_t *dlp)
683d62bc4baSyz {
684da14cebeSEric Cheng 	if (--dlp->dl_nactive == 0) {
685da14cebeSEric Cheng 		ASSERT(dlp->dl_mah != NULL);
686da14cebeSEric Cheng 		(void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah);
687da14cebeSEric Cheng 		dlp->dl_mah = NULL;
688da14cebeSEric Cheng 		mac_rx_clear(dlp->dl_mch);
689da14cebeSEric Cheng 	}
690d62bc4baSyz }
691d62bc4baSyz 
692da14cebeSEric Cheng int
dls_active_set(dld_str_t * dsp)693da14cebeSEric Cheng dls_active_set(dld_str_t *dsp)
6947c478bd9Sstevel@tonic-gate {
695da14cebeSEric Cheng 	int err = 0;
6967c478bd9Sstevel@tonic-gate 
697da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
6987c478bd9Sstevel@tonic-gate 
6995d460eafSCathy Zhou 	if (dsp->ds_passivestate == DLD_PASSIVE)
700da14cebeSEric Cheng 		return (0);
7017c478bd9Sstevel@tonic-gate 
7025d460eafSCathy Zhou 	/* If we're already active, then there's nothing more to do. */
7035d460eafSCathy Zhou 	if ((dsp->ds_nactive == 0) &&
7045d460eafSCathy Zhou 	    ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) {
705da14cebeSEric Cheng 		/* except for ENXIO all other errors are mapped to EBUSY */
706da14cebeSEric Cheng 		if (err != ENXIO)
707da14cebeSEric Cheng 			return (EBUSY);
708da14cebeSEric Cheng 		return (err);
7097c478bd9Sstevel@tonic-gate 	}
710da14cebeSEric Cheng 
7115d460eafSCathy Zhou 	dsp->ds_passivestate = DLD_ACTIVE;
7125d460eafSCathy Zhou 	dsp->ds_nactive++;
713da14cebeSEric Cheng 	return (0);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate 
7165d460eafSCathy Zhou /*
7175d460eafSCathy Zhou  * Note that dls_active_set() is called whenever an active operation
7185d460eafSCathy Zhou  * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and
7195d460eafSCathy Zhou  * dls_active_clear(dsp, B_FALSE) is called whenever the active operation
7205d460eafSCathy Zhou  * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases,
7215d460eafSCathy Zhou  * a stream is closed without every active operation being undone and we
7225d460eafSCathy Zhou  * need to clear all the "active" states by calling
7235d460eafSCathy Zhou  * dls_active_clear(dsp, B_TRUE).
7245d460eafSCathy Zhou  */
7257c478bd9Sstevel@tonic-gate void
dls_active_clear(dld_str_t * dsp,boolean_t all)7265d460eafSCathy Zhou dls_active_clear(dld_str_t *dsp, boolean_t all)
7277c478bd9Sstevel@tonic-gate {
728da14cebeSEric Cheng 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
7297c478bd9Sstevel@tonic-gate 
7305d460eafSCathy Zhou 	if (dsp->ds_passivestate == DLD_PASSIVE)
7315d460eafSCathy Zhou 		return;
7325d460eafSCathy Zhou 
7335d460eafSCathy Zhou 	if (all && dsp->ds_nactive == 0)
7345d460eafSCathy Zhou 		return;
7355d460eafSCathy Zhou 
7365d460eafSCathy Zhou 	ASSERT(dsp->ds_nactive > 0);
7375d460eafSCathy Zhou 
7385d460eafSCathy Zhou 	dsp->ds_nactive -= (all ? dsp->ds_nactive : 1);
7395d460eafSCathy Zhou 	if (dsp->ds_nactive != 0)
740da14cebeSEric Cheng 		return;
741d62bc4baSyz 
7425d460eafSCathy Zhou 	ASSERT(dsp->ds_passivestate == DLD_ACTIVE);
743da14cebeSEric Cheng 	dls_mac_active_clear(dsp->ds_dlp);
7445d460eafSCathy Zhou 	dsp->ds_passivestate = DLD_UNINITIALIZED;
7457c478bd9Sstevel@tonic-gate }
746