xref: /onnv-gate/usr/src/uts/common/io/mac/mac.c (revision 6512:707ffe0297ab)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51852Syz147064  * Common Development and Distribution License (the "License").
61852Syz147064  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
215084Sjohnlev 
220Sstevel@tonic-gate /*
235895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * MAC Services Module
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/conf.h>
355895Syz147064 #include <sys/id_space.h>
366077Syz147064 #include <sys/esunddi.h>
370Sstevel@tonic-gate #include <sys/stat.h>
385895Syz147064 #include <sys/mkdev.h>
390Sstevel@tonic-gate #include <sys/stream.h>
400Sstevel@tonic-gate #include <sys/strsun.h>
410Sstevel@tonic-gate #include <sys/strsubr.h>
420Sstevel@tonic-gate #include <sys/dlpi.h>
435895Syz147064 #include <sys/dls.h>
44269Sericheng #include <sys/modhash.h>
455895Syz147064 #include <sys/vlan.h>
460Sstevel@tonic-gate #include <sys/mac.h>
470Sstevel@tonic-gate #include <sys/mac_impl.h>
48269Sericheng #include <sys/dld.h>
492311Sseb #include <sys/modctl.h>
503448Sdh155122 #include <sys/fs/dv_node.h>
515009Sgd78059 #include <sys/thread.h>
525009Sgd78059 #include <sys/proc.h>
535009Sgd78059 #include <sys/callb.h>
545009Sgd78059 #include <sys/cpuvar.h>
553288Sseb #include <sys/atomic.h>
564913Sethindra #include <sys/sdt.h>
575903Ssowmini #include <inet/nd.h>
58*6512Ssowmini #include <sys/ethernet.h>
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #define	IMPL_HASHSZ	67	/* prime */
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static kmem_cache_t	*i_mac_impl_cachep;
63269Sericheng static mod_hash_t	*i_mac_impl_hash;
64269Sericheng krwlock_t		i_mac_impl_lock;
65269Sericheng uint_t			i_mac_impl_count;
665084Sjohnlev static kmem_cache_t	*mac_vnic_tx_cache;
675895Syz147064 static id_space_t	*minor_ids;
685895Syz147064 static uint32_t		minor_count;
690Sstevel@tonic-gate 
702311Sseb #define	MACTYPE_KMODDIR	"mac"
712311Sseb #define	MACTYPE_HASHSZ	67
722311Sseb static mod_hash_t	*i_mactype_hash;
733288Sseb /*
743288Sseb  * i_mactype_lock synchronizes threads that obtain references to mactype_t
753288Sseb  * structures through i_mactype_getplugin().
763288Sseb  */
773288Sseb static kmutex_t		i_mactype_lock;
782311Sseb 
795009Sgd78059 static void i_mac_notify_thread(void *);
805084Sjohnlev static mblk_t *mac_vnic_tx(void *, mblk_t *);
815084Sjohnlev static mblk_t *mac_vnic_txloop(void *, mblk_t *);
82*6512Ssowmini static void   mac_register_priv_prop(mac_impl_t *, mac_priv_prop_t *, uint_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 
5665895Syz147064 	err = mac_open(dls_devnet_mac(dlh), mhp);
5675895Syz147064 
5685895Syz147064 done:
5695895Syz147064 	dls_devnet_rele_tmp(dlh);
5700Sstevel@tonic-gate 	return (err);
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate 
5735895Syz147064 int
5745895Syz147064 mac_open_by_linkname(const char *link, mac_handle_t *mhp)
5755895Syz147064 {
5765895Syz147064 	datalink_id_t	linkid;
5775895Syz147064 	int		err;
5785895Syz147064 
5795895Syz147064 	if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0)
5805895Syz147064 		return (err);
5815895Syz147064 	return (mac_open_by_linkid(linkid, mhp));
5825895Syz147064 }
5835895Syz147064 
5840Sstevel@tonic-gate void
5850Sstevel@tonic-gate mac_close(mac_handle_t mh)
5860Sstevel@tonic-gate {
5870Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
5885895Syz147064 
5895895Syz147064 	rw_enter(&mip->mi_gen_lock, RW_WRITER);
5905895Syz147064 
5915895Syz147064 	ASSERT(mip->mi_oref != 0);
5925895Syz147064 	if (--mip->mi_oref == 0) {
5935895Syz147064 		if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE))
5945895Syz147064 			mip->mi_close(mip->mi_driver);
5950Sstevel@tonic-gate 	}
5965895Syz147064 	rw_exit(&mip->mi_gen_lock);
5975895Syz147064 
5986077Syz147064 	ddi_release_devi(mip->mi_dip);
5995895Syz147064 	mac_rele(mip);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate const mac_info_t *
6030Sstevel@tonic-gate mac_info(mac_handle_t mh)
6040Sstevel@tonic-gate {
6052311Sseb 	return (&((mac_impl_t *)mh)->mi_info);
6060Sstevel@tonic-gate }
6070Sstevel@tonic-gate 
608269Sericheng dev_info_t *
609269Sericheng mac_devinfo_get(mac_handle_t mh)
610269Sericheng {
6112311Sseb 	return (((mac_impl_t *)mh)->mi_dip);
612269Sericheng }
613269Sericheng 
6145895Syz147064 const char *
6155895Syz147064 mac_name(mac_handle_t mh)
6165895Syz147064 {
6175895Syz147064 	return (((mac_impl_t *)mh)->mi_name);
6185895Syz147064 }
6195895Syz147064 
6205895Syz147064 minor_t
6215895Syz147064 mac_minor(mac_handle_t mh)
6225895Syz147064 {
6235895Syz147064 	return (((mac_impl_t *)mh)->mi_minor);
6245895Syz147064 }
6255895Syz147064 
6260Sstevel@tonic-gate uint64_t
6272311Sseb mac_stat_get(mac_handle_t mh, uint_t stat)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6302311Sseb 	uint64_t	val;
6312311Sseb 	int		ret;
6320Sstevel@tonic-gate 
6332311Sseb 	/*
6342311Sseb 	 * The range of stat determines where it is maintained.  Stat
6352311Sseb 	 * values from 0 up to (but not including) MAC_STAT_MIN are
6362311Sseb 	 * mainteined by the mac module itself.  Everything else is
6372311Sseb 	 * maintained by the driver.
6382311Sseb 	 */
6392311Sseb 	if (stat < MAC_STAT_MIN) {
6402311Sseb 		/* These stats are maintained by the mac module itself. */
6412311Sseb 		switch (stat) {
6422311Sseb 		case MAC_STAT_LINK_STATE:
6432311Sseb 			return (mip->mi_linkstate);
6442311Sseb 		case MAC_STAT_LINK_UP:
6452311Sseb 			return (mip->mi_linkstate == LINK_STATE_UP);
6462311Sseb 		case MAC_STAT_PROMISC:
6472311Sseb 			return (mip->mi_devpromisc != 0);
6482311Sseb 		default:
6492311Sseb 			ASSERT(B_FALSE);
6502311Sseb 		}
6512311Sseb 	}
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	/*
6540Sstevel@tonic-gate 	 * Call the driver to get the given statistic.
6550Sstevel@tonic-gate 	 */
6562311Sseb 	ret = mip->mi_getstat(mip->mi_driver, stat, &val);
6572311Sseb 	if (ret != 0) {
6582311Sseb 		/*
6592311Sseb 		 * The driver doesn't support this statistic.  Get the
6602311Sseb 		 * statistic's default value.
6612311Sseb 		 */
6622311Sseb 		val = mac_stat_default(mip, stat);
6632311Sseb 	}
6642311Sseb 	return (val);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate int
6680Sstevel@tonic-gate mac_start(mac_handle_t mh)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6710Sstevel@tonic-gate 	int		err;
6720Sstevel@tonic-gate 
6732311Sseb 	ASSERT(mip->mi_start != NULL);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	/*
6780Sstevel@tonic-gate 	 * Check whether the device is already started.
6790Sstevel@tonic-gate 	 */
6800Sstevel@tonic-gate 	if (mip->mi_active++ != 0) {
6810Sstevel@tonic-gate 		/*
6820Sstevel@tonic-gate 		 * It's already started so there's nothing more to do.
6830Sstevel@tonic-gate 		 */
6840Sstevel@tonic-gate 		err = 0;
6850Sstevel@tonic-gate 		goto done;
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/*
6890Sstevel@tonic-gate 	 * Start the device.
6900Sstevel@tonic-gate 	 */
6912311Sseb 	if ((err = mip->mi_start(mip->mi_driver)) != 0)
6920Sstevel@tonic-gate 		--mip->mi_active;
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate done:
6950Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
6960Sstevel@tonic-gate 	return (err);
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate void
7000Sstevel@tonic-gate mac_stop(mac_handle_t mh)
7010Sstevel@tonic-gate {
7020Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7030Sstevel@tonic-gate 
7042311Sseb 	ASSERT(mip->mi_stop != NULL);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	/*
7090Sstevel@tonic-gate 	 * Check whether the device is still needed.
7100Sstevel@tonic-gate 	 */
7110Sstevel@tonic-gate 	ASSERT(mip->mi_active != 0);
7120Sstevel@tonic-gate 	if (--mip->mi_active != 0) {
7130Sstevel@tonic-gate 		/*
7140Sstevel@tonic-gate 		 * It's still needed so there's nothing more to do.
7150Sstevel@tonic-gate 		 */
7160Sstevel@tonic-gate 		goto done;
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	/*
7200Sstevel@tonic-gate 	 * Stop the device.
7210Sstevel@tonic-gate 	 */
7222311Sseb 	mip->mi_stop(mip->mi_driver);
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate done:
7250Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
7260Sstevel@tonic-gate }
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate int
7290Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
7300Sstevel@tonic-gate {
7310Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
7320Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
7330Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
7340Sstevel@tonic-gate 	int			err;
7350Sstevel@tonic-gate 
7362311Sseb 	ASSERT(mip->mi_multicst != NULL);
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	/*
7390Sstevel@tonic-gate 	 * Verify the address.
7400Sstevel@tonic-gate 	 */
7412311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
7422311Sseb 	    mip->mi_pdata)) != 0) {
7432311Sseb 		return (err);
7442311Sseb 	}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	/*
7470Sstevel@tonic-gate 	 * Check whether the given address is already enabled.
7480Sstevel@tonic-gate 	 */
7490Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
7500Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
7512311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
7522311Sseb 		    0) {
7530Sstevel@tonic-gate 			/*
7540Sstevel@tonic-gate 			 * The address is already enabled so just bump the
7550Sstevel@tonic-gate 			 * reference count.
7560Sstevel@tonic-gate 			 */
7570Sstevel@tonic-gate 			p->mma_ref++;
7580Sstevel@tonic-gate 			err = 0;
7590Sstevel@tonic-gate 			goto done;
7600Sstevel@tonic-gate 		}
7610Sstevel@tonic-gate 	}
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	/*
7640Sstevel@tonic-gate 	 * Allocate a new list entry.
7650Sstevel@tonic-gate 	 */
7660Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
7670Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
7680Sstevel@tonic-gate 		err = ENOMEM;
7690Sstevel@tonic-gate 		goto done;
7700Sstevel@tonic-gate 	}
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	/*
7730Sstevel@tonic-gate 	 * Enable a new multicast address.
7740Sstevel@tonic-gate 	 */
7752311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) {
7760Sstevel@tonic-gate 		kmem_free(p, sizeof (mac_multicst_addr_t));
7770Sstevel@tonic-gate 		goto done;
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	/*
7810Sstevel@tonic-gate 	 * Add the address to the list of enabled addresses.
7820Sstevel@tonic-gate 	 */
7832311Sseb 	bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length);
7840Sstevel@tonic-gate 	p->mma_ref++;
7850Sstevel@tonic-gate 	*pp = p;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate done:
7880Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7890Sstevel@tonic-gate 	return (err);
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate int
7930Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
7940Sstevel@tonic-gate {
7950Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
7960Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
7970Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
7980Sstevel@tonic-gate 	int			err;
7990Sstevel@tonic-gate 
8002311Sseb 	ASSERT(mip->mi_multicst != NULL);
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	/*
8030Sstevel@tonic-gate 	 * Find the entry in the list for the given address.
8040Sstevel@tonic-gate 	 */
8050Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
8060Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
8072311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
8082311Sseb 		    0) {
8090Sstevel@tonic-gate 			if (--p->mma_ref == 0)
8100Sstevel@tonic-gate 				break;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 			/*
8130Sstevel@tonic-gate 			 * There is still a reference to this address so
8140Sstevel@tonic-gate 			 * there's nothing more to do.
8150Sstevel@tonic-gate 			 */
8160Sstevel@tonic-gate 			err = 0;
8170Sstevel@tonic-gate 			goto done;
8180Sstevel@tonic-gate 		}
8190Sstevel@tonic-gate 	}
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	/*
8220Sstevel@tonic-gate 	 * We did not find an entry for the given address so it is not
8230Sstevel@tonic-gate 	 * currently enabled.
8240Sstevel@tonic-gate 	 */
8250Sstevel@tonic-gate 	if (p == NULL) {
8260Sstevel@tonic-gate 		err = ENOENT;
8270Sstevel@tonic-gate 		goto done;
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 	ASSERT(p->mma_ref == 0);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	/*
8320Sstevel@tonic-gate 	 * Disable the multicast address.
8330Sstevel@tonic-gate 	 */
8342311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) {
8350Sstevel@tonic-gate 		p->mma_ref++;
8360Sstevel@tonic-gate 		goto done;
8370Sstevel@tonic-gate 	}
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	/*
8400Sstevel@tonic-gate 	 * Remove it from the list.
8410Sstevel@tonic-gate 	 */
8420Sstevel@tonic-gate 	*pp = p->mma_nextp;
8430Sstevel@tonic-gate 	kmem_free(p, sizeof (mac_multicst_addr_t));
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate done:
8460Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
8470Sstevel@tonic-gate 	return (err);
8480Sstevel@tonic-gate }
8490Sstevel@tonic-gate 
8502331Skrgopi /*
8512331Skrgopi  * mac_unicst_verify: Verifies the passed address. It fails
8522331Skrgopi  * if the passed address is a group address or has incorrect length.
8532331Skrgopi  */
8542331Skrgopi boolean_t
8552331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
8562331Skrgopi {
8572331Skrgopi 	mac_impl_t	*mip = (mac_impl_t *)mh;
8582331Skrgopi 
8592331Skrgopi 	/*
8602331Skrgopi 	 * Verify the address.
8612331Skrgopi 	 */
8622331Skrgopi 	if ((len != mip->mi_type->mt_addr_length) ||
8632331Skrgopi 	    (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
8642331Skrgopi 	    mip->mi_pdata)) != 0) {
8652331Skrgopi 		return (B_FALSE);
8662331Skrgopi 	} else {
8672331Skrgopi 		return (B_TRUE);
8682331Skrgopi 	}
8692331Skrgopi }
8702331Skrgopi 
8710Sstevel@tonic-gate int
8720Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
8730Sstevel@tonic-gate {
8740Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8750Sstevel@tonic-gate 	int		err;
8760Sstevel@tonic-gate 	boolean_t	notify = B_FALSE;
8770Sstevel@tonic-gate 
8782311Sseb 	ASSERT(mip->mi_unicst != NULL);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	/*
8810Sstevel@tonic-gate 	 * Verify the address.
8820Sstevel@tonic-gate 	 */
8832311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr,
8842311Sseb 	    mip->mi_pdata)) != 0) {
8852311Sseb 		return (err);
8862311Sseb 	}
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	/*
8890Sstevel@tonic-gate 	 * Program the new unicast address.
8900Sstevel@tonic-gate 	 */
8910Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	/*
8940Sstevel@tonic-gate 	 * If address doesn't change, do nothing.
8950Sstevel@tonic-gate 	 * This check is necessary otherwise it may call into mac_unicst_set
8960Sstevel@tonic-gate 	 * recursively.
8970Sstevel@tonic-gate 	 */
8985895Syz147064 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0)
8990Sstevel@tonic-gate 		goto done;
9000Sstevel@tonic-gate 
9012311Sseb 	if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0)
9020Sstevel@tonic-gate 		goto done;
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	/*
9050Sstevel@tonic-gate 	 * Save the address and flag that we need to send a notification.
9060Sstevel@tonic-gate 	 */
9072311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
9080Sstevel@tonic-gate 	notify = B_TRUE;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate done:
9110Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	if (notify)
9140Sstevel@tonic-gate 		i_mac_notify(mip, MAC_NOTE_UNICST);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	return (err);
9170Sstevel@tonic-gate }
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate void
9200Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr)
9210Sstevel@tonic-gate {
9220Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	/*
9252311Sseb 	 * Copy out the current unicast source address.
9260Sstevel@tonic-gate 	 */
9270Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
9282311Sseb 	bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
9292311Sseb 	rw_exit(&(mip->mi_data_lock));
9302311Sseb }
9312311Sseb 
9322311Sseb void
9332311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr)
9342311Sseb {
9352311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
9362311Sseb 
9372311Sseb 	/*
9382311Sseb 	 * Copy out the current destination address.
9392311Sseb 	 */
9402311Sseb 	rw_enter(&(mip->mi_data_lock), RW_READER);
9412311Sseb 	bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
9420Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate int
9460Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
9470Sstevel@tonic-gate {
9480Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9490Sstevel@tonic-gate 	int		err = 0;
9500Sstevel@tonic-gate 
9512311Sseb 	ASSERT(mip->mi_setpromisc != NULL);
9520Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	/*
9550Sstevel@tonic-gate 	 * Determine whether we should enable or disable promiscuous mode.
9560Sstevel@tonic-gate 	 * For details on the distinction between "device promiscuous mode"
9570Sstevel@tonic-gate 	 * and "MAC promiscuous mode", see PSARC/2005/289.
9580Sstevel@tonic-gate 	 */
9590Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
9600Sstevel@tonic-gate 	if (on) {
9610Sstevel@tonic-gate 		/*
9620Sstevel@tonic-gate 		 * Enable promiscuous mode on the device if not yet enabled.
9630Sstevel@tonic-gate 		 */
9640Sstevel@tonic-gate 		if (mip->mi_devpromisc++ == 0) {
9652311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
9662311Sseb 			if (err != 0) {
9670Sstevel@tonic-gate 				mip->mi_devpromisc--;
9680Sstevel@tonic-gate 				goto done;
9690Sstevel@tonic-gate 			}
9700Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
9710Sstevel@tonic-gate 		}
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 		/*
9740Sstevel@tonic-gate 		 * Enable promiscuous mode on the MAC if not yet enabled.
9750Sstevel@tonic-gate 		 */
9760Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
9770Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
9780Sstevel@tonic-gate 	} else {
9790Sstevel@tonic-gate 		if (mip->mi_devpromisc == 0) {
9800Sstevel@tonic-gate 			err = EPROTO;
9810Sstevel@tonic-gate 			goto done;
9820Sstevel@tonic-gate 		}
9830Sstevel@tonic-gate 		/*
9840Sstevel@tonic-gate 		 * Disable promiscuous mode on the device if this is the last
9850Sstevel@tonic-gate 		 * enabling.
9860Sstevel@tonic-gate 		 */
9870Sstevel@tonic-gate 		if (--mip->mi_devpromisc == 0) {
9882311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
9892311Sseb 			if (err != 0) {
9900Sstevel@tonic-gate 				mip->mi_devpromisc++;
9910Sstevel@tonic-gate 				goto done;
9920Sstevel@tonic-gate 			}
9930Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
9940Sstevel@tonic-gate 		}
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 		/*
9970Sstevel@tonic-gate 		 * Disable promiscuous mode on the MAC if this is the last
9980Sstevel@tonic-gate 		 * enabling.
9990Sstevel@tonic-gate 		 */
10000Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
10010Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
10020Sstevel@tonic-gate 	}
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate done:
10050Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
10060Sstevel@tonic-gate 	return (err);
10070Sstevel@tonic-gate }
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate boolean_t
10100Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
10110Sstevel@tonic-gate {
10120Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	/*
10170Sstevel@tonic-gate 	 * Return the current promiscuity.
10180Sstevel@tonic-gate 	 */
10190Sstevel@tonic-gate 	if (ptype == MAC_DEVPROMISC)
10200Sstevel@tonic-gate 		return (mip->mi_devpromisc != 0);
10210Sstevel@tonic-gate 	else
10220Sstevel@tonic-gate 		return (mip->mi_promisc != 0);
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate void
10265903Ssowmini mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu)
10275903Ssowmini {
10285903Ssowmini 	mac_impl_t	*mip = (mac_impl_t *)mh;
10295903Ssowmini 
10305903Ssowmini 	if (min_sdu != NULL)
10315903Ssowmini 		*min_sdu = mip->mi_sdu_min;
10325903Ssowmini 	if (max_sdu != NULL)
10335903Ssowmini 		*max_sdu = mip->mi_sdu_max;
10345903Ssowmini }
10355903Ssowmini 
10365903Ssowmini void
10370Sstevel@tonic-gate mac_resources(mac_handle_t mh)
10380Sstevel@tonic-gate {
10390Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	/*
10422311Sseb 	 * If the driver supports resource registration, call the driver to
10432311Sseb 	 * ask it to register its resources.
10440Sstevel@tonic-gate 	 */
10452311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES)
10462311Sseb 		mip->mi_resources(mip->mi_driver);
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate void
10500Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
10510Sstevel@tonic-gate {
10520Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
1053*6512Ssowmini 	int cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd;
1054*6512Ssowmini 
1055*6512Ssowmini 	if ((cmd == ND_GET && (mip->mi_callbacks->mc_callbacks & MC_GETPROP)) ||
1056*6512Ssowmini 	    (cmd == ND_SET && (mip->mi_callbacks->mc_callbacks & MC_SETPROP))) {
1057*6512Ssowmini 		/*
1058*6512Ssowmini 		 * If ndd props were registered, call them.
1059*6512Ssowmini 		 * Note that ndd ioctls are Obsolete
1060*6512Ssowmini 		 */
1061*6512Ssowmini 		mac_ndd_ioctl(mip, wq, bp);
1062*6512Ssowmini 		return;
10635903Ssowmini 	}
1064*6512Ssowmini 
10650Sstevel@tonic-gate 	/*
10662311Sseb 	 * Call the driver to handle the ioctl.  The driver may not support
10672311Sseb 	 * any ioctls, in which case we reply with a NAK on its behalf.
10680Sstevel@tonic-gate 	 */
10692311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
10702311Sseb 		mip->mi_ioctl(mip->mi_driver, wq, bp);
10712311Sseb 	else
10722311Sseb 		miocnak(wq, bp, 0, EINVAL);
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate 
107556Smeem const mac_txinfo_t *
10765084Sjohnlev mac_do_tx_get(mac_handle_t mh, boolean_t is_vnic)
10770Sstevel@tonic-gate {
10780Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
107956Smeem 	mac_txinfo_t	*mtp;
108056Smeem 
108156Smeem 	/*
108256Smeem 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
108356Smeem 	 * changed.  This is sufficient since MAC clients are careful to always
108456Smeem 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
108556Smeem 	 * MAC_PROMISC prior to calling mac_txloop_remove().
108656Smeem 	 */
10875084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_READER);
10880Sstevel@tonic-gate 
108956Smeem 	if (mac_promisc_get(mh, MAC_PROMISC)) {
109056Smeem 		ASSERT(mip->mi_mtfp != NULL);
10915084Sjohnlev 		if (mip->mi_vnic_present && !is_vnic) {
10925084Sjohnlev 			mtp = &mip->mi_vnic_txloopinfo;
10935084Sjohnlev 		} else {
10945084Sjohnlev 			mtp = &mip->mi_txloopinfo;
10955084Sjohnlev 		}
109656Smeem 	} else {
10975084Sjohnlev 		if (mip->mi_vnic_present && !is_vnic) {
10985084Sjohnlev 			mtp = &mip->mi_vnic_txinfo;
10995084Sjohnlev 		} else {
11005084Sjohnlev 			/*
11015084Sjohnlev 			 * Note that we cannot ASSERT() that mip->mi_mtfp is
11025084Sjohnlev 			 * NULL, because to satisfy the above ASSERT(), we
11035084Sjohnlev 			 * have to disable MAC_PROMISC prior to calling
11045084Sjohnlev 			 * mac_txloop_remove().
11055084Sjohnlev 			 */
11065084Sjohnlev 			mtp = &mip->mi_txinfo;
11075084Sjohnlev 		}
110856Smeem 	}
110956Smeem 
11105084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
111156Smeem 	return (mtp);
11120Sstevel@tonic-gate }
11130Sstevel@tonic-gate 
11145084Sjohnlev /*
11155084Sjohnlev  * Invoked by VNIC to obtain the transmit entry point.
11165084Sjohnlev  */
11175084Sjohnlev const mac_txinfo_t *
11185084Sjohnlev mac_vnic_tx_get(mac_handle_t mh)
11195084Sjohnlev {
11205084Sjohnlev 	return (mac_do_tx_get(mh, B_TRUE));
11215084Sjohnlev }
11225084Sjohnlev 
11235084Sjohnlev /*
11245084Sjohnlev  * Invoked by any non-VNIC client to obtain the transmit entry point.
11255084Sjohnlev  * If a VNIC is present, the VNIC transmit function provided by the VNIC
11265084Sjohnlev  * will be returned to the MAC client.
11275084Sjohnlev  */
11285084Sjohnlev const mac_txinfo_t *
11295084Sjohnlev mac_tx_get(mac_handle_t mh)
11305084Sjohnlev {
11315084Sjohnlev 	return (mac_do_tx_get(mh, B_FALSE));
11325084Sjohnlev }
11335084Sjohnlev 
11340Sstevel@tonic-gate link_state_t
11350Sstevel@tonic-gate mac_link_get(mac_handle_t mh)
11360Sstevel@tonic-gate {
11372311Sseb 	return (((mac_impl_t *)mh)->mi_linkstate);
11380Sstevel@tonic-gate }
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate mac_notify_handle_t
11410Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
11420Sstevel@tonic-gate {
11430Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11440Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
11470Sstevel@tonic-gate 	mnfp->mnf_fn = notify;
11480Sstevel@tonic-gate 	mnfp->mnf_arg = arg;
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	/*
11510Sstevel@tonic-gate 	 * Add it to the head of the 'notify' callback list.
11520Sstevel@tonic-gate 	 */
11531852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
11540Sstevel@tonic-gate 	mnfp->mnf_nextp = mip->mi_mnfp;
11550Sstevel@tonic-gate 	mip->mi_mnfp = mnfp;
11561852Syz147064 	rw_exit(&mip->mi_notify_lock);
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	return ((mac_notify_handle_t)mnfp);
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate void
11620Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
11630Sstevel@tonic-gate {
11640Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11650Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
11660Sstevel@tonic-gate 	mac_notify_fn_t		**pp;
11670Sstevel@tonic-gate 	mac_notify_fn_t		*p;
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	/*
11700Sstevel@tonic-gate 	 * Search the 'notify' callback list for the function closure.
11710Sstevel@tonic-gate 	 */
11721852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
11730Sstevel@tonic-gate 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
11740Sstevel@tonic-gate 	    pp = &(p->mnf_nextp)) {
11750Sstevel@tonic-gate 		if (p == mnfp)
11760Sstevel@tonic-gate 			break;
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 	ASSERT(p != NULL);
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	/*
11810Sstevel@tonic-gate 	 * Remove it from the list.
11820Sstevel@tonic-gate 	 */
11830Sstevel@tonic-gate 	*pp = p->mnf_nextp;
11841852Syz147064 	rw_exit(&mip->mi_notify_lock);
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	/*
11870Sstevel@tonic-gate 	 * Free it.
11880Sstevel@tonic-gate 	 */
11890Sstevel@tonic-gate 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate void
11930Sstevel@tonic-gate mac_notify(mac_handle_t mh)
11940Sstevel@tonic-gate {
11950Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
11960Sstevel@tonic-gate 	mac_notify_type_t	type;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	for (type = 0; type < MAC_NNOTE; type++)
11990Sstevel@tonic-gate 		i_mac_notify(mip, type);
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12024913Sethindra /*
12034913Sethindra  * Register a receive function for this mac.
12044913Sethindra  * More information on this function's interaction with mac_rx()
12054913Sethindra  * can be found atop mac_rx().
12064913Sethindra  */
12070Sstevel@tonic-gate mac_rx_handle_t
12085084Sjohnlev mac_do_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg, boolean_t is_active)
12090Sstevel@tonic-gate {
12100Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
12110Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
12140Sstevel@tonic-gate 	mrfp->mrf_fn = rx;
12150Sstevel@tonic-gate 	mrfp->mrf_arg = arg;
12165084Sjohnlev 	mrfp->mrf_active = is_active;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	/*
12190Sstevel@tonic-gate 	 * Add it to the head of the 'rx' callback list.
12200Sstevel@tonic-gate 	 */
12210Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
12224913Sethindra 
12234913Sethindra 	/*
12244913Sethindra 	 * mac_rx() will only call callbacks that are marked inuse.
12254913Sethindra 	 */
12264913Sethindra 	mrfp->mrf_inuse = B_TRUE;
12270Sstevel@tonic-gate 	mrfp->mrf_nextp = mip->mi_mrfp;
12284913Sethindra 
12294913Sethindra 	/*
12304913Sethindra 	 * mac_rx() could be traversing the remainder of the list
12314913Sethindra 	 * and miss the new callback we're adding here. This is not a problem
12324913Sethindra 	 * because we do not guarantee the callback to take effect immediately
12334913Sethindra 	 * after mac_rx_add() returns.
12344913Sethindra 	 */
12350Sstevel@tonic-gate 	mip->mi_mrfp = mrfp;
12360Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	return ((mac_rx_handle_t)mrfp);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate 
12415084Sjohnlev mac_rx_handle_t
12425084Sjohnlev mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
12435084Sjohnlev {
12445084Sjohnlev 	return (mac_do_rx_add(mh, rx, arg, B_FALSE));
12455084Sjohnlev }
12465084Sjohnlev 
12475084Sjohnlev mac_rx_handle_t
12485084Sjohnlev mac_active_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
12495084Sjohnlev {
12505084Sjohnlev 	return (mac_do_rx_add(mh, rx, arg, B_TRUE));
12515084Sjohnlev }
12525084Sjohnlev 
12530Sstevel@tonic-gate /*
12544913Sethindra  * Unregister a receive function for this mac.
12554913Sethindra  * This function does not block if wait is B_FALSE. This is useful
12564913Sethindra  * for clients who call mac_rx_remove() from a non-blockable context.
12574913Sethindra  * More information on this function's interaction with mac_rx()
12584913Sethindra  * can be found atop mac_rx().
12590Sstevel@tonic-gate  */
12600Sstevel@tonic-gate void
12614913Sethindra mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh, boolean_t wait)
12620Sstevel@tonic-gate {
12630Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
12640Sstevel@tonic-gate 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
12650Sstevel@tonic-gate 	mac_rx_fn_t		**pp;
12660Sstevel@tonic-gate 	mac_rx_fn_t		*p;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	/*
12690Sstevel@tonic-gate 	 * Search the 'rx' callback list for the function closure.
12700Sstevel@tonic-gate 	 */
12714913Sethindra 	rw_enter(&mip->mi_rx_lock, RW_WRITER);
12720Sstevel@tonic-gate 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
12730Sstevel@tonic-gate 		if (p == mrfp)
12740Sstevel@tonic-gate 			break;
12750Sstevel@tonic-gate 	}
12760Sstevel@tonic-gate 	ASSERT(p != NULL);
12770Sstevel@tonic-gate 
12784913Sethindra 	/*
12794913Sethindra 	 * If mac_rx() is running, mark callback for deletion
12804913Sethindra 	 * and return (if wait is false), or wait until mac_rx()
12814913Sethindra 	 * exits (if wait is true).
12824913Sethindra 	 */
12834913Sethindra 	if (mip->mi_rx_ref > 0) {
12844913Sethindra 		DTRACE_PROBE1(defer_delete, mac_impl_t *, mip);
12854913Sethindra 		p->mrf_inuse = B_FALSE;
12864913Sethindra 		mutex_enter(&mip->mi_lock);
12874913Sethindra 		mip->mi_rx_removed++;
12884913Sethindra 		mutex_exit(&mip->mi_lock);
12894913Sethindra 
12904913Sethindra 		rw_exit(&mip->mi_rx_lock);
12914913Sethindra 		if (wait)
12924913Sethindra 			mac_rx_remove_wait(mh);
12934913Sethindra 		return;
12944913Sethindra 	}
12954913Sethindra 
12960Sstevel@tonic-gate 	/* Remove it from the list. */
12970Sstevel@tonic-gate 	*pp = p->mrf_nextp;
12980Sstevel@tonic-gate 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
12994913Sethindra 	rw_exit(&mip->mi_rx_lock);
13004913Sethindra }
13014913Sethindra 
13024913Sethindra /*
13034913Sethindra  * Wait for all pending callback removals to be completed by mac_rx().
13044913Sethindra  * Note that if we call mac_rx_remove() immediately before this, there is no
13054913Sethindra  * guarantee we would wait *only* on the callback that we specified.
13064913Sethindra  * mac_rx_remove() could have been called by other threads and we would have
13074913Sethindra  * to wait for other marked callbacks to be removed as well.
13084913Sethindra  */
13094913Sethindra void
13104913Sethindra mac_rx_remove_wait(mac_handle_t mh)
13114913Sethindra {
13124913Sethindra 	mac_impl_t	*mip = (mac_impl_t *)mh;
13134913Sethindra 
13144913Sethindra 	mutex_enter(&mip->mi_lock);
13154913Sethindra 	while (mip->mi_rx_removed > 0) {
13164913Sethindra 		DTRACE_PROBE1(need_wait, mac_impl_t *, mip);
13174913Sethindra 		cv_wait(&mip->mi_rx_cv, &mip->mi_lock);
13184913Sethindra 	}
13194913Sethindra 	mutex_exit(&mip->mi_lock);
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate mac_txloop_handle_t
13230Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
13240Sstevel@tonic-gate {
13250Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
13260Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
13290Sstevel@tonic-gate 	mtfp->mtf_fn = tx;
13300Sstevel@tonic-gate 	mtfp->mtf_arg = arg;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	/*
13330Sstevel@tonic-gate 	 * Add it to the head of the 'tx' callback list.
13340Sstevel@tonic-gate 	 */
13355084Sjohnlev 	rw_enter(&(mip->mi_tx_lock), RW_WRITER);
13360Sstevel@tonic-gate 	mtfp->mtf_nextp = mip->mi_mtfp;
13370Sstevel@tonic-gate 	mip->mi_mtfp = mtfp;
13385084Sjohnlev 	rw_exit(&(mip->mi_tx_lock));
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	return ((mac_txloop_handle_t)mtfp);
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate /*
13440Sstevel@tonic-gate  * Unregister a transmit function for this mac.  This removes the function
13450Sstevel@tonic-gate  * from the list of transmit functions for this mac.
13460Sstevel@tonic-gate  */
13470Sstevel@tonic-gate void
13480Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
13490Sstevel@tonic-gate {
13500Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
13510Sstevel@tonic-gate 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
13520Sstevel@tonic-gate 	mac_txloop_fn_t		**pp;
13530Sstevel@tonic-gate 	mac_txloop_fn_t		*p;
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	/*
13560Sstevel@tonic-gate 	 * Search the 'tx' callback list for the function.
13570Sstevel@tonic-gate 	 */
13585084Sjohnlev 	rw_enter(&(mip->mi_tx_lock), RW_WRITER);
13590Sstevel@tonic-gate 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
13600Sstevel@tonic-gate 		if (p == mtfp)
13610Sstevel@tonic-gate 			break;
13620Sstevel@tonic-gate 	}
13630Sstevel@tonic-gate 	ASSERT(p != NULL);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	/* Remove it from the list. */
13660Sstevel@tonic-gate 	*pp = p->mtf_nextp;
13670Sstevel@tonic-gate 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
13685084Sjohnlev 	rw_exit(&(mip->mi_tx_lock));
13690Sstevel@tonic-gate }
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate void
13720Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
13730Sstevel@tonic-gate {
13740Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	/*
13770Sstevel@tonic-gate 	 * Update the 'resource_add' callbacks.
13780Sstevel@tonic-gate 	 */
13790Sstevel@tonic-gate 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
13800Sstevel@tonic-gate 	mip->mi_resource_add = add;
13810Sstevel@tonic-gate 	mip->mi_resource_add_arg = arg;
13820Sstevel@tonic-gate 	rw_exit(&(mip->mi_resource_lock));
13830Sstevel@tonic-gate }
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate /*
13860Sstevel@tonic-gate  * Driver support functions.
13870Sstevel@tonic-gate  */
13880Sstevel@tonic-gate 
13892311Sseb mac_register_t *
13902311Sseb mac_alloc(uint_t mac_version)
13910Sstevel@tonic-gate {
13922311Sseb 	mac_register_t *mregp;
13932311Sseb 
13942311Sseb 	/*
13952311Sseb 	 * Make sure there isn't a version mismatch between the driver and
13962311Sseb 	 * the framework.  In the future, if multiple versions are
13972311Sseb 	 * supported, this check could become more sophisticated.
13982311Sseb 	 */
13992311Sseb 	if (mac_version != MAC_VERSION)
14002311Sseb 		return (NULL);
14012311Sseb 
14022311Sseb 	mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
14032311Sseb 	mregp->m_version = mac_version;
14042311Sseb 	return (mregp);
14052311Sseb }
14062311Sseb 
14072311Sseb void
14082311Sseb mac_free(mac_register_t *mregp)
14092311Sseb {
14102311Sseb 	kmem_free(mregp, sizeof (mac_register_t));
14112311Sseb }
14122311Sseb 
14132311Sseb /*
14145895Syz147064  * Allocate a minor number.
14155895Syz147064  */
14165895Syz147064 minor_t
14175895Syz147064 mac_minor_hold(boolean_t sleep)
14185895Syz147064 {
14195895Syz147064 	minor_t	minor;
14205895Syz147064 
14215895Syz147064 	/*
14225895Syz147064 	 * Grab a value from the arena.
14235895Syz147064 	 */
14245895Syz147064 	atomic_add_32(&minor_count, 1);
14255895Syz147064 
14265895Syz147064 	if (sleep)
14275895Syz147064 		minor = (uint_t)id_alloc(minor_ids);
14285895Syz147064 	else
14295895Syz147064 		minor = (uint_t)id_alloc_nosleep(minor_ids);
14305895Syz147064 
14315895Syz147064 	if (minor == 0) {
14325895Syz147064 		atomic_add_32(&minor_count, -1);
14335895Syz147064 		return (0);
14345895Syz147064 	}
14355895Syz147064 
14365895Syz147064 	return (minor);
14375895Syz147064 }
14385895Syz147064 
14395895Syz147064 /*
14405895Syz147064  * Release a previously allocated minor number.
14415895Syz147064  */
14425895Syz147064 void
14435895Syz147064 mac_minor_rele(minor_t minor)
14445895Syz147064 {
14455895Syz147064 	/*
14465895Syz147064 	 * Return the value to the arena.
14475895Syz147064 	 */
14485895Syz147064 	id_free(minor_ids, minor);
14495895Syz147064 	atomic_add_32(&minor_count, -1);
14505895Syz147064 }
14515895Syz147064 
14525895Syz147064 uint32_t
14535895Syz147064 mac_no_notification(mac_handle_t mh)
14545895Syz147064 {
14555895Syz147064 	mac_impl_t *mip = (mac_impl_t *)mh;
14565895Syz147064 	return (mip->mi_unsup_note);
14575895Syz147064 }
14585895Syz147064 
14595895Syz147064 boolean_t
14605895Syz147064 mac_is_legacy(mac_handle_t mh)
14615895Syz147064 {
14625895Syz147064 	mac_impl_t *mip = (mac_impl_t *)mh;
14635895Syz147064 	return (mip->mi_legacy);
14645895Syz147064 }
14655895Syz147064 
14665895Syz147064 /*
14672311Sseb  * mac_register() is how drivers register new MACs with the GLDv3
14682311Sseb  * framework.  The mregp argument is allocated by drivers using the
14692311Sseb  * mac_alloc() function, and can be freed using mac_free() immediately upon
14702311Sseb  * return from mac_register().  Upon success (0 return value), the mhp
14712311Sseb  * opaque pointer becomes the driver's handle to its MAC interface, and is
14722311Sseb  * the argument to all other mac module entry points.
14732311Sseb  */
14742311Sseb int
14752311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp)
14762311Sseb {
14775895Syz147064 	mac_impl_t		*mip;
14785895Syz147064 	mactype_t		*mtype;
14795895Syz147064 	int			err = EINVAL;
14805895Syz147064 	struct devnames		*dnp = NULL;
14815895Syz147064 	uint_t			instance;
14825895Syz147064 	boolean_t		style1_created = B_FALSE;
14835895Syz147064 	boolean_t		style2_created = B_FALSE;
14845895Syz147064 	mac_capab_legacy_t	legacy;
14855895Syz147064 	char			*driver;
14865895Syz147064 	minor_t			minor = 0;
14872311Sseb 
14882311Sseb 	/* Find the required MAC-Type plugin. */
14892311Sseb 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
14902311Sseb 		return (EINVAL);
14912311Sseb 
14922311Sseb 	/* Create a mac_impl_t to represent this MAC. */
14932311Sseb 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
14942311Sseb 
14952311Sseb 	/*
14962311Sseb 	 * The mac is not ready for open yet.
14972311Sseb 	 */
14982311Sseb 	mip->mi_disabled = B_TRUE;
14992311Sseb 
15002311Sseb 	/*
15015895Syz147064 	 * When a mac is registered, the m_instance field can be set to:
15025895Syz147064 	 *
15035895Syz147064 	 *  0:	Get the mac's instance number from m_dip.
15045895Syz147064 	 *	This is usually used for physical device dips.
15055895Syz147064 	 *
15065895Syz147064 	 *  [1 .. MAC_MAX_MINOR-1]: Use the value as the mac's instance number.
15075895Syz147064 	 *	For example, when an aggregation is created with the key option,
15085895Syz147064 	 *	"key" will be used as the instance number.
15095895Syz147064 	 *
15105895Syz147064 	 *  -1: Assign an instance number from [MAC_MAX_MINOR .. MAXMIN-1].
15115895Syz147064 	 *	This is often used when a MAC of a virtual link is registered
15125895Syz147064 	 *	(e.g., aggregation when "key" is not specified, or vnic).
15135895Syz147064 	 *
15145895Syz147064 	 * Note that the instance number is used to derive the mi_minor field
15155895Syz147064 	 * of mac_impl_t, which will then be used to derive the name of kstats
15165895Syz147064 	 * and the devfs nodes.  The first 2 cases are needed to preserve
15175895Syz147064 	 * backward compatibility.
15182311Sseb 	 */
15195895Syz147064 	switch (mregp->m_instance) {
15205895Syz147064 	case 0:
15215895Syz147064 		instance = ddi_get_instance(mregp->m_dip);
15225895Syz147064 		break;
15235895Syz147064 	case ((uint_t)-1):
15245895Syz147064 		minor = mac_minor_hold(B_TRUE);
15255895Syz147064 		if (minor == 0) {
15265895Syz147064 			err = ENOSPC;
15275895Syz147064 			goto fail;
15285895Syz147064 		}
15295895Syz147064 		instance = minor - 1;
15305895Syz147064 		break;
15315895Syz147064 	default:
15325895Syz147064 		instance = mregp->m_instance;
15335895Syz147064 		if (instance >= MAC_MAX_MINOR) {
15345895Syz147064 			err = EINVAL;
15355895Syz147064 			goto fail;
15365895Syz147064 		}
15375895Syz147064 		break;
15385895Syz147064 	}
15395895Syz147064 
15405895Syz147064 	mip->mi_minor = (minor_t)(instance + 1);
15415895Syz147064 	mip->mi_dip = mregp->m_dip;
15425895Syz147064 
15435895Syz147064 	driver = (char *)ddi_driver_name(mip->mi_dip);
15442311Sseb 
15452311Sseb 	/* Construct the MAC name as <drvname><instance> */
15462311Sseb 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
15475895Syz147064 	    driver, instance);
15482311Sseb 
15492311Sseb 	mip->mi_driver = mregp->m_driver;
15502311Sseb 
15512311Sseb 	mip->mi_type = mtype;
15525895Syz147064 	mip->mi_margin = mregp->m_margin;
15532311Sseb 	mip->mi_info.mi_media = mtype->mt_type;
15543147Sxc151355 	mip->mi_info.mi_nativemedia = mtype->mt_nativetype;
15553969Syz147064 	if (mregp->m_max_sdu <= mregp->m_min_sdu)
15562311Sseb 		goto fail;
15575903Ssowmini 	mip->mi_sdu_min = mregp->m_min_sdu;
15585903Ssowmini 	mip->mi_sdu_max = mregp->m_max_sdu;
15592311Sseb 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
15602311Sseb 	/*
15612311Sseb 	 * If the media supports a broadcast address, cache a pointer to it
15622311Sseb 	 * in the mac_info_t so that upper layers can use it.
15632311Sseb 	 */
15642311Sseb 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1565269Sericheng 
15662311Sseb 	/*
15672311Sseb 	 * Copy the unicast source address into the mac_info_t, but only if
15682311Sseb 	 * the MAC-Type defines a non-zero address length.  We need to
15692311Sseb 	 * handle MAC-Types that have an address length of 0
15702311Sseb 	 * (point-to-point protocol MACs for example).
15712311Sseb 	 */
15722311Sseb 	if (mip->mi_type->mt_addr_length > 0) {
15733969Syz147064 		if (mregp->m_src_addr == NULL)
15742311Sseb 			goto fail;
15752311Sseb 		mip->mi_info.mi_unicst_addr =
15762311Sseb 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
15772311Sseb 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
15782311Sseb 		    mip->mi_type->mt_addr_length);
15792311Sseb 
15802311Sseb 		/*
15812311Sseb 		 * Copy the fixed 'factory' MAC address from the immutable
15822311Sseb 		 * info.  This is taken to be the MAC address currently in
15832311Sseb 		 * use.
15842311Sseb 		 */
15852311Sseb 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
15862311Sseb 		    mip->mi_type->mt_addr_length);
15872311Sseb 		/* Copy the destination address if one is provided. */
15882311Sseb 		if (mregp->m_dst_addr != NULL) {
15892311Sseb 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
15902311Sseb 			    mip->mi_type->mt_addr_length);
15912311Sseb 		}
15922311Sseb 	} else if (mregp->m_src_addr != NULL) {
15932311Sseb 		goto fail;
1594269Sericheng 	}
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	/*
15972311Sseb 	 * The format of the m_pdata is specific to the plugin.  It is
15982311Sseb 	 * passed in as an argument to all of the plugin callbacks.  The
15992311Sseb 	 * driver can update this information by calling
16002311Sseb 	 * mac_pdata_update().
16010Sstevel@tonic-gate 	 */
16022311Sseb 	if (mregp->m_pdata != NULL) {
16032311Sseb 		/*
16042311Sseb 		 * Verify that the plugin supports MAC plugin data and that
16052311Sseb 		 * the supplied data is valid.
16062311Sseb 		 */
16073969Syz147064 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
16082311Sseb 			goto fail;
16092311Sseb 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
16102311Sseb 		    mregp->m_pdata_size)) {
16112311Sseb 			goto fail;
16122311Sseb 		}
16132311Sseb 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
16142311Sseb 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
16152311Sseb 		mip->mi_pdata_size = mregp->m_pdata_size;
16162311Sseb 	}
16172311Sseb 
16182311Sseb 	/*
1619*6512Ssowmini 	 * Register the private properties.
1620*6512Ssowmini 	 */
1621*6512Ssowmini 	mac_register_priv_prop(mip, mregp->m_priv_props,
1622*6512Ssowmini 	    mregp->m_priv_prop_count);
1623*6512Ssowmini 
1624*6512Ssowmini 	/*
16252311Sseb 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
16262311Sseb 	 * check to make sure all mandatory callbacks are set.
16272311Sseb 	 */
16282311Sseb 	if (mregp->m_callbacks->mc_getstat == NULL ||
16292311Sseb 	    mregp->m_callbacks->mc_start == NULL ||
16302311Sseb 	    mregp->m_callbacks->mc_stop == NULL ||
16312311Sseb 	    mregp->m_callbacks->mc_setpromisc == NULL ||
16322311Sseb 	    mregp->m_callbacks->mc_multicst == NULL ||
16332311Sseb 	    mregp->m_callbacks->mc_unicst == NULL ||
16342311Sseb 	    mregp->m_callbacks->mc_tx == NULL) {
16352311Sseb 		goto fail;
16362311Sseb 	}
16372311Sseb 	mip->mi_callbacks = mregp->m_callbacks;
16382311Sseb 
16392311Sseb 	/*
16405084Sjohnlev 	 * Set up the possible transmit routines.
16412311Sseb 	 */
16422311Sseb 	mip->mi_txinfo.mt_fn = mip->mi_tx;
16432311Sseb 	mip->mi_txinfo.mt_arg = mip->mi_driver;
16445084Sjohnlev 
16455895Syz147064 	mip->mi_legacy = mac_capab_get((mac_handle_t)mip,
16465895Syz147064 	    MAC_CAPAB_LEGACY, &legacy);
16475895Syz147064 
16485895Syz147064 	if (mip->mi_legacy) {
16495895Syz147064 		/*
16505895Syz147064 		 * Legacy device. Messages being sent will be looped back
16515895Syz147064 		 * by the underlying driver. Therefore the txloop function
16525895Syz147064 		 * pointer is the same as the tx function pointer.
16535895Syz147064 		 */
16545895Syz147064 		mip->mi_txloopinfo.mt_fn = mip->mi_txinfo.mt_fn;
16555895Syz147064 		mip->mi_txloopinfo.mt_arg = mip->mi_txinfo.mt_arg;
16565895Syz147064 		mip->mi_unsup_note = legacy.ml_unsup_note;
16575895Syz147064 		mip->mi_phy_dev = legacy.ml_dev;
16585895Syz147064 	} else {
16595895Syz147064 		/*
16605895Syz147064 		 * Normal device. The framework needs to do the loopback.
16615895Syz147064 		 */
16625895Syz147064 		mip->mi_txloopinfo.mt_fn = mac_txloop;
16635895Syz147064 		mip->mi_txloopinfo.mt_arg = mip;
16645895Syz147064 		mip->mi_unsup_note = 0;
16655895Syz147064 		mip->mi_phy_dev = makedevice(ddi_driver_major(mip->mi_dip),
16665895Syz147064 		    ddi_get_instance(mip->mi_dip) + 1);
16675895Syz147064 	}
16685895Syz147064 
16695084Sjohnlev 	mip->mi_vnic_txinfo.mt_fn = mac_vnic_tx;
16705084Sjohnlev 	mip->mi_vnic_txinfo.mt_arg = mip;
16715084Sjohnlev 
16725084Sjohnlev 	mip->mi_vnic_txloopinfo.mt_fn = mac_vnic_txloop;
16735084Sjohnlev 	mip->mi_vnic_txloopinfo.mt_arg = mip;
16745084Sjohnlev 
16752311Sseb 	/*
16765009Sgd78059 	 * Allocate a notification thread.
16775009Sgd78059 	 */
16785009Sgd78059 	mip->mi_notify_thread = thread_create(NULL, 0, i_mac_notify_thread,
16795009Sgd78059 	    mip, 0, &p0, TS_RUN, minclsyspri);
16805009Sgd78059 	if (mip->mi_notify_thread == NULL)
16815009Sgd78059 		goto fail;
16825009Sgd78059 
16835009Sgd78059 	/*
16842311Sseb 	 * Initialize the kstats for this device.
16852311Sseb 	 */
16862311Sseb 	mac_stat_create(mip);
16870Sstevel@tonic-gate 
1688*6512Ssowmini 
16890Sstevel@tonic-gate 	/* set the gldv3 flag in dn_flags */
16902311Sseb 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
16910Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
16925895Syz147064 	dnp->dn_flags |= (DN_GLDV3_DRIVER | DN_NETWORK_DRIVER);
16930Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
16940Sstevel@tonic-gate 
16955895Syz147064 	if (mip->mi_minor < MAC_MAX_MINOR + 1) {
16965895Syz147064 		/* Create a style-2 DLPI device */
16975895Syz147064 		if (ddi_create_minor_node(mip->mi_dip, driver, S_IFCHR, 0,
16985895Syz147064 		    DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
16995895Syz147064 			goto fail;
17005895Syz147064 		style2_created = B_TRUE;
17015895Syz147064 
17025895Syz147064 		/* Create a style-1 DLPI device */
17035895Syz147064 		if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR,
17045895Syz147064 		    mip->mi_minor, DDI_NT_NET, 0) != DDI_SUCCESS)
17055895Syz147064 			goto fail;
17065895Syz147064 		style1_created = B_TRUE;
17075895Syz147064 	}
17085895Syz147064 
17093969Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
17103969Syz147064 	if (mod_hash_insert(i_mac_impl_hash,
17113969Syz147064 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
17125895Syz147064 
17133969Syz147064 		rw_exit(&i_mac_impl_lock);
17143969Syz147064 		err = EEXIST;
17153969Syz147064 		goto fail;
17163969Syz147064 	}
17173969Syz147064 
17185903Ssowmini 	DTRACE_PROBE2(mac__register, struct devnames *, dnp,
17195903Ssowmini 	    (mac_impl_t *), mip);
17205903Ssowmini 
17211852Syz147064 	/*
17221852Syz147064 	 * Mark the MAC to be ready for open.
17231852Syz147064 	 */
17242311Sseb 	mip->mi_disabled = B_FALSE;
17252311Sseb 
17261852Syz147064 	rw_exit(&i_mac_impl_lock);
17273969Syz147064 
17283969Syz147064 	atomic_inc_32(&i_mac_impl_count);
17295895Syz147064 
17305895Syz147064 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
17312311Sseb 	*mhp = (mac_handle_t)mip;
1732269Sericheng 	return (0);
17330Sstevel@tonic-gate 
17342311Sseb fail:
17355895Syz147064 	if (style1_created)
17365895Syz147064 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
17375895Syz147064 
17385895Syz147064 	if (style2_created)
17395895Syz147064 		ddi_remove_minor_node(mip->mi_dip, driver);
17405895Syz147064 
17415009Sgd78059 	/* clean up notification thread */
17425009Sgd78059 	if (mip->mi_notify_thread != NULL) {
17435009Sgd78059 		mutex_enter(&mip->mi_notify_bits_lock);
17445009Sgd78059 		mip->mi_notify_bits = (1 << MAC_NNOTE);
17455009Sgd78059 		cv_broadcast(&mip->mi_notify_cv);
17465009Sgd78059 		while (mip->mi_notify_bits != 0)
17475009Sgd78059 			cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
17485009Sgd78059 		mutex_exit(&mip->mi_notify_bits_lock);
17495009Sgd78059 	}
17505009Sgd78059 
17512311Sseb 	if (mip->mi_info.mi_unicst_addr != NULL) {
17522311Sseb 		kmem_free(mip->mi_info.mi_unicst_addr,
17532311Sseb 		    mip->mi_type->mt_addr_length);
17542311Sseb 		mip->mi_info.mi_unicst_addr = NULL;
17552311Sseb 	}
17562311Sseb 
17572311Sseb 	mac_stat_destroy(mip);
17582311Sseb 
17592311Sseb 	if (mip->mi_type != NULL) {
17603288Sseb 		atomic_dec_32(&mip->mi_type->mt_ref);
17612311Sseb 		mip->mi_type = NULL;
17622311Sseb 	}
17632311Sseb 
17642311Sseb 	if (mip->mi_pdata != NULL) {
17652311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
17662311Sseb 		mip->mi_pdata = NULL;
17672311Sseb 		mip->mi_pdata_size = 0;
17682311Sseb 	}
17692311Sseb 
17705895Syz147064 	if (minor != 0) {
17715895Syz147064 		ASSERT(minor > MAC_MAX_MINOR);
17725895Syz147064 		mac_minor_rele(minor);
17735895Syz147064 	}
17745895Syz147064 
17752311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
1776269Sericheng 	return (err);
17770Sstevel@tonic-gate }
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate int
17805084Sjohnlev mac_disable(mac_handle_t mh)
17810Sstevel@tonic-gate {
17822311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
1783269Sericheng 
17840Sstevel@tonic-gate 	/*
17850Sstevel@tonic-gate 	 * See if there are any other references to this mac_t (e.g., VLAN's).
17861852Syz147064 	 * If not, set mi_disabled to prevent any new VLAN's from being
17872311Sseb 	 * created while we're destroying this mac.
17880Sstevel@tonic-gate 	 */
1789269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
17900Sstevel@tonic-gate 	if (mip->mi_ref > 0) {
1791269Sericheng 		rw_exit(&i_mac_impl_lock);
17920Sstevel@tonic-gate 		return (EBUSY);
17930Sstevel@tonic-gate 	}
17941852Syz147064 	mip->mi_disabled = B_TRUE;
1795269Sericheng 	rw_exit(&i_mac_impl_lock);
17965084Sjohnlev 	return (0);
17975084Sjohnlev }
17985084Sjohnlev 
17995084Sjohnlev int
18005084Sjohnlev mac_unregister(mac_handle_t mh)
18015084Sjohnlev {
18025084Sjohnlev 	int			err;
18035084Sjohnlev 	mac_impl_t		*mip = (mac_impl_t *)mh;
18045084Sjohnlev 	mod_hash_val_t		val;
18055084Sjohnlev 	mac_multicst_addr_t	*p, *nextp;
18065895Syz147064 	mac_margin_req_t	*mmr, *nextmmr;
1807*6512Ssowmini 	mac_priv_prop_t		*mpriv;
18085084Sjohnlev 
18095084Sjohnlev 	/*
18105084Sjohnlev 	 * See if there are any other references to this mac_t (e.g., VLAN's).
18115084Sjohnlev 	 * If not, set mi_disabled to prevent any new VLAN's from being
18125084Sjohnlev 	 * created while we're destroying this mac. Once mac_disable() returns
18135084Sjohnlev 	 * 0, the rest of mac_unregister() stuff should continue without
18145084Sjohnlev 	 * returning an error.
18155084Sjohnlev 	 */
18165084Sjohnlev 	if (!mip->mi_disabled) {
18175084Sjohnlev 		if ((err = mac_disable(mh)) != 0)
18185084Sjohnlev 			return (err);
18195084Sjohnlev 	}
18205084Sjohnlev 
18210Sstevel@tonic-gate 	/*
18225009Sgd78059 	 * Clean up notification thread (wait for it to exit).
18235009Sgd78059 	 */
18245009Sgd78059 	mutex_enter(&mip->mi_notify_bits_lock);
18255009Sgd78059 	mip->mi_notify_bits = (1 << MAC_NNOTE);
18265009Sgd78059 	cv_broadcast(&mip->mi_notify_cv);
18275009Sgd78059 	while (mip->mi_notify_bits != 0)
18285009Sgd78059 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock);
18295009Sgd78059 	mutex_exit(&mip->mi_notify_bits_lock);
18305009Sgd78059 
18315895Syz147064 	if (mip->mi_minor < MAC_MAX_MINOR + 1) {
18325895Syz147064 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
18335895Syz147064 		ddi_remove_minor_node(mip->mi_dip,
18345895Syz147064 		    (char *)ddi_driver_name(mip->mi_dip));
18355895Syz147064 	}
18362311Sseb 
18372311Sseb 	ASSERT(!mip->mi_activelink);
18382311Sseb 
18392311Sseb 	mac_stat_destroy(mip);
18402311Sseb 
18415895Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
18425895Syz147064 	(void) mod_hash_remove(i_mac_impl_hash,
18435895Syz147064 	    (mod_hash_key_t)mip->mi_name, &val);
18442311Sseb 	ASSERT(mip == (mac_impl_t *)val);
18452311Sseb 
18462311Sseb 	ASSERT(i_mac_impl_count > 0);
18473288Sseb 	atomic_dec_32(&i_mac_impl_count);
18485895Syz147064 	rw_exit(&i_mac_impl_lock);
18492311Sseb 
18502311Sseb 	if (mip->mi_pdata != NULL)
18512311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
18522311Sseb 	mip->mi_pdata = NULL;
18532311Sseb 	mip->mi_pdata_size = 0;
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 	/*
18562311Sseb 	 * Free the list of multicast addresses.
18570Sstevel@tonic-gate 	 */
18582311Sseb 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
18592311Sseb 		nextp = p->mma_nextp;
18602311Sseb 		kmem_free(p, sizeof (mac_multicst_addr_t));
18612311Sseb 	}
18622311Sseb 	mip->mi_mmap = NULL;
18630Sstevel@tonic-gate 
18645895Syz147064 	/*
18655895Syz147064 	 * Free the list of margin request.
18665895Syz147064 	 */
18675895Syz147064 	for (mmr = mip->mi_mmrp; mmr != NULL; mmr = nextmmr) {
18685895Syz147064 		nextmmr = mmr->mmr_nextp;
18695895Syz147064 		kmem_free(mmr, sizeof (mac_margin_req_t));
18705895Syz147064 	}
18715895Syz147064 	mip->mi_mmrp = NULL;
18725895Syz147064 
18732311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
18742311Sseb 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
18752311Sseb 	mip->mi_info.mi_unicst_addr = NULL;
18762311Sseb 
18773288Sseb 	atomic_dec_32(&mip->mi_type->mt_ref);
18782311Sseb 	mip->mi_type = NULL;
18792311Sseb 
18805895Syz147064 	if (mip->mi_minor > MAC_MAX_MINOR)
18815895Syz147064 		mac_minor_rele(mip->mi_minor);
18825895Syz147064 
18832311Sseb 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
18842311Sseb 
1885*6512Ssowmini 	mpriv = mip->mi_priv_prop;
1886*6512Ssowmini 	kmem_free(mpriv, mip->mi_priv_prop_count * sizeof (*mpriv));
1887*6512Ssowmini 
18882311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
18892311Sseb 
18900Sstevel@tonic-gate 	return (0);
18910Sstevel@tonic-gate }
18920Sstevel@tonic-gate 
18934913Sethindra /*
18944913Sethindra  * To avoid potential deadlocks, mac_rx() releases mi_rx_lock
18954913Sethindra  * before invoking its list of upcalls. This introduces races with
18964913Sethindra  * mac_rx_remove() and mac_rx_add(), who can potentially modify the
18974913Sethindra  * upcall list while mi_rx_lock is not being held. The race with
18984913Sethindra  * mac_rx_remove() is handled by incrementing mi_rx_ref upon entering
18994913Sethindra  * mac_rx(); a non-zero mi_rx_ref would tell mac_rx_remove()
19004913Sethindra  * to not modify the list but instead mark an upcall for deletion.
19014913Sethindra  * before mac_rx() exits, mi_rx_ref is decremented and if it
19024913Sethindra  * is 0, the marked upcalls will be removed from the list and freed.
19034913Sethindra  * The race with mac_rx_add() is harmless because mac_rx_add() only
19044913Sethindra  * prepends to the list and since mac_rx() saves the list head
19054913Sethindra  * before releasing mi_rx_lock, any prepended upcall won't be seen
19064913Sethindra  * until the next packet chain arrives.
19074913Sethindra  *
19084913Sethindra  * To minimize lock contention between multiple parallel invocations
19094913Sethindra  * of mac_rx(), mi_rx_lock is acquired as a READER lock. The
19104913Sethindra  * use of atomic operations ensures the sanity of mi_rx_ref. mi_rx_lock
19114913Sethindra  * will be upgraded to WRITER mode when there are marked upcalls to be
19124913Sethindra  * cleaned.
19134913Sethindra  */
19145084Sjohnlev static void
19155084Sjohnlev mac_do_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain,
19165084Sjohnlev     boolean_t active_only)
19170Sstevel@tonic-gate {
19182311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
19194913Sethindra 	mblk_t		*bp = mp_chain;
19200Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 	/*
19230Sstevel@tonic-gate 	 * Call all registered receive functions.
19240Sstevel@tonic-gate 	 */
19250Sstevel@tonic-gate 	rw_enter(&mip->mi_rx_lock, RW_READER);
19264913Sethindra 	if ((mrfp = mip->mi_mrfp) == NULL) {
19270Sstevel@tonic-gate 		/* There are no registered receive functions. */
19280Sstevel@tonic-gate 		freemsgchain(bp);
19290Sstevel@tonic-gate 		rw_exit(&mip->mi_rx_lock);
19300Sstevel@tonic-gate 		return;
19310Sstevel@tonic-gate 	}
19324913Sethindra 	atomic_inc_32(&mip->mi_rx_ref);
19334913Sethindra 	rw_exit(&mip->mi_rx_lock);
19344913Sethindra 
19354913Sethindra 	/*
19364913Sethindra 	 * Call registered receive functions.
19374913Sethindra 	 */
19380Sstevel@tonic-gate 	do {
19390Sstevel@tonic-gate 		mblk_t *recv_bp;
19400Sstevel@tonic-gate 
19415084Sjohnlev 		if (active_only && !mrfp->mrf_active) {
19425084Sjohnlev 			mrfp = mrfp->mrf_nextp;
19435084Sjohnlev 			if (mrfp == NULL) {
19445084Sjohnlev 				/*
19455084Sjohnlev 				 * We hit the last receiver, but it's not
19465084Sjohnlev 				 * active.
19475084Sjohnlev 				 */
19485084Sjohnlev 				freemsgchain(bp);
19495084Sjohnlev 			}
19505084Sjohnlev 			continue;
19515084Sjohnlev 		}
19525084Sjohnlev 
19534913Sethindra 		recv_bp = (mrfp->mrf_nextp != NULL) ? copymsgchain(bp) : bp;
19544913Sethindra 		if (recv_bp != NULL) {
19554913Sethindra 			if (mrfp->mrf_inuse) {
19564913Sethindra 				/*
19574913Sethindra 				 * Send bp itself and keep the copy.
19584913Sethindra 				 * If there's only one active receiver,
19594913Sethindra 				 * it should get the original message,
19604913Sethindra 				 * tagged with the hardware checksum flags.
19614913Sethindra 				 */
19624913Sethindra 				mrfp->mrf_fn(mrfp->mrf_arg, mrh, bp);
19634913Sethindra 				bp = recv_bp;
19644913Sethindra 			} else {
19654913Sethindra 				freemsgchain(recv_bp);
19664913Sethindra 			}
19670Sstevel@tonic-gate 		}
19685084Sjohnlev 
19690Sstevel@tonic-gate 		mrfp = mrfp->mrf_nextp;
19700Sstevel@tonic-gate 	} while (mrfp != NULL);
19714913Sethindra 
19724913Sethindra 	rw_enter(&mip->mi_rx_lock, RW_READER);
19734913Sethindra 	if (atomic_dec_32_nv(&mip->mi_rx_ref) == 0 && mip->mi_rx_removed > 0) {
19744913Sethindra 		mac_rx_fn_t	**pp, *p;
19754913Sethindra 		uint32_t	cnt = 0;
19764913Sethindra 
19774913Sethindra 		DTRACE_PROBE1(delete_callbacks, mac_impl_t *, mip);
19784913Sethindra 
19794913Sethindra 		/*
19804913Sethindra 		 * Need to become exclusive before doing cleanup
19814913Sethindra 		 */
19824913Sethindra 		if (rw_tryupgrade(&mip->mi_rx_lock) == 0) {
19834913Sethindra 			rw_exit(&mip->mi_rx_lock);
19844913Sethindra 			rw_enter(&mip->mi_rx_lock, RW_WRITER);
19854913Sethindra 		}
19864913Sethindra 
19874913Sethindra 		/*
19884913Sethindra 		 * We return if another thread has already entered and cleaned
19894913Sethindra 		 * up the list.
19904913Sethindra 		 */
19914913Sethindra 		if (mip->mi_rx_ref > 0 || mip->mi_rx_removed == 0) {
19924913Sethindra 			rw_exit(&mip->mi_rx_lock);
19934913Sethindra 			return;
19944913Sethindra 		}
19954913Sethindra 
19964913Sethindra 		/*
19974913Sethindra 		 * Free removed callbacks.
19984913Sethindra 		 */
19994913Sethindra 		pp = &mip->mi_mrfp;
20004913Sethindra 		while (*pp != NULL) {
20014913Sethindra 			if (!(*pp)->mrf_inuse) {
20024913Sethindra 				p = *pp;
20034913Sethindra 				*pp = (*pp)->mrf_nextp;
20044913Sethindra 				kmem_free(p, sizeof (*p));
20054913Sethindra 				cnt++;
20064913Sethindra 				continue;
20074913Sethindra 			}
20084913Sethindra 			pp = &(*pp)->mrf_nextp;
20094913Sethindra 		}
20104913Sethindra 
20114913Sethindra 		/*
20124913Sethindra 		 * Wake up mac_rx_remove_wait()
20134913Sethindra 		 */
20144913Sethindra 		mutex_enter(&mip->mi_lock);
20154913Sethindra 		ASSERT(mip->mi_rx_removed == cnt);
20164913Sethindra 		mip->mi_rx_removed = 0;
20174913Sethindra 		cv_broadcast(&mip->mi_rx_cv);
20184913Sethindra 		mutex_exit(&mip->mi_lock);
20194913Sethindra 	}
20200Sstevel@tonic-gate 	rw_exit(&mip->mi_rx_lock);
20210Sstevel@tonic-gate }
20220Sstevel@tonic-gate 
20235084Sjohnlev void
20245084Sjohnlev mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain)
20255084Sjohnlev {
20265084Sjohnlev 	mac_do_rx(mh, mrh, mp_chain, B_FALSE);
20275084Sjohnlev }
20285084Sjohnlev 
20295084Sjohnlev /*
20305084Sjohnlev  * Send a packet chain up to the receive callbacks which declared
20315084Sjohnlev  * themselves as being active.
20325084Sjohnlev  */
20335084Sjohnlev void
20345084Sjohnlev mac_active_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp_chain)
20355084Sjohnlev {
20365084Sjohnlev 	mac_do_rx(arg, mrh, mp_chain, B_TRUE);
20375084Sjohnlev }
20385084Sjohnlev 
20395084Sjohnlev /*
20405084Sjohnlev  * Function passed to the active client sharing a VNIC. This function
20415084Sjohnlev  * is returned by mac_tx_get() when a VNIC is present. It invokes
20425084Sjohnlev  * the VNIC transmit entry point which was specified by the VNIC when
20435084Sjohnlev  * it called mac_vnic_set(). The VNIC transmit entry point will
20445084Sjohnlev  * pass the packets to the local VNICs and/or to the underlying VNICs
20455084Sjohnlev  * if needed.
20465084Sjohnlev  */
20475084Sjohnlev static mblk_t *
20485084Sjohnlev mac_vnic_tx(void *arg, mblk_t *mp)
20495084Sjohnlev {
20505084Sjohnlev 	mac_impl_t	*mip = arg;
20515084Sjohnlev 	mac_txinfo_t	*mtfp;
20525084Sjohnlev 	mac_vnic_tx_t	*mvt;
20535084Sjohnlev 
20545084Sjohnlev 	/*
20555084Sjohnlev 	 * There is a race between the notification of the VNIC
20565084Sjohnlev 	 * addition and removal, and the processing of the VNIC notification
20575084Sjohnlev 	 * by the MAC client. During this window, it is possible for
20585084Sjohnlev 	 * an active MAC client to contine invoking mac_vnic_tx() while
20595084Sjohnlev 	 * the VNIC has already been removed. So we cannot assume
20605084Sjohnlev 	 * that mi_vnic_present will always be true when mac_vnic_tx()
20615084Sjohnlev 	 * is invoked.
20625084Sjohnlev 	 */
20635084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_READER);
20645084Sjohnlev 	if (!mip->mi_vnic_present) {
20655084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
20665084Sjohnlev 		freemsgchain(mp);
20675084Sjohnlev 		return (NULL);
20685084Sjohnlev 	}
20695084Sjohnlev 
20705084Sjohnlev 	ASSERT(mip->mi_vnic_tx != NULL);
20715084Sjohnlev 	mvt = mip->mi_vnic_tx;
20725084Sjohnlev 	MAC_VNIC_TXINFO_REFHOLD(mvt);
20735084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
20745084Sjohnlev 
20755084Sjohnlev 	mtfp = &mvt->mv_txinfo;
20765084Sjohnlev 	mtfp->mt_fn(mtfp->mt_arg, mp);
20775084Sjohnlev 
20785084Sjohnlev 	MAC_VNIC_TXINFO_REFRELE(mvt);
20795084Sjohnlev 	return (NULL);
20805084Sjohnlev }
20815084Sjohnlev 
20820Sstevel@tonic-gate /*
20830Sstevel@tonic-gate  * Transmit function -- ONLY used when there are registered loopback listeners.
20840Sstevel@tonic-gate  */
20850Sstevel@tonic-gate mblk_t *
20865084Sjohnlev mac_do_txloop(void *arg, mblk_t *bp, boolean_t call_vnic)
20870Sstevel@tonic-gate {
20880Sstevel@tonic-gate 	mac_impl_t	*mip = arg;
20890Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
20900Sstevel@tonic-gate 	mblk_t		*loop_bp, *resid_bp, *next_bp;
20910Sstevel@tonic-gate 
20925084Sjohnlev 	if (call_vnic) {
20935084Sjohnlev 		/*
20945084Sjohnlev 		 * In promiscous mode, a copy of the sent packet will
20955084Sjohnlev 		 * be sent to the client's promiscous receive entry
20965084Sjohnlev 		 * points via mac_vnic_tx()->
20975084Sjohnlev 		 * mac_active_rx_promisc()->mac_rx_default().
20985084Sjohnlev 		 */
20995084Sjohnlev 		return (mac_vnic_tx(arg, bp));
21005084Sjohnlev 	}
21015084Sjohnlev 
21020Sstevel@tonic-gate 	while (bp != NULL) {
21030Sstevel@tonic-gate 		next_bp = bp->b_next;
21040Sstevel@tonic-gate 		bp->b_next = NULL;
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 		if ((loop_bp = copymsg(bp)) == NULL)
21070Sstevel@tonic-gate 			goto noresources;
21080Sstevel@tonic-gate 
21092311Sseb 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
21100Sstevel@tonic-gate 			ASSERT(resid_bp == bp);
21110Sstevel@tonic-gate 			freemsg(loop_bp);
21120Sstevel@tonic-gate 			goto noresources;
21130Sstevel@tonic-gate 		}
21140Sstevel@tonic-gate 
21155084Sjohnlev 		rw_enter(&mip->mi_tx_lock, RW_READER);
21160Sstevel@tonic-gate 		mtfp = mip->mi_mtfp;
211756Smeem 		while (mtfp != NULL && loop_bp != NULL) {
21180Sstevel@tonic-gate 			bp = loop_bp;
211956Smeem 
212056Smeem 			/* XXX counter bump if copymsg() fails? */
212156Smeem 			if (mtfp->mtf_nextp != NULL)
21220Sstevel@tonic-gate 				loop_bp = copymsg(bp);
212356Smeem 			else
212456Smeem 				loop_bp = NULL;
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
212756Smeem 			mtfp = mtfp->mtf_nextp;
21280Sstevel@tonic-gate 		}
21295084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
21300Sstevel@tonic-gate 
213156Smeem 		/*
213256Smeem 		 * It's possible we've raced with the disabling of promiscuous
213356Smeem 		 * mode, in which case we can discard our copy.
213456Smeem 		 */
213556Smeem 		if (loop_bp != NULL)
213656Smeem 			freemsg(loop_bp);
213756Smeem 
21380Sstevel@tonic-gate 		bp = next_bp;
21390Sstevel@tonic-gate 	}
21400Sstevel@tonic-gate 
21410Sstevel@tonic-gate 	return (NULL);
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate noresources:
21440Sstevel@tonic-gate 	bp->b_next = next_bp;
21450Sstevel@tonic-gate 	return (bp);
21460Sstevel@tonic-gate }
21470Sstevel@tonic-gate 
21485084Sjohnlev mblk_t *
21495084Sjohnlev mac_txloop(void *arg, mblk_t *bp)
21505084Sjohnlev {
21515084Sjohnlev 	return (mac_do_txloop(arg, bp, B_FALSE));
21525084Sjohnlev }
21535084Sjohnlev 
21545084Sjohnlev static mblk_t *
21555084Sjohnlev mac_vnic_txloop(void *arg, mblk_t *bp)
21565084Sjohnlev {
21575084Sjohnlev 	return (mac_do_txloop(arg, bp, B_TRUE));
21585084Sjohnlev }
21595084Sjohnlev 
21600Sstevel@tonic-gate void
21612311Sseb mac_link_update(mac_handle_t mh, link_state_t link)
21620Sstevel@tonic-gate {
21632311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	/*
21660Sstevel@tonic-gate 	 * Save the link state.
21670Sstevel@tonic-gate 	 */
21682311Sseb 	mip->mi_linkstate = link;
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate 	/*
21710Sstevel@tonic-gate 	 * Send a MAC_NOTE_LINK notification.
21720Sstevel@tonic-gate 	 */
21730Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_LINK);
21740Sstevel@tonic-gate }
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate void
21772311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
21780Sstevel@tonic-gate {
21792311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
21800Sstevel@tonic-gate 
21812311Sseb 	if (mip->mi_type->mt_addr_length == 0)
21822311Sseb 		return;
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate 	/*
21855895Syz147064 	 * If the address has not changed, do nothing.
21865895Syz147064 	 */
21875895Syz147064 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0)
21885895Syz147064 		return;
21895895Syz147064 
21905895Syz147064 	/*
21910Sstevel@tonic-gate 	 * Save the address.
21920Sstevel@tonic-gate 	 */
21932311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 	/*
21960Sstevel@tonic-gate 	 * Send a MAC_NOTE_UNICST notification.
21970Sstevel@tonic-gate 	 */
21980Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_UNICST);
21990Sstevel@tonic-gate }
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate void
22022311Sseb mac_tx_update(mac_handle_t mh)
22030Sstevel@tonic-gate {
22040Sstevel@tonic-gate 	/*
22050Sstevel@tonic-gate 	 * Send a MAC_NOTE_TX notification.
22060Sstevel@tonic-gate 	 */
22072311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
22080Sstevel@tonic-gate }
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate void
22112311Sseb mac_resource_update(mac_handle_t mh)
22120Sstevel@tonic-gate {
22130Sstevel@tonic-gate 	/*
22140Sstevel@tonic-gate 	 * Send a MAC_NOTE_RESOURCE notification.
22150Sstevel@tonic-gate 	 */
22162311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
22170Sstevel@tonic-gate }
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate mac_resource_handle_t
22202311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
22210Sstevel@tonic-gate {
22222311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
22230Sstevel@tonic-gate 	mac_resource_handle_t	mrh;
22240Sstevel@tonic-gate 	mac_resource_add_t	add;
22250Sstevel@tonic-gate 	void			*arg;
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 	rw_enter(&mip->mi_resource_lock, RW_READER);
22280Sstevel@tonic-gate 	add = mip->mi_resource_add;
22290Sstevel@tonic-gate 	arg = mip->mi_resource_add_arg;
22300Sstevel@tonic-gate 
22311184Skrgopi 	if (add != NULL)
22321184Skrgopi 		mrh = add(arg, mrp);
22331184Skrgopi 	else
22341184Skrgopi 		mrh = NULL;
22350Sstevel@tonic-gate 	rw_exit(&mip->mi_resource_lock);
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate 	return (mrh);
22380Sstevel@tonic-gate }
22390Sstevel@tonic-gate 
22402311Sseb int
22412311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
22422311Sseb {
22432311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
22442311Sseb 
22452311Sseb 	/*
22462311Sseb 	 * Verify that the plugin supports MAC plugin data and that the
22472311Sseb 	 * supplied data is valid.
22482311Sseb 	 */
22492311Sseb 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
22502311Sseb 		return (EINVAL);
22512311Sseb 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
22522311Sseb 		return (EINVAL);
22532311Sseb 
22542311Sseb 	if (mip->mi_pdata != NULL)
22552311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
22562311Sseb 
22572311Sseb 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
22582311Sseb 	bcopy(mac_pdata, mip->mi_pdata, dsize);
22592311Sseb 	mip->mi_pdata_size = dsize;
22602311Sseb 
22612311Sseb 	/*
22622311Sseb 	 * Since the MAC plugin data is used to construct MAC headers that
22632311Sseb 	 * were cached in fast-path headers, we need to flush fast-path
22642311Sseb 	 * information for links associated with this mac.
22652311Sseb 	 */
22662311Sseb 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
22672311Sseb 	return (0);
22682311Sseb }
22692311Sseb 
22700Sstevel@tonic-gate void
22712311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
22720Sstevel@tonic-gate     boolean_t add)
22730Sstevel@tonic-gate {
22742311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
22750Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate 	/*
22780Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
22790Sstevel@tonic-gate 	 * driver's m_multicst entry point.
22800Sstevel@tonic-gate 	 */
22810Sstevel@tonic-gate 	if (refresh == NULL) {
22822311Sseb 		refresh = mip->mi_multicst;
22832311Sseb 		arg = mip->mi_driver;
22840Sstevel@tonic-gate 	}
22850Sstevel@tonic-gate 	ASSERT(refresh != NULL);
22860Sstevel@tonic-gate 
22870Sstevel@tonic-gate 	/*
22880Sstevel@tonic-gate 	 * Walk the multicast address list and call the refresh function for
22890Sstevel@tonic-gate 	 * each address.
22900Sstevel@tonic-gate 	 */
22910Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
22920Sstevel@tonic-gate 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
22930Sstevel@tonic-gate 		refresh(arg, add, p->mma_addr);
22940Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
22950Sstevel@tonic-gate }
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate void
22982311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
22990Sstevel@tonic-gate {
23002311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
23010Sstevel@tonic-gate 	/*
23020Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
23032311Sseb 	 * driver's mi_unicst entry point.
23040Sstevel@tonic-gate 	 */
23050Sstevel@tonic-gate 	if (refresh == NULL) {
23062311Sseb 		refresh = mip->mi_unicst;
23072311Sseb 		arg = mip->mi_driver;
23080Sstevel@tonic-gate 	}
23090Sstevel@tonic-gate 	ASSERT(refresh != NULL);
23100Sstevel@tonic-gate 
23110Sstevel@tonic-gate 	/*
23120Sstevel@tonic-gate 	 * Call the refresh function with the current unicast address.
23130Sstevel@tonic-gate 	 */
23140Sstevel@tonic-gate 	refresh(arg, mip->mi_addr);
23150Sstevel@tonic-gate }
23160Sstevel@tonic-gate 
23170Sstevel@tonic-gate void
23182311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
23190Sstevel@tonic-gate {
23202311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate 	/*
23230Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
23240Sstevel@tonic-gate 	 * driver's m_promisc entry point.
23250Sstevel@tonic-gate 	 */
23260Sstevel@tonic-gate 	if (refresh == NULL) {
23272311Sseb 		refresh = mip->mi_setpromisc;
23282311Sseb 		arg = mip->mi_driver;
23290Sstevel@tonic-gate 	}
23300Sstevel@tonic-gate 	ASSERT(refresh != NULL);
23310Sstevel@tonic-gate 
23320Sstevel@tonic-gate 	/*
23330Sstevel@tonic-gate 	 * Call the refresh function with the current promiscuity.
23340Sstevel@tonic-gate 	 */
23350Sstevel@tonic-gate 	refresh(arg, (mip->mi_devpromisc != 0));
23360Sstevel@tonic-gate }
23370Sstevel@tonic-gate 
23385895Syz147064 /*
23395895Syz147064  * The mac client requests that the mac not to change its margin size to
23405895Syz147064  * be less than the specified value.  If "current" is B_TRUE, then the client
23415895Syz147064  * requests the mac not to change its margin size to be smaller than the
23425895Syz147064  * current size. Further, return the current margin size value in this case.
23435895Syz147064  *
23445895Syz147064  * We keep every requested size in an ordered list from largest to smallest.
23455895Syz147064  */
23465895Syz147064 int
23475895Syz147064 mac_margin_add(mac_handle_t mh, uint32_t *marginp, boolean_t current)
23485895Syz147064 {
23495895Syz147064 	mac_impl_t		*mip = (mac_impl_t *)mh;
23505895Syz147064 	mac_margin_req_t	**pp, *p;
23515895Syz147064 	int			err = 0;
23525895Syz147064 
23535895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
23545895Syz147064 	if (current)
23555895Syz147064 		*marginp = mip->mi_margin;
23565895Syz147064 
23575895Syz147064 	/*
23585895Syz147064 	 * If the current margin value cannot satisfy the margin requested,
23595895Syz147064 	 * return ENOTSUP directly.
23605895Syz147064 	 */
23615895Syz147064 	if (*marginp > mip->mi_margin) {
23625895Syz147064 		err = ENOTSUP;
23635895Syz147064 		goto done;
23645895Syz147064 	}
23655895Syz147064 
23665895Syz147064 	/*
23675895Syz147064 	 * Check whether the given margin is already in the list. If so,
23685895Syz147064 	 * bump the reference count.
23695895Syz147064 	 */
23705895Syz147064 	for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
23715895Syz147064 		if (p->mmr_margin == *marginp) {
23725895Syz147064 			/*
23735895Syz147064 			 * The margin requested is already in the list,
23745895Syz147064 			 * so just bump the reference count.
23755895Syz147064 			 */
23765895Syz147064 			p->mmr_ref++;
23775895Syz147064 			goto done;
23785895Syz147064 		}
23795895Syz147064 		if (p->mmr_margin < *marginp)
23805895Syz147064 			break;
23815895Syz147064 	}
23825895Syz147064 
23835895Syz147064 
23845895Syz147064 	if ((p = kmem_zalloc(sizeof (mac_margin_req_t), KM_NOSLEEP)) == NULL) {
23855895Syz147064 		err = ENOMEM;
23865895Syz147064 		goto done;
23875895Syz147064 	}
23885895Syz147064 
23895895Syz147064 	p->mmr_margin = *marginp;
23905895Syz147064 	p->mmr_ref++;
23915895Syz147064 	p->mmr_nextp = *pp;
23925895Syz147064 	*pp = p;
23935895Syz147064 
23945895Syz147064 done:
23955895Syz147064 	rw_exit(&(mip->mi_data_lock));
23965895Syz147064 	return (err);
23975895Syz147064 }
23985895Syz147064 
23995895Syz147064 /*
24005895Syz147064  * The mac client requests to cancel its previous mac_margin_add() request.
24015895Syz147064  * We remove the requested margin size from the list.
24025895Syz147064  */
24035895Syz147064 int
24045895Syz147064 mac_margin_remove(mac_handle_t mh, uint32_t margin)
24055895Syz147064 {
24065895Syz147064 	mac_impl_t		*mip = (mac_impl_t *)mh;
24075895Syz147064 	mac_margin_req_t	**pp, *p;
24085895Syz147064 	int			err = 0;
24095895Syz147064 
24105895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
24115895Syz147064 	/*
24125895Syz147064 	 * Find the entry in the list for the given margin.
24135895Syz147064 	 */
24145895Syz147064 	for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) {
24155895Syz147064 		if (p->mmr_margin == margin) {
24165895Syz147064 			if (--p->mmr_ref == 0)
24175895Syz147064 				break;
24185895Syz147064 
24195895Syz147064 			/*
24205895Syz147064 			 * There is still a reference to this address so
24215895Syz147064 			 * there's nothing more to do.
24225895Syz147064 			 */
24235895Syz147064 			goto done;
24245895Syz147064 		}
24255895Syz147064 	}
24265895Syz147064 
24275895Syz147064 	/*
24285895Syz147064 	 * We did not find an entry for the given margin.
24295895Syz147064 	 */
24305895Syz147064 	if (p == NULL) {
24315895Syz147064 		err = ENOENT;
24325895Syz147064 		goto done;
24335895Syz147064 	}
24345895Syz147064 
24355895Syz147064 	ASSERT(p->mmr_ref == 0);
24365895Syz147064 
24375895Syz147064 	/*
24385895Syz147064 	 * Remove it from the list.
24395895Syz147064 	 */
24405895Syz147064 	*pp = p->mmr_nextp;
24415895Syz147064 	kmem_free(p, sizeof (mac_margin_req_t));
24425895Syz147064 done:
24435895Syz147064 	rw_exit(&(mip->mi_data_lock));
24445895Syz147064 	return (err);
24455895Syz147064 }
24465895Syz147064 
24475895Syz147064 /*
24485895Syz147064  * The mac client requests to get the mac's current margin value.
24495895Syz147064  */
24505895Syz147064 void
24515895Syz147064 mac_margin_get(mac_handle_t mh, uint32_t *marginp)
24525895Syz147064 {
24535895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
24545895Syz147064 
24555895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_READER);
24565895Syz147064 	*marginp = mip->mi_margin;
24575895Syz147064 	rw_exit(&(mip->mi_data_lock));
24585895Syz147064 }
24595895Syz147064 
24605895Syz147064 boolean_t
24615895Syz147064 mac_margin_update(mac_handle_t mh, uint32_t margin)
24625895Syz147064 {
24635895Syz147064 	mac_impl_t	*mip = (mac_impl_t *)mh;
24645895Syz147064 	uint32_t	margin_needed = 0;
24655895Syz147064 
24665895Syz147064 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
24675895Syz147064 
24685895Syz147064 	if (mip->mi_mmrp != NULL)
24695895Syz147064 		margin_needed = mip->mi_mmrp->mmr_margin;
24705895Syz147064 
24715895Syz147064 	if (margin_needed <= margin)
24725895Syz147064 		mip->mi_margin = margin;
24735895Syz147064 
24745895Syz147064 	rw_exit(&(mip->mi_data_lock));
24755895Syz147064 
24765895Syz147064 	if (margin_needed <= margin)
24775895Syz147064 		i_mac_notify(mip, MAC_NOTE_MARGIN);
24785895Syz147064 
24795895Syz147064 	return (margin_needed <= margin);
24805895Syz147064 }
24815895Syz147064 
24820Sstevel@tonic-gate boolean_t
24835084Sjohnlev mac_do_active_set(mac_handle_t mh, boolean_t shareable)
24840Sstevel@tonic-gate {
24850Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
24860Sstevel@tonic-gate 
24870Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
24880Sstevel@tonic-gate 	if (mip->mi_activelink) {
24890Sstevel@tonic-gate 		mutex_exit(&mip->mi_activelink_lock);
24900Sstevel@tonic-gate 		return (B_FALSE);
24910Sstevel@tonic-gate 	}
24920Sstevel@tonic-gate 	mip->mi_activelink = B_TRUE;
24935084Sjohnlev 	mip->mi_shareable = shareable;
24940Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
24950Sstevel@tonic-gate 	return (B_TRUE);
24960Sstevel@tonic-gate }
24970Sstevel@tonic-gate 
24985084Sjohnlev /*
24995084Sjohnlev  * Called by MAC clients. By default, active MAC clients cannot
25005084Sjohnlev  * share the NIC with VNICs.
25015084Sjohnlev  */
25025084Sjohnlev boolean_t
25035084Sjohnlev mac_active_set(mac_handle_t mh)
25045084Sjohnlev {
25055084Sjohnlev 	return (mac_do_active_set(mh, B_FALSE));
25065084Sjohnlev }
25075084Sjohnlev 
25085084Sjohnlev /*
25095084Sjohnlev  * Called by MAC clients which can share the NIC with VNICS, e.g. DLS.
25105084Sjohnlev  */
25115084Sjohnlev boolean_t
25125084Sjohnlev mac_active_shareable_set(mac_handle_t mh)
25135084Sjohnlev {
25145084Sjohnlev 	return (mac_do_active_set(mh, B_TRUE));
25155084Sjohnlev }
25165084Sjohnlev 
25170Sstevel@tonic-gate void
25180Sstevel@tonic-gate mac_active_clear(mac_handle_t mh)
25190Sstevel@tonic-gate {
25200Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
25230Sstevel@tonic-gate 	ASSERT(mip->mi_activelink);
25240Sstevel@tonic-gate 	mip->mi_activelink = B_FALSE;
25250Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
25260Sstevel@tonic-gate }
2527269Sericheng 
25285084Sjohnlev boolean_t
25295084Sjohnlev mac_vnic_set(mac_handle_t mh, mac_txinfo_t *tx_info, mac_getcapab_t getcapab_fn,
25305084Sjohnlev     void *getcapab_arg)
25315084Sjohnlev {
25325084Sjohnlev 	mac_impl_t	*mip = (mac_impl_t *)mh;
25335084Sjohnlev 	mac_vnic_tx_t	*vnic_tx;
25345084Sjohnlev 
25355084Sjohnlev 	mutex_enter(&mip->mi_activelink_lock);
25365084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_WRITER);
25375084Sjohnlev 	ASSERT(!mip->mi_vnic_present);
25385084Sjohnlev 
25395084Sjohnlev 	if (mip->mi_activelink && !mip->mi_shareable) {
25405084Sjohnlev 		/*
25415084Sjohnlev 		 * The NIC is already used by an active client which cannot
25425084Sjohnlev 		 * share it with VNICs.
25435084Sjohnlev 		 */
25445084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
25455084Sjohnlev 		mutex_exit(&mip->mi_activelink_lock);
25465084Sjohnlev 		return (B_FALSE);
25475084Sjohnlev 	}
25485084Sjohnlev 
25495084Sjohnlev 	vnic_tx = kmem_cache_alloc(mac_vnic_tx_cache, KM_SLEEP);
25505084Sjohnlev 	vnic_tx->mv_refs = 0;
25515084Sjohnlev 	vnic_tx->mv_txinfo = *tx_info;
25525084Sjohnlev 	vnic_tx->mv_clearing = B_FALSE;
25535084Sjohnlev 
25545084Sjohnlev 	mip->mi_vnic_present = B_TRUE;
25555084Sjohnlev 	mip->mi_vnic_tx = vnic_tx;
25565084Sjohnlev 	mip->mi_vnic_getcapab_fn = getcapab_fn;
25575084Sjohnlev 	mip->mi_vnic_getcapab_arg = getcapab_arg;
25585084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
25595084Sjohnlev 	mutex_exit(&mip->mi_activelink_lock);
25605084Sjohnlev 
25615084Sjohnlev 	i_mac_notify(mip, MAC_NOTE_VNIC);
25625084Sjohnlev 	return (B_TRUE);
25635084Sjohnlev }
25645084Sjohnlev 
25655084Sjohnlev void
25665084Sjohnlev mac_vnic_clear(mac_handle_t mh)
25675084Sjohnlev {
25685084Sjohnlev 	mac_impl_t *mip = (mac_impl_t *)mh;
25695084Sjohnlev 	mac_vnic_tx_t	*vnic_tx;
25705084Sjohnlev 
25715084Sjohnlev 	rw_enter(&mip->mi_tx_lock, RW_WRITER);
25725084Sjohnlev 	ASSERT(mip->mi_vnic_present);
25735084Sjohnlev 	mip->mi_vnic_present = B_FALSE;
25745084Sjohnlev 	/*
25755084Sjohnlev 	 * Setting mi_vnic_tx to NULL here under the lock guarantees
25765084Sjohnlev 	 * that no new references to the current VNIC transmit structure
25775084Sjohnlev 	 * will be taken by mac_vnic_tx(). This is a necessary condition
25785084Sjohnlev 	 * for safely waiting for the reference count to drop to
25795084Sjohnlev 	 * zero below.
25805084Sjohnlev 	 */
25815084Sjohnlev 	vnic_tx = mip->mi_vnic_tx;
25825084Sjohnlev 	mip->mi_vnic_tx = NULL;
25835084Sjohnlev 	mip->mi_vnic_getcapab_fn = NULL;
25845084Sjohnlev 	mip->mi_vnic_getcapab_arg = NULL;
25855084Sjohnlev 	rw_exit(&mip->mi_tx_lock);
25865084Sjohnlev 
25875084Sjohnlev 	i_mac_notify(mip, MAC_NOTE_VNIC);
25885084Sjohnlev 
25895084Sjohnlev 	/*
25905084Sjohnlev 	 * Wait for all TX calls referencing the VNIC transmit
25915084Sjohnlev 	 * entry point that was removed to complete.
25925084Sjohnlev 	 */
25935084Sjohnlev 	mutex_enter(&vnic_tx->mv_lock);
25945084Sjohnlev 	vnic_tx->mv_clearing = B_TRUE;
25955084Sjohnlev 	while (vnic_tx->mv_refs > 0)
25965084Sjohnlev 		cv_wait(&vnic_tx->mv_cv, &vnic_tx->mv_lock);
25975084Sjohnlev 	mutex_exit(&vnic_tx->mv_lock);
25985084Sjohnlev 	kmem_cache_free(mac_vnic_tx_cache, vnic_tx);
25995084Sjohnlev }
26005084Sjohnlev 
2601269Sericheng /*
2602269Sericheng  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
2603269Sericheng  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
2604269Sericheng  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
2605269Sericheng  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
2606269Sericheng  * cannot disappear while we are accessing it.
2607269Sericheng  */
2608269Sericheng typedef struct i_mac_info_state_s {
2609269Sericheng 	const char	*mi_name;
2610269Sericheng 	mac_info_t	*mi_infop;
2611269Sericheng } i_mac_info_state_t;
2612269Sericheng 
2613269Sericheng /*ARGSUSED*/
2614269Sericheng static uint_t
2615269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
2616269Sericheng {
2617269Sericheng 	i_mac_info_state_t	*statep = arg;
2618269Sericheng 	mac_impl_t		*mip = (mac_impl_t *)val;
2619269Sericheng 
26201852Syz147064 	if (mip->mi_disabled)
2621269Sericheng 		return (MH_WALK_CONTINUE);
2622269Sericheng 
2623269Sericheng 	if (strcmp(statep->mi_name,
26242311Sseb 	    ddi_driver_name(mip->mi_dip)) != 0)
2625269Sericheng 		return (MH_WALK_CONTINUE);
2626269Sericheng 
26272311Sseb 	statep->mi_infop = &mip->mi_info;
2628269Sericheng 	return (MH_WALK_TERMINATE);
2629269Sericheng }
2630269Sericheng 
2631269Sericheng boolean_t
2632269Sericheng mac_info_get(const char *name, mac_info_t *minfop)
2633269Sericheng {
2634269Sericheng 	i_mac_info_state_t	state;
2635269Sericheng 
2636269Sericheng 	rw_enter(&i_mac_impl_lock, RW_READER);
2637269Sericheng 	state.mi_name = name;
2638269Sericheng 	state.mi_infop = NULL;
2639269Sericheng 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
2640269Sericheng 	if (state.mi_infop == NULL) {
2641269Sericheng 		rw_exit(&i_mac_impl_lock);
2642269Sericheng 		return (B_FALSE);
2643269Sericheng 	}
2644269Sericheng 	*minfop = *state.mi_infop;
2645269Sericheng 	rw_exit(&i_mac_impl_lock);
2646269Sericheng 	return (B_TRUE);
2647269Sericheng }
2648269Sericheng 
26492311Sseb boolean_t
26505084Sjohnlev mac_do_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data,
26515084Sjohnlev     boolean_t is_vnic)
26522311Sseb {
26532311Sseb 	mac_impl_t *mip = (mac_impl_t *)mh;
26542311Sseb 
26555084Sjohnlev 	if (!is_vnic) {
26565084Sjohnlev 		rw_enter(&mip->mi_tx_lock, RW_READER);
26575084Sjohnlev 		if (mip->mi_vnic_present) {
26585084Sjohnlev 			boolean_t rv;
26595084Sjohnlev 
26605084Sjohnlev 			rv = mip->mi_vnic_getcapab_fn(mip->mi_vnic_getcapab_arg,
26615084Sjohnlev 			    cap, cap_data);
26625084Sjohnlev 			rw_exit(&mip->mi_tx_lock);
26635084Sjohnlev 			return (rv);
26645084Sjohnlev 		}
26655084Sjohnlev 		rw_exit(&mip->mi_tx_lock);
26665084Sjohnlev 	}
26675084Sjohnlev 
26682311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
26692311Sseb 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
26702311Sseb 	else
26712311Sseb 		return (B_FALSE);
26722311Sseb }
26732311Sseb 
26742311Sseb boolean_t
26755084Sjohnlev mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
26765084Sjohnlev {
26775084Sjohnlev 	return (mac_do_capab_get(mh, cap, cap_data, B_FALSE));
26785084Sjohnlev }
26795084Sjohnlev 
26805084Sjohnlev boolean_t
26815084Sjohnlev mac_vnic_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
26825084Sjohnlev {
26835084Sjohnlev 	return (mac_do_capab_get(mh, cap, cap_data, B_TRUE));
26845084Sjohnlev }
26855084Sjohnlev 
26865084Sjohnlev boolean_t
26872311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
26882311Sseb {
26892311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
26902311Sseb 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
26912311Sseb 	    mip->mi_pdata));
26922311Sseb }
26932311Sseb 
26942311Sseb mblk_t *
26952311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
26962311Sseb     size_t extra_len)
26972311Sseb {
26982311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
26992311Sseb 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
27002311Sseb 	    mip->mi_pdata, payload, extra_len));
27012311Sseb }
27022311Sseb 
27032311Sseb int
27042311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
27052311Sseb {
27062311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
27072311Sseb 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
27082311Sseb 	    mhip));
27092311Sseb }
27102311Sseb 
27112311Sseb mblk_t *
27122311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp)
27132311Sseb {
27142311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
27152311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
27162311Sseb 		if (DB_REF(mp) > 1) {
27172311Sseb 			mblk_t *newmp = copymsg(mp);
27182760Sdg199075 			if (newmp == NULL)
27192760Sdg199075 				return (NULL);
27202311Sseb 			freemsg(mp);
27212311Sseb 			mp = newmp;
27222311Sseb 		}
27232311Sseb 		return (mip->mi_type->mt_ops.mtops_header_cook(mp,
27242311Sseb 		    mip->mi_pdata));
27252311Sseb 	}
27262311Sseb 	return (mp);
27272311Sseb }
27282311Sseb 
27292311Sseb mblk_t *
27302311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp)
27312311Sseb {
27322311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
27332311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
27342311Sseb 		if (DB_REF(mp) > 1) {
27352311Sseb 			mblk_t *newmp = copymsg(mp);
27362760Sdg199075 			if (newmp == NULL)
27372760Sdg199075 				return (NULL);
27382311Sseb 			freemsg(mp);
27392311Sseb 			mp = newmp;
27402311Sseb 		}
27412311Sseb 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
27422311Sseb 		    mip->mi_pdata));
27432311Sseb 	}
27442311Sseb 	return (mp);
27452311Sseb }
27462311Sseb 
2747269Sericheng void
2748269Sericheng mac_init_ops(struct dev_ops *ops, const char *name)
2749269Sericheng {
2750269Sericheng 	dld_init_ops(ops, name);
2751269Sericheng }
2752269Sericheng 
2753269Sericheng void
2754269Sericheng mac_fini_ops(struct dev_ops *ops)
2755269Sericheng {
2756269Sericheng 	dld_fini_ops(ops);
2757269Sericheng }
27582311Sseb 
27592311Sseb /*
27602311Sseb  * MAC Type Plugin functions.
27612311Sseb  */
27622311Sseb 
27632311Sseb mactype_register_t *
27642311Sseb mactype_alloc(uint_t mactype_version)
27652311Sseb {
27662311Sseb 	mactype_register_t *mtrp;
27672311Sseb 
27682311Sseb 	/*
27692311Sseb 	 * Make sure there isn't a version mismatch between the plugin and
27702311Sseb 	 * the framework.  In the future, if multiple versions are
27712311Sseb 	 * supported, this check could become more sophisticated.
27722311Sseb 	 */
27732311Sseb 	if (mactype_version != MACTYPE_VERSION)
27742311Sseb 		return (NULL);
27752311Sseb 
27762311Sseb 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
27772311Sseb 	mtrp->mtr_version = mactype_version;
27782311Sseb 	return (mtrp);
27792311Sseb }
27802311Sseb 
27812311Sseb void
27822311Sseb mactype_free(mactype_register_t *mtrp)
27832311Sseb {
27842311Sseb 	kmem_free(mtrp, sizeof (mactype_register_t));
27852311Sseb }
27862311Sseb 
27872311Sseb int
27882311Sseb mactype_register(mactype_register_t *mtrp)
27892311Sseb {
27902311Sseb 	mactype_t	*mtp;
27912311Sseb 	mactype_ops_t	*ops = mtrp->mtr_ops;
27922311Sseb 
27932311Sseb 	/* Do some sanity checking before we register this MAC type. */
27946353Sdr146992 	if (mtrp->mtr_ident == NULL || ops == NULL)
27952311Sseb 		return (EINVAL);
27962311Sseb 
27972311Sseb 	/*
27982311Sseb 	 * Verify that all mandatory callbacks are set in the ops
27992311Sseb 	 * vector.
28002311Sseb 	 */
28012311Sseb 	if (ops->mtops_unicst_verify == NULL ||
28022311Sseb 	    ops->mtops_multicst_verify == NULL ||
28032311Sseb 	    ops->mtops_sap_verify == NULL ||
28042311Sseb 	    ops->mtops_header == NULL ||
28052311Sseb 	    ops->mtops_header_info == NULL) {
28062311Sseb 		return (EINVAL);
28072311Sseb 	}
28082311Sseb 
28092311Sseb 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
28102311Sseb 	mtp->mt_ident = mtrp->mtr_ident;
28112311Sseb 	mtp->mt_ops = *ops;
28122311Sseb 	mtp->mt_type = mtrp->mtr_mactype;
28133147Sxc151355 	mtp->mt_nativetype = mtrp->mtr_nativetype;
28142311Sseb 	mtp->mt_addr_length = mtrp->mtr_addrlen;
28152311Sseb 	if (mtrp->mtr_brdcst_addr != NULL) {
28162311Sseb 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
28172311Sseb 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
28182311Sseb 		    mtrp->mtr_addrlen);
28192311Sseb 	}
28202311Sseb 
28212311Sseb 	mtp->mt_stats = mtrp->mtr_stats;
28222311Sseb 	mtp->mt_statcount = mtrp->mtr_statcount;
28232311Sseb 
2824*6512Ssowmini 	mtp->mt_mapping = mtrp->mtr_mapping;
2825*6512Ssowmini 	mtp->mt_mappingcount = mtrp->mtr_mappingcount;
2826*6512Ssowmini 
28272311Sseb 	if (mod_hash_insert(i_mactype_hash,
28282311Sseb 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
28292311Sseb 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
28302311Sseb 		kmem_free(mtp, sizeof (*mtp));
28312311Sseb 		return (EEXIST);
28322311Sseb 	}
28332311Sseb 	return (0);
28342311Sseb }
28352311Sseb 
28362311Sseb int
28372311Sseb mactype_unregister(const char *ident)
28382311Sseb {
28392311Sseb 	mactype_t	*mtp;
28402311Sseb 	mod_hash_val_t	val;
28412311Sseb 	int 		err;
28422311Sseb 
28432311Sseb 	/*
28442311Sseb 	 * Let's not allow MAC drivers to use this plugin while we're
28453288Sseb 	 * trying to unregister it.  Holding i_mactype_lock also prevents a
28463288Sseb 	 * plugin from unregistering while a MAC driver is attempting to
28473288Sseb 	 * hold a reference to it in i_mactype_getplugin().
28482311Sseb 	 */
28493288Sseb 	mutex_enter(&i_mactype_lock);
28502311Sseb 
28512311Sseb 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
28522311Sseb 	    (mod_hash_val_t *)&mtp)) != 0) {
28532311Sseb 		/* A plugin is trying to unregister, but it never registered. */
28543288Sseb 		err = ENXIO;
28553288Sseb 		goto done;
28562311Sseb 	}
28572311Sseb 
28583288Sseb 	if (mtp->mt_ref != 0) {
28593288Sseb 		err = EBUSY;
28603288Sseb 		goto done;
28612311Sseb 	}
28622311Sseb 
28632311Sseb 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
28642311Sseb 	ASSERT(err == 0);
28652311Sseb 	if (err != 0) {
28662311Sseb 		/* This should never happen, thus the ASSERT() above. */
28673288Sseb 		err = EINVAL;
28683288Sseb 		goto done;
28692311Sseb 	}
28702311Sseb 	ASSERT(mtp == (mactype_t *)val);
28712311Sseb 
28722311Sseb 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
28732311Sseb 	kmem_free(mtp, sizeof (mactype_t));
28743288Sseb done:
28753288Sseb 	mutex_exit(&i_mactype_lock);
28763288Sseb 	return (err);
28772311Sseb }
28785903Ssowmini 
28795903Ssowmini int
28805903Ssowmini mac_set_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize)
28815903Ssowmini {
28825903Ssowmini 	int err = ENOTSUP;
28835903Ssowmini 	mac_impl_t *mip = (mac_impl_t *)mh;
28845903Ssowmini 
28855903Ssowmini 	if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) {
28865903Ssowmini 		err = mip->mi_callbacks->mc_setprop(mip->mi_driver,
28875903Ssowmini 		    macprop->mp_name, macprop->mp_id, valsize, val);
28885903Ssowmini 	}
28895903Ssowmini 	return (err);
28905903Ssowmini }
28915903Ssowmini 
28925903Ssowmini int
28935903Ssowmini mac_get_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize)
28945903Ssowmini {
28955903Ssowmini 	int err = ENOTSUP;
28965903Ssowmini 	mac_impl_t *mip = (mac_impl_t *)mh;
2897*6512Ssowmini 	uint32_t sdu;
2898*6512Ssowmini 	link_state_t link_state;
2899*6512Ssowmini 
2900*6512Ssowmini 	switch (macprop->mp_id) {
2901*6512Ssowmini 	case DLD_PROP_MTU:
2902*6512Ssowmini 		if (valsize < sizeof (sdu))
2903*6512Ssowmini 			return (EINVAL);
2904*6512Ssowmini 		if ((macprop->mp_flags & DLD_DEFAULT) == 0) {
2905*6512Ssowmini 			mac_sdu_get(mh, NULL, &sdu);
2906*6512Ssowmini 			bcopy(&sdu, val, sizeof (sdu));
2907*6512Ssowmini 			return (0);
2908*6512Ssowmini 		} else {
2909*6512Ssowmini 			if (mip->mi_info.mi_media == DL_ETHER) {
2910*6512Ssowmini 				sdu = ETHERMTU;
2911*6512Ssowmini 				bcopy(&sdu, val, sizeof (sdu));
2912*6512Ssowmini 				return (0);
2913*6512Ssowmini 			}
2914*6512Ssowmini 			/*
2915*6512Ssowmini 			 * ask driver for its default.
2916*6512Ssowmini 			 */
2917*6512Ssowmini 			break;
2918*6512Ssowmini 		}
2919*6512Ssowmini 	case DLD_PROP_STATUS:
2920*6512Ssowmini 		if (valsize < sizeof (link_state))
2921*6512Ssowmini 			return (EINVAL);
2922*6512Ssowmini 		link_state = mac_link_get(mh);
2923*6512Ssowmini 		bcopy(&link_state, val, sizeof (link_state));
2924*6512Ssowmini 		return (0);
2925*6512Ssowmini 	default:
2926*6512Ssowmini 		break;
2927*6512Ssowmini 	}
29285903Ssowmini 	if (mip->mi_callbacks->mc_callbacks & MC_GETPROP) {
29295903Ssowmini 		err = mip->mi_callbacks->mc_getprop(mip->mi_driver,
2930*6512Ssowmini 		    macprop->mp_name, macprop->mp_id, macprop->mp_flags,
2931*6512Ssowmini 		    valsize, val);
29325903Ssowmini 	}
29335903Ssowmini 	return (err);
29345903Ssowmini }
29355903Ssowmini 
29365903Ssowmini int
29375903Ssowmini mac_maxsdu_update(mac_handle_t mh, uint_t sdu_max)
29385903Ssowmini {
29395903Ssowmini 	mac_impl_t	*mip = (mac_impl_t *)mh;
29405903Ssowmini 
29415903Ssowmini 	if (sdu_max <= mip->mi_sdu_min)
29425903Ssowmini 		return (EINVAL);
29435903Ssowmini 	mip->mi_sdu_max = sdu_max;
29445903Ssowmini 
29455903Ssowmini 	/* Send a MAC_NOTE_SDU_SIZE notification. */
29465903Ssowmini 	i_mac_notify(mip, MAC_NOTE_SDU_SIZE);
29475903Ssowmini 	return (0);
29485903Ssowmini }
2949*6512Ssowmini 
2950*6512Ssowmini static void
2951*6512Ssowmini mac_register_priv_prop(mac_impl_t *mip, mac_priv_prop_t *mpp, uint_t nprop)
2952*6512Ssowmini {
2953*6512Ssowmini 	mac_priv_prop_t *mpriv;
2954*6512Ssowmini 
2955*6512Ssowmini 	if (mpp == NULL)
2956*6512Ssowmini 		return;
2957*6512Ssowmini 
2958*6512Ssowmini 	mpriv = kmem_zalloc(nprop * sizeof (*mpriv), KM_SLEEP);
2959*6512Ssowmini 	(void) memcpy(mpriv, mpp, nprop * sizeof (*mpriv));
2960*6512Ssowmini 	mip->mi_priv_prop = mpriv;
2961*6512Ssowmini 	mip->mi_priv_prop_count = nprop;
2962*6512Ssowmini }
2963