Home | History | Annotate | Download | only in dls
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * Data-Link Services Module
     28  */
     29 
     30 #include	<sys/strsun.h>
     31 #include	<sys/vlan.h>
     32 #include	<sys/dld_impl.h>
     33 #include	<sys/mac_client_priv.h>
     34 
     35 int
     36 dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
     37 {
     38 	zoneid_t	zid = getzoneid();
     39 	boolean_t	local;
     40 	int		err;
     41 
     42 	/*
     43 	 * Check whether this client belongs to the zone of this dlp. Note that
     44 	 * a global zone client is allowed to open a local zone dlp.
     45 	 */
     46 	if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid)
     47 		return (ENOENT);
     48 
     49 	/*
     50 	 * mac_start() is required for non-legacy MACs to show accurate
     51 	 * kstats even before the interface is brought up. For legacy
     52 	 * drivers, this is not needed. Further, calling mac_start() for
     53 	 * legacy drivers would make the shared-lower-stream to stay in
     54 	 * the DL_IDLE state, which in turn causes performance regression.
     55 	 */
     56 	if (!mac_capab_get(dlp->dl_mh, MAC_CAPAB_LEGACY, NULL) &&
     57 	    ((err = mac_start(dlp->dl_mh)) != 0)) {
     58 		return (err);
     59 	}
     60 
     61 	local = (zid == dlp->dl_zid);
     62 	dlp->dl_zone_ref += (local ? 1 : 0);
     63 
     64 	/*
     65 	 * Cache a copy of the MAC interface handle, a pointer to the
     66 	 * immutable MAC info.
     67 	 */
     68 	dsp->ds_dlp = dlp;
     69 	dsp->ds_mh = dlp->dl_mh;
     70 	dsp->ds_mch = dlp->dl_mch;
     71 	dsp->ds_mip = dlp->dl_mip;
     72 	dsp->ds_ddh = ddh;
     73 	dsp->ds_local = local;
     74 
     75 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
     76 	return (0);
     77 }
     78 
     79 void
     80 dls_close(dld_str_t *dsp)
     81 {
     82 	dls_link_t		*dlp = dsp->ds_dlp;
     83 	dls_multicst_addr_t	*p;
     84 	dls_multicst_addr_t	*nextp;
     85 	uint32_t		old_flags;
     86 
     87 	ASSERT(dsp->ds_datathr_cnt == 0);
     88 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
     89 
     90 	if (dsp->ds_local)
     91 		dlp->dl_zone_ref--;
     92 	dsp->ds_local = B_FALSE;
     93 
     94 	/*
     95 	 * Walk the list of multicast addresses, disabling each at the MAC.
     96 	 * Note that we must remove multicast address before
     97 	 * mac_unicast_remove() (called by dls_active_clear()) because
     98 	 * mac_multicast_remove() relies on the unicast flows on the mac
     99 	 * client.
    100 	 */
    101 	for (p = dsp->ds_dmap; p != NULL; p = nextp) {
    102 		(void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
    103 		nextp = p->dma_nextp;
    104 		kmem_free(p, sizeof (dls_multicst_addr_t));
    105 	}
    106 	dsp->ds_dmap = NULL;
    107 
    108 	dls_active_clear(dsp, B_TRUE);
    109 
    110 	/*
    111 	 * If the dld_str_t is bound then unbind it.
    112 	 */
    113 	if (dsp->ds_dlstate == DL_IDLE) {
    114 		dls_unbind(dsp);
    115 		dsp->ds_dlstate = DL_UNBOUND;
    116 	}
    117 
    118 	/*
    119 	 * If the MAC has been set in promiscuous mode then disable it.
    120 	 * This needs to be done before resetting ds_rx.
    121 	 */
    122 	old_flags = dsp->ds_promisc;
    123 	dsp->ds_promisc = 0;
    124 	(void) dls_promisc(dsp, old_flags);
    125 
    126 	/*
    127 	 * At this point we have cutoff inbound packet flow from the mac
    128 	 * for this 'dsp'. The dls_link_remove above cut off packets meant
    129 	 * for us and waited for upcalls to finish. Similarly the dls_promisc
    130 	 * reset above waited for promisc callbacks to finish. Now we can
    131 	 * safely reset ds_rx to NULL
    132 	 */
    133 	dsp->ds_rx = NULL;
    134 	dsp->ds_rx_arg = NULL;
    135 
    136 	dsp->ds_dlp = NULL;
    137 
    138 	if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
    139 		mac_stop(dsp->ds_mh);
    140 
    141 	/*
    142 	 * Release our reference to the dls_link_t allowing that to be
    143 	 * destroyed if there are no more dls_impl_t.
    144 	 */
    145 	dls_link_rele(dlp);
    146 }
    147 
    148 int
    149 dls_bind(dld_str_t *dsp, uint32_t sap)
    150 {
    151 	uint32_t	dls_sap;
    152 
    153 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    154 
    155 	/*
    156 	 * Check to see the value is legal for the media type.
    157 	 */
    158 	if (!mac_sap_verify(dsp->ds_mh, sap, &dls_sap))
    159 		return (EINVAL);
    160 
    161 	if (dsp->ds_promisc & DLS_PROMISC_SAP)
    162 		dls_sap = DLS_SAP_PROMISC;
    163 
    164 	/*
    165 	 * Set up the dld_str_t to mark it as able to receive packets.
    166 	 */
    167 	dsp->ds_sap = sap;
    168 
    169 	/*
    170 	 * The MAC layer does the VLAN demultiplexing and will only pass up
    171 	 * untagged packets to non-promiscuous primary MAC clients. In order to
    172 	 * support the binding to the VLAN SAP which is required by DLPI, dls
    173 	 * needs to get a copy of all tagged packets when the client binds to
    174 	 * the VLAN SAP. We do this by registering a separate promiscuous
    175 	 * callback for each dls client binding to that SAP.
    176 	 *
    177 	 * Note: even though there are two promiscuous handles in dld_str_t,
    178 	 * ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle
    179 	 * to receive VLAN pkt when promiscuous mode is not on. Only one of
    180 	 * them can be non-NULL at the same time, to avoid receiving dup copies
    181 	 * of pkts.
    182 	 */
    183 	if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) {
    184 		int err;
    185 
    186 		if (dsp->ds_vlan_mph != NULL)
    187 			return (EINVAL);
    188 		err = mac_promisc_add(dsp->ds_mch,
    189 		    MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
    190 		    &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
    191 
    192 		if (err == 0 && dsp->ds_nonip &&
    193 		    dsp->ds_dlp->dl_nonip_cnt++ == 0)
    194 			mac_rx_bypass_disable(dsp->ds_mch);
    195 
    196 		return (err);
    197 	}
    198 
    199 	/*
    200 	 * Now bind the dld_str_t by adding it into the hash table in the
    201 	 * dls_link_t.
    202 	 */
    203 	dls_link_add(dsp->ds_dlp, dls_sap, dsp);
    204 	if (dsp->ds_nonip && dsp->ds_dlp->dl_nonip_cnt++ == 0)
    205 		mac_rx_bypass_disable(dsp->ds_mch);
    206 
    207 	return (0);
    208 }
    209 
    210 void
    211 dls_unbind(dld_str_t *dsp)
    212 {
    213 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    214 
    215 	if (dsp->ds_nonip && --dsp->ds_dlp->dl_nonip_cnt == 0)
    216 		mac_rx_bypass_enable(dsp->ds_mch);
    217 
    218 	/*
    219 	 * For VLAN SAP, there was a promisc handle registered when dls_bind.
    220 	 * When unbind this dls link, we need to remove the promisc handle.
    221 	 * See comments in dls_bind().
    222 	 */
    223 	if (dsp->ds_vlan_mph != NULL) {
    224 		mac_promisc_remove(dsp->ds_vlan_mph);
    225 		dsp->ds_vlan_mph = NULL;
    226 		return;
    227 	}
    228 
    229 	/*
    230 	 * Unbind the dld_str_t by removing it from the hash table in the
    231 	 * dls_link_t.
    232 	 */
    233 	dls_link_remove(dsp->ds_dlp, dsp);
    234 	dsp->ds_sap = 0;
    235 }
    236 
    237 int
    238 dls_promisc(dld_str_t *dsp, uint32_t old_flags)
    239 {
    240 	int		err = 0;
    241 
    242 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    243 	ASSERT(!(dsp->ds_promisc & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
    244 	    DLS_PROMISC_PHYS)));
    245 
    246 	if (old_flags == 0 && dsp->ds_promisc != 0) {
    247 		/*
    248 		 * If only DLS_PROMISC_SAP, we don't turn on the
    249 		 * physical promisc mode
    250 		 */
    251 		err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
    252 		    dls_rx_promisc, dsp, &dsp->ds_mph,
    253 		    (dsp->ds_promisc != DLS_PROMISC_SAP) ? 0 :
    254 		    MAC_PROMISC_FLAGS_NO_PHYS);
    255 		if (err != 0)
    256 			return (err);
    257 
    258 		/* Remove vlan promisc handle to avoid sending dup copy up */
    259 		if (dsp->ds_vlan_mph != NULL) {
    260 			mac_promisc_remove(dsp->ds_vlan_mph);
    261 			dsp->ds_vlan_mph = NULL;
    262 		}
    263 	} else if (old_flags != 0 && dsp->ds_promisc == 0) {
    264 		ASSERT(dsp->ds_mph != NULL);
    265 
    266 		mac_promisc_remove(dsp->ds_mph);
    267 		dsp->ds_mph = NULL;
    268 
    269 		if (dsp->ds_sap == ETHERTYPE_VLAN &&
    270 		    dsp->ds_dlstate != DL_UNBOUND) {
    271 			int err;
    272 
    273 			if (dsp->ds_vlan_mph != NULL)
    274 				return (EINVAL);
    275 			err = mac_promisc_add(dsp->ds_mch,
    276 			    MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
    277 			    &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
    278 			return (err);
    279 		}
    280 	} else if (old_flags == DLS_PROMISC_SAP && dsp->ds_promisc != 0 &&
    281 	    dsp->ds_promisc != old_flags) {
    282 		/*
    283 		 * If the old flag is PROMISC_SAP, but the current flag has
    284 		 * changed to some new non-zero value, we need to turn the
    285 		 * physical promiscuous mode.
    286 		 */
    287 		ASSERT(dsp->ds_mph != NULL);
    288 		mac_promisc_remove(dsp->ds_mph);
    289 		err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
    290 		    dls_rx_promisc, dsp, &dsp->ds_mph, 0);
    291 	}
    292 
    293 	return (err);
    294 }
    295 
    296 int
    297 dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
    298 {
    299 	int			err;
    300 	dls_multicst_addr_t	**pp;
    301 	dls_multicst_addr_t	*p;
    302 	uint_t			addr_length;
    303 
    304 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    305 
    306 	/*
    307 	 * Check whether the address is in the list of enabled addresses for
    308 	 * this dld_str_t.
    309 	 */
    310 	addr_length = dsp->ds_mip->mi_addr_length;
    311 
    312 	/*
    313 	 * Protect against concurrent access of ds_dmap by data threads using
    314 	 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
    315 	 * remove operations. Dropping the ds_rw_lock across mac calls is thus
    316 	 * ok and is also required by the locking protocol.
    317 	 */
    318 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
    319 	for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
    320 		if (bcmp(addr, p->dma_addr, addr_length) == 0) {
    321 			/*
    322 			 * It is there so there's nothing to do.
    323 			 */
    324 			err = 0;
    325 			goto done;
    326 		}
    327 	}
    328 
    329 	/*
    330 	 * Allocate a new list item and add it to the list.
    331 	 */
    332 	p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP);
    333 	bcopy(addr, p->dma_addr, addr_length);
    334 	*pp = p;
    335 	rw_exit(&dsp->ds_rw_lock);
    336 
    337 	/*
    338 	 * Enable the address at the MAC.
    339 	 */
    340 	err = mac_multicast_add(dsp->ds_mch, addr);
    341 	if (err == 0)
    342 		return (0);
    343 
    344 	/* Undo the operation as it has failed */
    345 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
    346 	ASSERT(*pp == p && p->dma_nextp == NULL);
    347 	*pp = NULL;
    348 	kmem_free(p, sizeof (dls_multicst_addr_t));
    349 done:
    350 	rw_exit(&dsp->ds_rw_lock);
    351 	return (err);
    352 }
    353 
    354 int
    355 dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr)
    356 {
    357 	dls_multicst_addr_t	**pp;
    358 	dls_multicst_addr_t	*p;
    359 	uint_t			addr_length;
    360 
    361 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    362 
    363 	/*
    364 	 * Find the address in the list of enabled addresses for this
    365 	 * dld_str_t.
    366 	 */
    367 	addr_length = dsp->ds_mip->mi_addr_length;
    368 
    369 	/*
    370 	 * Protect against concurrent access to ds_dmap by data threads using
    371 	 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and
    372 	 * remove operations. Dropping the ds_rw_lock across mac calls is thus
    373 	 * ok and is also required by the locking protocol.
    374 	 */
    375 	rw_enter(&dsp->ds_rw_lock, RW_WRITER);
    376 	for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
    377 		if (bcmp(addr, p->dma_addr, addr_length) == 0)
    378 			break;
    379 	}
    380 
    381 	/*
    382 	 * If we walked to the end of the list then the given address is
    383 	 * not currently enabled for this dld_str_t.
    384 	 */
    385 	if (p == NULL) {
    386 		rw_exit(&dsp->ds_rw_lock);
    387 		return (ENOENT);
    388 	}
    389 
    390 	/*
    391 	 * Remove the address from the list.
    392 	 */
    393 	*pp = p->dma_nextp;
    394 	rw_exit(&dsp->ds_rw_lock);
    395 
    396 	/*
    397 	 * Disable the address at the MAC.
    398 	 */
    399 	mac_multicast_remove(dsp->ds_mch, addr);
    400 	kmem_free(p, sizeof (dls_multicst_addr_t));
    401 	return (0);
    402 }
    403 
    404 mblk_t *
    405 dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri,
    406     mblk_t **payloadp)
    407 {
    408 	uint16_t vid;
    409 	size_t extra_len;
    410 	uint16_t mac_sap;
    411 	mblk_t *mp, *payload;
    412 	boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER);
    413 	struct ether_vlan_header *evhp;
    414 
    415 	vid = mac_client_vid(dsp->ds_mch);
    416 	payload = (payloadp == NULL) ? NULL : (*payloadp);
    417 
    418 	/*
    419 	 * In the case of Ethernet, we need to tell mac_header() if we need
    420 	 * extra room beyond the Ethernet header for a VLAN header.  We'll
    421 	 * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener
    422 	 * (because such streams will be handling VLAN headers on their own)
    423 	 * and one of the following conditions is satisfied:
    424 	 *
    425 	 * - This is a VLAN stream
    426 	 * - This is a physical stream, the priority is not 0, and user
    427 	 *   priority tagging is allowed.
    428 	 */
    429 	if (is_ethernet && sap != ETHERTYPE_VLAN &&
    430 	    (vid != VLAN_ID_NONE ||
    431 	    (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) {
    432 		extra_len = sizeof (struct ether_vlan_header) -
    433 		    sizeof (struct ether_header);
    434 		mac_sap = ETHERTYPE_VLAN;
    435 	} else {
    436 		extra_len = 0;
    437 		mac_sap = sap;
    438 	}
    439 
    440 	mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len);
    441 	if (mp == NULL)
    442 		return (NULL);
    443 
    444 	if ((vid == VLAN_ID_NONE && (pri == 0 ||
    445 	    dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet)
    446 		return (mp);
    447 
    448 	/*
    449 	 * Fill in the tag information.
    450 	 */
    451 	ASSERT(MBLKL(mp) == sizeof (struct ether_header));
    452 	if (extra_len != 0) {
    453 		mp->b_wptr += extra_len;
    454 		evhp = (struct ether_vlan_header *)mp->b_rptr;
    455 		evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
    456 		evhp->ether_type = htons(sap);
    457 	} else {
    458 		/*
    459 		 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
    460 		 * in the payload. Update the priority.
    461 		 */
    462 		struct ether_vlan_extinfo *extinfo;
    463 		size_t len = sizeof (struct ether_vlan_extinfo);
    464 
    465 		ASSERT(sap == ETHERTYPE_VLAN);
    466 		ASSERT(payload != NULL);
    467 
    468 		if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
    469 			mblk_t *newmp;
    470 
    471 			/*
    472 			 * Because some DLS consumers only check the db_ref
    473 			 * count of the first mblk, we pullup 'payload' into
    474 			 * a single mblk.
    475 			 */
    476 			newmp = msgpullup(payload, -1);
    477 			if ((newmp == NULL) || (MBLKL(newmp) < len)) {
    478 				freemsg(newmp);
    479 				freemsg(mp);
    480 				return (NULL);
    481 			} else {
    482 				freemsg(payload);
    483 				*payloadp = payload = newmp;
    484 			}
    485 		}
    486 
    487 		extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
    488 		extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
    489 		    VLAN_ID(ntohs(extinfo->ether_tci))));
    490 	}
    491 	return (mp);
    492 }
    493 
    494 void
    495 dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg)
    496 {
    497 	mutex_enter(&dsp->ds_lock);
    498 	dsp->ds_rx = rx;
    499 	dsp->ds_rx_arg = arg;
    500 	mutex_exit(&dsp->ds_lock);
    501 }
    502 
    503 static boolean_t
    504 dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
    505     void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback)
    506 {
    507 	dls_multicst_addr_t	*dmap;
    508 	size_t			addr_length = dsp->ds_mip->mi_addr_length;
    509 
    510 	/*
    511 	 * We must not accept packets if the dld_str_t is not marked as bound
    512 	 * or is being removed.
    513 	 */
    514 	if (dsp->ds_dlstate != DL_IDLE)
    515 		goto refuse;
    516 
    517 	if (dsp->ds_promisc != 0) {
    518 		/*
    519 		 * Filter out packets that arrived from the data path
    520 		 * (i_dls_link_rx) when promisc mode is on.
    521 		 */
    522 		if (!promisc)
    523 			goto refuse;
    524 		/*
    525 		 * If the dls_impl_t is in 'all physical' mode then
    526 		 * always accept.
    527 		 */
    528 		if (dsp->ds_promisc & DLS_PROMISC_PHYS)
    529 			goto accept;
    530 
    531 		/*
    532 		 * Loopback packets i.e. packets sent out by DLS on a given
    533 		 * mac end point, will be accepted back by DLS on loopback
    534 		 * from the mac, only in the 'all physical' mode which has been
    535 		 * covered by the previous check above
    536 		 */
    537 		if (promisc_loopback)
    538 			goto refuse;
    539 	}
    540 
    541 	switch (mhip->mhi_dsttype) {
    542 	case MAC_ADDRTYPE_UNICAST:
    543 	case MAC_ADDRTYPE_BROADCAST:
    544 		/*
    545 		 * We can accept unicast and broadcast packets because
    546 		 * filtering is already done by the mac layer.
    547 		 */
    548 		goto accept;
    549 	case MAC_ADDRTYPE_MULTICAST:
    550 		/*
    551 		 * Additional filtering is needed for multicast addresses
    552 		 * because different streams may be interested in different
    553 		 * addresses.
    554 		 */
    555 		if (dsp->ds_promisc & DLS_PROMISC_MULTI)
    556 			goto accept;
    557 
    558 		rw_enter(&dsp->ds_rw_lock, RW_READER);
    559 		for (dmap = dsp->ds_dmap; dmap != NULL;
    560 		    dmap = dmap->dma_nextp) {
    561 			if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
    562 			    addr_length) == 0) {
    563 				rw_exit(&dsp->ds_rw_lock);
    564 				goto accept;
    565 			}
    566 		}
    567 		rw_exit(&dsp->ds_rw_lock);
    568 		break;
    569 	}
    570 
    571 refuse:
    572 	return (B_FALSE);
    573 
    574 accept:
    575 	/*
    576 	 * the returned ds_rx and ds_rx_arg will always be in sync.
    577 	 */
    578 	mutex_enter(&dsp->ds_lock);
    579 	*ds_rx = dsp->ds_rx;
    580 	*ds_rx_arg = dsp->ds_rx_arg;
    581 	mutex_exit(&dsp->ds_lock);
    582 
    583 	return (B_TRUE);
    584 }
    585 
    586 /* ARGSUSED */
    587 boolean_t
    588 dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
    589     void **ds_rx_arg)
    590 {
    591 	return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE,
    592 	    B_FALSE));
    593 }
    594 
    595 boolean_t
    596 dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx,
    597     void **ds_rx_arg, boolean_t loopback)
    598 {
    599 	return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE,
    600 	    loopback));
    601 }
    602 
    603 int
    604 dls_mac_active_set(dls_link_t *dlp)
    605 {
    606 	int err = 0;
    607 
    608 	/*
    609 	 * First client; add the primary unicast address.
    610 	 */
    611 	if (dlp->dl_nactive == 0) {
    612 		/*
    613 		 * First client; add the primary unicast address.
    614 		 */
    615 		mac_diag_t diag;
    616 
    617 		/* request the primary MAC address */
    618 		if ((err = mac_unicast_add(dlp->dl_mch, NULL,
    619 		    MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE |
    620 		    MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah, 0,
    621 		    &diag)) != 0) {
    622 			return (err);
    623 		}
    624 
    625 		/*
    626 		 * Set the function to start receiving packets.
    627 		 */
    628 		mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp);
    629 	}
    630 	dlp->dl_nactive++;
    631 	return (0);
    632 }
    633 
    634 void
    635 dls_mac_active_clear(dls_link_t *dlp)
    636 {
    637 	if (--dlp->dl_nactive == 0) {
    638 		ASSERT(dlp->dl_mah != NULL);
    639 		(void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah);
    640 		dlp->dl_mah = NULL;
    641 		mac_rx_clear(dlp->dl_mch);
    642 	}
    643 }
    644 
    645 int
    646 dls_active_set(dld_str_t *dsp)
    647 {
    648 	int err = 0;
    649 
    650 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    651 
    652 	if (dsp->ds_passivestate == DLD_PASSIVE)
    653 		return (0);
    654 
    655 	/* If we're already active, then there's nothing more to do. */
    656 	if ((dsp->ds_nactive == 0) &&
    657 	    ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) {
    658 		/* except for ENXIO all other errors are mapped to EBUSY */
    659 		if (err != ENXIO)
    660 			return (EBUSY);
    661 		return (err);
    662 	}
    663 
    664 	dsp->ds_passivestate = DLD_ACTIVE;
    665 	dsp->ds_nactive++;
    666 	return (0);
    667 }
    668 
    669 /*
    670  * Note that dls_active_set() is called whenever an active operation
    671  * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and
    672  * dls_active_clear(dsp, B_FALSE) is called whenever the active operation
    673  * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases,
    674  * a stream is closed without every active operation being undone and we
    675  * need to clear all the "active" states by calling
    676  * dls_active_clear(dsp, B_TRUE).
    677  */
    678 void
    679 dls_active_clear(dld_str_t *dsp, boolean_t all)
    680 {
    681 	ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
    682 
    683 	if (dsp->ds_passivestate == DLD_PASSIVE)
    684 		return;
    685 
    686 	if (all && dsp->ds_nactive == 0)
    687 		return;
    688 
    689 	ASSERT(dsp->ds_nactive > 0);
    690 
    691 	dsp->ds_nactive -= (all ? dsp->ds_nactive : 1);
    692 	if (dsp->ds_nactive != 0)
    693 		return;
    694 
    695 	ASSERT(dsp->ds_passivestate == DLD_ACTIVE);
    696 	dls_mac_active_clear(dsp->ds_dlp);
    697 	dsp->ds_passivestate = DLD_UNINITIALIZED;
    698 }
    699