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