xref: /onnv-gate/usr/src/uts/common/io/dls/dls.c (revision 2760:38f12e308f6d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51502Sericheng  * Common Development and Distribution License (the "License").
61502Sericheng  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
221502Sericheng  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Data-Link Services Module
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include	<sys/types.h>
330Sstevel@tonic-gate #include	<sys/stream.h>
340Sstevel@tonic-gate #include	<sys/strsun.h>
350Sstevel@tonic-gate #include	<sys/sysmacros.h>
360Sstevel@tonic-gate #include	<sys/atomic.h>
370Sstevel@tonic-gate #include	<sys/dlpi.h>
380Sstevel@tonic-gate #include	<sys/vlan.h>
390Sstevel@tonic-gate #include	<sys/ethernet.h>
400Sstevel@tonic-gate #include	<sys/byteorder.h>
410Sstevel@tonic-gate #include	<sys/mac.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include	<sys/dls.h>
440Sstevel@tonic-gate #include	<sys/dls_impl.h>
451184Skrgopi #include	<sys/dls_soft_ring.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate static kmem_cache_t	*i_dls_impl_cachep;
480Sstevel@tonic-gate static uint32_t		i_dls_impl_count;
490Sstevel@tonic-gate 
501184Skrgopi static kstat_t	*dls_ksp = (kstat_t *)NULL;
511184Skrgopi struct dls_kstats dls_kstat =
521184Skrgopi {
531184Skrgopi 	{ "soft_ring_pkt_drop", KSTAT_DATA_UINT32 },
541184Skrgopi };
551184Skrgopi 
561184Skrgopi 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * Private functions.
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /*ARGSUSED*/
620Sstevel@tonic-gate static int
630Sstevel@tonic-gate i_dls_constructor(void *buf, void *arg, int kmflag)
640Sstevel@tonic-gate {
650Sstevel@tonic-gate 	dls_impl_t	*dip = buf;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	bzero(buf, sizeof (dls_impl_t));
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	rw_init(&(dip->di_lock), NULL, RW_DRIVER, NULL);
700Sstevel@tonic-gate 	return (0);
710Sstevel@tonic-gate }
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*ARGSUSED*/
740Sstevel@tonic-gate static void
750Sstevel@tonic-gate i_dls_destructor(void *buf, void *arg)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	dls_impl_t	*dip = buf;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	ASSERT(dip->di_dvp == NULL);
800Sstevel@tonic-gate 	ASSERT(dip->di_mnh == NULL);
810Sstevel@tonic-gate 	ASSERT(dip->di_dmap == NULL);
820Sstevel@tonic-gate 	ASSERT(!dip->di_bound);
830Sstevel@tonic-gate 	ASSERT(dip->di_rx == NULL);
8456Smeem 	ASSERT(dip->di_txinfo == NULL);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	rw_destroy(&(dip->di_lock));
870Sstevel@tonic-gate }
880Sstevel@tonic-gate 
890Sstevel@tonic-gate static void
900Sstevel@tonic-gate i_dls_notify(void *arg, mac_notify_type_t type)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	dls_impl_t		*dip = arg;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	switch (type) {
950Sstevel@tonic-gate 	case MAC_NOTE_UNICST:
960Sstevel@tonic-gate 		mac_unicst_get(dip->di_mh, dip->di_unicst_addr);
970Sstevel@tonic-gate 		break;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	case MAC_NOTE_PROMISC:
1000Sstevel@tonic-gate 		/*
1010Sstevel@tonic-gate 		 * Every time the MAC interface changes promiscuity we
10256Smeem 		 * need to reset our transmit information.
1030Sstevel@tonic-gate 		 */
10456Smeem 		dip->di_txinfo = mac_tx_get(dip->di_mh);
1050Sstevel@tonic-gate 		break;
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate 
1091184Skrgopi static void
1101184Skrgopi dls_stat_init()
1111184Skrgopi {
1121184Skrgopi 	if ((dls_ksp = kstat_create("dls", 0, "dls_stat",
1131184Skrgopi 	    "net", KSTAT_TYPE_NAMED,
1141184Skrgopi 	    sizeof (dls_kstat) / sizeof (kstat_named_t),
1151184Skrgopi 	    KSTAT_FLAG_VIRTUAL)) == NULL) {
1161184Skrgopi 		cmn_err(CE_WARN,
1171184Skrgopi 		"DLS: failed to create kstat structure for dls stats");
1181184Skrgopi 		return;
1191184Skrgopi 	}
1201184Skrgopi 	dls_ksp->ks_data = (void *)&dls_kstat;
1211184Skrgopi 	kstat_install(dls_ksp);
1221184Skrgopi }
1231184Skrgopi 
1241184Skrgopi static void
1251184Skrgopi dls_stat_destroy()
1261184Skrgopi {
1271184Skrgopi 	kstat_delete(dls_ksp);
1281184Skrgopi }
1291184Skrgopi 
1300Sstevel@tonic-gate /*
1310Sstevel@tonic-gate  * Module initialization functions.
1320Sstevel@tonic-gate  */
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate void
1350Sstevel@tonic-gate dls_init(void)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	/*
1380Sstevel@tonic-gate 	 * Create a kmem_cache of dls_impl_t.
1390Sstevel@tonic-gate 	 */
1400Sstevel@tonic-gate 	i_dls_impl_cachep = kmem_cache_create("dls_cache",
1410Sstevel@tonic-gate 	    sizeof (dls_impl_t), 0, i_dls_constructor, i_dls_destructor, NULL,
1420Sstevel@tonic-gate 	    NULL, NULL, 0);
1430Sstevel@tonic-gate 	ASSERT(i_dls_impl_cachep != NULL);
1441184Skrgopi 	soft_ring_init();
1451184Skrgopi 	dls_stat_init();
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate int
1490Sstevel@tonic-gate dls_fini(void)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	/*
1520Sstevel@tonic-gate 	 * If there are any dls_impl_t in use then return EBUSY.
1530Sstevel@tonic-gate 	 */
1540Sstevel@tonic-gate 	if (i_dls_impl_count != 0)
1550Sstevel@tonic-gate 		return (EBUSY);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	/*
1580Sstevel@tonic-gate 	 * Destroy the kmem_cache.
1590Sstevel@tonic-gate 	 */
1600Sstevel@tonic-gate 	kmem_cache_destroy(i_dls_impl_cachep);
1611184Skrgopi 	dls_stat_destroy();
1620Sstevel@tonic-gate 	return (0);
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate  * Client function.
1670Sstevel@tonic-gate  */
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate int
1702311Sseb dls_create(const char *linkname, const char *macname, uint_t ddi_instance)
1710Sstevel@tonic-gate {
1722311Sseb 	return (dls_vlan_create(linkname, macname, ddi_instance, 0));
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate int
1760Sstevel@tonic-gate dls_destroy(const char *name)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate 	return (dls_vlan_destroy(name));
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate int
1820Sstevel@tonic-gate dls_open(const char *name, dls_channel_t *dcp)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	dls_impl_t	*dip;
1850Sstevel@tonic-gate 	dls_vlan_t	*dvp;
1860Sstevel@tonic-gate 	dls_link_t	*dlp;
1870Sstevel@tonic-gate 	int		err;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/*
1900Sstevel@tonic-gate 	 * Get a reference to the named dls_vlan_t.
191269Sericheng 	 * Tagged vlans get created automatically.
1920Sstevel@tonic-gate 	 */
193269Sericheng 	if ((err = dls_vlan_hold(name, &dvp, B_TRUE)) != 0)
1940Sstevel@tonic-gate 		return (err);
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	/*
1970Sstevel@tonic-gate 	 * Allocate a new dls_impl_t.
1980Sstevel@tonic-gate 	 */
1990Sstevel@tonic-gate 	dip = kmem_cache_alloc(i_dls_impl_cachep, KM_SLEEP);
2000Sstevel@tonic-gate 	dip->di_dvp = dvp;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	/*
2030Sstevel@tonic-gate 	 * Cache a copy of the MAC interface handle, a pointer to the
2040Sstevel@tonic-gate 	 * immutable MAC info and a copy of the current MAC address.
2050Sstevel@tonic-gate 	 */
2060Sstevel@tonic-gate 	dlp = dvp->dv_dlp;
2070Sstevel@tonic-gate 	dip->di_mh = dlp->dl_mh;
2080Sstevel@tonic-gate 	dip->di_mip = dlp->dl_mip;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	mac_unicst_get(dip->di_mh, dip->di_unicst_addr);
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	/*
21356Smeem 	 * Set the MAC transmit information.
2140Sstevel@tonic-gate 	 */
21556Smeem 	dip->di_txinfo = mac_tx_get(dip->di_mh);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	/*
2180Sstevel@tonic-gate 	 * Add a notification function so that we get updates from the MAC.
2190Sstevel@tonic-gate 	 */
2200Sstevel@tonic-gate 	dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify, (void *)dip);
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	/*
2230Sstevel@tonic-gate 	 * Bump the kmem_cache count to make sure it is not prematurely
2240Sstevel@tonic-gate 	 * destroyed.
2250Sstevel@tonic-gate 	 */
2260Sstevel@tonic-gate 	atomic_add_32(&i_dls_impl_count, 1);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	/*
2290Sstevel@tonic-gate 	 * Hand back a reference to the dls_impl_t.
2300Sstevel@tonic-gate 	 */
2310Sstevel@tonic-gate 	*dcp = (dls_channel_t)dip;
2320Sstevel@tonic-gate 	return (0);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate void
2360Sstevel@tonic-gate dls_close(dls_channel_t dc)
2370Sstevel@tonic-gate {
2380Sstevel@tonic-gate 	dls_impl_t		*dip = (dls_impl_t *)dc;
2390Sstevel@tonic-gate 	dls_vlan_t		*dvp;
2400Sstevel@tonic-gate 	dls_link_t		*dlp;
2410Sstevel@tonic-gate 	dls_multicst_addr_t	*p;
2420Sstevel@tonic-gate 	dls_multicst_addr_t	*nextp;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	dls_active_clear(dc);
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	/*
2490Sstevel@tonic-gate 	 * Remove the notify function.
2500Sstevel@tonic-gate 	 */
2510Sstevel@tonic-gate 	mac_notify_remove(dip->di_mh, dip->di_mnh);
2520Sstevel@tonic-gate 	dip->di_mnh = NULL;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	/*
2550Sstevel@tonic-gate 	 * If the dls_impl_t is bound then unbind it.
2560Sstevel@tonic-gate 	 */
2570Sstevel@tonic-gate 	dvp = dip->di_dvp;
2580Sstevel@tonic-gate 	dlp = dvp->dv_dlp;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	if (dip->di_bound) {
2610Sstevel@tonic-gate 		rw_exit(&(dip->di_lock));
2620Sstevel@tonic-gate 		dls_link_remove(dlp, dip);
2630Sstevel@tonic-gate 		rw_enter(&(dip->di_lock), RW_WRITER);
2640Sstevel@tonic-gate 		dip->di_bound = B_FALSE;
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2672311Sseb 	dip->di_rx = NULL;
2682311Sseb 	dip->di_rx_arg = NULL;
2692311Sseb 
2700Sstevel@tonic-gate 	/*
2710Sstevel@tonic-gate 	 * Walk the list of multicast addresses, disabling each at the MAC.
2720Sstevel@tonic-gate 	 */
2730Sstevel@tonic-gate 	for (p = dip->di_dmap; p != NULL; p = nextp) {
2740Sstevel@tonic-gate 		(void) mac_multicst_remove(dip->di_mh, p->dma_addr);
2750Sstevel@tonic-gate 		nextp = p->dma_nextp;
2760Sstevel@tonic-gate 		kmem_free(p, sizeof (dls_multicst_addr_t));
2770Sstevel@tonic-gate 	}
2780Sstevel@tonic-gate 	dip->di_dmap = NULL;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	/*
2830Sstevel@tonic-gate 	 * If the MAC has been set in promiscuous mode then disable it.
2840Sstevel@tonic-gate 	 */
2850Sstevel@tonic-gate 	(void) dls_promisc(dc, 0);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	/*
2880Sstevel@tonic-gate 	 * Free the dls_impl_t back to the cache.
2890Sstevel@tonic-gate 	 */
2900Sstevel@tonic-gate 	dip->di_dvp = NULL;
29156Smeem 	dip->di_txinfo = NULL;
2921184Skrgopi 
2931184Skrgopi 	if (dip->di_soft_ring_list != NULL) {
2941184Skrgopi 		soft_ring_set_destroy(dip->di_soft_ring_list,
2951184Skrgopi 		    dip->di_soft_ring_size);
2961184Skrgopi 		dip->di_soft_ring_list = NULL;
2971184Skrgopi 	}
2981184Skrgopi 	dip->di_soft_ring_size = 0;
2991184Skrgopi 
3000Sstevel@tonic-gate 	kmem_cache_free(i_dls_impl_cachep, dip);
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	/*
3030Sstevel@tonic-gate 	 * Decrement the reference count to allow the cache to be destroyed
3040Sstevel@tonic-gate 	 * if there are no more dls_impl_t.
3050Sstevel@tonic-gate 	 */
3060Sstevel@tonic-gate 	atomic_add_32(&i_dls_impl_count, -1);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/*
3090Sstevel@tonic-gate 	 * Release our reference to the dls_vlan_t allowing that to be
310269Sericheng 	 * destroyed if there are no more dls_impl_t. An unreferenced tagged
311269Sericheng 	 * vlan gets destroyed automatically.
3120Sstevel@tonic-gate 	 */
3130Sstevel@tonic-gate 	dls_vlan_rele(dvp);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate mac_handle_t
3170Sstevel@tonic-gate dls_mac(dls_channel_t dc)
3180Sstevel@tonic-gate {
3192311Sseb 	return (((dls_impl_t *)dc)->di_mh);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate uint16_t
3230Sstevel@tonic-gate dls_vid(dls_channel_t dc)
3240Sstevel@tonic-gate {
3252311Sseb 	return (((dls_impl_t *)dc)->di_dvp->dv_id);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate int
3292311Sseb dls_bind(dls_channel_t dc, uint32_t sap)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
3320Sstevel@tonic-gate 	dls_link_t	*dlp;
3332311Sseb 	uint32_t	dls_sap;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	/*
3360Sstevel@tonic-gate 	 * Check to see the value is legal for the media type.
3370Sstevel@tonic-gate 	 */
3382311Sseb 	if (!mac_sap_verify(dip->di_mh, sap, &dls_sap))
3390Sstevel@tonic-gate 		return (EINVAL);
3402311Sseb 	if (dip->di_promisc & DLS_PROMISC_SAP)
3412311Sseb 		dls_sap = DLS_SAP_PROMISC;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	/*
3440Sstevel@tonic-gate 	 * Set up the dls_impl_t to mark it as able to receive packets.
3450Sstevel@tonic-gate 	 */
3460Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
3470Sstevel@tonic-gate 	ASSERT(!dip->di_bound);
3480Sstevel@tonic-gate 	dip->di_sap = sap;
3490Sstevel@tonic-gate 	dip->di_bound = B_TRUE;
3500Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/*
3530Sstevel@tonic-gate 	 * Now bind the dls_impl_t by adding it into the hash table in the
3540Sstevel@tonic-gate 	 * dls_link_t.
3550Sstevel@tonic-gate 	 *
3560Sstevel@tonic-gate 	 * NOTE: This must be done without the dls_impl_t lock being held
3570Sstevel@tonic-gate 	 *	 otherwise deadlock may ensue.
3580Sstevel@tonic-gate 	 */
3590Sstevel@tonic-gate 	dlp = dip->di_dvp->dv_dlp;
3602311Sseb 	dls_link_add(dlp, dls_sap, dip);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	return (0);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate void
3660Sstevel@tonic-gate dls_unbind(dls_channel_t dc)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
3690Sstevel@tonic-gate 	dls_link_t	*dlp;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	/*
3720Sstevel@tonic-gate 	 * Unbind the dls_impl_t by removing it from the hash table in the
3730Sstevel@tonic-gate 	 * dls_link_t.
3740Sstevel@tonic-gate 	 *
3750Sstevel@tonic-gate 	 * NOTE: This must be done without the dls_impl_t lock being held
3760Sstevel@tonic-gate 	 *	 otherise deadlock may enuse.
3770Sstevel@tonic-gate 	 */
3780Sstevel@tonic-gate 	dlp = dip->di_dvp->dv_dlp;
3790Sstevel@tonic-gate 	dls_link_remove(dlp, dip);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	/*
3820Sstevel@tonic-gate 	 * Mark the dls_impl_t as unable to receive packets This will make
3830Sstevel@tonic-gate 	 * sure that 'receives in flight' will not come our way.
3840Sstevel@tonic-gate 	 */
3850Sstevel@tonic-gate 	dip->di_bound = B_FALSE;
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate int
3890Sstevel@tonic-gate dls_promisc(dls_channel_t dc, uint32_t flags)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
3920Sstevel@tonic-gate 	dls_link_t	*dlp;
3930Sstevel@tonic-gate 	int		err = 0;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	ASSERT(!(flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
3960Sstevel@tonic-gate 	    DLS_PROMISC_PHYS)));
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	/*
3990Sstevel@tonic-gate 	 * Check if we need to turn on 'all sap' mode.
4000Sstevel@tonic-gate 	 */
4010Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
4020Sstevel@tonic-gate 	dlp = dip->di_dvp->dv_dlp;
4030Sstevel@tonic-gate 	if ((flags & DLS_PROMISC_SAP) &&
4040Sstevel@tonic-gate 	    !(dip->di_promisc & DLS_PROMISC_SAP)) {
4050Sstevel@tonic-gate 		dip->di_promisc |= DLS_PROMISC_SAP;
4060Sstevel@tonic-gate 		if (!dip->di_bound)
4070Sstevel@tonic-gate 			goto multi;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 		rw_exit(&(dip->di_lock));
4100Sstevel@tonic-gate 		dls_link_remove(dlp, dip);
4110Sstevel@tonic-gate 		dls_link_add(dlp, DLS_SAP_PROMISC, dip);
4120Sstevel@tonic-gate 		rw_enter(&(dip->di_lock), RW_WRITER);
4130Sstevel@tonic-gate 		goto multi;
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/*
4170Sstevel@tonic-gate 	 * Check if we need to turn off 'all sap' mode.
4180Sstevel@tonic-gate 	 */
4190Sstevel@tonic-gate 	if (!(flags & DLS_PROMISC_SAP) &&
4200Sstevel@tonic-gate 	    (dip->di_promisc & DLS_PROMISC_SAP)) {
4212311Sseb 		uint32_t dls_sap;
4222311Sseb 
4230Sstevel@tonic-gate 		dip->di_promisc &= ~DLS_PROMISC_SAP;
4240Sstevel@tonic-gate 		if (!dip->di_bound)
4250Sstevel@tonic-gate 			goto multi;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		rw_exit(&(dip->di_lock));
4280Sstevel@tonic-gate 		dls_link_remove(dlp, dip);
4292311Sseb 		(void) mac_sap_verify(dip->di_mh, dip->di_sap, &dls_sap);
4302311Sseb 		dls_link_add(dlp, dls_sap, dip);
4310Sstevel@tonic-gate 		rw_enter(&(dip->di_lock), RW_WRITER);
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate multi:
4350Sstevel@tonic-gate 	/*
4360Sstevel@tonic-gate 	 * It's easiest to add the txloop handler up-front; if promiscuous
4370Sstevel@tonic-gate 	 * mode cannot be enabled, then we'll remove it before returning.
43856Smeem 	 * Use dl_promisc_lock to prevent racing with another thread also
43956Smeem 	 * manipulating the promiscuous state on another dls_impl_t associated
44056Smeem 	 * with the same dls_link_t.
4410Sstevel@tonic-gate 	 */
44256Smeem 	mutex_enter(&dlp->dl_promisc_lock);
4430Sstevel@tonic-gate 	if (dlp->dl_npromisc == 0 &&
4440Sstevel@tonic-gate 	    (flags & (DLS_PROMISC_MULTI|DLS_PROMISC_PHYS))) {
4450Sstevel@tonic-gate 		ASSERT(dlp->dl_mth == NULL);
4462311Sseb 		dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dlp->dl_txloop, dlp);
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	/*
45056Smeem 	 * Turn on or off 'all multicast' mode, if necessary.
4510Sstevel@tonic-gate 	 */
45256Smeem 	if (flags & DLS_PROMISC_MULTI) {
45356Smeem 		if (!(dip->di_promisc & DLS_PROMISC_MULTI)) {
45456Smeem 			err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC);
45556Smeem 			if (err != 0)
45656Smeem 				goto done;
45756Smeem 			dip->di_promisc |= DLS_PROMISC_MULTI;
45856Smeem 			dlp->dl_npromisc++;
45956Smeem 		}
46056Smeem 	} else {
46156Smeem 		if (dip->di_promisc & DLS_PROMISC_MULTI) {
46256Smeem 			err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC);
46356Smeem 			if (err != 0)
46456Smeem 				goto done;
46556Smeem 			dip->di_promisc &= ~DLS_PROMISC_MULTI;
46656Smeem 			dlp->dl_npromisc--;
46756Smeem 		}
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	/*
47156Smeem 	 * Turn on or off 'all physical' mode, if necessary.
4720Sstevel@tonic-gate 	 */
47356Smeem 	if (flags & DLS_PROMISC_PHYS) {
47456Smeem 		if (!(dip->di_promisc & DLS_PROMISC_PHYS)) {
47556Smeem 			err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC);
47656Smeem 			if (err != 0)
47756Smeem 				goto done;
47856Smeem 			dip->di_promisc |= DLS_PROMISC_PHYS;
47956Smeem 			dlp->dl_npromisc++;
48056Smeem 		}
48156Smeem 	} else {
48256Smeem 		if (dip->di_promisc & DLS_PROMISC_PHYS) {
48356Smeem 			err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC);
48456Smeem 			if (err != 0)
48556Smeem 				goto done;
48656Smeem 			dip->di_promisc &= ~DLS_PROMISC_PHYS;
48756Smeem 			dlp->dl_npromisc--;
48856Smeem 		}
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate done:
4920Sstevel@tonic-gate 	if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) {
4930Sstevel@tonic-gate 		mac_txloop_remove(dlp->dl_mh, dlp->dl_mth);
4940Sstevel@tonic-gate 		dlp->dl_mth = NULL;
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL);
49856Smeem 	mutex_exit(&dlp->dl_promisc_lock);
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
5010Sstevel@tonic-gate 	return (err);
5020Sstevel@tonic-gate }
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate int
5050Sstevel@tonic-gate dls_multicst_add(dls_channel_t dc, const uint8_t *addr)
5060Sstevel@tonic-gate {
5070Sstevel@tonic-gate 	dls_impl_t		*dip = (dls_impl_t *)dc;
5080Sstevel@tonic-gate 	int			err;
5090Sstevel@tonic-gate 	dls_multicst_addr_t	**pp;
5100Sstevel@tonic-gate 	dls_multicst_addr_t	*p;
5110Sstevel@tonic-gate 	uint_t			addr_length;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	/*
5140Sstevel@tonic-gate 	 * Check whether the address is in the list of enabled addresses for
5150Sstevel@tonic-gate 	 * this dls_impl_t.
5160Sstevel@tonic-gate 	 */
5170Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
5180Sstevel@tonic-gate 	addr_length = dip->di_mip->mi_addr_length;
5190Sstevel@tonic-gate 	for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
5200Sstevel@tonic-gate 		if (bcmp(addr, p->dma_addr, addr_length) == 0) {
5210Sstevel@tonic-gate 			/*
5220Sstevel@tonic-gate 			 * It is there so there's nothing to do.
5230Sstevel@tonic-gate 			 */
5240Sstevel@tonic-gate 			err = 0;
5250Sstevel@tonic-gate 			goto done;
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	/*
5300Sstevel@tonic-gate 	 * Allocate a new list item.
5310Sstevel@tonic-gate 	 */
5320Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t),
5330Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
5340Sstevel@tonic-gate 		err = ENOMEM;
5350Sstevel@tonic-gate 		goto done;
5360Sstevel@tonic-gate 	}
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	/*
5390Sstevel@tonic-gate 	 * Enable the address at the MAC.
5400Sstevel@tonic-gate 	 */
5410Sstevel@tonic-gate 	if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) {
5420Sstevel@tonic-gate 		kmem_free(p, sizeof (dls_multicst_addr_t));
5430Sstevel@tonic-gate 		goto done;
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	/*
5470Sstevel@tonic-gate 	 * The address is now enabled at the MAC so add it to the list.
5480Sstevel@tonic-gate 	 */
5490Sstevel@tonic-gate 	bcopy(addr, p->dma_addr, addr_length);
5500Sstevel@tonic-gate 	*pp = p;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate done:
5530Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
5540Sstevel@tonic-gate 	return (err);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate int
5580Sstevel@tonic-gate dls_multicst_remove(dls_channel_t dc, const uint8_t *addr)
5590Sstevel@tonic-gate {
5600Sstevel@tonic-gate 	dls_impl_t		*dip = (dls_impl_t *)dc;
5610Sstevel@tonic-gate 	int			err;
5620Sstevel@tonic-gate 	dls_multicst_addr_t	**pp;
5630Sstevel@tonic-gate 	dls_multicst_addr_t	*p;
5640Sstevel@tonic-gate 	uint_t			addr_length;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	/*
5670Sstevel@tonic-gate 	 * Find the address in the list of enabled addresses for this
5680Sstevel@tonic-gate 	 * dls_impl_t.
5690Sstevel@tonic-gate 	 */
5700Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
5710Sstevel@tonic-gate 	addr_length = dip->di_mip->mi_addr_length;
5720Sstevel@tonic-gate 	for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
5730Sstevel@tonic-gate 		if (bcmp(addr, p->dma_addr, addr_length) == 0)
5740Sstevel@tonic-gate 			break;
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	/*
5780Sstevel@tonic-gate 	 * If we walked to the end of the list then the given address is
5790Sstevel@tonic-gate 	 * not currently enabled for this dls_impl_t.
5800Sstevel@tonic-gate 	 */
5810Sstevel@tonic-gate 	if (p == NULL) {
5820Sstevel@tonic-gate 		err = ENOENT;
5830Sstevel@tonic-gate 		goto done;
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	/*
5870Sstevel@tonic-gate 	 * Disable the address at the MAC.
5880Sstevel@tonic-gate 	 */
5890Sstevel@tonic-gate 	if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0)
5900Sstevel@tonic-gate 		goto done;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	/*
5930Sstevel@tonic-gate 	 * Remove the address from the list.
5940Sstevel@tonic-gate 	 */
5950Sstevel@tonic-gate 	*pp = p->dma_nextp;
5960Sstevel@tonic-gate 	kmem_free(p, sizeof (dls_multicst_addr_t));
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate done:
5990Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
6000Sstevel@tonic-gate 	return (err);
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate mblk_t *
6042311Sseb dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri,
605*2760Sdg199075     mblk_t **payloadp)
6060Sstevel@tonic-gate {
607*2760Sdg199075 	dls_impl_t *dip = (dls_impl_t *)dc;
608*2760Sdg199075 	uint16_t vid;
609*2760Sdg199075 	size_t extra_len;
610*2760Sdg199075 	uint16_t mac_sap;
611*2760Sdg199075 	mblk_t *mp, *payload;
612*2760Sdg199075 	boolean_t is_ethernet = (dip->di_mip->mi_media == DL_ETHER);
6132311Sseb 	struct ether_vlan_header *evhp;
6140Sstevel@tonic-gate 
6152311Sseb 	vid = dip->di_dvp->dv_id;
616*2760Sdg199075 	payload = (payloadp == NULL) ? NULL : (*payloadp);
617*2760Sdg199075 
618*2760Sdg199075 	/*
619*2760Sdg199075 	 * If the following conditions are satisfied:
620*2760Sdg199075 	 *	- This is not a ETHERTYPE_VLAN listener; and
621*2760Sdg199075 	 *	- This is either a VLAN stream or this is a physical stream
622*2760Sdg199075 	 *	  but the priority is not 0.
623*2760Sdg199075 	 *
624*2760Sdg199075 	 * then we know ahead of time that we'll need to fill in additional
625*2760Sdg199075 	 * VLAN information in the link-layer header. We will tell the MAC
626*2760Sdg199075 	 * layer to pre-allocate some space at the end of the Ethernet
627*2760Sdg199075 	 * header for us.
628*2760Sdg199075 	 */
629*2760Sdg199075 	if (is_ethernet && sap != ETHERTYPE_VLAN &&
630*2760Sdg199075 	    (vid != VLAN_ID_NONE || pri != 0)) {
6312311Sseb 		extra_len = sizeof (struct ether_vlan_header) -
6322311Sseb 		    sizeof (struct ether_header);
633*2760Sdg199075 		mac_sap = ETHERTYPE_VLAN;
6342311Sseb 	} else {
6352311Sseb 		extra_len = 0;
6362311Sseb 		mac_sap = sap;
6372311Sseb 	}
6382311Sseb 
6392311Sseb 	mp = mac_header(dip->di_mh, addr, mac_sap, payload, extra_len);
640*2760Sdg199075 	if (mp == NULL)
641*2760Sdg199075 		return (NULL);
642*2760Sdg199075 
643*2760Sdg199075 	if ((vid == VLAN_ID_NONE && pri == 0) || !is_ethernet)
6442311Sseb 		return (mp);
6452311Sseb 
646*2760Sdg199075 	/*
647*2760Sdg199075 	 * Fill in the tag information.
648*2760Sdg199075 	 */
6492311Sseb 	ASSERT(MBLKL(mp) == sizeof (struct ether_header));
650*2760Sdg199075 	if (extra_len != 0) {
651*2760Sdg199075 		mp->b_wptr += extra_len;
652*2760Sdg199075 		evhp = (struct ether_vlan_header *)mp->b_rptr;
653*2760Sdg199075 		evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
654*2760Sdg199075 		evhp->ether_type = htons(sap);
655*2760Sdg199075 	} else {
656*2760Sdg199075 		/*
657*2760Sdg199075 		 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is
658*2760Sdg199075 		 * in the payload. Update the priority.
659*2760Sdg199075 		 */
660*2760Sdg199075 		struct ether_vlan_extinfo *extinfo;
661*2760Sdg199075 		size_t len = sizeof (struct ether_vlan_extinfo);
662*2760Sdg199075 
663*2760Sdg199075 		ASSERT(sap == ETHERTYPE_VLAN);
664*2760Sdg199075 		ASSERT(payload != NULL);
665*2760Sdg199075 
666*2760Sdg199075 		if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) {
667*2760Sdg199075 			mblk_t *newmp;
668*2760Sdg199075 
669*2760Sdg199075 			/*
670*2760Sdg199075 			 * Because some DLS consumers only check the db_ref
671*2760Sdg199075 			 * count of the first mblk, we pullup 'payload' into
672*2760Sdg199075 			 * a single mblk.
673*2760Sdg199075 			 */
674*2760Sdg199075 			newmp = msgpullup(payload, -1);
675*2760Sdg199075 			if ((newmp == NULL) || (MBLKL(newmp) < len)) {
676*2760Sdg199075 				freemsg(newmp);
677*2760Sdg199075 				freemsg(mp);
678*2760Sdg199075 				return (NULL);
679*2760Sdg199075 			} else {
680*2760Sdg199075 				freemsg(payload);
681*2760Sdg199075 				*payloadp = payload = newmp;
682*2760Sdg199075 			}
683*2760Sdg199075 		}
684*2760Sdg199075 
685*2760Sdg199075 		extinfo = (struct ether_vlan_extinfo *)payload->b_rptr;
686*2760Sdg199075 		extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI,
687*2760Sdg199075 		    VLAN_ID(ntohs(extinfo->ether_tci))));
688*2760Sdg199075 	}
6892311Sseb 	return (mp);
6900Sstevel@tonic-gate }
6910Sstevel@tonic-gate 
6922311Sseb int
6932311Sseb dls_header_info(dls_channel_t dc, mblk_t *mp, mac_header_info_t *mhip)
6940Sstevel@tonic-gate {
6952311Sseb 	return (dls_link_header_info(((dls_impl_t *)dc)->di_dvp->dv_dlp,
696*2760Sdg199075 	    mp, mhip));
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate void
7000Sstevel@tonic-gate dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg)
7010Sstevel@tonic-gate {
7020Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
7050Sstevel@tonic-gate 	dip->di_rx = rx;
7060Sstevel@tonic-gate 	dip->di_rx_arg = arg;
7070Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate mblk_t *
7110Sstevel@tonic-gate dls_tx(dls_channel_t dc, mblk_t *mp)
7120Sstevel@tonic-gate {
71356Smeem 	const mac_txinfo_t *mtp = ((dls_impl_t *)dc)->di_txinfo;
7140Sstevel@tonic-gate 
71556Smeem 	return (mtp->mt_fn(mtp->mt_arg, mp));
7160Sstevel@tonic-gate }
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate boolean_t
7192311Sseb dls_accept(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx,
720449Sericheng     void **di_rx_arg)
7210Sstevel@tonic-gate {
7220Sstevel@tonic-gate 	dls_multicst_addr_t	*dmap;
7232311Sseb 	size_t			addr_length = dip->di_mip->mi_addr_length;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	/*
7260Sstevel@tonic-gate 	 * We must not accept packets if the dls_impl_t is not marked as bound
7270Sstevel@tonic-gate 	 * or is being removed.
7280Sstevel@tonic-gate 	 */
7290Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_READER);
7300Sstevel@tonic-gate 	if (!dip->di_bound || dip->di_removing)
7310Sstevel@tonic-gate 		goto refuse;
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	/*
7340Sstevel@tonic-gate 	 * If the dls_impl_t is in 'all physical' mode then always accept.
7350Sstevel@tonic-gate 	 */
7360Sstevel@tonic-gate 	if (dip->di_promisc & DLS_PROMISC_PHYS)
7370Sstevel@tonic-gate 		goto accept;
7380Sstevel@tonic-gate 
7392311Sseb 	switch (mhip->mhi_dsttype) {
7402311Sseb 	case MAC_ADDRTYPE_UNICAST:
7412311Sseb 		/*
7422311Sseb 		 * Check to see if the destination address matches the
7432311Sseb 		 * dls_impl_t unicast address.
7442311Sseb 		 */
7452311Sseb 		if (memcmp(mhip->mhi_daddr, dip->di_unicst_addr, addr_length) ==
7462311Sseb 		    0) {
7472311Sseb 			goto accept;
7482311Sseb 		}
7492311Sseb 		break;
7502311Sseb 	case MAC_ADDRTYPE_MULTICAST:
7512311Sseb 		/*
7522311Sseb 		 * Check the address against the list of addresses enabled
7532311Sseb 		 * for this dls_impl_t or accept it unconditionally if the
7542311Sseb 		 * dls_impl_t is in 'all multicast' mode.
7552311Sseb 		 */
7562311Sseb 		if (dip->di_promisc & DLS_PROMISC_MULTI)
7572311Sseb 			goto accept;
7582311Sseb 		for (dmap = dip->di_dmap; dmap != NULL;
7592311Sseb 		    dmap = dmap->dma_nextp) {
7602311Sseb 			if (memcmp(mhip->mhi_daddr, dmap->dma_addr,
7612311Sseb 			    addr_length) == 0) {
7622311Sseb 				goto accept;
7632311Sseb 			}
7642311Sseb 		}
7652311Sseb 		break;
7662311Sseb 	case MAC_ADDRTYPE_BROADCAST:
7672311Sseb 		/*
7682311Sseb 		 * If the address is broadcast then the dls_impl_t will
7692311Sseb 		 * always accept it.
7702311Sseb 		 */
7710Sstevel@tonic-gate 		goto accept;
7720Sstevel@tonic-gate 	}
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate refuse:
7750Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
7760Sstevel@tonic-gate 	return (B_FALSE);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate accept:
779449Sericheng 	/*
780449Sericheng 	 * Since we hold di_lock here, the returned di_rx and di_rx_arg will
781449Sericheng 	 * always be in sync.
782449Sericheng 	 */
783449Sericheng 	*di_rx = dip->di_rx;
784449Sericheng 	*di_rx_arg = dip->di_rx_arg;
7850Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
7860Sstevel@tonic-gate 	return (B_TRUE);
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
789*2760Sdg199075 /* ARGSUSED */
7900Sstevel@tonic-gate boolean_t
791*2760Sdg199075 dls_accept_loopback(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx,
792*2760Sdg199075     void **di_rx_arg)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate 	/*
7950Sstevel@tonic-gate 	 * We must not accept packets if the dls_impl_t is not marked as bound
7960Sstevel@tonic-gate 	 * or is being removed.
7970Sstevel@tonic-gate 	 */
7980Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_READER);
7990Sstevel@tonic-gate 	if (!dip->di_bound || dip->di_removing)
8000Sstevel@tonic-gate 		goto refuse;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	/*
8030Sstevel@tonic-gate 	 * A dls_impl_t should only accept loopback packets if it is in
8040Sstevel@tonic-gate 	 * 'all physical' mode.
8050Sstevel@tonic-gate 	 */
8060Sstevel@tonic-gate 	if (dip->di_promisc & DLS_PROMISC_PHYS)
8070Sstevel@tonic-gate 		goto accept;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate refuse:
8100Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
8110Sstevel@tonic-gate 	return (B_FALSE);
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate accept:
814449Sericheng 	/*
815449Sericheng 	 * Since we hold di_lock here, the returned di_rx and di_rx_arg will
816449Sericheng 	 * always be in sync.
817449Sericheng 	 */
818449Sericheng 	*di_rx = dip->di_rx;
819449Sericheng 	*di_rx_arg = dip->di_rx_arg;
8200Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
8210Sstevel@tonic-gate 	return (B_TRUE);
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate boolean_t
8250Sstevel@tonic-gate dls_active_set(dls_channel_t dc)
8260Sstevel@tonic-gate {
8270Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
8280Sstevel@tonic-gate 	dls_link_t	*dlp = dip->di_dvp->dv_dlp;
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	rw_enter(&dip->di_lock, RW_WRITER);
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	/* If we're already active, then there's nothing more to do. */
8330Sstevel@tonic-gate 	if (dip->di_active) {
8340Sstevel@tonic-gate 		rw_exit(&dip->di_lock);
8350Sstevel@tonic-gate 		return (B_TRUE);
8360Sstevel@tonic-gate 	}
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	/*
8390Sstevel@tonic-gate 	 * If this is the first active client on this link, notify
8400Sstevel@tonic-gate 	 * the mac that we're becoming an active client.
8410Sstevel@tonic-gate 	 */
8420Sstevel@tonic-gate 	if (dlp->dl_nactive == 0 && !mac_active_set(dlp->dl_mh)) {
8430Sstevel@tonic-gate 		rw_exit(&dip->di_lock);
8440Sstevel@tonic-gate 		return (B_FALSE);
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 	dip->di_active = B_TRUE;
8470Sstevel@tonic-gate 	mutex_enter(&dlp->dl_lock);
8480Sstevel@tonic-gate 	dlp->dl_nactive++;
8490Sstevel@tonic-gate 	mutex_exit(&dlp->dl_lock);
8500Sstevel@tonic-gate 	rw_exit(&dip->di_lock);
8510Sstevel@tonic-gate 	return (B_TRUE);
8520Sstevel@tonic-gate }
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate void
8550Sstevel@tonic-gate dls_active_clear(dls_channel_t dc)
8560Sstevel@tonic-gate {
8570Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
8580Sstevel@tonic-gate 	dls_link_t	*dlp = dip->di_dvp->dv_dlp;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	rw_enter(&dip->di_lock, RW_WRITER);
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	if (!dip->di_active)
8630Sstevel@tonic-gate 		goto out;
8640Sstevel@tonic-gate 	dip->di_active = B_FALSE;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	mutex_enter(&dlp->dl_lock);
8670Sstevel@tonic-gate 	if (--dlp->dl_nactive == 0)
8680Sstevel@tonic-gate 		mac_active_clear(dip->di_mh);
8690Sstevel@tonic-gate 	mutex_exit(&dlp->dl_lock);
8700Sstevel@tonic-gate out:
8710Sstevel@tonic-gate 	rw_exit(&dip->di_lock);
8720Sstevel@tonic-gate }
873