xref: /onnv-gate/usr/src/uts/common/io/dls/dls.c (revision 56:8b051e816bd8)
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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Data-Link Services Module
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include	<sys/types.h>
340Sstevel@tonic-gate #include	<sys/stream.h>
350Sstevel@tonic-gate #include	<sys/strsun.h>
360Sstevel@tonic-gate #include	<sys/sysmacros.h>
370Sstevel@tonic-gate #include	<sys/atomic.h>
380Sstevel@tonic-gate #include	<sys/ght.h>
390Sstevel@tonic-gate #include	<sys/dlpi.h>
400Sstevel@tonic-gate #include	<sys/vlan.h>
410Sstevel@tonic-gate #include	<sys/ethernet.h>
420Sstevel@tonic-gate #include	<sys/byteorder.h>
430Sstevel@tonic-gate #include	<sys/mac.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include	<sys/dls.h>
460Sstevel@tonic-gate #include	<sys/dls_impl.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static kmem_cache_t	*i_dls_impl_cachep;
490Sstevel@tonic-gate static uint32_t		i_dls_impl_count;
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate  * Private functions.
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*ARGSUSED*/
560Sstevel@tonic-gate static int
570Sstevel@tonic-gate i_dls_constructor(void *buf, void *arg, int kmflag)
580Sstevel@tonic-gate {
590Sstevel@tonic-gate 	dls_impl_t	*dip = buf;
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 	bzero(buf, sizeof (dls_impl_t));
620Sstevel@tonic-gate 
630Sstevel@tonic-gate 	rw_init(&(dip->di_lock), NULL, RW_DRIVER, NULL);
640Sstevel@tonic-gate 	return (0);
650Sstevel@tonic-gate }
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*ARGSUSED*/
680Sstevel@tonic-gate static void
690Sstevel@tonic-gate i_dls_destructor(void *buf, void *arg)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate 	dls_impl_t	*dip = buf;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	ASSERT(dip->di_dvp == NULL);
740Sstevel@tonic-gate 	ASSERT(dip->di_mnh == NULL);
750Sstevel@tonic-gate 	ASSERT(dip->di_dmap == NULL);
760Sstevel@tonic-gate 	ASSERT(!dip->di_bound);
770Sstevel@tonic-gate 	ASSERT(dip->di_rx == NULL);
78*56Smeem 	ASSERT(dip->di_txinfo == NULL);
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	rw_destroy(&(dip->di_lock));
810Sstevel@tonic-gate }
820Sstevel@tonic-gate 
830Sstevel@tonic-gate static void
840Sstevel@tonic-gate i_dls_notify(void *arg, mac_notify_type_t type)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	dls_impl_t		*dip = arg;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	switch (type) {
890Sstevel@tonic-gate 	case MAC_NOTE_UNICST:
900Sstevel@tonic-gate 		mac_unicst_get(dip->di_mh, dip->di_unicst_addr);
910Sstevel@tonic-gate 		break;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	case MAC_NOTE_PROMISC:
940Sstevel@tonic-gate 		/*
950Sstevel@tonic-gate 		 * Every time the MAC interface changes promiscuity we
96*56Smeem 		 * need to reset our transmit information.
970Sstevel@tonic-gate 		 */
98*56Smeem 		dip->di_txinfo = mac_tx_get(dip->di_mh);
990Sstevel@tonic-gate 		break;
1000Sstevel@tonic-gate 	}
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate static mblk_t *
1040Sstevel@tonic-gate i_dls_ether_header(dls_impl_t *dip, const uint8_t *daddr, uint16_t sap,
1050Sstevel@tonic-gate     uint_t pri)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate 	struct ether_header		*ehp;
1080Sstevel@tonic-gate 	struct ether_vlan_header	*evhp;
1090Sstevel@tonic-gate 	const mac_info_t		*mip;
1100Sstevel@tonic-gate 	uint_t				addr_length;
1110Sstevel@tonic-gate 	uint16_t			vid;
1120Sstevel@tonic-gate 	mblk_t				*mp;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	mip = dip->di_mip;
1150Sstevel@tonic-gate 	addr_length = mip->mi_addr_length;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	/*
1180Sstevel@tonic-gate 	 * Check whether the DLSAP value is legal for ethernet.
1190Sstevel@tonic-gate 	 */
1200Sstevel@tonic-gate 	if (!SAP_LEGAL(mip->mi_media, sap))
1210Sstevel@tonic-gate 		return (NULL);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	/*
1240Sstevel@tonic-gate 	 * If the interface is a VLAN interface then we need VLAN packet
1250Sstevel@tonic-gate 	 * headers.
1260Sstevel@tonic-gate 	 */
1270Sstevel@tonic-gate 	if ((vid = dip->di_dvp->dv_id) != VLAN_ID_NONE)
1280Sstevel@tonic-gate 		goto vlan;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	/*
1310Sstevel@tonic-gate 	 * Allocate a normal ethernet packet header.
1320Sstevel@tonic-gate 	 */
1330Sstevel@tonic-gate 	if ((mp = allocb(sizeof (struct ether_header), BPRI_HI)) == NULL)
1340Sstevel@tonic-gate 		return (NULL);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	/*
1370Sstevel@tonic-gate 	 * Copy in the given address as the destination, our current unicast
1380Sstevel@tonic-gate 	 * address as the source and the given sap as the type/length.
1390Sstevel@tonic-gate 	 */
1400Sstevel@tonic-gate 	ehp = (struct ether_header *)mp->b_rptr;
1410Sstevel@tonic-gate 	bcopy(daddr, &(ehp->ether_dhost), addr_length);
1420Sstevel@tonic-gate 	bcopy(dip->di_unicst_addr, &(ehp->ether_shost), addr_length);
1430Sstevel@tonic-gate 	ehp->ether_type = htons(sap);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	mp->b_wptr += sizeof (struct ether_header);
1460Sstevel@tonic-gate 	return (mp);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate vlan:
1490Sstevel@tonic-gate 	/*
1500Sstevel@tonic-gate 	 * Allocate a VLAN ethernet packet header.
1510Sstevel@tonic-gate 	 */
1520Sstevel@tonic-gate 	if ((mp = allocb(sizeof (struct ether_vlan_header), BPRI_HI)) == NULL)
1530Sstevel@tonic-gate 		return (NULL);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	/*
1560Sstevel@tonic-gate 	 * Copy in the given address as the destination, our current unicast
1570Sstevel@tonic-gate 	 * address as the source, the VLAN tpid and tci and the given sap as
1580Sstevel@tonic-gate 	 * the type/length.
1590Sstevel@tonic-gate 	 */
1600Sstevel@tonic-gate 	evhp = (struct ether_vlan_header *)mp->b_rptr;
1610Sstevel@tonic-gate 	bcopy(daddr, &(evhp->ether_dhost), addr_length);
1620Sstevel@tonic-gate 	bcopy(dip->di_unicst_addr, &(evhp->ether_shost), addr_length);
1630Sstevel@tonic-gate 	evhp->ether_tpid = htons(VLAN_TPID);
1640Sstevel@tonic-gate 	evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
1650Sstevel@tonic-gate 	evhp->ether_type = htons(sap);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	mp->b_wptr += sizeof (struct ether_vlan_header);
1680Sstevel@tonic-gate 	return (mp);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /*ARGSUSED*/
1720Sstevel@tonic-gate static void
1730Sstevel@tonic-gate i_dls_ether_header_info(dls_impl_t *dip, mblk_t *mp, dls_header_info_t *dhip)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	struct ether_header		*ehp;
1760Sstevel@tonic-gate 	struct ether_vlan_header	*evhp;
1770Sstevel@tonic-gate 	uint16_t			type_length;
1780Sstevel@tonic-gate 	uint16_t			tci;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	ASSERT(MBLKL(mp) >= sizeof (struct ether_header));
1810Sstevel@tonic-gate 	ehp = (struct ether_header *)mp->b_rptr;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	/*
1840Sstevel@tonic-gate 	 * Determine whether to parse a normal or VLAN ethernet header.
1850Sstevel@tonic-gate 	 */
1860Sstevel@tonic-gate 	if ((type_length = ntohs(ehp->ether_type)) == VLAN_TPID)
1870Sstevel@tonic-gate 		goto vlan;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/*
1900Sstevel@tonic-gate 	 * Specify the length of the header.
1910Sstevel@tonic-gate 	 */
1920Sstevel@tonic-gate 	dhip->dhi_length = sizeof (struct ether_header);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	/*
1950Sstevel@tonic-gate 	 * Get the destination address.
1960Sstevel@tonic-gate 	 */
1970Sstevel@tonic-gate 	dhip->dhi_daddr = (const uint8_t *)&(ehp->ether_dhost);
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	/*
2000Sstevel@tonic-gate 	 * If the destination address was a group address then
2010Sstevel@tonic-gate 	 * dl_group_address field should be non-zero.
2020Sstevel@tonic-gate 	 */
2030Sstevel@tonic-gate 	dhip->dhi_isgroup = (dhip->dhi_daddr[0] & 0x01);
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	/*
2060Sstevel@tonic-gate 	 * Get the source address.
2070Sstevel@tonic-gate 	 */
2080Sstevel@tonic-gate 	dhip->dhi_saddr = (uint8_t *)&(ehp->ether_shost);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/*
2110Sstevel@tonic-gate 	 * Get the ethertype
2120Sstevel@tonic-gate 	 */
2130Sstevel@tonic-gate 	dhip->dhi_ethertype = (type_length > ETHERMTU) ? type_length : 0;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	/*
2160Sstevel@tonic-gate 	 * The VLAN identifier must be VLAN_ID_NONE.
2170Sstevel@tonic-gate 	 */
2180Sstevel@tonic-gate 	dhip->dhi_vid = VLAN_ID_NONE;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	return;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate vlan:
2230Sstevel@tonic-gate 	ASSERT(MBLKL(mp) >= sizeof (struct ether_vlan_header));
2240Sstevel@tonic-gate 	evhp = (struct ether_vlan_header *)mp->b_rptr;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	/*
2270Sstevel@tonic-gate 	 * Specify the length of the header.
2280Sstevel@tonic-gate 	 */
2290Sstevel@tonic-gate 	dhip->dhi_length = sizeof (struct ether_vlan_header);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	/*
2320Sstevel@tonic-gate 	 * Get the destination address.
2330Sstevel@tonic-gate 	 */
2340Sstevel@tonic-gate 	dhip->dhi_daddr = (const uint8_t *)&(evhp->ether_dhost);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	/*
2370Sstevel@tonic-gate 	 * If the destination address was a group address then
2380Sstevel@tonic-gate 	 * dl_group_address field should be non-zero.
2390Sstevel@tonic-gate 	 */
2400Sstevel@tonic-gate 	dhip->dhi_isgroup = (dhip->dhi_daddr[0] & 0x01);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	/*
2430Sstevel@tonic-gate 	 * Get the source address.
2440Sstevel@tonic-gate 	 */
2450Sstevel@tonic-gate 	dhip->dhi_saddr = (uint8_t *)&(evhp->ether_shost);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	/*
2480Sstevel@tonic-gate 	 * Get the ethertype
2490Sstevel@tonic-gate 	 */
2500Sstevel@tonic-gate 	type_length = ntohs(evhp->ether_type);
2510Sstevel@tonic-gate 	dhip->dhi_ethertype = (type_length > ETHERMTU) ? type_length : 0;
2520Sstevel@tonic-gate 	ASSERT(dhip->dhi_ethertype != VLAN_TPID);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	/*
2550Sstevel@tonic-gate 	 * Get the VLAN identifier.
2560Sstevel@tonic-gate 	 */
2570Sstevel@tonic-gate 	tci = ntohs(evhp->ether_tci);
2580Sstevel@tonic-gate 	dhip->dhi_vid = VLAN_ID(tci);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate /*
2620Sstevel@tonic-gate  * Module initialization functions.
2630Sstevel@tonic-gate  */
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate void
2660Sstevel@tonic-gate dls_init(void)
2670Sstevel@tonic-gate {
2680Sstevel@tonic-gate 	/*
2690Sstevel@tonic-gate 	 * Create a kmem_cache of dls_impl_t.
2700Sstevel@tonic-gate 	 */
2710Sstevel@tonic-gate 	i_dls_impl_cachep = kmem_cache_create("dls_cache",
2720Sstevel@tonic-gate 	    sizeof (dls_impl_t), 0, i_dls_constructor, i_dls_destructor, NULL,
2730Sstevel@tonic-gate 	    NULL, NULL, 0);
2740Sstevel@tonic-gate 	ASSERT(i_dls_impl_cachep != NULL);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate int
2780Sstevel@tonic-gate dls_fini(void)
2790Sstevel@tonic-gate {
2800Sstevel@tonic-gate 	/*
2810Sstevel@tonic-gate 	 * If there are any dls_impl_t in use then return EBUSY.
2820Sstevel@tonic-gate 	 */
2830Sstevel@tonic-gate 	if (i_dls_impl_count != 0)
2840Sstevel@tonic-gate 		return (EBUSY);
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	/*
2870Sstevel@tonic-gate 	 * Destroy the kmem_cache.
2880Sstevel@tonic-gate 	 */
2890Sstevel@tonic-gate 	kmem_cache_destroy(i_dls_impl_cachep);
2900Sstevel@tonic-gate 	return (0);
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate /*
2940Sstevel@tonic-gate  * Client function.
2950Sstevel@tonic-gate  */
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate int
2980Sstevel@tonic-gate dls_create(const char *name, const char *dev, uint_t port, uint16_t vid)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	return (dls_vlan_create(name, dev, port, vid));
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate int
3040Sstevel@tonic-gate dls_destroy(const char *name)
3050Sstevel@tonic-gate {
3060Sstevel@tonic-gate 	return (dls_vlan_destroy(name));
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate int
3100Sstevel@tonic-gate dls_open(const char *name, dls_channel_t *dcp)
3110Sstevel@tonic-gate {
3120Sstevel@tonic-gate 	dls_impl_t	*dip;
3130Sstevel@tonic-gate 	dls_vlan_t	*dvp;
3140Sstevel@tonic-gate 	dls_link_t	*dlp;
3150Sstevel@tonic-gate 	int		err;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	/*
3180Sstevel@tonic-gate 	 * Get a reference to the named dls_vlan_t.
3190Sstevel@tonic-gate 	 */
3200Sstevel@tonic-gate 	if ((err = dls_vlan_hold(name, &dvp)) != 0)
3210Sstevel@tonic-gate 		return (err);
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	/*
3240Sstevel@tonic-gate 	 * Allocate a new dls_impl_t.
3250Sstevel@tonic-gate 	 */
3260Sstevel@tonic-gate 	dip = kmem_cache_alloc(i_dls_impl_cachep, KM_SLEEP);
3270Sstevel@tonic-gate 	dip->di_dvp = dvp;
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	/*
3300Sstevel@tonic-gate 	 * Cache a copy of the MAC interface handle, a pointer to the
3310Sstevel@tonic-gate 	 * immutable MAC info and a copy of the current MAC address.
3320Sstevel@tonic-gate 	 */
3330Sstevel@tonic-gate 	dlp = dvp->dv_dlp;
3340Sstevel@tonic-gate 	dip->di_mh = dlp->dl_mh;
3350Sstevel@tonic-gate 	dip->di_mip = dlp->dl_mip;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	mac_unicst_get(dip->di_mh, dip->di_unicst_addr);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	/*
340*56Smeem 	 * Set the MAC transmit information.
3410Sstevel@tonic-gate 	 */
342*56Smeem 	dip->di_txinfo = mac_tx_get(dip->di_mh);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/*
3450Sstevel@tonic-gate 	 * Set up packet header constructor and parser functions. (We currently
3460Sstevel@tonic-gate 	 * only support ethernet).
3470Sstevel@tonic-gate 	 */
3480Sstevel@tonic-gate 	ASSERT(dip->di_mip->mi_media == DL_ETHER);
3490Sstevel@tonic-gate 	dip->di_header = i_dls_ether_header;
3500Sstevel@tonic-gate 	dip->di_header_info = i_dls_ether_header_info;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/*
3530Sstevel@tonic-gate 	 * Add a notification function so that we get updates from the MAC.
3540Sstevel@tonic-gate 	 */
3550Sstevel@tonic-gate 	dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify, (void *)dip);
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	/*
3580Sstevel@tonic-gate 	 * Bump the kmem_cache count to make sure it is not prematurely
3590Sstevel@tonic-gate 	 * destroyed.
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 	atomic_add_32(&i_dls_impl_count, 1);
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/*
3640Sstevel@tonic-gate 	 * Hand back a reference to the dls_impl_t.
3650Sstevel@tonic-gate 	 */
3660Sstevel@tonic-gate 	*dcp = (dls_channel_t)dip;
3670Sstevel@tonic-gate 	return (0);
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate void
3710Sstevel@tonic-gate dls_close(dls_channel_t dc)
3720Sstevel@tonic-gate {
3730Sstevel@tonic-gate 	dls_impl_t		*dip = (dls_impl_t *)dc;
3740Sstevel@tonic-gate 	dls_vlan_t		*dvp;
3750Sstevel@tonic-gate 	dls_link_t		*dlp;
3760Sstevel@tonic-gate 	dls_multicst_addr_t	*p;
3770Sstevel@tonic-gate 	dls_multicst_addr_t	*nextp;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	dls_active_clear(dc);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	/*
3840Sstevel@tonic-gate 	 * Remove the notify function.
3850Sstevel@tonic-gate 	 */
3860Sstevel@tonic-gate 	mac_notify_remove(dip->di_mh, dip->di_mnh);
3870Sstevel@tonic-gate 	dip->di_mnh = NULL;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	/*
3900Sstevel@tonic-gate 	 * If the dls_impl_t is bound then unbind it.
3910Sstevel@tonic-gate 	 */
3920Sstevel@tonic-gate 	dvp = dip->di_dvp;
3930Sstevel@tonic-gate 	dlp = dvp->dv_dlp;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	if (dip->di_bound) {
3960Sstevel@tonic-gate 		rw_exit(&(dip->di_lock));
3970Sstevel@tonic-gate 		dls_link_remove(dlp, dip);
3980Sstevel@tonic-gate 		rw_enter(&(dip->di_lock), RW_WRITER);
3990Sstevel@tonic-gate 		dip->di_rx = NULL;
4000Sstevel@tonic-gate 		dip->di_rx_arg = NULL;
4010Sstevel@tonic-gate 		dip->di_bound = B_FALSE;
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	/*
4050Sstevel@tonic-gate 	 * Walk the list of multicast addresses, disabling each at the MAC.
4060Sstevel@tonic-gate 	 */
4070Sstevel@tonic-gate 	for (p = dip->di_dmap; p != NULL; p = nextp) {
4080Sstevel@tonic-gate 		(void) mac_multicst_remove(dip->di_mh, p->dma_addr);
4090Sstevel@tonic-gate 		nextp = p->dma_nextp;
4100Sstevel@tonic-gate 		kmem_free(p, sizeof (dls_multicst_addr_t));
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 	dip->di_dmap = NULL;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/*
4170Sstevel@tonic-gate 	 * If the MAC has been set in promiscuous mode then disable it.
4180Sstevel@tonic-gate 	 */
4190Sstevel@tonic-gate 	(void) dls_promisc(dc, 0);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	/*
4220Sstevel@tonic-gate 	 * Free the dls_impl_t back to the cache.
4230Sstevel@tonic-gate 	 */
4240Sstevel@tonic-gate 	dip->di_dvp = NULL;
425*56Smeem 	dip->di_txinfo = NULL;
4260Sstevel@tonic-gate 	kmem_cache_free(i_dls_impl_cachep, dip);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	/*
4290Sstevel@tonic-gate 	 * Decrement the reference count to allow the cache to be destroyed
4300Sstevel@tonic-gate 	 * if there are no more dls_impl_t.
4310Sstevel@tonic-gate 	 */
4320Sstevel@tonic-gate 	atomic_add_32(&i_dls_impl_count, -1);
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	/*
4350Sstevel@tonic-gate 	 * Release our reference to the dls_vlan_t allowing that to be
4360Sstevel@tonic-gate 	 * destroyed if there are no more dls_impl_t.
4370Sstevel@tonic-gate 	 */
4380Sstevel@tonic-gate 	dls_vlan_rele(dvp);
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate mac_handle_t
4420Sstevel@tonic-gate dls_mac(dls_channel_t dc)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	return (dip->di_mh);
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate uint16_t
4500Sstevel@tonic-gate dls_vid(dls_channel_t dc)
4510Sstevel@tonic-gate {
4520Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	return (dip->di_dvp->dv_id);
4550Sstevel@tonic-gate }
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate int
4580Sstevel@tonic-gate dls_bind(dls_channel_t dc, uint16_t sap)
4590Sstevel@tonic-gate {
4600Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
4610Sstevel@tonic-gate 	dls_link_t	*dlp;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	/*
4640Sstevel@tonic-gate 	 * Check to see the value is legal for the media type.
4650Sstevel@tonic-gate 	 */
4660Sstevel@tonic-gate 	if (!SAP_LEGAL(dip->di_mip->mi_media, sap))
4670Sstevel@tonic-gate 		return (EINVAL);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	/*
4700Sstevel@tonic-gate 	 * Set up the dls_impl_t to mark it as able to receive packets.
4710Sstevel@tonic-gate 	 */
4720Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
4730Sstevel@tonic-gate 	ASSERT(!dip->di_bound);
4740Sstevel@tonic-gate 	dip->di_sap = sap;
4750Sstevel@tonic-gate 	dip->di_bound = B_TRUE;
4760Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	/*
4790Sstevel@tonic-gate 	 * Now bind the dls_impl_t by adding it into the hash table in the
4800Sstevel@tonic-gate 	 * dls_link_t.
4810Sstevel@tonic-gate 	 *
4820Sstevel@tonic-gate 	 * NOTE: This must be done without the dls_impl_t lock being held
4830Sstevel@tonic-gate 	 *	 otherwise deadlock may ensue.
4840Sstevel@tonic-gate 	 */
4850Sstevel@tonic-gate 	dlp = dip->di_dvp->dv_dlp;
4860Sstevel@tonic-gate 	dls_link_add(dlp,
4870Sstevel@tonic-gate 	    (dip->di_promisc & DLS_PROMISC_SAP) ? DLS_SAP_PROMISC :
4880Sstevel@tonic-gate 	    (uint32_t)sap, dip);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	return (0);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate void
4940Sstevel@tonic-gate dls_unbind(dls_channel_t dc)
4950Sstevel@tonic-gate {
4960Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
4970Sstevel@tonic-gate 	dls_link_t	*dlp;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	/*
5000Sstevel@tonic-gate 	 * Unbind the dls_impl_t by removing it from the hash table in the
5010Sstevel@tonic-gate 	 * dls_link_t.
5020Sstevel@tonic-gate 	 *
5030Sstevel@tonic-gate 	 * NOTE: This must be done without the dls_impl_t lock being held
5040Sstevel@tonic-gate 	 *	 otherise deadlock may enuse.
5050Sstevel@tonic-gate 	 */
5060Sstevel@tonic-gate 	dlp = dip->di_dvp->dv_dlp;
5070Sstevel@tonic-gate 	dls_link_remove(dlp, dip);
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	/*
5100Sstevel@tonic-gate 	 * Mark the dls_impl_t as unable to receive packets This will make
5110Sstevel@tonic-gate 	 * sure that 'receives in flight' will not come our way.
5120Sstevel@tonic-gate 	 */
5130Sstevel@tonic-gate 	dip->di_bound = B_FALSE;
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate int
5170Sstevel@tonic-gate dls_promisc(dls_channel_t dc, uint32_t flags)
5180Sstevel@tonic-gate {
5190Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
5200Sstevel@tonic-gate 	dls_link_t	*dlp;
5210Sstevel@tonic-gate 	int		err = 0;
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	ASSERT(!(flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
5240Sstevel@tonic-gate 	    DLS_PROMISC_PHYS)));
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	/*
5270Sstevel@tonic-gate 	 * Check if we need to turn on 'all sap' mode.
5280Sstevel@tonic-gate 	 */
5290Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
5300Sstevel@tonic-gate 	dlp = dip->di_dvp->dv_dlp;
5310Sstevel@tonic-gate 	if ((flags & DLS_PROMISC_SAP) &&
5320Sstevel@tonic-gate 	    !(dip->di_promisc & DLS_PROMISC_SAP)) {
5330Sstevel@tonic-gate 		dip->di_promisc |= DLS_PROMISC_SAP;
5340Sstevel@tonic-gate 		if (!dip->di_bound)
5350Sstevel@tonic-gate 			goto multi;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 		rw_exit(&(dip->di_lock));
5380Sstevel@tonic-gate 		dls_link_remove(dlp, dip);
5390Sstevel@tonic-gate 		dls_link_add(dlp, DLS_SAP_PROMISC, dip);
5400Sstevel@tonic-gate 		rw_enter(&(dip->di_lock), RW_WRITER);
5410Sstevel@tonic-gate 		goto multi;
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	/*
5450Sstevel@tonic-gate 	 * Check if we need to turn off 'all sap' mode.
5460Sstevel@tonic-gate 	 */
5470Sstevel@tonic-gate 	if (!(flags & DLS_PROMISC_SAP) &&
5480Sstevel@tonic-gate 	    (dip->di_promisc & DLS_PROMISC_SAP)) {
5490Sstevel@tonic-gate 		dip->di_promisc &= ~DLS_PROMISC_SAP;
5500Sstevel@tonic-gate 		if (!dip->di_bound)
5510Sstevel@tonic-gate 			goto multi;
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 		rw_exit(&(dip->di_lock));
5540Sstevel@tonic-gate 		dls_link_remove(dlp, dip);
5550Sstevel@tonic-gate 		dls_link_add(dlp, dip->di_sap, dip);
5560Sstevel@tonic-gate 		rw_enter(&(dip->di_lock), RW_WRITER);
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate multi:
5600Sstevel@tonic-gate 	/*
5610Sstevel@tonic-gate 	 * It's easiest to add the txloop handler up-front; if promiscuous
5620Sstevel@tonic-gate 	 * mode cannot be enabled, then we'll remove it before returning.
563*56Smeem 	 * Use dl_promisc_lock to prevent racing with another thread also
564*56Smeem 	 * manipulating the promiscuous state on another dls_impl_t associated
565*56Smeem 	 * with the same dls_link_t.
5660Sstevel@tonic-gate 	 */
567*56Smeem 	mutex_enter(&dlp->dl_promisc_lock);
5680Sstevel@tonic-gate 	if (dlp->dl_npromisc == 0 &&
5690Sstevel@tonic-gate 	    (flags & (DLS_PROMISC_MULTI|DLS_PROMISC_PHYS))) {
5700Sstevel@tonic-gate 		ASSERT(dlp->dl_mth == NULL);
5710Sstevel@tonic-gate 		dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dlp->dl_loopback, dlp);
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	/*
575*56Smeem 	 * Turn on or off 'all multicast' mode, if necessary.
5760Sstevel@tonic-gate 	 */
577*56Smeem 	if (flags & DLS_PROMISC_MULTI) {
578*56Smeem 		if (!(dip->di_promisc & DLS_PROMISC_MULTI)) {
579*56Smeem 			err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC);
580*56Smeem 			if (err != 0)
581*56Smeem 				goto done;
582*56Smeem 			dip->di_promisc |= DLS_PROMISC_MULTI;
583*56Smeem 			dlp->dl_npromisc++;
584*56Smeem 		}
585*56Smeem 	} else {
586*56Smeem 		if (dip->di_promisc & DLS_PROMISC_MULTI) {
587*56Smeem 			err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC);
588*56Smeem 			if (err != 0)
589*56Smeem 				goto done;
590*56Smeem 			dip->di_promisc &= ~DLS_PROMISC_MULTI;
591*56Smeem 			dlp->dl_npromisc--;
592*56Smeem 		}
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	/*
596*56Smeem 	 * Turn on or off 'all physical' mode, if necessary.
5970Sstevel@tonic-gate 	 */
598*56Smeem 	if (flags & DLS_PROMISC_PHYS) {
599*56Smeem 		if (!(dip->di_promisc & DLS_PROMISC_PHYS)) {
600*56Smeem 			err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC);
601*56Smeem 			if (err != 0)
602*56Smeem 				goto done;
603*56Smeem 			dip->di_promisc |= DLS_PROMISC_PHYS;
604*56Smeem 			dlp->dl_npromisc++;
605*56Smeem 		}
606*56Smeem 	} else {
607*56Smeem 		if (dip->di_promisc & DLS_PROMISC_PHYS) {
608*56Smeem 			err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC);
609*56Smeem 			if (err != 0)
610*56Smeem 				goto done;
611*56Smeem 			dip->di_promisc &= ~DLS_PROMISC_PHYS;
612*56Smeem 			dlp->dl_npromisc--;
613*56Smeem 		}
6140Sstevel@tonic-gate 	}
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate done:
6170Sstevel@tonic-gate 	if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) {
6180Sstevel@tonic-gate 		mac_txloop_remove(dlp->dl_mh, dlp->dl_mth);
6190Sstevel@tonic-gate 		dlp->dl_mth = NULL;
6200Sstevel@tonic-gate 	}
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL);
623*56Smeem 	mutex_exit(&dlp->dl_promisc_lock);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
6260Sstevel@tonic-gate 	return (err);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate int
6300Sstevel@tonic-gate dls_multicst_add(dls_channel_t dc, const uint8_t *addr)
6310Sstevel@tonic-gate {
6320Sstevel@tonic-gate 	dls_impl_t		*dip = (dls_impl_t *)dc;
6330Sstevel@tonic-gate 	int			err;
6340Sstevel@tonic-gate 	dls_multicst_addr_t	**pp;
6350Sstevel@tonic-gate 	dls_multicst_addr_t	*p;
6360Sstevel@tonic-gate 	uint_t			addr_length;
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	/*
6390Sstevel@tonic-gate 	 * Check whether the address is in the list of enabled addresses for
6400Sstevel@tonic-gate 	 * this dls_impl_t.
6410Sstevel@tonic-gate 	 */
6420Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
6430Sstevel@tonic-gate 	addr_length = dip->di_mip->mi_addr_length;
6440Sstevel@tonic-gate 	for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
6450Sstevel@tonic-gate 		if (bcmp(addr, p->dma_addr, addr_length) == 0) {
6460Sstevel@tonic-gate 			/*
6470Sstevel@tonic-gate 			 * It is there so there's nothing to do.
6480Sstevel@tonic-gate 			 */
6490Sstevel@tonic-gate 			err = 0;
6500Sstevel@tonic-gate 			goto done;
6510Sstevel@tonic-gate 		}
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/*
6550Sstevel@tonic-gate 	 * Allocate a new list item.
6560Sstevel@tonic-gate 	 */
6570Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t),
6580Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
6590Sstevel@tonic-gate 		err = ENOMEM;
6600Sstevel@tonic-gate 		goto done;
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	/*
6640Sstevel@tonic-gate 	 * Enable the address at the MAC.
6650Sstevel@tonic-gate 	 */
6660Sstevel@tonic-gate 	if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) {
6670Sstevel@tonic-gate 		kmem_free(p, sizeof (dls_multicst_addr_t));
6680Sstevel@tonic-gate 		goto done;
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	/*
6720Sstevel@tonic-gate 	 * The address is now enabled at the MAC so add it to the list.
6730Sstevel@tonic-gate 	 */
6740Sstevel@tonic-gate 	bcopy(addr, p->dma_addr, addr_length);
6750Sstevel@tonic-gate 	*pp = p;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate done:
6780Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
6790Sstevel@tonic-gate 	return (err);
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate int
6830Sstevel@tonic-gate dls_multicst_remove(dls_channel_t dc, const uint8_t *addr)
6840Sstevel@tonic-gate {
6850Sstevel@tonic-gate 	dls_impl_t		*dip = (dls_impl_t *)dc;
6860Sstevel@tonic-gate 	int			err;
6870Sstevel@tonic-gate 	dls_multicst_addr_t	**pp;
6880Sstevel@tonic-gate 	dls_multicst_addr_t	*p;
6890Sstevel@tonic-gate 	uint_t			addr_length;
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	/*
6920Sstevel@tonic-gate 	 * Find the address in the list of enabled addresses for this
6930Sstevel@tonic-gate 	 * dls_impl_t.
6940Sstevel@tonic-gate 	 */
6950Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
6960Sstevel@tonic-gate 	addr_length = dip->di_mip->mi_addr_length;
6970Sstevel@tonic-gate 	for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) {
6980Sstevel@tonic-gate 		if (bcmp(addr, p->dma_addr, addr_length) == 0)
6990Sstevel@tonic-gate 			break;
7000Sstevel@tonic-gate 	}
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	/*
7030Sstevel@tonic-gate 	 * If we walked to the end of the list then the given address is
7040Sstevel@tonic-gate 	 * not currently enabled for this dls_impl_t.
7050Sstevel@tonic-gate 	 */
7060Sstevel@tonic-gate 	if (p == NULL) {
7070Sstevel@tonic-gate 		err = ENOENT;
7080Sstevel@tonic-gate 		goto done;
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	/*
7120Sstevel@tonic-gate 	 * Disable the address at the MAC.
7130Sstevel@tonic-gate 	 */
7140Sstevel@tonic-gate 	if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0)
7150Sstevel@tonic-gate 		goto done;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	/*
7180Sstevel@tonic-gate 	 * Remove the address from the list.
7190Sstevel@tonic-gate 	 */
7200Sstevel@tonic-gate 	*pp = p->dma_nextp;
7210Sstevel@tonic-gate 	kmem_free(p, sizeof (dls_multicst_addr_t));
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate done:
7240Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
7250Sstevel@tonic-gate 	return (err);
7260Sstevel@tonic-gate }
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate mblk_t *
7290Sstevel@tonic-gate dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri)
7300Sstevel@tonic-gate {
7310Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	return (dip->di_header(dip, addr, sap, pri));
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate void
7370Sstevel@tonic-gate dls_header_info(dls_channel_t dc, mblk_t *mp, dls_header_info_t *dhip)
7380Sstevel@tonic-gate {
7390Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	dip->di_header_info(dip, mp, dhip);
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate void
7450Sstevel@tonic-gate dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg)
7460Sstevel@tonic-gate {
7470Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_WRITER);
7500Sstevel@tonic-gate 	dip->di_rx = rx;
7510Sstevel@tonic-gate 	dip->di_rx_arg = arg;
7520Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate mblk_t *
7560Sstevel@tonic-gate dls_tx(dls_channel_t dc, mblk_t *mp)
7570Sstevel@tonic-gate {
758*56Smeem 	const mac_txinfo_t *mtp = ((dls_impl_t *)dc)->di_txinfo;
7590Sstevel@tonic-gate 
760*56Smeem 	return (mtp->mt_fn(mtp->mt_arg, mp));
7610Sstevel@tonic-gate }
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate /*
7640Sstevel@tonic-gate  * Exported functions.
7650Sstevel@tonic-gate  */
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate #define	ADDR_MATCH(_addr_a, _addr_b, _length, _match)			\
7680Sstevel@tonic-gate 	{								\
7690Sstevel@tonic-gate 		uint_t	i;						\
7700Sstevel@tonic-gate 									\
7710Sstevel@tonic-gate 		/*							\
7720Sstevel@tonic-gate 		 * Make sure the addresses are 16 bit aligned and that	\
7730Sstevel@tonic-gate 		 * the length is an even number of octets.		\
7740Sstevel@tonic-gate 		 */							\
7750Sstevel@tonic-gate 		ASSERT(IS_P2ALIGNED((_addr_a), sizeof (uint16_t)));	\
7760Sstevel@tonic-gate 		ASSERT(IS_P2ALIGNED((_addr_b), sizeof (uint16_t)));	\
7770Sstevel@tonic-gate 		ASSERT((_length & 1) == 0);				\
7780Sstevel@tonic-gate 									\
7790Sstevel@tonic-gate 		(_match) = B_TRUE;					\
7800Sstevel@tonic-gate 		for (i = 0; i < (_length) >> 1; i++) {			\
7810Sstevel@tonic-gate 			if (((uint16_t *)(_addr_a))[i] !=		\
7820Sstevel@tonic-gate 			    ((uint16_t *)(_addr_b))[i]) {		\
7830Sstevel@tonic-gate 				(_match) = B_FALSE;			\
7840Sstevel@tonic-gate 				break;					\
7850Sstevel@tonic-gate 			}						\
7860Sstevel@tonic-gate 		}							\
7870Sstevel@tonic-gate 	}
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate boolean_t
7900Sstevel@tonic-gate dls_accept(dls_impl_t *dip, const uint8_t *daddr)
7910Sstevel@tonic-gate {
7920Sstevel@tonic-gate 	boolean_t		match;
7930Sstevel@tonic-gate 	dls_multicst_addr_t	*dmap;
7940Sstevel@tonic-gate 	uint_t			addr_length = dip->di_mip->mi_addr_length;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	/*
7970Sstevel@tonic-gate 	 * We must not accept packets if the dls_impl_t is not marked as bound
7980Sstevel@tonic-gate 	 * or is being removed.
7990Sstevel@tonic-gate 	 */
8000Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_READER);
8010Sstevel@tonic-gate 	if (!dip->di_bound || dip->di_removing)
8020Sstevel@tonic-gate 		goto refuse;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	/*
8050Sstevel@tonic-gate 	 * If the dls_impl_t is in 'all physical' mode then always accept.
8060Sstevel@tonic-gate 	 */
8070Sstevel@tonic-gate 	if (dip->di_promisc & DLS_PROMISC_PHYS)
8080Sstevel@tonic-gate 		goto accept;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	/*
8110Sstevel@tonic-gate 	 * Check to see if the destination address matches the dls_impl_t
8120Sstevel@tonic-gate 	 * unicast address.
8130Sstevel@tonic-gate 	 */
8140Sstevel@tonic-gate 	ADDR_MATCH(daddr, dip->di_unicst_addr, addr_length, match);
8150Sstevel@tonic-gate 	if (match)
8160Sstevel@tonic-gate 		goto accept;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	/*
8190Sstevel@tonic-gate 	 * Check for a 'group' address. If it is not then refuse it since we
8200Sstevel@tonic-gate 	 * already know it does not match the unicast address.
8210Sstevel@tonic-gate 	 */
8220Sstevel@tonic-gate 	if (!(daddr[0] & 0x01))
8230Sstevel@tonic-gate 		goto refuse;
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	/*
8260Sstevel@tonic-gate 	 * If the address is broadcast then the dls_impl_t will always accept
8270Sstevel@tonic-gate 	 * it.
8280Sstevel@tonic-gate 	 */
8290Sstevel@tonic-gate 	ADDR_MATCH(daddr, dip->di_mip->mi_brdcst_addr, addr_length,
8300Sstevel@tonic-gate 	    match);
8310Sstevel@tonic-gate 	if (match)
8320Sstevel@tonic-gate 		goto accept;
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	/*
8350Sstevel@tonic-gate 	 * If a group address is not broadcast then it must be multicast so
8360Sstevel@tonic-gate 	 * check it against the list of addresses enabled for this dls_impl_t
8370Sstevel@tonic-gate 	 * or accept it unconditionally if the dls_impl_t is in 'all
8380Sstevel@tonic-gate 	 * multicast' mode.
8390Sstevel@tonic-gate 	 */
8400Sstevel@tonic-gate 	if (dip->di_promisc & DLS_PROMISC_MULTI)
8410Sstevel@tonic-gate 		goto accept;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	for (dmap = dip->di_dmap; dmap != NULL; dmap = dmap->dma_nextp) {
8440Sstevel@tonic-gate 		ADDR_MATCH(daddr, dmap->dma_addr, addr_length, match);
8450Sstevel@tonic-gate 		if (match)
8460Sstevel@tonic-gate 			goto accept;
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate refuse:
8500Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
8510Sstevel@tonic-gate 	return (B_FALSE);
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate accept:
8540Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
8550Sstevel@tonic-gate 	return (B_TRUE);
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate /*ARGSUSED*/
8590Sstevel@tonic-gate boolean_t
8600Sstevel@tonic-gate dls_accept_loopback(dls_impl_t *dip, const uint8_t *daddr)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 	/*
8630Sstevel@tonic-gate 	 * We must not accept packets if the dls_impl_t is not marked as bound
8640Sstevel@tonic-gate 	 * or is being removed.
8650Sstevel@tonic-gate 	 */
8660Sstevel@tonic-gate 	rw_enter(&(dip->di_lock), RW_READER);
8670Sstevel@tonic-gate 	if (!dip->di_bound || dip->di_removing)
8680Sstevel@tonic-gate 		goto refuse;
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	/*
8710Sstevel@tonic-gate 	 * A dls_impl_t should only accept loopback packets if it is in
8720Sstevel@tonic-gate 	 * 'all physical' mode.
8730Sstevel@tonic-gate 	 */
8740Sstevel@tonic-gate 	if (dip->di_promisc & DLS_PROMISC_PHYS)
8750Sstevel@tonic-gate 		goto accept;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate refuse:
8780Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
8790Sstevel@tonic-gate 	return (B_FALSE);
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate accept:
8820Sstevel@tonic-gate 	rw_exit(&(dip->di_lock));
8830Sstevel@tonic-gate 	return (B_TRUE);
8840Sstevel@tonic-gate }
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate boolean_t
8870Sstevel@tonic-gate dls_active_set(dls_channel_t dc)
8880Sstevel@tonic-gate {
8890Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
8900Sstevel@tonic-gate 	dls_link_t	*dlp = dip->di_dvp->dv_dlp;
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	rw_enter(&dip->di_lock, RW_WRITER);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	/* If we're already active, then there's nothing more to do. */
8950Sstevel@tonic-gate 	if (dip->di_active) {
8960Sstevel@tonic-gate 		rw_exit(&dip->di_lock);
8970Sstevel@tonic-gate 		return (B_TRUE);
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	/*
9010Sstevel@tonic-gate 	 * If this is the first active client on this link, notify
9020Sstevel@tonic-gate 	 * the mac that we're becoming an active client.
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 	if (dlp->dl_nactive == 0 && !mac_active_set(dlp->dl_mh)) {
9050Sstevel@tonic-gate 		rw_exit(&dip->di_lock);
9060Sstevel@tonic-gate 		return (B_FALSE);
9070Sstevel@tonic-gate 	}
9080Sstevel@tonic-gate 	dip->di_active = B_TRUE;
9090Sstevel@tonic-gate 	mutex_enter(&dlp->dl_lock);
9100Sstevel@tonic-gate 	dlp->dl_nactive++;
9110Sstevel@tonic-gate 	mutex_exit(&dlp->dl_lock);
9120Sstevel@tonic-gate 	rw_exit(&dip->di_lock);
9130Sstevel@tonic-gate 	return (B_TRUE);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate void
9170Sstevel@tonic-gate dls_active_clear(dls_channel_t dc)
9180Sstevel@tonic-gate {
9190Sstevel@tonic-gate 	dls_impl_t	*dip = (dls_impl_t *)dc;
9200Sstevel@tonic-gate 	dls_link_t	*dlp = dip->di_dvp->dv_dlp;
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	rw_enter(&dip->di_lock, RW_WRITER);
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	if (!dip->di_active)
9250Sstevel@tonic-gate 		goto out;
9260Sstevel@tonic-gate 	dip->di_active = B_FALSE;
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	mutex_enter(&dlp->dl_lock);
9290Sstevel@tonic-gate 	if (--dlp->dl_nactive == 0)
9300Sstevel@tonic-gate 		mac_active_clear(dip->di_mh);
9310Sstevel@tonic-gate 	mutex_exit(&dlp->dl_lock);
9320Sstevel@tonic-gate out:
9330Sstevel@tonic-gate 	rw_exit(&dip->di_lock);
9340Sstevel@tonic-gate }
935