xref: /onnv-gate/usr/src/uts/common/io/mac/mac.c (revision 7406:c95120d1b5a9)
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 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * MAC Services Module
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/conf.h>
345895Syz147064 #include <sys/id_space.h>
356077Syz147064 #include <sys/esunddi.h>
360Sstevel@tonic-gate #include <sys/stat.h>
375895Syz147064 #include <sys/mkdev.h>
380Sstevel@tonic-gate #include <sys/stream.h>
390Sstevel@tonic-gate #include <sys/strsun.h>
400Sstevel@tonic-gate #include <sys/strsubr.h>
410Sstevel@tonic-gate #include <sys/dlpi.h>
425895Syz147064 #include <sys/dls.h>
43269Sericheng #include <sys/modhash.h>
445895Syz147064 #include <sys/vlan.h>
450Sstevel@tonic-gate #include <sys/mac.h>
460Sstevel@tonic-gate #include <sys/mac_impl.h>
47269Sericheng #include <sys/dld.h>
482311Sseb #include <sys/modctl.h>
493448Sdh155122 #include <sys/fs/dv_node.h>
505009Sgd78059 #include <sys/thread.h>
515009Sgd78059 #include <sys/proc.h>
525009Sgd78059 #include <sys/callb.h>
535009Sgd78059 #include <sys/cpuvar.h>
543288Sseb #include <sys/atomic.h>
554913Sethindra #include <sys/sdt.h>
565903Ssowmini #include <inet/nd.h>
576512Ssowmini #include <sys/ethernet.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 *);
816512Ssowmini static void   mac_register_priv_prop(mac_impl_t *, mac_priv_prop_t *, uint_t);
82*7406SSowmini.Varadhan@Sun.COM static void   mac_unregister_priv_prop(mac_impl_t *);
831852Syz147064 
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate  * Private functions.
860Sstevel@tonic-gate  */
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*ARGSUSED*/
890Sstevel@tonic-gate static int
900Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	bzero(buf, sizeof (mac_impl_t));
950Sstevel@tonic-gate 
962311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
995895Syz147064 	rw_init(&mip->mi_gen_lock, NULL, RW_DRIVER, NULL);
1000Sstevel@tonic-gate 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
1010Sstevel@tonic-gate 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
1020Sstevel@tonic-gate 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
1035084Sjohnlev 	rw_init(&mip->mi_tx_lock, NULL, RW_DRIVER, NULL);
1040Sstevel@tonic-gate 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
1050Sstevel@tonic-gate 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
1065009Sgd78059 	mutex_init(&mip->mi_notify_bits_lock, NULL, MUTEX_DRIVER, NULL);
1071852Syz147064 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL);
1084913Sethindra 	mutex_init(&mip->mi_lock, NULL, MUTEX_DRIVER, NULL);
1094913Sethindra 	cv_init(&mip->mi_rx_cv, NULL, CV_DRIVER, NULL);
1100Sstevel@tonic-gate 	return (0);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*ARGSUSED*/
1140Sstevel@tonic-gate static void
1150Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	ASSERT(mip->mi_ref == 0);
1205895Syz147064 	ASSERT(!mip->mi_exclusive);
1210Sstevel@tonic-gate 	ASSERT(mip->mi_active == 0);
1222311Sseb 	ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
1230Sstevel@tonic-gate 	ASSERT(mip->mi_devpromisc == 0);
1240Sstevel@tonic-gate 	ASSERT(mip->mi_promisc == 0);
1250Sstevel@tonic-gate 	ASSERT(mip->mi_mmap == NULL);
1265895Syz147064 	ASSERT(mip->mi_mmrp == NULL);
1270Sstevel@tonic-gate 	ASSERT(mip->mi_mnfp == NULL);
1280Sstevel@tonic-gate 	ASSERT(mip->mi_resource_add == NULL);
1290Sstevel@tonic-gate 	ASSERT(mip->mi_ksp == NULL);
1302311Sseb 	ASSERT(mip->mi_kstat_count == 0);
1315009Sgd78059 	ASSERT(mip->mi_notify_bits == 0);
1325009Sgd78059 	ASSERT(mip->mi_notify_thread == NULL);
1330Sstevel@tonic-gate 
1345895Syz147064 	rw_destroy(&mip->mi_gen_lock);
1350Sstevel@tonic-gate 	rw_destroy(&mip->mi_state_lock);
1360Sstevel@tonic-gate 	rw_destroy(&mip->mi_data_lock);
1370Sstevel@tonic-gate 	rw_destroy(&mip->mi_notify_lock);
1380Sstevel@tonic-gate 	rw_destroy(&mip->mi_rx_lock);
1395084Sjohnlev 	rw_destroy(&mip->mi_tx_lock);
1400Sstevel@tonic-gate 	rw_destroy(&mip->mi_resource_lock);
1410Sstevel@tonic-gate 	mutex_destroy(&mip->mi_activelink_lock);
1425009Sgd78059 	mutex_destroy(&mip->mi_notify_bits_lock);
1431852Syz147064 	cv_destroy(&mip->mi_notify_cv);
1444913Sethindra 	mutex_destroy(&mip->mi_lock);
1454913Sethindra 	cv_destroy(&mip->mi_rx_cv);
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1485084Sjohnlev /*
1495084Sjohnlev  * mac_vnic_tx_t kmem cache support functions.
1505084Sjohnlev  */
1515084Sjohnlev 
1525084Sjohnlev /* ARGSUSED */
1535084Sjohnlev static int
1545084Sjohnlev i_mac_vnic_tx_ctor(void *buf, void *arg, int mkflag)
1555084Sjohnlev {
1565084Sjohnlev 	mac_vnic_tx_t *vnic_tx = buf;
1575084Sjohnlev 
1585084Sjohnlev 	bzero(buf, sizeof (mac_vnic_tx_t));
1595084Sjohnlev 	mutex_init(&vnic_tx->mv_lock, NULL, MUTEX_DRIVER, NULL);
1605084Sjohnlev 	cv_init(&vnic_tx->mv_cv, NULL, CV_DRIVER, NULL);
1615084Sjohnlev 	return (0);
1625084Sjohnlev }
1635084Sjohnlev 
1645084Sjohnlev /* ARGSUSED */
1655084Sjohnlev static void
1665084Sjohnlev i_mac_vnic_tx_dtor(void *buf, void *arg)
1675084Sjohnlev {
1685084Sjohnlev 	mac_vnic_tx_t *vnic_tx = buf;
1695084Sjohnlev 
1705084Sjohnlev 	ASSERT(vnic_tx->mv_refs == 0);
1715084Sjohnlev 	mutex_destroy(&vnic_tx->mv_lock);
1725084Sjohnlev 	cv_destroy(&vnic_tx->mv_cv);
1735084Sjohnlev }
1745084Sjohnlev 
1750Sstevel@tonic-gate static void
1760Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
1770Sstevel@tonic-gate {
1781852Syz147064 	rw_enter(&i_mac_impl_lock, RW_READER);
1791852Syz147064 	if (mip->mi_disabled)
1801852Syz147064 		goto exit;
1811852Syz147064 
1825009Sgd78059 	/*
1835009Sgd78059 	 * Guard against incorrect notifications.  (Running a newer
1845009Sgd78059 	 * mac client against an older implementation?)
1855009Sgd78059 	 */
1865009Sgd78059 	if (type >= MAC_NNOTE)
1871852Syz147064 		goto exit;
1881852Syz147064 
1895009Sgd78059 	mutex_enter(&mip->mi_notify_bits_lock);
1905009Sgd78059 	mip->mi_notify_bits |= (1 << type);
1915009Sgd78059 	cv_broadcast(&mip->mi_notify_cv);
1925009Sgd78059 	mutex_exit(&mip->mi_notify_bits_lock);
1931852Syz147064 
1941852Syz147064 exit:
1951852Syz147064 	rw_exit(&i_mac_impl_lock);
1961852Syz147064 }
1971852Syz147064 
1981852Syz147064 static void
1994403Sgd78059 i_mac_log_link_state(mac_impl_t *mip)
2004403Sgd78059 {
2014403Sgd78059 	/*
2024403Sgd78059 	 * If no change, then it is not interesting.
2034403Sgd78059 	 */
2044403Sgd78059 	if (mip->mi_lastlinkstate == mip->mi_linkstate)
2054403Sgd78059 		return;
2064403Sgd78059 
2074403Sgd78059 	switch (mip->mi_linkstate) {
2084403Sgd78059 	case LINK_STATE_UP:
2094403Sgd78059 		if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) {
2104403Sgd78059 			char det[200];
2114403Sgd78059 
2124403Sgd78059 			mip->mi_type->mt_ops.mtops_link_details(det,
2134403Sgd78059 			    sizeof (det), (mac_handle_t)mip, mip->mi_pdata);
2144403Sgd78059 
2154403Sgd78059 			cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det);
2164403Sgd78059 		} else {
2174403Sgd78059 			cmn_err(CE_NOTE, "!%s link up", mip->mi_name);
2184403Sgd78059 		}
2194403Sgd78059 		break;
2204403Sgd78059 
2214403Sgd78059 	case LINK_STATE_DOWN:
2224403Sgd78059 		/*
2234403Sgd78059 		 * Only transitions from UP to DOWN are interesting
2244403Sgd78059 		 */
2254403Sgd78059 		if (mip->mi_lastlinkstate != LINK_STATE_UNKNOWN)
2264403Sgd78059 			cmn_err(CE_NOTE, "!%s link down", mip->mi_name);
2274403Sgd78059 		break;
2284403Sgd78059 
2294403Sgd78059 	case LINK_STATE_UNKNOWN:
2304403Sgd78059 		/*
2314403Sgd78059 		 * This case is normally not interesting.
2324403Sgd78059 		 */
2334403Sgd78059 		break;
2344403Sgd78059 	}
2354403Sgd78059 	mip->mi_lastlinkstate = mip->mi_linkstate;
2364403Sgd78059 }
2374403Sgd78059 
2384403Sgd78059 static void
2395009Sgd78059 i_mac_notify_thread(void *arg)
2401852Syz147064 {
2415009Sgd78059 	mac_impl_t	*mip = arg;
2425009Sgd78059 	callb_cpr_t	cprinfo;
2435009Sgd78059 
2445009Sgd78059 	CALLB_CPR_INIT(&cprinfo, &mip->mi_notify_bits_lock, callb_generic_cpr,
2455009Sgd78059 	    "i_mac_notify_thread");
2465009Sgd78059 
2475009Sgd78059 	mutex_enter(&mip->mi_notify_bits_lock);
2485009Sgd78059 	for (;;) {
2495009Sgd78059 		uint32_t	bits;
2505009Sgd78059 		uint32_t	type;
2510Sstevel@tonic-gate 
2525009Sgd78059 		bits = mip->mi_notify_bits;
2535009Sgd78059 		if (bits == 0) {
2545009Sgd78059 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
2555009Sgd78059 			cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
2565009Sgd78059 			CALLB_CPR_SAFE_END(&cprinfo, &mip->mi_notify_bits_lock);
2575009Sgd78059 			continue;
2585009Sgd78059 		}
2595009Sgd78059 		mip->mi_notify_bits = 0;
2605009Sgd78059 
2615009Sgd78059 		if ((bits & (1 << MAC_NNOTE)) != 0) {
2625009Sgd78059 			/* request to quit */
2635009Sgd78059 			ASSERT(mip->mi_disabled);
2645009Sgd78059 			break;
2655009Sgd78059 		}
2665009Sgd78059 
2675009Sgd78059 		mutex_exit(&mip->mi_notify_bits_lock);
2681852Syz147064 
2695009Sgd78059 		/*
2705009Sgd78059 		 * Log link changes.
2715009Sgd78059 		 */
2725009Sgd78059 		if ((bits & (1 << MAC_NOTE_LINK)) != 0)
2735009Sgd78059 			i_mac_log_link_state(mip);
2745009Sgd78059 
2755009Sgd78059 		/*
2765009Sgd78059 		 * Do notification callbacks for each notification type.
2775009Sgd78059 		 */
2785009Sgd78059 		for (type = 0; type < MAC_NNOTE; type++) {
2795009Sgd78059 			mac_notify_fn_t	*mnfp;
2805009Sgd78059 
2815009Sgd78059 			if ((bits & (1 << type)) == 0) {
2825009Sgd78059 				continue;
2835009Sgd78059 			}
2844403Sgd78059 
2855009Sgd78059 			/*
2865009Sgd78059 			 * Walk the list of notifications.
2875009Sgd78059 			 */
2885009Sgd78059 			rw_enter(&mip->mi_notify_lock, RW_READER);
2895009Sgd78059 			for (mnfp = mip->mi_mnfp; mnfp != NULL;
2905009Sgd78059 			    mnfp = mnfp->mnf_nextp) {
2910Sstevel@tonic-gate 
2925009Sgd78059 				mnfp->mnf_fn(mnfp->mnf_arg, type);
2935009Sgd78059 			}
2945009Sgd78059 			rw_exit(&mip->mi_notify_lock);
2955009Sgd78059 		}
2965009Sgd78059 
2975009Sgd78059 		mutex_enter(&mip->mi_notify_bits_lock);
2980Sstevel@tonic-gate 	}
2995009Sgd78059 
3005009Sgd78059 	mip->mi_notify_thread = NULL;
3015009Sgd78059 	cv_broadcast(&mip->mi_notify_cv);
3025009Sgd78059 
3035009Sgd78059 	CALLB_CPR_EXIT(&cprinfo);
3045009Sgd78059 
3055009Sgd78059 	thread_exit();
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3082311Sseb static mactype_t *
3093288Sseb i_mactype_getplugin(const char *pname)
3102311Sseb {
3112311Sseb 	mactype_t	*mtype = NULL;
3122311Sseb 	boolean_t	tried_modload = B_FALSE;
3132311Sseb 
3143288Sseb 	mutex_enter(&i_mactype_lock);
3153288Sseb 
3162311Sseb find_registered_mactype:
3173288Sseb 	if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname,
3183288Sseb 	    (mod_hash_val_t *)&mtype) != 0) {
3193288Sseb 		if (!tried_modload) {
3203288Sseb 			/*
3213288Sseb 			 * If the plugin has not yet been loaded, then
3223288Sseb 			 * attempt to load it now.  If modload() succeeds,
3233288Sseb 			 * the plugin should have registered using
3243288Sseb 			 * mactype_register(), in which case we can go back
3253288Sseb 			 * and attempt to find it again.
3263288Sseb 			 */
3273288Sseb 			if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) {
3283288Sseb 				tried_modload = B_TRUE;
3293288Sseb 				goto find_registered_mactype;
3303288Sseb 			}
3313288Sseb 		}
3323288Sseb 	} else {
3332311Sseb 		/*
3343288Sseb 		 * Note that there's no danger that the plugin we've loaded
3353288Sseb 		 * could be unloaded between the modload() step and the
3363288Sseb 		 * reference count bump here, as we're holding
3373288Sseb 		 * i_mactype_lock, which mactype_unregister() also holds.
3382311Sseb 		 */
3393288Sseb 		atomic_inc_32(&mtype->mt_ref);
3402311Sseb 	}
3412311Sseb 
3423288Sseb 	mutex_exit(&i_mactype_lock);
3433288Sseb 	return (mtype);
3442311Sseb }
3452311Sseb 
3460Sstevel@tonic-gate /*
3470Sstevel@tonic-gate  * Module initialization functions.
3480Sstevel@tonic-gate  */
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate void
3510Sstevel@tonic-gate mac_init(void)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
3542311Sseb 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
3552311Sseb 	    NULL, NULL, NULL, 0);
3560Sstevel@tonic-gate 	ASSERT(i_mac_impl_cachep != NULL);
3570Sstevel@tonic-gate 
3585084Sjohnlev 	mac_vnic_tx_cache = kmem_cache_create("mac_vnic_tx_cache",
3595084Sjohnlev 	    sizeof (mac_vnic_tx_t), 0, i_mac_vnic_tx_ctor, i_mac_vnic_tx_dtor,
3605084Sjohnlev 	    NULL, NULL, NULL, 0);
3615084Sjohnlev 	ASSERT(mac_vnic_tx_cache != NULL);
3625084Sjohnlev 
363269Sericheng 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
364269Sericheng 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
365269Sericheng 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
366269Sericheng 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
367269Sericheng 	i_mac_impl_count = 0;
3682311Sseb 
3692311Sseb 	i_mactype_hash = mod_hash_create_extended("mactype_hash",
3702311Sseb 	    MACTYPE_HASHSZ,
3712311Sseb 	    mod_hash_null_keydtor, mod_hash_null_valdtor,
3722311Sseb 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
3735895Syz147064 
3745895Syz147064 	/*
3755895Syz147064 	 * Allocate an id space to manage minor numbers. The range of the
3765895Syz147064 	 * space will be from MAC_MAX_MINOR+1 to MAXMIN32 (maximum legal
3775895Syz147064 	 * minor number is MAXMIN, but id_t is type of integer and does not
3785895Syz147064 	 * allow MAXMIN).
3795895Syz147064 	 */
3805895Syz147064 	minor_ids = id_space_create("mac_minor_ids", MAC_MAX_MINOR+1, MAXMIN32);
3815895Syz147064 	ASSERT(minor_ids != NULL);
3825895Syz147064 	minor_count = 0;
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate int
3860Sstevel@tonic-gate mac_fini(void)
3870Sstevel@tonic-gate {
3885895Syz147064 	if (i_mac_impl_count > 0 || minor_count > 0)
389269Sericheng 		return (EBUSY);
3900Sstevel@tonic-gate 
3915895Syz147064 	id_space_destroy(minor_ids);
3925895Syz147064 
393269Sericheng 	mod_hash_destroy_hash(i_mac_impl_hash);
394269Sericheng 	rw_destroy(&i_mac_impl_lock);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	kmem_cache_destroy(i_mac_impl_cachep);
3975084Sjohnlev 	kmem_cache_destroy(mac_vnic_tx_cache);
3982311Sseb 
3992311Sseb 	mod_hash_destroy_hash(i_mactype_hash);
4000Sstevel@tonic-gate 	return (0);
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate /*
4040Sstevel@tonic-gate  * Client functions.
4050Sstevel@tonic-gate  */
4060Sstevel@tonic-gate 
4075895Syz147064 static int
4085895Syz147064 mac_hold(const char *macname, mac_impl_t **pmip)
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate 	mac_impl_t	*mip;
4110Sstevel@tonic-gate 	int		err;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/*
4140Sstevel@tonic-gate 	 * Check the device name length to make sure it won't overflow our
4150Sstevel@tonic-gate 	 * buffer.
4160Sstevel@tonic-gate 	 */
4172311Sseb 	if (strlen(macname) >= MAXNAMELEN)
4180Sstevel@tonic-gate 		return (EINVAL);
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/*
4215895Syz147064 	 * Look up its entry in the global hash table.
4220Sstevel@tonic-gate 	 */
4235895Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4245895Syz147064 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
4255895Syz147064 	    (mod_hash_val_t *)&mip);
4265895Syz147064 
4275895Syz147064 	if (err != 0) {
4285895Syz147064 		rw_exit(&i_mac_impl_lock);
4295895Syz147064 		return (ENOENT);
4305895Syz147064 	}
4315895Syz147064 
4325895Syz147064 	if (mip->mi_disabled) {
4335895Syz147064 		rw_exit(&i_mac_impl_lock);
4345895Syz147064 		return (ENOENT);
4355895Syz147064 	}
4365895Syz147064 
4375895Syz147064 	if (mip->mi_exclusive) {
4385895Syz147064 		rw_exit(&i_mac_impl_lock);
4395895Syz147064 		return (EBUSY);
4405895Syz147064 	}
4415895Syz147064 
4425895Syz147064 	mip->mi_ref++;
4435895Syz147064 	rw_exit(&i_mac_impl_lock);
4445895Syz147064 
4455895Syz147064 	*pmip = mip;
4465895Syz147064 	return (0);
4475895Syz147064 }
4485895Syz147064 
4495895Syz147064 static void
4505895Syz147064 mac_rele(mac_impl_t *mip)
4515895Syz147064 {
4525895Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4535895Syz147064 	ASSERT(mip->mi_ref != 0);
4545895Syz147064 	if (--mip->mi_ref == 0)
4555895Syz147064 		ASSERT(!mip->mi_activelink);
4565895Syz147064 	rw_exit(&i_mac_impl_lock);
4575895Syz147064 }
4585895Syz147064 
4595895Syz147064 int
4605895Syz147064 mac_hold_exclusive(mac_handle_t mh)
4615895Syz147064 {
4625895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
4635084Sjohnlev 
4640Sstevel@tonic-gate 	/*
4655895Syz147064 	 * Look up its entry in the global hash table.
4660Sstevel@tonic-gate 	 */
4675895Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4685895Syz147064 	if (mip->mi_disabled) {
4695895Syz147064 		rw_exit(&i_mac_impl_lock);
4705895Syz147064 		return (ENOENT);
4715895Syz147064 	}
4725895Syz147064 
4735895Syz147064 	if (mip->mi_ref != 0) {
4745895Syz147064 		rw_exit(&i_mac_impl_lock);
4755895Syz147064 		return (EBUSY);
4765895Syz147064 	}
4775895Syz147064 
4785895Syz147064 	ASSERT(!mip->mi_exclusive);
4795895Syz147064 
4805895Syz147064 	mip->mi_ref++;
4815895Syz147064 	mip->mi_exclusive = B_TRUE;
4825895Syz147064 	rw_exit(&i_mac_impl_lock);
4835895Syz147064 	return (0);
4845895Syz147064 }
4855895Syz147064 
4865895Syz147064 void
4875895Syz147064 mac_rele_exclusive(mac_handle_t mh)
4885895Syz147064 {
4895895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	/*
4920Sstevel@tonic-gate 	 * Look up its entry in the global hash table.
4930Sstevel@tonic-gate 	 */
494269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
4955895Syz147064 	ASSERT(mip->mi_ref == 1 && mip->mi_exclusive);
4965895Syz147064 	mip->mi_ref--;
4975895Syz147064 	mip->mi_exclusive = B_FALSE;
4985895Syz147064 	rw_exit(&i_mac_impl_lock);
4995895Syz147064 }
5005895Syz147064 
5015895Syz147064 int
5025895Syz147064 mac_open(const char *macname, mac_handle_t *mhp)
5035895Syz147064 {
5045895Syz147064 	mac_impl_t	*mip;
5055895Syz147064 	int		err;
5065895Syz147064 
5075895Syz147064 	/*
5085895Syz147064 	 * Look up its entry in the global hash table.
5095895Syz147064 	 */
5105895Syz147064 	if ((err = mac_hold(macname, &mip)) != 0)
5115895Syz147064 		return (err);
5125895Syz147064 
5136077Syz147064 	/*
5146077Syz147064 	 * Hold the dip associated to the MAC to prevent it from being
5156077Syz147064 	 * detached. For a softmac, its underlying dip is held by the
5166077Syz147064 	 * mi_open() callback.
5176077Syz147064 	 *
5186077Syz147064 	 * This is done to be more tolerant with some defective drivers,
5196077Syz147064 	 * which incorrectly handle mac_unregister() failure in their
5206077Syz147064 	 * xxx_detach() routine. For example, some drivers ignore the
5216077Syz147064 	 * failure of mac_unregister() and free all resources that
5226077Syz147064 	 * that are needed for data transmition.
5236077Syz147064 	 */
5246077Syz147064 	e_ddi_hold_devi(mip->mi_dip);
5256077Syz147064 
5265895Syz147064 	rw_enter(&mip->mi_gen_lock, RW_WRITER);
5275895Syz147064 
5285895Syz147064 	if ((mip->mi_oref != 0) ||
5295895Syz147064 	    !(mip->mi_callbacks->mc_callbacks & MC_OPEN)) {
5305895Syz147064 		goto done;
531269Sericheng 	}
5320Sstevel@tonic-gate 
5335895Syz147064 	/*
5345895Syz147064 	 * Note that we do not hold i_mac_impl_lock when calling the
5355895Syz147064 	 * mc_open() callback function to avoid deadlock with the
5365895Syz147064 	 * i_mac_notify() function.
5375895Syz147064 	 */
5385895Syz147064 	if ((err = mip->mi_open(mip->mi_driver)) != 0) {
5395895Syz147064 		rw_exit(&mip->mi_gen_lock);
5406077Syz147064 		ddi_release_devi(mip->mi_dip);
5415895Syz147064 		mac_rele(mip);
5425895Syz147064 		return (err);
5430Sstevel@tonic-gate 	}
5440Sstevel@tonic-gate 
5455895Syz147064 done:
5465895Syz147064 	mip->mi_oref++;
5475895Syz147064 	rw_exit(&mip->mi_gen_lock);
5480Sstevel@tonic-gate 	*mhp = (mac_handle_t)mip;
5490Sstevel@tonic-gate 	return (0);
5505895Syz147064 }
5515895Syz147064 
5525895Syz147064 int
5535895Syz147064 mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp)
5545895Syz147064 {
5555895Syz147064 	dls_dl_handle_t	dlh;
5565895Syz147064 	int		err;
5575895Syz147064 
5585895Syz147064 	if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
5595895Syz147064 		return (err);
5605895Syz147064 
5615895Syz147064 	if (dls_devnet_vid(dlh) != VLAN_ID_NONE) {
5625895Syz147064 		err = EINVAL;
5635895Syz147064 		goto done;
5645895Syz147064 	}
5655895Syz147064 
5666916Sartem 	dls_devnet_prop_task_wait(dlh);
5676916Sartem 
5685895Syz147064 	err = mac_open(dls_devnet_mac(dlh), mhp);
5695895Syz147064 
5705895Syz147064 done:
5715895Syz147064 	dls_devnet_rele_tmp(dlh);
5720Sstevel@tonic-gate 	return (err);
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate 
5755895Syz147064 int
5765895Syz147064 mac_open_by_linkname(const char *link, mac_handle_t *mhp)
5775895Syz147064 {
5785895Syz147064 	datalink_id_t	linkid;
5795895Syz147064 	int		err;
5805895Syz147064 
5815895Syz147064 	if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0)
5825895Syz147064 		return (err);
5835895Syz147064 	return (mac_open_by_linkid(linkid, mhp));
5845895Syz147064 }
5855895Syz147064 
5860Sstevel@tonic-gate void
5870Sstevel@tonic-gate mac_close(mac_handle_t mh)
5880Sstevel@tonic-gate {
5890Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
5905895Syz147064 
5915895Syz147064 	rw_enter(&mip->mi_gen_lock, RW_WRITER);
5925895Syz147064 
5935895Syz147064 	ASSERT(mip->mi_oref != 0);
5945895Syz147064 	if (--mip->mi_oref == 0) {
5955895Syz147064 		if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE))
5965895Syz147064 			mip->mi_close(mip->mi_driver);
5970Sstevel@tonic-gate 	}
5985895Syz147064 	rw_exit(&mip->mi_gen_lock);
5995895Syz147064 
6006077Syz147064 	ddi_release_devi(mip->mi_dip);
6015895Syz147064 	mac_rele(mip);
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate const mac_info_t *
6050Sstevel@tonic-gate mac_info(mac_handle_t mh)
6060Sstevel@tonic-gate {
6072311Sseb 	return (&((mac_impl_t *)mh)->mi_info);
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate 
610269Sericheng dev_info_t *
611269Sericheng mac_devinfo_get(mac_handle_t mh)
612269Sericheng {
6132311Sseb 	return (((mac_impl_t *)mh)->mi_dip);
614269Sericheng }
615269Sericheng 
6165895Syz147064 const char *
6175895Syz147064 mac_name(mac_handle_t mh)
6185895Syz147064 {
6195895Syz147064 	return (((mac_impl_t *)mh)->mi_name);
6205895Syz147064 }
6215895Syz147064 
6225895Syz147064 minor_t
6235895Syz147064 mac_minor(mac_handle_t mh)
6245895Syz147064 {
6255895Syz147064 	return (((mac_impl_t *)mh)->mi_minor);
6265895Syz147064 }
6275895Syz147064 
6280Sstevel@tonic-gate uint64_t
6292311Sseb mac_stat_get(mac_handle_t mh, uint_t stat)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6322311Sseb 	uint64_t	val;
6332311Sseb 	int		ret;
6340Sstevel@tonic-gate 
6352311Sseb 	/*
6362311Sseb 	 * The range of stat determines where it is maintained.  Stat
6372311Sseb 	 * values from 0 up to (but not including) MAC_STAT_MIN are
6382311Sseb 	 * mainteined by the mac module itself.  Everything else is
6392311Sseb 	 * maintained by the driver.
6402311Sseb 	 */
6412311Sseb 	if (stat < MAC_STAT_MIN) {
6422311Sseb 		/* These stats are maintained by the mac module itself. */
6432311Sseb 		switch (stat) {
6442311Sseb 		case MAC_STAT_LINK_STATE:
6452311Sseb 			return (mip->mi_linkstate);
6462311Sseb 		case MAC_STAT_LINK_UP:
6472311Sseb 			return (mip->mi_linkstate == LINK_STATE_UP);
6482311Sseb 		case MAC_STAT_PROMISC:
6492311Sseb 			return (mip->mi_devpromisc != 0);
6502311Sseb 		default:
6512311Sseb 			ASSERT(B_FALSE);
6522311Sseb 		}
6532311Sseb 	}
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	/*
6560Sstevel@tonic-gate 	 * Call the driver to get the given statistic.
6570Sstevel@tonic-gate 	 */
6582311Sseb 	ret = mip->mi_getstat(mip->mi_driver, stat, &val);
6592311Sseb 	if (ret != 0) {
6602311Sseb 		/*
6612311Sseb 		 * The driver doesn't support this statistic.  Get the
6622311Sseb 		 * statistic's default value.
6632311Sseb 		 */
6642311Sseb 		val = mac_stat_default(mip, stat);
6652311Sseb 	}
6662311Sseb 	return (val);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate int
6700Sstevel@tonic-gate mac_start(mac_handle_t mh)
6710Sstevel@tonic-gate {
6720Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6730Sstevel@tonic-gate 	int		err;
6740Sstevel@tonic-gate 
6752311Sseb 	ASSERT(mip->mi_start != NULL);
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	/*
6800Sstevel@tonic-gate 	 * Check whether the device is already started.
6810Sstevel@tonic-gate 	 */
6820Sstevel@tonic-gate 	if (mip->mi_active++ != 0) {
6830Sstevel@tonic-gate 		/*
6840Sstevel@tonic-gate 		 * It's already started so there's nothing more to do.
6850Sstevel@tonic-gate 		 */
6860Sstevel@tonic-gate 		err = 0;
6870Sstevel@tonic-gate 		goto done;
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	/*
6910Sstevel@tonic-gate 	 * Start the device.
6920Sstevel@tonic-gate 	 */
6932311Sseb 	if ((err = mip->mi_start(mip->mi_driver)) != 0)
6940Sstevel@tonic-gate 		--mip->mi_active;
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate done:
6970Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
6980Sstevel@tonic-gate 	return (err);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate void
7020Sstevel@tonic-gate mac_stop(mac_handle_t mh)
7030Sstevel@tonic-gate {
7040Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7050Sstevel@tonic-gate 
7062311Sseb 	ASSERT(mip->mi_stop != NULL);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	/*
7110Sstevel@tonic-gate 	 * Check whether the device is still needed.
7120Sstevel@tonic-gate 	 */
7130Sstevel@tonic-gate 	ASSERT(mip->mi_active != 0);
7140Sstevel@tonic-gate 	if (--mip->mi_active != 0) {
7150Sstevel@tonic-gate 		/*
7160Sstevel@tonic-gate 		 * It's still needed so there's nothing more to do.
7170Sstevel@tonic-gate 		 */
7180Sstevel@tonic-gate 		goto done;
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	/*
7220Sstevel@tonic-gate 	 * Stop the device.
7230Sstevel@tonic-gate 	 */
7242311Sseb 	mip->mi_stop(mip->mi_driver);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate done:
7270Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate int
7310Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
7320Sstevel@tonic-gate {
7330Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
7340Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
7350Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
7360Sstevel@tonic-gate 	int			err;
7370Sstevel@tonic-gate 
7382311Sseb 	ASSERT(mip->mi_multicst != NULL);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	/*
7410Sstevel@tonic-gate 	 * Verify the address.
7420Sstevel@tonic-gate 	 */
7432311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
7442311Sseb 	    mip->mi_pdata)) != 0) {
7452311Sseb 		return (err);
7462311Sseb 	}
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	/*
7490Sstevel@tonic-gate 	 * Check whether the given address is already enabled.
7500Sstevel@tonic-gate 	 */
7510Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
7520Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
7532311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
7542311Sseb 		    0) {
7550Sstevel@tonic-gate 			/*
7560Sstevel@tonic-gate 			 * The address is already enabled so just bump the
7570Sstevel@tonic-gate 			 * reference count.
7580Sstevel@tonic-gate 			 */
7590Sstevel@tonic-gate 			p->mma_ref++;
7600Sstevel@tonic-gate 			err = 0;
7610Sstevel@tonic-gate 			goto done;
7620Sstevel@tonic-gate 		}
7630Sstevel@tonic-gate 	}
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	/*
7660Sstevel@tonic-gate 	 * Allocate a new list entry.
7670Sstevel@tonic-gate 	 */
7680Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
7690Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
7700Sstevel@tonic-gate 		err = ENOMEM;
7710Sstevel@tonic-gate 		goto done;
7720Sstevel@tonic-gate 	}
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	/*
7750Sstevel@tonic-gate 	 * Enable a new multicast address.
7760Sstevel@tonic-gate 	 */
7772311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) {
7780Sstevel@tonic-gate 		kmem_free(p, sizeof (mac_multicst_addr_t));
7790Sstevel@tonic-gate 		goto done;
7800Sstevel@tonic-gate 	}
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	/*
7830Sstevel@tonic-gate 	 * Add the address to the list of enabled addresses.
7840Sstevel@tonic-gate 	 */
7852311Sseb 	bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length);
7860Sstevel@tonic-gate 	p->mma_ref++;
7870Sstevel@tonic-gate 	*pp = p;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate done:
7900Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7910Sstevel@tonic-gate 	return (err);
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate int
7950Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
7980Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
7990Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
8000Sstevel@tonic-gate 	int			err;
8010Sstevel@tonic-gate 
8022311Sseb 	ASSERT(mip->mi_multicst != NULL);
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	/*
8050Sstevel@tonic-gate 	 * Find the entry in the list for the given address.
8060Sstevel@tonic-gate 	 */
8070Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
8080Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
8092311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
8102311Sseb 		    0) {
8110Sstevel@tonic-gate 			if (--p->mma_ref == 0)
8120Sstevel@tonic-gate 				break;
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 			/*
8150Sstevel@tonic-gate 			 * There is still a reference to this address so
8160Sstevel@tonic-gate 			 * there's nothing more to do.
8170Sstevel@tonic-gate 			 */
8180Sstevel@tonic-gate 			err = 0;
8190Sstevel@tonic-gate 			goto done;
8200Sstevel@tonic-gate 		}
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	/*
8240Sstevel@tonic-gate 	 * We did not find an entry for the given address so it is not
8250Sstevel@tonic-gate 	 * currently enabled.
8260Sstevel@tonic-gate 	 */
8270Sstevel@tonic-gate 	if (p == NULL) {
8280Sstevel@tonic-gate 		err = ENOENT;
8290Sstevel@tonic-gate 		goto done;
8300Sstevel@tonic-gate 	}
8310Sstevel@tonic-gate 	ASSERT(p->mma_ref == 0);
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	/*
8340Sstevel@tonic-gate 	 * Disable the multicast address.
8350Sstevel@tonic-gate 	 */
8362311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) {
8370Sstevel@tonic-gate 		p->mma_ref++;
8380Sstevel@tonic-gate 		goto done;
8390Sstevel@tonic-gate 	}
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	/*
8420Sstevel@tonic-gate 	 * Remove it from the list.
8430Sstevel@tonic-gate 	 */
8440Sstevel@tonic-gate 	*pp = p->mma_nextp;
8450Sstevel@tonic-gate 	kmem_free(p, sizeof (mac_multicst_addr_t));
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate done:
8480Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
8490Sstevel@tonic-gate 	return (err);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8522331Skrgopi /*
8532331Skrgopi  * mac_unicst_verify: Verifies the passed address. It fails
8542331Skrgopi  * if the passed address is a group address or has incorrect length.
8552331Skrgopi  */
8562331Skrgopi boolean_t
8572331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
8582331Skrgopi {
8592331Skrgopi 	mac_impl_t	*mip = (mac_impl_t *)mh;
8602331Skrgopi 
8612331Skrgopi 	/*
8622331Skrgopi 	 * Verify the address.
8632331Skrgopi 	 */
8642331Skrgopi 	if ((len != mip->mi_type->mt_addr_length) ||
8652331Skrgopi 	    (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
8662331Skrgopi 	    mip->mi_pdata)) != 0) {
8672331Skrgopi 		return (B_FALSE);
8682331Skrgopi 	} else {
8692331Skrgopi 		return (B_TRUE);
8702331Skrgopi 	}
8712331Skrgopi }
8722331Skrgopi 
8730Sstevel@tonic-gate int
8740Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
8750Sstevel@tonic-gate {
8760Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8770Sstevel@tonic-gate 	int		err;
8780Sstevel@tonic-gate 	boolean_t	notify = B_FALSE;
8790Sstevel@tonic-gate 
8802311Sseb 	ASSERT(mip->mi_unicst != NULL);
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	/*
8830Sstevel@tonic-gate 	 * Verify the address.
8840Sstevel@tonic-gate 	 */
8852311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr,
8862311Sseb 	    mip->mi_pdata)) != 0) {
8872311Sseb 		return (err);
8882311Sseb 	}
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	/*
8910Sstevel@tonic-gate 	 * Program the new unicast address.
8920Sstevel@tonic-gate 	 */
8930Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	/*
8960Sstevel@tonic-gate 	 * If address doesn't change, do nothing.
8970Sstevel@tonic-gate 	 * This check is necessary otherwise it may call into mac_unicst_set
8980Sstevel@tonic-gate 	 * recursively.
8990Sstevel@tonic-gate 	 */
9005895Syz147064 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0)
9010Sstevel@tonic-gate 		goto done;
9020Sstevel@tonic-gate 
9032311Sseb 	if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0)
9040Sstevel@tonic-gate 		goto done;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	/*
9070Sstevel@tonic-gate 	 * Save the address and flag that we need to send a notification.
9080Sstevel@tonic-gate 	 */
9092311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
9100Sstevel@tonic-gate 	notify = B_TRUE;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate done:
9130Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	if (notify)
9160Sstevel@tonic-gate 		i_mac_notify(mip, MAC_NOTE_UNICST);
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	return (err);
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate void
9220Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr)
9230Sstevel@tonic-gate {
9240Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	/*
9272311Sseb 	 * Copy out the current unicast source address.
9280Sstevel@tonic-gate 	 */
9290Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
9302311Sseb 	bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
9312311Sseb 	rw_exit(&(mip->mi_data_lock));
9322311Sseb }
9332311Sseb 
9342311Sseb void
9352311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr)
9362311Sseb {
9372311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
9382311Sseb 
9392311Sseb 	/*
9402311Sseb 	 * Copy out the current destination address.
9412311Sseb 	 */
9422311Sseb 	rw_enter(&(mip->mi_data_lock), RW_READER);
9432311Sseb 	bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
9440Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
9450Sstevel@tonic-gate }
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate int
9480Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
9490Sstevel@tonic-gate {
9500Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9510Sstevel@tonic-gate 	int		err = 0;
9520Sstevel@tonic-gate 
9532311Sseb 	ASSERT(mip->mi_setpromisc != NULL);
9540Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	/*
9570Sstevel@tonic-gate 	 * Determine whether we should enable or disable promiscuous mode.
9580Sstevel@tonic-gate 	 * For details on the distinction between "device promiscuous mode"
9590Sstevel@tonic-gate 	 * and "MAC promiscuous mode", see PSARC/2005/289.
9600Sstevel@tonic-gate 	 */
9610Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
9620Sstevel@tonic-gate 	if (on) {
9630Sstevel@tonic-gate 		/*
9640Sstevel@tonic-gate 		 * Enable promiscuous mode on the device if not yet enabled.
9650Sstevel@tonic-gate 		 */
9660Sstevel@tonic-gate 		if (mip->mi_devpromisc++ == 0) {
9672311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
9682311Sseb 			if (err != 0) {
9690Sstevel@tonic-gate 				mip->mi_devpromisc--;
9700Sstevel@tonic-gate 				goto done;
9710Sstevel@tonic-gate 			}
9720Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
9730Sstevel@tonic-gate 		}
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 		/*
9760Sstevel@tonic-gate 		 * Enable promiscuous mode on the MAC if not yet enabled.
9770Sstevel@tonic-gate 		 */
9780Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
9790Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
9800Sstevel@tonic-gate 	} else {
9810Sstevel@tonic-gate 		if (mip->mi_devpromisc == 0) {
9820Sstevel@tonic-gate 			err = EPROTO;
9830Sstevel@tonic-gate 			goto done;
9840Sstevel@tonic-gate 		}
9850Sstevel@tonic-gate 		/*
9860Sstevel@tonic-gate 		 * Disable promiscuous mode on the device if this is the last
9870Sstevel@tonic-gate 		 * enabling.
9880Sstevel@tonic-gate 		 */
9890Sstevel@tonic-gate 		if (--mip->mi_devpromisc == 0) {
9902311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
9912311Sseb 			if (err != 0) {
9920Sstevel@tonic-gate 				mip->mi_devpromisc++;
9930Sstevel@tonic-gate 				goto done;
9940Sstevel@tonic-gate 			}
9950Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
9960Sstevel@tonic-gate 		}
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 		/*
9990Sstevel@tonic-gate 		 * Disable promiscuous mode on the MAC if this is the last
10000Sstevel@tonic-gate 		 * enabling.
10010Sstevel@tonic-gate 		 */
10020Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
10030Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
10040Sstevel@tonic-gate 	}
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate done:
10070Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
10080Sstevel@tonic-gate 	return (err);
10090Sstevel@tonic-gate }
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate boolean_t
10120Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
10130Sstevel@tonic-gate {
10140Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	/*
10190Sstevel@tonic-gate 	 * Return the current promiscuity.
10200Sstevel@tonic-gate 	 */
10210Sstevel@tonic-gate 	if (ptype == MAC_DEVPROMISC)
10220Sstevel@tonic-gate 		return (mip->mi_devpromisc != 0);
10230Sstevel@tonic-gate 	else
10240Sstevel@tonic-gate 		return (mip->mi_promisc != 0);
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate void
10285903Ssowmini mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu)
10295903Ssowmini {
10305903Ssowmini 	mac_impl_t	*mip = (mac_impl_t *)mh;
10315903Ssowmini 
10325903Ssowmini 	if (min_sdu != NULL)
10335903Ssowmini 		*min_sdu = mip->mi_sdu_min;
10345903Ssowmini 	if (max_sdu != NULL)
10355903Ssowmini 		*max_sdu = mip->mi_sdu_max;
10365903Ssowmini }
10375903Ssowmini 
10385903Ssowmini void
10390Sstevel@tonic-gate mac_resources(mac_handle_t mh)
10400Sstevel@tonic-gate {
10410Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	/*
10442311Sseb 	 * If the driver supports resource registration, call the driver to
10452311Sseb 	 * ask it to register its resources.
10460Sstevel@tonic-gate 	 */
10472311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES)
10482311Sseb 		mip->mi_resources(mip->mi_driver);
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate void
10520Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
10530Sstevel@tonic-gate {
10540Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
10556512Ssowmini 	int cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd;
10566512Ssowmini 
10576512Ssowmini 	if ((cmd == ND_GET && (mip->mi_callbacks->mc_callbacks & MC_GETPROP)) ||
10586512Ssowmini 	    (cmd == ND_SET && (mip->mi_callbacks->mc_callbacks & MC_SETPROP))) {
10596512Ssowmini 		/*
10606512Ssowmini 		 * If ndd props were registered, call them.
10616512Ssowmini 		 * Note that ndd ioctls are Obsolete
10626512Ssowmini 		 */
10636512Ssowmini 		mac_ndd_ioctl(mip, wq, bp);
10646512Ssowmini 		return;
10655903Ssowmini 	}
10666512Ssowmini 
10670Sstevel@tonic-gate 	/*
10682311Sseb 	 * Call the driver to handle the ioctl.  The driver may not support
10692311Sseb 	 * any ioctls, in which case we reply with a NAK on its behalf.
10700Sstevel@tonic-gate 	 */
10712311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
10722311Sseb 		mip->mi_ioctl(mip->mi_driver, wq, bp);
10732311Sseb 	else
10742311Sseb 		miocnak(wq, bp, 0, EINVAL);
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate 
107756Smeem const mac_txinfo_t *
10785084Sjohnlev mac_do_tx_get(mac_handle_t mh, boolean_t is_vnic)
10790Sstevel@tonic-gate {
10800Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
108156Smeem 	mac_txinfo_t	*mtp;
108256Smeem 
108356Smeem 	/*
108456Smeem 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
108556Smeem 	 * changed.  This is sufficient since MAC clients are careful to always
108656Smeem 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
108756Smeem 	 * MAC_PROMISC prior to calling mac_txloop_remove().
108856Smeem 	 */
10895084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_READER);
10900Sstevel@tonic-gate 
109156Smeem 	if (mac_promisc_get(mh, MAC_PROMISC)) {
109256Smeem 		ASSERT(mip->mi_mtfp != NULL);
10935084Sjohnlev 		if (mip->mi_vnic_present && !is_vnic) {
10945084Sjohnlev 			mtp = &mip->mi_vnic_txloopinfo;
10955084Sjohnlev 		} else {
10965084Sjohnlev 			mtp = &mip->mi_txloopinfo;
10975084Sjohnlev 		}
109856Smeem 	} else {
10995084Sjohnlev 		if (mip->mi_vnic_present && !is_vnic) {
11005084Sjohnlev 			mtp = &mip->mi_vnic_txinfo;
11015084Sjohnlev 		} else {
11025084Sjohnlev 			/*
11035084Sjohnlev 			 * Note that we cannot ASSERT() that mip->mi_mtfp is
11045084Sjohnlev 			 * NULL, because to satisfy the above ASSERT(), we
11055084Sjohnlev 			 * have to disable MAC_PROMISC prior to calling
11065084Sjohnlev 			 * mac_txloop_remove().
11075084Sjohnlev 			 */
11085084Sjohnlev 			mtp = &mip->mi_txinfo;
11095084Sjohnlev 		}
111056Smeem 	}
111156Smeem 
11125084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
111356Smeem 	return (mtp);
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate 
11165084Sjohnlev /*
11175084Sjohnlev  * Invoked by VNIC to obtain the transmit entry point.
11185084Sjohnlev  */
11195084Sjohnlev const mac_txinfo_t *
11205084Sjohnlev mac_vnic_tx_get(mac_handle_t mh)
11215084Sjohnlev {
11225084Sjohnlev 	return (mac_do_tx_get(mh, B_TRUE));
11235084Sjohnlev }
11245084Sjohnlev 
11255084Sjohnlev /*
11265084Sjohnlev  * Invoked by any non-VNIC client to obtain the transmit entry point.
11275084Sjohnlev  * If a VNIC is present, the VNIC transmit function provided by the VNIC
11285084Sjohnlev  * will be returned to the MAC client.
11295084Sjohnlev  */
11305084Sjohnlev const mac_txinfo_t *
11315084Sjohnlev mac_tx_get(mac_handle_t mh)
11325084Sjohnlev {
11335084Sjohnlev 	return (mac_do_tx_get(mh, B_FALSE));
11345084Sjohnlev }
11355084Sjohnlev 
11360Sstevel@tonic-gate link_state_t
11370Sstevel@tonic-gate mac_link_get(mac_handle_t mh)
11380Sstevel@tonic-gate {
11392311Sseb 	return (((mac_impl_t *)mh)->mi_linkstate);
11400Sstevel@tonic-gate }
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate mac_notify_handle_t
11430Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
11440Sstevel@tonic-gate {
11450Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11460Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
11490Sstevel@tonic-gate 	mnfp->mnf_fn = notify;
11500Sstevel@tonic-gate 	mnfp->mnf_arg = arg;
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	/*
11530Sstevel@tonic-gate 	 * Add it to the head of the 'notify' callback list.
11540Sstevel@tonic-gate 	 */
11551852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
11560Sstevel@tonic-gate 	mnfp->mnf_nextp = mip->mi_mnfp;
11570Sstevel@tonic-gate 	mip->mi_mnfp = mnfp;
11581852Syz147064 	rw_exit(&mip->mi_notify_lock);
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	return ((mac_notify_handle_t)mnfp);
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate void
11640Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
11650Sstevel@tonic-gate {
11660Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11670Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
11680Sstevel@tonic-gate 	mac_notify_fn_t		**pp;
11690Sstevel@tonic-gate 	mac_notify_fn_t		*p;
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 	/*
11720Sstevel@tonic-gate 	 * Search the 'notify' callback list for the function closure.
11730Sstevel@tonic-gate 	 */
11741852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
11750Sstevel@tonic-gate 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
11760Sstevel@tonic-gate 	    pp = &(p->mnf_nextp)) {
11770Sstevel@tonic-gate 		if (p == mnfp)
11780Sstevel@tonic-gate 			break;
11790Sstevel@tonic-gate 	}
11800Sstevel@tonic-gate 	ASSERT(p != NULL);
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	/*
11830Sstevel@tonic-gate 	 * Remove it from the list.
11840Sstevel@tonic-gate 	 */
11850Sstevel@tonic-gate 	*pp = p->mnf_nextp;
11861852Syz147064 	rw_exit(&mip->mi_notify_lock);
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	/*
11890Sstevel@tonic-gate 	 * Free it.
11900Sstevel@tonic-gate 	 */
11910Sstevel@tonic-gate 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
11920Sstevel@tonic-gate }
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate void
11950Sstevel@tonic-gate mac_notify(mac_handle_t mh)
11960Sstevel@tonic-gate {
11970Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11980Sstevel@tonic-gate 	mac_notify_type_t	type;
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	for (type = 0; type < MAC_NNOTE; type++)
12010Sstevel@tonic-gate 		i_mac_notify(mip, type);
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate 
12044913Sethindra /*
12054913Sethindra  * Register a receive function for this mac.
12064913Sethindra  * More information on this function's interaction with mac_rx()
12074913Sethindra  * can be found atop mac_rx().
12084913Sethindra  */
12090Sstevel@tonic-gate mac_rx_handle_t
12105084Sjohnlev mac_do_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg, boolean_t is_active)
12110Sstevel@tonic-gate {
12120Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
12130Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
12160Sstevel@tonic-gate 	mrfp->mrf_fn = rx;
12170Sstevel@tonic-gate 	mrfp->mrf_arg = arg;
12185084Sjohnlev 	mrfp->mrf_active = is_active;
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 	/*
12210Sstevel@tonic-gate 	 * Add it to the head of the 'rx' callback list.
12220Sstevel@tonic-gate 	 */
12230Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
12244913Sethindra 
12254913Sethindra 	/*
12264913Sethindra 	 * mac_rx() will only call callbacks that are marked inuse.
12274913Sethindra 	 */
12284913Sethindra 	mrfp->mrf_inuse = B_TRUE;
12290Sstevel@tonic-gate 	mrfp->mrf_nextp = mip->mi_mrfp;
12304913Sethindra 
12314913Sethindra 	/*
12324913Sethindra 	 * mac_rx() could be traversing the remainder of the list
12334913Sethindra 	 * and miss the new callback we're adding here. This is not a problem
12344913Sethindra 	 * because we do not guarantee the callback to take effect immediately
12354913Sethindra 	 * after mac_rx_add() returns.
12364913Sethindra 	 */
12370Sstevel@tonic-gate 	mip->mi_mrfp = mrfp;
12380Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	return ((mac_rx_handle_t)mrfp);
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate 
12435084Sjohnlev mac_rx_handle_t
12445084Sjohnlev mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
12455084Sjohnlev {
12465084Sjohnlev 	return (mac_do_rx_add(mh, rx, arg, B_FALSE));
12475084Sjohnlev }
12485084Sjohnlev 
12495084Sjohnlev mac_rx_handle_t
12505084Sjohnlev mac_active_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
12515084Sjohnlev {
12525084Sjohnlev 	return (mac_do_rx_add(mh, rx, arg, B_TRUE));
12535084Sjohnlev }
12545084Sjohnlev 
12550Sstevel@tonic-gate /*
12564913Sethindra  * Unregister a receive function for this mac.
12574913Sethindra  * This function does not block if wait is B_FALSE. This is useful
12584913Sethindra  * for clients who call mac_rx_remove() from a non-blockable context.
12594913Sethindra  * More information on this function's interaction with mac_rx()
12604913Sethindra  * can be found atop mac_rx().
12610Sstevel@tonic-gate  */
12620Sstevel@tonic-gate void
12634913Sethindra mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh, boolean_t wait)
12640Sstevel@tonic-gate {
12650Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
12660Sstevel@tonic-gate 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
12670Sstevel@tonic-gate 	mac_rx_fn_t		**pp;
12680Sstevel@tonic-gate 	mac_rx_fn_t		*p;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	/*
12710Sstevel@tonic-gate 	 * Search the 'rx' callback list for the function closure.
12720Sstevel@tonic-gate 	 */
12734913Sethindra 	rw_enter(&mip->mi_rx_lock, RW_WRITER);
12740Sstevel@tonic-gate 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
12750Sstevel@tonic-gate 		if (p == mrfp)
12760Sstevel@tonic-gate 			break;
12770Sstevel@tonic-gate 	}
12780Sstevel@tonic-gate 	ASSERT(p != NULL);
12790Sstevel@tonic-gate 
12804913Sethindra 	/*
12814913Sethindra 	 * If mac_rx() is running, mark callback for deletion
12824913Sethindra 	 * and return (if wait is false), or wait until mac_rx()
12834913Sethindra 	 * exits (if wait is true).
12844913Sethindra 	 */
12854913Sethindra 	if (mip->mi_rx_ref > 0) {
12864913Sethindra 		DTRACE_PROBE1(defer_delete, mac_impl_t *, mip);
12874913Sethindra 		p->mrf_inuse = B_FALSE;
12884913Sethindra 		mutex_enter(&mip->mi_lock);
12894913Sethindra 		mip->mi_rx_removed++;
12904913Sethindra 		mutex_exit(&mip->mi_lock);
12914913Sethindra 
12924913Sethindra 		rw_exit(&mip->mi_rx_lock);
12934913Sethindra 		if (wait)
12944913Sethindra 			mac_rx_remove_wait(mh);
12954913Sethindra 		return;
12964913Sethindra 	}
12974913Sethindra 
12980Sstevel@tonic-gate 	/* Remove it from the list. */
12990Sstevel@tonic-gate 	*pp = p->mrf_nextp;
13000Sstevel@tonic-gate 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
13014913Sethindra 	rw_exit(&mip->mi_rx_lock);
13024913Sethindra }
13034913Sethindra 
13044913Sethindra /*
13054913Sethindra  * Wait for all pending callback removals to be completed by mac_rx().
13064913Sethindra  * Note that if we call mac_rx_remove() immediately before this, there is no
13074913Sethindra  * guarantee we would wait *only* on the callback that we specified.
13084913Sethindra  * mac_rx_remove() could have been called by other threads and we would have
13094913Sethindra  * to wait for other marked callbacks to be removed as well.
13104913Sethindra  */
13114913Sethindra void
13124913Sethindra mac_rx_remove_wait(mac_handle_t mh)
13134913Sethindra {
13144913Sethindra 	mac_impl_t	*mip = (mac_impl_t *)mh;
13154913Sethindra 
13164913Sethindra 	mutex_enter(&mip->mi_lock);
13174913Sethindra 	while (mip->mi_rx_removed > 0) {
13184913Sethindra 		DTRACE_PROBE1(need_wait, mac_impl_t *, mip);
13194913Sethindra 		cv_wait(&mip->mi_rx_cv, &mip->mi_lock);
13204913Sethindra 	}
13214913Sethindra 	mutex_exit(&mip->mi_lock);
13220Sstevel@tonic-gate }
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate mac_txloop_handle_t
13250Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
13260Sstevel@tonic-gate {
13270Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
13280Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
13310Sstevel@tonic-gate 	mtfp->mtf_fn = tx;
13320Sstevel@tonic-gate 	mtfp->mtf_arg = arg;
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	/*
13350Sstevel@tonic-gate 	 * Add it to the head of the 'tx' callback list.
13360Sstevel@tonic-gate 	 */
13375084Sjohnlev 	rw_enter(&(mip->mi_tx_lock), RW_WRITER);
13380Sstevel@tonic-gate 	mtfp->mtf_nextp = mip->mi_mtfp;
13390Sstevel@tonic-gate 	mip->mi_mtfp = mtfp;
13405084Sjohnlev 	rw_exit(&(mip->mi_tx_lock));
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	return ((mac_txloop_handle_t)mtfp);
13430Sstevel@tonic-gate }
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate /*
13460Sstevel@tonic-gate  * Unregister a transmit function for this mac.  This removes the function
13470Sstevel@tonic-gate  * from the list of transmit functions for this mac.
13480Sstevel@tonic-gate  */
13490Sstevel@tonic-gate void
13500Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
13510Sstevel@tonic-gate {
13520Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
13530Sstevel@tonic-gate 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
13540Sstevel@tonic-gate 	mac_txloop_fn_t		**pp;
13550Sstevel@tonic-gate 	mac_txloop_fn_t		*p;
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 	/*
13580Sstevel@tonic-gate 	 * Search the 'tx' callback list for the function.
13590Sstevel@tonic-gate 	 */
13605084Sjohnlev 	rw_enter(&(mip->mi_tx_lock), RW_WRITER);
13610Sstevel@tonic-gate 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
13620Sstevel@tonic-gate 		if (p == mtfp)
13630Sstevel@tonic-gate 			break;
13640Sstevel@tonic-gate 	}
13650Sstevel@tonic-gate 	ASSERT(p != NULL);
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	/* Remove it from the list. */
13680Sstevel@tonic-gate 	*pp = p->mtf_nextp;
13690Sstevel@tonic-gate 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
13705084Sjohnlev 	rw_exit(&(mip->mi_tx_lock));
13710Sstevel@tonic-gate }
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate void
13740Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
13750Sstevel@tonic-gate {
13760Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	/*
13790Sstevel@tonic-gate 	 * Update the 'resource_add' callbacks.
13800Sstevel@tonic-gate 	 */
13810Sstevel@tonic-gate 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
13820Sstevel@tonic-gate 	mip->mi_resource_add = add;
13830Sstevel@tonic-gate 	mip->mi_resource_add_arg = arg;
13840Sstevel@tonic-gate 	rw_exit(&(mip->mi_resource_lock));
13850Sstevel@tonic-gate }
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate /*
13880Sstevel@tonic-gate  * Driver support functions.
13890Sstevel@tonic-gate  */
13900Sstevel@tonic-gate 
13912311Sseb mac_register_t *
13922311Sseb mac_alloc(uint_t mac_version)
13930Sstevel@tonic-gate {
13942311Sseb 	mac_register_t *mregp;
13952311Sseb 
13962311Sseb 	/*
13972311Sseb 	 * Make sure there isn't a version mismatch between the driver and
13982311Sseb 	 * the framework.  In the future, if multiple versions are
13992311Sseb 	 * supported, this check could become more sophisticated.
14002311Sseb 	 */
14012311Sseb 	if (mac_version != MAC_VERSION)
14022311Sseb 		return (NULL);
14032311Sseb 
14042311Sseb 	mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
14052311Sseb 	mregp->m_version = mac_version;
14062311Sseb 	return (mregp);
14072311Sseb }
14082311Sseb 
14092311Sseb void
14102311Sseb mac_free(mac_register_t *mregp)
14112311Sseb {
14122311Sseb 	kmem_free(mregp, sizeof (mac_register_t));
14132311Sseb }
14142311Sseb 
14152311Sseb /*
14165895Syz147064  * Allocate a minor number.
14175895Syz147064  */
14185895Syz147064 minor_t
14195895Syz147064 mac_minor_hold(boolean_t sleep)
14205895Syz147064 {
14215895Syz147064 	minor_t	minor;
14225895Syz147064 
14235895Syz147064 	/*
14245895Syz147064 	 * Grab a value from the arena.
14255895Syz147064 	 */
14265895Syz147064 	atomic_add_32(&minor_count, 1);
14275895Syz147064 
14285895Syz147064 	if (sleep)
14295895Syz147064 		minor = (uint_t)id_alloc(minor_ids);
14305895Syz147064 	else
14315895Syz147064 		minor = (uint_t)id_alloc_nosleep(minor_ids);
14325895Syz147064 
14335895Syz147064 	if (minor == 0) {
14345895Syz147064 		atomic_add_32(&minor_count, -1);
14355895Syz147064 		return (0);
14365895Syz147064 	}
14375895Syz147064 
14385895Syz147064 	return (minor);
14395895Syz147064 }
14405895Syz147064 
14415895Syz147064 /*
14425895Syz147064  * Release a previously allocated minor number.
14435895Syz147064  */
14445895Syz147064 void
14455895Syz147064 mac_minor_rele(minor_t minor)
14465895Syz147064 {
14475895Syz147064 	/*
14485895Syz147064 	 * Return the value to the arena.
14495895Syz147064 	 */
14505895Syz147064 	id_free(minor_ids, minor);
14515895Syz147064 	atomic_add_32(&minor_count, -1);
14525895Syz147064 }
14535895Syz147064 
14545895Syz147064 uint32_t
14555895Syz147064 mac_no_notification(mac_handle_t mh)
14565895Syz147064 {
14575895Syz147064 	mac_impl_t *mip = (mac_impl_t *)mh;
14585895Syz147064 	return (mip->mi_unsup_note);
14595895Syz147064 }
14605895Syz147064 
14615895Syz147064 boolean_t
14625895Syz147064 mac_is_legacy(mac_handle_t mh)
14635895Syz147064 {
14645895Syz147064 	mac_impl_t *mip = (mac_impl_t *)mh;
14655895Syz147064 	return (mip->mi_legacy);
14665895Syz147064 }
14675895Syz147064 
14685895Syz147064 /*
14692311Sseb  * mac_register() is how drivers register new MACs with the GLDv3
14702311Sseb  * framework.  The mregp argument is allocated by drivers using the
14712311Sseb  * mac_alloc() function, and can be freed using mac_free() immediately upon
14722311Sseb  * return from mac_register().  Upon success (0 return value), the mhp
14732311Sseb  * opaque pointer becomes the driver's handle to its MAC interface, and is
14742311Sseb  * the argument to all other mac module entry points.
14752311Sseb  */
14762311Sseb int
14772311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp)
14782311Sseb {
14795895Syz147064 	mac_impl_t		*mip;
14805895Syz147064 	mactype_t		*mtype;
14815895Syz147064 	int			err = EINVAL;
14825895Syz147064 	struct devnames		*dnp = NULL;
14835895Syz147064 	uint_t			instance;
14845895Syz147064 	boolean_t		style1_created = B_FALSE;
14855895Syz147064 	boolean_t		style2_created = B_FALSE;
14865895Syz147064 	mac_capab_legacy_t	legacy;
14875895Syz147064 	char			*driver;
14885895Syz147064 	minor_t			minor = 0;
14892311Sseb 
14902311Sseb 	/* Find the required MAC-Type plugin. */
14912311Sseb 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
14922311Sseb 		return (EINVAL);
14932311Sseb 
14942311Sseb 	/* Create a mac_impl_t to represent this MAC. */
14952311Sseb 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
14962311Sseb 
14972311Sseb 	/*
14982311Sseb 	 * The mac is not ready for open yet.
14992311Sseb 	 */
15002311Sseb 	mip->mi_disabled = B_TRUE;
15012311Sseb 
15022311Sseb 	/*
15035895Syz147064 	 * When a mac is registered, the m_instance field can be set to:
15045895Syz147064 	 *
15055895Syz147064 	 *  0:	Get the mac's instance number from m_dip.
15065895Syz147064 	 *	This is usually used for physical device dips.
15075895Syz147064 	 *
15085895Syz147064 	 *  [1 .. MAC_MAX_MINOR-1]: Use the value as the mac's instance number.
15095895Syz147064 	 *	For example, when an aggregation is created with the key option,
15105895Syz147064 	 *	"key" will be used as the instance number.
15115895Syz147064 	 *
15125895Syz147064 	 *  -1: Assign an instance number from [MAC_MAX_MINOR .. MAXMIN-1].
15135895Syz147064 	 *	This is often used when a MAC of a virtual link is registered
15145895Syz147064 	 *	(e.g., aggregation when "key" is not specified, or vnic).
15155895Syz147064 	 *
15165895Syz147064 	 * Note that the instance number is used to derive the mi_minor field
15175895Syz147064 	 * of mac_impl_t, which will then be used to derive the name of kstats
15185895Syz147064 	 * and the devfs nodes.  The first 2 cases are needed to preserve
15195895Syz147064 	 * backward compatibility.
15202311Sseb 	 */
15215895Syz147064 	switch (mregp->m_instance) {
15225895Syz147064 	case 0:
15235895Syz147064 		instance = ddi_get_instance(mregp->m_dip);
15245895Syz147064 		break;
15255895Syz147064 	case ((uint_t)-1):
15265895Syz147064 		minor = mac_minor_hold(B_TRUE);
15275895Syz147064 		if (minor == 0) {
15285895Syz147064 			err = ENOSPC;
15295895Syz147064 			goto fail;
15305895Syz147064 		}
15315895Syz147064 		instance = minor - 1;
15325895Syz147064 		break;
15335895Syz147064 	default:
15345895Syz147064 		instance = mregp->m_instance;
15355895Syz147064 		if (instance >= MAC_MAX_MINOR) {
15365895Syz147064 			err = EINVAL;
15375895Syz147064 			goto fail;
15385895Syz147064 		}
15395895Syz147064 		break;
15405895Syz147064 	}
15415895Syz147064 
15425895Syz147064 	mip->mi_minor = (minor_t)(instance + 1);
15435895Syz147064 	mip->mi_dip = mregp->m_dip;
15445895Syz147064 
15455895Syz147064 	driver = (char *)ddi_driver_name(mip->mi_dip);
15462311Sseb 
15472311Sseb 	/* Construct the MAC name as <drvname><instance> */
15482311Sseb 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
15495895Syz147064 	    driver, instance);
15502311Sseb 
15512311Sseb 	mip->mi_driver = mregp->m_driver;
15522311Sseb 
15532311Sseb 	mip->mi_type = mtype;
15545895Syz147064 	mip->mi_margin = mregp->m_margin;
15552311Sseb 	mip->mi_info.mi_media = mtype->mt_type;
15563147Sxc151355 	mip->mi_info.mi_nativemedia = mtype->mt_nativetype;
15573969Syz147064 	if (mregp->m_max_sdu <= mregp->m_min_sdu)
15582311Sseb 		goto fail;
15595903Ssowmini 	mip->mi_sdu_min = mregp->m_min_sdu;
15605903Ssowmini 	mip->mi_sdu_max = mregp->m_max_sdu;
15612311Sseb 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
15622311Sseb 	/*
15632311Sseb 	 * If the media supports a broadcast address, cache a pointer to it
15642311Sseb 	 * in the mac_info_t so that upper layers can use it.
15652311Sseb 	 */
15662311Sseb 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1567269Sericheng 
15682311Sseb 	/*
15692311Sseb 	 * Copy the unicast source address into the mac_info_t, but only if
15702311Sseb 	 * the MAC-Type defines a non-zero address length.  We need to
15712311Sseb 	 * handle MAC-Types that have an address length of 0
15722311Sseb 	 * (point-to-point protocol MACs for example).
15732311Sseb 	 */
15742311Sseb 	if (mip->mi_type->mt_addr_length > 0) {
15753969Syz147064 		if (mregp->m_src_addr == NULL)
15762311Sseb 			goto fail;
15772311Sseb 		mip->mi_info.mi_unicst_addr =
15782311Sseb 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
15792311Sseb 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
15802311Sseb 		    mip->mi_type->mt_addr_length);
15812311Sseb 
15822311Sseb 		/*
15832311Sseb 		 * Copy the fixed 'factory' MAC address from the immutable
15842311Sseb 		 * info.  This is taken to be the MAC address currently in
15852311Sseb 		 * use.
15862311Sseb 		 */
15872311Sseb 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
15882311Sseb 		    mip->mi_type->mt_addr_length);
15892311Sseb 		/* Copy the destination address if one is provided. */
15902311Sseb 		if (mregp->m_dst_addr != NULL) {
15912311Sseb 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
15922311Sseb 			    mip->mi_type->mt_addr_length);
15932311Sseb 		}
15942311Sseb 	} else if (mregp->m_src_addr != NULL) {
15952311Sseb 		goto fail;
1596269Sericheng 	}
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	/*
15992311Sseb 	 * The format of the m_pdata is specific to the plugin.  It is
16002311Sseb 	 * passed in as an argument to all of the plugin callbacks.  The
16012311Sseb 	 * driver can update this information by calling
16022311Sseb 	 * mac_pdata_update().
16030Sstevel@tonic-gate 	 */
16042311Sseb 	if (mregp->m_pdata != NULL) {
16052311Sseb 		/*
16062311Sseb 		 * Verify that the plugin supports MAC plugin data and that
16072311Sseb 		 * the supplied data is valid.
16082311Sseb 		 */
16093969Syz147064 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
16102311Sseb 			goto fail;
16112311Sseb 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
16122311Sseb 		    mregp->m_pdata_size)) {
16132311Sseb 			goto fail;
16142311Sseb 		}
16152311Sseb 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
16162311Sseb 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
16172311Sseb 		mip->mi_pdata_size = mregp->m_pdata_size;
16182311Sseb 	}
16192311Sseb 
16202311Sseb 	/*
16216512Ssowmini 	 * Register the private properties.
16226512Ssowmini 	 */
16236512Ssowmini 	mac_register_priv_prop(mip, mregp->m_priv_props,
16246512Ssowmini 	    mregp->m_priv_prop_count);
16256512Ssowmini 
16266512Ssowmini 	/*
16272311Sseb 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
16282311Sseb 	 * check to make sure all mandatory callbacks are set.
16292311Sseb 	 */
16302311Sseb 	if (mregp->m_callbacks->mc_getstat == NULL ||
16312311Sseb 	    mregp->m_callbacks->mc_start == NULL ||
16322311Sseb 	    mregp->m_callbacks->mc_stop == NULL ||
16332311Sseb 	    mregp->m_callbacks->mc_setpromisc == NULL ||
16342311Sseb 	    mregp->m_callbacks->mc_multicst == NULL ||
16352311Sseb 	    mregp->m_callbacks->mc_unicst == NULL ||
16362311Sseb 	    mregp->m_callbacks->mc_tx == NULL) {
16372311Sseb 		goto fail;
16382311Sseb 	}
16392311Sseb 	mip->mi_callbacks = mregp->m_callbacks;
16402311Sseb 
16412311Sseb 	/*
16425084Sjohnlev 	 * Set up the possible transmit routines.
16432311Sseb 	 */
16442311Sseb 	mip->mi_txinfo.mt_fn = mip->mi_tx;
16452311Sseb 	mip->mi_txinfo.mt_arg = mip->mi_driver;
16465084Sjohnlev 
16475895Syz147064 	mip->mi_legacy = mac_capab_get((mac_handle_t)mip,
16485895Syz147064 	    MAC_CAPAB_LEGACY, &legacy);
16495895Syz147064 
16505895Syz147064 	if (mip->mi_legacy) {
16515895Syz147064 		/*
16525895Syz147064 		 * Legacy device. Messages being sent will be looped back
16535895Syz147064 		 * by the underlying driver. Therefore the txloop function
16545895Syz147064 		 * pointer is the same as the tx function pointer.
16555895Syz147064 		 */
16565895Syz147064 		mip->mi_txloopinfo.mt_fn = mip->mi_txinfo.mt_fn;
16575895Syz147064 		mip->mi_txloopinfo.mt_arg = mip->mi_txinfo.mt_arg;
16585895Syz147064 		mip->mi_unsup_note = legacy.ml_unsup_note;
16595895Syz147064 		mip->mi_phy_dev = legacy.ml_dev;
16605895Syz147064 	} else {
16615895Syz147064 		/*
16625895Syz147064 		 * Normal device. The framework needs to do the loopback.
16635895Syz147064 		 */
16645895Syz147064 		mip->mi_txloopinfo.mt_fn = mac_txloop;
16655895Syz147064 		mip->mi_txloopinfo.mt_arg = mip;
16665895Syz147064 		mip->mi_unsup_note = 0;
16675895Syz147064 		mip->mi_phy_dev = makedevice(ddi_driver_major(mip->mi_dip),
16685895Syz147064 		    ddi_get_instance(mip->mi_dip) + 1);
16695895Syz147064 	}
16705895Syz147064 
16715084Sjohnlev 	mip->mi_vnic_txinfo.mt_fn = mac_vnic_tx;
16725084Sjohnlev 	mip->mi_vnic_txinfo.mt_arg = mip;
16735084Sjohnlev 
16745084Sjohnlev 	mip->mi_vnic_txloopinfo.mt_fn = mac_vnic_txloop;
16755084Sjohnlev 	mip->mi_vnic_txloopinfo.mt_arg = mip;
16765084Sjohnlev 
16772311Sseb 	/*
16785009Sgd78059 	 * Allocate a notification thread.
16795009Sgd78059 	 */
16805009Sgd78059 	mip->mi_notify_thread = thread_create(NULL, 0, i_mac_notify_thread,
16815009Sgd78059 	    mip, 0, &p0, TS_RUN, minclsyspri);
16825009Sgd78059 	if (mip->mi_notify_thread == NULL)
16835009Sgd78059 		goto fail;
16845009Sgd78059 
16855009Sgd78059 	/*
16862311Sseb 	 * Initialize the kstats for this device.
16872311Sseb 	 */
16882311Sseb 	mac_stat_create(mip);
16890Sstevel@tonic-gate 
16906512Ssowmini 
16910Sstevel@tonic-gate 	/* set the gldv3 flag in dn_flags */
16922311Sseb 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
16930Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
16945895Syz147064 	dnp->dn_flags |= (DN_GLDV3_DRIVER | DN_NETWORK_DRIVER);
16950Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
16960Sstevel@tonic-gate 
16975895Syz147064 	if (mip->mi_minor < MAC_MAX_MINOR + 1) {
16985895Syz147064 		/* Create a style-2 DLPI device */
16995895Syz147064 		if (ddi_create_minor_node(mip->mi_dip, driver, S_IFCHR, 0,
17005895Syz147064 		    DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
17015895Syz147064 			goto fail;
17025895Syz147064 		style2_created = B_TRUE;
17035895Syz147064 
17045895Syz147064 		/* Create a style-1 DLPI device */
17055895Syz147064 		if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR,
17065895Syz147064 		    mip->mi_minor, DDI_NT_NET, 0) != DDI_SUCCESS)
17075895Syz147064 			goto fail;
17085895Syz147064 		style1_created = B_TRUE;
17095895Syz147064 	}
17105895Syz147064 
17113969Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
17123969Syz147064 	if (mod_hash_insert(i_mac_impl_hash,
17133969Syz147064 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
17145895Syz147064 
17153969Syz147064 		rw_exit(&i_mac_impl_lock);
17163969Syz147064 		err = EEXIST;
17173969Syz147064 		goto fail;
17183969Syz147064 	}
17193969Syz147064 
17205903Ssowmini 	DTRACE_PROBE2(mac__register, struct devnames *, dnp,
17215903Ssowmini 	    (mac_impl_t *), mip);
17225903Ssowmini 
17231852Syz147064 	/*
17241852Syz147064 	 * Mark the MAC to be ready for open.
17251852Syz147064 	 */
17262311Sseb 	mip->mi_disabled = B_FALSE;
17272311Sseb 
17281852Syz147064 	rw_exit(&i_mac_impl_lock);
17293969Syz147064 
17303969Syz147064 	atomic_inc_32(&i_mac_impl_count);
17315895Syz147064 
17325895Syz147064 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
17332311Sseb 	*mhp = (mac_handle_t)mip;
1734269Sericheng 	return (0);
17350Sstevel@tonic-gate 
17362311Sseb fail:
17375895Syz147064 	if (style1_created)
17385895Syz147064 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
17395895Syz147064 
17405895Syz147064 	if (style2_created)
17415895Syz147064 		ddi_remove_minor_node(mip->mi_dip, driver);
17425895Syz147064 
17435009Sgd78059 	/* clean up notification thread */
17445009Sgd78059 	if (mip->mi_notify_thread != NULL) {
17455009Sgd78059 		mutex_enter(&mip->mi_notify_bits_lock);
17465009Sgd78059 		mip->mi_notify_bits = (1 << MAC_NNOTE);
17475009Sgd78059 		cv_broadcast(&mip->mi_notify_cv);
17485009Sgd78059 		while (mip->mi_notify_bits != 0)
17495009Sgd78059 			cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
17505009Sgd78059 		mutex_exit(&mip->mi_notify_bits_lock);
17515009Sgd78059 	}
17525009Sgd78059 
17532311Sseb 	if (mip->mi_info.mi_unicst_addr != NULL) {
17542311Sseb 		kmem_free(mip->mi_info.mi_unicst_addr,
17552311Sseb 		    mip->mi_type->mt_addr_length);
17562311Sseb 		mip->mi_info.mi_unicst_addr = NULL;
17572311Sseb 	}
17582311Sseb 
17592311Sseb 	mac_stat_destroy(mip);
17602311Sseb 
17612311Sseb 	if (mip->mi_type != NULL) {
17623288Sseb 		atomic_dec_32(&mip->mi_type->mt_ref);
17632311Sseb 		mip->mi_type = NULL;
17642311Sseb 	}
17652311Sseb 
17662311Sseb 	if (mip->mi_pdata != NULL) {
17672311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
17682311Sseb 		mip->mi_pdata = NULL;
17692311Sseb 		mip->mi_pdata_size = 0;
17702311Sseb 	}
17712311Sseb 
17725895Syz147064 	if (minor != 0) {
17735895Syz147064 		ASSERT(minor > MAC_MAX_MINOR);
17745895Syz147064 		mac_minor_rele(minor);
17755895Syz147064 	}
17765895Syz147064 
1777*7406SSowmini.Varadhan@Sun.COM 	mac_unregister_priv_prop(mip);
1778*7406SSowmini.Varadhan@Sun.COM 
17792311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
1780269Sericheng 	return (err);
17810Sstevel@tonic-gate }
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate int
17845084Sjohnlev mac_disable(mac_handle_t mh)
17850Sstevel@tonic-gate {
17862311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
1787269Sericheng 
17880Sstevel@tonic-gate 	/*
17890Sstevel@tonic-gate 	 * See if there are any other references to this mac_t (e.g., VLAN's).
17901852Syz147064 	 * If not, set mi_disabled to prevent any new VLAN's from being
17912311Sseb 	 * created while we're destroying this mac.
17920Sstevel@tonic-gate 	 */
1793269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
17940Sstevel@tonic-gate 	if (mip->mi_ref > 0) {
1795269Sericheng 		rw_exit(&i_mac_impl_lock);
17960Sstevel@tonic-gate 		return (EBUSY);
17970Sstevel@tonic-gate 	}
17981852Syz147064 	mip->mi_disabled = B_TRUE;
1799269Sericheng 	rw_exit(&i_mac_impl_lock);
18005084Sjohnlev 	return (0);
18015084Sjohnlev }
18025084Sjohnlev 
18035084Sjohnlev int
18045084Sjohnlev mac_unregister(mac_handle_t mh)
18055084Sjohnlev {
18065084Sjohnlev 	int			err;
18075084Sjohnlev 	mac_impl_t		*mip = (mac_impl_t *)mh;
18085084Sjohnlev 	mod_hash_val_t		val;
18095084Sjohnlev 	mac_multicst_addr_t	*p, *nextp;
18105895Syz147064 	mac_margin_req_t	*mmr, *nextmmr;
18115084Sjohnlev 
18125084Sjohnlev 	/*
18135084Sjohnlev 	 * See if there are any other references to this mac_t (e.g., VLAN's).
18145084Sjohnlev 	 * If not, set mi_disabled to prevent any new VLAN's from being
18155084Sjohnlev 	 * created while we're destroying this mac. Once mac_disable() returns
18165084Sjohnlev 	 * 0, the rest of mac_unregister() stuff should continue without
18175084Sjohnlev 	 * returning an error.
18185084Sjohnlev 	 */
18195084Sjohnlev 	if (!mip->mi_disabled) {
18205084Sjohnlev 		if ((err = mac_disable(mh)) != 0)
18215084Sjohnlev 			return (err);
18225084Sjohnlev 	}
18235084Sjohnlev 
18240Sstevel@tonic-gate 	/*
18255009Sgd78059 	 * Clean up notification thread (wait for it to exit).
18265009Sgd78059 	 */
18275009Sgd78059 	mutex_enter(&mip->mi_notify_bits_lock);
18285009Sgd78059 	mip->mi_notify_bits = (1 << MAC_NNOTE);
18295009Sgd78059 	cv_broadcast(&mip->mi_notify_cv);
18305009Sgd78059 	while (mip->mi_notify_bits != 0)
18315009Sgd78059 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
18325009Sgd78059 	mutex_exit(&mip->mi_notify_bits_lock);
18335009Sgd78059 
18345895Syz147064 	if (mip->mi_minor < MAC_MAX_MINOR + 1) {
18355895Syz147064 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
18365895Syz147064 		ddi_remove_minor_node(mip->mi_dip,
18375895Syz147064 		    (char *)ddi_driver_name(mip->mi_dip));
18385895Syz147064 	}
18392311Sseb 
18402311Sseb 	ASSERT(!mip->mi_activelink);
18412311Sseb 
18422311Sseb 	mac_stat_destroy(mip);
18432311Sseb 
18445895Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
18455895Syz147064 	(void) mod_hash_remove(i_mac_impl_hash,
18465895Syz147064 	    (mod_hash_key_t)mip->mi_name, &val);
18472311Sseb 	ASSERT(mip == (mac_impl_t *)val);
18482311Sseb 
18492311Sseb 	ASSERT(i_mac_impl_count > 0);
18503288Sseb 	atomic_dec_32(&i_mac_impl_count);
18515895Syz147064 	rw_exit(&i_mac_impl_lock);
18522311Sseb 
18532311Sseb 	if (mip->mi_pdata != NULL)
18542311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
18552311Sseb 	mip->mi_pdata = NULL;
18562311Sseb 	mip->mi_pdata_size = 0;
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 	/*
18592311Sseb 	 * Free the list of multicast addresses.
18600Sstevel@tonic-gate 	 */
18612311Sseb 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
18622311Sseb 		nextp = p->mma_nextp;
18632311Sseb 		kmem_free(p, sizeof (mac_multicst_addr_t));
18642311Sseb 	}
18652311Sseb 	mip->mi_mmap = NULL;
18660Sstevel@tonic-gate 
18675895Syz147064 	/*
18685895Syz147064 	 * Free the list of margin request.
18695895Syz147064 	 */
18705895Syz147064 	for (mmr = mip->mi_mmrp; mmr != NULL; mmr = nextmmr) {
18715895Syz147064 		nextmmr = mmr->mmr_nextp;
18725895Syz147064 		kmem_free(mmr, sizeof (mac_margin_req_t));
18735895Syz147064 	}
18745895Syz147064 	mip->mi_mmrp = NULL;
18755895Syz147064 
18762311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
18772311Sseb 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
18782311Sseb 	mip->mi_info.mi_unicst_addr = NULL;
18792311Sseb 
18803288Sseb 	atomic_dec_32(&mip->mi_type->mt_ref);
18812311Sseb 	mip->mi_type = NULL;
18822311Sseb 
18835895Syz147064 	if (mip->mi_minor > MAC_MAX_MINOR)
18845895Syz147064 		mac_minor_rele(mip->mi_minor);
18855895Syz147064 
1886*7406SSowmini.Varadhan@Sun.COM 	mac_unregister_priv_prop(mip);
1887*7406SSowmini.Varadhan@Sun.COM 
18882311Sseb 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
18892311Sseb 
18902311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
18912311Sseb 
18920Sstevel@tonic-gate 	return (0);
18930Sstevel@tonic-gate }
18940Sstevel@tonic-gate 
18954913Sethindra /*
18964913Sethindra  * To avoid potential deadlocks, mac_rx() releases mi_rx_lock
18974913Sethindra  * before invoking its list of upcalls. This introduces races with
18984913Sethindra  * mac_rx_remove() and mac_rx_add(), who can potentially modify the
18994913Sethindra  * upcall list while mi_rx_lock is not being held. The race with
19004913Sethindra  * mac_rx_remove() is handled by incrementing mi_rx_ref upon entering
19014913Sethindra  * mac_rx(); a non-zero mi_rx_ref would tell mac_rx_remove()
19024913Sethindra  * to not modify the list but instead mark an upcall for deletion.
19034913Sethindra  * before mac_rx() exits, mi_rx_ref is decremented and if it
19044913Sethindra  * is 0, the marked upcalls will be removed from the list and freed.
19054913Sethindra  * The race with mac_rx_add() is harmless because mac_rx_add() only
19064913Sethindra  * prepends to the list and since mac_rx() saves the list head
19074913Sethindra  * before releasing mi_rx_lock, any prepended upcall won't be seen
19084913Sethindra  * until the next packet chain arrives.
19094913Sethindra  *
19104913Sethindra  * To minimize lock contention between multiple parallel invocations
19114913Sethindra  * of mac_rx(), mi_rx_lock is acquired as a READER lock. The
19124913Sethindra  * use of atomic operations ensures the sanity of mi_rx_ref. mi_rx_lock
19134913Sethindra  * will be upgraded to WRITER mode when there are marked upcalls to be
19144913Sethindra  * cleaned.
19154913Sethindra  */
19165084Sjohnlev static void
19175084Sjohnlev mac_do_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain,
19185084Sjohnlev     boolean_t active_only)
19190Sstevel@tonic-gate {
19202311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
19214913Sethindra 	mblk_t		*bp = mp_chain;
19220Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 	/*
19250Sstevel@tonic-gate 	 * Call all registered receive functions.
19260Sstevel@tonic-gate 	 */
19270Sstevel@tonic-gate 	rw_enter(&mip->mi_rx_lock, RW_READER);
19284913Sethindra 	if ((mrfp = mip->mi_mrfp) == NULL) {
19290Sstevel@tonic-gate 		/* There are no registered receive functions. */
19300Sstevel@tonic-gate 		freemsgchain(bp);
19310Sstevel@tonic-gate 		rw_exit(&mip->mi_rx_lock);
19320Sstevel@tonic-gate 		return;
19330Sstevel@tonic-gate 	}
19344913Sethindra 	atomic_inc_32(&mip->mi_rx_ref);
19354913Sethindra 	rw_exit(&mip->mi_rx_lock);
19364913Sethindra 
19374913Sethindra 	/*
19384913Sethindra 	 * Call registered receive functions.
19394913Sethindra 	 */
19400Sstevel@tonic-gate 	do {
19410Sstevel@tonic-gate 		mblk_t *recv_bp;
19420Sstevel@tonic-gate 
19435084Sjohnlev 		if (active_only && !mrfp->mrf_active) {
19445084Sjohnlev 			mrfp = mrfp->mrf_nextp;
19455084Sjohnlev 			if (mrfp == NULL) {
19465084Sjohnlev 				/*
19475084Sjohnlev 				 * We hit the last receiver, but it's not
19485084Sjohnlev 				 * active.
19495084Sjohnlev 				 */
19505084Sjohnlev 				freemsgchain(bp);
19515084Sjohnlev 			}
19525084Sjohnlev 			continue;
19535084Sjohnlev 		}
19545084Sjohnlev 
19554913Sethindra 		recv_bp = (mrfp->mrf_nextp != NULL) ? copymsgchain(bp) : bp;
19564913Sethindra 		if (recv_bp != NULL) {
19574913Sethindra 			if (mrfp->mrf_inuse) {
19584913Sethindra 				/*
19594913Sethindra 				 * Send bp itself and keep the copy.
19604913Sethindra 				 * If there's only one active receiver,
19614913Sethindra 				 * it should get the original message,
19624913Sethindra 				 * tagged with the hardware checksum flags.
19634913Sethindra 				 */
19644913Sethindra 				mrfp->mrf_fn(mrfp->mrf_arg, mrh, bp);
19654913Sethindra 				bp = recv_bp;
19664913Sethindra 			} else {
19674913Sethindra 				freemsgchain(recv_bp);
19684913Sethindra 			}
19690Sstevel@tonic-gate 		}
19705084Sjohnlev 
19710Sstevel@tonic-gate 		mrfp = mrfp->mrf_nextp;
19720Sstevel@tonic-gate 	} while (mrfp != NULL);
19734913Sethindra 
19744913Sethindra 	rw_enter(&mip->mi_rx_lock, RW_READER);
19754913Sethindra 	if (atomic_dec_32_nv(&mip->mi_rx_ref) == 0 && mip->mi_rx_removed > 0) {
19764913Sethindra 		mac_rx_fn_t	**pp, *p;
19774913Sethindra 		uint32_t	cnt = 0;
19784913Sethindra 
19794913Sethindra 		DTRACE_PROBE1(delete_callbacks, mac_impl_t *, mip);
19804913Sethindra 
19814913Sethindra 		/*
19824913Sethindra 		 * Need to become exclusive before doing cleanup
19834913Sethindra 		 */
19844913Sethindra 		if (rw_tryupgrade(&mip->mi_rx_lock) == 0) {
19854913Sethindra 			rw_exit(&mip->mi_rx_lock);
19864913Sethindra 			rw_enter(&mip->mi_rx_lock, RW_WRITER);
19874913Sethindra 		}
19884913Sethindra 
19894913Sethindra 		/*
19904913Sethindra 		 * We return if another thread has already entered and cleaned
19914913Sethindra 		 * up the list.
19924913Sethindra 		 */
19934913Sethindra 		if (mip->mi_rx_ref > 0 || mip->mi_rx_removed == 0) {
19944913Sethindra 			rw_exit(&mip->mi_rx_lock);
19954913Sethindra 			return;
19964913Sethindra 		}
19974913Sethindra 
19984913Sethindra 		/*
19994913Sethindra 		 * Free removed callbacks.
20004913Sethindra 		 */
20014913Sethindra 		pp = &mip->mi_mrfp;
20024913Sethindra 		while (*pp != NULL) {
20034913Sethindra 			if (!(*pp)->mrf_inuse) {
20044913Sethindra 				p = *pp;
20054913Sethindra 				*pp = (*pp)->mrf_nextp;
20064913Sethindra 				kmem_free(p, sizeof (*p));
20074913Sethindra 				cnt++;
20084913Sethindra 				continue;
20094913Sethindra 			}
20104913Sethindra 			pp = &(*pp)->mrf_nextp;
20114913Sethindra 		}
20124913Sethindra 
20134913Sethindra 		/*
20144913Sethindra 		 * Wake up mac_rx_remove_wait()
20154913Sethindra 		 */
20164913Sethindra 		mutex_enter(&mip->mi_lock);
20174913Sethindra 		ASSERT(mip->mi_rx_removed == cnt);
20184913Sethindra 		mip->mi_rx_removed = 0;
20194913Sethindra 		cv_broadcast(&mip->mi_rx_cv);
20204913Sethindra 		mutex_exit(&mip->mi_lock);
20214913Sethindra 	}
20220Sstevel@tonic-gate 	rw_exit(&mip->mi_rx_lock);
20230Sstevel@tonic-gate }
20240Sstevel@tonic-gate 
20255084Sjohnlev void
20265084Sjohnlev mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain)
20275084Sjohnlev {
20285084Sjohnlev 	mac_do_rx(mh, mrh, mp_chain, B_FALSE);
20295084Sjohnlev }
20305084Sjohnlev 
20315084Sjohnlev /*
20325084Sjohnlev  * Send a packet chain up to the receive callbacks which declared
20335084Sjohnlev  * themselves as being active.
20345084Sjohnlev  */
20355084Sjohnlev void
20365084Sjohnlev mac_active_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp_chain)
20375084Sjohnlev {
20385084Sjohnlev 	mac_do_rx(arg, mrh, mp_chain, B_TRUE);
20395084Sjohnlev }
20405084Sjohnlev 
20415084Sjohnlev /*
20425084Sjohnlev  * Function passed to the active client sharing a VNIC. This function
20435084Sjohnlev  * is returned by mac_tx_get() when a VNIC is present. It invokes
20445084Sjohnlev  * the VNIC transmit entry point which was specified by the VNIC when
20455084Sjohnlev  * it called mac_vnic_set(). The VNIC transmit entry point will
20465084Sjohnlev  * pass the packets to the local VNICs and/or to the underlying VNICs
20475084Sjohnlev  * if needed.
20485084Sjohnlev  */
20495084Sjohnlev static mblk_t *
20505084Sjohnlev mac_vnic_tx(void *arg, mblk_t *mp)
20515084Sjohnlev {
20525084Sjohnlev 	mac_impl_t	*mip = arg;
20535084Sjohnlev 	mac_txinfo_t	*mtfp;
20545084Sjohnlev 	mac_vnic_tx_t	*mvt;
20555084Sjohnlev 
20565084Sjohnlev 	/*
20575084Sjohnlev 	 * There is a race between the notification of the VNIC
20585084Sjohnlev 	 * addition and removal, and the processing of the VNIC notification
20595084Sjohnlev 	 * by the MAC client. During this window, it is possible for
20605084Sjohnlev 	 * an active MAC client to contine invoking mac_vnic_tx() while
20615084Sjohnlev 	 * the VNIC has already been removed. So we cannot assume
20625084Sjohnlev 	 * that mi_vnic_present will always be true when mac_vnic_tx()
20635084Sjohnlev 	 * is invoked.
20645084Sjohnlev 	 */
20655084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_READER);
20665084Sjohnlev 	if (!mip->mi_vnic_present) {
20675084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
20685084Sjohnlev 		freemsgchain(mp);
20695084Sjohnlev 		return (NULL);
20705084Sjohnlev 	}
20715084Sjohnlev 
20725084Sjohnlev 	ASSERT(mip->mi_vnic_tx != NULL);
20735084Sjohnlev 	mvt = mip->mi_vnic_tx;
20745084Sjohnlev 	MAC_VNIC_TXINFO_REFHOLD(mvt);
20755084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
20765084Sjohnlev 
20775084Sjohnlev 	mtfp = &mvt->mv_txinfo;
20785084Sjohnlev 	mtfp->mt_fn(mtfp->mt_arg, mp);
20795084Sjohnlev 
20805084Sjohnlev 	MAC_VNIC_TXINFO_REFRELE(mvt);
20815084Sjohnlev 	return (NULL);
20825084Sjohnlev }
20835084Sjohnlev 
20840Sstevel@tonic-gate /*
20850Sstevel@tonic-gate  * Transmit function -- ONLY used when there are registered loopback listeners.
20860Sstevel@tonic-gate  */
20870Sstevel@tonic-gate mblk_t *
20885084Sjohnlev mac_do_txloop(void *arg, mblk_t *bp, boolean_t call_vnic)
20890Sstevel@tonic-gate {
20900Sstevel@tonic-gate 	mac_impl_t	*mip = arg;
20910Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
20920Sstevel@tonic-gate 	mblk_t		*loop_bp, *resid_bp, *next_bp;
20930Sstevel@tonic-gate 
20945084Sjohnlev 	if (call_vnic) {
20955084Sjohnlev 		/*
20965084Sjohnlev 		 * In promiscous mode, a copy of the sent packet will
20975084Sjohnlev 		 * be sent to the client's promiscous receive entry
20985084Sjohnlev 		 * points via mac_vnic_tx()->
20995084Sjohnlev 		 * mac_active_rx_promisc()->mac_rx_default().
21005084Sjohnlev 		 */
21015084Sjohnlev 		return (mac_vnic_tx(arg, bp));
21025084Sjohnlev 	}
21035084Sjohnlev 
21040Sstevel@tonic-gate 	while (bp != NULL) {
21050Sstevel@tonic-gate 		next_bp = bp->b_next;
21060Sstevel@tonic-gate 		bp->b_next = NULL;
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 		if ((loop_bp = copymsg(bp)) == NULL)
21090Sstevel@tonic-gate 			goto noresources;
21100Sstevel@tonic-gate 
21112311Sseb 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
21120Sstevel@tonic-gate 			ASSERT(resid_bp == bp);
21130Sstevel@tonic-gate 			freemsg(loop_bp);
21140Sstevel@tonic-gate 			goto noresources;
21150Sstevel@tonic-gate 		}
21160Sstevel@tonic-gate 
21175084Sjohnlev 		rw_enter(&mip->mi_tx_lock, RW_READER);
21180Sstevel@tonic-gate 		mtfp = mip->mi_mtfp;
211956Smeem 		while (mtfp != NULL && loop_bp != NULL) {
21200Sstevel@tonic-gate 			bp = loop_bp;
212156Smeem 
212256Smeem 			/* XXX counter bump if copymsg() fails? */
212356Smeem 			if (mtfp->mtf_nextp != NULL)
21240Sstevel@tonic-gate 				loop_bp = copymsg(bp);
212556Smeem 			else
212656Smeem 				loop_bp = NULL;
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
212956Smeem 			mtfp = mtfp->mtf_nextp;
21300Sstevel@tonic-gate 		}
21315084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
21320Sstevel@tonic-gate 
213356Smeem 		/*
213456Smeem 		 * It's possible we've raced with the disabling of promiscuous
213556Smeem 		 * mode, in which case we can discard our copy.
213656Smeem 		 */
213756Smeem 		if (loop_bp != NULL)
213856Smeem 			freemsg(loop_bp);
213956Smeem 
21400Sstevel@tonic-gate 		bp = next_bp;
21410Sstevel@tonic-gate 	}
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 	return (NULL);
21440Sstevel@tonic-gate 
21450Sstevel@tonic-gate noresources:
21460Sstevel@tonic-gate 	bp->b_next = next_bp;
21470Sstevel@tonic-gate 	return (bp);
21480Sstevel@tonic-gate }
21490Sstevel@tonic-gate 
21505084Sjohnlev mblk_t *
21515084Sjohnlev mac_txloop(void *arg, mblk_t *bp)
21525084Sjohnlev {
21535084Sjohnlev 	return (mac_do_txloop(arg, bp, B_FALSE));
21545084Sjohnlev }
21555084Sjohnlev 
21565084Sjohnlev static mblk_t *
21575084Sjohnlev mac_vnic_txloop(void *arg, mblk_t *bp)
21585084Sjohnlev {
21595084Sjohnlev 	return (mac_do_txloop(arg, bp, B_TRUE));
21605084Sjohnlev }
21615084Sjohnlev 
21620Sstevel@tonic-gate void
21632311Sseb mac_link_update(mac_handle_t mh, link_state_t link)
21640Sstevel@tonic-gate {
21652311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	/*
21680Sstevel@tonic-gate 	 * Save the link state.
21690Sstevel@tonic-gate 	 */
21702311Sseb 	mip->mi_linkstate = link;
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate 	/*
21730Sstevel@tonic-gate 	 * Send a MAC_NOTE_LINK notification.
21740Sstevel@tonic-gate 	 */
21750Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_LINK);
21760Sstevel@tonic-gate }
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate void
21792311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
21800Sstevel@tonic-gate {
21812311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
21820Sstevel@tonic-gate 
21832311Sseb 	if (mip->mi_type->mt_addr_length == 0)
21842311Sseb 		return;
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 	/*
21875895Syz147064 	 * If the address has not changed, do nothing.
21885895Syz147064 	 */
21895895Syz147064 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0)
21905895Syz147064 		return;
21915895Syz147064 
21925895Syz147064 	/*
21930Sstevel@tonic-gate 	 * Save the address.
21940Sstevel@tonic-gate 	 */
21952311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 	/*
21980Sstevel@tonic-gate 	 * Send a MAC_NOTE_UNICST notification.
21990Sstevel@tonic-gate 	 */
22000Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_UNICST);
22010Sstevel@tonic-gate }
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate void
22042311Sseb mac_tx_update(mac_handle_t mh)
22050Sstevel@tonic-gate {
22060Sstevel@tonic-gate 	/*
22070Sstevel@tonic-gate 	 * Send a MAC_NOTE_TX notification.
22080Sstevel@tonic-gate 	 */
22092311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
22100Sstevel@tonic-gate }
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate void
22132311Sseb mac_resource_update(mac_handle_t mh)
22140Sstevel@tonic-gate {
22150Sstevel@tonic-gate 	/*
22160Sstevel@tonic-gate 	 * Send a MAC_NOTE_RESOURCE notification.
22170Sstevel@tonic-gate 	 */
22182311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
22190Sstevel@tonic-gate }
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate mac_resource_handle_t
22222311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
22230Sstevel@tonic-gate {
22242311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
22250Sstevel@tonic-gate 	mac_resource_handle_t	mrh;
22260Sstevel@tonic-gate 	mac_resource_add_t	add;
22270Sstevel@tonic-gate 	void			*arg;
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 	rw_enter(&mip->mi_resource_lock, RW_READER);
22300Sstevel@tonic-gate 	add = mip->mi_resource_add;
22310Sstevel@tonic-gate 	arg = mip->mi_resource_add_arg;
22320Sstevel@tonic-gate 
22331184Skrgopi 	if (add != NULL)
22341184Skrgopi 		mrh = add(arg, mrp);
22351184Skrgopi 	else
22361184Skrgopi 		mrh = NULL;
22370Sstevel@tonic-gate 	rw_exit(&mip->mi_resource_lock);
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 	return (mrh);
22400Sstevel@tonic-gate }
22410Sstevel@tonic-gate 
22422311Sseb int
22432311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
22442311Sseb {
22452311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
22462311Sseb 
22472311Sseb 	/*
22482311Sseb 	 * Verify that the plugin supports MAC plugin data and that the
22492311Sseb 	 * supplied data is valid.
22502311Sseb 	 */
22512311Sseb 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
22522311Sseb 		return (EINVAL);
22532311Sseb 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
22542311Sseb 		return (EINVAL);
22552311Sseb 
22562311Sseb 	if (mip->mi_pdata != NULL)
22572311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
22582311Sseb 
22592311Sseb 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
22602311Sseb 	bcopy(mac_pdata, mip->mi_pdata, dsize);
22612311Sseb 	mip->mi_pdata_size = dsize;
22622311Sseb 
22632311Sseb 	/*
22642311Sseb 	 * Since the MAC plugin data is used to construct MAC headers that
22652311Sseb 	 * were cached in fast-path headers, we need to flush fast-path
22662311Sseb 	 * information for links associated with this mac.
22672311Sseb 	 */
22682311Sseb 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
22692311Sseb 	return (0);
22702311Sseb }
22712311Sseb 
22720Sstevel@tonic-gate void
22732311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
22740Sstevel@tonic-gate     boolean_t add)
22750Sstevel@tonic-gate {
22762311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
22770Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 	/*
22800Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
22810Sstevel@tonic-gate 	 * driver's m_multicst entry point.
22820Sstevel@tonic-gate 	 */
22830Sstevel@tonic-gate 	if (refresh == NULL) {
22842311Sseb 		refresh = mip->mi_multicst;
22852311Sseb 		arg = mip->mi_driver;
22860Sstevel@tonic-gate 	}
22870Sstevel@tonic-gate 	ASSERT(refresh != NULL);
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	/*
22900Sstevel@tonic-gate 	 * Walk the multicast address list and call the refresh function for
22910Sstevel@tonic-gate 	 * each address.
22920Sstevel@tonic-gate 	 */
22930Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
22940Sstevel@tonic-gate 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
22950Sstevel@tonic-gate 		refresh(arg, add, p->mma_addr);
22960Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
22970Sstevel@tonic-gate }
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate void
23002311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
23010Sstevel@tonic-gate {
23022311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
23030Sstevel@tonic-gate 	/*
23040Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
23052311Sseb 	 * driver's mi_unicst entry point.
23060Sstevel@tonic-gate 	 */
23070Sstevel@tonic-gate 	if (refresh == NULL) {
23082311Sseb 		refresh = mip->mi_unicst;
23092311Sseb 		arg = mip->mi_driver;
23100Sstevel@tonic-gate 	}
23110Sstevel@tonic-gate 	ASSERT(refresh != NULL);
23120Sstevel@tonic-gate 
23130Sstevel@tonic-gate 	/*
23140Sstevel@tonic-gate 	 * Call the refresh function with the current unicast address.
23150Sstevel@tonic-gate 	 */
23160Sstevel@tonic-gate 	refresh(arg, mip->mi_addr);
23170Sstevel@tonic-gate }
23180Sstevel@tonic-gate 
23190Sstevel@tonic-gate void
23202311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
23210Sstevel@tonic-gate {
23222311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
23230Sstevel@tonic-gate 
23240Sstevel@tonic-gate 	/*
23250Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
23260Sstevel@tonic-gate 	 * driver's m_promisc entry point.
23270Sstevel@tonic-gate 	 */
23280Sstevel@tonic-gate 	if (refresh == NULL) {
23292311Sseb 		refresh = mip->mi_setpromisc;
23302311Sseb 		arg = mip->mi_driver;
23310Sstevel@tonic-gate 	}
23320Sstevel@tonic-gate 	ASSERT(refresh != NULL);
23330Sstevel@tonic-gate 
23340Sstevel@tonic-gate 	/*
23350Sstevel@tonic-gate 	 * Call the refresh function with the current promiscuity.
23360Sstevel@tonic-gate 	 */
23370Sstevel@tonic-gate 	refresh(arg, (mip->mi_devpromisc != 0));
23380Sstevel@tonic-gate }
23390Sstevel@tonic-gate 
23405895Syz147064 /*
23415895Syz147064  * The mac client requests that the mac not to change its margin size to
23425895Syz147064  * be less than the specified value.  If "current" is B_TRUE, then the client
23435895Syz147064  * requests the mac not to change its margin size to be smaller than the
23445895Syz147064  * current size. Further, return the current margin size value in this case.
23455895Syz147064  *
23465895Syz147064  * We keep every requested size in an ordered list from largest to smallest.
23475895Syz147064  */
23485895Syz147064 int
23495895Syz147064 mac_margin_add(mac_handle_t mh, uint32_t *marginp, boolean_t current)
23505895Syz147064 {
23515895Syz147064 	mac_impl_t		*mip = (mac_impl_t *)mh;
23525895Syz147064 	mac_margin_req_t	**pp, *p;
23535895Syz147064 	int			err = 0;
23545895Syz147064 
23555895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
23565895Syz147064 	if (current)
23575895Syz147064 		*marginp = mip->mi_margin;
23585895Syz147064 
23595895Syz147064 	/*
23605895Syz147064 	 * If the current margin value cannot satisfy the margin requested,
23615895Syz147064 	 * return ENOTSUP directly.
23625895Syz147064 	 */
23635895Syz147064 	if (*marginp > mip->mi_margin) {
23645895Syz147064 		err = ENOTSUP;
23655895Syz147064 		goto done;
23665895Syz147064 	}
23675895Syz147064 
23685895Syz147064 	/*
23695895Syz147064 	 * Check whether the given margin is already in the list. If so,
23705895Syz147064 	 * bump the reference count.
23715895Syz147064 	 */
23725895Syz147064 	for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
23735895Syz147064 		if (p->mmr_margin == *marginp) {
23745895Syz147064 			/*
23755895Syz147064 			 * The margin requested is already in the list,
23765895Syz147064 			 * so just bump the reference count.
23775895Syz147064 			 */
23785895Syz147064 			p->mmr_ref++;
23795895Syz147064 			goto done;
23805895Syz147064 		}
23815895Syz147064 		if (p->mmr_margin < *marginp)
23825895Syz147064 			break;
23835895Syz147064 	}
23845895Syz147064 
23855895Syz147064 
23865895Syz147064 	if ((p = kmem_zalloc(sizeof (mac_margin_req_t), KM_NOSLEEP)) == NULL) {
23875895Syz147064 		err = ENOMEM;
23885895Syz147064 		goto done;
23895895Syz147064 	}
23905895Syz147064 
23915895Syz147064 	p->mmr_margin = *marginp;
23925895Syz147064 	p->mmr_ref++;
23935895Syz147064 	p->mmr_nextp = *pp;
23945895Syz147064 	*pp = p;
23955895Syz147064 
23965895Syz147064 done:
23975895Syz147064 	rw_exit(&(mip->mi_data_lock));
23985895Syz147064 	return (err);
23995895Syz147064 }
24005895Syz147064 
24015895Syz147064 /*
24025895Syz147064  * The mac client requests to cancel its previous mac_margin_add() request.
24035895Syz147064  * We remove the requested margin size from the list.
24045895Syz147064  */
24055895Syz147064 int
24065895Syz147064 mac_margin_remove(mac_handle_t mh, uint32_t margin)
24075895Syz147064 {
24085895Syz147064 	mac_impl_t		*mip = (mac_impl_t *)mh;
24095895Syz147064 	mac_margin_req_t	**pp, *p;
24105895Syz147064 	int			err = 0;
24115895Syz147064 
24125895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
24135895Syz147064 	/*
24145895Syz147064 	 * Find the entry in the list for the given margin.
24155895Syz147064 	 */
24165895Syz147064 	for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
24175895Syz147064 		if (p->mmr_margin == margin) {
24185895Syz147064 			if (--p->mmr_ref == 0)
24195895Syz147064 				break;
24205895Syz147064 
24215895Syz147064 			/*
24225895Syz147064 			 * There is still a reference to this address so
24235895Syz147064 			 * there's nothing more to do.
24245895Syz147064 			 */
24255895Syz147064 			goto done;
24265895Syz147064 		}
24275895Syz147064 	}
24285895Syz147064 
24295895Syz147064 	/*
24305895Syz147064 	 * We did not find an entry for the given margin.
24315895Syz147064 	 */
24325895Syz147064 	if (p == NULL) {
24335895Syz147064 		err = ENOENT;
24345895Syz147064 		goto done;
24355895Syz147064 	}
24365895Syz147064 
24375895Syz147064 	ASSERT(p->mmr_ref == 0);
24385895Syz147064 
24395895Syz147064 	/*
24405895Syz147064 	 * Remove it from the list.
24415895Syz147064 	 */
24425895Syz147064 	*pp = p->mmr_nextp;
24435895Syz147064 	kmem_free(p, sizeof (mac_margin_req_t));
24445895Syz147064 done:
24455895Syz147064 	rw_exit(&(mip->mi_data_lock));
24465895Syz147064 	return (err);
24475895Syz147064 }
24485895Syz147064 
24495895Syz147064 /*
24505895Syz147064  * The mac client requests to get the mac's current margin value.
24515895Syz147064  */
24525895Syz147064 void
24535895Syz147064 mac_margin_get(mac_handle_t mh, uint32_t *marginp)
24545895Syz147064 {
24555895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
24565895Syz147064 
24575895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_READER);
24585895Syz147064 	*marginp = mip->mi_margin;
24595895Syz147064 	rw_exit(&(mip->mi_data_lock));
24605895Syz147064 }
24615895Syz147064 
24625895Syz147064 boolean_t
24635895Syz147064 mac_margin_update(mac_handle_t mh, uint32_t margin)
24645895Syz147064 {
24655895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
24665895Syz147064 	uint32_t	margin_needed = 0;
24675895Syz147064 
24685895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
24695895Syz147064 
24705895Syz147064 	if (mip->mi_mmrp != NULL)
24715895Syz147064 		margin_needed = mip->mi_mmrp->mmr_margin;
24725895Syz147064 
24735895Syz147064 	if (margin_needed <= margin)
24745895Syz147064 		mip->mi_margin = margin;
24755895Syz147064 
24765895Syz147064 	rw_exit(&(mip->mi_data_lock));
24775895Syz147064 
24785895Syz147064 	if (margin_needed <= margin)
24795895Syz147064 		i_mac_notify(mip, MAC_NOTE_MARGIN);
24805895Syz147064 
24815895Syz147064 	return (margin_needed <= margin);
24825895Syz147064 }
24835895Syz147064 
24840Sstevel@tonic-gate boolean_t
24855084Sjohnlev mac_do_active_set(mac_handle_t mh, boolean_t shareable)
24860Sstevel@tonic-gate {
24870Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
24900Sstevel@tonic-gate 	if (mip->mi_activelink) {
24910Sstevel@tonic-gate 		mutex_exit(&mip->mi_activelink_lock);
24920Sstevel@tonic-gate 		return (B_FALSE);
24930Sstevel@tonic-gate 	}
24940Sstevel@tonic-gate 	mip->mi_activelink = B_TRUE;
24955084Sjohnlev 	mip->mi_shareable = shareable;
24960Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
24970Sstevel@tonic-gate 	return (B_TRUE);
24980Sstevel@tonic-gate }
24990Sstevel@tonic-gate 
25005084Sjohnlev /*
25015084Sjohnlev  * Called by MAC clients. By default, active MAC clients cannot
25025084Sjohnlev  * share the NIC with VNICs.
25035084Sjohnlev  */
25045084Sjohnlev boolean_t
25055084Sjohnlev mac_active_set(mac_handle_t mh)
25065084Sjohnlev {
25075084Sjohnlev 	return (mac_do_active_set(mh, B_FALSE));
25085084Sjohnlev }
25095084Sjohnlev 
25105084Sjohnlev /*
25115084Sjohnlev  * Called by MAC clients which can share the NIC with VNICS, e.g. DLS.
25125084Sjohnlev  */
25135084Sjohnlev boolean_t
25145084Sjohnlev mac_active_shareable_set(mac_handle_t mh)
25155084Sjohnlev {
25165084Sjohnlev 	return (mac_do_active_set(mh, B_TRUE));
25175084Sjohnlev }
25185084Sjohnlev 
25190Sstevel@tonic-gate void
25200Sstevel@tonic-gate mac_active_clear(mac_handle_t mh)
25210Sstevel@tonic-gate {
25220Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
25250Sstevel@tonic-gate 	ASSERT(mip->mi_activelink);
25260Sstevel@tonic-gate 	mip->mi_activelink = B_FALSE;
25270Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
25280Sstevel@tonic-gate }
2529269Sericheng 
25305084Sjohnlev boolean_t
25315084Sjohnlev mac_vnic_set(mac_handle_t mh, mac_txinfo_t *tx_info, mac_getcapab_t getcapab_fn,
25325084Sjohnlev     void *getcapab_arg)
25335084Sjohnlev {
25345084Sjohnlev 	mac_impl_t	*mip = (mac_impl_t *)mh;
25355084Sjohnlev 	mac_vnic_tx_t	*vnic_tx;
25365084Sjohnlev 
25375084Sjohnlev 	mutex_enter(&mip->mi_activelink_lock);
25385084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_WRITER);
25395084Sjohnlev 	ASSERT(!mip->mi_vnic_present);
25405084Sjohnlev 
25415084Sjohnlev 	if (mip->mi_activelink && !mip->mi_shareable) {
25425084Sjohnlev 		/*
25435084Sjohnlev 		 * The NIC is already used by an active client which cannot
25445084Sjohnlev 		 * share it with VNICs.
25455084Sjohnlev 		 */
25465084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
25475084Sjohnlev 		mutex_exit(&mip->mi_activelink_lock);
25485084Sjohnlev 		return (B_FALSE);
25495084Sjohnlev 	}
25505084Sjohnlev 
25515084Sjohnlev 	vnic_tx = kmem_cache_alloc(mac_vnic_tx_cache, KM_SLEEP);
25525084Sjohnlev 	vnic_tx->mv_refs = 0;
25535084Sjohnlev 	vnic_tx->mv_txinfo = *tx_info;
25545084Sjohnlev 	vnic_tx->mv_clearing = B_FALSE;
25555084Sjohnlev 
25565084Sjohnlev 	mip->mi_vnic_present = B_TRUE;
25575084Sjohnlev 	mip->mi_vnic_tx = vnic_tx;
25585084Sjohnlev 	mip->mi_vnic_getcapab_fn = getcapab_fn;
25595084Sjohnlev 	mip->mi_vnic_getcapab_arg = getcapab_arg;
25605084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
25615084Sjohnlev 	mutex_exit(&mip->mi_activelink_lock);
25625084Sjohnlev 
25635084Sjohnlev 	i_mac_notify(mip, MAC_NOTE_VNIC);
25645084Sjohnlev 	return (B_TRUE);
25655084Sjohnlev }
25665084Sjohnlev 
25675084Sjohnlev void
25685084Sjohnlev mac_vnic_clear(mac_handle_t mh)
25695084Sjohnlev {
25705084Sjohnlev 	mac_impl_t *mip = (mac_impl_t *)mh;
25715084Sjohnlev 	mac_vnic_tx_t	*vnic_tx;
25725084Sjohnlev 
25735084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_WRITER);
25745084Sjohnlev 	ASSERT(mip->mi_vnic_present);
25755084Sjohnlev 	mip->mi_vnic_present = B_FALSE;
25765084Sjohnlev 	/*
25775084Sjohnlev 	 * Setting mi_vnic_tx to NULL here under the lock guarantees
25785084Sjohnlev 	 * that no new references to the current VNIC transmit structure
25795084Sjohnlev 	 * will be taken by mac_vnic_tx(). This is a necessary condition
25805084Sjohnlev 	 * for safely waiting for the reference count to drop to
25815084Sjohnlev 	 * zero below.
25825084Sjohnlev 	 */
25835084Sjohnlev 	vnic_tx = mip->mi_vnic_tx;
25845084Sjohnlev 	mip->mi_vnic_tx = NULL;
25855084Sjohnlev 	mip->mi_vnic_getcapab_fn = NULL;
25865084Sjohnlev 	mip->mi_vnic_getcapab_arg = NULL;
25875084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
25885084Sjohnlev 
25895084Sjohnlev 	i_mac_notify(mip, MAC_NOTE_VNIC);
25905084Sjohnlev 
25915084Sjohnlev 	/*
25925084Sjohnlev 	 * Wait for all TX calls referencing the VNIC transmit
25935084Sjohnlev 	 * entry point that was removed to complete.
25945084Sjohnlev 	 */
25955084Sjohnlev 	mutex_enter(&vnic_tx->mv_lock);
25965084Sjohnlev 	vnic_tx->mv_clearing = B_TRUE;
25975084Sjohnlev 	while (vnic_tx->mv_refs > 0)
25985084Sjohnlev 		cv_wait(&vnic_tx->mv_cv, &vnic_tx->mv_lock);
25995084Sjohnlev 	mutex_exit(&vnic_tx->mv_lock);
26005084Sjohnlev 	kmem_cache_free(mac_vnic_tx_cache, vnic_tx);
26015084Sjohnlev }
26025084Sjohnlev 
2603269Sericheng /*
2604269Sericheng  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
2605269Sericheng  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
2606269Sericheng  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
2607269Sericheng  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
2608269Sericheng  * cannot disappear while we are accessing it.
2609269Sericheng  */
2610269Sericheng typedef struct i_mac_info_state_s {
2611269Sericheng 	const char	*mi_name;
2612269Sericheng 	mac_info_t	*mi_infop;
2613269Sericheng } i_mac_info_state_t;
2614269Sericheng 
2615269Sericheng /*ARGSUSED*/
2616269Sericheng static uint_t
2617269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
2618269Sericheng {
2619269Sericheng 	i_mac_info_state_t	*statep = arg;
2620269Sericheng 	mac_impl_t		*mip = (mac_impl_t *)val;
2621269Sericheng 
26221852Syz147064 	if (mip->mi_disabled)
2623269Sericheng 		return (MH_WALK_CONTINUE);
2624269Sericheng 
2625269Sericheng 	if (strcmp(statep->mi_name,
26262311Sseb 	    ddi_driver_name(mip->mi_dip)) != 0)
2627269Sericheng 		return (MH_WALK_CONTINUE);
2628269Sericheng 
26292311Sseb 	statep->mi_infop = &mip->mi_info;
2630269Sericheng 	return (MH_WALK_TERMINATE);
2631269Sericheng }
2632269Sericheng 
2633269Sericheng boolean_t
2634269Sericheng mac_info_get(const char *name, mac_info_t *minfop)
2635269Sericheng {
2636269Sericheng 	i_mac_info_state_t	state;
2637269Sericheng 
2638269Sericheng 	rw_enter(&i_mac_impl_lock, RW_READER);
2639269Sericheng 	state.mi_name = name;
2640269Sericheng 	state.mi_infop = NULL;
2641269Sericheng 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
2642269Sericheng 	if (state.mi_infop == NULL) {
2643269Sericheng 		rw_exit(&i_mac_impl_lock);
2644269Sericheng 		return (B_FALSE);
2645269Sericheng 	}
2646269Sericheng 	*minfop = *state.mi_infop;
2647269Sericheng 	rw_exit(&i_mac_impl_lock);
2648269Sericheng 	return (B_TRUE);
2649269Sericheng }
2650269Sericheng 
26512311Sseb boolean_t
26525084Sjohnlev mac_do_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data,
26535084Sjohnlev     boolean_t is_vnic)
26542311Sseb {
26552311Sseb 	mac_impl_t *mip = (mac_impl_t *)mh;
26562311Sseb 
26575084Sjohnlev 	if (!is_vnic) {
26585084Sjohnlev 		rw_enter(&mip->mi_tx_lock, RW_READER);
26595084Sjohnlev 		if (mip->mi_vnic_present) {
26605084Sjohnlev 			boolean_t rv;
26615084Sjohnlev 
26625084Sjohnlev 			rv = mip->mi_vnic_getcapab_fn(mip->mi_vnic_getcapab_arg,
26635084Sjohnlev 			    cap, cap_data);
26645084Sjohnlev 			rw_exit(&mip->mi_tx_lock);
26655084Sjohnlev 			return (rv);
26665084Sjohnlev 		}
26675084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
26685084Sjohnlev 	}
26695084Sjohnlev 
26702311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
26712311Sseb 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
26722311Sseb 	else
26732311Sseb 		return (B_FALSE);
26742311Sseb }
26752311Sseb 
26762311Sseb boolean_t
26775084Sjohnlev mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
26785084Sjohnlev {
26795084Sjohnlev 	return (mac_do_capab_get(mh, cap, cap_data, B_FALSE));
26805084Sjohnlev }
26815084Sjohnlev 
26825084Sjohnlev boolean_t
26835084Sjohnlev mac_vnic_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
26845084Sjohnlev {
26855084Sjohnlev 	return (mac_do_capab_get(mh, cap, cap_data, B_TRUE));
26865084Sjohnlev }
26875084Sjohnlev 
26885084Sjohnlev boolean_t
26892311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
26902311Sseb {
26912311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
26922311Sseb 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
26932311Sseb 	    mip->mi_pdata));
26942311Sseb }
26952311Sseb 
26962311Sseb mblk_t *
26972311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
26982311Sseb     size_t extra_len)
26992311Sseb {
27002311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
27012311Sseb 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
27022311Sseb 	    mip->mi_pdata, payload, extra_len));
27032311Sseb }
27042311Sseb 
27052311Sseb int
27062311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
27072311Sseb {
27082311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
27092311Sseb 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
27102311Sseb 	    mhip));
27112311Sseb }
27122311Sseb 
27132311Sseb mblk_t *
27142311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp)
27152311Sseb {
27162311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
27172311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
27182311Sseb 		if (DB_REF(mp) > 1) {
27192311Sseb 			mblk_t *newmp = copymsg(mp);
27202760Sdg199075 			if (newmp == NULL)
27212760Sdg199075 				return (NULL);
27222311Sseb 			freemsg(mp);
27232311Sseb 			mp = newmp;
27242311Sseb 		}
27252311Sseb 		return (mip->mi_type->mt_ops.mtops_header_cook(mp,
27262311Sseb 		    mip->mi_pdata));
27272311Sseb 	}
27282311Sseb 	return (mp);
27292311Sseb }
27302311Sseb 
27312311Sseb mblk_t *
27322311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp)
27332311Sseb {
27342311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
27352311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
27362311Sseb 		if (DB_REF(mp) > 1) {
27372311Sseb 			mblk_t *newmp = copymsg(mp);
27382760Sdg199075 			if (newmp == NULL)
27392760Sdg199075 				return (NULL);
27402311Sseb 			freemsg(mp);
27412311Sseb 			mp = newmp;
27422311Sseb 		}
27432311Sseb 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
27442311Sseb 		    mip->mi_pdata));
27452311Sseb 	}
27462311Sseb 	return (mp);
27472311Sseb }
27482311Sseb 
2749269Sericheng void
2750269Sericheng mac_init_ops(struct dev_ops *ops, const char *name)
2751269Sericheng {
2752269Sericheng 	dld_init_ops(ops, name);
2753269Sericheng }
2754269Sericheng 
2755269Sericheng void
2756269Sericheng mac_fini_ops(struct dev_ops *ops)
2757269Sericheng {
2758269Sericheng 	dld_fini_ops(ops);
2759269Sericheng }
27602311Sseb 
27612311Sseb /*
27622311Sseb  * MAC Type Plugin functions.
27632311Sseb  */
27642311Sseb 
27652311Sseb mactype_register_t *
27662311Sseb mactype_alloc(uint_t mactype_version)
27672311Sseb {
27682311Sseb 	mactype_register_t *mtrp;
27692311Sseb 
27702311Sseb 	/*
27712311Sseb 	 * Make sure there isn't a version mismatch between the plugin and
27722311Sseb 	 * the framework.  In the future, if multiple versions are
27732311Sseb 	 * supported, this check could become more sophisticated.
27742311Sseb 	 */
27752311Sseb 	if (mactype_version != MACTYPE_VERSION)
27762311Sseb 		return (NULL);
27772311Sseb 
27782311Sseb 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
27792311Sseb 	mtrp->mtr_version = mactype_version;
27802311Sseb 	return (mtrp);
27812311Sseb }
27822311Sseb 
27832311Sseb void
27842311Sseb mactype_free(mactype_register_t *mtrp)
27852311Sseb {
27862311Sseb 	kmem_free(mtrp, sizeof (mactype_register_t));
27872311Sseb }
27882311Sseb 
27892311Sseb int
27902311Sseb mactype_register(mactype_register_t *mtrp)
27912311Sseb {
27922311Sseb 	mactype_t	*mtp;
27932311Sseb 	mactype_ops_t	*ops = mtrp->mtr_ops;
27942311Sseb 
27952311Sseb 	/* Do some sanity checking before we register this MAC type. */
27966353Sdr146992 	if (mtrp->mtr_ident == NULL || ops == NULL)
27972311Sseb 		return (EINVAL);
27982311Sseb 
27992311Sseb 	/*
28002311Sseb 	 * Verify that all mandatory callbacks are set in the ops
28012311Sseb 	 * vector.
28022311Sseb 	 */
28032311Sseb 	if (ops->mtops_unicst_verify == NULL ||
28042311Sseb 	    ops->mtops_multicst_verify == NULL ||
28052311Sseb 	    ops->mtops_sap_verify == NULL ||
28062311Sseb 	    ops->mtops_header == NULL ||
28072311Sseb 	    ops->mtops_header_info == NULL) {
28082311Sseb 		return (EINVAL);
28092311Sseb 	}
28102311Sseb 
28112311Sseb 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
28122311Sseb 	mtp->mt_ident = mtrp->mtr_ident;
28132311Sseb 	mtp->mt_ops = *ops;
28142311Sseb 	mtp->mt_type = mtrp->mtr_mactype;
28153147Sxc151355 	mtp->mt_nativetype = mtrp->mtr_nativetype;
28162311Sseb 	mtp->mt_addr_length = mtrp->mtr_addrlen;
28172311Sseb 	if (mtrp->mtr_brdcst_addr != NULL) {
28182311Sseb 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
28192311Sseb 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
28202311Sseb 		    mtrp->mtr_addrlen);
28212311Sseb 	}
28222311Sseb 
28232311Sseb 	mtp->mt_stats = mtrp->mtr_stats;
28242311Sseb 	mtp->mt_statcount = mtrp->mtr_statcount;
28252311Sseb 
28266512Ssowmini 	mtp->mt_mapping = mtrp->mtr_mapping;
28276512Ssowmini 	mtp->mt_mappingcount = mtrp->mtr_mappingcount;
28286512Ssowmini 
28292311Sseb 	if (mod_hash_insert(i_mactype_hash,
28302311Sseb 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
28312311Sseb 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
28322311Sseb 		kmem_free(mtp, sizeof (*mtp));
28332311Sseb 		return (EEXIST);
28342311Sseb 	}
28352311Sseb 	return (0);
28362311Sseb }
28372311Sseb 
28382311Sseb int
28392311Sseb mactype_unregister(const char *ident)
28402311Sseb {
28412311Sseb 	mactype_t	*mtp;
28422311Sseb 	mod_hash_val_t	val;
28432311Sseb 	int 		err;
28442311Sseb 
28452311Sseb 	/*
28462311Sseb 	 * Let's not allow MAC drivers to use this plugin while we're
28473288Sseb 	 * trying to unregister it.  Holding i_mactype_lock also prevents a
28483288Sseb 	 * plugin from unregistering while a MAC driver is attempting to
28493288Sseb 	 * hold a reference to it in i_mactype_getplugin().
28502311Sseb 	 */
28513288Sseb 	mutex_enter(&i_mactype_lock);
28522311Sseb 
28532311Sseb 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
28542311Sseb 	    (mod_hash_val_t *)&mtp)) != 0) {
28552311Sseb 		/* A plugin is trying to unregister, but it never registered. */
28563288Sseb 		err = ENXIO;
28573288Sseb 		goto done;
28582311Sseb 	}
28592311Sseb 
28603288Sseb 	if (mtp->mt_ref != 0) {
28613288Sseb 		err = EBUSY;
28623288Sseb 		goto done;
28632311Sseb 	}
28642311Sseb 
28652311Sseb 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
28662311Sseb 	ASSERT(err == 0);
28672311Sseb 	if (err != 0) {
28682311Sseb 		/* This should never happen, thus the ASSERT() above. */
28693288Sseb 		err = EINVAL;
28703288Sseb 		goto done;
28712311Sseb 	}
28722311Sseb 	ASSERT(mtp == (mactype_t *)val);
28732311Sseb 
28742311Sseb 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
28752311Sseb 	kmem_free(mtp, sizeof (mactype_t));
28763288Sseb done:
28773288Sseb 	mutex_exit(&i_mactype_lock);
28783288Sseb 	return (err);
28792311Sseb }
28805903Ssowmini 
28815903Ssowmini int
28825903Ssowmini mac_set_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize)
28835903Ssowmini {
28845903Ssowmini 	int err = ENOTSUP;
28855903Ssowmini 	mac_impl_t *mip = (mac_impl_t *)mh;
28865903Ssowmini 
28875903Ssowmini 	if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) {
28885903Ssowmini 		err = mip->mi_callbacks->mc_setprop(mip->mi_driver,
28895903Ssowmini 		    macprop->mp_name, macprop->mp_id, valsize, val);
28905903Ssowmini 	}
28915903Ssowmini 	return (err);
28925903Ssowmini }
28935903Ssowmini 
28945903Ssowmini int
28955903Ssowmini mac_get_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize)
28965903Ssowmini {
28975903Ssowmini 	int err = ENOTSUP;
28985903Ssowmini 	mac_impl_t *mip = (mac_impl_t *)mh;
28996512Ssowmini 	uint32_t sdu;
29006512Ssowmini 	link_state_t link_state;
29016512Ssowmini 
29026512Ssowmini 	switch (macprop->mp_id) {
29036789Sam223141 	case MAC_PROP_MTU:
29046512Ssowmini 		if (valsize < sizeof (sdu))
29056512Ssowmini 			return (EINVAL);
29066789Sam223141 		if ((macprop->mp_flags & MAC_PROP_DEFAULT) == 0) {
29076512Ssowmini 			mac_sdu_get(mh, NULL, &sdu);
29086512Ssowmini 			bcopy(&sdu, val, sizeof (sdu));
29096512Ssowmini 			return (0);
29106512Ssowmini 		} else {
29116512Ssowmini 			if (mip->mi_info.mi_media == DL_ETHER) {
29126512Ssowmini 				sdu = ETHERMTU;
29136512Ssowmini 				bcopy(&sdu, val, sizeof (sdu));
29146512Ssowmini 				return (0);
29156512Ssowmini 			}
29166512Ssowmini 			/*
29176512Ssowmini 			 * ask driver for its default.
29186512Ssowmini 			 */
29196512Ssowmini 			break;
29206512Ssowmini 		}
29216789Sam223141 	case MAC_PROP_STATUS:
29226512Ssowmini 		if (valsize < sizeof (link_state))
29236512Ssowmini 			return (EINVAL);
29246512Ssowmini 		link_state = mac_link_get(mh);
29256512Ssowmini 		bcopy(&link_state, val, sizeof (link_state));
29266512Ssowmini 		return (0);
29276512Ssowmini 	default:
29286512Ssowmini 		break;
29296512Ssowmini 	}
29305903Ssowmini 	if (mip->mi_callbacks->mc_callbacks & MC_GETPROP) {
29315903Ssowmini 		err = mip->mi_callbacks->mc_getprop(mip->mi_driver,
29326512Ssowmini 		    macprop->mp_name, macprop->mp_id, macprop->mp_flags,
29336512Ssowmini 		    valsize, val);
29345903Ssowmini 	}
29355903Ssowmini 	return (err);
29365903Ssowmini }
29375903Ssowmini 
29385903Ssowmini int
29395903Ssowmini mac_maxsdu_update(mac_handle_t mh, uint_t sdu_max)
29405903Ssowmini {
29415903Ssowmini 	mac_impl_t	*mip = (mac_impl_t *)mh;
29425903Ssowmini 
29435903Ssowmini 	if (sdu_max <= mip->mi_sdu_min)
29445903Ssowmini 		return (EINVAL);
29455903Ssowmini 	mip->mi_sdu_max = sdu_max;
29465903Ssowmini 
29475903Ssowmini 	/* Send a MAC_NOTE_SDU_SIZE notification. */
29485903Ssowmini 	i_mac_notify(mip, MAC_NOTE_SDU_SIZE);
29495903Ssowmini 	return (0);
29505903Ssowmini }
29516512Ssowmini 
29526512Ssowmini static void
29536512Ssowmini mac_register_priv_prop(mac_impl_t *mip, mac_priv_prop_t *mpp, uint_t nprop)
29546512Ssowmini {
29556512Ssowmini 	mac_priv_prop_t *mpriv;
29566512Ssowmini 
29576512Ssowmini 	if (mpp == NULL)
29586512Ssowmini 		return;
29596512Ssowmini 
29606512Ssowmini 	mpriv = kmem_zalloc(nprop * sizeof (*mpriv), KM_SLEEP);
29616512Ssowmini 	(void) memcpy(mpriv, mpp, nprop * sizeof (*mpriv));
29626512Ssowmini 	mip->mi_priv_prop = mpriv;
29636512Ssowmini 	mip->mi_priv_prop_count = nprop;
29646512Ssowmini }
2965*7406SSowmini.Varadhan@Sun.COM 
2966*7406SSowmini.Varadhan@Sun.COM static void
2967*7406SSowmini.Varadhan@Sun.COM mac_unregister_priv_prop(mac_impl_t *mip)
2968*7406SSowmini.Varadhan@Sun.COM {
2969*7406SSowmini.Varadhan@Sun.COM 	mac_priv_prop_t	*mpriv;
2970*7406SSowmini.Varadhan@Sun.COM 
2971*7406SSowmini.Varadhan@Sun.COM 	mpriv = mip->mi_priv_prop;
2972*7406SSowmini.Varadhan@Sun.COM 	if (mpriv != NULL) {
2973*7406SSowmini.Varadhan@Sun.COM 		kmem_free(mpriv, mip->mi_priv_prop_count * sizeof (*mpriv));
2974*7406SSowmini.Varadhan@Sun.COM 		mip->mi_priv_prop = NULL;
2975*7406SSowmini.Varadhan@Sun.COM 	}
2976*7406SSowmini.Varadhan@Sun.COM 	mip->mi_priv_prop_count = 0;
2977*7406SSowmini.Varadhan@Sun.COM }
2978