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 /*
22*11878SVenu.Iyer@Sun.COM * Copyright 2010 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,
87*11878SVenu.Iyer@Sun.COM uint_t, void *);
88*11878SVenu.Iyer@Sun.COM static void softmac_m_propinfo(void *, const char *, mac_prop_id_t,
89*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t);
905895Syz147064
915895Syz147064 #define SOFTMAC_M_CALLBACK_FLAGS \
92*11878SVenu.Iyer@Sun.COM (MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE | MC_SETPROP | \
93*11878SVenu.Iyer@Sun.COM MC_GETPROP | MC_PROPINFO)
945895Syz147064
955895Syz147064 static mac_callbacks_t softmac_m_callbacks = {
965895Syz147064 SOFTMAC_M_CALLBACK_FLAGS,
975895Syz147064 softmac_m_stat,
985895Syz147064 softmac_m_start,
995895Syz147064 softmac_m_stop,
1005895Syz147064 softmac_m_promisc,
1015895Syz147064 softmac_m_multicst,
1025895Syz147064 softmac_m_unicst,
1035895Syz147064 softmac_m_tx,
104*11878SVenu.Iyer@Sun.COM NULL,
1055895Syz147064 softmac_m_ioctl,
1065895Syz147064 softmac_m_getcapab,
1075895Syz147064 softmac_m_open,
1089073SCathy.Zhou@Sun.COM softmac_m_close,
1099073SCathy.Zhou@Sun.COM softmac_m_setprop,
110*11878SVenu.Iyer@Sun.COM softmac_m_getprop,
111*11878SVenu.Iyer@Sun.COM softmac_m_propinfo
1125895Syz147064 };
1135895Syz147064
1149073SCathy.Zhou@Sun.COM /*ARGSUSED*/
1159073SCathy.Zhou@Sun.COM static int
softmac_constructor(void * buf,void * arg,int kmflag)1169073SCathy.Zhou@Sun.COM softmac_constructor(void *buf, void *arg, int kmflag)
1179073SCathy.Zhou@Sun.COM {
1189073SCathy.Zhou@Sun.COM softmac_t *softmac = buf;
1199073SCathy.Zhou@Sun.COM
1209073SCathy.Zhou@Sun.COM bzero(buf, sizeof (softmac_t));
1219073SCathy.Zhou@Sun.COM mutex_init(&softmac->smac_mutex, NULL, MUTEX_DEFAULT, NULL);
1229073SCathy.Zhou@Sun.COM mutex_init(&softmac->smac_active_mutex, NULL, MUTEX_DEFAULT, NULL);
1239073SCathy.Zhou@Sun.COM mutex_init(&softmac->smac_fp_mutex, NULL, MUTEX_DEFAULT, NULL);
1249073SCathy.Zhou@Sun.COM cv_init(&softmac->smac_cv, NULL, CV_DEFAULT, NULL);
1259073SCathy.Zhou@Sun.COM cv_init(&softmac->smac_fp_cv, NULL, CV_DEFAULT, NULL);
1269073SCathy.Zhou@Sun.COM list_create(&softmac->smac_sup_list, sizeof (softmac_upper_t),
1279073SCathy.Zhou@Sun.COM offsetof(softmac_upper_t, su_list_node));
1289073SCathy.Zhou@Sun.COM return (0);
1299073SCathy.Zhou@Sun.COM }
1309073SCathy.Zhou@Sun.COM
1319073SCathy.Zhou@Sun.COM /*ARGSUSED*/
1329073SCathy.Zhou@Sun.COM static void
softmac_destructor(void * buf,void * arg)1339073SCathy.Zhou@Sun.COM softmac_destructor(void *buf, void *arg)
1349073SCathy.Zhou@Sun.COM {
1359073SCathy.Zhou@Sun.COM softmac_t *softmac = buf;
1369073SCathy.Zhou@Sun.COM
1379073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_fp_disable_clients == 0);
1389073SCathy.Zhou@Sun.COM ASSERT(!softmac->smac_fastpath_admin_disabled);
1399073SCathy.Zhou@Sun.COM
1409073SCathy.Zhou@Sun.COM ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE));
1419073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_hold_cnt == 0);
1429073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_attachok_cnt == 0);
1439073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_mh == NULL);
1449073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_softmac[0] == NULL &&
1459073SCathy.Zhou@Sun.COM softmac->smac_softmac[1] == NULL);
1469073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_state == SOFTMAC_INITIALIZED);
1479073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_lower == NULL);
1489073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_active == B_FALSE);
1499073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_nactive == 0);
1509073SCathy.Zhou@Sun.COM ASSERT(list_is_empty(&softmac->smac_sup_list));
1519073SCathy.Zhou@Sun.COM
1529073SCathy.Zhou@Sun.COM list_destroy(&softmac->smac_sup_list);
1539073SCathy.Zhou@Sun.COM mutex_destroy(&softmac->smac_mutex);
1549073SCathy.Zhou@Sun.COM mutex_destroy(&softmac->smac_active_mutex);
1559073SCathy.Zhou@Sun.COM mutex_destroy(&softmac->smac_fp_mutex);
1569073SCathy.Zhou@Sun.COM cv_destroy(&softmac->smac_cv);
1579073SCathy.Zhou@Sun.COM cv_destroy(&softmac->smac_fp_cv);
1589073SCathy.Zhou@Sun.COM }
1599073SCathy.Zhou@Sun.COM
1605895Syz147064 void
softmac_init()1615895Syz147064 softmac_init()
1625895Syz147064 {
1635895Syz147064 softmac_hash = mod_hash_create_extended("softmac_hash",
1645895Syz147064 SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
1655895Syz147064 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
1665895Syz147064
1675895Syz147064 rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL);
1688275SEric Cheng mutex_init(&smac_global_lock, NULL, MUTEX_DRIVER, NULL);
1698275SEric Cheng cv_init(&smac_global_cv, NULL, CV_DRIVER, NULL);
1709073SCathy.Zhou@Sun.COM
1719073SCathy.Zhou@Sun.COM softmac_cachep = kmem_cache_create("softmac_cache",
1729073SCathy.Zhou@Sun.COM sizeof (softmac_t), 0, softmac_constructor,
1739073SCathy.Zhou@Sun.COM softmac_destructor, NULL, NULL, NULL, 0);
1749073SCathy.Zhou@Sun.COM ASSERT(softmac_cachep != NULL);
1759073SCathy.Zhou@Sun.COM softmac_fp_init();
1765895Syz147064 }
1775895Syz147064
1785895Syz147064 void
softmac_fini()1795895Syz147064 softmac_fini()
1805895Syz147064 {
1819073SCathy.Zhou@Sun.COM softmac_fp_fini();
1829073SCathy.Zhou@Sun.COM kmem_cache_destroy(softmac_cachep);
1835895Syz147064 rw_destroy(&softmac_hash_lock);
1845895Syz147064 mod_hash_destroy_hash(softmac_hash);
1858275SEric Cheng mutex_destroy(&smac_global_lock);
1868275SEric Cheng cv_destroy(&smac_global_cv);
1875895Syz147064 }
1885895Syz147064
1895895Syz147064 /* ARGSUSED */
1905895Syz147064 static uint_t
softmac_exist(mod_hash_key_t key,mod_hash_val_t * val,void * arg)1915895Syz147064 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1925895Syz147064 {
1935895Syz147064 boolean_t *pexist = arg;
1945895Syz147064
1955895Syz147064 *pexist = B_TRUE;
1965895Syz147064 return (MH_WALK_TERMINATE);
1975895Syz147064 }
1985895Syz147064
1995895Syz147064 boolean_t
softmac_busy()2005895Syz147064 softmac_busy()
2015895Syz147064 {
2025895Syz147064 boolean_t exist = B_FALSE;
2035895Syz147064
2045895Syz147064 rw_enter(&softmac_hash_lock, RW_READER);
2055895Syz147064 mod_hash_walk(softmac_hash, softmac_exist, &exist);
2065895Syz147064 rw_exit(&softmac_hash_lock);
2075895Syz147064 return (exist);
2085895Syz147064 }
2095895Syz147064
2105895Syz147064 /*
2118275SEric Cheng *
2128275SEric Cheng * softmac_create() is called for each minor node during the post-attach of
2135895Syz147064 * each DDI_NT_NET device instance. Note that it is possible that a device
2145895Syz147064 * instance has two minor nodes (DLPI style-1 and style-2), so that for that
2155895Syz147064 * specific device, softmac_create() could be called twice.
2165895Syz147064 *
2175895Syz147064 * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t
2185895Syz147064 * is created to track each minor node.
2195895Syz147064 *
2205895Syz147064 * For each minor node of a legacy device, a taskq is started to finish
2215895Syz147064 * softmac_mac_register(), which will finish the rest of work (see comments
2225895Syz147064 * above softmac_mac_register()).
2238275SEric Cheng *
2248275SEric Cheng * softmac state machine
2258275SEric Cheng * --------------------------------------------------------------------------
2268275SEric Cheng * OLD STATE EVENT NEW STATE
2278275SEric Cheng * --------------------------------------------------------------------------
2288275SEric Cheng * UNINIT attach of 1st minor node ATTACH_INPROG
2298275SEric Cheng * okcnt = 0 net_postattach -> softmac_create okcnt = 1
2308275SEric Cheng *
2318275SEric Cheng * ATTACH_INPROG attach of 2nd minor node (GLDv3) ATTACH_DONE
2328275SEric Cheng * okcnt = 1 net_postattach -> softmac_create okcnt = 2
2338275SEric Cheng *
2348275SEric Cheng * ATTACH_INPROG attach of 2nd minor node (legacy) ATTACH_INPROG
2358275SEric Cheng * okcnt = 1 net_postattach -> softmac_create okcnt = 2
2368275SEric Cheng * schedule softmac_mac_register
2378275SEric Cheng *
2388275SEric Cheng * ATTACH_INPROG legacy device node ATTACH_DONE
2398275SEric Cheng * okcnt = 2 softmac_mac_register okcnt = 2
2408275SEric Cheng *
2418275SEric Cheng * ATTACH_DONE detach of 1st minor node DETACH_INPROG
2428275SEric Cheng * okcnt = 2 (success) okcnt = 1
2438275SEric Cheng *
2448275SEric Cheng * DETACH_INPROG detach of 2nd minor node UNINIT (or free)
2458275SEric Cheng * okcnt = 1 (success) okcnt = 0
2468275SEric Cheng *
2478275SEric Cheng * ATTACH_DONE detach failure state unchanged
2488275SEric Cheng * DETACH_INPROG left = okcnt
2498275SEric Cheng *
2508275SEric Cheng * DETACH_INPROG reattach ATTACH_INPROG
2518275SEric Cheng * okcnt = 0,1 net_postattach -> softmac_create
2528275SEric Cheng *
2538275SEric Cheng * ATTACH_DONE reattach ATTACH_DONE
2548275SEric Cheng * left != 0 net_postattach -> softmac_create left = 0
2558275SEric Cheng *
2568275SEric Cheng * Abbreviation notes:
2578275SEric Cheng * states have SOFTMAC_ prefix,
2588275SEric Cheng * okcnt - softmac_attach_okcnt,
2598275SEric Cheng * left - softmac_attached_left
2605895Syz147064 */
2618275SEric Cheng
2628275SEric Cheng #ifdef DEBUG
2638275SEric Cheng void
softmac_state_verify(softmac_t * softmac)2648275SEric Cheng softmac_state_verify(softmac_t *softmac)
2658275SEric Cheng {
2668275SEric Cheng ASSERT(MUTEX_HELD(&softmac->smac_mutex));
2678275SEric Cheng
2688275SEric Cheng /*
2698275SEric Cheng * There are at most 2 minor nodes, one per DLPI style
2708275SEric Cheng */
2718275SEric Cheng ASSERT(softmac->smac_cnt <= 2 && softmac->smac_attachok_cnt <= 2);
2728275SEric Cheng
2738275SEric Cheng /*
2748275SEric Cheng * The smac_attachok_cnt represents the number of attaches i.e. the
2758275SEric Cheng * number of times net_postattach -> softmac_create() has been called
2768275SEric Cheng * for a device instance.
2778275SEric Cheng */
2788275SEric Cheng ASSERT(softmac->smac_attachok_cnt == SMAC_NONZERO_NODECNT(softmac));
2798275SEric Cheng
2808275SEric Cheng /*
2818275SEric Cheng * softmac_create (or softmac_mac_register) -> softmac_create_datalink
2828275SEric Cheng * happens only after all minor nodes have been attached
2838275SEric Cheng */
2848275SEric Cheng ASSERT(softmac->smac_state != SOFTMAC_ATTACH_DONE ||
2858275SEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt);
2868275SEric Cheng
2878275SEric Cheng if (softmac->smac_attachok_cnt == 0) {
2888275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_UNINIT);
2898275SEric Cheng ASSERT(softmac->smac_mh == NULL);
2908275SEric Cheng } else if (softmac->smac_attachok_cnt < softmac->smac_cnt) {
2918275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG ||
2928275SEric Cheng softmac->smac_state == SOFTMAC_DETACH_INPROG);
2938275SEric Cheng ASSERT(softmac->smac_mh == NULL);
2948275SEric Cheng } else {
2958275SEric Cheng /*
2968275SEric Cheng * In the stable condition the state whould be
2978275SEric Cheng * SOFTMAC_ATTACH_DONE. But there is a small transient window
2988275SEric Cheng * in softmac_destroy where we change the state to
2998275SEric Cheng * SOFTMAC_DETACH_INPROG and drop the lock before doing
3008275SEric Cheng * the link destroy
3018275SEric Cheng */
3028275SEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
3038275SEric Cheng ASSERT(softmac->smac_state != SOFTMAC_UNINIT);
3048275SEric Cheng }
3058275SEric Cheng if (softmac->smac_mh != NULL)
3068275SEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
3078275SEric Cheng }
3088275SEric Cheng #endif
3098275SEric Cheng
3108275SEric Cheng #ifdef DEBUG
3118275SEric Cheng #define SOFTMAC_STATE_VERIFY(softmac) softmac_state_verify(softmac)
3128275SEric Cheng #else
3138275SEric Cheng #define SOFTMAC_STATE_VERIFY(softmac)
3148275SEric Cheng #endif
3158275SEric Cheng
3165895Syz147064 int
softmac_create(dev_info_t * dip,dev_t dev)3175895Syz147064 softmac_create(dev_info_t *dip, dev_t dev)
3185895Syz147064 {
3195895Syz147064 char devname[MAXNAMELEN];
3205895Syz147064 softmac_t *softmac;
3215895Syz147064 softmac_dev_t *softmac_dev = NULL;
3225895Syz147064 int index;
3235895Syz147064 int ppa, err = 0;
3245895Syz147064
3255895Syz147064 /*
3265895Syz147064 * Force the softmac driver to be attached.
3275895Syz147064 */
3285895Syz147064 if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) {
3295895Syz147064 cmn_err(CE_WARN, "softmac_create:softmac attach fails");
3305895Syz147064 return (ENXIO);
3315895Syz147064 }
3325895Syz147064
33310654SGarrett.Damore@Sun.COM if (GLDV3_DRV(ddi_driver_major(dip))) {
33410654SGarrett.Damore@Sun.COM minor_t minor = getminor(dev);
33510654SGarrett.Damore@Sun.COM /*
33610654SGarrett.Damore@Sun.COM * For GLDv3, we don't care about the DLPI style 2
33710654SGarrett.Damore@Sun.COM * compatibility node. (We know that all such devices
33810654SGarrett.Damore@Sun.COM * have style 1 nodes.)
33910654SGarrett.Damore@Sun.COM */
34010654SGarrett.Damore@Sun.COM if ((strcmp(ddi_driver_name(dip), "clone") == 0) ||
34110654SGarrett.Damore@Sun.COM (getmajor(dev) == ddi_name_to_major("clone")) ||
34210654SGarrett.Damore@Sun.COM (minor == 0)) {
34310654SGarrett.Damore@Sun.COM return (0);
34410654SGarrett.Damore@Sun.COM }
3455895Syz147064
34610654SGarrett.Damore@Sun.COM /*
34710654SGarrett.Damore@Sun.COM * Likewise, we know that the minor number for DLPI style 1
34810654SGarrett.Damore@Sun.COM * nodes is constrained to a maximum value.
34910654SGarrett.Damore@Sun.COM */
35010654SGarrett.Damore@Sun.COM if (minor >= DLS_MAX_MINOR) {
35110654SGarrett.Damore@Sun.COM return (ENOTSUP);
35210654SGarrett.Damore@Sun.COM }
35310654SGarrett.Damore@Sun.COM /*
35410654SGarrett.Damore@Sun.COM * Otherwise we can decode the instance from the minor number,
35510654SGarrett.Damore@Sun.COM * which allows for situations with multiple mac instances
35610654SGarrett.Damore@Sun.COM * for a single dev_info_t.
35710654SGarrett.Damore@Sun.COM */
35810654SGarrett.Damore@Sun.COM ppa = DLS_MINOR2INST(minor);
35910654SGarrett.Damore@Sun.COM } else {
36010654SGarrett.Damore@Sun.COM /*
36110654SGarrett.Damore@Sun.COM * For legacy drivers, we just have to limit them to
36210654SGarrett.Damore@Sun.COM * two minor nodes, one style 1 and one style 2, and
36310654SGarrett.Damore@Sun.COM * we assume the ddi_get_instance() is the PPA.
36410654SGarrett.Damore@Sun.COM * Drivers that need more flexibility should be ported
36510654SGarrett.Damore@Sun.COM * to GLDv3.
36610654SGarrett.Damore@Sun.COM */
36710654SGarrett.Damore@Sun.COM ppa = ddi_get_instance(dip);
36810654SGarrett.Damore@Sun.COM if (i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) {
36910654SGarrett.Damore@Sun.COM cmn_err(CE_WARN, "%s has more than 2 minor nodes; "
37010654SGarrett.Damore@Sun.COM "unsupported", devname);
37110654SGarrett.Damore@Sun.COM return (ENOTSUP);
37210654SGarrett.Damore@Sun.COM }
3735895Syz147064 }
3745895Syz147064
37510654SGarrett.Damore@Sun.COM (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
37610654SGarrett.Damore@Sun.COM
3775895Syz147064 /*
3785895Syz147064 * Check whether the softmac for the specified device already exists
3795895Syz147064 */
3805895Syz147064 rw_enter(&softmac_hash_lock, RW_WRITER);
3819073SCathy.Zhou@Sun.COM if ((mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
3825895Syz147064 (mod_hash_val_t *)&softmac)) != 0) {
3835895Syz147064
3849073SCathy.Zhou@Sun.COM softmac = kmem_cache_alloc(softmac_cachep, KM_SLEEP);
3855895Syz147064 (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN);
3869073SCathy.Zhou@Sun.COM
3875895Syz147064 err = mod_hash_insert(softmac_hash,
3885895Syz147064 (mod_hash_key_t)softmac->smac_devname,
3895895Syz147064 (mod_hash_val_t)softmac);
3905895Syz147064 ASSERT(err == 0);
3918275SEric Cheng mutex_enter(&smac_global_lock);
3928275SEric Cheng cv_broadcast(&smac_global_cv);
3938275SEric Cheng mutex_exit(&smac_global_lock);
3945895Syz147064 }
3955895Syz147064
3965895Syz147064 mutex_enter(&softmac->smac_mutex);
3978275SEric Cheng SOFTMAC_STATE_VERIFY(softmac);
3988275SEric Cheng if (softmac->smac_state != SOFTMAC_ATTACH_DONE)
3998275SEric Cheng softmac->smac_state = SOFTMAC_ATTACH_INPROG;
4005895Syz147064 if (softmac->smac_attachok_cnt == 0) {
4015895Syz147064 /*
4025895Syz147064 * Initialize the softmac if this is the post-attach of the
4035895Syz147064 * first minor node.
4045895Syz147064 */
4055895Syz147064 softmac->smac_flags = 0;
4065895Syz147064 softmac->smac_umajor = ddi_driver_major(dip);
4075895Syz147064 softmac->smac_uppa = ppa;
4085895Syz147064
4095895Syz147064 /*
41010654SGarrett.Damore@Sun.COM * For GLDv3, we ignore the style 2 node (see the logic
41110654SGarrett.Damore@Sun.COM * above on that), and we should have exactly one attach
41210654SGarrett.Damore@Sun.COM * per MAC instance (possibly more than one per dev_info_t).
4135895Syz147064 */
4145895Syz147064 if (GLDV3_DRV(ddi_driver_major(dip))) {
4155895Syz147064 softmac->smac_flags |= SOFTMAC_GLDV3;
41610654SGarrett.Damore@Sun.COM softmac->smac_cnt = 1;
4175895Syz147064 } else {
4185895Syz147064 softmac->smac_cnt =
4195895Syz147064 i_ddi_minor_node_count(dip, DDI_NT_NET);
4205895Syz147064 }
4215895Syz147064 }
4225895Syz147064
4235895Syz147064 index = (getmajor(dev) == ddi_name_to_major("clone"));
4245895Syz147064 if (softmac->smac_softmac[index] != NULL) {
4255895Syz147064 /*
4268275SEric Cheng * This is possible if the post_attach() is called after
4278275SEric Cheng * pre_detach() fails. This seems to be a defect of the DACF
4288275SEric Cheng * framework. We work around it by using a smac_attached_left
4298275SEric Cheng * field that tracks this
4305895Syz147064 */
4318275SEric Cheng ASSERT(softmac->smac_attached_left != 0);
4328275SEric Cheng softmac->smac_attached_left--;
4335895Syz147064 mutex_exit(&softmac->smac_mutex);
4345895Syz147064 rw_exit(&softmac_hash_lock);
4355895Syz147064 return (0);
4368275SEric Cheng
4375895Syz147064 }
4385895Syz147064 mutex_exit(&softmac->smac_mutex);
4395895Syz147064 rw_exit(&softmac_hash_lock);
4405895Syz147064
4415895Syz147064 softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP);
4425895Syz147064 softmac_dev->sd_dev = dev;
4438275SEric Cheng
4448275SEric Cheng mutex_enter(&softmac->smac_mutex);
4455895Syz147064 softmac->smac_softmac[index] = softmac_dev;
4465895Syz147064 /*
4475895Syz147064 * Continue to register the mac and create the datalink only when all
4485895Syz147064 * the minor nodes are attached.
4495895Syz147064 */
4505895Syz147064 if (++softmac->smac_attachok_cnt != softmac->smac_cnt) {
4515895Syz147064 mutex_exit(&softmac->smac_mutex);
4525895Syz147064 return (0);
4535895Syz147064 }
4545895Syz147064
4555895Syz147064 /*
4567323SCathy.Zhou@Sun.COM * All of the minor nodes have been attached; start a taskq
4578275SEric Cheng * to do the rest of the work. We use a taskq instead of
4587323SCathy.Zhou@Sun.COM * doing the work here because:
4597323SCathy.Zhou@Sun.COM *
4608275SEric Cheng * We could be called as a result of a open() system call
4618275SEric Cheng * where spec_open() already SLOCKED the snode. Using a taskq
4628275SEric Cheng * sidesteps the risk that our ldi_open_by_dev() call would
4638275SEric Cheng * deadlock trying to set SLOCKED on the snode again.
4647323SCathy.Zhou@Sun.COM *
4658275SEric Cheng * The devfs design requires that the downcalls don't use any
4668275SEric Cheng * interruptible cv_wait which happens when we do door upcalls.
4678275SEric Cheng * Otherwise the downcalls which may be holding devfs resources
4688275SEric Cheng * may cause a deadlock if the thread is stopped. Also we need to make
4698275SEric Cheng * sure these downcalls into softmac_create or softmac_destroy
4708275SEric Cheng * don't cv_wait on any devfs related condition. Thus softmac_destroy
4718275SEric Cheng * returns EBUSY if the asynchronous threads started in softmac_create
4728275SEric Cheng * haven't finished.
4735895Syz147064 */
4748527SCathy.Zhou@Sun.COM (void) taskq_dispatch(system_taskq, softmac_create_task,
4758527SCathy.Zhou@Sun.COM softmac, TQ_SLEEP);
4765895Syz147064 mutex_exit(&softmac->smac_mutex);
4777323SCathy.Zhou@Sun.COM return (0);
4785895Syz147064 }
4795895Syz147064
4805895Syz147064 static boolean_t
softmac_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)4815895Syz147064 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
4825895Syz147064 {
4835895Syz147064 softmac_t *softmac = arg;
4845895Syz147064
4855895Syz147064 if (!(softmac->smac_capab_flags & cap))
4865895Syz147064 return (B_FALSE);
4875895Syz147064
4885895Syz147064 switch (cap) {
4895895Syz147064 case MAC_CAPAB_HCKSUM: {
4905895Syz147064 uint32_t *txflags = cap_data;
4915895Syz147064
4925895Syz147064 *txflags = softmac->smac_hcksum_txflags;
4935895Syz147064 break;
4945895Syz147064 }
4955895Syz147064 case MAC_CAPAB_LEGACY: {
4965895Syz147064 mac_capab_legacy_t *legacy = cap_data;
4975895Syz147064
4989073SCathy.Zhou@Sun.COM /*
4999073SCathy.Zhou@Sun.COM * The caller is not interested in the details.
5009073SCathy.Zhou@Sun.COM */
5019073SCathy.Zhou@Sun.COM if (legacy == NULL)
5029073SCathy.Zhou@Sun.COM break;
5039073SCathy.Zhou@Sun.COM
5045895Syz147064 legacy->ml_unsup_note = ~softmac->smac_notifications &
5055895Syz147064 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED);
5069073SCathy.Zhou@Sun.COM legacy->ml_active_set = softmac_active_set;
5079073SCathy.Zhou@Sun.COM legacy->ml_active_clear = softmac_active_clear;
5089073SCathy.Zhou@Sun.COM legacy->ml_fastpath_disable = softmac_fastpath_disable;
5099073SCathy.Zhou@Sun.COM legacy->ml_fastpath_enable = softmac_fastpath_enable;
5105895Syz147064 legacy->ml_dev = makedevice(softmac->smac_umajor,
5115895Syz147064 softmac->smac_uppa + 1);
5125895Syz147064 break;
5135895Syz147064 }
5145895Syz147064
5155895Syz147064 /*
5165895Syz147064 * For the capabilities below, there's nothing for us to fill in;
5175895Syz147064 * simply return B_TRUE if we support it.
5185895Syz147064 */
5195895Syz147064 case MAC_CAPAB_NO_ZCOPY:
5205895Syz147064 case MAC_CAPAB_NO_NATIVEVLAN:
5215895Syz147064 default:
5225895Syz147064 break;
5235895Syz147064 }
5245895Syz147064 return (B_TRUE);
5255895Syz147064 }
5265895Syz147064
5275895Syz147064 static int
softmac_update_info(softmac_t * softmac,datalink_id_t * linkidp)5285895Syz147064 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp)
5295895Syz147064 {
5305895Syz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID;
5315895Syz147064 uint32_t media;
5325895Syz147064 int err;
5335895Syz147064
5345895Syz147064 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media,
5355895Syz147064 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) {
5365895Syz147064 *linkidp = linkid;
5375895Syz147064 }
5385895Syz147064
5395895Syz147064 if (err == EEXIST) {
5405895Syz147064 /*
5415895Syz147064 * There is a link name conflict. Either:
5425895Syz147064 *
5435895Syz147064 * - An existing link with the same device name with a
5445895Syz147064 * different media type from of the given type.
5455895Syz147064 * Mark this link back to persistent only; or
5465895Syz147064 *
5475895Syz147064 * - We cannot assign the "suggested" name because
5485895Syz147064 * GLDv3 and therefore vanity naming is not supported
5495895Syz147064 * for this link type. Delete this link's <link name,
5505895Syz147064 * linkid> mapping.
5515895Syz147064 */
5525895Syz147064 if (media != softmac->smac_media) {
5535895Syz147064 cmn_err(CE_WARN, "%s device %s conflicts with "
5545895Syz147064 "existing %s device %s.",
5555895Syz147064 dl_mactypestr(softmac->smac_media),
5565895Syz147064 softmac->smac_devname, dl_mactypestr(media),
5575895Syz147064 softmac->smac_devname);
5585895Syz147064 (void) dls_mgmt_destroy(linkid, B_FALSE);
5595895Syz147064 } else {
5605895Syz147064 cmn_err(CE_WARN, "link name %s is already in-use.",
5615895Syz147064 softmac->smac_devname);
5625895Syz147064 (void) dls_mgmt_destroy(linkid, B_TRUE);
5635895Syz147064 }
5645895Syz147064
5655895Syz147064 cmn_err(CE_WARN, "%s device might not be available "
5665895Syz147064 "for use.", softmac->smac_devname);
5675895Syz147064 cmn_err(CE_WARN, "See dladm(1M) for more information.");
5685895Syz147064 }
5695895Syz147064
5705895Syz147064 return (err);
5715895Syz147064 }
5725895Syz147064
5735895Syz147064 /*
5745895Syz147064 * This function:
5755895Syz147064 * 1. provides the link's media type to dlmgmtd.
5765895Syz147064 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
5775895Syz147064 */
5785895Syz147064 static int
softmac_create_datalink(softmac_t * softmac)5795895Syz147064 softmac_create_datalink(softmac_t *softmac)
5805895Syz147064 {
5815895Syz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID;
5825895Syz147064 int err;
5835895Syz147064
5845895Syz147064 /*
5857323SCathy.Zhou@Sun.COM * Inform dlmgmtd of this link so that softmac_hold_device() is able
5867323SCathy.Zhou@Sun.COM * to know the existence of this link. If this failed with EBADF,
5877323SCathy.Zhou@Sun.COM * it might be because dlmgmtd was not started in time (e.g.,
5887323SCathy.Zhou@Sun.COM * diskless boot); ignore the failure and continue to create
5897323SCathy.Zhou@Sun.COM * the GLDv3 datalink if needed.
5905895Syz147064 */
5917323SCathy.Zhou@Sun.COM err = dls_mgmt_create(softmac->smac_devname,
5927323SCathy.Zhou@Sun.COM makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
5937323SCathy.Zhou@Sun.COM DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid);
5947323SCathy.Zhou@Sun.COM if (err != 0 && err != EBADF)
5957323SCathy.Zhou@Sun.COM return (err);
5967323SCathy.Zhou@Sun.COM
5977323SCathy.Zhou@Sun.COM /*
5987323SCathy.Zhou@Sun.COM * Provide the media type of the physical link to dlmgmtd.
5997323SCathy.Zhou@Sun.COM */
6007323SCathy.Zhou@Sun.COM if ((err != EBADF) &&
6017323SCathy.Zhou@Sun.COM ((err = softmac_update_info(softmac, &linkid)) != 0)) {
6025895Syz147064 return (err);
6035895Syz147064 }
6045895Syz147064
6055895Syz147064 /*
6065895Syz147064 * Create the GLDv3 datalink.
6075895Syz147064 */
60810616SSebastien.Roy@Sun.COM if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
60910616SSebastien.Roy@Sun.COM err = dls_devnet_create(softmac->smac_mh, linkid,
61010616SSebastien.Roy@Sun.COM crgetzoneid(CRED()));
61110616SSebastien.Roy@Sun.COM if (err != 0) {
61210616SSebastien.Roy@Sun.COM cmn_err(CE_WARN, "dls_devnet_create failed for %s",
61310616SSebastien.Roy@Sun.COM softmac->smac_devname);
61410616SSebastien.Roy@Sun.COM return (err);
61510616SSebastien.Roy@Sun.COM }
6165895Syz147064 }
6175895Syz147064
6188275SEric Cheng if (linkid == DATALINK_INVALID_LINKID) {
6198275SEric Cheng mutex_enter(&softmac->smac_mutex);
6205895Syz147064 softmac->smac_flags |= SOFTMAC_NEED_RECREATE;
6218275SEric Cheng mutex_exit(&softmac->smac_mutex);
6228275SEric Cheng }
6235895Syz147064
6245895Syz147064 return (0);
6255895Syz147064 }
6265895Syz147064
6277323SCathy.Zhou@Sun.COM static void
softmac_create_task(void * arg)6287323SCathy.Zhou@Sun.COM softmac_create_task(void *arg)
6297323SCathy.Zhou@Sun.COM {
6307323SCathy.Zhou@Sun.COM softmac_t *softmac = arg;
6317323SCathy.Zhou@Sun.COM mac_handle_t mh;
6327323SCathy.Zhou@Sun.COM int err;
6337323SCathy.Zhou@Sun.COM
6347323SCathy.Zhou@Sun.COM if (!GLDV3_DRV(softmac->smac_umajor)) {
6357323SCathy.Zhou@Sun.COM softmac_mac_register(softmac);
6367323SCathy.Zhou@Sun.COM return;
6377323SCathy.Zhou@Sun.COM }
6387323SCathy.Zhou@Sun.COM
6397323SCathy.Zhou@Sun.COM if ((err = mac_open(softmac->smac_devname, &mh)) != 0)
6407323SCathy.Zhou@Sun.COM goto done;
6417323SCathy.Zhou@Sun.COM
6427323SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_mutex);
6437323SCathy.Zhou@Sun.COM softmac->smac_media = (mac_info(mh))->mi_nativemedia;
6447323SCathy.Zhou@Sun.COM softmac->smac_mh = mh;
6458275SEric Cheng mutex_exit(&softmac->smac_mutex);
6467323SCathy.Zhou@Sun.COM
6477323SCathy.Zhou@Sun.COM /*
6487323SCathy.Zhou@Sun.COM * We can safely release the reference on the mac because
6497323SCathy.Zhou@Sun.COM * this mac will only be unregistered and destroyed when
6507323SCathy.Zhou@Sun.COM * the device detaches, and the softmac will be destroyed
6517323SCathy.Zhou@Sun.COM * before then (in the pre-detach routine of the device).
6527323SCathy.Zhou@Sun.COM */
6537323SCathy.Zhou@Sun.COM mac_close(mh);
6547323SCathy.Zhou@Sun.COM
6557323SCathy.Zhou@Sun.COM /*
6567323SCathy.Zhou@Sun.COM * Create the GLDv3 datalink for this mac.
6577323SCathy.Zhou@Sun.COM */
6587323SCathy.Zhou@Sun.COM err = softmac_create_datalink(softmac);
6597323SCathy.Zhou@Sun.COM
6608527SCathy.Zhou@Sun.COM done:
6618275SEric Cheng mutex_enter(&softmac->smac_mutex);
6628527SCathy.Zhou@Sun.COM if (err != 0)
6638275SEric Cheng softmac->smac_mh = NULL;
6648527SCathy.Zhou@Sun.COM softmac->smac_attacherr = err;
6658275SEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE;
6667323SCathy.Zhou@Sun.COM cv_broadcast(&softmac->smac_cv);
6677323SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_mutex);
6687323SCathy.Zhou@Sun.COM }
6697323SCathy.Zhou@Sun.COM
6705895Syz147064 /*
6715895Syz147064 * This function is only called for legacy devices. It:
6725895Syz147064 * 1. registers the MAC for the legacy devices whose media type is supported
6735895Syz147064 * by the GLDv3 framework.
6745895Syz147064 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3.
6755895Syz147064 */
6765895Syz147064 static void
softmac_mac_register(softmac_t * softmac)6777323SCathy.Zhou@Sun.COM softmac_mac_register(softmac_t *softmac)
6785895Syz147064 {
6795895Syz147064 softmac_dev_t *softmac_dev;
6805895Syz147064 dev_t dev;
6815895Syz147064 ldi_handle_t lh = NULL;
6825895Syz147064 ldi_ident_t li = NULL;
6835895Syz147064 int index;
6845895Syz147064 boolean_t native_vlan = B_FALSE;
6855895Syz147064 int err;
6865895Syz147064
6875895Syz147064 /*
6885895Syz147064 * Note that we do not need any locks to access this softmac pointer,
6895895Syz147064 * as softmac_destroy() will wait until this function is called.
6905895Syz147064 */
6915895Syz147064 ASSERT(softmac != NULL);
6928275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG &&
6938275SEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt);
6945895Syz147064
6955895Syz147064 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) {
6965895Syz147064 mutex_enter(&softmac->smac_mutex);
6975895Syz147064 goto done;
6985895Syz147064 }
6995895Syz147064
7005895Syz147064 /*
7015895Syz147064 * Determine whether this legacy device support VLANs by opening
7025895Syz147064 * the style-2 device node (if it exists) and attaching to a VLAN
7035895Syz147064 * PPA (1000 + ppa).
7045895Syz147064 */
7055895Syz147064 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor);
7065895Syz147064 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
7075895Syz147064 if (err == 0) {
7085895Syz147064 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0)
7095895Syz147064 native_vlan = B_TRUE;
7105895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
7115895Syz147064 }
7125895Syz147064
7135895Syz147064 err = EINVAL;
7145895Syz147064 for (index = 0; index < 2; index++) {
7155895Syz147064 dl_info_ack_t dlia;
7165895Syz147064 dl_error_ack_t dlea;
7175895Syz147064 uint32_t notes;
7185895Syz147064 struct strioctl iocb;
7195895Syz147064 uint32_t margin;
7205895Syz147064 int rval;
7215895Syz147064
7225895Syz147064 if ((softmac_dev = softmac->smac_softmac[index]) == NULL)
7235895Syz147064 continue;
7245895Syz147064
7255895Syz147064 softmac->smac_dev = dev = softmac_dev->sd_dev;
7265895Syz147064 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh,
7275895Syz147064 li) != 0) {
7285895Syz147064 continue;
7295895Syz147064 }
7305895Syz147064
7315895Syz147064 /*
7325895Syz147064 * Pop all the intermediate modules in order to negotiate
7335895Syz147064 * capabilities correctly.
7345895Syz147064 */
7355895Syz147064 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
7365895Syz147064 ;
7375895Syz147064
7385895Syz147064 /* DLPI style-1 or DLPI style-2? */
7395895Syz147064 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) {
7405895Syz147064 if (rval == ENOTSUP) {
7415895Syz147064 cmn_err(CE_NOTE, "softmac: received "
7425895Syz147064 "DL_ERROR_ACK to DL_INFO_ACK; "
7435895Syz147064 "DLPI errno 0x%x, UNIX errno %d",
7445895Syz147064 dlea.dl_errno, dlea.dl_unix_errno);
7455895Syz147064 }
7465895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
7475895Syz147064 continue;
7485895Syz147064 }
7495895Syz147064
7505895Syz147064 /*
7515895Syz147064 * Currently only DL_ETHER has GLDv3 mac plugin support.
7525895Syz147064 * For media types that GLDv3 does not support, create a
7535895Syz147064 * link id for it.
7545895Syz147064 */
7555895Syz147064 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) {
7565895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
7575895Syz147064 err = 0;
7585895Syz147064 break;
7595895Syz147064 }
7605895Syz147064
7615895Syz147064 if ((dlia.dl_provider_style == DL_STYLE2) &&
7625895Syz147064 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) {
7635895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
7645895Syz147064 continue;
7655895Syz147064 }
7665895Syz147064
7675895Syz147064 if ((rval = dl_bind(lh, 0, NULL)) != 0) {
7685895Syz147064 if (rval == ENOTSUP) {
7695895Syz147064 cmn_err(CE_NOTE, "softmac: received "
7705895Syz147064 "DL_ERROR_ACK to DL_BIND_ACK; "
7715895Syz147064 "DLPI errno 0x%x, UNIX errno %d",
7725895Syz147064 dlea.dl_errno, dlea.dl_unix_errno);
7735895Syz147064 }
7745895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
7755895Syz147064 continue;
7765895Syz147064 }
7775895Syz147064
7785895Syz147064 /*
7795895Syz147064 * Call dl_info() after dl_bind() because some drivers only
7805895Syz147064 * provide correct information (e.g. MAC address) once bound.
7815895Syz147064 */
7825895Syz147064 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr);
7835895Syz147064 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr,
7845895Syz147064 &softmac->smac_addrlen, &dlea)) != 0) {
7855895Syz147064 if (rval == ENOTSUP) {
7865895Syz147064 cmn_err(CE_NOTE, "softmac: received "
7875895Syz147064 "DL_ERROR_ACK to DL_INFO_ACK; "
7885895Syz147064 "DLPI errno 0x%x, UNIX errno %d",
7895895Syz147064 dlea.dl_errno, dlea.dl_unix_errno);
7905895Syz147064 }
7915895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
7925895Syz147064 continue;
7935895Syz147064 }
7945895Syz147064
7955895Syz147064 softmac->smac_style = dlia.dl_provider_style;
7965895Syz147064 softmac->smac_saplen = ABS(dlia.dl_sap_length);
7975895Syz147064 softmac->smac_min_sdu = dlia.dl_min_sdu;
7985895Syz147064 softmac->smac_max_sdu = dlia.dl_max_sdu;
7995895Syz147064
8005895Syz147064 if ((softmac->smac_saplen != sizeof (uint16_t)) ||
8015895Syz147064 (softmac->smac_addrlen != ETHERADDRL) ||
8025895Syz147064 (dlia.dl_brdcst_addr_length != ETHERADDRL) ||
8035895Syz147064 (dlia.dl_brdcst_addr_offset == 0)) {
8045895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
8055895Syz147064 continue;
8065895Syz147064 }
8075895Syz147064
8085895Syz147064 /*
8095895Syz147064 * Check other DLPI capabilities. Note that this must be after
8105895Syz147064 * dl_bind() because some drivers return DL_ERROR_ACK if the
8115895Syz147064 * stream is not bound. It is also before mac_register(), so
8125895Syz147064 * we don't need any lock protection here.
8135895Syz147064 */
8145895Syz147064 softmac->smac_capab_flags =
8158275SEric Cheng (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY);
8165895Syz147064
8175895Syz147064 softmac->smac_no_capability_req = B_FALSE;
8185895Syz147064 if (softmac_fill_capab(lh, softmac) != 0)
8195895Syz147064 softmac->smac_no_capability_req = B_TRUE;
8205895Syz147064
8215895Syz147064 /*
8225895Syz147064 * Check the margin of the underlying driver.
8235895Syz147064 */
8245895Syz147064 margin = 0;
8255895Syz147064 iocb.ic_cmd = DLIOCMARGININFO;
8265895Syz147064 iocb.ic_timout = INFTIM;
8275895Syz147064 iocb.ic_len = sizeof (margin);
8285895Syz147064 iocb.ic_dp = (char *)&margin;
8295895Syz147064 softmac->smac_margin = 0;
8305895Syz147064
8315895Syz147064 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred,
8325895Syz147064 &rval) == 0) {
8335895Syz147064 softmac->smac_margin = margin;
8345895Syz147064 }
8355895Syz147064
8365895Syz147064 /*
8375895Syz147064 * If the legacy driver doesn't support DLIOCMARGININFO, but
8385895Syz147064 * it can support native VLAN, correct its margin value to 4.
8395895Syz147064 */
8405895Syz147064 if (native_vlan) {
8415895Syz147064 if (softmac->smac_margin == 0)
8425895Syz147064 softmac->smac_margin = VLAN_TAGSZ;
8435895Syz147064 } else {
8445895Syz147064 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN;
8455895Syz147064 }
8465895Syz147064
8475895Syz147064 /*
8485895Syz147064 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP.
8495895Syz147064 */
8505895Syz147064 softmac->smac_notifications = 0;
8515895Syz147064 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN;
8525895Syz147064 switch (dl_notify(lh, ¬es, NULL)) {
8535895Syz147064 case 0:
8545895Syz147064 softmac->smac_notifications = notes;
8555895Syz147064 break;
8565895Syz147064 case ENOTSUP:
8575895Syz147064 break;
8585895Syz147064 default:
8595895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
8605895Syz147064 continue;
8615895Syz147064 }
8625895Syz147064
8635895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
8645895Syz147064 err = 0;
8655895Syz147064 break;
8665895Syz147064 }
8675895Syz147064 ldi_ident_release(li);
8685895Syz147064
8695895Syz147064 mutex_enter(&softmac->smac_mutex);
8705895Syz147064
8715895Syz147064 if (err != 0)
8725895Syz147064 goto done;
8735895Syz147064
8745895Syz147064 if (softmac->smac_media != DL_ETHER)
8755895Syz147064 softmac->smac_flags |= SOFTMAC_NOSUPP;
8765895Syz147064
8775895Syz147064 /*
8785895Syz147064 * Finally, we're ready to register ourselves with the MAC layer
8795895Syz147064 * interface; if this succeeds, we're all ready to start()
8805895Syz147064 */
8815895Syz147064 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
8825895Syz147064 mac_register_t *macp;
8835895Syz147064
8845895Syz147064 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
8855895Syz147064 err = ENOMEM;
8865895Syz147064 goto done;
8875895Syz147064 }
8885895Syz147064
8895895Syz147064 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
8905895Syz147064 macp->m_driver = softmac;
8915895Syz147064 macp->m_dip = softmac_dip;
8925895Syz147064
8935895Syz147064 macp->m_margin = softmac->smac_margin;
8945895Syz147064 macp->m_src_addr = softmac->smac_unicst_addr;
8955895Syz147064 macp->m_min_sdu = softmac->smac_min_sdu;
8965895Syz147064 macp->m_max_sdu = softmac->smac_max_sdu;
8975895Syz147064 macp->m_callbacks = &softmac_m_callbacks;
8985895Syz147064 macp->m_instance = (uint_t)-1;
8995895Syz147064
9005895Syz147064 err = mac_register(macp, &softmac->smac_mh);
9015895Syz147064 mac_free(macp);
9025895Syz147064 if (err != 0) {
9035895Syz147064 cmn_err(CE_WARN, "mac_register failed for %s",
9045895Syz147064 softmac->smac_devname);
9055895Syz147064 goto done;
9065895Syz147064 }
9075895Syz147064 }
9088275SEric Cheng mutex_exit(&softmac->smac_mutex);
9095895Syz147064
9105895Syz147064 /*
9115895Syz147064 * Try to create the datalink for this softmac.
9125895Syz147064 */
9135895Syz147064 if ((err = softmac_create_datalink(softmac)) != 0) {
9149073SCathy.Zhou@Sun.COM if (!(softmac->smac_flags & SOFTMAC_NOSUPP))
9155895Syz147064 (void) mac_unregister(softmac->smac_mh);
9169073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_mutex);
9179073SCathy.Zhou@Sun.COM softmac->smac_mh = NULL;
9189073SCathy.Zhou@Sun.COM goto done;
9195895Syz147064 }
9208275SEric Cheng /*
9218275SEric Cheng * If succeed, create the thread which handles the DL_NOTIFY_IND from
9228275SEric Cheng * the lower stream.
9238275SEric Cheng */
9249073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_mutex);
9258275SEric Cheng if (softmac->smac_mh != NULL) {
9268275SEric Cheng softmac->smac_notify_thread = thread_create(NULL, 0,
9278275SEric Cheng softmac_notify_thread, softmac, 0, &p0,
9288275SEric Cheng TS_RUN, minclsyspri);
9298275SEric Cheng }
9305895Syz147064
9315895Syz147064 done:
9328275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG &&
9338275SEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt);
9348275SEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE;
9355895Syz147064 softmac->smac_attacherr = err;
9365895Syz147064 cv_broadcast(&softmac->smac_cv);
9375895Syz147064 mutex_exit(&softmac->smac_mutex);
9385895Syz147064 }
9395895Syz147064
9405895Syz147064 int
softmac_destroy(dev_info_t * dip,dev_t dev)9415895Syz147064 softmac_destroy(dev_info_t *dip, dev_t dev)
9425895Syz147064 {
9435895Syz147064 char devname[MAXNAMELEN];
9445895Syz147064 softmac_t *softmac;
9455895Syz147064 softmac_dev_t *softmac_dev;
9465895Syz147064 int index;
9475895Syz147064 int ppa, err;
9485895Syz147064 datalink_id_t linkid;
9498275SEric Cheng mac_handle_t smac_mh;
9508275SEric Cheng uint32_t smac_flags;
9515895Syz147064
95210654SGarrett.Damore@Sun.COM if (GLDV3_DRV(ddi_driver_major(dip))) {
95310654SGarrett.Damore@Sun.COM minor_t minor = getminor(dev);
95410654SGarrett.Damore@Sun.COM /*
95510654SGarrett.Damore@Sun.COM * For an explanation of this logic, see the
95610654SGarrett.Damore@Sun.COM * equivalent code in softmac_create.
95710654SGarrett.Damore@Sun.COM */
95810654SGarrett.Damore@Sun.COM if ((strcmp(ddi_driver_name(dip), "clone") == 0) ||
95910654SGarrett.Damore@Sun.COM (getmajor(dev) == ddi_name_to_major("clone")) ||
96010654SGarrett.Damore@Sun.COM (minor == 0)) {
96110654SGarrett.Damore@Sun.COM return (0);
96210654SGarrett.Damore@Sun.COM }
96310654SGarrett.Damore@Sun.COM if (minor >= DLS_MAX_MINOR) {
96410654SGarrett.Damore@Sun.COM return (ENOTSUP);
96510654SGarrett.Damore@Sun.COM }
96610654SGarrett.Damore@Sun.COM ppa = DLS_MINOR2INST(minor);
96710654SGarrett.Damore@Sun.COM } else {
96810654SGarrett.Damore@Sun.COM ppa = ddi_get_instance(dip);
96910654SGarrett.Damore@Sun.COM }
97010654SGarrett.Damore@Sun.COM
9715895Syz147064 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa);
9725895Syz147064
9738275SEric Cheng /*
9748275SEric Cheng * We are called only from the predetach entry point. The DACF
9758275SEric Cheng * framework ensures there can't be a concurrent postattach call
9768275SEric Cheng * for the same softmac. The softmac found out from the modhash
9778275SEric Cheng * below can't vanish beneath us since this is the only place where
9788275SEric Cheng * it is deleted.
9798275SEric Cheng */
9805895Syz147064 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
9815895Syz147064 (mod_hash_val_t *)&softmac);
9825895Syz147064 ASSERT(err == 0);
9835895Syz147064
9845895Syz147064 mutex_enter(&softmac->smac_mutex);
9858275SEric Cheng SOFTMAC_STATE_VERIFY(softmac);
9865895Syz147064
9875895Syz147064 /*
9885895Syz147064 * Fail the predetach routine if this softmac is in-use.
9898275SEric Cheng * Make sure these downcalls into softmac_create or softmac_destroy
9908275SEric Cheng * don't cv_wait on any devfs related condition. Thus softmac_destroy
9918275SEric Cheng * returns EBUSY if the asynchronous thread started in softmac_create
9928275SEric Cheng * hasn't finished
9935895Syz147064 */
9948275SEric Cheng if ((softmac->smac_hold_cnt != 0) ||
9958275SEric Cheng (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) {
9965895Syz147064 softmac->smac_attached_left = softmac->smac_attachok_cnt;
9975895Syz147064 mutex_exit(&softmac->smac_mutex);
9985895Syz147064 return (EBUSY);
9995895Syz147064 }
10005895Syz147064
10015895Syz147064 /*
10025895Syz147064 * Even if the predetach of one minor node has already failed
10035895Syz147064 * (smac_attached_left is not 0), the DACF framework will continue
10045895Syz147064 * to call the predetach routines of the other minor nodes,
10055895Syz147064 * so we fail these calls here.
10065895Syz147064 */
10075895Syz147064 if (softmac->smac_attached_left != 0) {
10085895Syz147064 mutex_exit(&softmac->smac_mutex);
10095895Syz147064 return (EBUSY);
10105895Syz147064 }
10115895Syz147064
10128275SEric Cheng smac_mh = softmac->smac_mh;
10138275SEric Cheng smac_flags = softmac->smac_flags;
10148275SEric Cheng softmac->smac_state = SOFTMAC_DETACH_INPROG;
10158275SEric Cheng mutex_exit(&softmac->smac_mutex);
10165895Syz147064
10178275SEric Cheng if (smac_mh != NULL) {
10188275SEric Cheng /*
10198275SEric Cheng * This is the first minor node that is being detached for this
10208275SEric Cheng * softmac.
10218275SEric Cheng */
10228275SEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt);
10238275SEric Cheng if (!(smac_flags & SOFTMAC_NOSUPP)) {
10248275SEric Cheng if ((err = dls_devnet_destroy(smac_mh, &linkid,
10258275SEric Cheng B_FALSE)) != 0) {
10268275SEric Cheng goto error;
10275895Syz147064 }
10285895Syz147064 }
10295895Syz147064 /*
10305895Syz147064 * If softmac_mac_register() succeeds in registering the mac
10315895Syz147064 * of the legacy device, unregister it.
10325895Syz147064 */
10338275SEric Cheng if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) {
10348275SEric Cheng if ((err = mac_disable_nowait(smac_mh)) != 0) {
103510616SSebastien.Roy@Sun.COM (void) dls_devnet_create(smac_mh, linkid,
103610616SSebastien.Roy@Sun.COM crgetzoneid(CRED()));
10378275SEric Cheng goto error;
10385895Syz147064 }
10398275SEric Cheng /*
10408275SEric Cheng * Ask softmac_notify_thread to quit, and wait for
10418275SEric Cheng * that to be done.
10428275SEric Cheng */
10438275SEric Cheng mutex_enter(&softmac->smac_mutex);
10448275SEric Cheng softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT;
10458275SEric Cheng cv_broadcast(&softmac->smac_cv);
10468275SEric Cheng while (softmac->smac_notify_thread != NULL) {
10478275SEric Cheng cv_wait(&softmac->smac_cv,
10488275SEric Cheng &softmac->smac_mutex);
10498275SEric Cheng }
10508275SEric Cheng mutex_exit(&softmac->smac_mutex);
10518275SEric Cheng VERIFY(mac_unregister(smac_mh) == 0);
10525895Syz147064 }
10535895Syz147064 softmac->smac_mh = NULL;
10545895Syz147064 }
10558275SEric Cheng
10568275SEric Cheng /*
10578275SEric Cheng * Free softmac_dev
10588275SEric Cheng */
10598275SEric Cheng rw_enter(&softmac_hash_lock, RW_WRITER);
10608275SEric Cheng mutex_enter(&softmac->smac_mutex);
10615895Syz147064
10628275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG &&
10638275SEric Cheng softmac->smac_attachok_cnt != 0);
10648275SEric Cheng softmac->smac_mh = NULL;
10658275SEric Cheng index = (getmajor(dev) == ddi_name_to_major("clone"));
10668275SEric Cheng softmac_dev = softmac->smac_softmac[index];
10678275SEric Cheng ASSERT(softmac_dev != NULL);
10688275SEric Cheng softmac->smac_softmac[index] = NULL;
10698275SEric Cheng kmem_free(softmac_dev, sizeof (softmac_dev_t));
10705895Syz147064
10718275SEric Cheng if (--softmac->smac_attachok_cnt == 0) {
10728275SEric Cheng mod_hash_val_t hashval;
10735895Syz147064
10748275SEric Cheng softmac->smac_state = SOFTMAC_UNINIT;
10758275SEric Cheng if (softmac->smac_hold_cnt != 0) {
10768275SEric Cheng /*
10778275SEric Cheng * Someone did a softmac_hold_device while we dropped
10788275SEric Cheng * the locks. Leave the softmac itself intact which
10798275SEric Cheng * will be reused by the reattach
10808275SEric Cheng */
10815895Syz147064 mutex_exit(&softmac->smac_mutex);
10825895Syz147064 rw_exit(&softmac_hash_lock);
10835895Syz147064 return (0);
10845895Syz147064 }
10858275SEric Cheng err = mod_hash_remove(softmac_hash,
10868275SEric Cheng (mod_hash_key_t)devname,
10878275SEric Cheng (mod_hash_val_t *)&hashval);
10888275SEric Cheng ASSERT(err == 0);
10898275SEric Cheng
10908275SEric Cheng mutex_exit(&softmac->smac_mutex);
10918275SEric Cheng rw_exit(&softmac_hash_lock);
10929073SCathy.Zhou@Sun.COM ASSERT(softmac->smac_fp_disable_clients == 0);
10939073SCathy.Zhou@Sun.COM softmac->smac_fastpath_admin_disabled = B_FALSE;
10949073SCathy.Zhou@Sun.COM kmem_cache_free(softmac_cachep, softmac);
10958275SEric Cheng return (0);
10965895Syz147064 }
10975895Syz147064 mutex_exit(&softmac->smac_mutex);
10985895Syz147064 rw_exit(&softmac_hash_lock);
10998275SEric Cheng return (0);
11008275SEric Cheng
11018275SEric Cheng error:
11028275SEric Cheng mutex_enter(&softmac->smac_mutex);
11038275SEric Cheng softmac->smac_attached_left = softmac->smac_attachok_cnt;
11048275SEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE;
11058275SEric Cheng cv_broadcast(&softmac->smac_cv);
11068275SEric Cheng mutex_exit(&softmac->smac_mutex);
11075895Syz147064 return (err);
11085895Syz147064 }
11095895Syz147064
11105895Syz147064 /*
11115895Syz147064 * This function is called as the result of a newly started dlmgmtd daemon.
11125895Syz147064 *
11135895Syz147064 * We walk through every softmac that was created but failed to notify
11145895Syz147064 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs
11155895Syz147064 * when softmacs are created before dlmgmtd is ready. For example, during
11165895Syz147064 * diskless boot, a network device is used (and therefore attached) before
11175895Syz147064 * the datalink-management service starts dlmgmtd.
11185895Syz147064 */
11195895Syz147064 /* ARGSUSED */
11205895Syz147064 static uint_t
softmac_mac_recreate(mod_hash_key_t key,mod_hash_val_t * val,void * arg)11215895Syz147064 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
11225895Syz147064 {
11235895Syz147064 softmac_t *softmac = (softmac_t *)val;
11245895Syz147064 datalink_id_t linkid;
11255895Syz147064 int err;
11268275SEric Cheng softmac_walk_t *smwp = arg;
11275895Syz147064
11285895Syz147064 /*
11298275SEric Cheng * The framework itself must not hold any locks across calls to the
11308275SEric Cheng * mac perimeter. Thus this function does not call any framework
11318275SEric Cheng * function that needs to grab the mac perimeter.
11325895Syz147064 */
11338275SEric Cheng ASSERT(RW_READ_HELD(&softmac_hash_lock));
11348275SEric Cheng
11358275SEric Cheng smwp->smw_retry = B_FALSE;
11365895Syz147064 mutex_enter(&softmac->smac_mutex);
11378275SEric Cheng SOFTMAC_STATE_VERIFY(softmac);
11388275SEric Cheng if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) {
11398275SEric Cheng /*
11408275SEric Cheng * Wait till softmac_create or softmac_mac_register finishes
11418275SEric Cheng * Hold the softmac to ensure it stays around. The wait itself
11428275SEric Cheng * is done in the caller, since we need to drop all locks
11438275SEric Cheng * including the mod hash's internal lock before calling
11448275SEric Cheng * cv_wait.
11458275SEric Cheng */
11468275SEric Cheng smwp->smw_retry = B_TRUE;
11478275SEric Cheng smwp->smw_softmac = softmac;
11488275SEric Cheng softmac->smac_hold_cnt++;
11498275SEric Cheng return (MH_WALK_TERMINATE);
11508275SEric Cheng }
11515895Syz147064
11528275SEric Cheng if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) ||
11535895Syz147064 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) {
11545895Syz147064 mutex_exit(&softmac->smac_mutex);
11555895Syz147064 return (MH_WALK_CONTINUE);
11565895Syz147064 }
11575895Syz147064
11588833SVenu.Iyer@Sun.COM /*
11598833SVenu.Iyer@Sun.COM * Bumping up the smac_hold_cnt allows us to drop the lock. It also
11608833SVenu.Iyer@Sun.COM * makes softmac_destroy() return failure on an attempted device detach.
11618833SVenu.Iyer@Sun.COM * We don't want to hold the lock across calls to other subsystems
11628833SVenu.Iyer@Sun.COM * like kstats, which will happen in the call to dls_devnet_recreate
11638833SVenu.Iyer@Sun.COM */
11648833SVenu.Iyer@Sun.COM softmac->smac_hold_cnt++;
11658833SVenu.Iyer@Sun.COM mutex_exit(&softmac->smac_mutex);
11668833SVenu.Iyer@Sun.COM
11675895Syz147064 if (dls_mgmt_create(softmac->smac_devname,
11685895Syz147064 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1),
11695895Syz147064 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) {
11708833SVenu.Iyer@Sun.COM softmac_rele_device((dls_dev_handle_t)softmac);
11715895Syz147064 return (MH_WALK_CONTINUE);
11725895Syz147064 }
11735895Syz147064
11745895Syz147064 if ((err = softmac_update_info(softmac, &linkid)) != 0) {
11755895Syz147064 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s "
11765895Syz147064 "failed (%d)", softmac->smac_devname, err);
11778833SVenu.Iyer@Sun.COM softmac_rele_device((dls_dev_handle_t)softmac);
11785895Syz147064 return (MH_WALK_CONTINUE);
11795895Syz147064 }
11805895Syz147064
11815895Syz147064 /*
11825895Syz147064 * Create a link for this MAC. The link name will be the same
11835895Syz147064 * as the MAC name.
11845895Syz147064 */
11855895Syz147064 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) {
11865895Syz147064 err = dls_devnet_recreate(softmac->smac_mh, linkid);
11875895Syz147064 if (err != 0) {
11885895Syz147064 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for "
11895895Syz147064 "%s (linkid %d) failed (%d)",
11905895Syz147064 softmac->smac_devname, linkid, err);
11915895Syz147064 }
11925895Syz147064 }
11935895Syz147064
11948833SVenu.Iyer@Sun.COM mutex_enter(&softmac->smac_mutex);
11955895Syz147064 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE;
11968833SVenu.Iyer@Sun.COM ASSERT(softmac->smac_hold_cnt != 0);
11978833SVenu.Iyer@Sun.COM softmac->smac_hold_cnt--;
11985895Syz147064 mutex_exit(&softmac->smac_mutex);
11995895Syz147064
12005895Syz147064 return (MH_WALK_CONTINUE);
12015895Syz147064 }
12025895Syz147064
12035895Syz147064 /*
12045895Syz147064 * See comments above softmac_mac_recreate().
12055895Syz147064 */
12065895Syz147064 void
softmac_recreate()12075895Syz147064 softmac_recreate()
12085895Syz147064 {
12098275SEric Cheng softmac_walk_t smw;
12108275SEric Cheng softmac_t *softmac;
12118275SEric Cheng
12125895Syz147064 /*
12135895Syz147064 * Walk through the softmac_hash table. Request to create the
12145895Syz147064 * [link name, linkid] mapping if we failed to do so.
12155895Syz147064 */
12168275SEric Cheng do {
12178275SEric Cheng smw.smw_retry = B_FALSE;
12188275SEric Cheng rw_enter(&softmac_hash_lock, RW_READER);
12198275SEric Cheng mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw);
12208275SEric Cheng rw_exit(&softmac_hash_lock);
12218275SEric Cheng if (smw.smw_retry) {
12228275SEric Cheng /*
12238275SEric Cheng * softmac_create or softmac_mac_register hasn't yet
12248275SEric Cheng * finished and the softmac is not yet in the
12258275SEric Cheng * SOFTMAC_ATTACH_DONE state.
12268275SEric Cheng */
12278275SEric Cheng softmac = smw.smw_softmac;
12288275SEric Cheng cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
12298275SEric Cheng softmac->smac_hold_cnt--;
12308275SEric Cheng mutex_exit(&softmac->smac_mutex);
12318275SEric Cheng }
12328275SEric Cheng } while (smw.smw_retry);
12335895Syz147064 }
12345895Syz147064
12355895Syz147064 static int
softmac_m_start(void * arg)12365895Syz147064 softmac_m_start(void *arg)
12375895Syz147064 {
12389073SCathy.Zhou@Sun.COM softmac_t *softmac = arg;
12399073SCathy.Zhou@Sun.COM softmac_lower_t *slp = softmac->smac_lower;
12409073SCathy.Zhou@Sun.COM int err;
12419073SCathy.Zhou@Sun.COM
12429073SCathy.Zhou@Sun.COM ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
12439073SCathy.Zhou@Sun.COM /*
12449073SCathy.Zhou@Sun.COM * Bind to SAP 2 on token ring, 0 on other interface types.
12459073SCathy.Zhou@Sun.COM * (SAP 0 has special significance on token ring).
12469073SCathy.Zhou@Sun.COM * Note that the receive-side packets could come anytime after bind.
12479073SCathy.Zhou@Sun.COM */
12489073SCathy.Zhou@Sun.COM err = softmac_send_bind_req(slp, softmac->smac_media == DL_TPR ? 2 : 0);
12499073SCathy.Zhou@Sun.COM if (err != 0)
12509073SCathy.Zhou@Sun.COM return (err);
12519073SCathy.Zhou@Sun.COM
12529073SCathy.Zhou@Sun.COM /*
12539073SCathy.Zhou@Sun.COM * Put the lower stream to the DL_PROMISC_SAP mode in order to receive
12549073SCathy.Zhou@Sun.COM * all packets of interest.
12559073SCathy.Zhou@Sun.COM *
12569073SCathy.Zhou@Sun.COM * some driver (e.g. the old legacy eri driver) incorrectly passes up
12579073SCathy.Zhou@Sun.COM * packets to DL_PROMISC_SAP stream when the lower stream is not bound,
12589073SCathy.Zhou@Sun.COM * so that we send DL_PROMISON_REQ after DL_BIND_REQ.
12599073SCathy.Zhou@Sun.COM */
12609073SCathy.Zhou@Sun.COM err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE);
12619073SCathy.Zhou@Sun.COM if (err != 0) {
12629073SCathy.Zhou@Sun.COM (void) softmac_send_unbind_req(slp);
12639073SCathy.Zhou@Sun.COM return (err);
12649073SCathy.Zhou@Sun.COM }
12659073SCathy.Zhou@Sun.COM
12669073SCathy.Zhou@Sun.COM /*
12679073SCathy.Zhou@Sun.COM * Enable capabilities the underlying driver claims to support.
12689073SCathy.Zhou@Sun.COM * Some driver requires this being called after the stream is bound.
12699073SCathy.Zhou@Sun.COM */
12709073SCathy.Zhou@Sun.COM if ((err = softmac_capab_enable(slp)) != 0) {
12719073SCathy.Zhou@Sun.COM (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE);
12729073SCathy.Zhou@Sun.COM (void) softmac_send_unbind_req(slp);
12739073SCathy.Zhou@Sun.COM }
12749073SCathy.Zhou@Sun.COM
12759073SCathy.Zhou@Sun.COM return (err);
12765895Syz147064 }
12775895Syz147064
12785895Syz147064 /* ARGSUSED */
12795895Syz147064 static void
softmac_m_stop(void * arg)12805895Syz147064 softmac_m_stop(void *arg)
12815895Syz147064 {
12829073SCathy.Zhou@Sun.COM softmac_t *softmac = arg;
12839073SCathy.Zhou@Sun.COM softmac_lower_t *slp = softmac->smac_lower;
12849073SCathy.Zhou@Sun.COM
12859073SCathy.Zhou@Sun.COM ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
12869073SCathy.Zhou@Sun.COM
12879073SCathy.Zhou@Sun.COM /*
12889073SCathy.Zhou@Sun.COM * It is not needed to reset zerocopy, MDT or HCKSUM capabilities.
12899073SCathy.Zhou@Sun.COM */
12909073SCathy.Zhou@Sun.COM (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE);
12919073SCathy.Zhou@Sun.COM (void) softmac_send_unbind_req(slp);
12925895Syz147064 }
12935895Syz147064
12945895Syz147064 /*
12959073SCathy.Zhou@Sun.COM * Set up the lower stream above the legacy device. There are two different
12969073SCathy.Zhou@Sun.COM * type of lower streams:
12979073SCathy.Zhou@Sun.COM *
12989073SCathy.Zhou@Sun.COM * - Shared lower-stream
12999073SCathy.Zhou@Sun.COM *
13009073SCathy.Zhou@Sun.COM * Shared by all GLDv3 MAC clients. Put the lower stream to the DLIOCRAW
13019073SCathy.Zhou@Sun.COM * mode to send and receive the raw data. Further, put the lower stream into
13025895Syz147064 * DL_PROMISC_SAP mode to receive all packets of interest.
13039073SCathy.Zhou@Sun.COM *
13049073SCathy.Zhou@Sun.COM * - Dedicated lower-stream
13059073SCathy.Zhou@Sun.COM *
13069073SCathy.Zhou@Sun.COM * The lower-stream which is dedicated to upper IP/ARP stream. This is used
13079073SCathy.Zhou@Sun.COM * as fast-path for IP. In this case, the second argument is the pointer to
13089073SCathy.Zhou@Sun.COM * the softmac upper-stream.
13095895Syz147064 */
13109073SCathy.Zhou@Sun.COM int
softmac_lower_setup(softmac_t * softmac,softmac_upper_t * sup,softmac_lower_t ** slpp)13119073SCathy.Zhou@Sun.COM softmac_lower_setup(softmac_t *softmac, softmac_upper_t *sup,
13129073SCathy.Zhou@Sun.COM softmac_lower_t **slpp)
13135895Syz147064 {
13145895Syz147064 ldi_ident_t li;
13155895Syz147064 dev_t dev;
13165895Syz147064 ldi_handle_t lh = NULL;
13175895Syz147064 softmac_lower_t *slp = NULL;
13185895Syz147064 smac_ioc_start_t start_arg;
13195895Syz147064 struct strioctl strioc;
13205895Syz147064 uint32_t notifications;
13215895Syz147064 int err, rval;
13225895Syz147064
13235895Syz147064 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0)
13245895Syz147064 return (err);
13255895Syz147064
13269073SCathy.Zhou@Sun.COM /*
13279073SCathy.Zhou@Sun.COM * The GLDv3 framework makes sure that mac_unregister(), mac_open(),
13289073SCathy.Zhou@Sun.COM * and mac_close() cannot be called at the same time. So we don't
13299073SCathy.Zhou@Sun.COM * need any protection to access softmac here.
13309073SCathy.Zhou@Sun.COM */
13315895Syz147064 dev = softmac->smac_dev;
13329073SCathy.Zhou@Sun.COM
13335895Syz147064 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li);
13345895Syz147064 ldi_ident_release(li);
13355895Syz147064 if (err != 0)
13365895Syz147064 goto done;
13375895Syz147064
13385895Syz147064 /*
13395895Syz147064 * Pop all the intermediate modules. The autopushed modules will
13405895Syz147064 * be pushed when the softmac node is opened.
13415895Syz147064 */
13425895Syz147064 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0)
13435895Syz147064 ;
13445895Syz147064
13455895Syz147064 if ((softmac->smac_style == DL_STYLE2) &&
13465895Syz147064 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) {
13475895Syz147064 goto done;
13485895Syz147064 }
13495895Syz147064
13505895Syz147064 /*
13519073SCathy.Zhou@Sun.COM * If this is the shared-lower-stream, put the lower stream to
13529073SCathy.Zhou@Sun.COM * the DLIOCRAW mode to send/receive raw data.
13535895Syz147064 */
13549073SCathy.Zhou@Sun.COM if ((sup == NULL) && (err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL,
13559073SCathy.Zhou@Sun.COM kcred, &rval)) != 0) {
13565895Syz147064 goto done;
13579073SCathy.Zhou@Sun.COM }
13585895Syz147064
13595895Syz147064 /*
13605895Syz147064 * Then push the softmac shim layer atop the lower stream.
13615895Syz147064 */
13625895Syz147064 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL,
13635895Syz147064 kcred, &rval)) != 0) {
13645895Syz147064 goto done;
13655895Syz147064 }
13665895Syz147064
13675895Syz147064 /*
13685895Syz147064 * Send the ioctl to get the slp pointer.
13695895Syz147064 */
13705895Syz147064 strioc.ic_cmd = SMAC_IOC_START;
13715895Syz147064 strioc.ic_timout = INFTIM;
13725895Syz147064 strioc.ic_len = sizeof (start_arg);
13735895Syz147064 strioc.ic_dp = (char *)&start_arg;
13745895Syz147064
13755895Syz147064 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL,
13765895Syz147064 kcred, &rval)) != 0) {
13775895Syz147064 goto done;
13785895Syz147064 }
13795895Syz147064 slp = start_arg.si_slp;
13809073SCathy.Zhou@Sun.COM slp->sl_sup = sup;
13815895Syz147064 slp->sl_lh = lh;
13825895Syz147064 slp->sl_softmac = softmac;
13835895Syz147064 *slpp = slp;
13845895Syz147064
13859073SCathy.Zhou@Sun.COM if (sup != NULL) {
13869073SCathy.Zhou@Sun.COM slp->sl_rxinfo = &sup->su_rxinfo;
13879073SCathy.Zhou@Sun.COM } else {
13889073SCathy.Zhou@Sun.COM /*
13899073SCathy.Zhou@Sun.COM * Send DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND.
13909073SCathy.Zhou@Sun.COM * We don't have to wait for the ack.
13919073SCathy.Zhou@Sun.COM */
13929073SCathy.Zhou@Sun.COM notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP |
13939073SCathy.Zhou@Sun.COM DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS |
13949073SCathy.Zhou@Sun.COM DL_NOTE_PROMISC_OFF_PHYS;
13955895Syz147064
13969073SCathy.Zhou@Sun.COM (void) softmac_send_notify_req(slp,
13979073SCathy.Zhou@Sun.COM (notifications & softmac->smac_notifications));
13989073SCathy.Zhou@Sun.COM }
13995895Syz147064
14005895Syz147064 done:
14015895Syz147064 if (err != 0)
14025895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred);
14035895Syz147064 return (err);
14045895Syz147064 }
14055895Syz147064
14065895Syz147064 static int
softmac_m_open(void * arg)14075895Syz147064 softmac_m_open(void *arg)
14085895Syz147064 {
14095895Syz147064 softmac_t *softmac = arg;
14105895Syz147064 softmac_lower_t *slp;
14115895Syz147064 int err;
14125895Syz147064
14138275SEric Cheng ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
14145895Syz147064
14159073SCathy.Zhou@Sun.COM if ((err = softmac_lower_setup(softmac, NULL, &slp)) != 0)
14165895Syz147064 return (err);
14175895Syz147064
14185895Syz147064 softmac->smac_lower = slp;
14195895Syz147064 return (0);
14205895Syz147064 }
14215895Syz147064
14225895Syz147064 static void
softmac_m_close(void * arg)14235895Syz147064 softmac_m_close(void *arg)
14245895Syz147064 {
14255895Syz147064 softmac_t *softmac = arg;
14265895Syz147064 softmac_lower_t *slp;
14275895Syz147064
14288275SEric Cheng ASSERT(MAC_PERIM_HELD(softmac->smac_mh));
14295895Syz147064 slp = softmac->smac_lower;
14305895Syz147064 ASSERT(slp != NULL);
14315895Syz147064
14325895Syz147064 /*
14335895Syz147064 * Note that slp is destroyed when lh is closed.
14345895Syz147064 */
14355895Syz147064 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred);
14365895Syz147064 softmac->smac_lower = NULL;
14375895Syz147064 }
14385895Syz147064
14399073SCathy.Zhou@Sun.COM /*
14409073SCathy.Zhou@Sun.COM * Softmac supports two priviate link properteis:
14419073SCathy.Zhou@Sun.COM *
14429073SCathy.Zhou@Sun.COM * - "_fastpath"
14439073SCathy.Zhou@Sun.COM *
14449073SCathy.Zhou@Sun.COM * This is a read-only link property which points out the current data-path
14459073SCathy.Zhou@Sun.COM * model of the given legacy link. The possible values are "disabled" and
14469073SCathy.Zhou@Sun.COM * "enabled".
14479073SCathy.Zhou@Sun.COM *
14489073SCathy.Zhou@Sun.COM * - "_disable_fastpath"
14499073SCathy.Zhou@Sun.COM *
14509073SCathy.Zhou@Sun.COM * This is a read-write link property which can be used to disable or enable
14519073SCathy.Zhou@Sun.COM * the fast-path of the given legacy link. The possible values are "true"
14529073SCathy.Zhou@Sun.COM * and "false". Note that even when "_disable_fastpath" is set to be
14539073SCathy.Zhou@Sun.COM * "false", the fast-path may still not be enabled since there may be
14549073SCathy.Zhou@Sun.COM * other mac cleints that request the fast-path to be disabled.
14559073SCathy.Zhou@Sun.COM */
14569073SCathy.Zhou@Sun.COM /* ARGSUSED */
14579073SCathy.Zhou@Sun.COM static int
softmac_m_setprop(void * arg,const char * name,mac_prop_id_t id,uint_t valsize,const void * val)14589073SCathy.Zhou@Sun.COM softmac_m_setprop(void *arg, const char *name, mac_prop_id_t id,
14599073SCathy.Zhou@Sun.COM uint_t valsize, const void *val)
14609073SCathy.Zhou@Sun.COM {
14619073SCathy.Zhou@Sun.COM softmac_t *softmac = arg;
14629073SCathy.Zhou@Sun.COM
14639073SCathy.Zhou@Sun.COM if (id != MAC_PROP_PRIVATE || strcmp(name, "_disable_fastpath") != 0)
14649073SCathy.Zhou@Sun.COM return (ENOTSUP);
14659073SCathy.Zhou@Sun.COM
14669073SCathy.Zhou@Sun.COM if (strcmp(val, "true") == 0)
14679073SCathy.Zhou@Sun.COM return (softmac_datapath_switch(softmac, B_TRUE, B_TRUE));
14689073SCathy.Zhou@Sun.COM else if (strcmp(val, "false") == 0)
14699073SCathy.Zhou@Sun.COM return (softmac_datapath_switch(softmac, B_FALSE, B_TRUE));
14709073SCathy.Zhou@Sun.COM else
14719073SCathy.Zhou@Sun.COM return (EINVAL);
14729073SCathy.Zhou@Sun.COM }
14739073SCathy.Zhou@Sun.COM
14749073SCathy.Zhou@Sun.COM static int
softmac_m_getprop(void * arg,const char * name,mac_prop_id_t id,uint_t valsize,void * val)1475*11878SVenu.Iyer@Sun.COM softmac_m_getprop(void *arg, const char *name, mac_prop_id_t id,
1476*11878SVenu.Iyer@Sun.COM uint_t valsize, void *val)
14779073SCathy.Zhou@Sun.COM {
14789073SCathy.Zhou@Sun.COM softmac_t *softmac = arg;
14799073SCathy.Zhou@Sun.COM char *fpstr;
14809073SCathy.Zhou@Sun.COM
14819073SCathy.Zhou@Sun.COM if (id != MAC_PROP_PRIVATE)
14829073SCathy.Zhou@Sun.COM return (ENOTSUP);
14839073SCathy.Zhou@Sun.COM
14849073SCathy.Zhou@Sun.COM if (strcmp(name, "_fastpath") == 0) {
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) {
1490*11878SVenu.Iyer@Sun.COM fpstr = softmac->smac_fastpath_admin_disabled ?
1491*11878SVenu.Iyer@Sun.COM "true" : "false";
1492*11878SVenu.Iyer@Sun.COM } else if (strcmp(name, "_softmac") == 0) {
1493*11878SVenu.Iyer@Sun.COM fpstr = "true";
14949073SCathy.Zhou@Sun.COM } else {
14959073SCathy.Zhou@Sun.COM return (ENOTSUP);
14969073SCathy.Zhou@Sun.COM }
14979073SCathy.Zhou@Sun.COM
14989073SCathy.Zhou@Sun.COM return (strlcpy(val, fpstr, valsize) >= valsize ? EINVAL : 0);
14999073SCathy.Zhou@Sun.COM }
15009073SCathy.Zhou@Sun.COM
1501*11878SVenu.Iyer@Sun.COM static void
softmac_m_propinfo(void * arg,const char * name,mac_prop_id_t id,mac_prop_info_handle_t prh)1502*11878SVenu.Iyer@Sun.COM softmac_m_propinfo(void *arg, const char *name, mac_prop_id_t id,
1503*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t prh)
1504*11878SVenu.Iyer@Sun.COM {
1505*11878SVenu.Iyer@Sun.COM _NOTE(ARGUNUSED(arg));
1506*11878SVenu.Iyer@Sun.COM
1507*11878SVenu.Iyer@Sun.COM if (id != MAC_PROP_PRIVATE)
1508*11878SVenu.Iyer@Sun.COM return;
1509*11878SVenu.Iyer@Sun.COM
1510*11878SVenu.Iyer@Sun.COM if (strcmp(name, "_fastpath") == 0) {
1511*11878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1512*11878SVenu.Iyer@Sun.COM } else if (strcmp(name, "_disable_fastpath") == 0) {
1513*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_str(prh, "false");
1514*11878SVenu.Iyer@Sun.COM }
1515*11878SVenu.Iyer@Sun.COM
1516*11878SVenu.Iyer@Sun.COM }
1517*11878SVenu.Iyer@Sun.COM
15185895Syz147064 int
softmac_hold_device(dev_t dev,dls_dev_handle_t * ddhp)15195895Syz147064 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp)
15205895Syz147064 {
15215895Syz147064 dev_info_t *dip;
15225895Syz147064 char devname[MAXNAMELEN];
15235895Syz147064 softmac_t *softmac;
152410986SSebastien.Roy@Sun.COM major_t major;
152510986SSebastien.Roy@Sun.COM int ppa, err = 0, inst;
152610654SGarrett.Damore@Sun.COM
152710986SSebastien.Roy@Sun.COM major = getmajor(dev);
152810986SSebastien.Roy@Sun.COM ppa = getminor(dev) - 1;
152910654SGarrett.Damore@Sun.COM
153010654SGarrett.Damore@Sun.COM /*
153110986SSebastien.Roy@Sun.COM * For GLDv3 devices, look up the device instance using getinfo(9e).
153210986SSebastien.Roy@Sun.COM * Otherwise, fall back to the old assumption that inst == ppa. The
153310986SSebastien.Roy@Sun.COM * GLDV3_DRV() macro depends on the driver module being loaded, hence
153410986SSebastien.Roy@Sun.COM * the call to ddi_hold_driver().
153510654SGarrett.Damore@Sun.COM */
153610986SSebastien.Roy@Sun.COM if (ddi_hold_driver(major) == NULL)
153710986SSebastien.Roy@Sun.COM return (ENXIO);
153810986SSebastien.Roy@Sun.COM if (GLDV3_DRV(major)) {
153910986SSebastien.Roy@Sun.COM if ((inst = dev_to_instance(dev)) < 0)
154010986SSebastien.Roy@Sun.COM err = ENOENT;
154110986SSebastien.Roy@Sun.COM } else {
154210986SSebastien.Roy@Sun.COM inst = ppa;
154310986SSebastien.Roy@Sun.COM }
154410986SSebastien.Roy@Sun.COM ddi_rele_driver(major);
154510986SSebastien.Roy@Sun.COM if (err != 0)
154610986SSebastien.Roy@Sun.COM return (err);
15475895Syz147064
15485895Syz147064 /*
154910986SSebastien.Roy@Sun.COM * First try to hold this device instance to force device to attach
155010986SSebastien.Roy@Sun.COM * and ensure that the softmac entry gets created in net_postattach().
15515895Syz147064 */
155210986SSebastien.Roy@Sun.COM if ((dip = ddi_hold_devi_by_instance(major, inst, 0)) == NULL)
15535895Syz147064 return (ENOENT);
15545895Syz147064
15555895Syz147064 /*
155610727Sgdamore@opensolaris.org * Exclude non-physical network device instances, for example, aggr0.
155710727Sgdamore@opensolaris.org * Note: this check *must* occur after the dip is held, or else
155810986SSebastien.Roy@Sun.COM * NETWORK_PHYSDRV might return false incorrectly. The
155910986SSebastien.Roy@Sun.COM * DN_NETWORK_PHYSDRIVER flag used by NETWORK_PHYSDRV() gets set if
156010986SSebastien.Roy@Sun.COM * ddi_create_minor_node() is called during the device's attach
156110986SSebastien.Roy@Sun.COM * phase.
156210727Sgdamore@opensolaris.org */
156310986SSebastien.Roy@Sun.COM if (!NETWORK_PHYSDRV(major)) {
156410727Sgdamore@opensolaris.org ddi_release_devi(dip);
156510727Sgdamore@opensolaris.org return (ENOENT);
156610727Sgdamore@opensolaris.org }
156710727Sgdamore@opensolaris.org
156810986SSebastien.Roy@Sun.COM /* Now wait for its softmac to be created. */
156910986SSebastien.Roy@Sun.COM (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_major_to_name(major),
157010986SSebastien.Roy@Sun.COM ppa);
15715895Syz147064 again:
15725895Syz147064 rw_enter(&softmac_hash_lock, RW_READER);
15735895Syz147064
15745895Syz147064 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname,
15755895Syz147064 (mod_hash_val_t *)&softmac) != 0) {
15765895Syz147064 /*
15775895Syz147064 * This is rare but possible. It could happen when pre-detach
15785895Syz147064 * routine of the device succeeds. But the softmac will then
15795895Syz147064 * be recreated when device fails to detach (as this device
15805895Syz147064 * is held).
15815895Syz147064 */
15828275SEric Cheng mutex_enter(&smac_global_lock);
15835895Syz147064 rw_exit(&softmac_hash_lock);
15848275SEric Cheng cv_wait(&smac_global_cv, &smac_global_lock);
15858275SEric Cheng mutex_exit(&smac_global_lock);
15865895Syz147064 goto again;
15875895Syz147064 }
15885895Syz147064
15895895Syz147064 /*
15905895Syz147064 * Bump smac_hold_cnt to prevent device detach.
15915895Syz147064 */
15925895Syz147064 mutex_enter(&softmac->smac_mutex);
15935895Syz147064 softmac->smac_hold_cnt++;
15945895Syz147064 rw_exit(&softmac_hash_lock);
15955895Syz147064
15965895Syz147064 /*
15975895Syz147064 * Wait till the device is fully attached.
15985895Syz147064 */
15998275SEric Cheng while (softmac->smac_state != SOFTMAC_ATTACH_DONE)
16005895Syz147064 cv_wait(&softmac->smac_cv, &softmac->smac_mutex);
16015895Syz147064
16028275SEric Cheng SOFTMAC_STATE_VERIFY(softmac);
16038275SEric Cheng
16045909Syz147064 if ((err = softmac->smac_attacherr) != 0)
16055909Syz147064 softmac->smac_hold_cnt--;
16065909Syz147064 else
16075895Syz147064 *ddhp = (dls_dev_handle_t)softmac;
16085895Syz147064 mutex_exit(&softmac->smac_mutex);
16095895Syz147064
16105909Syz147064 ddi_release_devi(dip);
16115895Syz147064 return (err);
16125895Syz147064 }
16135895Syz147064
16145895Syz147064 void
softmac_rele_device(dls_dev_handle_t ddh)16155895Syz147064 softmac_rele_device(dls_dev_handle_t ddh)
16165895Syz147064 {
16179073SCathy.Zhou@Sun.COM if (ddh != NULL)
16189073SCathy.Zhou@Sun.COM softmac_rele((softmac_t *)ddh);
16199073SCathy.Zhou@Sun.COM }
16209073SCathy.Zhou@Sun.COM
16219073SCathy.Zhou@Sun.COM int
softmac_hold(dev_t dev,softmac_t ** softmacp)16229073SCathy.Zhou@Sun.COM softmac_hold(dev_t dev, softmac_t **softmacp)
16239073SCathy.Zhou@Sun.COM {
16245895Syz147064 softmac_t *softmac;
16259073SCathy.Zhou@Sun.COM char *drv;
16269073SCathy.Zhou@Sun.COM mac_handle_t mh;
16279073SCathy.Zhou@Sun.COM char mac[MAXNAMELEN];
16289073SCathy.Zhou@Sun.COM int err;
16299073SCathy.Zhou@Sun.COM
16309073SCathy.Zhou@Sun.COM if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
16319073SCathy.Zhou@Sun.COM return (EINVAL);
16325895Syz147064
16339073SCathy.Zhou@Sun.COM (void) snprintf(mac, MAXNAMELEN, "%s%d", drv, getminor(dev) - 1);
16349073SCathy.Zhou@Sun.COM if ((err = mac_open(mac, &mh)) != 0)
16359073SCathy.Zhou@Sun.COM return (err);
16369073SCathy.Zhou@Sun.COM
16379073SCathy.Zhou@Sun.COM softmac = (softmac_t *)mac_driver(mh);
16385895Syz147064
16399073SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_mutex);
16409073SCathy.Zhou@Sun.COM softmac->smac_hold_cnt++;
16419073SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_mutex);
16429073SCathy.Zhou@Sun.COM mac_close(mh);
16439073SCathy.Zhou@Sun.COM *softmacp = softmac;
16449073SCathy.Zhou@Sun.COM return (0);
16459073SCathy.Zhou@Sun.COM }
16469073SCathy.Zhou@Sun.COM
16479073SCathy.Zhou@Sun.COM void
softmac_rele(softmac_t * softmac)16489073SCathy.Zhou@Sun.COM softmac_rele(softmac_t *softmac)
16499073SCathy.Zhou@Sun.COM {
16505895Syz147064 mutex_enter(&softmac->smac_mutex);
16515909Syz147064 softmac->smac_hold_cnt--;
16525895Syz147064 mutex_exit(&softmac->smac_mutex);
16535895Syz147064 }
1654