xref: /onnv-gate/usr/src/uts/common/io/softmac/softmac_main.c (revision 7323:f8232df17d05)
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 /*
225895Syz147064  * Copyright 2008 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>
475895Syz147064 #include <sys/sunndi.h>
485895Syz147064 #include <sys/modhash.h>
495895Syz147064 #include <sys/stropts.h>
505895Syz147064 #include <sys/sysmacros.h>
515895Syz147064 #include <sys/vlan.h>
525895Syz147064 #include <sys/softmac_impl.h>
535895Syz147064 #include <sys/softmac.h>
545895Syz147064 #include <sys/dls.h>
555895Syz147064 
565895Syz147064 /*
575895Syz147064  * Softmac hash table including softmacs for both style-2 and style-1 devices.
585895Syz147064  */
595895Syz147064 static krwlock_t	softmac_hash_lock;
605895Syz147064 static mod_hash_t	*softmac_hash;
615895Syz147064 
625895Syz147064 #define	SOFTMAC_HASHSZ		64
635895Syz147064 
64*7323SCathy.Zhou@Sun.COM static void softmac_create_task(void *);
65*7323SCathy.Zhou@Sun.COM static void softmac_mac_register(softmac_t *);
665895Syz147064 static int softmac_create_datalink(softmac_t *);
675895Syz147064 static int softmac_m_start(void *);
685895Syz147064 static void softmac_m_stop(void *);
695895Syz147064 static int softmac_m_open(void *);
705895Syz147064 static void softmac_m_close(void *);
715895Syz147064 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *);
725895Syz147064 
735895Syz147064 #define	SOFTMAC_M_CALLBACK_FLAGS	\
745895Syz147064 	(MC_RESOURCES | MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE)
755895Syz147064 
765895Syz147064 static mac_callbacks_t softmac_m_callbacks = {
775895Syz147064 	SOFTMAC_M_CALLBACK_FLAGS,
785895Syz147064 	softmac_m_stat,
795895Syz147064 	softmac_m_start,
805895Syz147064 	softmac_m_stop,
815895Syz147064 	softmac_m_promisc,
825895Syz147064 	softmac_m_multicst,
835895Syz147064 	softmac_m_unicst,
845895Syz147064 	softmac_m_tx,
855895Syz147064 	softmac_m_resources,
865895Syz147064 	softmac_m_ioctl,
875895Syz147064 	softmac_m_getcapab,
885895Syz147064 	softmac_m_open,
895895Syz147064 	softmac_m_close
905895Syz147064 };
915895Syz147064 
925895Syz147064 void
935895Syz147064 softmac_init()
945895Syz147064 {
955895Syz147064 	softmac_hash = mod_hash_create_extended("softmac_hash",
965895Syz147064 	    SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
975895Syz147064 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
985895Syz147064 
995895Syz147064 	rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL);
1005895Syz147064 }
1015895Syz147064 
1025895Syz147064 void
1035895Syz147064 softmac_fini()
1045895Syz147064 {
1055895Syz147064 	rw_destroy(&softmac_hash_lock);
1065895Syz147064 	mod_hash_destroy_hash(softmac_hash);
1075895Syz147064 }
1085895Syz147064 
1095895Syz147064 /* ARGSUSED */
1105895Syz147064 static uint_t
1115895Syz147064 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1125895Syz147064 {
1135895Syz147064 	boolean_t *pexist = arg;
1145895Syz147064 
1155895Syz147064 	*pexist = B_TRUE;
1165895Syz147064 	return (MH_WALK_TERMINATE);
1175895Syz147064 }
1185895Syz147064 
1195895Syz147064 boolean_t
1205895Syz147064 softmac_busy()
1215895Syz147064 {
1225895Syz147064 	boolean_t exist = B_FALSE;
1235895Syz147064 
1245895Syz147064 	rw_enter(&softmac_hash_lock, RW_READER);
1255895Syz147064 	mod_hash_walk(softmac_hash, softmac_exist, &exist);
1265895Syz147064 	rw_exit(&softmac_hash_lock);
1275895Syz147064 	return (exist);
1285895Syz147064 }
1295895Syz147064 
1305895Syz147064 /*
1315895Syz147064  * This function is called for each minor node during the post-attach of
1325895Syz147064  * each DDI_NT_NET device instance.  Note that it is possible that a device
1335895Syz147064  * instance has two minor nodes (DLPI style-1 and style-2), so that for that
1345895Syz147064  * specific device, softmac_create() could be called twice.
1355895Syz147064  *
1365895Syz147064  * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t
1375895Syz147064  * is created to track each minor node.
1385895Syz147064  *
1395895Syz147064  * For each minor node of a legacy device, a taskq is started to finish
1405895Syz147064  * softmac_mac_register(), which will finish the rest of work (see comments
1415895Syz147064  * above softmac_mac_register()).
1425895Syz147064  */
1435895Syz147064 int
1445895Syz147064 softmac_create(dev_info_t *dip, dev_t dev)
1455895Syz147064 {
1465895Syz147064 	char		devname[MAXNAMELEN];
1475895Syz147064 	softmac_t	*softmac;
1485895Syz147064 	softmac_dev_t	*softmac_dev = NULL;
1495895Syz147064 	int		index;
1505895Syz147064 	int		ppa, err = 0;
1515895Syz147064 
1525895Syz147064 	/*
1535895Syz147064 	 * Force the softmac driver to be attached.
1545895Syz147064 	 */
1555895Syz147064 	if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) {
1565895Syz147064 		cmn_err(CE_WARN, "softmac_create:softmac attach fails");
1575895Syz147064 		return (ENXIO);
1585895Syz147064 	}
1595895Syz147064 
1605895Syz147064 	ppa = ddi_get_instance(dip);
1615895Syz147064 	(void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
1625895Syz147064 
1635895Syz147064 	/*
1645895Syz147064 	 * We expect legacy devices have at most two minor nodes - one style-1
1655895Syz147064 	 * and one style-2.
1665895Syz147064 	 */
1675895Syz147064 	if (!GLDV3_DRV(ddi_driver_major(dip)) &&
1685895Syz147064 	    i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) {
1695895Syz147064 		cmn_err(CE_WARN, "%s has more than 2 minor nodes; unsupported",
1705895Syz147064 		    devname);
1715895Syz147064 		return (ENOTSUP);
1725895Syz147064 	}
1735895Syz147064 
1745895Syz147064 	/*
1755895Syz147064 	 * Check whether the softmac for the specified device already exists
1765895Syz147064 	 */
1775895Syz147064 	rw_enter(&softmac_hash_lock, RW_WRITER);
1785895Syz147064 	if ((err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
1795895Syz147064 	    (mod_hash_val_t *)&softmac)) != 0) {
1805895Syz147064 
1815895Syz147064 		softmac = kmem_zalloc(sizeof (softmac_t), KM_SLEEP);
1825895Syz147064 		mutex_init(&softmac->smac_mutex, NULL, MUTEX_DRIVER, NULL);
1835895Syz147064 		cv_init(&softmac->smac_cv, NULL, CV_DRIVER, NULL);
1845895Syz147064 		rw_init(&softmac->smac_lock, NULL, RW_DRIVER, NULL);
1855895Syz147064 		(void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN);
1865895Syz147064 
1875895Syz147064 		/*
1885895Syz147064 		 * Insert the softmac into the hash table.
1895895Syz147064 		 */
1905895Syz147064 		err = mod_hash_insert(softmac_hash,
1915895Syz147064 		    (mod_hash_key_t)softmac->smac_devname,
1925895Syz147064 		    (mod_hash_val_t)softmac);
1935895Syz147064 		ASSERT(err == 0);
1945895Syz147064 	}
1955895Syz147064 
1965895Syz147064 	mutex_enter(&softmac->smac_mutex);
1975895Syz147064 	if (softmac->smac_attachok_cnt == 0) {
1985895Syz147064 		/*
1995895Syz147064 		 * Initialize the softmac if this is the post-attach of the
2005895Syz147064 		 * first minor node.
2015895Syz147064 		 */
2025895Syz147064 		softmac->smac_flags = 0;
2035895Syz147064 		softmac->smac_umajor = ddi_driver_major(dip);
2045895Syz147064 		softmac->smac_uppa = ppa;
2055895Syz147064 
2065895Syz147064 		/*
2075895Syz147064 		 * Note that for GLDv3 devices, we create devfs minor nodes
2085895Syz147064 		 * for VLANs as well. Assume a GLDv3 driver on which only
2095895Syz147064 		 * a VLAN is created. During the detachment of this device
2105895Syz147064 		 * instance, the following would happen:
2115895Syz147064 		 * a. the pre-detach callback softmac_destroy() succeeds.
2125895Syz147064 		 *    Because the physical link itself is not in use,
2135895Syz147064 		 *    softmac_destroy() succeeds and destroys softmac_t;
2145895Syz147064 		 * b. the device detach fails in mac_unregister() because
2155895Syz147064 		 *    this MAC is still used by a VLAN.
2165895Syz147064 		 * c. the post-attach callback is then called which leads
2175895Syz147064 		 *    us here. Note that ddi_minor_node_count() returns 3
2185895Syz147064 		 *    (including the minior node of the VLAN). In that case,
2195895Syz147064 		 *    we must correct the minor node count to 2 as that is
2205895Syz147064 		 *    the count of minor nodes that go through post-attach.
2215895Syz147064 		 */
2225895Syz147064 		if (GLDV3_DRV(ddi_driver_major(dip))) {
2235895Syz147064 			softmac->smac_flags |= SOFTMAC_GLDV3;
2245895Syz147064 			softmac->smac_cnt = 2;
2255895Syz147064 		} else {
2265895Syz147064 			softmac->smac_cnt =
2275895Syz147064 			    i_ddi_minor_node_count(dip, DDI_NT_NET);
2285895Syz147064 		}
2295895Syz147064 	}
2305895Syz147064 
2315895Syz147064 	index = (getmajor(dev) == ddi_name_to_major("clone"));
2325895Syz147064 	if (softmac->smac_softmac[index] != NULL) {
2335895Syz147064 		/*
2345895Syz147064 		 * This is possible if the post_attach() is called:
2355895Syz147064 		 *
2365895Syz147064 		 * a. after pre_detach() fails.
2375895Syz147064 		 *
2385895Syz147064 		 * b. for a new round of reattachment. Note that DACF will not
2395895Syz147064 		 * call pre_detach() for successfully post_attached minor
2405895Syz147064 		 * nodes even when the post-attach failed after all.
2415895Syz147064 		 *
2425895Syz147064 		 * Both seem to be defects in the DACF framework. To work
2435895Syz147064 		 * around it and only clear the SOFTMAC_ATTACH_DONE flag for
2445895Syz147064 		 * the b case, a smac_attached_left field is used to tell
2455895Syz147064 		 * the two cases apart.
2465895Syz147064 		 */
2475895Syz147064 		ASSERT(softmac->smac_attachok_cnt != 0);
2485895Syz147064 
2495895Syz147064 		if (softmac->smac_attached_left != 0)
2505895Syz147064 			/* case a */
2515895Syz147064 			softmac->smac_attached_left--;
2525895Syz147064 		else if (softmac->smac_attachok_cnt != softmac->smac_cnt) {
2535895Syz147064 			/* case b */
2545895Syz147064 			softmac->smac_flags &= ~SOFTMAC_ATTACH_DONE;
2555895Syz147064 		}
2565895Syz147064 		mutex_exit(&softmac->smac_mutex);
2575895Syz147064 		rw_exit(&softmac_hash_lock);
2585895Syz147064 		return (0);
2595895Syz147064 	}
2605895Syz147064 	mutex_exit(&softmac->smac_mutex);
2615895Syz147064 	rw_exit(&softmac_hash_lock);
2625895Syz147064 
2635895Syz147064 	/*
2645895Syz147064 	 * No lock is needed for access this softmac pointer, as pre-detach and
2655895Syz147064 	 * post-attach won't happen at the same time.
2665895Syz147064 	 */
2675895Syz147064 	mutex_enter(&softmac->smac_mutex);
2685895Syz147064 
2695895Syz147064 	softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP);
2705895Syz147064 	softmac_dev->sd_dev = dev;
2715895Syz147064 	softmac->smac_softmac[index] = softmac_dev;
2725895Syz147064 
2735895Syz147064 	/*
2745895Syz147064 	 * Continue to register the mac and create the datalink only when all
2755895Syz147064 	 * the minor nodes are attached.
2765895Syz147064 	 */
2775895Syz147064 	if (++softmac->smac_attachok_cnt != softmac->smac_cnt) {
2785895Syz147064 		mutex_exit(&softmac->smac_mutex);
2795895Syz147064 		return (0);
2805895Syz147064 	}
2815895Syz147064 
2825895Syz147064 	/*
283*7323SCathy.Zhou@Sun.COM 	 * All of the minor nodes have been attached; start a taskq
284*7323SCathy.Zhou@Sun.COM 	 * to do the rest of the work.  We use a taskq instead of of
285*7323SCathy.Zhou@Sun.COM 	 * doing the work here because:
286*7323SCathy.Zhou@Sun.COM 	 *
287*7323SCathy.Zhou@Sun.COM 	 * - We could be called as a result of an open() system call
288*7323SCathy.Zhou@Sun.COM 	 *   where spec_open() already SLOCKED the snode.  Using a taskq
289*7323SCathy.Zhou@Sun.COM 	 *   sidesteps the risk that our ldi_open_by_dev() call would
290*7323SCathy.Zhou@Sun.COM 	 *   deadlock trying to set SLOCKED on the snode again.
291*7323SCathy.Zhou@Sun.COM 	 *
292*7323SCathy.Zhou@Sun.COM 	 * - The devfs design requires no interruptible function calls
293*7323SCathy.Zhou@Sun.COM 	 *   in the device post-attach routine, but we need to make an
294*7323SCathy.Zhou@Sun.COM 	 *   (interruptible) upcall.  Using a taskq to make the upcall
295*7323SCathy.Zhou@Sun.COM 	 *   sidesteps this.
2965895Syz147064 	 */
297*7323SCathy.Zhou@Sun.COM 	ASSERT(softmac->smac_taskq == NULL);
298*7323SCathy.Zhou@Sun.COM 	softmac->smac_taskq = taskq_dispatch(system_taskq,
299*7323SCathy.Zhou@Sun.COM 	    softmac_create_task, softmac, TQ_SLEEP);
3005895Syz147064 	mutex_exit(&softmac->smac_mutex);
301*7323SCathy.Zhou@Sun.COM 	return (0);
3025895Syz147064 }
3035895Syz147064 
3045895Syz147064 static boolean_t
3055895Syz147064 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
3065895Syz147064 {
3075895Syz147064 	softmac_t *softmac = arg;
3085895Syz147064 
3095895Syz147064 	if (!(softmac->smac_capab_flags & cap))
3105895Syz147064 		return (B_FALSE);
3115895Syz147064 
3125895Syz147064 	switch (cap) {
3135895Syz147064 	case MAC_CAPAB_HCKSUM: {
3145895Syz147064 		uint32_t *txflags = cap_data;
3155895Syz147064 
3165895Syz147064 		*txflags = softmac->smac_hcksum_txflags;
3175895Syz147064 		break;
3185895Syz147064 	}
3195895Syz147064 	case MAC_CAPAB_LEGACY: {
3205895Syz147064 		mac_capab_legacy_t *legacy = cap_data;
3215895Syz147064 
3225895Syz147064 		legacy->ml_unsup_note = ~softmac->smac_notifications &
3235895Syz147064 		    (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED);
3245895Syz147064 		legacy->ml_dev = makedevice(softmac->smac_umajor,
3255895Syz147064 		    softmac->smac_uppa + 1);
3265895Syz147064 		break;
3275895Syz147064 	}
3285895Syz147064 
3295895Syz147064 	/*
3305895Syz147064 	 * For the capabilities below, there's nothing for us to fill in;
3315895Syz147064 	 * simply return B_TRUE if we support it.
3325895Syz147064 	 */
3335895Syz147064 	case MAC_CAPAB_NO_ZCOPY:
3345895Syz147064 	case MAC_CAPAB_POLL:
3355895Syz147064 	case MAC_CAPAB_NO_NATIVEVLAN:
3365895Syz147064 	default:
3375895Syz147064 		break;
3385895Syz147064 	}
3395895Syz147064 	return (B_TRUE);
3405895Syz147064 }
3415895Syz147064 
3425895Syz147064 static int
3435895Syz147064 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp)
3445895Syz147064 {
3455895Syz147064 	datalink_id_t	linkid = DATALINK_INVALID_LINKID;
3465895Syz147064 	uint32_t	media;
3475895Syz147064 	int		err;
3485895Syz147064 
3495895Syz147064 	if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media,
3505895Syz147064 	    softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) {
3515895Syz147064 		*linkidp = linkid;
3525895Syz147064 	}
3535895Syz147064 
3545895Syz147064 	if (err == EEXIST) {
3555895Syz147064 		/*
3565895Syz147064 		 * There is a link name conflict.  Either:
3575895Syz147064 		 *
3585895Syz147064 		 * - An existing link with the same device name with a
3595895Syz147064 		 *   different media type from of the given type.
3605895Syz147064 		 *   Mark this link back to persistent only; or
3615895Syz147064 		 *
3625895Syz147064 		 * - We cannot assign the "suggested" name because
3635895Syz147064 		 *   GLDv3 and therefore vanity naming is not supported
3645895Syz147064 		 *   for this link type. Delete this link's <link name,
3655895Syz147064 		 *   linkid> mapping.
3665895Syz147064 		 */
3675895Syz147064 		if (media != softmac->smac_media) {
3685895Syz147064 			cmn_err(CE_WARN, "%s device %s conflicts with "
3695895Syz147064 			    "existing %s device %s.",
3705895Syz147064 			    dl_mactypestr(softmac->smac_media),
3715895Syz147064 			    softmac->smac_devname, dl_mactypestr(media),
3725895Syz147064 			    softmac->smac_devname);
3735895Syz147064 			(void) dls_mgmt_destroy(linkid, B_FALSE);
3745895Syz147064 		} else {
3755895Syz147064 			cmn_err(CE_WARN, "link name %s is already in-use.",
3765895Syz147064 			    softmac->smac_devname);
3775895Syz147064 			(void) dls_mgmt_destroy(linkid, B_TRUE);
3785895Syz147064 		}
3795895Syz147064 
3805895Syz147064 		cmn_err(CE_WARN, "%s device might not be available "
3815895Syz147064 		    "for use.", softmac->smac_devname);
3825895Syz147064 		cmn_err(CE_WARN, "See dladm(1M) for more information.");
3835895Syz147064 	}
3845895Syz147064 
3855895Syz147064 	return (err);
3865895Syz147064 }
3875895Syz147064 
3885895Syz147064 /*
3895895Syz147064  * This function:
3905895Syz147064  * 1. provides the link's media type to dlmgmtd.
3915895Syz147064  * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
3925895Syz147064  */
3935895Syz147064 static int
3945895Syz147064 softmac_create_datalink(softmac_t *softmac)
3955895Syz147064 {
3965895Syz147064 	datalink_id_t	linkid = DATALINK_INVALID_LINKID;
3975895Syz147064 	int		err;
3985895Syz147064 
3995895Syz147064 	ASSERT(MUTEX_HELD(&softmac->smac_mutex));
4005895Syz147064 
4015895Syz147064 	/*
402*7323SCathy.Zhou@Sun.COM 	 * Inform dlmgmtd of this link so that softmac_hold_device() is able
403*7323SCathy.Zhou@Sun.COM 	 * to know the existence of this link. If this failed with EBADF,
404*7323SCathy.Zhou@Sun.COM 	 * it might be because dlmgmtd was not started in time (e.g.,
405*7323SCathy.Zhou@Sun.COM 	 * diskless boot); ignore the failure and continue to create
406*7323SCathy.Zhou@Sun.COM 	 * the GLDv3 datalink if needed.
4075895Syz147064 	 */
408*7323SCathy.Zhou@Sun.COM 	err = dls_mgmt_create(softmac->smac_devname,
409*7323SCathy.Zhou@Sun.COM 	    makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
410*7323SCathy.Zhou@Sun.COM 	    DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid);
411*7323SCathy.Zhou@Sun.COM 	if (err != 0 && err != EBADF)
412*7323SCathy.Zhou@Sun.COM 		return (err);
413*7323SCathy.Zhou@Sun.COM 
414*7323SCathy.Zhou@Sun.COM 	/*
415*7323SCathy.Zhou@Sun.COM 	 * Provide the media type of the physical link to dlmgmtd.
416*7323SCathy.Zhou@Sun.COM 	 */
417*7323SCathy.Zhou@Sun.COM 	if ((err != EBADF) &&
418*7323SCathy.Zhou@Sun.COM 	    ((err = softmac_update_info(softmac, &linkid)) != 0)) {
4195895Syz147064 		return (err);
4205895Syz147064 	}
4215895Syz147064 
4225895Syz147064 	/*
4235895Syz147064 	 * Create the GLDv3 datalink.
4245895Syz147064 	 */
4255895Syz147064 	if ((!(softmac->smac_flags & SOFTMAC_NOSUPP)) &&
4265895Syz147064 	    ((err = dls_devnet_create(softmac->smac_mh, linkid)) != 0)) {
4275895Syz147064 		cmn_err(CE_WARN, "dls_devnet_create failed for %s",
4285895Syz147064 		    softmac->smac_devname);
4295895Syz147064 		return (err);
4305895Syz147064 	}
4315895Syz147064 
4325895Syz147064 	if (linkid == DATALINK_INVALID_LINKID)
4335895Syz147064 		softmac->smac_flags |= SOFTMAC_NEED_RECREATE;
4345895Syz147064 
4355895Syz147064 	return (0);
4365895Syz147064 }
4375895Syz147064 
438*7323SCathy.Zhou@Sun.COM static void
439*7323SCathy.Zhou@Sun.COM softmac_create_task(void *arg)
440*7323SCathy.Zhou@Sun.COM {
441*7323SCathy.Zhou@Sun.COM 	softmac_t	*softmac = arg;
442*7323SCathy.Zhou@Sun.COM 	mac_handle_t	mh;
443*7323SCathy.Zhou@Sun.COM 	int		err;
444*7323SCathy.Zhou@Sun.COM 
445*7323SCathy.Zhou@Sun.COM 	if (!GLDV3_DRV(softmac->smac_umajor)) {
446*7323SCathy.Zhou@Sun.COM 		softmac_mac_register(softmac);
447*7323SCathy.Zhou@Sun.COM 		return;
448*7323SCathy.Zhou@Sun.COM 	}
449*7323SCathy.Zhou@Sun.COM 
450*7323SCathy.Zhou@Sun.COM 	if ((err = mac_open(softmac->smac_devname, &mh)) != 0)
451*7323SCathy.Zhou@Sun.COM 		goto done;
452*7323SCathy.Zhou@Sun.COM 
453*7323SCathy.Zhou@Sun.COM 	mutex_enter(&softmac->smac_mutex);
454*7323SCathy.Zhou@Sun.COM 	softmac->smac_media = (mac_info(mh))->mi_nativemedia;
455*7323SCathy.Zhou@Sun.COM 	softmac->smac_mh = mh;
456*7323SCathy.Zhou@Sun.COM 
457*7323SCathy.Zhou@Sun.COM 	/*
458*7323SCathy.Zhou@Sun.COM 	 * We can safely release the reference on the mac because
459*7323SCathy.Zhou@Sun.COM 	 * this mac will only be unregistered and destroyed when
460*7323SCathy.Zhou@Sun.COM 	 * the device detaches, and the softmac will be destroyed
461*7323SCathy.Zhou@Sun.COM 	 * before then (in the pre-detach routine of the device).
462*7323SCathy.Zhou@Sun.COM 	 */
463*7323SCathy.Zhou@Sun.COM 	mac_close(mh);
464*7323SCathy.Zhou@Sun.COM 
465*7323SCathy.Zhou@Sun.COM 	/*
466*7323SCathy.Zhou@Sun.COM 	 * Create the GLDv3 datalink for this mac.
467*7323SCathy.Zhou@Sun.COM 	 */
468*7323SCathy.Zhou@Sun.COM 	err = softmac_create_datalink(softmac);
469*7323SCathy.Zhou@Sun.COM 
470*7323SCathy.Zhou@Sun.COM done:
471*7323SCathy.Zhou@Sun.COM 	ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
472*7323SCathy.Zhou@Sun.COM 	softmac->smac_flags |= SOFTMAC_ATTACH_DONE;
473*7323SCathy.Zhou@Sun.COM 	softmac->smac_attacherr = err;
474*7323SCathy.Zhou@Sun.COM 	softmac->smac_taskq = NULL;
475*7323SCathy.Zhou@Sun.COM 	cv_broadcast(&softmac->smac_cv);
476*7323SCathy.Zhou@Sun.COM 	mutex_exit(&softmac->smac_mutex);
477*7323SCathy.Zhou@Sun.COM }
478*7323SCathy.Zhou@Sun.COM 
4795895Syz147064 /*
4805895Syz147064  * This function is only called for legacy devices. It:
4815895Syz147064  * 1. registers the MAC for the legacy devices whose media type is supported
4825895Syz147064  *    by the GLDv3 framework.
4835895Syz147064  * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
4845895Syz147064  */
4855895Syz147064 static void
486*7323SCathy.Zhou@Sun.COM softmac_mac_register(softmac_t *softmac)
4875895Syz147064 {
4885895Syz147064 	softmac_dev_t	*softmac_dev;
4895895Syz147064 	dev_t		dev;
4905895Syz147064 	ldi_handle_t	lh = NULL;
4915895Syz147064 	ldi_ident_t	li = NULL;
4925895Syz147064 	int		index;
4935895Syz147064 	boolean_t	native_vlan = B_FALSE;
4945895Syz147064 	int		err;
4955895Syz147064 
4965895Syz147064 	/*
4975895Syz147064 	 * Note that we do not need any locks to access this softmac pointer,
4985895Syz147064 	 * as softmac_destroy() will wait until this function is called.
4995895Syz147064 	 */
5005895Syz147064 	ASSERT(softmac != NULL);
5015895Syz147064 
5025895Syz147064 	if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) {
5035895Syz147064 		mutex_enter(&softmac->smac_mutex);
5045895Syz147064 		goto done;
5055895Syz147064 	}
5065895Syz147064 
5075895Syz147064 	/*
5085895Syz147064 	 * Determine whether this legacy device support VLANs by opening
5095895Syz147064 	 * the style-2 device node (if it exists) and attaching to a VLAN
5105895Syz147064 	 * PPA (1000 + ppa).
5115895Syz147064 	 */
5125895Syz147064 	dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor);
5135895Syz147064 	err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
5145895Syz147064 	if (err == 0) {
5155895Syz147064 		if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0)
5165895Syz147064 			native_vlan = B_TRUE;
5175895Syz147064 		(void) ldi_close(lh, FREAD|FWRITE, kcred);
5185895Syz147064 	}
5195895Syz147064 
5205895Syz147064 	err = EINVAL;
5215895Syz147064 	for (index = 0; index < 2; index++) {
5225895Syz147064 		dl_info_ack_t	dlia;
5235895Syz147064 		dl_error_ack_t	dlea;
5245895Syz147064 		uint32_t	notes;
5255895Syz147064 		struct strioctl	iocb;
5265895Syz147064 		uint32_t	margin;
5275895Syz147064 		int		rval;
5285895Syz147064 
5295895Syz147064 		if ((softmac_dev = softmac->smac_softmac[index]) == NULL)
5305895Syz147064 			continue;
5315895Syz147064 
5325895Syz147064 		softmac->smac_dev = dev = softmac_dev->sd_dev;
5335895Syz147064 		if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh,
5345895Syz147064 		    li) != 0) {
5355895Syz147064 			continue;
5365895Syz147064 		}
5375895Syz147064 
5385895Syz147064 		/*
5395895Syz147064 		 * Pop all the intermediate modules in order to negotiate
5405895Syz147064 		 * capabilities correctly.
5415895Syz147064 		 */
5425895Syz147064 		while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
5435895Syz147064 			;
5445895Syz147064 
5455895Syz147064 		/* DLPI style-1 or DLPI style-2? */
5465895Syz147064 		if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) {
5475895Syz147064 			if (rval == ENOTSUP) {
5485895Syz147064 				cmn_err(CE_NOTE, "softmac: received "
5495895Syz147064 				    "DL_ERROR_ACK to DL_INFO_ACK; "
5505895Syz147064 				    "DLPI errno 0x%x, UNIX errno %d",
5515895Syz147064 				    dlea.dl_errno, dlea.dl_unix_errno);
5525895Syz147064 			}
5535895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
5545895Syz147064 			continue;
5555895Syz147064 		}
5565895Syz147064 
5575895Syz147064 		/*
5585895Syz147064 		 * Currently only DL_ETHER has GLDv3 mac plugin support.
5595895Syz147064 		 * For media types that GLDv3 does not support, create a
5605895Syz147064 		 * link id for it.
5615895Syz147064 		 */
5625895Syz147064 		if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) {
5635895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
5645895Syz147064 			err = 0;
5655895Syz147064 			break;
5665895Syz147064 		}
5675895Syz147064 
5685895Syz147064 		if ((dlia.dl_provider_style == DL_STYLE2) &&
5695895Syz147064 		    (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) {
5705895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
5715895Syz147064 			continue;
5725895Syz147064 		}
5735895Syz147064 
5745895Syz147064 		if ((rval = dl_bind(lh, 0, NULL)) != 0) {
5755895Syz147064 			if (rval == ENOTSUP) {
5765895Syz147064 				cmn_err(CE_NOTE, "softmac: received "
5775895Syz147064 				    "DL_ERROR_ACK to DL_BIND_ACK; "
5785895Syz147064 				    "DLPI errno 0x%x, UNIX errno %d",
5795895Syz147064 				    dlea.dl_errno, dlea.dl_unix_errno);
5805895Syz147064 			}
5815895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
5825895Syz147064 			continue;
5835895Syz147064 		}
5845895Syz147064 
5855895Syz147064 		/*
5865895Syz147064 		 * Call dl_info() after dl_bind() because some drivers only
5875895Syz147064 		 * provide correct information (e.g. MAC address) once bound.
5885895Syz147064 		 */
5895895Syz147064 		softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr);
5905895Syz147064 		if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr,
5915895Syz147064 		    &softmac->smac_addrlen, &dlea)) != 0) {
5925895Syz147064 			if (rval == ENOTSUP) {
5935895Syz147064 				cmn_err(CE_NOTE, "softmac: received "
5945895Syz147064 				    "DL_ERROR_ACK to DL_INFO_ACK; "
5955895Syz147064 				    "DLPI errno 0x%x, UNIX errno %d",
5965895Syz147064 				    dlea.dl_errno, dlea.dl_unix_errno);
5975895Syz147064 			}
5985895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
5995895Syz147064 			continue;
6005895Syz147064 		}
6015895Syz147064 
6025895Syz147064 		softmac->smac_style = dlia.dl_provider_style;
6035895Syz147064 		softmac->smac_saplen = ABS(dlia.dl_sap_length);
6045895Syz147064 		softmac->smac_min_sdu = dlia.dl_min_sdu;
6055895Syz147064 		softmac->smac_max_sdu = dlia.dl_max_sdu;
6065895Syz147064 
6075895Syz147064 		if ((softmac->smac_saplen != sizeof (uint16_t)) ||
6085895Syz147064 		    (softmac->smac_addrlen != ETHERADDRL) ||
6095895Syz147064 		    (dlia.dl_brdcst_addr_length != ETHERADDRL) ||
6105895Syz147064 		    (dlia.dl_brdcst_addr_offset == 0)) {
6115895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
6125895Syz147064 			continue;
6135895Syz147064 		}
6145895Syz147064 
6155895Syz147064 		/*
6165895Syz147064 		 * Check other DLPI capabilities. Note that this must be after
6175895Syz147064 		 * dl_bind() because some drivers return DL_ERROR_ACK if the
6185895Syz147064 		 * stream is not bound. It is also before mac_register(), so
6195895Syz147064 		 * we don't need any lock protection here.
6205895Syz147064 		 *
6215895Syz147064 		 * Softmac always supports POLL.
6225895Syz147064 		 */
6235895Syz147064 		softmac->smac_capab_flags =
6245895Syz147064 		    (MAC_CAPAB_POLL | MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY);
6255895Syz147064 
6265895Syz147064 		softmac->smac_no_capability_req = B_FALSE;
6275895Syz147064 		if (softmac_fill_capab(lh, softmac) != 0)
6285895Syz147064 			softmac->smac_no_capability_req = B_TRUE;
6295895Syz147064 
6305895Syz147064 		/*
6315895Syz147064 		 * Check the margin of the underlying driver.
6325895Syz147064 		 */
6335895Syz147064 		margin = 0;
6345895Syz147064 		iocb.ic_cmd = DLIOCMARGININFO;
6355895Syz147064 		iocb.ic_timout = INFTIM;
6365895Syz147064 		iocb.ic_len = sizeof (margin);
6375895Syz147064 		iocb.ic_dp = (char *)&margin;
6385895Syz147064 		softmac->smac_margin = 0;
6395895Syz147064 
6405895Syz147064 		if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred,
6415895Syz147064 		    &rval) == 0) {
6425895Syz147064 			softmac->smac_margin = margin;
6435895Syz147064 		}
6445895Syz147064 
6455895Syz147064 		/*
6465895Syz147064 		 * If the legacy driver doesn't support DLIOCMARGININFO, but
6475895Syz147064 		 * it can support native VLAN, correct its margin value to 4.
6485895Syz147064 		 */
6495895Syz147064 		if (native_vlan) {
6505895Syz147064 			if (softmac->smac_margin == 0)
6515895Syz147064 				softmac->smac_margin = VLAN_TAGSZ;
6525895Syz147064 		} else {
6535895Syz147064 			softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN;
6545895Syz147064 		}
6555895Syz147064 
6565895Syz147064 		/*
6575895Syz147064 		 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP.
6585895Syz147064 		 */
6595895Syz147064 		softmac->smac_notifications = 0;
6605895Syz147064 		notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN;
6615895Syz147064 		switch (dl_notify(lh, &notes, NULL)) {
6625895Syz147064 		case 0:
6635895Syz147064 			softmac->smac_notifications = notes;
6645895Syz147064 			break;
6655895Syz147064 		case ENOTSUP:
6665895Syz147064 			break;
6675895Syz147064 		default:
6685895Syz147064 			(void) ldi_close(lh, FREAD|FWRITE, kcred);
6695895Syz147064 			continue;
6705895Syz147064 		}
6715895Syz147064 
6725895Syz147064 		(void) ldi_close(lh, FREAD|FWRITE, kcred);
6735895Syz147064 		err = 0;
6745895Syz147064 		break;
6755895Syz147064 	}
6765895Syz147064 	ldi_ident_release(li);
6775895Syz147064 
6785895Syz147064 	mutex_enter(&softmac->smac_mutex);
6795895Syz147064 
6805895Syz147064 	if (err != 0)
6815895Syz147064 		goto done;
6825895Syz147064 
6835895Syz147064 	if (softmac->smac_media != DL_ETHER)
6845895Syz147064 		softmac->smac_flags |= SOFTMAC_NOSUPP;
6855895Syz147064 
6865895Syz147064 	/*
6875895Syz147064 	 * Finally, we're ready to register ourselves with the MAC layer
6885895Syz147064 	 * interface; if this succeeds, we're all ready to start()
6895895Syz147064 	 */
6905895Syz147064 	if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
6915895Syz147064 		mac_register_t	*macp;
6925895Syz147064 
6935895Syz147064 		if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
6945895Syz147064 			err = ENOMEM;
6955895Syz147064 			goto done;
6965895Syz147064 		}
6975895Syz147064 
6985895Syz147064 		macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
6995895Syz147064 		macp->m_driver = softmac;
7005895Syz147064 		macp->m_dip = softmac_dip;
7015895Syz147064 
7025895Syz147064 		macp->m_margin = softmac->smac_margin;
7035895Syz147064 		macp->m_src_addr = softmac->smac_unicst_addr;
7045895Syz147064 		macp->m_min_sdu = softmac->smac_min_sdu;
7055895Syz147064 		macp->m_max_sdu = softmac->smac_max_sdu;
7065895Syz147064 		macp->m_callbacks = &softmac_m_callbacks;
7075895Syz147064 		macp->m_instance = (uint_t)-1;
7085895Syz147064 
7095895Syz147064 		err = mac_register(macp, &softmac->smac_mh);
7105895Syz147064 		mac_free(macp);
7115895Syz147064 		if (err != 0) {
7125895Syz147064 			cmn_err(CE_WARN, "mac_register failed for %s",
7135895Syz147064 			    softmac->smac_devname);
7145895Syz147064 			goto done;
7155895Syz147064 		}
7165895Syz147064 	}
7175895Syz147064 
7185895Syz147064 	/*
7195895Syz147064 	 * Try to create the datalink for this softmac.
7205895Syz147064 	 */
7215895Syz147064 	if ((err = softmac_create_datalink(softmac)) != 0) {
7225895Syz147064 		if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
7235895Syz147064 			(void) mac_unregister(softmac->smac_mh);
7245895Syz147064 			softmac->smac_mh = NULL;
7255895Syz147064 		}
7265895Syz147064 	}
7275895Syz147064 
7285895Syz147064 done:
7295895Syz147064 	ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
7305895Syz147064 	softmac->smac_flags |= SOFTMAC_ATTACH_DONE;
7315895Syz147064 	softmac->smac_attacherr = err;
7325895Syz147064 	softmac->smac_taskq = NULL;
7335895Syz147064 	cv_broadcast(&softmac->smac_cv);
7345895Syz147064 	mutex_exit(&softmac->smac_mutex);
7355895Syz147064 }
7365895Syz147064 
7375895Syz147064 int
7385895Syz147064 softmac_destroy(dev_info_t *dip, dev_t dev)
7395895Syz147064 {
7405895Syz147064 	char			devname[MAXNAMELEN];
7415895Syz147064 	softmac_t		*softmac;
7425895Syz147064 	softmac_dev_t		*softmac_dev;
7435895Syz147064 	int			index;
7445895Syz147064 	int			ppa, err;
7455895Syz147064 	datalink_id_t		linkid;
7465895Syz147064 
7475895Syz147064 	ppa = ddi_get_instance(dip);
7485895Syz147064 	(void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
7495895Syz147064 
7505895Syz147064 	rw_enter(&softmac_hash_lock, RW_WRITER);
7515895Syz147064 	err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
7525895Syz147064 	    (mod_hash_val_t *)&softmac);
7535895Syz147064 	ASSERT(err == 0);
7545895Syz147064 
7555895Syz147064 	mutex_enter(&softmac->smac_mutex);
7565895Syz147064 
7575895Syz147064 	/*
7585895Syz147064 	 * Fail the predetach routine if this softmac is in-use.
7595895Syz147064 	 */
7605895Syz147064 	if (softmac->smac_hold_cnt != 0) {
7615895Syz147064 		softmac->smac_attached_left = softmac->smac_attachok_cnt;
7625895Syz147064 		mutex_exit(&softmac->smac_mutex);
7635895Syz147064 		rw_exit(&softmac_hash_lock);
7645895Syz147064 		return (EBUSY);
7655895Syz147064 	}
7665895Syz147064 
7675895Syz147064 	/*
7685895Syz147064 	 * Even if the predetach of one minor node has already failed
7695895Syz147064 	 * (smac_attached_left is not 0), the DACF framework will continue
7705895Syz147064 	 * to call the predetach routines of the other minor nodes,
7715895Syz147064 	 * so we fail these calls here.
7725895Syz147064 	 */
7735895Syz147064 	if (softmac->smac_attached_left != 0) {
7745895Syz147064 		mutex_exit(&softmac->smac_mutex);
7755895Syz147064 		rw_exit(&softmac_hash_lock);
7765895Syz147064 		return (EBUSY);
7775895Syz147064 	}
7785895Syz147064 
7795895Syz147064 	if (softmac->smac_attachok_cnt != softmac->smac_cnt)
7805895Syz147064 		goto done;
7815895Syz147064 
7825895Syz147064 	/*
7835895Syz147064 	 * This is the detach for the first minor node.  Wait until all the
7845895Syz147064 	 * minor nodes are attached.
7855895Syz147064 	 */
7865895Syz147064 	while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE))
7875895Syz147064 		cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
7885895Syz147064 
7895895Syz147064 	if (softmac->smac_mh != NULL) {
7905895Syz147064 		if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
7915895Syz147064 			if ((err = dls_devnet_destroy(softmac->smac_mh,
7925895Syz147064 			    &linkid)) != 0) {
7935895Syz147064 				goto done;
7945895Syz147064 			}
7955895Syz147064 		}
7965895Syz147064 		/*
7975895Syz147064 		 * If softmac_mac_register() succeeds in registering the mac
7985895Syz147064 		 * of the legacy device, unregister it.
7995895Syz147064 		 */
8005895Syz147064 		if (!(softmac->smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) {
8015895Syz147064 			if ((err = mac_unregister(softmac->smac_mh)) != 0) {
8025895Syz147064 				(void) dls_devnet_create(softmac->smac_mh,
8035895Syz147064 				    linkid);
8045895Syz147064 				goto done;
8055895Syz147064 			}
8065895Syz147064 		}
8075895Syz147064 		softmac->smac_mh = NULL;
8085895Syz147064 	}
8095895Syz147064 	softmac->smac_flags &= ~SOFTMAC_ATTACH_DONE;
8105895Syz147064 
8115895Syz147064 done:
8125895Syz147064 	if (err == 0) {
8135895Syz147064 		/*
8145895Syz147064 		 * Free softmac_dev
8155895Syz147064 		 */
8165895Syz147064 		index = (getmajor(dev) == ddi_name_to_major("clone"));
8175895Syz147064 		softmac_dev = softmac->smac_softmac[index];
8185895Syz147064 		ASSERT(softmac_dev != NULL);
8195895Syz147064 		softmac->smac_softmac[index] = NULL;
8205895Syz147064 		kmem_free(softmac_dev, sizeof (softmac_dev_t));
8215895Syz147064 
8225895Syz147064 		if (--softmac->smac_attachok_cnt == 0) {
8235895Syz147064 			mod_hash_val_t	hashval;
8245895Syz147064 
8255895Syz147064 			err = mod_hash_remove(softmac_hash,
8265895Syz147064 			    (mod_hash_key_t)devname,
8275895Syz147064 			    (mod_hash_val_t *)&hashval);
8285895Syz147064 			ASSERT(err == 0);
8295895Syz147064 
8305895Syz147064 			mutex_exit(&softmac->smac_mutex);
8315895Syz147064 			rw_exit(&softmac_hash_lock);
8325895Syz147064 
8335895Syz147064 			ASSERT(softmac->smac_taskq == NULL);
8345895Syz147064 			ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
8355895Syz147064 			mutex_destroy(&softmac->smac_mutex);
8365895Syz147064 			cv_destroy(&softmac->smac_cv);
8375895Syz147064 			rw_destroy(&softmac->smac_lock);
8385895Syz147064 			kmem_free(softmac, sizeof (softmac_t));
8395895Syz147064 			return (0);
8405895Syz147064 		}
8415895Syz147064 	} else {
8425895Syz147064 		softmac->smac_attached_left = softmac->smac_attachok_cnt;
8435895Syz147064 	}
8445895Syz147064 
8455895Syz147064 	mutex_exit(&softmac->smac_mutex);
8465895Syz147064 	rw_exit(&softmac_hash_lock);
8475895Syz147064 	return (err);
8485895Syz147064 }
8495895Syz147064 
8505895Syz147064 /*
8515895Syz147064  * This function is called as the result of a newly started dlmgmtd daemon.
8525895Syz147064  *
8535895Syz147064  * We walk through every softmac that was created but failed to notify
8545895Syz147064  * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set).  This occurs
8555895Syz147064  * when softmacs are created before dlmgmtd is ready.  For example, during
8565895Syz147064  * diskless boot, a network device is used (and therefore attached) before
8575895Syz147064  * the datalink-management service starts dlmgmtd.
8585895Syz147064  */
8595895Syz147064 /* ARGSUSED */
8605895Syz147064 static uint_t
8615895Syz147064 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
8625895Syz147064 {
8635895Syz147064 	softmac_t	*softmac = (softmac_t *)val;
8645895Syz147064 	datalink_id_t	linkid;
8655895Syz147064 	int		err;
8665895Syz147064 
8675895Syz147064 	ASSERT(RW_READ_HELD(&softmac_hash_lock));
8685895Syz147064 
8695895Syz147064 	/*
8705895Syz147064 	 * Wait for softmac_create() and softmac_mac_register() to exit.
8715895Syz147064 	 */
8725895Syz147064 	mutex_enter(&softmac->smac_mutex);
8735895Syz147064 	while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE))
8745895Syz147064 		cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
8755895Syz147064 
8765895Syz147064 	if ((softmac->smac_attacherr != 0) ||
8775895Syz147064 	    !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) {
8785895Syz147064 		mutex_exit(&softmac->smac_mutex);
8795895Syz147064 		return (MH_WALK_CONTINUE);
8805895Syz147064 	}
8815895Syz147064 
8825895Syz147064 	if (dls_mgmt_create(softmac->smac_devname,
8835895Syz147064 	    makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
8845895Syz147064 	    DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) {
8855895Syz147064 		mutex_exit(&softmac->smac_mutex);
8865895Syz147064 		return (MH_WALK_CONTINUE);
8875895Syz147064 	}
8885895Syz147064 
8895895Syz147064 	if ((err = softmac_update_info(softmac, &linkid)) != 0) {
8905895Syz147064 		cmn_err(CE_WARN, "softmac: softmac_update_info() for %s "
8915895Syz147064 		    "failed (%d)", softmac->smac_devname, err);
8925895Syz147064 		mutex_exit(&softmac->smac_mutex);
8935895Syz147064 		return (MH_WALK_CONTINUE);
8945895Syz147064 	}
8955895Syz147064 
8965895Syz147064 	/*
8975895Syz147064 	 * Create a link for this MAC. The link name will be the same
8985895Syz147064 	 * as the MAC name.
8995895Syz147064 	 */
9005895Syz147064 	if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
9015895Syz147064 		err = dls_devnet_recreate(softmac->smac_mh, linkid);
9025895Syz147064 		if (err != 0) {
9035895Syz147064 			cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for "
9045895Syz147064 			    "%s (linkid %d) failed (%d)",
9055895Syz147064 			    softmac->smac_devname, linkid, err);
9065895Syz147064 		}
9075895Syz147064 	}
9085895Syz147064 
9095895Syz147064 	softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE;
9105895Syz147064 	mutex_exit(&softmac->smac_mutex);
9115895Syz147064 
9125895Syz147064 	return (MH_WALK_CONTINUE);
9135895Syz147064 }
9145895Syz147064 
9155895Syz147064 /*
9165895Syz147064  * See comments above softmac_mac_recreate().
9175895Syz147064  */
9185895Syz147064 void
9195895Syz147064 softmac_recreate()
9205895Syz147064 {
9215895Syz147064 	/*
9225895Syz147064 	 * Walk through the softmac_hash table. Request to create the
9235895Syz147064 	 * [link name, linkid] mapping if we failed to do so.
9245895Syz147064 	 */
9255895Syz147064 	rw_enter(&softmac_hash_lock, RW_READER);
9265895Syz147064 	mod_hash_walk(softmac_hash, softmac_mac_recreate, NULL);
9275895Syz147064 	rw_exit(&softmac_hash_lock);
9285895Syz147064 }
9295895Syz147064 
9305895Syz147064 /* ARGSUSED */
9315895Syz147064 static int
9325895Syz147064 softmac_m_start(void *arg)
9335895Syz147064 {
9345895Syz147064 	return (0);
9355895Syz147064 }
9365895Syz147064 
9375895Syz147064 /* ARGSUSED */
9385895Syz147064 static void
9395895Syz147064 softmac_m_stop(void *arg)
9405895Syz147064 {
9415895Syz147064 }
9425895Syz147064 
9435895Syz147064 /*
9445895Syz147064  * Set up the lower stream above the legacy device which is shared by
9455895Syz147064  * GLDv3 MAC clients. Put the lower stream into DLIOCRAW mode to send
9465895Syz147064  * and receive the raw data. Further, put the lower stream into
9475895Syz147064  * DL_PROMISC_SAP mode to receive all packets of interest.
9485895Syz147064  */
9495895Syz147064 static int
9505895Syz147064 softmac_lower_setup(softmac_t *softmac, softmac_lower_t **slpp)
9515895Syz147064 {
9525895Syz147064 	ldi_ident_t		li;
9535895Syz147064 	dev_t			dev;
9545895Syz147064 	ldi_handle_t		lh = NULL;
9555895Syz147064 	softmac_lower_t		*slp = NULL;
9565895Syz147064 	smac_ioc_start_t	start_arg;
9575895Syz147064 	struct strioctl		strioc;
9585895Syz147064 	uint32_t		notifications;
9595895Syz147064 	int			err, rval;
9605895Syz147064 
9615895Syz147064 	if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0)
9625895Syz147064 		return (err);
9635895Syz147064 
9645895Syz147064 	dev = softmac->smac_dev;
9655895Syz147064 	err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
9665895Syz147064 	ldi_ident_release(li);
9675895Syz147064 	if (err != 0)
9685895Syz147064 		goto done;
9695895Syz147064 
9705895Syz147064 	/*
9715895Syz147064 	 * Pop all the intermediate modules. The autopushed modules will
9725895Syz147064 	 * be pushed when the softmac node is opened.
9735895Syz147064 	 */
9745895Syz147064 	while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
9755895Syz147064 		;
9765895Syz147064 
9775895Syz147064 	if ((softmac->smac_style == DL_STYLE2) &&
9785895Syz147064 	    ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) {
9795895Syz147064 		goto done;
9805895Syz147064 	}
9815895Syz147064 
9825895Syz147064 	/*
9835895Syz147064 	 * Put the lower stream into DLIOCRAW mode to send/receive raw data.
9845895Syz147064 	 */
9855895Syz147064 	if ((err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, kcred, &rval)) != 0)
9865895Syz147064 		goto done;
9875895Syz147064 
9885895Syz147064 	/*
9895895Syz147064 	 * Then push the softmac shim layer atop the lower stream.
9905895Syz147064 	 */
9915895Syz147064 	if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL,
9925895Syz147064 	    kcred, &rval)) != 0) {
9935895Syz147064 		goto done;
9945895Syz147064 	}
9955895Syz147064 
9965895Syz147064 	/*
9975895Syz147064 	 * Send the ioctl to get the slp pointer.
9985895Syz147064 	 */
9995895Syz147064 	strioc.ic_cmd = SMAC_IOC_START;
10005895Syz147064 	strioc.ic_timout = INFTIM;
10015895Syz147064 	strioc.ic_len = sizeof (start_arg);
10025895Syz147064 	strioc.ic_dp = (char *)&start_arg;
10035895Syz147064 
10045895Syz147064 	if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL,
10055895Syz147064 	    kcred, &rval)) != 0) {
10065895Syz147064 		goto done;
10075895Syz147064 	}
10085895Syz147064 	slp = start_arg.si_slp;
10095895Syz147064 	slp->sl_lh = lh;
10105895Syz147064 	slp->sl_softmac = softmac;
10115895Syz147064 	*slpp = slp;
10125895Syz147064 
10135895Syz147064 	/*
10145895Syz147064 	 * Bind to SAP 2 on token ring, 0 on other interface types.
10155895Syz147064 	 * (SAP 0 has special significance on token ring).
10165895Syz147064 	 * Note that the receive-side packets could come anytime after bind.
10175895Syz147064 	 */
10185895Syz147064 	if (softmac->smac_media == DL_TPR)
10195895Syz147064 		err = softmac_send_bind_req(slp, 2);
10205895Syz147064 	else
10215895Syz147064 		err = softmac_send_bind_req(slp, 0);
10225895Syz147064 	if (err != 0)
10235895Syz147064 		goto done;
10245895Syz147064 
10255895Syz147064 	/*
10265895Syz147064 	 * Put the lower stream into DL_PROMISC_SAP mode to receive all
10275895Syz147064 	 * packets of interest.
10285895Syz147064 	 *
10295895Syz147064 	 * Some drivers (e.g. the old legacy eri driver) incorrectly pass up
10305895Syz147064 	 * packets to DL_PROMISC_SAP stream when the lower stream is not bound,
10315895Syz147064 	 * so we send DL_PROMISON_REQ after DL_BIND_REQ.
10325895Syz147064 	 */
10335895Syz147064 	if ((err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE)) != 0)
10345895Syz147064 		goto done;
10355895Syz147064 
10365895Syz147064 	/*
10375895Syz147064 	 * Enable the capabilities the underlying driver claims to support.
10385895Syz147064 	 * Some drivers require this to be called after the stream is bound.
10395895Syz147064 	 */
10405895Syz147064 	if ((err = softmac_capab_enable(slp)) != 0)
10415895Syz147064 		goto done;
10425895Syz147064 
10435895Syz147064 	/*
10445895Syz147064 	 * Send the DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND.
10455895Syz147064 	 * We don't have to wait for the ack.
10465895Syz147064 	 */
10475895Syz147064 	notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP |
10485895Syz147064 	    DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS |
10495895Syz147064 	    DL_NOTE_PROMISC_OFF_PHYS;
10505895Syz147064 
10515895Syz147064 	(void) softmac_send_notify_req(slp,
10525895Syz147064 	    (notifications & softmac->smac_notifications));
10535895Syz147064 
10545895Syz147064 done:
10555895Syz147064 	if (err != 0)
10565895Syz147064 		(void) ldi_close(lh, FREAD|FWRITE, kcred);
10575895Syz147064 	return (err);
10585895Syz147064 }
10595895Syz147064 
10605895Syz147064 static int
10615895Syz147064 softmac_m_open(void *arg)
10625895Syz147064 {
10635895Syz147064 	softmac_t	*softmac = arg;
10645895Syz147064 	softmac_lower_t	*slp;
10655895Syz147064 	int		err;
10665895Syz147064 
10675895Syz147064 	rw_enter(&softmac->smac_lock, RW_READER);
10685895Syz147064 	if (softmac->smac_state == SOFTMAC_READY)
10695895Syz147064 		goto done;
10705895Syz147064 	rw_exit(&softmac->smac_lock);
10715895Syz147064 
10725895Syz147064 	if ((err = softmac_lower_setup(softmac, &slp)) != 0)
10735895Syz147064 		return (err);
10745895Syz147064 
10755895Syz147064 	rw_enter(&softmac->smac_lock, RW_WRITER);
10765895Syz147064 	ASSERT(softmac->smac_state == SOFTMAC_INITIALIZED);
10775895Syz147064 	softmac->smac_lower = slp;
10785895Syz147064 	softmac->smac_state = SOFTMAC_READY;
10795895Syz147064 done:
10805895Syz147064 	rw_exit(&softmac->smac_lock);
10815895Syz147064 	return (0);
10825895Syz147064 }
10835895Syz147064 
10845895Syz147064 static void
10855895Syz147064 softmac_m_close(void *arg)
10865895Syz147064 {
10875895Syz147064 	softmac_t	*softmac = arg;
10885895Syz147064 	softmac_lower_t	*slp;
10895895Syz147064 
10905895Syz147064 	rw_enter(&softmac->smac_lock, RW_WRITER);
10915895Syz147064 	slp = softmac->smac_lower;
10925895Syz147064 	ASSERT(slp != NULL);
10935895Syz147064 
10945895Syz147064 	/*
10955895Syz147064 	 * Note that slp is destroyed when lh is closed.
10965895Syz147064 	 */
10975895Syz147064 	(void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred);
10985895Syz147064 	softmac->smac_state = SOFTMAC_INITIALIZED;
10995895Syz147064 	softmac->smac_lower = NULL;
11005895Syz147064 	rw_exit(&softmac->smac_lock);
11015895Syz147064 }
11025895Syz147064 
11035895Syz147064 int
11045895Syz147064 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp)
11055895Syz147064 {
11065895Syz147064 	dev_info_t	*dip;
11076915Syz147064 	const char	*drvname;
11085895Syz147064 	char		devname[MAXNAMELEN];
11095895Syz147064 	softmac_t	*softmac;
11105895Syz147064 	int		ppa, err;
11115895Syz147064 
11125895Syz147064 	if ((ppa = getminor(dev) - 1) > 1000)
11135895Syz147064 		return (ENOENT);
11145895Syz147064 
11155895Syz147064 	/*
11165895Syz147064 	 * First try to hold this device instance to force the MAC
11175895Syz147064 	 * to be registered.
11185895Syz147064 	 */
11195895Syz147064 	if ((dip = ddi_hold_devi_by_instance(getmajor(dev), ppa, 0)) == NULL)
11205895Syz147064 		return (ENOENT);
11215895Syz147064 
11226915Syz147064 	drvname = ddi_driver_name(dip);
11236915Syz147064 
11246915Syz147064 	/*
11256915Syz147064 	 * Exclude non-physical network device instances, for example, aggr0.
11266915Syz147064 	 */
11275895Syz147064 	if ((ddi_driver_major(dip) != getmajor(dev)) ||
11286915Syz147064 	    !NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) ||
11296915Syz147064 	    (strcmp(drvname, "vnic") == 0)) {
11305895Syz147064 		ddi_release_devi(dip);
11315895Syz147064 		return (ENOENT);
11325895Syz147064 	}
11335895Syz147064 
11345895Syz147064 	/*
11355895Syz147064 	 * This is a network device; wait for its softmac to be registered.
11365895Syz147064 	 */
11376915Syz147064 	(void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa);
11385895Syz147064 again:
11395895Syz147064 	rw_enter(&softmac_hash_lock, RW_READER);
11405895Syz147064 
11415895Syz147064 	if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
11425895Syz147064 	    (mod_hash_val_t *)&softmac) != 0) {
11435895Syz147064 		/*
11445895Syz147064 		 * This is rare but possible. It could happen when pre-detach
11455895Syz147064 		 * routine of the device succeeds. But the softmac will then
11465895Syz147064 		 * be recreated when device fails to detach (as this device
11475895Syz147064 		 * is held).
11485895Syz147064 		 */
11495895Syz147064 		rw_exit(&softmac_hash_lock);
11505895Syz147064 		goto again;
11515895Syz147064 	}
11525895Syz147064 
11535895Syz147064 	/*
11545895Syz147064 	 * Bump smac_hold_cnt to prevent device detach.
11555895Syz147064 	 */
11565895Syz147064 	mutex_enter(&softmac->smac_mutex);
11575895Syz147064 	softmac->smac_hold_cnt++;
11585895Syz147064 	mutex_exit(&softmac->smac_mutex);
11595895Syz147064 
11605895Syz147064 	rw_exit(&softmac_hash_lock);
11615895Syz147064 
11625895Syz147064 	/*
11635895Syz147064 	 * Wait till the device is fully attached.
11645895Syz147064 	 */
11655895Syz147064 	mutex_enter(&softmac->smac_mutex);
11665895Syz147064 	while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE))
11675895Syz147064 		cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
11685895Syz147064 
11695909Syz147064 	if ((err = softmac->smac_attacherr) != 0)
11705909Syz147064 		softmac->smac_hold_cnt--;
11715909Syz147064 	else
11725895Syz147064 		*ddhp = (dls_dev_handle_t)softmac;
11735895Syz147064 	mutex_exit(&softmac->smac_mutex);
11745895Syz147064 
11755909Syz147064 	ddi_release_devi(dip);
11765895Syz147064 	return (err);
11775895Syz147064 }
11785895Syz147064 
11795895Syz147064 void
11805895Syz147064 softmac_rele_device(dls_dev_handle_t ddh)
11815895Syz147064 {
11825895Syz147064 	softmac_t	*softmac;
11835895Syz147064 
11845895Syz147064 	if (ddh == NULL)
11855895Syz147064 		return;
11865895Syz147064 
11875895Syz147064 	softmac = (softmac_t *)ddh;
11885895Syz147064 	mutex_enter(&softmac->smac_mutex);
11895909Syz147064 	softmac->smac_hold_cnt--;
11905895Syz147064 	mutex_exit(&softmac->smac_mutex);
11915895Syz147064 }
1192