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