xref: /onnv-gate/usr/src/uts/common/io/mac/mac.c (revision 3448:aaf16568054b)
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
51852Syz147064  * Common Development and Distribution License (the "License").
61852Syz147064  * 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*3448Sdh155122  * Copyright 2007 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>
442311Sseb #include <sys/modctl.h>
45*3448Sdh155122 #include <sys/fs/dv_node.h>
463288Sseb #include <sys/atomic.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	IMPL_HASHSZ	67	/* prime */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static kmem_cache_t	*i_mac_impl_cachep;
51269Sericheng static mod_hash_t	*i_mac_impl_hash;
52269Sericheng krwlock_t		i_mac_impl_lock;
53269Sericheng uint_t			i_mac_impl_count;
540Sstevel@tonic-gate 
552311Sseb #define	MACTYPE_KMODDIR	"mac"
562311Sseb #define	MACTYPE_HASHSZ	67
572311Sseb static mod_hash_t	*i_mactype_hash;
583288Sseb /*
593288Sseb  * i_mactype_lock synchronizes threads that obtain references to mactype_t
603288Sseb  * structures through i_mactype_getplugin().
613288Sseb  */
623288Sseb static kmutex_t		i_mactype_lock;
632311Sseb 
641852Syz147064 static void i_mac_notify_task(void *);
651852Syz147064 
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate  * Private functions.
680Sstevel@tonic-gate  */
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*ARGSUSED*/
710Sstevel@tonic-gate static int
720Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	bzero(buf, sizeof (mac_impl_t));
770Sstevel@tonic-gate 
782311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
810Sstevel@tonic-gate 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
820Sstevel@tonic-gate 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
830Sstevel@tonic-gate 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
840Sstevel@tonic-gate 	rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL);
850Sstevel@tonic-gate 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
860Sstevel@tonic-gate 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
871852Syz147064 	mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL);
881852Syz147064 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, 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_mac_destructor(void *buf, void *arg)
950Sstevel@tonic-gate {
960Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	ASSERT(mip->mi_ref == 0);
990Sstevel@tonic-gate 	ASSERT(mip->mi_active == 0);
1002311Sseb 	ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
1010Sstevel@tonic-gate 	ASSERT(mip->mi_devpromisc == 0);
1020Sstevel@tonic-gate 	ASSERT(mip->mi_promisc == 0);
1030Sstevel@tonic-gate 	ASSERT(mip->mi_mmap == NULL);
1040Sstevel@tonic-gate 	ASSERT(mip->mi_mnfp == NULL);
1050Sstevel@tonic-gate 	ASSERT(mip->mi_resource_add == NULL);
1060Sstevel@tonic-gate 	ASSERT(mip->mi_ksp == NULL);
1072311Sseb 	ASSERT(mip->mi_kstat_count == 0);
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	rw_destroy(&mip->mi_state_lock);
1100Sstevel@tonic-gate 	rw_destroy(&mip->mi_data_lock);
1110Sstevel@tonic-gate 	rw_destroy(&mip->mi_notify_lock);
1120Sstevel@tonic-gate 	rw_destroy(&mip->mi_rx_lock);
1130Sstevel@tonic-gate 	rw_destroy(&mip->mi_txloop_lock);
1140Sstevel@tonic-gate 	rw_destroy(&mip->mi_resource_lock);
1150Sstevel@tonic-gate 	mutex_destroy(&mip->mi_activelink_lock);
1161852Syz147064 	mutex_destroy(&mip->mi_notify_ref_lock);
1171852Syz147064 	cv_destroy(&mip->mi_notify_cv);
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static void
1210Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
1220Sstevel@tonic-gate {
1231852Syz147064 	mac_notify_task_arg_t	*mnta;
1241852Syz147064 
1251852Syz147064 	rw_enter(&i_mac_impl_lock, RW_READER);
1261852Syz147064 	if (mip->mi_disabled)
1271852Syz147064 		goto exit;
1281852Syz147064 
1291852Syz147064 	if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) {
1301852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory "
1311852Syz147064 		    "allocation failed", mip->mi_name, type);
1321852Syz147064 		goto exit;
1331852Syz147064 	}
1341852Syz147064 
1351852Syz147064 	mnta->mnt_mip = mip;
1361852Syz147064 	mnta->mnt_type = type;
1371852Syz147064 
1381852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
1391852Syz147064 	mip->mi_notify_ref++;
1401852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
1411852Syz147064 
1421852Syz147064 	rw_exit(&i_mac_impl_lock);
1431852Syz147064 
1441852Syz147064 	if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta,
1451852Syz147064 	    TQ_NOSLEEP) == NULL) {
1461852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch "
1471852Syz147064 		    "failed", mip->mi_name, type);
1481852Syz147064 
1491852Syz147064 		mutex_enter(&mip->mi_notify_ref_lock);
1501852Syz147064 		if (--mip->mi_notify_ref == 0)
1511852Syz147064 			cv_signal(&mip->mi_notify_cv);
1521852Syz147064 		mutex_exit(&mip->mi_notify_ref_lock);
1531852Syz147064 
1541852Syz147064 		kmem_free(mnta, sizeof (*mnta));
1551852Syz147064 	}
1561852Syz147064 	return;
1571852Syz147064 
1581852Syz147064 exit:
1591852Syz147064 	rw_exit(&i_mac_impl_lock);
1601852Syz147064 }
1611852Syz147064 
1621852Syz147064 static void
1631852Syz147064 i_mac_notify_task(void *notify_arg)
1641852Syz147064 {
1651852Syz147064 	mac_notify_task_arg_t	*mnta = (mac_notify_task_arg_t *)notify_arg;
1661852Syz147064 	mac_impl_t		*mip;
1671852Syz147064 	mac_notify_type_t	type;
1680Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
1690Sstevel@tonic-gate 	mac_notify_t		notify;
1700Sstevel@tonic-gate 	void			*arg;
1710Sstevel@tonic-gate 
1721852Syz147064 	mip = mnta->mnt_mip;
1731852Syz147064 	type = mnta->mnt_type;
1741852Syz147064 	kmem_free(mnta, sizeof (*mnta));
1751852Syz147064 
1760Sstevel@tonic-gate 	/*
1770Sstevel@tonic-gate 	 * Walk the list of notifications.
1780Sstevel@tonic-gate 	 */
1791852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_READER);
1800Sstevel@tonic-gate 	for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) {
1810Sstevel@tonic-gate 		notify = mnfp->mnf_fn;
1820Sstevel@tonic-gate 		arg = mnfp->mnf_arg;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 		ASSERT(notify != NULL);
1850Sstevel@tonic-gate 		notify(arg, type);
1860Sstevel@tonic-gate 	}
1871852Syz147064 	rw_exit(&mip->mi_notify_lock);
1881852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
1891852Syz147064 	if (--mip->mi_notify_ref == 0)
1901852Syz147064 		cv_signal(&mip->mi_notify_cv);
1911852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate 
1942311Sseb static mactype_t *
1953288Sseb i_mactype_getplugin(const char *pname)
1962311Sseb {
1972311Sseb 	mactype_t	*mtype = NULL;
1982311Sseb 	boolean_t	tried_modload = B_FALSE;
1992311Sseb 
2003288Sseb 	mutex_enter(&i_mactype_lock);
2013288Sseb 
2022311Sseb find_registered_mactype:
2033288Sseb 	if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname,
2043288Sseb 	    (mod_hash_val_t *)&mtype) != 0) {
2053288Sseb 		if (!tried_modload) {
2063288Sseb 			/*
2073288Sseb 			 * If the plugin has not yet been loaded, then
2083288Sseb 			 * attempt to load it now.  If modload() succeeds,
2093288Sseb 			 * the plugin should have registered using
2103288Sseb 			 * mactype_register(), in which case we can go back
2113288Sseb 			 * and attempt to find it again.
2123288Sseb 			 */
2133288Sseb 			if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) {
2143288Sseb 				tried_modload = B_TRUE;
2153288Sseb 				goto find_registered_mactype;
2163288Sseb 			}
2173288Sseb 		}
2183288Sseb 	} else {
2192311Sseb 		/*
2203288Sseb 		 * Note that there's no danger that the plugin we've loaded
2213288Sseb 		 * could be unloaded between the modload() step and the
2223288Sseb 		 * reference count bump here, as we're holding
2233288Sseb 		 * i_mactype_lock, which mactype_unregister() also holds.
2242311Sseb 		 */
2253288Sseb 		atomic_inc_32(&mtype->mt_ref);
2262311Sseb 	}
2272311Sseb 
2283288Sseb 	mutex_exit(&i_mactype_lock);
2293288Sseb 	return (mtype);
2302311Sseb }
2312311Sseb 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * Module initialization functions.
2340Sstevel@tonic-gate  */
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate void
2370Sstevel@tonic-gate mac_init(void)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
2402311Sseb 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
2412311Sseb 	    NULL, NULL, NULL, 0);
2420Sstevel@tonic-gate 	ASSERT(i_mac_impl_cachep != NULL);
2430Sstevel@tonic-gate 
244269Sericheng 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
245269Sericheng 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
246269Sericheng 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
247269Sericheng 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
248269Sericheng 	i_mac_impl_count = 0;
2492311Sseb 
2502311Sseb 	i_mactype_hash = mod_hash_create_extended("mactype_hash",
2512311Sseb 	    MACTYPE_HASHSZ,
2522311Sseb 	    mod_hash_null_keydtor, mod_hash_null_valdtor,
2532311Sseb 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate int
2570Sstevel@tonic-gate mac_fini(void)
2580Sstevel@tonic-gate {
259269Sericheng 	if (i_mac_impl_count > 0)
260269Sericheng 		return (EBUSY);
2610Sstevel@tonic-gate 
262269Sericheng 	mod_hash_destroy_hash(i_mac_impl_hash);
263269Sericheng 	rw_destroy(&i_mac_impl_lock);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	kmem_cache_destroy(i_mac_impl_cachep);
2662311Sseb 
2672311Sseb 	mod_hash_destroy_hash(i_mactype_hash);
2680Sstevel@tonic-gate 	return (0);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate  * Client functions.
2730Sstevel@tonic-gate  */
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate int
2762311Sseb mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp)
2770Sstevel@tonic-gate {
2780Sstevel@tonic-gate 	char		driver[MAXNAMELEN];
2790Sstevel@tonic-gate 	uint_t		instance;
2800Sstevel@tonic-gate 	major_t		major;
2810Sstevel@tonic-gate 	dev_info_t	*dip;
2820Sstevel@tonic-gate 	mac_impl_t	*mip;
2830Sstevel@tonic-gate 	int		err;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	/*
2860Sstevel@tonic-gate 	 * Check the device name length to make sure it won't overflow our
2870Sstevel@tonic-gate 	 * buffer.
2880Sstevel@tonic-gate 	 */
2892311Sseb 	if (strlen(macname) >= MAXNAMELEN)
2900Sstevel@tonic-gate 		return (EINVAL);
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	/*
2930Sstevel@tonic-gate 	 * Split the device name into driver and instance components.
2940Sstevel@tonic-gate 	 */
2952311Sseb 	if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS)
2960Sstevel@tonic-gate 		return (EINVAL);
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	/*
2990Sstevel@tonic-gate 	 * Get the major number of the driver.
3000Sstevel@tonic-gate 	 */
3010Sstevel@tonic-gate 	if ((major = ddi_name_to_major(driver)) == (major_t)-1)
3020Sstevel@tonic-gate 		return (EINVAL);
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	/*
3050Sstevel@tonic-gate 	 * Hold the given instance to prevent it from being detached.
306269Sericheng 	 * This will also attach the instance if it is not currently attached.
307269Sericheng 	 * Currently we ensure that mac_register() (called by the driver's
308269Sericheng 	 * attach entry point) and all code paths under it cannot possibly
309269Sericheng 	 * call mac_open() because this would lead to a recursive attach
310269Sericheng 	 * panic.
3110Sstevel@tonic-gate 	 */
3122311Sseb 	if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL)
3130Sstevel@tonic-gate 		return (EINVAL);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	/*
3160Sstevel@tonic-gate 	 * Look up its entry in the global hash table.
3170Sstevel@tonic-gate 	 */
3180Sstevel@tonic-gate again:
319269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
3202311Sseb 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
321269Sericheng 	    (mod_hash_val_t *)&mip);
322269Sericheng 	if (err != 0) {
323269Sericheng 		err = ENOENT;
3240Sstevel@tonic-gate 		goto failed;
325269Sericheng 	}
3260Sstevel@tonic-gate 
3271852Syz147064 	if (mip->mi_disabled) {
328269Sericheng 		rw_exit(&i_mac_impl_lock);
3290Sstevel@tonic-gate 		goto again;
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	mip->mi_ref++;
333269Sericheng 	rw_exit(&i_mac_impl_lock);
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	*mhp = (mac_handle_t)mip;
3360Sstevel@tonic-gate 	return (0);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate failed:
339269Sericheng 	rw_exit(&i_mac_impl_lock);
3400Sstevel@tonic-gate 	ddi_release_devi(dip);
3410Sstevel@tonic-gate 	return (err);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate void
3450Sstevel@tonic-gate mac_close(mac_handle_t mh)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
3482311Sseb 	dev_info_t	*dip = mip->mi_dip;
3490Sstevel@tonic-gate 
350269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	ASSERT(mip->mi_ref != 0);
3530Sstevel@tonic-gate 	if (--mip->mi_ref == 0) {
3540Sstevel@tonic-gate 		ASSERT(!mip->mi_activelink);
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 	ddi_release_devi(dip);
357269Sericheng 	rw_exit(&i_mac_impl_lock);
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate const mac_info_t *
3610Sstevel@tonic-gate mac_info(mac_handle_t mh)
3620Sstevel@tonic-gate {
3632311Sseb 	return (&((mac_impl_t *)mh)->mi_info);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
366269Sericheng dev_info_t *
367269Sericheng mac_devinfo_get(mac_handle_t mh)
368269Sericheng {
3692311Sseb 	return (((mac_impl_t *)mh)->mi_dip);
370269Sericheng }
371269Sericheng 
3720Sstevel@tonic-gate uint64_t
3732311Sseb mac_stat_get(mac_handle_t mh, uint_t stat)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
3762311Sseb 	uint64_t	val;
3772311Sseb 	int		ret;
3780Sstevel@tonic-gate 
3792311Sseb 	/*
3802311Sseb 	 * The range of stat determines where it is maintained.  Stat
3812311Sseb 	 * values from 0 up to (but not including) MAC_STAT_MIN are
3822311Sseb 	 * mainteined by the mac module itself.  Everything else is
3832311Sseb 	 * maintained by the driver.
3842311Sseb 	 */
3852311Sseb 	if (stat < MAC_STAT_MIN) {
3862311Sseb 		/* These stats are maintained by the mac module itself. */
3872311Sseb 		switch (stat) {
3882311Sseb 		case MAC_STAT_LINK_STATE:
3892311Sseb 			return (mip->mi_linkstate);
3902311Sseb 		case MAC_STAT_LINK_UP:
3912311Sseb 			return (mip->mi_linkstate == LINK_STATE_UP);
3922311Sseb 		case MAC_STAT_PROMISC:
3932311Sseb 			return (mip->mi_devpromisc != 0);
3942311Sseb 		default:
3952311Sseb 			ASSERT(B_FALSE);
3962311Sseb 		}
3972311Sseb 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/*
4000Sstevel@tonic-gate 	 * Call the driver to get the given statistic.
4010Sstevel@tonic-gate 	 */
4022311Sseb 	ret = mip->mi_getstat(mip->mi_driver, stat, &val);
4032311Sseb 	if (ret != 0) {
4042311Sseb 		/*
4052311Sseb 		 * The driver doesn't support this statistic.  Get the
4062311Sseb 		 * statistic's default value.
4072311Sseb 		 */
4082311Sseb 		val = mac_stat_default(mip, stat);
4092311Sseb 	}
4102311Sseb 	return (val);
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate int
4140Sstevel@tonic-gate mac_start(mac_handle_t mh)
4150Sstevel@tonic-gate {
4160Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4170Sstevel@tonic-gate 	int		err;
4180Sstevel@tonic-gate 
4192311Sseb 	ASSERT(mip->mi_start != NULL);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	/*
4240Sstevel@tonic-gate 	 * Check whether the device is already started.
4250Sstevel@tonic-gate 	 */
4260Sstevel@tonic-gate 	if (mip->mi_active++ != 0) {
4270Sstevel@tonic-gate 		/*
4280Sstevel@tonic-gate 		 * It's already started so there's nothing more to do.
4290Sstevel@tonic-gate 		 */
4300Sstevel@tonic-gate 		err = 0;
4310Sstevel@tonic-gate 		goto done;
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	/*
4350Sstevel@tonic-gate 	 * Start the device.
4360Sstevel@tonic-gate 	 */
4372311Sseb 	if ((err = mip->mi_start(mip->mi_driver)) != 0)
4380Sstevel@tonic-gate 		--mip->mi_active;
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate done:
4410Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
4420Sstevel@tonic-gate 	return (err);
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate void
4460Sstevel@tonic-gate mac_stop(mac_handle_t mh)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4490Sstevel@tonic-gate 
4502311Sseb 	ASSERT(mip->mi_stop != NULL);
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/*
4550Sstevel@tonic-gate 	 * Check whether the device is still needed.
4560Sstevel@tonic-gate 	 */
4570Sstevel@tonic-gate 	ASSERT(mip->mi_active != 0);
4580Sstevel@tonic-gate 	if (--mip->mi_active != 0) {
4590Sstevel@tonic-gate 		/*
4600Sstevel@tonic-gate 		 * It's still needed so there's nothing more to do.
4610Sstevel@tonic-gate 		 */
4620Sstevel@tonic-gate 		goto done;
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	/*
4660Sstevel@tonic-gate 	 * Stop the device.
4670Sstevel@tonic-gate 	 */
4682311Sseb 	mip->mi_stop(mip->mi_driver);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate done:
4710Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate int
4750Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
4780Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
4790Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
4800Sstevel@tonic-gate 	int			err;
4810Sstevel@tonic-gate 
4822311Sseb 	ASSERT(mip->mi_multicst != NULL);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * Verify the address.
4860Sstevel@tonic-gate 	 */
4872311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
4882311Sseb 	    mip->mi_pdata)) != 0) {
4892311Sseb 		return (err);
4902311Sseb 	}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	/*
4930Sstevel@tonic-gate 	 * Check whether the given address is already enabled.
4940Sstevel@tonic-gate 	 */
4950Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
4960Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
4972311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
4982311Sseb 		    0) {
4990Sstevel@tonic-gate 			/*
5000Sstevel@tonic-gate 			 * The address is already enabled so just bump the
5010Sstevel@tonic-gate 			 * reference count.
5020Sstevel@tonic-gate 			 */
5030Sstevel@tonic-gate 			p->mma_ref++;
5040Sstevel@tonic-gate 			err = 0;
5050Sstevel@tonic-gate 			goto done;
5060Sstevel@tonic-gate 		}
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	/*
5100Sstevel@tonic-gate 	 * Allocate a new list entry.
5110Sstevel@tonic-gate 	 */
5120Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
5130Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
5140Sstevel@tonic-gate 		err = ENOMEM;
5150Sstevel@tonic-gate 		goto done;
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	/*
5190Sstevel@tonic-gate 	 * Enable a new multicast address.
5200Sstevel@tonic-gate 	 */
5212311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) {
5220Sstevel@tonic-gate 		kmem_free(p, sizeof (mac_multicst_addr_t));
5230Sstevel@tonic-gate 		goto done;
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	/*
5270Sstevel@tonic-gate 	 * Add the address to the list of enabled addresses.
5280Sstevel@tonic-gate 	 */
5292311Sseb 	bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length);
5300Sstevel@tonic-gate 	p->mma_ref++;
5310Sstevel@tonic-gate 	*pp = p;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate done:
5340Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
5350Sstevel@tonic-gate 	return (err);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate int
5390Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
5420Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
5430Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
5440Sstevel@tonic-gate 	int			err;
5450Sstevel@tonic-gate 
5462311Sseb 	ASSERT(mip->mi_multicst != NULL);
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	/*
5490Sstevel@tonic-gate 	 * Find the entry in the list for the given address.
5500Sstevel@tonic-gate 	 */
5510Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
5520Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
5532311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
5542311Sseb 		    0) {
5550Sstevel@tonic-gate 			if (--p->mma_ref == 0)
5560Sstevel@tonic-gate 				break;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 			/*
5590Sstevel@tonic-gate 			 * There is still a reference to this address so
5600Sstevel@tonic-gate 			 * there's nothing more to do.
5610Sstevel@tonic-gate 			 */
5620Sstevel@tonic-gate 			err = 0;
5630Sstevel@tonic-gate 			goto done;
5640Sstevel@tonic-gate 		}
5650Sstevel@tonic-gate 	}
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	/*
5680Sstevel@tonic-gate 	 * We did not find an entry for the given address so it is not
5690Sstevel@tonic-gate 	 * currently enabled.
5700Sstevel@tonic-gate 	 */
5710Sstevel@tonic-gate 	if (p == NULL) {
5720Sstevel@tonic-gate 		err = ENOENT;
5730Sstevel@tonic-gate 		goto done;
5740Sstevel@tonic-gate 	}
5750Sstevel@tonic-gate 	ASSERT(p->mma_ref == 0);
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	/*
5780Sstevel@tonic-gate 	 * Disable the multicast address.
5790Sstevel@tonic-gate 	 */
5802311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) {
5810Sstevel@tonic-gate 		p->mma_ref++;
5820Sstevel@tonic-gate 		goto done;
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	/*
5860Sstevel@tonic-gate 	 * Remove it from the list.
5870Sstevel@tonic-gate 	 */
5880Sstevel@tonic-gate 	*pp = p->mma_nextp;
5890Sstevel@tonic-gate 	kmem_free(p, sizeof (mac_multicst_addr_t));
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate done:
5920Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
5930Sstevel@tonic-gate 	return (err);
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate 
5962331Skrgopi /*
5972331Skrgopi  * mac_unicst_verify: Verifies the passed address. It fails
5982331Skrgopi  * if the passed address is a group address or has incorrect length.
5992331Skrgopi  */
6002331Skrgopi boolean_t
6012331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
6022331Skrgopi {
6032331Skrgopi 	mac_impl_t	*mip = (mac_impl_t *)mh;
6042331Skrgopi 
6052331Skrgopi 	/*
6062331Skrgopi 	 * Verify the address.
6072331Skrgopi 	 */
6082331Skrgopi 	if ((len != mip->mi_type->mt_addr_length) ||
6092331Skrgopi 	    (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
6102331Skrgopi 	    mip->mi_pdata)) != 0) {
6112331Skrgopi 		return (B_FALSE);
6122331Skrgopi 	} else {
6132331Skrgopi 		return (B_TRUE);
6142331Skrgopi 	}
6152331Skrgopi }
6162331Skrgopi 
6170Sstevel@tonic-gate int
6180Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6210Sstevel@tonic-gate 	int		err;
6220Sstevel@tonic-gate 	boolean_t	notify = B_FALSE;
6230Sstevel@tonic-gate 
6242311Sseb 	ASSERT(mip->mi_unicst != NULL);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	/*
6270Sstevel@tonic-gate 	 * Verify the address.
6280Sstevel@tonic-gate 	 */
6292311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr,
6302311Sseb 	    mip->mi_pdata)) != 0) {
6312311Sseb 		return (err);
6322311Sseb 	}
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	/*
6350Sstevel@tonic-gate 	 * Program the new unicast address.
6360Sstevel@tonic-gate 	 */
6370Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	/*
6400Sstevel@tonic-gate 	 * If address doesn't change, do nothing.
6410Sstevel@tonic-gate 	 * This check is necessary otherwise it may call into mac_unicst_set
6420Sstevel@tonic-gate 	 * recursively.
6430Sstevel@tonic-gate 	 */
6442311Sseb 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) {
6450Sstevel@tonic-gate 		err = 0;
6460Sstevel@tonic-gate 		goto done;
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 
6492311Sseb 	if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0)
6500Sstevel@tonic-gate 		goto done;
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	/*
6530Sstevel@tonic-gate 	 * Save the address and flag that we need to send a notification.
6540Sstevel@tonic-gate 	 */
6552311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
6560Sstevel@tonic-gate 	notify = B_TRUE;
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate done:
6590Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	if (notify)
6620Sstevel@tonic-gate 		i_mac_notify(mip, MAC_NOTE_UNICST);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	return (err);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate void
6680Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	/*
6732311Sseb 	 * Copy out the current unicast source address.
6740Sstevel@tonic-gate 	 */
6750Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
6762311Sseb 	bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
6772311Sseb 	rw_exit(&(mip->mi_data_lock));
6782311Sseb }
6792311Sseb 
6802311Sseb void
6812311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr)
6822311Sseb {
6832311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
6842311Sseb 
6852311Sseb 	/*
6862311Sseb 	 * Copy out the current destination address.
6872311Sseb 	 */
6882311Sseb 	rw_enter(&(mip->mi_data_lock), RW_READER);
6892311Sseb 	bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
6900Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate int
6940Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
6950Sstevel@tonic-gate {
6960Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6970Sstevel@tonic-gate 	int		err = 0;
6980Sstevel@tonic-gate 
6992311Sseb 	ASSERT(mip->mi_setpromisc != NULL);
7000Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	/*
7030Sstevel@tonic-gate 	 * Determine whether we should enable or disable promiscuous mode.
7040Sstevel@tonic-gate 	 * For details on the distinction between "device promiscuous mode"
7050Sstevel@tonic-gate 	 * and "MAC promiscuous mode", see PSARC/2005/289.
7060Sstevel@tonic-gate 	 */
7070Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
7080Sstevel@tonic-gate 	if (on) {
7090Sstevel@tonic-gate 		/*
7100Sstevel@tonic-gate 		 * Enable promiscuous mode on the device if not yet enabled.
7110Sstevel@tonic-gate 		 */
7120Sstevel@tonic-gate 		if (mip->mi_devpromisc++ == 0) {
7132311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
7142311Sseb 			if (err != 0) {
7150Sstevel@tonic-gate 				mip->mi_devpromisc--;
7160Sstevel@tonic-gate 				goto done;
7170Sstevel@tonic-gate 			}
7180Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
7190Sstevel@tonic-gate 		}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 		/*
7220Sstevel@tonic-gate 		 * Enable promiscuous mode on the MAC if not yet enabled.
7230Sstevel@tonic-gate 		 */
7240Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
7250Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
7260Sstevel@tonic-gate 	} else {
7270Sstevel@tonic-gate 		if (mip->mi_devpromisc == 0) {
7280Sstevel@tonic-gate 			err = EPROTO;
7290Sstevel@tonic-gate 			goto done;
7300Sstevel@tonic-gate 		}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 		/*
7330Sstevel@tonic-gate 		 * Disable promiscuous mode on the device if this is the last
7340Sstevel@tonic-gate 		 * enabling.
7350Sstevel@tonic-gate 		 */
7360Sstevel@tonic-gate 		if (--mip->mi_devpromisc == 0) {
7372311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
7382311Sseb 			if (err != 0) {
7390Sstevel@tonic-gate 				mip->mi_devpromisc++;
7400Sstevel@tonic-gate 				goto done;
7410Sstevel@tonic-gate 			}
7420Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
7430Sstevel@tonic-gate 		}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 		/*
7460Sstevel@tonic-gate 		 * Disable promiscuous mode on the MAC if this is the last
7470Sstevel@tonic-gate 		 * enabling.
7480Sstevel@tonic-gate 		 */
7490Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
7500Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
7510Sstevel@tonic-gate 	}
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate done:
7540Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7550Sstevel@tonic-gate 	return (err);
7560Sstevel@tonic-gate }
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate boolean_t
7590Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
7600Sstevel@tonic-gate {
7610Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	/*
7660Sstevel@tonic-gate 	 * Return the current promiscuity.
7670Sstevel@tonic-gate 	 */
7680Sstevel@tonic-gate 	if (ptype == MAC_DEVPROMISC)
7690Sstevel@tonic-gate 		return (mip->mi_devpromisc != 0);
7700Sstevel@tonic-gate 	else
7710Sstevel@tonic-gate 		return (mip->mi_promisc != 0);
7720Sstevel@tonic-gate }
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate void
7750Sstevel@tonic-gate mac_resources(mac_handle_t mh)
7760Sstevel@tonic-gate {
7770Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	/*
7802311Sseb 	 * If the driver supports resource registration, call the driver to
7812311Sseb 	 * ask it to register its resources.
7820Sstevel@tonic-gate 	 */
7832311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES)
7842311Sseb 		mip->mi_resources(mip->mi_driver);
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate void
7880Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
7890Sstevel@tonic-gate {
7900Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	/*
7932311Sseb 	 * Call the driver to handle the ioctl.  The driver may not support
7942311Sseb 	 * any ioctls, in which case we reply with a NAK on its behalf.
7950Sstevel@tonic-gate 	 */
7962311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
7972311Sseb 		mip->mi_ioctl(mip->mi_driver, wq, bp);
7982311Sseb 	else
7992311Sseb 		miocnak(wq, bp, 0, EINVAL);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate 
80256Smeem const mac_txinfo_t *
80356Smeem mac_tx_get(mac_handle_t mh)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
80656Smeem 	mac_txinfo_t	*mtp;
80756Smeem 
80856Smeem 	/*
80956Smeem 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
81056Smeem 	 * changed.  This is sufficient since MAC clients are careful to always
81156Smeem 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
81256Smeem 	 * MAC_PROMISC prior to calling mac_txloop_remove().
81356Smeem 	 */
81456Smeem 	rw_enter(&mip->mi_txloop_lock, RW_READER);
8150Sstevel@tonic-gate 
81656Smeem 	if (mac_promisc_get(mh, MAC_PROMISC)) {
81756Smeem 		ASSERT(mip->mi_mtfp != NULL);
81856Smeem 		mtp = &mip->mi_txloopinfo;
81956Smeem 	} else {
82056Smeem 		/*
82156Smeem 		 * Note that we cannot ASSERT() that mip->mi_mtfp is NULL,
82256Smeem 		 * because to satisfy the above ASSERT(), we have to disable
82356Smeem 		 * MAC_PROMISC prior to calling mac_txloop_remove().
82456Smeem 		 */
82556Smeem 		mtp = &mip->mi_txinfo;
82656Smeem 	}
82756Smeem 
82856Smeem 	rw_exit(&mip->mi_txloop_lock);
82956Smeem 	return (mtp);
8300Sstevel@tonic-gate }
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate link_state_t
8330Sstevel@tonic-gate mac_link_get(mac_handle_t mh)
8340Sstevel@tonic-gate {
8352311Sseb 	return (((mac_impl_t *)mh)->mi_linkstate);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate mac_notify_handle_t
8390Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8420Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
8450Sstevel@tonic-gate 	mnfp->mnf_fn = notify;
8460Sstevel@tonic-gate 	mnfp->mnf_arg = arg;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	/*
8490Sstevel@tonic-gate 	 * Add it to the head of the 'notify' callback list.
8500Sstevel@tonic-gate 	 */
8511852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
8520Sstevel@tonic-gate 	mnfp->mnf_nextp = mip->mi_mnfp;
8530Sstevel@tonic-gate 	mip->mi_mnfp = mnfp;
8541852Syz147064 	rw_exit(&mip->mi_notify_lock);
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 	return ((mac_notify_handle_t)mnfp);
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate void
8600Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8630Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
8640Sstevel@tonic-gate 	mac_notify_fn_t		**pp;
8650Sstevel@tonic-gate 	mac_notify_fn_t		*p;
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	/*
8680Sstevel@tonic-gate 	 * Search the 'notify' callback list for the function closure.
8690Sstevel@tonic-gate 	 */
8701852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
8710Sstevel@tonic-gate 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
8720Sstevel@tonic-gate 	    pp = &(p->mnf_nextp)) {
8730Sstevel@tonic-gate 		if (p == mnfp)
8740Sstevel@tonic-gate 			break;
8750Sstevel@tonic-gate 	}
8760Sstevel@tonic-gate 	ASSERT(p != NULL);
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/*
8790Sstevel@tonic-gate 	 * Remove it from the list.
8800Sstevel@tonic-gate 	 */
8810Sstevel@tonic-gate 	*pp = p->mnf_nextp;
8821852Syz147064 	rw_exit(&mip->mi_notify_lock);
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	/*
8850Sstevel@tonic-gate 	 * Free it.
8860Sstevel@tonic-gate 	 */
8870Sstevel@tonic-gate 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate void
8910Sstevel@tonic-gate mac_notify(mac_handle_t mh)
8920Sstevel@tonic-gate {
8930Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8940Sstevel@tonic-gate 	mac_notify_type_t	type;
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	for (type = 0; type < MAC_NNOTE; type++)
8970Sstevel@tonic-gate 		i_mac_notify(mip, type);
8980Sstevel@tonic-gate }
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate mac_rx_handle_t
9010Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
9020Sstevel@tonic-gate {
9030Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9040Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
9070Sstevel@tonic-gate 	mrfp->mrf_fn = rx;
9080Sstevel@tonic-gate 	mrfp->mrf_arg = arg;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	/*
9110Sstevel@tonic-gate 	 * Add it to the head of the 'rx' callback list.
9120Sstevel@tonic-gate 	 */
9130Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
9140Sstevel@tonic-gate 	mrfp->mrf_nextp = mip->mi_mrfp;
9150Sstevel@tonic-gate 	mip->mi_mrfp = mrfp;
9160Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	return ((mac_rx_handle_t)mrfp);
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate /*
9220Sstevel@tonic-gate  * Unregister a receive function for this mac.  This removes the function
9230Sstevel@tonic-gate  * from the list of receive functions for this mac.
9240Sstevel@tonic-gate  */
9250Sstevel@tonic-gate void
9260Sstevel@tonic-gate mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh)
9270Sstevel@tonic-gate {
9280Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9290Sstevel@tonic-gate 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
9300Sstevel@tonic-gate 	mac_rx_fn_t		**pp;
9310Sstevel@tonic-gate 	mac_rx_fn_t		*p;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	/*
9340Sstevel@tonic-gate 	 * Search the 'rx' callback list for the function closure.
9350Sstevel@tonic-gate 	 */
9360Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
9370Sstevel@tonic-gate 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
9380Sstevel@tonic-gate 		if (p == mrfp)
9390Sstevel@tonic-gate 			break;
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 	ASSERT(p != NULL);
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	/* Remove it from the list. */
9440Sstevel@tonic-gate 	*pp = p->mrf_nextp;
9450Sstevel@tonic-gate 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
9460Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate mac_txloop_handle_t
9500Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
9510Sstevel@tonic-gate {
9520Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9530Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
9560Sstevel@tonic-gate 	mtfp->mtf_fn = tx;
9570Sstevel@tonic-gate 	mtfp->mtf_arg = arg;
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	/*
9600Sstevel@tonic-gate 	 * Add it to the head of the 'tx' callback list.
9610Sstevel@tonic-gate 	 */
9620Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
9630Sstevel@tonic-gate 	mtfp->mtf_nextp = mip->mi_mtfp;
9640Sstevel@tonic-gate 	mip->mi_mtfp = mtfp;
9650Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	return ((mac_txloop_handle_t)mtfp);
9680Sstevel@tonic-gate }
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate /*
9710Sstevel@tonic-gate  * Unregister a transmit function for this mac.  This removes the function
9720Sstevel@tonic-gate  * from the list of transmit functions for this mac.
9730Sstevel@tonic-gate  */
9740Sstevel@tonic-gate void
9750Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
9760Sstevel@tonic-gate {
9770Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9780Sstevel@tonic-gate 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
9790Sstevel@tonic-gate 	mac_txloop_fn_t		**pp;
9800Sstevel@tonic-gate 	mac_txloop_fn_t		*p;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	/*
9830Sstevel@tonic-gate 	 * Search the 'tx' callback list for the function.
9840Sstevel@tonic-gate 	 */
9850Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
9860Sstevel@tonic-gate 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
9870Sstevel@tonic-gate 		if (p == mtfp)
9880Sstevel@tonic-gate 			break;
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate 	ASSERT(p != NULL);
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	/* Remove it from the list. */
9930Sstevel@tonic-gate 	*pp = p->mtf_nextp;
9940Sstevel@tonic-gate 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
9950Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate void
9990Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
10000Sstevel@tonic-gate {
10010Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	/*
10040Sstevel@tonic-gate 	 * Update the 'resource_add' callbacks.
10050Sstevel@tonic-gate 	 */
10060Sstevel@tonic-gate 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
10070Sstevel@tonic-gate 	mip->mi_resource_add = add;
10080Sstevel@tonic-gate 	mip->mi_resource_add_arg = arg;
10090Sstevel@tonic-gate 	rw_exit(&(mip->mi_resource_lock));
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate /*
10130Sstevel@tonic-gate  * Driver support functions.
10140Sstevel@tonic-gate  */
10150Sstevel@tonic-gate 
10162311Sseb mac_register_t *
10172311Sseb mac_alloc(uint_t mac_version)
10180Sstevel@tonic-gate {
10192311Sseb 	mac_register_t *mregp;
10202311Sseb 
10212311Sseb 	/*
10222311Sseb 	 * Make sure there isn't a version mismatch between the driver and
10232311Sseb 	 * the framework.  In the future, if multiple versions are
10242311Sseb 	 * supported, this check could become more sophisticated.
10252311Sseb 	 */
10262311Sseb 	if (mac_version != MAC_VERSION)
10272311Sseb 		return (NULL);
10282311Sseb 
10292311Sseb 	mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
10302311Sseb 	mregp->m_version = mac_version;
10312311Sseb 	return (mregp);
10322311Sseb }
10332311Sseb 
10342311Sseb void
10352311Sseb mac_free(mac_register_t *mregp)
10362311Sseb {
10372311Sseb 	kmem_free(mregp, sizeof (mac_register_t));
10382311Sseb }
10392311Sseb 
10402311Sseb /*
10412311Sseb  * mac_register() is how drivers register new MACs with the GLDv3
10422311Sseb  * framework.  The mregp argument is allocated by drivers using the
10432311Sseb  * mac_alloc() function, and can be freed using mac_free() immediately upon
10442311Sseb  * return from mac_register().  Upon success (0 return value), the mhp
10452311Sseb  * opaque pointer becomes the driver's handle to its MAC interface, and is
10462311Sseb  * the argument to all other mac module entry points.
10472311Sseb  */
10482311Sseb int
10492311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp)
10502311Sseb {
10512311Sseb 	mac_impl_t	*mip;
10522311Sseb 	mactype_t	*mtype;
10532311Sseb 	int		err;
10540Sstevel@tonic-gate 	struct devnames *dnp;
10552311Sseb 	minor_t		minor;
10562311Sseb 	mod_hash_val_t	val;
10572311Sseb 	boolean_t	style1_created = B_FALSE, style2_created = B_FALSE;
10582311Sseb 
10592311Sseb 	/* Find the required MAC-Type plugin. */
10602311Sseb 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
10612311Sseb 		return (EINVAL);
10622311Sseb 
10632311Sseb 	/* Create a mac_impl_t to represent this MAC. */
10642311Sseb 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
10652311Sseb 
10662311Sseb 	/*
10672311Sseb 	 * The mac is not ready for open yet.
10682311Sseb 	 */
10692311Sseb 	mip->mi_disabled = B_TRUE;
10702311Sseb 
10712311Sseb 	mip->mi_drvname = ddi_driver_name(mregp->m_dip);
10722311Sseb 	/*
10732311Sseb 	 * Some drivers such as aggr need to register multiple MACs.  Such
10742311Sseb 	 * drivers must supply a non-zero "instance" argument so that each
10752311Sseb 	 * MAC can be assigned a unique MAC name and can have unique
10762311Sseb 	 * kstats.
10772311Sseb 	 */
10782311Sseb 	mip->mi_instance = ((mregp->m_instance == 0) ?
10792311Sseb 	    ddi_get_instance(mregp->m_dip) : mregp->m_instance);
10802311Sseb 
10812311Sseb 	/* Construct the MAC name as <drvname><instance> */
10822311Sseb 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
10832311Sseb 	    mip->mi_drvname, mip->mi_instance);
10842311Sseb 
10852311Sseb 	rw_enter(&i_mac_impl_lock, RW_WRITER);
10862311Sseb 	if (mod_hash_insert(i_mac_impl_hash,
10872311Sseb 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
10882311Sseb 		kmem_cache_free(i_mac_impl_cachep, mip);
10892311Sseb 		rw_exit(&i_mac_impl_lock);
10902311Sseb 		return (EEXIST);
10912311Sseb 	}
10923288Sseb 	atomic_inc_32(&i_mac_impl_count);
10932311Sseb 
10942311Sseb 	mip->mi_driver = mregp->m_driver;
10952311Sseb 
10962311Sseb 	mip->mi_type = mtype;
10972311Sseb 	mip->mi_info.mi_media = mtype->mt_type;
10983147Sxc151355 	mip->mi_info.mi_nativemedia = mtype->mt_nativetype;
10992311Sseb 	mip->mi_info.mi_sdu_min = mregp->m_min_sdu;
11002311Sseb 	if (mregp->m_max_sdu <= mregp->m_min_sdu) {
11012311Sseb 		err = EINVAL;
11022311Sseb 		goto fail;
11032311Sseb 	}
11042311Sseb 	mip->mi_info.mi_sdu_max = mregp->m_max_sdu;
11052311Sseb 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
11062311Sseb 	/*
11072311Sseb 	 * If the media supports a broadcast address, cache a pointer to it
11082311Sseb 	 * in the mac_info_t so that upper layers can use it.
11092311Sseb 	 */
11102311Sseb 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1111269Sericheng 
11122311Sseb 	/*
11132311Sseb 	 * Copy the unicast source address into the mac_info_t, but only if
11142311Sseb 	 * the MAC-Type defines a non-zero address length.  We need to
11152311Sseb 	 * handle MAC-Types that have an address length of 0
11162311Sseb 	 * (point-to-point protocol MACs for example).
11172311Sseb 	 */
11182311Sseb 	if (mip->mi_type->mt_addr_length > 0) {
11192311Sseb 		if (mregp->m_src_addr == NULL) {
11202311Sseb 			err = EINVAL;
11212311Sseb 			goto fail;
11222311Sseb 		}
11232311Sseb 		mip->mi_info.mi_unicst_addr =
11242311Sseb 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
11252311Sseb 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
11262311Sseb 		    mip->mi_type->mt_addr_length);
11272311Sseb 
11282311Sseb 		/*
11292311Sseb 		 * Copy the fixed 'factory' MAC address from the immutable
11302311Sseb 		 * info.  This is taken to be the MAC address currently in
11312311Sseb 		 * use.
11322311Sseb 		 */
11332311Sseb 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
11342311Sseb 		    mip->mi_type->mt_addr_length);
11352311Sseb 		/* Copy the destination address if one is provided. */
11362311Sseb 		if (mregp->m_dst_addr != NULL) {
11372311Sseb 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
11382311Sseb 			    mip->mi_type->mt_addr_length);
11392311Sseb 		}
11402311Sseb 	} else if (mregp->m_src_addr != NULL) {
11412311Sseb 		err = EINVAL;
11422311Sseb 		goto fail;
1143269Sericheng 	}
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	/*
11462311Sseb 	 * The format of the m_pdata is specific to the plugin.  It is
11472311Sseb 	 * passed in as an argument to all of the plugin callbacks.  The
11482311Sseb 	 * driver can update this information by calling
11492311Sseb 	 * mac_pdata_update().
11500Sstevel@tonic-gate 	 */
11512311Sseb 	if (mregp->m_pdata != NULL) {
11522311Sseb 		/*
11532311Sseb 		 * Verify that the plugin supports MAC plugin data and that
11542311Sseb 		 * the supplied data is valid.
11552311Sseb 		 */
11562311Sseb 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) {
11572311Sseb 			err = EINVAL;
11582311Sseb 			goto fail;
11592311Sseb 		}
11602311Sseb 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
11612311Sseb 		    mregp->m_pdata_size)) {
11622311Sseb 			err = EINVAL;
11632311Sseb 			goto fail;
11642311Sseb 		}
11652311Sseb 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
11662311Sseb 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
11672311Sseb 		mip->mi_pdata_size = mregp->m_pdata_size;
11682311Sseb 	}
11692311Sseb 
11702311Sseb 	/*
11712311Sseb 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
11722311Sseb 	 * check to make sure all mandatory callbacks are set.
11732311Sseb 	 */
11742311Sseb 	if (mregp->m_callbacks->mc_getstat == NULL ||
11752311Sseb 	    mregp->m_callbacks->mc_start == NULL ||
11762311Sseb 	    mregp->m_callbacks->mc_stop == NULL ||
11772311Sseb 	    mregp->m_callbacks->mc_setpromisc == NULL ||
11782311Sseb 	    mregp->m_callbacks->mc_multicst == NULL ||
11792311Sseb 	    mregp->m_callbacks->mc_unicst == NULL ||
11802311Sseb 	    mregp->m_callbacks->mc_tx == NULL) {
11812311Sseb 		err = EINVAL;
11822311Sseb 		goto fail;
11832311Sseb 	}
11842311Sseb 	mip->mi_callbacks = mregp->m_callbacks;
11852311Sseb 
11862311Sseb 	mip->mi_dip = mregp->m_dip;
11872311Sseb 
11882311Sseb 	/*
11892311Sseb 	 * Set up the two possible transmit routines.
11902311Sseb 	 */
11912311Sseb 	mip->mi_txinfo.mt_fn = mip->mi_tx;
11922311Sseb 	mip->mi_txinfo.mt_arg = mip->mi_driver;
11932311Sseb 	mip->mi_txloopinfo.mt_fn = mac_txloop;
11942311Sseb 	mip->mi_txloopinfo.mt_arg = mip;
11952311Sseb 
11962311Sseb 	/*
11972311Sseb 	 * Initialize the kstats for this device.
11982311Sseb 	 */
11992311Sseb 	mac_stat_create(mip);
12000Sstevel@tonic-gate 
1201269Sericheng 	err = EEXIST;
12022311Sseb 	/* Create a style-2 DLPI device */
12032311Sseb 	if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname,
12042311Sseb 	    S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
12052311Sseb 		goto fail;
12062311Sseb 	style2_created = B_TRUE;
1207269Sericheng 
12082311Sseb 	/* Create a style-1 DLPI device */
12092311Sseb 	minor = (minor_t)mip->mi_instance + 1;
12102311Sseb 	if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor,
12112311Sseb 	    DDI_NT_NET, 0) != DDI_SUCCESS)
12122311Sseb 		goto fail;
12132311Sseb 	style1_created = B_TRUE;
12140Sstevel@tonic-gate 
12152311Sseb 	/*
12162311Sseb 	 * Create a link for this MAC.  The link name will be the same as
12172311Sseb 	 * the MAC name.
12182311Sseb 	 */
12192311Sseb 	err = dls_create(mip->mi_name, mip->mi_name,
12202311Sseb 	    ddi_get_instance(mip->mi_dip));
12212311Sseb 	if (err != 0)
12222311Sseb 		goto fail;
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	/* set the gldv3 flag in dn_flags */
12252311Sseb 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
12260Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
12270Sstevel@tonic-gate 	dnp->dn_flags |= DN_GLDV3_DRIVER;
12280Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
12290Sstevel@tonic-gate 
12301852Syz147064 	/*
12311852Syz147064 	 * Mark the MAC to be ready for open.
12321852Syz147064 	 */
12332311Sseb 	mip->mi_disabled = B_FALSE;
12342311Sseb 
12352311Sseb 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
12361852Syz147064 	rw_exit(&i_mac_impl_lock);
12372311Sseb 	*mhp = (mac_handle_t)mip;
1238269Sericheng 	return (0);
12390Sstevel@tonic-gate 
12402311Sseb fail:
12412311Sseb 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
12422311Sseb 	    &val);
12432311Sseb 	ASSERT(mip == (mac_impl_t *)val);
12443288Sseb 	atomic_dec_32(&i_mac_impl_count);
12452311Sseb 
12462311Sseb 	if (mip->mi_info.mi_unicst_addr != NULL) {
12472311Sseb 		kmem_free(mip->mi_info.mi_unicst_addr,
12482311Sseb 		    mip->mi_type->mt_addr_length);
12492311Sseb 		mip->mi_info.mi_unicst_addr = NULL;
12502311Sseb 	}
12512311Sseb 	if (style1_created)
12522311Sseb 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
12532311Sseb 	if (style2_created)
12542311Sseb 		ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
12552311Sseb 
12562311Sseb 	mac_stat_destroy(mip);
12572311Sseb 
12582311Sseb 	if (mip->mi_type != NULL) {
12593288Sseb 		atomic_dec_32(&mip->mi_type->mt_ref);
12602311Sseb 		mip->mi_type = NULL;
12612311Sseb 	}
12622311Sseb 
12632311Sseb 	if (mip->mi_pdata != NULL) {
12642311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
12652311Sseb 		mip->mi_pdata = NULL;
12662311Sseb 		mip->mi_pdata_size = 0;
12672311Sseb 	}
12682311Sseb 
12692311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
12702311Sseb 	rw_exit(&i_mac_impl_lock);
1271269Sericheng 	return (err);
12720Sstevel@tonic-gate }
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate int
12752311Sseb mac_unregister(mac_handle_t mh)
12760Sstevel@tonic-gate {
12772311Sseb 	int			err;
12782311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
12792311Sseb 	mod_hash_val_t		val;
12802311Sseb 	mac_multicst_addr_t	*p, *nextp;
1281269Sericheng 
12820Sstevel@tonic-gate 	/*
12830Sstevel@tonic-gate 	 * See if there are any other references to this mac_t (e.g., VLAN's).
12841852Syz147064 	 * If not, set mi_disabled to prevent any new VLAN's from being
12852311Sseb 	 * created while we're destroying this mac.
12860Sstevel@tonic-gate 	 */
1287269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
12880Sstevel@tonic-gate 	if (mip->mi_ref > 0) {
1289269Sericheng 		rw_exit(&i_mac_impl_lock);
12900Sstevel@tonic-gate 		return (EBUSY);
12910Sstevel@tonic-gate 	}
12921852Syz147064 	mip->mi_disabled = B_TRUE;
1293269Sericheng 	rw_exit(&i_mac_impl_lock);
12940Sstevel@tonic-gate 
12951852Syz147064 	/*
12961852Syz147064 	 * Wait for all taskqs which process the mac notifications to finish.
12971852Syz147064 	 */
12981852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
12991852Syz147064 	while (mip->mi_notify_ref != 0)
13001852Syz147064 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock);
13011852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
13021852Syz147064 
13032311Sseb 	if ((err = dls_destroy(mip->mi_name)) != 0) {
1304269Sericheng 		rw_enter(&i_mac_impl_lock, RW_WRITER);
13051852Syz147064 		mip->mi_disabled = B_FALSE;
1306269Sericheng 		rw_exit(&i_mac_impl_lock);
1307269Sericheng 		return (err);
13080Sstevel@tonic-gate 	}
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	/*
13112311Sseb 	 * Remove both style 1 and style 2 minor nodes
13120Sstevel@tonic-gate 	 */
13132311Sseb 	ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
13142311Sseb 	ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
13152311Sseb 
13162311Sseb 	ASSERT(!mip->mi_activelink);
13172311Sseb 
13182311Sseb 	mac_stat_destroy(mip);
13192311Sseb 
13202311Sseb 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
13212311Sseb 	    &val);
13222311Sseb 	ASSERT(mip == (mac_impl_t *)val);
13232311Sseb 
13242311Sseb 	ASSERT(i_mac_impl_count > 0);
13253288Sseb 	atomic_dec_32(&i_mac_impl_count);
13262311Sseb 
13272311Sseb 	if (mip->mi_pdata != NULL)
13282311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
13292311Sseb 	mip->mi_pdata = NULL;
13302311Sseb 	mip->mi_pdata_size = 0;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	/*
13332311Sseb 	 * Free the list of multicast addresses.
13340Sstevel@tonic-gate 	 */
13352311Sseb 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
13362311Sseb 		nextp = p->mma_nextp;
13372311Sseb 		kmem_free(p, sizeof (mac_multicst_addr_t));
13382311Sseb 	}
13392311Sseb 	mip->mi_mmap = NULL;
13400Sstevel@tonic-gate 
13412311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
13422311Sseb 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
13432311Sseb 	mip->mi_info.mi_unicst_addr = NULL;
13442311Sseb 
13453288Sseb 	atomic_dec_32(&mip->mi_type->mt_ref);
13462311Sseb 	mip->mi_type = NULL;
13472311Sseb 
13482311Sseb 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
13492311Sseb 
13502311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
13512311Sseb 
13520Sstevel@tonic-gate 	return (0);
13530Sstevel@tonic-gate }
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate void
13562311Sseb mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp)
13570Sstevel@tonic-gate {
13582311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
13590Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	/*
13620Sstevel@tonic-gate 	 * Call all registered receive functions.
13630Sstevel@tonic-gate 	 */
13640Sstevel@tonic-gate 	rw_enter(&mip->mi_rx_lock, RW_READER);
13650Sstevel@tonic-gate 	mrfp = mip->mi_mrfp;
13660Sstevel@tonic-gate 	if (mrfp == NULL) {
13670Sstevel@tonic-gate 		/* There are no registered receive functions. */
13680Sstevel@tonic-gate 		freemsgchain(bp);
13690Sstevel@tonic-gate 		rw_exit(&mip->mi_rx_lock);
13700Sstevel@tonic-gate 		return;
13710Sstevel@tonic-gate 	}
13720Sstevel@tonic-gate 	do {
13730Sstevel@tonic-gate 		mblk_t *recv_bp;
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 		if (mrfp->mrf_nextp != NULL) {
13760Sstevel@tonic-gate 			/* XXX Do we bump a counter if copymsgchain() fails? */
13770Sstevel@tonic-gate 			recv_bp = copymsgchain(bp);
13780Sstevel@tonic-gate 		} else {
13790Sstevel@tonic-gate 			recv_bp = bp;
13800Sstevel@tonic-gate 		}
13810Sstevel@tonic-gate 		if (recv_bp != NULL)
13820Sstevel@tonic-gate 			mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp);
13830Sstevel@tonic-gate 		mrfp = mrfp->mrf_nextp;
13840Sstevel@tonic-gate 	} while (mrfp != NULL);
13850Sstevel@tonic-gate 	rw_exit(&mip->mi_rx_lock);
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate /*
13890Sstevel@tonic-gate  * Transmit function -- ONLY used when there are registered loopback listeners.
13900Sstevel@tonic-gate  */
13910Sstevel@tonic-gate mblk_t *
13920Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp)
13930Sstevel@tonic-gate {
13940Sstevel@tonic-gate 	mac_impl_t	*mip = arg;
13950Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
13960Sstevel@tonic-gate 	mblk_t		*loop_bp, *resid_bp, *next_bp;
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	while (bp != NULL) {
13990Sstevel@tonic-gate 		next_bp = bp->b_next;
14000Sstevel@tonic-gate 		bp->b_next = NULL;
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate 		if ((loop_bp = copymsg(bp)) == NULL)
14030Sstevel@tonic-gate 			goto noresources;
14040Sstevel@tonic-gate 
14052311Sseb 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
14060Sstevel@tonic-gate 			ASSERT(resid_bp == bp);
14070Sstevel@tonic-gate 			freemsg(loop_bp);
14080Sstevel@tonic-gate 			goto noresources;
14090Sstevel@tonic-gate 		}
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 		rw_enter(&mip->mi_txloop_lock, RW_READER);
14120Sstevel@tonic-gate 		mtfp = mip->mi_mtfp;
141356Smeem 		while (mtfp != NULL && loop_bp != NULL) {
14140Sstevel@tonic-gate 			bp = loop_bp;
141556Smeem 
141656Smeem 			/* XXX counter bump if copymsg() fails? */
141756Smeem 			if (mtfp->mtf_nextp != NULL)
14180Sstevel@tonic-gate 				loop_bp = copymsg(bp);
141956Smeem 			else
142056Smeem 				loop_bp = NULL;
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
142356Smeem 			mtfp = mtfp->mtf_nextp;
14240Sstevel@tonic-gate 		}
142556Smeem 		rw_exit(&mip->mi_txloop_lock);
14260Sstevel@tonic-gate 
142756Smeem 		/*
142856Smeem 		 * It's possible we've raced with the disabling of promiscuous
142956Smeem 		 * mode, in which case we can discard our copy.
143056Smeem 		 */
143156Smeem 		if (loop_bp != NULL)
143256Smeem 			freemsg(loop_bp);
143356Smeem 
14340Sstevel@tonic-gate 		bp = next_bp;
14350Sstevel@tonic-gate 	}
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	return (NULL);
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate noresources:
14400Sstevel@tonic-gate 	bp->b_next = next_bp;
14410Sstevel@tonic-gate 	return (bp);
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate void
14452311Sseb mac_link_update(mac_handle_t mh, link_state_t link)
14460Sstevel@tonic-gate {
14472311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	/*
14500Sstevel@tonic-gate 	 * Save the link state.
14510Sstevel@tonic-gate 	 */
14522311Sseb 	mip->mi_linkstate = link;
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	/*
14550Sstevel@tonic-gate 	 * Send a MAC_NOTE_LINK notification.
14560Sstevel@tonic-gate 	 */
14570Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_LINK);
14580Sstevel@tonic-gate }
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate void
14612311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
14620Sstevel@tonic-gate {
14632311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
14640Sstevel@tonic-gate 
14652311Sseb 	if (mip->mi_type->mt_addr_length == 0)
14662311Sseb 		return;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	/*
14690Sstevel@tonic-gate 	 * Save the address.
14700Sstevel@tonic-gate 	 */
14712311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 	/*
14740Sstevel@tonic-gate 	 * Send a MAC_NOTE_UNICST notification.
14750Sstevel@tonic-gate 	 */
14760Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_UNICST);
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate void
14802311Sseb mac_tx_update(mac_handle_t mh)
14810Sstevel@tonic-gate {
14820Sstevel@tonic-gate 	/*
14830Sstevel@tonic-gate 	 * Send a MAC_NOTE_TX notification.
14840Sstevel@tonic-gate 	 */
14852311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate void
14892311Sseb mac_resource_update(mac_handle_t mh)
14900Sstevel@tonic-gate {
14910Sstevel@tonic-gate 	/*
14920Sstevel@tonic-gate 	 * Send a MAC_NOTE_RESOURCE notification.
14930Sstevel@tonic-gate 	 */
14942311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
14950Sstevel@tonic-gate }
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate mac_resource_handle_t
14982311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
14990Sstevel@tonic-gate {
15002311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
15010Sstevel@tonic-gate 	mac_resource_handle_t	mrh;
15020Sstevel@tonic-gate 	mac_resource_add_t	add;
15030Sstevel@tonic-gate 	void			*arg;
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	rw_enter(&mip->mi_resource_lock, RW_READER);
15060Sstevel@tonic-gate 	add = mip->mi_resource_add;
15070Sstevel@tonic-gate 	arg = mip->mi_resource_add_arg;
15080Sstevel@tonic-gate 
15091184Skrgopi 	if (add != NULL)
15101184Skrgopi 		mrh = add(arg, mrp);
15111184Skrgopi 	else
15121184Skrgopi 		mrh = NULL;
15130Sstevel@tonic-gate 	rw_exit(&mip->mi_resource_lock);
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	return (mrh);
15160Sstevel@tonic-gate }
15170Sstevel@tonic-gate 
15182311Sseb int
15192311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
15202311Sseb {
15212311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
15222311Sseb 
15232311Sseb 	/*
15242311Sseb 	 * Verify that the plugin supports MAC plugin data and that the
15252311Sseb 	 * supplied data is valid.
15262311Sseb 	 */
15272311Sseb 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
15282311Sseb 		return (EINVAL);
15292311Sseb 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
15302311Sseb 		return (EINVAL);
15312311Sseb 
15322311Sseb 	if (mip->mi_pdata != NULL)
15332311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
15342311Sseb 
15352311Sseb 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
15362311Sseb 	bcopy(mac_pdata, mip->mi_pdata, dsize);
15372311Sseb 	mip->mi_pdata_size = dsize;
15382311Sseb 
15392311Sseb 	/*
15402311Sseb 	 * Since the MAC plugin data is used to construct MAC headers that
15412311Sseb 	 * were cached in fast-path headers, we need to flush fast-path
15422311Sseb 	 * information for links associated with this mac.
15432311Sseb 	 */
15442311Sseb 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
15452311Sseb 	return (0);
15462311Sseb }
15472311Sseb 
15480Sstevel@tonic-gate void
15492311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
15500Sstevel@tonic-gate     boolean_t add)
15510Sstevel@tonic-gate {
15522311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
15530Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 	/*
15560Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
15570Sstevel@tonic-gate 	 * driver's m_multicst entry point.
15580Sstevel@tonic-gate 	 */
15590Sstevel@tonic-gate 	if (refresh == NULL) {
15602311Sseb 		refresh = mip->mi_multicst;
15612311Sseb 		arg = mip->mi_driver;
15620Sstevel@tonic-gate 	}
15630Sstevel@tonic-gate 	ASSERT(refresh != NULL);
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	/*
15660Sstevel@tonic-gate 	 * Walk the multicast address list and call the refresh function for
15670Sstevel@tonic-gate 	 * each address.
15680Sstevel@tonic-gate 	 */
15690Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
15700Sstevel@tonic-gate 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
15710Sstevel@tonic-gate 		refresh(arg, add, p->mma_addr);
15720Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
15730Sstevel@tonic-gate }
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate void
15762311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
15770Sstevel@tonic-gate {
15782311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
15790Sstevel@tonic-gate 	/*
15800Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
15812311Sseb 	 * driver's mi_unicst entry point.
15820Sstevel@tonic-gate 	 */
15830Sstevel@tonic-gate 	if (refresh == NULL) {
15842311Sseb 		refresh = mip->mi_unicst;
15852311Sseb 		arg = mip->mi_driver;
15860Sstevel@tonic-gate 	}
15870Sstevel@tonic-gate 	ASSERT(refresh != NULL);
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 	/*
15900Sstevel@tonic-gate 	 * Call the refresh function with the current unicast address.
15910Sstevel@tonic-gate 	 */
15920Sstevel@tonic-gate 	refresh(arg, mip->mi_addr);
15930Sstevel@tonic-gate }
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate void
15962311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
15970Sstevel@tonic-gate {
15982311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 	/*
16010Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
16020Sstevel@tonic-gate 	 * driver's m_promisc entry point.
16030Sstevel@tonic-gate 	 */
16040Sstevel@tonic-gate 	if (refresh == NULL) {
16052311Sseb 		refresh = mip->mi_setpromisc;
16062311Sseb 		arg = mip->mi_driver;
16070Sstevel@tonic-gate 	}
16080Sstevel@tonic-gate 	ASSERT(refresh != NULL);
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	/*
16110Sstevel@tonic-gate 	 * Call the refresh function with the current promiscuity.
16120Sstevel@tonic-gate 	 */
16130Sstevel@tonic-gate 	refresh(arg, (mip->mi_devpromisc != 0));
16140Sstevel@tonic-gate }
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate boolean_t
16170Sstevel@tonic-gate mac_active_set(mac_handle_t mh)
16180Sstevel@tonic-gate {
16190Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
16220Sstevel@tonic-gate 	if (mip->mi_activelink) {
16230Sstevel@tonic-gate 		mutex_exit(&mip->mi_activelink_lock);
16240Sstevel@tonic-gate 		return (B_FALSE);
16250Sstevel@tonic-gate 	}
16260Sstevel@tonic-gate 	mip->mi_activelink = B_TRUE;
16270Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
16280Sstevel@tonic-gate 	return (B_TRUE);
16290Sstevel@tonic-gate }
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate void
16320Sstevel@tonic-gate mac_active_clear(mac_handle_t mh)
16330Sstevel@tonic-gate {
16340Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
16370Sstevel@tonic-gate 	ASSERT(mip->mi_activelink);
16380Sstevel@tonic-gate 	mip->mi_activelink = B_FALSE;
16390Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
16400Sstevel@tonic-gate }
1641269Sericheng 
1642269Sericheng /*
1643269Sericheng  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
1644269Sericheng  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
1645269Sericheng  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
1646269Sericheng  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
1647269Sericheng  * cannot disappear while we are accessing it.
1648269Sericheng  */
1649269Sericheng typedef struct i_mac_info_state_s {
1650269Sericheng 	const char	*mi_name;
1651269Sericheng 	mac_info_t	*mi_infop;
1652269Sericheng } i_mac_info_state_t;
1653269Sericheng 
1654269Sericheng /*ARGSUSED*/
1655269Sericheng static uint_t
1656269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1657269Sericheng {
1658269Sericheng 	i_mac_info_state_t	*statep = arg;
1659269Sericheng 	mac_impl_t		*mip = (mac_impl_t *)val;
1660269Sericheng 
16611852Syz147064 	if (mip->mi_disabled)
1662269Sericheng 		return (MH_WALK_CONTINUE);
1663269Sericheng 
1664269Sericheng 	if (strcmp(statep->mi_name,
16652311Sseb 	    ddi_driver_name(mip->mi_dip)) != 0)
1666269Sericheng 		return (MH_WALK_CONTINUE);
1667269Sericheng 
16682311Sseb 	statep->mi_infop = &mip->mi_info;
1669269Sericheng 	return (MH_WALK_TERMINATE);
1670269Sericheng }
1671269Sericheng 
1672269Sericheng boolean_t
1673269Sericheng mac_info_get(const char *name, mac_info_t *minfop)
1674269Sericheng {
1675269Sericheng 	i_mac_info_state_t	state;
1676269Sericheng 
1677269Sericheng 	rw_enter(&i_mac_impl_lock, RW_READER);
1678269Sericheng 	state.mi_name = name;
1679269Sericheng 	state.mi_infop = NULL;
1680269Sericheng 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
1681269Sericheng 	if (state.mi_infop == NULL) {
1682269Sericheng 		rw_exit(&i_mac_impl_lock);
1683269Sericheng 		return (B_FALSE);
1684269Sericheng 	}
1685269Sericheng 	*minfop = *state.mi_infop;
1686269Sericheng 	rw_exit(&i_mac_impl_lock);
1687269Sericheng 	return (B_TRUE);
1688269Sericheng }
1689269Sericheng 
16902311Sseb boolean_t
16912311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
16922311Sseb {
16932311Sseb 	mac_impl_t *mip = (mac_impl_t *)mh;
16942311Sseb 
16952311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
16962311Sseb 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
16972311Sseb 	else
16982311Sseb 		return (B_FALSE);
16992311Sseb }
17002311Sseb 
17012311Sseb boolean_t
17022311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
17032311Sseb {
17042311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17052311Sseb 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
17062311Sseb 	    mip->mi_pdata));
17072311Sseb }
17082311Sseb 
17092311Sseb mblk_t *
17102311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
17112311Sseb     size_t extra_len)
17122311Sseb {
17132311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17142311Sseb 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
17152311Sseb 	    mip->mi_pdata, payload, extra_len));
17162311Sseb }
17172311Sseb 
17182311Sseb int
17192311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
17202311Sseb {
17212311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17222311Sseb 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
17232311Sseb 	    mhip));
17242311Sseb }
17252311Sseb 
17262311Sseb mblk_t *
17272311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp)
17282311Sseb {
17292311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17302311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
17312311Sseb 		if (DB_REF(mp) > 1) {
17322311Sseb 			mblk_t *newmp = copymsg(mp);
17332760Sdg199075 			if (newmp == NULL)
17342760Sdg199075 				return (NULL);
17352311Sseb 			freemsg(mp);
17362311Sseb 			mp = newmp;
17372311Sseb 		}
17382311Sseb 		return (mip->mi_type->mt_ops.mtops_header_cook(mp,
17392311Sseb 		    mip->mi_pdata));
17402311Sseb 	}
17412311Sseb 	return (mp);
17422311Sseb }
17432311Sseb 
17442311Sseb mblk_t *
17452311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp)
17462311Sseb {
17472311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17482311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
17492311Sseb 		if (DB_REF(mp) > 1) {
17502311Sseb 			mblk_t *newmp = copymsg(mp);
17512760Sdg199075 			if (newmp == NULL)
17522760Sdg199075 				return (NULL);
17532311Sseb 			freemsg(mp);
17542311Sseb 			mp = newmp;
17552311Sseb 		}
17562311Sseb 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
17572311Sseb 		    mip->mi_pdata));
17582311Sseb 	}
17592311Sseb 	return (mp);
17602311Sseb }
17612311Sseb 
1762269Sericheng void
1763269Sericheng mac_init_ops(struct dev_ops *ops, const char *name)
1764269Sericheng {
1765269Sericheng 	dld_init_ops(ops, name);
1766269Sericheng }
1767269Sericheng 
1768269Sericheng void
1769269Sericheng mac_fini_ops(struct dev_ops *ops)
1770269Sericheng {
1771269Sericheng 	dld_fini_ops(ops);
1772269Sericheng }
17732311Sseb 
17742311Sseb /*
17752311Sseb  * MAC Type Plugin functions.
17762311Sseb  */
17772311Sseb 
17782311Sseb mactype_register_t *
17792311Sseb mactype_alloc(uint_t mactype_version)
17802311Sseb {
17812311Sseb 	mactype_register_t *mtrp;
17822311Sseb 
17832311Sseb 	/*
17842311Sseb 	 * Make sure there isn't a version mismatch between the plugin and
17852311Sseb 	 * the framework.  In the future, if multiple versions are
17862311Sseb 	 * supported, this check could become more sophisticated.
17872311Sseb 	 */
17882311Sseb 	if (mactype_version != MACTYPE_VERSION)
17892311Sseb 		return (NULL);
17902311Sseb 
17912311Sseb 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
17922311Sseb 	mtrp->mtr_version = mactype_version;
17932311Sseb 	return (mtrp);
17942311Sseb }
17952311Sseb 
17962311Sseb void
17972311Sseb mactype_free(mactype_register_t *mtrp)
17982311Sseb {
17992311Sseb 	kmem_free(mtrp, sizeof (mactype_register_t));
18002311Sseb }
18012311Sseb 
18022311Sseb int
18032311Sseb mactype_register(mactype_register_t *mtrp)
18042311Sseb {
18052311Sseb 	mactype_t	*mtp;
18062311Sseb 	mactype_ops_t	*ops = mtrp->mtr_ops;
18072311Sseb 
18082311Sseb 	/* Do some sanity checking before we register this MAC type. */
18092311Sseb 	if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0)
18102311Sseb 		return (EINVAL);
18112311Sseb 
18122311Sseb 	/*
18132311Sseb 	 * Verify that all mandatory callbacks are set in the ops
18142311Sseb 	 * vector.
18152311Sseb 	 */
18162311Sseb 	if (ops->mtops_unicst_verify == NULL ||
18172311Sseb 	    ops->mtops_multicst_verify == NULL ||
18182311Sseb 	    ops->mtops_sap_verify == NULL ||
18192311Sseb 	    ops->mtops_header == NULL ||
18202311Sseb 	    ops->mtops_header_info == NULL) {
18212311Sseb 		return (EINVAL);
18222311Sseb 	}
18232311Sseb 
18242311Sseb 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
18252311Sseb 	mtp->mt_ident = mtrp->mtr_ident;
18262311Sseb 	mtp->mt_ops = *ops;
18272311Sseb 	mtp->mt_type = mtrp->mtr_mactype;
18283147Sxc151355 	mtp->mt_nativetype = mtrp->mtr_nativetype;
18292311Sseb 	mtp->mt_addr_length = mtrp->mtr_addrlen;
18302311Sseb 	if (mtrp->mtr_brdcst_addr != NULL) {
18312311Sseb 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
18322311Sseb 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
18332311Sseb 		    mtrp->mtr_addrlen);
18342311Sseb 	}
18352311Sseb 
18362311Sseb 	mtp->mt_stats = mtrp->mtr_stats;
18372311Sseb 	mtp->mt_statcount = mtrp->mtr_statcount;
18382311Sseb 
18392311Sseb 	if (mod_hash_insert(i_mactype_hash,
18402311Sseb 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
18412311Sseb 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
18422311Sseb 		kmem_free(mtp, sizeof (*mtp));
18432311Sseb 		return (EEXIST);
18442311Sseb 	}
18452311Sseb 	return (0);
18462311Sseb }
18472311Sseb 
18482311Sseb int
18492311Sseb mactype_unregister(const char *ident)
18502311Sseb {
18512311Sseb 	mactype_t	*mtp;
18522311Sseb 	mod_hash_val_t	val;
18532311Sseb 	int 		err;
18542311Sseb 
18552311Sseb 	/*
18562311Sseb 	 * Let's not allow MAC drivers to use this plugin while we're
18573288Sseb 	 * trying to unregister it.  Holding i_mactype_lock also prevents a
18583288Sseb 	 * plugin from unregistering while a MAC driver is attempting to
18593288Sseb 	 * hold a reference to it in i_mactype_getplugin().
18602311Sseb 	 */
18613288Sseb 	mutex_enter(&i_mactype_lock);
18622311Sseb 
18632311Sseb 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
18642311Sseb 	    (mod_hash_val_t *)&mtp)) != 0) {
18652311Sseb 		/* A plugin is trying to unregister, but it never registered. */
18663288Sseb 		err = ENXIO;
18673288Sseb 		goto done;
18682311Sseb 	}
18692311Sseb 
18703288Sseb 	if (mtp->mt_ref != 0) {
18713288Sseb 		err = EBUSY;
18723288Sseb 		goto done;
18732311Sseb 	}
18742311Sseb 
18752311Sseb 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
18762311Sseb 	ASSERT(err == 0);
18772311Sseb 	if (err != 0) {
18782311Sseb 		/* This should never happen, thus the ASSERT() above. */
18793288Sseb 		err = EINVAL;
18803288Sseb 		goto done;
18812311Sseb 	}
18822311Sseb 	ASSERT(mtp == (mactype_t *)val);
18832311Sseb 
18842311Sseb 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
18852311Sseb 	kmem_free(mtp, sizeof (mactype_t));
18863288Sseb done:
18873288Sseb 	mutex_exit(&i_mactype_lock);
18883288Sseb 	return (err);
18892311Sseb }
1890*3448Sdh155122 
1891*3448Sdh155122 int
1892*3448Sdh155122 mac_vlan_create(mac_handle_t mh, const char *name, minor_t minor)
1893*3448Sdh155122 {
1894*3448Sdh155122 	mac_impl_t		*mip = (mac_impl_t *)mh;
1895*3448Sdh155122 
1896*3448Sdh155122 	/* Create a style-1 DLPI device */
1897*3448Sdh155122 	if (ddi_create_minor_node(mip->mi_dip, (char *)name, S_IFCHR, minor,
1898*3448Sdh155122 	    DDI_NT_NET, 0) != DDI_SUCCESS) {
1899*3448Sdh155122 		return (-1);
1900*3448Sdh155122 	}
1901*3448Sdh155122 	return (0);
1902*3448Sdh155122 }
1903*3448Sdh155122 
1904*3448Sdh155122 void
1905*3448Sdh155122 mac_vlan_remove(mac_handle_t mh, const char *name)
1906*3448Sdh155122 {
1907*3448Sdh155122 	mac_impl_t		*mip = (mac_impl_t *)mh;
1908*3448Sdh155122 	dev_info_t		*dipp;
1909*3448Sdh155122 
1910*3448Sdh155122 	ddi_remove_minor_node(mip->mi_dip, (char *)name);
1911*3448Sdh155122 	dipp = ddi_get_parent(mip->mi_dip);
1912*3448Sdh155122 	(void) devfs_clean(dipp, NULL, 0);
1913*3448Sdh155122 }
1914