xref: /onnv-gate/usr/src/uts/common/io/softmac/softmac_main.c (revision 10654:ff1ef49164ba)
15895Syz147064 /*
25895Syz147064  * CDDL HEADER START
35895Syz147064  *
45895Syz147064  * The contents of this file are subject to the terms of the
55895Syz147064  * Common Development and Distribution License (the "License").
65895Syz147064  * You may not use this file except in compliance with the License.
75895Syz147064  *
85895Syz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95895Syz147064  * or http://www.opensolaris.org/os/licensing.
105895Syz147064  * See the License for the specific language governing permissions
115895Syz147064  * and limitations under the License.
125895Syz147064  *
135895Syz147064  * When distributing Covered Code, include this CDDL HEADER in each
145895Syz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155895Syz147064  * If applicable, add the following below this CDDL HEADER, with the
165895Syz147064  * fields enclosed by brackets "[]" replaced with your own identifying
175895Syz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
185895Syz147064  *
195895Syz147064  * CDDL HEADER END
205895Syz147064  */
215895Syz147064 /*
228527SCathy.Zhou@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235895Syz147064  * Use is subject to license terms.
245895Syz147064  */
255895Syz147064 
265895Syz147064 /*
275895Syz147064  * The softmac driver is used to "unify" non-GLDv3 drivers to the GLDv3
285895Syz147064  * framework.  It also creates the kernel datalink structure for each
295895Syz147064  * physical network device.
305895Syz147064  *
315895Syz147064  * Specifically, a softmac will be created for each physical network device
325895Syz147064  * (dip) during the device's post-attach process.  When this softmac is
335895Syz147064  * created, the following will also be done:
345895Syz147064  *   - create the device's <link name, linkid> mapping;
355895Syz147064  *   - register the mac if this is a non-GLDv3 device and the media type is
365895Syz147064  *     supported by the GLDv3 framework;
375895Syz147064  *   - create the kernel data-link structure for this physical device;
385895Syz147064  *
395895Syz147064  * This softmac will be destroyed during the device's pre-detach process,
405895Syz147064  * and all the above will be undone.
415895Syz147064  */
425895Syz147064 
435895Syz147064 #include <sys/types.h>
445895Syz147064 #include <sys/file.h>
455895Syz147064 #include <sys/cred.h>
465895Syz147064 #include <sys/dlpi.h>
478275SEric Cheng #include <sys/mac_provider.h>
488275SEric Cheng #include <sys/disp.h>
495895Syz147064 #include <sys/sunndi.h>
505895Syz147064 #include <sys/modhash.h>
515895Syz147064 #include <sys/stropts.h>
525895Syz147064 #include <sys/sysmacros.h>
535895Syz147064 #include <sys/vlan.h>
545895Syz147064 #include <sys/softmac_impl.h>
555895Syz147064 #include <sys/softmac.h>
565895Syz147064 #include <sys/dls.h>
575895Syz147064 
588275SEric Cheng /* Used as a parameter to the mod hash walk of softmac structures */
598275SEric Cheng typedef struct {
608275SEric Cheng 	softmac_t	*smw_softmac;
618275SEric Cheng 	boolean_t	smw_retry;
628275SEric Cheng } softmac_walk_t;
638275SEric Cheng 
645895Syz147064 /*
655895Syz147064  * Softmac hash table including softmacs for both style-2 and style-1 devices.
665895Syz147064  */
675895Syz147064 static krwlock_t	softmac_hash_lock;
685895Syz147064 static mod_hash_t	*softmac_hash;
698275SEric Cheng static kmutex_t		smac_global_lock;
708275SEric Cheng static kcondvar_t	smac_global_cv;
715895Syz147064 
729073SCathy.Zhou@Sun.COM static kmem_cache_t	*softmac_cachep;
739073SCathy.Zhou@Sun.COM 
745895Syz147064 #define	SOFTMAC_HASHSZ		64
755895Syz147064 
767323SCathy.Zhou@Sun.COM static void softmac_create_task(void *);
777323SCathy.Zhou@Sun.COM static void softmac_mac_register(softmac_t *);
785895Syz147064 static int softmac_create_datalink(softmac_t *);
795895Syz147064 static int softmac_m_start(void *);
805895Syz147064 static void softmac_m_stop(void *);
815895Syz147064 static int softmac_m_open(void *);
825895Syz147064 static void softmac_m_close(void *);
835895Syz147064 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *);
849073SCathy.Zhou@Sun.COM static int softmac_m_setprop(void *, const char *, mac_prop_id_t,
859073SCathy.Zhou@Sun.COM     uint_t, const void *);
869073SCathy.Zhou@Sun.COM static int softmac_m_getprop(void *, const char *, mac_prop_id_t,
879073SCathy.Zhou@Sun.COM     uint_t, uint_t, void *, uint_t *);
889073SCathy.Zhou@Sun.COM 
895895Syz147064 
905895Syz147064 #define	SOFTMAC_M_CALLBACK_FLAGS	\
919073SCathy.Zhou@Sun.COM 	(MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE | MC_SETPROP | MC_GETPROP)
925895Syz147064 
935895Syz147064 static mac_callbacks_t softmac_m_callbacks = {
945895Syz147064 	SOFTMAC_M_CALLBACK_FLAGS,
955895Syz147064 	softmac_m_stat,
965895Syz147064 	softmac_m_start,
975895Syz147064 	softmac_m_stop,
985895Syz147064 	softmac_m_promisc,
995895Syz147064 	softmac_m_multicst,
1005895Syz147064 	softmac_m_unicst,
1015895Syz147064 	softmac_m_tx,
1025895Syz147064 	softmac_m_ioctl,
1035895Syz147064 	softmac_m_getcapab,
1045895Syz147064 	softmac_m_open,
1059073SCathy.Zhou@Sun.COM 	softmac_m_close,
1069073SCathy.Zhou@Sun.COM 	softmac_m_setprop,
1079073SCathy.Zhou@Sun.COM 	softmac_m_getprop
1085895Syz147064 };
1095895Syz147064 
1109073SCathy.Zhou@Sun.COM /*ARGSUSED*/
1119073SCathy.Zhou@Sun.COM static int
1129073SCathy.Zhou@Sun.COM softmac_constructor(void *buf, void *arg, int kmflag)
1139073SCathy.Zhou@Sun.COM {
1149073SCathy.Zhou@Sun.COM 	softmac_t	*softmac = buf;
1159073SCathy.Zhou@Sun.COM 
1169073SCathy.Zhou@Sun.COM 	bzero(buf, sizeof (softmac_t));
1179073SCathy.Zhou@Sun.COM 	mutex_init(&softmac->smac_mutex, NULL, MUTEX_DEFAULT, NULL);
1189073SCathy.Zhou@Sun.COM 	mutex_init(&softmac->smac_active_mutex, NULL, MUTEX_DEFAULT, NULL);
1199073SCathy.Zhou@Sun.COM 	mutex_init(&softmac->smac_fp_mutex, NULL, MUTEX_DEFAULT, NULL);
1209073SCathy.Zhou@Sun.COM 	cv_init(&softmac->smac_cv, NULL, CV_DEFAULT, NULL);
1219073SCathy.Zhou@Sun.COM 	cv_init(&softmac->smac_fp_cv, NULL, CV_DEFAULT, NULL);
1229073SCathy.Zhou@Sun.COM 	list_create(&softmac->smac_sup_list, sizeof (softmac_upper_t),
1239073SCathy.Zhou@Sun.COM 	    offsetof(softmac_upper_t, su_list_node));
1249073SCathy.Zhou@Sun.COM 	return (0);
1259073SCathy.Zhou@Sun.COM }
1269073SCathy.Zhou@Sun.COM 
1279073SCathy.Zhou@Sun.COM /*ARGSUSED*/
1289073SCathy.Zhou@Sun.COM static void
1299073SCathy.Zhou@Sun.COM softmac_destructor(void *buf, void *arg)
1309073SCathy.Zhou@Sun.COM {
1319073SCathy.Zhou@Sun.COM 	softmac_t	*softmac = buf;
1329073SCathy.Zhou@Sun.COM 
1339073SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_fp_disable_clients == 0);
1349073SCathy.Zhou@Sun.COM 	ASSERT(!softmac->smac_fastpath_admin_disabled);
1359073SCathy.Zhou@Sun.COM 
1369073SCathy.Zhou@Sun.COM 	ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
1379073SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_hold_cnt == 0);
1389073SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_attachok_cnt == 0);
1399073SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_mh == NULL);
1409073SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_softmac[0] == NULL &&
1419073SCathy.Zhou@Sun.COM 	    softmac->smac_softmac[1] == NULL);
1429073SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_state == SOFTMAC_INITIALIZED);
1439073SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_lower == NULL);
1449073SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_active == B_FALSE);
1459073SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_nactive == 0);
1469073SCathy.Zhou@Sun.COM 	ASSERT(list_is_empty(&softmac->smac_sup_list));
1479073SCathy.Zhou@Sun.COM 
1489073SCathy.Zhou@Sun.COM 	list_destroy(&softmac->smac_sup_list);
1499073SCathy.Zhou@Sun.COM 	mutex_destroy(&softmac->smac_mutex);
1509073SCathy.Zhou@Sun.COM 	mutex_destroy(&softmac->smac_active_mutex);
1519073SCathy.Zhou@Sun.COM 	mutex_destroy(&softmac->smac_fp_mutex);
1529073SCathy.Zhou@Sun.COM 	cv_destroy(&softmac->smac_cv);
1539073SCathy.Zhou@Sun.COM 	cv_destroy(&softmac->smac_fp_cv);
1549073SCathy.Zhou@Sun.COM }
1559073SCathy.Zhou@Sun.COM 
1565895Syz147064 void
1575895Syz147064 softmac_init()
1585895Syz147064 {
1595895Syz147064 	softmac_hash = mod_hash_create_extended("softmac_hash",
1605895Syz147064 	    SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
1615895Syz147064 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
1625895Syz147064 
1635895Syz147064 	rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL);
1648275SEric Cheng 	mutex_init(&smac_global_lock, NULL, MUTEX_DRIVER, NULL);
1658275SEric Cheng 	cv_init(&smac_global_cv, NULL, CV_DRIVER, NULL);
1669073SCathy.Zhou@Sun.COM 
1679073SCathy.Zhou@Sun.COM 	softmac_cachep = kmem_cache_create("softmac_cache",
1689073SCathy.Zhou@Sun.COM 	    sizeof (softmac_t), 0, softmac_constructor,
1699073SCathy.Zhou@Sun.COM 	    softmac_destructor, NULL, NULL, NULL, 0);
1709073SCathy.Zhou@Sun.COM 	ASSERT(softmac_cachep != NULL);
1719073SCathy.Zhou@Sun.COM 	softmac_fp_init();
1725895Syz147064 }
1735895Syz147064 
1745895Syz147064 void
1755895Syz147064 softmac_fini()
1765895Syz147064 {
1779073SCathy.Zhou@Sun.COM 	softmac_fp_fini();
1789073SCathy.Zhou@Sun.COM 	kmem_cache_destroy(softmac_cachep);
1795895Syz147064 	rw_destroy(&softmac_hash_lock);
1805895Syz147064 	mod_hash_destroy_hash(softmac_hash);
1818275SEric Cheng 	mutex_destroy(&smac_global_lock);
1828275SEric Cheng 	cv_destroy(&smac_global_cv);
1835895Syz147064 }
1845895Syz147064 
1855895Syz147064 /* ARGSUSED */
1865895Syz147064 static uint_t
1875895Syz147064 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1885895Syz147064 {
1895895Syz147064 	boolean_t *pexist = arg;
1905895Syz147064 
1915895Syz147064 	*pexist = B_TRUE;
1925895Syz147064 	return (MH_WALK_TERMINATE);
1935895Syz147064 }
1945895Syz147064 
1955895Syz147064 boolean_t
1965895Syz147064 softmac_busy()
1975895Syz147064 {
1985895Syz147064 	boolean_t exist = B_FALSE;
1995895Syz147064 
2005895Syz147064 	rw_enter(&softmac_hash_lock, RW_READER);
2015895Syz147064 	mod_hash_walk(softmac_hash, softmac_exist, &exist);
2025895Syz147064 	rw_exit(&softmac_hash_lock);
2035895Syz147064 	return (exist);
2045895Syz147064 }
2055895Syz147064 
2065895Syz147064 /*
2078275SEric Cheng  *
2088275SEric Cheng  * softmac_create() is called for each minor node during the post-attach of
2095895Syz147064  * each DDI_NT_NET device instance.  Note that it is possible that a device
2105895Syz147064  * instance has two minor nodes (DLPI style-1 and style-2), so that for that
2115895Syz147064  * specific device, softmac_create() could be called twice.
2125895Syz147064  *
2135895Syz147064  * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t
2145895Syz147064  * is created to track each minor node.
2155895Syz147064  *
2165895Syz147064  * For each minor node of a legacy device, a taskq is started to finish
2175895Syz147064  * softmac_mac_register(), which will finish the rest of work (see comments
2185895Syz147064  * above softmac_mac_register()).
2198275SEric Cheng  *
2208275SEric Cheng  *			softmac state machine
2218275SEric Cheng  * --------------------------------------------------------------------------
2228275SEric Cheng  * OLD STATE		EVENT					NEW STATE
2238275SEric Cheng  * --------------------------------------------------------------------------
2248275SEric Cheng  * UNINIT		attach of 1st minor node 		ATTACH_INPROG
2258275SEric Cheng  * okcnt = 0		net_postattach -> softmac_create	okcnt = 1
2268275SEric Cheng  *
2278275SEric Cheng  * ATTACH_INPROG	attach of 2nd minor node (GLDv3)	ATTACH_DONE
2288275SEric Cheng  * okcnt = 1		net_postattach -> softmac_create	okcnt = 2
2298275SEric Cheng  *
2308275SEric Cheng  * ATTACH_INPROG	attach of 2nd minor node (legacy)	ATTACH_INPROG
2318275SEric Cheng  * okcnt = 1		net_postattach -> softmac_create	okcnt = 2
2328275SEric Cheng  *			schedule softmac_mac_register
2338275SEric Cheng  *
2348275SEric Cheng  * ATTACH_INPROG	legacy device node			ATTACH_DONE
2358275SEric Cheng  * okcnt = 2		softmac_mac_register			okcnt = 2
2368275SEric Cheng  *
2378275SEric Cheng  * ATTACH_DONE		detach of 1st minor node		DETACH_INPROG
2388275SEric Cheng  * okcnt = 2		(success)				okcnt = 1
2398275SEric Cheng  *
2408275SEric Cheng  * DETACH_INPROG	detach of 2nd minor node		UNINIT (or free)
2418275SEric Cheng  * okcnt = 1		(success)				okcnt = 0
2428275SEric Cheng  *
2438275SEric Cheng  * ATTACH_DONE		detach failure				state unchanged
2448275SEric Cheng  * DETACH_INPROG						left = okcnt
2458275SEric Cheng  *
2468275SEric Cheng  * DETACH_INPROG	reattach				ATTACH_INPROG
2478275SEric Cheng  * okcnt = 0,1		net_postattach -> softmac_create
2488275SEric Cheng  *
2498275SEric Cheng  * ATTACH_DONE		reattach				ATTACH_DONE
2508275SEric Cheng  * left != 0		net_postattach -> softmac_create	left = 0
2518275SEric Cheng  *
2528275SEric Cheng  * Abbreviation notes:
2538275SEric Cheng  * states have SOFTMAC_ prefix,
2548275SEric Cheng  * okcnt - softmac_attach_okcnt,
2558275SEric Cheng  * left - softmac_attached_left
2565895Syz147064  */
2578275SEric Cheng 
2588275SEric Cheng #ifdef DEBUG
2598275SEric Cheng void
2608275SEric Cheng softmac_state_verify(softmac_t *softmac)
2618275SEric Cheng {
2628275SEric Cheng 	ASSERT(MUTEX_HELD(&softmac->smac_mutex));
2638275SEric Cheng 
2648275SEric Cheng 	/*
2658275SEric Cheng 	 * There are at most 2 minor nodes, one per DLPI style
2668275SEric Cheng 	 */
2678275SEric Cheng 	ASSERT(softmac->smac_cnt <= 2 && softmac->smac_attachok_cnt <= 2);
2688275SEric Cheng 
2698275SEric Cheng 	/*
2708275SEric Cheng 	 * The smac_attachok_cnt represents the number of attaches i.e. the
2718275SEric Cheng 	 * number of times net_postattach -> softmac_create() has been called
2728275SEric Cheng 	 * for a device instance.
2738275SEric Cheng 	 */
2748275SEric Cheng 	ASSERT(softmac->smac_attachok_cnt == SMAC_NONZERO_NODECNT(softmac));
2758275SEric Cheng 
2768275SEric Cheng 	/*
2778275SEric Cheng 	 * softmac_create (or softmac_mac_register) ->  softmac_create_datalink
2788275SEric Cheng 	 * happens only after all minor nodes have been attached
2798275SEric Cheng 	 */
2808275SEric Cheng 	ASSERT(softmac->smac_state != SOFTMAC_ATTACH_DONE ||
2818275SEric Cheng 	    softmac->smac_attachok_cnt == softmac->smac_cnt);
2828275SEric Cheng 
2838275SEric Cheng 	if (softmac->smac_attachok_cnt == 0) {
2848275SEric Cheng 		ASSERT(softmac->smac_state == SOFTMAC_UNINIT);
2858275SEric Cheng 		ASSERT(softmac->smac_mh == NULL);
2868275SEric Cheng 	} else if (softmac->smac_attachok_cnt < softmac->smac_cnt) {
2878275SEric Cheng 		ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG ||
2888275SEric Cheng 		    softmac->smac_state == SOFTMAC_DETACH_INPROG);
2898275SEric Cheng 		ASSERT(softmac->smac_mh == NULL);
2908275SEric Cheng 	} else {
2918275SEric Cheng 		/*
2928275SEric Cheng 		 * In the stable condition the state whould be
2938275SEric Cheng 		 * SOFTMAC_ATTACH_DONE. But there is a small transient window
2948275SEric Cheng 		 * in softmac_destroy where we change the state to
2958275SEric Cheng 		 * SOFTMAC_DETACH_INPROG and drop the lock before doing
2968275SEric Cheng 		 * the link destroy
2978275SEric Cheng 		 */
2988275SEric Cheng 		ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
2998275SEric Cheng 		ASSERT(softmac->smac_state != SOFTMAC_UNINIT);
3008275SEric Cheng 	}
3018275SEric Cheng 	if (softmac->smac_mh != NULL)
3028275SEric Cheng 		ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
3038275SEric Cheng }
3048275SEric Cheng #endif
3058275SEric Cheng 
3068275SEric Cheng #ifdef DEBUG
3078275SEric Cheng #define	SOFTMAC_STATE_VERIFY(softmac)	softmac_state_verify(softmac)
3088275SEric Cheng #else
3098275SEric Cheng #define	SOFTMAC_STATE_VERIFY(softmac)
3108275SEric Cheng #endif
3118275SEric Cheng 
3125895Syz147064 int
3135895Syz147064 softmac_create(dev_info_t *dip, dev_t dev)
3145895Syz147064 {
3155895Syz147064 	char		devname[MAXNAMELEN];
3165895Syz147064 	softmac_t	*softmac;
3175895Syz147064 	softmac_dev_t	*softmac_dev = NULL;
3185895Syz147064 	int		index;
3195895Syz147064 	int		ppa, err = 0;
3205895Syz147064 
3215895Syz147064 	/*
3225895Syz147064 	 * Force the softmac driver to be attached.
3235895Syz147064 	 */
3245895Syz147064 	if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) {
3255895Syz147064 		cmn_err(CE_WARN, "softmac_create:softmac attach fails");
3265895Syz147064 		return (ENXIO);
3275895Syz147064 	}
3285895Syz147064 
329*10654SGarrett.Damore@Sun.COM 	if (GLDV3_DRV(ddi_driver_major(dip))) {
330*10654SGarrett.Damore@Sun.COM 		minor_t minor = getminor(dev);
331*10654SGarrett.Damore@Sun.COM 		/*
332*10654SGarrett.Damore@Sun.COM 		 * For GLDv3, we don't care about the DLPI style 2
333*10654SGarrett.Damore@Sun.COM 		 * compatibility node.  (We know that all such devices
334*10654SGarrett.Damore@Sun.COM 		 * have style 1 nodes.)
335*10654SGarrett.Damore@Sun.COM 		 */
336*10654SGarrett.Damore@Sun.COM 		if ((strcmp(ddi_driver_name(dip), "clone") == 0) ||
337*10654SGarrett.Damore@Sun.COM 		    (getmajor(dev) == ddi_name_to_major("clone")) ||
338*10654SGarrett.Damore@Sun.COM 		    (minor == 0)) {
339*10654SGarrett.Damore@Sun.COM 			return (0);
340*10654SGarrett.Damore@Sun.COM 		}
3415895Syz147064 
342*10654SGarrett.Damore@Sun.COM 		/*
343*10654SGarrett.Damore@Sun.COM 		 * Likewise, we know that the minor number for DLPI style 1
344*10654SGarrett.Damore@Sun.COM 		 * nodes is constrained to a maximum value.
345*10654SGarrett.Damore@Sun.COM 		 */
346*10654SGarrett.Damore@Sun.COM 		if (minor >= DLS_MAX_MINOR) {
347*10654SGarrett.Damore@Sun.COM 			return (ENOTSUP);
348*10654SGarrett.Damore@Sun.COM 		}
349*10654SGarrett.Damore@Sun.COM 		/*
350*10654SGarrett.Damore@Sun.COM 		 * Otherwise we can decode the instance from the minor number,
351*10654SGarrett.Damore@Sun.COM 		 * which allows for situations with multiple mac instances
352*10654SGarrett.Damore@Sun.COM 		 * for a single dev_info_t.
353*10654SGarrett.Damore@Sun.COM 		 */
354*10654SGarrett.Damore@Sun.COM 		ppa = DLS_MINOR2INST(minor);
355*10654SGarrett.Damore@Sun.COM 	} else {
356*10654SGarrett.Damore@Sun.COM 		/*
357*10654SGarrett.Damore@Sun.COM 		 * For legacy drivers, we just have to limit them to
358*10654SGarrett.Damore@Sun.COM 		 * two minor nodes, one style 1 and one style 2, and
359*10654SGarrett.Damore@Sun.COM 		 * we assume the ddi_get_instance() is the PPA.
360*10654SGarrett.Damore@Sun.COM 		 * Drivers that need more flexibility should be ported
361*10654SGarrett.Damore@Sun.COM 		 * to GLDv3.
362*10654SGarrett.Damore@Sun.COM 		 */
363*10654SGarrett.Damore@Sun.COM 		ppa = ddi_get_instance(dip);
364*10654SGarrett.Damore@Sun.COM 		if (i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) {
365*10654SGarrett.Damore@Sun.COM 			cmn_err(CE_WARN, "%s has more than 2 minor nodes; "
366*10654SGarrett.Damore@Sun.COM 			    "unsupported", devname);
367*10654SGarrett.Damore@Sun.COM 			return (ENOTSUP);
368*10654SGarrett.Damore@Sun.COM 		}
3695895Syz147064 	}
3705895Syz147064 
371*10654SGarrett.Damore@Sun.COM 	(void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
372*10654SGarrett.Damore@Sun.COM 
3735895Syz147064 	/*
3745895Syz147064 	 * Check whether the softmac for the specified device already exists
3755895Syz147064 	 */
3765895Syz147064 	rw_enter(&softmac_hash_lock, RW_WRITER);
3779073SCathy.Zhou@Sun.COM 	if ((mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
3785895Syz147064 	    (mod_hash_val_t *)&softmac)) != 0) {
3795895Syz147064 
3809073SCathy.Zhou@Sun.COM 		softmac = kmem_cache_alloc(softmac_cachep, KM_SLEEP);
3815895Syz147064 		(void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN);
3829073SCathy.Zhou@Sun.COM 
3835895Syz147064 		err = mod_hash_insert(softmac_hash,
3845895Syz147064 		    (mod_hash_key_t)softmac->smac_devname,
3855895Syz147064 		    (mod_hash_val_t)softmac);
3865895Syz147064 		ASSERT(err == 0);
3878275SEric Cheng 		mutex_enter(&smac_global_lock);
3888275SEric Cheng 		cv_broadcast(&smac_global_cv);
3898275SEric Cheng 		mutex_exit(&smac_global_lock);
3905895Syz147064 	}
3915895Syz147064 
3925895Syz147064 	mutex_enter(&softmac->smac_mutex);
3938275SEric Cheng 	SOFTMAC_STATE_VERIFY(softmac);
3948275SEric Cheng 	if (softmac->smac_state != SOFTMAC_ATTACH_DONE)
3958275SEric Cheng 		softmac->smac_state = SOFTMAC_ATTACH_INPROG;
3965895Syz147064 	if (softmac->smac_attachok_cnt == 0) {
3975895Syz147064 		/*
3985895Syz147064 		 * Initialize the softmac if this is the post-attach of the
3995895Syz147064 		 * first minor node.
4005895Syz147064 		 */
4015895Syz147064 		softmac->smac_flags = 0;
4025895Syz147064 		softmac->smac_umajor = ddi_driver_major(dip);
4035895Syz147064 		softmac->smac_uppa = ppa;
4045895Syz147064 
4055895Syz147064 		/*
406*10654SGarrett.Damore@Sun.COM 		 * For GLDv3, we ignore the style 2 node (see the logic
407*10654SGarrett.Damore@Sun.COM 		 * above on that), and we should have exactly one attach
408*10654SGarrett.Damore@Sun.COM 		 * per MAC instance (possibly more than one per dev_info_t).
4095895Syz147064 		 */
4105895Syz147064 		if (GLDV3_DRV(ddi_driver_major(dip))) {
4115895Syz147064 			softmac->smac_flags |= SOFTMAC_GLDV3;
412*10654SGarrett.Damore@Sun.COM 			softmac->smac_cnt = 1;
4135895Syz147064 		} else {
4145895Syz147064 			softmac->smac_cnt =
4155895Syz147064 			    i_ddi_minor_node_count(dip, DDI_NT_NET);
4165895Syz147064 		}
4175895Syz147064 	}
4185895Syz147064 
4195895Syz147064 	index = (getmajor(dev) == ddi_name_to_major("clone"));
4205895Syz147064 	if (softmac->smac_softmac[index] != NULL) {
4215895Syz147064 		/*
4228275SEric Cheng 		 * This is possible if the post_attach() is called after
4238275SEric Cheng 		 * pre_detach() fails. This seems to be a defect of the DACF
4248275SEric Cheng 		 * framework. We work around it by using a smac_attached_left
4258275SEric Cheng 		 * field that tracks this
4265895Syz147064 		 */
4278275SEric Cheng 		ASSERT(softmac->smac_attached_left != 0);
4288275SEric Cheng 		softmac->smac_attached_left--;
4295895Syz147064 		mutex_exit(&softmac->smac_mutex);
4305895Syz147064 		rw_exit(&softmac_hash_lock);
4315895Syz147064 		return (0);
4328275SEric Cheng 
4335895Syz147064 	}
4345895Syz147064 	mutex_exit(&softmac->smac_mutex);
4355895Syz147064 	rw_exit(&softmac_hash_lock);
4365895Syz147064 
4375895Syz147064 	softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP);
4385895Syz147064 	softmac_dev->sd_dev = dev;
4398275SEric Cheng 
4408275SEric Cheng 	mutex_enter(&softmac->smac_mutex);
4415895Syz147064 	softmac->smac_softmac[index] = softmac_dev;
4425895Syz147064 	/*
4435895Syz147064 	 * Continue to register the mac and create the datalink only when all
4445895Syz147064 	 * the minor nodes are attached.
4455895Syz147064 	 */
4465895Syz147064 	if (++softmac->smac_attachok_cnt != softmac->smac_cnt) {
4475895Syz147064 		mutex_exit(&softmac->smac_mutex);
4485895Syz147064 		return (0);
4495895Syz147064 	}
4505895Syz147064 
4515895Syz147064 	/*
4527323SCathy.Zhou@Sun.COM 	 * All of the minor nodes have been attached; start a taskq
4538275SEric Cheng 	 * to do the rest of the work.  We use a taskq instead of
4547323SCathy.Zhou@Sun.COM 	 * doing the work here because:
4557323SCathy.Zhou@Sun.COM 	 *
4568275SEric Cheng 	 * We could be called as a result of a open() system call
4578275SEric Cheng 	 * where spec_open() already SLOCKED the snode. Using a taskq
4588275SEric Cheng 	 * sidesteps the risk that our ldi_open_by_dev() call would
4598275SEric Cheng 	 * deadlock trying to set SLOCKED on the snode again.
4607323SCathy.Zhou@Sun.COM 	 *
4618275SEric Cheng 	 * The devfs design requires that the downcalls don't use any
4628275SEric Cheng 	 * interruptible cv_wait which happens when we do door upcalls.
4638275SEric Cheng 	 * Otherwise the downcalls which may be holding devfs resources
4648275SEric Cheng 	 * may cause a deadlock if the thread is stopped. Also we need to make
4658275SEric Cheng 	 * sure these downcalls into softmac_create or softmac_destroy
4668275SEric Cheng 	 * don't cv_wait on any devfs related condition. Thus softmac_destroy
4678275SEric Cheng 	 * returns EBUSY if the asynchronous threads started in softmac_create
4688275SEric Cheng 	 * haven't finished.
4695895Syz147064 	 */
4708527SCathy.Zhou@Sun.COM 	(void) taskq_dispatch(system_taskq, softmac_create_task,
4718527SCathy.Zhou@Sun.COM 	    softmac, TQ_SLEEP);
4725895Syz147064 	mutex_exit(&softmac->smac_mutex);
4737323SCathy.Zhou@Sun.COM 	return (0);
4745895Syz147064 }
4755895Syz147064 
4765895Syz147064 static boolean_t
4775895Syz147064 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
4785895Syz147064 {
4795895Syz147064 	softmac_t *softmac = arg;
4805895Syz147064 
4815895Syz147064 	if (!(softmac->smac_capab_flags & cap))
4825895Syz147064 		return (B_FALSE);
4835895Syz147064 
4845895Syz147064 	switch (cap) {
4855895Syz147064 	case MAC_CAPAB_HCKSUM: {
4865895Syz147064 		uint32_t *txflags = cap_data;
4875895Syz147064 
4885895Syz147064 		*txflags = softmac->smac_hcksum_txflags;
4895895Syz147064 		break;
4905895Syz147064 	}
4915895Syz147064 	case MAC_CAPAB_LEGACY: {
4925895Syz147064 		mac_capab_legacy_t *legacy = cap_data;
4935895Syz147064 
4949073SCathy.Zhou@Sun.COM 		/*
4959073SCathy.Zhou@Sun.COM 		 * The caller is not interested in the details.
4969073SCathy.Zhou@Sun.COM 		 */
4979073SCathy.Zhou@Sun.COM 		if (legacy == NULL)
4989073SCathy.Zhou@Sun.COM 			break;
4999073SCathy.Zhou@Sun.COM 
5005895Syz147064 		legacy->ml_unsup_note = ~softmac->smac_notifications &
5015895Syz147064 		    (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED);
5029073SCathy.Zhou@Sun.COM 		legacy->ml_active_set = softmac_active_set;
5039073SCathy.Zhou@Sun.COM 		legacy->ml_active_clear = softmac_active_clear;
5049073SCathy.Zhou@Sun.COM 		legacy->ml_fastpath_disable = softmac_fastpath_disable;
5059073SCathy.Zhou@Sun.COM 		legacy->ml_fastpath_enable = softmac_fastpath_enable;
5065895Syz147064 		legacy->ml_dev = makedevice(softmac->smac_umajor,
5075895Syz147064 		    softmac->smac_uppa + 1);
5085895Syz147064 		break;
5095895Syz147064 	}
5105895Syz147064 
5115895Syz147064 	/*
5125895Syz147064 	 * For the capabilities below, there's nothing for us to fill in;
5135895Syz147064 	 * simply return B_TRUE if we support it.
5145895Syz147064 	 */
5155895Syz147064 	case MAC_CAPAB_NO_ZCOPY:
5165895Syz147064 	case MAC_CAPAB_NO_NATIVEVLAN:
5175895Syz147064 	default:
5185895Syz147064 		break;
5195895Syz147064 	}
5205895Syz147064 	return (B_TRUE);
5215895Syz147064 }
5225895Syz147064 
5235895Syz147064 static int
5245895Syz147064 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp)
5255895Syz147064 {
5265895Syz147064 	datalink_id_t	linkid = DATALINK_INVALID_LINKID;
5275895Syz147064 	uint32_t	media;
5285895Syz147064 	int		err;
5295895Syz147064 
5305895Syz147064 	if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media,
5315895Syz147064 	    softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) {
5325895Syz147064 		*linkidp = linkid;
5335895Syz147064 	}
5345895Syz147064 
5355895Syz147064 	if (err == EEXIST) {
5365895Syz147064 		/*
5375895Syz147064 		 * There is a link name conflict.  Either:
5385895Syz147064 		 *
5395895Syz147064 		 * - An existing link with the same device name with a
5405895Syz147064 		 *   different media type from of the given type.
5415895Syz147064 		 *   Mark this link back to persistent only; or
5425895Syz147064 		 *
5435895Syz147064 		 * - We cannot assign the "suggested" name because
5445895Syz147064 		 *   GLDv3 and therefore vanity naming is not supported
5455895Syz147064 		 *   for this link type. Delete this link's <link name,
5465895Syz147064 		 *   linkid> mapping.
5475895Syz147064 		 */
5485895Syz147064 		if (media != softmac->smac_media) {
5495895Syz147064 			cmn_err(CE_WARN, "%s device %s conflicts with "
5505895Syz147064 			    "existing %s device %s.",
5515895Syz147064 			    dl_mactypestr(softmac->smac_media),
5525895Syz147064 			    softmac->smac_devname, dl_mactypestr(media),
5535895Syz147064 			    softmac->smac_devname);
5545895Syz147064 			(void) dls_mgmt_destroy(linkid, B_FALSE);
5555895Syz147064 		} else {
5565895Syz147064 			cmn_err(CE_WARN, "link name %s is already in-use.",
5575895Syz147064 			    softmac->smac_devname);
5585895Syz147064 			(void) dls_mgmt_destroy(linkid, B_TRUE);
5595895Syz147064 		}
5605895Syz147064 
5615895Syz147064 		cmn_err(CE_WARN, "%s device might not be available "
5625895Syz147064 		    "for use.", softmac->smac_devname);
5635895Syz147064 		cmn_err(CE_WARN, "See dladm(1M) for more information.");
5645895Syz147064 	}
5655895Syz147064 
5665895Syz147064 	return (err);
5675895Syz147064 }
5685895Syz147064 
5695895Syz147064 /*
5705895Syz147064  * This function:
5715895Syz147064  * 1. provides the link's media type to dlmgmtd.
5725895Syz147064  * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
5735895Syz147064  */
5745895Syz147064 static int
5755895Syz147064 softmac_create_datalink(softmac_t *softmac)
5765895Syz147064 {
5775895Syz147064 	datalink_id_t	linkid = DATALINK_INVALID_LINKID;
5785895Syz147064 	int		err;
5795895Syz147064 
5805895Syz147064 	/*
5817323SCathy.Zhou@Sun.COM 	 * Inform dlmgmtd of this link so that softmac_hold_device() is able
5827323SCathy.Zhou@Sun.COM 	 * to know the existence of this link. If this failed with EBADF,
5837323SCathy.Zhou@Sun.COM 	 * it might be because dlmgmtd was not started in time (e.g.,
5847323SCathy.Zhou@Sun.COM 	 * diskless boot); ignore the failure and continue to create
5857323SCathy.Zhou@Sun.COM 	 * the GLDv3 datalink if needed.
5865895Syz147064 	 */
5877323SCathy.Zhou@Sun.COM 	err = dls_mgmt_create(softmac->smac_devname,
5887323SCathy.Zhou@Sun.COM 	    makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
5897323SCathy.Zhou@Sun.COM 	    DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid);
5907323SCathy.Zhou@Sun.COM 	if (err != 0 && err != EBADF)
5917323SCathy.Zhou@Sun.COM 		return (err);
5927323SCathy.Zhou@Sun.COM 
5937323SCathy.Zhou@Sun.COM 	/*
5947323SCathy.Zhou@Sun.COM 	 * Provide the media type of the physical link to dlmgmtd.
5957323SCathy.Zhou@Sun.COM 	 */
5967323SCathy.Zhou@Sun.COM 	if ((err != EBADF) &&
5977323SCathy.Zhou@Sun.COM 	    ((err = softmac_update_info(softmac, &linkid)) != 0)) {
5985895Syz147064 		return (err);
5995895Syz147064 	}
6005895Syz147064 
6015895Syz147064 	/*
6025895Syz147064 	 * Create the GLDv3 datalink.
6035895Syz147064 	 */
60410616SSebastien.Roy@Sun.COM 	if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
60510616SSebastien.Roy@Sun.COM 		err = dls_devnet_create(softmac->smac_mh, linkid,
60610616SSebastien.Roy@Sun.COM 		    crgetzoneid(CRED()));
60710616SSebastien.Roy@Sun.COM 		if (err != 0) {
60810616SSebastien.Roy@Sun.COM 			cmn_err(CE_WARN, "dls_devnet_create failed for %s",
60910616SSebastien.Roy@Sun.COM 			    softmac->smac_devname);
61010616SSebastien.Roy@Sun.COM 			return (err);
61110616SSebastien.Roy@Sun.COM 		}
6125895Syz147064 	}
6135895Syz147064 
6148275SEric Cheng 	if (linkid == DATALINK_INVALID_LINKID) {
6158275SEric Cheng 		mutex_enter(&softmac->smac_mutex);
6165895Syz147064 		softmac->smac_flags |= SOFTMAC_NEED_RECREATE;
6178275SEric Cheng 		mutex_exit(&softmac->smac_mutex);
6188275SEric Cheng 	}
6195895Syz147064 
6205895Syz147064 	return (0);
6215895Syz147064 }
6225895Syz147064 
6237323SCathy.Zhou@Sun.COM static void
6247323SCathy.Zhou@Sun.COM softmac_create_task(void *arg)
6257323SCathy.Zhou@Sun.COM {
6267323SCathy.Zhou@Sun.COM 	softmac_t	*softmac = arg;
6277323SCathy.Zhou@Sun.COM 	mac_handle_t	mh;
6287323SCathy.Zhou@Sun.COM 	int		err;
6297323SCathy.Zhou@Sun.COM 
6307323SCathy.Zhou@Sun.COM 	if (!GLDV3_DRV(softmac->smac_umajor)) {
6317323SCathy.Zhou@Sun.COM 		softmac_mac_register(softmac);
6327323SCathy.Zhou@Sun.COM 		return;
6337323SCathy.Zhou@Sun.COM 	}
6347323SCathy.Zhou@Sun.COM 
6357323SCathy.Zhou@Sun.COM 	if ((err = mac_open(softmac->smac_devname, &mh)) != 0)
6367323SCathy.Zhou@Sun.COM 		goto done;
6377323SCathy.Zhou@Sun.COM 
6387323SCathy.Zhou@Sun.COM 	mutex_enter(&softmac->smac_mutex);
6397323SCathy.Zhou@Sun.COM 	softmac->smac_media = (mac_info(mh))->mi_nativemedia;
6407323SCathy.Zhou@Sun.COM 	softmac->smac_mh = mh;
6418275SEric Cheng 	mutex_exit(&softmac->smac_mutex);
6427323SCathy.Zhou@Sun.COM 
6437323SCathy.Zhou@Sun.COM 	/*
6447323SCathy.Zhou@Sun.COM 	 * We can safely release the reference on the mac because
6457323SCathy.Zhou@Sun.COM 	 * this mac will only be unregistered and destroyed when
6467323SCathy.Zhou@Sun.COM 	 * the device detaches, and the softmac will be destroyed
6477323SCathy.Zhou@Sun.COM 	 * before then (in the pre-detach routine of the device).
6487323SCathy.Zhou@Sun.COM 	 */
6497323SCathy.Zhou@Sun.COM 	mac_close(mh);
6507323SCathy.Zhou@Sun.COM 
6517323SCathy.Zhou@Sun.COM 	/*
6527323SCathy.Zhou@Sun.COM 	 * Create the GLDv3 datalink for this mac.
6537323SCathy.Zhou@Sun.COM 	 */
6547323SCathy.Zhou@Sun.COM 	err = softmac_create_datalink(softmac);
6557323SCathy.Zhou@Sun.COM 
6568527SCathy.Zhou@Sun.COM done:
6578275SEric Cheng 	mutex_enter(&softmac->smac_mutex);
6588527SCathy.Zhou@Sun.COM 	if (err != 0)
6598275SEric Cheng 		softmac->smac_mh = NULL;
6608527SCathy.Zhou@Sun.COM 	softmac->smac_attacherr = err;
6618275SEric Cheng 	softmac->smac_state = SOFTMAC_ATTACH_DONE;
6627323SCathy.Zhou@Sun.COM 	cv_broadcast(&softmac->smac_cv);
6637323SCathy.Zhou@Sun.COM 	mutex_exit(&softmac->smac_mutex);
6647323SCathy.Zhou@Sun.COM }
6657323SCathy.Zhou@Sun.COM 
6665895Syz147064 /*
6675895Syz147064  * This function is only called for legacy devices. It:
6685895Syz147064  * 1. registers the MAC for the legacy devices whose media type is supported
6695895Syz147064  *    by the GLDv3 framework.
6705895Syz147064  * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
6715895Syz147064  */
6725895Syz147064 static void
6737323SCathy.Zhou@Sun.COM softmac_mac_register(softmac_t *softmac)
6745895Syz147064 {
6755895Syz147064 	softmac_dev_t	*softmac_dev;
6765895Syz147064 	dev_t		dev;
6775895Syz147064 	ldi_handle_t	lh = NULL;
6785895Syz147064 	ldi_ident_t	li = NULL;
6795895Syz147064 	int		index;
6805895Syz147064 	boolean_t	native_vlan = B_FALSE;
6815895Syz147064 	int		err;
6825895Syz147064 
6835895Syz147064 	/*
6845895Syz147064 	 * Note that we do not need any locks to access this softmac pointer,
6855895Syz147064 	 * as softmac_destroy() will wait until this function is called.
6865895Syz147064 	 */
6875895Syz147064 	ASSERT(softmac != NULL);
6888275SEric Cheng 	ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG &&
6898275SEric Cheng 	    softmac->smac_attachok_cnt == softmac->smac_cnt);
6905895Syz147064 
6915895Syz147064 	if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) {
6925895Syz147064 		mutex_enter(&softmac->smac_mutex);
6935895Syz147064 		goto done;
6945895Syz147064 	}
6955895Syz147064 
6965895Syz147064 	/*
6975895Syz147064 	 * Determine whether this legacy device support VLANs by opening
6985895Syz147064 	 * the style-2 device node (if it exists) and attaching to a VLAN
6995895Syz147064 	 * PPA (1000 + ppa).
7005895Syz147064 	 */
7015895Syz147064 	dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor);
7025895Syz147064 	err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
7035895Syz147064 	if (err == 0) {
7045895Syz147064 		if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0)
7055895Syz147064 			native_vlan = B_TRUE;
7065895Syz147064 		(void) ldi_close(lh, FREAD|FWRITE, kcred);
7075895Syz147064 	}
7085895Syz147064 
7095895Syz147064 	err = EINVAL;
7105895Syz147064 	for (index = 0; index < 2; index++) {
7115895Syz147064 		dl_info_ack_t	dlia;
7125895Syz147064 		dl_error_ack_t	dlea;
7135895Syz147064 		uint32_t	notes;
7145895Syz147064 		struct strioctl	iocb;
7155895Syz147064 		uint32_t	margin;
7165895Syz147064 		int		rval;
7175895Syz147064 
7185895Syz147064 		if ((softmac_dev = softmac->smac_softmac[index]) == NULL)
7195895Syz147064 			continue;
7205895Syz147064 
7215895Syz147064 		softmac->smac_dev = dev = softmac_dev->sd_dev;
7225895Syz147064 		if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh,
7235895Syz147064 		    li) != 0) {
7245895Syz147064 			continue;
7255895Syz147064 		}
7265895Syz147064 
7275895Syz147064 		/*
7285895Syz147064 		 * Pop all the intermediate modules in order to negotiate
7295895Syz147064 		 * capabilities correctly.
7305895Syz147064 		 */
7315895Syz147064 		while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
7325895Syz147064 			;
7335895Syz147064 
7345895Syz147064 		/* DLPI style-1 or DLPI style-2? */
7355895Syz147064 		if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) {
7365895Syz147064 			if (rval == ENOTSUP) {
7375895Syz147064 				cmn_err(CE_NOTE, "softmac: received "
7385895Syz147064 				    "DL_ERROR_ACK to DL_INFO_ACK; "
7395895Syz147064 				    "DLPI errno 0x%x, UNIX errno %d",
7405895Syz147064 				    dlea.dl_errno, dlea.dl_unix_errno);
7415895Syz147064 			}
7425895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
7435895Syz147064 			continue;
7445895Syz147064 		}
7455895Syz147064 
7465895Syz147064 		/*
7475895Syz147064 		 * Currently only DL_ETHER has GLDv3 mac plugin support.
7485895Syz147064 		 * For media types that GLDv3 does not support, create a
7495895Syz147064 		 * link id for it.
7505895Syz147064 		 */
7515895Syz147064 		if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) {
7525895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
7535895Syz147064 			err = 0;
7545895Syz147064 			break;
7555895Syz147064 		}
7565895Syz147064 
7575895Syz147064 		if ((dlia.dl_provider_style == DL_STYLE2) &&
7585895Syz147064 		    (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) {
7595895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
7605895Syz147064 			continue;
7615895Syz147064 		}
7625895Syz147064 
7635895Syz147064 		if ((rval = dl_bind(lh, 0, NULL)) != 0) {
7645895Syz147064 			if (rval == ENOTSUP) {
7655895Syz147064 				cmn_err(CE_NOTE, "softmac: received "
7665895Syz147064 				    "DL_ERROR_ACK to DL_BIND_ACK; "
7675895Syz147064 				    "DLPI errno 0x%x, UNIX errno %d",
7685895Syz147064 				    dlea.dl_errno, dlea.dl_unix_errno);
7695895Syz147064 			}
7705895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
7715895Syz147064 			continue;
7725895Syz147064 		}
7735895Syz147064 
7745895Syz147064 		/*
7755895Syz147064 		 * Call dl_info() after dl_bind() because some drivers only
7765895Syz147064 		 * provide correct information (e.g. MAC address) once bound.
7775895Syz147064 		 */
7785895Syz147064 		softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr);
7795895Syz147064 		if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr,
7805895Syz147064 		    &softmac->smac_addrlen, &dlea)) != 0) {
7815895Syz147064 			if (rval == ENOTSUP) {
7825895Syz147064 				cmn_err(CE_NOTE, "softmac: received "
7835895Syz147064 				    "DL_ERROR_ACK to DL_INFO_ACK; "
7845895Syz147064 				    "DLPI errno 0x%x, UNIX errno %d",
7855895Syz147064 				    dlea.dl_errno, dlea.dl_unix_errno);
7865895Syz147064 			}
7875895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
7885895Syz147064 			continue;
7895895Syz147064 		}
7905895Syz147064 
7915895Syz147064 		softmac->smac_style = dlia.dl_provider_style;
7925895Syz147064 		softmac->smac_saplen = ABS(dlia.dl_sap_length);
7935895Syz147064 		softmac->smac_min_sdu = dlia.dl_min_sdu;
7945895Syz147064 		softmac->smac_max_sdu = dlia.dl_max_sdu;
7955895Syz147064 
7965895Syz147064 		if ((softmac->smac_saplen != sizeof (uint16_t)) ||
7975895Syz147064 		    (softmac->smac_addrlen != ETHERADDRL) ||
7985895Syz147064 		    (dlia.dl_brdcst_addr_length != ETHERADDRL) ||
7995895Syz147064 		    (dlia.dl_brdcst_addr_offset == 0)) {
8005895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
8015895Syz147064 			continue;
8025895Syz147064 		}
8035895Syz147064 
8045895Syz147064 		/*
8055895Syz147064 		 * Check other DLPI capabilities. Note that this must be after
8065895Syz147064 		 * dl_bind() because some drivers return DL_ERROR_ACK if the
8075895Syz147064 		 * stream is not bound. It is also before mac_register(), so
8085895Syz147064 		 * we don't need any lock protection here.
8095895Syz147064 		 */
8105895Syz147064 		softmac->smac_capab_flags =
8118275SEric Cheng 		    (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY);
8125895Syz147064 
8135895Syz147064 		softmac->smac_no_capability_req = B_FALSE;
8145895Syz147064 		if (softmac_fill_capab(lh, softmac) != 0)
8155895Syz147064 			softmac->smac_no_capability_req = B_TRUE;
8165895Syz147064 
8175895Syz147064 		/*
8185895Syz147064 		 * Check the margin of the underlying driver.
8195895Syz147064 		 */
8205895Syz147064 		margin = 0;
8215895Syz147064 		iocb.ic_cmd = DLIOCMARGININFO;
8225895Syz147064 		iocb.ic_timout = INFTIM;
8235895Syz147064 		iocb.ic_len = sizeof (margin);
8245895Syz147064 		iocb.ic_dp = (char *)&margin;
8255895Syz147064 		softmac->smac_margin = 0;
8265895Syz147064 
8275895Syz147064 		if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred,
8285895Syz147064 		    &rval) == 0) {
8295895Syz147064 			softmac->smac_margin = margin;
8305895Syz147064 		}
8315895Syz147064 
8325895Syz147064 		/*
8335895Syz147064 		 * If the legacy driver doesn't support DLIOCMARGININFO, but
8345895Syz147064 		 * it can support native VLAN, correct its margin value to 4.
8355895Syz147064 		 */
8365895Syz147064 		if (native_vlan) {
8375895Syz147064 			if (softmac->smac_margin == 0)
8385895Syz147064 				softmac->smac_margin = VLAN_TAGSZ;
8395895Syz147064 		} else {
8405895Syz147064 			softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN;
8415895Syz147064 		}
8425895Syz147064 
8435895Syz147064 		/*
8445895Syz147064 		 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP.
8455895Syz147064 		 */
8465895Syz147064 		softmac->smac_notifications = 0;
8475895Syz147064 		notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN;
8485895Syz147064 		switch (dl_notify(lh, &notes, NULL)) {
8495895Syz147064 		case 0:
8505895Syz147064 			softmac->smac_notifications = notes;
8515895Syz147064 			break;
8525895Syz147064 		case ENOTSUP:
8535895Syz147064 			break;
8545895Syz147064 		default:
8555895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
8565895Syz147064 			continue;
8575895Syz147064 		}
8585895Syz147064 
8595895Syz147064 		(void) ldi_close(lh, FREAD|FWRITE, kcred);
8605895Syz147064 		err = 0;
8615895Syz147064 		break;
8625895Syz147064 	}
8635895Syz147064 	ldi_ident_release(li);
8645895Syz147064 
8655895Syz147064 	mutex_enter(&softmac->smac_mutex);
8665895Syz147064 
8675895Syz147064 	if (err != 0)
8685895Syz147064 		goto done;
8695895Syz147064 
8705895Syz147064 	if (softmac->smac_media != DL_ETHER)
8715895Syz147064 		softmac->smac_flags |= SOFTMAC_NOSUPP;
8725895Syz147064 
8735895Syz147064 	/*
8745895Syz147064 	 * Finally, we're ready to register ourselves with the MAC layer
8755895Syz147064 	 * interface; if this succeeds, we're all ready to start()
8765895Syz147064 	 */
8775895Syz147064 	if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
8785895Syz147064 		mac_register_t	*macp;
8795895Syz147064 
8805895Syz147064 		if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
8815895Syz147064 			err = ENOMEM;
8825895Syz147064 			goto done;
8835895Syz147064 		}
8845895Syz147064 
8855895Syz147064 		macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
8865895Syz147064 		macp->m_driver = softmac;
8875895Syz147064 		macp->m_dip = softmac_dip;
8885895Syz147064 
8895895Syz147064 		macp->m_margin = softmac->smac_margin;
8905895Syz147064 		macp->m_src_addr = softmac->smac_unicst_addr;
8915895Syz147064 		macp->m_min_sdu = softmac->smac_min_sdu;
8925895Syz147064 		macp->m_max_sdu = softmac->smac_max_sdu;
8935895Syz147064 		macp->m_callbacks = &softmac_m_callbacks;
8945895Syz147064 		macp->m_instance = (uint_t)-1;
8955895Syz147064 
8965895Syz147064 		err = mac_register(macp, &softmac->smac_mh);
8975895Syz147064 		mac_free(macp);
8985895Syz147064 		if (err != 0) {
8995895Syz147064 			cmn_err(CE_WARN, "mac_register failed for %s",
9005895Syz147064 			    softmac->smac_devname);
9015895Syz147064 			goto done;
9025895Syz147064 		}
9035895Syz147064 	}
9048275SEric Cheng 	mutex_exit(&softmac->smac_mutex);
9055895Syz147064 
9065895Syz147064 	/*
9075895Syz147064 	 * Try to create the datalink for this softmac.
9085895Syz147064 	 */
9095895Syz147064 	if ((err = softmac_create_datalink(softmac)) != 0) {
9109073SCathy.Zhou@Sun.COM 		if (!(softmac->smac_flags & SOFTMAC_NOSUPP))
9115895Syz147064 			(void) mac_unregister(softmac->smac_mh);
9129073SCathy.Zhou@Sun.COM 		mutex_enter(&softmac->smac_mutex);
9139073SCathy.Zhou@Sun.COM 		softmac->smac_mh = NULL;
9149073SCathy.Zhou@Sun.COM 		goto done;
9155895Syz147064 	}
9168275SEric Cheng 	/*
9178275SEric Cheng 	 * If succeed, create the thread which handles the DL_NOTIFY_IND from
9188275SEric Cheng 	 * the lower stream.
9198275SEric Cheng 	 */
9209073SCathy.Zhou@Sun.COM 	mutex_enter(&softmac->smac_mutex);
9218275SEric Cheng 	if (softmac->smac_mh != NULL) {
9228275SEric Cheng 		softmac->smac_notify_thread = thread_create(NULL, 0,
9238275SEric Cheng 		    softmac_notify_thread, softmac, 0, &p0,
9248275SEric Cheng 		    TS_RUN, minclsyspri);
9258275SEric Cheng 	}
9265895Syz147064 
9275895Syz147064 done:
9288275SEric Cheng 	ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG &&
9298275SEric Cheng 	    softmac->smac_attachok_cnt == softmac->smac_cnt);
9308275SEric Cheng 	softmac->smac_state = SOFTMAC_ATTACH_DONE;
9315895Syz147064 	softmac->smac_attacherr = err;
9325895Syz147064 	cv_broadcast(&softmac->smac_cv);
9335895Syz147064 	mutex_exit(&softmac->smac_mutex);
9345895Syz147064 }
9355895Syz147064 
9365895Syz147064 int
9375895Syz147064 softmac_destroy(dev_info_t *dip, dev_t dev)
9385895Syz147064 {
9395895Syz147064 	char			devname[MAXNAMELEN];
9405895Syz147064 	softmac_t		*softmac;
9415895Syz147064 	softmac_dev_t		*softmac_dev;
9425895Syz147064 	int			index;
9435895Syz147064 	int			ppa, err;
9445895Syz147064 	datalink_id_t		linkid;
9458275SEric Cheng 	mac_handle_t		smac_mh;
9468275SEric Cheng 	uint32_t		smac_flags;
9475895Syz147064 
948*10654SGarrett.Damore@Sun.COM 	if (GLDV3_DRV(ddi_driver_major(dip))) {
949*10654SGarrett.Damore@Sun.COM 		minor_t minor = getminor(dev);
950*10654SGarrett.Damore@Sun.COM 		/*
951*10654SGarrett.Damore@Sun.COM 		 * For an explanation of this logic, see the
952*10654SGarrett.Damore@Sun.COM 		 * equivalent code in softmac_create.
953*10654SGarrett.Damore@Sun.COM 		 */
954*10654SGarrett.Damore@Sun.COM 		if ((strcmp(ddi_driver_name(dip), "clone") == 0) ||
955*10654SGarrett.Damore@Sun.COM 		    (getmajor(dev) == ddi_name_to_major("clone")) ||
956*10654SGarrett.Damore@Sun.COM 		    (minor == 0)) {
957*10654SGarrett.Damore@Sun.COM 			return (0);
958*10654SGarrett.Damore@Sun.COM 		}
959*10654SGarrett.Damore@Sun.COM 		if (minor >= DLS_MAX_MINOR) {
960*10654SGarrett.Damore@Sun.COM 			return (ENOTSUP);
961*10654SGarrett.Damore@Sun.COM 		}
962*10654SGarrett.Damore@Sun.COM 		ppa = DLS_MINOR2INST(minor);
963*10654SGarrett.Damore@Sun.COM 	} else {
964*10654SGarrett.Damore@Sun.COM 		ppa = ddi_get_instance(dip);
965*10654SGarrett.Damore@Sun.COM 	}
966*10654SGarrett.Damore@Sun.COM 
9675895Syz147064 	(void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
9685895Syz147064 
9698275SEric Cheng 	/*
9708275SEric Cheng 	 * We are called only from the predetach entry point. The DACF
9718275SEric Cheng 	 * framework ensures there can't be a concurrent postattach call
9728275SEric Cheng 	 * for the same softmac. The softmac found out from the modhash
9738275SEric Cheng 	 * below can't vanish beneath us since this is the only place where
9748275SEric Cheng 	 * it is deleted.
9758275SEric Cheng 	 */
9765895Syz147064 	err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
9775895Syz147064 	    (mod_hash_val_t *)&softmac);
9785895Syz147064 	ASSERT(err == 0);
9795895Syz147064 
9805895Syz147064 	mutex_enter(&softmac->smac_mutex);
9818275SEric Cheng 	SOFTMAC_STATE_VERIFY(softmac);
9825895Syz147064 
9835895Syz147064 	/*
9845895Syz147064 	 * Fail the predetach routine if this softmac is in-use.
9858275SEric Cheng 	 * Make sure these downcalls into softmac_create or softmac_destroy
9868275SEric Cheng 	 * don't cv_wait on any devfs related condition. Thus softmac_destroy
9878275SEric Cheng 	 * returns EBUSY if the asynchronous thread started in softmac_create
9888275SEric Cheng 	 * hasn't finished
9895895Syz147064 	 */
9908275SEric Cheng 	if ((softmac->smac_hold_cnt != 0) ||
9918275SEric Cheng 	    (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) {
9925895Syz147064 		softmac->smac_attached_left = softmac->smac_attachok_cnt;
9935895Syz147064 		mutex_exit(&softmac->smac_mutex);
9945895Syz147064 		return (EBUSY);
9955895Syz147064 	}
9965895Syz147064 
9975895Syz147064 	/*
9985895Syz147064 	 * Even if the predetach of one minor node has already failed
9995895Syz147064 	 * (smac_attached_left is not 0), the DACF framework will continue
10005895Syz147064 	 * to call the predetach routines of the other minor nodes,
10015895Syz147064 	 * so we fail these calls here.
10025895Syz147064 	 */
10035895Syz147064 	if (softmac->smac_attached_left != 0) {
10045895Syz147064 		mutex_exit(&softmac->smac_mutex);
10055895Syz147064 		return (EBUSY);
10065895Syz147064 	}
10075895Syz147064 
10088275SEric Cheng 	smac_mh = softmac->smac_mh;
10098275SEric Cheng 	smac_flags = softmac->smac_flags;
10108275SEric Cheng 	softmac->smac_state = SOFTMAC_DETACH_INPROG;
10118275SEric Cheng 	mutex_exit(&softmac->smac_mutex);
10125895Syz147064 
10138275SEric Cheng 	if (smac_mh != NULL) {
10148275SEric Cheng 		/*
10158275SEric Cheng 		 * This is the first minor node that is being detached for this
10168275SEric Cheng 		 * softmac.
10178275SEric Cheng 		 */
10188275SEric Cheng 		ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
10198275SEric Cheng 		if (!(smac_flags & SOFTMAC_NOSUPP)) {
10208275SEric Cheng 			if ((err = dls_devnet_destroy(smac_mh, &linkid,
10218275SEric Cheng 			    B_FALSE)) != 0) {
10228275SEric Cheng 				goto error;
10235895Syz147064 			}
10245895Syz147064 		}
10255895Syz147064 		/*
10265895Syz147064 		 * If softmac_mac_register() succeeds in registering the mac
10275895Syz147064 		 * of the legacy device, unregister it.
10285895Syz147064 		 */
10298275SEric Cheng 		if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) {
10308275SEric Cheng 			if ((err = mac_disable_nowait(smac_mh)) != 0) {
103110616SSebastien.Roy@Sun.COM 				(void) dls_devnet_create(smac_mh, linkid,
103210616SSebastien.Roy@Sun.COM 				    crgetzoneid(CRED()));
10338275SEric Cheng 				goto error;
10345895Syz147064 			}
10358275SEric Cheng 			/*
10368275SEric Cheng 			 * Ask softmac_notify_thread to quit, and wait for
10378275SEric Cheng 			 * that to be done.
10388275SEric Cheng 			 */
10398275SEric Cheng 			mutex_enter(&softmac->smac_mutex);
10408275SEric Cheng 			softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT;
10418275SEric Cheng 			cv_broadcast(&softmac->smac_cv);
10428275SEric Cheng 			while (softmac->smac_notify_thread != NULL) {
10438275SEric Cheng 				cv_wait(&softmac->smac_cv,
10448275SEric Cheng 				    &softmac->smac_mutex);
10458275SEric Cheng 			}
10468275SEric Cheng 			mutex_exit(&softmac->smac_mutex);
10478275SEric Cheng 			VERIFY(mac_unregister(smac_mh) == 0);
10485895Syz147064 		}
10495895Syz147064 		softmac->smac_mh = NULL;
10505895Syz147064 	}
10518275SEric Cheng 
10528275SEric Cheng 	/*
10538275SEric Cheng 	 * Free softmac_dev
10548275SEric Cheng 	 */
10558275SEric Cheng 	rw_enter(&softmac_hash_lock, RW_WRITER);
10568275SEric Cheng 	mutex_enter(&softmac->smac_mutex);
10575895Syz147064 
10588275SEric Cheng 	ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG &&
10598275SEric Cheng 	    softmac->smac_attachok_cnt != 0);
10608275SEric Cheng 	softmac->smac_mh = NULL;
10618275SEric Cheng 	index = (getmajor(dev) == ddi_name_to_major("clone"));
10628275SEric Cheng 	softmac_dev = softmac->smac_softmac[index];
10638275SEric Cheng 	ASSERT(softmac_dev != NULL);
10648275SEric Cheng 	softmac->smac_softmac[index] = NULL;
10658275SEric Cheng 	kmem_free(softmac_dev, sizeof (softmac_dev_t));
10665895Syz147064 
10678275SEric Cheng 	if (--softmac->smac_attachok_cnt == 0) {
10688275SEric Cheng 		mod_hash_val_t	hashval;
10695895Syz147064 
10708275SEric Cheng 		softmac->smac_state = SOFTMAC_UNINIT;
10718275SEric Cheng 		if (softmac->smac_hold_cnt != 0) {
10728275SEric Cheng 			/*
10738275SEric Cheng 			 * Someone did a softmac_hold_device while we dropped
10748275SEric Cheng 			 * the locks. Leave the softmac itself intact which
10758275SEric Cheng 			 * will be reused by the reattach
10768275SEric Cheng 			 */
10775895Syz147064 			mutex_exit(&softmac->smac_mutex);
10785895Syz147064 			rw_exit(&softmac_hash_lock);
10795895Syz147064 			return (0);
10805895Syz147064 		}
10818275SEric Cheng 		err = mod_hash_remove(softmac_hash,
10828275SEric Cheng 		    (mod_hash_key_t)devname,
10838275SEric Cheng 		    (mod_hash_val_t *)&hashval);
10848275SEric Cheng 		ASSERT(err == 0);
10858275SEric Cheng 
10868275SEric Cheng 		mutex_exit(&softmac->smac_mutex);
10878275SEric Cheng 		rw_exit(&softmac_hash_lock);
10889073SCathy.Zhou@Sun.COM 		ASSERT(softmac->smac_fp_disable_clients == 0);
10899073SCathy.Zhou@Sun.COM 		softmac->smac_fastpath_admin_disabled = B_FALSE;
10909073SCathy.Zhou@Sun.COM 		kmem_cache_free(softmac_cachep, softmac);
10918275SEric Cheng 		return (0);
10925895Syz147064 	}
10935895Syz147064 	mutex_exit(&softmac->smac_mutex);
10945895Syz147064 	rw_exit(&softmac_hash_lock);
10958275SEric Cheng 	return (0);
10968275SEric Cheng 
10978275SEric Cheng error:
10988275SEric Cheng 	mutex_enter(&softmac->smac_mutex);
10998275SEric Cheng 	softmac->smac_attached_left = softmac->smac_attachok_cnt;
11008275SEric Cheng 	softmac->smac_state = SOFTMAC_ATTACH_DONE;
11018275SEric Cheng 	cv_broadcast(&softmac->smac_cv);
11028275SEric Cheng 	mutex_exit(&softmac->smac_mutex);
11035895Syz147064 	return (err);
11045895Syz147064 }
11055895Syz147064 
11065895Syz147064 /*
11075895Syz147064  * This function is called as the result of a newly started dlmgmtd daemon.
11085895Syz147064  *
11095895Syz147064  * We walk through every softmac that was created but failed to notify
11105895Syz147064  * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set).  This occurs
11115895Syz147064  * when softmacs are created before dlmgmtd is ready.  For example, during
11125895Syz147064  * diskless boot, a network device is used (and therefore attached) before
11135895Syz147064  * the datalink-management service starts dlmgmtd.
11145895Syz147064  */
11155895Syz147064 /* ARGSUSED */
11165895Syz147064 static uint_t
11175895Syz147064 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
11185895Syz147064 {
11195895Syz147064 	softmac_t	*softmac = (softmac_t *)val;
11205895Syz147064 	datalink_id_t	linkid;
11215895Syz147064 	int		err;
11228275SEric Cheng 	softmac_walk_t	*smwp = arg;
11235895Syz147064 
11245895Syz147064 	/*
11258275SEric Cheng 	 * The framework itself must not hold any locks across calls to the
11268275SEric Cheng 	 * mac perimeter. Thus this function does not call any framework
11278275SEric Cheng 	 * function that needs to grab the mac perimeter.
11285895Syz147064 	 */
11298275SEric Cheng 	ASSERT(RW_READ_HELD(&softmac_hash_lock));
11308275SEric Cheng 
11318275SEric Cheng 	smwp->smw_retry = B_FALSE;
11325895Syz147064 	mutex_enter(&softmac->smac_mutex);
11338275SEric Cheng 	SOFTMAC_STATE_VERIFY(softmac);
11348275SEric Cheng 	if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) {
11358275SEric Cheng 		/*
11368275SEric Cheng 		 * Wait till softmac_create or softmac_mac_register finishes
11378275SEric Cheng 		 * Hold the softmac to ensure it stays around. The wait itself
11388275SEric Cheng 		 * is done in the caller, since we need to drop all locks
11398275SEric Cheng 		 * including the mod hash's internal lock before calling
11408275SEric Cheng 		 * cv_wait.
11418275SEric Cheng 		 */
11428275SEric Cheng 		smwp->smw_retry = B_TRUE;
11438275SEric Cheng 		smwp->smw_softmac = softmac;
11448275SEric Cheng 		softmac->smac_hold_cnt++;
11458275SEric Cheng 		return (MH_WALK_TERMINATE);
11468275SEric Cheng 	}
11475895Syz147064 
11488275SEric Cheng 	if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) ||
11495895Syz147064 	    !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) {
11505895Syz147064 		mutex_exit(&softmac->smac_mutex);
11515895Syz147064 		return (MH_WALK_CONTINUE);
11525895Syz147064 	}
11535895Syz147064 
11548833SVenu.Iyer@Sun.COM 	/*
11558833SVenu.Iyer@Sun.COM 	 * Bumping up the smac_hold_cnt allows us to drop the lock. It also
11568833SVenu.Iyer@Sun.COM 	 * makes softmac_destroy() return failure on an attempted device detach.
11578833SVenu.Iyer@Sun.COM 	 * We don't want to hold the lock across calls to other subsystems
11588833SVenu.Iyer@Sun.COM 	 * like kstats, which will happen in the call to dls_devnet_recreate
11598833SVenu.Iyer@Sun.COM 	 */
11608833SVenu.Iyer@Sun.COM 	softmac->smac_hold_cnt++;
11618833SVenu.Iyer@Sun.COM 	mutex_exit(&softmac->smac_mutex);
11628833SVenu.Iyer@Sun.COM 
11635895Syz147064 	if (dls_mgmt_create(softmac->smac_devname,
11645895Syz147064 	    makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
11655895Syz147064 	    DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) {
11668833SVenu.Iyer@Sun.COM 		softmac_rele_device((dls_dev_handle_t)softmac);
11675895Syz147064 		return (MH_WALK_CONTINUE);
11685895Syz147064 	}
11695895Syz147064 
11705895Syz147064 	if ((err = softmac_update_info(softmac, &linkid)) != 0) {
11715895Syz147064 		cmn_err(CE_WARN, "softmac: softmac_update_info() for %s "
11725895Syz147064 		    "failed (%d)", softmac->smac_devname, err);
11738833SVenu.Iyer@Sun.COM 		softmac_rele_device((dls_dev_handle_t)softmac);
11745895Syz147064 		return (MH_WALK_CONTINUE);
11755895Syz147064 	}
11765895Syz147064 
11775895Syz147064 	/*
11785895Syz147064 	 * Create a link for this MAC. The link name will be the same
11795895Syz147064 	 * as the MAC name.
11805895Syz147064 	 */
11815895Syz147064 	if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
11825895Syz147064 		err = dls_devnet_recreate(softmac->smac_mh, linkid);
11835895Syz147064 		if (err != 0) {
11845895Syz147064 			cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for "
11855895Syz147064 			    "%s (linkid %d) failed (%d)",
11865895Syz147064 			    softmac->smac_devname, linkid, err);
11875895Syz147064 		}
11885895Syz147064 	}
11895895Syz147064 
11908833SVenu.Iyer@Sun.COM 	mutex_enter(&softmac->smac_mutex);
11915895Syz147064 	softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE;
11928833SVenu.Iyer@Sun.COM 	ASSERT(softmac->smac_hold_cnt != 0);
11938833SVenu.Iyer@Sun.COM 	softmac->smac_hold_cnt--;
11945895Syz147064 	mutex_exit(&softmac->smac_mutex);
11955895Syz147064 
11965895Syz147064 	return (MH_WALK_CONTINUE);
11975895Syz147064 }
11985895Syz147064 
11995895Syz147064 /*
12005895Syz147064  * See comments above softmac_mac_recreate().
12015895Syz147064  */
12025895Syz147064 void
12035895Syz147064 softmac_recreate()
12045895Syz147064 {
12058275SEric Cheng 	softmac_walk_t	smw;
12068275SEric Cheng 	softmac_t	*softmac;
12078275SEric Cheng 
12085895Syz147064 	/*
12095895Syz147064 	 * Walk through the softmac_hash table. Request to create the
12105895Syz147064 	 * [link name, linkid] mapping if we failed to do so.
12115895Syz147064 	 */
12128275SEric Cheng 	do {
12138275SEric Cheng 		smw.smw_retry = B_FALSE;
12148275SEric Cheng 		rw_enter(&softmac_hash_lock, RW_READER);
12158275SEric Cheng 		mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw);
12168275SEric Cheng 		rw_exit(&softmac_hash_lock);
12178275SEric Cheng 		if (smw.smw_retry) {
12188275SEric Cheng 			/*
12198275SEric Cheng 			 * softmac_create or softmac_mac_register hasn't yet
12208275SEric Cheng 			 * finished and the softmac is not yet in the
12218275SEric Cheng 			 * SOFTMAC_ATTACH_DONE state.
12228275SEric Cheng 			 */
12238275SEric Cheng 			softmac = smw.smw_softmac;
12248275SEric Cheng 			cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
12258275SEric Cheng 			softmac->smac_hold_cnt--;
12268275SEric Cheng 			mutex_exit(&softmac->smac_mutex);
12278275SEric Cheng 		}
12288275SEric Cheng 	} while (smw.smw_retry);
12295895Syz147064 }
12305895Syz147064 
12315895Syz147064 static int
12325895Syz147064 softmac_m_start(void *arg)
12335895Syz147064 {
12349073SCathy.Zhou@Sun.COM 	softmac_t	*softmac = arg;
12359073SCathy.Zhou@Sun.COM 	softmac_lower_t	*slp = softmac->smac_lower;
12369073SCathy.Zhou@Sun.COM 	int		err;
12379073SCathy.Zhou@Sun.COM 
12389073SCathy.Zhou@Sun.COM 	ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
12399073SCathy.Zhou@Sun.COM 	/*
12409073SCathy.Zhou@Sun.COM 	 * Bind to SAP 2 on token ring, 0 on other interface types.
12419073SCathy.Zhou@Sun.COM 	 * (SAP 0 has special significance on token ring).
12429073SCathy.Zhou@Sun.COM 	 * Note that the receive-side packets could come anytime after bind.
12439073SCathy.Zhou@Sun.COM 	 */
12449073SCathy.Zhou@Sun.COM 	err = softmac_send_bind_req(slp, softmac->smac_media == DL_TPR ? 2 : 0);
12459073SCathy.Zhou@Sun.COM 	if (err != 0)
12469073SCathy.Zhou@Sun.COM 		return (err);
12479073SCathy.Zhou@Sun.COM 
12489073SCathy.Zhou@Sun.COM 	/*
12499073SCathy.Zhou@Sun.COM 	 * Put the lower stream to the DL_PROMISC_SAP mode in order to receive
12509073SCathy.Zhou@Sun.COM 	 * all packets of interest.
12519073SCathy.Zhou@Sun.COM 	 *
12529073SCathy.Zhou@Sun.COM 	 * some driver (e.g. the old legacy eri driver) incorrectly passes up
12539073SCathy.Zhou@Sun.COM 	 * packets to DL_PROMISC_SAP stream when the lower stream is not bound,
12549073SCathy.Zhou@Sun.COM 	 * so that we send DL_PROMISON_REQ after DL_BIND_REQ.
12559073SCathy.Zhou@Sun.COM 	 */
12569073SCathy.Zhou@Sun.COM 	err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE);
12579073SCathy.Zhou@Sun.COM 	if (err != 0) {
12589073SCathy.Zhou@Sun.COM 		(void) softmac_send_unbind_req(slp);
12599073SCathy.Zhou@Sun.COM 		return (err);
12609073SCathy.Zhou@Sun.COM 	}
12619073SCathy.Zhou@Sun.COM 
12629073SCathy.Zhou@Sun.COM 	/*
12639073SCathy.Zhou@Sun.COM 	 * Enable capabilities the underlying driver claims to support.
12649073SCathy.Zhou@Sun.COM 	 * Some driver requires this being called after the stream is bound.
12659073SCathy.Zhou@Sun.COM 	 */
12669073SCathy.Zhou@Sun.COM 	if ((err = softmac_capab_enable(slp)) != 0) {
12679073SCathy.Zhou@Sun.COM 		(void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE);
12689073SCathy.Zhou@Sun.COM 		(void) softmac_send_unbind_req(slp);
12699073SCathy.Zhou@Sun.COM 	}
12709073SCathy.Zhou@Sun.COM 
12719073SCathy.Zhou@Sun.COM 	return (err);
12725895Syz147064 }
12735895Syz147064 
12745895Syz147064 /* ARGSUSED */
12755895Syz147064 static void
12765895Syz147064 softmac_m_stop(void *arg)
12775895Syz147064 {
12789073SCathy.Zhou@Sun.COM 	softmac_t	*softmac = arg;
12799073SCathy.Zhou@Sun.COM 	softmac_lower_t	*slp = softmac->smac_lower;
12809073SCathy.Zhou@Sun.COM 
12819073SCathy.Zhou@Sun.COM 	ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
12829073SCathy.Zhou@Sun.COM 
12839073SCathy.Zhou@Sun.COM 	/*
12849073SCathy.Zhou@Sun.COM 	 * It is not needed to reset zerocopy, MDT or HCKSUM capabilities.
12859073SCathy.Zhou@Sun.COM 	 */
12869073SCathy.Zhou@Sun.COM 	(void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE);
12879073SCathy.Zhou@Sun.COM 	(void) softmac_send_unbind_req(slp);
12885895Syz147064 }
12895895Syz147064 
12905895Syz147064 /*
12919073SCathy.Zhou@Sun.COM  * Set up the lower stream above the legacy device. There are two different
12929073SCathy.Zhou@Sun.COM  * type of lower streams:
12939073SCathy.Zhou@Sun.COM  *
12949073SCathy.Zhou@Sun.COM  * - Shared lower-stream
12959073SCathy.Zhou@Sun.COM  *
12969073SCathy.Zhou@Sun.COM  * Shared by all GLDv3 MAC clients. Put the lower stream to the DLIOCRAW
12979073SCathy.Zhou@Sun.COM  * mode to send and receive the raw data. Further, put the lower stream into
12985895Syz147064  * DL_PROMISC_SAP mode to receive all packets of interest.
12999073SCathy.Zhou@Sun.COM  *
13009073SCathy.Zhou@Sun.COM  * - Dedicated lower-stream
13019073SCathy.Zhou@Sun.COM  *
13029073SCathy.Zhou@Sun.COM  * The lower-stream which is dedicated to upper IP/ARP stream. This is used
13039073SCathy.Zhou@Sun.COM  * as fast-path for IP. In this case, the second argument is the pointer to
13049073SCathy.Zhou@Sun.COM  * the softmac upper-stream.
13055895Syz147064  */
13069073SCathy.Zhou@Sun.COM int
13079073SCathy.Zhou@Sun.COM softmac_lower_setup(softmac_t *softmac, softmac_upper_t *sup,
13089073SCathy.Zhou@Sun.COM     softmac_lower_t **slpp)
13095895Syz147064 {
13105895Syz147064 	ldi_ident_t		li;
13115895Syz147064 	dev_t			dev;
13125895Syz147064 	ldi_handle_t		lh = NULL;
13135895Syz147064 	softmac_lower_t		*slp = NULL;
13145895Syz147064 	smac_ioc_start_t	start_arg;
13155895Syz147064 	struct strioctl		strioc;
13165895Syz147064 	uint32_t		notifications;
13175895Syz147064 	int			err, rval;
13185895Syz147064 
13195895Syz147064 	if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0)
13205895Syz147064 		return (err);
13215895Syz147064 
13229073SCathy.Zhou@Sun.COM 	/*
13239073SCathy.Zhou@Sun.COM 	 * The GLDv3 framework makes sure that mac_unregister(), mac_open(),
13249073SCathy.Zhou@Sun.COM 	 * and mac_close() cannot be called at the same time. So we don't
13259073SCathy.Zhou@Sun.COM 	 * need any protection to access softmac here.
13269073SCathy.Zhou@Sun.COM 	 */
13275895Syz147064 	dev = softmac->smac_dev;
13289073SCathy.Zhou@Sun.COM 
13295895Syz147064 	err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
13305895Syz147064 	ldi_ident_release(li);
13315895Syz147064 	if (err != 0)
13325895Syz147064 		goto done;
13335895Syz147064 
13345895Syz147064 	/*
13355895Syz147064 	 * Pop all the intermediate modules. The autopushed modules will
13365895Syz147064 	 * be pushed when the softmac node is opened.
13375895Syz147064 	 */
13385895Syz147064 	while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
13395895Syz147064 		;
13405895Syz147064 
13415895Syz147064 	if ((softmac->smac_style == DL_STYLE2) &&
13425895Syz147064 	    ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) {
13435895Syz147064 		goto done;
13445895Syz147064 	}
13455895Syz147064 
13465895Syz147064 	/*
13479073SCathy.Zhou@Sun.COM 	 * If this is the shared-lower-stream, put the lower stream to
13489073SCathy.Zhou@Sun.COM 	 * the DLIOCRAW mode to send/receive raw data.
13495895Syz147064 	 */
13509073SCathy.Zhou@Sun.COM 	if ((sup == NULL) && (err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL,
13519073SCathy.Zhou@Sun.COM 	    kcred, &rval)) != 0) {
13525895Syz147064 		goto done;
13539073SCathy.Zhou@Sun.COM 	}
13545895Syz147064 
13555895Syz147064 	/*
13565895Syz147064 	 * Then push the softmac shim layer atop the lower stream.
13575895Syz147064 	 */
13585895Syz147064 	if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL,
13595895Syz147064 	    kcred, &rval)) != 0) {
13605895Syz147064 		goto done;
13615895Syz147064 	}
13625895Syz147064 
13635895Syz147064 	/*
13645895Syz147064 	 * Send the ioctl to get the slp pointer.
13655895Syz147064 	 */
13665895Syz147064 	strioc.ic_cmd = SMAC_IOC_START;
13675895Syz147064 	strioc.ic_timout = INFTIM;
13685895Syz147064 	strioc.ic_len = sizeof (start_arg);
13695895Syz147064 	strioc.ic_dp = (char *)&start_arg;
13705895Syz147064 
13715895Syz147064 	if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL,
13725895Syz147064 	    kcred, &rval)) != 0) {
13735895Syz147064 		goto done;
13745895Syz147064 	}
13755895Syz147064 	slp = start_arg.si_slp;
13769073SCathy.Zhou@Sun.COM 	slp->sl_sup = sup;
13775895Syz147064 	slp->sl_lh = lh;
13785895Syz147064 	slp->sl_softmac = softmac;
13795895Syz147064 	*slpp = slp;
13805895Syz147064 
13819073SCathy.Zhou@Sun.COM 	if (sup != NULL) {
13829073SCathy.Zhou@Sun.COM 		slp->sl_rxinfo = &sup->su_rxinfo;
13839073SCathy.Zhou@Sun.COM 	} else {
13849073SCathy.Zhou@Sun.COM 		/*
13859073SCathy.Zhou@Sun.COM 		 * Send DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND.
13869073SCathy.Zhou@Sun.COM 		 * We don't have to wait for the ack.
13879073SCathy.Zhou@Sun.COM 		 */
13889073SCathy.Zhou@Sun.COM 		notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP |
13899073SCathy.Zhou@Sun.COM 		    DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS |
13909073SCathy.Zhou@Sun.COM 		    DL_NOTE_PROMISC_OFF_PHYS;
13915895Syz147064 
13929073SCathy.Zhou@Sun.COM 		(void) softmac_send_notify_req(slp,
13939073SCathy.Zhou@Sun.COM 		    (notifications & softmac->smac_notifications));
13949073SCathy.Zhou@Sun.COM 	}
13955895Syz147064 
13965895Syz147064 done:
13975895Syz147064 	if (err != 0)
13985895Syz147064 		(void) ldi_close(lh, FREAD|FWRITE, kcred);
13995895Syz147064 	return (err);
14005895Syz147064 }
14015895Syz147064 
14025895Syz147064 static int
14035895Syz147064 softmac_m_open(void *arg)
14045895Syz147064 {
14055895Syz147064 	softmac_t	*softmac = arg;
14065895Syz147064 	softmac_lower_t	*slp;
14075895Syz147064 	int		err;
14085895Syz147064 
14098275SEric Cheng 	ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
14105895Syz147064 
14119073SCathy.Zhou@Sun.COM 	if ((err = softmac_lower_setup(softmac, NULL, &slp)) != 0)
14125895Syz147064 		return (err);
14135895Syz147064 
14145895Syz147064 	softmac->smac_lower = slp;
14155895Syz147064 	return (0);
14165895Syz147064 }
14175895Syz147064 
14185895Syz147064 static void
14195895Syz147064 softmac_m_close(void *arg)
14205895Syz147064 {
14215895Syz147064 	softmac_t	*softmac = arg;
14225895Syz147064 	softmac_lower_t	*slp;
14235895Syz147064 
14248275SEric Cheng 	ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
14255895Syz147064 	slp = softmac->smac_lower;
14265895Syz147064 	ASSERT(slp != NULL);
14275895Syz147064 
14285895Syz147064 	/*
14295895Syz147064 	 * Note that slp is destroyed when lh is closed.
14305895Syz147064 	 */
14315895Syz147064 	(void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred);
14325895Syz147064 	softmac->smac_lower = NULL;
14335895Syz147064 }
14345895Syz147064 
14359073SCathy.Zhou@Sun.COM /*
14369073SCathy.Zhou@Sun.COM  * Softmac supports two priviate link properteis:
14379073SCathy.Zhou@Sun.COM  *
14389073SCathy.Zhou@Sun.COM  * - "_fastpath"
14399073SCathy.Zhou@Sun.COM  *
14409073SCathy.Zhou@Sun.COM  *    This is a read-only link property which points out the current data-path
14419073SCathy.Zhou@Sun.COM  *    model of the given legacy link. The possible values are "disabled" and
14429073SCathy.Zhou@Sun.COM  *    "enabled".
14439073SCathy.Zhou@Sun.COM  *
14449073SCathy.Zhou@Sun.COM  * - "_disable_fastpath"
14459073SCathy.Zhou@Sun.COM  *
14469073SCathy.Zhou@Sun.COM  *    This is a read-write link property which can be used to disable or enable
14479073SCathy.Zhou@Sun.COM  *    the fast-path of the given legacy link. The possible values are "true"
14489073SCathy.Zhou@Sun.COM  *    and "false". Note that even when "_disable_fastpath" is set to be
14499073SCathy.Zhou@Sun.COM  *    "false", the fast-path may still not be enabled since there may be
14509073SCathy.Zhou@Sun.COM  *    other mac cleints that request the fast-path to be disabled.
14519073SCathy.Zhou@Sun.COM  */
14529073SCathy.Zhou@Sun.COM /* ARGSUSED */
14539073SCathy.Zhou@Sun.COM static int
14549073SCathy.Zhou@Sun.COM softmac_m_setprop(void *arg, const char *name, mac_prop_id_t id,
14559073SCathy.Zhou@Sun.COM     uint_t valsize, const void *val)
14569073SCathy.Zhou@Sun.COM {
14579073SCathy.Zhou@Sun.COM 	softmac_t	*softmac = arg;
14589073SCathy.Zhou@Sun.COM 
14599073SCathy.Zhou@Sun.COM 	if (id != MAC_PROP_PRIVATE || strcmp(name, "_disable_fastpath") != 0)
14609073SCathy.Zhou@Sun.COM 		return (ENOTSUP);
14619073SCathy.Zhou@Sun.COM 
14629073SCathy.Zhou@Sun.COM 	if (strcmp(val, "true") == 0)
14639073SCathy.Zhou@Sun.COM 		return (softmac_datapath_switch(softmac, B_TRUE, B_TRUE));
14649073SCathy.Zhou@Sun.COM 	else if (strcmp(val, "false") == 0)
14659073SCathy.Zhou@Sun.COM 		return (softmac_datapath_switch(softmac, B_FALSE, B_TRUE));
14669073SCathy.Zhou@Sun.COM 	else
14679073SCathy.Zhou@Sun.COM 		return (EINVAL);
14689073SCathy.Zhou@Sun.COM }
14699073SCathy.Zhou@Sun.COM 
14709073SCathy.Zhou@Sun.COM static int
14719073SCathy.Zhou@Sun.COM softmac_m_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t flags,
14729073SCathy.Zhou@Sun.COM     uint_t valsize, void *val, uint_t *perm)
14739073SCathy.Zhou@Sun.COM {
14749073SCathy.Zhou@Sun.COM 	softmac_t	*softmac = arg;
14759073SCathy.Zhou@Sun.COM 	char		*fpstr;
14769073SCathy.Zhou@Sun.COM 
14779073SCathy.Zhou@Sun.COM 	if (id != MAC_PROP_PRIVATE)
14789073SCathy.Zhou@Sun.COM 		return (ENOTSUP);
14799073SCathy.Zhou@Sun.COM 
14809073SCathy.Zhou@Sun.COM 	if (strcmp(name, "_fastpath") == 0) {
14819073SCathy.Zhou@Sun.COM 		if ((flags & MAC_PROP_DEFAULT) != 0)
14829073SCathy.Zhou@Sun.COM 			return (ENOTSUP);
14839073SCathy.Zhou@Sun.COM 
14849073SCathy.Zhou@Sun.COM 		*perm = MAC_PROP_PERM_READ;
14859073SCathy.Zhou@Sun.COM 		mutex_enter(&softmac->smac_fp_mutex);
14869073SCathy.Zhou@Sun.COM 		fpstr = (DATAPATH_MODE(softmac) == SOFTMAC_SLOWPATH) ?
14879073SCathy.Zhou@Sun.COM 		    "disabled" : "enabled";
14889073SCathy.Zhou@Sun.COM 		mutex_exit(&softmac->smac_fp_mutex);
14899073SCathy.Zhou@Sun.COM 	} else if (strcmp(name, "_disable_fastpath") == 0) {
14909073SCathy.Zhou@Sun.COM 		*perm = MAC_PROP_PERM_RW;
14919073SCathy.Zhou@Sun.COM 		fpstr = ((flags & MAC_PROP_DEFAULT) != 0) ? "false" :
14929073SCathy.Zhou@Sun.COM 		    (softmac->smac_fastpath_admin_disabled ? "true" : "false");
14939073SCathy.Zhou@Sun.COM 	} else {
14949073SCathy.Zhou@Sun.COM 		return (ENOTSUP);
14959073SCathy.Zhou@Sun.COM 	}
14969073SCathy.Zhou@Sun.COM 
14979073SCathy.Zhou@Sun.COM 	return (strlcpy(val, fpstr, valsize) >= valsize ? EINVAL : 0);
14989073SCathy.Zhou@Sun.COM }
14999073SCathy.Zhou@Sun.COM 
15005895Syz147064 int
15015895Syz147064 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp)
15025895Syz147064 {
15035895Syz147064 	dev_info_t	*dip;
15046915Syz147064 	const char	*drvname;
15055895Syz147064 	char		devname[MAXNAMELEN];
15065895Syz147064 	softmac_t	*softmac;
1507*10654SGarrett.Damore@Sun.COM 	int		ppa, err, inst;
1508*10654SGarrett.Damore@Sun.COM 
1509*10654SGarrett.Damore@Sun.COM 	drvname = ddi_major_to_name(getmajor(dev));
1510*10654SGarrett.Damore@Sun.COM 
1511*10654SGarrett.Damore@Sun.COM 	/*
1512*10654SGarrett.Damore@Sun.COM 	 * Exclude non-physical network device instances, for example, aggr0.
1513*10654SGarrett.Damore@Sun.COM 	 */
1514*10654SGarrett.Damore@Sun.COM 	if (!NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) ||
1515*10654SGarrett.Damore@Sun.COM 	    (strcmp(drvname, "vnic") == 0)) {
1516*10654SGarrett.Damore@Sun.COM 		return (ENOENT);
1517*10654SGarrett.Damore@Sun.COM 	}
1518*10654SGarrett.Damore@Sun.COM 
1519*10654SGarrett.Damore@Sun.COM 	/*
1520*10654SGarrett.Damore@Sun.COM 	 * We have to lookup the device instance using getinfo(9e).
1521*10654SGarrett.Damore@Sun.COM 	 */
1522*10654SGarrett.Damore@Sun.COM 	inst = dev_to_instance(dev);
1523*10654SGarrett.Damore@Sun.COM 	if (inst < 0)
1524*10654SGarrett.Damore@Sun.COM 		return (ENOENT);
15255895Syz147064 
15265895Syz147064 	if ((ppa = getminor(dev) - 1) > 1000)
15275895Syz147064 		return (ENOENT);
15285895Syz147064 
15295895Syz147064 	/*
15305895Syz147064 	 * First try to hold this device instance to force the MAC
15315895Syz147064 	 * to be registered.
15325895Syz147064 	 */
1533*10654SGarrett.Damore@Sun.COM 	if ((dip = ddi_hold_devi_by_instance(getmajor(dev), inst, 0)) == NULL)
15345895Syz147064 		return (ENOENT);
15355895Syz147064 
15365895Syz147064 	/*
15375895Syz147064 	 * This is a network device; wait for its softmac to be registered.
15385895Syz147064 	 */
15396915Syz147064 	(void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa);
15405895Syz147064 again:
15415895Syz147064 	rw_enter(&softmac_hash_lock, RW_READER);
15425895Syz147064 
15435895Syz147064 	if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
15445895Syz147064 	    (mod_hash_val_t *)&softmac) != 0) {
15455895Syz147064 		/*
15465895Syz147064 		 * This is rare but possible. It could happen when pre-detach
15475895Syz147064 		 * routine of the device succeeds. But the softmac will then
15485895Syz147064 		 * be recreated when device fails to detach (as this device
15495895Syz147064 		 * is held).
15505895Syz147064 		 */
15518275SEric Cheng 		mutex_enter(&smac_global_lock);
15525895Syz147064 		rw_exit(&softmac_hash_lock);
15538275SEric Cheng 		cv_wait(&smac_global_cv, &smac_global_lock);
15548275SEric Cheng 		mutex_exit(&smac_global_lock);
15555895Syz147064 		goto again;
15565895Syz147064 	}
15575895Syz147064 
15585895Syz147064 	/*
15595895Syz147064 	 * Bump smac_hold_cnt to prevent device detach.
15605895Syz147064 	 */
15615895Syz147064 	mutex_enter(&softmac->smac_mutex);
15625895Syz147064 	softmac->smac_hold_cnt++;
15635895Syz147064 	rw_exit(&softmac_hash_lock);
15645895Syz147064 
15655895Syz147064 	/*
15665895Syz147064 	 * Wait till the device is fully attached.
15675895Syz147064 	 */
15688275SEric Cheng 	while (softmac->smac_state != SOFTMAC_ATTACH_DONE)
15695895Syz147064 		cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
15705895Syz147064 
15718275SEric Cheng 	SOFTMAC_STATE_VERIFY(softmac);
15728275SEric Cheng 
15735909Syz147064 	if ((err = softmac->smac_attacherr) != 0)
15745909Syz147064 		softmac->smac_hold_cnt--;
15755909Syz147064 	else
15765895Syz147064 		*ddhp = (dls_dev_handle_t)softmac;
15775895Syz147064 	mutex_exit(&softmac->smac_mutex);
15785895Syz147064 
15795909Syz147064 	ddi_release_devi(dip);
15805895Syz147064 	return (err);
15815895Syz147064 }
15825895Syz147064 
15835895Syz147064 void
15845895Syz147064 softmac_rele_device(dls_dev_handle_t ddh)
15855895Syz147064 {
15869073SCathy.Zhou@Sun.COM 	if (ddh != NULL)
15879073SCathy.Zhou@Sun.COM 		softmac_rele((softmac_t *)ddh);
15889073SCathy.Zhou@Sun.COM }
15899073SCathy.Zhou@Sun.COM 
15909073SCathy.Zhou@Sun.COM int
15919073SCathy.Zhou@Sun.COM softmac_hold(dev_t dev, softmac_t **softmacp)
15929073SCathy.Zhou@Sun.COM {
15935895Syz147064 	softmac_t	*softmac;
15949073SCathy.Zhou@Sun.COM 	char		*drv;
15959073SCathy.Zhou@Sun.COM 	mac_handle_t	mh;
15969073SCathy.Zhou@Sun.COM 	char		mac[MAXNAMELEN];
15979073SCathy.Zhou@Sun.COM 	int		err;
15989073SCathy.Zhou@Sun.COM 
15999073SCathy.Zhou@Sun.COM 	if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
16009073SCathy.Zhou@Sun.COM 		return (EINVAL);
16015895Syz147064 
16029073SCathy.Zhou@Sun.COM 	(void) snprintf(mac, MAXNAMELEN, "%s%d", drv, getminor(dev) - 1);
16039073SCathy.Zhou@Sun.COM 	if ((err = mac_open(mac, &mh)) != 0)
16049073SCathy.Zhou@Sun.COM 		return (err);
16059073SCathy.Zhou@Sun.COM 
16069073SCathy.Zhou@Sun.COM 	softmac = (softmac_t *)mac_driver(mh);
16075895Syz147064 
16089073SCathy.Zhou@Sun.COM 	mutex_enter(&softmac->smac_mutex);
16099073SCathy.Zhou@Sun.COM 	softmac->smac_hold_cnt++;
16109073SCathy.Zhou@Sun.COM 	mutex_exit(&softmac->smac_mutex);
16119073SCathy.Zhou@Sun.COM 	mac_close(mh);
16129073SCathy.Zhou@Sun.COM 	*softmacp = softmac;
16139073SCathy.Zhou@Sun.COM 	return (0);
16149073SCathy.Zhou@Sun.COM }
16159073SCathy.Zhou@Sun.COM 
16169073SCathy.Zhou@Sun.COM void
16179073SCathy.Zhou@Sun.COM softmac_rele(softmac_t *softmac)
16189073SCathy.Zhou@Sun.COM {
16195895Syz147064 	mutex_enter(&softmac->smac_mutex);
16205909Syz147064 	softmac->smac_hold_cnt--;
16215895Syz147064 	mutex_exit(&softmac->smac_mutex);
16225895Syz147064 }
1623