xref: /onnv-gate/usr/src/uts/common/io/mac/mac.c (revision 1852:d0cfec858815)
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
5*1852Syz147064  * Common Development and Distribution License (the "License").
6*1852Syz147064  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*1852Syz147064  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * MAC Services Module
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/conf.h>
340Sstevel@tonic-gate #include <sys/stat.h>
350Sstevel@tonic-gate #include <sys/stream.h>
360Sstevel@tonic-gate #include <sys/strsun.h>
370Sstevel@tonic-gate #include <sys/strsubr.h>
380Sstevel@tonic-gate #include <sys/dlpi.h>
39269Sericheng #include <sys/modhash.h>
400Sstevel@tonic-gate #include <sys/mac.h>
410Sstevel@tonic-gate #include <sys/mac_impl.h>
42269Sericheng #include <sys/dls.h>
43269Sericheng #include <sys/dld.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #define	IMPL_HASHSZ	67	/* prime */
460Sstevel@tonic-gate 
470Sstevel@tonic-gate static kmem_cache_t	*i_mac_impl_cachep;
48269Sericheng static mod_hash_t	*i_mac_impl_hash;
49269Sericheng krwlock_t		i_mac_impl_lock;
50269Sericheng uint_t			i_mac_impl_count;
510Sstevel@tonic-gate 
52*1852Syz147064 static void i_mac_notify_task(void *);
53*1852Syz147064 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  * Private functions.
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*ARGSUSED*/
590Sstevel@tonic-gate static boolean_t
600Sstevel@tonic-gate i_mac_ether_unicst_verify(mac_impl_t *mip, const uint8_t *addr)
610Sstevel@tonic-gate {
620Sstevel@tonic-gate 	/*
630Sstevel@tonic-gate 	 * Check the address is not a group address.
640Sstevel@tonic-gate 	 */
650Sstevel@tonic-gate 	if (addr[0] & 0x01)
660Sstevel@tonic-gate 		return (B_FALSE);
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	return (B_TRUE);
690Sstevel@tonic-gate }
700Sstevel@tonic-gate 
710Sstevel@tonic-gate static boolean_t
720Sstevel@tonic-gate i_mac_ether_multicst_verify(mac_impl_t *mip, const uint8_t *addr)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	/*
770Sstevel@tonic-gate 	 * Check the address is a group address.
780Sstevel@tonic-gate 	 */
790Sstevel@tonic-gate 	if (!(addr[0] & 0x01))
800Sstevel@tonic-gate 		return (B_FALSE);
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	/*
830Sstevel@tonic-gate 	 * Check the address is not the media broadcast address.
840Sstevel@tonic-gate 	 */
850Sstevel@tonic-gate 	if (bcmp(addr, mp->m_info.mi_brdcst_addr, mip->mi_addr_length) == 0)
860Sstevel@tonic-gate 		return (B_FALSE);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	return (B_TRUE);
890Sstevel@tonic-gate }
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /*ARGSUSED*/
920Sstevel@tonic-gate static int
930Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	bzero(buf, sizeof (mac_impl_t));
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	mip->mi_link = LINK_STATE_UNKNOWN;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
1020Sstevel@tonic-gate 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
1030Sstevel@tonic-gate 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
1040Sstevel@tonic-gate 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
1050Sstevel@tonic-gate 	rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL);
1060Sstevel@tonic-gate 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
1070Sstevel@tonic-gate 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
108*1852Syz147064 	mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL);
109*1852Syz147064 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL);
1100Sstevel@tonic-gate 	return (0);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*ARGSUSED*/
1140Sstevel@tonic-gate static void
1150Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	ASSERT(mip->mi_mp == NULL);
1200Sstevel@tonic-gate 	ASSERT(mip->mi_ref == 0);
1210Sstevel@tonic-gate 	ASSERT(mip->mi_active == 0);
1220Sstevel@tonic-gate 	ASSERT(mip->mi_link == LINK_STATE_UNKNOWN);
1230Sstevel@tonic-gate 	ASSERT(mip->mi_devpromisc == 0);
1240Sstevel@tonic-gate 	ASSERT(mip->mi_promisc == 0);
1250Sstevel@tonic-gate 	ASSERT(mip->mi_mmap == NULL);
1260Sstevel@tonic-gate 	ASSERT(mip->mi_mnfp == NULL);
1270Sstevel@tonic-gate 	ASSERT(mip->mi_resource_add == NULL);
1280Sstevel@tonic-gate 	ASSERT(mip->mi_ksp == NULL);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	rw_destroy(&mip->mi_state_lock);
1310Sstevel@tonic-gate 	rw_destroy(&mip->mi_data_lock);
1320Sstevel@tonic-gate 	rw_destroy(&mip->mi_notify_lock);
1330Sstevel@tonic-gate 	rw_destroy(&mip->mi_rx_lock);
1340Sstevel@tonic-gate 	rw_destroy(&mip->mi_txloop_lock);
1350Sstevel@tonic-gate 	rw_destroy(&mip->mi_resource_lock);
1360Sstevel@tonic-gate 	mutex_destroy(&mip->mi_activelink_lock);
137*1852Syz147064 	mutex_destroy(&mip->mi_notify_ref_lock);
138*1852Syz147064 	cv_destroy(&mip->mi_notify_cv);
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate 
141269Sericheng static int
1420Sstevel@tonic-gate i_mac_create(mac_t *mp)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	dev_info_t	*dip;
1450Sstevel@tonic-gate 	mac_impl_t	*mip;
146269Sericheng 	int		err = 0;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	dip = mp->m_dip;
1490Sstevel@tonic-gate 	ASSERT(dip != NULL);
1500Sstevel@tonic-gate 	ASSERT(ddi_get_instance(dip) >= 0);
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	/*
1530Sstevel@tonic-gate 	 * Allocate a new mac_impl_t.
1540Sstevel@tonic-gate 	 */
1550Sstevel@tonic-gate 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	/*
1580Sstevel@tonic-gate 	 * Construct a name.
1590Sstevel@tonic-gate 	 */
1600Sstevel@tonic-gate 	(void) snprintf(mip->mi_dev, MAXNAMELEN - 1, "%s%d",
1610Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_get_instance(dip));
1620Sstevel@tonic-gate 	mip->mi_port = mp->m_port;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	MAC_NAME(mip->mi_name, mip->mi_dev, mip->mi_port);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	/*
1670Sstevel@tonic-gate 	 * Set the mac_t/mac_impl_t cross-references.
1680Sstevel@tonic-gate 	 */
1690Sstevel@tonic-gate 	mip->mi_mp = mp;
1700Sstevel@tonic-gate 	mp->m_impl = (void *)mip;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	/*
173*1852Syz147064 	 * The mac is not ready for open yet.
174*1852Syz147064 	 */
175*1852Syz147064 	mip->mi_disabled = B_TRUE;
176*1852Syz147064 
177*1852Syz147064 	/*
1780Sstevel@tonic-gate 	 * Insert the hash table entry.
1790Sstevel@tonic-gate 	 */
180269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
181269Sericheng 	if (mod_hash_insert(i_mac_impl_hash,
182269Sericheng 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
1830Sstevel@tonic-gate 		kmem_cache_free(i_mac_impl_cachep, mip);
184269Sericheng 		err = EEXIST;
1850Sstevel@tonic-gate 		goto done;
1860Sstevel@tonic-gate 	}
187269Sericheng 	i_mac_impl_count++;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/*
1900Sstevel@tonic-gate 	 * Copy the fixed 'factory' MAC address from the immutable info.
1910Sstevel@tonic-gate 	 * This is taken to be the MAC address currently in use.
1920Sstevel@tonic-gate 	 */
1930Sstevel@tonic-gate 	mip->mi_addr_length = mp->m_info.mi_addr_length;
1940Sstevel@tonic-gate 	bcopy(mp->m_info.mi_unicst_addr, mip->mi_addr, mip->mi_addr_length);
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	/*
1970Sstevel@tonic-gate 	 * Set up the address verification functions.
1980Sstevel@tonic-gate 	 */
1990Sstevel@tonic-gate 	ASSERT(mp->m_info.mi_media == DL_ETHER);
2000Sstevel@tonic-gate 	mip->mi_unicst_verify = i_mac_ether_unicst_verify;
2010Sstevel@tonic-gate 	mip->mi_multicst_verify = i_mac_ether_multicst_verify;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	/*
20456Smeem 	 * Set up the two possible transmit routines.
20556Smeem 	 */
20656Smeem 	mip->mi_txinfo.mt_fn = mp->m_tx;
20756Smeem 	mip->mi_txinfo.mt_arg = mp->m_driver;
20856Smeem 	mip->mi_txloopinfo.mt_fn = mac_txloop;
20956Smeem 	mip->mi_txloopinfo.mt_arg = mip;
21056Smeem 
21156Smeem 	/*
2120Sstevel@tonic-gate 	 * Initialize the kstats for this device.
2130Sstevel@tonic-gate 	 */
2140Sstevel@tonic-gate 	mac_stat_create(mip);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate done:
217269Sericheng 	rw_exit(&i_mac_impl_lock);
2180Sstevel@tonic-gate 	return (err);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate static void
2220Sstevel@tonic-gate i_mac_destroy(mac_t *mp)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	mac_impl_t		*mip = mp->m_impl;
2250Sstevel@tonic-gate 	mac_multicst_addr_t	*p, *nextp;
226269Sericheng 	mod_hash_val_t		val;
2270Sstevel@tonic-gate 
228269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	ASSERT(mip->mi_ref == 0);
2310Sstevel@tonic-gate 	ASSERT(!mip->mi_activelink);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	/*
2340Sstevel@tonic-gate 	 * Destroy the kstats.
2350Sstevel@tonic-gate 	 */
2360Sstevel@tonic-gate 	mac_stat_destroy(mip);
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	/*
2390Sstevel@tonic-gate 	 * Remove and destroy the hash table entry.
2400Sstevel@tonic-gate 	 */
241269Sericheng 	(void) mod_hash_remove(i_mac_impl_hash,
242269Sericheng 	    (mod_hash_key_t)mip->mi_name, &val);
243269Sericheng 	ASSERT(mip == (mac_impl_t *)val);
244269Sericheng 
245269Sericheng 	ASSERT(i_mac_impl_count > 0);
246269Sericheng 	i_mac_impl_count--;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	/*
2490Sstevel@tonic-gate 	 * Free the list of multicast addresses.
2500Sstevel@tonic-gate 	 */
2510Sstevel@tonic-gate 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
2520Sstevel@tonic-gate 		nextp = p->mma_nextp;
2530Sstevel@tonic-gate 		kmem_free(p, sizeof (mac_multicst_addr_t));
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 	mip->mi_mmap = NULL;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	/*
2580Sstevel@tonic-gate 	 * Clean up the mac_impl_t ready to go back into the cache.
2590Sstevel@tonic-gate 	 */
2600Sstevel@tonic-gate 	mp->m_impl = NULL;
2610Sstevel@tonic-gate 	mip->mi_mp = NULL;
2620Sstevel@tonic-gate 	mip->mi_link = LINK_STATE_UNKNOWN;
263*1852Syz147064 	mip->mi_disabled = B_FALSE;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	/*
2660Sstevel@tonic-gate 	 * Free the structure back to the cache.
2670Sstevel@tonic-gate 	 */
2680Sstevel@tonic-gate 	kmem_cache_free(i_mac_impl_cachep, mip);
2690Sstevel@tonic-gate 
270269Sericheng 	rw_exit(&i_mac_impl_lock);
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate static void
2740Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
2750Sstevel@tonic-gate {
276*1852Syz147064 	mac_notify_task_arg_t	*mnta;
277*1852Syz147064 
278*1852Syz147064 	rw_enter(&i_mac_impl_lock, RW_READER);
279*1852Syz147064 	if (mip->mi_disabled)
280*1852Syz147064 		goto exit;
281*1852Syz147064 
282*1852Syz147064 	if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) {
283*1852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory "
284*1852Syz147064 		    "allocation failed", mip->mi_name, type);
285*1852Syz147064 		goto exit;
286*1852Syz147064 	}
287*1852Syz147064 
288*1852Syz147064 	mnta->mnt_mip = mip;
289*1852Syz147064 	mnta->mnt_type = type;
290*1852Syz147064 
291*1852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
292*1852Syz147064 	mip->mi_notify_ref++;
293*1852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
294*1852Syz147064 
295*1852Syz147064 	rw_exit(&i_mac_impl_lock);
296*1852Syz147064 
297*1852Syz147064 	if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta,
298*1852Syz147064 	    TQ_NOSLEEP) == NULL) {
299*1852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch "
300*1852Syz147064 		    "failed", mip->mi_name, type);
301*1852Syz147064 
302*1852Syz147064 		mutex_enter(&mip->mi_notify_ref_lock);
303*1852Syz147064 		if (--mip->mi_notify_ref == 0)
304*1852Syz147064 			cv_signal(&mip->mi_notify_cv);
305*1852Syz147064 		mutex_exit(&mip->mi_notify_ref_lock);
306*1852Syz147064 
307*1852Syz147064 		kmem_free(mnta, sizeof (*mnta));
308*1852Syz147064 	}
309*1852Syz147064 	return;
310*1852Syz147064 
311*1852Syz147064 exit:
312*1852Syz147064 	rw_exit(&i_mac_impl_lock);
313*1852Syz147064 }
314*1852Syz147064 
315*1852Syz147064 static void
316*1852Syz147064 i_mac_notify_task(void *notify_arg)
317*1852Syz147064 {
318*1852Syz147064 	mac_notify_task_arg_t	*mnta = (mac_notify_task_arg_t *)notify_arg;
319*1852Syz147064 	mac_impl_t		*mip;
320*1852Syz147064 	mac_notify_type_t	type;
3210Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
3220Sstevel@tonic-gate 	mac_notify_t		notify;
3230Sstevel@tonic-gate 	void			*arg;
3240Sstevel@tonic-gate 
325*1852Syz147064 	mip = mnta->mnt_mip;
326*1852Syz147064 	type = mnta->mnt_type;
327*1852Syz147064 	kmem_free(mnta, sizeof (*mnta));
328*1852Syz147064 
3290Sstevel@tonic-gate 	/*
3300Sstevel@tonic-gate 	 * Walk the list of notifications.
3310Sstevel@tonic-gate 	 */
332*1852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_READER);
3330Sstevel@tonic-gate 	for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) {
3340Sstevel@tonic-gate 		notify = mnfp->mnf_fn;
3350Sstevel@tonic-gate 		arg = mnfp->mnf_arg;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 		ASSERT(notify != NULL);
3380Sstevel@tonic-gate 		notify(arg, type);
3390Sstevel@tonic-gate 	}
340*1852Syz147064 	rw_exit(&mip->mi_notify_lock);
341*1852Syz147064 
342*1852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
343*1852Syz147064 	if (--mip->mi_notify_ref == 0)
344*1852Syz147064 		cv_signal(&mip->mi_notify_cv);
345*1852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate /*
3490Sstevel@tonic-gate  * Module initialization functions.
3500Sstevel@tonic-gate  */
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate void
3530Sstevel@tonic-gate mac_init(void)
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
3560Sstevel@tonic-gate 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, NULL,
3570Sstevel@tonic-gate 	    NULL, NULL, 0);
3580Sstevel@tonic-gate 	ASSERT(i_mac_impl_cachep != NULL);
3590Sstevel@tonic-gate 
360269Sericheng 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
361269Sericheng 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
362269Sericheng 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
363269Sericheng 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
364269Sericheng 	i_mac_impl_count = 0;
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate int
3680Sstevel@tonic-gate mac_fini(void)
3690Sstevel@tonic-gate {
370269Sericheng 	if (i_mac_impl_count > 0)
371269Sericheng 		return (EBUSY);
3720Sstevel@tonic-gate 
373269Sericheng 	mod_hash_destroy_hash(i_mac_impl_hash);
374269Sericheng 	rw_destroy(&i_mac_impl_lock);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	kmem_cache_destroy(i_mac_impl_cachep);
3770Sstevel@tonic-gate 	return (0);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate /*
3810Sstevel@tonic-gate  * Client functions.
3820Sstevel@tonic-gate  */
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate int
3850Sstevel@tonic-gate mac_open(const char *dev, uint_t port, mac_handle_t *mhp)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	char		name[MAXNAMELEN];
3880Sstevel@tonic-gate 	char		driver[MAXNAMELEN];
3890Sstevel@tonic-gate 	uint_t		instance;
3900Sstevel@tonic-gate 	major_t		major;
3910Sstevel@tonic-gate 	dev_info_t	*dip;
3920Sstevel@tonic-gate 	mac_impl_t	*mip;
3930Sstevel@tonic-gate 	int		err;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	/*
3960Sstevel@tonic-gate 	 * Check the device name length to make sure it won't overflow our
3970Sstevel@tonic-gate 	 * buffer.
3980Sstevel@tonic-gate 	 */
3990Sstevel@tonic-gate 	if (strlen(dev) >= MAXNAMELEN)
4000Sstevel@tonic-gate 		return (EINVAL);
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/*
4030Sstevel@tonic-gate 	 * Split the device name into driver and instance components.
4040Sstevel@tonic-gate 	 */
4050Sstevel@tonic-gate 	if (ddi_parse(dev, driver, &instance) != DDI_SUCCESS)
4060Sstevel@tonic-gate 		return (EINVAL);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/*
4090Sstevel@tonic-gate 	 * Get the major number of the driver.
4100Sstevel@tonic-gate 	 */
4110Sstevel@tonic-gate 	if ((major = ddi_name_to_major(driver)) == (major_t)-1)
4120Sstevel@tonic-gate 		return (EINVAL);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/*
4150Sstevel@tonic-gate 	 * Hold the given instance to prevent it from being detached.
416269Sericheng 	 * This will also attach the instance if it is not currently attached.
417269Sericheng 	 * Currently we ensure that mac_register() (called by the driver's
418269Sericheng 	 * attach entry point) and all code paths under it cannot possibly
419269Sericheng 	 * call mac_open() because this would lead to a recursive attach
420269Sericheng 	 * panic.
4210Sstevel@tonic-gate 	 */
4220Sstevel@tonic-gate 	if ((dip = ddi_hold_devi_by_instance(major, instance, 0)) == NULL)
4230Sstevel@tonic-gate 		return (EINVAL);
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	/*
4260Sstevel@tonic-gate 	 * Construct the name of the MAC interface.
4270Sstevel@tonic-gate 	 */
4280Sstevel@tonic-gate 	MAC_NAME(name, dev, port);
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	/*
4310Sstevel@tonic-gate 	 * Look up its entry in the global hash table.
4320Sstevel@tonic-gate 	 */
4330Sstevel@tonic-gate again:
434269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
435269Sericheng 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)name,
436269Sericheng 	    (mod_hash_val_t *)&mip);
437269Sericheng 	if (err != 0) {
438269Sericheng 		err = ENOENT;
4390Sstevel@tonic-gate 		goto failed;
440269Sericheng 	}
4410Sstevel@tonic-gate 
442*1852Syz147064 	if (mip->mi_disabled) {
443269Sericheng 		rw_exit(&i_mac_impl_lock);
4440Sstevel@tonic-gate 		goto again;
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate 
447269Sericheng 	/*
448269Sericheng 	 * We currently only support the DL_ETHER media type.
449269Sericheng 	 */
450269Sericheng 	ASSERT(mip->mi_mp->m_info.mi_media == DL_ETHER);
4510Sstevel@tonic-gate 	mip->mi_ref++;
452269Sericheng 	rw_exit(&i_mac_impl_lock);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	*mhp = (mac_handle_t)mip;
4550Sstevel@tonic-gate 	return (0);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate failed:
458269Sericheng 	rw_exit(&i_mac_impl_lock);
4590Sstevel@tonic-gate 	ddi_release_devi(dip);
4600Sstevel@tonic-gate 	return (err);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate void
4640Sstevel@tonic-gate mac_close(mac_handle_t mh)
4650Sstevel@tonic-gate {
4660Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4670Sstevel@tonic-gate 	dev_info_t	*dip = mip->mi_mp->m_dip;
4680Sstevel@tonic-gate 
469269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	ASSERT(mip->mi_ref != 0);
4720Sstevel@tonic-gate 	if (--mip->mi_ref == 0) {
4730Sstevel@tonic-gate 		ASSERT(!mip->mi_activelink);
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 	ddi_release_devi(dip);
476269Sericheng 	rw_exit(&i_mac_impl_lock);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate const mac_info_t *
4800Sstevel@tonic-gate mac_info(mac_handle_t mh)
4810Sstevel@tonic-gate {
4820Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4830Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	/*
4860Sstevel@tonic-gate 	 * Return a pointer to the mac_info_t embedded in the mac_t.
4870Sstevel@tonic-gate 	 */
4880Sstevel@tonic-gate 	return (&(mp->m_info));
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate 
491269Sericheng dev_info_t *
492269Sericheng mac_devinfo_get(mac_handle_t mh)
493269Sericheng {
494269Sericheng 	return (((mac_impl_t *)mh)->mi_mp->m_dip);
495269Sericheng }
496269Sericheng 
4970Sstevel@tonic-gate uint64_t
4980Sstevel@tonic-gate mac_stat_get(mac_handle_t mh, enum mac_stat stat)
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
5010Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	ASSERT(mp->m_info.mi_stat[stat]);
5040Sstevel@tonic-gate 	ASSERT(mp->m_stat != NULL);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	/*
5070Sstevel@tonic-gate 	 * Call the driver to get the given statistic.
5080Sstevel@tonic-gate 	 */
5090Sstevel@tonic-gate 	return (mp->m_stat(mp->m_driver, stat));
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate int
5130Sstevel@tonic-gate mac_start(mac_handle_t mh)
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
5160Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
5170Sstevel@tonic-gate 	int		err;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	ASSERT(mp->m_start != NULL);
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	/*
5240Sstevel@tonic-gate 	 * Check whether the device is already started.
5250Sstevel@tonic-gate 	 */
5260Sstevel@tonic-gate 	if (mip->mi_active++ != 0) {
5270Sstevel@tonic-gate 		/*
5280Sstevel@tonic-gate 		 * It's already started so there's nothing more to do.
5290Sstevel@tonic-gate 		 */
5300Sstevel@tonic-gate 		err = 0;
5310Sstevel@tonic-gate 		goto done;
5320Sstevel@tonic-gate 	}
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	/*
5350Sstevel@tonic-gate 	 * Start the device.
5360Sstevel@tonic-gate 	 */
5370Sstevel@tonic-gate 	if ((err = mp->m_start(mp->m_driver)) != 0)
5380Sstevel@tonic-gate 		--mip->mi_active;
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate done:
5410Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
5420Sstevel@tonic-gate 	return (err);
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate void
5460Sstevel@tonic-gate mac_stop(mac_handle_t mh)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
5490Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	ASSERT(mp->m_stop != NULL);
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	/*
5560Sstevel@tonic-gate 	 * Check whether the device is still needed.
5570Sstevel@tonic-gate 	 */
5580Sstevel@tonic-gate 	ASSERT(mip->mi_active != 0);
5590Sstevel@tonic-gate 	if (--mip->mi_active != 0) {
5600Sstevel@tonic-gate 		/*
5610Sstevel@tonic-gate 		 * It's still needed so there's nothing more to do.
5620Sstevel@tonic-gate 		 */
5630Sstevel@tonic-gate 		goto done;
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	/*
5670Sstevel@tonic-gate 	 * Stop the device.
5680Sstevel@tonic-gate 	 */
5690Sstevel@tonic-gate 	mp->m_stop(mp->m_driver);
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate done:
5720Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate int
5760Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
5790Sstevel@tonic-gate 	mac_t			*mp = mip->mi_mp;
5800Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
5810Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
5820Sstevel@tonic-gate 	int			err;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	ASSERT(mp->m_multicst != NULL);
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	/*
5870Sstevel@tonic-gate 	 * Verify the address.
5880Sstevel@tonic-gate 	 */
5890Sstevel@tonic-gate 	if (!(mip->mi_multicst_verify(mip, addr)))
5900Sstevel@tonic-gate 		return (EINVAL);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	/*
5930Sstevel@tonic-gate 	 * Check whether the given address is already enabled.
5940Sstevel@tonic-gate 	 */
5950Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
5960Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
5970Sstevel@tonic-gate 		if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) {
5980Sstevel@tonic-gate 			/*
5990Sstevel@tonic-gate 			 * The address is already enabled so just bump the
6000Sstevel@tonic-gate 			 * reference count.
6010Sstevel@tonic-gate 			 */
6020Sstevel@tonic-gate 			p->mma_ref++;
6030Sstevel@tonic-gate 			err = 0;
6040Sstevel@tonic-gate 			goto done;
6050Sstevel@tonic-gate 		}
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	/*
6090Sstevel@tonic-gate 	 * Allocate a new list entry.
6100Sstevel@tonic-gate 	 */
6110Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
6120Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
6130Sstevel@tonic-gate 		err = ENOMEM;
6140Sstevel@tonic-gate 		goto done;
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	/*
6180Sstevel@tonic-gate 	 * Enable a new multicast address.
6190Sstevel@tonic-gate 	 */
6200Sstevel@tonic-gate 	if ((err = mp->m_multicst(mp->m_driver, B_TRUE, addr)) != 0) {
6210Sstevel@tonic-gate 		kmem_free(p, sizeof (mac_multicst_addr_t));
6220Sstevel@tonic-gate 		goto done;
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	/*
6260Sstevel@tonic-gate 	 * Add the address to the list of enabled addresses.
6270Sstevel@tonic-gate 	 */
6280Sstevel@tonic-gate 	bcopy(addr, p->mma_addr, mip->mi_addr_length);
6290Sstevel@tonic-gate 	p->mma_ref++;
6300Sstevel@tonic-gate 	*pp = p;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate done:
6330Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
6340Sstevel@tonic-gate 	return (err);
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate int
6380Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
6390Sstevel@tonic-gate {
6400Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
6410Sstevel@tonic-gate 	mac_t			*mp = mip->mi_mp;
6420Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
6430Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
6440Sstevel@tonic-gate 	int			err;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	ASSERT(mp->m_multicst != NULL);
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	/*
6490Sstevel@tonic-gate 	 * Find the entry in the list for the given address.
6500Sstevel@tonic-gate 	 */
6510Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
6520Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
6530Sstevel@tonic-gate 		if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) {
6540Sstevel@tonic-gate 			if (--p->mma_ref == 0)
6550Sstevel@tonic-gate 				break;
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 			/*
6580Sstevel@tonic-gate 			 * There is still a reference to this address so
6590Sstevel@tonic-gate 			 * there's nothing more to do.
6600Sstevel@tonic-gate 			 */
6610Sstevel@tonic-gate 			err = 0;
6620Sstevel@tonic-gate 			goto done;
6630Sstevel@tonic-gate 		}
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	/*
6670Sstevel@tonic-gate 	 * We did not find an entry for the given address so it is not
6680Sstevel@tonic-gate 	 * currently enabled.
6690Sstevel@tonic-gate 	 */
6700Sstevel@tonic-gate 	if (p == NULL) {
6710Sstevel@tonic-gate 		err = ENOENT;
6720Sstevel@tonic-gate 		goto done;
6730Sstevel@tonic-gate 	}
6740Sstevel@tonic-gate 	ASSERT(p->mma_ref == 0);
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	/*
6770Sstevel@tonic-gate 	 * Disable the multicast address.
6780Sstevel@tonic-gate 	 */
6790Sstevel@tonic-gate 	if ((err = mp->m_multicst(mp->m_driver, B_FALSE, addr)) != 0) {
6800Sstevel@tonic-gate 		p->mma_ref++;
6810Sstevel@tonic-gate 		goto done;
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	/*
6850Sstevel@tonic-gate 	 * Remove it from the list.
6860Sstevel@tonic-gate 	 */
6870Sstevel@tonic-gate 	*pp = p->mma_nextp;
6880Sstevel@tonic-gate 	kmem_free(p, sizeof (mac_multicst_addr_t));
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate done:
6910Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
6920Sstevel@tonic-gate 	return (err);
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate int
6960Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
6970Sstevel@tonic-gate {
6980Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6990Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
7000Sstevel@tonic-gate 	int		err;
7010Sstevel@tonic-gate 	boolean_t	notify = B_FALSE;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	ASSERT(mp->m_unicst != NULL);
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	/*
7060Sstevel@tonic-gate 	 * Verify the address.
7070Sstevel@tonic-gate 	 */
7080Sstevel@tonic-gate 	if (!(mip->mi_unicst_verify(mip, addr)))
7090Sstevel@tonic-gate 		return (EINVAL);
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	/*
7120Sstevel@tonic-gate 	 * Program the new unicast address.
7130Sstevel@tonic-gate 	 */
7140Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	/*
7170Sstevel@tonic-gate 	 * If address doesn't change, do nothing.
7180Sstevel@tonic-gate 	 * This check is necessary otherwise it may call into mac_unicst_set
7190Sstevel@tonic-gate 	 * recursively.
7200Sstevel@tonic-gate 	 */
7210Sstevel@tonic-gate 	if (bcmp(addr, mip->mi_addr, mip->mi_addr_length) == 0) {
7220Sstevel@tonic-gate 		err = 0;
7230Sstevel@tonic-gate 		goto done;
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	if ((err = mp->m_unicst(mp->m_driver, addr)) != 0)
7270Sstevel@tonic-gate 		goto done;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/*
7300Sstevel@tonic-gate 	 * Save the address and flag that we need to send a notification.
7310Sstevel@tonic-gate 	 */
7320Sstevel@tonic-gate 	bcopy(addr, mip->mi_addr, mip->mi_addr_length);
7330Sstevel@tonic-gate 	notify = B_TRUE;
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate done:
7360Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	if (notify)
7390Sstevel@tonic-gate 		i_mac_notify(mip, MAC_NOTE_UNICST);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	return (err);
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate void
7450Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr)
7460Sstevel@tonic-gate {
7470Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	/*
7500Sstevel@tonic-gate 	 * Copy out the current unicast address.
7510Sstevel@tonic-gate 	 */
7520Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
7530Sstevel@tonic-gate 	bcopy(mip->mi_addr, addr, mip->mi_addr_length);
7540Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7550Sstevel@tonic-gate }
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate int
7580Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
7590Sstevel@tonic-gate {
7600Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7610Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
7620Sstevel@tonic-gate 	int		err = 0;
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	ASSERT(mp->m_promisc != NULL);
7650Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/*
7680Sstevel@tonic-gate 	 * Determine whether we should enable or disable promiscuous mode.
7690Sstevel@tonic-gate 	 * For details on the distinction between "device promiscuous mode"
7700Sstevel@tonic-gate 	 * and "MAC promiscuous mode", see PSARC/2005/289.
7710Sstevel@tonic-gate 	 */
7720Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
7730Sstevel@tonic-gate 	if (on) {
7740Sstevel@tonic-gate 		/*
7750Sstevel@tonic-gate 		 * Enable promiscuous mode on the device if not yet enabled.
7760Sstevel@tonic-gate 		 */
7770Sstevel@tonic-gate 		if (mip->mi_devpromisc++ == 0) {
7780Sstevel@tonic-gate 			if ((err = mp->m_promisc(mp->m_driver, B_TRUE)) != 0) {
7790Sstevel@tonic-gate 				mip->mi_devpromisc--;
7800Sstevel@tonic-gate 				goto done;
7810Sstevel@tonic-gate 			}
7820Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
7830Sstevel@tonic-gate 		}
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 		/*
7860Sstevel@tonic-gate 		 * Enable promiscuous mode on the MAC if not yet enabled.
7870Sstevel@tonic-gate 		 */
7880Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
7890Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
7900Sstevel@tonic-gate 	} else {
7910Sstevel@tonic-gate 		if (mip->mi_devpromisc == 0) {
7920Sstevel@tonic-gate 			err = EPROTO;
7930Sstevel@tonic-gate 			goto done;
7940Sstevel@tonic-gate 		}
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		/*
7970Sstevel@tonic-gate 		 * Disable promiscuous mode on the device if this is the last
7980Sstevel@tonic-gate 		 * enabling.
7990Sstevel@tonic-gate 		 */
8000Sstevel@tonic-gate 		if (--mip->mi_devpromisc == 0) {
8010Sstevel@tonic-gate 			if ((err = mp->m_promisc(mp->m_driver, B_FALSE)) != 0) {
8020Sstevel@tonic-gate 				mip->mi_devpromisc++;
8030Sstevel@tonic-gate 				goto done;
8040Sstevel@tonic-gate 			}
8050Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
8060Sstevel@tonic-gate 		}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		/*
8090Sstevel@tonic-gate 		 * Disable promiscuous mode on the MAC if this is the last
8100Sstevel@tonic-gate 		 * enabling.
8110Sstevel@tonic-gate 		 */
8120Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
8130Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate done:
8170Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
8180Sstevel@tonic-gate 	return (err);
8190Sstevel@tonic-gate }
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate boolean_t
8220Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
8230Sstevel@tonic-gate {
8240Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	/*
8290Sstevel@tonic-gate 	 * Return the current promiscuity.
8300Sstevel@tonic-gate 	 */
8310Sstevel@tonic-gate 	if (ptype == MAC_DEVPROMISC)
8320Sstevel@tonic-gate 		return (mip->mi_devpromisc != 0);
8330Sstevel@tonic-gate 	else
8340Sstevel@tonic-gate 		return (mip->mi_promisc != 0);
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate void
8380Sstevel@tonic-gate mac_resources(mac_handle_t mh)
8390Sstevel@tonic-gate {
8400Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8410Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	ASSERT(mp->m_resources != NULL);
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	/*
8460Sstevel@tonic-gate 	 * Call the driver to register its resources.
8470Sstevel@tonic-gate 	 */
8480Sstevel@tonic-gate 	mp->m_resources(mp->m_driver);
8490Sstevel@tonic-gate }
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate void
8520Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
8530Sstevel@tonic-gate {
8540Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8550Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	ASSERT(mp->m_ioctl != NULL);
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	/*
8600Sstevel@tonic-gate 	 * Call the driver to handle the ioctl.
8610Sstevel@tonic-gate 	 */
8620Sstevel@tonic-gate 	mp->m_ioctl(mp->m_driver, wq, bp);
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate 
86556Smeem const mac_txinfo_t *
86656Smeem mac_tx_get(mac_handle_t mh)
8670Sstevel@tonic-gate {
8680Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
86956Smeem 	mac_txinfo_t	*mtp;
87056Smeem 
87156Smeem 	/*
87256Smeem 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
87356Smeem 	 * changed.  This is sufficient since MAC clients are careful to always
87456Smeem 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
87556Smeem 	 * MAC_PROMISC prior to calling mac_txloop_remove().
87656Smeem 	 */
87756Smeem 	rw_enter(&mip->mi_txloop_lock, RW_READER);
8780Sstevel@tonic-gate 
87956Smeem 	if (mac_promisc_get(mh, MAC_PROMISC)) {
88056Smeem 		ASSERT(mip->mi_mtfp != NULL);
88156Smeem 		mtp = &mip->mi_txloopinfo;
88256Smeem 	} else {
88356Smeem 		/*
88456Smeem 		 * Note that we cannot ASSERT() that mip->mi_mtfp is NULL,
88556Smeem 		 * because to satisfy the above ASSERT(), we have to disable
88656Smeem 		 * MAC_PROMISC prior to calling mac_txloop_remove().
88756Smeem 		 */
88856Smeem 		mtp = &mip->mi_txinfo;
8890Sstevel@tonic-gate 
89056Smeem 	}
89156Smeem 
89256Smeem 	rw_exit(&mip->mi_txloop_lock);
89356Smeem 	return (mtp);
8940Sstevel@tonic-gate }
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate link_state_t
8970Sstevel@tonic-gate mac_link_get(mac_handle_t mh)
8980Sstevel@tonic-gate {
8990Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/*
9020Sstevel@tonic-gate 	 * Return the current link state.
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 	return (mip->mi_link);
9050Sstevel@tonic-gate }
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate mac_notify_handle_t
9080Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
9090Sstevel@tonic-gate {
9100Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9110Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
9140Sstevel@tonic-gate 	mnfp->mnf_fn = notify;
9150Sstevel@tonic-gate 	mnfp->mnf_arg = arg;
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	/*
9180Sstevel@tonic-gate 	 * Add it to the head of the 'notify' callback list.
9190Sstevel@tonic-gate 	 */
920*1852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
9210Sstevel@tonic-gate 	mnfp->mnf_nextp = mip->mi_mnfp;
9220Sstevel@tonic-gate 	mip->mi_mnfp = mnfp;
923*1852Syz147064 	rw_exit(&mip->mi_notify_lock);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	return ((mac_notify_handle_t)mnfp);
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate void
9290Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
9300Sstevel@tonic-gate {
9310Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9320Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
9330Sstevel@tonic-gate 	mac_notify_fn_t		**pp;
9340Sstevel@tonic-gate 	mac_notify_fn_t		*p;
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	/*
9370Sstevel@tonic-gate 	 * Search the 'notify' callback list for the function closure.
9380Sstevel@tonic-gate 	 */
939*1852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
9400Sstevel@tonic-gate 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
9410Sstevel@tonic-gate 	    pp = &(p->mnf_nextp)) {
9420Sstevel@tonic-gate 		if (p == mnfp)
9430Sstevel@tonic-gate 			break;
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 	ASSERT(p != NULL);
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	/*
9480Sstevel@tonic-gate 	 * Remove it from the list.
9490Sstevel@tonic-gate 	 */
9500Sstevel@tonic-gate 	*pp = p->mnf_nextp;
951*1852Syz147064 	rw_exit(&mip->mi_notify_lock);
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	/*
9540Sstevel@tonic-gate 	 * Free it.
9550Sstevel@tonic-gate 	 */
9560Sstevel@tonic-gate 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate void
9600Sstevel@tonic-gate mac_notify(mac_handle_t mh)
9610Sstevel@tonic-gate {
9620Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9630Sstevel@tonic-gate 	mac_notify_type_t	type;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	for (type = 0; type < MAC_NNOTE; type++)
9660Sstevel@tonic-gate 		i_mac_notify(mip, type);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate mac_rx_handle_t
9700Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9730Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
9760Sstevel@tonic-gate 	mrfp->mrf_fn = rx;
9770Sstevel@tonic-gate 	mrfp->mrf_arg = arg;
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	/*
9800Sstevel@tonic-gate 	 * Add it to the head of the 'rx' callback list.
9810Sstevel@tonic-gate 	 */
9820Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
9830Sstevel@tonic-gate 	mrfp->mrf_nextp = mip->mi_mrfp;
9840Sstevel@tonic-gate 	mip->mi_mrfp = mrfp;
9850Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	return ((mac_rx_handle_t)mrfp);
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate /*
9910Sstevel@tonic-gate  * Unregister a receive function for this mac.  This removes the function
9920Sstevel@tonic-gate  * from the list of receive functions for this mac.
9930Sstevel@tonic-gate  */
9940Sstevel@tonic-gate void
9950Sstevel@tonic-gate mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh)
9960Sstevel@tonic-gate {
9970Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9980Sstevel@tonic-gate 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
9990Sstevel@tonic-gate 	mac_rx_fn_t		**pp;
10000Sstevel@tonic-gate 	mac_rx_fn_t		*p;
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	/*
10030Sstevel@tonic-gate 	 * Search the 'rx' callback list for the function closure.
10040Sstevel@tonic-gate 	 */
10050Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
10060Sstevel@tonic-gate 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
10070Sstevel@tonic-gate 		if (p == mrfp)
10080Sstevel@tonic-gate 			break;
10090Sstevel@tonic-gate 	}
10100Sstevel@tonic-gate 	ASSERT(p != NULL);
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	/* Remove it from the list. */
10130Sstevel@tonic-gate 	*pp = p->mrf_nextp;
10140Sstevel@tonic-gate 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
10150Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate mac_txloop_handle_t
10190Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
10200Sstevel@tonic-gate {
10210Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
10220Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
10250Sstevel@tonic-gate 	mtfp->mtf_fn = tx;
10260Sstevel@tonic-gate 	mtfp->mtf_arg = arg;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	/*
10290Sstevel@tonic-gate 	 * Add it to the head of the 'tx' callback list.
10300Sstevel@tonic-gate 	 */
10310Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
10320Sstevel@tonic-gate 	mtfp->mtf_nextp = mip->mi_mtfp;
10330Sstevel@tonic-gate 	mip->mi_mtfp = mtfp;
10340Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	return ((mac_txloop_handle_t)mtfp);
10370Sstevel@tonic-gate }
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate /*
10400Sstevel@tonic-gate  * Unregister a transmit function for this mac.  This removes the function
10410Sstevel@tonic-gate  * from the list of transmit functions for this mac.
10420Sstevel@tonic-gate  */
10430Sstevel@tonic-gate void
10440Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
10450Sstevel@tonic-gate {
10460Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10470Sstevel@tonic-gate 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
10480Sstevel@tonic-gate 	mac_txloop_fn_t		**pp;
10490Sstevel@tonic-gate 	mac_txloop_fn_t		*p;
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	/*
10520Sstevel@tonic-gate 	 * Search the 'tx' callback list for the function.
10530Sstevel@tonic-gate 	 */
10540Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
10550Sstevel@tonic-gate 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
10560Sstevel@tonic-gate 		if (p == mtfp)
10570Sstevel@tonic-gate 			break;
10580Sstevel@tonic-gate 	}
10590Sstevel@tonic-gate 	ASSERT(p != NULL);
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	/* Remove it from the list. */
10620Sstevel@tonic-gate 	*pp = p->mtf_nextp;
10630Sstevel@tonic-gate 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
10640Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate void
10680Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
10690Sstevel@tonic-gate {
10700Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	/*
10730Sstevel@tonic-gate 	 * Update the 'resource_add' callbacks.
10740Sstevel@tonic-gate 	 */
10750Sstevel@tonic-gate 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
10760Sstevel@tonic-gate 	mip->mi_resource_add = add;
10770Sstevel@tonic-gate 	mip->mi_resource_add_arg = arg;
10780Sstevel@tonic-gate 	rw_exit(&(mip->mi_resource_lock));
10790Sstevel@tonic-gate }
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate /*
10820Sstevel@tonic-gate  * Driver support functions.
10830Sstevel@tonic-gate  */
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate int
10860Sstevel@tonic-gate mac_register(mac_t *mp)
10870Sstevel@tonic-gate {
1088269Sericheng 	int	err, instance;
1089269Sericheng 	char	name[MAXNAMELEN], devname[MAXNAMELEN];
1090269Sericheng 	const char *drvname;
10910Sstevel@tonic-gate 	struct devnames *dnp;
1092269Sericheng 	minor_t	minor;
10930Sstevel@tonic-gate 
1094269Sericheng 	drvname = ddi_driver_name(mp->m_dip);
1095269Sericheng 	instance = ddi_get_instance(mp->m_dip);
1096269Sericheng 
1097269Sericheng 	if (strcmp(mp->m_ident, MAC_IDENT) != 0) {
10980Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d/%d: possible mac interface mismatch",
1099269Sericheng 		    drvname, instance, mp->m_port);
1100269Sericheng 	}
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	/*
11030Sstevel@tonic-gate 	 * Create a new mac_impl_t to pair with the mac_t.
11040Sstevel@tonic-gate 	 */
11050Sstevel@tonic-gate 	if ((err = i_mac_create(mp)) != 0)
11060Sstevel@tonic-gate 		return (err);
11070Sstevel@tonic-gate 
1108269Sericheng 	err = EEXIST;
1109269Sericheng 	if (ddi_create_minor_node(mp->m_dip, (char *)drvname, S_IFCHR, 0,
1110269Sericheng 	    DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
1111269Sericheng 		goto fail1;
1112269Sericheng 
1113269Sericheng 	(void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, instance);
1114269Sericheng 
1115269Sericheng 	if (strcmp(drvname, "aggr") == 0) {
1116269Sericheng 		(void) snprintf(name, MAXNAMELEN, "aggr%u", mp->m_port);
1117269Sericheng 		minor = (minor_t)mp->m_port + 1;
1118269Sericheng 	} else {
1119269Sericheng 		(void) strlcpy(name, devname, MAXNAMELEN);
1120269Sericheng 		minor = (minor_t)instance + 1;
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 
1123269Sericheng 	if (ddi_create_minor_node(mp->m_dip, name, S_IFCHR, minor,
1124269Sericheng 	    DDI_NT_NET, 0) != DDI_SUCCESS)
1125269Sericheng 		goto fail2;
1126269Sericheng 
1127269Sericheng 	if ((err = dls_create(name, devname, mp->m_port)) != 0)
1128269Sericheng 		goto fail3;
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	/* set the gldv3 flag in dn_flags */
11310Sstevel@tonic-gate 	dnp = &devnamesp[ddi_driver_major(mp->m_dip)];
11320Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
11330Sstevel@tonic-gate 	dnp->dn_flags |= DN_GLDV3_DRIVER;
11340Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
11350Sstevel@tonic-gate 
1136*1852Syz147064 	/*
1137*1852Syz147064 	 * Mark the MAC to be ready for open.
1138*1852Syz147064 	 */
1139*1852Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1140*1852Syz147064 	((mac_impl_t *)mp->m_impl)->mi_disabled = B_FALSE;
1141*1852Syz147064 	rw_exit(&i_mac_impl_lock);
1142*1852Syz147064 
1143269Sericheng 	cmn_err(CE_NOTE, "!%s%d/%d registered", drvname, instance, mp->m_port);
1144269Sericheng 	return (0);
11450Sstevel@tonic-gate 
1146269Sericheng fail3:
1147269Sericheng 	ddi_remove_minor_node(mp->m_dip, name);
1148269Sericheng fail2:
1149269Sericheng 	ddi_remove_minor_node(mp->m_dip, (char *)drvname);
1150269Sericheng fail1:
1151269Sericheng 	i_mac_destroy(mp);
1152269Sericheng 	return (err);
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate int
11560Sstevel@tonic-gate mac_unregister(mac_t *mp)
11570Sstevel@tonic-gate {
1158269Sericheng 	int		err, instance;
11590Sstevel@tonic-gate 	char		name[MAXNAMELEN];
1160269Sericheng 	const char	*drvname;
11610Sstevel@tonic-gate 	mac_impl_t	*mip = mp->m_impl;
11620Sstevel@tonic-gate 
1163269Sericheng 	drvname = ddi_driver_name(mp->m_dip);
1164269Sericheng 	instance = ddi_get_instance(mp->m_dip);
1165269Sericheng 
11660Sstevel@tonic-gate 	/*
11670Sstevel@tonic-gate 	 * See if there are any other references to this mac_t (e.g., VLAN's).
1168*1852Syz147064 	 * If not, set mi_disabled to prevent any new VLAN's from being
11690Sstevel@tonic-gate 	 * created before we can perform the i_mac_destroy() below.
11700Sstevel@tonic-gate 	 */
1171269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
11720Sstevel@tonic-gate 	if (mip->mi_ref > 0) {
1173269Sericheng 		rw_exit(&i_mac_impl_lock);
11740Sstevel@tonic-gate 		return (EBUSY);
11750Sstevel@tonic-gate 	}
1176*1852Syz147064 	mip->mi_disabled = B_TRUE;
1177269Sericheng 	rw_exit(&i_mac_impl_lock);
11780Sstevel@tonic-gate 
1179*1852Syz147064 	/*
1180*1852Syz147064 	 * Wait for all taskqs which process the mac notifications to finish.
1181*1852Syz147064 	 */
1182*1852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
1183*1852Syz147064 	while (mip->mi_notify_ref != 0)
1184*1852Syz147064 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock);
1185*1852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
1186*1852Syz147064 
1187269Sericheng 	if (strcmp(drvname, "aggr") == 0)
11880Sstevel@tonic-gate 		(void) snprintf(name, MAXNAMELEN, "aggr%u", mp->m_port);
1189269Sericheng 	else
1190269Sericheng 		(void) snprintf(name, MAXNAMELEN, "%s%d", drvname, instance);
1191269Sericheng 
1192269Sericheng 	if ((err = dls_destroy(name)) != 0) {
1193269Sericheng 		rw_enter(&i_mac_impl_lock, RW_WRITER);
1194*1852Syz147064 		mip->mi_disabled = B_FALSE;
1195269Sericheng 		rw_exit(&i_mac_impl_lock);
1196269Sericheng 		return (err);
11970Sstevel@tonic-gate 	}
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	/*
12000Sstevel@tonic-gate 	 * Destroy the mac_impl_t.
12010Sstevel@tonic-gate 	 */
12020Sstevel@tonic-gate 	i_mac_destroy(mp);
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	/*
1205269Sericheng 	 * Remove both style 1 and style 2 minor nodes
12060Sstevel@tonic-gate 	 */
1207269Sericheng 	ddi_remove_minor_node(mp->m_dip, (char *)drvname);
12080Sstevel@tonic-gate 	ddi_remove_minor_node(mp->m_dip, name);
12090Sstevel@tonic-gate 
1210269Sericheng 	cmn_err(CE_NOTE, "!%s%d/%d unregistered", drvname, instance,
12110Sstevel@tonic-gate 	    mp->m_port);
12120Sstevel@tonic-gate 	return (0);
12130Sstevel@tonic-gate }
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate void
12160Sstevel@tonic-gate mac_rx(mac_t *mp, mac_resource_handle_t mrh, mblk_t *bp)
12170Sstevel@tonic-gate {
12180Sstevel@tonic-gate 	mac_impl_t	*mip = mp->m_impl;
12190Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	/*
12220Sstevel@tonic-gate 	 * Call all registered receive functions.
12230Sstevel@tonic-gate 	 */
12240Sstevel@tonic-gate 	rw_enter(&mip->mi_rx_lock, RW_READER);
12250Sstevel@tonic-gate 	mrfp = mip->mi_mrfp;
12260Sstevel@tonic-gate 	if (mrfp == NULL) {
12270Sstevel@tonic-gate 		/* There are no registered receive functions. */
12280Sstevel@tonic-gate 		freemsgchain(bp);
12290Sstevel@tonic-gate 		rw_exit(&mip->mi_rx_lock);
12300Sstevel@tonic-gate 		return;
12310Sstevel@tonic-gate 	}
12320Sstevel@tonic-gate 	do {
12330Sstevel@tonic-gate 		mblk_t *recv_bp;
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 		if (mrfp->mrf_nextp != NULL) {
12360Sstevel@tonic-gate 			/* XXX Do we bump a counter if copymsgchain() fails? */
12370Sstevel@tonic-gate 			recv_bp = copymsgchain(bp);
12380Sstevel@tonic-gate 		} else {
12390Sstevel@tonic-gate 			recv_bp = bp;
12400Sstevel@tonic-gate 		}
12410Sstevel@tonic-gate 		if (recv_bp != NULL)
12420Sstevel@tonic-gate 			mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp);
12430Sstevel@tonic-gate 		mrfp = mrfp->mrf_nextp;
12440Sstevel@tonic-gate 	} while (mrfp != NULL);
12450Sstevel@tonic-gate 	rw_exit(&mip->mi_rx_lock);
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate /*
12490Sstevel@tonic-gate  * Transmit function -- ONLY used when there are registered loopback listeners.
12500Sstevel@tonic-gate  */
12510Sstevel@tonic-gate mblk_t *
12520Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp)
12530Sstevel@tonic-gate {
12540Sstevel@tonic-gate 	mac_impl_t	*mip = arg;
12550Sstevel@tonic-gate 	mac_t		*mp = mip->mi_mp;
12560Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
12570Sstevel@tonic-gate 	mblk_t		*loop_bp, *resid_bp, *next_bp;
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	while (bp != NULL) {
12600Sstevel@tonic-gate 		next_bp = bp->b_next;
12610Sstevel@tonic-gate 		bp->b_next = NULL;
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 		if ((loop_bp = copymsg(bp)) == NULL)
12640Sstevel@tonic-gate 			goto noresources;
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 		if ((resid_bp = mp->m_tx(mp->m_driver, bp)) != NULL) {
12670Sstevel@tonic-gate 			ASSERT(resid_bp == bp);
12680Sstevel@tonic-gate 			freemsg(loop_bp);
12690Sstevel@tonic-gate 			goto noresources;
12700Sstevel@tonic-gate 		}
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 		rw_enter(&mip->mi_txloop_lock, RW_READER);
12730Sstevel@tonic-gate 		mtfp = mip->mi_mtfp;
127456Smeem 		while (mtfp != NULL && loop_bp != NULL) {
12750Sstevel@tonic-gate 			bp = loop_bp;
127656Smeem 
127756Smeem 			/* XXX counter bump if copymsg() fails? */
127856Smeem 			if (mtfp->mtf_nextp != NULL)
12790Sstevel@tonic-gate 				loop_bp = copymsg(bp);
128056Smeem 			else
128156Smeem 				loop_bp = NULL;
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
128456Smeem 			mtfp = mtfp->mtf_nextp;
12850Sstevel@tonic-gate 		}
128656Smeem 		rw_exit(&mip->mi_txloop_lock);
12870Sstevel@tonic-gate 
128856Smeem 		/*
128956Smeem 		 * It's possible we've raced with the disabling of promiscuous
129056Smeem 		 * mode, in which case we can discard our copy.
129156Smeem 		 */
129256Smeem 		if (loop_bp != NULL)
129356Smeem 			freemsg(loop_bp);
129456Smeem 
12950Sstevel@tonic-gate 		bp = next_bp;
12960Sstevel@tonic-gate 	}
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	return (NULL);
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate noresources:
13010Sstevel@tonic-gate 	bp->b_next = next_bp;
13020Sstevel@tonic-gate 	return (bp);
13030Sstevel@tonic-gate }
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate void
13060Sstevel@tonic-gate mac_link_update(mac_t *mp, link_state_t link)
13070Sstevel@tonic-gate {
13080Sstevel@tonic-gate 	mac_impl_t	*mip = mp->m_impl;
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	ASSERT(mip->mi_mp == mp);
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	/*
13130Sstevel@tonic-gate 	 * Save the link state.
13140Sstevel@tonic-gate 	 */
13150Sstevel@tonic-gate 	mip->mi_link = link;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	/*
13180Sstevel@tonic-gate 	 * Send a MAC_NOTE_LINK notification.
13190Sstevel@tonic-gate 	 */
13200Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_LINK);
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate void
13240Sstevel@tonic-gate mac_unicst_update(mac_t *mp, const uint8_t *addr)
13250Sstevel@tonic-gate {
13260Sstevel@tonic-gate 	mac_impl_t	*mip = mp->m_impl;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	ASSERT(mip->mi_mp == mp);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	/*
13310Sstevel@tonic-gate 	 * Save the address.
13320Sstevel@tonic-gate 	 */
13330Sstevel@tonic-gate 	bcopy(addr, mip->mi_addr, mip->mi_addr_length);
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	/*
13360Sstevel@tonic-gate 	 * Send a MAC_NOTE_UNICST notification.
13370Sstevel@tonic-gate 	 */
13380Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_UNICST);
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate void
13420Sstevel@tonic-gate mac_tx_update(mac_t *mp)
13430Sstevel@tonic-gate {
13440Sstevel@tonic-gate 	mac_impl_t	*mip = mp->m_impl;
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 	ASSERT(mip->mi_mp == mp);
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate 	/*
13490Sstevel@tonic-gate 	 * Send a MAC_NOTE_TX notification.
13500Sstevel@tonic-gate 	 */
13510Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_TX);
13520Sstevel@tonic-gate }
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate void
13550Sstevel@tonic-gate mac_resource_update(mac_t *mp)
13560Sstevel@tonic-gate {
13570Sstevel@tonic-gate 	mac_impl_t	*mip = mp->m_impl;
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	ASSERT(mip->mi_mp == mp);
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	/*
13620Sstevel@tonic-gate 	 * Send a MAC_NOTE_RESOURCE notification.
13630Sstevel@tonic-gate 	 */
13640Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_RESOURCE);
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate mac_resource_handle_t
13680Sstevel@tonic-gate mac_resource_add(mac_t *mp, mac_resource_t *mrp)
13690Sstevel@tonic-gate {
13700Sstevel@tonic-gate 	mac_impl_t		*mip = mp->m_impl;
13710Sstevel@tonic-gate 	mac_resource_handle_t	mrh;
13720Sstevel@tonic-gate 	mac_resource_add_t	add;
13730Sstevel@tonic-gate 	void			*arg;
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 	rw_enter(&mip->mi_resource_lock, RW_READER);
13760Sstevel@tonic-gate 	add = mip->mi_resource_add;
13770Sstevel@tonic-gate 	arg = mip->mi_resource_add_arg;
13780Sstevel@tonic-gate 
13791184Skrgopi 	if (add != NULL)
13801184Skrgopi 		mrh = add(arg, mrp);
13811184Skrgopi 	else
13821184Skrgopi 		mrh = NULL;
13830Sstevel@tonic-gate 	rw_exit(&mip->mi_resource_lock);
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	return (mrh);
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate void
13890Sstevel@tonic-gate mac_multicst_refresh(mac_t *mp, mac_multicst_t refresh, void *arg,
13900Sstevel@tonic-gate     boolean_t add)
13910Sstevel@tonic-gate {
13920Sstevel@tonic-gate 	mac_impl_t		*mip = mp->m_impl;
13930Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	/*
13960Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
13970Sstevel@tonic-gate 	 * driver's m_multicst entry point.
13980Sstevel@tonic-gate 	 */
13990Sstevel@tonic-gate 	if (refresh == NULL) {
14000Sstevel@tonic-gate 		refresh = mp->m_multicst;
14010Sstevel@tonic-gate 		arg = mp->m_driver;
14020Sstevel@tonic-gate 	}
14030Sstevel@tonic-gate 	ASSERT(refresh != NULL);
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 	/*
14060Sstevel@tonic-gate 	 * Walk the multicast address list and call the refresh function for
14070Sstevel@tonic-gate 	 * each address.
14080Sstevel@tonic-gate 	 */
14090Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
14100Sstevel@tonic-gate 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
14110Sstevel@tonic-gate 		refresh(arg, add, p->mma_addr);
14120Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
14130Sstevel@tonic-gate }
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate void
14160Sstevel@tonic-gate mac_unicst_refresh(mac_t *mp, mac_unicst_t refresh, void *arg)
14170Sstevel@tonic-gate {
14180Sstevel@tonic-gate 	mac_impl_t	*mip = mp->m_impl;
14190Sstevel@tonic-gate 	/*
14200Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
14210Sstevel@tonic-gate 	 * driver's m_unicst entry point.
14220Sstevel@tonic-gate 	 */
14230Sstevel@tonic-gate 	if (refresh == NULL) {
14240Sstevel@tonic-gate 		refresh = mp->m_unicst;
14250Sstevel@tonic-gate 		arg = mp->m_driver;
14260Sstevel@tonic-gate 	}
14270Sstevel@tonic-gate 	ASSERT(refresh != NULL);
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	/*
14300Sstevel@tonic-gate 	 * Call the refresh function with the current unicast address.
14310Sstevel@tonic-gate 	 */
14320Sstevel@tonic-gate 	refresh(arg, mip->mi_addr);
14330Sstevel@tonic-gate }
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate void
14360Sstevel@tonic-gate mac_promisc_refresh(mac_t *mp, mac_promisc_t refresh, void *arg)
14370Sstevel@tonic-gate {
14380Sstevel@tonic-gate 	mac_impl_t	*mip = mp->m_impl;
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 	/*
14410Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
14420Sstevel@tonic-gate 	 * driver's m_promisc entry point.
14430Sstevel@tonic-gate 	 */
14440Sstevel@tonic-gate 	if (refresh == NULL) {
14450Sstevel@tonic-gate 		refresh = mp->m_promisc;
14460Sstevel@tonic-gate 		arg = mp->m_driver;
14470Sstevel@tonic-gate 	}
14480Sstevel@tonic-gate 	ASSERT(refresh != NULL);
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 	/*
14510Sstevel@tonic-gate 	 * Call the refresh function with the current promiscuity.
14520Sstevel@tonic-gate 	 */
14530Sstevel@tonic-gate 	refresh(arg, (mip->mi_devpromisc != 0));
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate boolean_t
14570Sstevel@tonic-gate mac_active_set(mac_handle_t mh)
14580Sstevel@tonic-gate {
14590Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
14620Sstevel@tonic-gate 	if (mip->mi_activelink) {
14630Sstevel@tonic-gate 		mutex_exit(&mip->mi_activelink_lock);
14640Sstevel@tonic-gate 		return (B_FALSE);
14650Sstevel@tonic-gate 	}
14660Sstevel@tonic-gate 	mip->mi_activelink = B_TRUE;
14670Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
14680Sstevel@tonic-gate 	return (B_TRUE);
14690Sstevel@tonic-gate }
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate void
14720Sstevel@tonic-gate mac_active_clear(mac_handle_t mh)
14730Sstevel@tonic-gate {
14740Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
14770Sstevel@tonic-gate 	ASSERT(mip->mi_activelink);
14780Sstevel@tonic-gate 	mip->mi_activelink = B_FALSE;
14790Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
14800Sstevel@tonic-gate }
1481269Sericheng 
1482269Sericheng /*
1483269Sericheng  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
1484269Sericheng  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
1485269Sericheng  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
1486269Sericheng  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
1487269Sericheng  * cannot disappear while we are accessing it.
1488269Sericheng  */
1489269Sericheng typedef struct i_mac_info_state_s {
1490269Sericheng 	const char	*mi_name;
1491269Sericheng 	mac_info_t	*mi_infop;
1492269Sericheng } i_mac_info_state_t;
1493269Sericheng 
1494269Sericheng /*ARGSUSED*/
1495269Sericheng static uint_t
1496269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1497269Sericheng {
1498269Sericheng 	i_mac_info_state_t	*statep = arg;
1499269Sericheng 	mac_impl_t		*mip = (mac_impl_t *)val;
1500269Sericheng 
1501*1852Syz147064 	if (mip->mi_disabled)
1502269Sericheng 		return (MH_WALK_CONTINUE);
1503269Sericheng 
1504269Sericheng 	if (strcmp(statep->mi_name,
1505269Sericheng 	    ddi_driver_name(mip->mi_mp->m_dip)) != 0)
1506269Sericheng 		return (MH_WALK_CONTINUE);
1507269Sericheng 
1508269Sericheng 	statep->mi_infop = &mip->mi_mp->m_info;
1509269Sericheng 	return (MH_WALK_TERMINATE);
1510269Sericheng }
1511269Sericheng 
1512269Sericheng boolean_t
1513269Sericheng mac_info_get(const char *name, mac_info_t *minfop)
1514269Sericheng {
1515269Sericheng 	i_mac_info_state_t	state;
1516269Sericheng 
1517269Sericheng 	rw_enter(&i_mac_impl_lock, RW_READER);
1518269Sericheng 	state.mi_name = name;
1519269Sericheng 	state.mi_infop = NULL;
1520269Sericheng 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
1521269Sericheng 	if (state.mi_infop == NULL) {
1522269Sericheng 		rw_exit(&i_mac_impl_lock);
1523269Sericheng 		return (B_FALSE);
1524269Sericheng 	}
1525269Sericheng 	*minfop = *state.mi_infop;
1526269Sericheng 	rw_exit(&i_mac_impl_lock);
1527269Sericheng 	return (B_TRUE);
1528269Sericheng }
1529269Sericheng 
1530269Sericheng void
1531269Sericheng mac_init_ops(struct dev_ops *ops, const char *name)
1532269Sericheng {
1533269Sericheng 	dld_init_ops(ops, name);
1534269Sericheng }
1535269Sericheng 
1536269Sericheng void
1537269Sericheng mac_fini_ops(struct dev_ops *ops)
1538269Sericheng {
1539269Sericheng 	dld_fini_ops(ops);
1540269Sericheng }
1541