xref: /onnv-gate/usr/src/uts/common/io/mac/mac.c (revision 6353:b927a053de8e)
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  */
215084Sjohnlev 
220Sstevel@tonic-gate /*
235895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * MAC Services Module
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/conf.h>
355895Syz147064 #include <sys/id_space.h>
366077Syz147064 #include <sys/esunddi.h>
370Sstevel@tonic-gate #include <sys/stat.h>
385895Syz147064 #include <sys/mkdev.h>
390Sstevel@tonic-gate #include <sys/stream.h>
400Sstevel@tonic-gate #include <sys/strsun.h>
410Sstevel@tonic-gate #include <sys/strsubr.h>
420Sstevel@tonic-gate #include <sys/dlpi.h>
435895Syz147064 #include <sys/dls.h>
44269Sericheng #include <sys/modhash.h>
455895Syz147064 #include <sys/vlan.h>
460Sstevel@tonic-gate #include <sys/mac.h>
470Sstevel@tonic-gate #include <sys/mac_impl.h>
48269Sericheng #include <sys/dld.h>
492311Sseb #include <sys/modctl.h>
503448Sdh155122 #include <sys/fs/dv_node.h>
515009Sgd78059 #include <sys/thread.h>
525009Sgd78059 #include <sys/proc.h>
535009Sgd78059 #include <sys/callb.h>
545009Sgd78059 #include <sys/cpuvar.h>
553288Sseb #include <sys/atomic.h>
564913Sethindra #include <sys/sdt.h>
575903Ssowmini #include <inet/nd.h>
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #define	IMPL_HASHSZ	67	/* prime */
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static kmem_cache_t	*i_mac_impl_cachep;
62269Sericheng static mod_hash_t	*i_mac_impl_hash;
63269Sericheng krwlock_t		i_mac_impl_lock;
64269Sericheng uint_t			i_mac_impl_count;
655084Sjohnlev static kmem_cache_t	*mac_vnic_tx_cache;
665895Syz147064 static id_space_t	*minor_ids;
675895Syz147064 static uint32_t		minor_count;
680Sstevel@tonic-gate 
692311Sseb #define	MACTYPE_KMODDIR	"mac"
702311Sseb #define	MACTYPE_HASHSZ	67
712311Sseb static mod_hash_t	*i_mactype_hash;
723288Sseb /*
733288Sseb  * i_mactype_lock synchronizes threads that obtain references to mactype_t
743288Sseb  * structures through i_mactype_getplugin().
753288Sseb  */
763288Sseb static kmutex_t		i_mactype_lock;
772311Sseb 
785009Sgd78059 static void i_mac_notify_thread(void *);
795084Sjohnlev static mblk_t *mac_vnic_tx(void *, mblk_t *);
805084Sjohnlev static mblk_t *mac_vnic_txloop(void *, mblk_t *);
811852Syz147064 
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate  * Private functions.
840Sstevel@tonic-gate  */
850Sstevel@tonic-gate 
860Sstevel@tonic-gate /*ARGSUSED*/
870Sstevel@tonic-gate static int
880Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag)
890Sstevel@tonic-gate {
900Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	bzero(buf, sizeof (mac_impl_t));
930Sstevel@tonic-gate 
942311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
975895Syz147064 	rw_init(&mip->mi_gen_lock, NULL, RW_DRIVER, NULL);
980Sstevel@tonic-gate 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
990Sstevel@tonic-gate 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
1000Sstevel@tonic-gate 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
1015084Sjohnlev 	rw_init(&mip->mi_tx_lock, NULL, RW_DRIVER, NULL);
1020Sstevel@tonic-gate 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
1030Sstevel@tonic-gate 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
1045009Sgd78059 	mutex_init(&mip->mi_notify_bits_lock, NULL, MUTEX_DRIVER, NULL);
1051852Syz147064 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL);
1064913Sethindra 	mutex_init(&mip->mi_lock, NULL, MUTEX_DRIVER, NULL);
1074913Sethindra 	cv_init(&mip->mi_rx_cv, NULL, CV_DRIVER, NULL);
1080Sstevel@tonic-gate 	return (0);
1090Sstevel@tonic-gate }
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /*ARGSUSED*/
1120Sstevel@tonic-gate static void
1130Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	ASSERT(mip->mi_ref == 0);
1185895Syz147064 	ASSERT(!mip->mi_exclusive);
1190Sstevel@tonic-gate 	ASSERT(mip->mi_active == 0);
1202311Sseb 	ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
1210Sstevel@tonic-gate 	ASSERT(mip->mi_devpromisc == 0);
1220Sstevel@tonic-gate 	ASSERT(mip->mi_promisc == 0);
1230Sstevel@tonic-gate 	ASSERT(mip->mi_mmap == NULL);
1245895Syz147064 	ASSERT(mip->mi_mmrp == NULL);
1250Sstevel@tonic-gate 	ASSERT(mip->mi_mnfp == NULL);
1260Sstevel@tonic-gate 	ASSERT(mip->mi_resource_add == NULL);
1270Sstevel@tonic-gate 	ASSERT(mip->mi_ksp == NULL);
1282311Sseb 	ASSERT(mip->mi_kstat_count == 0);
1295009Sgd78059 	ASSERT(mip->mi_notify_bits == 0);
1305009Sgd78059 	ASSERT(mip->mi_notify_thread == NULL);
1310Sstevel@tonic-gate 
1325895Syz147064 	rw_destroy(&mip->mi_gen_lock);
1330Sstevel@tonic-gate 	rw_destroy(&mip->mi_state_lock);
1340Sstevel@tonic-gate 	rw_destroy(&mip->mi_data_lock);
1350Sstevel@tonic-gate 	rw_destroy(&mip->mi_notify_lock);
1360Sstevel@tonic-gate 	rw_destroy(&mip->mi_rx_lock);
1375084Sjohnlev 	rw_destroy(&mip->mi_tx_lock);
1380Sstevel@tonic-gate 	rw_destroy(&mip->mi_resource_lock);
1390Sstevel@tonic-gate 	mutex_destroy(&mip->mi_activelink_lock);
1405009Sgd78059 	mutex_destroy(&mip->mi_notify_bits_lock);
1411852Syz147064 	cv_destroy(&mip->mi_notify_cv);
1424913Sethindra 	mutex_destroy(&mip->mi_lock);
1434913Sethindra 	cv_destroy(&mip->mi_rx_cv);
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate 
1465084Sjohnlev /*
1475084Sjohnlev  * mac_vnic_tx_t kmem cache support functions.
1485084Sjohnlev  */
1495084Sjohnlev 
1505084Sjohnlev /* ARGSUSED */
1515084Sjohnlev static int
1525084Sjohnlev i_mac_vnic_tx_ctor(void *buf, void *arg, int mkflag)
1535084Sjohnlev {
1545084Sjohnlev 	mac_vnic_tx_t *vnic_tx = buf;
1555084Sjohnlev 
1565084Sjohnlev 	bzero(buf, sizeof (mac_vnic_tx_t));
1575084Sjohnlev 	mutex_init(&vnic_tx->mv_lock, NULL, MUTEX_DRIVER, NULL);
1585084Sjohnlev 	cv_init(&vnic_tx->mv_cv, NULL, CV_DRIVER, NULL);
1595084Sjohnlev 	return (0);
1605084Sjohnlev }
1615084Sjohnlev 
1625084Sjohnlev /* ARGSUSED */
1635084Sjohnlev static void
1645084Sjohnlev i_mac_vnic_tx_dtor(void *buf, void *arg)
1655084Sjohnlev {
1665084Sjohnlev 	mac_vnic_tx_t *vnic_tx = buf;
1675084Sjohnlev 
1685084Sjohnlev 	ASSERT(vnic_tx->mv_refs == 0);
1695084Sjohnlev 	mutex_destroy(&vnic_tx->mv_lock);
1705084Sjohnlev 	cv_destroy(&vnic_tx->mv_cv);
1715084Sjohnlev }
1725084Sjohnlev 
1730Sstevel@tonic-gate static void
1740Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
1750Sstevel@tonic-gate {
1761852Syz147064 	rw_enter(&i_mac_impl_lock, RW_READER);
1771852Syz147064 	if (mip->mi_disabled)
1781852Syz147064 		goto exit;
1791852Syz147064 
1805009Sgd78059 	/*
1815009Sgd78059 	 * Guard against incorrect notifications.  (Running a newer
1825009Sgd78059 	 * mac client against an older implementation?)
1835009Sgd78059 	 */
1845009Sgd78059 	if (type >= MAC_NNOTE)
1851852Syz147064 		goto exit;
1861852Syz147064 
1875009Sgd78059 	mutex_enter(&mip->mi_notify_bits_lock);
1885009Sgd78059 	mip->mi_notify_bits |= (1 << type);
1895009Sgd78059 	cv_broadcast(&mip->mi_notify_cv);
1905009Sgd78059 	mutex_exit(&mip->mi_notify_bits_lock);
1911852Syz147064 
1921852Syz147064 exit:
1931852Syz147064 	rw_exit(&i_mac_impl_lock);
1941852Syz147064 }
1951852Syz147064 
1961852Syz147064 static void
1974403Sgd78059 i_mac_log_link_state(mac_impl_t *mip)
1984403Sgd78059 {
1994403Sgd78059 	/*
2004403Sgd78059 	 * If no change, then it is not interesting.
2014403Sgd78059 	 */
2024403Sgd78059 	if (mip->mi_lastlinkstate == mip->mi_linkstate)
2034403Sgd78059 		return;
2044403Sgd78059 
2054403Sgd78059 	switch (mip->mi_linkstate) {
2064403Sgd78059 	case LINK_STATE_UP:
2074403Sgd78059 		if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) {
2084403Sgd78059 			char det[200];
2094403Sgd78059 
2104403Sgd78059 			mip->mi_type->mt_ops.mtops_link_details(det,
2114403Sgd78059 			    sizeof (det), (mac_handle_t)mip, mip->mi_pdata);
2124403Sgd78059 
2134403Sgd78059 			cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det);
2144403Sgd78059 		} else {
2154403Sgd78059 			cmn_err(CE_NOTE, "!%s link up", mip->mi_name);
2164403Sgd78059 		}
2174403Sgd78059 		break;
2184403Sgd78059 
2194403Sgd78059 	case LINK_STATE_DOWN:
2204403Sgd78059 		/*
2214403Sgd78059 		 * Only transitions from UP to DOWN are interesting
2224403Sgd78059 		 */
2234403Sgd78059 		if (mip->mi_lastlinkstate != LINK_STATE_UNKNOWN)
2244403Sgd78059 			cmn_err(CE_NOTE, "!%s link down", mip->mi_name);
2254403Sgd78059 		break;
2264403Sgd78059 
2274403Sgd78059 	case LINK_STATE_UNKNOWN:
2284403Sgd78059 		/*
2294403Sgd78059 		 * This case is normally not interesting.
2304403Sgd78059 		 */
2314403Sgd78059 		break;
2324403Sgd78059 	}
2334403Sgd78059 	mip->mi_lastlinkstate = mip->mi_linkstate;
2344403Sgd78059 }
2354403Sgd78059 
2364403Sgd78059 static void
2375009Sgd78059 i_mac_notify_thread(void *arg)
2381852Syz147064 {
2395009Sgd78059 	mac_impl_t	*mip = arg;
2405009Sgd78059 	callb_cpr_t	cprinfo;
2415009Sgd78059 
2425009Sgd78059 	CALLB_CPR_INIT(&cprinfo, &mip->mi_notify_bits_lock, callb_generic_cpr,
2435009Sgd78059 	    "i_mac_notify_thread");
2445009Sgd78059 
2455009Sgd78059 	mutex_enter(&mip->mi_notify_bits_lock);
2465009Sgd78059 	for (;;) {
2475009Sgd78059 		uint32_t	bits;
2485009Sgd78059 		uint32_t	type;
2490Sstevel@tonic-gate 
2505009Sgd78059 		bits = mip->mi_notify_bits;
2515009Sgd78059 		if (bits == 0) {
2525009Sgd78059 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
2535009Sgd78059 			cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
2545009Sgd78059 			CALLB_CPR_SAFE_END(&cprinfo, &mip->mi_notify_bits_lock);
2555009Sgd78059 			continue;
2565009Sgd78059 		}
2575009Sgd78059 		mip->mi_notify_bits = 0;
2585009Sgd78059 
2595009Sgd78059 		if ((bits & (1 << MAC_NNOTE)) != 0) {
2605009Sgd78059 			/* request to quit */
2615009Sgd78059 			ASSERT(mip->mi_disabled);
2625009Sgd78059 			break;
2635009Sgd78059 		}
2645009Sgd78059 
2655009Sgd78059 		mutex_exit(&mip->mi_notify_bits_lock);
2661852Syz147064 
2675009Sgd78059 		/*
2685009Sgd78059 		 * Log link changes.
2695009Sgd78059 		 */
2705009Sgd78059 		if ((bits & (1 << MAC_NOTE_LINK)) != 0)
2715009Sgd78059 			i_mac_log_link_state(mip);
2725009Sgd78059 
2735009Sgd78059 		/*
2745009Sgd78059 		 * Do notification callbacks for each notification type.
2755009Sgd78059 		 */
2765009Sgd78059 		for (type = 0; type < MAC_NNOTE; type++) {
2775009Sgd78059 			mac_notify_fn_t	*mnfp;
2785009Sgd78059 
2795009Sgd78059 			if ((bits & (1 << type)) == 0) {
2805009Sgd78059 				continue;
2815009Sgd78059 			}
2824403Sgd78059 
2835009Sgd78059 			/*
2845009Sgd78059 			 * Walk the list of notifications.
2855009Sgd78059 			 */
2865009Sgd78059 			rw_enter(&mip->mi_notify_lock, RW_READER);
2875009Sgd78059 			for (mnfp = mip->mi_mnfp; mnfp != NULL;
2885009Sgd78059 			    mnfp = mnfp->mnf_nextp) {
2890Sstevel@tonic-gate 
2905009Sgd78059 				mnfp->mnf_fn(mnfp->mnf_arg, type);
2915009Sgd78059 			}
2925009Sgd78059 			rw_exit(&mip->mi_notify_lock);
2935009Sgd78059 		}
2945009Sgd78059 
2955009Sgd78059 		mutex_enter(&mip->mi_notify_bits_lock);
2960Sstevel@tonic-gate 	}
2975009Sgd78059 
2985009Sgd78059 	mip->mi_notify_thread = NULL;
2995009Sgd78059 	cv_broadcast(&mip->mi_notify_cv);
3005009Sgd78059 
3015009Sgd78059 	CALLB_CPR_EXIT(&cprinfo);
3025009Sgd78059 
3035009Sgd78059 	thread_exit();
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate 
3062311Sseb static mactype_t *
3073288Sseb i_mactype_getplugin(const char *pname)
3082311Sseb {
3092311Sseb 	mactype_t	*mtype = NULL;
3102311Sseb 	boolean_t	tried_modload = B_FALSE;
3112311Sseb 
3123288Sseb 	mutex_enter(&i_mactype_lock);
3133288Sseb 
3142311Sseb find_registered_mactype:
3153288Sseb 	if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname,
3163288Sseb 	    (mod_hash_val_t *)&mtype) != 0) {
3173288Sseb 		if (!tried_modload) {
3183288Sseb 			/*
3193288Sseb 			 * If the plugin has not yet been loaded, then
3203288Sseb 			 * attempt to load it now.  If modload() succeeds,
3213288Sseb 			 * the plugin should have registered using
3223288Sseb 			 * mactype_register(), in which case we can go back
3233288Sseb 			 * and attempt to find it again.
3243288Sseb 			 */
3253288Sseb 			if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) {
3263288Sseb 				tried_modload = B_TRUE;
3273288Sseb 				goto find_registered_mactype;
3283288Sseb 			}
3293288Sseb 		}
3303288Sseb 	} else {
3312311Sseb 		/*
3323288Sseb 		 * Note that there's no danger that the plugin we've loaded
3333288Sseb 		 * could be unloaded between the modload() step and the
3343288Sseb 		 * reference count bump here, as we're holding
3353288Sseb 		 * i_mactype_lock, which mactype_unregister() also holds.
3362311Sseb 		 */
3373288Sseb 		atomic_inc_32(&mtype->mt_ref);
3382311Sseb 	}
3392311Sseb 
3403288Sseb 	mutex_exit(&i_mactype_lock);
3413288Sseb 	return (mtype);
3422311Sseb }
3432311Sseb 
3440Sstevel@tonic-gate /*
3450Sstevel@tonic-gate  * Module initialization functions.
3460Sstevel@tonic-gate  */
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate void
3490Sstevel@tonic-gate mac_init(void)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
3522311Sseb 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
3532311Sseb 	    NULL, NULL, NULL, 0);
3540Sstevel@tonic-gate 	ASSERT(i_mac_impl_cachep != NULL);
3550Sstevel@tonic-gate 
3565084Sjohnlev 	mac_vnic_tx_cache = kmem_cache_create("mac_vnic_tx_cache",
3575084Sjohnlev 	    sizeof (mac_vnic_tx_t), 0, i_mac_vnic_tx_ctor, i_mac_vnic_tx_dtor,
3585084Sjohnlev 	    NULL, NULL, NULL, 0);
3595084Sjohnlev 	ASSERT(mac_vnic_tx_cache != NULL);
3605084Sjohnlev 
361269Sericheng 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
362269Sericheng 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
363269Sericheng 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
364269Sericheng 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
365269Sericheng 	i_mac_impl_count = 0;
3662311Sseb 
3672311Sseb 	i_mactype_hash = mod_hash_create_extended("mactype_hash",
3682311Sseb 	    MACTYPE_HASHSZ,
3692311Sseb 	    mod_hash_null_keydtor, mod_hash_null_valdtor,
3702311Sseb 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
3715895Syz147064 
3725895Syz147064 	/*
3735895Syz147064 	 * Allocate an id space to manage minor numbers. The range of the
3745895Syz147064 	 * space will be from MAC_MAX_MINOR+1 to MAXMIN32 (maximum legal
3755895Syz147064 	 * minor number is MAXMIN, but id_t is type of integer and does not
3765895Syz147064 	 * allow MAXMIN).
3775895Syz147064 	 */
3785895Syz147064 	minor_ids = id_space_create("mac_minor_ids", MAC_MAX_MINOR+1, MAXMIN32);
3795895Syz147064 	ASSERT(minor_ids != NULL);
3805895Syz147064 	minor_count = 0;
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate int
3840Sstevel@tonic-gate mac_fini(void)
3850Sstevel@tonic-gate {
3865895Syz147064 	if (i_mac_impl_count > 0 || minor_count > 0)
387269Sericheng 		return (EBUSY);
3880Sstevel@tonic-gate 
3895895Syz147064 	id_space_destroy(minor_ids);
3905895Syz147064 
391269Sericheng 	mod_hash_destroy_hash(i_mac_impl_hash);
392269Sericheng 	rw_destroy(&i_mac_impl_lock);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	kmem_cache_destroy(i_mac_impl_cachep);
3955084Sjohnlev 	kmem_cache_destroy(mac_vnic_tx_cache);
3962311Sseb 
3972311Sseb 	mod_hash_destroy_hash(i_mactype_hash);
3980Sstevel@tonic-gate 	return (0);
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate /*
4020Sstevel@tonic-gate  * Client functions.
4030Sstevel@tonic-gate  */
4040Sstevel@tonic-gate 
4055895Syz147064 static int
4065895Syz147064 mac_hold(const char *macname, mac_impl_t **pmip)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate 	mac_impl_t	*mip;
4090Sstevel@tonic-gate 	int		err;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	/*
4120Sstevel@tonic-gate 	 * Check the device name length to make sure it won't overflow our
4130Sstevel@tonic-gate 	 * buffer.
4140Sstevel@tonic-gate 	 */
4152311Sseb 	if (strlen(macname) >= MAXNAMELEN)
4160Sstevel@tonic-gate 		return (EINVAL);
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	/*
4195895Syz147064 	 * Look up its entry in the global hash table.
4200Sstevel@tonic-gate 	 */
4215895Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4225895Syz147064 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
4235895Syz147064 	    (mod_hash_val_t *)&mip);
4245895Syz147064 
4255895Syz147064 	if (err != 0) {
4265895Syz147064 		rw_exit(&i_mac_impl_lock);
4275895Syz147064 		return (ENOENT);
4285895Syz147064 	}
4295895Syz147064 
4305895Syz147064 	if (mip->mi_disabled) {
4315895Syz147064 		rw_exit(&i_mac_impl_lock);
4325895Syz147064 		return (ENOENT);
4335895Syz147064 	}
4345895Syz147064 
4355895Syz147064 	if (mip->mi_exclusive) {
4365895Syz147064 		rw_exit(&i_mac_impl_lock);
4375895Syz147064 		return (EBUSY);
4385895Syz147064 	}
4395895Syz147064 
4405895Syz147064 	mip->mi_ref++;
4415895Syz147064 	rw_exit(&i_mac_impl_lock);
4425895Syz147064 
4435895Syz147064 	*pmip = mip;
4445895Syz147064 	return (0);
4455895Syz147064 }
4465895Syz147064 
4475895Syz147064 static void
4485895Syz147064 mac_rele(mac_impl_t *mip)
4495895Syz147064 {
4505895Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4515895Syz147064 	ASSERT(mip->mi_ref != 0);
4525895Syz147064 	if (--mip->mi_ref == 0)
4535895Syz147064 		ASSERT(!mip->mi_activelink);
4545895Syz147064 	rw_exit(&i_mac_impl_lock);
4555895Syz147064 }
4565895Syz147064 
4575895Syz147064 int
4585895Syz147064 mac_hold_exclusive(mac_handle_t mh)
4595895Syz147064 {
4605895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
4615084Sjohnlev 
4620Sstevel@tonic-gate 	/*
4635895Syz147064 	 * Look up its entry in the global hash table.
4640Sstevel@tonic-gate 	 */
4655895Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4665895Syz147064 	if (mip->mi_disabled) {
4675895Syz147064 		rw_exit(&i_mac_impl_lock);
4685895Syz147064 		return (ENOENT);
4695895Syz147064 	}
4705895Syz147064 
4715895Syz147064 	if (mip->mi_ref != 0) {
4725895Syz147064 		rw_exit(&i_mac_impl_lock);
4735895Syz147064 		return (EBUSY);
4745895Syz147064 	}
4755895Syz147064 
4765895Syz147064 	ASSERT(!mip->mi_exclusive);
4775895Syz147064 
4785895Syz147064 	mip->mi_ref++;
4795895Syz147064 	mip->mi_exclusive = B_TRUE;
4805895Syz147064 	rw_exit(&i_mac_impl_lock);
4815895Syz147064 	return (0);
4825895Syz147064 }
4835895Syz147064 
4845895Syz147064 void
4855895Syz147064 mac_rele_exclusive(mac_handle_t mh)
4865895Syz147064 {
4875895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	/*
4900Sstevel@tonic-gate 	 * Look up its entry in the global hash table.
4910Sstevel@tonic-gate 	 */
492269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4935895Syz147064 	ASSERT(mip->mi_ref == 1 && mip->mi_exclusive);
4945895Syz147064 	mip->mi_ref--;
4955895Syz147064 	mip->mi_exclusive = B_FALSE;
4965895Syz147064 	rw_exit(&i_mac_impl_lock);
4975895Syz147064 }
4985895Syz147064 
4995895Syz147064 int
5005895Syz147064 mac_open(const char *macname, mac_handle_t *mhp)
5015895Syz147064 {
5025895Syz147064 	mac_impl_t	*mip;
5035895Syz147064 	int		err;
5045895Syz147064 
5055895Syz147064 	/*
5065895Syz147064 	 * Look up its entry in the global hash table.
5075895Syz147064 	 */
5085895Syz147064 	if ((err = mac_hold(macname, &mip)) != 0)
5095895Syz147064 		return (err);
5105895Syz147064 
5116077Syz147064 	/*
5126077Syz147064 	 * Hold the dip associated to the MAC to prevent it from being
5136077Syz147064 	 * detached. For a softmac, its underlying dip is held by the
5146077Syz147064 	 * mi_open() callback.
5156077Syz147064 	 *
5166077Syz147064 	 * This is done to be more tolerant with some defective drivers,
5176077Syz147064 	 * which incorrectly handle mac_unregister() failure in their
5186077Syz147064 	 * xxx_detach() routine. For example, some drivers ignore the
5196077Syz147064 	 * failure of mac_unregister() and free all resources that
5206077Syz147064 	 * that are needed for data transmition.
5216077Syz147064 	 */
5226077Syz147064 	e_ddi_hold_devi(mip->mi_dip);
5236077Syz147064 
5245895Syz147064 	rw_enter(&mip->mi_gen_lock, RW_WRITER);
5255895Syz147064 
5265895Syz147064 	if ((mip->mi_oref != 0) ||
5275895Syz147064 	    !(mip->mi_callbacks->mc_callbacks & MC_OPEN)) {
5285895Syz147064 		goto done;
529269Sericheng 	}
5300Sstevel@tonic-gate 
5315895Syz147064 	/*
5325895Syz147064 	 * Note that we do not hold i_mac_impl_lock when calling the
5335895Syz147064 	 * mc_open() callback function to avoid deadlock with the
5345895Syz147064 	 * i_mac_notify() function.
5355895Syz147064 	 */
5365895Syz147064 	if ((err = mip->mi_open(mip->mi_driver)) != 0) {
5375895Syz147064 		rw_exit(&mip->mi_gen_lock);
5386077Syz147064 		ddi_release_devi(mip->mi_dip);
5395895Syz147064 		mac_rele(mip);
5405895Syz147064 		return (err);
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate 
5435895Syz147064 done:
5445895Syz147064 	mip->mi_oref++;
5455895Syz147064 	rw_exit(&mip->mi_gen_lock);
5460Sstevel@tonic-gate 	*mhp = (mac_handle_t)mip;
5470Sstevel@tonic-gate 	return (0);
5485895Syz147064 }
5495895Syz147064 
5505895Syz147064 int
5515895Syz147064 mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp)
5525895Syz147064 {
5535895Syz147064 	dls_dl_handle_t	dlh;
5545895Syz147064 	int		err;
5555895Syz147064 
5565895Syz147064 	if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
5575895Syz147064 		return (err);
5585895Syz147064 
5595895Syz147064 	if (dls_devnet_vid(dlh) != VLAN_ID_NONE) {
5605895Syz147064 		err = EINVAL;
5615895Syz147064 		goto done;
5625895Syz147064 	}
5635895Syz147064 
5645895Syz147064 	err = mac_open(dls_devnet_mac(dlh), mhp);
5655895Syz147064 
5665895Syz147064 done:
5675895Syz147064 	dls_devnet_rele_tmp(dlh);
5680Sstevel@tonic-gate 	return (err);
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate 
5715895Syz147064 int
5725895Syz147064 mac_open_by_linkname(const char *link, mac_handle_t *mhp)
5735895Syz147064 {
5745895Syz147064 	datalink_id_t	linkid;
5755895Syz147064 	int		err;
5765895Syz147064 
5775895Syz147064 	if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0)
5785895Syz147064 		return (err);
5795895Syz147064 	return (mac_open_by_linkid(linkid, mhp));
5805895Syz147064 }
5815895Syz147064 
5820Sstevel@tonic-gate void
5830Sstevel@tonic-gate mac_close(mac_handle_t mh)
5840Sstevel@tonic-gate {
5850Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
5865895Syz147064 
5875895Syz147064 	rw_enter(&mip->mi_gen_lock, RW_WRITER);
5885895Syz147064 
5895895Syz147064 	ASSERT(mip->mi_oref != 0);
5905895Syz147064 	if (--mip->mi_oref == 0) {
5915895Syz147064 		if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE))
5925895Syz147064 			mip->mi_close(mip->mi_driver);
5930Sstevel@tonic-gate 	}
5945895Syz147064 	rw_exit(&mip->mi_gen_lock);
5955895Syz147064 
5966077Syz147064 	ddi_release_devi(mip->mi_dip);
5975895Syz147064 	mac_rele(mip);
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate const mac_info_t *
6010Sstevel@tonic-gate mac_info(mac_handle_t mh)
6020Sstevel@tonic-gate {
6032311Sseb 	return (&((mac_impl_t *)mh)->mi_info);
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate 
606269Sericheng dev_info_t *
607269Sericheng mac_devinfo_get(mac_handle_t mh)
608269Sericheng {
6092311Sseb 	return (((mac_impl_t *)mh)->mi_dip);
610269Sericheng }
611269Sericheng 
6125895Syz147064 const char *
6135895Syz147064 mac_name(mac_handle_t mh)
6145895Syz147064 {
6155895Syz147064 	return (((mac_impl_t *)mh)->mi_name);
6165895Syz147064 }
6175895Syz147064 
6185895Syz147064 minor_t
6195895Syz147064 mac_minor(mac_handle_t mh)
6205895Syz147064 {
6215895Syz147064 	return (((mac_impl_t *)mh)->mi_minor);
6225895Syz147064 }
6235895Syz147064 
6240Sstevel@tonic-gate uint64_t
6252311Sseb mac_stat_get(mac_handle_t mh, uint_t stat)
6260Sstevel@tonic-gate {
6270Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6282311Sseb 	uint64_t	val;
6292311Sseb 	int		ret;
6300Sstevel@tonic-gate 
6312311Sseb 	/*
6322311Sseb 	 * The range of stat determines where it is maintained.  Stat
6332311Sseb 	 * values from 0 up to (but not including) MAC_STAT_MIN are
6342311Sseb 	 * mainteined by the mac module itself.  Everything else is
6352311Sseb 	 * maintained by the driver.
6362311Sseb 	 */
6372311Sseb 	if (stat < MAC_STAT_MIN) {
6382311Sseb 		/* These stats are maintained by the mac module itself. */
6392311Sseb 		switch (stat) {
6402311Sseb 		case MAC_STAT_LINK_STATE:
6412311Sseb 			return (mip->mi_linkstate);
6422311Sseb 		case MAC_STAT_LINK_UP:
6432311Sseb 			return (mip->mi_linkstate == LINK_STATE_UP);
6442311Sseb 		case MAC_STAT_PROMISC:
6452311Sseb 			return (mip->mi_devpromisc != 0);
6462311Sseb 		default:
6472311Sseb 			ASSERT(B_FALSE);
6482311Sseb 		}
6492311Sseb 	}
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	/*
6520Sstevel@tonic-gate 	 * Call the driver to get the given statistic.
6530Sstevel@tonic-gate 	 */
6542311Sseb 	ret = mip->mi_getstat(mip->mi_driver, stat, &val);
6552311Sseb 	if (ret != 0) {
6562311Sseb 		/*
6572311Sseb 		 * The driver doesn't support this statistic.  Get the
6582311Sseb 		 * statistic's default value.
6592311Sseb 		 */
6602311Sseb 		val = mac_stat_default(mip, stat);
6612311Sseb 	}
6622311Sseb 	return (val);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate int
6660Sstevel@tonic-gate mac_start(mac_handle_t mh)
6670Sstevel@tonic-gate {
6680Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6690Sstevel@tonic-gate 	int		err;
6700Sstevel@tonic-gate 
6712311Sseb 	ASSERT(mip->mi_start != NULL);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	/*
6760Sstevel@tonic-gate 	 * Check whether the device is already started.
6770Sstevel@tonic-gate 	 */
6780Sstevel@tonic-gate 	if (mip->mi_active++ != 0) {
6790Sstevel@tonic-gate 		/*
6800Sstevel@tonic-gate 		 * It's already started so there's nothing more to do.
6810Sstevel@tonic-gate 		 */
6820Sstevel@tonic-gate 		err = 0;
6830Sstevel@tonic-gate 		goto done;
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	/*
6870Sstevel@tonic-gate 	 * Start the device.
6880Sstevel@tonic-gate 	 */
6892311Sseb 	if ((err = mip->mi_start(mip->mi_driver)) != 0)
6900Sstevel@tonic-gate 		--mip->mi_active;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate done:
6930Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
6940Sstevel@tonic-gate 	return (err);
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate void
6980Sstevel@tonic-gate mac_stop(mac_handle_t mh)
6990Sstevel@tonic-gate {
7000Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7010Sstevel@tonic-gate 
7022311Sseb 	ASSERT(mip->mi_stop != NULL);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/*
7070Sstevel@tonic-gate 	 * Check whether the device is still needed.
7080Sstevel@tonic-gate 	 */
7090Sstevel@tonic-gate 	ASSERT(mip->mi_active != 0);
7100Sstevel@tonic-gate 	if (--mip->mi_active != 0) {
7110Sstevel@tonic-gate 		/*
7120Sstevel@tonic-gate 		 * It's still needed so there's nothing more to do.
7130Sstevel@tonic-gate 		 */
7140Sstevel@tonic-gate 		goto done;
7150Sstevel@tonic-gate 	}
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	/*
7180Sstevel@tonic-gate 	 * Stop the device.
7190Sstevel@tonic-gate 	 */
7202311Sseb 	mip->mi_stop(mip->mi_driver);
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate done:
7230Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate int
7270Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
7280Sstevel@tonic-gate {
7290Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
7300Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
7310Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
7320Sstevel@tonic-gate 	int			err;
7330Sstevel@tonic-gate 
7342311Sseb 	ASSERT(mip->mi_multicst != NULL);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	/*
7370Sstevel@tonic-gate 	 * Verify the address.
7380Sstevel@tonic-gate 	 */
7392311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
7402311Sseb 	    mip->mi_pdata)) != 0) {
7412311Sseb 		return (err);
7422311Sseb 	}
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	/*
7450Sstevel@tonic-gate 	 * Check whether the given address is already enabled.
7460Sstevel@tonic-gate 	 */
7470Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
7480Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
7492311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
7502311Sseb 		    0) {
7510Sstevel@tonic-gate 			/*
7520Sstevel@tonic-gate 			 * The address is already enabled so just bump the
7530Sstevel@tonic-gate 			 * reference count.
7540Sstevel@tonic-gate 			 */
7550Sstevel@tonic-gate 			p->mma_ref++;
7560Sstevel@tonic-gate 			err = 0;
7570Sstevel@tonic-gate 			goto done;
7580Sstevel@tonic-gate 		}
7590Sstevel@tonic-gate 	}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	/*
7620Sstevel@tonic-gate 	 * Allocate a new list entry.
7630Sstevel@tonic-gate 	 */
7640Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
7650Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
7660Sstevel@tonic-gate 		err = ENOMEM;
7670Sstevel@tonic-gate 		goto done;
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	/*
7710Sstevel@tonic-gate 	 * Enable a new multicast address.
7720Sstevel@tonic-gate 	 */
7732311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) {
7740Sstevel@tonic-gate 		kmem_free(p, sizeof (mac_multicst_addr_t));
7750Sstevel@tonic-gate 		goto done;
7760Sstevel@tonic-gate 	}
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	/*
7790Sstevel@tonic-gate 	 * Add the address to the list of enabled addresses.
7800Sstevel@tonic-gate 	 */
7812311Sseb 	bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length);
7820Sstevel@tonic-gate 	p->mma_ref++;
7830Sstevel@tonic-gate 	*pp = p;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate done:
7860Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7870Sstevel@tonic-gate 	return (err);
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate int
7910Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
7920Sstevel@tonic-gate {
7930Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
7940Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
7950Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
7960Sstevel@tonic-gate 	int			err;
7970Sstevel@tonic-gate 
7982311Sseb 	ASSERT(mip->mi_multicst != NULL);
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	/*
8010Sstevel@tonic-gate 	 * Find the entry in the list for the given address.
8020Sstevel@tonic-gate 	 */
8030Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
8040Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
8052311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
8062311Sseb 		    0) {
8070Sstevel@tonic-gate 			if (--p->mma_ref == 0)
8080Sstevel@tonic-gate 				break;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 			/*
8110Sstevel@tonic-gate 			 * There is still a reference to this address so
8120Sstevel@tonic-gate 			 * there's nothing more to do.
8130Sstevel@tonic-gate 			 */
8140Sstevel@tonic-gate 			err = 0;
8150Sstevel@tonic-gate 			goto done;
8160Sstevel@tonic-gate 		}
8170Sstevel@tonic-gate 	}
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	/*
8200Sstevel@tonic-gate 	 * We did not find an entry for the given address so it is not
8210Sstevel@tonic-gate 	 * currently enabled.
8220Sstevel@tonic-gate 	 */
8230Sstevel@tonic-gate 	if (p == NULL) {
8240Sstevel@tonic-gate 		err = ENOENT;
8250Sstevel@tonic-gate 		goto done;
8260Sstevel@tonic-gate 	}
8270Sstevel@tonic-gate 	ASSERT(p->mma_ref == 0);
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	/*
8300Sstevel@tonic-gate 	 * Disable the multicast address.
8310Sstevel@tonic-gate 	 */
8322311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) {
8330Sstevel@tonic-gate 		p->mma_ref++;
8340Sstevel@tonic-gate 		goto done;
8350Sstevel@tonic-gate 	}
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	/*
8380Sstevel@tonic-gate 	 * Remove it from the list.
8390Sstevel@tonic-gate 	 */
8400Sstevel@tonic-gate 	*pp = p->mma_nextp;
8410Sstevel@tonic-gate 	kmem_free(p, sizeof (mac_multicst_addr_t));
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate done:
8440Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
8450Sstevel@tonic-gate 	return (err);
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate 
8482331Skrgopi /*
8492331Skrgopi  * mac_unicst_verify: Verifies the passed address. It fails
8502331Skrgopi  * if the passed address is a group address or has incorrect length.
8512331Skrgopi  */
8522331Skrgopi boolean_t
8532331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
8542331Skrgopi {
8552331Skrgopi 	mac_impl_t	*mip = (mac_impl_t *)mh;
8562331Skrgopi 
8572331Skrgopi 	/*
8582331Skrgopi 	 * Verify the address.
8592331Skrgopi 	 */
8602331Skrgopi 	if ((len != mip->mi_type->mt_addr_length) ||
8612331Skrgopi 	    (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
8622331Skrgopi 	    mip->mi_pdata)) != 0) {
8632331Skrgopi 		return (B_FALSE);
8642331Skrgopi 	} else {
8652331Skrgopi 		return (B_TRUE);
8662331Skrgopi 	}
8672331Skrgopi }
8682331Skrgopi 
8690Sstevel@tonic-gate int
8700Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
8710Sstevel@tonic-gate {
8720Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8730Sstevel@tonic-gate 	int		err;
8740Sstevel@tonic-gate 	boolean_t	notify = B_FALSE;
8750Sstevel@tonic-gate 
8762311Sseb 	ASSERT(mip->mi_unicst != NULL);
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/*
8790Sstevel@tonic-gate 	 * Verify the address.
8800Sstevel@tonic-gate 	 */
8812311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr,
8822311Sseb 	    mip->mi_pdata)) != 0) {
8832311Sseb 		return (err);
8842311Sseb 	}
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	/*
8870Sstevel@tonic-gate 	 * Program the new unicast address.
8880Sstevel@tonic-gate 	 */
8890Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	/*
8920Sstevel@tonic-gate 	 * If address doesn't change, do nothing.
8930Sstevel@tonic-gate 	 * This check is necessary otherwise it may call into mac_unicst_set
8940Sstevel@tonic-gate 	 * recursively.
8950Sstevel@tonic-gate 	 */
8965895Syz147064 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0)
8970Sstevel@tonic-gate 		goto done;
8980Sstevel@tonic-gate 
8992311Sseb 	if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0)
9000Sstevel@tonic-gate 		goto done;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	/*
9030Sstevel@tonic-gate 	 * Save the address and flag that we need to send a notification.
9040Sstevel@tonic-gate 	 */
9052311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
9060Sstevel@tonic-gate 	notify = B_TRUE;
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate done:
9090Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	if (notify)
9120Sstevel@tonic-gate 		i_mac_notify(mip, MAC_NOTE_UNICST);
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	return (err);
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate void
9180Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr)
9190Sstevel@tonic-gate {
9200Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	/*
9232311Sseb 	 * Copy out the current unicast source address.
9240Sstevel@tonic-gate 	 */
9250Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
9262311Sseb 	bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
9272311Sseb 	rw_exit(&(mip->mi_data_lock));
9282311Sseb }
9292311Sseb 
9302311Sseb void
9312311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr)
9322311Sseb {
9332311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
9342311Sseb 
9352311Sseb 	/*
9362311Sseb 	 * Copy out the current destination address.
9372311Sseb 	 */
9382311Sseb 	rw_enter(&(mip->mi_data_lock), RW_READER);
9392311Sseb 	bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
9400Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate int
9440Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
9450Sstevel@tonic-gate {
9460Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9470Sstevel@tonic-gate 	int		err = 0;
9480Sstevel@tonic-gate 
9492311Sseb 	ASSERT(mip->mi_setpromisc != NULL);
9500Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	/*
9530Sstevel@tonic-gate 	 * Determine whether we should enable or disable promiscuous mode.
9540Sstevel@tonic-gate 	 * For details on the distinction between "device promiscuous mode"
9550Sstevel@tonic-gate 	 * and "MAC promiscuous mode", see PSARC/2005/289.
9560Sstevel@tonic-gate 	 */
9570Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
9580Sstevel@tonic-gate 	if (on) {
9590Sstevel@tonic-gate 		/*
9600Sstevel@tonic-gate 		 * Enable promiscuous mode on the device if not yet enabled.
9610Sstevel@tonic-gate 		 */
9620Sstevel@tonic-gate 		if (mip->mi_devpromisc++ == 0) {
9632311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
9642311Sseb 			if (err != 0) {
9650Sstevel@tonic-gate 				mip->mi_devpromisc--;
9660Sstevel@tonic-gate 				goto done;
9670Sstevel@tonic-gate 			}
9680Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
9690Sstevel@tonic-gate 		}
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 		/*
9720Sstevel@tonic-gate 		 * Enable promiscuous mode on the MAC if not yet enabled.
9730Sstevel@tonic-gate 		 */
9740Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
9750Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
9760Sstevel@tonic-gate 	} else {
9770Sstevel@tonic-gate 		if (mip->mi_devpromisc == 0) {
9780Sstevel@tonic-gate 			err = EPROTO;
9790Sstevel@tonic-gate 			goto done;
9800Sstevel@tonic-gate 		}
9810Sstevel@tonic-gate 		/*
9820Sstevel@tonic-gate 		 * Disable promiscuous mode on the device if this is the last
9830Sstevel@tonic-gate 		 * enabling.
9840Sstevel@tonic-gate 		 */
9850Sstevel@tonic-gate 		if (--mip->mi_devpromisc == 0) {
9862311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
9872311Sseb 			if (err != 0) {
9880Sstevel@tonic-gate 				mip->mi_devpromisc++;
9890Sstevel@tonic-gate 				goto done;
9900Sstevel@tonic-gate 			}
9910Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
9920Sstevel@tonic-gate 		}
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 		/*
9950Sstevel@tonic-gate 		 * Disable promiscuous mode on the MAC if this is the last
9960Sstevel@tonic-gate 		 * enabling.
9970Sstevel@tonic-gate 		 */
9980Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
9990Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
10000Sstevel@tonic-gate 	}
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate done:
10030Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
10040Sstevel@tonic-gate 	return (err);
10050Sstevel@tonic-gate }
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate boolean_t
10080Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
10090Sstevel@tonic-gate {
10100Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	/*
10150Sstevel@tonic-gate 	 * Return the current promiscuity.
10160Sstevel@tonic-gate 	 */
10170Sstevel@tonic-gate 	if (ptype == MAC_DEVPROMISC)
10180Sstevel@tonic-gate 		return (mip->mi_devpromisc != 0);
10190Sstevel@tonic-gate 	else
10200Sstevel@tonic-gate 		return (mip->mi_promisc != 0);
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate void
10245903Ssowmini mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu)
10255903Ssowmini {
10265903Ssowmini 	mac_impl_t	*mip = (mac_impl_t *)mh;
10275903Ssowmini 
10285903Ssowmini 	if (min_sdu != NULL)
10295903Ssowmini 		*min_sdu = mip->mi_sdu_min;
10305903Ssowmini 	if (max_sdu != NULL)
10315903Ssowmini 		*max_sdu = mip->mi_sdu_max;
10325903Ssowmini }
10335903Ssowmini 
10345903Ssowmini void
10350Sstevel@tonic-gate mac_resources(mac_handle_t mh)
10360Sstevel@tonic-gate {
10370Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	/*
10402311Sseb 	 * If the driver supports resource registration, call the driver to
10412311Sseb 	 * ask it to register its resources.
10420Sstevel@tonic-gate 	 */
10432311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES)
10442311Sseb 		mip->mi_resources(mip->mi_driver);
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate void
10480Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
10490Sstevel@tonic-gate {
10500Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
10515903Ssowmini 	int		cmd;
10525903Ssowmini 
10535903Ssowmini 	if (mip->mi_callbacks->mc_callbacks & (MC_SETPROP|MC_GETPROP)) {
10545903Ssowmini 		cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd;
10555903Ssowmini 		if (cmd == ND_SET || cmd == ND_GET) {
10565903Ssowmini 			/*
10575903Ssowmini 			 * ndd ioctls are Obsolete
10585903Ssowmini 			 */
10595903Ssowmini 			cmn_err(CE_WARN,
10605903Ssowmini 			    "The ndd commands are obsolete and may be removed "
10615903Ssowmini 			    "in a future release of Solaris. "
10625903Ssowmini 			    "Use dladm(1M) to manage driver tunables\n");
10635903Ssowmini 		}
10645903Ssowmini 	}
10650Sstevel@tonic-gate 	/*
10662311Sseb 	 * Call the driver to handle the ioctl.  The driver may not support
10672311Sseb 	 * any ioctls, in which case we reply with a NAK on its behalf.
10680Sstevel@tonic-gate 	 */
10692311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
10702311Sseb 		mip->mi_ioctl(mip->mi_driver, wq, bp);
10712311Sseb 	else
10722311Sseb 		miocnak(wq, bp, 0, EINVAL);
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate 
107556Smeem const mac_txinfo_t *
10765084Sjohnlev mac_do_tx_get(mac_handle_t mh, boolean_t is_vnic)
10770Sstevel@tonic-gate {
10780Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
107956Smeem 	mac_txinfo_t	*mtp;
108056Smeem 
108156Smeem 	/*
108256Smeem 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
108356Smeem 	 * changed.  This is sufficient since MAC clients are careful to always
108456Smeem 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
108556Smeem 	 * MAC_PROMISC prior to calling mac_txloop_remove().
108656Smeem 	 */
10875084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_READER);
10880Sstevel@tonic-gate 
108956Smeem 	if (mac_promisc_get(mh, MAC_PROMISC)) {
109056Smeem 		ASSERT(mip->mi_mtfp != NULL);
10915084Sjohnlev 		if (mip->mi_vnic_present && !is_vnic) {
10925084Sjohnlev 			mtp = &mip->mi_vnic_txloopinfo;
10935084Sjohnlev 		} else {
10945084Sjohnlev 			mtp = &mip->mi_txloopinfo;
10955084Sjohnlev 		}
109656Smeem 	} else {
10975084Sjohnlev 		if (mip->mi_vnic_present && !is_vnic) {
10985084Sjohnlev 			mtp = &mip->mi_vnic_txinfo;
10995084Sjohnlev 		} else {
11005084Sjohnlev 			/*
11015084Sjohnlev 			 * Note that we cannot ASSERT() that mip->mi_mtfp is
11025084Sjohnlev 			 * NULL, because to satisfy the above ASSERT(), we
11035084Sjohnlev 			 * have to disable MAC_PROMISC prior to calling
11045084Sjohnlev 			 * mac_txloop_remove().
11055084Sjohnlev 			 */
11065084Sjohnlev 			mtp = &mip->mi_txinfo;
11075084Sjohnlev 		}
110856Smeem 	}
110956Smeem 
11105084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
111156Smeem 	return (mtp);
11120Sstevel@tonic-gate }
11130Sstevel@tonic-gate 
11145084Sjohnlev /*
11155084Sjohnlev  * Invoked by VNIC to obtain the transmit entry point.
11165084Sjohnlev  */
11175084Sjohnlev const mac_txinfo_t *
11185084Sjohnlev mac_vnic_tx_get(mac_handle_t mh)
11195084Sjohnlev {
11205084Sjohnlev 	return (mac_do_tx_get(mh, B_TRUE));
11215084Sjohnlev }
11225084Sjohnlev 
11235084Sjohnlev /*
11245084Sjohnlev  * Invoked by any non-VNIC client to obtain the transmit entry point.
11255084Sjohnlev  * If a VNIC is present, the VNIC transmit function provided by the VNIC
11265084Sjohnlev  * will be returned to the MAC client.
11275084Sjohnlev  */
11285084Sjohnlev const mac_txinfo_t *
11295084Sjohnlev mac_tx_get(mac_handle_t mh)
11305084Sjohnlev {
11315084Sjohnlev 	return (mac_do_tx_get(mh, B_FALSE));
11325084Sjohnlev }
11335084Sjohnlev 
11340Sstevel@tonic-gate link_state_t
11350Sstevel@tonic-gate mac_link_get(mac_handle_t mh)
11360Sstevel@tonic-gate {
11372311Sseb 	return (((mac_impl_t *)mh)->mi_linkstate);
11380Sstevel@tonic-gate }
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate mac_notify_handle_t
11410Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
11420Sstevel@tonic-gate {
11430Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11440Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
11470Sstevel@tonic-gate 	mnfp->mnf_fn = notify;
11480Sstevel@tonic-gate 	mnfp->mnf_arg = arg;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	/*
11510Sstevel@tonic-gate 	 * Add it to the head of the 'notify' callback list.
11520Sstevel@tonic-gate 	 */
11531852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
11540Sstevel@tonic-gate 	mnfp->mnf_nextp = mip->mi_mnfp;
11550Sstevel@tonic-gate 	mip->mi_mnfp = mnfp;
11561852Syz147064 	rw_exit(&mip->mi_notify_lock);
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	return ((mac_notify_handle_t)mnfp);
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate void
11620Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
11630Sstevel@tonic-gate {
11640Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11650Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
11660Sstevel@tonic-gate 	mac_notify_fn_t		**pp;
11670Sstevel@tonic-gate 	mac_notify_fn_t		*p;
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	/*
11700Sstevel@tonic-gate 	 * Search the 'notify' callback list for the function closure.
11710Sstevel@tonic-gate 	 */
11721852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
11730Sstevel@tonic-gate 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
11740Sstevel@tonic-gate 	    pp = &(p->mnf_nextp)) {
11750Sstevel@tonic-gate 		if (p == mnfp)
11760Sstevel@tonic-gate 			break;
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 	ASSERT(p != NULL);
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	/*
11810Sstevel@tonic-gate 	 * Remove it from the list.
11820Sstevel@tonic-gate 	 */
11830Sstevel@tonic-gate 	*pp = p->mnf_nextp;
11841852Syz147064 	rw_exit(&mip->mi_notify_lock);
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	/*
11870Sstevel@tonic-gate 	 * Free it.
11880Sstevel@tonic-gate 	 */
11890Sstevel@tonic-gate 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate void
11930Sstevel@tonic-gate mac_notify(mac_handle_t mh)
11940Sstevel@tonic-gate {
11950Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11960Sstevel@tonic-gate 	mac_notify_type_t	type;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	for (type = 0; type < MAC_NNOTE; type++)
11990Sstevel@tonic-gate 		i_mac_notify(mip, type);
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12024913Sethindra /*
12034913Sethindra  * Register a receive function for this mac.
12044913Sethindra  * More information on this function's interaction with mac_rx()
12054913Sethindra  * can be found atop mac_rx().
12064913Sethindra  */
12070Sstevel@tonic-gate mac_rx_handle_t
12085084Sjohnlev mac_do_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg, boolean_t is_active)
12090Sstevel@tonic-gate {
12100Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
12110Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
12140Sstevel@tonic-gate 	mrfp->mrf_fn = rx;
12150Sstevel@tonic-gate 	mrfp->mrf_arg = arg;
12165084Sjohnlev 	mrfp->mrf_active = is_active;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	/*
12190Sstevel@tonic-gate 	 * Add it to the head of the 'rx' callback list.
12200Sstevel@tonic-gate 	 */
12210Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
12224913Sethindra 
12234913Sethindra 	/*
12244913Sethindra 	 * mac_rx() will only call callbacks that are marked inuse.
12254913Sethindra 	 */
12264913Sethindra 	mrfp->mrf_inuse = B_TRUE;
12270Sstevel@tonic-gate 	mrfp->mrf_nextp = mip->mi_mrfp;
12284913Sethindra 
12294913Sethindra 	/*
12304913Sethindra 	 * mac_rx() could be traversing the remainder of the list
12314913Sethindra 	 * and miss the new callback we're adding here. This is not a problem
12324913Sethindra 	 * because we do not guarantee the callback to take effect immediately
12334913Sethindra 	 * after mac_rx_add() returns.
12344913Sethindra 	 */
12350Sstevel@tonic-gate 	mip->mi_mrfp = mrfp;
12360Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	return ((mac_rx_handle_t)mrfp);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate 
12415084Sjohnlev mac_rx_handle_t
12425084Sjohnlev mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
12435084Sjohnlev {
12445084Sjohnlev 	return (mac_do_rx_add(mh, rx, arg, B_FALSE));
12455084Sjohnlev }
12465084Sjohnlev 
12475084Sjohnlev mac_rx_handle_t
12485084Sjohnlev mac_active_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
12495084Sjohnlev {
12505084Sjohnlev 	return (mac_do_rx_add(mh, rx, arg, B_TRUE));
12515084Sjohnlev }
12525084Sjohnlev 
12530Sstevel@tonic-gate /*
12544913Sethindra  * Unregister a receive function for this mac.
12554913Sethindra  * This function does not block if wait is B_FALSE. This is useful
12564913Sethindra  * for clients who call mac_rx_remove() from a non-blockable context.
12574913Sethindra  * More information on this function's interaction with mac_rx()
12584913Sethindra  * can be found atop mac_rx().
12590Sstevel@tonic-gate  */
12600Sstevel@tonic-gate void
12614913Sethindra mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh, boolean_t wait)
12620Sstevel@tonic-gate {
12630Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
12640Sstevel@tonic-gate 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
12650Sstevel@tonic-gate 	mac_rx_fn_t		**pp;
12660Sstevel@tonic-gate 	mac_rx_fn_t		*p;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	/*
12690Sstevel@tonic-gate 	 * Search the 'rx' callback list for the function closure.
12700Sstevel@tonic-gate 	 */
12714913Sethindra 	rw_enter(&mip->mi_rx_lock, RW_WRITER);
12720Sstevel@tonic-gate 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
12730Sstevel@tonic-gate 		if (p == mrfp)
12740Sstevel@tonic-gate 			break;
12750Sstevel@tonic-gate 	}
12760Sstevel@tonic-gate 	ASSERT(p != NULL);
12770Sstevel@tonic-gate 
12784913Sethindra 	/*
12794913Sethindra 	 * If mac_rx() is running, mark callback for deletion
12804913Sethindra 	 * and return (if wait is false), or wait until mac_rx()
12814913Sethindra 	 * exits (if wait is true).
12824913Sethindra 	 */
12834913Sethindra 	if (mip->mi_rx_ref > 0) {
12844913Sethindra 		DTRACE_PROBE1(defer_delete, mac_impl_t *, mip);
12854913Sethindra 		p->mrf_inuse = B_FALSE;
12864913Sethindra 		mutex_enter(&mip->mi_lock);
12874913Sethindra 		mip->mi_rx_removed++;
12884913Sethindra 		mutex_exit(&mip->mi_lock);
12894913Sethindra 
12904913Sethindra 		rw_exit(&mip->mi_rx_lock);
12914913Sethindra 		if (wait)
12924913Sethindra 			mac_rx_remove_wait(mh);
12934913Sethindra 		return;
12944913Sethindra 	}
12954913Sethindra 
12960Sstevel@tonic-gate 	/* Remove it from the list. */
12970Sstevel@tonic-gate 	*pp = p->mrf_nextp;
12980Sstevel@tonic-gate 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
12994913Sethindra 	rw_exit(&mip->mi_rx_lock);
13004913Sethindra }
13014913Sethindra 
13024913Sethindra /*
13034913Sethindra  * Wait for all pending callback removals to be completed by mac_rx().
13044913Sethindra  * Note that if we call mac_rx_remove() immediately before this, there is no
13054913Sethindra  * guarantee we would wait *only* on the callback that we specified.
13064913Sethindra  * mac_rx_remove() could have been called by other threads and we would have
13074913Sethindra  * to wait for other marked callbacks to be removed as well.
13084913Sethindra  */
13094913Sethindra void
13104913Sethindra mac_rx_remove_wait(mac_handle_t mh)
13114913Sethindra {
13124913Sethindra 	mac_impl_t	*mip = (mac_impl_t *)mh;
13134913Sethindra 
13144913Sethindra 	mutex_enter(&mip->mi_lock);
13154913Sethindra 	while (mip->mi_rx_removed > 0) {
13164913Sethindra 		DTRACE_PROBE1(need_wait, mac_impl_t *, mip);
13174913Sethindra 		cv_wait(&mip->mi_rx_cv, &mip->mi_lock);
13184913Sethindra 	}
13194913Sethindra 	mutex_exit(&mip->mi_lock);
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate mac_txloop_handle_t
13230Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
13240Sstevel@tonic-gate {
13250Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
13260Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
13290Sstevel@tonic-gate 	mtfp->mtf_fn = tx;
13300Sstevel@tonic-gate 	mtfp->mtf_arg = arg;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	/*
13330Sstevel@tonic-gate 	 * Add it to the head of the 'tx' callback list.
13340Sstevel@tonic-gate 	 */
13355084Sjohnlev 	rw_enter(&(mip->mi_tx_lock), RW_WRITER);
13360Sstevel@tonic-gate 	mtfp->mtf_nextp = mip->mi_mtfp;
13370Sstevel@tonic-gate 	mip->mi_mtfp = mtfp;
13385084Sjohnlev 	rw_exit(&(mip->mi_tx_lock));
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	return ((mac_txloop_handle_t)mtfp);
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate /*
13440Sstevel@tonic-gate  * Unregister a transmit function for this mac.  This removes the function
13450Sstevel@tonic-gate  * from the list of transmit functions for this mac.
13460Sstevel@tonic-gate  */
13470Sstevel@tonic-gate void
13480Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
13490Sstevel@tonic-gate {
13500Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
13510Sstevel@tonic-gate 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
13520Sstevel@tonic-gate 	mac_txloop_fn_t		**pp;
13530Sstevel@tonic-gate 	mac_txloop_fn_t		*p;
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	/*
13560Sstevel@tonic-gate 	 * Search the 'tx' callback list for the function.
13570Sstevel@tonic-gate 	 */
13585084Sjohnlev 	rw_enter(&(mip->mi_tx_lock), RW_WRITER);
13590Sstevel@tonic-gate 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
13600Sstevel@tonic-gate 		if (p == mtfp)
13610Sstevel@tonic-gate 			break;
13620Sstevel@tonic-gate 	}
13630Sstevel@tonic-gate 	ASSERT(p != NULL);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	/* Remove it from the list. */
13660Sstevel@tonic-gate 	*pp = p->mtf_nextp;
13670Sstevel@tonic-gate 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
13685084Sjohnlev 	rw_exit(&(mip->mi_tx_lock));
13690Sstevel@tonic-gate }
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate void
13720Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
13730Sstevel@tonic-gate {
13740Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	/*
13770Sstevel@tonic-gate 	 * Update the 'resource_add' callbacks.
13780Sstevel@tonic-gate 	 */
13790Sstevel@tonic-gate 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
13800Sstevel@tonic-gate 	mip->mi_resource_add = add;
13810Sstevel@tonic-gate 	mip->mi_resource_add_arg = arg;
13820Sstevel@tonic-gate 	rw_exit(&(mip->mi_resource_lock));
13830Sstevel@tonic-gate }
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate /*
13860Sstevel@tonic-gate  * Driver support functions.
13870Sstevel@tonic-gate  */
13880Sstevel@tonic-gate 
13892311Sseb mac_register_t *
13902311Sseb mac_alloc(uint_t mac_version)
13910Sstevel@tonic-gate {
13922311Sseb 	mac_register_t *mregp;
13932311Sseb 
13942311Sseb 	/*
13952311Sseb 	 * Make sure there isn't a version mismatch between the driver and
13962311Sseb 	 * the framework.  In the future, if multiple versions are
13972311Sseb 	 * supported, this check could become more sophisticated.
13982311Sseb 	 */
13992311Sseb 	if (mac_version != MAC_VERSION)
14002311Sseb 		return (NULL);
14012311Sseb 
14022311Sseb 	mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
14032311Sseb 	mregp->m_version = mac_version;
14042311Sseb 	return (mregp);
14052311Sseb }
14062311Sseb 
14072311Sseb void
14082311Sseb mac_free(mac_register_t *mregp)
14092311Sseb {
14102311Sseb 	kmem_free(mregp, sizeof (mac_register_t));
14112311Sseb }
14122311Sseb 
14132311Sseb /*
14145895Syz147064  * Allocate a minor number.
14155895Syz147064  */
14165895Syz147064 minor_t
14175895Syz147064 mac_minor_hold(boolean_t sleep)
14185895Syz147064 {
14195895Syz147064 	minor_t	minor;
14205895Syz147064 
14215895Syz147064 	/*
14225895Syz147064 	 * Grab a value from the arena.
14235895Syz147064 	 */
14245895Syz147064 	atomic_add_32(&minor_count, 1);
14255895Syz147064 
14265895Syz147064 	if (sleep)
14275895Syz147064 		minor = (uint_t)id_alloc(minor_ids);
14285895Syz147064 	else
14295895Syz147064 		minor = (uint_t)id_alloc_nosleep(minor_ids);
14305895Syz147064 
14315895Syz147064 	if (minor == 0) {
14325895Syz147064 		atomic_add_32(&minor_count, -1);
14335895Syz147064 		return (0);
14345895Syz147064 	}
14355895Syz147064 
14365895Syz147064 	return (minor);
14375895Syz147064 }
14385895Syz147064 
14395895Syz147064 /*
14405895Syz147064  * Release a previously allocated minor number.
14415895Syz147064  */
14425895Syz147064 void
14435895Syz147064 mac_minor_rele(minor_t minor)
14445895Syz147064 {
14455895Syz147064 	/*
14465895Syz147064 	 * Return the value to the arena.
14475895Syz147064 	 */
14485895Syz147064 	id_free(minor_ids, minor);
14495895Syz147064 	atomic_add_32(&minor_count, -1);
14505895Syz147064 }
14515895Syz147064 
14525895Syz147064 uint32_t
14535895Syz147064 mac_no_notification(mac_handle_t mh)
14545895Syz147064 {
14555895Syz147064 	mac_impl_t *mip = (mac_impl_t *)mh;
14565895Syz147064 	return (mip->mi_unsup_note);
14575895Syz147064 }
14585895Syz147064 
14595895Syz147064 boolean_t
14605895Syz147064 mac_is_legacy(mac_handle_t mh)
14615895Syz147064 {
14625895Syz147064 	mac_impl_t *mip = (mac_impl_t *)mh;
14635895Syz147064 	return (mip->mi_legacy);
14645895Syz147064 }
14655895Syz147064 
14665895Syz147064 /*
14672311Sseb  * mac_register() is how drivers register new MACs with the GLDv3
14682311Sseb  * framework.  The mregp argument is allocated by drivers using the
14692311Sseb  * mac_alloc() function, and can be freed using mac_free() immediately upon
14702311Sseb  * return from mac_register().  Upon success (0 return value), the mhp
14712311Sseb  * opaque pointer becomes the driver's handle to its MAC interface, and is
14722311Sseb  * the argument to all other mac module entry points.
14732311Sseb  */
14742311Sseb int
14752311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp)
14762311Sseb {
14775895Syz147064 	mac_impl_t		*mip;
14785895Syz147064 	mactype_t		*mtype;
14795895Syz147064 	int			err = EINVAL;
14805895Syz147064 	struct devnames		*dnp = NULL;
14815895Syz147064 	uint_t			instance;
14825895Syz147064 	boolean_t		style1_created = B_FALSE;
14835895Syz147064 	boolean_t		style2_created = B_FALSE;
14845895Syz147064 	mac_capab_legacy_t	legacy;
14855895Syz147064 	char			*driver;
14865895Syz147064 	minor_t			minor = 0;
14872311Sseb 
14882311Sseb 	/* Find the required MAC-Type plugin. */
14892311Sseb 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
14902311Sseb 		return (EINVAL);
14912311Sseb 
14922311Sseb 	/* Create a mac_impl_t to represent this MAC. */
14932311Sseb 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
14942311Sseb 
14952311Sseb 	/*
14962311Sseb 	 * The mac is not ready for open yet.
14972311Sseb 	 */
14982311Sseb 	mip->mi_disabled = B_TRUE;
14992311Sseb 
15002311Sseb 	/*
15015895Syz147064 	 * When a mac is registered, the m_instance field can be set to:
15025895Syz147064 	 *
15035895Syz147064 	 *  0:	Get the mac's instance number from m_dip.
15045895Syz147064 	 *	This is usually used for physical device dips.
15055895Syz147064 	 *
15065895Syz147064 	 *  [1 .. MAC_MAX_MINOR-1]: Use the value as the mac's instance number.
15075895Syz147064 	 *	For example, when an aggregation is created with the key option,
15085895Syz147064 	 *	"key" will be used as the instance number.
15095895Syz147064 	 *
15105895Syz147064 	 *  -1: Assign an instance number from [MAC_MAX_MINOR .. MAXMIN-1].
15115895Syz147064 	 *	This is often used when a MAC of a virtual link is registered
15125895Syz147064 	 *	(e.g., aggregation when "key" is not specified, or vnic).
15135895Syz147064 	 *
15145895Syz147064 	 * Note that the instance number is used to derive the mi_minor field
15155895Syz147064 	 * of mac_impl_t, which will then be used to derive the name of kstats
15165895Syz147064 	 * and the devfs nodes.  The first 2 cases are needed to preserve
15175895Syz147064 	 * backward compatibility.
15182311Sseb 	 */
15195895Syz147064 	switch (mregp->m_instance) {
15205895Syz147064 	case 0:
15215895Syz147064 		instance = ddi_get_instance(mregp->m_dip);
15225895Syz147064 		break;
15235895Syz147064 	case ((uint_t)-1):
15245895Syz147064 		minor = mac_minor_hold(B_TRUE);
15255895Syz147064 		if (minor == 0) {
15265895Syz147064 			err = ENOSPC;
15275895Syz147064 			goto fail;
15285895Syz147064 		}
15295895Syz147064 		instance = minor - 1;
15305895Syz147064 		break;
15315895Syz147064 	default:
15325895Syz147064 		instance = mregp->m_instance;
15335895Syz147064 		if (instance >= MAC_MAX_MINOR) {
15345895Syz147064 			err = EINVAL;
15355895Syz147064 			goto fail;
15365895Syz147064 		}
15375895Syz147064 		break;
15385895Syz147064 	}
15395895Syz147064 
15405895Syz147064 	mip->mi_minor = (minor_t)(instance + 1);
15415895Syz147064 	mip->mi_dip = mregp->m_dip;
15425895Syz147064 
15435895Syz147064 	driver = (char *)ddi_driver_name(mip->mi_dip);
15442311Sseb 
15452311Sseb 	/* Construct the MAC name as <drvname><instance> */
15462311Sseb 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
15475895Syz147064 	    driver, instance);
15482311Sseb 
15492311Sseb 	mip->mi_driver = mregp->m_driver;
15502311Sseb 
15512311Sseb 	mip->mi_type = mtype;
15525895Syz147064 	mip->mi_margin = mregp->m_margin;
15532311Sseb 	mip->mi_info.mi_media = mtype->mt_type;
15543147Sxc151355 	mip->mi_info.mi_nativemedia = mtype->mt_nativetype;
15553969Syz147064 	if (mregp->m_max_sdu <= mregp->m_min_sdu)
15562311Sseb 		goto fail;
15575903Ssowmini 	mip->mi_sdu_min = mregp->m_min_sdu;
15585903Ssowmini 	mip->mi_sdu_max = mregp->m_max_sdu;
15592311Sseb 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
15602311Sseb 	/*
15612311Sseb 	 * If the media supports a broadcast address, cache a pointer to it
15622311Sseb 	 * in the mac_info_t so that upper layers can use it.
15632311Sseb 	 */
15642311Sseb 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1565269Sericheng 
15662311Sseb 	/*
15672311Sseb 	 * Copy the unicast source address into the mac_info_t, but only if
15682311Sseb 	 * the MAC-Type defines a non-zero address length.  We need to
15692311Sseb 	 * handle MAC-Types that have an address length of 0
15702311Sseb 	 * (point-to-point protocol MACs for example).
15712311Sseb 	 */
15722311Sseb 	if (mip->mi_type->mt_addr_length > 0) {
15733969Syz147064 		if (mregp->m_src_addr == NULL)
15742311Sseb 			goto fail;
15752311Sseb 		mip->mi_info.mi_unicst_addr =
15762311Sseb 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
15772311Sseb 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
15782311Sseb 		    mip->mi_type->mt_addr_length);
15792311Sseb 
15802311Sseb 		/*
15812311Sseb 		 * Copy the fixed 'factory' MAC address from the immutable
15822311Sseb 		 * info.  This is taken to be the MAC address currently in
15832311Sseb 		 * use.
15842311Sseb 		 */
15852311Sseb 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
15862311Sseb 		    mip->mi_type->mt_addr_length);
15872311Sseb 		/* Copy the destination address if one is provided. */
15882311Sseb 		if (mregp->m_dst_addr != NULL) {
15892311Sseb 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
15902311Sseb 			    mip->mi_type->mt_addr_length);
15912311Sseb 		}
15922311Sseb 	} else if (mregp->m_src_addr != NULL) {
15932311Sseb 		goto fail;
1594269Sericheng 	}
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	/*
15972311Sseb 	 * The format of the m_pdata is specific to the plugin.  It is
15982311Sseb 	 * passed in as an argument to all of the plugin callbacks.  The
15992311Sseb 	 * driver can update this information by calling
16002311Sseb 	 * mac_pdata_update().
16010Sstevel@tonic-gate 	 */
16022311Sseb 	if (mregp->m_pdata != NULL) {
16032311Sseb 		/*
16042311Sseb 		 * Verify that the plugin supports MAC plugin data and that
16052311Sseb 		 * the supplied data is valid.
16062311Sseb 		 */
16073969Syz147064 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
16082311Sseb 			goto fail;
16092311Sseb 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
16102311Sseb 		    mregp->m_pdata_size)) {
16112311Sseb 			goto fail;
16122311Sseb 		}
16132311Sseb 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
16142311Sseb 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
16152311Sseb 		mip->mi_pdata_size = mregp->m_pdata_size;
16162311Sseb 	}
16172311Sseb 
16182311Sseb 	/*
16192311Sseb 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
16202311Sseb 	 * check to make sure all mandatory callbacks are set.
16212311Sseb 	 */
16222311Sseb 	if (mregp->m_callbacks->mc_getstat == NULL ||
16232311Sseb 	    mregp->m_callbacks->mc_start == NULL ||
16242311Sseb 	    mregp->m_callbacks->mc_stop == NULL ||
16252311Sseb 	    mregp->m_callbacks->mc_setpromisc == NULL ||
16262311Sseb 	    mregp->m_callbacks->mc_multicst == NULL ||
16272311Sseb 	    mregp->m_callbacks->mc_unicst == NULL ||
16282311Sseb 	    mregp->m_callbacks->mc_tx == NULL) {
16292311Sseb 		goto fail;
16302311Sseb 	}
16312311Sseb 	mip->mi_callbacks = mregp->m_callbacks;
16322311Sseb 
16332311Sseb 	/*
16345084Sjohnlev 	 * Set up the possible transmit routines.
16352311Sseb 	 */
16362311Sseb 	mip->mi_txinfo.mt_fn = mip->mi_tx;
16372311Sseb 	mip->mi_txinfo.mt_arg = mip->mi_driver;
16385084Sjohnlev 
16395895Syz147064 	mip->mi_legacy = mac_capab_get((mac_handle_t)mip,
16405895Syz147064 	    MAC_CAPAB_LEGACY, &legacy);
16415895Syz147064 
16425895Syz147064 	if (mip->mi_legacy) {
16435895Syz147064 		/*
16445895Syz147064 		 * Legacy device. Messages being sent will be looped back
16455895Syz147064 		 * by the underlying driver. Therefore the txloop function
16465895Syz147064 		 * pointer is the same as the tx function pointer.
16475895Syz147064 		 */
16485895Syz147064 		mip->mi_txloopinfo.mt_fn = mip->mi_txinfo.mt_fn;
16495895Syz147064 		mip->mi_txloopinfo.mt_arg = mip->mi_txinfo.mt_arg;
16505895Syz147064 		mip->mi_unsup_note = legacy.ml_unsup_note;
16515895Syz147064 		mip->mi_phy_dev = legacy.ml_dev;
16525895Syz147064 	} else {
16535895Syz147064 		/*
16545895Syz147064 		 * Normal device. The framework needs to do the loopback.
16555895Syz147064 		 */
16565895Syz147064 		mip->mi_txloopinfo.mt_fn = mac_txloop;
16575895Syz147064 		mip->mi_txloopinfo.mt_arg = mip;
16585895Syz147064 		mip->mi_unsup_note = 0;
16595895Syz147064 		mip->mi_phy_dev = makedevice(ddi_driver_major(mip->mi_dip),
16605895Syz147064 		    ddi_get_instance(mip->mi_dip) + 1);
16615895Syz147064 	}
16625895Syz147064 
16635084Sjohnlev 	mip->mi_vnic_txinfo.mt_fn = mac_vnic_tx;
16645084Sjohnlev 	mip->mi_vnic_txinfo.mt_arg = mip;
16655084Sjohnlev 
16665084Sjohnlev 	mip->mi_vnic_txloopinfo.mt_fn = mac_vnic_txloop;
16675084Sjohnlev 	mip->mi_vnic_txloopinfo.mt_arg = mip;
16685084Sjohnlev 
16692311Sseb 	/*
16705009Sgd78059 	 * Allocate a notification thread.
16715009Sgd78059 	 */
16725009Sgd78059 	mip->mi_notify_thread = thread_create(NULL, 0, i_mac_notify_thread,
16735009Sgd78059 	    mip, 0, &p0, TS_RUN, minclsyspri);
16745009Sgd78059 	if (mip->mi_notify_thread == NULL)
16755009Sgd78059 		goto fail;
16765009Sgd78059 
16775009Sgd78059 	/*
16782311Sseb 	 * Initialize the kstats for this device.
16792311Sseb 	 */
16802311Sseb 	mac_stat_create(mip);
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	/* set the gldv3 flag in dn_flags */
16832311Sseb 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
16840Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
16855895Syz147064 	dnp->dn_flags |= (DN_GLDV3_DRIVER | DN_NETWORK_DRIVER);
16860Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
16870Sstevel@tonic-gate 
16885895Syz147064 	if (mip->mi_minor < MAC_MAX_MINOR + 1) {
16895895Syz147064 		/* Create a style-2 DLPI device */
16905895Syz147064 		if (ddi_create_minor_node(mip->mi_dip, driver, S_IFCHR, 0,
16915895Syz147064 		    DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
16925895Syz147064 			goto fail;
16935895Syz147064 		style2_created = B_TRUE;
16945895Syz147064 
16955895Syz147064 		/* Create a style-1 DLPI device */
16965895Syz147064 		if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR,
16975895Syz147064 		    mip->mi_minor, DDI_NT_NET, 0) != DDI_SUCCESS)
16985895Syz147064 			goto fail;
16995895Syz147064 		style1_created = B_TRUE;
17005895Syz147064 	}
17015895Syz147064 
17023969Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
17033969Syz147064 	if (mod_hash_insert(i_mac_impl_hash,
17043969Syz147064 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
17055895Syz147064 
17063969Syz147064 		rw_exit(&i_mac_impl_lock);
17073969Syz147064 		err = EEXIST;
17083969Syz147064 		goto fail;
17093969Syz147064 	}
17103969Syz147064 
17115903Ssowmini 	DTRACE_PROBE2(mac__register, struct devnames *, dnp,
17125903Ssowmini 	    (mac_impl_t *), mip);
17135903Ssowmini 
17141852Syz147064 	/*
17151852Syz147064 	 * Mark the MAC to be ready for open.
17161852Syz147064 	 */
17172311Sseb 	mip->mi_disabled = B_FALSE;
17182311Sseb 
17191852Syz147064 	rw_exit(&i_mac_impl_lock);
17203969Syz147064 
17213969Syz147064 	atomic_inc_32(&i_mac_impl_count);
17225895Syz147064 
17235895Syz147064 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
17242311Sseb 	*mhp = (mac_handle_t)mip;
1725269Sericheng 	return (0);
17260Sstevel@tonic-gate 
17272311Sseb fail:
17285895Syz147064 	if (style1_created)
17295895Syz147064 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
17305895Syz147064 
17315895Syz147064 	if (style2_created)
17325895Syz147064 		ddi_remove_minor_node(mip->mi_dip, driver);
17335895Syz147064 
17345009Sgd78059 	/* clean up notification thread */
17355009Sgd78059 	if (mip->mi_notify_thread != NULL) {
17365009Sgd78059 		mutex_enter(&mip->mi_notify_bits_lock);
17375009Sgd78059 		mip->mi_notify_bits = (1 << MAC_NNOTE);
17385009Sgd78059 		cv_broadcast(&mip->mi_notify_cv);
17395009Sgd78059 		while (mip->mi_notify_bits != 0)
17405009Sgd78059 			cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
17415009Sgd78059 		mutex_exit(&mip->mi_notify_bits_lock);
17425009Sgd78059 	}
17435009Sgd78059 
17442311Sseb 	if (mip->mi_info.mi_unicst_addr != NULL) {
17452311Sseb 		kmem_free(mip->mi_info.mi_unicst_addr,
17462311Sseb 		    mip->mi_type->mt_addr_length);
17472311Sseb 		mip->mi_info.mi_unicst_addr = NULL;
17482311Sseb 	}
17492311Sseb 
17502311Sseb 	mac_stat_destroy(mip);
17512311Sseb 
17522311Sseb 	if (mip->mi_type != NULL) {
17533288Sseb 		atomic_dec_32(&mip->mi_type->mt_ref);
17542311Sseb 		mip->mi_type = NULL;
17552311Sseb 	}
17562311Sseb 
17572311Sseb 	if (mip->mi_pdata != NULL) {
17582311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
17592311Sseb 		mip->mi_pdata = NULL;
17602311Sseb 		mip->mi_pdata_size = 0;
17612311Sseb 	}
17622311Sseb 
17635895Syz147064 	if (minor != 0) {
17645895Syz147064 		ASSERT(minor > MAC_MAX_MINOR);
17655895Syz147064 		mac_minor_rele(minor);
17665895Syz147064 	}
17675895Syz147064 
17682311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
1769269Sericheng 	return (err);
17700Sstevel@tonic-gate }
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate int
17735084Sjohnlev mac_disable(mac_handle_t mh)
17740Sstevel@tonic-gate {
17752311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
1776269Sericheng 
17770Sstevel@tonic-gate 	/*
17780Sstevel@tonic-gate 	 * See if there are any other references to this mac_t (e.g., VLAN's).
17791852Syz147064 	 * If not, set mi_disabled to prevent any new VLAN's from being
17802311Sseb 	 * created while we're destroying this mac.
17810Sstevel@tonic-gate 	 */
1782269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
17830Sstevel@tonic-gate 	if (mip->mi_ref > 0) {
1784269Sericheng 		rw_exit(&i_mac_impl_lock);
17850Sstevel@tonic-gate 		return (EBUSY);
17860Sstevel@tonic-gate 	}
17871852Syz147064 	mip->mi_disabled = B_TRUE;
1788269Sericheng 	rw_exit(&i_mac_impl_lock);
17895084Sjohnlev 	return (0);
17905084Sjohnlev }
17915084Sjohnlev 
17925084Sjohnlev int
17935084Sjohnlev mac_unregister(mac_handle_t mh)
17945084Sjohnlev {
17955084Sjohnlev 	int			err;
17965084Sjohnlev 	mac_impl_t		*mip = (mac_impl_t *)mh;
17975084Sjohnlev 	mod_hash_val_t		val;
17985084Sjohnlev 	mac_multicst_addr_t	*p, *nextp;
17995895Syz147064 	mac_margin_req_t	*mmr, *nextmmr;
18005084Sjohnlev 
18015084Sjohnlev 	/*
18025084Sjohnlev 	 * See if there are any other references to this mac_t (e.g., VLAN's).
18035084Sjohnlev 	 * If not, set mi_disabled to prevent any new VLAN's from being
18045084Sjohnlev 	 * created while we're destroying this mac. Once mac_disable() returns
18055084Sjohnlev 	 * 0, the rest of mac_unregister() stuff should continue without
18065084Sjohnlev 	 * returning an error.
18075084Sjohnlev 	 */
18085084Sjohnlev 	if (!mip->mi_disabled) {
18095084Sjohnlev 		if ((err = mac_disable(mh)) != 0)
18105084Sjohnlev 			return (err);
18115084Sjohnlev 	}
18125084Sjohnlev 
18130Sstevel@tonic-gate 	/*
18145009Sgd78059 	 * Clean up notification thread (wait for it to exit).
18155009Sgd78059 	 */
18165009Sgd78059 	mutex_enter(&mip->mi_notify_bits_lock);
18175009Sgd78059 	mip->mi_notify_bits = (1 << MAC_NNOTE);
18185009Sgd78059 	cv_broadcast(&mip->mi_notify_cv);
18195009Sgd78059 	while (mip->mi_notify_bits != 0)
18205009Sgd78059 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
18215009Sgd78059 	mutex_exit(&mip->mi_notify_bits_lock);
18225009Sgd78059 
18235895Syz147064 	if (mip->mi_minor < MAC_MAX_MINOR + 1) {
18245895Syz147064 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
18255895Syz147064 		ddi_remove_minor_node(mip->mi_dip,
18265895Syz147064 		    (char *)ddi_driver_name(mip->mi_dip));
18275895Syz147064 	}
18282311Sseb 
18292311Sseb 	ASSERT(!mip->mi_activelink);
18302311Sseb 
18312311Sseb 	mac_stat_destroy(mip);
18322311Sseb 
18335895Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
18345895Syz147064 	(void) mod_hash_remove(i_mac_impl_hash,
18355895Syz147064 	    (mod_hash_key_t)mip->mi_name, &val);
18362311Sseb 	ASSERT(mip == (mac_impl_t *)val);
18372311Sseb 
18382311Sseb 	ASSERT(i_mac_impl_count > 0);
18393288Sseb 	atomic_dec_32(&i_mac_impl_count);
18405895Syz147064 	rw_exit(&i_mac_impl_lock);
18412311Sseb 
18422311Sseb 	if (mip->mi_pdata != NULL)
18432311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
18442311Sseb 	mip->mi_pdata = NULL;
18452311Sseb 	mip->mi_pdata_size = 0;
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 	/*
18482311Sseb 	 * Free the list of multicast addresses.
18490Sstevel@tonic-gate 	 */
18502311Sseb 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
18512311Sseb 		nextp = p->mma_nextp;
18522311Sseb 		kmem_free(p, sizeof (mac_multicst_addr_t));
18532311Sseb 	}
18542311Sseb 	mip->mi_mmap = NULL;
18550Sstevel@tonic-gate 
18565895Syz147064 	/*
18575895Syz147064 	 * Free the list of margin request.
18585895Syz147064 	 */
18595895Syz147064 	for (mmr = mip->mi_mmrp; mmr != NULL; mmr = nextmmr) {
18605895Syz147064 		nextmmr = mmr->mmr_nextp;
18615895Syz147064 		kmem_free(mmr, sizeof (mac_margin_req_t));
18625895Syz147064 	}
18635895Syz147064 	mip->mi_mmrp = NULL;
18645895Syz147064 
18652311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
18662311Sseb 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
18672311Sseb 	mip->mi_info.mi_unicst_addr = NULL;
18682311Sseb 
18693288Sseb 	atomic_dec_32(&mip->mi_type->mt_ref);
18702311Sseb 	mip->mi_type = NULL;
18712311Sseb 
18725895Syz147064 	if (mip->mi_minor > MAC_MAX_MINOR)
18735895Syz147064 		mac_minor_rele(mip->mi_minor);
18745895Syz147064 
18752311Sseb 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
18762311Sseb 
18772311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
18782311Sseb 
18790Sstevel@tonic-gate 	return (0);
18800Sstevel@tonic-gate }
18810Sstevel@tonic-gate 
18824913Sethindra /*
18834913Sethindra  * To avoid potential deadlocks, mac_rx() releases mi_rx_lock
18844913Sethindra  * before invoking its list of upcalls. This introduces races with
18854913Sethindra  * mac_rx_remove() and mac_rx_add(), who can potentially modify the
18864913Sethindra  * upcall list while mi_rx_lock is not being held. The race with
18874913Sethindra  * mac_rx_remove() is handled by incrementing mi_rx_ref upon entering
18884913Sethindra  * mac_rx(); a non-zero mi_rx_ref would tell mac_rx_remove()
18894913Sethindra  * to not modify the list but instead mark an upcall for deletion.
18904913Sethindra  * before mac_rx() exits, mi_rx_ref is decremented and if it
18914913Sethindra  * is 0, the marked upcalls will be removed from the list and freed.
18924913Sethindra  * The race with mac_rx_add() is harmless because mac_rx_add() only
18934913Sethindra  * prepends to the list and since mac_rx() saves the list head
18944913Sethindra  * before releasing mi_rx_lock, any prepended upcall won't be seen
18954913Sethindra  * until the next packet chain arrives.
18964913Sethindra  *
18974913Sethindra  * To minimize lock contention between multiple parallel invocations
18984913Sethindra  * of mac_rx(), mi_rx_lock is acquired as a READER lock. The
18994913Sethindra  * use of atomic operations ensures the sanity of mi_rx_ref. mi_rx_lock
19004913Sethindra  * will be upgraded to WRITER mode when there are marked upcalls to be
19014913Sethindra  * cleaned.
19024913Sethindra  */
19035084Sjohnlev static void
19045084Sjohnlev mac_do_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain,
19055084Sjohnlev     boolean_t active_only)
19060Sstevel@tonic-gate {
19072311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
19084913Sethindra 	mblk_t		*bp = mp_chain;
19090Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 	/*
19120Sstevel@tonic-gate 	 * Call all registered receive functions.
19130Sstevel@tonic-gate 	 */
19140Sstevel@tonic-gate 	rw_enter(&mip->mi_rx_lock, RW_READER);
19154913Sethindra 	if ((mrfp = mip->mi_mrfp) == NULL) {
19160Sstevel@tonic-gate 		/* There are no registered receive functions. */
19170Sstevel@tonic-gate 		freemsgchain(bp);
19180Sstevel@tonic-gate 		rw_exit(&mip->mi_rx_lock);
19190Sstevel@tonic-gate 		return;
19200Sstevel@tonic-gate 	}
19214913Sethindra 	atomic_inc_32(&mip->mi_rx_ref);
19224913Sethindra 	rw_exit(&mip->mi_rx_lock);
19234913Sethindra 
19244913Sethindra 	/*
19254913Sethindra 	 * Call registered receive functions.
19264913Sethindra 	 */
19270Sstevel@tonic-gate 	do {
19280Sstevel@tonic-gate 		mblk_t *recv_bp;
19290Sstevel@tonic-gate 
19305084Sjohnlev 		if (active_only && !mrfp->mrf_active) {
19315084Sjohnlev 			mrfp = mrfp->mrf_nextp;
19325084Sjohnlev 			if (mrfp == NULL) {
19335084Sjohnlev 				/*
19345084Sjohnlev 				 * We hit the last receiver, but it's not
19355084Sjohnlev 				 * active.
19365084Sjohnlev 				 */
19375084Sjohnlev 				freemsgchain(bp);
19385084Sjohnlev 			}
19395084Sjohnlev 			continue;
19405084Sjohnlev 		}
19415084Sjohnlev 
19424913Sethindra 		recv_bp = (mrfp->mrf_nextp != NULL) ? copymsgchain(bp) : bp;
19434913Sethindra 		if (recv_bp != NULL) {
19444913Sethindra 			if (mrfp->mrf_inuse) {
19454913Sethindra 				/*
19464913Sethindra 				 * Send bp itself and keep the copy.
19474913Sethindra 				 * If there's only one active receiver,
19484913Sethindra 				 * it should get the original message,
19494913Sethindra 				 * tagged with the hardware checksum flags.
19504913Sethindra 				 */
19514913Sethindra 				mrfp->mrf_fn(mrfp->mrf_arg, mrh, bp);
19524913Sethindra 				bp = recv_bp;
19534913Sethindra 			} else {
19544913Sethindra 				freemsgchain(recv_bp);
19554913Sethindra 			}
19560Sstevel@tonic-gate 		}
19575084Sjohnlev 
19580Sstevel@tonic-gate 		mrfp = mrfp->mrf_nextp;
19590Sstevel@tonic-gate 	} while (mrfp != NULL);
19604913Sethindra 
19614913Sethindra 	rw_enter(&mip->mi_rx_lock, RW_READER);
19624913Sethindra 	if (atomic_dec_32_nv(&mip->mi_rx_ref) == 0 && mip->mi_rx_removed > 0) {
19634913Sethindra 		mac_rx_fn_t	**pp, *p;
19644913Sethindra 		uint32_t	cnt = 0;
19654913Sethindra 
19664913Sethindra 		DTRACE_PROBE1(delete_callbacks, mac_impl_t *, mip);
19674913Sethindra 
19684913Sethindra 		/*
19694913Sethindra 		 * Need to become exclusive before doing cleanup
19704913Sethindra 		 */
19714913Sethindra 		if (rw_tryupgrade(&mip->mi_rx_lock) == 0) {
19724913Sethindra 			rw_exit(&mip->mi_rx_lock);
19734913Sethindra 			rw_enter(&mip->mi_rx_lock, RW_WRITER);
19744913Sethindra 		}
19754913Sethindra 
19764913Sethindra 		/*
19774913Sethindra 		 * We return if another thread has already entered and cleaned
19784913Sethindra 		 * up the list.
19794913Sethindra 		 */
19804913Sethindra 		if (mip->mi_rx_ref > 0 || mip->mi_rx_removed == 0) {
19814913Sethindra 			rw_exit(&mip->mi_rx_lock);
19824913Sethindra 			return;
19834913Sethindra 		}
19844913Sethindra 
19854913Sethindra 		/*
19864913Sethindra 		 * Free removed callbacks.
19874913Sethindra 		 */
19884913Sethindra 		pp = &mip->mi_mrfp;
19894913Sethindra 		while (*pp != NULL) {
19904913Sethindra 			if (!(*pp)->mrf_inuse) {
19914913Sethindra 				p = *pp;
19924913Sethindra 				*pp = (*pp)->mrf_nextp;
19934913Sethindra 				kmem_free(p, sizeof (*p));
19944913Sethindra 				cnt++;
19954913Sethindra 				continue;
19964913Sethindra 			}
19974913Sethindra 			pp = &(*pp)->mrf_nextp;
19984913Sethindra 		}
19994913Sethindra 
20004913Sethindra 		/*
20014913Sethindra 		 * Wake up mac_rx_remove_wait()
20024913Sethindra 		 */
20034913Sethindra 		mutex_enter(&mip->mi_lock);
20044913Sethindra 		ASSERT(mip->mi_rx_removed == cnt);
20054913Sethindra 		mip->mi_rx_removed = 0;
20064913Sethindra 		cv_broadcast(&mip->mi_rx_cv);
20074913Sethindra 		mutex_exit(&mip->mi_lock);
20084913Sethindra 	}
20090Sstevel@tonic-gate 	rw_exit(&mip->mi_rx_lock);
20100Sstevel@tonic-gate }
20110Sstevel@tonic-gate 
20125084Sjohnlev void
20135084Sjohnlev mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain)
20145084Sjohnlev {
20155084Sjohnlev 	mac_do_rx(mh, mrh, mp_chain, B_FALSE);
20165084Sjohnlev }
20175084Sjohnlev 
20185084Sjohnlev /*
20195084Sjohnlev  * Send a packet chain up to the receive callbacks which declared
20205084Sjohnlev  * themselves as being active.
20215084Sjohnlev  */
20225084Sjohnlev void
20235084Sjohnlev mac_active_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp_chain)
20245084Sjohnlev {
20255084Sjohnlev 	mac_do_rx(arg, mrh, mp_chain, B_TRUE);
20265084Sjohnlev }
20275084Sjohnlev 
20285084Sjohnlev /*
20295084Sjohnlev  * Function passed to the active client sharing a VNIC. This function
20305084Sjohnlev  * is returned by mac_tx_get() when a VNIC is present. It invokes
20315084Sjohnlev  * the VNIC transmit entry point which was specified by the VNIC when
20325084Sjohnlev  * it called mac_vnic_set(). The VNIC transmit entry point will
20335084Sjohnlev  * pass the packets to the local VNICs and/or to the underlying VNICs
20345084Sjohnlev  * if needed.
20355084Sjohnlev  */
20365084Sjohnlev static mblk_t *
20375084Sjohnlev mac_vnic_tx(void *arg, mblk_t *mp)
20385084Sjohnlev {
20395084Sjohnlev 	mac_impl_t	*mip = arg;
20405084Sjohnlev 	mac_txinfo_t	*mtfp;
20415084Sjohnlev 	mac_vnic_tx_t	*mvt;
20425084Sjohnlev 
20435084Sjohnlev 	/*
20445084Sjohnlev 	 * There is a race between the notification of the VNIC
20455084Sjohnlev 	 * addition and removal, and the processing of the VNIC notification
20465084Sjohnlev 	 * by the MAC client. During this window, it is possible for
20475084Sjohnlev 	 * an active MAC client to contine invoking mac_vnic_tx() while
20485084Sjohnlev 	 * the VNIC has already been removed. So we cannot assume
20495084Sjohnlev 	 * that mi_vnic_present will always be true when mac_vnic_tx()
20505084Sjohnlev 	 * is invoked.
20515084Sjohnlev 	 */
20525084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_READER);
20535084Sjohnlev 	if (!mip->mi_vnic_present) {
20545084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
20555084Sjohnlev 		freemsgchain(mp);
20565084Sjohnlev 		return (NULL);
20575084Sjohnlev 	}
20585084Sjohnlev 
20595084Sjohnlev 	ASSERT(mip->mi_vnic_tx != NULL);
20605084Sjohnlev 	mvt = mip->mi_vnic_tx;
20615084Sjohnlev 	MAC_VNIC_TXINFO_REFHOLD(mvt);
20625084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
20635084Sjohnlev 
20645084Sjohnlev 	mtfp = &mvt->mv_txinfo;
20655084Sjohnlev 	mtfp->mt_fn(mtfp->mt_arg, mp);
20665084Sjohnlev 
20675084Sjohnlev 	MAC_VNIC_TXINFO_REFRELE(mvt);
20685084Sjohnlev 	return (NULL);
20695084Sjohnlev }
20705084Sjohnlev 
20710Sstevel@tonic-gate /*
20720Sstevel@tonic-gate  * Transmit function -- ONLY used when there are registered loopback listeners.
20730Sstevel@tonic-gate  */
20740Sstevel@tonic-gate mblk_t *
20755084Sjohnlev mac_do_txloop(void *arg, mblk_t *bp, boolean_t call_vnic)
20760Sstevel@tonic-gate {
20770Sstevel@tonic-gate 	mac_impl_t	*mip = arg;
20780Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
20790Sstevel@tonic-gate 	mblk_t		*loop_bp, *resid_bp, *next_bp;
20800Sstevel@tonic-gate 
20815084Sjohnlev 	if (call_vnic) {
20825084Sjohnlev 		/*
20835084Sjohnlev 		 * In promiscous mode, a copy of the sent packet will
20845084Sjohnlev 		 * be sent to the client's promiscous receive entry
20855084Sjohnlev 		 * points via mac_vnic_tx()->
20865084Sjohnlev 		 * mac_active_rx_promisc()->mac_rx_default().
20875084Sjohnlev 		 */
20885084Sjohnlev 		return (mac_vnic_tx(arg, bp));
20895084Sjohnlev 	}
20905084Sjohnlev 
20910Sstevel@tonic-gate 	while (bp != NULL) {
20920Sstevel@tonic-gate 		next_bp = bp->b_next;
20930Sstevel@tonic-gate 		bp->b_next = NULL;
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 		if ((loop_bp = copymsg(bp)) == NULL)
20960Sstevel@tonic-gate 			goto noresources;
20970Sstevel@tonic-gate 
20982311Sseb 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
20990Sstevel@tonic-gate 			ASSERT(resid_bp == bp);
21000Sstevel@tonic-gate 			freemsg(loop_bp);
21010Sstevel@tonic-gate 			goto noresources;
21020Sstevel@tonic-gate 		}
21030Sstevel@tonic-gate 
21045084Sjohnlev 		rw_enter(&mip->mi_tx_lock, RW_READER);
21050Sstevel@tonic-gate 		mtfp = mip->mi_mtfp;
210656Smeem 		while (mtfp != NULL && loop_bp != NULL) {
21070Sstevel@tonic-gate 			bp = loop_bp;
210856Smeem 
210956Smeem 			/* XXX counter bump if copymsg() fails? */
211056Smeem 			if (mtfp->mtf_nextp != NULL)
21110Sstevel@tonic-gate 				loop_bp = copymsg(bp);
211256Smeem 			else
211356Smeem 				loop_bp = NULL;
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
211656Smeem 			mtfp = mtfp->mtf_nextp;
21170Sstevel@tonic-gate 		}
21185084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
21190Sstevel@tonic-gate 
212056Smeem 		/*
212156Smeem 		 * It's possible we've raced with the disabling of promiscuous
212256Smeem 		 * mode, in which case we can discard our copy.
212356Smeem 		 */
212456Smeem 		if (loop_bp != NULL)
212556Smeem 			freemsg(loop_bp);
212656Smeem 
21270Sstevel@tonic-gate 		bp = next_bp;
21280Sstevel@tonic-gate 	}
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 	return (NULL);
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate noresources:
21330Sstevel@tonic-gate 	bp->b_next = next_bp;
21340Sstevel@tonic-gate 	return (bp);
21350Sstevel@tonic-gate }
21360Sstevel@tonic-gate 
21375084Sjohnlev mblk_t *
21385084Sjohnlev mac_txloop(void *arg, mblk_t *bp)
21395084Sjohnlev {
21405084Sjohnlev 	return (mac_do_txloop(arg, bp, B_FALSE));
21415084Sjohnlev }
21425084Sjohnlev 
21435084Sjohnlev static mblk_t *
21445084Sjohnlev mac_vnic_txloop(void *arg, mblk_t *bp)
21455084Sjohnlev {
21465084Sjohnlev 	return (mac_do_txloop(arg, bp, B_TRUE));
21475084Sjohnlev }
21485084Sjohnlev 
21490Sstevel@tonic-gate void
21502311Sseb mac_link_update(mac_handle_t mh, link_state_t link)
21510Sstevel@tonic-gate {
21522311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
21530Sstevel@tonic-gate 
21540Sstevel@tonic-gate 	/*
21550Sstevel@tonic-gate 	 * Save the link state.
21560Sstevel@tonic-gate 	 */
21572311Sseb 	mip->mi_linkstate = link;
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate 	/*
21600Sstevel@tonic-gate 	 * Send a MAC_NOTE_LINK notification.
21610Sstevel@tonic-gate 	 */
21620Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_LINK);
21630Sstevel@tonic-gate }
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate void
21662311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
21670Sstevel@tonic-gate {
21682311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
21690Sstevel@tonic-gate 
21702311Sseb 	if (mip->mi_type->mt_addr_length == 0)
21712311Sseb 		return;
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate 	/*
21745895Syz147064 	 * If the address has not changed, do nothing.
21755895Syz147064 	 */
21765895Syz147064 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0)
21775895Syz147064 		return;
21785895Syz147064 
21795895Syz147064 	/*
21800Sstevel@tonic-gate 	 * Save the address.
21810Sstevel@tonic-gate 	 */
21822311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 	/*
21850Sstevel@tonic-gate 	 * Send a MAC_NOTE_UNICST notification.
21860Sstevel@tonic-gate 	 */
21870Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_UNICST);
21880Sstevel@tonic-gate }
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate void
21912311Sseb mac_tx_update(mac_handle_t mh)
21920Sstevel@tonic-gate {
21930Sstevel@tonic-gate 	/*
21940Sstevel@tonic-gate 	 * Send a MAC_NOTE_TX notification.
21950Sstevel@tonic-gate 	 */
21962311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
21970Sstevel@tonic-gate }
21980Sstevel@tonic-gate 
21990Sstevel@tonic-gate void
22002311Sseb mac_resource_update(mac_handle_t mh)
22010Sstevel@tonic-gate {
22020Sstevel@tonic-gate 	/*
22030Sstevel@tonic-gate 	 * Send a MAC_NOTE_RESOURCE notification.
22040Sstevel@tonic-gate 	 */
22052311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
22060Sstevel@tonic-gate }
22070Sstevel@tonic-gate 
22080Sstevel@tonic-gate mac_resource_handle_t
22092311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
22100Sstevel@tonic-gate {
22112311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
22120Sstevel@tonic-gate 	mac_resource_handle_t	mrh;
22130Sstevel@tonic-gate 	mac_resource_add_t	add;
22140Sstevel@tonic-gate 	void			*arg;
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 	rw_enter(&mip->mi_resource_lock, RW_READER);
22170Sstevel@tonic-gate 	add = mip->mi_resource_add;
22180Sstevel@tonic-gate 	arg = mip->mi_resource_add_arg;
22190Sstevel@tonic-gate 
22201184Skrgopi 	if (add != NULL)
22211184Skrgopi 		mrh = add(arg, mrp);
22221184Skrgopi 	else
22231184Skrgopi 		mrh = NULL;
22240Sstevel@tonic-gate 	rw_exit(&mip->mi_resource_lock);
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 	return (mrh);
22270Sstevel@tonic-gate }
22280Sstevel@tonic-gate 
22292311Sseb int
22302311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
22312311Sseb {
22322311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
22332311Sseb 
22342311Sseb 	/*
22352311Sseb 	 * Verify that the plugin supports MAC plugin data and that the
22362311Sseb 	 * supplied data is valid.
22372311Sseb 	 */
22382311Sseb 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
22392311Sseb 		return (EINVAL);
22402311Sseb 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
22412311Sseb 		return (EINVAL);
22422311Sseb 
22432311Sseb 	if (mip->mi_pdata != NULL)
22442311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
22452311Sseb 
22462311Sseb 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
22472311Sseb 	bcopy(mac_pdata, mip->mi_pdata, dsize);
22482311Sseb 	mip->mi_pdata_size = dsize;
22492311Sseb 
22502311Sseb 	/*
22512311Sseb 	 * Since the MAC plugin data is used to construct MAC headers that
22522311Sseb 	 * were cached in fast-path headers, we need to flush fast-path
22532311Sseb 	 * information for links associated with this mac.
22542311Sseb 	 */
22552311Sseb 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
22562311Sseb 	return (0);
22572311Sseb }
22582311Sseb 
22590Sstevel@tonic-gate void
22602311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
22610Sstevel@tonic-gate     boolean_t add)
22620Sstevel@tonic-gate {
22632311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
22640Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate 	/*
22670Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
22680Sstevel@tonic-gate 	 * driver's m_multicst entry point.
22690Sstevel@tonic-gate 	 */
22700Sstevel@tonic-gate 	if (refresh == NULL) {
22712311Sseb 		refresh = mip->mi_multicst;
22722311Sseb 		arg = mip->mi_driver;
22730Sstevel@tonic-gate 	}
22740Sstevel@tonic-gate 	ASSERT(refresh != NULL);
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 	/*
22770Sstevel@tonic-gate 	 * Walk the multicast address list and call the refresh function for
22780Sstevel@tonic-gate 	 * each address.
22790Sstevel@tonic-gate 	 */
22800Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
22810Sstevel@tonic-gate 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
22820Sstevel@tonic-gate 		refresh(arg, add, p->mma_addr);
22830Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
22840Sstevel@tonic-gate }
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate void
22872311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
22880Sstevel@tonic-gate {
22892311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
22900Sstevel@tonic-gate 	/*
22910Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
22922311Sseb 	 * driver's mi_unicst entry point.
22930Sstevel@tonic-gate 	 */
22940Sstevel@tonic-gate 	if (refresh == NULL) {
22952311Sseb 		refresh = mip->mi_unicst;
22962311Sseb 		arg = mip->mi_driver;
22970Sstevel@tonic-gate 	}
22980Sstevel@tonic-gate 	ASSERT(refresh != NULL);
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 	/*
23010Sstevel@tonic-gate 	 * Call the refresh function with the current unicast address.
23020Sstevel@tonic-gate 	 */
23030Sstevel@tonic-gate 	refresh(arg, mip->mi_addr);
23040Sstevel@tonic-gate }
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate void
23072311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
23080Sstevel@tonic-gate {
23092311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
23100Sstevel@tonic-gate 
23110Sstevel@tonic-gate 	/*
23120Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
23130Sstevel@tonic-gate 	 * driver's m_promisc entry point.
23140Sstevel@tonic-gate 	 */
23150Sstevel@tonic-gate 	if (refresh == NULL) {
23162311Sseb 		refresh = mip->mi_setpromisc;
23172311Sseb 		arg = mip->mi_driver;
23180Sstevel@tonic-gate 	}
23190Sstevel@tonic-gate 	ASSERT(refresh != NULL);
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate 	/*
23220Sstevel@tonic-gate 	 * Call the refresh function with the current promiscuity.
23230Sstevel@tonic-gate 	 */
23240Sstevel@tonic-gate 	refresh(arg, (mip->mi_devpromisc != 0));
23250Sstevel@tonic-gate }
23260Sstevel@tonic-gate 
23275895Syz147064 /*
23285895Syz147064  * The mac client requests that the mac not to change its margin size to
23295895Syz147064  * be less than the specified value.  If "current" is B_TRUE, then the client
23305895Syz147064  * requests the mac not to change its margin size to be smaller than the
23315895Syz147064  * current size. Further, return the current margin size value in this case.
23325895Syz147064  *
23335895Syz147064  * We keep every requested size in an ordered list from largest to smallest.
23345895Syz147064  */
23355895Syz147064 int
23365895Syz147064 mac_margin_add(mac_handle_t mh, uint32_t *marginp, boolean_t current)
23375895Syz147064 {
23385895Syz147064 	mac_impl_t		*mip = (mac_impl_t *)mh;
23395895Syz147064 	mac_margin_req_t	**pp, *p;
23405895Syz147064 	int			err = 0;
23415895Syz147064 
23425895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
23435895Syz147064 	if (current)
23445895Syz147064 		*marginp = mip->mi_margin;
23455895Syz147064 
23465895Syz147064 	/*
23475895Syz147064 	 * If the current margin value cannot satisfy the margin requested,
23485895Syz147064 	 * return ENOTSUP directly.
23495895Syz147064 	 */
23505895Syz147064 	if (*marginp > mip->mi_margin) {
23515895Syz147064 		err = ENOTSUP;
23525895Syz147064 		goto done;
23535895Syz147064 	}
23545895Syz147064 
23555895Syz147064 	/*
23565895Syz147064 	 * Check whether the given margin is already in the list. If so,
23575895Syz147064 	 * bump the reference count.
23585895Syz147064 	 */
23595895Syz147064 	for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
23605895Syz147064 		if (p->mmr_margin == *marginp) {
23615895Syz147064 			/*
23625895Syz147064 			 * The margin requested is already in the list,
23635895Syz147064 			 * so just bump the reference count.
23645895Syz147064 			 */
23655895Syz147064 			p->mmr_ref++;
23665895Syz147064 			goto done;
23675895Syz147064 		}
23685895Syz147064 		if (p->mmr_margin < *marginp)
23695895Syz147064 			break;
23705895Syz147064 	}
23715895Syz147064 
23725895Syz147064 
23735895Syz147064 	if ((p = kmem_zalloc(sizeof (mac_margin_req_t), KM_NOSLEEP)) == NULL) {
23745895Syz147064 		err = ENOMEM;
23755895Syz147064 		goto done;
23765895Syz147064 	}
23775895Syz147064 
23785895Syz147064 	p->mmr_margin = *marginp;
23795895Syz147064 	p->mmr_ref++;
23805895Syz147064 	p->mmr_nextp = *pp;
23815895Syz147064 	*pp = p;
23825895Syz147064 
23835895Syz147064 done:
23845895Syz147064 	rw_exit(&(mip->mi_data_lock));
23855895Syz147064 	return (err);
23865895Syz147064 }
23875895Syz147064 
23885895Syz147064 /*
23895895Syz147064  * The mac client requests to cancel its previous mac_margin_add() request.
23905895Syz147064  * We remove the requested margin size from the list.
23915895Syz147064  */
23925895Syz147064 int
23935895Syz147064 mac_margin_remove(mac_handle_t mh, uint32_t margin)
23945895Syz147064 {
23955895Syz147064 	mac_impl_t		*mip = (mac_impl_t *)mh;
23965895Syz147064 	mac_margin_req_t	**pp, *p;
23975895Syz147064 	int			err = 0;
23985895Syz147064 
23995895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
24005895Syz147064 	/*
24015895Syz147064 	 * Find the entry in the list for the given margin.
24025895Syz147064 	 */
24035895Syz147064 	for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
24045895Syz147064 		if (p->mmr_margin == margin) {
24055895Syz147064 			if (--p->mmr_ref == 0)
24065895Syz147064 				break;
24075895Syz147064 
24085895Syz147064 			/*
24095895Syz147064 			 * There is still a reference to this address so
24105895Syz147064 			 * there's nothing more to do.
24115895Syz147064 			 */
24125895Syz147064 			goto done;
24135895Syz147064 		}
24145895Syz147064 	}
24155895Syz147064 
24165895Syz147064 	/*
24175895Syz147064 	 * We did not find an entry for the given margin.
24185895Syz147064 	 */
24195895Syz147064 	if (p == NULL) {
24205895Syz147064 		err = ENOENT;
24215895Syz147064 		goto done;
24225895Syz147064 	}
24235895Syz147064 
24245895Syz147064 	ASSERT(p->mmr_ref == 0);
24255895Syz147064 
24265895Syz147064 	/*
24275895Syz147064 	 * Remove it from the list.
24285895Syz147064 	 */
24295895Syz147064 	*pp = p->mmr_nextp;
24305895Syz147064 	kmem_free(p, sizeof (mac_margin_req_t));
24315895Syz147064 done:
24325895Syz147064 	rw_exit(&(mip->mi_data_lock));
24335895Syz147064 	return (err);
24345895Syz147064 }
24355895Syz147064 
24365895Syz147064 /*
24375895Syz147064  * The mac client requests to get the mac's current margin value.
24385895Syz147064  */
24395895Syz147064 void
24405895Syz147064 mac_margin_get(mac_handle_t mh, uint32_t *marginp)
24415895Syz147064 {
24425895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
24435895Syz147064 
24445895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_READER);
24455895Syz147064 	*marginp = mip->mi_margin;
24465895Syz147064 	rw_exit(&(mip->mi_data_lock));
24475895Syz147064 }
24485895Syz147064 
24495895Syz147064 boolean_t
24505895Syz147064 mac_margin_update(mac_handle_t mh, uint32_t margin)
24515895Syz147064 {
24525895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
24535895Syz147064 	uint32_t	margin_needed = 0;
24545895Syz147064 
24555895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
24565895Syz147064 
24575895Syz147064 	if (mip->mi_mmrp != NULL)
24585895Syz147064 		margin_needed = mip->mi_mmrp->mmr_margin;
24595895Syz147064 
24605895Syz147064 	if (margin_needed <= margin)
24615895Syz147064 		mip->mi_margin = margin;
24625895Syz147064 
24635895Syz147064 	rw_exit(&(mip->mi_data_lock));
24645895Syz147064 
24655895Syz147064 	if (margin_needed <= margin)
24665895Syz147064 		i_mac_notify(mip, MAC_NOTE_MARGIN);
24675895Syz147064 
24685895Syz147064 	return (margin_needed <= margin);
24695895Syz147064 }
24705895Syz147064 
24710Sstevel@tonic-gate boolean_t
24725084Sjohnlev mac_do_active_set(mac_handle_t mh, boolean_t shareable)
24730Sstevel@tonic-gate {
24740Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
24770Sstevel@tonic-gate 	if (mip->mi_activelink) {
24780Sstevel@tonic-gate 		mutex_exit(&mip->mi_activelink_lock);
24790Sstevel@tonic-gate 		return (B_FALSE);
24800Sstevel@tonic-gate 	}
24810Sstevel@tonic-gate 	mip->mi_activelink = B_TRUE;
24825084Sjohnlev 	mip->mi_shareable = shareable;
24830Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
24840Sstevel@tonic-gate 	return (B_TRUE);
24850Sstevel@tonic-gate }
24860Sstevel@tonic-gate 
24875084Sjohnlev /*
24885084Sjohnlev  * Called by MAC clients. By default, active MAC clients cannot
24895084Sjohnlev  * share the NIC with VNICs.
24905084Sjohnlev  */
24915084Sjohnlev boolean_t
24925084Sjohnlev mac_active_set(mac_handle_t mh)
24935084Sjohnlev {
24945084Sjohnlev 	return (mac_do_active_set(mh, B_FALSE));
24955084Sjohnlev }
24965084Sjohnlev 
24975084Sjohnlev /*
24985084Sjohnlev  * Called by MAC clients which can share the NIC with VNICS, e.g. DLS.
24995084Sjohnlev  */
25005084Sjohnlev boolean_t
25015084Sjohnlev mac_active_shareable_set(mac_handle_t mh)
25025084Sjohnlev {
25035084Sjohnlev 	return (mac_do_active_set(mh, B_TRUE));
25045084Sjohnlev }
25055084Sjohnlev 
25060Sstevel@tonic-gate void
25070Sstevel@tonic-gate mac_active_clear(mac_handle_t mh)
25080Sstevel@tonic-gate {
25090Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
25120Sstevel@tonic-gate 	ASSERT(mip->mi_activelink);
25130Sstevel@tonic-gate 	mip->mi_activelink = B_FALSE;
25140Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
25150Sstevel@tonic-gate }
2516269Sericheng 
25175084Sjohnlev boolean_t
25185084Sjohnlev mac_vnic_set(mac_handle_t mh, mac_txinfo_t *tx_info, mac_getcapab_t getcapab_fn,
25195084Sjohnlev     void *getcapab_arg)
25205084Sjohnlev {
25215084Sjohnlev 	mac_impl_t	*mip = (mac_impl_t *)mh;
25225084Sjohnlev 	mac_vnic_tx_t	*vnic_tx;
25235084Sjohnlev 
25245084Sjohnlev 	mutex_enter(&mip->mi_activelink_lock);
25255084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_WRITER);
25265084Sjohnlev 	ASSERT(!mip->mi_vnic_present);
25275084Sjohnlev 
25285084Sjohnlev 	if (mip->mi_activelink && !mip->mi_shareable) {
25295084Sjohnlev 		/*
25305084Sjohnlev 		 * The NIC is already used by an active client which cannot
25315084Sjohnlev 		 * share it with VNICs.
25325084Sjohnlev 		 */
25335084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
25345084Sjohnlev 		mutex_exit(&mip->mi_activelink_lock);
25355084Sjohnlev 		return (B_FALSE);
25365084Sjohnlev 	}
25375084Sjohnlev 
25385084Sjohnlev 	vnic_tx = kmem_cache_alloc(mac_vnic_tx_cache, KM_SLEEP);
25395084Sjohnlev 	vnic_tx->mv_refs = 0;
25405084Sjohnlev 	vnic_tx->mv_txinfo = *tx_info;
25415084Sjohnlev 	vnic_tx->mv_clearing = B_FALSE;
25425084Sjohnlev 
25435084Sjohnlev 	mip->mi_vnic_present = B_TRUE;
25445084Sjohnlev 	mip->mi_vnic_tx = vnic_tx;
25455084Sjohnlev 	mip->mi_vnic_getcapab_fn = getcapab_fn;
25465084Sjohnlev 	mip->mi_vnic_getcapab_arg = getcapab_arg;
25475084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
25485084Sjohnlev 	mutex_exit(&mip->mi_activelink_lock);
25495084Sjohnlev 
25505084Sjohnlev 	i_mac_notify(mip, MAC_NOTE_VNIC);
25515084Sjohnlev 	return (B_TRUE);
25525084Sjohnlev }
25535084Sjohnlev 
25545084Sjohnlev void
25555084Sjohnlev mac_vnic_clear(mac_handle_t mh)
25565084Sjohnlev {
25575084Sjohnlev 	mac_impl_t *mip = (mac_impl_t *)mh;
25585084Sjohnlev 	mac_vnic_tx_t	*vnic_tx;
25595084Sjohnlev 
25605084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_WRITER);
25615084Sjohnlev 	ASSERT(mip->mi_vnic_present);
25625084Sjohnlev 	mip->mi_vnic_present = B_FALSE;
25635084Sjohnlev 	/*
25645084Sjohnlev 	 * Setting mi_vnic_tx to NULL here under the lock guarantees
25655084Sjohnlev 	 * that no new references to the current VNIC transmit structure
25665084Sjohnlev 	 * will be taken by mac_vnic_tx(). This is a necessary condition
25675084Sjohnlev 	 * for safely waiting for the reference count to drop to
25685084Sjohnlev 	 * zero below.
25695084Sjohnlev 	 */
25705084Sjohnlev 	vnic_tx = mip->mi_vnic_tx;
25715084Sjohnlev 	mip->mi_vnic_tx = NULL;
25725084Sjohnlev 	mip->mi_vnic_getcapab_fn = NULL;
25735084Sjohnlev 	mip->mi_vnic_getcapab_arg = NULL;
25745084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
25755084Sjohnlev 
25765084Sjohnlev 	i_mac_notify(mip, MAC_NOTE_VNIC);
25775084Sjohnlev 
25785084Sjohnlev 	/*
25795084Sjohnlev 	 * Wait for all TX calls referencing the VNIC transmit
25805084Sjohnlev 	 * entry point that was removed to complete.
25815084Sjohnlev 	 */
25825084Sjohnlev 	mutex_enter(&vnic_tx->mv_lock);
25835084Sjohnlev 	vnic_tx->mv_clearing = B_TRUE;
25845084Sjohnlev 	while (vnic_tx->mv_refs > 0)
25855084Sjohnlev 		cv_wait(&vnic_tx->mv_cv, &vnic_tx->mv_lock);
25865084Sjohnlev 	mutex_exit(&vnic_tx->mv_lock);
25875084Sjohnlev 	kmem_cache_free(mac_vnic_tx_cache, vnic_tx);
25885084Sjohnlev }
25895084Sjohnlev 
2590269Sericheng /*
2591269Sericheng  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
2592269Sericheng  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
2593269Sericheng  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
2594269Sericheng  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
2595269Sericheng  * cannot disappear while we are accessing it.
2596269Sericheng  */
2597269Sericheng typedef struct i_mac_info_state_s {
2598269Sericheng 	const char	*mi_name;
2599269Sericheng 	mac_info_t	*mi_infop;
2600269Sericheng } i_mac_info_state_t;
2601269Sericheng 
2602269Sericheng /*ARGSUSED*/
2603269Sericheng static uint_t
2604269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
2605269Sericheng {
2606269Sericheng 	i_mac_info_state_t	*statep = arg;
2607269Sericheng 	mac_impl_t		*mip = (mac_impl_t *)val;
2608269Sericheng 
26091852Syz147064 	if (mip->mi_disabled)
2610269Sericheng 		return (MH_WALK_CONTINUE);
2611269Sericheng 
2612269Sericheng 	if (strcmp(statep->mi_name,
26132311Sseb 	    ddi_driver_name(mip->mi_dip)) != 0)
2614269Sericheng 		return (MH_WALK_CONTINUE);
2615269Sericheng 
26162311Sseb 	statep->mi_infop = &mip->mi_info;
2617269Sericheng 	return (MH_WALK_TERMINATE);
2618269Sericheng }
2619269Sericheng 
2620269Sericheng boolean_t
2621269Sericheng mac_info_get(const char *name, mac_info_t *minfop)
2622269Sericheng {
2623269Sericheng 	i_mac_info_state_t	state;
2624269Sericheng 
2625269Sericheng 	rw_enter(&i_mac_impl_lock, RW_READER);
2626269Sericheng 	state.mi_name = name;
2627269Sericheng 	state.mi_infop = NULL;
2628269Sericheng 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
2629269Sericheng 	if (state.mi_infop == NULL) {
2630269Sericheng 		rw_exit(&i_mac_impl_lock);
2631269Sericheng 		return (B_FALSE);
2632269Sericheng 	}
2633269Sericheng 	*minfop = *state.mi_infop;
2634269Sericheng 	rw_exit(&i_mac_impl_lock);
2635269Sericheng 	return (B_TRUE);
2636269Sericheng }
2637269Sericheng 
26382311Sseb boolean_t
26395084Sjohnlev mac_do_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data,
26405084Sjohnlev     boolean_t is_vnic)
26412311Sseb {
26422311Sseb 	mac_impl_t *mip = (mac_impl_t *)mh;
26432311Sseb 
26445084Sjohnlev 	if (!is_vnic) {
26455084Sjohnlev 		rw_enter(&mip->mi_tx_lock, RW_READER);
26465084Sjohnlev 		if (mip->mi_vnic_present) {
26475084Sjohnlev 			boolean_t rv;
26485084Sjohnlev 
26495084Sjohnlev 			rv = mip->mi_vnic_getcapab_fn(mip->mi_vnic_getcapab_arg,
26505084Sjohnlev 			    cap, cap_data);
26515084Sjohnlev 			rw_exit(&mip->mi_tx_lock);
26525084Sjohnlev 			return (rv);
26535084Sjohnlev 		}
26545084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
26555084Sjohnlev 	}
26565084Sjohnlev 
26572311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
26582311Sseb 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
26592311Sseb 	else
26602311Sseb 		return (B_FALSE);
26612311Sseb }
26622311Sseb 
26632311Sseb boolean_t
26645084Sjohnlev mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
26655084Sjohnlev {
26665084Sjohnlev 	return (mac_do_capab_get(mh, cap, cap_data, B_FALSE));
26675084Sjohnlev }
26685084Sjohnlev 
26695084Sjohnlev boolean_t
26705084Sjohnlev mac_vnic_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
26715084Sjohnlev {
26725084Sjohnlev 	return (mac_do_capab_get(mh, cap, cap_data, B_TRUE));
26735084Sjohnlev }
26745084Sjohnlev 
26755084Sjohnlev boolean_t
26762311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
26772311Sseb {
26782311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
26792311Sseb 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
26802311Sseb 	    mip->mi_pdata));
26812311Sseb }
26822311Sseb 
26832311Sseb mblk_t *
26842311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
26852311Sseb     size_t extra_len)
26862311Sseb {
26872311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
26882311Sseb 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
26892311Sseb 	    mip->mi_pdata, payload, extra_len));
26902311Sseb }
26912311Sseb 
26922311Sseb int
26932311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
26942311Sseb {
26952311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
26962311Sseb 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
26972311Sseb 	    mhip));
26982311Sseb }
26992311Sseb 
27002311Sseb mblk_t *
27012311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp)
27022311Sseb {
27032311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
27042311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
27052311Sseb 		if (DB_REF(mp) > 1) {
27062311Sseb 			mblk_t *newmp = copymsg(mp);
27072760Sdg199075 			if (newmp == NULL)
27082760Sdg199075 				return (NULL);
27092311Sseb 			freemsg(mp);
27102311Sseb 			mp = newmp;
27112311Sseb 		}
27122311Sseb 		return (mip->mi_type->mt_ops.mtops_header_cook(mp,
27132311Sseb 		    mip->mi_pdata));
27142311Sseb 	}
27152311Sseb 	return (mp);
27162311Sseb }
27172311Sseb 
27182311Sseb mblk_t *
27192311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp)
27202311Sseb {
27212311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
27222311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
27232311Sseb 		if (DB_REF(mp) > 1) {
27242311Sseb 			mblk_t *newmp = copymsg(mp);
27252760Sdg199075 			if (newmp == NULL)
27262760Sdg199075 				return (NULL);
27272311Sseb 			freemsg(mp);
27282311Sseb 			mp = newmp;
27292311Sseb 		}
27302311Sseb 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
27312311Sseb 		    mip->mi_pdata));
27322311Sseb 	}
27332311Sseb 	return (mp);
27342311Sseb }
27352311Sseb 
2736269Sericheng void
2737269Sericheng mac_init_ops(struct dev_ops *ops, const char *name)
2738269Sericheng {
2739269Sericheng 	dld_init_ops(ops, name);
2740269Sericheng }
2741269Sericheng 
2742269Sericheng void
2743269Sericheng mac_fini_ops(struct dev_ops *ops)
2744269Sericheng {
2745269Sericheng 	dld_fini_ops(ops);
2746269Sericheng }
27472311Sseb 
27482311Sseb /*
27492311Sseb  * MAC Type Plugin functions.
27502311Sseb  */
27512311Sseb 
27522311Sseb mactype_register_t *
27532311Sseb mactype_alloc(uint_t mactype_version)
27542311Sseb {
27552311Sseb 	mactype_register_t *mtrp;
27562311Sseb 
27572311Sseb 	/*
27582311Sseb 	 * Make sure there isn't a version mismatch between the plugin and
27592311Sseb 	 * the framework.  In the future, if multiple versions are
27602311Sseb 	 * supported, this check could become more sophisticated.
27612311Sseb 	 */
27622311Sseb 	if (mactype_version != MACTYPE_VERSION)
27632311Sseb 		return (NULL);
27642311Sseb 
27652311Sseb 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
27662311Sseb 	mtrp->mtr_version = mactype_version;
27672311Sseb 	return (mtrp);
27682311Sseb }
27692311Sseb 
27702311Sseb void
27712311Sseb mactype_free(mactype_register_t *mtrp)
27722311Sseb {
27732311Sseb 	kmem_free(mtrp, sizeof (mactype_register_t));
27742311Sseb }
27752311Sseb 
27762311Sseb int
27772311Sseb mactype_register(mactype_register_t *mtrp)
27782311Sseb {
27792311Sseb 	mactype_t	*mtp;
27802311Sseb 	mactype_ops_t	*ops = mtrp->mtr_ops;
27812311Sseb 
27822311Sseb 	/* Do some sanity checking before we register this MAC type. */
2783*6353Sdr146992 	if (mtrp->mtr_ident == NULL || ops == NULL)
27842311Sseb 		return (EINVAL);
27852311Sseb 
27862311Sseb 	/*
27872311Sseb 	 * Verify that all mandatory callbacks are set in the ops
27882311Sseb 	 * vector.
27892311Sseb 	 */
27902311Sseb 	if (ops->mtops_unicst_verify == NULL ||
27912311Sseb 	    ops->mtops_multicst_verify == NULL ||
27922311Sseb 	    ops->mtops_sap_verify == NULL ||
27932311Sseb 	    ops->mtops_header == NULL ||
27942311Sseb 	    ops->mtops_header_info == NULL) {
27952311Sseb 		return (EINVAL);
27962311Sseb 	}
27972311Sseb 
27982311Sseb 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
27992311Sseb 	mtp->mt_ident = mtrp->mtr_ident;
28002311Sseb 	mtp->mt_ops = *ops;
28012311Sseb 	mtp->mt_type = mtrp->mtr_mactype;
28023147Sxc151355 	mtp->mt_nativetype = mtrp->mtr_nativetype;
28032311Sseb 	mtp->mt_addr_length = mtrp->mtr_addrlen;
28042311Sseb 	if (mtrp->mtr_brdcst_addr != NULL) {
28052311Sseb 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
28062311Sseb 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
28072311Sseb 		    mtrp->mtr_addrlen);
28082311Sseb 	}
28092311Sseb 
28102311Sseb 	mtp->mt_stats = mtrp->mtr_stats;
28112311Sseb 	mtp->mt_statcount = mtrp->mtr_statcount;
28122311Sseb 
28132311Sseb 	if (mod_hash_insert(i_mactype_hash,
28142311Sseb 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
28152311Sseb 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
28162311Sseb 		kmem_free(mtp, sizeof (*mtp));
28172311Sseb 		return (EEXIST);
28182311Sseb 	}
28192311Sseb 	return (0);
28202311Sseb }
28212311Sseb 
28222311Sseb int
28232311Sseb mactype_unregister(const char *ident)
28242311Sseb {
28252311Sseb 	mactype_t	*mtp;
28262311Sseb 	mod_hash_val_t	val;
28272311Sseb 	int 		err;
28282311Sseb 
28292311Sseb 	/*
28302311Sseb 	 * Let's not allow MAC drivers to use this plugin while we're
28313288Sseb 	 * trying to unregister it.  Holding i_mactype_lock also prevents a
28323288Sseb 	 * plugin from unregistering while a MAC driver is attempting to
28333288Sseb 	 * hold a reference to it in i_mactype_getplugin().
28342311Sseb 	 */
28353288Sseb 	mutex_enter(&i_mactype_lock);
28362311Sseb 
28372311Sseb 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
28382311Sseb 	    (mod_hash_val_t *)&mtp)) != 0) {
28392311Sseb 		/* A plugin is trying to unregister, but it never registered. */
28403288Sseb 		err = ENXIO;
28413288Sseb 		goto done;
28422311Sseb 	}
28432311Sseb 
28443288Sseb 	if (mtp->mt_ref != 0) {
28453288Sseb 		err = EBUSY;
28463288Sseb 		goto done;
28472311Sseb 	}
28482311Sseb 
28492311Sseb 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
28502311Sseb 	ASSERT(err == 0);
28512311Sseb 	if (err != 0) {
28522311Sseb 		/* This should never happen, thus the ASSERT() above. */
28533288Sseb 		err = EINVAL;
28543288Sseb 		goto done;
28552311Sseb 	}
28562311Sseb 	ASSERT(mtp == (mactype_t *)val);
28572311Sseb 
28582311Sseb 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
28592311Sseb 	kmem_free(mtp, sizeof (mactype_t));
28603288Sseb done:
28613288Sseb 	mutex_exit(&i_mactype_lock);
28623288Sseb 	return (err);
28632311Sseb }
28645903Ssowmini 
28655903Ssowmini int
28665903Ssowmini mac_set_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize)
28675903Ssowmini {
28685903Ssowmini 	int err = ENOTSUP;
28695903Ssowmini 	mac_impl_t *mip = (mac_impl_t *)mh;
28705903Ssowmini 
28715903Ssowmini 	if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) {
28725903Ssowmini 		err = mip->mi_callbacks->mc_setprop(mip->mi_driver,
28735903Ssowmini 		    macprop->mp_name, macprop->mp_id, valsize, val);
28745903Ssowmini 	}
28755903Ssowmini 	return (err);
28765903Ssowmini }
28775903Ssowmini 
28785903Ssowmini int
28795903Ssowmini mac_get_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize)
28805903Ssowmini {
28815903Ssowmini 	int err = ENOTSUP;
28825903Ssowmini 	mac_impl_t *mip = (mac_impl_t *)mh;
28835903Ssowmini 
28845903Ssowmini 	if (mip->mi_callbacks->mc_callbacks & MC_GETPROP) {
28855903Ssowmini 		err = mip->mi_callbacks->mc_getprop(mip->mi_driver,
28865903Ssowmini 		    macprop->mp_name, macprop->mp_id, valsize, val);
28875903Ssowmini 	}
28885903Ssowmini 	return (err);
28895903Ssowmini }
28905903Ssowmini 
28915903Ssowmini int
28925903Ssowmini mac_maxsdu_update(mac_handle_t mh, uint_t sdu_max)
28935903Ssowmini {
28945903Ssowmini 	mac_impl_t	*mip = (mac_impl_t *)mh;
28955903Ssowmini 
28965903Ssowmini 	if (sdu_max <= mip->mi_sdu_min)
28975903Ssowmini 		return (EINVAL);
28985903Ssowmini 	mip->mi_sdu_max = sdu_max;
28995903Ssowmini 
29005903Ssowmini 	/* Send a MAC_NOTE_SDU_SIZE notification. */
29015903Ssowmini 	i_mac_notify(mip, MAC_NOTE_SDU_SIZE);
29025903Ssowmini 	return (0);
29035903Ssowmini }
2904