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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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