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
277c478bd9Sstevel@tonic-gate /*
28*cba073b1SRobert Mustacchi * Copyright (c) 2013 Joyent, Inc. All rights reserved.
29*cba073b1SRobert Mustacchi */
30*cba073b1SRobert Mustacchi
31*cba073b1SRobert Mustacchi /*
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 {
43d62bc4baSyz147064 zoneid_t zid = getzoneid();
44d62bc4baSyz147064 boolean_t local;
453bdd2dd4SMichael Lim int err;
46d62bc4baSyz147064
47d62bc4baSyz147064 /*
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.
50d62bc4baSyz147064 */
51da14cebeSEric Cheng if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid)
52d62bc4baSyz147064 return (ENOENT);
53d62bc4baSyz147064
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;
90d62bc4baSyz147064
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);
113da14cebeSEric Cheng
114da14cebeSEric Cheng /*
115da14cebeSEric Cheng * If the dld_str_t is bound then unbind it.
116da14cebeSEric Cheng */
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 /*
1237c478bd9Sstevel@tonic-gate * 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);
1277c478bd9Sstevel@tonic-gate
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;
1374b46d1efSkrgopi
138da14cebeSEric Cheng dsp->ds_dlp = NULL;
1394b46d1efSkrgopi
1405d460eafSCathy Zhou if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
1413bdd2dd4SMichael Lim 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
174da14cebeSEric Cheng * support the 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
177da14cebeSEric Cheng * 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
181da14cebeSEric Cheng * to receive VLAN pkt when promiscuous mode is not on. Only one of
182da14cebeSEric Cheng * them can be non-NULL at the same time, to avoid receiving dup copies
183da14cebeSEric Cheng * of pkts.
1847c478bd9Sstevel@tonic-gate */
185da14cebeSEric Cheng if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) {
186da14cebeSEric Cheng int err;
1877c478bd9Sstevel@tonic-gate
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 }
200da14cebeSEric Cheng
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 /*
221da14cebeSEric Cheng * For VLAN SAP, there was a promisc handle registered when dls_bind.
222da14cebeSEric Cheng * When unbind this dls link, we need to remove the promisc handle.
223da14cebeSEric Cheng * See comments in dls_bind().
224da14cebeSEric Cheng */
225da14cebeSEric Cheng if (dsp->ds_vlan_mph != NULL) {
2265ecc58b1SGirish Moodalbail mac_promisc_remove(dsp->ds_vlan_mph);
227da14cebeSEric Cheng dsp->ds_vlan_mph = NULL;
2285ecc58b1SGirish Moodalbail return;
229da14cebeSEric Cheng }
230da14cebeSEric Cheng
231da14cebeSEric Cheng /*
232da14cebeSEric Cheng * Unbind the dld_str_t by removing it from the hash table in the
2337c478bd9Sstevel@tonic-gate * dls_link_t.
2347c478bd9Sstevel@tonic-gate */
235da14cebeSEric Cheng dls_link_remove(dsp->ds_dlp, dsp);
236da14cebeSEric Cheng dsp->ds_sap = 0;
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate
239cabb4db9SDan McDonald /*
240cabb4db9SDan McDonald * In order to prevent promiscuous-mode processing with dsp->ds_promisc
241cabb4db9SDan McDonald * set to inaccurate values, this function sets dsp->ds_promisc with new
242cabb4db9SDan McDonald * flags. For enabling (mac_promisc_add), the flags are set prior to the
243cabb4db9SDan McDonald * actual enabling. For disabling (mac_promisc_remove), the flags are set
244cabb4db9SDan McDonald * after the actual disabling.
245cabb4db9SDan McDonald */
2467c478bd9Sstevel@tonic-gate int
dls_promisc(dld_str_t * dsp,uint32_t new_flags)247cabb4db9SDan McDonald dls_promisc(dld_str_t *dsp, uint32_t new_flags)
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate int err = 0;
250cabb4db9SDan McDonald uint32_t old_flags = dsp->ds_promisc;
251*cba073b1SRobert Mustacchi mac_client_promisc_type_t mptype = MAC_CLIENT_PROMISC_ALL;
2527c478bd9Sstevel@tonic-gate
253da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
254cabb4db9SDan McDonald ASSERT(!(new_flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
2557c478bd9Sstevel@tonic-gate DLS_PROMISC_PHYS)));
2567c478bd9Sstevel@tonic-gate
257*cba073b1SRobert Mustacchi /*
258*cba073b1SRobert Mustacchi * If the user has only requested DLS_PROMISC_MULTI then we need to make
259*cba073b1SRobert Mustacchi * sure that they don't see all packets.
260*cba073b1SRobert Mustacchi */
261*cba073b1SRobert Mustacchi if (new_flags == DLS_PROMISC_MULTI)
262*cba073b1SRobert Mustacchi mptype = MAC_CLIENT_PROMISC_MULTI;
263*cba073b1SRobert Mustacchi
264cabb4db9SDan McDonald if (dsp->ds_promisc == 0 && new_flags != 0) {
2657c478bd9Sstevel@tonic-gate /*
266da14cebeSEric Cheng * If only DLS_PROMISC_SAP, we don't turn on the
267da14cebeSEric Cheng * physical promisc mode
2687c478bd9Sstevel@tonic-gate */
269cabb4db9SDan McDonald dsp->ds_promisc = new_flags;
270*cba073b1SRobert Mustacchi err = mac_promisc_add(dsp->ds_mch, mptype,
271da14cebeSEric Cheng dls_rx_promisc, dsp, &dsp->ds_mph,
272cabb4db9SDan McDonald (new_flags != DLS_PROMISC_SAP) ? 0 :
273da14cebeSEric Cheng MAC_PROMISC_FLAGS_NO_PHYS);
274cabb4db9SDan McDonald if (err != 0) {
275cabb4db9SDan McDonald dsp->ds_promisc = old_flags;
276da14cebeSEric Cheng return (err);
277cabb4db9SDan McDonald }
278d62bc4baSyz147064
279da14cebeSEric Cheng /* Remove vlan promisc handle to avoid sending dup copy up */
280da14cebeSEric Cheng if (dsp->ds_vlan_mph != NULL) {
2815ecc58b1SGirish Moodalbail mac_promisc_remove(dsp->ds_vlan_mph);
282da14cebeSEric Cheng dsp->ds_vlan_mph = NULL;
2837c478bd9Sstevel@tonic-gate }
284cabb4db9SDan McDonald } else if (dsp->ds_promisc != 0 && new_flags == 0) {
285da14cebeSEric Cheng ASSERT(dsp->ds_mph != NULL);
2865ecc58b1SGirish Moodalbail
2875ecc58b1SGirish Moodalbail mac_promisc_remove(dsp->ds_mph);
288cabb4db9SDan McDonald dsp->ds_promisc = new_flags;
289da14cebeSEric Cheng dsp->ds_mph = NULL;
290d62bc4baSyz147064
291da14cebeSEric Cheng if (dsp->ds_sap == ETHERTYPE_VLAN &&
292da14cebeSEric Cheng dsp->ds_dlstate != DL_UNBOUND) {
293da14cebeSEric Cheng if (dsp->ds_vlan_mph != NULL)
294da14cebeSEric Cheng return (EINVAL);
295da14cebeSEric Cheng err = mac_promisc_add(dsp->ds_mch,
296da14cebeSEric Cheng MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
297da14cebeSEric Cheng &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
2987c478bd9Sstevel@tonic-gate }
299cabb4db9SDan McDonald } else if (dsp->ds_promisc == DLS_PROMISC_SAP && new_flags != 0 &&
300cabb4db9SDan McDonald new_flags != dsp->ds_promisc) {
301da14cebeSEric Cheng /*
302da14cebeSEric Cheng * If the old flag is PROMISC_SAP, but the current flag has
303da14cebeSEric Cheng * changed to some new non-zero value, we need to turn the
304da14cebeSEric Cheng * physical promiscuous mode.
305da14cebeSEric Cheng */
306da14cebeSEric Cheng ASSERT(dsp->ds_mph != NULL);
3075ecc58b1SGirish Moodalbail mac_promisc_remove(dsp->ds_mph);
308cabb4db9SDan McDonald /* Honors both after-remove and before-add semantics! */
309cabb4db9SDan McDonald dsp->ds_promisc = new_flags;
310*cba073b1SRobert Mustacchi err = mac_promisc_add(dsp->ds_mch, mptype,
311da14cebeSEric Cheng dls_rx_promisc, dsp, &dsp->ds_mph, 0);
312cabb4db9SDan McDonald if (err != 0)
313cabb4db9SDan McDonald dsp->ds_promisc = old_flags;
314cabb4db9SDan McDonald } else {
315cabb4db9SDan McDonald /* No adding or removing, but record the new flags anyway. */
316cabb4db9SDan McDonald dsp->ds_promisc = new_flags;
31798b1442aSmeem }
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate return (err);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate int
dls_multicst_add(dld_str_t * dsp,const uint8_t * addr)323da14cebeSEric Cheng dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate int err;
3267c478bd9Sstevel@tonic-gate dls_multicst_addr_t **pp;
3277c478bd9Sstevel@tonic-gate dls_multicst_addr_t *p;
3287c478bd9Sstevel@tonic-gate uint_t addr_length;
3297c478bd9Sstevel@tonic-gate
330da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
331da14cebeSEric Cheng
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate * Check whether the address is in the list of enabled addresses for
334da14cebeSEric Cheng * this dld_str_t.
3357c478bd9Sstevel@tonic-gate */
336da14cebeSEric Cheng addr_length = dsp->ds_mip->mi_addr_length;
337da14cebeSEric Cheng
338da14cebeSEric Cheng /*
339da14cebeSEric Cheng * Protect against concurrent access of ds_dmap by data threads using
340da14cebeSEric Cheng * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
341da14cebeSEric Cheng * remove operations. Dropping the ds_rw_lock across mac calls is thus
342da14cebeSEric Cheng * ok and is also required by the locking protocol.
343da14cebeSEric Cheng */
344da14cebeSEric Cheng rw_enter(&dsp->ds_rw_lock, RW_WRITER);
345da14cebeSEric Cheng for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
3467c478bd9Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0) {
3477c478bd9Sstevel@tonic-gate /*
3487c478bd9Sstevel@tonic-gate * It is there so there's nothing to do.
3497c478bd9Sstevel@tonic-gate */
3507c478bd9Sstevel@tonic-gate err = 0;
3517c478bd9Sstevel@tonic-gate goto done;
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate
3557c478bd9Sstevel@tonic-gate /*
356da14cebeSEric Cheng * Allocate a new list item and add it to the list.
3577c478bd9Sstevel@tonic-gate */
358da14cebeSEric Cheng p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP);
359da14cebeSEric Cheng bcopy(addr, p->dma_addr, addr_length);
360da14cebeSEric Cheng *pp = p;
361da14cebeSEric Cheng rw_exit(&dsp->ds_rw_lock);
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate /*
3647c478bd9Sstevel@tonic-gate * Enable the address at the MAC.
3657c478bd9Sstevel@tonic-gate */
366da14cebeSEric Cheng err = mac_multicast_add(dsp->ds_mch, addr);
367da14cebeSEric Cheng if (err == 0)
368da14cebeSEric Cheng return (0);
369da14cebeSEric Cheng
370da14cebeSEric Cheng /* Undo the operation as it has failed */
371da14cebeSEric Cheng rw_enter(&dsp->ds_rw_lock, RW_WRITER);
372da14cebeSEric Cheng ASSERT(*pp == p && p->dma_nextp == NULL);
373da14cebeSEric Cheng *pp = NULL;
3747c478bd9Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t));
3757c478bd9Sstevel@tonic-gate done:
376da14cebeSEric Cheng rw_exit(&dsp->ds_rw_lock);
3777c478bd9Sstevel@tonic-gate return (err);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate int
dls_multicst_remove(dld_str_t * dsp,const uint8_t * addr)381da14cebeSEric Cheng dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate dls_multicst_addr_t **pp;
3847c478bd9Sstevel@tonic-gate dls_multicst_addr_t *p;
3857c478bd9Sstevel@tonic-gate uint_t addr_length;
3867c478bd9Sstevel@tonic-gate
387da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
388da14cebeSEric Cheng
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate * Find the address in the list of enabled addresses for this
391da14cebeSEric Cheng * dld_str_t.
3927c478bd9Sstevel@tonic-gate */
393da14cebeSEric Cheng addr_length = dsp->ds_mip->mi_addr_length;
394da14cebeSEric Cheng
395da14cebeSEric Cheng /*
396da14cebeSEric Cheng * Protect against concurrent access to ds_dmap by data threads using
397da14cebeSEric Cheng * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
398da14cebeSEric Cheng * remove operations. Dropping the ds_rw_lock across mac calls is thus
399da14cebeSEric Cheng * ok and is also required by the locking protocol.
400da14cebeSEric Cheng */
401da14cebeSEric Cheng rw_enter(&dsp->ds_rw_lock, RW_WRITER);
402da14cebeSEric Cheng for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
4037c478bd9Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0)
4047c478bd9Sstevel@tonic-gate break;
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate * If we walked to the end of the list then the given address is
409da14cebeSEric Cheng * not currently enabled for this dld_str_t.
4107c478bd9Sstevel@tonic-gate */
4117c478bd9Sstevel@tonic-gate if (p == NULL) {
412da14cebeSEric Cheng rw_exit(&dsp->ds_rw_lock);
413da14cebeSEric Cheng return (ENOENT);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate * Remove the address from the list.
4187c478bd9Sstevel@tonic-gate */
4197c478bd9Sstevel@tonic-gate *pp = p->dma_nextp;
420da14cebeSEric Cheng rw_exit(&dsp->ds_rw_lock);
4217c478bd9Sstevel@tonic-gate
422da14cebeSEric Cheng /*
423da14cebeSEric Cheng * Disable the address at the MAC.
424da14cebeSEric Cheng */
425da14cebeSEric Cheng mac_multicast_remove(dsp->ds_mch, addr);
426da14cebeSEric Cheng kmem_free(p, sizeof (dls_multicst_addr_t));
427da14cebeSEric Cheng return (0);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate mblk_t *
dls_header(dld_str_t * dsp,const uint8_t * addr,uint16_t sap,uint_t pri,mblk_t ** payloadp)431da14cebeSEric Cheng dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri,
432605445d5Sdg199075 mblk_t **payloadp)
4337c478bd9Sstevel@tonic-gate {
434ba2e4443Sseb uint16_t vid;
435ba2e4443Sseb size_t extra_len;
436ba2e4443Sseb uint16_t mac_sap;
437605445d5Sdg199075 mblk_t *mp, *payload;
438da14cebeSEric Cheng boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
439ba2e4443Sseb struct ether_vlan_header *evhp;
4407c478bd9Sstevel@tonic-gate
441da14cebeSEric Cheng vid = mac_client_vid(dsp->ds_mch);
442605445d5Sdg199075 payload = (payloadp == NULL) ? NULL : (*payloadp);
443605445d5Sdg199075
444ba2e4443Sseb /*
445e75f0919SSebastien Roy * In the case of Ethernet, we need to tell mac_header() if we need
446e75f0919SSebastien Roy * extra room beyond the Ethernet header for a VLAN header. We'll
447e75f0919SSebastien Roy * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener
448e75f0919SSebastien Roy * (because such streams will be handling VLAN headers on their own)
449e75f0919SSebastien Roy * and one of the following conditions is satisfied:
450605445d5Sdg199075 *
451e75f0919SSebastien Roy * - This is a VLAN stream
452e75f0919SSebastien Roy * - This is a physical stream, the priority is not 0, and user
453e75f0919SSebastien Roy * priority tagging is allowed.
454ba2e4443Sseb */
455605445d5Sdg199075 if (is_ethernet && sap != ETHERTYPE_VLAN &&
456e75f0919SSebastien Roy (vid != VLAN_ID_NONE ||
457e75f0919SSebastien Roy (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) {
458ba2e4443Sseb extra_len = sizeof (struct ether_vlan_header) -
459ba2e4443Sseb sizeof (struct ether_header);
460605445d5Sdg199075 mac_sap = ETHERTYPE_VLAN;
461ba2e4443Sseb } else {
462ba2e4443Sseb extra_len = 0;
463ba2e4443Sseb mac_sap = sap;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate
466da14cebeSEric Cheng mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len);
467605445d5Sdg199075 if (mp == NULL)
468605445d5Sdg199075 return (NULL);
469605445d5Sdg199075
470e75f0919SSebastien Roy if ((vid == VLAN_ID_NONE && (pri == 0 ||
471e75f0919SSebastien Roy dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet)
472ba2e4443Sseb return (mp);
4737c478bd9Sstevel@tonic-gate
474605445d5Sdg199075 /*
475605445d5Sdg199075 * Fill in the tag information.
476605445d5Sdg199075 */
477ba2e4443Sseb ASSERT(MBLKL(mp) == sizeof (struct ether_header));
478605445d5Sdg199075 if (extra_len != 0) {
479ba2e4443Sseb mp->b_wptr += extra_len;
480ba2e4443Sseb evhp = (struct ether_vlan_header *)mp->b_rptr;
481ba2e4443Sseb evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
482ba2e4443Sseb evhp->ether_type = htons(sap);
483605445d5Sdg199075 } else {
484605445d5Sdg199075 /*
485605445d5Sdg199075 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
486605445d5Sdg199075 * in the payload. Update the priority.
487605445d5Sdg199075 */
488605445d5Sdg199075 struct ether_vlan_extinfo *extinfo;
489605445d5Sdg199075 size_t len = sizeof (struct ether_vlan_extinfo);
490605445d5Sdg199075
491605445d5Sdg199075 ASSERT(sap == ETHERTYPE_VLAN);
492605445d5Sdg199075 ASSERT(payload != NULL);
493605445d5Sdg199075
494605445d5Sdg199075 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
495605445d5Sdg199075 mblk_t *newmp;
496605445d5Sdg199075
497605445d5Sdg199075 /*
498605445d5Sdg199075 * Because some DLS consumers only check the db_ref
499605445d5Sdg199075 * count of the first mblk, we pullup 'payload' into
500605445d5Sdg199075 * a single mblk.
501605445d5Sdg199075 */
502605445d5Sdg199075 newmp = msgpullup(payload, -1);
503605445d5Sdg199075 if ((newmp == NULL) || (MBLKL(newmp) < len)) {
504605445d5Sdg199075 freemsg(newmp);
505605445d5Sdg199075 freemsg(mp);
506605445d5Sdg199075 return (NULL);
507605445d5Sdg199075 } else {
508605445d5Sdg199075 freemsg(payload);
509605445d5Sdg199075 *payloadp = payload = newmp;
510605445d5Sdg199075 }
511605445d5Sdg199075 }
512605445d5Sdg199075
513605445d5Sdg199075 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
514605445d5Sdg199075 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
515605445d5Sdg199075 VLAN_ID(ntohs(extinfo->ether_tci))));
516605445d5Sdg199075 }
517ba2e4443Sseb return (mp);
518ba2e4443Sseb }
519ba2e4443Sseb
5207c478bd9Sstevel@tonic-gate void
dls_rx_set(dld_str_t * dsp,dls_rx_t rx,void * arg)521da14cebeSEric Cheng dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg)
5227c478bd9Sstevel@tonic-gate {
523da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
524da14cebeSEric Cheng dsp->ds_rx = rx;
525da14cebeSEric Cheng dsp->ds_rx_arg = arg;
526da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate
529da14cebeSEric 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)530da14cebeSEric Cheng dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
531da14cebeSEric Cheng void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate dls_multicst_addr_t *dmap;
534da14cebeSEric Cheng size_t addr_length = dsp->ds_mip->mi_addr_length;
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate /*
537da14cebeSEric Cheng * We must not accept packets if the dld_str_t is not marked as bound
5387c478bd9Sstevel@tonic-gate * or is being removed.
5397c478bd9Sstevel@tonic-gate */
540da14cebeSEric Cheng if (dsp->ds_dlstate != DL_IDLE)
5417c478bd9Sstevel@tonic-gate goto refuse;
5427c478bd9Sstevel@tonic-gate
543da14cebeSEric Cheng if (dsp->ds_promisc != 0) {
5447c478bd9Sstevel@tonic-gate /*
545da14cebeSEric Cheng * Filter out packets that arrived from the data path
546*cba073b1SRobert Mustacchi * (i_dls_link_rx) when promisc mode is on. We need to correlate
547*cba073b1SRobert Mustacchi * the ds_promisc flags with the mac header destination type. If
548*cba073b1SRobert Mustacchi * only DLS_PROMISC_MULTI is enabled, we need to only reject
549*cba073b1SRobert Mustacchi * multicast packets as those are the only ones which filter up
550*cba073b1SRobert Mustacchi * the promiscuous path. If we have DLS_PROMISC_PHYS or
551*cba073b1SRobert Mustacchi * DLS_PROMISC_SAP set, then we know that we'll be seeing
552*cba073b1SRobert Mustacchi * everything, so we should drop it now.
5537c478bd9Sstevel@tonic-gate */
554*cba073b1SRobert Mustacchi if (!promisc && !(dsp->ds_promisc == DLS_PROMISC_MULTI &&
555*cba073b1SRobert Mustacchi mhip->mhi_dsttype != MAC_ADDRTYPE_MULTICAST))
556da14cebeSEric Cheng goto refuse;
557da14cebeSEric Cheng /*
558da14cebeSEric Cheng * If the dls_impl_t is in 'all physical' mode then
559da14cebeSEric Cheng * always accept.
560da14cebeSEric Cheng */
561da14cebeSEric Cheng if (dsp->ds_promisc & DLS_PROMISC_PHYS)
5627c478bd9Sstevel@tonic-gate goto accept;
5637c478bd9Sstevel@tonic-gate
564d62bc4baSyz147064 /*
565da14cebeSEric Cheng * Loopback packets i.e. packets sent out by DLS on a given
566da14cebeSEric Cheng * mac end point, will be accepted back by DLS on loopback
567da14cebeSEric Cheng * from the mac, only in the 'all physical' mode which has been
568da14cebeSEric Cheng * covered by the previous check above
569d62bc4baSyz147064 */
570da14cebeSEric Cheng if (promisc_loopback)
571d62bc4baSyz147064 goto refuse;
572da14cebeSEric Cheng }
573d62bc4baSyz147064
574ba2e4443Sseb switch (mhip->mhi_dsttype) {
575ba2e4443Sseb case MAC_ADDRTYPE_UNICAST:
576da14cebeSEric Cheng case MAC_ADDRTYPE_BROADCAST:
5777c478bd9Sstevel@tonic-gate /*
578da14cebeSEric Cheng * We can accept unicast and broadcast packets because
579da14cebeSEric Cheng * filtering is already done by the mac layer.
5807c478bd9Sstevel@tonic-gate */
5817c478bd9Sstevel@tonic-gate goto accept;
582ba2e4443Sseb case MAC_ADDRTYPE_MULTICAST:
5837c478bd9Sstevel@tonic-gate /*
584da14cebeSEric Cheng * Additional filtering is needed for multicast addresses
585da14cebeSEric Cheng * because different streams may be interested in different
586da14cebeSEric Cheng * addresses.
5877c478bd9Sstevel@tonic-gate */
588da14cebeSEric Cheng if (dsp->ds_promisc & DLS_PROMISC_MULTI)
5897c478bd9Sstevel@tonic-gate goto accept;
590da14cebeSEric Cheng
591da14cebeSEric Cheng rw_enter(&dsp->ds_rw_lock, RW_READER);
592da14cebeSEric Cheng for (dmap = dsp->ds_dmap; dmap != NULL;
593ba2e4443Sseb dmap = dmap->dma_nextp) {
594ba2e4443Sseb if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
595ba2e4443Sseb addr_length) == 0) {
596da14cebeSEric Cheng rw_exit(&dsp->ds_rw_lock);
597ba2e4443Sseb goto accept;
598ba2e4443Sseb }
599ba2e4443Sseb }
600da14cebeSEric Cheng rw_exit(&dsp->ds_rw_lock);
601ba2e4443Sseb break;
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate refuse:
6057c478bd9Sstevel@tonic-gate return (B_FALSE);
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate accept:
608cd93090eSericheng /*
609da14cebeSEric Cheng * the returned ds_rx and ds_rx_arg will always be in sync.
610cd93090eSericheng */
611da14cebeSEric Cheng mutex_enter(&dsp->ds_lock);
612da14cebeSEric Cheng *ds_rx = dsp->ds_rx;
613da14cebeSEric Cheng *ds_rx_arg = dsp->ds_rx_arg;
614da14cebeSEric Cheng mutex_exit(&dsp->ds_lock);
615da14cebeSEric Cheng
6167c478bd9Sstevel@tonic-gate return (B_TRUE);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate
619605445d5Sdg199075 /* ARGSUSED */
6207c478bd9Sstevel@tonic-gate boolean_t
dls_accept(dld_str_t * dsp,mac_header_info_t * mhip,dls_rx_t * ds_rx,void ** ds_rx_arg)621da14cebeSEric Cheng dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
622da14cebeSEric Cheng void **ds_rx_arg)
6237c478bd9Sstevel@tonic-gate {
624da14cebeSEric Cheng return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE,
625da14cebeSEric Cheng B_FALSE));
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate 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)629da14cebeSEric Cheng dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
630da14cebeSEric Cheng void **ds_rx_arg, boolean_t loopback)
631da14cebeSEric Cheng {
632da14cebeSEric Cheng return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE,
633da14cebeSEric Cheng loopback));
634da14cebeSEric Cheng }
635da14cebeSEric Cheng
636da14cebeSEric Cheng int
dls_mac_active_set(dls_link_t * dlp)637d62bc4baSyz147064 dls_mac_active_set(dls_link_t *dlp)
638d62bc4baSyz147064 {
639da14cebeSEric Cheng int err = 0;
640d62bc4baSyz147064
641d62bc4baSyz147064 /*
642da14cebeSEric Cheng * First client; add the primary unicast address.
643d62bc4baSyz147064 */
644da14cebeSEric Cheng if (dlp->dl_nactive == 0) {
645da14cebeSEric Cheng /*
646da14cebeSEric Cheng * First client; add the primary unicast address.
647da14cebeSEric Cheng */
648da14cebeSEric Cheng mac_diag_t diag;
649da14cebeSEric Cheng
650da14cebeSEric Cheng /* request the primary MAC address */
6514c91d6c6SVenugopal Iyer if ((err = mac_unicast_add(dlp->dl_mch, NULL,
6524c91d6c6SVenugopal Iyer MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE |
6534c91d6c6SVenugopal Iyer MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah, 0,
654da14cebeSEric Cheng &diag)) != 0) {
655da14cebeSEric Cheng return (err);
656da14cebeSEric Cheng }
657da14cebeSEric Cheng
658da14cebeSEric Cheng /*
659da14cebeSEric Cheng * Set the function to start receiving packets.
660da14cebeSEric Cheng */
661da14cebeSEric Cheng mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp);
662d62bc4baSyz147064 }
663d62bc4baSyz147064 dlp->dl_nactive++;
664da14cebeSEric Cheng return (0);
665d62bc4baSyz147064 }
666d62bc4baSyz147064
667d62bc4baSyz147064 void
dls_mac_active_clear(dls_link_t * dlp)668d62bc4baSyz147064 dls_mac_active_clear(dls_link_t *dlp)
669d62bc4baSyz147064 {
670da14cebeSEric Cheng if (--dlp->dl_nactive == 0) {
671da14cebeSEric Cheng ASSERT(dlp->dl_mah != NULL);
672da14cebeSEric Cheng (void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah);
673da14cebeSEric Cheng dlp->dl_mah = NULL;
674da14cebeSEric Cheng mac_rx_clear(dlp->dl_mch);
675da14cebeSEric Cheng }
676d62bc4baSyz147064 }
677d62bc4baSyz147064
678da14cebeSEric Cheng int
dls_active_set(dld_str_t * dsp)679da14cebeSEric Cheng dls_active_set(dld_str_t *dsp)
6807c478bd9Sstevel@tonic-gate {
681da14cebeSEric Cheng int err = 0;
6827c478bd9Sstevel@tonic-gate
683da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
6847c478bd9Sstevel@tonic-gate
6855d460eafSCathy Zhou if (dsp->ds_passivestate == DLD_PASSIVE)
686da14cebeSEric Cheng return (0);
687da14cebeSEric Cheng
6885d460eafSCathy Zhou /* If we're already active, then there's nothing more to do. */
6895d460eafSCathy Zhou if ((dsp->ds_nactive == 0) &&
6905d460eafSCathy Zhou ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) {
691da14cebeSEric Cheng /* except for ENXIO all other errors are mapped to EBUSY */
692da14cebeSEric Cheng if (err != ENXIO)
693da14cebeSEric Cheng return (EBUSY);
694da14cebeSEric Cheng return (err);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate
6975d460eafSCathy Zhou dsp->ds_passivestate = DLD_ACTIVE;
6985d460eafSCathy Zhou dsp->ds_nactive++;
699da14cebeSEric Cheng return (0);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate
7025d460eafSCathy Zhou /*
7035d460eafSCathy Zhou * Note that dls_active_set() is called whenever an active operation
7045d460eafSCathy Zhou * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and
7055d460eafSCathy Zhou * dls_active_clear(dsp, B_FALSE) is called whenever the active operation
7065d460eafSCathy Zhou * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases,
7075d460eafSCathy Zhou * a stream is closed without every active operation being undone and we
7085d460eafSCathy Zhou * need to clear all the "active" states by calling
7095d460eafSCathy Zhou * dls_active_clear(dsp, B_TRUE).
7105d460eafSCathy Zhou */
7117c478bd9Sstevel@tonic-gate void
dls_active_clear(dld_str_t * dsp,boolean_t all)7125d460eafSCathy Zhou dls_active_clear(dld_str_t *dsp, boolean_t all)
7137c478bd9Sstevel@tonic-gate {
714da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
7157c478bd9Sstevel@tonic-gate
7165d460eafSCathy Zhou if (dsp->ds_passivestate == DLD_PASSIVE)
717da14cebeSEric Cheng return;
7187c478bd9Sstevel@tonic-gate
7195d460eafSCathy Zhou if (all && dsp->ds_nactive == 0)
7205d460eafSCathy Zhou return;
7215d460eafSCathy Zhou
7225d460eafSCathy Zhou ASSERT(dsp->ds_nactive > 0);
7235d460eafSCathy Zhou
7245d460eafSCathy Zhou dsp->ds_nactive -= (all ? dsp->ds_nactive : 1);
7255d460eafSCathy Zhou if (dsp->ds_nactive != 0)
7265d460eafSCathy Zhou return;
7275d460eafSCathy Zhou
7285d460eafSCathy Zhou ASSERT(dsp->ds_passivestate == DLD_ACTIVE);
729da14cebeSEric Cheng dls_mac_active_clear(dsp->ds_dlp);
7305d460eafSCathy Zhou dsp->ds_passivestate = DLD_UNINITIALIZED;
7317c478bd9Sstevel@tonic-gate }
732