1d62bc4baSyz147064 /* 2d62bc4baSyz147064 * CDDL HEADER START 3d62bc4baSyz147064 * 4d62bc4baSyz147064 * The contents of this file are subject to the terms of the 5d62bc4baSyz147064 * Common Development and Distribution License (the "License"). 6d62bc4baSyz147064 * You may not use this file except in compliance with the License. 7d62bc4baSyz147064 * 8d62bc4baSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d62bc4baSyz147064 * or http://www.opensolaris.org/os/licensing. 10d62bc4baSyz147064 * See the License for the specific language governing permissions 11d62bc4baSyz147064 * and limitations under the License. 12d62bc4baSyz147064 * 13d62bc4baSyz147064 * When distributing Covered Code, include this CDDL HEADER in each 14d62bc4baSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d62bc4baSyz147064 * If applicable, add the following below this CDDL HEADER, with the 16d62bc4baSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying 17d62bc4baSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 18d62bc4baSyz147064 * 19d62bc4baSyz147064 * CDDL HEADER END 20d62bc4baSyz147064 */ 21d62bc4baSyz147064 /* 2265041820SCathy Zhou * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23d62bc4baSyz147064 * Use is subject to license terms. 24d62bc4baSyz147064 */ 25d62bc4baSyz147064 26d62bc4baSyz147064 /* 27d62bc4baSyz147064 * The softmac driver is used to "unify" non-GLDv3 drivers to the GLDv3 28d62bc4baSyz147064 * framework. It also creates the kernel datalink structure for each 29d62bc4baSyz147064 * physical network device. 30d62bc4baSyz147064 * 31d62bc4baSyz147064 * Specifically, a softmac will be created for each physical network device 32d62bc4baSyz147064 * (dip) during the device's post-attach process. When this softmac is 33d62bc4baSyz147064 * created, the following will also be done: 34d62bc4baSyz147064 * - create the device's <link name, linkid> mapping; 35d62bc4baSyz147064 * - register the mac if this is a non-GLDv3 device and the media type is 36d62bc4baSyz147064 * supported by the GLDv3 framework; 37d62bc4baSyz147064 * - create the kernel data-link structure for this physical device; 38d62bc4baSyz147064 * 39d62bc4baSyz147064 * This softmac will be destroyed during the device's pre-detach process, 40d62bc4baSyz147064 * and all the above will be undone. 41d62bc4baSyz147064 */ 42d62bc4baSyz147064 43d62bc4baSyz147064 #include <sys/types.h> 44d62bc4baSyz147064 #include <sys/file.h> 45d62bc4baSyz147064 #include <sys/cred.h> 46d62bc4baSyz147064 #include <sys/dlpi.h> 47da14cebeSEric Cheng #include <sys/mac_provider.h> 48da14cebeSEric Cheng #include <sys/disp.h> 49d62bc4baSyz147064 #include <sys/sunndi.h> 50d62bc4baSyz147064 #include <sys/modhash.h> 51d62bc4baSyz147064 #include <sys/stropts.h> 52d62bc4baSyz147064 #include <sys/sysmacros.h> 53d62bc4baSyz147064 #include <sys/vlan.h> 54d62bc4baSyz147064 #include <sys/softmac_impl.h> 55d62bc4baSyz147064 #include <sys/softmac.h> 56d62bc4baSyz147064 #include <sys/dls.h> 57d62bc4baSyz147064 58da14cebeSEric Cheng /* Used as a parameter to the mod hash walk of softmac structures */ 59da14cebeSEric Cheng typedef struct { 60da14cebeSEric Cheng softmac_t *smw_softmac; 61da14cebeSEric Cheng boolean_t smw_retry; 62da14cebeSEric Cheng } softmac_walk_t; 63da14cebeSEric Cheng 64d62bc4baSyz147064 /* 65d62bc4baSyz147064 * Softmac hash table including softmacs for both style-2 and style-1 devices. 66d62bc4baSyz147064 */ 67d62bc4baSyz147064 static krwlock_t softmac_hash_lock; 68d62bc4baSyz147064 static mod_hash_t *softmac_hash; 69da14cebeSEric Cheng static kmutex_t smac_global_lock; 70da14cebeSEric Cheng static kcondvar_t smac_global_cv; 71d62bc4baSyz147064 725d460eafSCathy Zhou static kmem_cache_t *softmac_cachep; 735d460eafSCathy Zhou 74d62bc4baSyz147064 #define SOFTMAC_HASHSZ 64 75d62bc4baSyz147064 760dc974a9SCathy Zhou static void softmac_create_task(void *); 770dc974a9SCathy Zhou static void softmac_mac_register(softmac_t *); 78d62bc4baSyz147064 static int softmac_create_datalink(softmac_t *); 79d62bc4baSyz147064 static int softmac_m_start(void *); 80d62bc4baSyz147064 static void softmac_m_stop(void *); 81d62bc4baSyz147064 static int softmac_m_open(void *); 82d62bc4baSyz147064 static void softmac_m_close(void *); 83d62bc4baSyz147064 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *); 845d460eafSCathy Zhou static int softmac_m_setprop(void *, const char *, mac_prop_id_t, 855d460eafSCathy Zhou uint_t, const void *); 865d460eafSCathy Zhou static int softmac_m_getprop(void *, const char *, mac_prop_id_t, 875d460eafSCathy Zhou uint_t, uint_t, void *, uint_t *); 885d460eafSCathy Zhou 89d62bc4baSyz147064 90d62bc4baSyz147064 #define SOFTMAC_M_CALLBACK_FLAGS \ 915d460eafSCathy Zhou (MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE | MC_SETPROP | MC_GETPROP) 92d62bc4baSyz147064 93d62bc4baSyz147064 static mac_callbacks_t softmac_m_callbacks = { 94d62bc4baSyz147064 SOFTMAC_M_CALLBACK_FLAGS, 95d62bc4baSyz147064 softmac_m_stat, 96d62bc4baSyz147064 softmac_m_start, 97d62bc4baSyz147064 softmac_m_stop, 98d62bc4baSyz147064 softmac_m_promisc, 99d62bc4baSyz147064 softmac_m_multicst, 100d62bc4baSyz147064 softmac_m_unicst, 101d62bc4baSyz147064 softmac_m_tx, 102d62bc4baSyz147064 softmac_m_ioctl, 103d62bc4baSyz147064 softmac_m_getcapab, 104d62bc4baSyz147064 softmac_m_open, 1055d460eafSCathy Zhou softmac_m_close, 1065d460eafSCathy Zhou softmac_m_setprop, 1075d460eafSCathy Zhou softmac_m_getprop 108d62bc4baSyz147064 }; 109d62bc4baSyz147064 1105d460eafSCathy Zhou /*ARGSUSED*/ 1115d460eafSCathy Zhou static int 1125d460eafSCathy Zhou softmac_constructor(void *buf, void *arg, int kmflag) 1135d460eafSCathy Zhou { 1145d460eafSCathy Zhou softmac_t *softmac = buf; 1155d460eafSCathy Zhou 1165d460eafSCathy Zhou bzero(buf, sizeof (softmac_t)); 1175d460eafSCathy Zhou mutex_init(&softmac->smac_mutex, NULL, MUTEX_DEFAULT, NULL); 1185d460eafSCathy Zhou mutex_init(&softmac->smac_active_mutex, NULL, MUTEX_DEFAULT, NULL); 1195d460eafSCathy Zhou mutex_init(&softmac->smac_fp_mutex, NULL, MUTEX_DEFAULT, NULL); 1205d460eafSCathy Zhou cv_init(&softmac->smac_cv, NULL, CV_DEFAULT, NULL); 1215d460eafSCathy Zhou cv_init(&softmac->smac_fp_cv, NULL, CV_DEFAULT, NULL); 1225d460eafSCathy Zhou list_create(&softmac->smac_sup_list, sizeof (softmac_upper_t), 1235d460eafSCathy Zhou offsetof(softmac_upper_t, su_list_node)); 1245d460eafSCathy Zhou return (0); 1255d460eafSCathy Zhou } 1265d460eafSCathy Zhou 1275d460eafSCathy Zhou /*ARGSUSED*/ 1285d460eafSCathy Zhou static void 1295d460eafSCathy Zhou softmac_destructor(void *buf, void *arg) 1305d460eafSCathy Zhou { 1315d460eafSCathy Zhou softmac_t *softmac = buf; 1325d460eafSCathy Zhou 1335d460eafSCathy Zhou ASSERT(softmac->smac_fp_disable_clients == 0); 1345d460eafSCathy Zhou ASSERT(!softmac->smac_fastpath_admin_disabled); 1355d460eafSCathy Zhou 1365d460eafSCathy Zhou ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)); 1375d460eafSCathy Zhou ASSERT(softmac->smac_hold_cnt == 0); 1385d460eafSCathy Zhou ASSERT(softmac->smac_attachok_cnt == 0); 1395d460eafSCathy Zhou ASSERT(softmac->smac_mh == NULL); 1405d460eafSCathy Zhou ASSERT(softmac->smac_softmac[0] == NULL && 1415d460eafSCathy Zhou softmac->smac_softmac[1] == NULL); 1425d460eafSCathy Zhou ASSERT(softmac->smac_state == SOFTMAC_INITIALIZED); 1435d460eafSCathy Zhou ASSERT(softmac->smac_lower == NULL); 1445d460eafSCathy Zhou ASSERT(softmac->smac_active == B_FALSE); 1455d460eafSCathy Zhou ASSERT(softmac->smac_nactive == 0); 1465d460eafSCathy Zhou ASSERT(list_is_empty(&softmac->smac_sup_list)); 1475d460eafSCathy Zhou 1485d460eafSCathy Zhou list_destroy(&softmac->smac_sup_list); 1495d460eafSCathy Zhou mutex_destroy(&softmac->smac_mutex); 1505d460eafSCathy Zhou mutex_destroy(&softmac->smac_active_mutex); 1515d460eafSCathy Zhou mutex_destroy(&softmac->smac_fp_mutex); 1525d460eafSCathy Zhou cv_destroy(&softmac->smac_cv); 1535d460eafSCathy Zhou cv_destroy(&softmac->smac_fp_cv); 1545d460eafSCathy Zhou } 1555d460eafSCathy Zhou 156d62bc4baSyz147064 void 157d62bc4baSyz147064 softmac_init() 158d62bc4baSyz147064 { 159d62bc4baSyz147064 softmac_hash = mod_hash_create_extended("softmac_hash", 160d62bc4baSyz147064 SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 161d62bc4baSyz147064 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 162d62bc4baSyz147064 163d62bc4baSyz147064 rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL); 164da14cebeSEric Cheng mutex_init(&smac_global_lock, NULL, MUTEX_DRIVER, NULL); 165da14cebeSEric Cheng cv_init(&smac_global_cv, NULL, CV_DRIVER, NULL); 1665d460eafSCathy Zhou 1675d460eafSCathy Zhou softmac_cachep = kmem_cache_create("softmac_cache", 1685d460eafSCathy Zhou sizeof (softmac_t), 0, softmac_constructor, 1695d460eafSCathy Zhou softmac_destructor, NULL, NULL, NULL, 0); 1705d460eafSCathy Zhou ASSERT(softmac_cachep != NULL); 1715d460eafSCathy Zhou softmac_fp_init(); 172d62bc4baSyz147064 } 173d62bc4baSyz147064 174d62bc4baSyz147064 void 175d62bc4baSyz147064 softmac_fini() 176d62bc4baSyz147064 { 1775d460eafSCathy Zhou softmac_fp_fini(); 1785d460eafSCathy Zhou kmem_cache_destroy(softmac_cachep); 179d62bc4baSyz147064 rw_destroy(&softmac_hash_lock); 180d62bc4baSyz147064 mod_hash_destroy_hash(softmac_hash); 181da14cebeSEric Cheng mutex_destroy(&smac_global_lock); 182da14cebeSEric Cheng cv_destroy(&smac_global_cv); 183d62bc4baSyz147064 } 184d62bc4baSyz147064 185d62bc4baSyz147064 /* ARGSUSED */ 186d62bc4baSyz147064 static uint_t 187d62bc4baSyz147064 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 188d62bc4baSyz147064 { 189d62bc4baSyz147064 boolean_t *pexist = arg; 190d62bc4baSyz147064 191d62bc4baSyz147064 *pexist = B_TRUE; 192d62bc4baSyz147064 return (MH_WALK_TERMINATE); 193d62bc4baSyz147064 } 194d62bc4baSyz147064 195d62bc4baSyz147064 boolean_t 196d62bc4baSyz147064 softmac_busy() 197d62bc4baSyz147064 { 198d62bc4baSyz147064 boolean_t exist = B_FALSE; 199d62bc4baSyz147064 200d62bc4baSyz147064 rw_enter(&softmac_hash_lock, RW_READER); 201d62bc4baSyz147064 mod_hash_walk(softmac_hash, softmac_exist, &exist); 202d62bc4baSyz147064 rw_exit(&softmac_hash_lock); 203d62bc4baSyz147064 return (exist); 204d62bc4baSyz147064 } 205d62bc4baSyz147064 206d62bc4baSyz147064 /* 207da14cebeSEric Cheng * 208da14cebeSEric Cheng * softmac_create() is called for each minor node during the post-attach of 209d62bc4baSyz147064 * each DDI_NT_NET device instance. Note that it is possible that a device 210d62bc4baSyz147064 * instance has two minor nodes (DLPI style-1 and style-2), so that for that 211d62bc4baSyz147064 * specific device, softmac_create() could be called twice. 212d62bc4baSyz147064 * 213d62bc4baSyz147064 * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t 214d62bc4baSyz147064 * is created to track each minor node. 215d62bc4baSyz147064 * 216d62bc4baSyz147064 * For each minor node of a legacy device, a taskq is started to finish 217d62bc4baSyz147064 * softmac_mac_register(), which will finish the rest of work (see comments 218d62bc4baSyz147064 * above softmac_mac_register()). 219da14cebeSEric Cheng * 220da14cebeSEric Cheng * softmac state machine 221da14cebeSEric Cheng * -------------------------------------------------------------------------- 222da14cebeSEric Cheng * OLD STATE EVENT NEW STATE 223da14cebeSEric Cheng * -------------------------------------------------------------------------- 224da14cebeSEric Cheng * UNINIT attach of 1st minor node ATTACH_INPROG 225da14cebeSEric Cheng * okcnt = 0 net_postattach -> softmac_create okcnt = 1 226da14cebeSEric Cheng * 227da14cebeSEric Cheng * ATTACH_INPROG attach of 2nd minor node (GLDv3) ATTACH_DONE 228da14cebeSEric Cheng * okcnt = 1 net_postattach -> softmac_create okcnt = 2 229da14cebeSEric Cheng * 230da14cebeSEric Cheng * ATTACH_INPROG attach of 2nd minor node (legacy) ATTACH_INPROG 231da14cebeSEric Cheng * okcnt = 1 net_postattach -> softmac_create okcnt = 2 232da14cebeSEric Cheng * schedule softmac_mac_register 233da14cebeSEric Cheng * 234da14cebeSEric Cheng * ATTACH_INPROG legacy device node ATTACH_DONE 235da14cebeSEric Cheng * okcnt = 2 softmac_mac_register okcnt = 2 236da14cebeSEric Cheng * 237da14cebeSEric Cheng * ATTACH_DONE detach of 1st minor node DETACH_INPROG 238da14cebeSEric Cheng * okcnt = 2 (success) okcnt = 1 239da14cebeSEric Cheng * 240da14cebeSEric Cheng * DETACH_INPROG detach of 2nd minor node UNINIT (or free) 241da14cebeSEric Cheng * okcnt = 1 (success) okcnt = 0 242da14cebeSEric Cheng * 243da14cebeSEric Cheng * ATTACH_DONE detach failure state unchanged 244da14cebeSEric Cheng * DETACH_INPROG left = okcnt 245da14cebeSEric Cheng * 246da14cebeSEric Cheng * DETACH_INPROG reattach ATTACH_INPROG 247da14cebeSEric Cheng * okcnt = 0,1 net_postattach -> softmac_create 248da14cebeSEric Cheng * 249da14cebeSEric Cheng * ATTACH_DONE reattach ATTACH_DONE 250da14cebeSEric Cheng * left != 0 net_postattach -> softmac_create left = 0 251da14cebeSEric Cheng * 252da14cebeSEric Cheng * Abbreviation notes: 253da14cebeSEric Cheng * states have SOFTMAC_ prefix, 254da14cebeSEric Cheng * okcnt - softmac_attach_okcnt, 255da14cebeSEric Cheng * left - softmac_attached_left 256d62bc4baSyz147064 */ 257da14cebeSEric Cheng 258da14cebeSEric Cheng #ifdef DEBUG 259da14cebeSEric Cheng void 260da14cebeSEric Cheng softmac_state_verify(softmac_t *softmac) 261da14cebeSEric Cheng { 262da14cebeSEric Cheng ASSERT(MUTEX_HELD(&softmac->smac_mutex)); 263da14cebeSEric Cheng 264da14cebeSEric Cheng /* 265da14cebeSEric Cheng * There are at most 2 minor nodes, one per DLPI style 266da14cebeSEric Cheng */ 267da14cebeSEric Cheng ASSERT(softmac->smac_cnt <= 2 && softmac->smac_attachok_cnt <= 2); 268da14cebeSEric Cheng 269da14cebeSEric Cheng /* 270da14cebeSEric Cheng * The smac_attachok_cnt represents the number of attaches i.e. the 271da14cebeSEric Cheng * number of times net_postattach -> softmac_create() has been called 272da14cebeSEric Cheng * for a device instance. 273da14cebeSEric Cheng */ 274da14cebeSEric Cheng ASSERT(softmac->smac_attachok_cnt == SMAC_NONZERO_NODECNT(softmac)); 275da14cebeSEric Cheng 276da14cebeSEric Cheng /* 277da14cebeSEric Cheng * softmac_create (or softmac_mac_register) -> softmac_create_datalink 278da14cebeSEric Cheng * happens only after all minor nodes have been attached 279da14cebeSEric Cheng */ 280da14cebeSEric Cheng ASSERT(softmac->smac_state != SOFTMAC_ATTACH_DONE || 281da14cebeSEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt); 282da14cebeSEric Cheng 283da14cebeSEric Cheng if (softmac->smac_attachok_cnt == 0) { 284da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_UNINIT); 285da14cebeSEric Cheng ASSERT(softmac->smac_mh == NULL); 286da14cebeSEric Cheng } else if (softmac->smac_attachok_cnt < softmac->smac_cnt) { 287da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG || 288da14cebeSEric Cheng softmac->smac_state == SOFTMAC_DETACH_INPROG); 289da14cebeSEric Cheng ASSERT(softmac->smac_mh == NULL); 290da14cebeSEric Cheng } else { 291da14cebeSEric Cheng /* 292da14cebeSEric Cheng * In the stable condition the state whould be 293da14cebeSEric Cheng * SOFTMAC_ATTACH_DONE. But there is a small transient window 294da14cebeSEric Cheng * in softmac_destroy where we change the state to 295da14cebeSEric Cheng * SOFTMAC_DETACH_INPROG and drop the lock before doing 296da14cebeSEric Cheng * the link destroy 297da14cebeSEric Cheng */ 298da14cebeSEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 299da14cebeSEric Cheng ASSERT(softmac->smac_state != SOFTMAC_UNINIT); 300da14cebeSEric Cheng } 301da14cebeSEric Cheng if (softmac->smac_mh != NULL) 302da14cebeSEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 303da14cebeSEric Cheng } 304da14cebeSEric Cheng #endif 305da14cebeSEric Cheng 306da14cebeSEric Cheng #ifdef DEBUG 307da14cebeSEric Cheng #define SOFTMAC_STATE_VERIFY(softmac) softmac_state_verify(softmac) 308da14cebeSEric Cheng #else 309da14cebeSEric Cheng #define SOFTMAC_STATE_VERIFY(softmac) 310da14cebeSEric Cheng #endif 311da14cebeSEric Cheng 312d62bc4baSyz147064 int 313d62bc4baSyz147064 softmac_create(dev_info_t *dip, dev_t dev) 314d62bc4baSyz147064 { 315d62bc4baSyz147064 char devname[MAXNAMELEN]; 316d62bc4baSyz147064 softmac_t *softmac; 317d62bc4baSyz147064 softmac_dev_t *softmac_dev = NULL; 318d62bc4baSyz147064 int index; 319d62bc4baSyz147064 int ppa, err = 0; 320d62bc4baSyz147064 321d62bc4baSyz147064 /* 322d62bc4baSyz147064 * Force the softmac driver to be attached. 323d62bc4baSyz147064 */ 324d62bc4baSyz147064 if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) { 325d62bc4baSyz147064 cmn_err(CE_WARN, "softmac_create:softmac attach fails"); 326d62bc4baSyz147064 return (ENXIO); 327d62bc4baSyz147064 } 328d62bc4baSyz147064 32961af1958SGarrett D'Amore if (GLDV3_DRV(ddi_driver_major(dip))) { 33061af1958SGarrett D'Amore minor_t minor = getminor(dev); 33161af1958SGarrett D'Amore /* 33261af1958SGarrett D'Amore * For GLDv3, we don't care about the DLPI style 2 33361af1958SGarrett D'Amore * compatibility node. (We know that all such devices 33461af1958SGarrett D'Amore * have style 1 nodes.) 33561af1958SGarrett D'Amore */ 33661af1958SGarrett D'Amore if ((strcmp(ddi_driver_name(dip), "clone") == 0) || 33761af1958SGarrett D'Amore (getmajor(dev) == ddi_name_to_major("clone")) || 33861af1958SGarrett D'Amore (minor == 0)) { 33961af1958SGarrett D'Amore return (0); 34061af1958SGarrett D'Amore } 341d62bc4baSyz147064 342d62bc4baSyz147064 /* 34361af1958SGarrett D'Amore * Likewise, we know that the minor number for DLPI style 1 34461af1958SGarrett D'Amore * nodes is constrained to a maximum value. 345d62bc4baSyz147064 */ 34661af1958SGarrett D'Amore if (minor >= DLS_MAX_MINOR) { 347d62bc4baSyz147064 return (ENOTSUP); 348d62bc4baSyz147064 } 34961af1958SGarrett D'Amore /* 35061af1958SGarrett D'Amore * Otherwise we can decode the instance from the minor number, 35161af1958SGarrett D'Amore * which allows for situations with multiple mac instances 35261af1958SGarrett D'Amore * for a single dev_info_t. 35361af1958SGarrett D'Amore */ 35461af1958SGarrett D'Amore ppa = DLS_MINOR2INST(minor); 35561af1958SGarrett D'Amore } else { 35661af1958SGarrett D'Amore /* 35761af1958SGarrett D'Amore * For legacy drivers, we just have to limit them to 35861af1958SGarrett D'Amore * two minor nodes, one style 1 and one style 2, and 35961af1958SGarrett D'Amore * we assume the ddi_get_instance() is the PPA. 36061af1958SGarrett D'Amore * Drivers that need more flexibility should be ported 36161af1958SGarrett D'Amore * to GLDv3. 36261af1958SGarrett D'Amore */ 36361af1958SGarrett D'Amore ppa = ddi_get_instance(dip); 36461af1958SGarrett D'Amore if (i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) { 36561af1958SGarrett D'Amore cmn_err(CE_WARN, "%s has more than 2 minor nodes; " 36661af1958SGarrett D'Amore "unsupported", devname); 36761af1958SGarrett D'Amore return (ENOTSUP); 36861af1958SGarrett D'Amore } 36961af1958SGarrett D'Amore } 37061af1958SGarrett D'Amore 37161af1958SGarrett D'Amore (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 372d62bc4baSyz147064 373d62bc4baSyz147064 /* 374d62bc4baSyz147064 * Check whether the softmac for the specified device already exists 375d62bc4baSyz147064 */ 376d62bc4baSyz147064 rw_enter(&softmac_hash_lock, RW_WRITER); 3775d460eafSCathy Zhou if ((mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 378d62bc4baSyz147064 (mod_hash_val_t *)&softmac)) != 0) { 379d62bc4baSyz147064 3805d460eafSCathy Zhou softmac = kmem_cache_alloc(softmac_cachep, KM_SLEEP); 381d62bc4baSyz147064 (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN); 3825d460eafSCathy Zhou 383d62bc4baSyz147064 err = mod_hash_insert(softmac_hash, 384d62bc4baSyz147064 (mod_hash_key_t)softmac->smac_devname, 385d62bc4baSyz147064 (mod_hash_val_t)softmac); 386d62bc4baSyz147064 ASSERT(err == 0); 387da14cebeSEric Cheng mutex_enter(&smac_global_lock); 388da14cebeSEric Cheng cv_broadcast(&smac_global_cv); 389da14cebeSEric Cheng mutex_exit(&smac_global_lock); 390d62bc4baSyz147064 } 391d62bc4baSyz147064 392d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex); 393da14cebeSEric Cheng SOFTMAC_STATE_VERIFY(softmac); 394da14cebeSEric Cheng if (softmac->smac_state != SOFTMAC_ATTACH_DONE) 395da14cebeSEric Cheng softmac->smac_state = SOFTMAC_ATTACH_INPROG; 396d62bc4baSyz147064 if (softmac->smac_attachok_cnt == 0) { 397d62bc4baSyz147064 /* 398d62bc4baSyz147064 * Initialize the softmac if this is the post-attach of the 399d62bc4baSyz147064 * first minor node. 400d62bc4baSyz147064 */ 401d62bc4baSyz147064 softmac->smac_flags = 0; 402d62bc4baSyz147064 softmac->smac_umajor = ddi_driver_major(dip); 403d62bc4baSyz147064 softmac->smac_uppa = ppa; 404d62bc4baSyz147064 405d62bc4baSyz147064 /* 40661af1958SGarrett D'Amore * For GLDv3, we ignore the style 2 node (see the logic 40761af1958SGarrett D'Amore * above on that), and we should have exactly one attach 40861af1958SGarrett D'Amore * per MAC instance (possibly more than one per dev_info_t). 409d62bc4baSyz147064 */ 410d62bc4baSyz147064 if (GLDV3_DRV(ddi_driver_major(dip))) { 411d62bc4baSyz147064 softmac->smac_flags |= SOFTMAC_GLDV3; 41261af1958SGarrett D'Amore softmac->smac_cnt = 1; 413d62bc4baSyz147064 } else { 414d62bc4baSyz147064 softmac->smac_cnt = 415d62bc4baSyz147064 i_ddi_minor_node_count(dip, DDI_NT_NET); 416d62bc4baSyz147064 } 417d62bc4baSyz147064 } 418d62bc4baSyz147064 419d62bc4baSyz147064 index = (getmajor(dev) == ddi_name_to_major("clone")); 420d62bc4baSyz147064 if (softmac->smac_softmac[index] != NULL) { 421d62bc4baSyz147064 /* 422da14cebeSEric Cheng * This is possible if the post_attach() is called after 423da14cebeSEric Cheng * pre_detach() fails. This seems to be a defect of the DACF 424da14cebeSEric Cheng * framework. We work around it by using a smac_attached_left 425da14cebeSEric Cheng * field that tracks this 426d62bc4baSyz147064 */ 427da14cebeSEric Cheng ASSERT(softmac->smac_attached_left != 0); 428d62bc4baSyz147064 softmac->smac_attached_left--; 429d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 430d62bc4baSyz147064 rw_exit(&softmac_hash_lock); 431d62bc4baSyz147064 return (0); 432da14cebeSEric Cheng 433d62bc4baSyz147064 } 434d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 435d62bc4baSyz147064 rw_exit(&softmac_hash_lock); 436d62bc4baSyz147064 437d62bc4baSyz147064 softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP); 438d62bc4baSyz147064 softmac_dev->sd_dev = dev; 439d62bc4baSyz147064 440da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex); 441da14cebeSEric Cheng softmac->smac_softmac[index] = softmac_dev; 442d62bc4baSyz147064 /* 443d62bc4baSyz147064 * Continue to register the mac and create the datalink only when all 444d62bc4baSyz147064 * the minor nodes are attached. 445d62bc4baSyz147064 */ 446d62bc4baSyz147064 if (++softmac->smac_attachok_cnt != softmac->smac_cnt) { 447d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 448d62bc4baSyz147064 return (0); 449d62bc4baSyz147064 } 450d62bc4baSyz147064 451d62bc4baSyz147064 /* 4520dc974a9SCathy Zhou * All of the minor nodes have been attached; start a taskq 453da14cebeSEric Cheng * to do the rest of the work. We use a taskq instead of 4540dc974a9SCathy Zhou * doing the work here because: 455d62bc4baSyz147064 * 456da14cebeSEric Cheng * We could be called as a result of a open() system call 4570dc974a9SCathy Zhou * where spec_open() already SLOCKED the snode. Using a taskq 4580dc974a9SCathy Zhou * sidesteps the risk that our ldi_open_by_dev() call would 4590dc974a9SCathy Zhou * deadlock trying to set SLOCKED on the snode again. 4600dc974a9SCathy Zhou * 461da14cebeSEric Cheng * The devfs design requires that the downcalls don't use any 462da14cebeSEric Cheng * interruptible cv_wait which happens when we do door upcalls. 463da14cebeSEric Cheng * Otherwise the downcalls which may be holding devfs resources 464da14cebeSEric Cheng * may cause a deadlock if the thread is stopped. Also we need to make 465da14cebeSEric Cheng * sure these downcalls into softmac_create or softmac_destroy 466da14cebeSEric Cheng * don't cv_wait on any devfs related condition. Thus softmac_destroy 467da14cebeSEric Cheng * returns EBUSY if the asynchronous threads started in softmac_create 468da14cebeSEric Cheng * haven't finished. 469d62bc4baSyz147064 */ 47065041820SCathy Zhou (void) taskq_dispatch(system_taskq, softmac_create_task, 47165041820SCathy Zhou softmac, TQ_SLEEP); 472d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 473d62bc4baSyz147064 return (0); 474d62bc4baSyz147064 } 475d62bc4baSyz147064 476d62bc4baSyz147064 static boolean_t 477d62bc4baSyz147064 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 478d62bc4baSyz147064 { 479d62bc4baSyz147064 softmac_t *softmac = arg; 480d62bc4baSyz147064 481d62bc4baSyz147064 if (!(softmac->smac_capab_flags & cap)) 482d62bc4baSyz147064 return (B_FALSE); 483d62bc4baSyz147064 484d62bc4baSyz147064 switch (cap) { 485d62bc4baSyz147064 case MAC_CAPAB_HCKSUM: { 486d62bc4baSyz147064 uint32_t *txflags = cap_data; 487d62bc4baSyz147064 488d62bc4baSyz147064 *txflags = softmac->smac_hcksum_txflags; 489d62bc4baSyz147064 break; 490d62bc4baSyz147064 } 491d62bc4baSyz147064 case MAC_CAPAB_LEGACY: { 492d62bc4baSyz147064 mac_capab_legacy_t *legacy = cap_data; 493d62bc4baSyz147064 4945d460eafSCathy Zhou /* 4955d460eafSCathy Zhou * The caller is not interested in the details. 4965d460eafSCathy Zhou */ 4975d460eafSCathy Zhou if (legacy == NULL) 4985d460eafSCathy Zhou break; 4995d460eafSCathy Zhou 500d62bc4baSyz147064 legacy->ml_unsup_note = ~softmac->smac_notifications & 501d62bc4baSyz147064 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED); 5025d460eafSCathy Zhou legacy->ml_active_set = softmac_active_set; 5035d460eafSCathy Zhou legacy->ml_active_clear = softmac_active_clear; 5045d460eafSCathy Zhou legacy->ml_fastpath_disable = softmac_fastpath_disable; 5055d460eafSCathy Zhou legacy->ml_fastpath_enable = softmac_fastpath_enable; 506d62bc4baSyz147064 legacy->ml_dev = makedevice(softmac->smac_umajor, 507d62bc4baSyz147064 softmac->smac_uppa + 1); 508d62bc4baSyz147064 break; 509d62bc4baSyz147064 } 510d62bc4baSyz147064 511d62bc4baSyz147064 /* 512d62bc4baSyz147064 * For the capabilities below, there's nothing for us to fill in; 513d62bc4baSyz147064 * simply return B_TRUE if we support it. 514d62bc4baSyz147064 */ 515d62bc4baSyz147064 case MAC_CAPAB_NO_ZCOPY: 516d62bc4baSyz147064 case MAC_CAPAB_NO_NATIVEVLAN: 517d62bc4baSyz147064 default: 518d62bc4baSyz147064 break; 519d62bc4baSyz147064 } 520d62bc4baSyz147064 return (B_TRUE); 521d62bc4baSyz147064 } 522d62bc4baSyz147064 523d62bc4baSyz147064 static int 524d62bc4baSyz147064 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp) 525d62bc4baSyz147064 { 526d62bc4baSyz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID; 527d62bc4baSyz147064 uint32_t media; 528d62bc4baSyz147064 int err; 529d62bc4baSyz147064 530d62bc4baSyz147064 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media, 531d62bc4baSyz147064 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) { 532d62bc4baSyz147064 *linkidp = linkid; 533d62bc4baSyz147064 } 534d62bc4baSyz147064 535d62bc4baSyz147064 if (err == EEXIST) { 536d62bc4baSyz147064 /* 537d62bc4baSyz147064 * There is a link name conflict. Either: 538d62bc4baSyz147064 * 539d62bc4baSyz147064 * - An existing link with the same device name with a 540d62bc4baSyz147064 * different media type from of the given type. 541d62bc4baSyz147064 * Mark this link back to persistent only; or 542d62bc4baSyz147064 * 543d62bc4baSyz147064 * - We cannot assign the "suggested" name because 544d62bc4baSyz147064 * GLDv3 and therefore vanity naming is not supported 545d62bc4baSyz147064 * for this link type. Delete this link's <link name, 546d62bc4baSyz147064 * linkid> mapping. 547d62bc4baSyz147064 */ 548d62bc4baSyz147064 if (media != softmac->smac_media) { 549d62bc4baSyz147064 cmn_err(CE_WARN, "%s device %s conflicts with " 550d62bc4baSyz147064 "existing %s device %s.", 551d62bc4baSyz147064 dl_mactypestr(softmac->smac_media), 552d62bc4baSyz147064 softmac->smac_devname, dl_mactypestr(media), 553d62bc4baSyz147064 softmac->smac_devname); 554d62bc4baSyz147064 (void) dls_mgmt_destroy(linkid, B_FALSE); 555d62bc4baSyz147064 } else { 556d62bc4baSyz147064 cmn_err(CE_WARN, "link name %s is already in-use.", 557d62bc4baSyz147064 softmac->smac_devname); 558d62bc4baSyz147064 (void) dls_mgmt_destroy(linkid, B_TRUE); 559d62bc4baSyz147064 } 560d62bc4baSyz147064 561d62bc4baSyz147064 cmn_err(CE_WARN, "%s device might not be available " 562d62bc4baSyz147064 "for use.", softmac->smac_devname); 563d62bc4baSyz147064 cmn_err(CE_WARN, "See dladm(1M) for more information."); 564d62bc4baSyz147064 } 565d62bc4baSyz147064 566d62bc4baSyz147064 return (err); 567d62bc4baSyz147064 } 568d62bc4baSyz147064 569d62bc4baSyz147064 /* 570d62bc4baSyz147064 * This function: 571d62bc4baSyz147064 * 1. provides the link's media type to dlmgmtd. 572d62bc4baSyz147064 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 573d62bc4baSyz147064 */ 574d62bc4baSyz147064 static int 575d62bc4baSyz147064 softmac_create_datalink(softmac_t *softmac) 576d62bc4baSyz147064 { 577d62bc4baSyz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID; 578d62bc4baSyz147064 int err; 579d62bc4baSyz147064 580d62bc4baSyz147064 /* 5810dc974a9SCathy Zhou * Inform dlmgmtd of this link so that softmac_hold_device() is able 5820dc974a9SCathy Zhou * to know the existence of this link. If this failed with EBADF, 5830dc974a9SCathy Zhou * it might be because dlmgmtd was not started in time (e.g., 5840dc974a9SCathy Zhou * diskless boot); ignore the failure and continue to create 5850dc974a9SCathy Zhou * the GLDv3 datalink if needed. 586d62bc4baSyz147064 */ 5870dc974a9SCathy Zhou err = dls_mgmt_create(softmac->smac_devname, 5880dc974a9SCathy Zhou makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 5890dc974a9SCathy Zhou DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid); 5900dc974a9SCathy Zhou if (err != 0 && err != EBADF) 5910dc974a9SCathy Zhou return (err); 5920dc974a9SCathy Zhou 5930dc974a9SCathy Zhou /* 5940dc974a9SCathy Zhou * Provide the media type of the physical link to dlmgmtd. 5950dc974a9SCathy Zhou */ 5960dc974a9SCathy Zhou if ((err != EBADF) && 5970dc974a9SCathy Zhou ((err = softmac_update_info(softmac, &linkid)) != 0)) { 598d62bc4baSyz147064 return (err); 599d62bc4baSyz147064 } 600d62bc4baSyz147064 601d62bc4baSyz147064 /* 602d62bc4baSyz147064 * Create the GLDv3 datalink. 603d62bc4baSyz147064 */ 6042b24ab6bSSebastien Roy if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 6052b24ab6bSSebastien Roy err = dls_devnet_create(softmac->smac_mh, linkid, 6062b24ab6bSSebastien Roy crgetzoneid(CRED())); 6072b24ab6bSSebastien Roy if (err != 0) { 608d62bc4baSyz147064 cmn_err(CE_WARN, "dls_devnet_create failed for %s", 609d62bc4baSyz147064 softmac->smac_devname); 610d62bc4baSyz147064 return (err); 611d62bc4baSyz147064 } 6122b24ab6bSSebastien Roy } 613d62bc4baSyz147064 614da14cebeSEric Cheng if (linkid == DATALINK_INVALID_LINKID) { 615da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex); 616d62bc4baSyz147064 softmac->smac_flags |= SOFTMAC_NEED_RECREATE; 617da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 618da14cebeSEric Cheng } 619d62bc4baSyz147064 620d62bc4baSyz147064 return (0); 621d62bc4baSyz147064 } 622d62bc4baSyz147064 6230dc974a9SCathy Zhou static void 6240dc974a9SCathy Zhou softmac_create_task(void *arg) 6250dc974a9SCathy Zhou { 6260dc974a9SCathy Zhou softmac_t *softmac = arg; 6270dc974a9SCathy Zhou mac_handle_t mh; 6280dc974a9SCathy Zhou int err; 6290dc974a9SCathy Zhou 6300dc974a9SCathy Zhou if (!GLDV3_DRV(softmac->smac_umajor)) { 6310dc974a9SCathy Zhou softmac_mac_register(softmac); 6320dc974a9SCathy Zhou return; 6330dc974a9SCathy Zhou } 6340dc974a9SCathy Zhou 6350dc974a9SCathy Zhou if ((err = mac_open(softmac->smac_devname, &mh)) != 0) 6360dc974a9SCathy Zhou goto done; 6370dc974a9SCathy Zhou 6380dc974a9SCathy Zhou mutex_enter(&softmac->smac_mutex); 6390dc974a9SCathy Zhou softmac->smac_media = (mac_info(mh))->mi_nativemedia; 6400dc974a9SCathy Zhou softmac->smac_mh = mh; 641da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 6420dc974a9SCathy Zhou 6430dc974a9SCathy Zhou /* 6440dc974a9SCathy Zhou * We can safely release the reference on the mac because 6450dc974a9SCathy Zhou * this mac will only be unregistered and destroyed when 6460dc974a9SCathy Zhou * the device detaches, and the softmac will be destroyed 6470dc974a9SCathy Zhou * before then (in the pre-detach routine of the device). 6480dc974a9SCathy Zhou */ 6490dc974a9SCathy Zhou mac_close(mh); 6500dc974a9SCathy Zhou 6510dc974a9SCathy Zhou /* 6520dc974a9SCathy Zhou * Create the GLDv3 datalink for this mac. 6530dc974a9SCathy Zhou */ 6540dc974a9SCathy Zhou err = softmac_create_datalink(softmac); 6550dc974a9SCathy Zhou 6560dc974a9SCathy Zhou done: 65765041820SCathy Zhou mutex_enter(&softmac->smac_mutex); 65865041820SCathy Zhou if (err != 0) 659da14cebeSEric Cheng softmac->smac_mh = NULL; 6600dc974a9SCathy Zhou softmac->smac_attacherr = err; 661da14cebeSEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE; 6620dc974a9SCathy Zhou cv_broadcast(&softmac->smac_cv); 6630dc974a9SCathy Zhou mutex_exit(&softmac->smac_mutex); 6640dc974a9SCathy Zhou } 6650dc974a9SCathy Zhou 666d62bc4baSyz147064 /* 667d62bc4baSyz147064 * This function is only called for legacy devices. It: 668d62bc4baSyz147064 * 1. registers the MAC for the legacy devices whose media type is supported 669d62bc4baSyz147064 * by the GLDv3 framework. 670d62bc4baSyz147064 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 671d62bc4baSyz147064 */ 672d62bc4baSyz147064 static void 6730dc974a9SCathy Zhou softmac_mac_register(softmac_t *softmac) 674d62bc4baSyz147064 { 675d62bc4baSyz147064 softmac_dev_t *softmac_dev; 676d62bc4baSyz147064 dev_t dev; 677d62bc4baSyz147064 ldi_handle_t lh = NULL; 678d62bc4baSyz147064 ldi_ident_t li = NULL; 679d62bc4baSyz147064 int index; 680d62bc4baSyz147064 boolean_t native_vlan = B_FALSE; 681d62bc4baSyz147064 int err; 682d62bc4baSyz147064 683d62bc4baSyz147064 /* 684d62bc4baSyz147064 * Note that we do not need any locks to access this softmac pointer, 685d62bc4baSyz147064 * as softmac_destroy() will wait until this function is called. 686d62bc4baSyz147064 */ 687d62bc4baSyz147064 ASSERT(softmac != NULL); 688da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 689da14cebeSEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt); 690d62bc4baSyz147064 691d62bc4baSyz147064 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) { 692d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex); 693d62bc4baSyz147064 goto done; 694d62bc4baSyz147064 } 695d62bc4baSyz147064 696d62bc4baSyz147064 /* 697d62bc4baSyz147064 * Determine whether this legacy device support VLANs by opening 698d62bc4baSyz147064 * the style-2 device node (if it exists) and attaching to a VLAN 699d62bc4baSyz147064 * PPA (1000 + ppa). 700d62bc4baSyz147064 */ 701d62bc4baSyz147064 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor); 702d62bc4baSyz147064 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 703d62bc4baSyz147064 if (err == 0) { 704d62bc4baSyz147064 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0) 705d62bc4baSyz147064 native_vlan = B_TRUE; 706d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 707d62bc4baSyz147064 } 708d62bc4baSyz147064 709d62bc4baSyz147064 err = EINVAL; 710d62bc4baSyz147064 for (index = 0; index < 2; index++) { 711d62bc4baSyz147064 dl_info_ack_t dlia; 712d62bc4baSyz147064 dl_error_ack_t dlea; 713d62bc4baSyz147064 uint32_t notes; 714d62bc4baSyz147064 struct strioctl iocb; 715d62bc4baSyz147064 uint32_t margin; 716d62bc4baSyz147064 int rval; 717d62bc4baSyz147064 718d62bc4baSyz147064 if ((softmac_dev = softmac->smac_softmac[index]) == NULL) 719d62bc4baSyz147064 continue; 720d62bc4baSyz147064 721d62bc4baSyz147064 softmac->smac_dev = dev = softmac_dev->sd_dev; 722d62bc4baSyz147064 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, 723d62bc4baSyz147064 li) != 0) { 724d62bc4baSyz147064 continue; 725d62bc4baSyz147064 } 726d62bc4baSyz147064 727d62bc4baSyz147064 /* 728d62bc4baSyz147064 * Pop all the intermediate modules in order to negotiate 729d62bc4baSyz147064 * capabilities correctly. 730d62bc4baSyz147064 */ 731d62bc4baSyz147064 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 732d62bc4baSyz147064 ; 733d62bc4baSyz147064 734d62bc4baSyz147064 /* DLPI style-1 or DLPI style-2? */ 735d62bc4baSyz147064 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) { 736d62bc4baSyz147064 if (rval == ENOTSUP) { 737d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: received " 738d62bc4baSyz147064 "DL_ERROR_ACK to DL_INFO_ACK; " 739d62bc4baSyz147064 "DLPI errno 0x%x, UNIX errno %d", 740d62bc4baSyz147064 dlea.dl_errno, dlea.dl_unix_errno); 741d62bc4baSyz147064 } 742d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 743d62bc4baSyz147064 continue; 744d62bc4baSyz147064 } 745d62bc4baSyz147064 746d62bc4baSyz147064 /* 747d62bc4baSyz147064 * Currently only DL_ETHER has GLDv3 mac plugin support. 748d62bc4baSyz147064 * For media types that GLDv3 does not support, create a 749d62bc4baSyz147064 * link id for it. 750d62bc4baSyz147064 */ 751d62bc4baSyz147064 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) { 752d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 753d62bc4baSyz147064 err = 0; 754d62bc4baSyz147064 break; 755d62bc4baSyz147064 } 756d62bc4baSyz147064 757d62bc4baSyz147064 if ((dlia.dl_provider_style == DL_STYLE2) && 758d62bc4baSyz147064 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) { 759d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 760d62bc4baSyz147064 continue; 761d62bc4baSyz147064 } 762d62bc4baSyz147064 763d62bc4baSyz147064 if ((rval = dl_bind(lh, 0, NULL)) != 0) { 764d62bc4baSyz147064 if (rval == ENOTSUP) { 765d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: received " 766d62bc4baSyz147064 "DL_ERROR_ACK to DL_BIND_ACK; " 767d62bc4baSyz147064 "DLPI errno 0x%x, UNIX errno %d", 768d62bc4baSyz147064 dlea.dl_errno, dlea.dl_unix_errno); 769d62bc4baSyz147064 } 770d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 771d62bc4baSyz147064 continue; 772d62bc4baSyz147064 } 773d62bc4baSyz147064 774d62bc4baSyz147064 /* 775d62bc4baSyz147064 * Call dl_info() after dl_bind() because some drivers only 776d62bc4baSyz147064 * provide correct information (e.g. MAC address) once bound. 777d62bc4baSyz147064 */ 778d62bc4baSyz147064 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr); 779d62bc4baSyz147064 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr, 780d62bc4baSyz147064 &softmac->smac_addrlen, &dlea)) != 0) { 781d62bc4baSyz147064 if (rval == ENOTSUP) { 782d62bc4baSyz147064 cmn_err(CE_NOTE, "softmac: received " 783d62bc4baSyz147064 "DL_ERROR_ACK to DL_INFO_ACK; " 784d62bc4baSyz147064 "DLPI errno 0x%x, UNIX errno %d", 785d62bc4baSyz147064 dlea.dl_errno, dlea.dl_unix_errno); 786d62bc4baSyz147064 } 787d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 788d62bc4baSyz147064 continue; 789d62bc4baSyz147064 } 790d62bc4baSyz147064 791d62bc4baSyz147064 softmac->smac_style = dlia.dl_provider_style; 792d62bc4baSyz147064 softmac->smac_saplen = ABS(dlia.dl_sap_length); 793d62bc4baSyz147064 softmac->smac_min_sdu = dlia.dl_min_sdu; 794d62bc4baSyz147064 softmac->smac_max_sdu = dlia.dl_max_sdu; 795d62bc4baSyz147064 796d62bc4baSyz147064 if ((softmac->smac_saplen != sizeof (uint16_t)) || 797d62bc4baSyz147064 (softmac->smac_addrlen != ETHERADDRL) || 798d62bc4baSyz147064 (dlia.dl_brdcst_addr_length != ETHERADDRL) || 799d62bc4baSyz147064 (dlia.dl_brdcst_addr_offset == 0)) { 800d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 801d62bc4baSyz147064 continue; 802d62bc4baSyz147064 } 803d62bc4baSyz147064 804d62bc4baSyz147064 /* 805d62bc4baSyz147064 * Check other DLPI capabilities. Note that this must be after 806d62bc4baSyz147064 * dl_bind() because some drivers return DL_ERROR_ACK if the 807d62bc4baSyz147064 * stream is not bound. It is also before mac_register(), so 808d62bc4baSyz147064 * we don't need any lock protection here. 809d62bc4baSyz147064 */ 810d62bc4baSyz147064 softmac->smac_capab_flags = 811da14cebeSEric Cheng (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY); 812d62bc4baSyz147064 813d62bc4baSyz147064 softmac->smac_no_capability_req = B_FALSE; 814d62bc4baSyz147064 if (softmac_fill_capab(lh, softmac) != 0) 815d62bc4baSyz147064 softmac->smac_no_capability_req = B_TRUE; 816d62bc4baSyz147064 817d62bc4baSyz147064 /* 818d62bc4baSyz147064 * Check the margin of the underlying driver. 819d62bc4baSyz147064 */ 820d62bc4baSyz147064 margin = 0; 821d62bc4baSyz147064 iocb.ic_cmd = DLIOCMARGININFO; 822d62bc4baSyz147064 iocb.ic_timout = INFTIM; 823d62bc4baSyz147064 iocb.ic_len = sizeof (margin); 824d62bc4baSyz147064 iocb.ic_dp = (char *)&margin; 825d62bc4baSyz147064 softmac->smac_margin = 0; 826d62bc4baSyz147064 827d62bc4baSyz147064 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred, 828d62bc4baSyz147064 &rval) == 0) { 829d62bc4baSyz147064 softmac->smac_margin = margin; 830d62bc4baSyz147064 } 831d62bc4baSyz147064 832d62bc4baSyz147064 /* 833d62bc4baSyz147064 * If the legacy driver doesn't support DLIOCMARGININFO, but 834d62bc4baSyz147064 * it can support native VLAN, correct its margin value to 4. 835d62bc4baSyz147064 */ 836d62bc4baSyz147064 if (native_vlan) { 837d62bc4baSyz147064 if (softmac->smac_margin == 0) 838d62bc4baSyz147064 softmac->smac_margin = VLAN_TAGSZ; 839d62bc4baSyz147064 } else { 840d62bc4baSyz147064 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN; 841d62bc4baSyz147064 } 842d62bc4baSyz147064 843d62bc4baSyz147064 /* 844d62bc4baSyz147064 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP. 845d62bc4baSyz147064 */ 846d62bc4baSyz147064 softmac->smac_notifications = 0; 847d62bc4baSyz147064 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN; 848d62bc4baSyz147064 switch (dl_notify(lh, ¬es, NULL)) { 849d62bc4baSyz147064 case 0: 850d62bc4baSyz147064 softmac->smac_notifications = notes; 851d62bc4baSyz147064 break; 852d62bc4baSyz147064 case ENOTSUP: 853d62bc4baSyz147064 break; 854d62bc4baSyz147064 default: 855d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 856d62bc4baSyz147064 continue; 857d62bc4baSyz147064 } 858d62bc4baSyz147064 859d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 860d62bc4baSyz147064 err = 0; 861d62bc4baSyz147064 break; 862d62bc4baSyz147064 } 863d62bc4baSyz147064 ldi_ident_release(li); 864d62bc4baSyz147064 865d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex); 866d62bc4baSyz147064 867d62bc4baSyz147064 if (err != 0) 868d62bc4baSyz147064 goto done; 869d62bc4baSyz147064 870d62bc4baSyz147064 if (softmac->smac_media != DL_ETHER) 871d62bc4baSyz147064 softmac->smac_flags |= SOFTMAC_NOSUPP; 872d62bc4baSyz147064 873d62bc4baSyz147064 /* 874d62bc4baSyz147064 * Finally, we're ready to register ourselves with the MAC layer 875d62bc4baSyz147064 * interface; if this succeeds, we're all ready to start() 876d62bc4baSyz147064 */ 877d62bc4baSyz147064 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 878d62bc4baSyz147064 mac_register_t *macp; 879d62bc4baSyz147064 880d62bc4baSyz147064 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 881d62bc4baSyz147064 err = ENOMEM; 882d62bc4baSyz147064 goto done; 883d62bc4baSyz147064 } 884d62bc4baSyz147064 885d62bc4baSyz147064 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 886d62bc4baSyz147064 macp->m_driver = softmac; 887d62bc4baSyz147064 macp->m_dip = softmac_dip; 888d62bc4baSyz147064 889d62bc4baSyz147064 macp->m_margin = softmac->smac_margin; 890d62bc4baSyz147064 macp->m_src_addr = softmac->smac_unicst_addr; 891d62bc4baSyz147064 macp->m_min_sdu = softmac->smac_min_sdu; 892d62bc4baSyz147064 macp->m_max_sdu = softmac->smac_max_sdu; 893d62bc4baSyz147064 macp->m_callbacks = &softmac_m_callbacks; 894d62bc4baSyz147064 macp->m_instance = (uint_t)-1; 895d62bc4baSyz147064 896d62bc4baSyz147064 err = mac_register(macp, &softmac->smac_mh); 897d62bc4baSyz147064 mac_free(macp); 898d62bc4baSyz147064 if (err != 0) { 899d62bc4baSyz147064 cmn_err(CE_WARN, "mac_register failed for %s", 900d62bc4baSyz147064 softmac->smac_devname); 901d62bc4baSyz147064 goto done; 902d62bc4baSyz147064 } 903d62bc4baSyz147064 } 904da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 905d62bc4baSyz147064 906d62bc4baSyz147064 /* 907d62bc4baSyz147064 * Try to create the datalink for this softmac. 908d62bc4baSyz147064 */ 909d62bc4baSyz147064 if ((err = softmac_create_datalink(softmac)) != 0) { 9105d460eafSCathy Zhou if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) 911d62bc4baSyz147064 (void) mac_unregister(softmac->smac_mh); 9125d460eafSCathy Zhou mutex_enter(&softmac->smac_mutex); 913d62bc4baSyz147064 softmac->smac_mh = NULL; 9145d460eafSCathy Zhou goto done; 915d62bc4baSyz147064 } 916da14cebeSEric Cheng /* 917da14cebeSEric Cheng * If succeed, create the thread which handles the DL_NOTIFY_IND from 918da14cebeSEric Cheng * the lower stream. 919da14cebeSEric Cheng */ 9205d460eafSCathy Zhou mutex_enter(&softmac->smac_mutex); 921da14cebeSEric Cheng if (softmac->smac_mh != NULL) { 922da14cebeSEric Cheng softmac->smac_notify_thread = thread_create(NULL, 0, 923da14cebeSEric Cheng softmac_notify_thread, softmac, 0, &p0, 924da14cebeSEric Cheng TS_RUN, minclsyspri); 925da14cebeSEric Cheng } 926d62bc4baSyz147064 927d62bc4baSyz147064 done: 928da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 929da14cebeSEric Cheng softmac->smac_attachok_cnt == softmac->smac_cnt); 930da14cebeSEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE; 931d62bc4baSyz147064 softmac->smac_attacherr = err; 932d62bc4baSyz147064 cv_broadcast(&softmac->smac_cv); 933d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 934d62bc4baSyz147064 } 935d62bc4baSyz147064 936d62bc4baSyz147064 int 937d62bc4baSyz147064 softmac_destroy(dev_info_t *dip, dev_t dev) 938d62bc4baSyz147064 { 939d62bc4baSyz147064 char devname[MAXNAMELEN]; 940d62bc4baSyz147064 softmac_t *softmac; 941d62bc4baSyz147064 softmac_dev_t *softmac_dev; 942d62bc4baSyz147064 int index; 943d62bc4baSyz147064 int ppa, err; 944d62bc4baSyz147064 datalink_id_t linkid; 945da14cebeSEric Cheng mac_handle_t smac_mh; 946da14cebeSEric Cheng uint32_t smac_flags; 947d62bc4baSyz147064 94861af1958SGarrett D'Amore if (GLDV3_DRV(ddi_driver_major(dip))) { 94961af1958SGarrett D'Amore minor_t minor = getminor(dev); 95061af1958SGarrett D'Amore /* 95161af1958SGarrett D'Amore * For an explanation of this logic, see the 95261af1958SGarrett D'Amore * equivalent code in softmac_create. 95361af1958SGarrett D'Amore */ 95461af1958SGarrett D'Amore if ((strcmp(ddi_driver_name(dip), "clone") == 0) || 95561af1958SGarrett D'Amore (getmajor(dev) == ddi_name_to_major("clone")) || 95661af1958SGarrett D'Amore (minor == 0)) { 95761af1958SGarrett D'Amore return (0); 95861af1958SGarrett D'Amore } 95961af1958SGarrett D'Amore if (minor >= DLS_MAX_MINOR) { 96061af1958SGarrett D'Amore return (ENOTSUP); 96161af1958SGarrett D'Amore } 96261af1958SGarrett D'Amore ppa = DLS_MINOR2INST(minor); 96361af1958SGarrett D'Amore } else { 964d62bc4baSyz147064 ppa = ddi_get_instance(dip); 96561af1958SGarrett D'Amore } 96661af1958SGarrett D'Amore 967d62bc4baSyz147064 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 968d62bc4baSyz147064 969da14cebeSEric Cheng /* 970da14cebeSEric Cheng * We are called only from the predetach entry point. The DACF 971da14cebeSEric Cheng * framework ensures there can't be a concurrent postattach call 972da14cebeSEric Cheng * for the same softmac. The softmac found out from the modhash 973da14cebeSEric Cheng * below can't vanish beneath us since this is the only place where 974da14cebeSEric Cheng * it is deleted. 975da14cebeSEric Cheng */ 976d62bc4baSyz147064 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 977d62bc4baSyz147064 (mod_hash_val_t *)&softmac); 978d62bc4baSyz147064 ASSERT(err == 0); 979d62bc4baSyz147064 980d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex); 981da14cebeSEric Cheng SOFTMAC_STATE_VERIFY(softmac); 982d62bc4baSyz147064 983d62bc4baSyz147064 /* 984d62bc4baSyz147064 * Fail the predetach routine if this softmac is in-use. 985da14cebeSEric Cheng * Make sure these downcalls into softmac_create or softmac_destroy 986da14cebeSEric Cheng * don't cv_wait on any devfs related condition. Thus softmac_destroy 987da14cebeSEric Cheng * returns EBUSY if the asynchronous thread started in softmac_create 988da14cebeSEric Cheng * hasn't finished 989d62bc4baSyz147064 */ 990da14cebeSEric Cheng if ((softmac->smac_hold_cnt != 0) || 991da14cebeSEric Cheng (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) { 992d62bc4baSyz147064 softmac->smac_attached_left = softmac->smac_attachok_cnt; 993d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 994d62bc4baSyz147064 return (EBUSY); 995d62bc4baSyz147064 } 996d62bc4baSyz147064 997d62bc4baSyz147064 /* 998d62bc4baSyz147064 * Even if the predetach of one minor node has already failed 999d62bc4baSyz147064 * (smac_attached_left is not 0), the DACF framework will continue 1000d62bc4baSyz147064 * to call the predetach routines of the other minor nodes, 1001d62bc4baSyz147064 * so we fail these calls here. 1002d62bc4baSyz147064 */ 1003d62bc4baSyz147064 if (softmac->smac_attached_left != 0) { 1004d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 1005d62bc4baSyz147064 return (EBUSY); 1006d62bc4baSyz147064 } 1007d62bc4baSyz147064 1008da14cebeSEric Cheng smac_mh = softmac->smac_mh; 1009da14cebeSEric Cheng smac_flags = softmac->smac_flags; 1010da14cebeSEric Cheng softmac->smac_state = SOFTMAC_DETACH_INPROG; 1011da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 1012d62bc4baSyz147064 1013da14cebeSEric Cheng if (smac_mh != NULL) { 1014d62bc4baSyz147064 /* 1015da14cebeSEric Cheng * This is the first minor node that is being detached for this 1016da14cebeSEric Cheng * softmac. 1017d62bc4baSyz147064 */ 1018da14cebeSEric Cheng ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 1019da14cebeSEric Cheng if (!(smac_flags & SOFTMAC_NOSUPP)) { 1020da14cebeSEric Cheng if ((err = dls_devnet_destroy(smac_mh, &linkid, 1021da14cebeSEric Cheng B_FALSE)) != 0) { 1022da14cebeSEric Cheng goto error; 1023d62bc4baSyz147064 } 1024d62bc4baSyz147064 } 1025d62bc4baSyz147064 /* 1026d62bc4baSyz147064 * If softmac_mac_register() succeeds in registering the mac 1027d62bc4baSyz147064 * of the legacy device, unregister it. 1028d62bc4baSyz147064 */ 1029da14cebeSEric Cheng if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) { 1030da14cebeSEric Cheng if ((err = mac_disable_nowait(smac_mh)) != 0) { 10312b24ab6bSSebastien Roy (void) dls_devnet_create(smac_mh, linkid, 10322b24ab6bSSebastien Roy crgetzoneid(CRED())); 1033da14cebeSEric Cheng goto error; 1034d62bc4baSyz147064 } 1035da14cebeSEric Cheng /* 1036da14cebeSEric Cheng * Ask softmac_notify_thread to quit, and wait for 1037da14cebeSEric Cheng * that to be done. 1038da14cebeSEric Cheng */ 1039da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex); 1040da14cebeSEric Cheng softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT; 1041da14cebeSEric Cheng cv_broadcast(&softmac->smac_cv); 1042da14cebeSEric Cheng while (softmac->smac_notify_thread != NULL) { 1043da14cebeSEric Cheng cv_wait(&softmac->smac_cv, 1044da14cebeSEric Cheng &softmac->smac_mutex); 1045da14cebeSEric Cheng } 1046da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 1047da14cebeSEric Cheng VERIFY(mac_unregister(smac_mh) == 0); 1048d62bc4baSyz147064 } 1049d62bc4baSyz147064 softmac->smac_mh = NULL; 1050d62bc4baSyz147064 } 1051d62bc4baSyz147064 1052d62bc4baSyz147064 /* 1053d62bc4baSyz147064 * Free softmac_dev 1054d62bc4baSyz147064 */ 1055da14cebeSEric Cheng rw_enter(&softmac_hash_lock, RW_WRITER); 1056da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex); 1057da14cebeSEric Cheng 1058da14cebeSEric Cheng ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG && 1059da14cebeSEric Cheng softmac->smac_attachok_cnt != 0); 1060da14cebeSEric Cheng softmac->smac_mh = NULL; 1061d62bc4baSyz147064 index = (getmajor(dev) == ddi_name_to_major("clone")); 1062d62bc4baSyz147064 softmac_dev = softmac->smac_softmac[index]; 1063d62bc4baSyz147064 ASSERT(softmac_dev != NULL); 1064d62bc4baSyz147064 softmac->smac_softmac[index] = NULL; 1065d62bc4baSyz147064 kmem_free(softmac_dev, sizeof (softmac_dev_t)); 1066d62bc4baSyz147064 1067d62bc4baSyz147064 if (--softmac->smac_attachok_cnt == 0) { 1068d62bc4baSyz147064 mod_hash_val_t hashval; 1069d62bc4baSyz147064 1070da14cebeSEric Cheng softmac->smac_state = SOFTMAC_UNINIT; 1071da14cebeSEric Cheng if (softmac->smac_hold_cnt != 0) { 1072da14cebeSEric Cheng /* 1073da14cebeSEric Cheng * Someone did a softmac_hold_device while we dropped 1074da14cebeSEric Cheng * the locks. Leave the softmac itself intact which 1075da14cebeSEric Cheng * will be reused by the reattach 1076da14cebeSEric Cheng */ 1077da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 1078da14cebeSEric Cheng rw_exit(&softmac_hash_lock); 1079da14cebeSEric Cheng return (0); 1080da14cebeSEric Cheng } 1081d62bc4baSyz147064 err = mod_hash_remove(softmac_hash, 1082d62bc4baSyz147064 (mod_hash_key_t)devname, 1083d62bc4baSyz147064 (mod_hash_val_t *)&hashval); 1084d62bc4baSyz147064 ASSERT(err == 0); 1085d62bc4baSyz147064 1086d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 1087d62bc4baSyz147064 rw_exit(&softmac_hash_lock); 10885d460eafSCathy Zhou ASSERT(softmac->smac_fp_disable_clients == 0); 10895d460eafSCathy Zhou softmac->smac_fastpath_admin_disabled = B_FALSE; 10905d460eafSCathy Zhou kmem_cache_free(softmac_cachep, softmac); 1091d62bc4baSyz147064 return (0); 1092d62bc4baSyz147064 } 1093d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 1094d62bc4baSyz147064 rw_exit(&softmac_hash_lock); 1095da14cebeSEric Cheng return (0); 1096da14cebeSEric Cheng 1097da14cebeSEric Cheng error: 1098da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex); 1099da14cebeSEric Cheng softmac->smac_attached_left = softmac->smac_attachok_cnt; 1100da14cebeSEric Cheng softmac->smac_state = SOFTMAC_ATTACH_DONE; 1101da14cebeSEric Cheng cv_broadcast(&softmac->smac_cv); 1102da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 1103d62bc4baSyz147064 return (err); 1104d62bc4baSyz147064 } 1105d62bc4baSyz147064 1106d62bc4baSyz147064 /* 1107d62bc4baSyz147064 * This function is called as the result of a newly started dlmgmtd daemon. 1108d62bc4baSyz147064 * 1109d62bc4baSyz147064 * We walk through every softmac that was created but failed to notify 1110d62bc4baSyz147064 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs 1111d62bc4baSyz147064 * when softmacs are created before dlmgmtd is ready. For example, during 1112d62bc4baSyz147064 * diskless boot, a network device is used (and therefore attached) before 1113d62bc4baSyz147064 * the datalink-management service starts dlmgmtd. 1114d62bc4baSyz147064 */ 1115d62bc4baSyz147064 /* ARGSUSED */ 1116d62bc4baSyz147064 static uint_t 1117d62bc4baSyz147064 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1118d62bc4baSyz147064 { 1119d62bc4baSyz147064 softmac_t *softmac = (softmac_t *)val; 1120d62bc4baSyz147064 datalink_id_t linkid; 1121d62bc4baSyz147064 int err; 1122da14cebeSEric Cheng softmac_walk_t *smwp = arg; 1123d62bc4baSyz147064 1124d62bc4baSyz147064 /* 1125da14cebeSEric Cheng * The framework itself must not hold any locks across calls to the 1126da14cebeSEric Cheng * mac perimeter. Thus this function does not call any framework 1127da14cebeSEric Cheng * function that needs to grab the mac perimeter. 1128d62bc4baSyz147064 */ 1129da14cebeSEric Cheng ASSERT(RW_READ_HELD(&softmac_hash_lock)); 1130d62bc4baSyz147064 1131da14cebeSEric Cheng smwp->smw_retry = B_FALSE; 1132da14cebeSEric Cheng mutex_enter(&softmac->smac_mutex); 1133da14cebeSEric Cheng SOFTMAC_STATE_VERIFY(softmac); 1134da14cebeSEric Cheng if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) { 1135da14cebeSEric Cheng /* 1136da14cebeSEric Cheng * Wait till softmac_create or softmac_mac_register finishes 1137da14cebeSEric Cheng * Hold the softmac to ensure it stays around. The wait itself 1138da14cebeSEric Cheng * is done in the caller, since we need to drop all locks 1139da14cebeSEric Cheng * including the mod hash's internal lock before calling 1140da14cebeSEric Cheng * cv_wait. 1141da14cebeSEric Cheng */ 1142da14cebeSEric Cheng smwp->smw_retry = B_TRUE; 1143da14cebeSEric Cheng smwp->smw_softmac = softmac; 1144da14cebeSEric Cheng softmac->smac_hold_cnt++; 1145da14cebeSEric Cheng return (MH_WALK_TERMINATE); 1146da14cebeSEric Cheng } 1147da14cebeSEric Cheng 1148da14cebeSEric Cheng if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) || 1149d62bc4baSyz147064 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) { 1150d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 1151d62bc4baSyz147064 return (MH_WALK_CONTINUE); 1152d62bc4baSyz147064 } 1153d62bc4baSyz147064 1154ae6aa22aSVenugopal Iyer /* 1155ae6aa22aSVenugopal Iyer * Bumping up the smac_hold_cnt allows us to drop the lock. It also 1156ae6aa22aSVenugopal Iyer * makes softmac_destroy() return failure on an attempted device detach. 1157ae6aa22aSVenugopal Iyer * We don't want to hold the lock across calls to other subsystems 1158ae6aa22aSVenugopal Iyer * like kstats, which will happen in the call to dls_devnet_recreate 1159ae6aa22aSVenugopal Iyer */ 1160ae6aa22aSVenugopal Iyer softmac->smac_hold_cnt++; 1161ae6aa22aSVenugopal Iyer mutex_exit(&softmac->smac_mutex); 1162ae6aa22aSVenugopal Iyer 1163d62bc4baSyz147064 if (dls_mgmt_create(softmac->smac_devname, 1164d62bc4baSyz147064 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 1165d62bc4baSyz147064 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) { 1166ae6aa22aSVenugopal Iyer softmac_rele_device((dls_dev_handle_t)softmac); 1167d62bc4baSyz147064 return (MH_WALK_CONTINUE); 1168d62bc4baSyz147064 } 1169d62bc4baSyz147064 1170d62bc4baSyz147064 if ((err = softmac_update_info(softmac, &linkid)) != 0) { 1171d62bc4baSyz147064 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s " 1172d62bc4baSyz147064 "failed (%d)", softmac->smac_devname, err); 1173ae6aa22aSVenugopal Iyer softmac_rele_device((dls_dev_handle_t)softmac); 1174d62bc4baSyz147064 return (MH_WALK_CONTINUE); 1175d62bc4baSyz147064 } 1176d62bc4baSyz147064 1177d62bc4baSyz147064 /* 1178d62bc4baSyz147064 * Create a link for this MAC. The link name will be the same 1179d62bc4baSyz147064 * as the MAC name. 1180d62bc4baSyz147064 */ 1181d62bc4baSyz147064 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 1182d62bc4baSyz147064 err = dls_devnet_recreate(softmac->smac_mh, linkid); 1183d62bc4baSyz147064 if (err != 0) { 1184d62bc4baSyz147064 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for " 1185d62bc4baSyz147064 "%s (linkid %d) failed (%d)", 1186d62bc4baSyz147064 softmac->smac_devname, linkid, err); 1187d62bc4baSyz147064 } 1188d62bc4baSyz147064 } 1189d62bc4baSyz147064 1190ae6aa22aSVenugopal Iyer mutex_enter(&softmac->smac_mutex); 1191d62bc4baSyz147064 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE; 1192ae6aa22aSVenugopal Iyer ASSERT(softmac->smac_hold_cnt != 0); 1193ae6aa22aSVenugopal Iyer softmac->smac_hold_cnt--; 1194d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 1195d62bc4baSyz147064 1196d62bc4baSyz147064 return (MH_WALK_CONTINUE); 1197d62bc4baSyz147064 } 1198d62bc4baSyz147064 1199d62bc4baSyz147064 /* 1200d62bc4baSyz147064 * See comments above softmac_mac_recreate(). 1201d62bc4baSyz147064 */ 1202d62bc4baSyz147064 void 1203d62bc4baSyz147064 softmac_recreate() 1204d62bc4baSyz147064 { 1205da14cebeSEric Cheng softmac_walk_t smw; 1206da14cebeSEric Cheng softmac_t *softmac; 1207da14cebeSEric Cheng 1208d62bc4baSyz147064 /* 1209d62bc4baSyz147064 * Walk through the softmac_hash table. Request to create the 1210d62bc4baSyz147064 * [link name, linkid] mapping if we failed to do so. 1211d62bc4baSyz147064 */ 1212da14cebeSEric Cheng do { 1213da14cebeSEric Cheng smw.smw_retry = B_FALSE; 1214d62bc4baSyz147064 rw_enter(&softmac_hash_lock, RW_READER); 1215da14cebeSEric Cheng mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw); 1216d62bc4baSyz147064 rw_exit(&softmac_hash_lock); 1217da14cebeSEric Cheng if (smw.smw_retry) { 1218da14cebeSEric Cheng /* 1219da14cebeSEric Cheng * softmac_create or softmac_mac_register hasn't yet 1220da14cebeSEric Cheng * finished and the softmac is not yet in the 1221da14cebeSEric Cheng * SOFTMAC_ATTACH_DONE state. 1222da14cebeSEric Cheng */ 1223da14cebeSEric Cheng softmac = smw.smw_softmac; 1224da14cebeSEric Cheng cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1225da14cebeSEric Cheng softmac->smac_hold_cnt--; 1226da14cebeSEric Cheng mutex_exit(&softmac->smac_mutex); 1227da14cebeSEric Cheng } 1228da14cebeSEric Cheng } while (smw.smw_retry); 1229d62bc4baSyz147064 } 1230d62bc4baSyz147064 1231d62bc4baSyz147064 static int 1232d62bc4baSyz147064 softmac_m_start(void *arg) 1233d62bc4baSyz147064 { 12345d460eafSCathy Zhou softmac_t *softmac = arg; 12355d460eafSCathy Zhou softmac_lower_t *slp = softmac->smac_lower; 12365d460eafSCathy Zhou int err; 12375d460eafSCathy Zhou 12385d460eafSCathy Zhou ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 12395d460eafSCathy Zhou /* 12405d460eafSCathy Zhou * Bind to SAP 2 on token ring, 0 on other interface types. 12415d460eafSCathy Zhou * (SAP 0 has special significance on token ring). 12425d460eafSCathy Zhou * Note that the receive-side packets could come anytime after bind. 12435d460eafSCathy Zhou */ 12445d460eafSCathy Zhou err = softmac_send_bind_req(slp, softmac->smac_media == DL_TPR ? 2 : 0); 12455d460eafSCathy Zhou if (err != 0) 12465d460eafSCathy Zhou return (err); 12475d460eafSCathy Zhou 12485d460eafSCathy Zhou /* 12495d460eafSCathy Zhou * Put the lower stream to the DL_PROMISC_SAP mode in order to receive 12505d460eafSCathy Zhou * all packets of interest. 12515d460eafSCathy Zhou * 12525d460eafSCathy Zhou * some driver (e.g. the old legacy eri driver) incorrectly passes up 12535d460eafSCathy Zhou * packets to DL_PROMISC_SAP stream when the lower stream is not bound, 12545d460eafSCathy Zhou * so that we send DL_PROMISON_REQ after DL_BIND_REQ. 12555d460eafSCathy Zhou */ 12565d460eafSCathy Zhou err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE); 12575d460eafSCathy Zhou if (err != 0) { 12585d460eafSCathy Zhou (void) softmac_send_unbind_req(slp); 12595d460eafSCathy Zhou return (err); 12605d460eafSCathy Zhou } 12615d460eafSCathy Zhou 12625d460eafSCathy Zhou /* 12635d460eafSCathy Zhou * Enable capabilities the underlying driver claims to support. 12645d460eafSCathy Zhou * Some driver requires this being called after the stream is bound. 12655d460eafSCathy Zhou */ 12665d460eafSCathy Zhou if ((err = softmac_capab_enable(slp)) != 0) { 12675d460eafSCathy Zhou (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE); 12685d460eafSCathy Zhou (void) softmac_send_unbind_req(slp); 12695d460eafSCathy Zhou } 12705d460eafSCathy Zhou 12715d460eafSCathy Zhou return (err); 1272d62bc4baSyz147064 } 1273d62bc4baSyz147064 1274d62bc4baSyz147064 /* ARGSUSED */ 1275d62bc4baSyz147064 static void 1276d62bc4baSyz147064 softmac_m_stop(void *arg) 1277d62bc4baSyz147064 { 12785d460eafSCathy Zhou softmac_t *softmac = arg; 12795d460eafSCathy Zhou softmac_lower_t *slp = softmac->smac_lower; 12805d460eafSCathy Zhou 12815d460eafSCathy Zhou ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 12825d460eafSCathy Zhou 12835d460eafSCathy Zhou /* 12845d460eafSCathy Zhou * It is not needed to reset zerocopy, MDT or HCKSUM capabilities. 12855d460eafSCathy Zhou */ 12865d460eafSCathy Zhou (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE); 12875d460eafSCathy Zhou (void) softmac_send_unbind_req(slp); 1288d62bc4baSyz147064 } 1289d62bc4baSyz147064 1290d62bc4baSyz147064 /* 12915d460eafSCathy Zhou * Set up the lower stream above the legacy device. There are two different 12925d460eafSCathy Zhou * type of lower streams: 12935d460eafSCathy Zhou * 12945d460eafSCathy Zhou * - Shared lower-stream 12955d460eafSCathy Zhou * 12965d460eafSCathy Zhou * Shared by all GLDv3 MAC clients. Put the lower stream to the DLIOCRAW 12975d460eafSCathy Zhou * mode to send and receive the raw data. Further, put the lower stream into 1298d62bc4baSyz147064 * DL_PROMISC_SAP mode to receive all packets of interest. 12995d460eafSCathy Zhou * 13005d460eafSCathy Zhou * - Dedicated lower-stream 13015d460eafSCathy Zhou * 13025d460eafSCathy Zhou * The lower-stream which is dedicated to upper IP/ARP stream. This is used 13035d460eafSCathy Zhou * as fast-path for IP. In this case, the second argument is the pointer to 13045d460eafSCathy Zhou * the softmac upper-stream. 1305d62bc4baSyz147064 */ 13065d460eafSCathy Zhou int 13075d460eafSCathy Zhou softmac_lower_setup(softmac_t *softmac, softmac_upper_t *sup, 13085d460eafSCathy Zhou softmac_lower_t **slpp) 1309d62bc4baSyz147064 { 1310d62bc4baSyz147064 ldi_ident_t li; 1311d62bc4baSyz147064 dev_t dev; 1312d62bc4baSyz147064 ldi_handle_t lh = NULL; 1313d62bc4baSyz147064 softmac_lower_t *slp = NULL; 1314d62bc4baSyz147064 smac_ioc_start_t start_arg; 1315d62bc4baSyz147064 struct strioctl strioc; 1316d62bc4baSyz147064 uint32_t notifications; 1317d62bc4baSyz147064 int err, rval; 1318d62bc4baSyz147064 1319d62bc4baSyz147064 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) 1320d62bc4baSyz147064 return (err); 1321d62bc4baSyz147064 13225d460eafSCathy Zhou /* 13235d460eafSCathy Zhou * The GLDv3 framework makes sure that mac_unregister(), mac_open(), 13245d460eafSCathy Zhou * and mac_close() cannot be called at the same time. So we don't 13255d460eafSCathy Zhou * need any protection to access softmac here. 13265d460eafSCathy Zhou */ 1327d62bc4baSyz147064 dev = softmac->smac_dev; 13285d460eafSCathy Zhou 1329d62bc4baSyz147064 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 1330d62bc4baSyz147064 ldi_ident_release(li); 1331d62bc4baSyz147064 if (err != 0) 1332d62bc4baSyz147064 goto done; 1333d62bc4baSyz147064 1334d62bc4baSyz147064 /* 1335d62bc4baSyz147064 * Pop all the intermediate modules. The autopushed modules will 1336d62bc4baSyz147064 * be pushed when the softmac node is opened. 1337d62bc4baSyz147064 */ 1338d62bc4baSyz147064 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 1339d62bc4baSyz147064 ; 1340d62bc4baSyz147064 1341d62bc4baSyz147064 if ((softmac->smac_style == DL_STYLE2) && 1342d62bc4baSyz147064 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) { 1343d62bc4baSyz147064 goto done; 1344d62bc4baSyz147064 } 1345d62bc4baSyz147064 1346d62bc4baSyz147064 /* 13475d460eafSCathy Zhou * If this is the shared-lower-stream, put the lower stream to 13485d460eafSCathy Zhou * the DLIOCRAW mode to send/receive raw data. 1349d62bc4baSyz147064 */ 13505d460eafSCathy Zhou if ((sup == NULL) && (err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, 13515d460eafSCathy Zhou kcred, &rval)) != 0) { 1352d62bc4baSyz147064 goto done; 13535d460eafSCathy Zhou } 1354d62bc4baSyz147064 1355d62bc4baSyz147064 /* 1356d62bc4baSyz147064 * Then push the softmac shim layer atop the lower stream. 1357d62bc4baSyz147064 */ 1358d62bc4baSyz147064 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL, 1359d62bc4baSyz147064 kcred, &rval)) != 0) { 1360d62bc4baSyz147064 goto done; 1361d62bc4baSyz147064 } 1362d62bc4baSyz147064 1363d62bc4baSyz147064 /* 1364d62bc4baSyz147064 * Send the ioctl to get the slp pointer. 1365d62bc4baSyz147064 */ 1366d62bc4baSyz147064 strioc.ic_cmd = SMAC_IOC_START; 1367d62bc4baSyz147064 strioc.ic_timout = INFTIM; 1368d62bc4baSyz147064 strioc.ic_len = sizeof (start_arg); 1369d62bc4baSyz147064 strioc.ic_dp = (char *)&start_arg; 1370d62bc4baSyz147064 1371d62bc4baSyz147064 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL, 1372d62bc4baSyz147064 kcred, &rval)) != 0) { 1373d62bc4baSyz147064 goto done; 1374d62bc4baSyz147064 } 1375d62bc4baSyz147064 slp = start_arg.si_slp; 13765d460eafSCathy Zhou slp->sl_sup = sup; 1377d62bc4baSyz147064 slp->sl_lh = lh; 1378d62bc4baSyz147064 slp->sl_softmac = softmac; 1379d62bc4baSyz147064 *slpp = slp; 1380d62bc4baSyz147064 13815d460eafSCathy Zhou if (sup != NULL) { 13825d460eafSCathy Zhou slp->sl_rxinfo = &sup->su_rxinfo; 13835d460eafSCathy Zhou } else { 1384d62bc4baSyz147064 /* 13855d460eafSCathy Zhou * Send DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND. 1386d62bc4baSyz147064 * We don't have to wait for the ack. 1387d62bc4baSyz147064 */ 1388d62bc4baSyz147064 notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | 1389d62bc4baSyz147064 DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS | 1390d62bc4baSyz147064 DL_NOTE_PROMISC_OFF_PHYS; 1391d62bc4baSyz147064 1392d62bc4baSyz147064 (void) softmac_send_notify_req(slp, 1393d62bc4baSyz147064 (notifications & softmac->smac_notifications)); 13945d460eafSCathy Zhou } 1395d62bc4baSyz147064 1396d62bc4baSyz147064 done: 1397d62bc4baSyz147064 if (err != 0) 1398d62bc4baSyz147064 (void) ldi_close(lh, FREAD|FWRITE, kcred); 1399d62bc4baSyz147064 return (err); 1400d62bc4baSyz147064 } 1401d62bc4baSyz147064 1402d62bc4baSyz147064 static int 1403d62bc4baSyz147064 softmac_m_open(void *arg) 1404d62bc4baSyz147064 { 1405d62bc4baSyz147064 softmac_t *softmac = arg; 1406d62bc4baSyz147064 softmac_lower_t *slp; 1407d62bc4baSyz147064 int err; 1408d62bc4baSyz147064 1409da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1410d62bc4baSyz147064 14115d460eafSCathy Zhou if ((err = softmac_lower_setup(softmac, NULL, &slp)) != 0) 1412d62bc4baSyz147064 return (err); 1413d62bc4baSyz147064 1414d62bc4baSyz147064 softmac->smac_lower = slp; 1415d62bc4baSyz147064 return (0); 1416d62bc4baSyz147064 } 1417d62bc4baSyz147064 1418d62bc4baSyz147064 static void 1419d62bc4baSyz147064 softmac_m_close(void *arg) 1420d62bc4baSyz147064 { 1421d62bc4baSyz147064 softmac_t *softmac = arg; 1422d62bc4baSyz147064 softmac_lower_t *slp; 1423d62bc4baSyz147064 1424da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1425d62bc4baSyz147064 slp = softmac->smac_lower; 1426d62bc4baSyz147064 ASSERT(slp != NULL); 1427d62bc4baSyz147064 1428d62bc4baSyz147064 /* 1429d62bc4baSyz147064 * Note that slp is destroyed when lh is closed. 1430d62bc4baSyz147064 */ 1431d62bc4baSyz147064 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred); 1432d62bc4baSyz147064 softmac->smac_lower = NULL; 1433d62bc4baSyz147064 } 1434d62bc4baSyz147064 14355d460eafSCathy Zhou /* 14365d460eafSCathy Zhou * Softmac supports two priviate link properteis: 14375d460eafSCathy Zhou * 14385d460eafSCathy Zhou * - "_fastpath" 14395d460eafSCathy Zhou * 14405d460eafSCathy Zhou * This is a read-only link property which points out the current data-path 14415d460eafSCathy Zhou * model of the given legacy link. The possible values are "disabled" and 14425d460eafSCathy Zhou * "enabled". 14435d460eafSCathy Zhou * 14445d460eafSCathy Zhou * - "_disable_fastpath" 14455d460eafSCathy Zhou * 14465d460eafSCathy Zhou * This is a read-write link property which can be used to disable or enable 14475d460eafSCathy Zhou * the fast-path of the given legacy link. The possible values are "true" 14485d460eafSCathy Zhou * and "false". Note that even when "_disable_fastpath" is set to be 14495d460eafSCathy Zhou * "false", the fast-path may still not be enabled since there may be 14505d460eafSCathy Zhou * other mac cleints that request the fast-path to be disabled. 14515d460eafSCathy Zhou */ 14525d460eafSCathy Zhou /* ARGSUSED */ 14535d460eafSCathy Zhou static int 14545d460eafSCathy Zhou softmac_m_setprop(void *arg, const char *name, mac_prop_id_t id, 14555d460eafSCathy Zhou uint_t valsize, const void *val) 14565d460eafSCathy Zhou { 14575d460eafSCathy Zhou softmac_t *softmac = arg; 14585d460eafSCathy Zhou 14595d460eafSCathy Zhou if (id != MAC_PROP_PRIVATE || strcmp(name, "_disable_fastpath") != 0) 14605d460eafSCathy Zhou return (ENOTSUP); 14615d460eafSCathy Zhou 14625d460eafSCathy Zhou if (strcmp(val, "true") == 0) 14635d460eafSCathy Zhou return (softmac_datapath_switch(softmac, B_TRUE, B_TRUE)); 14645d460eafSCathy Zhou else if (strcmp(val, "false") == 0) 14655d460eafSCathy Zhou return (softmac_datapath_switch(softmac, B_FALSE, B_TRUE)); 14665d460eafSCathy Zhou else 14675d460eafSCathy Zhou return (EINVAL); 14685d460eafSCathy Zhou } 14695d460eafSCathy Zhou 14705d460eafSCathy Zhou static int 14715d460eafSCathy Zhou softmac_m_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t flags, 14725d460eafSCathy Zhou uint_t valsize, void *val, uint_t *perm) 14735d460eafSCathy Zhou { 14745d460eafSCathy Zhou softmac_t *softmac = arg; 14755d460eafSCathy Zhou char *fpstr; 14765d460eafSCathy Zhou 14775d460eafSCathy Zhou if (id != MAC_PROP_PRIVATE) 14785d460eafSCathy Zhou return (ENOTSUP); 14795d460eafSCathy Zhou 14805d460eafSCathy Zhou if (strcmp(name, "_fastpath") == 0) { 14815d460eafSCathy Zhou if ((flags & MAC_PROP_DEFAULT) != 0) 14825d460eafSCathy Zhou return (ENOTSUP); 14835d460eafSCathy Zhou 14845d460eafSCathy Zhou *perm = MAC_PROP_PERM_READ; 14855d460eafSCathy Zhou mutex_enter(&softmac->smac_fp_mutex); 14865d460eafSCathy Zhou fpstr = (DATAPATH_MODE(softmac) == SOFTMAC_SLOWPATH) ? 14875d460eafSCathy Zhou "disabled" : "enabled"; 14885d460eafSCathy Zhou mutex_exit(&softmac->smac_fp_mutex); 14895d460eafSCathy Zhou } else if (strcmp(name, "_disable_fastpath") == 0) { 14905d460eafSCathy Zhou *perm = MAC_PROP_PERM_RW; 14915d460eafSCathy Zhou fpstr = ((flags & MAC_PROP_DEFAULT) != 0) ? "false" : 14925d460eafSCathy Zhou (softmac->smac_fastpath_admin_disabled ? "true" : "false"); 14935d460eafSCathy Zhou } else { 14945d460eafSCathy Zhou return (ENOTSUP); 14955d460eafSCathy Zhou } 14965d460eafSCathy Zhou 14975d460eafSCathy Zhou return (strlcpy(val, fpstr, valsize) >= valsize ? EINVAL : 0); 14985d460eafSCathy Zhou } 14995d460eafSCathy Zhou 1500d62bc4baSyz147064 int 1501d62bc4baSyz147064 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp) 1502d62bc4baSyz147064 { 1503d62bc4baSyz147064 dev_info_t *dip; 1504d81b850fSyz147064 const char *drvname; 1505d62bc4baSyz147064 char devname[MAXNAMELEN]; 1506d62bc4baSyz147064 softmac_t *softmac; 150761af1958SGarrett D'Amore int ppa, err, inst; 150861af1958SGarrett D'Amore 150961af1958SGarrett D'Amore drvname = ddi_major_to_name(getmajor(dev)); 151061af1958SGarrett D'Amore 151161af1958SGarrett D'Amore /* 151261af1958SGarrett D'Amore * We have to lookup the device instance using getinfo(9e). 151361af1958SGarrett D'Amore */ 151461af1958SGarrett D'Amore inst = dev_to_instance(dev); 151561af1958SGarrett D'Amore if (inst < 0) 151661af1958SGarrett D'Amore return (ENOENT); 1517d62bc4baSyz147064 1518*3ade6e84SGarrett D'Amore if ((ppa = getminor(dev) - 1) > DLS_MAX_PPA) 1519d62bc4baSyz147064 return (ENOENT); 1520d62bc4baSyz147064 1521d62bc4baSyz147064 /* 1522d62bc4baSyz147064 * First try to hold this device instance to force the MAC 1523d62bc4baSyz147064 * to be registered. 1524d62bc4baSyz147064 */ 152561af1958SGarrett D'Amore if ((dip = ddi_hold_devi_by_instance(getmajor(dev), inst, 0)) == NULL) 1526d62bc4baSyz147064 return (ENOENT); 1527d62bc4baSyz147064 1528d62bc4baSyz147064 /* 1529*3ade6e84SGarrett D'Amore * Exclude non-physical network device instances, for example, aggr0. 1530*3ade6e84SGarrett D'Amore * Note: this check *must* occur after the dip is held, or else 1531*3ade6e84SGarrett D'Amore * NETWORK_DRV might return false incorrectly. (Essentially, the 1532*3ade6e84SGarrett D'Amore * driver needs to be loaded to populate the dev_ops structure 1533*3ade6e84SGarrett D'Amore * that NETWORK_DRV checks.) 1534*3ade6e84SGarrett D'Amore */ 1535*3ade6e84SGarrett D'Amore if (!NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) || 1536*3ade6e84SGarrett D'Amore (strcmp(drvname, "vnic") == 0)) { 1537*3ade6e84SGarrett D'Amore ddi_release_devi(dip); 1538*3ade6e84SGarrett D'Amore return (ENOENT); 1539*3ade6e84SGarrett D'Amore } 1540*3ade6e84SGarrett D'Amore 1541*3ade6e84SGarrett D'Amore /* 1542d62bc4baSyz147064 * This is a network device; wait for its softmac to be registered. 1543d62bc4baSyz147064 */ 1544d81b850fSyz147064 (void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa); 1545d62bc4baSyz147064 again: 1546d62bc4baSyz147064 rw_enter(&softmac_hash_lock, RW_READER); 1547d62bc4baSyz147064 1548d62bc4baSyz147064 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 1549d62bc4baSyz147064 (mod_hash_val_t *)&softmac) != 0) { 1550d62bc4baSyz147064 /* 1551d62bc4baSyz147064 * This is rare but possible. It could happen when pre-detach 1552d62bc4baSyz147064 * routine of the device succeeds. But the softmac will then 1553d62bc4baSyz147064 * be recreated when device fails to detach (as this device 1554d62bc4baSyz147064 * is held). 1555d62bc4baSyz147064 */ 1556da14cebeSEric Cheng mutex_enter(&smac_global_lock); 1557d62bc4baSyz147064 rw_exit(&softmac_hash_lock); 1558da14cebeSEric Cheng cv_wait(&smac_global_cv, &smac_global_lock); 1559da14cebeSEric Cheng mutex_exit(&smac_global_lock); 1560d62bc4baSyz147064 goto again; 1561d62bc4baSyz147064 } 1562d62bc4baSyz147064 1563d62bc4baSyz147064 /* 1564d62bc4baSyz147064 * Bump smac_hold_cnt to prevent device detach. 1565d62bc4baSyz147064 */ 1566d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex); 1567d62bc4baSyz147064 softmac->smac_hold_cnt++; 1568d62bc4baSyz147064 rw_exit(&softmac_hash_lock); 1569d62bc4baSyz147064 1570d62bc4baSyz147064 /* 1571d62bc4baSyz147064 * Wait till the device is fully attached. 1572d62bc4baSyz147064 */ 1573da14cebeSEric Cheng while (softmac->smac_state != SOFTMAC_ATTACH_DONE) 1574d62bc4baSyz147064 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1575d62bc4baSyz147064 1576da14cebeSEric Cheng SOFTMAC_STATE_VERIFY(softmac); 1577da14cebeSEric Cheng 1578050fb016Syz147064 if ((err = softmac->smac_attacherr) != 0) 1579050fb016Syz147064 softmac->smac_hold_cnt--; 1580050fb016Syz147064 else 1581d62bc4baSyz147064 *ddhp = (dls_dev_handle_t)softmac; 1582d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 1583d62bc4baSyz147064 1584050fb016Syz147064 ddi_release_devi(dip); 1585d62bc4baSyz147064 return (err); 1586d62bc4baSyz147064 } 1587d62bc4baSyz147064 1588d62bc4baSyz147064 void 1589d62bc4baSyz147064 softmac_rele_device(dls_dev_handle_t ddh) 1590d62bc4baSyz147064 { 15915d460eafSCathy Zhou if (ddh != NULL) 15925d460eafSCathy Zhou softmac_rele((softmac_t *)ddh); 15935d460eafSCathy Zhou } 15945d460eafSCathy Zhou 15955d460eafSCathy Zhou int 15965d460eafSCathy Zhou softmac_hold(dev_t dev, softmac_t **softmacp) 15975d460eafSCathy Zhou { 1598d62bc4baSyz147064 softmac_t *softmac; 15995d460eafSCathy Zhou char *drv; 16005d460eafSCathy Zhou mac_handle_t mh; 16015d460eafSCathy Zhou char mac[MAXNAMELEN]; 16025d460eafSCathy Zhou int err; 1603d62bc4baSyz147064 16045d460eafSCathy Zhou if ((drv = ddi_major_to_name(getmajor(dev))) == NULL) 16055d460eafSCathy Zhou return (EINVAL); 1606d62bc4baSyz147064 16075d460eafSCathy Zhou (void) snprintf(mac, MAXNAMELEN, "%s%d", drv, getminor(dev) - 1); 16085d460eafSCathy Zhou if ((err = mac_open(mac, &mh)) != 0) 16095d460eafSCathy Zhou return (err); 16105d460eafSCathy Zhou 16115d460eafSCathy Zhou softmac = (softmac_t *)mac_driver(mh); 16125d460eafSCathy Zhou 16135d460eafSCathy Zhou mutex_enter(&softmac->smac_mutex); 16145d460eafSCathy Zhou softmac->smac_hold_cnt++; 16155d460eafSCathy Zhou mutex_exit(&softmac->smac_mutex); 16165d460eafSCathy Zhou mac_close(mh); 16175d460eafSCathy Zhou *softmacp = softmac; 16185d460eafSCathy Zhou return (0); 16195d460eafSCathy Zhou } 16205d460eafSCathy Zhou 16215d460eafSCathy Zhou void 16225d460eafSCathy Zhou softmac_rele(softmac_t *softmac) 16235d460eafSCathy Zhou { 1624d62bc4baSyz147064 mutex_enter(&softmac->smac_mutex); 1625050fb016Syz147064 softmac->smac_hold_cnt--; 1626d62bc4baSyz147064 mutex_exit(&softmac->smac_mutex); 1627d62bc4baSyz147064 } 1628