xref: /onnv-gate/usr/src/uts/common/io/mac/mac.c (revision 4403:77da60925cac)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51852Syz147064  * Common Development and Distribution License (the "License").
61852Syz147064  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223448Sdh155122  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * MAC Services Module
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/conf.h>
340Sstevel@tonic-gate #include <sys/stat.h>
350Sstevel@tonic-gate #include <sys/stream.h>
360Sstevel@tonic-gate #include <sys/strsun.h>
370Sstevel@tonic-gate #include <sys/strsubr.h>
380Sstevel@tonic-gate #include <sys/dlpi.h>
39269Sericheng #include <sys/modhash.h>
400Sstevel@tonic-gate #include <sys/mac.h>
410Sstevel@tonic-gate #include <sys/mac_impl.h>
42269Sericheng #include <sys/dls.h>
43269Sericheng #include <sys/dld.h>
442311Sseb #include <sys/modctl.h>
453448Sdh155122 #include <sys/fs/dv_node.h>
463288Sseb #include <sys/atomic.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	IMPL_HASHSZ	67	/* prime */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static kmem_cache_t	*i_mac_impl_cachep;
51269Sericheng static mod_hash_t	*i_mac_impl_hash;
52269Sericheng krwlock_t		i_mac_impl_lock;
53269Sericheng uint_t			i_mac_impl_count;
540Sstevel@tonic-gate 
552311Sseb #define	MACTYPE_KMODDIR	"mac"
562311Sseb #define	MACTYPE_HASHSZ	67
572311Sseb static mod_hash_t	*i_mactype_hash;
583288Sseb /*
593288Sseb  * i_mactype_lock synchronizes threads that obtain references to mactype_t
603288Sseb  * structures through i_mactype_getplugin().
613288Sseb  */
623288Sseb static kmutex_t		i_mactype_lock;
632311Sseb 
641852Syz147064 static void i_mac_notify_task(void *);
651852Syz147064 
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate  * Private functions.
680Sstevel@tonic-gate  */
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*ARGSUSED*/
710Sstevel@tonic-gate static int
720Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	bzero(buf, sizeof (mac_impl_t));
770Sstevel@tonic-gate 
782311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
810Sstevel@tonic-gate 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
820Sstevel@tonic-gate 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
830Sstevel@tonic-gate 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
840Sstevel@tonic-gate 	rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL);
850Sstevel@tonic-gate 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
860Sstevel@tonic-gate 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
871852Syz147064 	mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL);
881852Syz147064 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL);
890Sstevel@tonic-gate 	return (0);
900Sstevel@tonic-gate }
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*ARGSUSED*/
930Sstevel@tonic-gate static void
940Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg)
950Sstevel@tonic-gate {
960Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	ASSERT(mip->mi_ref == 0);
990Sstevel@tonic-gate 	ASSERT(mip->mi_active == 0);
1002311Sseb 	ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
1010Sstevel@tonic-gate 	ASSERT(mip->mi_devpromisc == 0);
1020Sstevel@tonic-gate 	ASSERT(mip->mi_promisc == 0);
1030Sstevel@tonic-gate 	ASSERT(mip->mi_mmap == NULL);
1040Sstevel@tonic-gate 	ASSERT(mip->mi_mnfp == NULL);
1050Sstevel@tonic-gate 	ASSERT(mip->mi_resource_add == NULL);
1060Sstevel@tonic-gate 	ASSERT(mip->mi_ksp == NULL);
1072311Sseb 	ASSERT(mip->mi_kstat_count == 0);
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	rw_destroy(&mip->mi_state_lock);
1100Sstevel@tonic-gate 	rw_destroy(&mip->mi_data_lock);
1110Sstevel@tonic-gate 	rw_destroy(&mip->mi_notify_lock);
1120Sstevel@tonic-gate 	rw_destroy(&mip->mi_rx_lock);
1130Sstevel@tonic-gate 	rw_destroy(&mip->mi_txloop_lock);
1140Sstevel@tonic-gate 	rw_destroy(&mip->mi_resource_lock);
1150Sstevel@tonic-gate 	mutex_destroy(&mip->mi_activelink_lock);
1161852Syz147064 	mutex_destroy(&mip->mi_notify_ref_lock);
1171852Syz147064 	cv_destroy(&mip->mi_notify_cv);
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static void
1210Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
1220Sstevel@tonic-gate {
1231852Syz147064 	mac_notify_task_arg_t	*mnta;
1241852Syz147064 
1251852Syz147064 	rw_enter(&i_mac_impl_lock, RW_READER);
1261852Syz147064 	if (mip->mi_disabled)
1271852Syz147064 		goto exit;
1281852Syz147064 
1291852Syz147064 	if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) {
1301852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory "
1311852Syz147064 		    "allocation failed", mip->mi_name, type);
1321852Syz147064 		goto exit;
1331852Syz147064 	}
1341852Syz147064 
1351852Syz147064 	mnta->mnt_mip = mip;
1361852Syz147064 	mnta->mnt_type = type;
1371852Syz147064 
1381852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
1391852Syz147064 	mip->mi_notify_ref++;
1401852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
1411852Syz147064 
1421852Syz147064 	rw_exit(&i_mac_impl_lock);
1431852Syz147064 
1441852Syz147064 	if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta,
1451852Syz147064 	    TQ_NOSLEEP) == NULL) {
1461852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch "
1471852Syz147064 		    "failed", mip->mi_name, type);
1481852Syz147064 
1491852Syz147064 		mutex_enter(&mip->mi_notify_ref_lock);
1501852Syz147064 		if (--mip->mi_notify_ref == 0)
1511852Syz147064 			cv_signal(&mip->mi_notify_cv);
1521852Syz147064 		mutex_exit(&mip->mi_notify_ref_lock);
1531852Syz147064 
1541852Syz147064 		kmem_free(mnta, sizeof (*mnta));
1551852Syz147064 	}
1561852Syz147064 	return;
1571852Syz147064 
1581852Syz147064 exit:
1591852Syz147064 	rw_exit(&i_mac_impl_lock);
1601852Syz147064 }
1611852Syz147064 
1621852Syz147064 static void
163*4403Sgd78059 i_mac_log_link_state(mac_impl_t *mip)
164*4403Sgd78059 {
165*4403Sgd78059 	/*
166*4403Sgd78059 	 * If no change, then it is not interesting.
167*4403Sgd78059 	 */
168*4403Sgd78059 	if (mip->mi_lastlinkstate == mip->mi_linkstate)
169*4403Sgd78059 		return;
170*4403Sgd78059 
171*4403Sgd78059 	switch (mip->mi_linkstate) {
172*4403Sgd78059 	case LINK_STATE_UP:
173*4403Sgd78059 		if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) {
174*4403Sgd78059 			char det[200];
175*4403Sgd78059 
176*4403Sgd78059 			mip->mi_type->mt_ops.mtops_link_details(det,
177*4403Sgd78059 			    sizeof (det), (mac_handle_t)mip, mip->mi_pdata);
178*4403Sgd78059 
179*4403Sgd78059 			cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det);
180*4403Sgd78059 		} else {
181*4403Sgd78059 			cmn_err(CE_NOTE, "!%s link up", mip->mi_name);
182*4403Sgd78059 		}
183*4403Sgd78059 		break;
184*4403Sgd78059 
185*4403Sgd78059 	case LINK_STATE_DOWN:
186*4403Sgd78059 		/*
187*4403Sgd78059 		 * Only transitions from UP to DOWN are interesting
188*4403Sgd78059 		 */
189*4403Sgd78059 		if (mip->mi_lastlinkstate != LINK_STATE_UNKNOWN)
190*4403Sgd78059 			cmn_err(CE_NOTE, "!%s link down", mip->mi_name);
191*4403Sgd78059 		break;
192*4403Sgd78059 
193*4403Sgd78059 	case LINK_STATE_UNKNOWN:
194*4403Sgd78059 		/*
195*4403Sgd78059 		 * This case is normally not interesting.
196*4403Sgd78059 		 */
197*4403Sgd78059 		break;
198*4403Sgd78059 	}
199*4403Sgd78059 	mip->mi_lastlinkstate = mip->mi_linkstate;
200*4403Sgd78059 }
201*4403Sgd78059 
202*4403Sgd78059 static void
2031852Syz147064 i_mac_notify_task(void *notify_arg)
2041852Syz147064 {
2051852Syz147064 	mac_notify_task_arg_t	*mnta = (mac_notify_task_arg_t *)notify_arg;
2061852Syz147064 	mac_impl_t		*mip;
2071852Syz147064 	mac_notify_type_t	type;
2080Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
2090Sstevel@tonic-gate 	mac_notify_t		notify;
2100Sstevel@tonic-gate 	void			*arg;
2110Sstevel@tonic-gate 
2121852Syz147064 	mip = mnta->mnt_mip;
2131852Syz147064 	type = mnta->mnt_type;
2141852Syz147064 	kmem_free(mnta, sizeof (*mnta));
2151852Syz147064 
2160Sstevel@tonic-gate 	/*
217*4403Sgd78059 	 * Log it.
218*4403Sgd78059 	 */
219*4403Sgd78059 	if (type == MAC_NOTE_LINK)
220*4403Sgd78059 		i_mac_log_link_state(mip);
221*4403Sgd78059 
222*4403Sgd78059 	/*
2230Sstevel@tonic-gate 	 * Walk the list of notifications.
2240Sstevel@tonic-gate 	 */
2251852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_READER);
2260Sstevel@tonic-gate 	for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) {
2270Sstevel@tonic-gate 		notify = mnfp->mnf_fn;
2280Sstevel@tonic-gate 		arg = mnfp->mnf_arg;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 		ASSERT(notify != NULL);
2310Sstevel@tonic-gate 		notify(arg, type);
2320Sstevel@tonic-gate 	}
2331852Syz147064 	rw_exit(&mip->mi_notify_lock);
2341852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
2351852Syz147064 	if (--mip->mi_notify_ref == 0)
2361852Syz147064 		cv_signal(&mip->mi_notify_cv);
2371852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2402311Sseb static mactype_t *
2413288Sseb i_mactype_getplugin(const char *pname)
2422311Sseb {
2432311Sseb 	mactype_t	*mtype = NULL;
2442311Sseb 	boolean_t	tried_modload = B_FALSE;
2452311Sseb 
2463288Sseb 	mutex_enter(&i_mactype_lock);
2473288Sseb 
2482311Sseb find_registered_mactype:
2493288Sseb 	if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname,
2503288Sseb 	    (mod_hash_val_t *)&mtype) != 0) {
2513288Sseb 		if (!tried_modload) {
2523288Sseb 			/*
2533288Sseb 			 * If the plugin has not yet been loaded, then
2543288Sseb 			 * attempt to load it now.  If modload() succeeds,
2553288Sseb 			 * the plugin should have registered using
2563288Sseb 			 * mactype_register(), in which case we can go back
2573288Sseb 			 * and attempt to find it again.
2583288Sseb 			 */
2593288Sseb 			if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) {
2603288Sseb 				tried_modload = B_TRUE;
2613288Sseb 				goto find_registered_mactype;
2623288Sseb 			}
2633288Sseb 		}
2643288Sseb 	} else {
2652311Sseb 		/*
2663288Sseb 		 * Note that there's no danger that the plugin we've loaded
2673288Sseb 		 * could be unloaded between the modload() step and the
2683288Sseb 		 * reference count bump here, as we're holding
2693288Sseb 		 * i_mactype_lock, which mactype_unregister() also holds.
2702311Sseb 		 */
2713288Sseb 		atomic_inc_32(&mtype->mt_ref);
2722311Sseb 	}
2732311Sseb 
2743288Sseb 	mutex_exit(&i_mactype_lock);
2753288Sseb 	return (mtype);
2762311Sseb }
2772311Sseb 
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate  * Module initialization functions.
2800Sstevel@tonic-gate  */
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate void
2830Sstevel@tonic-gate mac_init(void)
2840Sstevel@tonic-gate {
2850Sstevel@tonic-gate 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
2862311Sseb 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
2872311Sseb 	    NULL, NULL, NULL, 0);
2880Sstevel@tonic-gate 	ASSERT(i_mac_impl_cachep != NULL);
2890Sstevel@tonic-gate 
290269Sericheng 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
291269Sericheng 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
292269Sericheng 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
293269Sericheng 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
294269Sericheng 	i_mac_impl_count = 0;
2952311Sseb 
2962311Sseb 	i_mactype_hash = mod_hash_create_extended("mactype_hash",
2972311Sseb 	    MACTYPE_HASHSZ,
2982311Sseb 	    mod_hash_null_keydtor, mod_hash_null_valdtor,
2992311Sseb 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate int
3030Sstevel@tonic-gate mac_fini(void)
3040Sstevel@tonic-gate {
305269Sericheng 	if (i_mac_impl_count > 0)
306269Sericheng 		return (EBUSY);
3070Sstevel@tonic-gate 
308269Sericheng 	mod_hash_destroy_hash(i_mac_impl_hash);
309269Sericheng 	rw_destroy(&i_mac_impl_lock);
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	kmem_cache_destroy(i_mac_impl_cachep);
3122311Sseb 
3132311Sseb 	mod_hash_destroy_hash(i_mactype_hash);
3140Sstevel@tonic-gate 	return (0);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate /*
3180Sstevel@tonic-gate  * Client functions.
3190Sstevel@tonic-gate  */
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate int
3222311Sseb mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	char		driver[MAXNAMELEN];
3250Sstevel@tonic-gate 	uint_t		instance;
3260Sstevel@tonic-gate 	major_t		major;
3270Sstevel@tonic-gate 	dev_info_t	*dip;
3280Sstevel@tonic-gate 	mac_impl_t	*mip;
3290Sstevel@tonic-gate 	int		err;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	/*
3320Sstevel@tonic-gate 	 * Check the device name length to make sure it won't overflow our
3330Sstevel@tonic-gate 	 * buffer.
3340Sstevel@tonic-gate 	 */
3352311Sseb 	if (strlen(macname) >= MAXNAMELEN)
3360Sstevel@tonic-gate 		return (EINVAL);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	/*
3390Sstevel@tonic-gate 	 * Split the device name into driver and instance components.
3400Sstevel@tonic-gate 	 */
3412311Sseb 	if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS)
3420Sstevel@tonic-gate 		return (EINVAL);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/*
3450Sstevel@tonic-gate 	 * Get the major number of the driver.
3460Sstevel@tonic-gate 	 */
3470Sstevel@tonic-gate 	if ((major = ddi_name_to_major(driver)) == (major_t)-1)
3480Sstevel@tonic-gate 		return (EINVAL);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	/*
3510Sstevel@tonic-gate 	 * Hold the given instance to prevent it from being detached.
352269Sericheng 	 * This will also attach the instance if it is not currently attached.
353269Sericheng 	 * Currently we ensure that mac_register() (called by the driver's
354269Sericheng 	 * attach entry point) and all code paths under it cannot possibly
355269Sericheng 	 * call mac_open() because this would lead to a recursive attach
356269Sericheng 	 * panic.
3570Sstevel@tonic-gate 	 */
3582311Sseb 	if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL)
3590Sstevel@tonic-gate 		return (EINVAL);
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	/*
3620Sstevel@tonic-gate 	 * Look up its entry in the global hash table.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate again:
365269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
3662311Sseb 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
367269Sericheng 	    (mod_hash_val_t *)&mip);
368269Sericheng 	if (err != 0) {
369269Sericheng 		err = ENOENT;
3700Sstevel@tonic-gate 		goto failed;
371269Sericheng 	}
3720Sstevel@tonic-gate 
3731852Syz147064 	if (mip->mi_disabled) {
374269Sericheng 		rw_exit(&i_mac_impl_lock);
3750Sstevel@tonic-gate 		goto again;
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	mip->mi_ref++;
379269Sericheng 	rw_exit(&i_mac_impl_lock);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	*mhp = (mac_handle_t)mip;
3820Sstevel@tonic-gate 	return (0);
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate failed:
385269Sericheng 	rw_exit(&i_mac_impl_lock);
3860Sstevel@tonic-gate 	ddi_release_devi(dip);
3870Sstevel@tonic-gate 	return (err);
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate void
3910Sstevel@tonic-gate mac_close(mac_handle_t mh)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
3942311Sseb 	dev_info_t	*dip = mip->mi_dip;
3950Sstevel@tonic-gate 
396269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	ASSERT(mip->mi_ref != 0);
3990Sstevel@tonic-gate 	if (--mip->mi_ref == 0) {
4000Sstevel@tonic-gate 		ASSERT(!mip->mi_activelink);
4010Sstevel@tonic-gate 	}
4020Sstevel@tonic-gate 	ddi_release_devi(dip);
403269Sericheng 	rw_exit(&i_mac_impl_lock);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate const mac_info_t *
4070Sstevel@tonic-gate mac_info(mac_handle_t mh)
4080Sstevel@tonic-gate {
4092311Sseb 	return (&((mac_impl_t *)mh)->mi_info);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate 
412269Sericheng dev_info_t *
413269Sericheng mac_devinfo_get(mac_handle_t mh)
414269Sericheng {
4152311Sseb 	return (((mac_impl_t *)mh)->mi_dip);
416269Sericheng }
417269Sericheng 
4180Sstevel@tonic-gate uint64_t
4192311Sseb mac_stat_get(mac_handle_t mh, uint_t stat)
4200Sstevel@tonic-gate {
4210Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4222311Sseb 	uint64_t	val;
4232311Sseb 	int		ret;
4240Sstevel@tonic-gate 
4252311Sseb 	/*
4262311Sseb 	 * The range of stat determines where it is maintained.  Stat
4272311Sseb 	 * values from 0 up to (but not including) MAC_STAT_MIN are
4282311Sseb 	 * mainteined by the mac module itself.  Everything else is
4292311Sseb 	 * maintained by the driver.
4302311Sseb 	 */
4312311Sseb 	if (stat < MAC_STAT_MIN) {
4322311Sseb 		/* These stats are maintained by the mac module itself. */
4332311Sseb 		switch (stat) {
4342311Sseb 		case MAC_STAT_LINK_STATE:
4352311Sseb 			return (mip->mi_linkstate);
4362311Sseb 		case MAC_STAT_LINK_UP:
4372311Sseb 			return (mip->mi_linkstate == LINK_STATE_UP);
4382311Sseb 		case MAC_STAT_PROMISC:
4392311Sseb 			return (mip->mi_devpromisc != 0);
4402311Sseb 		default:
4412311Sseb 			ASSERT(B_FALSE);
4422311Sseb 		}
4432311Sseb 	}
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	/*
4460Sstevel@tonic-gate 	 * Call the driver to get the given statistic.
4470Sstevel@tonic-gate 	 */
4482311Sseb 	ret = mip->mi_getstat(mip->mi_driver, stat, &val);
4492311Sseb 	if (ret != 0) {
4502311Sseb 		/*
4512311Sseb 		 * The driver doesn't support this statistic.  Get the
4522311Sseb 		 * statistic's default value.
4532311Sseb 		 */
4542311Sseb 		val = mac_stat_default(mip, stat);
4552311Sseb 	}
4562311Sseb 	return (val);
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate int
4600Sstevel@tonic-gate mac_start(mac_handle_t mh)
4610Sstevel@tonic-gate {
4620Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4630Sstevel@tonic-gate 	int		err;
4640Sstevel@tonic-gate 
4652311Sseb 	ASSERT(mip->mi_start != NULL);
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	/*
4700Sstevel@tonic-gate 	 * Check whether the device is already started.
4710Sstevel@tonic-gate 	 */
4720Sstevel@tonic-gate 	if (mip->mi_active++ != 0) {
4730Sstevel@tonic-gate 		/*
4740Sstevel@tonic-gate 		 * It's already started so there's nothing more to do.
4750Sstevel@tonic-gate 		 */
4760Sstevel@tonic-gate 		err = 0;
4770Sstevel@tonic-gate 		goto done;
4780Sstevel@tonic-gate 	}
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	/*
4810Sstevel@tonic-gate 	 * Start the device.
4820Sstevel@tonic-gate 	 */
4832311Sseb 	if ((err = mip->mi_start(mip->mi_driver)) != 0)
4840Sstevel@tonic-gate 		--mip->mi_active;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate done:
4870Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
4880Sstevel@tonic-gate 	return (err);
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate void
4920Sstevel@tonic-gate mac_stop(mac_handle_t mh)
4930Sstevel@tonic-gate {
4940Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4950Sstevel@tonic-gate 
4962311Sseb 	ASSERT(mip->mi_stop != NULL);
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	/*
5010Sstevel@tonic-gate 	 * Check whether the device is still needed.
5020Sstevel@tonic-gate 	 */
5030Sstevel@tonic-gate 	ASSERT(mip->mi_active != 0);
5040Sstevel@tonic-gate 	if (--mip->mi_active != 0) {
5050Sstevel@tonic-gate 		/*
5060Sstevel@tonic-gate 		 * It's still needed so there's nothing more to do.
5070Sstevel@tonic-gate 		 */
5080Sstevel@tonic-gate 		goto done;
5090Sstevel@tonic-gate 	}
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	/*
5120Sstevel@tonic-gate 	 * Stop the device.
5130Sstevel@tonic-gate 	 */
5142311Sseb 	mip->mi_stop(mip->mi_driver);
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate done:
5170Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate int
5210Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
5240Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
5250Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
5260Sstevel@tonic-gate 	int			err;
5270Sstevel@tonic-gate 
5282311Sseb 	ASSERT(mip->mi_multicst != NULL);
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	/*
5310Sstevel@tonic-gate 	 * Verify the address.
5320Sstevel@tonic-gate 	 */
5332311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
5342311Sseb 	    mip->mi_pdata)) != 0) {
5352311Sseb 		return (err);
5362311Sseb 	}
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	/*
5390Sstevel@tonic-gate 	 * Check whether the given address is already enabled.
5400Sstevel@tonic-gate 	 */
5410Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
5420Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
5432311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
5442311Sseb 		    0) {
5450Sstevel@tonic-gate 			/*
5460Sstevel@tonic-gate 			 * The address is already enabled so just bump the
5470Sstevel@tonic-gate 			 * reference count.
5480Sstevel@tonic-gate 			 */
5490Sstevel@tonic-gate 			p->mma_ref++;
5500Sstevel@tonic-gate 			err = 0;
5510Sstevel@tonic-gate 			goto done;
5520Sstevel@tonic-gate 		}
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	/*
5560Sstevel@tonic-gate 	 * Allocate a new list entry.
5570Sstevel@tonic-gate 	 */
5580Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
5590Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
5600Sstevel@tonic-gate 		err = ENOMEM;
5610Sstevel@tonic-gate 		goto done;
5620Sstevel@tonic-gate 	}
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	/*
5650Sstevel@tonic-gate 	 * Enable a new multicast address.
5660Sstevel@tonic-gate 	 */
5672311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) {
5680Sstevel@tonic-gate 		kmem_free(p, sizeof (mac_multicst_addr_t));
5690Sstevel@tonic-gate 		goto done;
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	/*
5730Sstevel@tonic-gate 	 * Add the address to the list of enabled addresses.
5740Sstevel@tonic-gate 	 */
5752311Sseb 	bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length);
5760Sstevel@tonic-gate 	p->mma_ref++;
5770Sstevel@tonic-gate 	*pp = p;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate done:
5800Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
5810Sstevel@tonic-gate 	return (err);
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate int
5850Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
5860Sstevel@tonic-gate {
5870Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
5880Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
5890Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
5900Sstevel@tonic-gate 	int			err;
5910Sstevel@tonic-gate 
5922311Sseb 	ASSERT(mip->mi_multicst != NULL);
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	/*
5950Sstevel@tonic-gate 	 * Find the entry in the list for the given address.
5960Sstevel@tonic-gate 	 */
5970Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
5980Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
5992311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
6002311Sseb 		    0) {
6010Sstevel@tonic-gate 			if (--p->mma_ref == 0)
6020Sstevel@tonic-gate 				break;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 			/*
6050Sstevel@tonic-gate 			 * There is still a reference to this address so
6060Sstevel@tonic-gate 			 * there's nothing more to do.
6070Sstevel@tonic-gate 			 */
6080Sstevel@tonic-gate 			err = 0;
6090Sstevel@tonic-gate 			goto done;
6100Sstevel@tonic-gate 		}
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	/*
6140Sstevel@tonic-gate 	 * We did not find an entry for the given address so it is not
6150Sstevel@tonic-gate 	 * currently enabled.
6160Sstevel@tonic-gate 	 */
6170Sstevel@tonic-gate 	if (p == NULL) {
6180Sstevel@tonic-gate 		err = ENOENT;
6190Sstevel@tonic-gate 		goto done;
6200Sstevel@tonic-gate 	}
6210Sstevel@tonic-gate 	ASSERT(p->mma_ref == 0);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	/*
6240Sstevel@tonic-gate 	 * Disable the multicast address.
6250Sstevel@tonic-gate 	 */
6262311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) {
6270Sstevel@tonic-gate 		p->mma_ref++;
6280Sstevel@tonic-gate 		goto done;
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	/*
6320Sstevel@tonic-gate 	 * Remove it from the list.
6330Sstevel@tonic-gate 	 */
6340Sstevel@tonic-gate 	*pp = p->mma_nextp;
6350Sstevel@tonic-gate 	kmem_free(p, sizeof (mac_multicst_addr_t));
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate done:
6380Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
6390Sstevel@tonic-gate 	return (err);
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate 
6422331Skrgopi /*
6432331Skrgopi  * mac_unicst_verify: Verifies the passed address. It fails
6442331Skrgopi  * if the passed address is a group address or has incorrect length.
6452331Skrgopi  */
6462331Skrgopi boolean_t
6472331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len)
6482331Skrgopi {
6492331Skrgopi 	mac_impl_t	*mip = (mac_impl_t *)mh;
6502331Skrgopi 
6512331Skrgopi 	/*
6522331Skrgopi 	 * Verify the address.
6532331Skrgopi 	 */
6542331Skrgopi 	if ((len != mip->mi_type->mt_addr_length) ||
6552331Skrgopi 	    (mip->mi_type->mt_ops.mtops_unicst_verify(addr,
6562331Skrgopi 	    mip->mi_pdata)) != 0) {
6572331Skrgopi 		return (B_FALSE);
6582331Skrgopi 	} else {
6592331Skrgopi 		return (B_TRUE);
6602331Skrgopi 	}
6612331Skrgopi }
6622331Skrgopi 
6630Sstevel@tonic-gate int
6640Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
6650Sstevel@tonic-gate {
6660Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6670Sstevel@tonic-gate 	int		err;
6680Sstevel@tonic-gate 	boolean_t	notify = B_FALSE;
6690Sstevel@tonic-gate 
6702311Sseb 	ASSERT(mip->mi_unicst != NULL);
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	/*
6730Sstevel@tonic-gate 	 * Verify the address.
6740Sstevel@tonic-gate 	 */
6752311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr,
6762311Sseb 	    mip->mi_pdata)) != 0) {
6772311Sseb 		return (err);
6782311Sseb 	}
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	/*
6810Sstevel@tonic-gate 	 * Program the new unicast address.
6820Sstevel@tonic-gate 	 */
6830Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	/*
6860Sstevel@tonic-gate 	 * If address doesn't change, do nothing.
6870Sstevel@tonic-gate 	 * This check is necessary otherwise it may call into mac_unicst_set
6880Sstevel@tonic-gate 	 * recursively.
6890Sstevel@tonic-gate 	 */
6902311Sseb 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) {
6910Sstevel@tonic-gate 		err = 0;
6920Sstevel@tonic-gate 		goto done;
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6952311Sseb 	if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0)
6960Sstevel@tonic-gate 		goto done;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	/*
6990Sstevel@tonic-gate 	 * Save the address and flag that we need to send a notification.
7000Sstevel@tonic-gate 	 */
7012311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
7020Sstevel@tonic-gate 	notify = B_TRUE;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate done:
7050Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	if (notify)
7080Sstevel@tonic-gate 		i_mac_notify(mip, MAC_NOTE_UNICST);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	return (err);
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate void
7140Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr)
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	/*
7192311Sseb 	 * Copy out the current unicast source address.
7200Sstevel@tonic-gate 	 */
7210Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
7222311Sseb 	bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
7232311Sseb 	rw_exit(&(mip->mi_data_lock));
7242311Sseb }
7252311Sseb 
7262311Sseb void
7272311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr)
7282311Sseb {
7292311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
7302311Sseb 
7312311Sseb 	/*
7322311Sseb 	 * Copy out the current destination address.
7332311Sseb 	 */
7342311Sseb 	rw_enter(&(mip->mi_data_lock), RW_READER);
7352311Sseb 	bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
7360Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate int
7400Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
7410Sstevel@tonic-gate {
7420Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7430Sstevel@tonic-gate 	int		err = 0;
7440Sstevel@tonic-gate 
7452311Sseb 	ASSERT(mip->mi_setpromisc != NULL);
7460Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	/*
7490Sstevel@tonic-gate 	 * Determine whether we should enable or disable promiscuous mode.
7500Sstevel@tonic-gate 	 * For details on the distinction between "device promiscuous mode"
7510Sstevel@tonic-gate 	 * and "MAC promiscuous mode", see PSARC/2005/289.
7520Sstevel@tonic-gate 	 */
7530Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
7540Sstevel@tonic-gate 	if (on) {
7550Sstevel@tonic-gate 		/*
7560Sstevel@tonic-gate 		 * Enable promiscuous mode on the device if not yet enabled.
7570Sstevel@tonic-gate 		 */
7580Sstevel@tonic-gate 		if (mip->mi_devpromisc++ == 0) {
7592311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
7602311Sseb 			if (err != 0) {
7610Sstevel@tonic-gate 				mip->mi_devpromisc--;
7620Sstevel@tonic-gate 				goto done;
7630Sstevel@tonic-gate 			}
7640Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
7650Sstevel@tonic-gate 		}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 		/*
7680Sstevel@tonic-gate 		 * Enable promiscuous mode on the MAC if not yet enabled.
7690Sstevel@tonic-gate 		 */
7700Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
7710Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
7720Sstevel@tonic-gate 	} else {
7730Sstevel@tonic-gate 		if (mip->mi_devpromisc == 0) {
7740Sstevel@tonic-gate 			err = EPROTO;
7750Sstevel@tonic-gate 			goto done;
7760Sstevel@tonic-gate 		}
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 		/*
7790Sstevel@tonic-gate 		 * Disable promiscuous mode on the device if this is the last
7800Sstevel@tonic-gate 		 * enabling.
7810Sstevel@tonic-gate 		 */
7820Sstevel@tonic-gate 		if (--mip->mi_devpromisc == 0) {
7832311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
7842311Sseb 			if (err != 0) {
7850Sstevel@tonic-gate 				mip->mi_devpromisc++;
7860Sstevel@tonic-gate 				goto done;
7870Sstevel@tonic-gate 			}
7880Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 		/*
7920Sstevel@tonic-gate 		 * Disable promiscuous mode on the MAC if this is the last
7930Sstevel@tonic-gate 		 * enabling.
7940Sstevel@tonic-gate 		 */
7950Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
7960Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
7970Sstevel@tonic-gate 	}
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate done:
8000Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
8010Sstevel@tonic-gate 	return (err);
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate boolean_t
8050Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	/*
8120Sstevel@tonic-gate 	 * Return the current promiscuity.
8130Sstevel@tonic-gate 	 */
8140Sstevel@tonic-gate 	if (ptype == MAC_DEVPROMISC)
8150Sstevel@tonic-gate 		return (mip->mi_devpromisc != 0);
8160Sstevel@tonic-gate 	else
8170Sstevel@tonic-gate 		return (mip->mi_promisc != 0);
8180Sstevel@tonic-gate }
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate void
8210Sstevel@tonic-gate mac_resources(mac_handle_t mh)
8220Sstevel@tonic-gate {
8230Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	/*
8262311Sseb 	 * If the driver supports resource registration, call the driver to
8272311Sseb 	 * ask it to register its resources.
8280Sstevel@tonic-gate 	 */
8292311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES)
8302311Sseb 		mip->mi_resources(mip->mi_driver);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate void
8340Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	/*
8392311Sseb 	 * Call the driver to handle the ioctl.  The driver may not support
8402311Sseb 	 * any ioctls, in which case we reply with a NAK on its behalf.
8410Sstevel@tonic-gate 	 */
8422311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
8432311Sseb 		mip->mi_ioctl(mip->mi_driver, wq, bp);
8442311Sseb 	else
8452311Sseb 		miocnak(wq, bp, 0, EINVAL);
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate 
84856Smeem const mac_txinfo_t *
84956Smeem mac_tx_get(mac_handle_t mh)
8500Sstevel@tonic-gate {
8510Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
85256Smeem 	mac_txinfo_t	*mtp;
85356Smeem 
85456Smeem 	/*
85556Smeem 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
85656Smeem 	 * changed.  This is sufficient since MAC clients are careful to always
85756Smeem 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
85856Smeem 	 * MAC_PROMISC prior to calling mac_txloop_remove().
85956Smeem 	 */
86056Smeem 	rw_enter(&mip->mi_txloop_lock, RW_READER);
8610Sstevel@tonic-gate 
86256Smeem 	if (mac_promisc_get(mh, MAC_PROMISC)) {
86356Smeem 		ASSERT(mip->mi_mtfp != NULL);
86456Smeem 		mtp = &mip->mi_txloopinfo;
86556Smeem 	} else {
86656Smeem 		/*
86756Smeem 		 * Note that we cannot ASSERT() that mip->mi_mtfp is NULL,
86856Smeem 		 * because to satisfy the above ASSERT(), we have to disable
86956Smeem 		 * MAC_PROMISC prior to calling mac_txloop_remove().
87056Smeem 		 */
87156Smeem 		mtp = &mip->mi_txinfo;
87256Smeem 	}
87356Smeem 
87456Smeem 	rw_exit(&mip->mi_txloop_lock);
87556Smeem 	return (mtp);
8760Sstevel@tonic-gate }
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate link_state_t
8790Sstevel@tonic-gate mac_link_get(mac_handle_t mh)
8800Sstevel@tonic-gate {
8812311Sseb 	return (((mac_impl_t *)mh)->mi_linkstate);
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate mac_notify_handle_t
8850Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
8860Sstevel@tonic-gate {
8870Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8880Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
8910Sstevel@tonic-gate 	mnfp->mnf_fn = notify;
8920Sstevel@tonic-gate 	mnfp->mnf_arg = arg;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	/*
8950Sstevel@tonic-gate 	 * Add it to the head of the 'notify' callback list.
8960Sstevel@tonic-gate 	 */
8971852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
8980Sstevel@tonic-gate 	mnfp->mnf_nextp = mip->mi_mnfp;
8990Sstevel@tonic-gate 	mip->mi_mnfp = mnfp;
9001852Syz147064 	rw_exit(&mip->mi_notify_lock);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	return ((mac_notify_handle_t)mnfp);
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate void
9060Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
9070Sstevel@tonic-gate {
9080Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9090Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
9100Sstevel@tonic-gate 	mac_notify_fn_t		**pp;
9110Sstevel@tonic-gate 	mac_notify_fn_t		*p;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/*
9140Sstevel@tonic-gate 	 * Search the 'notify' callback list for the function closure.
9150Sstevel@tonic-gate 	 */
9161852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
9170Sstevel@tonic-gate 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
9180Sstevel@tonic-gate 	    pp = &(p->mnf_nextp)) {
9190Sstevel@tonic-gate 		if (p == mnfp)
9200Sstevel@tonic-gate 			break;
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate 	ASSERT(p != NULL);
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	/*
9250Sstevel@tonic-gate 	 * Remove it from the list.
9260Sstevel@tonic-gate 	 */
9270Sstevel@tonic-gate 	*pp = p->mnf_nextp;
9281852Syz147064 	rw_exit(&mip->mi_notify_lock);
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	/*
9310Sstevel@tonic-gate 	 * Free it.
9320Sstevel@tonic-gate 	 */
9330Sstevel@tonic-gate 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate void
9370Sstevel@tonic-gate mac_notify(mac_handle_t mh)
9380Sstevel@tonic-gate {
9390Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9400Sstevel@tonic-gate 	mac_notify_type_t	type;
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	for (type = 0; type < MAC_NNOTE; type++)
9430Sstevel@tonic-gate 		i_mac_notify(mip, type);
9440Sstevel@tonic-gate }
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate mac_rx_handle_t
9470Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
9480Sstevel@tonic-gate {
9490Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9500Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
9530Sstevel@tonic-gate 	mrfp->mrf_fn = rx;
9540Sstevel@tonic-gate 	mrfp->mrf_arg = arg;
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	/*
9570Sstevel@tonic-gate 	 * Add it to the head of the 'rx' callback list.
9580Sstevel@tonic-gate 	 */
9590Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
9600Sstevel@tonic-gate 	mrfp->mrf_nextp = mip->mi_mrfp;
9610Sstevel@tonic-gate 	mip->mi_mrfp = mrfp;
9620Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	return ((mac_rx_handle_t)mrfp);
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate /*
9680Sstevel@tonic-gate  * Unregister a receive function for this mac.  This removes the function
9690Sstevel@tonic-gate  * from the list of receive functions for this mac.
9700Sstevel@tonic-gate  */
9710Sstevel@tonic-gate void
9720Sstevel@tonic-gate mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh)
9730Sstevel@tonic-gate {
9740Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9750Sstevel@tonic-gate 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
9760Sstevel@tonic-gate 	mac_rx_fn_t		**pp;
9770Sstevel@tonic-gate 	mac_rx_fn_t		*p;
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	/*
9800Sstevel@tonic-gate 	 * Search the 'rx' callback list for the function closure.
9810Sstevel@tonic-gate 	 */
9820Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
9830Sstevel@tonic-gate 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
9840Sstevel@tonic-gate 		if (p == mrfp)
9850Sstevel@tonic-gate 			break;
9860Sstevel@tonic-gate 	}
9870Sstevel@tonic-gate 	ASSERT(p != NULL);
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	/* Remove it from the list. */
9900Sstevel@tonic-gate 	*pp = p->mrf_nextp;
9910Sstevel@tonic-gate 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
9920Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
9930Sstevel@tonic-gate }
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate mac_txloop_handle_t
9960Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
9970Sstevel@tonic-gate {
9980Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9990Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
10020Sstevel@tonic-gate 	mtfp->mtf_fn = tx;
10030Sstevel@tonic-gate 	mtfp->mtf_arg = arg;
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	/*
10060Sstevel@tonic-gate 	 * Add it to the head of the 'tx' callback list.
10070Sstevel@tonic-gate 	 */
10080Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
10090Sstevel@tonic-gate 	mtfp->mtf_nextp = mip->mi_mtfp;
10100Sstevel@tonic-gate 	mip->mi_mtfp = mtfp;
10110Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	return ((mac_txloop_handle_t)mtfp);
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate  * Unregister a transmit function for this mac.  This removes the function
10180Sstevel@tonic-gate  * from the list of transmit functions for this mac.
10190Sstevel@tonic-gate  */
10200Sstevel@tonic-gate void
10210Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
10220Sstevel@tonic-gate {
10230Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10240Sstevel@tonic-gate 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
10250Sstevel@tonic-gate 	mac_txloop_fn_t		**pp;
10260Sstevel@tonic-gate 	mac_txloop_fn_t		*p;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	/*
10290Sstevel@tonic-gate 	 * Search the 'tx' callback list for the function.
10300Sstevel@tonic-gate 	 */
10310Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
10320Sstevel@tonic-gate 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
10330Sstevel@tonic-gate 		if (p == mtfp)
10340Sstevel@tonic-gate 			break;
10350Sstevel@tonic-gate 	}
10360Sstevel@tonic-gate 	ASSERT(p != NULL);
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	/* Remove it from the list. */
10390Sstevel@tonic-gate 	*pp = p->mtf_nextp;
10400Sstevel@tonic-gate 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
10410Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate void
10450Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
10460Sstevel@tonic-gate {
10470Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	/*
10500Sstevel@tonic-gate 	 * Update the 'resource_add' callbacks.
10510Sstevel@tonic-gate 	 */
10520Sstevel@tonic-gate 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
10530Sstevel@tonic-gate 	mip->mi_resource_add = add;
10540Sstevel@tonic-gate 	mip->mi_resource_add_arg = arg;
10550Sstevel@tonic-gate 	rw_exit(&(mip->mi_resource_lock));
10560Sstevel@tonic-gate }
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate /*
10590Sstevel@tonic-gate  * Driver support functions.
10600Sstevel@tonic-gate  */
10610Sstevel@tonic-gate 
10622311Sseb mac_register_t *
10632311Sseb mac_alloc(uint_t mac_version)
10640Sstevel@tonic-gate {
10652311Sseb 	mac_register_t *mregp;
10662311Sseb 
10672311Sseb 	/*
10682311Sseb 	 * Make sure there isn't a version mismatch between the driver and
10692311Sseb 	 * the framework.  In the future, if multiple versions are
10702311Sseb 	 * supported, this check could become more sophisticated.
10712311Sseb 	 */
10722311Sseb 	if (mac_version != MAC_VERSION)
10732311Sseb 		return (NULL);
10742311Sseb 
10752311Sseb 	mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
10762311Sseb 	mregp->m_version = mac_version;
10772311Sseb 	return (mregp);
10782311Sseb }
10792311Sseb 
10802311Sseb void
10812311Sseb mac_free(mac_register_t *mregp)
10822311Sseb {
10832311Sseb 	kmem_free(mregp, sizeof (mac_register_t));
10842311Sseb }
10852311Sseb 
10862311Sseb /*
10872311Sseb  * mac_register() is how drivers register new MACs with the GLDv3
10882311Sseb  * framework.  The mregp argument is allocated by drivers using the
10892311Sseb  * mac_alloc() function, and can be freed using mac_free() immediately upon
10902311Sseb  * return from mac_register().  Upon success (0 return value), the mhp
10912311Sseb  * opaque pointer becomes the driver's handle to its MAC interface, and is
10922311Sseb  * the argument to all other mac module entry points.
10932311Sseb  */
10942311Sseb int
10952311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp)
10962311Sseb {
10972311Sseb 	mac_impl_t	*mip;
10982311Sseb 	mactype_t	*mtype;
10993969Syz147064 	int		err = EINVAL;
11000Sstevel@tonic-gate 	struct devnames *dnp;
11012311Sseb 	minor_t		minor;
11022311Sseb 	boolean_t	style1_created = B_FALSE, style2_created = B_FALSE;
11032311Sseb 
11042311Sseb 	/* Find the required MAC-Type plugin. */
11052311Sseb 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
11062311Sseb 		return (EINVAL);
11072311Sseb 
11082311Sseb 	/* Create a mac_impl_t to represent this MAC. */
11092311Sseb 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
11102311Sseb 
11112311Sseb 	/*
11122311Sseb 	 * The mac is not ready for open yet.
11132311Sseb 	 */
11142311Sseb 	mip->mi_disabled = B_TRUE;
11152311Sseb 
11162311Sseb 	mip->mi_drvname = ddi_driver_name(mregp->m_dip);
11172311Sseb 	/*
11182311Sseb 	 * Some drivers such as aggr need to register multiple MACs.  Such
11192311Sseb 	 * drivers must supply a non-zero "instance" argument so that each
11202311Sseb 	 * MAC can be assigned a unique MAC name and can have unique
11212311Sseb 	 * kstats.
11222311Sseb 	 */
11232311Sseb 	mip->mi_instance = ((mregp->m_instance == 0) ?
11242311Sseb 	    ddi_get_instance(mregp->m_dip) : mregp->m_instance);
11252311Sseb 
11262311Sseb 	/* Construct the MAC name as <drvname><instance> */
11272311Sseb 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
11282311Sseb 	    mip->mi_drvname, mip->mi_instance);
11292311Sseb 
11302311Sseb 	mip->mi_driver = mregp->m_driver;
11312311Sseb 
11322311Sseb 	mip->mi_type = mtype;
11332311Sseb 	mip->mi_info.mi_media = mtype->mt_type;
11343147Sxc151355 	mip->mi_info.mi_nativemedia = mtype->mt_nativetype;
11352311Sseb 	mip->mi_info.mi_sdu_min = mregp->m_min_sdu;
11363969Syz147064 	if (mregp->m_max_sdu <= mregp->m_min_sdu)
11372311Sseb 		goto fail;
11382311Sseb 	mip->mi_info.mi_sdu_max = mregp->m_max_sdu;
11392311Sseb 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
11402311Sseb 	/*
11412311Sseb 	 * If the media supports a broadcast address, cache a pointer to it
11422311Sseb 	 * in the mac_info_t so that upper layers can use it.
11432311Sseb 	 */
11442311Sseb 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1145269Sericheng 
11462311Sseb 	/*
11472311Sseb 	 * Copy the unicast source address into the mac_info_t, but only if
11482311Sseb 	 * the MAC-Type defines a non-zero address length.  We need to
11492311Sseb 	 * handle MAC-Types that have an address length of 0
11502311Sseb 	 * (point-to-point protocol MACs for example).
11512311Sseb 	 */
11522311Sseb 	if (mip->mi_type->mt_addr_length > 0) {
11533969Syz147064 		if (mregp->m_src_addr == NULL)
11542311Sseb 			goto fail;
11552311Sseb 		mip->mi_info.mi_unicst_addr =
11562311Sseb 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
11572311Sseb 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
11582311Sseb 		    mip->mi_type->mt_addr_length);
11592311Sseb 
11602311Sseb 		/*
11612311Sseb 		 * Copy the fixed 'factory' MAC address from the immutable
11622311Sseb 		 * info.  This is taken to be the MAC address currently in
11632311Sseb 		 * use.
11642311Sseb 		 */
11652311Sseb 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
11662311Sseb 		    mip->mi_type->mt_addr_length);
11672311Sseb 		/* Copy the destination address if one is provided. */
11682311Sseb 		if (mregp->m_dst_addr != NULL) {
11692311Sseb 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
11702311Sseb 			    mip->mi_type->mt_addr_length);
11712311Sseb 		}
11722311Sseb 	} else if (mregp->m_src_addr != NULL) {
11732311Sseb 		goto fail;
1174269Sericheng 	}
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	/*
11772311Sseb 	 * The format of the m_pdata is specific to the plugin.  It is
11782311Sseb 	 * passed in as an argument to all of the plugin callbacks.  The
11792311Sseb 	 * driver can update this information by calling
11802311Sseb 	 * mac_pdata_update().
11810Sstevel@tonic-gate 	 */
11822311Sseb 	if (mregp->m_pdata != NULL) {
11832311Sseb 		/*
11842311Sseb 		 * Verify that the plugin supports MAC plugin data and that
11852311Sseb 		 * the supplied data is valid.
11862311Sseb 		 */
11873969Syz147064 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
11882311Sseb 			goto fail;
11892311Sseb 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
11902311Sseb 		    mregp->m_pdata_size)) {
11912311Sseb 			goto fail;
11922311Sseb 		}
11932311Sseb 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
11942311Sseb 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
11952311Sseb 		mip->mi_pdata_size = mregp->m_pdata_size;
11962311Sseb 	}
11972311Sseb 
11982311Sseb 	/*
11992311Sseb 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
12002311Sseb 	 * check to make sure all mandatory callbacks are set.
12012311Sseb 	 */
12022311Sseb 	if (mregp->m_callbacks->mc_getstat == NULL ||
12032311Sseb 	    mregp->m_callbacks->mc_start == NULL ||
12042311Sseb 	    mregp->m_callbacks->mc_stop == NULL ||
12052311Sseb 	    mregp->m_callbacks->mc_setpromisc == NULL ||
12062311Sseb 	    mregp->m_callbacks->mc_multicst == NULL ||
12072311Sseb 	    mregp->m_callbacks->mc_unicst == NULL ||
12082311Sseb 	    mregp->m_callbacks->mc_tx == NULL) {
12092311Sseb 		goto fail;
12102311Sseb 	}
12112311Sseb 	mip->mi_callbacks = mregp->m_callbacks;
12122311Sseb 
12132311Sseb 	mip->mi_dip = mregp->m_dip;
12142311Sseb 
12152311Sseb 	/*
12162311Sseb 	 * Set up the two possible transmit routines.
12172311Sseb 	 */
12182311Sseb 	mip->mi_txinfo.mt_fn = mip->mi_tx;
12192311Sseb 	mip->mi_txinfo.mt_arg = mip->mi_driver;
12202311Sseb 	mip->mi_txloopinfo.mt_fn = mac_txloop;
12212311Sseb 	mip->mi_txloopinfo.mt_arg = mip;
12222311Sseb 
12232311Sseb 	/*
12242311Sseb 	 * Initialize the kstats for this device.
12252311Sseb 	 */
12262311Sseb 	mac_stat_create(mip);
12270Sstevel@tonic-gate 
1228269Sericheng 	err = EEXIST;
12292311Sseb 	/* Create a style-2 DLPI device */
12302311Sseb 	if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname,
12312311Sseb 	    S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
12322311Sseb 		goto fail;
12332311Sseb 	style2_created = B_TRUE;
1234269Sericheng 
12352311Sseb 	/* Create a style-1 DLPI device */
12362311Sseb 	minor = (minor_t)mip->mi_instance + 1;
12372311Sseb 	if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor,
12382311Sseb 	    DDI_NT_NET, 0) != DDI_SUCCESS)
12392311Sseb 		goto fail;
12402311Sseb 	style1_created = B_TRUE;
12410Sstevel@tonic-gate 
12422311Sseb 	/*
12432311Sseb 	 * Create a link for this MAC.  The link name will be the same as
12442311Sseb 	 * the MAC name.
12452311Sseb 	 */
12462311Sseb 	err = dls_create(mip->mi_name, mip->mi_name,
12472311Sseb 	    ddi_get_instance(mip->mi_dip));
12482311Sseb 	if (err != 0)
12492311Sseb 		goto fail;
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	/* set the gldv3 flag in dn_flags */
12522311Sseb 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
12530Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
12540Sstevel@tonic-gate 	dnp->dn_flags |= DN_GLDV3_DRIVER;
12550Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
12560Sstevel@tonic-gate 
12573969Syz147064 	rw_enter(&i_mac_impl_lock, RW_WRITER);
12583969Syz147064 	if (mod_hash_insert(i_mac_impl_hash,
12593969Syz147064 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
12603969Syz147064 		rw_exit(&i_mac_impl_lock);
12613969Syz147064 		VERIFY(dls_destroy(mip->mi_name) == 0);
12623969Syz147064 		err = EEXIST;
12633969Syz147064 		goto fail;
12643969Syz147064 	}
12653969Syz147064 
12661852Syz147064 	/*
12671852Syz147064 	 * Mark the MAC to be ready for open.
12681852Syz147064 	 */
12692311Sseb 	mip->mi_disabled = B_FALSE;
12702311Sseb 
12712311Sseb 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
12723969Syz147064 
12731852Syz147064 	rw_exit(&i_mac_impl_lock);
12743969Syz147064 
12753969Syz147064 	atomic_inc_32(&i_mac_impl_count);
12762311Sseb 	*mhp = (mac_handle_t)mip;
1277269Sericheng 	return (0);
12780Sstevel@tonic-gate 
12792311Sseb fail:
12802311Sseb 	if (mip->mi_info.mi_unicst_addr != NULL) {
12812311Sseb 		kmem_free(mip->mi_info.mi_unicst_addr,
12822311Sseb 		    mip->mi_type->mt_addr_length);
12832311Sseb 		mip->mi_info.mi_unicst_addr = NULL;
12842311Sseb 	}
12852311Sseb 	if (style1_created)
12862311Sseb 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
12872311Sseb 	if (style2_created)
12882311Sseb 		ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
12892311Sseb 
12902311Sseb 	mac_stat_destroy(mip);
12912311Sseb 
12922311Sseb 	if (mip->mi_type != NULL) {
12933288Sseb 		atomic_dec_32(&mip->mi_type->mt_ref);
12942311Sseb 		mip->mi_type = NULL;
12952311Sseb 	}
12962311Sseb 
12972311Sseb 	if (mip->mi_pdata != NULL) {
12982311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
12992311Sseb 		mip->mi_pdata = NULL;
13002311Sseb 		mip->mi_pdata_size = 0;
13012311Sseb 	}
13022311Sseb 
13032311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
1304269Sericheng 	return (err);
13050Sstevel@tonic-gate }
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate int
13082311Sseb mac_unregister(mac_handle_t mh)
13090Sstevel@tonic-gate {
13102311Sseb 	int			err;
13112311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
13122311Sseb 	mod_hash_val_t		val;
13132311Sseb 	mac_multicst_addr_t	*p, *nextp;
1314269Sericheng 
13150Sstevel@tonic-gate 	/*
13160Sstevel@tonic-gate 	 * See if there are any other references to this mac_t (e.g., VLAN's).
13171852Syz147064 	 * If not, set mi_disabled to prevent any new VLAN's from being
13182311Sseb 	 * created while we're destroying this mac.
13190Sstevel@tonic-gate 	 */
1320269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
13210Sstevel@tonic-gate 	if (mip->mi_ref > 0) {
1322269Sericheng 		rw_exit(&i_mac_impl_lock);
13230Sstevel@tonic-gate 		return (EBUSY);
13240Sstevel@tonic-gate 	}
13251852Syz147064 	mip->mi_disabled = B_TRUE;
1326269Sericheng 	rw_exit(&i_mac_impl_lock);
13270Sstevel@tonic-gate 
13281852Syz147064 	/*
13291852Syz147064 	 * Wait for all taskqs which process the mac notifications to finish.
13301852Syz147064 	 */
13311852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
13321852Syz147064 	while (mip->mi_notify_ref != 0)
13331852Syz147064 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock);
13341852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
13351852Syz147064 
13362311Sseb 	if ((err = dls_destroy(mip->mi_name)) != 0) {
1337269Sericheng 		rw_enter(&i_mac_impl_lock, RW_WRITER);
13381852Syz147064 		mip->mi_disabled = B_FALSE;
1339269Sericheng 		rw_exit(&i_mac_impl_lock);
1340269Sericheng 		return (err);
13410Sstevel@tonic-gate 	}
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	/*
13442311Sseb 	 * Remove both style 1 and style 2 minor nodes
13450Sstevel@tonic-gate 	 */
13462311Sseb 	ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
13472311Sseb 	ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
13482311Sseb 
13492311Sseb 	ASSERT(!mip->mi_activelink);
13502311Sseb 
13512311Sseb 	mac_stat_destroy(mip);
13522311Sseb 
13532311Sseb 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
13542311Sseb 	    &val);
13552311Sseb 	ASSERT(mip == (mac_impl_t *)val);
13562311Sseb 
13572311Sseb 	ASSERT(i_mac_impl_count > 0);
13583288Sseb 	atomic_dec_32(&i_mac_impl_count);
13592311Sseb 
13602311Sseb 	if (mip->mi_pdata != NULL)
13612311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
13622311Sseb 	mip->mi_pdata = NULL;
13632311Sseb 	mip->mi_pdata_size = 0;
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	/*
13662311Sseb 	 * Free the list of multicast addresses.
13670Sstevel@tonic-gate 	 */
13682311Sseb 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
13692311Sseb 		nextp = p->mma_nextp;
13702311Sseb 		kmem_free(p, sizeof (mac_multicst_addr_t));
13712311Sseb 	}
13722311Sseb 	mip->mi_mmap = NULL;
13730Sstevel@tonic-gate 
13742311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
13752311Sseb 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
13762311Sseb 	mip->mi_info.mi_unicst_addr = NULL;
13772311Sseb 
13783288Sseb 	atomic_dec_32(&mip->mi_type->mt_ref);
13792311Sseb 	mip->mi_type = NULL;
13802311Sseb 
13812311Sseb 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
13822311Sseb 
13832311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
13842311Sseb 
13850Sstevel@tonic-gate 	return (0);
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate void
13892311Sseb mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp)
13900Sstevel@tonic-gate {
13912311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
13920Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 	/*
13950Sstevel@tonic-gate 	 * Call all registered receive functions.
13960Sstevel@tonic-gate 	 */
13970Sstevel@tonic-gate 	rw_enter(&mip->mi_rx_lock, RW_READER);
13980Sstevel@tonic-gate 	mrfp = mip->mi_mrfp;
13990Sstevel@tonic-gate 	if (mrfp == NULL) {
14000Sstevel@tonic-gate 		/* There are no registered receive functions. */
14010Sstevel@tonic-gate 		freemsgchain(bp);
14020Sstevel@tonic-gate 		rw_exit(&mip->mi_rx_lock);
14030Sstevel@tonic-gate 		return;
14040Sstevel@tonic-gate 	}
14050Sstevel@tonic-gate 	do {
14060Sstevel@tonic-gate 		mblk_t *recv_bp;
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 		if (mrfp->mrf_nextp != NULL) {
14090Sstevel@tonic-gate 			/* XXX Do we bump a counter if copymsgchain() fails? */
14100Sstevel@tonic-gate 			recv_bp = copymsgchain(bp);
14110Sstevel@tonic-gate 		} else {
14120Sstevel@tonic-gate 			recv_bp = bp;
14130Sstevel@tonic-gate 		}
14140Sstevel@tonic-gate 		if (recv_bp != NULL)
14150Sstevel@tonic-gate 			mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp);
14160Sstevel@tonic-gate 		mrfp = mrfp->mrf_nextp;
14170Sstevel@tonic-gate 	} while (mrfp != NULL);
14180Sstevel@tonic-gate 	rw_exit(&mip->mi_rx_lock);
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate /*
14220Sstevel@tonic-gate  * Transmit function -- ONLY used when there are registered loopback listeners.
14230Sstevel@tonic-gate  */
14240Sstevel@tonic-gate mblk_t *
14250Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp)
14260Sstevel@tonic-gate {
14270Sstevel@tonic-gate 	mac_impl_t	*mip = arg;
14280Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
14290Sstevel@tonic-gate 	mblk_t		*loop_bp, *resid_bp, *next_bp;
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	while (bp != NULL) {
14320Sstevel@tonic-gate 		next_bp = bp->b_next;
14330Sstevel@tonic-gate 		bp->b_next = NULL;
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 		if ((loop_bp = copymsg(bp)) == NULL)
14360Sstevel@tonic-gate 			goto noresources;
14370Sstevel@tonic-gate 
14382311Sseb 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
14390Sstevel@tonic-gate 			ASSERT(resid_bp == bp);
14400Sstevel@tonic-gate 			freemsg(loop_bp);
14410Sstevel@tonic-gate 			goto noresources;
14420Sstevel@tonic-gate 		}
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 		rw_enter(&mip->mi_txloop_lock, RW_READER);
14450Sstevel@tonic-gate 		mtfp = mip->mi_mtfp;
144656Smeem 		while (mtfp != NULL && loop_bp != NULL) {
14470Sstevel@tonic-gate 			bp = loop_bp;
144856Smeem 
144956Smeem 			/* XXX counter bump if copymsg() fails? */
145056Smeem 			if (mtfp->mtf_nextp != NULL)
14510Sstevel@tonic-gate 				loop_bp = copymsg(bp);
145256Smeem 			else
145356Smeem 				loop_bp = NULL;
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
145656Smeem 			mtfp = mtfp->mtf_nextp;
14570Sstevel@tonic-gate 		}
145856Smeem 		rw_exit(&mip->mi_txloop_lock);
14590Sstevel@tonic-gate 
146056Smeem 		/*
146156Smeem 		 * It's possible we've raced with the disabling of promiscuous
146256Smeem 		 * mode, in which case we can discard our copy.
146356Smeem 		 */
146456Smeem 		if (loop_bp != NULL)
146556Smeem 			freemsg(loop_bp);
146656Smeem 
14670Sstevel@tonic-gate 		bp = next_bp;
14680Sstevel@tonic-gate 	}
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	return (NULL);
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate noresources:
14730Sstevel@tonic-gate 	bp->b_next = next_bp;
14740Sstevel@tonic-gate 	return (bp);
14750Sstevel@tonic-gate }
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate void
14782311Sseb mac_link_update(mac_handle_t mh, link_state_t link)
14790Sstevel@tonic-gate {
14802311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 	/*
14830Sstevel@tonic-gate 	 * Save the link state.
14840Sstevel@tonic-gate 	 */
14852311Sseb 	mip->mi_linkstate = link;
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	/*
14880Sstevel@tonic-gate 	 * Send a MAC_NOTE_LINK notification.
14890Sstevel@tonic-gate 	 */
14900Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_LINK);
14910Sstevel@tonic-gate }
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate void
14942311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
14950Sstevel@tonic-gate {
14962311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
14970Sstevel@tonic-gate 
14982311Sseb 	if (mip->mi_type->mt_addr_length == 0)
14992311Sseb 		return;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	/*
15020Sstevel@tonic-gate 	 * Save the address.
15030Sstevel@tonic-gate 	 */
15042311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	/*
15070Sstevel@tonic-gate 	 * Send a MAC_NOTE_UNICST notification.
15080Sstevel@tonic-gate 	 */
15090Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_UNICST);
15100Sstevel@tonic-gate }
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate void
15132311Sseb mac_tx_update(mac_handle_t mh)
15140Sstevel@tonic-gate {
15150Sstevel@tonic-gate 	/*
15160Sstevel@tonic-gate 	 * Send a MAC_NOTE_TX notification.
15170Sstevel@tonic-gate 	 */
15182311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate void
15222311Sseb mac_resource_update(mac_handle_t mh)
15230Sstevel@tonic-gate {
15240Sstevel@tonic-gate 	/*
15250Sstevel@tonic-gate 	 * Send a MAC_NOTE_RESOURCE notification.
15260Sstevel@tonic-gate 	 */
15272311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
15280Sstevel@tonic-gate }
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate mac_resource_handle_t
15312311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
15320Sstevel@tonic-gate {
15332311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
15340Sstevel@tonic-gate 	mac_resource_handle_t	mrh;
15350Sstevel@tonic-gate 	mac_resource_add_t	add;
15360Sstevel@tonic-gate 	void			*arg;
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 	rw_enter(&mip->mi_resource_lock, RW_READER);
15390Sstevel@tonic-gate 	add = mip->mi_resource_add;
15400Sstevel@tonic-gate 	arg = mip->mi_resource_add_arg;
15410Sstevel@tonic-gate 
15421184Skrgopi 	if (add != NULL)
15431184Skrgopi 		mrh = add(arg, mrp);
15441184Skrgopi 	else
15451184Skrgopi 		mrh = NULL;
15460Sstevel@tonic-gate 	rw_exit(&mip->mi_resource_lock);
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	return (mrh);
15490Sstevel@tonic-gate }
15500Sstevel@tonic-gate 
15512311Sseb int
15522311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
15532311Sseb {
15542311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
15552311Sseb 
15562311Sseb 	/*
15572311Sseb 	 * Verify that the plugin supports MAC plugin data and that the
15582311Sseb 	 * supplied data is valid.
15592311Sseb 	 */
15602311Sseb 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
15612311Sseb 		return (EINVAL);
15622311Sseb 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
15632311Sseb 		return (EINVAL);
15642311Sseb 
15652311Sseb 	if (mip->mi_pdata != NULL)
15662311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
15672311Sseb 
15682311Sseb 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
15692311Sseb 	bcopy(mac_pdata, mip->mi_pdata, dsize);
15702311Sseb 	mip->mi_pdata_size = dsize;
15712311Sseb 
15722311Sseb 	/*
15732311Sseb 	 * Since the MAC plugin data is used to construct MAC headers that
15742311Sseb 	 * were cached in fast-path headers, we need to flush fast-path
15752311Sseb 	 * information for links associated with this mac.
15762311Sseb 	 */
15772311Sseb 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
15782311Sseb 	return (0);
15792311Sseb }
15802311Sseb 
15810Sstevel@tonic-gate void
15822311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
15830Sstevel@tonic-gate     boolean_t add)
15840Sstevel@tonic-gate {
15852311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
15860Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 	/*
15890Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
15900Sstevel@tonic-gate 	 * driver's m_multicst entry point.
15910Sstevel@tonic-gate 	 */
15920Sstevel@tonic-gate 	if (refresh == NULL) {
15932311Sseb 		refresh = mip->mi_multicst;
15942311Sseb 		arg = mip->mi_driver;
15950Sstevel@tonic-gate 	}
15960Sstevel@tonic-gate 	ASSERT(refresh != NULL);
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	/*
15990Sstevel@tonic-gate 	 * Walk the multicast address list and call the refresh function for
16000Sstevel@tonic-gate 	 * each address.
16010Sstevel@tonic-gate 	 */
16020Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
16030Sstevel@tonic-gate 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
16040Sstevel@tonic-gate 		refresh(arg, add, p->mma_addr);
16050Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
16060Sstevel@tonic-gate }
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate void
16092311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
16100Sstevel@tonic-gate {
16112311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
16120Sstevel@tonic-gate 	/*
16130Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
16142311Sseb 	 * driver's mi_unicst entry point.
16150Sstevel@tonic-gate 	 */
16160Sstevel@tonic-gate 	if (refresh == NULL) {
16172311Sseb 		refresh = mip->mi_unicst;
16182311Sseb 		arg = mip->mi_driver;
16190Sstevel@tonic-gate 	}
16200Sstevel@tonic-gate 	ASSERT(refresh != NULL);
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 	/*
16230Sstevel@tonic-gate 	 * Call the refresh function with the current unicast address.
16240Sstevel@tonic-gate 	 */
16250Sstevel@tonic-gate 	refresh(arg, mip->mi_addr);
16260Sstevel@tonic-gate }
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate void
16292311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
16300Sstevel@tonic-gate {
16312311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	/*
16340Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
16350Sstevel@tonic-gate 	 * driver's m_promisc entry point.
16360Sstevel@tonic-gate 	 */
16370Sstevel@tonic-gate 	if (refresh == NULL) {
16382311Sseb 		refresh = mip->mi_setpromisc;
16392311Sseb 		arg = mip->mi_driver;
16400Sstevel@tonic-gate 	}
16410Sstevel@tonic-gate 	ASSERT(refresh != NULL);
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 	/*
16440Sstevel@tonic-gate 	 * Call the refresh function with the current promiscuity.
16450Sstevel@tonic-gate 	 */
16460Sstevel@tonic-gate 	refresh(arg, (mip->mi_devpromisc != 0));
16470Sstevel@tonic-gate }
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate boolean_t
16500Sstevel@tonic-gate mac_active_set(mac_handle_t mh)
16510Sstevel@tonic-gate {
16520Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
16550Sstevel@tonic-gate 	if (mip->mi_activelink) {
16560Sstevel@tonic-gate 		mutex_exit(&mip->mi_activelink_lock);
16570Sstevel@tonic-gate 		return (B_FALSE);
16580Sstevel@tonic-gate 	}
16590Sstevel@tonic-gate 	mip->mi_activelink = B_TRUE;
16600Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
16610Sstevel@tonic-gate 	return (B_TRUE);
16620Sstevel@tonic-gate }
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate void
16650Sstevel@tonic-gate mac_active_clear(mac_handle_t mh)
16660Sstevel@tonic-gate {
16670Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
16700Sstevel@tonic-gate 	ASSERT(mip->mi_activelink);
16710Sstevel@tonic-gate 	mip->mi_activelink = B_FALSE;
16720Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
16730Sstevel@tonic-gate }
1674269Sericheng 
1675269Sericheng /*
1676269Sericheng  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
1677269Sericheng  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
1678269Sericheng  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
1679269Sericheng  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
1680269Sericheng  * cannot disappear while we are accessing it.
1681269Sericheng  */
1682269Sericheng typedef struct i_mac_info_state_s {
1683269Sericheng 	const char	*mi_name;
1684269Sericheng 	mac_info_t	*mi_infop;
1685269Sericheng } i_mac_info_state_t;
1686269Sericheng 
1687269Sericheng /*ARGSUSED*/
1688269Sericheng static uint_t
1689269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1690269Sericheng {
1691269Sericheng 	i_mac_info_state_t	*statep = arg;
1692269Sericheng 	mac_impl_t		*mip = (mac_impl_t *)val;
1693269Sericheng 
16941852Syz147064 	if (mip->mi_disabled)
1695269Sericheng 		return (MH_WALK_CONTINUE);
1696269Sericheng 
1697269Sericheng 	if (strcmp(statep->mi_name,
16982311Sseb 	    ddi_driver_name(mip->mi_dip)) != 0)
1699269Sericheng 		return (MH_WALK_CONTINUE);
1700269Sericheng 
17012311Sseb 	statep->mi_infop = &mip->mi_info;
1702269Sericheng 	return (MH_WALK_TERMINATE);
1703269Sericheng }
1704269Sericheng 
1705269Sericheng boolean_t
1706269Sericheng mac_info_get(const char *name, mac_info_t *minfop)
1707269Sericheng {
1708269Sericheng 	i_mac_info_state_t	state;
1709269Sericheng 
1710269Sericheng 	rw_enter(&i_mac_impl_lock, RW_READER);
1711269Sericheng 	state.mi_name = name;
1712269Sericheng 	state.mi_infop = NULL;
1713269Sericheng 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
1714269Sericheng 	if (state.mi_infop == NULL) {
1715269Sericheng 		rw_exit(&i_mac_impl_lock);
1716269Sericheng 		return (B_FALSE);
1717269Sericheng 	}
1718269Sericheng 	*minfop = *state.mi_infop;
1719269Sericheng 	rw_exit(&i_mac_impl_lock);
1720269Sericheng 	return (B_TRUE);
1721269Sericheng }
1722269Sericheng 
17232311Sseb boolean_t
17242311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
17252311Sseb {
17262311Sseb 	mac_impl_t *mip = (mac_impl_t *)mh;
17272311Sseb 
17282311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
17292311Sseb 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
17302311Sseb 	else
17312311Sseb 		return (B_FALSE);
17322311Sseb }
17332311Sseb 
17342311Sseb boolean_t
17352311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
17362311Sseb {
17372311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17382311Sseb 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
17392311Sseb 	    mip->mi_pdata));
17402311Sseb }
17412311Sseb 
17422311Sseb mblk_t *
17432311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
17442311Sseb     size_t extra_len)
17452311Sseb {
17462311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17472311Sseb 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
17482311Sseb 	    mip->mi_pdata, payload, extra_len));
17492311Sseb }
17502311Sseb 
17512311Sseb int
17522311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
17532311Sseb {
17542311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17552311Sseb 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
17562311Sseb 	    mhip));
17572311Sseb }
17582311Sseb 
17592311Sseb mblk_t *
17602311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp)
17612311Sseb {
17622311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17632311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
17642311Sseb 		if (DB_REF(mp) > 1) {
17652311Sseb 			mblk_t *newmp = copymsg(mp);
17662760Sdg199075 			if (newmp == NULL)
17672760Sdg199075 				return (NULL);
17682311Sseb 			freemsg(mp);
17692311Sseb 			mp = newmp;
17702311Sseb 		}
17712311Sseb 		return (mip->mi_type->mt_ops.mtops_header_cook(mp,
17722311Sseb 		    mip->mi_pdata));
17732311Sseb 	}
17742311Sseb 	return (mp);
17752311Sseb }
17762311Sseb 
17772311Sseb mblk_t *
17782311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp)
17792311Sseb {
17802311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
17812311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
17822311Sseb 		if (DB_REF(mp) > 1) {
17832311Sseb 			mblk_t *newmp = copymsg(mp);
17842760Sdg199075 			if (newmp == NULL)
17852760Sdg199075 				return (NULL);
17862311Sseb 			freemsg(mp);
17872311Sseb 			mp = newmp;
17882311Sseb 		}
17892311Sseb 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
17902311Sseb 		    mip->mi_pdata));
17912311Sseb 	}
17922311Sseb 	return (mp);
17932311Sseb }
17942311Sseb 
1795269Sericheng void
1796269Sericheng mac_init_ops(struct dev_ops *ops, const char *name)
1797269Sericheng {
1798269Sericheng 	dld_init_ops(ops, name);
1799269Sericheng }
1800269Sericheng 
1801269Sericheng void
1802269Sericheng mac_fini_ops(struct dev_ops *ops)
1803269Sericheng {
1804269Sericheng 	dld_fini_ops(ops);
1805269Sericheng }
18062311Sseb 
18072311Sseb /*
18082311Sseb  * MAC Type Plugin functions.
18092311Sseb  */
18102311Sseb 
18112311Sseb mactype_register_t *
18122311Sseb mactype_alloc(uint_t mactype_version)
18132311Sseb {
18142311Sseb 	mactype_register_t *mtrp;
18152311Sseb 
18162311Sseb 	/*
18172311Sseb 	 * Make sure there isn't a version mismatch between the plugin and
18182311Sseb 	 * the framework.  In the future, if multiple versions are
18192311Sseb 	 * supported, this check could become more sophisticated.
18202311Sseb 	 */
18212311Sseb 	if (mactype_version != MACTYPE_VERSION)
18222311Sseb 		return (NULL);
18232311Sseb 
18242311Sseb 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
18252311Sseb 	mtrp->mtr_version = mactype_version;
18262311Sseb 	return (mtrp);
18272311Sseb }
18282311Sseb 
18292311Sseb void
18302311Sseb mactype_free(mactype_register_t *mtrp)
18312311Sseb {
18322311Sseb 	kmem_free(mtrp, sizeof (mactype_register_t));
18332311Sseb }
18342311Sseb 
18352311Sseb int
18362311Sseb mactype_register(mactype_register_t *mtrp)
18372311Sseb {
18382311Sseb 	mactype_t	*mtp;
18392311Sseb 	mactype_ops_t	*ops = mtrp->mtr_ops;
18402311Sseb 
18412311Sseb 	/* Do some sanity checking before we register this MAC type. */
18422311Sseb 	if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0)
18432311Sseb 		return (EINVAL);
18442311Sseb 
18452311Sseb 	/*
18462311Sseb 	 * Verify that all mandatory callbacks are set in the ops
18472311Sseb 	 * vector.
18482311Sseb 	 */
18492311Sseb 	if (ops->mtops_unicst_verify == NULL ||
18502311Sseb 	    ops->mtops_multicst_verify == NULL ||
18512311Sseb 	    ops->mtops_sap_verify == NULL ||
18522311Sseb 	    ops->mtops_header == NULL ||
18532311Sseb 	    ops->mtops_header_info == NULL) {
18542311Sseb 		return (EINVAL);
18552311Sseb 	}
18562311Sseb 
18572311Sseb 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
18582311Sseb 	mtp->mt_ident = mtrp->mtr_ident;
18592311Sseb 	mtp->mt_ops = *ops;
18602311Sseb 	mtp->mt_type = mtrp->mtr_mactype;
18613147Sxc151355 	mtp->mt_nativetype = mtrp->mtr_nativetype;
18622311Sseb 	mtp->mt_addr_length = mtrp->mtr_addrlen;
18632311Sseb 	if (mtrp->mtr_brdcst_addr != NULL) {
18642311Sseb 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
18652311Sseb 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
18662311Sseb 		    mtrp->mtr_addrlen);
18672311Sseb 	}
18682311Sseb 
18692311Sseb 	mtp->mt_stats = mtrp->mtr_stats;
18702311Sseb 	mtp->mt_statcount = mtrp->mtr_statcount;
18712311Sseb 
18722311Sseb 	if (mod_hash_insert(i_mactype_hash,
18732311Sseb 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
18742311Sseb 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
18752311Sseb 		kmem_free(mtp, sizeof (*mtp));
18762311Sseb 		return (EEXIST);
18772311Sseb 	}
18782311Sseb 	return (0);
18792311Sseb }
18802311Sseb 
18812311Sseb int
18822311Sseb mactype_unregister(const char *ident)
18832311Sseb {
18842311Sseb 	mactype_t	*mtp;
18852311Sseb 	mod_hash_val_t	val;
18862311Sseb 	int 		err;
18872311Sseb 
18882311Sseb 	/*
18892311Sseb 	 * Let's not allow MAC drivers to use this plugin while we're
18903288Sseb 	 * trying to unregister it.  Holding i_mactype_lock also prevents a
18913288Sseb 	 * plugin from unregistering while a MAC driver is attempting to
18923288Sseb 	 * hold a reference to it in i_mactype_getplugin().
18932311Sseb 	 */
18943288Sseb 	mutex_enter(&i_mactype_lock);
18952311Sseb 
18962311Sseb 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
18972311Sseb 	    (mod_hash_val_t *)&mtp)) != 0) {
18982311Sseb 		/* A plugin is trying to unregister, but it never registered. */
18993288Sseb 		err = ENXIO;
19003288Sseb 		goto done;
19012311Sseb 	}
19022311Sseb 
19033288Sseb 	if (mtp->mt_ref != 0) {
19043288Sseb 		err = EBUSY;
19053288Sseb 		goto done;
19062311Sseb 	}
19072311Sseb 
19082311Sseb 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
19092311Sseb 	ASSERT(err == 0);
19102311Sseb 	if (err != 0) {
19112311Sseb 		/* This should never happen, thus the ASSERT() above. */
19123288Sseb 		err = EINVAL;
19133288Sseb 		goto done;
19142311Sseb 	}
19152311Sseb 	ASSERT(mtp == (mactype_t *)val);
19162311Sseb 
19172311Sseb 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
19182311Sseb 	kmem_free(mtp, sizeof (mactype_t));
19193288Sseb done:
19203288Sseb 	mutex_exit(&i_mactype_lock);
19213288Sseb 	return (err);
19222311Sseb }
19233448Sdh155122 
19243448Sdh155122 int
19253448Sdh155122 mac_vlan_create(mac_handle_t mh, const char *name, minor_t minor)
19263448Sdh155122 {
19273448Sdh155122 	mac_impl_t		*mip = (mac_impl_t *)mh;
19283448Sdh155122 
19293448Sdh155122 	/* Create a style-1 DLPI device */
19303448Sdh155122 	if (ddi_create_minor_node(mip->mi_dip, (char *)name, S_IFCHR, minor,
19313448Sdh155122 	    DDI_NT_NET, 0) != DDI_SUCCESS) {
19323448Sdh155122 		return (-1);
19333448Sdh155122 	}
19343448Sdh155122 	return (0);
19353448Sdh155122 }
19363448Sdh155122 
19373448Sdh155122 void
19383448Sdh155122 mac_vlan_remove(mac_handle_t mh, const char *name)
19393448Sdh155122 {
19403448Sdh155122 	mac_impl_t		*mip = (mac_impl_t *)mh;
19413448Sdh155122 	dev_info_t		*dipp;
19423448Sdh155122 
19433448Sdh155122 	ddi_remove_minor_node(mip->mi_dip, (char *)name);
19443448Sdh155122 	dipp = ddi_get_parent(mip->mi_dip);
19453448Sdh155122 	(void) devfs_clean(dipp, NULL, 0);
19463448Sdh155122 }
1947