xref: /onnv-gate/usr/src/uts/common/io/dls/dls_link.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/strsubr.h>
370Sstevel@tonic-gate #include	<sys/sysmacros.h>
380Sstevel@tonic-gate #include	<sys/atomic.h>
390Sstevel@tonic-gate #include	<sys/ght.h>
400Sstevel@tonic-gate #include	<sys/dlpi.h>
410Sstevel@tonic-gate #include	<sys/ethernet.h>
420Sstevel@tonic-gate #include	<sys/byteorder.h>
430Sstevel@tonic-gate #include	<sys/vlan.h>
440Sstevel@tonic-gate #include	<sys/mac.h>
450Sstevel@tonic-gate #include	<sys/sdt.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #include	<sys/dls.h>
480Sstevel@tonic-gate #include	<sys/dld_impl.h>
490Sstevel@tonic-gate #include	<sys/dls_impl.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static kmem_cache_t	*i_dls_link_cachep;
520Sstevel@tonic-gate static ght_t		i_dls_link_hash;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #define		LINK_HASHSZ	67	/* prime */
550Sstevel@tonic-gate #define		IMPL_HASHSZ	67	/* prime */
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * Construct a hash key encompassing both DLSAP value and VLAN idenitifier.
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate #define	MAKE_KEY(_sap, _vid)						\
610Sstevel@tonic-gate 	GHT_SCALAR_TO_KEY(((_sap) << VLAN_ID_SIZE) | (_vid) & VLAN_ID_MASK)
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate  * Extract the DLSAP value from the hash key.
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate #define	KEY_SAP(_key)							\
670Sstevel@tonic-gate 	(((uint32_t)(uintptr_t)(_key)) >> VLAN_ID_SIZE)
680Sstevel@tonic-gate 
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate  * Private functions.
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*ARGSUSED*/
740Sstevel@tonic-gate static int
750Sstevel@tonic-gate i_dls_link_constructor(void *buf, void *arg, int kmflag)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	dls_link_t	*dlp = buf;
780Sstevel@tonic-gate 	char		name[MAXNAMELEN];
790Sstevel@tonic-gate 	int		err;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	bzero(buf, sizeof (dls_link_t));
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	(void) sprintf(name, "dls_link_t_%p_impl_hash", buf);
840Sstevel@tonic-gate 	err = ght_scalar_create(name, IMPL_HASHSZ, &(dlp->dl_impl_hash));
850Sstevel@tonic-gate 	ASSERT(err == 0);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	mutex_init(&dlp->dl_lock, NULL, MUTEX_DEFAULT, NULL);
88*56Smeem 	mutex_init(&dlp->dl_promisc_lock, NULL, MUTEX_DEFAULT, NULL);
890Sstevel@tonic-gate 	return (0);
900Sstevel@tonic-gate }
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*ARGSUSED*/
930Sstevel@tonic-gate static void
940Sstevel@tonic-gate i_dls_link_destructor(void *buf, void *arg)
950Sstevel@tonic-gate {
960Sstevel@tonic-gate 	dls_link_t	*dlp = buf;
970Sstevel@tonic-gate 	int		err;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	ASSERT(dlp->dl_ref == 0);
1000Sstevel@tonic-gate 	ASSERT(dlp->dl_hte == NULL);
1010Sstevel@tonic-gate 	ASSERT(dlp->dl_mh == NULL);
1020Sstevel@tonic-gate 	ASSERT(dlp->dl_unknowns == 0);
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	err = ght_destroy(dlp->dl_impl_hash);
1050Sstevel@tonic-gate 	ASSERT(err == 0);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	mutex_destroy(&dlp->dl_lock);
108*56Smeem 	mutex_destroy(&dlp->dl_promisc_lock);
1090Sstevel@tonic-gate }
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate #define	ETHER_MATCH(_pkt_a, _pkt_b)					\
1120Sstevel@tonic-gate 	((((uint16_t *)(_pkt_a))[0] == ((uint16_t *)(_pkt_b))[0]) &&	\
1130Sstevel@tonic-gate 	(((uint16_t *)(_pkt_a))[1] == ((uint16_t *)(_pkt_b))[1]) &&	\
1140Sstevel@tonic-gate 	(((uint16_t *)(_pkt_a))[2] == ((uint16_t *)(_pkt_b))[2]) &&	\
1150Sstevel@tonic-gate 	(((uint16_t *)(_pkt_a))[6] == ((uint16_t *)(_pkt_b))[6]))
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate #define	ETHER_VLAN_MATCH(_pkt_a, _pkt_b)				\
1180Sstevel@tonic-gate 	((((uint16_t *)(_pkt_a))[0] == ((uint16_t *)(_pkt_b))[0]) &&	\
1190Sstevel@tonic-gate 	(((uint16_t *)(_pkt_a))[1] == ((uint16_t *)(_pkt_b))[1]) &&	\
1200Sstevel@tonic-gate 	(((uint16_t *)(_pkt_a))[2] == ((uint16_t *)(_pkt_b))[2]) &&	\
1210Sstevel@tonic-gate 	(((uint16_t *)(_pkt_a))[6] == ((uint16_t *)(_pkt_b))[6]) &&	\
1220Sstevel@tonic-gate 	(((uint16_t *)(_pkt_a))[7] == ((uint16_t *)(_pkt_b))[7]) &&	\
1230Sstevel@tonic-gate 	(((uint16_t *)(_pkt_a))[8] == ((uint16_t *)(_pkt_b))[8]))
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate static mblk_t *
1260Sstevel@tonic-gate i_dls_link_ether_subchain(mblk_t *mp, uint_t *header_lengthp,
1270Sstevel@tonic-gate     uint8_t **daddrp, uint16_t *type_lengthp, uint16_t *vidp,
1280Sstevel@tonic-gate     uint_t *countp)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	struct ether_header		*ehp;
1310Sstevel@tonic-gate 	struct ether_vlan_header	*evhp;
1320Sstevel@tonic-gate 	mblk_t				**pp;
1330Sstevel@tonic-gate 	mblk_t				*p;
1340Sstevel@tonic-gate 	uint_t				npacket;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	/*
1370Sstevel@tonic-gate 	 * Packets should always be at least 16 bit aligned.
1380Sstevel@tonic-gate 	 */
1390Sstevel@tonic-gate 	ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	/*
1420Sstevel@tonic-gate 	 * Determine whether this is a VLAN or non-VLAN packet.
1430Sstevel@tonic-gate 	 */
1440Sstevel@tonic-gate 	ASSERT(MBLKL(mp) >= sizeof (struct ether_header));
1450Sstevel@tonic-gate 	ehp = (struct ether_header *)mp->b_rptr;
1460Sstevel@tonic-gate 	if ((*type_lengthp = ntohs(ehp->ether_type)) == VLAN_TPID)
1470Sstevel@tonic-gate 		goto vlan;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	/*
1500Sstevel@tonic-gate 	 * It is a non-VLAN header.
1510Sstevel@tonic-gate 	 */
1520Sstevel@tonic-gate 	*header_lengthp = sizeof (struct ether_header);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	/*
1550Sstevel@tonic-gate 	 * Parse the rest of the header information that we need.
1560Sstevel@tonic-gate 	 */
1570Sstevel@tonic-gate 	*daddrp = (uint8_t *)&(ehp->ether_dhost);
1580Sstevel@tonic-gate 	*vidp = VLAN_ID_NONE;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	/*
1610Sstevel@tonic-gate 	 * Compare with subsequent headers until we find one that has
1620Sstevel@tonic-gate 	 * differing header information. After checking each packet skip over
1630Sstevel@tonic-gate 	 * the header.
1640Sstevel@tonic-gate 	 */
1650Sstevel@tonic-gate 	npacket = 1;
1660Sstevel@tonic-gate 	for (pp = &(mp->b_next); (p = *pp) != NULL; pp = &(p->b_next)) {
1670Sstevel@tonic-gate 		if (!ETHER_MATCH(p->b_rptr, mp->b_rptr) != 0)
1680Sstevel@tonic-gate 			break;
1690Sstevel@tonic-gate 		p->b_rptr += sizeof (struct ether_header);
1700Sstevel@tonic-gate 		npacket++;
1710Sstevel@tonic-gate 	}
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	/*
1740Sstevel@tonic-gate 	 * Skip over the initial packet's header.
1750Sstevel@tonic-gate 	 */
1760Sstevel@tonic-gate 	mp->b_rptr += sizeof (struct ether_header);
1770Sstevel@tonic-gate 	goto done;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate vlan:
1800Sstevel@tonic-gate 	/*
1810Sstevel@tonic-gate 	 * It is a VLAN header.
1820Sstevel@tonic-gate 	 */
1830Sstevel@tonic-gate 	evhp = (struct ether_vlan_header *)mp->b_rptr;
1840Sstevel@tonic-gate 	*header_lengthp = sizeof (struct ether_vlan_header);
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	/*
1870Sstevel@tonic-gate 	 * Parse the header information.
1880Sstevel@tonic-gate 	 */
1890Sstevel@tonic-gate 	*daddrp = (uint8_t *)&(evhp->ether_dhost);
1900Sstevel@tonic-gate 	*vidp = VLAN_ID(ntohs(evhp->ether_tci));
1910Sstevel@tonic-gate 	*type_lengthp = ntohs(evhp->ether_type);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	/*
1940Sstevel@tonic-gate 	 * Compare with subsequent headers until we find one that has
1950Sstevel@tonic-gate 	 * differing header information. After checking each packet skip over
1960Sstevel@tonic-gate 	 * the header.
1970Sstevel@tonic-gate 	 */
1980Sstevel@tonic-gate 	npacket = 1;
1990Sstevel@tonic-gate 	for (pp = &(mp->b_next); (p = *pp) != NULL; pp = &(p->b_next)) {
2000Sstevel@tonic-gate 		if (!ETHER_VLAN_MATCH(p->b_rptr, mp->b_rptr) != 0)
2010Sstevel@tonic-gate 			break;
2020Sstevel@tonic-gate 		p->b_rptr += sizeof (struct ether_vlan_header);
2030Sstevel@tonic-gate 		npacket++;
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/*
2070Sstevel@tonic-gate 	 * Skip over the initial packet's header.
2080Sstevel@tonic-gate 	 */
2090Sstevel@tonic-gate 	mp->b_rptr += sizeof (struct ether_vlan_header);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate done:
2120Sstevel@tonic-gate 	/*
2130Sstevel@tonic-gate 	 * Break the chain at this point and return a pointer to the next
2140Sstevel@tonic-gate 	 * sub-chain.
2150Sstevel@tonic-gate 	 */
2160Sstevel@tonic-gate 	*pp = NULL;
2170Sstevel@tonic-gate 	*countp = npacket;
2180Sstevel@tonic-gate 	return (p);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate static void
2220Sstevel@tonic-gate i_dls_link_ether_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	dls_link_t			*dlp = arg;
2250Sstevel@tonic-gate 	ght_t				hash = dlp->dl_impl_hash;
2260Sstevel@tonic-gate 	mblk_t				*nextp;
2270Sstevel@tonic-gate 	uint_t				header_length;
2280Sstevel@tonic-gate 	uint8_t				*daddr;
2290Sstevel@tonic-gate 	uint16_t			type_length;
2300Sstevel@tonic-gate 	uint16_t			vid;
2310Sstevel@tonic-gate 	uint16_t			sap;
2320Sstevel@tonic-gate 	ghte_t				hte;
2330Sstevel@tonic-gate 	dls_impl_t			*dip;
2340Sstevel@tonic-gate 	dls_impl_t			*ndip;
2350Sstevel@tonic-gate 	mblk_t				*nmp;
2360Sstevel@tonic-gate 	ght_key_t			key;
2370Sstevel@tonic-gate 	uint_t				npacket;
2380Sstevel@tonic-gate 	boolean_t			accepted;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	/*
2410Sstevel@tonic-gate 	 * Walk the packet chain.
2420Sstevel@tonic-gate 	 */
2430Sstevel@tonic-gate 	while (mp != NULL) {
2440Sstevel@tonic-gate 		/*
2450Sstevel@tonic-gate 		 * Wipe the accepted state.
2460Sstevel@tonic-gate 		 */
2470Sstevel@tonic-gate 		accepted = B_FALSE;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 		/*
2500Sstevel@tonic-gate 		 * Grab the longest sub-chain we can process as a single
2510Sstevel@tonic-gate 		 * unit.
2520Sstevel@tonic-gate 		 */
2530Sstevel@tonic-gate 		nextp = i_dls_link_ether_subchain(mp, &header_length, &daddr,
2540Sstevel@tonic-gate 		    &type_length, &vid, &npacket);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 		/*
2570Sstevel@tonic-gate 		 * Calculate the DLSAP: LLC (0) if the type/length field is
2580Sstevel@tonic-gate 		 * interpreted as a length, otherwise it is the value of the
2590Sstevel@tonic-gate 		 * type/length field.
2600Sstevel@tonic-gate 		 */
2610Sstevel@tonic-gate 		sap = (type_length <= ETHERMTU) ? DLS_SAP_LLC : type_length;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		/*
2640Sstevel@tonic-gate 		 * Construct a hash key from the VLAN identifier and the
2650Sstevel@tonic-gate 		 * DLSAP.
2660Sstevel@tonic-gate 		 */
2670Sstevel@tonic-gate 		key = MAKE_KEY(sap, vid);
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 		/*
2700Sstevel@tonic-gate 		 * Search the has table for dls_impl_t eligible to receive
2710Sstevel@tonic-gate 		 * a packet chain for this DLSAP/VLAN combination.
2720Sstevel@tonic-gate 		 */
2730Sstevel@tonic-gate 		ght_lock(hash, GHT_READ);
2740Sstevel@tonic-gate 		if (ght_find(hash, key, &hte) != 0) {
2750Sstevel@tonic-gate 			ght_unlock(hash);
2760Sstevel@tonic-gate 			freemsgchain(mp);
2770Sstevel@tonic-gate 			goto loop;
2780Sstevel@tonic-gate 		}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		/*
2810Sstevel@tonic-gate 		 * Place a hold the chain of dls_impl_t to make sure none are
2820Sstevel@tonic-gate 		 * removed from under our feet.
2830Sstevel@tonic-gate 		 */
2840Sstevel@tonic-gate 		ght_hold(hte);
2850Sstevel@tonic-gate 		ght_unlock(hash);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 		/*
2880Sstevel@tonic-gate 		 * Find the first dls_impl_t that will accept the sub-chain.
2890Sstevel@tonic-gate 		 */
2900Sstevel@tonic-gate 		for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL;
2910Sstevel@tonic-gate 		    dip = dip->di_nextp)
2920Sstevel@tonic-gate 			if (dls_accept(dip, daddr))
2930Sstevel@tonic-gate 				break;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 		/*
2960Sstevel@tonic-gate 		 * If we did not find any dls_impl_t willing to accept the
2970Sstevel@tonic-gate 		 * sub-chain then throw it away.
2980Sstevel@tonic-gate 		 */
2990Sstevel@tonic-gate 		if (dip == NULL) {
3000Sstevel@tonic-gate 			ght_rele(hte);
3010Sstevel@tonic-gate 			freemsgchain(mp);
3020Sstevel@tonic-gate 			goto loop;
3030Sstevel@tonic-gate 		}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 		/*
3060Sstevel@tonic-gate 		 * We have at least one acceptor.
3070Sstevel@tonic-gate 		 */
3080Sstevel@tonic-gate 		accepted = B_TRUE;
3090Sstevel@tonic-gate 		for (;;) {
3100Sstevel@tonic-gate 			/*
3110Sstevel@tonic-gate 			 * Find the next dls_impl_t that will accept the
3120Sstevel@tonic-gate 			 * sub-chain.
3130Sstevel@tonic-gate 			 */
3140Sstevel@tonic-gate 			for (ndip = dip->di_nextp; ndip != NULL;
3150Sstevel@tonic-gate 			    ndip = ndip->di_nextp)
3160Sstevel@tonic-gate 				if (dls_accept(ndip, daddr))
3170Sstevel@tonic-gate 					break;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 			/*
3200Sstevel@tonic-gate 			 * If there are no more dls_impl_t that are willing
3210Sstevel@tonic-gate 			 * to accept the sub-chain then we don't need to dup
3220Sstevel@tonic-gate 			 * it before handing it to the current one.
3230Sstevel@tonic-gate 			 */
3240Sstevel@tonic-gate 			if (ndip == NULL) {
3250Sstevel@tonic-gate 				dip->di_rx(dip->di_rx_arg, mrh, mp,
3260Sstevel@tonic-gate 				    header_length);
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 				/*
3290Sstevel@tonic-gate 				 * Since there are no more dls_impl_t, we're
3300Sstevel@tonic-gate 				 * done.
3310Sstevel@tonic-gate 				 */
3320Sstevel@tonic-gate 				break;
3330Sstevel@tonic-gate 			}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 			/*
3360Sstevel@tonic-gate 			 * There are more dls_impl_t so dup the sub-chain.
3370Sstevel@tonic-gate 			 */
3380Sstevel@tonic-gate 			if ((nmp = copymsgchain(mp)) != NULL)
3390Sstevel@tonic-gate 				dip->di_rx(dip->di_rx_arg, mrh, nmp,
3400Sstevel@tonic-gate 				    header_length);
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 			dip = ndip;
3430Sstevel@tonic-gate 		}
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 		/*
3460Sstevel@tonic-gate 		 * Release the hold on the dls_impl_t chain now that we have
3470Sstevel@tonic-gate 		 * finished walking it.
3480Sstevel@tonic-gate 		 */
3490Sstevel@tonic-gate 		ght_rele(hte);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate loop:
3520Sstevel@tonic-gate 		/*
3530Sstevel@tonic-gate 		 * If there were no acceptors then add the packet count to the
3540Sstevel@tonic-gate 		 * 'unknown' count.
3550Sstevel@tonic-gate 		 */
3560Sstevel@tonic-gate 		if (!accepted)
3570Sstevel@tonic-gate 			atomic_add_32(&(dlp->dl_unknowns), npacket);
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 		/*
3600Sstevel@tonic-gate 		 * Move onto the next sub-chain.
3610Sstevel@tonic-gate 		 */
3620Sstevel@tonic-gate 		mp = nextp;
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate static void
3670Sstevel@tonic-gate i_dls_link_ether_rx_promisc(void *arg, mac_resource_handle_t mrh,
3680Sstevel@tonic-gate     mblk_t *mp)
3690Sstevel@tonic-gate {
3700Sstevel@tonic-gate 	dls_link_t			*dlp = arg;
3710Sstevel@tonic-gate 	ght_t				hash = dlp->dl_impl_hash;
3720Sstevel@tonic-gate 	mblk_t				*nextp;
3730Sstevel@tonic-gate 	uint_t				header_length;
3740Sstevel@tonic-gate 	uint8_t				*daddr;
3750Sstevel@tonic-gate 	uint16_t			type_length;
3760Sstevel@tonic-gate 	uint16_t			vid;
3770Sstevel@tonic-gate 	uint16_t			sap;
3780Sstevel@tonic-gate 	ghte_t				hte;
3790Sstevel@tonic-gate 	dls_impl_t			*dip;
3800Sstevel@tonic-gate 	dls_impl_t			*ndip;
3810Sstevel@tonic-gate 	mblk_t				*nmp;
3820Sstevel@tonic-gate 	ght_key_t			key;
3830Sstevel@tonic-gate 	uint_t				npacket;
3840Sstevel@tonic-gate 	boolean_t			accepted;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	/*
3870Sstevel@tonic-gate 	 * Walk the packet chain.
3880Sstevel@tonic-gate 	 */
3890Sstevel@tonic-gate 	while (mp != NULL) {
3900Sstevel@tonic-gate 		/*
3910Sstevel@tonic-gate 		 * Wipe the accepted state.
3920Sstevel@tonic-gate 		 */
3930Sstevel@tonic-gate 		accepted = B_FALSE;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 		/*
3960Sstevel@tonic-gate 		 * Grab the longest sub-chain we can process as a single
3970Sstevel@tonic-gate 		 * unit.
3980Sstevel@tonic-gate 		 */
3990Sstevel@tonic-gate 		nextp = i_dls_link_ether_subchain(mp, &header_length, &daddr,
4000Sstevel@tonic-gate 		    &type_length, &vid, &npacket);
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 		/*
4030Sstevel@tonic-gate 		 * Construct a hash key from the VLAN identifier and the
4040Sstevel@tonic-gate 		 * DLSAP that represents dls_impl_t in promiscuous mode.
4050Sstevel@tonic-gate 		 */
4060Sstevel@tonic-gate 		key = MAKE_KEY(DLS_SAP_PROMISC, vid);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 		/*
4090Sstevel@tonic-gate 		 * Search the has table for dls_impl_t eligible to receive
4100Sstevel@tonic-gate 		 * a packet chain for this DLSAP/VLAN combination.
4110Sstevel@tonic-gate 		 */
4120Sstevel@tonic-gate 		ght_lock(hash, GHT_READ);
4130Sstevel@tonic-gate 		if (ght_find(hash, key, &hte) != 0) {
4140Sstevel@tonic-gate 			ght_unlock(hash);
4150Sstevel@tonic-gate 			goto non_promisc;
4160Sstevel@tonic-gate 		}
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 		/*
4190Sstevel@tonic-gate 		 * Place a hold the chain of dls_impl_t to make sure none are
4200Sstevel@tonic-gate 		 * removed from under our feet.
4210Sstevel@tonic-gate 		 */
4220Sstevel@tonic-gate 		ght_hold(hte);
4230Sstevel@tonic-gate 		ght_unlock(hash);
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 		/*
4260Sstevel@tonic-gate 		 * Find dls_impl_t that will accept the sub-chain.
4270Sstevel@tonic-gate 		 */
4280Sstevel@tonic-gate 		for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL;
4290Sstevel@tonic-gate 		    dip = dip->di_nextp) {
4300Sstevel@tonic-gate 			if (!dls_accept(dip, daddr))
4310Sstevel@tonic-gate 				continue;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 			/*
4340Sstevel@tonic-gate 			 * We have at least one acceptor.
4350Sstevel@tonic-gate 			 */
4360Sstevel@tonic-gate 			accepted = B_TRUE;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 			/*
4390Sstevel@tonic-gate 			 * There will normally be at least more dls_impl_t
4400Sstevel@tonic-gate 			 * (since we've yet to check for non-promiscuous
4410Sstevel@tonic-gate 			 * dls_impl_t) so dup the sub-chain.
4420Sstevel@tonic-gate 			 */
4430Sstevel@tonic-gate 			if ((nmp = copymsgchain(mp)) != NULL)
4440Sstevel@tonic-gate 				dip->di_rx(dip->di_rx_arg, mrh, nmp,
4450Sstevel@tonic-gate 				    header_length);
4460Sstevel@tonic-gate 		}
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 		/*
4490Sstevel@tonic-gate 		 * Release the hold on the dls_impl_t chain now that we have
4500Sstevel@tonic-gate 		 * finished walking it.
4510Sstevel@tonic-gate 		 */
4520Sstevel@tonic-gate 		ght_rele(hte);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate non_promisc:
4550Sstevel@tonic-gate 		/*
4560Sstevel@tonic-gate 		 * Calculate the DLSAP: LLC (0) if the type/length field is
4570Sstevel@tonic-gate 		 * interpreted as a length, otherwise it is the value of the
4580Sstevel@tonic-gate 		 * type/length field.
4590Sstevel@tonic-gate 		 */
4600Sstevel@tonic-gate 		sap = (type_length <= ETHERMTU) ? DLS_SAP_LLC : type_length;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		/*
4630Sstevel@tonic-gate 		 * Construct a hash key from the VLAN identifier and the
4640Sstevel@tonic-gate 		 * DLSAP.
4650Sstevel@tonic-gate 		 */
4660Sstevel@tonic-gate 		key = MAKE_KEY(sap, vid);
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 		/*
4690Sstevel@tonic-gate 		 * Search the has table for dls_impl_t eligible to receive
4700Sstevel@tonic-gate 		 * a packet chain for this DLSAP/VLAN combination.
4710Sstevel@tonic-gate 		 */
4720Sstevel@tonic-gate 		ght_lock(hash, GHT_READ);
4730Sstevel@tonic-gate 		if (ght_find(hash, key, &hte) != 0) {
4740Sstevel@tonic-gate 			ght_unlock(hash);
4750Sstevel@tonic-gate 			freemsgchain(mp);
4760Sstevel@tonic-gate 			goto loop;
4770Sstevel@tonic-gate 		}
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 		/*
4800Sstevel@tonic-gate 		 * Place a hold the chain of dls_impl_t to make sure none are
4810Sstevel@tonic-gate 		 * removed from under our feet.
4820Sstevel@tonic-gate 		 */
4830Sstevel@tonic-gate 		ght_hold(hte);
4840Sstevel@tonic-gate 		ght_unlock(hash);
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 		/*
4870Sstevel@tonic-gate 		 * Find the first dls_impl_t that will accept the sub-chain.
4880Sstevel@tonic-gate 		 */
4890Sstevel@tonic-gate 		for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL;
4900Sstevel@tonic-gate 		    dip = dip->di_nextp)
4910Sstevel@tonic-gate 			if (dls_accept(dip, daddr))
4920Sstevel@tonic-gate 				break;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		/*
4950Sstevel@tonic-gate 		 * If we did not find any dls_impl_t willing to accept the
4960Sstevel@tonic-gate 		 * sub-chain then throw it away.
4970Sstevel@tonic-gate 		 */
4980Sstevel@tonic-gate 		if (dip == NULL) {
4990Sstevel@tonic-gate 			ght_rele(hte);
5000Sstevel@tonic-gate 			freemsgchain(mp);
5010Sstevel@tonic-gate 			goto loop;
5020Sstevel@tonic-gate 		}
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 		/*
5050Sstevel@tonic-gate 		 * We have at least one acceptor.
5060Sstevel@tonic-gate 		 */
5070Sstevel@tonic-gate 		accepted = B_TRUE;
5080Sstevel@tonic-gate 		for (;;) {
5090Sstevel@tonic-gate 			/*
5100Sstevel@tonic-gate 			 * Find the next dls_impl_t that will accept the
5110Sstevel@tonic-gate 			 * sub-chain.
5120Sstevel@tonic-gate 			 */
5130Sstevel@tonic-gate 			for (ndip = dip->di_nextp; ndip != NULL;
5140Sstevel@tonic-gate 			    ndip = ndip->di_nextp)
5150Sstevel@tonic-gate 				if (dls_accept(ndip, daddr))
5160Sstevel@tonic-gate 					break;
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 			/*
5190Sstevel@tonic-gate 			 * If there are no more dls_impl_t that are willing
5200Sstevel@tonic-gate 			 * to accept the sub-chain then we don't need to dup
5210Sstevel@tonic-gate 			 * it before handing it to the current one.
5220Sstevel@tonic-gate 			 */
5230Sstevel@tonic-gate 			if (ndip == NULL) {
5240Sstevel@tonic-gate 				dip->di_rx(dip->di_rx_arg, mrh, mp,
5250Sstevel@tonic-gate 				    header_length);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 				/*
5280Sstevel@tonic-gate 				 * Since there are no more dls_impl_t, we're
5290Sstevel@tonic-gate 				 * done.
5300Sstevel@tonic-gate 				 */
5310Sstevel@tonic-gate 				break;
5320Sstevel@tonic-gate 			}
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 			/*
5350Sstevel@tonic-gate 			 * There are more dls_impl_t so dup the sub-chain.
5360Sstevel@tonic-gate 			 */
5370Sstevel@tonic-gate 			if ((nmp = copymsgchain(mp)) != NULL)
5380Sstevel@tonic-gate 				dip->di_rx(dip->di_rx_arg, mrh, nmp,
5390Sstevel@tonic-gate 				    header_length);
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 			dip = ndip;
5420Sstevel@tonic-gate 		}
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 		/*
5450Sstevel@tonic-gate 		 * Release the hold on the dls_impl_t chain now that we have
5460Sstevel@tonic-gate 		 * finished walking it.
5470Sstevel@tonic-gate 		 */
5480Sstevel@tonic-gate 		ght_rele(hte);
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate loop:
5510Sstevel@tonic-gate 		/*
5520Sstevel@tonic-gate 		 * If there were no acceptors then add the packet count to the
5530Sstevel@tonic-gate 		 * 'unknown' count.
5540Sstevel@tonic-gate 		 */
5550Sstevel@tonic-gate 		if (!accepted)
5560Sstevel@tonic-gate 			atomic_add_32(&(dlp->dl_unknowns), npacket);
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 		/*
5590Sstevel@tonic-gate 		 * Move onto the next sub-chain.
5600Sstevel@tonic-gate 		 */
5610Sstevel@tonic-gate 		mp = nextp;
5620Sstevel@tonic-gate 	}
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate static void
5660Sstevel@tonic-gate i_dls_link_ether_loopback(void *arg, mblk_t *mp)
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate 	dls_link_t			*dlp = arg;
5690Sstevel@tonic-gate 	ght_t				hash = dlp->dl_impl_hash;
5700Sstevel@tonic-gate 	mblk_t				*nextp;
5710Sstevel@tonic-gate 	uint_t				header_length;
5720Sstevel@tonic-gate 	uint8_t				*daddr;
5730Sstevel@tonic-gate 	uint16_t			type_length;
5740Sstevel@tonic-gate 	uint16_t			vid;
5750Sstevel@tonic-gate 	uint16_t			sap;
5760Sstevel@tonic-gate 	ghte_t				hte;
5770Sstevel@tonic-gate 	dls_impl_t			*dip;
5780Sstevel@tonic-gate 	dls_impl_t			*ndip;
5790Sstevel@tonic-gate 	mblk_t				*nmp;
5800Sstevel@tonic-gate 	ght_key_t			key;
5810Sstevel@tonic-gate 	uint_t				npacket;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	/*
5840Sstevel@tonic-gate 	 * Walk the packet chain.
5850Sstevel@tonic-gate 	 */
5860Sstevel@tonic-gate 	while (mp != NULL) {
5870Sstevel@tonic-gate 		/*
5880Sstevel@tonic-gate 		 * Grab the longest sub-chain we can process as a single
5890Sstevel@tonic-gate 		 * unit.
5900Sstevel@tonic-gate 		 */
5910Sstevel@tonic-gate 		nextp = i_dls_link_ether_subchain(mp, &header_length, &daddr,
5920Sstevel@tonic-gate 		    &type_length, &vid, &npacket);
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 		/*
5950Sstevel@tonic-gate 		 * Calculate the DLSAP: LLC (0) if the type/length field is
5960Sstevel@tonic-gate 		 * interpreted as a length, otherwise it is the value of the
5970Sstevel@tonic-gate 		 * type/length field.
5980Sstevel@tonic-gate 		 */
5990Sstevel@tonic-gate 		sap = (type_length <= ETHERMTU) ? DLS_SAP_LLC : type_length;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		/*
6020Sstevel@tonic-gate 		 * Construct a hash key from the VLAN identifier and the
6030Sstevel@tonic-gate 		 * DLSAP.
6040Sstevel@tonic-gate 		 */
6050Sstevel@tonic-gate 		key = MAKE_KEY(sap, vid);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 		/*
6080Sstevel@tonic-gate 		 * Search the has table for dls_impl_t eligible to receive
6090Sstevel@tonic-gate 		 * a packet chain for this DLSAP/VLAN combination.
6100Sstevel@tonic-gate 		 */
6110Sstevel@tonic-gate 		ght_lock(hash, GHT_READ);
6120Sstevel@tonic-gate 		if (ght_find(hash, key, &hte) != 0) {
6130Sstevel@tonic-gate 			ght_unlock(hash);
6140Sstevel@tonic-gate 			goto promisc;
6150Sstevel@tonic-gate 		}
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 		/*
6180Sstevel@tonic-gate 		 * Place a hold the chain of dls_impl_t to make sure none are
6190Sstevel@tonic-gate 		 * removed from under our feet.
6200Sstevel@tonic-gate 		 */
6210Sstevel@tonic-gate 		ght_hold(hte);
6220Sstevel@tonic-gate 		ght_unlock(hash);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 		/*
6250Sstevel@tonic-gate 		 * Find dls_impl_t that will accept the sub-chain.
6260Sstevel@tonic-gate 		 */
6270Sstevel@tonic-gate 		for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL;
6280Sstevel@tonic-gate 		    dip = dip->di_nextp) {
6290Sstevel@tonic-gate 			if (!dls_accept_loopback(dip, daddr))
6300Sstevel@tonic-gate 				continue;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 			/*
6330Sstevel@tonic-gate 			 * There should be at least more dls_impl_t (since
6340Sstevel@tonic-gate 			 * we've yet to check for dls_impl_t in promiscuous
6350Sstevel@tonic-gate 			 * mode) so dup the sub-chain.
6360Sstevel@tonic-gate 			 */
6370Sstevel@tonic-gate 			if ((nmp = copymsgchain(mp)) != NULL)
6380Sstevel@tonic-gate 				dip->di_rx(dip->di_rx_arg, NULL, nmp,
6390Sstevel@tonic-gate 				    header_length);
6400Sstevel@tonic-gate 		}
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		/*
6430Sstevel@tonic-gate 		 * Release the hold on the dls_impl_t chain now that we have
6440Sstevel@tonic-gate 		 * finished walking it.
6450Sstevel@tonic-gate 		 */
6460Sstevel@tonic-gate 		ght_rele(hte);
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate promisc:
6490Sstevel@tonic-gate 		/*
6500Sstevel@tonic-gate 		 * Construct a hash key from the VLAN identifier and the
6510Sstevel@tonic-gate 		 * DLSAP that represents dls_impl_t in promiscuous mode.
6520Sstevel@tonic-gate 		 */
6530Sstevel@tonic-gate 		key = MAKE_KEY(DLS_SAP_PROMISC, vid);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		/*
6560Sstevel@tonic-gate 		 * Search the has table for dls_impl_t eligible to receive
6570Sstevel@tonic-gate 		 * a packet chain for this DLSAP/VLAN combination.
6580Sstevel@tonic-gate 		 */
6590Sstevel@tonic-gate 		ght_lock(hash, GHT_READ);
6600Sstevel@tonic-gate 		if (ght_find(hash, key, &hte) != 0) {
6610Sstevel@tonic-gate 			ght_unlock(hash);
6620Sstevel@tonic-gate 			freemsgchain(mp);
6630Sstevel@tonic-gate 			goto loop;
6640Sstevel@tonic-gate 		}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 		/*
6670Sstevel@tonic-gate 		 * Place a hold the chain of dls_impl_t to make sure none are
6680Sstevel@tonic-gate 		 * removed from under our feet.
6690Sstevel@tonic-gate 		 */
6700Sstevel@tonic-gate 		ght_hold(hte);
6710Sstevel@tonic-gate 		ght_unlock(hash);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 		/*
6740Sstevel@tonic-gate 		 * Find the first dls_impl_t that will accept the sub-chain.
6750Sstevel@tonic-gate 		 */
6760Sstevel@tonic-gate 		for (dip = (dls_impl_t *)GHT_VAL(hte); dip != NULL;
6770Sstevel@tonic-gate 		    dip = dip->di_nextp)
6780Sstevel@tonic-gate 			if (dls_accept_loopback(dip, daddr))
6790Sstevel@tonic-gate 				break;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 		/*
6820Sstevel@tonic-gate 		 * If we did not find any dls_impl_t willing to accept the
6830Sstevel@tonic-gate 		 * sub-chain then throw it away.
6840Sstevel@tonic-gate 		 */
6850Sstevel@tonic-gate 		if (dip == NULL) {
6860Sstevel@tonic-gate 			ght_rele(hte);
6870Sstevel@tonic-gate 			freemsgchain(mp);
6880Sstevel@tonic-gate 			goto loop;
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 		for (;;) {
6920Sstevel@tonic-gate 			/*
6930Sstevel@tonic-gate 			 * Find the next dls_impl_t that will accept the
6940Sstevel@tonic-gate 			 * sub-chain.
6950Sstevel@tonic-gate 			 */
6960Sstevel@tonic-gate 			for (ndip = dip->di_nextp; ndip != NULL;
6970Sstevel@tonic-gate 			    ndip = ndip->di_nextp)
6980Sstevel@tonic-gate 				if (dls_accept_loopback(ndip, daddr))
6990Sstevel@tonic-gate 					break;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 			/*
7020Sstevel@tonic-gate 			 * If there are no more dls_impl_t that are willing
7030Sstevel@tonic-gate 			 * to accept the sub-chain then we don't need to dup
7040Sstevel@tonic-gate 			 * it before handing it to the current one.
7050Sstevel@tonic-gate 			 */
7060Sstevel@tonic-gate 			if (ndip == NULL) {
7070Sstevel@tonic-gate 				dip->di_rx(dip->di_rx_arg, NULL, mp,
7080Sstevel@tonic-gate 				    header_length);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 				/*
7110Sstevel@tonic-gate 				 * Since there are no more dls_impl_t, we're
7120Sstevel@tonic-gate 				 * done.
7130Sstevel@tonic-gate 				 */
7140Sstevel@tonic-gate 				break;
7150Sstevel@tonic-gate 			}
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 			/*
7180Sstevel@tonic-gate 			 * There are more dls_impl_t so dup the sub-chain.
7190Sstevel@tonic-gate 			 */
7200Sstevel@tonic-gate 			if ((nmp = copymsgchain(mp)) != NULL)
7210Sstevel@tonic-gate 				dip->di_rx(dip->di_rx_arg, NULL, nmp,
7220Sstevel@tonic-gate 				    header_length);
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 			dip = ndip;
7250Sstevel@tonic-gate 		}
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		/*
7280Sstevel@tonic-gate 		 * Release the hold on the dls_impl_t chain now that we have
7290Sstevel@tonic-gate 		 * finished walking it.
7300Sstevel@tonic-gate 		 */
7310Sstevel@tonic-gate 		ght_rele(hte);
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate loop:
7340Sstevel@tonic-gate 		/*
7350Sstevel@tonic-gate 		 * Move onto the next sub-chain.
7360Sstevel@tonic-gate 		 */
7370Sstevel@tonic-gate 		mp = nextp;
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate static boolean_t
7420Sstevel@tonic-gate i_dls_link_walk(void *arg, ghte_t hte)
7430Sstevel@tonic-gate {
7440Sstevel@tonic-gate 	boolean_t	*promiscp = arg;
7450Sstevel@tonic-gate 	ght_key_t	key = GHT_KEY(hte);
7460Sstevel@tonic-gate 	uint32_t	sap = KEY_SAP(key);
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	if (sap == DLS_SAP_PROMISC) {
7490Sstevel@tonic-gate 		*promiscp = B_TRUE;
7500Sstevel@tonic-gate 		return (B_FALSE);	/* terminate walk */
7510Sstevel@tonic-gate 	}
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	return (B_TRUE);
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate static int
7570Sstevel@tonic-gate i_dls_link_create(const char *dev, uint_t port, dls_link_t **dlpp)
7580Sstevel@tonic-gate {
7590Sstevel@tonic-gate 	dls_link_t		*dlp;
7600Sstevel@tonic-gate 	int			err;
7610Sstevel@tonic-gate 	mac_handle_t		mh;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	/*
7640Sstevel@tonic-gate 	 * Check that the MAC exists, and (for now) that it's
7650Sstevel@tonic-gate 	 * of type DL_ETHER.
7660Sstevel@tonic-gate 	 */
7670Sstevel@tonic-gate 	if ((err = mac_open(dev, port, &mh)) != 0)
7680Sstevel@tonic-gate 		return (err);
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	ASSERT(mac_info(mh)->mi_media == DL_ETHER);
7710Sstevel@tonic-gate 	mac_close(mh);
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	/*
7740Sstevel@tonic-gate 	 * Allocate a new dls_link_t structure.
7750Sstevel@tonic-gate 	 */
7760Sstevel@tonic-gate 	dlp = kmem_cache_alloc(i_dls_link_cachep, KM_SLEEP);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	/*
7790Sstevel@tonic-gate 	 * Name the dls_link_t after the MAC interface it represents.
7800Sstevel@tonic-gate 	 */
7810Sstevel@tonic-gate 	MAC_NAME(dlp->dl_name, dev, port);
7820Sstevel@tonic-gate 	(void) strlcpy(dlp->dl_dev, dev, MAXNAMELEN);
7830Sstevel@tonic-gate 	dlp->dl_port = port;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	/*
7860Sstevel@tonic-gate 	 * Set the initial packet receive function.
7870Sstevel@tonic-gate 	 */
7880Sstevel@tonic-gate 	ASSERT(ght_count(dlp->dl_impl_hash) == 0);
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	/*
7910Sstevel@tonic-gate 	 * Set the packet loopback function for use when the MAC is in
7920Sstevel@tonic-gate 	 * promiscuous mode, and initialize promiscuous bookeeping fields.
7930Sstevel@tonic-gate 	 */
7940Sstevel@tonic-gate 	dlp->dl_loopback = i_dls_link_ether_loopback;
7950Sstevel@tonic-gate 	dlp->dl_npromisc = 0;
7960Sstevel@tonic-gate 	dlp->dl_mth = NULL;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	*dlpp = dlp;
7990Sstevel@tonic-gate 	return (0);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate static void
8030Sstevel@tonic-gate i_dls_link_destroy(dls_link_t *dlp)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate 	ASSERT(dlp->dl_npromisc == 0);
8060Sstevel@tonic-gate 	ASSERT(dlp->dl_nactive == 0);
8070Sstevel@tonic-gate 	ASSERT(dlp->dl_mth == NULL);
8080Sstevel@tonic-gate 	ASSERT(dlp->dl_macref == 0);
8090Sstevel@tonic-gate 	ASSERT(dlp->dl_mh == NULL);
8100Sstevel@tonic-gate 	ASSERT(dlp->dl_mip == NULL);
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	/*
8130Sstevel@tonic-gate 	 * Free the structure back to the cache.
8140Sstevel@tonic-gate 	 */
8150Sstevel@tonic-gate 	dlp->dl_mrh = NULL;
8160Sstevel@tonic-gate 	dlp->dl_unknowns = 0;
8170Sstevel@tonic-gate 	kmem_cache_free(i_dls_link_cachep, dlp);
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate }
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate /*
8220Sstevel@tonic-gate  * Module initialization functions.
8230Sstevel@tonic-gate  */
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate void
8260Sstevel@tonic-gate dls_link_init(void)
8270Sstevel@tonic-gate {
8280Sstevel@tonic-gate 	int	err;
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	/*
8310Sstevel@tonic-gate 	 * Create a kmem_cache of dls_link_t structures.
8320Sstevel@tonic-gate 	 */
8330Sstevel@tonic-gate 	i_dls_link_cachep = kmem_cache_create("dls_link_cache",
8340Sstevel@tonic-gate 	    sizeof (dls_link_t), 0, i_dls_link_constructor,
8350Sstevel@tonic-gate 	    i_dls_link_destructor, NULL, NULL, NULL, 0);
8360Sstevel@tonic-gate 	ASSERT(i_dls_link_cachep != NULL);
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	/*
8390Sstevel@tonic-gate 	 * Create a global hash tables to be keyed by a name.
8400Sstevel@tonic-gate 	 */
8410Sstevel@tonic-gate 	err = ght_str_create("dls_link_hash", LINK_HASHSZ, &i_dls_link_hash);
8420Sstevel@tonic-gate 	ASSERT(err == 0);
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate int
8460Sstevel@tonic-gate dls_link_fini(void)
8470Sstevel@tonic-gate {
8480Sstevel@tonic-gate 	int	err;
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	/*
8510Sstevel@tonic-gate 	 * Destroy the hash table. This will return EBUSY if there are
8520Sstevel@tonic-gate 	 * still entries present.
8530Sstevel@tonic-gate 	 */
8540Sstevel@tonic-gate 	if ((err = ght_destroy(i_dls_link_hash)) != 0)
8550Sstevel@tonic-gate 		return (err);
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	/*
8580Sstevel@tonic-gate 	 * Destroy the kmem_cache.
8590Sstevel@tonic-gate 	 */
8600Sstevel@tonic-gate 	kmem_cache_destroy(i_dls_link_cachep);
8610Sstevel@tonic-gate 	return (0);
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate /*
8650Sstevel@tonic-gate  * Exported functions.
8660Sstevel@tonic-gate  */
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate int
8690Sstevel@tonic-gate dls_link_hold(const char *dev, uint_t port, dls_link_t **dlpp)
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 	char			name[MAXNAMELEN];
8720Sstevel@tonic-gate 	dls_link_t		*dlp;
8730Sstevel@tonic-gate 	int			err;
8740Sstevel@tonic-gate 	ghte_t			hte;
8750Sstevel@tonic-gate 	ghte_t			nhte;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	/*
8780Sstevel@tonic-gate 	 * Allocate a new hash table entry.
8790Sstevel@tonic-gate 	 */
8800Sstevel@tonic-gate 	nhte = ght_alloc(i_dls_link_hash, KM_SLEEP);
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	/*
8830Sstevel@tonic-gate 	 * Construct a copy of the name used to identify any existing
8840Sstevel@tonic-gate 	 * dls_link_t.
8850Sstevel@tonic-gate 	 */
8860Sstevel@tonic-gate 	MAC_NAME(name, dev, port);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	/*
8890Sstevel@tonic-gate 	 * Look up a dls_link_t corresponding to the given mac_handle_t
8900Sstevel@tonic-gate 	 * in the global hash table.
8910Sstevel@tonic-gate 	 */
8920Sstevel@tonic-gate 	ght_lock(i_dls_link_hash, GHT_WRITE);
8930Sstevel@tonic-gate 	if ((err = ght_find(i_dls_link_hash, GHT_PTR_TO_KEY(name),
8940Sstevel@tonic-gate 	    &hte)) == 0) {
8950Sstevel@tonic-gate 		dlp = (dls_link_t *)GHT_VAL(hte);
8960Sstevel@tonic-gate 		ght_free(nhte);
8970Sstevel@tonic-gate 		goto done;
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 	ASSERT(err == ENOENT);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/*
9020Sstevel@tonic-gate 	 * We didn't find anything so we need to create one.
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 	if ((err = i_dls_link_create(dev, port, &dlp)) != 0) {
9050Sstevel@tonic-gate 		ght_free(nhte);
9060Sstevel@tonic-gate 		ght_unlock(i_dls_link_hash);
9070Sstevel@tonic-gate 		return (err);
9080Sstevel@tonic-gate 	}
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	GHT_KEY(nhte) = GHT_PTR_TO_KEY(dlp->dl_name);
9110Sstevel@tonic-gate 	GHT_VAL(nhte) = GHT_PTR_TO_VAL(dlp);
9120Sstevel@tonic-gate 	dlp->dl_hte = nhte;
9130Sstevel@tonic-gate 	/*
9140Sstevel@tonic-gate 	 * Insert the entry.
9150Sstevel@tonic-gate 	 */
9160Sstevel@tonic-gate 	err = ght_insert(nhte);
9170Sstevel@tonic-gate 	ASSERT(err == 0);
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate done:
9200Sstevel@tonic-gate 	/*
9210Sstevel@tonic-gate 	 * Bump the reference count and hand back the reference.
9220Sstevel@tonic-gate 	 */
9230Sstevel@tonic-gate 	dlp->dl_ref++;
9240Sstevel@tonic-gate 	*dlpp = dlp;
9250Sstevel@tonic-gate 	ght_unlock(i_dls_link_hash);
9260Sstevel@tonic-gate 	return (err);
9270Sstevel@tonic-gate }
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate void
9300Sstevel@tonic-gate dls_link_rele(dls_link_t *dlp)
9310Sstevel@tonic-gate {
9320Sstevel@tonic-gate 	ghte_t		hte;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	ght_lock(i_dls_link_hash, GHT_WRITE);
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	/*
9370Sstevel@tonic-gate 	 * Check if there are any more references.
9380Sstevel@tonic-gate 	 */
9390Sstevel@tonic-gate 	if (--dlp->dl_ref != 0) {
9400Sstevel@tonic-gate 		/*
9410Sstevel@tonic-gate 		 * There are more references so there's nothing more to do.
9420Sstevel@tonic-gate 		 */
9430Sstevel@tonic-gate 		goto done;
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	hte = dlp->dl_hte;
9470Sstevel@tonic-gate 	dlp->dl_hte = NULL;
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	/*
9500Sstevel@tonic-gate 	 * Remove the hash table entry.
9510Sstevel@tonic-gate 	 */
9520Sstevel@tonic-gate 	ght_remove(hte);
9530Sstevel@tonic-gate 	ght_free(hte);
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	/*
9560Sstevel@tonic-gate 	 * Destroy the dls_link_t.
9570Sstevel@tonic-gate 	 */
9580Sstevel@tonic-gate 	i_dls_link_destroy(dlp);
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate done:
9610Sstevel@tonic-gate 	ght_unlock(i_dls_link_hash);
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate int
9650Sstevel@tonic-gate dls_mac_hold(dls_link_t *dlp)
9660Sstevel@tonic-gate {
9670Sstevel@tonic-gate 	int err = 0;
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	mutex_enter(&dlp->dl_lock);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	ASSERT(IMPLY(dlp->dl_macref != 0, dlp->dl_mh != NULL));
9720Sstevel@tonic-gate 	ASSERT(IMPLY(dlp->dl_macref == 0, dlp->dl_mh == NULL));
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	if (dlp->dl_macref == 0) {
9750Sstevel@tonic-gate 		/*
9760Sstevel@tonic-gate 		 * First reference; hold open the MAC interface.
9770Sstevel@tonic-gate 		 */
9780Sstevel@tonic-gate 		err = mac_open(dlp->dl_dev, dlp->dl_port, &dlp->dl_mh);
9790Sstevel@tonic-gate 		if (err != 0)
9800Sstevel@tonic-gate 			goto done;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 		dlp->dl_mip = mac_info(dlp->dl_mh);
9830Sstevel@tonic-gate 	}
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	dlp->dl_macref++;
9860Sstevel@tonic-gate done:
9870Sstevel@tonic-gate 	mutex_exit(&dlp->dl_lock);
9880Sstevel@tonic-gate 	return (err);
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate void
9920Sstevel@tonic-gate dls_mac_rele(dls_link_t *dlp)
9930Sstevel@tonic-gate {
9940Sstevel@tonic-gate 	mutex_enter(&dlp->dl_lock);
9950Sstevel@tonic-gate 	ASSERT(dlp->dl_mh != NULL);
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	if (--dlp->dl_macref == 0) {
9980Sstevel@tonic-gate 		mac_close(dlp->dl_mh);
9990Sstevel@tonic-gate 		dlp->dl_mh = NULL;
10000Sstevel@tonic-gate 		dlp->dl_mip = NULL;
10010Sstevel@tonic-gate 	}
10020Sstevel@tonic-gate 	mutex_exit(&dlp->dl_lock);
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate void
10060Sstevel@tonic-gate dls_link_add(dls_link_t *dlp, uint32_t sap, dls_impl_t *dip)
10070Sstevel@tonic-gate {
10080Sstevel@tonic-gate 	dls_vlan_t	*dvp = dip->di_dvp;
10090Sstevel@tonic-gate 	ght_t		hash = dlp->dl_impl_hash;
10100Sstevel@tonic-gate 	ghte_t		hte;
10110Sstevel@tonic-gate 	ghte_t		nhte;
10120Sstevel@tonic-gate 	ght_key_t	key;
10130Sstevel@tonic-gate 	dls_impl_t	**pp;
10140Sstevel@tonic-gate 	dls_impl_t	*p;
10150Sstevel@tonic-gate 	mac_rx_t	rx;
10160Sstevel@tonic-gate 	int		err;
10170Sstevel@tonic-gate 	uint_t		impl_count;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	ASSERT(dip->di_nextp == NULL);
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	/*
10220Sstevel@tonic-gate 	 * For ethernet media, sap values less than or equal to
10230Sstevel@tonic-gate 	 * ETHERMTU (1500) represent LLC channels. (See PSARC 2003/150).
10240Sstevel@tonic-gate 	 * We strictly use 0 to represent LLC channels.
10250Sstevel@tonic-gate 	 */
10260Sstevel@tonic-gate 	sap = (sap <= ETHERMTU) ? 0 : sap;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	/*
10290Sstevel@tonic-gate 	 * Make the appropriate key value depending on whether the
10300Sstevel@tonic-gate 	 * dls_impl_t is in promiscuous mode or not.
10310Sstevel@tonic-gate 	 */
10320Sstevel@tonic-gate 	key = MAKE_KEY(sap, dvp->dv_id);
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	/*
10350Sstevel@tonic-gate 	 * We need dl_lock here because we want to be able to walk
10360Sstevel@tonic-gate 	 * the hash table *and* set the mac rx func atomically. if
10370Sstevel@tonic-gate 	 * these two operations are separate, someone else could
10380Sstevel@tonic-gate 	 * insert/remove dls_impl_t from the ght after we drop the
10390Sstevel@tonic-gate 	 * ght lock and this could cause our chosen rx func to be
10400Sstevel@tonic-gate 	 * incorrect. note that we cannot call mac_rx_set when
10410Sstevel@tonic-gate 	 * holding the ght lock because this can cause deadlock.
10420Sstevel@tonic-gate 	 */
10430Sstevel@tonic-gate 	mutex_enter(&dlp->dl_lock);
10440Sstevel@tonic-gate 	/*
10450Sstevel@tonic-gate 	 * Allocate a new entry.
10460Sstevel@tonic-gate 	 */
10470Sstevel@tonic-gate 	nhte = ght_alloc(hash, KM_SLEEP);
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	/*
10500Sstevel@tonic-gate 	 * Search the table for any existing entry with this key.
10510Sstevel@tonic-gate 	 */
10520Sstevel@tonic-gate 	ght_lock(hash, GHT_WRITE);
10530Sstevel@tonic-gate 	if ((err = ght_find(hash, key, &hte)) != 0) {
10540Sstevel@tonic-gate 		ASSERT(err == ENOENT);
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 		GHT_KEY(nhte) = key;
10570Sstevel@tonic-gate 		GHT_VAL(nhte) = GHT_PTR_TO_VAL(dip);
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 		/*
10600Sstevel@tonic-gate 		 * Insert it in the table to be the head of a new list.
10610Sstevel@tonic-gate 		 */
10620Sstevel@tonic-gate 		err = ght_insert(nhte);
10630Sstevel@tonic-gate 		ASSERT(err == 0);
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 		/*
10660Sstevel@tonic-gate 		 * Cache a reference to the hash table entry.
10670Sstevel@tonic-gate 		 */
10680Sstevel@tonic-gate 		ASSERT(dip->di_hte == NULL);
10690Sstevel@tonic-gate 		dip->di_hte = nhte;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 		goto done;
10720Sstevel@tonic-gate 	}
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	/*
10750Sstevel@tonic-gate 	 * Free the unused hash table entry.
10760Sstevel@tonic-gate 	 */
10770Sstevel@tonic-gate 	ght_free(nhte);
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	/*
10800Sstevel@tonic-gate 	 * Add the dls_impl_t to the end of the list. We can't add to the head
10810Sstevel@tonic-gate 	 * because the hash table internals already have a reference to the
10820Sstevel@tonic-gate 	 * head of the list.
10830Sstevel@tonic-gate 	 */
10840Sstevel@tonic-gate 	for (pp = (dls_impl_t **)&(GHT_VAL(hte)); (p = *pp) != NULL;
10850Sstevel@tonic-gate 	    pp = &(p->di_nextp))
10860Sstevel@tonic-gate 		ASSERT(p != dip);
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	*pp = dip;
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	/*
10910Sstevel@tonic-gate 	 * Cache a reference to the hash table entry.
10920Sstevel@tonic-gate 	 */
10930Sstevel@tonic-gate 	ASSERT(dip->di_hte == NULL);
10940Sstevel@tonic-gate 	dip->di_hte = hte;
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate done:
10970Sstevel@tonic-gate 	/*
10980Sstevel@tonic-gate 	 * If there are no dls_impl_t then we can just drop all received
10990Sstevel@tonic-gate 	 * packets on the floor.
11000Sstevel@tonic-gate 	 */
11010Sstevel@tonic-gate 	impl_count = ght_count(hash);
11020Sstevel@tonic-gate 	if (impl_count == 0) {
11030Sstevel@tonic-gate 		ght_unlock(hash);
11040Sstevel@tonic-gate 	} else {
11050Sstevel@tonic-gate 		boolean_t promisc = B_FALSE;
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 		/*
11080Sstevel@tonic-gate 		 * Walk the bound dls_impl_t to see if there are any
11090Sstevel@tonic-gate 		 * in promiscuous 'all sap' mode.
11100Sstevel@tonic-gate 		 */
11110Sstevel@tonic-gate 		ght_walk(hash, i_dls_link_walk, (void *)&promisc);
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 		/*
11140Sstevel@tonic-gate 		 * If there are then we need to use a receive routine
11150Sstevel@tonic-gate 		 * which will route packets to those dls_impl_t as well
11160Sstevel@tonic-gate 		 * as ones bound to the  DLSAP of the packet.
11170Sstevel@tonic-gate 		 */
11180Sstevel@tonic-gate 		if (promisc)
11190Sstevel@tonic-gate 			rx = i_dls_link_ether_rx_promisc;
11200Sstevel@tonic-gate 		else
11210Sstevel@tonic-gate 			rx = i_dls_link_ether_rx;
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 		ght_unlock(hash);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 		/* Replace the existing receive function if there is one. */
11260Sstevel@tonic-gate 		if (dlp->dl_mrh != NULL)
11270Sstevel@tonic-gate 			mac_rx_remove(dlp->dl_mh, dlp->dl_mrh);
11280Sstevel@tonic-gate 		dlp->dl_mrh = mac_rx_add(dlp->dl_mh, rx, (void *)dlp);
11290Sstevel@tonic-gate 	}
11300Sstevel@tonic-gate 	mutex_exit(&dlp->dl_lock);
11310Sstevel@tonic-gate }
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate void
11340Sstevel@tonic-gate dls_link_remove(dls_link_t *dlp, dls_impl_t *dip)
11350Sstevel@tonic-gate {
11360Sstevel@tonic-gate 	ght_t		hash = dlp->dl_impl_hash;
11370Sstevel@tonic-gate 	ghte_t		hte;
11380Sstevel@tonic-gate 	dls_impl_t	**pp;
11390Sstevel@tonic-gate 	dls_impl_t	*p;
11400Sstevel@tonic-gate 	mac_rx_t	rx;
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	/*
11430Sstevel@tonic-gate 	 * We need dl_lock here because we want to be able to walk
11440Sstevel@tonic-gate 	 * the hash table *and* set the mac rx func atomically. if
11450Sstevel@tonic-gate 	 * these two operations are separate, someone else could
11460Sstevel@tonic-gate 	 * insert/remove dls_impl_t from the ght after we drop the
11470Sstevel@tonic-gate 	 * ght lock and this could cause our chosen rx func to be
11480Sstevel@tonic-gate 	 * incorrect. note that we cannot call mac_rx_add when
11490Sstevel@tonic-gate 	 * holding the ght lock because this can cause deadlock.
11500Sstevel@tonic-gate 	 */
11510Sstevel@tonic-gate 	mutex_enter(&dlp->dl_lock);
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	ght_lock(hash, GHT_WRITE);
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	/*
11560Sstevel@tonic-gate 	 * Get the cached hash table entry reference.
11570Sstevel@tonic-gate 	 */
11580Sstevel@tonic-gate 	hte = dip->di_hte;
11590Sstevel@tonic-gate 	ASSERT(hte != NULL);
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	/*
11620Sstevel@tonic-gate 	 * Poll the hash table entry until all references have been dropped.
11630Sstevel@tonic-gate 	 * We need to drop all locks before sleeping because we don't want
11640Sstevel@tonic-gate 	 * the interrupt handler to block. We set di_removing here to
11650Sstevel@tonic-gate 	 * tell the receive callbacks not to pass up packets anymore.
11660Sstevel@tonic-gate 	 * This is only a hint to quicken the decrease of the refcnt so
11670Sstevel@tonic-gate 	 * the assignment need not be protected by any lock.
11680Sstevel@tonic-gate 	 */
11690Sstevel@tonic-gate 	dip->di_removing = B_TRUE;
11700Sstevel@tonic-gate 	while (ght_ref(hte) != 0) {
11710Sstevel@tonic-gate 		ght_unlock(hash);
11720Sstevel@tonic-gate 		mutex_exit(&dlp->dl_lock);
11730Sstevel@tonic-gate 		delay(drv_usectohz(1000));	/* 1ms delay */
11740Sstevel@tonic-gate 		mutex_enter(&dlp->dl_lock);
11750Sstevel@tonic-gate 		ght_lock(hash, GHT_WRITE);
11760Sstevel@tonic-gate 	}
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	/*
11790Sstevel@tonic-gate 	 * Walk the list and remove the dls_impl_t.
11800Sstevel@tonic-gate 	 */
11810Sstevel@tonic-gate 	for (pp = (dls_impl_t **)&(GHT_VAL(hte)); (p = *pp) != NULL;
11820Sstevel@tonic-gate 	    pp = &(p->di_nextp)) {
11830Sstevel@tonic-gate 		if (p == dip)
11840Sstevel@tonic-gate 			break;
11850Sstevel@tonic-gate 	}
11860Sstevel@tonic-gate 	ASSERT(p != NULL);
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	*pp = p->di_nextp;
11890Sstevel@tonic-gate 	p->di_nextp = NULL;
11900Sstevel@tonic-gate 	dip->di_hte = NULL;
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	if (GHT_VAL(hte) == NULL) {
11930Sstevel@tonic-gate 		/*
11940Sstevel@tonic-gate 		 * The list is empty so remove the hash table entry.
11950Sstevel@tonic-gate 		 */
11960Sstevel@tonic-gate 		ght_remove(hte);
11970Sstevel@tonic-gate 		ght_free(hte);
11980Sstevel@tonic-gate 	}
11990Sstevel@tonic-gate 	dip->di_removing = B_FALSE;
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	/*
12020Sstevel@tonic-gate 	 * If there are no dls_impl_t then there's no need to register a
12030Sstevel@tonic-gate 	 * receive function with the mac.
12040Sstevel@tonic-gate 	 */
12050Sstevel@tonic-gate 	if (ght_count(hash) == 0) {
12060Sstevel@tonic-gate 		ght_unlock(hash);
12070Sstevel@tonic-gate 		mac_rx_remove(dlp->dl_mh, dlp->dl_mrh);
12080Sstevel@tonic-gate 		dlp->dl_mrh = NULL;
12090Sstevel@tonic-gate 	} else {
12100Sstevel@tonic-gate 		boolean_t promisc = B_FALSE;
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 		/*
12130Sstevel@tonic-gate 		 * Walk the bound dls_impl_t to see if there are any
12140Sstevel@tonic-gate 		 * in promiscuous 'all sap' mode.
12150Sstevel@tonic-gate 		 */
12160Sstevel@tonic-gate 		ght_walk(hash, i_dls_link_walk, (void *)&promisc);
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 		/*
12190Sstevel@tonic-gate 		 * If there are then we need to use a receive routine
12200Sstevel@tonic-gate 		 * which will route packets to those dls_impl_t as well
12210Sstevel@tonic-gate 		 * as ones bound to the  DLSAP of the packet.
12220Sstevel@tonic-gate 		 */
12230Sstevel@tonic-gate 		if (promisc)
12240Sstevel@tonic-gate 			rx = i_dls_link_ether_rx_promisc;
12250Sstevel@tonic-gate 		else
12260Sstevel@tonic-gate 			rx = i_dls_link_ether_rx;
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 		ght_unlock(hash);
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 		mac_rx_remove(dlp->dl_mh, dlp->dl_mrh);
12310Sstevel@tonic-gate 		dlp->dl_mrh = mac_rx_add(dlp->dl_mh, rx, (void *)dlp);
12320Sstevel@tonic-gate 	}
12330Sstevel@tonic-gate 	mutex_exit(&dlp->dl_lock);
12340Sstevel@tonic-gate }
1235