xref: /onnv-gate/usr/src/uts/common/io/mac/mac.c (revision 2311:2d86e52dcdf0)
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 /*
221852Syz147064  * Copyright 2006 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>
44*2311Sseb #include <sys/modctl.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #define	IMPL_HASHSZ	67	/* prime */
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static kmem_cache_t	*i_mac_impl_cachep;
49269Sericheng static mod_hash_t	*i_mac_impl_hash;
50269Sericheng krwlock_t		i_mac_impl_lock;
51269Sericheng uint_t			i_mac_impl_count;
520Sstevel@tonic-gate 
53*2311Sseb #define	MACTYPE_KMODDIR	"mac"
54*2311Sseb #define	MACTYPE_HASHSZ	67
55*2311Sseb static mod_hash_t	*i_mactype_hash;
56*2311Sseb 
571852Syz147064 static void i_mac_notify_task(void *);
581852Syz147064 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * Private functions.
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /*ARGSUSED*/
640Sstevel@tonic-gate static int
650Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag)
660Sstevel@tonic-gate {
670Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	bzero(buf, sizeof (mac_impl_t));
700Sstevel@tonic-gate 
71*2311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL);
740Sstevel@tonic-gate 	rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL);
750Sstevel@tonic-gate 	rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL);
760Sstevel@tonic-gate 	rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL);
770Sstevel@tonic-gate 	rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL);
780Sstevel@tonic-gate 	rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL);
790Sstevel@tonic-gate 	mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL);
801852Syz147064 	mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL);
811852Syz147064 	cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL);
820Sstevel@tonic-gate 	return (0);
830Sstevel@tonic-gate }
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*ARGSUSED*/
860Sstevel@tonic-gate static void
870Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate 	mac_impl_t	*mip = buf;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	ASSERT(mip->mi_ref == 0);
920Sstevel@tonic-gate 	ASSERT(mip->mi_active == 0);
93*2311Sseb 	ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN);
940Sstevel@tonic-gate 	ASSERT(mip->mi_devpromisc == 0);
950Sstevel@tonic-gate 	ASSERT(mip->mi_promisc == 0);
960Sstevel@tonic-gate 	ASSERT(mip->mi_mmap == NULL);
970Sstevel@tonic-gate 	ASSERT(mip->mi_mnfp == NULL);
980Sstevel@tonic-gate 	ASSERT(mip->mi_resource_add == NULL);
990Sstevel@tonic-gate 	ASSERT(mip->mi_ksp == NULL);
100*2311Sseb 	ASSERT(mip->mi_kstat_count == 0);
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	rw_destroy(&mip->mi_state_lock);
1030Sstevel@tonic-gate 	rw_destroy(&mip->mi_data_lock);
1040Sstevel@tonic-gate 	rw_destroy(&mip->mi_notify_lock);
1050Sstevel@tonic-gate 	rw_destroy(&mip->mi_rx_lock);
1060Sstevel@tonic-gate 	rw_destroy(&mip->mi_txloop_lock);
1070Sstevel@tonic-gate 	rw_destroy(&mip->mi_resource_lock);
1080Sstevel@tonic-gate 	mutex_destroy(&mip->mi_activelink_lock);
1091852Syz147064 	mutex_destroy(&mip->mi_notify_ref_lock);
1101852Syz147064 	cv_destroy(&mip->mi_notify_cv);
1110Sstevel@tonic-gate }
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate static void
1140Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type)
1150Sstevel@tonic-gate {
1161852Syz147064 	mac_notify_task_arg_t	*mnta;
1171852Syz147064 
1181852Syz147064 	rw_enter(&i_mac_impl_lock, RW_READER);
1191852Syz147064 	if (mip->mi_disabled)
1201852Syz147064 		goto exit;
1211852Syz147064 
1221852Syz147064 	if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) {
1231852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory "
1241852Syz147064 		    "allocation failed", mip->mi_name, type);
1251852Syz147064 		goto exit;
1261852Syz147064 	}
1271852Syz147064 
1281852Syz147064 	mnta->mnt_mip = mip;
1291852Syz147064 	mnta->mnt_type = type;
1301852Syz147064 
1311852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
1321852Syz147064 	mip->mi_notify_ref++;
1331852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
1341852Syz147064 
1351852Syz147064 	rw_exit(&i_mac_impl_lock);
1361852Syz147064 
1371852Syz147064 	if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta,
1381852Syz147064 	    TQ_NOSLEEP) == NULL) {
1391852Syz147064 		cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch "
1401852Syz147064 		    "failed", mip->mi_name, type);
1411852Syz147064 
1421852Syz147064 		mutex_enter(&mip->mi_notify_ref_lock);
1431852Syz147064 		if (--mip->mi_notify_ref == 0)
1441852Syz147064 			cv_signal(&mip->mi_notify_cv);
1451852Syz147064 		mutex_exit(&mip->mi_notify_ref_lock);
1461852Syz147064 
1471852Syz147064 		kmem_free(mnta, sizeof (*mnta));
1481852Syz147064 	}
1491852Syz147064 	return;
1501852Syz147064 
1511852Syz147064 exit:
1521852Syz147064 	rw_exit(&i_mac_impl_lock);
1531852Syz147064 }
1541852Syz147064 
1551852Syz147064 static void
1561852Syz147064 i_mac_notify_task(void *notify_arg)
1571852Syz147064 {
1581852Syz147064 	mac_notify_task_arg_t	*mnta = (mac_notify_task_arg_t *)notify_arg;
1591852Syz147064 	mac_impl_t		*mip;
1601852Syz147064 	mac_notify_type_t	type;
1610Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
1620Sstevel@tonic-gate 	mac_notify_t		notify;
1630Sstevel@tonic-gate 	void			*arg;
1640Sstevel@tonic-gate 
1651852Syz147064 	mip = mnta->mnt_mip;
1661852Syz147064 	type = mnta->mnt_type;
1671852Syz147064 	kmem_free(mnta, sizeof (*mnta));
1681852Syz147064 
1690Sstevel@tonic-gate 	/*
1700Sstevel@tonic-gate 	 * Walk the list of notifications.
1710Sstevel@tonic-gate 	 */
1721852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_READER);
1730Sstevel@tonic-gate 	for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) {
1740Sstevel@tonic-gate 		notify = mnfp->mnf_fn;
1750Sstevel@tonic-gate 		arg = mnfp->mnf_arg;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 		ASSERT(notify != NULL);
1780Sstevel@tonic-gate 		notify(arg, type);
1790Sstevel@tonic-gate 	}
1801852Syz147064 	rw_exit(&mip->mi_notify_lock);
1811852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
1821852Syz147064 	if (--mip->mi_notify_ref == 0)
1831852Syz147064 		cv_signal(&mip->mi_notify_cv);
1841852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
187*2311Sseb static mactype_t *
188*2311Sseb i_mactype_getplugin(const char *plugin_name)
189*2311Sseb {
190*2311Sseb 	mactype_t	*mtype = NULL;
191*2311Sseb 	boolean_t	tried_modload = B_FALSE;
192*2311Sseb 
193*2311Sseb find_registered_mactype:
194*2311Sseb 	if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)plugin_name,
195*2311Sseb 	    (mod_hash_val_t *)&mtype) == 0) {
196*2311Sseb 		/*
197*2311Sseb 		 * Because the reference count is initialized at 1 (see
198*2311Sseb 		 * mactype_register()), we don't need to bump up the
199*2311Sseb 		 * reference count if we're the first reference.
200*2311Sseb 		 */
201*2311Sseb 		if (!tried_modload)
202*2311Sseb 			mtype->mt_ref++;
203*2311Sseb 		return (mtype);
204*2311Sseb 	} else if (tried_modload) {
205*2311Sseb 		return (NULL);
206*2311Sseb 	}
207*2311Sseb 
208*2311Sseb 	/*
209*2311Sseb 	 * If the plugin has not yet been loaded, then attempt to load it
210*2311Sseb 	 * now.  If modload succeeds, the plugin should have registered
211*2311Sseb 	 * using mactype_register(), in which case we can go back and
212*2311Sseb 	 * attempt to find it again.
213*2311Sseb 	 */
214*2311Sseb 	if (modload(MACTYPE_KMODDIR, (char *)plugin_name) != -1) {
215*2311Sseb 		tried_modload = B_TRUE;
216*2311Sseb 		goto find_registered_mactype;
217*2311Sseb 	}
218*2311Sseb 	return (NULL);
219*2311Sseb }
220*2311Sseb 
2210Sstevel@tonic-gate /*
2220Sstevel@tonic-gate  * Module initialization functions.
2230Sstevel@tonic-gate  */
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate void
2260Sstevel@tonic-gate mac_init(void)
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate 	i_mac_impl_cachep = kmem_cache_create("mac_impl_cache",
229*2311Sseb 	    sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor,
230*2311Sseb 	    NULL, NULL, NULL, 0);
2310Sstevel@tonic-gate 	ASSERT(i_mac_impl_cachep != NULL);
2320Sstevel@tonic-gate 
233269Sericheng 	i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash",
234269Sericheng 	    IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
235269Sericheng 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
236269Sericheng 	rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL);
237269Sericheng 	i_mac_impl_count = 0;
238*2311Sseb 
239*2311Sseb 	i_mactype_hash = mod_hash_create_extended("mactype_hash",
240*2311Sseb 	    MACTYPE_HASHSZ,
241*2311Sseb 	    mod_hash_null_keydtor, mod_hash_null_valdtor,
242*2311Sseb 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate int
2460Sstevel@tonic-gate mac_fini(void)
2470Sstevel@tonic-gate {
248269Sericheng 	if (i_mac_impl_count > 0)
249269Sericheng 		return (EBUSY);
2500Sstevel@tonic-gate 
251269Sericheng 	mod_hash_destroy_hash(i_mac_impl_hash);
252269Sericheng 	rw_destroy(&i_mac_impl_lock);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	kmem_cache_destroy(i_mac_impl_cachep);
255*2311Sseb 
256*2311Sseb 	mod_hash_destroy_hash(i_mactype_hash);
2570Sstevel@tonic-gate 	return (0);
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate /*
2610Sstevel@tonic-gate  * Client functions.
2620Sstevel@tonic-gate  */
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate int
265*2311Sseb mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp)
2660Sstevel@tonic-gate {
2670Sstevel@tonic-gate 	char		driver[MAXNAMELEN];
2680Sstevel@tonic-gate 	uint_t		instance;
2690Sstevel@tonic-gate 	major_t		major;
2700Sstevel@tonic-gate 	dev_info_t	*dip;
2710Sstevel@tonic-gate 	mac_impl_t	*mip;
2720Sstevel@tonic-gate 	int		err;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/*
2750Sstevel@tonic-gate 	 * Check the device name length to make sure it won't overflow our
2760Sstevel@tonic-gate 	 * buffer.
2770Sstevel@tonic-gate 	 */
278*2311Sseb 	if (strlen(macname) >= MAXNAMELEN)
2790Sstevel@tonic-gate 		return (EINVAL);
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	/*
2820Sstevel@tonic-gate 	 * Split the device name into driver and instance components.
2830Sstevel@tonic-gate 	 */
284*2311Sseb 	if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS)
2850Sstevel@tonic-gate 		return (EINVAL);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	/*
2880Sstevel@tonic-gate 	 * Get the major number of the driver.
2890Sstevel@tonic-gate 	 */
2900Sstevel@tonic-gate 	if ((major = ddi_name_to_major(driver)) == (major_t)-1)
2910Sstevel@tonic-gate 		return (EINVAL);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	/*
2940Sstevel@tonic-gate 	 * Hold the given instance to prevent it from being detached.
295269Sericheng 	 * This will also attach the instance if it is not currently attached.
296269Sericheng 	 * Currently we ensure that mac_register() (called by the driver's
297269Sericheng 	 * attach entry point) and all code paths under it cannot possibly
298269Sericheng 	 * call mac_open() because this would lead to a recursive attach
299269Sericheng 	 * panic.
3000Sstevel@tonic-gate 	 */
301*2311Sseb 	if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL)
3020Sstevel@tonic-gate 		return (EINVAL);
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	/*
3050Sstevel@tonic-gate 	 * Look up its entry in the global hash table.
3060Sstevel@tonic-gate 	 */
3070Sstevel@tonic-gate again:
308269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
309*2311Sseb 	err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname,
310269Sericheng 	    (mod_hash_val_t *)&mip);
311269Sericheng 	if (err != 0) {
312269Sericheng 		err = ENOENT;
3130Sstevel@tonic-gate 		goto failed;
314269Sericheng 	}
3150Sstevel@tonic-gate 
3161852Syz147064 	if (mip->mi_disabled) {
317269Sericheng 		rw_exit(&i_mac_impl_lock);
3180Sstevel@tonic-gate 		goto again;
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	mip->mi_ref++;
322269Sericheng 	rw_exit(&i_mac_impl_lock);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	*mhp = (mac_handle_t)mip;
3250Sstevel@tonic-gate 	return (0);
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate failed:
328269Sericheng 	rw_exit(&i_mac_impl_lock);
3290Sstevel@tonic-gate 	ddi_release_devi(dip);
3300Sstevel@tonic-gate 	return (err);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate void
3340Sstevel@tonic-gate mac_close(mac_handle_t mh)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
337*2311Sseb 	dev_info_t	*dip = mip->mi_dip;
3380Sstevel@tonic-gate 
339269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	ASSERT(mip->mi_ref != 0);
3420Sstevel@tonic-gate 	if (--mip->mi_ref == 0) {
3430Sstevel@tonic-gate 		ASSERT(!mip->mi_activelink);
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 	ddi_release_devi(dip);
346269Sericheng 	rw_exit(&i_mac_impl_lock);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate const mac_info_t *
3500Sstevel@tonic-gate mac_info(mac_handle_t mh)
3510Sstevel@tonic-gate {
352*2311Sseb 	return (&((mac_impl_t *)mh)->mi_info);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate 
355269Sericheng dev_info_t *
356269Sericheng mac_devinfo_get(mac_handle_t mh)
357269Sericheng {
358*2311Sseb 	return (((mac_impl_t *)mh)->mi_dip);
359269Sericheng }
360269Sericheng 
3610Sstevel@tonic-gate uint64_t
362*2311Sseb mac_stat_get(mac_handle_t mh, uint_t stat)
3630Sstevel@tonic-gate {
3640Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
365*2311Sseb 	uint64_t	val;
366*2311Sseb 	int		ret;
3670Sstevel@tonic-gate 
368*2311Sseb 	/*
369*2311Sseb 	 * The range of stat determines where it is maintained.  Stat
370*2311Sseb 	 * values from 0 up to (but not including) MAC_STAT_MIN are
371*2311Sseb 	 * mainteined by the mac module itself.  Everything else is
372*2311Sseb 	 * maintained by the driver.
373*2311Sseb 	 */
374*2311Sseb 	if (stat < MAC_STAT_MIN) {
375*2311Sseb 		/* These stats are maintained by the mac module itself. */
376*2311Sseb 		switch (stat) {
377*2311Sseb 		case MAC_STAT_LINK_STATE:
378*2311Sseb 			return (mip->mi_linkstate);
379*2311Sseb 		case MAC_STAT_LINK_UP:
380*2311Sseb 			return (mip->mi_linkstate == LINK_STATE_UP);
381*2311Sseb 		case MAC_STAT_PROMISC:
382*2311Sseb 			return (mip->mi_devpromisc != 0);
383*2311Sseb 		default:
384*2311Sseb 			ASSERT(B_FALSE);
385*2311Sseb 		}
386*2311Sseb 	}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	/*
3890Sstevel@tonic-gate 	 * Call the driver to get the given statistic.
3900Sstevel@tonic-gate 	 */
391*2311Sseb 	ret = mip->mi_getstat(mip->mi_driver, stat, &val);
392*2311Sseb 	if (ret != 0) {
393*2311Sseb 		/*
394*2311Sseb 		 * The driver doesn't support this statistic.  Get the
395*2311Sseb 		 * statistic's default value.
396*2311Sseb 		 */
397*2311Sseb 		val = mac_stat_default(mip, stat);
398*2311Sseb 	}
399*2311Sseb 	return (val);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate int
4030Sstevel@tonic-gate mac_start(mac_handle_t mh)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4060Sstevel@tonic-gate 	int		err;
4070Sstevel@tonic-gate 
408*2311Sseb 	ASSERT(mip->mi_start != NULL);
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	/*
4130Sstevel@tonic-gate 	 * Check whether the device is already started.
4140Sstevel@tonic-gate 	 */
4150Sstevel@tonic-gate 	if (mip->mi_active++ != 0) {
4160Sstevel@tonic-gate 		/*
4170Sstevel@tonic-gate 		 * It's already started so there's nothing more to do.
4180Sstevel@tonic-gate 		 */
4190Sstevel@tonic-gate 		err = 0;
4200Sstevel@tonic-gate 		goto done;
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	/*
4240Sstevel@tonic-gate 	 * Start the device.
4250Sstevel@tonic-gate 	 */
426*2311Sseb 	if ((err = mip->mi_start(mip->mi_driver)) != 0)
4270Sstevel@tonic-gate 		--mip->mi_active;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate done:
4300Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
4310Sstevel@tonic-gate 	return (err);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate void
4350Sstevel@tonic-gate mac_stop(mac_handle_t mh)
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
4380Sstevel@tonic-gate 
439*2311Sseb 	ASSERT(mip->mi_stop != NULL);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	rw_enter(&(mip->mi_state_lock), RW_WRITER);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	/*
4440Sstevel@tonic-gate 	 * Check whether the device is still needed.
4450Sstevel@tonic-gate 	 */
4460Sstevel@tonic-gate 	ASSERT(mip->mi_active != 0);
4470Sstevel@tonic-gate 	if (--mip->mi_active != 0) {
4480Sstevel@tonic-gate 		/*
4490Sstevel@tonic-gate 		 * It's still needed so there's nothing more to do.
4500Sstevel@tonic-gate 		 */
4510Sstevel@tonic-gate 		goto done;
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/*
4550Sstevel@tonic-gate 	 * Stop the device.
4560Sstevel@tonic-gate 	 */
457*2311Sseb 	mip->mi_stop(mip->mi_driver);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate done:
4600Sstevel@tonic-gate 	rw_exit(&(mip->mi_state_lock));
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate int
4640Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr)
4650Sstevel@tonic-gate {
4660Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
4670Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
4680Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
4690Sstevel@tonic-gate 	int			err;
4700Sstevel@tonic-gate 
471*2311Sseb 	ASSERT(mip->mi_multicst != NULL);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	/*
4740Sstevel@tonic-gate 	 * Verify the address.
4750Sstevel@tonic-gate 	 */
476*2311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr,
477*2311Sseb 	    mip->mi_pdata)) != 0) {
478*2311Sseb 		return (err);
479*2311Sseb 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	/*
4820Sstevel@tonic-gate 	 * Check whether the given address is already enabled.
4830Sstevel@tonic-gate 	 */
4840Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
4850Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
486*2311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
487*2311Sseb 		    0) {
4880Sstevel@tonic-gate 			/*
4890Sstevel@tonic-gate 			 * The address is already enabled so just bump the
4900Sstevel@tonic-gate 			 * reference count.
4910Sstevel@tonic-gate 			 */
4920Sstevel@tonic-gate 			p->mma_ref++;
4930Sstevel@tonic-gate 			err = 0;
4940Sstevel@tonic-gate 			goto done;
4950Sstevel@tonic-gate 		}
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	/*
4990Sstevel@tonic-gate 	 * Allocate a new list entry.
5000Sstevel@tonic-gate 	 */
5010Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t),
5020Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
5030Sstevel@tonic-gate 		err = ENOMEM;
5040Sstevel@tonic-gate 		goto done;
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	/*
5080Sstevel@tonic-gate 	 * Enable a new multicast address.
5090Sstevel@tonic-gate 	 */
510*2311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) {
5110Sstevel@tonic-gate 		kmem_free(p, sizeof (mac_multicst_addr_t));
5120Sstevel@tonic-gate 		goto done;
5130Sstevel@tonic-gate 	}
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	/*
5160Sstevel@tonic-gate 	 * Add the address to the list of enabled addresses.
5170Sstevel@tonic-gate 	 */
518*2311Sseb 	bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length);
5190Sstevel@tonic-gate 	p->mma_ref++;
5200Sstevel@tonic-gate 	*pp = p;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate done:
5230Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
5240Sstevel@tonic-gate 	return (err);
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate int
5280Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr)
5290Sstevel@tonic-gate {
5300Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
5310Sstevel@tonic-gate 	mac_multicst_addr_t	**pp;
5320Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
5330Sstevel@tonic-gate 	int			err;
5340Sstevel@tonic-gate 
535*2311Sseb 	ASSERT(mip->mi_multicst != NULL);
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	/*
5380Sstevel@tonic-gate 	 * Find the entry in the list for the given address.
5390Sstevel@tonic-gate 	 */
5400Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
5410Sstevel@tonic-gate 	for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) {
542*2311Sseb 		if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) ==
543*2311Sseb 		    0) {
5440Sstevel@tonic-gate 			if (--p->mma_ref == 0)
5450Sstevel@tonic-gate 				break;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 			/*
5480Sstevel@tonic-gate 			 * There is still a reference to this address so
5490Sstevel@tonic-gate 			 * there's nothing more to do.
5500Sstevel@tonic-gate 			 */
5510Sstevel@tonic-gate 			err = 0;
5520Sstevel@tonic-gate 			goto done;
5530Sstevel@tonic-gate 		}
5540Sstevel@tonic-gate 	}
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	/*
5570Sstevel@tonic-gate 	 * We did not find an entry for the given address so it is not
5580Sstevel@tonic-gate 	 * currently enabled.
5590Sstevel@tonic-gate 	 */
5600Sstevel@tonic-gate 	if (p == NULL) {
5610Sstevel@tonic-gate 		err = ENOENT;
5620Sstevel@tonic-gate 		goto done;
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 	ASSERT(p->mma_ref == 0);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	/*
5670Sstevel@tonic-gate 	 * Disable the multicast address.
5680Sstevel@tonic-gate 	 */
569*2311Sseb 	if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) {
5700Sstevel@tonic-gate 		p->mma_ref++;
5710Sstevel@tonic-gate 		goto done;
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	/*
5750Sstevel@tonic-gate 	 * Remove it from the list.
5760Sstevel@tonic-gate 	 */
5770Sstevel@tonic-gate 	*pp = p->mma_nextp;
5780Sstevel@tonic-gate 	kmem_free(p, sizeof (mac_multicst_addr_t));
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate done:
5810Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
5820Sstevel@tonic-gate 	return (err);
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate int
5860Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr)
5870Sstevel@tonic-gate {
5880Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
5890Sstevel@tonic-gate 	int		err;
5900Sstevel@tonic-gate 	boolean_t	notify = B_FALSE;
5910Sstevel@tonic-gate 
592*2311Sseb 	ASSERT(mip->mi_unicst != NULL);
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	/*
5950Sstevel@tonic-gate 	 * Verify the address.
5960Sstevel@tonic-gate 	 */
597*2311Sseb 	if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr,
598*2311Sseb 	    mip->mi_pdata)) != 0) {
599*2311Sseb 		return (err);
600*2311Sseb 	}
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	/*
6030Sstevel@tonic-gate 	 * Program the new unicast address.
6040Sstevel@tonic-gate 	 */
6050Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	/*
6080Sstevel@tonic-gate 	 * If address doesn't change, do nothing.
6090Sstevel@tonic-gate 	 * This check is necessary otherwise it may call into mac_unicst_set
6100Sstevel@tonic-gate 	 * recursively.
6110Sstevel@tonic-gate 	 */
612*2311Sseb 	if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) {
6130Sstevel@tonic-gate 		err = 0;
6140Sstevel@tonic-gate 		goto done;
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 
617*2311Sseb 	if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0)
6180Sstevel@tonic-gate 		goto done;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	/*
6210Sstevel@tonic-gate 	 * Save the address and flag that we need to send a notification.
6220Sstevel@tonic-gate 	 */
623*2311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
6240Sstevel@tonic-gate 	notify = B_TRUE;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate done:
6270Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	if (notify)
6300Sstevel@tonic-gate 		i_mac_notify(mip, MAC_NOTE_UNICST);
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	return (err);
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate void
6360Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr)
6370Sstevel@tonic-gate {
6380Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	/*
641*2311Sseb 	 * Copy out the current unicast source address.
6420Sstevel@tonic-gate 	 */
6430Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
644*2311Sseb 	bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length);
645*2311Sseb 	rw_exit(&(mip->mi_data_lock));
646*2311Sseb }
647*2311Sseb 
648*2311Sseb void
649*2311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr)
650*2311Sseb {
651*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
652*2311Sseb 
653*2311Sseb 	/*
654*2311Sseb 	 * Copy out the current destination address.
655*2311Sseb 	 */
656*2311Sseb 	rw_enter(&(mip->mi_data_lock), RW_READER);
657*2311Sseb 	bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length);
6580Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate int
6620Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype)
6630Sstevel@tonic-gate {
6640Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
6650Sstevel@tonic-gate 	int		err = 0;
6660Sstevel@tonic-gate 
667*2311Sseb 	ASSERT(mip->mi_setpromisc != NULL);
6680Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	/*
6710Sstevel@tonic-gate 	 * Determine whether we should enable or disable promiscuous mode.
6720Sstevel@tonic-gate 	 * For details on the distinction between "device promiscuous mode"
6730Sstevel@tonic-gate 	 * and "MAC promiscuous mode", see PSARC/2005/289.
6740Sstevel@tonic-gate 	 */
6750Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_WRITER);
6760Sstevel@tonic-gate 	if (on) {
6770Sstevel@tonic-gate 		/*
6780Sstevel@tonic-gate 		 * Enable promiscuous mode on the device if not yet enabled.
6790Sstevel@tonic-gate 		 */
6800Sstevel@tonic-gate 		if (mip->mi_devpromisc++ == 0) {
681*2311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_TRUE);
682*2311Sseb 			if (err != 0) {
6830Sstevel@tonic-gate 				mip->mi_devpromisc--;
6840Sstevel@tonic-gate 				goto done;
6850Sstevel@tonic-gate 			}
6860Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
6870Sstevel@tonic-gate 		}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 		/*
6900Sstevel@tonic-gate 		 * Enable promiscuous mode on the MAC if not yet enabled.
6910Sstevel@tonic-gate 		 */
6920Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0)
6930Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
6940Sstevel@tonic-gate 	} else {
6950Sstevel@tonic-gate 		if (mip->mi_devpromisc == 0) {
6960Sstevel@tonic-gate 			err = EPROTO;
6970Sstevel@tonic-gate 			goto done;
6980Sstevel@tonic-gate 		}
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 		/*
7010Sstevel@tonic-gate 		 * Disable promiscuous mode on the device if this is the last
7020Sstevel@tonic-gate 		 * enabling.
7030Sstevel@tonic-gate 		 */
7040Sstevel@tonic-gate 		if (--mip->mi_devpromisc == 0) {
705*2311Sseb 			err = mip->mi_setpromisc(mip->mi_driver, B_FALSE);
706*2311Sseb 			if (err != 0) {
7070Sstevel@tonic-gate 				mip->mi_devpromisc++;
7080Sstevel@tonic-gate 				goto done;
7090Sstevel@tonic-gate 			}
7100Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_DEVPROMISC);
7110Sstevel@tonic-gate 		}
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 		/*
7140Sstevel@tonic-gate 		 * Disable promiscuous mode on the MAC if this is the last
7150Sstevel@tonic-gate 		 * enabling.
7160Sstevel@tonic-gate 		 */
7170Sstevel@tonic-gate 		if (ptype == MAC_PROMISC && --mip->mi_promisc == 0)
7180Sstevel@tonic-gate 			i_mac_notify(mip, MAC_NOTE_PROMISC);
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate done:
7220Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
7230Sstevel@tonic-gate 	return (err);
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate boolean_t
7270Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype)
7280Sstevel@tonic-gate {
7290Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC);
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	/*
7340Sstevel@tonic-gate 	 * Return the current promiscuity.
7350Sstevel@tonic-gate 	 */
7360Sstevel@tonic-gate 	if (ptype == MAC_DEVPROMISC)
7370Sstevel@tonic-gate 		return (mip->mi_devpromisc != 0);
7380Sstevel@tonic-gate 	else
7390Sstevel@tonic-gate 		return (mip->mi_promisc != 0);
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate void
7430Sstevel@tonic-gate mac_resources(mac_handle_t mh)
7440Sstevel@tonic-gate {
7450Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	/*
748*2311Sseb 	 * If the driver supports resource registration, call the driver to
749*2311Sseb 	 * ask it to register its resources.
7500Sstevel@tonic-gate 	 */
751*2311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES)
752*2311Sseb 		mip->mi_resources(mip->mi_driver);
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate void
7560Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp)
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	/*
761*2311Sseb 	 * Call the driver to handle the ioctl.  The driver may not support
762*2311Sseb 	 * any ioctls, in which case we reply with a NAK on its behalf.
7630Sstevel@tonic-gate 	 */
764*2311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_IOCTL)
765*2311Sseb 		mip->mi_ioctl(mip->mi_driver, wq, bp);
766*2311Sseb 	else
767*2311Sseb 		miocnak(wq, bp, 0, EINVAL);
7680Sstevel@tonic-gate }
7690Sstevel@tonic-gate 
77056Smeem const mac_txinfo_t *
77156Smeem mac_tx_get(mac_handle_t mh)
7720Sstevel@tonic-gate {
7730Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
77456Smeem 	mac_txinfo_t	*mtp;
77556Smeem 
77656Smeem 	/*
77756Smeem 	 * Grab the lock to prevent us from racing with MAC_PROMISC being
77856Smeem 	 * changed.  This is sufficient since MAC clients are careful to always
77956Smeem 	 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable
78056Smeem 	 * MAC_PROMISC prior to calling mac_txloop_remove().
78156Smeem 	 */
78256Smeem 	rw_enter(&mip->mi_txloop_lock, RW_READER);
7830Sstevel@tonic-gate 
78456Smeem 	if (mac_promisc_get(mh, MAC_PROMISC)) {
78556Smeem 		ASSERT(mip->mi_mtfp != NULL);
78656Smeem 		mtp = &mip->mi_txloopinfo;
78756Smeem 	} else {
78856Smeem 		/*
78956Smeem 		 * Note that we cannot ASSERT() that mip->mi_mtfp is NULL,
79056Smeem 		 * because to satisfy the above ASSERT(), we have to disable
79156Smeem 		 * MAC_PROMISC prior to calling mac_txloop_remove().
79256Smeem 		 */
79356Smeem 		mtp = &mip->mi_txinfo;
79456Smeem 	}
79556Smeem 
79656Smeem 	rw_exit(&mip->mi_txloop_lock);
79756Smeem 	return (mtp);
7980Sstevel@tonic-gate }
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate link_state_t
8010Sstevel@tonic-gate mac_link_get(mac_handle_t mh)
8020Sstevel@tonic-gate {
803*2311Sseb 	return (((mac_impl_t *)mh)->mi_linkstate);
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate mac_notify_handle_t
8070Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg)
8080Sstevel@tonic-gate {
8090Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8100Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP);
8130Sstevel@tonic-gate 	mnfp->mnf_fn = notify;
8140Sstevel@tonic-gate 	mnfp->mnf_arg = arg;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	/*
8170Sstevel@tonic-gate 	 * Add it to the head of the 'notify' callback list.
8180Sstevel@tonic-gate 	 */
8191852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
8200Sstevel@tonic-gate 	mnfp->mnf_nextp = mip->mi_mnfp;
8210Sstevel@tonic-gate 	mip->mi_mnfp = mnfp;
8221852Syz147064 	rw_exit(&mip->mi_notify_lock);
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	return ((mac_notify_handle_t)mnfp);
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate void
8280Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh)
8290Sstevel@tonic-gate {
8300Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8310Sstevel@tonic-gate 	mac_notify_fn_t		*mnfp = (mac_notify_fn_t *)mnh;
8320Sstevel@tonic-gate 	mac_notify_fn_t		**pp;
8330Sstevel@tonic-gate 	mac_notify_fn_t		*p;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	/*
8360Sstevel@tonic-gate 	 * Search the 'notify' callback list for the function closure.
8370Sstevel@tonic-gate 	 */
8381852Syz147064 	rw_enter(&mip->mi_notify_lock, RW_WRITER);
8390Sstevel@tonic-gate 	for (pp = &(mip->mi_mnfp); (p = *pp) != NULL;
8400Sstevel@tonic-gate 	    pp = &(p->mnf_nextp)) {
8410Sstevel@tonic-gate 		if (p == mnfp)
8420Sstevel@tonic-gate 			break;
8430Sstevel@tonic-gate 	}
8440Sstevel@tonic-gate 	ASSERT(p != NULL);
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	/*
8470Sstevel@tonic-gate 	 * Remove it from the list.
8480Sstevel@tonic-gate 	 */
8490Sstevel@tonic-gate 	*pp = p->mnf_nextp;
8501852Syz147064 	rw_exit(&mip->mi_notify_lock);
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	/*
8530Sstevel@tonic-gate 	 * Free it.
8540Sstevel@tonic-gate 	 */
8550Sstevel@tonic-gate 	kmem_free(mnfp, sizeof (mac_notify_fn_t));
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate void
8590Sstevel@tonic-gate mac_notify(mac_handle_t mh)
8600Sstevel@tonic-gate {
8610Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8620Sstevel@tonic-gate 	mac_notify_type_t	type;
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	for (type = 0; type < MAC_NNOTE; type++)
8650Sstevel@tonic-gate 		i_mac_notify(mip, type);
8660Sstevel@tonic-gate }
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate mac_rx_handle_t
8690Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg)
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
8720Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP);
8750Sstevel@tonic-gate 	mrfp->mrf_fn = rx;
8760Sstevel@tonic-gate 	mrfp->mrf_arg = arg;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/*
8790Sstevel@tonic-gate 	 * Add it to the head of the 'rx' callback list.
8800Sstevel@tonic-gate 	 */
8810Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
8820Sstevel@tonic-gate 	mrfp->mrf_nextp = mip->mi_mrfp;
8830Sstevel@tonic-gate 	mip->mi_mrfp = mrfp;
8840Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	return ((mac_rx_handle_t)mrfp);
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate /*
8900Sstevel@tonic-gate  * Unregister a receive function for this mac.  This removes the function
8910Sstevel@tonic-gate  * from the list of receive functions for this mac.
8920Sstevel@tonic-gate  */
8930Sstevel@tonic-gate void
8940Sstevel@tonic-gate mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh)
8950Sstevel@tonic-gate {
8960Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
8970Sstevel@tonic-gate 	mac_rx_fn_t		*mrfp = (mac_rx_fn_t *)mrh;
8980Sstevel@tonic-gate 	mac_rx_fn_t		**pp;
8990Sstevel@tonic-gate 	mac_rx_fn_t		*p;
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/*
9020Sstevel@tonic-gate 	 * Search the 'rx' callback list for the function closure.
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 	rw_enter(&(mip->mi_rx_lock), RW_WRITER);
9050Sstevel@tonic-gate 	for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) {
9060Sstevel@tonic-gate 		if (p == mrfp)
9070Sstevel@tonic-gate 			break;
9080Sstevel@tonic-gate 	}
9090Sstevel@tonic-gate 	ASSERT(p != NULL);
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	/* Remove it from the list. */
9120Sstevel@tonic-gate 	*pp = p->mrf_nextp;
9130Sstevel@tonic-gate 	kmem_free(mrfp, sizeof (mac_rx_fn_t));
9140Sstevel@tonic-gate 	rw_exit(&(mip->mi_rx_lock));
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate mac_txloop_handle_t
9180Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg)
9190Sstevel@tonic-gate {
9200Sstevel@tonic-gate 	mac_impl_t	*mip = (mac_impl_t *)mh;
9210Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP);
9240Sstevel@tonic-gate 	mtfp->mtf_fn = tx;
9250Sstevel@tonic-gate 	mtfp->mtf_arg = arg;
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	/*
9280Sstevel@tonic-gate 	 * Add it to the head of the 'tx' callback list.
9290Sstevel@tonic-gate 	 */
9300Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
9310Sstevel@tonic-gate 	mtfp->mtf_nextp = mip->mi_mtfp;
9320Sstevel@tonic-gate 	mip->mi_mtfp = mtfp;
9330Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	return ((mac_txloop_handle_t)mtfp);
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate /*
9390Sstevel@tonic-gate  * Unregister a transmit function for this mac.  This removes the function
9400Sstevel@tonic-gate  * from the list of transmit functions for this mac.
9410Sstevel@tonic-gate  */
9420Sstevel@tonic-gate void
9430Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth)
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9460Sstevel@tonic-gate 	mac_txloop_fn_t		*mtfp = (mac_txloop_fn_t *)mth;
9470Sstevel@tonic-gate 	mac_txloop_fn_t		**pp;
9480Sstevel@tonic-gate 	mac_txloop_fn_t		*p;
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	/*
9510Sstevel@tonic-gate 	 * Search the 'tx' callback list for the function.
9520Sstevel@tonic-gate 	 */
9530Sstevel@tonic-gate 	rw_enter(&(mip->mi_txloop_lock), RW_WRITER);
9540Sstevel@tonic-gate 	for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) {
9550Sstevel@tonic-gate 		if (p == mtfp)
9560Sstevel@tonic-gate 			break;
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 	ASSERT(p != NULL);
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	/* Remove it from the list. */
9610Sstevel@tonic-gate 	*pp = p->mtf_nextp;
9620Sstevel@tonic-gate 	kmem_free(mtfp, sizeof (mac_txloop_fn_t));
9630Sstevel@tonic-gate 	rw_exit(&(mip->mi_txloop_lock));
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate void
9670Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg)
9680Sstevel@tonic-gate {
9690Sstevel@tonic-gate 	mac_impl_t		*mip = (mac_impl_t *)mh;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	/*
9720Sstevel@tonic-gate 	 * Update the 'resource_add' callbacks.
9730Sstevel@tonic-gate 	 */
9740Sstevel@tonic-gate 	rw_enter(&(mip->mi_resource_lock), RW_WRITER);
9750Sstevel@tonic-gate 	mip->mi_resource_add = add;
9760Sstevel@tonic-gate 	mip->mi_resource_add_arg = arg;
9770Sstevel@tonic-gate 	rw_exit(&(mip->mi_resource_lock));
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate /*
9810Sstevel@tonic-gate  * Driver support functions.
9820Sstevel@tonic-gate  */
9830Sstevel@tonic-gate 
984*2311Sseb mac_register_t *
985*2311Sseb mac_alloc(uint_t mac_version)
9860Sstevel@tonic-gate {
987*2311Sseb 	mac_register_t *mregp;
988*2311Sseb 
989*2311Sseb 	/*
990*2311Sseb 	 * Make sure there isn't a version mismatch between the driver and
991*2311Sseb 	 * the framework.  In the future, if multiple versions are
992*2311Sseb 	 * supported, this check could become more sophisticated.
993*2311Sseb 	 */
994*2311Sseb 	if (mac_version != MAC_VERSION)
995*2311Sseb 		return (NULL);
996*2311Sseb 
997*2311Sseb 	mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP);
998*2311Sseb 	mregp->m_version = mac_version;
999*2311Sseb 	return (mregp);
1000*2311Sseb }
1001*2311Sseb 
1002*2311Sseb void
1003*2311Sseb mac_free(mac_register_t *mregp)
1004*2311Sseb {
1005*2311Sseb 	kmem_free(mregp, sizeof (mac_register_t));
1006*2311Sseb }
1007*2311Sseb 
1008*2311Sseb /*
1009*2311Sseb  * mac_register() is how drivers register new MACs with the GLDv3
1010*2311Sseb  * framework.  The mregp argument is allocated by drivers using the
1011*2311Sseb  * mac_alloc() function, and can be freed using mac_free() immediately upon
1012*2311Sseb  * return from mac_register().  Upon success (0 return value), the mhp
1013*2311Sseb  * opaque pointer becomes the driver's handle to its MAC interface, and is
1014*2311Sseb  * the argument to all other mac module entry points.
1015*2311Sseb  */
1016*2311Sseb /* ARGSUSED */
1017*2311Sseb int
1018*2311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp)
1019*2311Sseb {
1020*2311Sseb 	mac_impl_t	*mip;
1021*2311Sseb 	mactype_t	*mtype;
1022*2311Sseb 	int		err;
10230Sstevel@tonic-gate 	struct devnames *dnp;
1024*2311Sseb 	minor_t		minor;
1025*2311Sseb 	mod_hash_val_t	val;
1026*2311Sseb 	boolean_t	style1_created = B_FALSE, style2_created = B_FALSE;
1027*2311Sseb 
1028*2311Sseb 	/* Find the required MAC-Type plugin. */
1029*2311Sseb 	if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL)
1030*2311Sseb 		return (EINVAL);
1031*2311Sseb 
1032*2311Sseb 	/* Create a mac_impl_t to represent this MAC. */
1033*2311Sseb 	mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP);
1034*2311Sseb 
1035*2311Sseb 	/*
1036*2311Sseb 	 * The mac is not ready for open yet.
1037*2311Sseb 	 */
1038*2311Sseb 	mip->mi_disabled = B_TRUE;
1039*2311Sseb 
1040*2311Sseb 	mip->mi_drvname = ddi_driver_name(mregp->m_dip);
1041*2311Sseb 	/*
1042*2311Sseb 	 * Some drivers such as aggr need to register multiple MACs.  Such
1043*2311Sseb 	 * drivers must supply a non-zero "instance" argument so that each
1044*2311Sseb 	 * MAC can be assigned a unique MAC name and can have unique
1045*2311Sseb 	 * kstats.
1046*2311Sseb 	 */
1047*2311Sseb 	mip->mi_instance = ((mregp->m_instance == 0) ?
1048*2311Sseb 	    ddi_get_instance(mregp->m_dip) : mregp->m_instance);
1049*2311Sseb 
1050*2311Sseb 	/* Construct the MAC name as <drvname><instance> */
1051*2311Sseb 	(void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d",
1052*2311Sseb 	    mip->mi_drvname, mip->mi_instance);
1053*2311Sseb 
1054*2311Sseb 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1055*2311Sseb 	if (mod_hash_insert(i_mac_impl_hash,
1056*2311Sseb 	    (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) {
1057*2311Sseb 		kmem_cache_free(i_mac_impl_cachep, mip);
1058*2311Sseb 		rw_exit(&i_mac_impl_lock);
1059*2311Sseb 		return (EEXIST);
1060*2311Sseb 	}
1061*2311Sseb 	i_mac_impl_count++;
1062*2311Sseb 
1063*2311Sseb 	mip->mi_driver = mregp->m_driver;
1064*2311Sseb 
1065*2311Sseb 	mip->mi_type = mtype;
10660Sstevel@tonic-gate 
1067*2311Sseb 	mip->mi_info.mi_media = mtype->mt_type;
1068*2311Sseb 	mip->mi_info.mi_sdu_min = mregp->m_min_sdu;
1069*2311Sseb 	if (mregp->m_max_sdu <= mregp->m_min_sdu) {
1070*2311Sseb 		err = EINVAL;
1071*2311Sseb 		goto fail;
1072*2311Sseb 	}
1073*2311Sseb 	mip->mi_info.mi_sdu_max = mregp->m_max_sdu;
1074*2311Sseb 	mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length;
1075*2311Sseb 	/*
1076*2311Sseb 	 * If the media supports a broadcast address, cache a pointer to it
1077*2311Sseb 	 * in the mac_info_t so that upper layers can use it.
1078*2311Sseb 	 */
1079*2311Sseb 	mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr;
1080269Sericheng 
1081*2311Sseb 	/*
1082*2311Sseb 	 * Copy the unicast source address into the mac_info_t, but only if
1083*2311Sseb 	 * the MAC-Type defines a non-zero address length.  We need to
1084*2311Sseb 	 * handle MAC-Types that have an address length of 0
1085*2311Sseb 	 * (point-to-point protocol MACs for example).
1086*2311Sseb 	 */
1087*2311Sseb 	if (mip->mi_type->mt_addr_length > 0) {
1088*2311Sseb 		if (mregp->m_src_addr == NULL) {
1089*2311Sseb 			err = EINVAL;
1090*2311Sseb 			goto fail;
1091*2311Sseb 		}
1092*2311Sseb 		mip->mi_info.mi_unicst_addr =
1093*2311Sseb 		    kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP);
1094*2311Sseb 		bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr,
1095*2311Sseb 		    mip->mi_type->mt_addr_length);
1096*2311Sseb 
1097*2311Sseb 		/*
1098*2311Sseb 		 * Copy the fixed 'factory' MAC address from the immutable
1099*2311Sseb 		 * info.  This is taken to be the MAC address currently in
1100*2311Sseb 		 * use.
1101*2311Sseb 		 */
1102*2311Sseb 		bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr,
1103*2311Sseb 		    mip->mi_type->mt_addr_length);
1104*2311Sseb 		/* Copy the destination address if one is provided. */
1105*2311Sseb 		if (mregp->m_dst_addr != NULL) {
1106*2311Sseb 			bcopy(mregp->m_dst_addr, mip->mi_dstaddr,
1107*2311Sseb 			    mip->mi_type->mt_addr_length);
1108*2311Sseb 		}
1109*2311Sseb 	} else if (mregp->m_src_addr != NULL) {
1110*2311Sseb 		err = EINVAL;
1111*2311Sseb 		goto fail;
1112269Sericheng 	}
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	/*
1115*2311Sseb 	 * The format of the m_pdata is specific to the plugin.  It is
1116*2311Sseb 	 * passed in as an argument to all of the plugin callbacks.  The
1117*2311Sseb 	 * driver can update this information by calling
1118*2311Sseb 	 * mac_pdata_update().
11190Sstevel@tonic-gate 	 */
1120*2311Sseb 	if (mregp->m_pdata != NULL) {
1121*2311Sseb 		/*
1122*2311Sseb 		 * Verify that the plugin supports MAC plugin data and that
1123*2311Sseb 		 * the supplied data is valid.
1124*2311Sseb 		 */
1125*2311Sseb 		if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) {
1126*2311Sseb 			err = EINVAL;
1127*2311Sseb 			goto fail;
1128*2311Sseb 		}
1129*2311Sseb 		if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata,
1130*2311Sseb 		    mregp->m_pdata_size)) {
1131*2311Sseb 			err = EINVAL;
1132*2311Sseb 			goto fail;
1133*2311Sseb 		}
1134*2311Sseb 		mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP);
1135*2311Sseb 		bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size);
1136*2311Sseb 		mip->mi_pdata_size = mregp->m_pdata_size;
1137*2311Sseb 	}
1138*2311Sseb 
1139*2311Sseb 	/*
1140*2311Sseb 	 * Stash the driver callbacks into the mac_impl_t, but first sanity
1141*2311Sseb 	 * check to make sure all mandatory callbacks are set.
1142*2311Sseb 	 */
1143*2311Sseb 	if (mregp->m_callbacks->mc_getstat == NULL ||
1144*2311Sseb 	    mregp->m_callbacks->mc_start == NULL ||
1145*2311Sseb 	    mregp->m_callbacks->mc_stop == NULL ||
1146*2311Sseb 	    mregp->m_callbacks->mc_setpromisc == NULL ||
1147*2311Sseb 	    mregp->m_callbacks->mc_multicst == NULL ||
1148*2311Sseb 	    mregp->m_callbacks->mc_unicst == NULL ||
1149*2311Sseb 	    mregp->m_callbacks->mc_tx == NULL) {
1150*2311Sseb 		err = EINVAL;
1151*2311Sseb 		goto fail;
1152*2311Sseb 	}
1153*2311Sseb 	mip->mi_callbacks = mregp->m_callbacks;
1154*2311Sseb 
1155*2311Sseb 	mip->mi_dip = mregp->m_dip;
1156*2311Sseb 
1157*2311Sseb 	/*
1158*2311Sseb 	 * Set up the two possible transmit routines.
1159*2311Sseb 	 */
1160*2311Sseb 	mip->mi_txinfo.mt_fn = mip->mi_tx;
1161*2311Sseb 	mip->mi_txinfo.mt_arg = mip->mi_driver;
1162*2311Sseb 	mip->mi_txloopinfo.mt_fn = mac_txloop;
1163*2311Sseb 	mip->mi_txloopinfo.mt_arg = mip;
1164*2311Sseb 
1165*2311Sseb 	/*
1166*2311Sseb 	 * Initialize the kstats for this device.
1167*2311Sseb 	 */
1168*2311Sseb 	mac_stat_create(mip);
11690Sstevel@tonic-gate 
1170269Sericheng 	err = EEXIST;
1171*2311Sseb 	/* Create a style-2 DLPI device */
1172*2311Sseb 	if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname,
1173*2311Sseb 	    S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS)
1174*2311Sseb 		goto fail;
1175*2311Sseb 	style2_created = B_TRUE;
1176269Sericheng 
1177*2311Sseb 	/* Create a style-1 DLPI device */
1178*2311Sseb 	minor = (minor_t)mip->mi_instance + 1;
1179*2311Sseb 	if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor,
1180*2311Sseb 	    DDI_NT_NET, 0) != DDI_SUCCESS)
1181*2311Sseb 		goto fail;
1182*2311Sseb 	style1_created = B_TRUE;
11830Sstevel@tonic-gate 
1184*2311Sseb 	/*
1185*2311Sseb 	 * Create a link for this MAC.  The link name will be the same as
1186*2311Sseb 	 * the MAC name.
1187*2311Sseb 	 */
1188*2311Sseb 	err = dls_create(mip->mi_name, mip->mi_name,
1189*2311Sseb 	    ddi_get_instance(mip->mi_dip));
1190*2311Sseb 	if (err != 0)
1191*2311Sseb 		goto fail;
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	/* set the gldv3 flag in dn_flags */
1194*2311Sseb 	dnp = &devnamesp[ddi_driver_major(mip->mi_dip)];
11950Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
11960Sstevel@tonic-gate 	dnp->dn_flags |= DN_GLDV3_DRIVER;
11970Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
11980Sstevel@tonic-gate 
11991852Syz147064 	/*
12001852Syz147064 	 * Mark the MAC to be ready for open.
12011852Syz147064 	 */
1202*2311Sseb 	mip->mi_disabled = B_FALSE;
1203*2311Sseb 
1204*2311Sseb 	cmn_err(CE_NOTE, "!%s registered", mip->mi_name);
12051852Syz147064 	rw_exit(&i_mac_impl_lock);
1206*2311Sseb 	*mhp = (mac_handle_t)mip;
1207269Sericheng 	return (0);
12080Sstevel@tonic-gate 
1209*2311Sseb fail:
1210*2311Sseb 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
1211*2311Sseb 	    &val);
1212*2311Sseb 	ASSERT(mip == (mac_impl_t *)val);
1213*2311Sseb 	i_mac_impl_count--;
1214*2311Sseb 
1215*2311Sseb 	if (mip->mi_info.mi_unicst_addr != NULL) {
1216*2311Sseb 		kmem_free(mip->mi_info.mi_unicst_addr,
1217*2311Sseb 		    mip->mi_type->mt_addr_length);
1218*2311Sseb 		mip->mi_info.mi_unicst_addr = NULL;
1219*2311Sseb 	}
1220*2311Sseb 	if (style1_created)
1221*2311Sseb 		ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
1222*2311Sseb 	if (style2_created)
1223*2311Sseb 		ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
1224*2311Sseb 
1225*2311Sseb 	mac_stat_destroy(mip);
1226*2311Sseb 
1227*2311Sseb 	if (mip->mi_type != NULL) {
1228*2311Sseb 		mip->mi_type->mt_ref--;
1229*2311Sseb 		mip->mi_type = NULL;
1230*2311Sseb 	}
1231*2311Sseb 
1232*2311Sseb 	if (mip->mi_pdata != NULL) {
1233*2311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1234*2311Sseb 		mip->mi_pdata = NULL;
1235*2311Sseb 		mip->mi_pdata_size = 0;
1236*2311Sseb 	}
1237*2311Sseb 
1238*2311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
1239*2311Sseb 	rw_exit(&i_mac_impl_lock);
1240269Sericheng 	return (err);
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate int
1244*2311Sseb mac_unregister(mac_handle_t mh)
12450Sstevel@tonic-gate {
1246*2311Sseb 	int			err;
1247*2311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
1248*2311Sseb 	mod_hash_val_t		val;
1249*2311Sseb 	mac_multicst_addr_t	*p, *nextp;
1250269Sericheng 
12510Sstevel@tonic-gate 	/*
12520Sstevel@tonic-gate 	 * See if there are any other references to this mac_t (e.g., VLAN's).
12531852Syz147064 	 * If not, set mi_disabled to prevent any new VLAN's from being
1254*2311Sseb 	 * created while we're destroying this mac.
12550Sstevel@tonic-gate 	 */
1256269Sericheng 	rw_enter(&i_mac_impl_lock, RW_WRITER);
12570Sstevel@tonic-gate 	if (mip->mi_ref > 0) {
1258269Sericheng 		rw_exit(&i_mac_impl_lock);
12590Sstevel@tonic-gate 		return (EBUSY);
12600Sstevel@tonic-gate 	}
12611852Syz147064 	mip->mi_disabled = B_TRUE;
1262269Sericheng 	rw_exit(&i_mac_impl_lock);
12630Sstevel@tonic-gate 
12641852Syz147064 	/*
12651852Syz147064 	 * Wait for all taskqs which process the mac notifications to finish.
12661852Syz147064 	 */
12671852Syz147064 	mutex_enter(&mip->mi_notify_ref_lock);
12681852Syz147064 	while (mip->mi_notify_ref != 0)
12691852Syz147064 		cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock);
12701852Syz147064 	mutex_exit(&mip->mi_notify_ref_lock);
12711852Syz147064 
1272*2311Sseb 	if ((err = dls_destroy(mip->mi_name)) != 0) {
1273269Sericheng 		rw_enter(&i_mac_impl_lock, RW_WRITER);
12741852Syz147064 		mip->mi_disabled = B_FALSE;
1275269Sericheng 		rw_exit(&i_mac_impl_lock);
1276269Sericheng 		return (err);
12770Sstevel@tonic-gate 	}
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	/*
1280*2311Sseb 	 * Remove both style 1 and style 2 minor nodes
12810Sstevel@tonic-gate 	 */
1282*2311Sseb 	ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname);
1283*2311Sseb 	ddi_remove_minor_node(mip->mi_dip, mip->mi_name);
1284*2311Sseb 
1285*2311Sseb 	ASSERT(!mip->mi_activelink);
1286*2311Sseb 
1287*2311Sseb 	mac_stat_destroy(mip);
1288*2311Sseb 
1289*2311Sseb 	(void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name,
1290*2311Sseb 	    &val);
1291*2311Sseb 	ASSERT(mip == (mac_impl_t *)val);
1292*2311Sseb 
1293*2311Sseb 	ASSERT(i_mac_impl_count > 0);
1294*2311Sseb 	i_mac_impl_count--;
1295*2311Sseb 
1296*2311Sseb 	if (mip->mi_pdata != NULL)
1297*2311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1298*2311Sseb 	mip->mi_pdata = NULL;
1299*2311Sseb 	mip->mi_pdata_size = 0;
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	/*
1302*2311Sseb 	 * Free the list of multicast addresses.
13030Sstevel@tonic-gate 	 */
1304*2311Sseb 	for (p = mip->mi_mmap; p != NULL; p = nextp) {
1305*2311Sseb 		nextp = p->mma_nextp;
1306*2311Sseb 		kmem_free(p, sizeof (mac_multicst_addr_t));
1307*2311Sseb 	}
1308*2311Sseb 	mip->mi_mmap = NULL;
13090Sstevel@tonic-gate 
1310*2311Sseb 	mip->mi_linkstate = LINK_STATE_UNKNOWN;
1311*2311Sseb 	kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length);
1312*2311Sseb 	mip->mi_info.mi_unicst_addr = NULL;
1313*2311Sseb 
1314*2311Sseb 	mip->mi_type->mt_ref--;
1315*2311Sseb 	mip->mi_type = NULL;
1316*2311Sseb 
1317*2311Sseb 	cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name);
1318*2311Sseb 
1319*2311Sseb 	kmem_cache_free(i_mac_impl_cachep, mip);
1320*2311Sseb 
13210Sstevel@tonic-gate 	return (0);
13220Sstevel@tonic-gate }
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate void
1325*2311Sseb mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp)
13260Sstevel@tonic-gate {
1327*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
13280Sstevel@tonic-gate 	mac_rx_fn_t	*mrfp;
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	/*
13310Sstevel@tonic-gate 	 * Call all registered receive functions.
13320Sstevel@tonic-gate 	 */
13330Sstevel@tonic-gate 	rw_enter(&mip->mi_rx_lock, RW_READER);
13340Sstevel@tonic-gate 	mrfp = mip->mi_mrfp;
13350Sstevel@tonic-gate 	if (mrfp == NULL) {
13360Sstevel@tonic-gate 		/* There are no registered receive functions. */
13370Sstevel@tonic-gate 		freemsgchain(bp);
13380Sstevel@tonic-gate 		rw_exit(&mip->mi_rx_lock);
13390Sstevel@tonic-gate 		return;
13400Sstevel@tonic-gate 	}
13410Sstevel@tonic-gate 	do {
13420Sstevel@tonic-gate 		mblk_t *recv_bp;
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 		if (mrfp->mrf_nextp != NULL) {
13450Sstevel@tonic-gate 			/* XXX Do we bump a counter if copymsgchain() fails? */
13460Sstevel@tonic-gate 			recv_bp = copymsgchain(bp);
13470Sstevel@tonic-gate 		} else {
13480Sstevel@tonic-gate 			recv_bp = bp;
13490Sstevel@tonic-gate 		}
13500Sstevel@tonic-gate 		if (recv_bp != NULL)
13510Sstevel@tonic-gate 			mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp);
13520Sstevel@tonic-gate 		mrfp = mrfp->mrf_nextp;
13530Sstevel@tonic-gate 	} while (mrfp != NULL);
13540Sstevel@tonic-gate 	rw_exit(&mip->mi_rx_lock);
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate /*
13580Sstevel@tonic-gate  * Transmit function -- ONLY used when there are registered loopback listeners.
13590Sstevel@tonic-gate  */
13600Sstevel@tonic-gate mblk_t *
13610Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp)
13620Sstevel@tonic-gate {
13630Sstevel@tonic-gate 	mac_impl_t	*mip = arg;
13640Sstevel@tonic-gate 	mac_txloop_fn_t	*mtfp;
13650Sstevel@tonic-gate 	mblk_t		*loop_bp, *resid_bp, *next_bp;
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	while (bp != NULL) {
13680Sstevel@tonic-gate 		next_bp = bp->b_next;
13690Sstevel@tonic-gate 		bp->b_next = NULL;
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 		if ((loop_bp = copymsg(bp)) == NULL)
13720Sstevel@tonic-gate 			goto noresources;
13730Sstevel@tonic-gate 
1374*2311Sseb 		if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) {
13750Sstevel@tonic-gate 			ASSERT(resid_bp == bp);
13760Sstevel@tonic-gate 			freemsg(loop_bp);
13770Sstevel@tonic-gate 			goto noresources;
13780Sstevel@tonic-gate 		}
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 		rw_enter(&mip->mi_txloop_lock, RW_READER);
13810Sstevel@tonic-gate 		mtfp = mip->mi_mtfp;
138256Smeem 		while (mtfp != NULL && loop_bp != NULL) {
13830Sstevel@tonic-gate 			bp = loop_bp;
138456Smeem 
138556Smeem 			/* XXX counter bump if copymsg() fails? */
138656Smeem 			if (mtfp->mtf_nextp != NULL)
13870Sstevel@tonic-gate 				loop_bp = copymsg(bp);
138856Smeem 			else
138956Smeem 				loop_bp = NULL;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 			mtfp->mtf_fn(mtfp->mtf_arg, bp);
139256Smeem 			mtfp = mtfp->mtf_nextp;
13930Sstevel@tonic-gate 		}
139456Smeem 		rw_exit(&mip->mi_txloop_lock);
13950Sstevel@tonic-gate 
139656Smeem 		/*
139756Smeem 		 * It's possible we've raced with the disabling of promiscuous
139856Smeem 		 * mode, in which case we can discard our copy.
139956Smeem 		 */
140056Smeem 		if (loop_bp != NULL)
140156Smeem 			freemsg(loop_bp);
140256Smeem 
14030Sstevel@tonic-gate 		bp = next_bp;
14040Sstevel@tonic-gate 	}
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	return (NULL);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate noresources:
14090Sstevel@tonic-gate 	bp->b_next = next_bp;
14100Sstevel@tonic-gate 	return (bp);
14110Sstevel@tonic-gate }
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate void
1414*2311Sseb mac_link_update(mac_handle_t mh, link_state_t link)
14150Sstevel@tonic-gate {
1416*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 	/*
14190Sstevel@tonic-gate 	 * Save the link state.
14200Sstevel@tonic-gate 	 */
1421*2311Sseb 	mip->mi_linkstate = link;
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	/*
14240Sstevel@tonic-gate 	 * Send a MAC_NOTE_LINK notification.
14250Sstevel@tonic-gate 	 */
14260Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_LINK);
14270Sstevel@tonic-gate }
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate void
1430*2311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr)
14310Sstevel@tonic-gate {
1432*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
14330Sstevel@tonic-gate 
1434*2311Sseb 	if (mip->mi_type->mt_addr_length == 0)
1435*2311Sseb 		return;
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	/*
14380Sstevel@tonic-gate 	 * Save the address.
14390Sstevel@tonic-gate 	 */
1440*2311Sseb 	bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length);
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	/*
14430Sstevel@tonic-gate 	 * Send a MAC_NOTE_UNICST notification.
14440Sstevel@tonic-gate 	 */
14450Sstevel@tonic-gate 	i_mac_notify(mip, MAC_NOTE_UNICST);
14460Sstevel@tonic-gate }
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate void
1449*2311Sseb mac_tx_update(mac_handle_t mh)
14500Sstevel@tonic-gate {
14510Sstevel@tonic-gate 	/*
14520Sstevel@tonic-gate 	 * Send a MAC_NOTE_TX notification.
14530Sstevel@tonic-gate 	 */
1454*2311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX);
14550Sstevel@tonic-gate }
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate void
1458*2311Sseb mac_resource_update(mac_handle_t mh)
14590Sstevel@tonic-gate {
14600Sstevel@tonic-gate 	/*
14610Sstevel@tonic-gate 	 * Send a MAC_NOTE_RESOURCE notification.
14620Sstevel@tonic-gate 	 */
1463*2311Sseb 	i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE);
14640Sstevel@tonic-gate }
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate mac_resource_handle_t
1467*2311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp)
14680Sstevel@tonic-gate {
1469*2311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
14700Sstevel@tonic-gate 	mac_resource_handle_t	mrh;
14710Sstevel@tonic-gate 	mac_resource_add_t	add;
14720Sstevel@tonic-gate 	void			*arg;
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	rw_enter(&mip->mi_resource_lock, RW_READER);
14750Sstevel@tonic-gate 	add = mip->mi_resource_add;
14760Sstevel@tonic-gate 	arg = mip->mi_resource_add_arg;
14770Sstevel@tonic-gate 
14781184Skrgopi 	if (add != NULL)
14791184Skrgopi 		mrh = add(arg, mrp);
14801184Skrgopi 	else
14811184Skrgopi 		mrh = NULL;
14820Sstevel@tonic-gate 	rw_exit(&mip->mi_resource_lock);
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 	return (mrh);
14850Sstevel@tonic-gate }
14860Sstevel@tonic-gate 
1487*2311Sseb int
1488*2311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize)
1489*2311Sseb {
1490*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
1491*2311Sseb 
1492*2311Sseb 	/*
1493*2311Sseb 	 * Verify that the plugin supports MAC plugin data and that the
1494*2311Sseb 	 * supplied data is valid.
1495*2311Sseb 	 */
1496*2311Sseb 	if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY))
1497*2311Sseb 		return (EINVAL);
1498*2311Sseb 	if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize))
1499*2311Sseb 		return (EINVAL);
1500*2311Sseb 
1501*2311Sseb 	if (mip->mi_pdata != NULL)
1502*2311Sseb 		kmem_free(mip->mi_pdata, mip->mi_pdata_size);
1503*2311Sseb 
1504*2311Sseb 	mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP);
1505*2311Sseb 	bcopy(mac_pdata, mip->mi_pdata, dsize);
1506*2311Sseb 	mip->mi_pdata_size = dsize;
1507*2311Sseb 
1508*2311Sseb 	/*
1509*2311Sseb 	 * Since the MAC plugin data is used to construct MAC headers that
1510*2311Sseb 	 * were cached in fast-path headers, we need to flush fast-path
1511*2311Sseb 	 * information for links associated with this mac.
1512*2311Sseb 	 */
1513*2311Sseb 	i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH);
1514*2311Sseb 	return (0);
1515*2311Sseb }
1516*2311Sseb 
15170Sstevel@tonic-gate void
1518*2311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg,
15190Sstevel@tonic-gate     boolean_t add)
15200Sstevel@tonic-gate {
1521*2311Sseb 	mac_impl_t		*mip = (mac_impl_t *)mh;
15220Sstevel@tonic-gate 	mac_multicst_addr_t	*p;
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	/*
15250Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
15260Sstevel@tonic-gate 	 * driver's m_multicst entry point.
15270Sstevel@tonic-gate 	 */
15280Sstevel@tonic-gate 	if (refresh == NULL) {
1529*2311Sseb 		refresh = mip->mi_multicst;
1530*2311Sseb 		arg = mip->mi_driver;
15310Sstevel@tonic-gate 	}
15320Sstevel@tonic-gate 	ASSERT(refresh != NULL);
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	/*
15350Sstevel@tonic-gate 	 * Walk the multicast address list and call the refresh function for
15360Sstevel@tonic-gate 	 * each address.
15370Sstevel@tonic-gate 	 */
15380Sstevel@tonic-gate 	rw_enter(&(mip->mi_data_lock), RW_READER);
15390Sstevel@tonic-gate 	for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp)
15400Sstevel@tonic-gate 		refresh(arg, add, p->mma_addr);
15410Sstevel@tonic-gate 	rw_exit(&(mip->mi_data_lock));
15420Sstevel@tonic-gate }
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate void
1545*2311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg)
15460Sstevel@tonic-gate {
1547*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
15480Sstevel@tonic-gate 	/*
15490Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
1550*2311Sseb 	 * driver's mi_unicst entry point.
15510Sstevel@tonic-gate 	 */
15520Sstevel@tonic-gate 	if (refresh == NULL) {
1553*2311Sseb 		refresh = mip->mi_unicst;
1554*2311Sseb 		arg = mip->mi_driver;
15550Sstevel@tonic-gate 	}
15560Sstevel@tonic-gate 	ASSERT(refresh != NULL);
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 	/*
15590Sstevel@tonic-gate 	 * Call the refresh function with the current unicast address.
15600Sstevel@tonic-gate 	 */
15610Sstevel@tonic-gate 	refresh(arg, mip->mi_addr);
15620Sstevel@tonic-gate }
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate void
1565*2311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg)
15660Sstevel@tonic-gate {
1567*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 	/*
15700Sstevel@tonic-gate 	 * If no specific refresh function was given then default to the
15710Sstevel@tonic-gate 	 * driver's m_promisc entry point.
15720Sstevel@tonic-gate 	 */
15730Sstevel@tonic-gate 	if (refresh == NULL) {
1574*2311Sseb 		refresh = mip->mi_setpromisc;
1575*2311Sseb 		arg = mip->mi_driver;
15760Sstevel@tonic-gate 	}
15770Sstevel@tonic-gate 	ASSERT(refresh != NULL);
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	/*
15800Sstevel@tonic-gate 	 * Call the refresh function with the current promiscuity.
15810Sstevel@tonic-gate 	 */
15820Sstevel@tonic-gate 	refresh(arg, (mip->mi_devpromisc != 0));
15830Sstevel@tonic-gate }
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate boolean_t
15860Sstevel@tonic-gate mac_active_set(mac_handle_t mh)
15870Sstevel@tonic-gate {
15880Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
15910Sstevel@tonic-gate 	if (mip->mi_activelink) {
15920Sstevel@tonic-gate 		mutex_exit(&mip->mi_activelink_lock);
15930Sstevel@tonic-gate 		return (B_FALSE);
15940Sstevel@tonic-gate 	}
15950Sstevel@tonic-gate 	mip->mi_activelink = B_TRUE;
15960Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
15970Sstevel@tonic-gate 	return (B_TRUE);
15980Sstevel@tonic-gate }
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate void
16010Sstevel@tonic-gate mac_active_clear(mac_handle_t mh)
16020Sstevel@tonic-gate {
16030Sstevel@tonic-gate 	mac_impl_t *mip = (mac_impl_t *)mh;
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	mutex_enter(&mip->mi_activelink_lock);
16060Sstevel@tonic-gate 	ASSERT(mip->mi_activelink);
16070Sstevel@tonic-gate 	mip->mi_activelink = B_FALSE;
16080Sstevel@tonic-gate 	mutex_exit(&mip->mi_activelink_lock);
16090Sstevel@tonic-gate }
1610269Sericheng 
1611269Sericheng /*
1612269Sericheng  * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is
1613269Sericheng  * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find
1614269Sericheng  * the first mac_impl_t with a matching driver name; then we copy its mac_info_t
1615269Sericheng  * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t
1616269Sericheng  * cannot disappear while we are accessing it.
1617269Sericheng  */
1618269Sericheng typedef struct i_mac_info_state_s {
1619269Sericheng 	const char	*mi_name;
1620269Sericheng 	mac_info_t	*mi_infop;
1621269Sericheng } i_mac_info_state_t;
1622269Sericheng 
1623269Sericheng /*ARGSUSED*/
1624269Sericheng static uint_t
1625269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1626269Sericheng {
1627269Sericheng 	i_mac_info_state_t	*statep = arg;
1628269Sericheng 	mac_impl_t		*mip = (mac_impl_t *)val;
1629269Sericheng 
16301852Syz147064 	if (mip->mi_disabled)
1631269Sericheng 		return (MH_WALK_CONTINUE);
1632269Sericheng 
1633269Sericheng 	if (strcmp(statep->mi_name,
1634*2311Sseb 	    ddi_driver_name(mip->mi_dip)) != 0)
1635269Sericheng 		return (MH_WALK_CONTINUE);
1636269Sericheng 
1637*2311Sseb 	statep->mi_infop = &mip->mi_info;
1638269Sericheng 	return (MH_WALK_TERMINATE);
1639269Sericheng }
1640269Sericheng 
1641269Sericheng boolean_t
1642269Sericheng mac_info_get(const char *name, mac_info_t *minfop)
1643269Sericheng {
1644269Sericheng 	i_mac_info_state_t	state;
1645269Sericheng 
1646269Sericheng 	rw_enter(&i_mac_impl_lock, RW_READER);
1647269Sericheng 	state.mi_name = name;
1648269Sericheng 	state.mi_infop = NULL;
1649269Sericheng 	mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state);
1650269Sericheng 	if (state.mi_infop == NULL) {
1651269Sericheng 		rw_exit(&i_mac_impl_lock);
1652269Sericheng 		return (B_FALSE);
1653269Sericheng 	}
1654269Sericheng 	*minfop = *state.mi_infop;
1655269Sericheng 	rw_exit(&i_mac_impl_lock);
1656269Sericheng 	return (B_TRUE);
1657269Sericheng }
1658269Sericheng 
1659*2311Sseb boolean_t
1660*2311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data)
1661*2311Sseb {
1662*2311Sseb 	mac_impl_t *mip = (mac_impl_t *)mh;
1663*2311Sseb 
1664*2311Sseb 	if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB)
1665*2311Sseb 		return (mip->mi_getcapab(mip->mi_driver, cap, cap_data));
1666*2311Sseb 	else
1667*2311Sseb 		return (B_FALSE);
1668*2311Sseb }
1669*2311Sseb 
1670*2311Sseb boolean_t
1671*2311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap)
1672*2311Sseb {
1673*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
1674*2311Sseb 	return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap,
1675*2311Sseb 	    mip->mi_pdata));
1676*2311Sseb }
1677*2311Sseb 
1678*2311Sseb mblk_t *
1679*2311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload,
1680*2311Sseb     size_t extra_len)
1681*2311Sseb {
1682*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
1683*2311Sseb 	return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap,
1684*2311Sseb 	    mip->mi_pdata, payload, extra_len));
1685*2311Sseb }
1686*2311Sseb 
1687*2311Sseb int
1688*2311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
1689*2311Sseb {
1690*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
1691*2311Sseb 	return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata,
1692*2311Sseb 	    mhip));
1693*2311Sseb }
1694*2311Sseb 
1695*2311Sseb mblk_t *
1696*2311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp)
1697*2311Sseb {
1698*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
1699*2311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) {
1700*2311Sseb 		if (DB_REF(mp) > 1) {
1701*2311Sseb 			mblk_t *newmp = copymsg(mp);
1702*2311Sseb 			freemsg(mp);
1703*2311Sseb 			mp = newmp;
1704*2311Sseb 		}
1705*2311Sseb 		return (mip->mi_type->mt_ops.mtops_header_cook(mp,
1706*2311Sseb 		    mip->mi_pdata));
1707*2311Sseb 	}
1708*2311Sseb 	return (mp);
1709*2311Sseb }
1710*2311Sseb 
1711*2311Sseb mblk_t *
1712*2311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp)
1713*2311Sseb {
1714*2311Sseb 	mac_impl_t	*mip = (mac_impl_t *)mh;
1715*2311Sseb 	if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) {
1716*2311Sseb 		if (DB_REF(mp) > 1) {
1717*2311Sseb 			mblk_t *newmp = copymsg(mp);
1718*2311Sseb 			freemsg(mp);
1719*2311Sseb 			mp = newmp;
1720*2311Sseb 		}
1721*2311Sseb 		return (mip->mi_type->mt_ops.mtops_header_uncook(mp,
1722*2311Sseb 		    mip->mi_pdata));
1723*2311Sseb 	}
1724*2311Sseb 	return (mp);
1725*2311Sseb }
1726*2311Sseb 
1727269Sericheng void
1728269Sericheng mac_init_ops(struct dev_ops *ops, const char *name)
1729269Sericheng {
1730269Sericheng 	dld_init_ops(ops, name);
1731269Sericheng }
1732269Sericheng 
1733269Sericheng void
1734269Sericheng mac_fini_ops(struct dev_ops *ops)
1735269Sericheng {
1736269Sericheng 	dld_fini_ops(ops);
1737269Sericheng }
1738*2311Sseb 
1739*2311Sseb /*
1740*2311Sseb  * MAC Type Plugin functions.
1741*2311Sseb  */
1742*2311Sseb 
1743*2311Sseb mactype_register_t *
1744*2311Sseb mactype_alloc(uint_t mactype_version)
1745*2311Sseb {
1746*2311Sseb 	mactype_register_t *mtrp;
1747*2311Sseb 
1748*2311Sseb 	/*
1749*2311Sseb 	 * Make sure there isn't a version mismatch between the plugin and
1750*2311Sseb 	 * the framework.  In the future, if multiple versions are
1751*2311Sseb 	 * supported, this check could become more sophisticated.
1752*2311Sseb 	 */
1753*2311Sseb 	if (mactype_version != MACTYPE_VERSION)
1754*2311Sseb 		return (NULL);
1755*2311Sseb 
1756*2311Sseb 	mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP);
1757*2311Sseb 	mtrp->mtr_version = mactype_version;
1758*2311Sseb 	return (mtrp);
1759*2311Sseb }
1760*2311Sseb 
1761*2311Sseb void
1762*2311Sseb mactype_free(mactype_register_t *mtrp)
1763*2311Sseb {
1764*2311Sseb 	kmem_free(mtrp, sizeof (mactype_register_t));
1765*2311Sseb }
1766*2311Sseb 
1767*2311Sseb int
1768*2311Sseb mactype_register(mactype_register_t *mtrp)
1769*2311Sseb {
1770*2311Sseb 	mactype_t	*mtp;
1771*2311Sseb 	mactype_ops_t	*ops = mtrp->mtr_ops;
1772*2311Sseb 
1773*2311Sseb 	/* Do some sanity checking before we register this MAC type. */
1774*2311Sseb 	if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0)
1775*2311Sseb 		return (EINVAL);
1776*2311Sseb 
1777*2311Sseb 	/*
1778*2311Sseb 	 * Verify that all mandatory callbacks are set in the ops
1779*2311Sseb 	 * vector.
1780*2311Sseb 	 */
1781*2311Sseb 	if (ops->mtops_unicst_verify == NULL ||
1782*2311Sseb 	    ops->mtops_multicst_verify == NULL ||
1783*2311Sseb 	    ops->mtops_sap_verify == NULL ||
1784*2311Sseb 	    ops->mtops_header == NULL ||
1785*2311Sseb 	    ops->mtops_header_info == NULL) {
1786*2311Sseb 		return (EINVAL);
1787*2311Sseb 	}
1788*2311Sseb 
1789*2311Sseb 	mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP);
1790*2311Sseb 	mtp->mt_ident = mtrp->mtr_ident;
1791*2311Sseb 	mtp->mt_ops = *ops;
1792*2311Sseb 	mtp->mt_type = mtrp->mtr_mactype;
1793*2311Sseb 	mtp->mt_addr_length = mtrp->mtr_addrlen;
1794*2311Sseb 	if (mtrp->mtr_brdcst_addr != NULL) {
1795*2311Sseb 		mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP);
1796*2311Sseb 		bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr,
1797*2311Sseb 		    mtrp->mtr_addrlen);
1798*2311Sseb 	}
1799*2311Sseb 
1800*2311Sseb 	mtp->mt_stats = mtrp->mtr_stats;
1801*2311Sseb 	mtp->mt_statcount = mtrp->mtr_statcount;
1802*2311Sseb 
1803*2311Sseb 	/*
1804*2311Sseb 	 * A MAC-Type plugin only registers when i_mactype_getplugin() does
1805*2311Sseb 	 * an explicit modload() as a result of a driver requesting to use
1806*2311Sseb 	 * that plugin in mac_register().  We pre-emptively set the initial
1807*2311Sseb 	 * reference count to 1 here to prevent the plugin module from
1808*2311Sseb 	 * unloading before the driver's mac_register() completes.  If we
1809*2311Sseb 	 * were to initialize the reference count to 0, then there would be
1810*2311Sseb 	 * a window during which the module could unload before the
1811*2311Sseb 	 * reference count could be bumped up to 1.
1812*2311Sseb 	 */
1813*2311Sseb 	mtp->mt_ref = 1;
1814*2311Sseb 
1815*2311Sseb 	if (mod_hash_insert(i_mactype_hash,
1816*2311Sseb 	    (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) {
1817*2311Sseb 		kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
1818*2311Sseb 		kmem_free(mtp, sizeof (*mtp));
1819*2311Sseb 		return (EEXIST);
1820*2311Sseb 	}
1821*2311Sseb 	return (0);
1822*2311Sseb }
1823*2311Sseb 
1824*2311Sseb int
1825*2311Sseb mactype_unregister(const char *ident)
1826*2311Sseb {
1827*2311Sseb 	mactype_t	*mtp;
1828*2311Sseb 	mod_hash_val_t	val;
1829*2311Sseb 	int 		err;
1830*2311Sseb 
1831*2311Sseb 	/*
1832*2311Sseb 	 * Let's not allow MAC drivers to use this plugin while we're
1833*2311Sseb 	 * trying to unregister it...
1834*2311Sseb 	 */
1835*2311Sseb 	rw_enter(&i_mac_impl_lock, RW_WRITER);
1836*2311Sseb 
1837*2311Sseb 	if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident,
1838*2311Sseb 	    (mod_hash_val_t *)&mtp)) != 0) {
1839*2311Sseb 		/* A plugin is trying to unregister, but it never registered. */
1840*2311Sseb 		rw_exit(&i_mac_impl_lock);
1841*2311Sseb 		return (ENXIO);
1842*2311Sseb 	}
1843*2311Sseb 
1844*2311Sseb 	if (mtp->mt_ref > 0) {
1845*2311Sseb 		rw_exit(&i_mac_impl_lock);
1846*2311Sseb 		return (EBUSY);
1847*2311Sseb 	}
1848*2311Sseb 
1849*2311Sseb 	err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val);
1850*2311Sseb 	ASSERT(err == 0);
1851*2311Sseb 	if (err != 0) {
1852*2311Sseb 		/* This should never happen, thus the ASSERT() above. */
1853*2311Sseb 		rw_exit(&i_mac_impl_lock);
1854*2311Sseb 		return (EINVAL);
1855*2311Sseb 	}
1856*2311Sseb 	ASSERT(mtp == (mactype_t *)val);
1857*2311Sseb 
1858*2311Sseb 	kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length);
1859*2311Sseb 	kmem_free(mtp, sizeof (mactype_t));
1860*2311Sseb 	rw_exit(&i_mac_impl_lock);
1861*2311Sseb 
1862*2311Sseb 	return (0);
1863*2311Sseb }
1864