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> 47*8275SEric Cheng #include <sys/mac_provider.h> 48*8275SEric 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 58*8275SEric Cheng /* Used as a parameter to the mod hash walk of softmac structures */ 59*8275SEric Cheng typedef struct { 60*8275SEric Cheng softmac_t *smw_softmac; 61*8275SEric Cheng boolean_t smw_retry; 62*8275SEric Cheng } softmac_walk_t; 63*8275SEric 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; 69*8275SEric Cheng static kmutex_t smac_global_lock; 70*8275SEric Cheng static kcondvar_t smac_global_cv; 715895Syz147064 725895Syz147064 #define SOFTMAC_HASHSZ 64 735895Syz147064 747323SCathy.Zhou@Sun.COM static void softmac_create_task(void *); 757323SCathy.Zhou@Sun.COM static void softmac_mac_register(softmac_t *); 765895Syz147064 static int softmac_create_datalink(softmac_t *); 775895Syz147064 static int softmac_m_start(void *); 785895Syz147064 static void softmac_m_stop(void *); 795895Syz147064 static int softmac_m_open(void *); 805895Syz147064 static void softmac_m_close(void *); 815895Syz147064 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *); 825895Syz147064 835895Syz147064 #define SOFTMAC_M_CALLBACK_FLAGS \ 84*8275SEric Cheng (MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE) 855895Syz147064 865895Syz147064 static mac_callbacks_t softmac_m_callbacks = { 875895Syz147064 SOFTMAC_M_CALLBACK_FLAGS, 885895Syz147064 softmac_m_stat, 895895Syz147064 softmac_m_start, 905895Syz147064 softmac_m_stop, 915895Syz147064 softmac_m_promisc, 925895Syz147064 softmac_m_multicst, 935895Syz147064 softmac_m_unicst, 945895Syz147064 softmac_m_tx, 955895Syz147064 softmac_m_ioctl, 965895Syz147064 softmac_m_getcapab, 975895Syz147064 softmac_m_open, 985895Syz147064 softmac_m_close 995895Syz147064 }; 1005895Syz147064 1015895Syz147064 void 1025895Syz147064 softmac_init() 1035895Syz147064 { 1045895Syz147064 softmac_hash = mod_hash_create_extended("softmac_hash", 1055895Syz147064 SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 1065895Syz147064 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 1075895Syz147064 1085895Syz147064 rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL); 109*8275SEric Cheng mutex_init(&smac_global_lock, NULL, MUTEX_DRIVER, NULL); 110*8275SEric Cheng cv_init(&smac_global_cv, NULL, CV_DRIVER, NULL); 1115895Syz147064 } 1125895Syz147064 1135895Syz147064 void 1145895Syz147064 softmac_fini() 1155895Syz147064 { 1165895Syz147064 rw_destroy(&softmac_hash_lock); 1175895Syz147064 mod_hash_destroy_hash(softmac_hash); 118*8275SEric Cheng mutex_destroy(&smac_global_lock); 119*8275SEric Cheng cv_destroy(&smac_global_cv); 1205895Syz147064 } 1215895Syz147064 1225895Syz147064 /* ARGSUSED */ 1235895Syz147064 static uint_t 1245895Syz147064 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1255895Syz147064 { 1265895Syz147064 boolean_t *pexist = arg; 1275895Syz147064 1285895Syz147064 *pexist = B_TRUE; 1295895Syz147064 return (MH_WALK_TERMINATE); 1305895Syz147064 } 1315895Syz147064 1325895Syz147064 boolean_t 1335895Syz147064 softmac_busy() 1345895Syz147064 { 1355895Syz147064 boolean_t exist = B_FALSE; 1365895Syz147064 1375895Syz147064 rw_enter(&softmac_hash_lock, RW_READER); 1385895Syz147064 mod_hash_walk(softmac_hash, softmac_exist, &exist); 1395895Syz147064 rw_exit(&softmac_hash_lock); 1405895Syz147064 return (exist); 1415895Syz147064 } 1425895Syz147064 1435895Syz147064 /* 144*8275SEric Cheng * 145*8275SEric Cheng * softmac_create() is called for each minor node during the post-attach of 1465895Syz147064 * each DDI_NT_NET device instance. Note that it is possible that a device 1475895Syz147064 * instance has two minor nodes (DLPI style-1 and style-2), so that for that 1485895Syz147064 * specific device, softmac_create() could be called twice. 1495895Syz147064 * 1505895Syz147064 * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t 1515895Syz147064 * is created to track each minor node. 1525895Syz147064 * 1535895Syz147064 * For each minor node of a legacy device, a taskq is started to finish 1545895Syz147064 * softmac_mac_register(), which will finish the rest of work (see comments 1555895Syz147064 * above softmac_mac_register()). 156*8275SEric Cheng * 157*8275SEric Cheng * softmac state machine 158*8275SEric Cheng * -------------------------------------------------------------------------- 159*8275SEric Cheng * OLD STATE EVENT NEW STATE 160*8275SEric Cheng * -------------------------------------------------------------------------- 161*8275SEric Cheng * UNINIT attach of 1st minor node ATTACH_INPROG 162*8275SEric Cheng * okcnt = 0 net_postattach -> softmac_create okcnt = 1 163*8275SEric Cheng * 164*8275SEric Cheng * ATTACH_INPROG attach of 2nd minor node (GLDv3) ATTACH_DONE 165*8275SEric Cheng * okcnt = 1 net_postattach -> softmac_create okcnt = 2 166*8275SEric Cheng * 167*8275SEric Cheng * ATTACH_INPROG attach of 2nd minor node (legacy) ATTACH_INPROG 168*8275SEric Cheng * okcnt = 1 net_postattach -> softmac_create okcnt = 2 169*8275SEric Cheng * schedule softmac_mac_register 170*8275SEric Cheng * 171*8275SEric Cheng * ATTACH_INPROG legacy device node ATTACH_DONE 172*8275SEric Cheng * okcnt = 2 softmac_mac_register okcnt = 2 173*8275SEric Cheng * 174*8275SEric Cheng * ATTACH_DONE detach of 1st minor node DETACH_INPROG 175*8275SEric Cheng * okcnt = 2 (success) okcnt = 1 176*8275SEric Cheng * 177*8275SEric Cheng * DETACH_INPROG detach of 2nd minor node UNINIT (or free) 178*8275SEric Cheng * okcnt = 1 (success) okcnt = 0 179*8275SEric Cheng * 180*8275SEric Cheng * ATTACH_DONE detach failure state unchanged 181*8275SEric Cheng * DETACH_INPROG left = okcnt 182*8275SEric Cheng * 183*8275SEric Cheng * DETACH_INPROG reattach ATTACH_INPROG 184*8275SEric Cheng * okcnt = 0,1 net_postattach -> softmac_create 185*8275SEric Cheng * 186*8275SEric Cheng * ATTACH_DONE reattach ATTACH_DONE 187*8275SEric Cheng * left != 0 net_postattach -> softmac_create left = 0 188*8275SEric Cheng * 189*8275SEric Cheng * Abbreviation notes: 190*8275SEric Cheng * states have SOFTMAC_ prefix, 191*8275SEric Cheng * okcnt - softmac_attach_okcnt, 192*8275SEric Cheng * left - softmac_attached_left 1935895Syz147064 */ 194*8275SEric Cheng 195*8275SEric Cheng #ifdef DEBUG 196*8275SEric Cheng void 197*8275SEric Cheng softmac_state_verify(softmac_t *softmac) 198*8275SEric Cheng { 199*8275SEric Cheng ASSERT(MUTEX_HELD(&softmac->smac_mutex)); 200*8275SEric Cheng 201*8275SEric Cheng /* 202*8275SEric Cheng * There are at most 2 minor nodes, one per DLPI style 203*8275SEric Cheng */ 204*8275SEric Cheng ASSERT(softmac->smac_cnt <= 2 && softmac->smac_attachok_cnt <= 2); 205*8275SEric Cheng 206*8275SEric Cheng /* 207*8275SEric Cheng * The smac_attachok_cnt represents the number of attaches i.e. the 208*8275SEric Cheng * number of times net_postattach -> softmac_create() has been called 209*8275SEric Cheng * for a device instance. 210*8275SEric Cheng */ 211*8275SEric Cheng ASSERT(softmac->smac_attachok_cnt == SMAC_NONZERO_NODECNT(softmac)); 212*8275SEric Cheng 213*8275SEric Cheng /* 214*8275SEric Cheng * softmac_create (or softmac_mac_register) -> softmac_create_datalink 215*8275SEric Cheng * happens only after all minor nodes have been attached 216*8275SEric Cheng */ 217*8275SEric Cheng ASSERT(softmac->smac_state != SOFTMAC_ATTACH_DONE || 218*8275SEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt); 219*8275SEric Cheng 220*8275SEric Cheng if (softmac->smac_attachok_cnt == 0) { 221*8275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_UNINIT); 222*8275SEric Cheng ASSERT(softmac->smac_mh == NULL); 223*8275SEric Cheng } else if (softmac->smac_attachok_cnt < softmac->smac_cnt) { 224*8275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG || 225*8275SEric Cheng softmac->smac_state == SOFTMAC_DETACH_INPROG); 226*8275SEric Cheng ASSERT(softmac->smac_mh == NULL); 227*8275SEric Cheng } else { 228*8275SEric Cheng /* 229*8275SEric Cheng * In the stable condition the state whould be 230*8275SEric Cheng * SOFTMAC_ATTACH_DONE. But there is a small transient window 231*8275SEric Cheng * in softmac_destroy where we change the state to 232*8275SEric Cheng * SOFTMAC_DETACH_INPROG and drop the lock before doing 233*8275SEric Cheng * the link destroy 234*8275SEric Cheng */ 235*8275SEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 236*8275SEric Cheng ASSERT(softmac->smac_state != SOFTMAC_UNINIT); 237*8275SEric Cheng } 238*8275SEric Cheng if (softmac->smac_mh != NULL) 239*8275SEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 240*8275SEric Cheng } 241*8275SEric Cheng #endif 242*8275SEric Cheng 243*8275SEric Cheng #ifdef DEBUG 244*8275SEric Cheng #define SOFTMAC_STATE_VERIFY(softmac) softmac_state_verify(softmac) 245*8275SEric Cheng #else 246*8275SEric Cheng #define SOFTMAC_STATE_VERIFY(softmac) 247*8275SEric Cheng #endif 248*8275SEric Cheng 2495895Syz147064 int 2505895Syz147064 softmac_create(dev_info_t *dip, dev_t dev) 2515895Syz147064 { 2525895Syz147064 char devname[MAXNAMELEN]; 2535895Syz147064 softmac_t *softmac; 2545895Syz147064 softmac_dev_t *softmac_dev = NULL; 2555895Syz147064 int index; 2565895Syz147064 int ppa, err = 0; 2575895Syz147064 2585895Syz147064 /* 2595895Syz147064 * Force the softmac driver to be attached. 2605895Syz147064 */ 2615895Syz147064 if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) { 2625895Syz147064 cmn_err(CE_WARN, "softmac_create:softmac attach fails"); 2635895Syz147064 return (ENXIO); 2645895Syz147064 } 2655895Syz147064 2665895Syz147064 ppa = ddi_get_instance(dip); 2675895Syz147064 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 2685895Syz147064 2695895Syz147064 /* 2705895Syz147064 * We expect legacy devices have at most two minor nodes - one style-1 2715895Syz147064 * and one style-2. 2725895Syz147064 */ 2735895Syz147064 if (!GLDV3_DRV(ddi_driver_major(dip)) && 2745895Syz147064 i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) { 2755895Syz147064 cmn_err(CE_WARN, "%s has more than 2 minor nodes; unsupported", 2765895Syz147064 devname); 2775895Syz147064 return (ENOTSUP); 2785895Syz147064 } 2795895Syz147064 2805895Syz147064 /* 2815895Syz147064 * Check whether the softmac for the specified device already exists 2825895Syz147064 */ 2835895Syz147064 rw_enter(&softmac_hash_lock, RW_WRITER); 2845895Syz147064 if ((err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 2855895Syz147064 (mod_hash_val_t *)&softmac)) != 0) { 2865895Syz147064 2875895Syz147064 softmac = kmem_zalloc(sizeof (softmac_t), KM_SLEEP); 2885895Syz147064 mutex_init(&softmac->smac_mutex, NULL, MUTEX_DRIVER, NULL); 2895895Syz147064 cv_init(&softmac->smac_cv, NULL, CV_DRIVER, NULL); 2905895Syz147064 (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN); 2915895Syz147064 /* 2925895Syz147064 * Insert the softmac into the hash table. 2935895Syz147064 */ 2945895Syz147064 err = mod_hash_insert(softmac_hash, 2955895Syz147064 (mod_hash_key_t)softmac->smac_devname, 2965895Syz147064 (mod_hash_val_t)softmac); 2975895Syz147064 ASSERT(err == 0); 298*8275SEric Cheng mutex_enter(&smac_global_lock); 299*8275SEric Cheng cv_broadcast(&smac_global_cv); 300*8275SEric Cheng mutex_exit(&smac_global_lock); 3015895Syz147064 } 3025895Syz147064 3035895Syz147064 mutex_enter(&softmac->smac_mutex); 304*8275SEric Cheng SOFTMAC_STATE_VERIFY(softmac); 305*8275SEric Cheng if (softmac->smac_state != SOFTMAC_ATTACH_DONE) 306*8275SEric Cheng softmac->smac_state = SOFTMAC_ATTACH_INPROG; 3075895Syz147064 if (softmac->smac_attachok_cnt == 0) { 3085895Syz147064 /* 3095895Syz147064 * Initialize the softmac if this is the post-attach of the 3105895Syz147064 * first minor node. 3115895Syz147064 */ 3125895Syz147064 softmac->smac_flags = 0; 3135895Syz147064 softmac->smac_umajor = ddi_driver_major(dip); 3145895Syz147064 softmac->smac_uppa = ppa; 3155895Syz147064 3165895Syz147064 /* 3175895Syz147064 * Note that for GLDv3 devices, we create devfs minor nodes 3185895Syz147064 * for VLANs as well. Assume a GLDv3 driver on which only 3195895Syz147064 * a VLAN is created. During the detachment of this device 3205895Syz147064 * instance, the following would happen: 3215895Syz147064 * a. the pre-detach callback softmac_destroy() succeeds. 3225895Syz147064 * Because the physical link itself is not in use, 3235895Syz147064 * softmac_destroy() succeeds and destroys softmac_t; 3245895Syz147064 * b. the device detach fails in mac_unregister() because 3255895Syz147064 * this MAC is still used by a VLAN. 3265895Syz147064 * c. the post-attach callback is then called which leads 3275895Syz147064 * us here. Note that ddi_minor_node_count() returns 3 3285895Syz147064 * (including the minior node of the VLAN). In that case, 3295895Syz147064 * we must correct the minor node count to 2 as that is 3305895Syz147064 * the count of minor nodes that go through post-attach. 3315895Syz147064 */ 3325895Syz147064 if (GLDV3_DRV(ddi_driver_major(dip))) { 3335895Syz147064 softmac->smac_flags |= SOFTMAC_GLDV3; 3345895Syz147064 softmac->smac_cnt = 2; 3355895Syz147064 } else { 3365895Syz147064 softmac->smac_cnt = 3375895Syz147064 i_ddi_minor_node_count(dip, DDI_NT_NET); 3385895Syz147064 } 3395895Syz147064 } 3405895Syz147064 3415895Syz147064 index = (getmajor(dev) == ddi_name_to_major("clone")); 3425895Syz147064 if (softmac->smac_softmac[index] != NULL) { 3435895Syz147064 /* 344*8275SEric Cheng * This is possible if the post_attach() is called after 345*8275SEric Cheng * pre_detach() fails. This seems to be a defect of the DACF 346*8275SEric Cheng * framework. We work around it by using a smac_attached_left 347*8275SEric Cheng * field that tracks this 3485895Syz147064 */ 349*8275SEric Cheng ASSERT(softmac->smac_attached_left != 0); 350*8275SEric Cheng softmac->smac_attached_left--; 3515895Syz147064 mutex_exit(&softmac->smac_mutex); 3525895Syz147064 rw_exit(&softmac_hash_lock); 3535895Syz147064 return (0); 354*8275SEric Cheng 3555895Syz147064 } 3565895Syz147064 mutex_exit(&softmac->smac_mutex); 3575895Syz147064 rw_exit(&softmac_hash_lock); 3585895Syz147064 3595895Syz147064 softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP); 3605895Syz147064 softmac_dev->sd_dev = dev; 361*8275SEric Cheng 362*8275SEric Cheng mutex_enter(&softmac->smac_mutex); 3635895Syz147064 softmac->smac_softmac[index] = softmac_dev; 3645895Syz147064 /* 3655895Syz147064 * Continue to register the mac and create the datalink only when all 3665895Syz147064 * the minor nodes are attached. 3675895Syz147064 */ 3685895Syz147064 if (++softmac->smac_attachok_cnt != softmac->smac_cnt) { 3695895Syz147064 mutex_exit(&softmac->smac_mutex); 3705895Syz147064 return (0); 3715895Syz147064 } 3725895Syz147064 3735895Syz147064 /* 3747323SCathy.Zhou@Sun.COM * All of the minor nodes have been attached; start a taskq 375*8275SEric Cheng * to do the rest of the work. We use a taskq instead of 3767323SCathy.Zhou@Sun.COM * doing the work here because: 3777323SCathy.Zhou@Sun.COM * 378*8275SEric Cheng * We could be called as a result of a open() system call 379*8275SEric Cheng * where spec_open() already SLOCKED the snode. Using a taskq 380*8275SEric Cheng * sidesteps the risk that our ldi_open_by_dev() call would 381*8275SEric Cheng * deadlock trying to set SLOCKED on the snode again. 3827323SCathy.Zhou@Sun.COM * 383*8275SEric Cheng * The devfs design requires that the downcalls don't use any 384*8275SEric Cheng * interruptible cv_wait which happens when we do door upcalls. 385*8275SEric Cheng * Otherwise the downcalls which may be holding devfs resources 386*8275SEric Cheng * may cause a deadlock if the thread is stopped. Also we need to make 387*8275SEric Cheng * sure these downcalls into softmac_create or softmac_destroy 388*8275SEric Cheng * don't cv_wait on any devfs related condition. Thus softmac_destroy 389*8275SEric Cheng * returns EBUSY if the asynchronous threads started in softmac_create 390*8275SEric Cheng * haven't finished. 3915895Syz147064 */ 3927323SCathy.Zhou@Sun.COM ASSERT(softmac->smac_taskq == NULL); 3937323SCathy.Zhou@Sun.COM softmac->smac_taskq = taskq_dispatch(system_taskq, 3947323SCathy.Zhou@Sun.COM softmac_create_task, softmac, TQ_SLEEP); 3955895Syz147064 mutex_exit(&softmac->smac_mutex); 3967323SCathy.Zhou@Sun.COM return (0); 3975895Syz147064 } 3985895Syz147064 3995895Syz147064 static boolean_t 4005895Syz147064 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 4015895Syz147064 { 4025895Syz147064 softmac_t *softmac = arg; 4035895Syz147064 4045895Syz147064 if (!(softmac->smac_capab_flags & cap)) 4055895Syz147064 return (B_FALSE); 4065895Syz147064 4075895Syz147064 switch (cap) { 4085895Syz147064 case MAC_CAPAB_HCKSUM: { 4095895Syz147064 uint32_t *txflags = cap_data; 4105895Syz147064 4115895Syz147064 *txflags = softmac->smac_hcksum_txflags; 4125895Syz147064 break; 4135895Syz147064 } 4145895Syz147064 case MAC_CAPAB_LEGACY: { 4155895Syz147064 mac_capab_legacy_t *legacy = cap_data; 4165895Syz147064 4175895Syz147064 legacy->ml_unsup_note = ~softmac->smac_notifications & 4185895Syz147064 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED); 4195895Syz147064 legacy->ml_dev = makedevice(softmac->smac_umajor, 4205895Syz147064 softmac->smac_uppa + 1); 4215895Syz147064 break; 4225895Syz147064 } 4235895Syz147064 4245895Syz147064 /* 4255895Syz147064 * For the capabilities below, there's nothing for us to fill in; 4265895Syz147064 * simply return B_TRUE if we support it. 4275895Syz147064 */ 4285895Syz147064 case MAC_CAPAB_NO_ZCOPY: 4295895Syz147064 case MAC_CAPAB_NO_NATIVEVLAN: 4305895Syz147064 default: 4315895Syz147064 break; 4325895Syz147064 } 4335895Syz147064 return (B_TRUE); 4345895Syz147064 } 4355895Syz147064 4365895Syz147064 static int 4375895Syz147064 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp) 4385895Syz147064 { 4395895Syz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID; 4405895Syz147064 uint32_t media; 4415895Syz147064 int err; 4425895Syz147064 4435895Syz147064 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media, 4445895Syz147064 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) { 4455895Syz147064 *linkidp = linkid; 4465895Syz147064 } 4475895Syz147064 4485895Syz147064 if (err == EEXIST) { 4495895Syz147064 /* 4505895Syz147064 * There is a link name conflict. Either: 4515895Syz147064 * 4525895Syz147064 * - An existing link with the same device name with a 4535895Syz147064 * different media type from of the given type. 4545895Syz147064 * Mark this link back to persistent only; or 4555895Syz147064 * 4565895Syz147064 * - We cannot assign the "suggested" name because 4575895Syz147064 * GLDv3 and therefore vanity naming is not supported 4585895Syz147064 * for this link type. Delete this link's <link name, 4595895Syz147064 * linkid> mapping. 4605895Syz147064 */ 4615895Syz147064 if (media != softmac->smac_media) { 4625895Syz147064 cmn_err(CE_WARN, "%s device %s conflicts with " 4635895Syz147064 "existing %s device %s.", 4645895Syz147064 dl_mactypestr(softmac->smac_media), 4655895Syz147064 softmac->smac_devname, dl_mactypestr(media), 4665895Syz147064 softmac->smac_devname); 4675895Syz147064 (void) dls_mgmt_destroy(linkid, B_FALSE); 4685895Syz147064 } else { 4695895Syz147064 cmn_err(CE_WARN, "link name %s is already in-use.", 4705895Syz147064 softmac->smac_devname); 4715895Syz147064 (void) dls_mgmt_destroy(linkid, B_TRUE); 4725895Syz147064 } 4735895Syz147064 4745895Syz147064 cmn_err(CE_WARN, "%s device might not be available " 4755895Syz147064 "for use.", softmac->smac_devname); 4765895Syz147064 cmn_err(CE_WARN, "See dladm(1M) for more information."); 4775895Syz147064 } 4785895Syz147064 4795895Syz147064 return (err); 4805895Syz147064 } 4815895Syz147064 4825895Syz147064 /* 4835895Syz147064 * This function: 4845895Syz147064 * 1. provides the link's media type to dlmgmtd. 4855895Syz147064 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 4865895Syz147064 */ 4875895Syz147064 static int 4885895Syz147064 softmac_create_datalink(softmac_t *softmac) 4895895Syz147064 { 4905895Syz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID; 4915895Syz147064 int err; 4925895Syz147064 4935895Syz147064 /* 4947323SCathy.Zhou@Sun.COM * Inform dlmgmtd of this link so that softmac_hold_device() is able 4957323SCathy.Zhou@Sun.COM * to know the existence of this link. If this failed with EBADF, 4967323SCathy.Zhou@Sun.COM * it might be because dlmgmtd was not started in time (e.g., 4977323SCathy.Zhou@Sun.COM * diskless boot); ignore the failure and continue to create 4987323SCathy.Zhou@Sun.COM * the GLDv3 datalink if needed. 4995895Syz147064 */ 5007323SCathy.Zhou@Sun.COM err = dls_mgmt_create(softmac->smac_devname, 5017323SCathy.Zhou@Sun.COM makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 5027323SCathy.Zhou@Sun.COM DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid); 5037323SCathy.Zhou@Sun.COM if (err != 0 && err != EBADF) 5047323SCathy.Zhou@Sun.COM return (err); 5057323SCathy.Zhou@Sun.COM 5067323SCathy.Zhou@Sun.COM /* 5077323SCathy.Zhou@Sun.COM * Provide the media type of the physical link to dlmgmtd. 5087323SCathy.Zhou@Sun.COM */ 5097323SCathy.Zhou@Sun.COM if ((err != EBADF) && 5107323SCathy.Zhou@Sun.COM ((err = softmac_update_info(softmac, &linkid)) != 0)) { 5115895Syz147064 return (err); 5125895Syz147064 } 5135895Syz147064 5145895Syz147064 /* 5155895Syz147064 * Create the GLDv3 datalink. 5165895Syz147064 */ 5175895Syz147064 if ((!(softmac->smac_flags & SOFTMAC_NOSUPP)) && 5185895Syz147064 ((err = dls_devnet_create(softmac->smac_mh, linkid)) != 0)) { 5195895Syz147064 cmn_err(CE_WARN, "dls_devnet_create failed for %s", 5205895Syz147064 softmac->smac_devname); 5215895Syz147064 return (err); 5225895Syz147064 } 5235895Syz147064 524*8275SEric Cheng if (linkid == DATALINK_INVALID_LINKID) { 525*8275SEric Cheng mutex_enter(&softmac->smac_mutex); 5265895Syz147064 softmac->smac_flags |= SOFTMAC_NEED_RECREATE; 527*8275SEric Cheng mutex_exit(&softmac->smac_mutex); 528*8275SEric Cheng } 5295895Syz147064 5305895Syz147064 return (0); 5315895Syz147064 } 5325895Syz147064 5337323SCathy.Zhou@Sun.COM static void 5347323SCathy.Zhou@Sun.COM softmac_create_task(void *arg) 5357323SCathy.Zhou@Sun.COM { 5367323SCathy.Zhou@Sun.COM softmac_t *softmac = arg; 5377323SCathy.Zhou@Sun.COM mac_handle_t mh; 5387323SCathy.Zhou@Sun.COM int err; 5397323SCathy.Zhou@Sun.COM 5407323SCathy.Zhou@Sun.COM if (!GLDV3_DRV(softmac->smac_umajor)) { 5417323SCathy.Zhou@Sun.COM softmac_mac_register(softmac); 5427323SCathy.Zhou@Sun.COM return; 5437323SCathy.Zhou@Sun.COM } 5447323SCathy.Zhou@Sun.COM 5457323SCathy.Zhou@Sun.COM if ((err = mac_open(softmac->smac_devname, &mh)) != 0) 5467323SCathy.Zhou@Sun.COM goto done; 5477323SCathy.Zhou@Sun.COM 5487323SCathy.Zhou@Sun.COM mutex_enter(&softmac->smac_mutex); 5497323SCathy.Zhou@Sun.COM softmac->smac_media = (mac_info(mh))->mi_nativemedia; 5507323SCathy.Zhou@Sun.COM softmac->smac_mh = mh; 551*8275SEric Cheng softmac->smac_taskq = NULL; 552*8275SEric Cheng mutex_exit(&softmac->smac_mutex); 5537323SCathy.Zhou@Sun.COM 5547323SCathy.Zhou@Sun.COM /* 5557323SCathy.Zhou@Sun.COM * We can safely release the reference on the mac because 5567323SCathy.Zhou@Sun.COM * this mac will only be unregistered and destroyed when 5577323SCathy.Zhou@Sun.COM * the device detaches, and the softmac will be destroyed 5587323SCathy.Zhou@Sun.COM * before then (in the pre-detach routine of the device). 5597323SCathy.Zhou@Sun.COM */ 5607323SCathy.Zhou@Sun.COM mac_close(mh); 5617323SCathy.Zhou@Sun.COM 5627323SCathy.Zhou@Sun.COM /* 5637323SCathy.Zhou@Sun.COM * Create the GLDv3 datalink for this mac. 5647323SCathy.Zhou@Sun.COM */ 5657323SCathy.Zhou@Sun.COM err = softmac_create_datalink(softmac); 5667323SCathy.Zhou@Sun.COM 567*8275SEric Cheng mutex_enter(&softmac->smac_mutex); 5687323SCathy.Zhou@Sun.COM done: 569*8275SEric Cheng if (err != 0) { 570*8275SEric Cheng softmac->smac_mh = NULL; 571*8275SEric Cheng softmac->smac_attacherr = err; 572*8275SEric Cheng } 573*8275SEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE; 5747323SCathy.Zhou@Sun.COM softmac->smac_taskq = NULL; 5757323SCathy.Zhou@Sun.COM cv_broadcast(&softmac->smac_cv); 5767323SCathy.Zhou@Sun.COM mutex_exit(&softmac->smac_mutex); 5777323SCathy.Zhou@Sun.COM } 5787323SCathy.Zhou@Sun.COM 5795895Syz147064 /* 5805895Syz147064 * This function is only called for legacy devices. It: 5815895Syz147064 * 1. registers the MAC for the legacy devices whose media type is supported 5825895Syz147064 * by the GLDv3 framework. 5835895Syz147064 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 5845895Syz147064 */ 5855895Syz147064 static void 5867323SCathy.Zhou@Sun.COM softmac_mac_register(softmac_t *softmac) 5875895Syz147064 { 5885895Syz147064 softmac_dev_t *softmac_dev; 5895895Syz147064 dev_t dev; 5905895Syz147064 ldi_handle_t lh = NULL; 5915895Syz147064 ldi_ident_t li = NULL; 5925895Syz147064 int index; 5935895Syz147064 boolean_t native_vlan = B_FALSE; 5945895Syz147064 int err; 5955895Syz147064 5965895Syz147064 /* 5975895Syz147064 * Note that we do not need any locks to access this softmac pointer, 5985895Syz147064 * as softmac_destroy() will wait until this function is called. 5995895Syz147064 */ 6005895Syz147064 ASSERT(softmac != NULL); 601*8275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 602*8275SEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt); 6035895Syz147064 6045895Syz147064 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) { 6055895Syz147064 mutex_enter(&softmac->smac_mutex); 6065895Syz147064 goto done; 6075895Syz147064 } 6085895Syz147064 6095895Syz147064 /* 6105895Syz147064 * Determine whether this legacy device support VLANs by opening 6115895Syz147064 * the style-2 device node (if it exists) and attaching to a VLAN 6125895Syz147064 * PPA (1000 + ppa). 6135895Syz147064 */ 6145895Syz147064 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor); 6155895Syz147064 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 6165895Syz147064 if (err == 0) { 6175895Syz147064 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0) 6185895Syz147064 native_vlan = B_TRUE; 6195895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 6205895Syz147064 } 6215895Syz147064 6225895Syz147064 err = EINVAL; 6235895Syz147064 for (index = 0; index < 2; index++) { 6245895Syz147064 dl_info_ack_t dlia; 6255895Syz147064 dl_error_ack_t dlea; 6265895Syz147064 uint32_t notes; 6275895Syz147064 struct strioctl iocb; 6285895Syz147064 uint32_t margin; 6295895Syz147064 int rval; 6305895Syz147064 6315895Syz147064 if ((softmac_dev = softmac->smac_softmac[index]) == NULL) 6325895Syz147064 continue; 6335895Syz147064 6345895Syz147064 softmac->smac_dev = dev = softmac_dev->sd_dev; 6355895Syz147064 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, 6365895Syz147064 li) != 0) { 6375895Syz147064 continue; 6385895Syz147064 } 6395895Syz147064 6405895Syz147064 /* 6415895Syz147064 * Pop all the intermediate modules in order to negotiate 6425895Syz147064 * capabilities correctly. 6435895Syz147064 */ 6445895Syz147064 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 6455895Syz147064 ; 6465895Syz147064 6475895Syz147064 /* DLPI style-1 or DLPI style-2? */ 6485895Syz147064 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) { 6495895Syz147064 if (rval == ENOTSUP) { 6505895Syz147064 cmn_err(CE_NOTE, "softmac: received " 6515895Syz147064 "DL_ERROR_ACK to DL_INFO_ACK; " 6525895Syz147064 "DLPI errno 0x%x, UNIX errno %d", 6535895Syz147064 dlea.dl_errno, dlea.dl_unix_errno); 6545895Syz147064 } 6555895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 6565895Syz147064 continue; 6575895Syz147064 } 6585895Syz147064 6595895Syz147064 /* 6605895Syz147064 * Currently only DL_ETHER has GLDv3 mac plugin support. 6615895Syz147064 * For media types that GLDv3 does not support, create a 6625895Syz147064 * link id for it. 6635895Syz147064 */ 6645895Syz147064 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) { 6655895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 6665895Syz147064 err = 0; 6675895Syz147064 break; 6685895Syz147064 } 6695895Syz147064 6705895Syz147064 if ((dlia.dl_provider_style == DL_STYLE2) && 6715895Syz147064 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) { 6725895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 6735895Syz147064 continue; 6745895Syz147064 } 6755895Syz147064 6765895Syz147064 if ((rval = dl_bind(lh, 0, NULL)) != 0) { 6775895Syz147064 if (rval == ENOTSUP) { 6785895Syz147064 cmn_err(CE_NOTE, "softmac: received " 6795895Syz147064 "DL_ERROR_ACK to DL_BIND_ACK; " 6805895Syz147064 "DLPI errno 0x%x, UNIX errno %d", 6815895Syz147064 dlea.dl_errno, dlea.dl_unix_errno); 6825895Syz147064 } 6835895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 6845895Syz147064 continue; 6855895Syz147064 } 6865895Syz147064 6875895Syz147064 /* 6885895Syz147064 * Call dl_info() after dl_bind() because some drivers only 6895895Syz147064 * provide correct information (e.g. MAC address) once bound. 6905895Syz147064 */ 6915895Syz147064 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr); 6925895Syz147064 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr, 6935895Syz147064 &softmac->smac_addrlen, &dlea)) != 0) { 6945895Syz147064 if (rval == ENOTSUP) { 6955895Syz147064 cmn_err(CE_NOTE, "softmac: received " 6965895Syz147064 "DL_ERROR_ACK to DL_INFO_ACK; " 6975895Syz147064 "DLPI errno 0x%x, UNIX errno %d", 6985895Syz147064 dlea.dl_errno, dlea.dl_unix_errno); 6995895Syz147064 } 7005895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 7015895Syz147064 continue; 7025895Syz147064 } 7035895Syz147064 7045895Syz147064 softmac->smac_style = dlia.dl_provider_style; 7055895Syz147064 softmac->smac_saplen = ABS(dlia.dl_sap_length); 7065895Syz147064 softmac->smac_min_sdu = dlia.dl_min_sdu; 7075895Syz147064 softmac->smac_max_sdu = dlia.dl_max_sdu; 7085895Syz147064 7095895Syz147064 if ((softmac->smac_saplen != sizeof (uint16_t)) || 7105895Syz147064 (softmac->smac_addrlen != ETHERADDRL) || 7115895Syz147064 (dlia.dl_brdcst_addr_length != ETHERADDRL) || 7125895Syz147064 (dlia.dl_brdcst_addr_offset == 0)) { 7135895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 7145895Syz147064 continue; 7155895Syz147064 } 7165895Syz147064 7175895Syz147064 /* 7185895Syz147064 * Check other DLPI capabilities. Note that this must be after 7195895Syz147064 * dl_bind() because some drivers return DL_ERROR_ACK if the 7205895Syz147064 * stream is not bound. It is also before mac_register(), so 7215895Syz147064 * we don't need any lock protection here. 7225895Syz147064 */ 7235895Syz147064 softmac->smac_capab_flags = 724*8275SEric Cheng (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY); 7255895Syz147064 7265895Syz147064 softmac->smac_no_capability_req = B_FALSE; 7275895Syz147064 if (softmac_fill_capab(lh, softmac) != 0) 7285895Syz147064 softmac->smac_no_capability_req = B_TRUE; 7295895Syz147064 7305895Syz147064 /* 7315895Syz147064 * Check the margin of the underlying driver. 7325895Syz147064 */ 7335895Syz147064 margin = 0; 7345895Syz147064 iocb.ic_cmd = DLIOCMARGININFO; 7355895Syz147064 iocb.ic_timout = INFTIM; 7365895Syz147064 iocb.ic_len = sizeof (margin); 7375895Syz147064 iocb.ic_dp = (char *)&margin; 7385895Syz147064 softmac->smac_margin = 0; 7395895Syz147064 7405895Syz147064 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred, 7415895Syz147064 &rval) == 0) { 7425895Syz147064 softmac->smac_margin = margin; 7435895Syz147064 } 7445895Syz147064 7455895Syz147064 /* 7465895Syz147064 * If the legacy driver doesn't support DLIOCMARGININFO, but 7475895Syz147064 * it can support native VLAN, correct its margin value to 4. 7485895Syz147064 */ 7495895Syz147064 if (native_vlan) { 7505895Syz147064 if (softmac->smac_margin == 0) 7515895Syz147064 softmac->smac_margin = VLAN_TAGSZ; 7525895Syz147064 } else { 7535895Syz147064 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN; 7545895Syz147064 } 7555895Syz147064 7565895Syz147064 /* 7575895Syz147064 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP. 7585895Syz147064 */ 7595895Syz147064 softmac->smac_notifications = 0; 7605895Syz147064 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN; 7615895Syz147064 switch (dl_notify(lh, ¬es, NULL)) { 7625895Syz147064 case 0: 7635895Syz147064 softmac->smac_notifications = notes; 7645895Syz147064 break; 7655895Syz147064 case ENOTSUP: 7665895Syz147064 break; 7675895Syz147064 default: 7685895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 7695895Syz147064 continue; 7705895Syz147064 } 7715895Syz147064 7725895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 7735895Syz147064 err = 0; 7745895Syz147064 break; 7755895Syz147064 } 7765895Syz147064 ldi_ident_release(li); 7775895Syz147064 7785895Syz147064 mutex_enter(&softmac->smac_mutex); 7795895Syz147064 7805895Syz147064 if (err != 0) 7815895Syz147064 goto done; 7825895Syz147064 7835895Syz147064 if (softmac->smac_media != DL_ETHER) 7845895Syz147064 softmac->smac_flags |= SOFTMAC_NOSUPP; 7855895Syz147064 7865895Syz147064 /* 7875895Syz147064 * Finally, we're ready to register ourselves with the MAC layer 7885895Syz147064 * interface; if this succeeds, we're all ready to start() 7895895Syz147064 */ 7905895Syz147064 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 7915895Syz147064 mac_register_t *macp; 7925895Syz147064 7935895Syz147064 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 7945895Syz147064 err = ENOMEM; 7955895Syz147064 goto done; 7965895Syz147064 } 7975895Syz147064 7985895Syz147064 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7995895Syz147064 macp->m_driver = softmac; 8005895Syz147064 macp->m_dip = softmac_dip; 8015895Syz147064 8025895Syz147064 macp->m_margin = softmac->smac_margin; 8035895Syz147064 macp->m_src_addr = softmac->smac_unicst_addr; 8045895Syz147064 macp->m_min_sdu = softmac->smac_min_sdu; 8055895Syz147064 macp->m_max_sdu = softmac->smac_max_sdu; 8065895Syz147064 macp->m_callbacks = &softmac_m_callbacks; 8075895Syz147064 macp->m_instance = (uint_t)-1; 8085895Syz147064 8095895Syz147064 err = mac_register(macp, &softmac->smac_mh); 8105895Syz147064 mac_free(macp); 8115895Syz147064 if (err != 0) { 8125895Syz147064 cmn_err(CE_WARN, "mac_register failed for %s", 8135895Syz147064 softmac->smac_devname); 8145895Syz147064 goto done; 8155895Syz147064 } 8165895Syz147064 } 817*8275SEric Cheng mutex_exit(&softmac->smac_mutex); 8185895Syz147064 8195895Syz147064 /* 8205895Syz147064 * Try to create the datalink for this softmac. 8215895Syz147064 */ 8225895Syz147064 if ((err = softmac_create_datalink(softmac)) != 0) { 8235895Syz147064 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 8245895Syz147064 (void) mac_unregister(softmac->smac_mh); 8255895Syz147064 softmac->smac_mh = NULL; 8265895Syz147064 } 8275895Syz147064 } 828*8275SEric Cheng /* 829*8275SEric Cheng * If succeed, create the thread which handles the DL_NOTIFY_IND from 830*8275SEric Cheng * the lower stream. 831*8275SEric Cheng */ 832*8275SEric Cheng if (softmac->smac_mh != NULL) { 833*8275SEric Cheng softmac->smac_notify_thread = thread_create(NULL, 0, 834*8275SEric Cheng softmac_notify_thread, softmac, 0, &p0, 835*8275SEric Cheng TS_RUN, minclsyspri); 836*8275SEric Cheng } 8375895Syz147064 838*8275SEric Cheng mutex_enter(&softmac->smac_mutex); 8395895Syz147064 done: 840*8275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 841*8275SEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt); 842*8275SEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE; 8435895Syz147064 softmac->smac_attacherr = err; 8445895Syz147064 softmac->smac_taskq = NULL; 8455895Syz147064 cv_broadcast(&softmac->smac_cv); 8465895Syz147064 mutex_exit(&softmac->smac_mutex); 8475895Syz147064 } 8485895Syz147064 8495895Syz147064 int 8505895Syz147064 softmac_destroy(dev_info_t *dip, dev_t dev) 8515895Syz147064 { 8525895Syz147064 char devname[MAXNAMELEN]; 8535895Syz147064 softmac_t *softmac; 8545895Syz147064 softmac_dev_t *softmac_dev; 8555895Syz147064 int index; 8565895Syz147064 int ppa, err; 8575895Syz147064 datalink_id_t linkid; 858*8275SEric Cheng mac_handle_t smac_mh; 859*8275SEric Cheng uint32_t smac_flags; 8605895Syz147064 8615895Syz147064 ppa = ddi_get_instance(dip); 8625895Syz147064 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 8635895Syz147064 864*8275SEric Cheng /* 865*8275SEric Cheng * We are called only from the predetach entry point. The DACF 866*8275SEric Cheng * framework ensures there can't be a concurrent postattach call 867*8275SEric Cheng * for the same softmac. The softmac found out from the modhash 868*8275SEric Cheng * below can't vanish beneath us since this is the only place where 869*8275SEric Cheng * it is deleted. 870*8275SEric Cheng */ 8715895Syz147064 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 8725895Syz147064 (mod_hash_val_t *)&softmac); 8735895Syz147064 ASSERT(err == 0); 8745895Syz147064 8755895Syz147064 mutex_enter(&softmac->smac_mutex); 876*8275SEric Cheng SOFTMAC_STATE_VERIFY(softmac); 8775895Syz147064 8785895Syz147064 /* 8795895Syz147064 * Fail the predetach routine if this softmac is in-use. 880*8275SEric Cheng * Make sure these downcalls into softmac_create or softmac_destroy 881*8275SEric Cheng * don't cv_wait on any devfs related condition. Thus softmac_destroy 882*8275SEric Cheng * returns EBUSY if the asynchronous thread started in softmac_create 883*8275SEric Cheng * hasn't finished 8845895Syz147064 */ 885*8275SEric Cheng if ((softmac->smac_hold_cnt != 0) || 886*8275SEric Cheng (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) { 8875895Syz147064 softmac->smac_attached_left = softmac->smac_attachok_cnt; 8885895Syz147064 mutex_exit(&softmac->smac_mutex); 8895895Syz147064 return (EBUSY); 8905895Syz147064 } 8915895Syz147064 8925895Syz147064 /* 8935895Syz147064 * Even if the predetach of one minor node has already failed 8945895Syz147064 * (smac_attached_left is not 0), the DACF framework will continue 8955895Syz147064 * to call the predetach routines of the other minor nodes, 8965895Syz147064 * so we fail these calls here. 8975895Syz147064 */ 8985895Syz147064 if (softmac->smac_attached_left != 0) { 8995895Syz147064 mutex_exit(&softmac->smac_mutex); 9005895Syz147064 return (EBUSY); 9015895Syz147064 } 9025895Syz147064 903*8275SEric Cheng smac_mh = softmac->smac_mh; 904*8275SEric Cheng smac_flags = softmac->smac_flags; 905*8275SEric Cheng softmac->smac_state = SOFTMAC_DETACH_INPROG; 906*8275SEric Cheng mutex_exit(&softmac->smac_mutex); 9075895Syz147064 908*8275SEric Cheng if (smac_mh != NULL) { 909*8275SEric Cheng /* 910*8275SEric Cheng * This is the first minor node that is being detached for this 911*8275SEric Cheng * softmac. 912*8275SEric Cheng */ 913*8275SEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 914*8275SEric Cheng if (!(smac_flags & SOFTMAC_NOSUPP)) { 915*8275SEric Cheng if ((err = dls_devnet_destroy(smac_mh, &linkid, 916*8275SEric Cheng B_FALSE)) != 0) { 917*8275SEric Cheng goto error; 9185895Syz147064 } 9195895Syz147064 } 9205895Syz147064 /* 9215895Syz147064 * If softmac_mac_register() succeeds in registering the mac 9225895Syz147064 * of the legacy device, unregister it. 9235895Syz147064 */ 924*8275SEric Cheng if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) { 925*8275SEric Cheng if ((err = mac_disable_nowait(smac_mh)) != 0) { 926*8275SEric Cheng (void) dls_devnet_create(smac_mh, linkid); 927*8275SEric Cheng goto error; 9285895Syz147064 } 929*8275SEric Cheng /* 930*8275SEric Cheng * Ask softmac_notify_thread to quit, and wait for 931*8275SEric Cheng * that to be done. 932*8275SEric Cheng */ 933*8275SEric Cheng mutex_enter(&softmac->smac_mutex); 934*8275SEric Cheng softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT; 935*8275SEric Cheng cv_broadcast(&softmac->smac_cv); 936*8275SEric Cheng while (softmac->smac_notify_thread != NULL) { 937*8275SEric Cheng cv_wait(&softmac->smac_cv, 938*8275SEric Cheng &softmac->smac_mutex); 939*8275SEric Cheng } 940*8275SEric Cheng mutex_exit(&softmac->smac_mutex); 941*8275SEric Cheng VERIFY(mac_unregister(smac_mh) == 0); 9425895Syz147064 } 9435895Syz147064 softmac->smac_mh = NULL; 9445895Syz147064 } 945*8275SEric Cheng 946*8275SEric Cheng /* 947*8275SEric Cheng * Free softmac_dev 948*8275SEric Cheng */ 949*8275SEric Cheng rw_enter(&softmac_hash_lock, RW_WRITER); 950*8275SEric Cheng mutex_enter(&softmac->smac_mutex); 9515895Syz147064 952*8275SEric Cheng ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG && 953*8275SEric Cheng softmac->smac_attachok_cnt != 0); 954*8275SEric Cheng softmac->smac_mh = NULL; 955*8275SEric Cheng index = (getmajor(dev) == ddi_name_to_major("clone")); 956*8275SEric Cheng softmac_dev = softmac->smac_softmac[index]; 957*8275SEric Cheng ASSERT(softmac_dev != NULL); 958*8275SEric Cheng softmac->smac_softmac[index] = NULL; 959*8275SEric Cheng kmem_free(softmac_dev, sizeof (softmac_dev_t)); 9605895Syz147064 961*8275SEric Cheng if (--softmac->smac_attachok_cnt == 0) { 962*8275SEric Cheng mod_hash_val_t hashval; 9635895Syz147064 964*8275SEric Cheng softmac->smac_state = SOFTMAC_UNINIT; 965*8275SEric Cheng if (softmac->smac_hold_cnt != 0) { 966*8275SEric Cheng /* 967*8275SEric Cheng * Someone did a softmac_hold_device while we dropped 968*8275SEric Cheng * the locks. Leave the softmac itself intact which 969*8275SEric Cheng * will be reused by the reattach 970*8275SEric Cheng */ 9715895Syz147064 mutex_exit(&softmac->smac_mutex); 9725895Syz147064 rw_exit(&softmac_hash_lock); 9735895Syz147064 return (0); 9745895Syz147064 } 975*8275SEric Cheng ASSERT(softmac->smac_taskq == NULL); 976*8275SEric Cheng 977*8275SEric Cheng err = mod_hash_remove(softmac_hash, 978*8275SEric Cheng (mod_hash_key_t)devname, 979*8275SEric Cheng (mod_hash_val_t *)&hashval); 980*8275SEric Cheng ASSERT(err == 0); 981*8275SEric Cheng 982*8275SEric Cheng mutex_exit(&softmac->smac_mutex); 983*8275SEric Cheng rw_exit(&softmac_hash_lock); 984*8275SEric Cheng 985*8275SEric Cheng mutex_destroy(&softmac->smac_mutex); 986*8275SEric Cheng cv_destroy(&softmac->smac_cv); 987*8275SEric Cheng kmem_free(softmac, sizeof (softmac_t)); 988*8275SEric Cheng return (0); 9895895Syz147064 } 9905895Syz147064 mutex_exit(&softmac->smac_mutex); 9915895Syz147064 rw_exit(&softmac_hash_lock); 992*8275SEric Cheng return (0); 993*8275SEric Cheng 994*8275SEric Cheng error: 995*8275SEric Cheng mutex_enter(&softmac->smac_mutex); 996*8275SEric Cheng softmac->smac_attached_left = softmac->smac_attachok_cnt; 997*8275SEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE; 998*8275SEric Cheng cv_broadcast(&softmac->smac_cv); 999*8275SEric Cheng mutex_exit(&softmac->smac_mutex); 10005895Syz147064 return (err); 10015895Syz147064 } 10025895Syz147064 10035895Syz147064 /* 10045895Syz147064 * This function is called as the result of a newly started dlmgmtd daemon. 10055895Syz147064 * 10065895Syz147064 * We walk through every softmac that was created but failed to notify 10075895Syz147064 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs 10085895Syz147064 * when softmacs are created before dlmgmtd is ready. For example, during 10095895Syz147064 * diskless boot, a network device is used (and therefore attached) before 10105895Syz147064 * the datalink-management service starts dlmgmtd. 10115895Syz147064 */ 10125895Syz147064 /* ARGSUSED */ 10135895Syz147064 static uint_t 10145895Syz147064 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 10155895Syz147064 { 10165895Syz147064 softmac_t *softmac = (softmac_t *)val; 10175895Syz147064 datalink_id_t linkid; 10185895Syz147064 int err; 1019*8275SEric Cheng softmac_walk_t *smwp = arg; 10205895Syz147064 10215895Syz147064 /* 1022*8275SEric Cheng * The framework itself must not hold any locks across calls to the 1023*8275SEric Cheng * mac perimeter. Thus this function does not call any framework 1024*8275SEric Cheng * function that needs to grab the mac perimeter. 10255895Syz147064 */ 1026*8275SEric Cheng ASSERT(RW_READ_HELD(&softmac_hash_lock)); 1027*8275SEric Cheng 1028*8275SEric Cheng smwp->smw_retry = B_FALSE; 10295895Syz147064 mutex_enter(&softmac->smac_mutex); 1030*8275SEric Cheng SOFTMAC_STATE_VERIFY(softmac); 1031*8275SEric Cheng if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) { 1032*8275SEric Cheng /* 1033*8275SEric Cheng * Wait till softmac_create or softmac_mac_register finishes 1034*8275SEric Cheng * Hold the softmac to ensure it stays around. The wait itself 1035*8275SEric Cheng * is done in the caller, since we need to drop all locks 1036*8275SEric Cheng * including the mod hash's internal lock before calling 1037*8275SEric Cheng * cv_wait. 1038*8275SEric Cheng */ 1039*8275SEric Cheng smwp->smw_retry = B_TRUE; 1040*8275SEric Cheng smwp->smw_softmac = softmac; 1041*8275SEric Cheng softmac->smac_hold_cnt++; 1042*8275SEric Cheng return (MH_WALK_TERMINATE); 1043*8275SEric Cheng } 10445895Syz147064 1045*8275SEric Cheng if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) || 10465895Syz147064 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) { 10475895Syz147064 mutex_exit(&softmac->smac_mutex); 10485895Syz147064 return (MH_WALK_CONTINUE); 10495895Syz147064 } 10505895Syz147064 10515895Syz147064 if (dls_mgmt_create(softmac->smac_devname, 10525895Syz147064 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 10535895Syz147064 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) { 10545895Syz147064 mutex_exit(&softmac->smac_mutex); 10555895Syz147064 return (MH_WALK_CONTINUE); 10565895Syz147064 } 10575895Syz147064 10585895Syz147064 if ((err = softmac_update_info(softmac, &linkid)) != 0) { 10595895Syz147064 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s " 10605895Syz147064 "failed (%d)", softmac->smac_devname, err); 10615895Syz147064 mutex_exit(&softmac->smac_mutex); 10625895Syz147064 return (MH_WALK_CONTINUE); 10635895Syz147064 } 10645895Syz147064 10655895Syz147064 /* 10665895Syz147064 * Create a link for this MAC. The link name will be the same 10675895Syz147064 * as the MAC name. 10685895Syz147064 */ 10695895Syz147064 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 10705895Syz147064 err = dls_devnet_recreate(softmac->smac_mh, linkid); 10715895Syz147064 if (err != 0) { 10725895Syz147064 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for " 10735895Syz147064 "%s (linkid %d) failed (%d)", 10745895Syz147064 softmac->smac_devname, linkid, err); 10755895Syz147064 } 10765895Syz147064 } 10775895Syz147064 10785895Syz147064 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE; 10795895Syz147064 mutex_exit(&softmac->smac_mutex); 10805895Syz147064 10815895Syz147064 return (MH_WALK_CONTINUE); 10825895Syz147064 } 10835895Syz147064 10845895Syz147064 /* 10855895Syz147064 * See comments above softmac_mac_recreate(). 10865895Syz147064 */ 10875895Syz147064 void 10885895Syz147064 softmac_recreate() 10895895Syz147064 { 1090*8275SEric Cheng softmac_walk_t smw; 1091*8275SEric Cheng softmac_t *softmac; 1092*8275SEric Cheng 10935895Syz147064 /* 10945895Syz147064 * Walk through the softmac_hash table. Request to create the 10955895Syz147064 * [link name, linkid] mapping if we failed to do so. 10965895Syz147064 */ 1097*8275SEric Cheng do { 1098*8275SEric Cheng smw.smw_retry = B_FALSE; 1099*8275SEric Cheng rw_enter(&softmac_hash_lock, RW_READER); 1100*8275SEric Cheng mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw); 1101*8275SEric Cheng rw_exit(&softmac_hash_lock); 1102*8275SEric Cheng if (smw.smw_retry) { 1103*8275SEric Cheng /* 1104*8275SEric Cheng * softmac_create or softmac_mac_register hasn't yet 1105*8275SEric Cheng * finished and the softmac is not yet in the 1106*8275SEric Cheng * SOFTMAC_ATTACH_DONE state. 1107*8275SEric Cheng */ 1108*8275SEric Cheng softmac = smw.smw_softmac; 1109*8275SEric Cheng cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1110*8275SEric Cheng softmac->smac_hold_cnt--; 1111*8275SEric Cheng mutex_exit(&softmac->smac_mutex); 1112*8275SEric Cheng } 1113*8275SEric Cheng } while (smw.smw_retry); 11145895Syz147064 } 11155895Syz147064 11165895Syz147064 /* ARGSUSED */ 11175895Syz147064 static int 11185895Syz147064 softmac_m_start(void *arg) 11195895Syz147064 { 11205895Syz147064 return (0); 11215895Syz147064 } 11225895Syz147064 11235895Syz147064 /* ARGSUSED */ 11245895Syz147064 static void 11255895Syz147064 softmac_m_stop(void *arg) 11265895Syz147064 { 11275895Syz147064 } 11285895Syz147064 11295895Syz147064 /* 11305895Syz147064 * Set up the lower stream above the legacy device which is shared by 11315895Syz147064 * GLDv3 MAC clients. Put the lower stream into DLIOCRAW mode to send 11325895Syz147064 * and receive the raw data. Further, put the lower stream into 11335895Syz147064 * DL_PROMISC_SAP mode to receive all packets of interest. 11345895Syz147064 */ 11355895Syz147064 static int 11365895Syz147064 softmac_lower_setup(softmac_t *softmac, softmac_lower_t **slpp) 11375895Syz147064 { 11385895Syz147064 ldi_ident_t li; 11395895Syz147064 dev_t dev; 11405895Syz147064 ldi_handle_t lh = NULL; 11415895Syz147064 softmac_lower_t *slp = NULL; 11425895Syz147064 smac_ioc_start_t start_arg; 11435895Syz147064 struct strioctl strioc; 11445895Syz147064 uint32_t notifications; 11455895Syz147064 int err, rval; 11465895Syz147064 11475895Syz147064 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) 11485895Syz147064 return (err); 11495895Syz147064 11505895Syz147064 dev = softmac->smac_dev; 11515895Syz147064 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 11525895Syz147064 ldi_ident_release(li); 11535895Syz147064 if (err != 0) 11545895Syz147064 goto done; 11555895Syz147064 11565895Syz147064 /* 11575895Syz147064 * Pop all the intermediate modules. The autopushed modules will 11585895Syz147064 * be pushed when the softmac node is opened. 11595895Syz147064 */ 11605895Syz147064 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 11615895Syz147064 ; 11625895Syz147064 11635895Syz147064 if ((softmac->smac_style == DL_STYLE2) && 11645895Syz147064 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) { 11655895Syz147064 goto done; 11665895Syz147064 } 11675895Syz147064 11685895Syz147064 /* 11695895Syz147064 * Put the lower stream into DLIOCRAW mode to send/receive raw data. 11705895Syz147064 */ 11715895Syz147064 if ((err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, kcred, &rval)) != 0) 11725895Syz147064 goto done; 11735895Syz147064 11745895Syz147064 /* 11755895Syz147064 * Then push the softmac shim layer atop the lower stream. 11765895Syz147064 */ 11775895Syz147064 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL, 11785895Syz147064 kcred, &rval)) != 0) { 11795895Syz147064 goto done; 11805895Syz147064 } 11815895Syz147064 11825895Syz147064 /* 11835895Syz147064 * Send the ioctl to get the slp pointer. 11845895Syz147064 */ 11855895Syz147064 strioc.ic_cmd = SMAC_IOC_START; 11865895Syz147064 strioc.ic_timout = INFTIM; 11875895Syz147064 strioc.ic_len = sizeof (start_arg); 11885895Syz147064 strioc.ic_dp = (char *)&start_arg; 11895895Syz147064 11905895Syz147064 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL, 11915895Syz147064 kcred, &rval)) != 0) { 11925895Syz147064 goto done; 11935895Syz147064 } 11945895Syz147064 slp = start_arg.si_slp; 11955895Syz147064 slp->sl_lh = lh; 11965895Syz147064 slp->sl_softmac = softmac; 11975895Syz147064 *slpp = slp; 11985895Syz147064 11995895Syz147064 /* 12005895Syz147064 * Bind to SAP 2 on token ring, 0 on other interface types. 12015895Syz147064 * (SAP 0 has special significance on token ring). 12025895Syz147064 * Note that the receive-side packets could come anytime after bind. 12035895Syz147064 */ 12045895Syz147064 if (softmac->smac_media == DL_TPR) 12055895Syz147064 err = softmac_send_bind_req(slp, 2); 12065895Syz147064 else 12075895Syz147064 err = softmac_send_bind_req(slp, 0); 12085895Syz147064 if (err != 0) 12095895Syz147064 goto done; 12105895Syz147064 12115895Syz147064 /* 12125895Syz147064 * Put the lower stream into DL_PROMISC_SAP mode to receive all 12135895Syz147064 * packets of interest. 12145895Syz147064 * 12155895Syz147064 * Some drivers (e.g. the old legacy eri driver) incorrectly pass up 12165895Syz147064 * packets to DL_PROMISC_SAP stream when the lower stream is not bound, 12175895Syz147064 * so we send DL_PROMISON_REQ after DL_BIND_REQ. 12185895Syz147064 */ 12195895Syz147064 if ((err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE)) != 0) 12205895Syz147064 goto done; 12215895Syz147064 12225895Syz147064 /* 12235895Syz147064 * Enable the capabilities the underlying driver claims to support. 12245895Syz147064 * Some drivers require this to be called after the stream is bound. 12255895Syz147064 */ 12265895Syz147064 if ((err = softmac_capab_enable(slp)) != 0) 12275895Syz147064 goto done; 12285895Syz147064 12295895Syz147064 /* 12305895Syz147064 * Send the DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND. 12315895Syz147064 * We don't have to wait for the ack. 12325895Syz147064 */ 12335895Syz147064 notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | 12345895Syz147064 DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS | 12355895Syz147064 DL_NOTE_PROMISC_OFF_PHYS; 12365895Syz147064 12375895Syz147064 (void) softmac_send_notify_req(slp, 12385895Syz147064 (notifications & softmac->smac_notifications)); 12395895Syz147064 12405895Syz147064 done: 12415895Syz147064 if (err != 0) 12425895Syz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 12435895Syz147064 return (err); 12445895Syz147064 } 12455895Syz147064 12465895Syz147064 static int 12475895Syz147064 softmac_m_open(void *arg) 12485895Syz147064 { 12495895Syz147064 softmac_t *softmac = arg; 12505895Syz147064 softmac_lower_t *slp; 12515895Syz147064 int err; 12525895Syz147064 1253*8275SEric Cheng ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1254*8275SEric Cheng ASSERT(softmac->smac_lower_state == SOFTMAC_INITIALIZED); 12555895Syz147064 12565895Syz147064 if ((err = softmac_lower_setup(softmac, &slp)) != 0) 12575895Syz147064 return (err); 12585895Syz147064 12595895Syz147064 softmac->smac_lower = slp; 1260*8275SEric Cheng softmac->smac_lower_state = SOFTMAC_READY; 12615895Syz147064 return (0); 12625895Syz147064 } 12635895Syz147064 12645895Syz147064 static void 12655895Syz147064 softmac_m_close(void *arg) 12665895Syz147064 { 12675895Syz147064 softmac_t *softmac = arg; 12685895Syz147064 softmac_lower_t *slp; 12695895Syz147064 1270*8275SEric Cheng ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1271*8275SEric Cheng ASSERT(softmac->smac_lower_state == SOFTMAC_READY); 12725895Syz147064 slp = softmac->smac_lower; 12735895Syz147064 ASSERT(slp != NULL); 12745895Syz147064 12755895Syz147064 /* 12765895Syz147064 * Note that slp is destroyed when lh is closed. 12775895Syz147064 */ 12785895Syz147064 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred); 1279*8275SEric Cheng softmac->smac_lower_state = SOFTMAC_INITIALIZED; 12805895Syz147064 softmac->smac_lower = NULL; 12815895Syz147064 } 12825895Syz147064 12835895Syz147064 int 12845895Syz147064 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp) 12855895Syz147064 { 12865895Syz147064 dev_info_t *dip; 12876915Syz147064 const char *drvname; 12885895Syz147064 char devname[MAXNAMELEN]; 12895895Syz147064 softmac_t *softmac; 12905895Syz147064 int ppa, err; 12915895Syz147064 12925895Syz147064 if ((ppa = getminor(dev) - 1) > 1000) 12935895Syz147064 return (ENOENT); 12945895Syz147064 12955895Syz147064 /* 12965895Syz147064 * First try to hold this device instance to force the MAC 12975895Syz147064 * to be registered. 12985895Syz147064 */ 12995895Syz147064 if ((dip = ddi_hold_devi_by_instance(getmajor(dev), ppa, 0)) == NULL) 13005895Syz147064 return (ENOENT); 13015895Syz147064 13026915Syz147064 drvname = ddi_driver_name(dip); 13036915Syz147064 13046915Syz147064 /* 13056915Syz147064 * Exclude non-physical network device instances, for example, aggr0. 13066915Syz147064 */ 13075895Syz147064 if ((ddi_driver_major(dip) != getmajor(dev)) || 13086915Syz147064 !NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) || 13096915Syz147064 (strcmp(drvname, "vnic") == 0)) { 13105895Syz147064 ddi_release_devi(dip); 13115895Syz147064 return (ENOENT); 13125895Syz147064 } 13135895Syz147064 13145895Syz147064 /* 13155895Syz147064 * This is a network device; wait for its softmac to be registered. 13165895Syz147064 */ 13176915Syz147064 (void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa); 13185895Syz147064 again: 13195895Syz147064 rw_enter(&softmac_hash_lock, RW_READER); 13205895Syz147064 13215895Syz147064 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 13225895Syz147064 (mod_hash_val_t *)&softmac) != 0) { 13235895Syz147064 /* 13245895Syz147064 * This is rare but possible. It could happen when pre-detach 13255895Syz147064 * routine of the device succeeds. But the softmac will then 13265895Syz147064 * be recreated when device fails to detach (as this device 13275895Syz147064 * is held). 13285895Syz147064 */ 1329*8275SEric Cheng mutex_enter(&smac_global_lock); 13305895Syz147064 rw_exit(&softmac_hash_lock); 1331*8275SEric Cheng cv_wait(&smac_global_cv, &smac_global_lock); 1332*8275SEric Cheng mutex_exit(&smac_global_lock); 13335895Syz147064 goto again; 13345895Syz147064 } 13355895Syz147064 13365895Syz147064 /* 13375895Syz147064 * Bump smac_hold_cnt to prevent device detach. 13385895Syz147064 */ 13395895Syz147064 mutex_enter(&softmac->smac_mutex); 13405895Syz147064 softmac->smac_hold_cnt++; 13415895Syz147064 rw_exit(&softmac_hash_lock); 13425895Syz147064 13435895Syz147064 /* 13445895Syz147064 * Wait till the device is fully attached. 13455895Syz147064 */ 1346*8275SEric Cheng while (softmac->smac_state != SOFTMAC_ATTACH_DONE) 13475895Syz147064 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 13485895Syz147064 1349*8275SEric Cheng SOFTMAC_STATE_VERIFY(softmac); 1350*8275SEric Cheng 13515909Syz147064 if ((err = softmac->smac_attacherr) != 0) 13525909Syz147064 softmac->smac_hold_cnt--; 13535909Syz147064 else 13545895Syz147064 *ddhp = (dls_dev_handle_t)softmac; 13555895Syz147064 mutex_exit(&softmac->smac_mutex); 13565895Syz147064 13575909Syz147064 ddi_release_devi(dip); 13585895Syz147064 return (err); 13595895Syz147064 } 13605895Syz147064 13615895Syz147064 void 13625895Syz147064 softmac_rele_device(dls_dev_handle_t ddh) 13635895Syz147064 { 13645895Syz147064 softmac_t *softmac; 13655895Syz147064 13665895Syz147064 if (ddh == NULL) 13675895Syz147064 return; 13685895Syz147064 13695895Syz147064 softmac = (softmac_t *)ddh; 13705895Syz147064 mutex_enter(&softmac->smac_mutex); 13715909Syz147064 softmac->smac_hold_cnt--; 13725895Syz147064 mutex_exit(&softmac->smac_mutex); 13735895Syz147064 } 1374