19815SRishi.Srivatsavai@Sun.COM /* 29815SRishi.Srivatsavai@Sun.COM * CDDL HEADER START 39815SRishi.Srivatsavai@Sun.COM * 49815SRishi.Srivatsavai@Sun.COM * The contents of this file are subject to the terms of the 59815SRishi.Srivatsavai@Sun.COM * Common Development and Distribution License (the "License"). 69815SRishi.Srivatsavai@Sun.COM * You may not use this file except in compliance with the License. 79815SRishi.Srivatsavai@Sun.COM * 89815SRishi.Srivatsavai@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99815SRishi.Srivatsavai@Sun.COM * or http://www.opensolaris.org/os/licensing. 109815SRishi.Srivatsavai@Sun.COM * See the License for the specific language governing permissions 119815SRishi.Srivatsavai@Sun.COM * and limitations under the License. 129815SRishi.Srivatsavai@Sun.COM * 139815SRishi.Srivatsavai@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 149815SRishi.Srivatsavai@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159815SRishi.Srivatsavai@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 169815SRishi.Srivatsavai@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 179815SRishi.Srivatsavai@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 189815SRishi.Srivatsavai@Sun.COM * 199815SRishi.Srivatsavai@Sun.COM * CDDL HEADER END 209815SRishi.Srivatsavai@Sun.COM */ 219815SRishi.Srivatsavai@Sun.COM /* 229815SRishi.Srivatsavai@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 239815SRishi.Srivatsavai@Sun.COM * Use is subject to license terms. 249815SRishi.Srivatsavai@Sun.COM */ 259815SRishi.Srivatsavai@Sun.COM 269815SRishi.Srivatsavai@Sun.COM /* 279815SRishi.Srivatsavai@Sun.COM * Simulated network device (simnet) driver: simulates a pseudo GLDv3 network 289815SRishi.Srivatsavai@Sun.COM * device. Can simulate an Ethernet or WiFi network device. In addition, another 299815SRishi.Srivatsavai@Sun.COM * simnet instance can be attached as a peer to create a point-to-point link on 309815SRishi.Srivatsavai@Sun.COM * the same system. 319815SRishi.Srivatsavai@Sun.COM */ 329815SRishi.Srivatsavai@Sun.COM 339815SRishi.Srivatsavai@Sun.COM #include <sys/policy.h> 349815SRishi.Srivatsavai@Sun.COM #include <sys/conf.h> 359815SRishi.Srivatsavai@Sun.COM #include <sys/modctl.h> 369815SRishi.Srivatsavai@Sun.COM #include <sys/priv_names.h> 379815SRishi.Srivatsavai@Sun.COM #include <sys/dlpi.h> 389815SRishi.Srivatsavai@Sun.COM #include <net/simnet.h> 399815SRishi.Srivatsavai@Sun.COM #include <sys/ethernet.h> 409815SRishi.Srivatsavai@Sun.COM #include <sys/mac.h> 419815SRishi.Srivatsavai@Sun.COM #include <sys/dls.h> 429815SRishi.Srivatsavai@Sun.COM #include <sys/mac_ether.h> 439815SRishi.Srivatsavai@Sun.COM #include <sys/mac_provider.h> 449815SRishi.Srivatsavai@Sun.COM #include <sys/mac_client_priv.h> 459815SRishi.Srivatsavai@Sun.COM #include <sys/vlan.h> 469815SRishi.Srivatsavai@Sun.COM #include <sys/random.h> 479815SRishi.Srivatsavai@Sun.COM #include <sys/sysmacros.h> 489815SRishi.Srivatsavai@Sun.COM #include <sys/list.h> 499815SRishi.Srivatsavai@Sun.COM #include <sys/strsubr.h> 509815SRishi.Srivatsavai@Sun.COM #include <sys/strsun.h> 519815SRishi.Srivatsavai@Sun.COM #include <sys/atomic.h> 529815SRishi.Srivatsavai@Sun.COM #include <sys/mac_wifi.h> 539815SRishi.Srivatsavai@Sun.COM #include <sys/mac_impl.h> 549815SRishi.Srivatsavai@Sun.COM #include <inet/wifi_ioctl.h> 559815SRishi.Srivatsavai@Sun.COM #include <sys/thread.h> 569815SRishi.Srivatsavai@Sun.COM #include <sys/synch.h> 57*10416SRishi.Srivatsavai@Sun.COM #include <sys/sunddi.h> 589815SRishi.Srivatsavai@Sun.COM 599815SRishi.Srivatsavai@Sun.COM #include "simnet_impl.h" 609815SRishi.Srivatsavai@Sun.COM 619815SRishi.Srivatsavai@Sun.COM #define SIMNETINFO "Simulated Network Driver" 629815SRishi.Srivatsavai@Sun.COM 639815SRishi.Srivatsavai@Sun.COM static dev_info_t *simnet_dip; 64*10416SRishi.Srivatsavai@Sun.COM static ddi_taskq_t *simnet_rxq; 659815SRishi.Srivatsavai@Sun.COM 669815SRishi.Srivatsavai@Sun.COM static int simnet_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 679815SRishi.Srivatsavai@Sun.COM static int simnet_attach(dev_info_t *, ddi_attach_cmd_t); 689815SRishi.Srivatsavai@Sun.COM static int simnet_detach(dev_info_t *, ddi_detach_cmd_t); 699815SRishi.Srivatsavai@Sun.COM static int simnet_ioc_create(void *, intptr_t, int, cred_t *, int *); 709815SRishi.Srivatsavai@Sun.COM static int simnet_ioc_delete(void *, intptr_t, int, cred_t *, int *); 719815SRishi.Srivatsavai@Sun.COM static int simnet_ioc_info(void *, intptr_t, int, cred_t *, int *); 729815SRishi.Srivatsavai@Sun.COM static int simnet_ioc_modify(void *, intptr_t, int, cred_t *, int *); 739815SRishi.Srivatsavai@Sun.COM static uint8_t *mcastaddr_lookup(simnet_dev_t *, const uint8_t *); 749815SRishi.Srivatsavai@Sun.COM 759815SRishi.Srivatsavai@Sun.COM static dld_ioc_info_t simnet_ioc_list[] = { 769815SRishi.Srivatsavai@Sun.COM {SIMNET_IOC_CREATE, DLDCOPYINOUT, sizeof (simnet_ioc_create_t), 779815SRishi.Srivatsavai@Sun.COM simnet_ioc_create, {PRIV_SYS_DL_CONFIG}}, 789815SRishi.Srivatsavai@Sun.COM {SIMNET_IOC_DELETE, DLDCOPYIN, sizeof (simnet_ioc_delete_t), 799815SRishi.Srivatsavai@Sun.COM simnet_ioc_delete, {PRIV_SYS_DL_CONFIG}}, 809815SRishi.Srivatsavai@Sun.COM {SIMNET_IOC_INFO, DLDCOPYINOUT, sizeof (simnet_ioc_info_t), 819815SRishi.Srivatsavai@Sun.COM simnet_ioc_info, {NULL}}, 829815SRishi.Srivatsavai@Sun.COM {SIMNET_IOC_MODIFY, DLDCOPYIN, sizeof (simnet_ioc_modify_t), 839815SRishi.Srivatsavai@Sun.COM simnet_ioc_modify, {PRIV_SYS_DL_CONFIG}}, 849815SRishi.Srivatsavai@Sun.COM }; 859815SRishi.Srivatsavai@Sun.COM 869815SRishi.Srivatsavai@Sun.COM DDI_DEFINE_STREAM_OPS(simnet_dev_ops, nulldev, nulldev, simnet_attach, 879815SRishi.Srivatsavai@Sun.COM simnet_detach, nodev, simnet_getinfo, D_MP, NULL, 889815SRishi.Srivatsavai@Sun.COM ddi_quiesce_not_supported); 899815SRishi.Srivatsavai@Sun.COM 909815SRishi.Srivatsavai@Sun.COM static struct modldrv simnet_modldrv = { 919815SRishi.Srivatsavai@Sun.COM &mod_driverops, /* Type of module. This one is a driver */ 929815SRishi.Srivatsavai@Sun.COM SIMNETINFO, /* short description */ 939815SRishi.Srivatsavai@Sun.COM &simnet_dev_ops /* driver specific ops */ 949815SRishi.Srivatsavai@Sun.COM }; 959815SRishi.Srivatsavai@Sun.COM 969815SRishi.Srivatsavai@Sun.COM static struct modlinkage modlinkage = { 979815SRishi.Srivatsavai@Sun.COM MODREV_1, &simnet_modldrv, NULL 989815SRishi.Srivatsavai@Sun.COM }; 999815SRishi.Srivatsavai@Sun.COM 1009815SRishi.Srivatsavai@Sun.COM /* MAC callback function declarations */ 1019815SRishi.Srivatsavai@Sun.COM static int simnet_m_start(void *); 1029815SRishi.Srivatsavai@Sun.COM static void simnet_m_stop(void *); 1039815SRishi.Srivatsavai@Sun.COM static int simnet_m_promisc(void *, boolean_t); 1049815SRishi.Srivatsavai@Sun.COM static int simnet_m_multicst(void *, boolean_t, const uint8_t *); 1059815SRishi.Srivatsavai@Sun.COM static int simnet_m_unicst(void *, const uint8_t *); 1069815SRishi.Srivatsavai@Sun.COM static int simnet_m_stat(void *, uint_t, uint64_t *); 1079815SRishi.Srivatsavai@Sun.COM static void simnet_m_ioctl(void *, queue_t *, mblk_t *); 1089815SRishi.Srivatsavai@Sun.COM static mblk_t *simnet_m_tx(void *, mblk_t *); 1099815SRishi.Srivatsavai@Sun.COM static int simnet_m_setprop(void *, const char *, mac_prop_id_t, 1109815SRishi.Srivatsavai@Sun.COM uint_t, const void *); 1119815SRishi.Srivatsavai@Sun.COM static int simnet_m_getprop(void *, const char *, mac_prop_id_t, 1129815SRishi.Srivatsavai@Sun.COM uint_t, uint_t, void *, uint_t *); 1139815SRishi.Srivatsavai@Sun.COM 1149815SRishi.Srivatsavai@Sun.COM static mac_callbacks_t simnet_m_callbacks = { 1159815SRishi.Srivatsavai@Sun.COM (MC_IOCTL | MC_SETPROP | MC_GETPROP), 1169815SRishi.Srivatsavai@Sun.COM simnet_m_stat, 1179815SRishi.Srivatsavai@Sun.COM simnet_m_start, 1189815SRishi.Srivatsavai@Sun.COM simnet_m_stop, 1199815SRishi.Srivatsavai@Sun.COM simnet_m_promisc, 1209815SRishi.Srivatsavai@Sun.COM simnet_m_multicst, 1219815SRishi.Srivatsavai@Sun.COM simnet_m_unicst, 1229815SRishi.Srivatsavai@Sun.COM simnet_m_tx, 1239815SRishi.Srivatsavai@Sun.COM simnet_m_ioctl, 1249815SRishi.Srivatsavai@Sun.COM NULL, 1259815SRishi.Srivatsavai@Sun.COM NULL, 1269815SRishi.Srivatsavai@Sun.COM NULL, 1279815SRishi.Srivatsavai@Sun.COM simnet_m_setprop, 1289815SRishi.Srivatsavai@Sun.COM simnet_m_getprop 1299815SRishi.Srivatsavai@Sun.COM }; 1309815SRishi.Srivatsavai@Sun.COM 1319815SRishi.Srivatsavai@Sun.COM /* 1329815SRishi.Srivatsavai@Sun.COM * simnet_dev_lock protects the simnet device list. 1339815SRishi.Srivatsavai@Sun.COM * sd_instlock in each simnet_dev_t protects access to 1349815SRishi.Srivatsavai@Sun.COM * a single simnet_dev_t. 1359815SRishi.Srivatsavai@Sun.COM */ 1369815SRishi.Srivatsavai@Sun.COM static krwlock_t simnet_dev_lock; 1379815SRishi.Srivatsavai@Sun.COM static list_t simnet_dev_list; 1389815SRishi.Srivatsavai@Sun.COM static int simnet_count; /* Num of simnet instances */ 1399815SRishi.Srivatsavai@Sun.COM 1409815SRishi.Srivatsavai@Sun.COM int 1419815SRishi.Srivatsavai@Sun.COM _init(void) 1429815SRishi.Srivatsavai@Sun.COM { 1439815SRishi.Srivatsavai@Sun.COM int status; 1449815SRishi.Srivatsavai@Sun.COM 1459815SRishi.Srivatsavai@Sun.COM mac_init_ops(&simnet_dev_ops, "simnet"); 1469815SRishi.Srivatsavai@Sun.COM status = mod_install(&modlinkage); 1479815SRishi.Srivatsavai@Sun.COM if (status != DDI_SUCCESS) 1489815SRishi.Srivatsavai@Sun.COM mac_fini_ops(&simnet_dev_ops); 1499815SRishi.Srivatsavai@Sun.COM 1509815SRishi.Srivatsavai@Sun.COM return (status); 1519815SRishi.Srivatsavai@Sun.COM } 1529815SRishi.Srivatsavai@Sun.COM 1539815SRishi.Srivatsavai@Sun.COM int 1549815SRishi.Srivatsavai@Sun.COM _fini(void) 1559815SRishi.Srivatsavai@Sun.COM { 1569815SRishi.Srivatsavai@Sun.COM int status; 1579815SRishi.Srivatsavai@Sun.COM 1589815SRishi.Srivatsavai@Sun.COM status = mod_remove(&modlinkage); 1599815SRishi.Srivatsavai@Sun.COM if (status == DDI_SUCCESS) 1609815SRishi.Srivatsavai@Sun.COM mac_fini_ops(&simnet_dev_ops); 1619815SRishi.Srivatsavai@Sun.COM 1629815SRishi.Srivatsavai@Sun.COM return (status); 1639815SRishi.Srivatsavai@Sun.COM } 1649815SRishi.Srivatsavai@Sun.COM 1659815SRishi.Srivatsavai@Sun.COM int 1669815SRishi.Srivatsavai@Sun.COM _info(struct modinfo *modinfop) 1679815SRishi.Srivatsavai@Sun.COM { 1689815SRishi.Srivatsavai@Sun.COM return (mod_info(&modlinkage, modinfop)); 1699815SRishi.Srivatsavai@Sun.COM } 1709815SRishi.Srivatsavai@Sun.COM 171*10416SRishi.Srivatsavai@Sun.COM static boolean_t 1729815SRishi.Srivatsavai@Sun.COM simnet_init(void) 1739815SRishi.Srivatsavai@Sun.COM { 174*10416SRishi.Srivatsavai@Sun.COM if ((simnet_rxq = ddi_taskq_create(simnet_dip, "simnet", 1, 175*10416SRishi.Srivatsavai@Sun.COM TASKQ_DEFAULTPRI, 0)) == NULL) 176*10416SRishi.Srivatsavai@Sun.COM return (B_FALSE); 1779815SRishi.Srivatsavai@Sun.COM rw_init(&simnet_dev_lock, NULL, RW_DEFAULT, NULL); 1789815SRishi.Srivatsavai@Sun.COM list_create(&simnet_dev_list, sizeof (simnet_dev_t), 1799815SRishi.Srivatsavai@Sun.COM offsetof(simnet_dev_t, sd_listnode)); 180*10416SRishi.Srivatsavai@Sun.COM return (B_TRUE); 1819815SRishi.Srivatsavai@Sun.COM } 1829815SRishi.Srivatsavai@Sun.COM 1839815SRishi.Srivatsavai@Sun.COM static void 1849815SRishi.Srivatsavai@Sun.COM simnet_fini(void) 1859815SRishi.Srivatsavai@Sun.COM { 1869815SRishi.Srivatsavai@Sun.COM ASSERT(simnet_count == 0); 1879815SRishi.Srivatsavai@Sun.COM rw_destroy(&simnet_dev_lock); 1889815SRishi.Srivatsavai@Sun.COM list_destroy(&simnet_dev_list); 189*10416SRishi.Srivatsavai@Sun.COM ddi_taskq_destroy(simnet_rxq); 1909815SRishi.Srivatsavai@Sun.COM } 1919815SRishi.Srivatsavai@Sun.COM 1929815SRishi.Srivatsavai@Sun.COM /*ARGSUSED*/ 1939815SRishi.Srivatsavai@Sun.COM static int 1949815SRishi.Srivatsavai@Sun.COM simnet_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1959815SRishi.Srivatsavai@Sun.COM void **result) 1969815SRishi.Srivatsavai@Sun.COM { 1979815SRishi.Srivatsavai@Sun.COM switch (infocmd) { 1989815SRishi.Srivatsavai@Sun.COM case DDI_INFO_DEVT2DEVINFO: 1999815SRishi.Srivatsavai@Sun.COM *result = simnet_dip; 2009815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 2019815SRishi.Srivatsavai@Sun.COM case DDI_INFO_DEVT2INSTANCE: 2029815SRishi.Srivatsavai@Sun.COM *result = NULL; 2039815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 2049815SRishi.Srivatsavai@Sun.COM } 2059815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 2069815SRishi.Srivatsavai@Sun.COM } 2079815SRishi.Srivatsavai@Sun.COM 2089815SRishi.Srivatsavai@Sun.COM static int 2099815SRishi.Srivatsavai@Sun.COM simnet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2109815SRishi.Srivatsavai@Sun.COM { 2119815SRishi.Srivatsavai@Sun.COM switch (cmd) { 2129815SRishi.Srivatsavai@Sun.COM case DDI_ATTACH: 2139815SRishi.Srivatsavai@Sun.COM if (ddi_get_instance(dip) != 0) { 2149815SRishi.Srivatsavai@Sun.COM /* we only allow instance 0 to attach */ 2159815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 2169815SRishi.Srivatsavai@Sun.COM } 217*10416SRishi.Srivatsavai@Sun.COM 2189815SRishi.Srivatsavai@Sun.COM if (dld_ioc_register(SIMNET_IOC, simnet_ioc_list, 2199815SRishi.Srivatsavai@Sun.COM DLDIOCCNT(simnet_ioc_list)) != 0) 2209815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 2219815SRishi.Srivatsavai@Sun.COM 2229815SRishi.Srivatsavai@Sun.COM simnet_dip = dip; 223*10416SRishi.Srivatsavai@Sun.COM if (!simnet_init()) 224*10416SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 2259815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 2269815SRishi.Srivatsavai@Sun.COM 2279815SRishi.Srivatsavai@Sun.COM case DDI_RESUME: 2289815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 2299815SRishi.Srivatsavai@Sun.COM 2309815SRishi.Srivatsavai@Sun.COM default: 2319815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 2329815SRishi.Srivatsavai@Sun.COM } 2339815SRishi.Srivatsavai@Sun.COM } 2349815SRishi.Srivatsavai@Sun.COM 2359815SRishi.Srivatsavai@Sun.COM /*ARGSUSED*/ 2369815SRishi.Srivatsavai@Sun.COM static int 2379815SRishi.Srivatsavai@Sun.COM simnet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2389815SRishi.Srivatsavai@Sun.COM { 2399815SRishi.Srivatsavai@Sun.COM switch (cmd) { 2409815SRishi.Srivatsavai@Sun.COM case DDI_DETACH: 2419815SRishi.Srivatsavai@Sun.COM /* 2429815SRishi.Srivatsavai@Sun.COM * Allow the simnet instance to be detached only if there 2439815SRishi.Srivatsavai@Sun.COM * are no simnets configured. 2449815SRishi.Srivatsavai@Sun.COM */ 2459815SRishi.Srivatsavai@Sun.COM if (simnet_count > 0) 2469815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 2479815SRishi.Srivatsavai@Sun.COM 248*10416SRishi.Srivatsavai@Sun.COM dld_ioc_unregister(SIMNET_IOC); 2499815SRishi.Srivatsavai@Sun.COM simnet_fini(); 250*10416SRishi.Srivatsavai@Sun.COM simnet_dip = NULL; 2519815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 2529815SRishi.Srivatsavai@Sun.COM 2539815SRishi.Srivatsavai@Sun.COM case DDI_SUSPEND: 2549815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS); 2559815SRishi.Srivatsavai@Sun.COM 2569815SRishi.Srivatsavai@Sun.COM default: 2579815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE); 2589815SRishi.Srivatsavai@Sun.COM } 2599815SRishi.Srivatsavai@Sun.COM } 2609815SRishi.Srivatsavai@Sun.COM 2619815SRishi.Srivatsavai@Sun.COM /* Caller must hold simnet_dev_lock */ 2629815SRishi.Srivatsavai@Sun.COM static simnet_dev_t * 2639815SRishi.Srivatsavai@Sun.COM simnet_dev_lookup(datalink_id_t link_id) 2649815SRishi.Srivatsavai@Sun.COM { 2659815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev; 2669815SRishi.Srivatsavai@Sun.COM 267*10416SRishi.Srivatsavai@Sun.COM ASSERT(RW_LOCK_HELD(&simnet_dev_lock)); 2689815SRishi.Srivatsavai@Sun.COM for (sdev = list_head(&simnet_dev_list); sdev != NULL; 2699815SRishi.Srivatsavai@Sun.COM sdev = list_next(&simnet_dev_list, sdev)) { 2709815SRishi.Srivatsavai@Sun.COM if (!(sdev->sd_flags & SDF_SHUTDOWN) && 2719815SRishi.Srivatsavai@Sun.COM (sdev->sd_link_id == link_id)) { 2729815SRishi.Srivatsavai@Sun.COM atomic_inc_32(&sdev->sd_refcount); 2739815SRishi.Srivatsavai@Sun.COM return (sdev); 2749815SRishi.Srivatsavai@Sun.COM } 2759815SRishi.Srivatsavai@Sun.COM } 2769815SRishi.Srivatsavai@Sun.COM 2779815SRishi.Srivatsavai@Sun.COM return (NULL); 2789815SRishi.Srivatsavai@Sun.COM } 2799815SRishi.Srivatsavai@Sun.COM 2809815SRishi.Srivatsavai@Sun.COM static void 2819815SRishi.Srivatsavai@Sun.COM simnet_wifidev_free(simnet_dev_t *sdev) 2829815SRishi.Srivatsavai@Sun.COM { 2839815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev; 2849815SRishi.Srivatsavai@Sun.COM int i; 2859815SRishi.Srivatsavai@Sun.COM 2869815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) { 2879815SRishi.Srivatsavai@Sun.COM kmem_free(wdev->swd_esslist[i], 2889815SRishi.Srivatsavai@Sun.COM sizeof (wl_ess_conf_t)); 2899815SRishi.Srivatsavai@Sun.COM } 2909815SRishi.Srivatsavai@Sun.COM kmem_free(wdev, sizeof (simnet_wifidev_t)); 2919815SRishi.Srivatsavai@Sun.COM } 2929815SRishi.Srivatsavai@Sun.COM 2939815SRishi.Srivatsavai@Sun.COM static void 2949815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(simnet_dev_t *sdev) 2959815SRishi.Srivatsavai@Sun.COM { 2969815SRishi.Srivatsavai@Sun.COM 2979815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_refcount > 0); 2989815SRishi.Srivatsavai@Sun.COM if (atomic_dec_32_nv(&sdev->sd_refcount) != 0) 2999815SRishi.Srivatsavai@Sun.COM return; 3009815SRishi.Srivatsavai@Sun.COM 3019815SRishi.Srivatsavai@Sun.COM if (sdev->sd_mh != NULL) 3029815SRishi.Srivatsavai@Sun.COM (void) mac_unregister(sdev->sd_mh); 3039815SRishi.Srivatsavai@Sun.COM 3049815SRishi.Srivatsavai@Sun.COM if (sdev->sd_wifidev != NULL) { 3059815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_type == DL_WIFI); 3069815SRishi.Srivatsavai@Sun.COM simnet_wifidev_free(sdev); 3079815SRishi.Srivatsavai@Sun.COM } 3089815SRishi.Srivatsavai@Sun.COM 3099815SRishi.Srivatsavai@Sun.COM mutex_destroy(&sdev->sd_instlock); 3109815SRishi.Srivatsavai@Sun.COM cv_destroy(&sdev->sd_threadwait); 3119815SRishi.Srivatsavai@Sun.COM kmem_free(sdev->sd_mcastaddrs, ETHERADDRL * sdev->sd_mcastaddr_count); 3129815SRishi.Srivatsavai@Sun.COM kmem_free(sdev, sizeof (*sdev)); 3139815SRishi.Srivatsavai@Sun.COM simnet_count--; 3149815SRishi.Srivatsavai@Sun.COM } 3159815SRishi.Srivatsavai@Sun.COM 3169815SRishi.Srivatsavai@Sun.COM static int 3179815SRishi.Srivatsavai@Sun.COM simnet_init_wifi(simnet_dev_t *sdev, mac_register_t *mac) 3189815SRishi.Srivatsavai@Sun.COM { 3199815SRishi.Srivatsavai@Sun.COM wifi_data_t wd = { 0 }; 3209815SRishi.Srivatsavai@Sun.COM int err; 3219815SRishi.Srivatsavai@Sun.COM 3229815SRishi.Srivatsavai@Sun.COM sdev->sd_wifidev = kmem_zalloc(sizeof (simnet_wifidev_t), KM_NOSLEEP); 3239815SRishi.Srivatsavai@Sun.COM if (sdev->sd_wifidev == NULL) 3249815SRishi.Srivatsavai@Sun.COM return (ENOMEM); 3259815SRishi.Srivatsavai@Sun.COM 3269815SRishi.Srivatsavai@Sun.COM sdev->sd_wifidev->swd_sdev = sdev; 3279815SRishi.Srivatsavai@Sun.COM sdev->sd_wifidev->swd_linkstatus = WL_NOTCONNECTED; 3289815SRishi.Srivatsavai@Sun.COM wd.wd_secalloc = WIFI_SEC_NONE; 3299815SRishi.Srivatsavai@Sun.COM wd.wd_opmode = IEEE80211_M_STA; 3309815SRishi.Srivatsavai@Sun.COM mac->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 3319815SRishi.Srivatsavai@Sun.COM mac->m_max_sdu = IEEE80211_MTU; 3329815SRishi.Srivatsavai@Sun.COM mac->m_pdata = &wd; 3339815SRishi.Srivatsavai@Sun.COM mac->m_pdata_size = sizeof (wd); 3349815SRishi.Srivatsavai@Sun.COM err = mac_register(mac, &sdev->sd_mh); 3359815SRishi.Srivatsavai@Sun.COM return (err); 3369815SRishi.Srivatsavai@Sun.COM } 3379815SRishi.Srivatsavai@Sun.COM 3389815SRishi.Srivatsavai@Sun.COM static int 3399815SRishi.Srivatsavai@Sun.COM simnet_init_ether(simnet_dev_t *sdev, mac_register_t *mac) 3409815SRishi.Srivatsavai@Sun.COM { 3419815SRishi.Srivatsavai@Sun.COM int err; 3429815SRishi.Srivatsavai@Sun.COM 3439815SRishi.Srivatsavai@Sun.COM mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 3449815SRishi.Srivatsavai@Sun.COM mac->m_max_sdu = SIMNET_MAX_MTU; 3459815SRishi.Srivatsavai@Sun.COM mac->m_margin = VLAN_TAGSZ; 3469815SRishi.Srivatsavai@Sun.COM err = mac_register(mac, &sdev->sd_mh); 3479815SRishi.Srivatsavai@Sun.COM return (err); 3489815SRishi.Srivatsavai@Sun.COM } 3499815SRishi.Srivatsavai@Sun.COM 3509815SRishi.Srivatsavai@Sun.COM static int 3519815SRishi.Srivatsavai@Sun.COM simnet_init_mac(simnet_dev_t *sdev) 3529815SRishi.Srivatsavai@Sun.COM { 3539815SRishi.Srivatsavai@Sun.COM mac_register_t *mac; 3549815SRishi.Srivatsavai@Sun.COM int err; 3559815SRishi.Srivatsavai@Sun.COM 3569815SRishi.Srivatsavai@Sun.COM if ((mac = mac_alloc(MAC_VERSION)) == NULL) 3579815SRishi.Srivatsavai@Sun.COM return (ENOMEM); 3589815SRishi.Srivatsavai@Sun.COM 3599815SRishi.Srivatsavai@Sun.COM mac->m_driver = sdev; 3609815SRishi.Srivatsavai@Sun.COM mac->m_dip = simnet_dip; 3619815SRishi.Srivatsavai@Sun.COM mac->m_instance = (uint_t)-1; 3629815SRishi.Srivatsavai@Sun.COM mac->m_src_addr = sdev->sd_mac_addr; 3639815SRishi.Srivatsavai@Sun.COM mac->m_callbacks = &simnet_m_callbacks; 3649815SRishi.Srivatsavai@Sun.COM mac->m_min_sdu = 0; 3659815SRishi.Srivatsavai@Sun.COM 3669815SRishi.Srivatsavai@Sun.COM if (sdev->sd_type == DL_ETHER) 3679815SRishi.Srivatsavai@Sun.COM err = simnet_init_ether(sdev, mac); 3689815SRishi.Srivatsavai@Sun.COM else if (sdev->sd_type == DL_WIFI) 3699815SRishi.Srivatsavai@Sun.COM err = simnet_init_wifi(sdev, mac); 3709815SRishi.Srivatsavai@Sun.COM else 3719815SRishi.Srivatsavai@Sun.COM err = EINVAL; 3729815SRishi.Srivatsavai@Sun.COM 3739815SRishi.Srivatsavai@Sun.COM mac_free(mac); 3749815SRishi.Srivatsavai@Sun.COM return (err); 3759815SRishi.Srivatsavai@Sun.COM } 3769815SRishi.Srivatsavai@Sun.COM 3779815SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 3789815SRishi.Srivatsavai@Sun.COM static int 3799815SRishi.Srivatsavai@Sun.COM simnet_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 3809815SRishi.Srivatsavai@Sun.COM { 3819815SRishi.Srivatsavai@Sun.COM simnet_ioc_create_t *create_arg = karg; 3829815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev; 3839815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_tmp; 3849815SRishi.Srivatsavai@Sun.COM int err = 0; 3859815SRishi.Srivatsavai@Sun.COM 3869815SRishi.Srivatsavai@Sun.COM sdev = kmem_zalloc(sizeof (*sdev), KM_NOSLEEP); 3879815SRishi.Srivatsavai@Sun.COM if (sdev == NULL) 3889815SRishi.Srivatsavai@Sun.COM return (ENOMEM); 3899815SRishi.Srivatsavai@Sun.COM 3909815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_WRITER); 3919815SRishi.Srivatsavai@Sun.COM if ((sdev_tmp = simnet_dev_lookup(create_arg->sic_link_id)) != NULL) { 3929815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev_tmp); 3939815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 3949815SRishi.Srivatsavai@Sun.COM kmem_free(sdev, sizeof (*sdev)); 3959815SRishi.Srivatsavai@Sun.COM return (EEXIST); 3969815SRishi.Srivatsavai@Sun.COM } 3979815SRishi.Srivatsavai@Sun.COM 3989815SRishi.Srivatsavai@Sun.COM sdev->sd_type = create_arg->sic_type; 3999815SRishi.Srivatsavai@Sun.COM sdev->sd_link_id = create_arg->sic_link_id; 4009815SRishi.Srivatsavai@Sun.COM sdev->sd_refcount++; 4019815SRishi.Srivatsavai@Sun.COM mutex_init(&sdev->sd_instlock, NULL, MUTEX_DRIVER, NULL); 4029815SRishi.Srivatsavai@Sun.COM cv_init(&sdev->sd_threadwait, NULL, CV_DRIVER, NULL); 4039815SRishi.Srivatsavai@Sun.COM simnet_count++; 4049815SRishi.Srivatsavai@Sun.COM 4059815SRishi.Srivatsavai@Sun.COM /* Simnets created from configuration on boot pass saved MAC address */ 4069815SRishi.Srivatsavai@Sun.COM if (create_arg->sic_mac_len == 0) { 4079815SRishi.Srivatsavai@Sun.COM /* Generate random MAC address */ 4089815SRishi.Srivatsavai@Sun.COM (void) random_get_pseudo_bytes(sdev->sd_mac_addr, ETHERADDRL); 4099815SRishi.Srivatsavai@Sun.COM /* Ensure MAC address is not multicast and is local */ 4109815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_addr[0] = (sdev->sd_mac_addr[0] & ~1) | 2; 4119815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_len = ETHERADDRL; 4129815SRishi.Srivatsavai@Sun.COM } else { 4139815SRishi.Srivatsavai@Sun.COM (void) memcpy(sdev->sd_mac_addr, create_arg->sic_mac_addr, 4149815SRishi.Srivatsavai@Sun.COM create_arg->sic_mac_len); 4159815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_len = create_arg->sic_mac_len; 4169815SRishi.Srivatsavai@Sun.COM } 4179815SRishi.Srivatsavai@Sun.COM 4189815SRishi.Srivatsavai@Sun.COM if ((err = simnet_init_mac(sdev)) != 0) { 4199815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 4209815SRishi.Srivatsavai@Sun.COM goto exit; 4219815SRishi.Srivatsavai@Sun.COM } 4229815SRishi.Srivatsavai@Sun.COM 4239815SRishi.Srivatsavai@Sun.COM if ((err = dls_devnet_create(sdev->sd_mh, sdev->sd_link_id)) != 0) { 4249815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 4259815SRishi.Srivatsavai@Sun.COM goto exit; 4269815SRishi.Srivatsavai@Sun.COM } 4279815SRishi.Srivatsavai@Sun.COM 4289815SRishi.Srivatsavai@Sun.COM mac_link_update(sdev->sd_mh, LINK_STATE_UP); 4299815SRishi.Srivatsavai@Sun.COM mac_tx_update(sdev->sd_mh); 4309815SRishi.Srivatsavai@Sun.COM list_insert_tail(&simnet_dev_list, sdev); 4319815SRishi.Srivatsavai@Sun.COM 4329815SRishi.Srivatsavai@Sun.COM /* Always return MAC address back to caller */ 4339815SRishi.Srivatsavai@Sun.COM (void) memcpy(create_arg->sic_mac_addr, sdev->sd_mac_addr, 4349815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_len); 4359815SRishi.Srivatsavai@Sun.COM create_arg->sic_mac_len = sdev->sd_mac_len; 4369815SRishi.Srivatsavai@Sun.COM exit: 4379815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 4389815SRishi.Srivatsavai@Sun.COM return (err); 4399815SRishi.Srivatsavai@Sun.COM } 4409815SRishi.Srivatsavai@Sun.COM 4419815SRishi.Srivatsavai@Sun.COM /* Caller must hold writer simnet_dev_lock */ 4429815SRishi.Srivatsavai@Sun.COM static datalink_id_t 4439815SRishi.Srivatsavai@Sun.COM simnet_remove_peer(simnet_dev_t *sdev) 4449815SRishi.Srivatsavai@Sun.COM { 4459815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_peer; 4469815SRishi.Srivatsavai@Sun.COM datalink_id_t peer_link_id = DATALINK_INVALID_LINKID; 4479815SRishi.Srivatsavai@Sun.COM 448*10416SRishi.Srivatsavai@Sun.COM ASSERT(RW_WRITE_HELD(&simnet_dev_lock)); 4499815SRishi.Srivatsavai@Sun.COM if ((sdev_peer = sdev->sd_peer_dev) != NULL) { 4509815SRishi.Srivatsavai@Sun.COM ASSERT(sdev == sdev_peer->sd_peer_dev); 4519815SRishi.Srivatsavai@Sun.COM sdev_peer->sd_peer_dev = NULL; 4529815SRishi.Srivatsavai@Sun.COM sdev->sd_peer_dev = NULL; 4539815SRishi.Srivatsavai@Sun.COM peer_link_id = sdev_peer->sd_link_id; 4549815SRishi.Srivatsavai@Sun.COM /* Release previous references held on both simnets */ 4559815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev_peer); 4569815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 4579815SRishi.Srivatsavai@Sun.COM } 4589815SRishi.Srivatsavai@Sun.COM 4599815SRishi.Srivatsavai@Sun.COM return (peer_link_id); 4609815SRishi.Srivatsavai@Sun.COM } 4619815SRishi.Srivatsavai@Sun.COM 4629815SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 4639815SRishi.Srivatsavai@Sun.COM static int 4649815SRishi.Srivatsavai@Sun.COM simnet_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 4659815SRishi.Srivatsavai@Sun.COM { 4669815SRishi.Srivatsavai@Sun.COM simnet_ioc_modify_t *modify_arg = karg; 4679815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev; 4689815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_peer = NULL; 4699815SRishi.Srivatsavai@Sun.COM 4709815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_WRITER); 4719815SRishi.Srivatsavai@Sun.COM if ((sdev = simnet_dev_lookup(modify_arg->sim_link_id)) == NULL) { 4729815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 4739815SRishi.Srivatsavai@Sun.COM return (ENOENT); 4749815SRishi.Srivatsavai@Sun.COM } 4759815SRishi.Srivatsavai@Sun.COM 4769815SRishi.Srivatsavai@Sun.COM if (sdev->sd_link_id == modify_arg->sim_peer_link_id) { 4779815SRishi.Srivatsavai@Sun.COM /* Cannot peer with self */ 4789815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 4799815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 4809815SRishi.Srivatsavai@Sun.COM return (EINVAL); 4819815SRishi.Srivatsavai@Sun.COM } 4829815SRishi.Srivatsavai@Sun.COM 4839815SRishi.Srivatsavai@Sun.COM if (sdev->sd_peer_dev != NULL && sdev->sd_peer_dev->sd_link_id == 4849815SRishi.Srivatsavai@Sun.COM modify_arg->sim_peer_link_id) { 4859815SRishi.Srivatsavai@Sun.COM /* Nothing to modify */ 4869815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 4879815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 4889815SRishi.Srivatsavai@Sun.COM return (0); 4899815SRishi.Srivatsavai@Sun.COM } 4909815SRishi.Srivatsavai@Sun.COM 4919815SRishi.Srivatsavai@Sun.COM if (modify_arg->sim_peer_link_id != DATALINK_INVALID_LINKID && 4929815SRishi.Srivatsavai@Sun.COM (sdev_peer = simnet_dev_lookup(modify_arg->sim_peer_link_id)) == 4939815SRishi.Srivatsavai@Sun.COM NULL) { 4949815SRishi.Srivatsavai@Sun.COM /* Peer simnet device not available */ 4959815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 4969815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 4979815SRishi.Srivatsavai@Sun.COM return (ENOENT); 4989815SRishi.Srivatsavai@Sun.COM } 4999815SRishi.Srivatsavai@Sun.COM 5009815SRishi.Srivatsavai@Sun.COM /* First remove any previous peer */ 5019815SRishi.Srivatsavai@Sun.COM (void) simnet_remove_peer(sdev); 5029815SRishi.Srivatsavai@Sun.COM 5039815SRishi.Srivatsavai@Sun.COM if (sdev_peer != NULL) { 5049815SRishi.Srivatsavai@Sun.COM /* Remove any previous peer of sdev_peer */ 5059815SRishi.Srivatsavai@Sun.COM (void) simnet_remove_peer(sdev_peer); 5069815SRishi.Srivatsavai@Sun.COM /* Update both devices with the new peer */ 5079815SRishi.Srivatsavai@Sun.COM sdev_peer->sd_peer_dev = sdev; 5089815SRishi.Srivatsavai@Sun.COM sdev->sd_peer_dev = sdev_peer; 5099815SRishi.Srivatsavai@Sun.COM /* Hold references on both devices */ 5109815SRishi.Srivatsavai@Sun.COM } else { 5119815SRishi.Srivatsavai@Sun.COM /* Release sdev lookup reference */ 5129815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 5139815SRishi.Srivatsavai@Sun.COM } 5149815SRishi.Srivatsavai@Sun.COM 5159815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 5169815SRishi.Srivatsavai@Sun.COM return (0); 5179815SRishi.Srivatsavai@Sun.COM } 5189815SRishi.Srivatsavai@Sun.COM 5199815SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 5209815SRishi.Srivatsavai@Sun.COM static int 5219815SRishi.Srivatsavai@Sun.COM simnet_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 5229815SRishi.Srivatsavai@Sun.COM { 5239815SRishi.Srivatsavai@Sun.COM int err; 5249815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev; 5259815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_peer; 5269815SRishi.Srivatsavai@Sun.COM simnet_ioc_delete_t *delete_arg = karg; 5279815SRishi.Srivatsavai@Sun.COM datalink_id_t tmpid; 5289815SRishi.Srivatsavai@Sun.COM datalink_id_t peerid; 5299815SRishi.Srivatsavai@Sun.COM 5309815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_WRITER); 5319815SRishi.Srivatsavai@Sun.COM if ((sdev = simnet_dev_lookup(delete_arg->sid_link_id)) == NULL) { 5329815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 5339815SRishi.Srivatsavai@Sun.COM return (ENOENT); 5349815SRishi.Srivatsavai@Sun.COM } 5359815SRishi.Srivatsavai@Sun.COM 5369815SRishi.Srivatsavai@Sun.COM if ((err = dls_devnet_destroy(sdev->sd_mh, &tmpid, B_TRUE)) != 0) { 5379815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 5389815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 5399815SRishi.Srivatsavai@Sun.COM return (err); 5409815SRishi.Srivatsavai@Sun.COM } 5419815SRishi.Srivatsavai@Sun.COM 5429815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_link_id == tmpid); 5439815SRishi.Srivatsavai@Sun.COM /* Remove any attached peer link */ 5449815SRishi.Srivatsavai@Sun.COM peerid = simnet_remove_peer(sdev); 5459815SRishi.Srivatsavai@Sun.COM 5469815SRishi.Srivatsavai@Sun.COM /* Prevent new threads from using the instance */ 5479815SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock); 5489815SRishi.Srivatsavai@Sun.COM sdev->sd_flags |= SDF_SHUTDOWN; 5499815SRishi.Srivatsavai@Sun.COM /* Wait until all active threads using the instance exit */ 5509815SRishi.Srivatsavai@Sun.COM while (sdev->sd_threadcount > 0) { 5519815SRishi.Srivatsavai@Sun.COM if (cv_wait_sig(&sdev->sd_threadwait, 5529815SRishi.Srivatsavai@Sun.COM &sdev->sd_instlock) == 0) { 5539815SRishi.Srivatsavai@Sun.COM /* Signaled */ 5549815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 5559815SRishi.Srivatsavai@Sun.COM err = EINTR; 5569815SRishi.Srivatsavai@Sun.COM goto fail; 5579815SRishi.Srivatsavai@Sun.COM } 5589815SRishi.Srivatsavai@Sun.COM } 5599815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 5609815SRishi.Srivatsavai@Sun.COM 5619815SRishi.Srivatsavai@Sun.COM /* Try disabling the MAC */ 5629815SRishi.Srivatsavai@Sun.COM if ((err = mac_disable(sdev->sd_mh)) != 0) 5639815SRishi.Srivatsavai@Sun.COM goto fail; 5649815SRishi.Srivatsavai@Sun.COM 5659815SRishi.Srivatsavai@Sun.COM list_remove(&simnet_dev_list, sdev); 5669815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 5679815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); /* Release lookup ref */ 5689815SRishi.Srivatsavai@Sun.COM /* Releasing the last ref performs sdev/mem free */ 5699815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 5709815SRishi.Srivatsavai@Sun.COM return (err); 5719815SRishi.Srivatsavai@Sun.COM fail: 5729815SRishi.Srivatsavai@Sun.COM /* Re-create simnet instance and add any previous peer */ 5739815SRishi.Srivatsavai@Sun.COM (void) dls_devnet_create(sdev->sd_mh, sdev->sd_link_id); 5749815SRishi.Srivatsavai@Sun.COM sdev->sd_flags &= ~SDF_SHUTDOWN; 5759815SRishi.Srivatsavai@Sun.COM 5769815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_peer_dev == NULL); 5779815SRishi.Srivatsavai@Sun.COM if (peerid != DATALINK_INVALID_LINKID && 5789815SRishi.Srivatsavai@Sun.COM ((sdev_peer = simnet_dev_lookup(peerid)) != NULL)) { 5799815SRishi.Srivatsavai@Sun.COM /* Attach peer device back */ 5809815SRishi.Srivatsavai@Sun.COM ASSERT(sdev_peer->sd_peer_dev == NULL); 5819815SRishi.Srivatsavai@Sun.COM sdev_peer->sd_peer_dev = sdev; 5829815SRishi.Srivatsavai@Sun.COM sdev->sd_peer_dev = sdev_peer; 5839815SRishi.Srivatsavai@Sun.COM /* Hold reference on both devices */ 5849815SRishi.Srivatsavai@Sun.COM } else { 5859815SRishi.Srivatsavai@Sun.COM /* 5869815SRishi.Srivatsavai@Sun.COM * No previous peer or previous peer no longer 5879815SRishi.Srivatsavai@Sun.COM * available so release lookup reference. 5889815SRishi.Srivatsavai@Sun.COM */ 5899815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 5909815SRishi.Srivatsavai@Sun.COM } 5919815SRishi.Srivatsavai@Sun.COM 5929815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 5939815SRishi.Srivatsavai@Sun.COM return (err); 5949815SRishi.Srivatsavai@Sun.COM } 5959815SRishi.Srivatsavai@Sun.COM 5969815SRishi.Srivatsavai@Sun.COM /* ARGSUSED */ 5979815SRishi.Srivatsavai@Sun.COM static int 5989815SRishi.Srivatsavai@Sun.COM simnet_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 5999815SRishi.Srivatsavai@Sun.COM { 6009815SRishi.Srivatsavai@Sun.COM simnet_ioc_info_t *info_arg = karg; 6019815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev; 6029815SRishi.Srivatsavai@Sun.COM 6039815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_READER); 6049815SRishi.Srivatsavai@Sun.COM if ((sdev = simnet_dev_lookup(info_arg->sii_link_id)) == NULL) { 6059815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 6069815SRishi.Srivatsavai@Sun.COM return (ENOENT); 6079815SRishi.Srivatsavai@Sun.COM } 6089815SRishi.Srivatsavai@Sun.COM 6099815SRishi.Srivatsavai@Sun.COM (void) memcpy(info_arg->sii_mac_addr, sdev->sd_mac_addr, 6109815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_len); 6119815SRishi.Srivatsavai@Sun.COM info_arg->sii_mac_len = sdev->sd_mac_len; 6129815SRishi.Srivatsavai@Sun.COM info_arg->sii_type = sdev->sd_type; 6139815SRishi.Srivatsavai@Sun.COM if (sdev->sd_peer_dev != NULL) 6149815SRishi.Srivatsavai@Sun.COM info_arg->sii_peer_link_id = sdev->sd_peer_dev->sd_link_id; 6159815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 6169815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); 6179815SRishi.Srivatsavai@Sun.COM return (0); 6189815SRishi.Srivatsavai@Sun.COM } 6199815SRishi.Srivatsavai@Sun.COM 620*10416SRishi.Srivatsavai@Sun.COM static boolean_t 621*10416SRishi.Srivatsavai@Sun.COM simnet_thread_ref(simnet_dev_t *sdev) 622*10416SRishi.Srivatsavai@Sun.COM { 623*10416SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock); 624*10416SRishi.Srivatsavai@Sun.COM if (sdev->sd_flags & SDF_SHUTDOWN || 625*10416SRishi.Srivatsavai@Sun.COM !(sdev->sd_flags & SDF_STARTED)) { 626*10416SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 627*10416SRishi.Srivatsavai@Sun.COM return (B_FALSE); 628*10416SRishi.Srivatsavai@Sun.COM } 629*10416SRishi.Srivatsavai@Sun.COM sdev->sd_threadcount++; 630*10416SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 631*10416SRishi.Srivatsavai@Sun.COM return (B_TRUE); 632*10416SRishi.Srivatsavai@Sun.COM } 633*10416SRishi.Srivatsavai@Sun.COM 6349815SRishi.Srivatsavai@Sun.COM static void 635*10416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(simnet_dev_t *sdev) 6369815SRishi.Srivatsavai@Sun.COM { 637*10416SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock); 638*10416SRishi.Srivatsavai@Sun.COM if (--sdev->sd_threadcount == 0) 639*10416SRishi.Srivatsavai@Sun.COM cv_broadcast(&sdev->sd_threadwait); 640*10416SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 641*10416SRishi.Srivatsavai@Sun.COM } 642*10416SRishi.Srivatsavai@Sun.COM 643*10416SRishi.Srivatsavai@Sun.COM static void 644*10416SRishi.Srivatsavai@Sun.COM simnet_rx(void *arg) 645*10416SRishi.Srivatsavai@Sun.COM { 646*10416SRishi.Srivatsavai@Sun.COM mblk_t *mp = arg; 6479815SRishi.Srivatsavai@Sun.COM mac_header_info_t hdr_info; 648*10416SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev; 649*10416SRishi.Srivatsavai@Sun.COM 650*10416SRishi.Srivatsavai@Sun.COM sdev = (simnet_dev_t *)mp->b_next; 651*10416SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 6529815SRishi.Srivatsavai@Sun.COM 6539815SRishi.Srivatsavai@Sun.COM /* Check for valid packet header */ 6549815SRishi.Srivatsavai@Sun.COM if (mac_header_info(sdev->sd_mh, mp, &hdr_info) != 0) { 6559815SRishi.Srivatsavai@Sun.COM freemsg(mp); 6569815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.recv_errors++; 657*10416SRishi.Srivatsavai@Sun.COM goto rx_done; 6589815SRishi.Srivatsavai@Sun.COM } 6599815SRishi.Srivatsavai@Sun.COM 6609815SRishi.Srivatsavai@Sun.COM /* 6619815SRishi.Srivatsavai@Sun.COM * When we are NOT in promiscuous mode we only receive 6629815SRishi.Srivatsavai@Sun.COM * unicast packets addressed to us and multicast packets that 6639815SRishi.Srivatsavai@Sun.COM * MAC clients have requested. 6649815SRishi.Srivatsavai@Sun.COM */ 6659815SRishi.Srivatsavai@Sun.COM if (!sdev->sd_promisc && 6669815SRishi.Srivatsavai@Sun.COM hdr_info.mhi_dsttype != MAC_ADDRTYPE_BROADCAST) { 6679815SRishi.Srivatsavai@Sun.COM if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_UNICAST && 6689815SRishi.Srivatsavai@Sun.COM bcmp(hdr_info.mhi_daddr, sdev->sd_mac_addr, 6699815SRishi.Srivatsavai@Sun.COM ETHERADDRL) != 0) { 6709815SRishi.Srivatsavai@Sun.COM freemsg(mp); 671*10416SRishi.Srivatsavai@Sun.COM goto rx_done; 6729815SRishi.Srivatsavai@Sun.COM } else if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) { 6739815SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock); 6749815SRishi.Srivatsavai@Sun.COM if (mcastaddr_lookup(sdev, hdr_info.mhi_daddr) == 6759815SRishi.Srivatsavai@Sun.COM NULL) { 6769815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 6779815SRishi.Srivatsavai@Sun.COM freemsg(mp); 678*10416SRishi.Srivatsavai@Sun.COM goto rx_done; 6799815SRishi.Srivatsavai@Sun.COM } 6809815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 6819815SRishi.Srivatsavai@Sun.COM } 6829815SRishi.Srivatsavai@Sun.COM } 6839815SRishi.Srivatsavai@Sun.COM 6849815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.recv_count++; 6859815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.rbytes += msgdsize(mp); 6869815SRishi.Srivatsavai@Sun.COM mac_rx(sdev->sd_mh, NULL, mp); 687*10416SRishi.Srivatsavai@Sun.COM rx_done: 688*10416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev); 6899815SRishi.Srivatsavai@Sun.COM } 6909815SRishi.Srivatsavai@Sun.COM 6919815SRishi.Srivatsavai@Sun.COM static mblk_t * 6929815SRishi.Srivatsavai@Sun.COM simnet_m_tx(void *arg, mblk_t *mp_chain) 6939815SRishi.Srivatsavai@Sun.COM { 6949815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 6959815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_rx; 6969815SRishi.Srivatsavai@Sun.COM mblk_t *mpnext = mp_chain; 6979815SRishi.Srivatsavai@Sun.COM mblk_t *mp; 6989815SRishi.Srivatsavai@Sun.COM 6999815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_READER); 7009815SRishi.Srivatsavai@Sun.COM if ((sdev_rx = sdev->sd_peer_dev) == NULL) { 7019815SRishi.Srivatsavai@Sun.COM /* Discard packets when no peer exists */ 7029815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 7039815SRishi.Srivatsavai@Sun.COM freemsgchain(mp_chain); 7049815SRishi.Srivatsavai@Sun.COM return (NULL); 7059815SRishi.Srivatsavai@Sun.COM } 7069815SRishi.Srivatsavai@Sun.COM 7079815SRishi.Srivatsavai@Sun.COM /* 7089815SRishi.Srivatsavai@Sun.COM * Discard packets when either device is shutting down or not ready. 7099815SRishi.Srivatsavai@Sun.COM * Though MAC layer ensures a reference is held on the MAC while we 7109815SRishi.Srivatsavai@Sun.COM * process the packet chain, there is no guarantee the peer MAC will 7119815SRishi.Srivatsavai@Sun.COM * remain enabled. So we increment per-instance threadcount to ensure 7129815SRishi.Srivatsavai@Sun.COM * either MAC instance is not disabled while we handle the chain of 7139815SRishi.Srivatsavai@Sun.COM * packets. It is okay if the peer device is disconnected while we are 7149815SRishi.Srivatsavai@Sun.COM * here since we lookup the peer device while holding simnet_dev_lock 7159815SRishi.Srivatsavai@Sun.COM * (reader lock) and increment the threadcount of the peer, the peer 7169815SRishi.Srivatsavai@Sun.COM * MAC cannot be disabled in simnet_ioc_delete. 7179815SRishi.Srivatsavai@Sun.COM */ 718*10416SRishi.Srivatsavai@Sun.COM if (!simnet_thread_ref(sdev_rx)) { 7199815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 7209815SRishi.Srivatsavai@Sun.COM freemsgchain(mp_chain); 7219815SRishi.Srivatsavai@Sun.COM return (NULL); 7229815SRishi.Srivatsavai@Sun.COM } 7239815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock); 7249815SRishi.Srivatsavai@Sun.COM 725*10416SRishi.Srivatsavai@Sun.COM if (!simnet_thread_ref(sdev)) { 726*10416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev_rx); 7279815SRishi.Srivatsavai@Sun.COM freemsgchain(mp_chain); 7289815SRishi.Srivatsavai@Sun.COM return (NULL); 7299815SRishi.Srivatsavai@Sun.COM } 7309815SRishi.Srivatsavai@Sun.COM 7319815SRishi.Srivatsavai@Sun.COM while ((mp = mpnext) != NULL) { 7329815SRishi.Srivatsavai@Sun.COM int len; 7339815SRishi.Srivatsavai@Sun.COM int size; 7349815SRishi.Srivatsavai@Sun.COM mblk_t *mp_new; 7359815SRishi.Srivatsavai@Sun.COM mblk_t *mp_tmp; 7369815SRishi.Srivatsavai@Sun.COM 7379815SRishi.Srivatsavai@Sun.COM mpnext = mp->b_next; 7389815SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 7399815SRishi.Srivatsavai@Sun.COM len = msgdsize(mp); 7409815SRishi.Srivatsavai@Sun.COM 7419815SRishi.Srivatsavai@Sun.COM /* Pad packet to minimum Ethernet frame size */ 7429815SRishi.Srivatsavai@Sun.COM if (len < ETHERMIN) { 7439815SRishi.Srivatsavai@Sun.COM size = ETHERMIN - len; 7449815SRishi.Srivatsavai@Sun.COM mp_new = allocb(size, BPRI_HI); 7459815SRishi.Srivatsavai@Sun.COM if (mp_new == NULL) { 7469815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.xmit_errors++; 7479815SRishi.Srivatsavai@Sun.COM freemsg(mp); 7489815SRishi.Srivatsavai@Sun.COM continue; 7499815SRishi.Srivatsavai@Sun.COM } 7509815SRishi.Srivatsavai@Sun.COM bzero(mp_new->b_wptr, size); 7519815SRishi.Srivatsavai@Sun.COM mp_new->b_wptr += size; 7529815SRishi.Srivatsavai@Sun.COM 7539815SRishi.Srivatsavai@Sun.COM mp_tmp = mp; 7549815SRishi.Srivatsavai@Sun.COM while (mp_tmp->b_cont != NULL) 7559815SRishi.Srivatsavai@Sun.COM mp_tmp = mp_tmp->b_cont; 7569815SRishi.Srivatsavai@Sun.COM mp_tmp->b_cont = mp_new; 7579815SRishi.Srivatsavai@Sun.COM len += size; 7589815SRishi.Srivatsavai@Sun.COM } 7599815SRishi.Srivatsavai@Sun.COM 7609815SRishi.Srivatsavai@Sun.COM /* Pullup packet into a single mblk */ 7619815SRishi.Srivatsavai@Sun.COM if (!pullupmsg(mp, -1)) { 7629815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.xmit_errors++; 7639815SRishi.Srivatsavai@Sun.COM freemsg(mp); 7649815SRishi.Srivatsavai@Sun.COM continue; 7659815SRishi.Srivatsavai@Sun.COM } 7669815SRishi.Srivatsavai@Sun.COM 7679815SRishi.Srivatsavai@Sun.COM /* Fix mblk checksum as the pkt dest is local */ 7689815SRishi.Srivatsavai@Sun.COM if ((mp = mac_fix_cksum(mp)) == NULL) { 7699815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.xmit_errors++; 7709815SRishi.Srivatsavai@Sun.COM continue; 7719815SRishi.Srivatsavai@Sun.COM } 7729815SRishi.Srivatsavai@Sun.COM 773*10416SRishi.Srivatsavai@Sun.COM /* Hold reference for taskq receive processing per-pkt */ 774*10416SRishi.Srivatsavai@Sun.COM if (!simnet_thread_ref(sdev_rx)) { 775*10416SRishi.Srivatsavai@Sun.COM freemsg(mp); 776*10416SRishi.Srivatsavai@Sun.COM freemsgchain(mpnext); 777*10416SRishi.Srivatsavai@Sun.COM break; 778*10416SRishi.Srivatsavai@Sun.COM } 779*10416SRishi.Srivatsavai@Sun.COM 780*10416SRishi.Srivatsavai@Sun.COM /* Use taskq for pkt receive to avoid kernel stack explosion */ 781*10416SRishi.Srivatsavai@Sun.COM mp->b_next = (mblk_t *)sdev_rx; 782*10416SRishi.Srivatsavai@Sun.COM if (ddi_taskq_dispatch(simnet_rxq, simnet_rx, mp, 783*10416SRishi.Srivatsavai@Sun.COM DDI_NOSLEEP) == DDI_SUCCESS) { 784*10416SRishi.Srivatsavai@Sun.COM sdev->sd_stats.xmit_count++; 785*10416SRishi.Srivatsavai@Sun.COM sdev->sd_stats.obytes += len; 786*10416SRishi.Srivatsavai@Sun.COM } else { 787*10416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev_rx); 788*10416SRishi.Srivatsavai@Sun.COM mp->b_next = NULL; 789*10416SRishi.Srivatsavai@Sun.COM freemsg(mp); 790*10416SRishi.Srivatsavai@Sun.COM sdev_rx->sd_stats.recv_errors++; 791*10416SRishi.Srivatsavai@Sun.COM } 7929815SRishi.Srivatsavai@Sun.COM } 7939815SRishi.Srivatsavai@Sun.COM 794*10416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev); 795*10416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev_rx); 7969815SRishi.Srivatsavai@Sun.COM return (NULL); 7979815SRishi.Srivatsavai@Sun.COM } 7989815SRishi.Srivatsavai@Sun.COM 7999815SRishi.Srivatsavai@Sun.COM static int 8009815SRishi.Srivatsavai@Sun.COM simnet_wifi_ioctl(simnet_dev_t *sdev, mblk_t *mp) 8019815SRishi.Srivatsavai@Sun.COM { 8029815SRishi.Srivatsavai@Sun.COM int rc = WL_SUCCESS; 8039815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev; 8049815SRishi.Srivatsavai@Sun.COM 8059815SRishi.Srivatsavai@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */ 8069815SRishi.Srivatsavai@Sun.COM switch (((wldp_t *)mp->b_rptr)->wldp_id) { 8079815SRishi.Srivatsavai@Sun.COM case WL_DISASSOCIATE: 8089815SRishi.Srivatsavai@Sun.COM wdev->swd_linkstatus = WL_NOTCONNECTED; 8099815SRishi.Srivatsavai@Sun.COM break; 8109815SRishi.Srivatsavai@Sun.COM default: 8119815SRishi.Srivatsavai@Sun.COM break; 8129815SRishi.Srivatsavai@Sun.COM } 8139815SRishi.Srivatsavai@Sun.COM return (rc); 8149815SRishi.Srivatsavai@Sun.COM } 8159815SRishi.Srivatsavai@Sun.COM 8169815SRishi.Srivatsavai@Sun.COM static void 8179815SRishi.Srivatsavai@Sun.COM simnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 8189815SRishi.Srivatsavai@Sun.COM { 8199815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 8209815SRishi.Srivatsavai@Sun.COM struct iocblk *iocp; 8219815SRishi.Srivatsavai@Sun.COM mblk_t *mp1; 8229815SRishi.Srivatsavai@Sun.COM uint32_t cmd; 8239815SRishi.Srivatsavai@Sun.COM int rc; 8249815SRishi.Srivatsavai@Sun.COM 8259815SRishi.Srivatsavai@Sun.COM if (sdev->sd_type != DL_WIFI) { 8269815SRishi.Srivatsavai@Sun.COM miocnak(q, mp, 0, ENOTSUP); 8279815SRishi.Srivatsavai@Sun.COM return; 8289815SRishi.Srivatsavai@Sun.COM } 8299815SRishi.Srivatsavai@Sun.COM 8309815SRishi.Srivatsavai@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */ 8319815SRishi.Srivatsavai@Sun.COM iocp = (struct iocblk *)mp->b_rptr; 8329815SRishi.Srivatsavai@Sun.COM if (iocp->ioc_count == 0) { 8339815SRishi.Srivatsavai@Sun.COM miocnak(q, mp, 0, EINVAL); 8349815SRishi.Srivatsavai@Sun.COM return; 8359815SRishi.Srivatsavai@Sun.COM } 8369815SRishi.Srivatsavai@Sun.COM 8379815SRishi.Srivatsavai@Sun.COM /* We only claim support for WiFi operation commands */ 8389815SRishi.Srivatsavai@Sun.COM cmd = iocp->ioc_cmd; 8399815SRishi.Srivatsavai@Sun.COM switch (cmd) { 8409815SRishi.Srivatsavai@Sun.COM default: 8419815SRishi.Srivatsavai@Sun.COM miocnak(q, mp, 0, EINVAL); 8429815SRishi.Srivatsavai@Sun.COM return; 8439815SRishi.Srivatsavai@Sun.COM case WLAN_GET_PARAM: 8449815SRishi.Srivatsavai@Sun.COM case WLAN_SET_PARAM: 8459815SRishi.Srivatsavai@Sun.COM case WLAN_COMMAND: 8469815SRishi.Srivatsavai@Sun.COM break; 8479815SRishi.Srivatsavai@Sun.COM } 8489815SRishi.Srivatsavai@Sun.COM 8499815SRishi.Srivatsavai@Sun.COM mp1 = mp->b_cont; 8509815SRishi.Srivatsavai@Sun.COM freemsg(mp1->b_cont); 8519815SRishi.Srivatsavai@Sun.COM mp1->b_cont = NULL; 8529815SRishi.Srivatsavai@Sun.COM /* overwrite everything */ 8539815SRishi.Srivatsavai@Sun.COM mp1->b_wptr = mp1->b_rptr; 8549815SRishi.Srivatsavai@Sun.COM rc = simnet_wifi_ioctl(sdev, mp1); 8559815SRishi.Srivatsavai@Sun.COM miocack(q, mp, msgdsize(mp1), rc); 8569815SRishi.Srivatsavai@Sun.COM } 8579815SRishi.Srivatsavai@Sun.COM 8589815SRishi.Srivatsavai@Sun.COM static int 8599815SRishi.Srivatsavai@Sun.COM simnet_m_stat(void *arg, uint_t stat, uint64_t *val) 8609815SRishi.Srivatsavai@Sun.COM { 8619815SRishi.Srivatsavai@Sun.COM int rval = 0; 8629815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 8639815SRishi.Srivatsavai@Sun.COM 8649815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_mh != NULL); 8659815SRishi.Srivatsavai@Sun.COM 8669815SRishi.Srivatsavai@Sun.COM switch (stat) { 8679815SRishi.Srivatsavai@Sun.COM case MAC_STAT_IFSPEED: 8689815SRishi.Srivatsavai@Sun.COM *val = 100 * 1000000ull; /* 100 Mbps */ 8699815SRishi.Srivatsavai@Sun.COM break; 8709815SRishi.Srivatsavai@Sun.COM case MAC_STAT_LINK_STATE: 8719815SRishi.Srivatsavai@Sun.COM *val = LINK_DUPLEX_FULL; 8729815SRishi.Srivatsavai@Sun.COM break; 8739815SRishi.Srivatsavai@Sun.COM case MAC_STAT_LINK_UP: 8749815SRishi.Srivatsavai@Sun.COM if (sdev->sd_flags & SDF_STARTED) 8759815SRishi.Srivatsavai@Sun.COM *val = LINK_STATE_UP; 8769815SRishi.Srivatsavai@Sun.COM else 8779815SRishi.Srivatsavai@Sun.COM *val = LINK_STATE_DOWN; 8789815SRishi.Srivatsavai@Sun.COM break; 8799815SRishi.Srivatsavai@Sun.COM case MAC_STAT_PROMISC: 8809815SRishi.Srivatsavai@Sun.COM case MAC_STAT_MULTIRCV: 8819815SRishi.Srivatsavai@Sun.COM case MAC_STAT_MULTIXMT: 8829815SRishi.Srivatsavai@Sun.COM case MAC_STAT_BRDCSTRCV: 8839815SRishi.Srivatsavai@Sun.COM case MAC_STAT_BRDCSTXMT: 8849815SRishi.Srivatsavai@Sun.COM rval = ENOTSUP; 8859815SRishi.Srivatsavai@Sun.COM break; 8869815SRishi.Srivatsavai@Sun.COM case MAC_STAT_OPACKETS: 8879815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.xmit_count; 8889815SRishi.Srivatsavai@Sun.COM break; 8899815SRishi.Srivatsavai@Sun.COM case MAC_STAT_OBYTES: 8909815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.obytes; 8919815SRishi.Srivatsavai@Sun.COM break; 8929815SRishi.Srivatsavai@Sun.COM case MAC_STAT_IERRORS: 8939815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.recv_errors; 8949815SRishi.Srivatsavai@Sun.COM break; 8959815SRishi.Srivatsavai@Sun.COM case MAC_STAT_OERRORS: 8969815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.xmit_errors; 8979815SRishi.Srivatsavai@Sun.COM break; 8989815SRishi.Srivatsavai@Sun.COM case MAC_STAT_RBYTES: 8999815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.rbytes; 9009815SRishi.Srivatsavai@Sun.COM break; 9019815SRishi.Srivatsavai@Sun.COM case MAC_STAT_IPACKETS: 9029815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.recv_count; 9039815SRishi.Srivatsavai@Sun.COM break; 9049815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_FCS_ERRORS: 9059815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_WEP_ERRORS: 9069815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_TX_FRAGS: 9079815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_MCAST_TX: 9089815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_RTS_SUCCESS: 9099815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_RTS_FAILURE: 9109815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_ACK_FAILURE: 9119815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_RX_FRAGS: 9129815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_MCAST_RX: 9139815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_RX_DUPS: 9149815SRishi.Srivatsavai@Sun.COM rval = ENOTSUP; 9159815SRishi.Srivatsavai@Sun.COM break; 9169815SRishi.Srivatsavai@Sun.COM default: 9179815SRishi.Srivatsavai@Sun.COM rval = ENOTSUP; 9189815SRishi.Srivatsavai@Sun.COM break; 9199815SRishi.Srivatsavai@Sun.COM } 9209815SRishi.Srivatsavai@Sun.COM 9219815SRishi.Srivatsavai@Sun.COM return (rval); 9229815SRishi.Srivatsavai@Sun.COM } 9239815SRishi.Srivatsavai@Sun.COM 9249815SRishi.Srivatsavai@Sun.COM static int 9259815SRishi.Srivatsavai@Sun.COM simnet_m_start(void *arg) 9269815SRishi.Srivatsavai@Sun.COM { 9279815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 9289815SRishi.Srivatsavai@Sun.COM 9299815SRishi.Srivatsavai@Sun.COM sdev->sd_flags |= SDF_STARTED; 9309815SRishi.Srivatsavai@Sun.COM return (0); 9319815SRishi.Srivatsavai@Sun.COM } 9329815SRishi.Srivatsavai@Sun.COM 9339815SRishi.Srivatsavai@Sun.COM static void 9349815SRishi.Srivatsavai@Sun.COM simnet_m_stop(void *arg) 9359815SRishi.Srivatsavai@Sun.COM { 9369815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 9379815SRishi.Srivatsavai@Sun.COM 9389815SRishi.Srivatsavai@Sun.COM sdev->sd_flags &= ~SDF_STARTED; 9399815SRishi.Srivatsavai@Sun.COM } 9409815SRishi.Srivatsavai@Sun.COM 9419815SRishi.Srivatsavai@Sun.COM static int 9429815SRishi.Srivatsavai@Sun.COM simnet_m_promisc(void *arg, boolean_t on) 9439815SRishi.Srivatsavai@Sun.COM { 9449815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 9459815SRishi.Srivatsavai@Sun.COM 9469815SRishi.Srivatsavai@Sun.COM sdev->sd_promisc = on; 9479815SRishi.Srivatsavai@Sun.COM return (0); 9489815SRishi.Srivatsavai@Sun.COM } 9499815SRishi.Srivatsavai@Sun.COM 9509815SRishi.Srivatsavai@Sun.COM /* 9519815SRishi.Srivatsavai@Sun.COM * Returns matching multicast address enabled on the simnet instance. 9529815SRishi.Srivatsavai@Sun.COM * Assumes simnet instance mutex lock is held. 9539815SRishi.Srivatsavai@Sun.COM */ 9549815SRishi.Srivatsavai@Sun.COM static uint8_t * 9559815SRishi.Srivatsavai@Sun.COM mcastaddr_lookup(simnet_dev_t *sdev, const uint8_t *addrp) 9569815SRishi.Srivatsavai@Sun.COM { 9579815SRishi.Srivatsavai@Sun.COM int idx; 9589815SRishi.Srivatsavai@Sun.COM uint8_t *maddrptr; 9599815SRishi.Srivatsavai@Sun.COM 960*10416SRishi.Srivatsavai@Sun.COM ASSERT(MUTEX_HELD(&sdev->sd_instlock)); 9619815SRishi.Srivatsavai@Sun.COM maddrptr = sdev->sd_mcastaddrs; 9629815SRishi.Srivatsavai@Sun.COM for (idx = 0; idx < sdev->sd_mcastaddr_count; idx++) { 9639815SRishi.Srivatsavai@Sun.COM if (bcmp(maddrptr, addrp, ETHERADDRL) == 0) 9649815SRishi.Srivatsavai@Sun.COM return (maddrptr); 9659815SRishi.Srivatsavai@Sun.COM maddrptr += ETHERADDRL; 9669815SRishi.Srivatsavai@Sun.COM } 9679815SRishi.Srivatsavai@Sun.COM 9689815SRishi.Srivatsavai@Sun.COM return (NULL); 9699815SRishi.Srivatsavai@Sun.COM } 9709815SRishi.Srivatsavai@Sun.COM 9719815SRishi.Srivatsavai@Sun.COM /* Add or remove Multicast addresses on simnet instance */ 9729815SRishi.Srivatsavai@Sun.COM static int 9739815SRishi.Srivatsavai@Sun.COM simnet_m_multicst(void *arg, boolean_t add, const uint8_t *addrp) 9749815SRishi.Srivatsavai@Sun.COM { 9759815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 9769815SRishi.Srivatsavai@Sun.COM uint8_t *maddrptr; 9779815SRishi.Srivatsavai@Sun.COM uint8_t *newbuf; 9789815SRishi.Srivatsavai@Sun.COM size_t prevsize; 9799815SRishi.Srivatsavai@Sun.COM size_t newsize; 9809815SRishi.Srivatsavai@Sun.COM ptrdiff_t len; 9819815SRishi.Srivatsavai@Sun.COM ptrdiff_t len2; 9829815SRishi.Srivatsavai@Sun.COM 9839815SRishi.Srivatsavai@Sun.COM alloc_retry: 9849815SRishi.Srivatsavai@Sun.COM prevsize = sdev->sd_mcastaddr_count * ETHERADDRL; 9859815SRishi.Srivatsavai@Sun.COM newsize = prevsize + (add ? ETHERADDRL:-ETHERADDRL); 9869815SRishi.Srivatsavai@Sun.COM newbuf = kmem_alloc(newsize, KM_SLEEP); 9879815SRishi.Srivatsavai@Sun.COM 9889815SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock); 9899815SRishi.Srivatsavai@Sun.COM if (prevsize != (sdev->sd_mcastaddr_count * ETHERADDRL)) { 9909815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 9919815SRishi.Srivatsavai@Sun.COM kmem_free(newbuf, newsize); 9929815SRishi.Srivatsavai@Sun.COM goto alloc_retry; 9939815SRishi.Srivatsavai@Sun.COM } 9949815SRishi.Srivatsavai@Sun.COM 9959815SRishi.Srivatsavai@Sun.COM maddrptr = mcastaddr_lookup(sdev, addrp); 9969815SRishi.Srivatsavai@Sun.COM if (!add && maddrptr != NULL) { 9979815SRishi.Srivatsavai@Sun.COM /* Removing a Multicast address */ 9989815SRishi.Srivatsavai@Sun.COM if (newbuf != NULL) { 9999815SRishi.Srivatsavai@Sun.COM /* LINTED: E_PTRDIFF_OVERFLOW */ 10009815SRishi.Srivatsavai@Sun.COM len = maddrptr - sdev->sd_mcastaddrs; 10019815SRishi.Srivatsavai@Sun.COM (void) memcpy(newbuf, sdev->sd_mcastaddrs, len); 10029815SRishi.Srivatsavai@Sun.COM len2 = prevsize - len - ETHERADDRL; 10039815SRishi.Srivatsavai@Sun.COM (void) memcpy(newbuf + len, 10049815SRishi.Srivatsavai@Sun.COM maddrptr + ETHERADDRL, len2); 10059815SRishi.Srivatsavai@Sun.COM } 10069815SRishi.Srivatsavai@Sun.COM sdev->sd_mcastaddr_count--; 10079815SRishi.Srivatsavai@Sun.COM } else if (add && maddrptr == NULL) { 10089815SRishi.Srivatsavai@Sun.COM /* Adding a new Multicast address */ 10099815SRishi.Srivatsavai@Sun.COM (void) memcpy(newbuf, sdev->sd_mcastaddrs, prevsize); 10109815SRishi.Srivatsavai@Sun.COM (void) memcpy(newbuf + prevsize, addrp, ETHERADDRL); 10119815SRishi.Srivatsavai@Sun.COM sdev->sd_mcastaddr_count++; 10129815SRishi.Srivatsavai@Sun.COM } else { 10139815SRishi.Srivatsavai@Sun.COM /* Error: removing a non-existing Multicast address */ 10149815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 10159815SRishi.Srivatsavai@Sun.COM kmem_free(newbuf, newsize); 10169815SRishi.Srivatsavai@Sun.COM cmn_err(CE_WARN, "simnet: MAC call to remove a " 10179815SRishi.Srivatsavai@Sun.COM "Multicast address failed"); 10189815SRishi.Srivatsavai@Sun.COM return (EINVAL); 10199815SRishi.Srivatsavai@Sun.COM } 10209815SRishi.Srivatsavai@Sun.COM 10219815SRishi.Srivatsavai@Sun.COM kmem_free(sdev->sd_mcastaddrs, prevsize); 10229815SRishi.Srivatsavai@Sun.COM sdev->sd_mcastaddrs = newbuf; 10239815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock); 10249815SRishi.Srivatsavai@Sun.COM return (0); 10259815SRishi.Srivatsavai@Sun.COM } 10269815SRishi.Srivatsavai@Sun.COM 10279815SRishi.Srivatsavai@Sun.COM static int 10289815SRishi.Srivatsavai@Sun.COM simnet_m_unicst(void *arg, const uint8_t *macaddr) 10299815SRishi.Srivatsavai@Sun.COM { 10309815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 10319815SRishi.Srivatsavai@Sun.COM 10329815SRishi.Srivatsavai@Sun.COM (void) memcpy(sdev->sd_mac_addr, macaddr, ETHERADDRL); 10339815SRishi.Srivatsavai@Sun.COM return (0); 10349815SRishi.Srivatsavai@Sun.COM } 10359815SRishi.Srivatsavai@Sun.COM 10369815SRishi.Srivatsavai@Sun.COM /* Parse WiFi scan list entry arguments and return the arg count */ 10379815SRishi.Srivatsavai@Sun.COM static int 10389815SRishi.Srivatsavai@Sun.COM parse_esslist_args(const void *pr_val, uint_t pr_valsize, 10399815SRishi.Srivatsavai@Sun.COM char args[][MAX_ESSLIST_ARGLEN]) 10409815SRishi.Srivatsavai@Sun.COM { 10419815SRishi.Srivatsavai@Sun.COM char *sep; 10429815SRishi.Srivatsavai@Sun.COM ptrdiff_t len = pr_valsize; 10439815SRishi.Srivatsavai@Sun.COM const char *piece = pr_val; 10449815SRishi.Srivatsavai@Sun.COM const char *end = (const char *)pr_val + pr_valsize - 1; 10459815SRishi.Srivatsavai@Sun.COM int arg = 0; 10469815SRishi.Srivatsavai@Sun.COM 10479815SRishi.Srivatsavai@Sun.COM while (piece < end && (arg < MAX_ESSLIST_ARGS)) { 10489815SRishi.Srivatsavai@Sun.COM sep = strchr(piece, ','); 10499815SRishi.Srivatsavai@Sun.COM if (sep == NULL) 10509815SRishi.Srivatsavai@Sun.COM sep = (char *)end; 10519815SRishi.Srivatsavai@Sun.COM /* LINTED E_PTRDIFF_OVERFLOW */ 10529815SRishi.Srivatsavai@Sun.COM len = sep - piece; 10539815SRishi.Srivatsavai@Sun.COM /* If first arg is zero then return none to delete all */ 10549815SRishi.Srivatsavai@Sun.COM if (arg == 0 && strnlen(piece, len) == 1 && piece[0] == '0') 10559815SRishi.Srivatsavai@Sun.COM return (0); 10569815SRishi.Srivatsavai@Sun.COM if (len > MAX_ESSLIST_ARGLEN) 10579815SRishi.Srivatsavai@Sun.COM len = MAX_ESSLIST_ARGLEN - 1; 10589815SRishi.Srivatsavai@Sun.COM (void) memcpy(&args[arg][0], piece, len); 10599815SRishi.Srivatsavai@Sun.COM args[arg][len] = '\0'; 10609815SRishi.Srivatsavai@Sun.COM piece = sep + 1; 10619815SRishi.Srivatsavai@Sun.COM arg++; 10629815SRishi.Srivatsavai@Sun.COM } 10639815SRishi.Srivatsavai@Sun.COM 10649815SRishi.Srivatsavai@Sun.COM return (arg); 10659815SRishi.Srivatsavai@Sun.COM } 10669815SRishi.Srivatsavai@Sun.COM 10679815SRishi.Srivatsavai@Sun.COM /* Set WiFi scan list entry from private property _wl_esslist */ 10689815SRishi.Srivatsavai@Sun.COM static int 10699815SRishi.Srivatsavai@Sun.COM set_wl_esslist_priv_prop(simnet_wifidev_t *wdev, uint_t pr_valsize, 10709815SRishi.Srivatsavai@Sun.COM const void *pr_val) 10719815SRishi.Srivatsavai@Sun.COM { 10729815SRishi.Srivatsavai@Sun.COM char essargs[MAX_ESSLIST_ARGS][MAX_ESSLIST_ARGLEN]; 10739815SRishi.Srivatsavai@Sun.COM wl_ess_conf_t *wls; 10749815SRishi.Srivatsavai@Sun.COM long result; 10759815SRishi.Srivatsavai@Sun.COM int i; 10769815SRishi.Srivatsavai@Sun.COM 10779815SRishi.Srivatsavai@Sun.COM bzero(essargs, sizeof (essargs)); 10789815SRishi.Srivatsavai@Sun.COM if (parse_esslist_args(pr_val, pr_valsize, essargs) == 0) { 10799815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) { 10809815SRishi.Srivatsavai@Sun.COM kmem_free(wdev->swd_esslist[i], sizeof (wl_ess_conf_t)); 10819815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist[i] = NULL; 10829815SRishi.Srivatsavai@Sun.COM } 10839815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist_num = 0; 10849815SRishi.Srivatsavai@Sun.COM return (0); 10859815SRishi.Srivatsavai@Sun.COM } 10869815SRishi.Srivatsavai@Sun.COM 10879815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) { 10889815SRishi.Srivatsavai@Sun.COM wls = wdev->swd_esslist[i]; 10899815SRishi.Srivatsavai@Sun.COM if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid, 10909815SRishi.Srivatsavai@Sun.COM essargs[0]) == 0) 10919815SRishi.Srivatsavai@Sun.COM return (EEXIST); 10929815SRishi.Srivatsavai@Sun.COM } 10939815SRishi.Srivatsavai@Sun.COM 10949815SRishi.Srivatsavai@Sun.COM if (wdev->swd_esslist_num >= MAX_SIMNET_ESSCONF) 10959815SRishi.Srivatsavai@Sun.COM return (EINVAL); 10969815SRishi.Srivatsavai@Sun.COM 10979815SRishi.Srivatsavai@Sun.COM wls = kmem_zalloc(sizeof (wl_ess_conf_t), KM_SLEEP); 10989815SRishi.Srivatsavai@Sun.COM (void) strlcpy(wls->wl_ess_conf_essid.wl_essid_essid, 10999815SRishi.Srivatsavai@Sun.COM essargs[0], sizeof (wls->wl_ess_conf_essid.wl_essid_essid)); 11009815SRishi.Srivatsavai@Sun.COM wls->wl_ess_conf_essid.wl_essid_length = 11019815SRishi.Srivatsavai@Sun.COM strlen(wls->wl_ess_conf_essid.wl_essid_essid); 11029815SRishi.Srivatsavai@Sun.COM (void) random_get_pseudo_bytes((uint8_t *) 11039815SRishi.Srivatsavai@Sun.COM &wls->wl_ess_conf_bssid, sizeof (wl_bssid_t)); 11049815SRishi.Srivatsavai@Sun.COM (void) ddi_strtol(essargs[1], (char **)NULL, 0, &result); 11059815SRishi.Srivatsavai@Sun.COM wls->wl_ess_conf_sl = (wl_rssi_t) 11069815SRishi.Srivatsavai@Sun.COM ((result > MAX_RSSI || result < 0) ? 0:result); 11079815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist[wdev->swd_esslist_num] = wls; 11089815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist_num++; 11099815SRishi.Srivatsavai@Sun.COM 11109815SRishi.Srivatsavai@Sun.COM return (0); 11119815SRishi.Srivatsavai@Sun.COM } 11129815SRishi.Srivatsavai@Sun.COM 11139815SRishi.Srivatsavai@Sun.COM static int 11149815SRishi.Srivatsavai@Sun.COM simnet_set_priv_prop(simnet_dev_t *sdev, const char *pr_name, 11159815SRishi.Srivatsavai@Sun.COM uint_t pr_valsize, const void *pr_val) 11169815SRishi.Srivatsavai@Sun.COM { 11179815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev; 11189815SRishi.Srivatsavai@Sun.COM long result; 11199815SRishi.Srivatsavai@Sun.COM 11209815SRishi.Srivatsavai@Sun.COM if (strcmp(pr_name, "_wl_esslist") == 0) { 11219815SRishi.Srivatsavai@Sun.COM if (pr_val == NULL) 11229815SRishi.Srivatsavai@Sun.COM return (EINVAL); 11239815SRishi.Srivatsavai@Sun.COM return (set_wl_esslist_priv_prop(wdev, pr_valsize, pr_val)); 11249815SRishi.Srivatsavai@Sun.COM } else if (strcmp(pr_name, "_wl_connected") == 0) { 11259815SRishi.Srivatsavai@Sun.COM if (pr_val == NULL) 11269815SRishi.Srivatsavai@Sun.COM return (EINVAL); 11279815SRishi.Srivatsavai@Sun.COM (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 11289815SRishi.Srivatsavai@Sun.COM wdev->swd_linkstatus = ((result == 1) ? 11299815SRishi.Srivatsavai@Sun.COM WL_CONNECTED:WL_NOTCONNECTED); 11309815SRishi.Srivatsavai@Sun.COM return (0); 11319815SRishi.Srivatsavai@Sun.COM } 11329815SRishi.Srivatsavai@Sun.COM 11339815SRishi.Srivatsavai@Sun.COM return (EINVAL); 11349815SRishi.Srivatsavai@Sun.COM } 11359815SRishi.Srivatsavai@Sun.COM 11369815SRishi.Srivatsavai@Sun.COM static int 11379815SRishi.Srivatsavai@Sun.COM simnet_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 11389815SRishi.Srivatsavai@Sun.COM uint_t wldp_length, const void *wldp_buf) 11399815SRishi.Srivatsavai@Sun.COM { 11409815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 11419815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev; 11429815SRishi.Srivatsavai@Sun.COM int err = 0; 11439815SRishi.Srivatsavai@Sun.COM uint32_t mtu; 11449815SRishi.Srivatsavai@Sun.COM 11459815SRishi.Srivatsavai@Sun.COM switch (wldp_pr_num) { 11469815SRishi.Srivatsavai@Sun.COM case MAC_PROP_MTU: 11479815SRishi.Srivatsavai@Sun.COM (void) memcpy(&mtu, wldp_buf, sizeof (mtu)); 11489815SRishi.Srivatsavai@Sun.COM if (mtu > ETHERMIN && mtu < SIMNET_MAX_MTU) 11499815SRishi.Srivatsavai@Sun.COM return (mac_maxsdu_update(sdev->sd_mh, mtu)); 11509815SRishi.Srivatsavai@Sun.COM else 11519815SRishi.Srivatsavai@Sun.COM return (EINVAL); 11529815SRishi.Srivatsavai@Sun.COM default: 11539815SRishi.Srivatsavai@Sun.COM break; 11549815SRishi.Srivatsavai@Sun.COM } 11559815SRishi.Srivatsavai@Sun.COM 11569815SRishi.Srivatsavai@Sun.COM if (sdev->sd_type == DL_ETHER) 11579815SRishi.Srivatsavai@Sun.COM return (ENOTSUP); 11589815SRishi.Srivatsavai@Sun.COM 11599815SRishi.Srivatsavai@Sun.COM /* mac_prop_id */ 11609815SRishi.Srivatsavai@Sun.COM switch (wldp_pr_num) { 11619815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ESSID: { 11629815SRishi.Srivatsavai@Sun.COM int i; 11639815SRishi.Srivatsavai@Sun.COM wl_ess_conf_t *wls; 11649815SRishi.Srivatsavai@Sun.COM 11659815SRishi.Srivatsavai@Sun.COM (void) memcpy(&wdev->swd_essid, wldp_buf, 11669815SRishi.Srivatsavai@Sun.COM sizeof (wl_essid_t)); 11679815SRishi.Srivatsavai@Sun.COM wdev->swd_linkstatus = WL_CONNECTED; 11689815SRishi.Srivatsavai@Sun.COM 11699815SRishi.Srivatsavai@Sun.COM /* Lookup the signal strength of the connected ESSID */ 11709815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) { 11719815SRishi.Srivatsavai@Sun.COM wls = wdev->swd_esslist[i]; 11729815SRishi.Srivatsavai@Sun.COM if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid, 11739815SRishi.Srivatsavai@Sun.COM wdev->swd_essid.wl_essid_essid) == 0) { 11749815SRishi.Srivatsavai@Sun.COM wdev->swd_rssi = wls->wl_ess_conf_sl; 11759815SRishi.Srivatsavai@Sun.COM break; 11769815SRishi.Srivatsavai@Sun.COM } 11779815SRishi.Srivatsavai@Sun.COM } 11789815SRishi.Srivatsavai@Sun.COM break; 11799815SRishi.Srivatsavai@Sun.COM } 11809815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_BSSID: { 11819815SRishi.Srivatsavai@Sun.COM (void) memcpy(&wdev->swd_bssid, wldp_buf, 11829815SRishi.Srivatsavai@Sun.COM sizeof (wl_bssid_t)); 11839815SRishi.Srivatsavai@Sun.COM break; 11849815SRishi.Srivatsavai@Sun.COM } 11859815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_PHY_CONFIG: 11869815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_KEY_TAB: 11879815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_AUTH_MODE: 11889815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ENCRYPTION: 11899815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_BSSTYPE: 11909815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_DESIRED_RATES: 11919815SRishi.Srivatsavai@Sun.COM break; 11929815SRishi.Srivatsavai@Sun.COM case MAC_PROP_PRIVATE: 11939815SRishi.Srivatsavai@Sun.COM err = simnet_set_priv_prop(sdev, pr_name, 11949815SRishi.Srivatsavai@Sun.COM wldp_length, wldp_buf); 11959815SRishi.Srivatsavai@Sun.COM break; 11969815SRishi.Srivatsavai@Sun.COM default: 11979815SRishi.Srivatsavai@Sun.COM break; 11989815SRishi.Srivatsavai@Sun.COM } 11999815SRishi.Srivatsavai@Sun.COM 12009815SRishi.Srivatsavai@Sun.COM return (err); 12019815SRishi.Srivatsavai@Sun.COM } 12029815SRishi.Srivatsavai@Sun.COM 12039815SRishi.Srivatsavai@Sun.COM static int 12049815SRishi.Srivatsavai@Sun.COM simnet_get_priv_prop(simnet_dev_t *sdev, const char *pr_name, uint_t pr_flags, 12059815SRishi.Srivatsavai@Sun.COM uint_t pr_valsize, void *pr_val) 12069815SRishi.Srivatsavai@Sun.COM { 12079815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev; 12089815SRishi.Srivatsavai@Sun.COM boolean_t is_default = ((pr_flags & MAC_PROP_DEFAULT) != 0); 12099815SRishi.Srivatsavai@Sun.COM int err = 0; 12109815SRishi.Srivatsavai@Sun.COM int value; 12119815SRishi.Srivatsavai@Sun.COM 12129815SRishi.Srivatsavai@Sun.COM if (strcmp(pr_name, "_wl_esslist") == 0) { 12139815SRishi.Srivatsavai@Sun.COM /* Returns num of _wl_ess_conf_t that have been set */ 12149815SRishi.Srivatsavai@Sun.COM value = (is_default ? 0:wdev->swd_esslist_num); 12159815SRishi.Srivatsavai@Sun.COM } else if (strcmp(pr_name, "_wl_connected") == 0) { 12169815SRishi.Srivatsavai@Sun.COM value = ((wdev->swd_linkstatus == WL_CONNECTED) ? 1:0); 12179815SRishi.Srivatsavai@Sun.COM } else { 12189815SRishi.Srivatsavai@Sun.COM err = ENOTSUP; 12199815SRishi.Srivatsavai@Sun.COM } 12209815SRishi.Srivatsavai@Sun.COM 12219815SRishi.Srivatsavai@Sun.COM if (err == 0) 12229815SRishi.Srivatsavai@Sun.COM (void) snprintf(pr_val, pr_valsize, "%d", value); 12239815SRishi.Srivatsavai@Sun.COM return (err); 12249815SRishi.Srivatsavai@Sun.COM } 12259815SRishi.Srivatsavai@Sun.COM 12269815SRishi.Srivatsavai@Sun.COM static int 12279815SRishi.Srivatsavai@Sun.COM simnet_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 12289815SRishi.Srivatsavai@Sun.COM uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm) 12299815SRishi.Srivatsavai@Sun.COM { 12309815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg; 12319815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev; 12329815SRishi.Srivatsavai@Sun.COM int err = 0; 12339815SRishi.Srivatsavai@Sun.COM int i; 12349815SRishi.Srivatsavai@Sun.COM 12359815SRishi.Srivatsavai@Sun.COM if (sdev->sd_type == DL_ETHER) 12369815SRishi.Srivatsavai@Sun.COM return (ENOTSUP); 12379815SRishi.Srivatsavai@Sun.COM 12389815SRishi.Srivatsavai@Sun.COM /* mac_prop_id */ 12399815SRishi.Srivatsavai@Sun.COM switch (wldp_pr_num) { 12409815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ESSID: 12419815SRishi.Srivatsavai@Sun.COM (void) memcpy(wldp_buf, &wdev->swd_essid, 12429815SRishi.Srivatsavai@Sun.COM sizeof (wl_essid_t)); 12439815SRishi.Srivatsavai@Sun.COM break; 12449815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_BSSID: 12459815SRishi.Srivatsavai@Sun.COM (void) memcpy(wldp_buf, &wdev->swd_bssid, 12469815SRishi.Srivatsavai@Sun.COM sizeof (wl_bssid_t)); 12479815SRishi.Srivatsavai@Sun.COM break; 12489815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_PHY_CONFIG: 12499815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_AUTH_MODE: 12509815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ENCRYPTION: 12519815SRishi.Srivatsavai@Sun.COM break; 12529815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_BSSTYPE: 12539815SRishi.Srivatsavai@Sun.COM *perm = MAC_PROP_PERM_READ; 12549815SRishi.Srivatsavai@Sun.COM break; 12559815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_LINKSTATUS: 12569815SRishi.Srivatsavai@Sun.COM (void) memcpy(wldp_buf, &wdev->swd_linkstatus, 12579815SRishi.Srivatsavai@Sun.COM sizeof (wdev->swd_linkstatus)); 12589815SRishi.Srivatsavai@Sun.COM break; 12599815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ESS_LIST: { 12609815SRishi.Srivatsavai@Sun.COM wl_ess_conf_t *w_ess_conf; 12619815SRishi.Srivatsavai@Sun.COM 12629815SRishi.Srivatsavai@Sun.COM *perm = MAC_PROP_PERM_READ; 12639815SRishi.Srivatsavai@Sun.COM ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num = 12649815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist_num; 12659815SRishi.Srivatsavai@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */ 12669815SRishi.Srivatsavai@Sun.COM w_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf + 12679815SRishi.Srivatsavai@Sun.COM offsetof(wl_ess_list_t, wl_ess_list_ess)); 12689815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) { 12699815SRishi.Srivatsavai@Sun.COM (void) memcpy(w_ess_conf, wdev->swd_esslist[i], 12709815SRishi.Srivatsavai@Sun.COM sizeof (wl_ess_conf_t)); 12719815SRishi.Srivatsavai@Sun.COM w_ess_conf++; 12729815SRishi.Srivatsavai@Sun.COM } 12739815SRishi.Srivatsavai@Sun.COM break; 12749815SRishi.Srivatsavai@Sun.COM } 12759815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES: 12769815SRishi.Srivatsavai@Sun.COM *perm = MAC_PROP_PERM_READ; 12779815SRishi.Srivatsavai@Sun.COM break; 12789815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_RSSI: 12799815SRishi.Srivatsavai@Sun.COM *perm = MAC_PROP_PERM_READ; 12809815SRishi.Srivatsavai@Sun.COM *(wl_rssi_t *)wldp_buf = wdev->swd_rssi; 12819815SRishi.Srivatsavai@Sun.COM break; 12829815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_RADIO: 12839815SRishi.Srivatsavai@Sun.COM *(wl_radio_t *)wldp_buf = B_TRUE; 12849815SRishi.Srivatsavai@Sun.COM break; 12859815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_POWER_MODE: 12869815SRishi.Srivatsavai@Sun.COM break; 12879815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_DESIRED_RATES: 12889815SRishi.Srivatsavai@Sun.COM break; 12899815SRishi.Srivatsavai@Sun.COM case MAC_PROP_PRIVATE: 12909815SRishi.Srivatsavai@Sun.COM err = simnet_get_priv_prop(sdev, pr_name, pr_flags, 12919815SRishi.Srivatsavai@Sun.COM wldp_length, wldp_buf); 12929815SRishi.Srivatsavai@Sun.COM break; 12939815SRishi.Srivatsavai@Sun.COM default: 12949815SRishi.Srivatsavai@Sun.COM err = ENOTSUP; 12959815SRishi.Srivatsavai@Sun.COM break; 12969815SRishi.Srivatsavai@Sun.COM } 12979815SRishi.Srivatsavai@Sun.COM 12989815SRishi.Srivatsavai@Sun.COM return (err); 12999815SRishi.Srivatsavai@Sun.COM } 1300