xref: /onnv-gate/usr/src/uts/common/io/mac/mac.c (revision 4913:8d95fa5f1def)
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 /*
223448Sdh155122  * 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>
453448Sdh155122 #include <sys/fs/dv_node.h>
463288Sseb #include <sys/atomic.h>
47*4913Sethindra #include <sys/sdt.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #define	IMPL_HASHSZ	67	/* prime */
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static kmem_cache_t	*i_mac_impl_cachep;
52269Sericheng static mod_hash_t	*i_mac_impl_hash;
53269Sericheng krwlock_t		i_mac_impl_lock;
54269Sericheng uint_t			i_mac_impl_count;
550Sstevel@tonic-gate 
562311Sseb #define	MACTYPE_KMODDIR	"mac"
572311Sseb #define	MACTYPE_HASHSZ	67
582311Sseb static mod_hash_t	*i_mactype_hash;
593288Sseb /*
603288Sseb  * i_mactype_lock synchronizes threads that obtain references to mactype_t
613288Sseb  * structures through i_mactype_getplugin().
623288Sseb  */
633288Sseb static kmutex_t		i_mactype_lock;
642311Sseb 
651852Syz147064 static void i_mac_notify_task(void *);
661852Syz147064 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * Private functions.
690Sstevel@tonic-gate  */
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*ARGSUSED*/
720Sstevel@tonic-gate static int
730Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag)
740Sstevel@tonic-gate {
750Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	bzero(buf, sizeof (mac_impl_t));
780Sstevel@tonic-gate 
792311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
820Sstevel@tonic-gate 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
830Sstevel@tonic-gate 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
840Sstevel@tonic-gate 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
850Sstevel@tonic-gate 	rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL);
860Sstevel@tonic-gate 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
870Sstevel@tonic-gate 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
881852Syz147064 	mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL);
891852Syz147064 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL);
90*4913Sethindra 	mutex_init(&mip->mi_lock, NULL, MUTEX_DRIVER, NULL);
91*4913Sethindra 	cv_init(&mip->mi_rx_cv, NULL, CV_DRIVER, NULL);
920Sstevel@tonic-gate 	return (0);
930Sstevel@tonic-gate }
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /*ARGSUSED*/
960Sstevel@tonic-gate static void
970Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	ASSERT(mip->mi_ref == 0);
1020Sstevel@tonic-gate 	ASSERT(mip->mi_active == 0);
1032311Sseb 	ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
1040Sstevel@tonic-gate 	ASSERT(mip->mi_devpromisc == 0);
1050Sstevel@tonic-gate 	ASSERT(mip->mi_promisc == 0);
1060Sstevel@tonic-gate 	ASSERT(mip->mi_mmap == NULL);
1070Sstevel@tonic-gate 	ASSERT(mip->mi_mnfp == NULL);
1080Sstevel@tonic-gate 	ASSERT(mip->mi_resource_add == NULL);
1090Sstevel@tonic-gate 	ASSERT(mip->mi_ksp == NULL);
1102311Sseb 	ASSERT(mip->mi_kstat_count == 0);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	rw_destroy(&mip->mi_state_lock);
1130Sstevel@tonic-gate 	rw_destroy(&mip->mi_data_lock);
1140Sstevel@tonic-gate 	rw_destroy(&mip->mi_notify_lock);
1150Sstevel@tonic-gate 	rw_destroy(&mip->mi_rx_lock);
1160Sstevel@tonic-gate 	rw_destroy(&mip->mi_txloop_lock);
1170Sstevel@tonic-gate 	rw_destroy(&mip->mi_resource_lock);
1180Sstevel@tonic-gate 	mutex_destroy(&mip->mi_activelink_lock);
1191852Syz147064 	mutex_destroy(&mip->mi_notify_ref_lock);
1201852Syz147064 	cv_destroy(&mip->mi_notify_cv);
121*4913Sethindra 	mutex_destroy(&mip->mi_lock);
122*4913Sethindra 	cv_destroy(&mip->mi_rx_cv);
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate static void
1260Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
1270Sstevel@tonic-gate {
1281852Syz147064 	mac_notify_task_arg_t	*mnta;
1291852Syz147064 
1301852Syz147064 	rw_enter(&i_mac_impl_lock, RW_READER);
1311852Syz147064 	if (mip->mi_disabled)
1321852Syz147064 		goto exit;
1331852Syz147064 
1341852Syz147064 	if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) {
1351852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory "
1361852Syz147064 		    "allocation failed", mip->mi_name, type);
1371852Syz147064 		goto exit;
1381852Syz147064 	}
1391852Syz147064 
1401852Syz147064 	mnta->mnt_mip = mip;
1411852Syz147064 	mnta->mnt_type = type;
1421852Syz147064 
1431852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
1441852Syz147064 	mip->mi_notify_ref++;
1451852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
1461852Syz147064 
1471852Syz147064 	rw_exit(&i_mac_impl_lock);
1481852Syz147064 
1491852Syz147064 	if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta,
1501852Syz147064 	    TQ_NOSLEEP) == NULL) {
1511852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch "
1521852Syz147064 		    "failed", mip->mi_name, type);
1531852Syz147064 
1541852Syz147064 		mutex_enter(&mip->mi_notify_ref_lock);
1551852Syz147064 		if (--mip->mi_notify_ref == 0)
1561852Syz147064 			cv_signal(&mip->mi_notify_cv);
1571852Syz147064 		mutex_exit(&mip->mi_notify_ref_lock);
1581852Syz147064 
1591852Syz147064 		kmem_free(mnta, sizeof (*mnta));
1601852Syz147064 	}
1611852Syz147064 	return;
1621852Syz147064 
1631852Syz147064 exit:
1641852Syz147064 	rw_exit(&i_mac_impl_lock);
1651852Syz147064 }
1661852Syz147064 
1671852Syz147064 static void
1684403Sgd78059 i_mac_log_link_state(mac_impl_t *mip)
1694403Sgd78059 {
1704403Sgd78059 	/*
1714403Sgd78059 	 * If no change, then it is not interesting.
1724403Sgd78059 	 */
1734403Sgd78059 	if (mip->mi_lastlinkstate == mip->mi_linkstate)
1744403Sgd78059 		return;
1754403Sgd78059 
1764403Sgd78059 	switch (mip->mi_linkstate) {
1774403Sgd78059 	case LINK_STATE_UP:
1784403Sgd78059 		if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) {
1794403Sgd78059 			char det[200];
1804403Sgd78059 
1814403Sgd78059 			mip->mi_type->mt_ops.mtops_link_details(det,
1824403Sgd78059 			    sizeof (det), (mac_handle_t)mip, mip->mi_pdata);
1834403Sgd78059 
1844403Sgd78059 			cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det);
1854403Sgd78059 		} else {
1864403Sgd78059 			cmn_err(CE_NOTE, "!%s link up", mip->mi_name);
1874403Sgd78059 		}
1884403Sgd78059 		break;
1894403Sgd78059 
1904403Sgd78059 	case LINK_STATE_DOWN:
1914403Sgd78059 		/*
1924403Sgd78059 		 * Only transitions from UP to DOWN are interesting
1934403Sgd78059 		 */
1944403Sgd78059 		if (mip->mi_lastlinkstate != LINK_STATE_UNKNOWN)
1954403Sgd78059 			cmn_err(CE_NOTE, "!%s link down", mip->mi_name);
1964403Sgd78059 		break;
1974403Sgd78059 
1984403Sgd78059 	case LINK_STATE_UNKNOWN:
1994403Sgd78059 		/*
2004403Sgd78059 		 * This case is normally not interesting.
2014403Sgd78059 		 */
2024403Sgd78059 		break;
2034403Sgd78059 	}
2044403Sgd78059 	mip->mi_lastlinkstate = mip->mi_linkstate;
2054403Sgd78059 }
2064403Sgd78059 
2074403Sgd78059 static void
2081852Syz147064 i_mac_notify_task(void *notify_arg)
2091852Syz147064 {
2101852Syz147064 	mac_notify_task_arg_t	*mnta = (mac_notify_task_arg_t *)notify_arg;
2111852Syz147064 	mac_impl_t		*mip;
2121852Syz147064 	mac_notify_type_t	type;
2130Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
2140Sstevel@tonic-gate 	mac_notify_t		notify;
2150Sstevel@tonic-gate 	void			*arg;
2160Sstevel@tonic-gate 
2171852Syz147064 	mip = mnta->mnt_mip;
2181852Syz147064 	type = mnta->mnt_type;
2191852Syz147064 	kmem_free(mnta, sizeof (*mnta));
2201852Syz147064 
2210Sstevel@tonic-gate 	/*
2224403Sgd78059 	 * Log it.
2234403Sgd78059 	 */
2244403Sgd78059 	if (type == MAC_NOTE_LINK)
2254403Sgd78059 		i_mac_log_link_state(mip);
2264403Sgd78059 
2274403Sgd78059 	/*
2280Sstevel@tonic-gate 	 * Walk the list of notifications.
2290Sstevel@tonic-gate 	 */
2301852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_READER);
2310Sstevel@tonic-gate 	for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) {
2320Sstevel@tonic-gate 		notify = mnfp->mnf_fn;
2330Sstevel@tonic-gate 		arg = mnfp->mnf_arg;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 		ASSERT(notify != NULL);
2360Sstevel@tonic-gate 		notify(arg, type);
2370Sstevel@tonic-gate 	}
2381852Syz147064 	rw_exit(&mip->mi_notify_lock);
2391852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
2401852Syz147064 	if (--mip->mi_notify_ref == 0)
2411852Syz147064 		cv_signal(&mip->mi_notify_cv);
2421852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate 
2452311Sseb static mactype_t *
2463288Sseb i_mactype_getplugin(const char *pname)
2472311Sseb {
2482311Sseb 	mactype_t	*mtype = NULL;
2492311Sseb 	boolean_t	tried_modload = B_FALSE;
2502311Sseb 
2513288Sseb 	mutex_enter(&i_mactype_lock);
2523288Sseb 
2532311Sseb find_registered_mactype:
2543288Sseb 	if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname,
2553288Sseb 	    (mod_hash_val_t *)&mtype) != 0) {
2563288Sseb 		if (!tried_modload) {
2573288Sseb 			/*
2583288Sseb 			 * If the plugin has not yet been loaded, then
2593288Sseb 			 * attempt to load it now.  If modload() succeeds,
2603288Sseb 			 * the plugin should have registered using
2613288Sseb 			 * mactype_register(), in which case we can go back
2623288Sseb 			 * and attempt to find it again.
2633288Sseb 			 */
2643288Sseb 			if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) {
2653288Sseb 				tried_modload = B_TRUE;
2663288Sseb 				goto find_registered_mactype;
2673288Sseb 			}
2683288Sseb 		}
2693288Sseb 	} else {
2702311Sseb 		/*
2713288Sseb 		 * Note that there's no danger that the plugin we've loaded
2723288Sseb 		 * could be unloaded between the modload() step and the
2733288Sseb 		 * reference count bump here, as we're holding
2743288Sseb 		 * i_mactype_lock, which mactype_unregister() also holds.
2752311Sseb 		 */
2763288Sseb 		atomic_inc_32(&mtype->mt_ref);
2772311Sseb 	}
2782311Sseb 
2793288Sseb 	mutex_exit(&i_mactype_lock);
2803288Sseb 	return (mtype);
2812311Sseb }
2822311Sseb 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * Module initialization functions.
2850Sstevel@tonic-gate  */
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate void
2880Sstevel@tonic-gate mac_init(void)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
2912311Sseb 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
2922311Sseb 	    NULL, NULL, NULL, 0);
2930Sstevel@tonic-gate 	ASSERT(i_mac_impl_cachep != NULL);
2940Sstevel@tonic-gate 
295269Sericheng 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
296269Sericheng 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
297269Sericheng 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
298269Sericheng 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
299269Sericheng 	i_mac_impl_count = 0;
3002311Sseb 
3012311Sseb 	i_mactype_hash = mod_hash_create_extended("mactype_hash",
3022311Sseb 	    MACTYPE_HASHSZ,
3032311Sseb 	    mod_hash_null_keydtor, mod_hash_null_valdtor,
3042311Sseb 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate int
3080Sstevel@tonic-gate mac_fini(void)
3090Sstevel@tonic-gate {
310269Sericheng 	if (i_mac_impl_count > 0)
311269Sericheng 		return (EBUSY);
3120Sstevel@tonic-gate 
313269Sericheng 	mod_hash_destroy_hash(i_mac_impl_hash);
314269Sericheng 	rw_destroy(&i_mac_impl_lock);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	kmem_cache_destroy(i_mac_impl_cachep);
3172311Sseb 
3182311Sseb 	mod_hash_destroy_hash(i_mactype_hash);
3190Sstevel@tonic-gate 	return (0);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate /*
3230Sstevel@tonic-gate  * Client functions.
3240Sstevel@tonic-gate  */
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate int
3272311Sseb mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	char		driver[MAXNAMELEN];
3300Sstevel@tonic-gate 	uint_t		instance;
3310Sstevel@tonic-gate 	major_t		major;
3320Sstevel@tonic-gate 	dev_info_t	*dip;
3330Sstevel@tonic-gate 	mac_impl_t	*mip;
3340Sstevel@tonic-gate 	int		err;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	/*
3370Sstevel@tonic-gate 	 * Check the device name length to make sure it won't overflow our
3380Sstevel@tonic-gate 	 * buffer.
3390Sstevel@tonic-gate 	 */
3402311Sseb 	if (strlen(macname) >= MAXNAMELEN)
3410Sstevel@tonic-gate 		return (EINVAL);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	/*
3440Sstevel@tonic-gate 	 * Split the device name into driver and instance components.
3450Sstevel@tonic-gate 	 */
3462311Sseb 	if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS)
3470Sstevel@tonic-gate 		return (EINVAL);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	/*
3500Sstevel@tonic-gate 	 * Get the major number of the driver.
3510Sstevel@tonic-gate 	 */
3520Sstevel@tonic-gate 	if ((major = ddi_name_to_major(driver)) == (major_t)-1)
3530Sstevel@tonic-gate 		return (EINVAL);
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	/*
3560Sstevel@tonic-gate 	 * Hold the given instance to prevent it from being detached.
357269Sericheng 	 * This will also attach the instance if it is not currently attached.
358269Sericheng 	 * Currently we ensure that mac_register() (called by the driver's
359269Sericheng 	 * attach entry point) and all code paths under it cannot possibly
360269Sericheng 	 * call mac_open() because this would lead to a recursive attach
361269Sericheng 	 * panic.
3620Sstevel@tonic-gate 	 */
3632311Sseb 	if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL)
3640Sstevel@tonic-gate 		return (EINVAL);
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	/*
3670Sstevel@tonic-gate 	 * Look up its entry in the global hash table.
3680Sstevel@tonic-gate 	 */
3690Sstevel@tonic-gate again:
370269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
3712311Sseb 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
372269Sericheng 	    (mod_hash_val_t *)&mip);
373269Sericheng 	if (err != 0) {
374269Sericheng 		err = ENOENT;
3750Sstevel@tonic-gate 		goto failed;
376269Sericheng 	}
3770Sstevel@tonic-gate 
3781852Syz147064 	if (mip->mi_disabled) {
379269Sericheng 		rw_exit(&i_mac_impl_lock);
3800Sstevel@tonic-gate 		goto again;
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	mip->mi_ref++;
384269Sericheng 	rw_exit(&i_mac_impl_lock);
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	*mhp = (mac_handle_t)mip;
3870Sstevel@tonic-gate 	return (0);
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate failed:
390269Sericheng 	rw_exit(&i_mac_impl_lock);
3910Sstevel@tonic-gate 	ddi_release_devi(dip);
3920Sstevel@tonic-gate 	return (err);
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate void
3960Sstevel@tonic-gate mac_close(mac_handle_t mh)
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
3992311Sseb 	dev_info_t	*dip = mip->mi_dip;
4000Sstevel@tonic-gate 
401269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	ASSERT(mip->mi_ref != 0);
4040Sstevel@tonic-gate 	if (--mip->mi_ref == 0) {
4050Sstevel@tonic-gate 		ASSERT(!mip->mi_activelink);
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 	ddi_release_devi(dip);
408269Sericheng 	rw_exit(&i_mac_impl_lock);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate const mac_info_t *
4120Sstevel@tonic-gate mac_info(mac_handle_t mh)
4130Sstevel@tonic-gate {
4142311Sseb 	return (&((mac_impl_t *)mh)->mi_info);
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate 
417269Sericheng dev_info_t *
418269Sericheng mac_devinfo_get(mac_handle_t mh)
419269Sericheng {
4202311Sseb 	return (((mac_impl_t *)mh)->mi_dip);
421269Sericheng }
422269Sericheng 
4230Sstevel@tonic-gate uint64_t
4242311Sseb mac_stat_get(mac_handle_t mh, uint_t stat)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4272311Sseb 	uint64_t	val;
4282311Sseb 	int		ret;
4290Sstevel@tonic-gate 
4302311Sseb 	/*
4312311Sseb 	 * The range of stat determines where it is maintained.  Stat
4322311Sseb 	 * values from 0 up to (but not including) MAC_STAT_MIN are
4332311Sseb 	 * mainteined by the mac module itself.  Everything else is
4342311Sseb 	 * maintained by the driver.
4352311Sseb 	 */
4362311Sseb 	if (stat < MAC_STAT_MIN) {
4372311Sseb 		/* These stats are maintained by the mac module itself. */
4382311Sseb 		switch (stat) {
4392311Sseb 		case MAC_STAT_LINK_STATE:
4402311Sseb 			return (mip->mi_linkstate);
4412311Sseb 		case MAC_STAT_LINK_UP:
4422311Sseb 			return (mip->mi_linkstate == LINK_STATE_UP);
4432311Sseb 		case MAC_STAT_PROMISC:
4442311Sseb 			return (mip->mi_devpromisc != 0);
4452311Sseb 		default:
4462311Sseb 			ASSERT(B_FALSE);
4472311Sseb 		}
4482311Sseb 	}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	/*
4510Sstevel@tonic-gate 	 * Call the driver to get the given statistic.
4520Sstevel@tonic-gate 	 */
4532311Sseb 	ret = mip->mi_getstat(mip->mi_driver, stat, &val);
4542311Sseb 	if (ret != 0) {
4552311Sseb 		/*
4562311Sseb 		 * The driver doesn't support this statistic.  Get the
4572311Sseb 		 * statistic's default value.
4582311Sseb 		 */
4592311Sseb 		val = mac_stat_default(mip, stat);
4602311Sseb 	}
4612311Sseb 	return (val);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate int
4650Sstevel@tonic-gate mac_start(mac_handle_t mh)
4660Sstevel@tonic-gate {
4670Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4680Sstevel@tonic-gate 	int		err;
4690Sstevel@tonic-gate 
4702311Sseb 	ASSERT(mip->mi_start != NULL);
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/*
4750Sstevel@tonic-gate 	 * Check whether the device is already started.
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	if (mip->mi_active++ != 0) {
4780Sstevel@tonic-gate 		/*
4790Sstevel@tonic-gate 		 * It's already started so there's nothing more to do.
4800Sstevel@tonic-gate 		 */
4810Sstevel@tonic-gate 		err = 0;
4820Sstevel@tonic-gate 		goto done;
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	/*
4860Sstevel@tonic-gate 	 * Start the device.
4870Sstevel@tonic-gate 	 */
4882311Sseb 	if ((err = mip->mi_start(mip->mi_driver)) != 0)
4890Sstevel@tonic-gate 		--mip->mi_active;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate done:
4920Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
4930Sstevel@tonic-gate 	return (err);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate void
4970Sstevel@tonic-gate mac_stop(mac_handle_t mh)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
5000Sstevel@tonic-gate 
5012311Sseb 	ASSERT(mip->mi_stop != NULL);
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/*
5060Sstevel@tonic-gate 	 * Check whether the device is still needed.
5070Sstevel@tonic-gate 	 */
5080Sstevel@tonic-gate 	ASSERT(mip->mi_active != 0);
5090Sstevel@tonic-gate 	if (--mip->mi_active != 0) {
5100Sstevel@tonic-gate 		/*
5110Sstevel@tonic-gate 		 * It's still needed so there's nothing more to do.
5120Sstevel@tonic-gate 		 */
5130Sstevel@tonic-gate 		goto done;
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	/*
5170Sstevel@tonic-gate 	 * Stop the device.
5180Sstevel@tonic-gate 	 */
5192311Sseb 	mip->mi_stop(mip->mi_driver);
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate done:
5220Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate int
5260Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
5270Sstevel@tonic-gate {
5280Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
5290Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
5300Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
5310Sstevel@tonic-gate 	int			err;
5320Sstevel@tonic-gate 
5332311Sseb 	ASSERT(mip->mi_multicst != NULL);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	/*
5360Sstevel@tonic-gate 	 * Verify the address.
5370Sstevel@tonic-gate 	 */
5382311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
5392311Sseb 	    mip->mi_pdata)) != 0) {
5402311Sseb 		return (err);
5412311Sseb 	}
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	/*
5440Sstevel@tonic-gate 	 * Check whether the given address is already enabled.
5450Sstevel@tonic-gate 	 */
5460Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
5470Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
5482311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
5492311Sseb 		    0) {
5500Sstevel@tonic-gate 			/*
5510Sstevel@tonic-gate 			 * The address is already enabled so just bump the
5520Sstevel@tonic-gate 			 * reference count.
5530Sstevel@tonic-gate 			 */
5540Sstevel@tonic-gate 			p->mma_ref++;
5550Sstevel@tonic-gate 			err = 0;
5560Sstevel@tonic-gate 			goto done;
5570Sstevel@tonic-gate 		}
5580Sstevel@tonic-gate 	}
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	/*
5610Sstevel@tonic-gate 	 * Allocate a new list entry.
5620Sstevel@tonic-gate 	 */
5630Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
5640Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
5650Sstevel@tonic-gate 		err = ENOMEM;
5660Sstevel@tonic-gate 		goto done;
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	/*
5700Sstevel@tonic-gate 	 * Enable a new multicast address.
5710Sstevel@tonic-gate 	 */
5722311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) {
5730Sstevel@tonic-gate 		kmem_free(p, sizeof (mac_multicst_addr_t));
5740Sstevel@tonic-gate 		goto done;
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	/*
5780Sstevel@tonic-gate 	 * Add the address to the list of enabled addresses.
5790Sstevel@tonic-gate 	 */
5802311Sseb 	bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length);
5810Sstevel@tonic-gate 	p->mma_ref++;
5820Sstevel@tonic-gate 	*pp = p;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate done:
5850Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
5860Sstevel@tonic-gate 	return (err);
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate int
5900Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
5910Sstevel@tonic-gate {
5920Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
5930Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
5940Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
5950Sstevel@tonic-gate 	int			err;
5960Sstevel@tonic-gate 
5972311Sseb 	ASSERT(mip->mi_multicst != NULL);
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	/*
6000Sstevel@tonic-gate 	 * Find the entry in the list for the given address.
6010Sstevel@tonic-gate 	 */
6020Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
6030Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
6042311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
6052311Sseb 		    0) {
6060Sstevel@tonic-gate 			if (--p->mma_ref == 0)
6070Sstevel@tonic-gate 				break;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 			/*
6100Sstevel@tonic-gate 			 * There is still a reference to this address so
6110Sstevel@tonic-gate 			 * there's nothing more to do.
6120Sstevel@tonic-gate 			 */
6130Sstevel@tonic-gate 			err = 0;
6140Sstevel@tonic-gate 			goto done;
6150Sstevel@tonic-gate 		}
6160Sstevel@tonic-gate 	}
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	/*
6190Sstevel@tonic-gate 	 * We did not find an entry for the given address so it is not
6200Sstevel@tonic-gate 	 * currently enabled.
6210Sstevel@tonic-gate 	 */
6220Sstevel@tonic-gate 	if (p == NULL) {
6230Sstevel@tonic-gate 		err = ENOENT;
6240Sstevel@tonic-gate 		goto done;
6250Sstevel@tonic-gate 	}
6260Sstevel@tonic-gate 	ASSERT(p->mma_ref == 0);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	/*
6290Sstevel@tonic-gate 	 * Disable the multicast address.
6300Sstevel@tonic-gate 	 */
6312311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) {
6320Sstevel@tonic-gate 		p->mma_ref++;
6330Sstevel@tonic-gate 		goto done;
6340Sstevel@tonic-gate 	}
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	/*
6370Sstevel@tonic-gate 	 * Remove it from the list.
6380Sstevel@tonic-gate 	 */
6390Sstevel@tonic-gate 	*pp = p->mma_nextp;
6400Sstevel@tonic-gate 	kmem_free(p, sizeof (mac_multicst_addr_t));
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate done:
6430Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
6440Sstevel@tonic-gate 	return (err);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate 
6472331Skrgopi /*
6482331Skrgopi  * mac_unicst_verify: Verifies the passed address. It fails
6492331Skrgopi  * if the passed address is a group address or has incorrect length.
6502331Skrgopi  */
6512331Skrgopi boolean_t
6522331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
6532331Skrgopi {
6542331Skrgopi 	mac_impl_t	*mip = (mac_impl_t *)mh;
6552331Skrgopi 
6562331Skrgopi 	/*
6572331Skrgopi 	 * Verify the address.
6582331Skrgopi 	 */
6592331Skrgopi 	if ((len != mip->mi_type->mt_addr_length) ||
6602331Skrgopi 	    (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
6612331Skrgopi 	    mip->mi_pdata)) != 0) {
6622331Skrgopi 		return (B_FALSE);
6632331Skrgopi 	} else {
6642331Skrgopi 		return (B_TRUE);
6652331Skrgopi 	}
6662331Skrgopi }
6672331Skrgopi 
6680Sstevel@tonic-gate int
6690Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6720Sstevel@tonic-gate 	int		err;
6730Sstevel@tonic-gate 	boolean_t	notify = B_FALSE;
6740Sstevel@tonic-gate 
6752311Sseb 	ASSERT(mip->mi_unicst != NULL);
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	/*
6780Sstevel@tonic-gate 	 * Verify the address.
6790Sstevel@tonic-gate 	 */
6802311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr,
6812311Sseb 	    mip->mi_pdata)) != 0) {
6822311Sseb 		return (err);
6832311Sseb 	}
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	/*
6860Sstevel@tonic-gate 	 * Program the new unicast address.
6870Sstevel@tonic-gate 	 */
6880Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	/*
6910Sstevel@tonic-gate 	 * If address doesn't change, do nothing.
6920Sstevel@tonic-gate 	 * This check is necessary otherwise it may call into mac_unicst_set
6930Sstevel@tonic-gate 	 * recursively.
6940Sstevel@tonic-gate 	 */
6952311Sseb 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) {
6960Sstevel@tonic-gate 		err = 0;
6970Sstevel@tonic-gate 		goto done;
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 
7002311Sseb 	if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0)
7010Sstevel@tonic-gate 		goto done;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	/*
7040Sstevel@tonic-gate 	 * Save the address and flag that we need to send a notification.
7050Sstevel@tonic-gate 	 */
7062311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
7070Sstevel@tonic-gate 	notify = B_TRUE;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate done:
7100Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	if (notify)
7130Sstevel@tonic-gate 		i_mac_notify(mip, MAC_NOTE_UNICST);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	return (err);
7160Sstevel@tonic-gate }
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate void
7190Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr)
7200Sstevel@tonic-gate {
7210Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	/*
7242311Sseb 	 * Copy out the current unicast source address.
7250Sstevel@tonic-gate 	 */
7260Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
7272311Sseb 	bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
7282311Sseb 	rw_exit(&(mip->mi_data_lock));
7292311Sseb }
7302311Sseb 
7312311Sseb void
7322311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr)
7332311Sseb {
7342311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
7352311Sseb 
7362311Sseb 	/*
7372311Sseb 	 * Copy out the current destination address.
7382311Sseb 	 */
7392311Sseb 	rw_enter(&(mip->mi_data_lock), RW_READER);
7402311Sseb 	bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
7410Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate int
7450Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
7460Sstevel@tonic-gate {
7470Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7480Sstevel@tonic-gate 	int		err = 0;
7490Sstevel@tonic-gate 
7502311Sseb 	ASSERT(mip->mi_setpromisc != NULL);
7510Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	/*
7540Sstevel@tonic-gate 	 * Determine whether we should enable or disable promiscuous mode.
7550Sstevel@tonic-gate 	 * For details on the distinction between "device promiscuous mode"
7560Sstevel@tonic-gate 	 * and "MAC promiscuous mode", see PSARC/2005/289.
7570Sstevel@tonic-gate 	 */
7580Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
7590Sstevel@tonic-gate 	if (on) {
7600Sstevel@tonic-gate 		/*
7610Sstevel@tonic-gate 		 * Enable promiscuous mode on the device if not yet enabled.
7620Sstevel@tonic-gate 		 */
7630Sstevel@tonic-gate 		if (mip->mi_devpromisc++ == 0) {
7642311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
7652311Sseb 			if (err != 0) {
7660Sstevel@tonic-gate 				mip->mi_devpromisc--;
7670Sstevel@tonic-gate 				goto done;
7680Sstevel@tonic-gate 			}
7690Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
7700Sstevel@tonic-gate 		}
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 		/*
7730Sstevel@tonic-gate 		 * Enable promiscuous mode on the MAC if not yet enabled.
7740Sstevel@tonic-gate 		 */
7750Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
7760Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
7770Sstevel@tonic-gate 	} else {
7780Sstevel@tonic-gate 		if (mip->mi_devpromisc == 0) {
7790Sstevel@tonic-gate 			err = EPROTO;
7800Sstevel@tonic-gate 			goto done;
7810Sstevel@tonic-gate 		}
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 		/*
7840Sstevel@tonic-gate 		 * Disable promiscuous mode on the device if this is the last
7850Sstevel@tonic-gate 		 * enabling.
7860Sstevel@tonic-gate 		 */
7870Sstevel@tonic-gate 		if (--mip->mi_devpromisc == 0) {
7882311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
7892311Sseb 			if (err != 0) {
7900Sstevel@tonic-gate 				mip->mi_devpromisc++;
7910Sstevel@tonic-gate 				goto done;
7920Sstevel@tonic-gate 			}
7930Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
7940Sstevel@tonic-gate 		}
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		/*
7970Sstevel@tonic-gate 		 * Disable promiscuous mode on the MAC if this is the last
7980Sstevel@tonic-gate 		 * enabling.
7990Sstevel@tonic-gate 		 */
8000Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
8010Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
8020Sstevel@tonic-gate 	}
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate done:
8050Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
8060Sstevel@tonic-gate 	return (err);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate boolean_t
8100Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
8110Sstevel@tonic-gate {
8120Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	/*
8170Sstevel@tonic-gate 	 * Return the current promiscuity.
8180Sstevel@tonic-gate 	 */
8190Sstevel@tonic-gate 	if (ptype == MAC_DEVPROMISC)
8200Sstevel@tonic-gate 		return (mip->mi_devpromisc != 0);
8210Sstevel@tonic-gate 	else
8220Sstevel@tonic-gate 		return (mip->mi_promisc != 0);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate void
8260Sstevel@tonic-gate mac_resources(mac_handle_t mh)
8270Sstevel@tonic-gate {
8280Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	/*
8312311Sseb 	 * If the driver supports resource registration, call the driver to
8322311Sseb 	 * ask it to register its resources.
8330Sstevel@tonic-gate 	 */
8342311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES)
8352311Sseb 		mip->mi_resources(mip->mi_driver);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate void
8390Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	/*
8442311Sseb 	 * Call the driver to handle the ioctl.  The driver may not support
8452311Sseb 	 * any ioctls, in which case we reply with a NAK on its behalf.
8460Sstevel@tonic-gate 	 */
8472311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
8482311Sseb 		mip->mi_ioctl(mip->mi_driver, wq, bp);
8492311Sseb 	else
8502311Sseb 		miocnak(wq, bp, 0, EINVAL);
8510Sstevel@tonic-gate }
8520Sstevel@tonic-gate 
85356Smeem const mac_txinfo_t *
85456Smeem mac_tx_get(mac_handle_t mh)
8550Sstevel@tonic-gate {
8560Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
85756Smeem 	mac_txinfo_t	*mtp;
85856Smeem 
85956Smeem 	/*
86056Smeem 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
86156Smeem 	 * changed.  This is sufficient since MAC clients are careful to always
86256Smeem 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
86356Smeem 	 * MAC_PROMISC prior to calling mac_txloop_remove().
86456Smeem 	 */
86556Smeem 	rw_enter(&mip->mi_txloop_lock, RW_READER);
8660Sstevel@tonic-gate 
86756Smeem 	if (mac_promisc_get(mh, MAC_PROMISC)) {
86856Smeem 		ASSERT(mip->mi_mtfp != NULL);
86956Smeem 		mtp = &mip->mi_txloopinfo;
87056Smeem 	} else {
87156Smeem 		/*
87256Smeem 		 * Note that we cannot ASSERT() that mip->mi_mtfp is NULL,
87356Smeem 		 * because to satisfy the above ASSERT(), we have to disable
87456Smeem 		 * MAC_PROMISC prior to calling mac_txloop_remove().
87556Smeem 		 */
87656Smeem 		mtp = &mip->mi_txinfo;
87756Smeem 	}
87856Smeem 
87956Smeem 	rw_exit(&mip->mi_txloop_lock);
88056Smeem 	return (mtp);
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate link_state_t
8840Sstevel@tonic-gate mac_link_get(mac_handle_t mh)
8850Sstevel@tonic-gate {
8862311Sseb 	return (((mac_impl_t *)mh)->mi_linkstate);
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate mac_notify_handle_t
8900Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
8910Sstevel@tonic-gate {
8920Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8930Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
8960Sstevel@tonic-gate 	mnfp->mnf_fn = notify;
8970Sstevel@tonic-gate 	mnfp->mnf_arg = arg;
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	/*
9000Sstevel@tonic-gate 	 * Add it to the head of the 'notify' callback list.
9010Sstevel@tonic-gate 	 */
9021852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
9030Sstevel@tonic-gate 	mnfp->mnf_nextp = mip->mi_mnfp;
9040Sstevel@tonic-gate 	mip->mi_mnfp = mnfp;
9051852Syz147064 	rw_exit(&mip->mi_notify_lock);
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	return ((mac_notify_handle_t)mnfp);
9080Sstevel@tonic-gate }
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate void
9110Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
9120Sstevel@tonic-gate {
9130Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9140Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
9150Sstevel@tonic-gate 	mac_notify_fn_t		**pp;
9160Sstevel@tonic-gate 	mac_notify_fn_t		*p;
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	/*
9190Sstevel@tonic-gate 	 * Search the 'notify' callback list for the function closure.
9200Sstevel@tonic-gate 	 */
9211852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
9220Sstevel@tonic-gate 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
9230Sstevel@tonic-gate 	    pp = &(p->mnf_nextp)) {
9240Sstevel@tonic-gate 		if (p == mnfp)
9250Sstevel@tonic-gate 			break;
9260Sstevel@tonic-gate 	}
9270Sstevel@tonic-gate 	ASSERT(p != NULL);
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	/*
9300Sstevel@tonic-gate 	 * Remove it from the list.
9310Sstevel@tonic-gate 	 */
9320Sstevel@tonic-gate 	*pp = p->mnf_nextp;
9331852Syz147064 	rw_exit(&mip->mi_notify_lock);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	/*
9360Sstevel@tonic-gate 	 * Free it.
9370Sstevel@tonic-gate 	 */
9380Sstevel@tonic-gate 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
9390Sstevel@tonic-gate }
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate void
9420Sstevel@tonic-gate mac_notify(mac_handle_t mh)
9430Sstevel@tonic-gate {
9440Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9450Sstevel@tonic-gate 	mac_notify_type_t	type;
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	for (type = 0; type < MAC_NNOTE; type++)
9480Sstevel@tonic-gate 		i_mac_notify(mip, type);
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate 
951*4913Sethindra /*
952*4913Sethindra  * Register a receive function for this mac.
953*4913Sethindra  * More information on this function's interaction with mac_rx()
954*4913Sethindra  * can be found atop mac_rx().
955*4913Sethindra  */
9560Sstevel@tonic-gate mac_rx_handle_t
9570Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
9580Sstevel@tonic-gate {
9590Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9600Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
9630Sstevel@tonic-gate 	mrfp->mrf_fn = rx;
9640Sstevel@tonic-gate 	mrfp->mrf_arg = arg;
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	/*
9670Sstevel@tonic-gate 	 * Add it to the head of the 'rx' callback list.
9680Sstevel@tonic-gate 	 */
9690Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
970*4913Sethindra 
971*4913Sethindra 	/*
972*4913Sethindra 	 * mac_rx() will only call callbacks that are marked inuse.
973*4913Sethindra 	 */
974*4913Sethindra 	mrfp->mrf_inuse = B_TRUE;
9750Sstevel@tonic-gate 	mrfp->mrf_nextp = mip->mi_mrfp;
976*4913Sethindra 
977*4913Sethindra 	/*
978*4913Sethindra 	 * mac_rx() could be traversing the remainder of the list
979*4913Sethindra 	 * and miss the new callback we're adding here. This is not a problem
980*4913Sethindra 	 * because we do not guarantee the callback to take effect immediately
981*4913Sethindra 	 * after mac_rx_add() returns.
982*4913Sethindra 	 */
9830Sstevel@tonic-gate 	mip->mi_mrfp = mrfp;
9840Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	return ((mac_rx_handle_t)mrfp);
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate /*
990*4913Sethindra  * Unregister a receive function for this mac.
991*4913Sethindra  * This function does not block if wait is B_FALSE. This is useful
992*4913Sethindra  * for clients who call mac_rx_remove() from a non-blockable context.
993*4913Sethindra  * More information on this function's interaction with mac_rx()
994*4913Sethindra  * can be found atop mac_rx().
9950Sstevel@tonic-gate  */
9960Sstevel@tonic-gate void
997*4913Sethindra mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh, boolean_t wait)
9980Sstevel@tonic-gate {
9990Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10000Sstevel@tonic-gate 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
10010Sstevel@tonic-gate 	mac_rx_fn_t		**pp;
10020Sstevel@tonic-gate 	mac_rx_fn_t		*p;
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/*
10050Sstevel@tonic-gate 	 * Search the 'rx' callback list for the function closure.
10060Sstevel@tonic-gate 	 */
1007*4913Sethindra 	rw_enter(&mip->mi_rx_lock, RW_WRITER);
10080Sstevel@tonic-gate 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
10090Sstevel@tonic-gate 		if (p == mrfp)
10100Sstevel@tonic-gate 			break;
10110Sstevel@tonic-gate 	}
10120Sstevel@tonic-gate 	ASSERT(p != NULL);
10130Sstevel@tonic-gate 
1014*4913Sethindra 	/*
1015*4913Sethindra 	 * If mac_rx() is running, mark callback for deletion
1016*4913Sethindra 	 * and return (if wait is false), or wait until mac_rx()
1017*4913Sethindra 	 * exits (if wait is true).
1018*4913Sethindra 	 */
1019*4913Sethindra 	if (mip->mi_rx_ref > 0) {
1020*4913Sethindra 		DTRACE_PROBE1(defer_delete, mac_impl_t *, mip);
1021*4913Sethindra 		p->mrf_inuse = B_FALSE;
1022*4913Sethindra 		mutex_enter(&mip->mi_lock);
1023*4913Sethindra 		mip->mi_rx_removed++;
1024*4913Sethindra 		mutex_exit(&mip->mi_lock);
1025*4913Sethindra 
1026*4913Sethindra 		rw_exit(&mip->mi_rx_lock);
1027*4913Sethindra 		if (wait)
1028*4913Sethindra 			mac_rx_remove_wait(mh);
1029*4913Sethindra 		return;
1030*4913Sethindra 	}
1031*4913Sethindra 
10320Sstevel@tonic-gate 	/* Remove it from the list. */
10330Sstevel@tonic-gate 	*pp = p->mrf_nextp;
10340Sstevel@tonic-gate 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
1035*4913Sethindra 	rw_exit(&mip->mi_rx_lock);
1036*4913Sethindra }
1037*4913Sethindra 
1038*4913Sethindra /*
1039*4913Sethindra  * Wait for all pending callback removals to be completed by mac_rx().
1040*4913Sethindra  * Note that if we call mac_rx_remove() immediately before this, there is no
1041*4913Sethindra  * guarantee we would wait *only* on the callback that we specified.
1042*4913Sethindra  * mac_rx_remove() could have been called by other threads and we would have
1043*4913Sethindra  * to wait for other marked callbacks to be removed as well.
1044*4913Sethindra  */
1045*4913Sethindra void
1046*4913Sethindra mac_rx_remove_wait(mac_handle_t mh)
1047*4913Sethindra {
1048*4913Sethindra 	mac_impl_t	*mip = (mac_impl_t *)mh;
1049*4913Sethindra 
1050*4913Sethindra 	mutex_enter(&mip->mi_lock);
1051*4913Sethindra 	while (mip->mi_rx_removed > 0) {
1052*4913Sethindra 		DTRACE_PROBE1(need_wait, mac_impl_t *, mip);
1053*4913Sethindra 		cv_wait(&mip->mi_rx_cv, &mip->mi_lock);
1054*4913Sethindra 	}
1055*4913Sethindra 	mutex_exit(&mip->mi_lock);
10560Sstevel@tonic-gate }
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate mac_txloop_handle_t
10590Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
10600Sstevel@tonic-gate {
10610Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
10620Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
10650Sstevel@tonic-gate 	mtfp->mtf_fn = tx;
10660Sstevel@tonic-gate 	mtfp->mtf_arg = arg;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	/*
10690Sstevel@tonic-gate 	 * Add it to the head of the 'tx' callback list.
10700Sstevel@tonic-gate 	 */
10710Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
10720Sstevel@tonic-gate 	mtfp->mtf_nextp = mip->mi_mtfp;
10730Sstevel@tonic-gate 	mip->mi_mtfp = mtfp;
10740Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	return ((mac_txloop_handle_t)mtfp);
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate /*
10800Sstevel@tonic-gate  * Unregister a transmit function for this mac.  This removes the function
10810Sstevel@tonic-gate  * from the list of transmit functions for this mac.
10820Sstevel@tonic-gate  */
10830Sstevel@tonic-gate void
10840Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
10850Sstevel@tonic-gate {
10860Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10870Sstevel@tonic-gate 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
10880Sstevel@tonic-gate 	mac_txloop_fn_t		**pp;
10890Sstevel@tonic-gate 	mac_txloop_fn_t		*p;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	/*
10920Sstevel@tonic-gate 	 * Search the 'tx' callback list for the function.
10930Sstevel@tonic-gate 	 */
10940Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
10950Sstevel@tonic-gate 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
10960Sstevel@tonic-gate 		if (p == mtfp)
10970Sstevel@tonic-gate 			break;
10980Sstevel@tonic-gate 	}
10990Sstevel@tonic-gate 	ASSERT(p != NULL);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	/* Remove it from the list. */
11020Sstevel@tonic-gate 	*pp = p->mtf_nextp;
11030Sstevel@tonic-gate 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
11040Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate void
11080Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
11090Sstevel@tonic-gate {
11100Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	/*
11130Sstevel@tonic-gate 	 * Update the 'resource_add' callbacks.
11140Sstevel@tonic-gate 	 */
11150Sstevel@tonic-gate 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
11160Sstevel@tonic-gate 	mip->mi_resource_add = add;
11170Sstevel@tonic-gate 	mip->mi_resource_add_arg = arg;
11180Sstevel@tonic-gate 	rw_exit(&(mip->mi_resource_lock));
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate /*
11220Sstevel@tonic-gate  * Driver support functions.
11230Sstevel@tonic-gate  */
11240Sstevel@tonic-gate 
11252311Sseb mac_register_t *
11262311Sseb mac_alloc(uint_t mac_version)
11270Sstevel@tonic-gate {
11282311Sseb 	mac_register_t *mregp;
11292311Sseb 
11302311Sseb 	/*
11312311Sseb 	 * Make sure there isn't a version mismatch between the driver and
11322311Sseb 	 * the framework.  In the future, if multiple versions are
11332311Sseb 	 * supported, this check could become more sophisticated.
11342311Sseb 	 */
11352311Sseb 	if (mac_version != MAC_VERSION)
11362311Sseb 		return (NULL);
11372311Sseb 
11382311Sseb 	mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
11392311Sseb 	mregp->m_version = mac_version;
11402311Sseb 	return (mregp);
11412311Sseb }
11422311Sseb 
11432311Sseb void
11442311Sseb mac_free(mac_register_t *mregp)
11452311Sseb {
11462311Sseb 	kmem_free(mregp, sizeof (mac_register_t));
11472311Sseb }
11482311Sseb 
11492311Sseb /*
11502311Sseb  * mac_register() is how drivers register new MACs with the GLDv3
11512311Sseb  * framework.  The mregp argument is allocated by drivers using the
11522311Sseb  * mac_alloc() function, and can be freed using mac_free() immediately upon
11532311Sseb  * return from mac_register().  Upon success (0 return value), the mhp
11542311Sseb  * opaque pointer becomes the driver's handle to its MAC interface, and is
11552311Sseb  * the argument to all other mac module entry points.
11562311Sseb  */
11572311Sseb int
11582311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp)
11592311Sseb {
11602311Sseb 	mac_impl_t	*mip;
11612311Sseb 	mactype_t	*mtype;
11623969Syz147064 	int		err = EINVAL;
11630Sstevel@tonic-gate 	struct devnames *dnp;
11642311Sseb 	minor_t		minor;
11652311Sseb 	boolean_t	style1_created = B_FALSE, style2_created = B_FALSE;
11662311Sseb 
11672311Sseb 	/* Find the required MAC-Type plugin. */
11682311Sseb 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
11692311Sseb 		return (EINVAL);
11702311Sseb 
11712311Sseb 	/* Create a mac_impl_t to represent this MAC. */
11722311Sseb 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
11732311Sseb 
11742311Sseb 	/*
11752311Sseb 	 * The mac is not ready for open yet.
11762311Sseb 	 */
11772311Sseb 	mip->mi_disabled = B_TRUE;
11782311Sseb 
11792311Sseb 	mip->mi_drvname = ddi_driver_name(mregp->m_dip);
11802311Sseb 	/*
11812311Sseb 	 * Some drivers such as aggr need to register multiple MACs.  Such
11822311Sseb 	 * drivers must supply a non-zero "instance" argument so that each
11832311Sseb 	 * MAC can be assigned a unique MAC name and can have unique
11842311Sseb 	 * kstats.
11852311Sseb 	 */
11862311Sseb 	mip->mi_instance = ((mregp->m_instance == 0) ?
11872311Sseb 	    ddi_get_instance(mregp->m_dip) : mregp->m_instance);
11882311Sseb 
11892311Sseb 	/* Construct the MAC name as <drvname><instance> */
11902311Sseb 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
11912311Sseb 	    mip->mi_drvname, mip->mi_instance);
11922311Sseb 
11932311Sseb 	mip->mi_driver = mregp->m_driver;
11942311Sseb 
11952311Sseb 	mip->mi_type = mtype;
11962311Sseb 	mip->mi_info.mi_media = mtype->mt_type;
11973147Sxc151355 	mip->mi_info.mi_nativemedia = mtype->mt_nativetype;
11982311Sseb 	mip->mi_info.mi_sdu_min = mregp->m_min_sdu;
11993969Syz147064 	if (mregp->m_max_sdu <= mregp->m_min_sdu)
12002311Sseb 		goto fail;
12012311Sseb 	mip->mi_info.mi_sdu_max = mregp->m_max_sdu;
12022311Sseb 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
12032311Sseb 	/*
12042311Sseb 	 * If the media supports a broadcast address, cache a pointer to it
12052311Sseb 	 * in the mac_info_t so that upper layers can use it.
12062311Sseb 	 */
12072311Sseb 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1208269Sericheng 
12092311Sseb 	/*
12102311Sseb 	 * Copy the unicast source address into the mac_info_t, but only if
12112311Sseb 	 * the MAC-Type defines a non-zero address length.  We need to
12122311Sseb 	 * handle MAC-Types that have an address length of 0
12132311Sseb 	 * (point-to-point protocol MACs for example).
12142311Sseb 	 */
12152311Sseb 	if (mip->mi_type->mt_addr_length > 0) {
12163969Syz147064 		if (mregp->m_src_addr == NULL)
12172311Sseb 			goto fail;
12182311Sseb 		mip->mi_info.mi_unicst_addr =
12192311Sseb 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
12202311Sseb 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
12212311Sseb 		    mip->mi_type->mt_addr_length);
12222311Sseb 
12232311Sseb 		/*
12242311Sseb 		 * Copy the fixed 'factory' MAC address from the immutable
12252311Sseb 		 * info.  This is taken to be the MAC address currently in
12262311Sseb 		 * use.
12272311Sseb 		 */
12282311Sseb 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
12292311Sseb 		    mip->mi_type->mt_addr_length);
12302311Sseb 		/* Copy the destination address if one is provided. */
12312311Sseb 		if (mregp->m_dst_addr != NULL) {
12322311Sseb 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
12332311Sseb 			    mip->mi_type->mt_addr_length);
12342311Sseb 		}
12352311Sseb 	} else if (mregp->m_src_addr != NULL) {
12362311Sseb 		goto fail;
1237269Sericheng 	}
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	/*
12402311Sseb 	 * The format of the m_pdata is specific to the plugin.  It is
12412311Sseb 	 * passed in as an argument to all of the plugin callbacks.  The
12422311Sseb 	 * driver can update this information by calling
12432311Sseb 	 * mac_pdata_update().
12440Sstevel@tonic-gate 	 */
12452311Sseb 	if (mregp->m_pdata != NULL) {
12462311Sseb 		/*
12472311Sseb 		 * Verify that the plugin supports MAC plugin data and that
12482311Sseb 		 * the supplied data is valid.
12492311Sseb 		 */
12503969Syz147064 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
12512311Sseb 			goto fail;
12522311Sseb 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
12532311Sseb 		    mregp->m_pdata_size)) {
12542311Sseb 			goto fail;
12552311Sseb 		}
12562311Sseb 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
12572311Sseb 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
12582311Sseb 		mip->mi_pdata_size = mregp->m_pdata_size;
12592311Sseb 	}
12602311Sseb 
12612311Sseb 	/*
12622311Sseb 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
12632311Sseb 	 * check to make sure all mandatory callbacks are set.
12642311Sseb 	 */
12652311Sseb 	if (mregp->m_callbacks->mc_getstat == NULL ||
12662311Sseb 	    mregp->m_callbacks->mc_start == NULL ||
12672311Sseb 	    mregp->m_callbacks->mc_stop == NULL ||
12682311Sseb 	    mregp->m_callbacks->mc_setpromisc == NULL ||
12692311Sseb 	    mregp->m_callbacks->mc_multicst == NULL ||
12702311Sseb 	    mregp->m_callbacks->mc_unicst == NULL ||
12712311Sseb 	    mregp->m_callbacks->mc_tx == NULL) {
12722311Sseb 		goto fail;
12732311Sseb 	}
12742311Sseb 	mip->mi_callbacks = mregp->m_callbacks;
12752311Sseb 
12762311Sseb 	mip->mi_dip = mregp->m_dip;
12772311Sseb 
12782311Sseb 	/*
12792311Sseb 	 * Set up the two possible transmit routines.
12802311Sseb 	 */
12812311Sseb 	mip->mi_txinfo.mt_fn = mip->mi_tx;
12822311Sseb 	mip->mi_txinfo.mt_arg = mip->mi_driver;
12832311Sseb 	mip->mi_txloopinfo.mt_fn = mac_txloop;
12842311Sseb 	mip->mi_txloopinfo.mt_arg = mip;
12852311Sseb 
12862311Sseb 	/*
12872311Sseb 	 * Initialize the kstats for this device.
12882311Sseb 	 */
12892311Sseb 	mac_stat_create(mip);
12900Sstevel@tonic-gate 
1291269Sericheng 	err = EEXIST;
12922311Sseb 	/* Create a style-2 DLPI device */
12932311Sseb 	if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname,
12942311Sseb 	    S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
12952311Sseb 		goto fail;
12962311Sseb 	style2_created = B_TRUE;
1297269Sericheng 
12982311Sseb 	/* Create a style-1 DLPI device */
12992311Sseb 	minor = (minor_t)mip->mi_instance + 1;
13002311Sseb 	if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor,
13012311Sseb 	    DDI_NT_NET, 0) != DDI_SUCCESS)
13022311Sseb 		goto fail;
13032311Sseb 	style1_created = B_TRUE;
13040Sstevel@tonic-gate 
13052311Sseb 	/*
13062311Sseb 	 * Create a link for this MAC.  The link name will be the same as
13072311Sseb 	 * the MAC name.
13082311Sseb 	 */
13092311Sseb 	err = dls_create(mip->mi_name, mip->mi_name,
13102311Sseb 	    ddi_get_instance(mip->mi_dip));
13112311Sseb 	if (err != 0)
13122311Sseb 		goto fail;
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	/* set the gldv3 flag in dn_flags */
13152311Sseb 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
13160Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
13170Sstevel@tonic-gate 	dnp->dn_flags |= DN_GLDV3_DRIVER;
13180Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
13190Sstevel@tonic-gate 
13203969Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
13213969Syz147064 	if (mod_hash_insert(i_mac_impl_hash,
13223969Syz147064 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
13233969Syz147064 		rw_exit(&i_mac_impl_lock);
13243969Syz147064 		VERIFY(dls_destroy(mip->mi_name) == 0);
13253969Syz147064 		err = EEXIST;
13263969Syz147064 		goto fail;
13273969Syz147064 	}
13283969Syz147064 
13291852Syz147064 	/*
13301852Syz147064 	 * Mark the MAC to be ready for open.
13311852Syz147064 	 */
13322311Sseb 	mip->mi_disabled = B_FALSE;
13332311Sseb 
13342311Sseb 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
13353969Syz147064 
13361852Syz147064 	rw_exit(&i_mac_impl_lock);
13373969Syz147064 
13383969Syz147064 	atomic_inc_32(&i_mac_impl_count);
13392311Sseb 	*mhp = (mac_handle_t)mip;
1340269Sericheng 	return (0);
13410Sstevel@tonic-gate 
13422311Sseb fail:
13432311Sseb 	if (mip->mi_info.mi_unicst_addr != NULL) {
13442311Sseb 		kmem_free(mip->mi_info.mi_unicst_addr,
13452311Sseb 		    mip->mi_type->mt_addr_length);
13462311Sseb 		mip->mi_info.mi_unicst_addr = NULL;
13472311Sseb 	}
13482311Sseb 	if (style1_created)
13492311Sseb 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
13502311Sseb 	if (style2_created)
13512311Sseb 		ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
13522311Sseb 
13532311Sseb 	mac_stat_destroy(mip);
13542311Sseb 
13552311Sseb 	if (mip->mi_type != NULL) {
13563288Sseb 		atomic_dec_32(&mip->mi_type->mt_ref);
13572311Sseb 		mip->mi_type = NULL;
13582311Sseb 	}
13592311Sseb 
13602311Sseb 	if (mip->mi_pdata != NULL) {
13612311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
13622311Sseb 		mip->mi_pdata = NULL;
13632311Sseb 		mip->mi_pdata_size = 0;
13642311Sseb 	}
13652311Sseb 
13662311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
1367269Sericheng 	return (err);
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate int
13712311Sseb mac_unregister(mac_handle_t mh)
13720Sstevel@tonic-gate {
13732311Sseb 	int			err;
13742311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
13752311Sseb 	mod_hash_val_t		val;
13762311Sseb 	mac_multicst_addr_t	*p, *nextp;
1377269Sericheng 
13780Sstevel@tonic-gate 	/*
13790Sstevel@tonic-gate 	 * See if there are any other references to this mac_t (e.g., VLAN's).
13801852Syz147064 	 * If not, set mi_disabled to prevent any new VLAN's from being
13812311Sseb 	 * created while we're destroying this mac.
13820Sstevel@tonic-gate 	 */
1383269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
13840Sstevel@tonic-gate 	if (mip->mi_ref > 0) {
1385269Sericheng 		rw_exit(&i_mac_impl_lock);
13860Sstevel@tonic-gate 		return (EBUSY);
13870Sstevel@tonic-gate 	}
13881852Syz147064 	mip->mi_disabled = B_TRUE;
1389269Sericheng 	rw_exit(&i_mac_impl_lock);
13900Sstevel@tonic-gate 
13911852Syz147064 	/*
13921852Syz147064 	 * Wait for all taskqs which process the mac notifications to finish.
13931852Syz147064 	 */
13941852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
13951852Syz147064 	while (mip->mi_notify_ref != 0)
13961852Syz147064 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock);
13971852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
13981852Syz147064 
13992311Sseb 	if ((err = dls_destroy(mip->mi_name)) != 0) {
1400269Sericheng 		rw_enter(&i_mac_impl_lock, RW_WRITER);
14011852Syz147064 		mip->mi_disabled = B_FALSE;
1402269Sericheng 		rw_exit(&i_mac_impl_lock);
1403269Sericheng 		return (err);
14040Sstevel@tonic-gate 	}
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	/*
14072311Sseb 	 * Remove both style 1 and style 2 minor nodes
14080Sstevel@tonic-gate 	 */
14092311Sseb 	ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
14102311Sseb 	ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
14112311Sseb 
14122311Sseb 	ASSERT(!mip->mi_activelink);
14132311Sseb 
14142311Sseb 	mac_stat_destroy(mip);
14152311Sseb 
14162311Sseb 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
14172311Sseb 	    &val);
14182311Sseb 	ASSERT(mip == (mac_impl_t *)val);
14192311Sseb 
14202311Sseb 	ASSERT(i_mac_impl_count > 0);
14213288Sseb 	atomic_dec_32(&i_mac_impl_count);
14222311Sseb 
14232311Sseb 	if (mip->mi_pdata != NULL)
14242311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
14252311Sseb 	mip->mi_pdata = NULL;
14262311Sseb 	mip->mi_pdata_size = 0;
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	/*
14292311Sseb 	 * Free the list of multicast addresses.
14300Sstevel@tonic-gate 	 */
14312311Sseb 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
14322311Sseb 		nextp = p->mma_nextp;
14332311Sseb 		kmem_free(p, sizeof (mac_multicst_addr_t));
14342311Sseb 	}
14352311Sseb 	mip->mi_mmap = NULL;
14360Sstevel@tonic-gate 
14372311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
14382311Sseb 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
14392311Sseb 	mip->mi_info.mi_unicst_addr = NULL;
14402311Sseb 
14413288Sseb 	atomic_dec_32(&mip->mi_type->mt_ref);
14422311Sseb 	mip->mi_type = NULL;
14432311Sseb 
14442311Sseb 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
14452311Sseb 
14462311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
14472311Sseb 
14480Sstevel@tonic-gate 	return (0);
14490Sstevel@tonic-gate }
14500Sstevel@tonic-gate 
1451*4913Sethindra /*
1452*4913Sethindra  * To avoid potential deadlocks, mac_rx() releases mi_rx_lock
1453*4913Sethindra  * before invoking its list of upcalls. This introduces races with
1454*4913Sethindra  * mac_rx_remove() and mac_rx_add(), who can potentially modify the
1455*4913Sethindra  * upcall list while mi_rx_lock is not being held. The race with
1456*4913Sethindra  * mac_rx_remove() is handled by incrementing mi_rx_ref upon entering
1457*4913Sethindra  * mac_rx(); a non-zero mi_rx_ref would tell mac_rx_remove()
1458*4913Sethindra  * to not modify the list but instead mark an upcall for deletion.
1459*4913Sethindra  * before mac_rx() exits, mi_rx_ref is decremented and if it
1460*4913Sethindra  * is 0, the marked upcalls will be removed from the list and freed.
1461*4913Sethindra  * The race with mac_rx_add() is harmless because mac_rx_add() only
1462*4913Sethindra  * prepends to the list and since mac_rx() saves the list head
1463*4913Sethindra  * before releasing mi_rx_lock, any prepended upcall won't be seen
1464*4913Sethindra  * until the next packet chain arrives.
1465*4913Sethindra  *
1466*4913Sethindra  * To minimize lock contention between multiple parallel invocations
1467*4913Sethindra  * of mac_rx(), mi_rx_lock is acquired as a READER lock. The
1468*4913Sethindra  * use of atomic operations ensures the sanity of mi_rx_ref. mi_rx_lock
1469*4913Sethindra  * will be upgraded to WRITER mode when there are marked upcalls to be
1470*4913Sethindra  * cleaned.
1471*4913Sethindra  */
14720Sstevel@tonic-gate void
1473*4913Sethindra mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain)
14740Sstevel@tonic-gate {
14752311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
1476*4913Sethindra 	mblk_t		*bp = mp_chain;
14770Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 	/*
14800Sstevel@tonic-gate 	 * Call all registered receive functions.
14810Sstevel@tonic-gate 	 */
14820Sstevel@tonic-gate 	rw_enter(&mip->mi_rx_lock, RW_READER);
1483*4913Sethindra 	if ((mrfp = mip->mi_mrfp) == NULL) {
14840Sstevel@tonic-gate 		/* There are no registered receive functions. */
14850Sstevel@tonic-gate 		freemsgchain(bp);
14860Sstevel@tonic-gate 		rw_exit(&mip->mi_rx_lock);
14870Sstevel@tonic-gate 		return;
14880Sstevel@tonic-gate 	}
1489*4913Sethindra 	atomic_inc_32(&mip->mi_rx_ref);
1490*4913Sethindra 	rw_exit(&mip->mi_rx_lock);
1491*4913Sethindra 
1492*4913Sethindra 	/*
1493*4913Sethindra 	 * Call registered receive functions.
1494*4913Sethindra 	 */
14950Sstevel@tonic-gate 	do {
14960Sstevel@tonic-gate 		mblk_t *recv_bp;
14970Sstevel@tonic-gate 
1498*4913Sethindra 		recv_bp = (mrfp->mrf_nextp != NULL) ? copymsgchain(bp) : bp;
1499*4913Sethindra 		if (recv_bp != NULL) {
1500*4913Sethindra 			if (mrfp->mrf_inuse) {
1501*4913Sethindra 				/*
1502*4913Sethindra 				 * Send bp itself and keep the copy.
1503*4913Sethindra 				 * If there's only one active receiver,
1504*4913Sethindra 				 * it should get the original message,
1505*4913Sethindra 				 * tagged with the hardware checksum flags.
1506*4913Sethindra 				 */
1507*4913Sethindra 				mrfp->mrf_fn(mrfp->mrf_arg, mrh, bp);
1508*4913Sethindra 				bp = recv_bp;
1509*4913Sethindra 			} else {
1510*4913Sethindra 				freemsgchain(recv_bp);
1511*4913Sethindra 			}
15120Sstevel@tonic-gate 		}
15130Sstevel@tonic-gate 		mrfp = mrfp->mrf_nextp;
15140Sstevel@tonic-gate 	} while (mrfp != NULL);
1515*4913Sethindra 
1516*4913Sethindra 	rw_enter(&mip->mi_rx_lock, RW_READER);
1517*4913Sethindra 	if (atomic_dec_32_nv(&mip->mi_rx_ref) == 0 && mip->mi_rx_removed > 0) {
1518*4913Sethindra 		mac_rx_fn_t	**pp, *p;
1519*4913Sethindra 		uint32_t	cnt = 0;
1520*4913Sethindra 
1521*4913Sethindra 		DTRACE_PROBE1(delete_callbacks, mac_impl_t *, mip);
1522*4913Sethindra 
1523*4913Sethindra 		/*
1524*4913Sethindra 		 * Need to become exclusive before doing cleanup
1525*4913Sethindra 		 */
1526*4913Sethindra 		if (rw_tryupgrade(&mip->mi_rx_lock) == 0) {
1527*4913Sethindra 			rw_exit(&mip->mi_rx_lock);
1528*4913Sethindra 			rw_enter(&mip->mi_rx_lock, RW_WRITER);
1529*4913Sethindra 		}
1530*4913Sethindra 
1531*4913Sethindra 		/*
1532*4913Sethindra 		 * We return if another thread has already entered and cleaned
1533*4913Sethindra 		 * up the list.
1534*4913Sethindra 		 */
1535*4913Sethindra 		if (mip->mi_rx_ref > 0 || mip->mi_rx_removed == 0) {
1536*4913Sethindra 			rw_exit(&mip->mi_rx_lock);
1537*4913Sethindra 			return;
1538*4913Sethindra 		}
1539*4913Sethindra 
1540*4913Sethindra 		/*
1541*4913Sethindra 		 * Free removed callbacks.
1542*4913Sethindra 		 */
1543*4913Sethindra 		pp = &mip->mi_mrfp;
1544*4913Sethindra 		while (*pp != NULL) {
1545*4913Sethindra 			if (!(*pp)->mrf_inuse) {
1546*4913Sethindra 				p = *pp;
1547*4913Sethindra 				*pp = (*pp)->mrf_nextp;
1548*4913Sethindra 				kmem_free(p, sizeof (*p));
1549*4913Sethindra 				cnt++;
1550*4913Sethindra 				continue;
1551*4913Sethindra 			}
1552*4913Sethindra 			pp = &(*pp)->mrf_nextp;
1553*4913Sethindra 		}
1554*4913Sethindra 
1555*4913Sethindra 		/*
1556*4913Sethindra 		 * Wake up mac_rx_remove_wait()
1557*4913Sethindra 		 */
1558*4913Sethindra 		mutex_enter(&mip->mi_lock);
1559*4913Sethindra 		ASSERT(mip->mi_rx_removed == cnt);
1560*4913Sethindra 		mip->mi_rx_removed = 0;
1561*4913Sethindra 		cv_broadcast(&mip->mi_rx_cv);
1562*4913Sethindra 		mutex_exit(&mip->mi_lock);
1563*4913Sethindra 	}
15640Sstevel@tonic-gate 	rw_exit(&mip->mi_rx_lock);
15650Sstevel@tonic-gate }
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate /*
15680Sstevel@tonic-gate  * Transmit function -- ONLY used when there are registered loopback listeners.
15690Sstevel@tonic-gate  */
15700Sstevel@tonic-gate mblk_t *
15710Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp)
15720Sstevel@tonic-gate {
15730Sstevel@tonic-gate 	mac_impl_t	*mip = arg;
15740Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
15750Sstevel@tonic-gate 	mblk_t		*loop_bp, *resid_bp, *next_bp;
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate 	while (bp != NULL) {
15780Sstevel@tonic-gate 		next_bp = bp->b_next;
15790Sstevel@tonic-gate 		bp->b_next = NULL;
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 		if ((loop_bp = copymsg(bp)) == NULL)
15820Sstevel@tonic-gate 			goto noresources;
15830Sstevel@tonic-gate 
15842311Sseb 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
15850Sstevel@tonic-gate 			ASSERT(resid_bp == bp);
15860Sstevel@tonic-gate 			freemsg(loop_bp);
15870Sstevel@tonic-gate 			goto noresources;
15880Sstevel@tonic-gate 		}
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 		rw_enter(&mip->mi_txloop_lock, RW_READER);
15910Sstevel@tonic-gate 		mtfp = mip->mi_mtfp;
159256Smeem 		while (mtfp != NULL && loop_bp != NULL) {
15930Sstevel@tonic-gate 			bp = loop_bp;
159456Smeem 
159556Smeem 			/* XXX counter bump if copymsg() fails? */
159656Smeem 			if (mtfp->mtf_nextp != NULL)
15970Sstevel@tonic-gate 				loop_bp = copymsg(bp);
159856Smeem 			else
159956Smeem 				loop_bp = NULL;
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
160256Smeem 			mtfp = mtfp->mtf_nextp;
16030Sstevel@tonic-gate 		}
160456Smeem 		rw_exit(&mip->mi_txloop_lock);
16050Sstevel@tonic-gate 
160656Smeem 		/*
160756Smeem 		 * It's possible we've raced with the disabling of promiscuous
160856Smeem 		 * mode, in which case we can discard our copy.
160956Smeem 		 */
161056Smeem 		if (loop_bp != NULL)
161156Smeem 			freemsg(loop_bp);
161256Smeem 
16130Sstevel@tonic-gate 		bp = next_bp;
16140Sstevel@tonic-gate 	}
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	return (NULL);
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate noresources:
16190Sstevel@tonic-gate 	bp->b_next = next_bp;
16200Sstevel@tonic-gate 	return (bp);
16210Sstevel@tonic-gate }
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate void
16242311Sseb mac_link_update(mac_handle_t mh, link_state_t link)
16250Sstevel@tonic-gate {
16262311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	/*
16290Sstevel@tonic-gate 	 * Save the link state.
16300Sstevel@tonic-gate 	 */
16312311Sseb 	mip->mi_linkstate = link;
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	/*
16340Sstevel@tonic-gate 	 * Send a MAC_NOTE_LINK notification.
16350Sstevel@tonic-gate 	 */
16360Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_LINK);
16370Sstevel@tonic-gate }
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate void
16402311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
16410Sstevel@tonic-gate {
16422311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
16430Sstevel@tonic-gate 
16442311Sseb 	if (mip->mi_type->mt_addr_length == 0)
16452311Sseb 		return;
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	/*
16480Sstevel@tonic-gate 	 * Save the address.
16490Sstevel@tonic-gate 	 */
16502311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 	/*
16530Sstevel@tonic-gate 	 * Send a MAC_NOTE_UNICST notification.
16540Sstevel@tonic-gate 	 */
16550Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_UNICST);
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate void
16592311Sseb mac_tx_update(mac_handle_t mh)
16600Sstevel@tonic-gate {
16610Sstevel@tonic-gate 	/*
16620Sstevel@tonic-gate 	 * Send a MAC_NOTE_TX notification.
16630Sstevel@tonic-gate 	 */
16642311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
16650Sstevel@tonic-gate }
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate void
16682311Sseb mac_resource_update(mac_handle_t mh)
16690Sstevel@tonic-gate {
16700Sstevel@tonic-gate 	/*
16710Sstevel@tonic-gate 	 * Send a MAC_NOTE_RESOURCE notification.
16720Sstevel@tonic-gate 	 */
16732311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
16740Sstevel@tonic-gate }
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate mac_resource_handle_t
16772311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
16780Sstevel@tonic-gate {
16792311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
16800Sstevel@tonic-gate 	mac_resource_handle_t	mrh;
16810Sstevel@tonic-gate 	mac_resource_add_t	add;
16820Sstevel@tonic-gate 	void			*arg;
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	rw_enter(&mip->mi_resource_lock, RW_READER);
16850Sstevel@tonic-gate 	add = mip->mi_resource_add;
16860Sstevel@tonic-gate 	arg = mip->mi_resource_add_arg;
16870Sstevel@tonic-gate 
16881184Skrgopi 	if (add != NULL)
16891184Skrgopi 		mrh = add(arg, mrp);
16901184Skrgopi 	else
16911184Skrgopi 		mrh = NULL;
16920Sstevel@tonic-gate 	rw_exit(&mip->mi_resource_lock);
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 	return (mrh);
16950Sstevel@tonic-gate }
16960Sstevel@tonic-gate 
16972311Sseb int
16982311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
16992311Sseb {
17002311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17012311Sseb 
17022311Sseb 	/*
17032311Sseb 	 * Verify that the plugin supports MAC plugin data and that the
17042311Sseb 	 * supplied data is valid.
17052311Sseb 	 */
17062311Sseb 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
17072311Sseb 		return (EINVAL);
17082311Sseb 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
17092311Sseb 		return (EINVAL);
17102311Sseb 
17112311Sseb 	if (mip->mi_pdata != NULL)
17122311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
17132311Sseb 
17142311Sseb 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
17152311Sseb 	bcopy(mac_pdata, mip->mi_pdata, dsize);
17162311Sseb 	mip->mi_pdata_size = dsize;
17172311Sseb 
17182311Sseb 	/*
17192311Sseb 	 * Since the MAC plugin data is used to construct MAC headers that
17202311Sseb 	 * were cached in fast-path headers, we need to flush fast-path
17212311Sseb 	 * information for links associated with this mac.
17222311Sseb 	 */
17232311Sseb 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
17242311Sseb 	return (0);
17252311Sseb }
17262311Sseb 
17270Sstevel@tonic-gate void
17282311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
17290Sstevel@tonic-gate     boolean_t add)
17300Sstevel@tonic-gate {
17312311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
17320Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 	/*
17350Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
17360Sstevel@tonic-gate 	 * driver's m_multicst entry point.
17370Sstevel@tonic-gate 	 */
17380Sstevel@tonic-gate 	if (refresh == NULL) {
17392311Sseb 		refresh = mip->mi_multicst;
17402311Sseb 		arg = mip->mi_driver;
17410Sstevel@tonic-gate 	}
17420Sstevel@tonic-gate 	ASSERT(refresh != NULL);
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 	/*
17450Sstevel@tonic-gate 	 * Walk the multicast address list and call the refresh function for
17460Sstevel@tonic-gate 	 * each address.
17470Sstevel@tonic-gate 	 */
17480Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
17490Sstevel@tonic-gate 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
17500Sstevel@tonic-gate 		refresh(arg, add, p->mma_addr);
17510Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
17520Sstevel@tonic-gate }
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate void
17552311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
17560Sstevel@tonic-gate {
17572311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17580Sstevel@tonic-gate 	/*
17590Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
17602311Sseb 	 * driver's mi_unicst entry point.
17610Sstevel@tonic-gate 	 */
17620Sstevel@tonic-gate 	if (refresh == NULL) {
17632311Sseb 		refresh = mip->mi_unicst;
17642311Sseb 		arg = mip->mi_driver;
17650Sstevel@tonic-gate 	}
17660Sstevel@tonic-gate 	ASSERT(refresh != NULL);
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 	/*
17690Sstevel@tonic-gate 	 * Call the refresh function with the current unicast address.
17700Sstevel@tonic-gate 	 */
17710Sstevel@tonic-gate 	refresh(arg, mip->mi_addr);
17720Sstevel@tonic-gate }
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate void
17752311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
17760Sstevel@tonic-gate {
17772311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	/*
17800Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
17810Sstevel@tonic-gate 	 * driver's m_promisc entry point.
17820Sstevel@tonic-gate 	 */
17830Sstevel@tonic-gate 	if (refresh == NULL) {
17842311Sseb 		refresh = mip->mi_setpromisc;
17852311Sseb 		arg = mip->mi_driver;
17860Sstevel@tonic-gate 	}
17870Sstevel@tonic-gate 	ASSERT(refresh != NULL);
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 	/*
17900Sstevel@tonic-gate 	 * Call the refresh function with the current promiscuity.
17910Sstevel@tonic-gate 	 */
17920Sstevel@tonic-gate 	refresh(arg, (mip->mi_devpromisc != 0));
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate boolean_t
17960Sstevel@tonic-gate mac_active_set(mac_handle_t mh)
17970Sstevel@tonic-gate {
17980Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
18010Sstevel@tonic-gate 	if (mip->mi_activelink) {
18020Sstevel@tonic-gate 		mutex_exit(&mip->mi_activelink_lock);
18030Sstevel@tonic-gate 		return (B_FALSE);
18040Sstevel@tonic-gate 	}
18050Sstevel@tonic-gate 	mip->mi_activelink = B_TRUE;
18060Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
18070Sstevel@tonic-gate 	return (B_TRUE);
18080Sstevel@tonic-gate }
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate void
18110Sstevel@tonic-gate mac_active_clear(mac_handle_t mh)
18120Sstevel@tonic-gate {
18130Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
18160Sstevel@tonic-gate 	ASSERT(mip->mi_activelink);
18170Sstevel@tonic-gate 	mip->mi_activelink = B_FALSE;
18180Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
18190Sstevel@tonic-gate }
1820269Sericheng 
1821269Sericheng /*
1822269Sericheng  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
1823269Sericheng  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
1824269Sericheng  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
1825269Sericheng  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
1826269Sericheng  * cannot disappear while we are accessing it.
1827269Sericheng  */
1828269Sericheng typedef struct i_mac_info_state_s {
1829269Sericheng 	const char	*mi_name;
1830269Sericheng 	mac_info_t	*mi_infop;
1831269Sericheng } i_mac_info_state_t;
1832269Sericheng 
1833269Sericheng /*ARGSUSED*/
1834269Sericheng static uint_t
1835269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1836269Sericheng {
1837269Sericheng 	i_mac_info_state_t	*statep = arg;
1838269Sericheng 	mac_impl_t		*mip = (mac_impl_t *)val;
1839269Sericheng 
18401852Syz147064 	if (mip->mi_disabled)
1841269Sericheng 		return (MH_WALK_CONTINUE);
1842269Sericheng 
1843269Sericheng 	if (strcmp(statep->mi_name,
18442311Sseb 	    ddi_driver_name(mip->mi_dip)) != 0)
1845269Sericheng 		return (MH_WALK_CONTINUE);
1846269Sericheng 
18472311Sseb 	statep->mi_infop = &mip->mi_info;
1848269Sericheng 	return (MH_WALK_TERMINATE);
1849269Sericheng }
1850269Sericheng 
1851269Sericheng boolean_t
1852269Sericheng mac_info_get(const char *name, mac_info_t *minfop)
1853269Sericheng {
1854269Sericheng 	i_mac_info_state_t	state;
1855269Sericheng 
1856269Sericheng 	rw_enter(&i_mac_impl_lock, RW_READER);
1857269Sericheng 	state.mi_name = name;
1858269Sericheng 	state.mi_infop = NULL;
1859269Sericheng 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
1860269Sericheng 	if (state.mi_infop == NULL) {
1861269Sericheng 		rw_exit(&i_mac_impl_lock);
1862269Sericheng 		return (B_FALSE);
1863269Sericheng 	}
1864269Sericheng 	*minfop = *state.mi_infop;
1865269Sericheng 	rw_exit(&i_mac_impl_lock);
1866269Sericheng 	return (B_TRUE);
1867269Sericheng }
1868269Sericheng 
18692311Sseb boolean_t
18702311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
18712311Sseb {
18722311Sseb 	mac_impl_t *mip = (mac_impl_t *)mh;
18732311Sseb 
18742311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
18752311Sseb 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
18762311Sseb 	else
18772311Sseb 		return (B_FALSE);
18782311Sseb }
18792311Sseb 
18802311Sseb boolean_t
18812311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
18822311Sseb {
18832311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
18842311Sseb 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
18852311Sseb 	    mip->mi_pdata));
18862311Sseb }
18872311Sseb 
18882311Sseb mblk_t *
18892311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
18902311Sseb     size_t extra_len)
18912311Sseb {
18922311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
18932311Sseb 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
18942311Sseb 	    mip->mi_pdata, payload, extra_len));
18952311Sseb }
18962311Sseb 
18972311Sseb int
18982311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
18992311Sseb {
19002311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
19012311Sseb 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
19022311Sseb 	    mhip));
19032311Sseb }
19042311Sseb 
19052311Sseb mblk_t *
19062311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp)
19072311Sseb {
19082311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
19092311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
19102311Sseb 		if (DB_REF(mp) > 1) {
19112311Sseb 			mblk_t *newmp = copymsg(mp);
19122760Sdg199075 			if (newmp == NULL)
19132760Sdg199075 				return (NULL);
19142311Sseb 			freemsg(mp);
19152311Sseb 			mp = newmp;
19162311Sseb 		}
19172311Sseb 		return (mip->mi_type->mt_ops.mtops_header_cook(mp,
19182311Sseb 		    mip->mi_pdata));
19192311Sseb 	}
19202311Sseb 	return (mp);
19212311Sseb }
19222311Sseb 
19232311Sseb mblk_t *
19242311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp)
19252311Sseb {
19262311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
19272311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
19282311Sseb 		if (DB_REF(mp) > 1) {
19292311Sseb 			mblk_t *newmp = copymsg(mp);
19302760Sdg199075 			if (newmp == NULL)
19312760Sdg199075 				return (NULL);
19322311Sseb 			freemsg(mp);
19332311Sseb 			mp = newmp;
19342311Sseb 		}
19352311Sseb 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
19362311Sseb 		    mip->mi_pdata));
19372311Sseb 	}
19382311Sseb 	return (mp);
19392311Sseb }
19402311Sseb 
1941269Sericheng void
1942269Sericheng mac_init_ops(struct dev_ops *ops, const char *name)
1943269Sericheng {
1944269Sericheng 	dld_init_ops(ops, name);
1945269Sericheng }
1946269Sericheng 
1947269Sericheng void
1948269Sericheng mac_fini_ops(struct dev_ops *ops)
1949269Sericheng {
1950269Sericheng 	dld_fini_ops(ops);
1951269Sericheng }
19522311Sseb 
19532311Sseb /*
19542311Sseb  * MAC Type Plugin functions.
19552311Sseb  */
19562311Sseb 
19572311Sseb mactype_register_t *
19582311Sseb mactype_alloc(uint_t mactype_version)
19592311Sseb {
19602311Sseb 	mactype_register_t *mtrp;
19612311Sseb 
19622311Sseb 	/*
19632311Sseb 	 * Make sure there isn't a version mismatch between the plugin and
19642311Sseb 	 * the framework.  In the future, if multiple versions are
19652311Sseb 	 * supported, this check could become more sophisticated.
19662311Sseb 	 */
19672311Sseb 	if (mactype_version != MACTYPE_VERSION)
19682311Sseb 		return (NULL);
19692311Sseb 
19702311Sseb 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
19712311Sseb 	mtrp->mtr_version = mactype_version;
19722311Sseb 	return (mtrp);
19732311Sseb }
19742311Sseb 
19752311Sseb void
19762311Sseb mactype_free(mactype_register_t *mtrp)
19772311Sseb {
19782311Sseb 	kmem_free(mtrp, sizeof (mactype_register_t));
19792311Sseb }
19802311Sseb 
19812311Sseb int
19822311Sseb mactype_register(mactype_register_t *mtrp)
19832311Sseb {
19842311Sseb 	mactype_t	*mtp;
19852311Sseb 	mactype_ops_t	*ops = mtrp->mtr_ops;
19862311Sseb 
19872311Sseb 	/* Do some sanity checking before we register this MAC type. */
19882311Sseb 	if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0)
19892311Sseb 		return (EINVAL);
19902311Sseb 
19912311Sseb 	/*
19922311Sseb 	 * Verify that all mandatory callbacks are set in the ops
19932311Sseb 	 * vector.
19942311Sseb 	 */
19952311Sseb 	if (ops->mtops_unicst_verify == NULL ||
19962311Sseb 	    ops->mtops_multicst_verify == NULL ||
19972311Sseb 	    ops->mtops_sap_verify == NULL ||
19982311Sseb 	    ops->mtops_header == NULL ||
19992311Sseb 	    ops->mtops_header_info == NULL) {
20002311Sseb 		return (EINVAL);
20012311Sseb 	}
20022311Sseb 
20032311Sseb 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
20042311Sseb 	mtp->mt_ident = mtrp->mtr_ident;
20052311Sseb 	mtp->mt_ops = *ops;
20062311Sseb 	mtp->mt_type = mtrp->mtr_mactype;
20073147Sxc151355 	mtp->mt_nativetype = mtrp->mtr_nativetype;
20082311Sseb 	mtp->mt_addr_length = mtrp->mtr_addrlen;
20092311Sseb 	if (mtrp->mtr_brdcst_addr != NULL) {
20102311Sseb 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
20112311Sseb 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
20122311Sseb 		    mtrp->mtr_addrlen);
20132311Sseb 	}
20142311Sseb 
20152311Sseb 	mtp->mt_stats = mtrp->mtr_stats;
20162311Sseb 	mtp->mt_statcount = mtrp->mtr_statcount;
20172311Sseb 
20182311Sseb 	if (mod_hash_insert(i_mactype_hash,
20192311Sseb 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
20202311Sseb 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
20212311Sseb 		kmem_free(mtp, sizeof (*mtp));
20222311Sseb 		return (EEXIST);
20232311Sseb 	}
20242311Sseb 	return (0);
20252311Sseb }
20262311Sseb 
20272311Sseb int
20282311Sseb mactype_unregister(const char *ident)
20292311Sseb {
20302311Sseb 	mactype_t	*mtp;
20312311Sseb 	mod_hash_val_t	val;
20322311Sseb 	int 		err;
20332311Sseb 
20342311Sseb 	/*
20352311Sseb 	 * Let's not allow MAC drivers to use this plugin while we're
20363288Sseb 	 * trying to unregister it.  Holding i_mactype_lock also prevents a
20373288Sseb 	 * plugin from unregistering while a MAC driver is attempting to
20383288Sseb 	 * hold a reference to it in i_mactype_getplugin().
20392311Sseb 	 */
20403288Sseb 	mutex_enter(&i_mactype_lock);
20412311Sseb 
20422311Sseb 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
20432311Sseb 	    (mod_hash_val_t *)&mtp)) != 0) {
20442311Sseb 		/* A plugin is trying to unregister, but it never registered. */
20453288Sseb 		err = ENXIO;
20463288Sseb 		goto done;
20472311Sseb 	}
20482311Sseb 
20493288Sseb 	if (mtp->mt_ref != 0) {
20503288Sseb 		err = EBUSY;
20513288Sseb 		goto done;
20522311Sseb 	}
20532311Sseb 
20542311Sseb 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
20552311Sseb 	ASSERT(err == 0);
20562311Sseb 	if (err != 0) {
20572311Sseb 		/* This should never happen, thus the ASSERT() above. */
20583288Sseb 		err = EINVAL;
20593288Sseb 		goto done;
20602311Sseb 	}
20612311Sseb 	ASSERT(mtp == (mactype_t *)val);
20622311Sseb 
20632311Sseb 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
20642311Sseb 	kmem_free(mtp, sizeof (mactype_t));
20653288Sseb done:
20663288Sseb 	mutex_exit(&i_mactype_lock);
20673288Sseb 	return (err);
20682311Sseb }
20693448Sdh155122 
20703448Sdh155122 int
20713448Sdh155122 mac_vlan_create(mac_handle_t mh, const char *name, minor_t minor)
20723448Sdh155122 {
20733448Sdh155122 	mac_impl_t		*mip = (mac_impl_t *)mh;
20743448Sdh155122 
20753448Sdh155122 	/* Create a style-1 DLPI device */
20763448Sdh155122 	if (ddi_create_minor_node(mip->mi_dip, (char *)name, S_IFCHR, minor,
20773448Sdh155122 	    DDI_NT_NET, 0) != DDI_SUCCESS) {
20783448Sdh155122 		return (-1);
20793448Sdh155122 	}
20803448Sdh155122 	return (0);
20813448Sdh155122 }
20823448Sdh155122 
20833448Sdh155122 void
20843448Sdh155122 mac_vlan_remove(mac_handle_t mh, const char *name)
20853448Sdh155122 {
20863448Sdh155122 	mac_impl_t		*mip = (mac_impl_t *)mh;
20873448Sdh155122 	dev_info_t		*dipp;
20883448Sdh155122 
20893448Sdh155122 	ddi_remove_minor_node(mip->mi_dip, (char *)name);
20903448Sdh155122 	dipp = ddi_get_parent(mip->mi_dip);
20913448Sdh155122 	(void) devfs_clean(dipp, NULL, 0);
20923448Sdh155122 }
2093