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 /*
22*11878SVenu.Iyer@Sun.COM * Copyright 2010 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>
5710416SRishi.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;
6410416SRishi.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),
7710616SSebastien.Roy@Sun.COM simnet_ioc_create, secpolicy_dl_config},
789815SRishi.Srivatsavai@Sun.COM {SIMNET_IOC_DELETE, DLDCOPYIN, sizeof (simnet_ioc_delete_t),
7910616SSebastien.Roy@Sun.COM simnet_ioc_delete, secpolicy_dl_config},
809815SRishi.Srivatsavai@Sun.COM {SIMNET_IOC_INFO, DLDCOPYINOUT, sizeof (simnet_ioc_info_t),
8110616SSebastien.Roy@Sun.COM simnet_ioc_info, NULL},
829815SRishi.Srivatsavai@Sun.COM {SIMNET_IOC_MODIFY, DLDCOPYIN, sizeof (simnet_ioc_modify_t),
8310616SSebastien.Roy@Sun.COM simnet_ioc_modify, secpolicy_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,
112*11878SVenu.Iyer@Sun.COM uint_t, void *);
113*11878SVenu.Iyer@Sun.COM static void simnet_m_propinfo(void *, const char *, mac_prop_id_t,
114*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t);
1159815SRishi.Srivatsavai@Sun.COM
1169815SRishi.Srivatsavai@Sun.COM static mac_callbacks_t simnet_m_callbacks = {
117*11878SVenu.Iyer@Sun.COM (MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO),
1189815SRishi.Srivatsavai@Sun.COM simnet_m_stat,
1199815SRishi.Srivatsavai@Sun.COM simnet_m_start,
1209815SRishi.Srivatsavai@Sun.COM simnet_m_stop,
1219815SRishi.Srivatsavai@Sun.COM simnet_m_promisc,
1229815SRishi.Srivatsavai@Sun.COM simnet_m_multicst,
1239815SRishi.Srivatsavai@Sun.COM simnet_m_unicst,
1249815SRishi.Srivatsavai@Sun.COM simnet_m_tx,
125*11878SVenu.Iyer@Sun.COM NULL,
1269815SRishi.Srivatsavai@Sun.COM simnet_m_ioctl,
1279815SRishi.Srivatsavai@Sun.COM NULL,
1289815SRishi.Srivatsavai@Sun.COM NULL,
1299815SRishi.Srivatsavai@Sun.COM NULL,
1309815SRishi.Srivatsavai@Sun.COM simnet_m_setprop,
131*11878SVenu.Iyer@Sun.COM simnet_m_getprop,
132*11878SVenu.Iyer@Sun.COM simnet_m_propinfo
1339815SRishi.Srivatsavai@Sun.COM };
1349815SRishi.Srivatsavai@Sun.COM
1359815SRishi.Srivatsavai@Sun.COM /*
1369815SRishi.Srivatsavai@Sun.COM * simnet_dev_lock protects the simnet device list.
1379815SRishi.Srivatsavai@Sun.COM * sd_instlock in each simnet_dev_t protects access to
1389815SRishi.Srivatsavai@Sun.COM * a single simnet_dev_t.
1399815SRishi.Srivatsavai@Sun.COM */
1409815SRishi.Srivatsavai@Sun.COM static krwlock_t simnet_dev_lock;
1419815SRishi.Srivatsavai@Sun.COM static list_t simnet_dev_list;
1429815SRishi.Srivatsavai@Sun.COM static int simnet_count; /* Num of simnet instances */
1439815SRishi.Srivatsavai@Sun.COM
1449815SRishi.Srivatsavai@Sun.COM int
_init(void)1459815SRishi.Srivatsavai@Sun.COM _init(void)
1469815SRishi.Srivatsavai@Sun.COM {
1479815SRishi.Srivatsavai@Sun.COM int status;
1489815SRishi.Srivatsavai@Sun.COM
1499815SRishi.Srivatsavai@Sun.COM mac_init_ops(&simnet_dev_ops, "simnet");
1509815SRishi.Srivatsavai@Sun.COM status = mod_install(&modlinkage);
1519815SRishi.Srivatsavai@Sun.COM if (status != DDI_SUCCESS)
1529815SRishi.Srivatsavai@Sun.COM mac_fini_ops(&simnet_dev_ops);
1539815SRishi.Srivatsavai@Sun.COM
1549815SRishi.Srivatsavai@Sun.COM return (status);
1559815SRishi.Srivatsavai@Sun.COM }
1569815SRishi.Srivatsavai@Sun.COM
1579815SRishi.Srivatsavai@Sun.COM int
_fini(void)1589815SRishi.Srivatsavai@Sun.COM _fini(void)
1599815SRishi.Srivatsavai@Sun.COM {
1609815SRishi.Srivatsavai@Sun.COM int status;
1619815SRishi.Srivatsavai@Sun.COM
1629815SRishi.Srivatsavai@Sun.COM status = mod_remove(&modlinkage);
1639815SRishi.Srivatsavai@Sun.COM if (status == DDI_SUCCESS)
1649815SRishi.Srivatsavai@Sun.COM mac_fini_ops(&simnet_dev_ops);
1659815SRishi.Srivatsavai@Sun.COM
1669815SRishi.Srivatsavai@Sun.COM return (status);
1679815SRishi.Srivatsavai@Sun.COM }
1689815SRishi.Srivatsavai@Sun.COM
1699815SRishi.Srivatsavai@Sun.COM int
_info(struct modinfo * modinfop)1709815SRishi.Srivatsavai@Sun.COM _info(struct modinfo *modinfop)
1719815SRishi.Srivatsavai@Sun.COM {
1729815SRishi.Srivatsavai@Sun.COM return (mod_info(&modlinkage, modinfop));
1739815SRishi.Srivatsavai@Sun.COM }
1749815SRishi.Srivatsavai@Sun.COM
17510416SRishi.Srivatsavai@Sun.COM static boolean_t
simnet_init(void)1769815SRishi.Srivatsavai@Sun.COM simnet_init(void)
1779815SRishi.Srivatsavai@Sun.COM {
17810416SRishi.Srivatsavai@Sun.COM if ((simnet_rxq = ddi_taskq_create(simnet_dip, "simnet", 1,
17910416SRishi.Srivatsavai@Sun.COM TASKQ_DEFAULTPRI, 0)) == NULL)
18010416SRishi.Srivatsavai@Sun.COM return (B_FALSE);
1819815SRishi.Srivatsavai@Sun.COM rw_init(&simnet_dev_lock, NULL, RW_DEFAULT, NULL);
1829815SRishi.Srivatsavai@Sun.COM list_create(&simnet_dev_list, sizeof (simnet_dev_t),
1839815SRishi.Srivatsavai@Sun.COM offsetof(simnet_dev_t, sd_listnode));
18410416SRishi.Srivatsavai@Sun.COM return (B_TRUE);
1859815SRishi.Srivatsavai@Sun.COM }
1869815SRishi.Srivatsavai@Sun.COM
1879815SRishi.Srivatsavai@Sun.COM static void
simnet_fini(void)1889815SRishi.Srivatsavai@Sun.COM simnet_fini(void)
1899815SRishi.Srivatsavai@Sun.COM {
1909815SRishi.Srivatsavai@Sun.COM ASSERT(simnet_count == 0);
1919815SRishi.Srivatsavai@Sun.COM rw_destroy(&simnet_dev_lock);
1929815SRishi.Srivatsavai@Sun.COM list_destroy(&simnet_dev_list);
19310416SRishi.Srivatsavai@Sun.COM ddi_taskq_destroy(simnet_rxq);
1949815SRishi.Srivatsavai@Sun.COM }
1959815SRishi.Srivatsavai@Sun.COM
1969815SRishi.Srivatsavai@Sun.COM /*ARGSUSED*/
1979815SRishi.Srivatsavai@Sun.COM static int
simnet_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)1989815SRishi.Srivatsavai@Sun.COM simnet_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1999815SRishi.Srivatsavai@Sun.COM void **result)
2009815SRishi.Srivatsavai@Sun.COM {
2019815SRishi.Srivatsavai@Sun.COM switch (infocmd) {
2029815SRishi.Srivatsavai@Sun.COM case DDI_INFO_DEVT2DEVINFO:
2039815SRishi.Srivatsavai@Sun.COM *result = simnet_dip;
2049815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS);
2059815SRishi.Srivatsavai@Sun.COM case DDI_INFO_DEVT2INSTANCE:
2069815SRishi.Srivatsavai@Sun.COM *result = NULL;
2079815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS);
2089815SRishi.Srivatsavai@Sun.COM }
2099815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE);
2109815SRishi.Srivatsavai@Sun.COM }
2119815SRishi.Srivatsavai@Sun.COM
2129815SRishi.Srivatsavai@Sun.COM static int
simnet_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2139815SRishi.Srivatsavai@Sun.COM simnet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2149815SRishi.Srivatsavai@Sun.COM {
2159815SRishi.Srivatsavai@Sun.COM switch (cmd) {
2169815SRishi.Srivatsavai@Sun.COM case DDI_ATTACH:
2179815SRishi.Srivatsavai@Sun.COM if (ddi_get_instance(dip) != 0) {
2189815SRishi.Srivatsavai@Sun.COM /* we only allow instance 0 to attach */
2199815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE);
2209815SRishi.Srivatsavai@Sun.COM }
22110416SRishi.Srivatsavai@Sun.COM
2229815SRishi.Srivatsavai@Sun.COM if (dld_ioc_register(SIMNET_IOC, simnet_ioc_list,
2239815SRishi.Srivatsavai@Sun.COM DLDIOCCNT(simnet_ioc_list)) != 0)
2249815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE);
2259815SRishi.Srivatsavai@Sun.COM
2269815SRishi.Srivatsavai@Sun.COM simnet_dip = dip;
22710416SRishi.Srivatsavai@Sun.COM if (!simnet_init())
22810416SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE);
2299815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS);
2309815SRishi.Srivatsavai@Sun.COM
2319815SRishi.Srivatsavai@Sun.COM case DDI_RESUME:
2329815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS);
2339815SRishi.Srivatsavai@Sun.COM
2349815SRishi.Srivatsavai@Sun.COM default:
2359815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE);
2369815SRishi.Srivatsavai@Sun.COM }
2379815SRishi.Srivatsavai@Sun.COM }
2389815SRishi.Srivatsavai@Sun.COM
2399815SRishi.Srivatsavai@Sun.COM /*ARGSUSED*/
2409815SRishi.Srivatsavai@Sun.COM static int
simnet_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2419815SRishi.Srivatsavai@Sun.COM simnet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2429815SRishi.Srivatsavai@Sun.COM {
2439815SRishi.Srivatsavai@Sun.COM switch (cmd) {
2449815SRishi.Srivatsavai@Sun.COM case DDI_DETACH:
2459815SRishi.Srivatsavai@Sun.COM /*
2469815SRishi.Srivatsavai@Sun.COM * Allow the simnet instance to be detached only if there
2479815SRishi.Srivatsavai@Sun.COM * are no simnets configured.
2489815SRishi.Srivatsavai@Sun.COM */
2499815SRishi.Srivatsavai@Sun.COM if (simnet_count > 0)
2509815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE);
2519815SRishi.Srivatsavai@Sun.COM
25210416SRishi.Srivatsavai@Sun.COM dld_ioc_unregister(SIMNET_IOC);
2539815SRishi.Srivatsavai@Sun.COM simnet_fini();
25410416SRishi.Srivatsavai@Sun.COM simnet_dip = NULL;
2559815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS);
2569815SRishi.Srivatsavai@Sun.COM
2579815SRishi.Srivatsavai@Sun.COM case DDI_SUSPEND:
2589815SRishi.Srivatsavai@Sun.COM return (DDI_SUCCESS);
2599815SRishi.Srivatsavai@Sun.COM
2609815SRishi.Srivatsavai@Sun.COM default:
2619815SRishi.Srivatsavai@Sun.COM return (DDI_FAILURE);
2629815SRishi.Srivatsavai@Sun.COM }
2639815SRishi.Srivatsavai@Sun.COM }
2649815SRishi.Srivatsavai@Sun.COM
2659815SRishi.Srivatsavai@Sun.COM /* Caller must hold simnet_dev_lock */
2669815SRishi.Srivatsavai@Sun.COM static simnet_dev_t *
simnet_dev_lookup(datalink_id_t link_id)2679815SRishi.Srivatsavai@Sun.COM simnet_dev_lookup(datalink_id_t link_id)
2689815SRishi.Srivatsavai@Sun.COM {
2699815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev;
2709815SRishi.Srivatsavai@Sun.COM
27110416SRishi.Srivatsavai@Sun.COM ASSERT(RW_LOCK_HELD(&simnet_dev_lock));
2729815SRishi.Srivatsavai@Sun.COM for (sdev = list_head(&simnet_dev_list); sdev != NULL;
2739815SRishi.Srivatsavai@Sun.COM sdev = list_next(&simnet_dev_list, sdev)) {
2749815SRishi.Srivatsavai@Sun.COM if (!(sdev->sd_flags & SDF_SHUTDOWN) &&
2759815SRishi.Srivatsavai@Sun.COM (sdev->sd_link_id == link_id)) {
2769815SRishi.Srivatsavai@Sun.COM atomic_inc_32(&sdev->sd_refcount);
2779815SRishi.Srivatsavai@Sun.COM return (sdev);
2789815SRishi.Srivatsavai@Sun.COM }
2799815SRishi.Srivatsavai@Sun.COM }
2809815SRishi.Srivatsavai@Sun.COM
2819815SRishi.Srivatsavai@Sun.COM return (NULL);
2829815SRishi.Srivatsavai@Sun.COM }
2839815SRishi.Srivatsavai@Sun.COM
2849815SRishi.Srivatsavai@Sun.COM static void
simnet_wifidev_free(simnet_dev_t * sdev)2859815SRishi.Srivatsavai@Sun.COM simnet_wifidev_free(simnet_dev_t *sdev)
2869815SRishi.Srivatsavai@Sun.COM {
2879815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev;
2889815SRishi.Srivatsavai@Sun.COM int i;
2899815SRishi.Srivatsavai@Sun.COM
2909815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) {
2919815SRishi.Srivatsavai@Sun.COM kmem_free(wdev->swd_esslist[i],
2929815SRishi.Srivatsavai@Sun.COM sizeof (wl_ess_conf_t));
2939815SRishi.Srivatsavai@Sun.COM }
2949815SRishi.Srivatsavai@Sun.COM kmem_free(wdev, sizeof (simnet_wifidev_t));
2959815SRishi.Srivatsavai@Sun.COM }
2969815SRishi.Srivatsavai@Sun.COM
2979815SRishi.Srivatsavai@Sun.COM static void
simnet_dev_unref(simnet_dev_t * sdev)2989815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(simnet_dev_t *sdev)
2999815SRishi.Srivatsavai@Sun.COM {
3009815SRishi.Srivatsavai@Sun.COM
3019815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_refcount > 0);
3029815SRishi.Srivatsavai@Sun.COM if (atomic_dec_32_nv(&sdev->sd_refcount) != 0)
3039815SRishi.Srivatsavai@Sun.COM return;
3049815SRishi.Srivatsavai@Sun.COM
3059815SRishi.Srivatsavai@Sun.COM if (sdev->sd_mh != NULL)
3069815SRishi.Srivatsavai@Sun.COM (void) mac_unregister(sdev->sd_mh);
3079815SRishi.Srivatsavai@Sun.COM
3089815SRishi.Srivatsavai@Sun.COM if (sdev->sd_wifidev != NULL) {
3099815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_type == DL_WIFI);
3109815SRishi.Srivatsavai@Sun.COM simnet_wifidev_free(sdev);
3119815SRishi.Srivatsavai@Sun.COM }
3129815SRishi.Srivatsavai@Sun.COM
3139815SRishi.Srivatsavai@Sun.COM mutex_destroy(&sdev->sd_instlock);
3149815SRishi.Srivatsavai@Sun.COM cv_destroy(&sdev->sd_threadwait);
3159815SRishi.Srivatsavai@Sun.COM kmem_free(sdev->sd_mcastaddrs, ETHERADDRL * sdev->sd_mcastaddr_count);
3169815SRishi.Srivatsavai@Sun.COM kmem_free(sdev, sizeof (*sdev));
3179815SRishi.Srivatsavai@Sun.COM simnet_count--;
3189815SRishi.Srivatsavai@Sun.COM }
3199815SRishi.Srivatsavai@Sun.COM
3209815SRishi.Srivatsavai@Sun.COM static int
simnet_init_wifi(simnet_dev_t * sdev,mac_register_t * mac)3219815SRishi.Srivatsavai@Sun.COM simnet_init_wifi(simnet_dev_t *sdev, mac_register_t *mac)
3229815SRishi.Srivatsavai@Sun.COM {
3239815SRishi.Srivatsavai@Sun.COM wifi_data_t wd = { 0 };
3249815SRishi.Srivatsavai@Sun.COM int err;
3259815SRishi.Srivatsavai@Sun.COM
3269815SRishi.Srivatsavai@Sun.COM sdev->sd_wifidev = kmem_zalloc(sizeof (simnet_wifidev_t), KM_NOSLEEP);
3279815SRishi.Srivatsavai@Sun.COM if (sdev->sd_wifidev == NULL)
3289815SRishi.Srivatsavai@Sun.COM return (ENOMEM);
3299815SRishi.Srivatsavai@Sun.COM
3309815SRishi.Srivatsavai@Sun.COM sdev->sd_wifidev->swd_sdev = sdev;
3319815SRishi.Srivatsavai@Sun.COM sdev->sd_wifidev->swd_linkstatus = WL_NOTCONNECTED;
3329815SRishi.Srivatsavai@Sun.COM wd.wd_secalloc = WIFI_SEC_NONE;
3339815SRishi.Srivatsavai@Sun.COM wd.wd_opmode = IEEE80211_M_STA;
3349815SRishi.Srivatsavai@Sun.COM mac->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
3359815SRishi.Srivatsavai@Sun.COM mac->m_max_sdu = IEEE80211_MTU;
3369815SRishi.Srivatsavai@Sun.COM mac->m_pdata = &wd;
3379815SRishi.Srivatsavai@Sun.COM mac->m_pdata_size = sizeof (wd);
3389815SRishi.Srivatsavai@Sun.COM err = mac_register(mac, &sdev->sd_mh);
3399815SRishi.Srivatsavai@Sun.COM return (err);
3409815SRishi.Srivatsavai@Sun.COM }
3419815SRishi.Srivatsavai@Sun.COM
3429815SRishi.Srivatsavai@Sun.COM static int
simnet_init_ether(simnet_dev_t * sdev,mac_register_t * mac)3439815SRishi.Srivatsavai@Sun.COM simnet_init_ether(simnet_dev_t *sdev, mac_register_t *mac)
3449815SRishi.Srivatsavai@Sun.COM {
3459815SRishi.Srivatsavai@Sun.COM int err;
3469815SRishi.Srivatsavai@Sun.COM
3479815SRishi.Srivatsavai@Sun.COM mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
3489815SRishi.Srivatsavai@Sun.COM mac->m_max_sdu = SIMNET_MAX_MTU;
3499815SRishi.Srivatsavai@Sun.COM mac->m_margin = VLAN_TAGSZ;
3509815SRishi.Srivatsavai@Sun.COM err = mac_register(mac, &sdev->sd_mh);
3519815SRishi.Srivatsavai@Sun.COM return (err);
3529815SRishi.Srivatsavai@Sun.COM }
3539815SRishi.Srivatsavai@Sun.COM
3549815SRishi.Srivatsavai@Sun.COM static int
simnet_init_mac(simnet_dev_t * sdev)3559815SRishi.Srivatsavai@Sun.COM simnet_init_mac(simnet_dev_t *sdev)
3569815SRishi.Srivatsavai@Sun.COM {
3579815SRishi.Srivatsavai@Sun.COM mac_register_t *mac;
3589815SRishi.Srivatsavai@Sun.COM int err;
3599815SRishi.Srivatsavai@Sun.COM
3609815SRishi.Srivatsavai@Sun.COM if ((mac = mac_alloc(MAC_VERSION)) == NULL)
3619815SRishi.Srivatsavai@Sun.COM return (ENOMEM);
3629815SRishi.Srivatsavai@Sun.COM
3639815SRishi.Srivatsavai@Sun.COM mac->m_driver = sdev;
3649815SRishi.Srivatsavai@Sun.COM mac->m_dip = simnet_dip;
3659815SRishi.Srivatsavai@Sun.COM mac->m_instance = (uint_t)-1;
3669815SRishi.Srivatsavai@Sun.COM mac->m_src_addr = sdev->sd_mac_addr;
3679815SRishi.Srivatsavai@Sun.COM mac->m_callbacks = &simnet_m_callbacks;
3689815SRishi.Srivatsavai@Sun.COM mac->m_min_sdu = 0;
3699815SRishi.Srivatsavai@Sun.COM
3709815SRishi.Srivatsavai@Sun.COM if (sdev->sd_type == DL_ETHER)
3719815SRishi.Srivatsavai@Sun.COM err = simnet_init_ether(sdev, mac);
3729815SRishi.Srivatsavai@Sun.COM else if (sdev->sd_type == DL_WIFI)
3739815SRishi.Srivatsavai@Sun.COM err = simnet_init_wifi(sdev, mac);
3749815SRishi.Srivatsavai@Sun.COM else
3759815SRishi.Srivatsavai@Sun.COM err = EINVAL;
3769815SRishi.Srivatsavai@Sun.COM
3779815SRishi.Srivatsavai@Sun.COM mac_free(mac);
3789815SRishi.Srivatsavai@Sun.COM return (err);
3799815SRishi.Srivatsavai@Sun.COM }
3809815SRishi.Srivatsavai@Sun.COM
3819815SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
3829815SRishi.Srivatsavai@Sun.COM static int
simnet_ioc_create(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)3839815SRishi.Srivatsavai@Sun.COM simnet_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
3849815SRishi.Srivatsavai@Sun.COM {
3859815SRishi.Srivatsavai@Sun.COM simnet_ioc_create_t *create_arg = karg;
3869815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev;
3879815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_tmp;
3889815SRishi.Srivatsavai@Sun.COM int err = 0;
3899815SRishi.Srivatsavai@Sun.COM
3909815SRishi.Srivatsavai@Sun.COM sdev = kmem_zalloc(sizeof (*sdev), KM_NOSLEEP);
3919815SRishi.Srivatsavai@Sun.COM if (sdev == NULL)
3929815SRishi.Srivatsavai@Sun.COM return (ENOMEM);
3939815SRishi.Srivatsavai@Sun.COM
3949815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_WRITER);
3959815SRishi.Srivatsavai@Sun.COM if ((sdev_tmp = simnet_dev_lookup(create_arg->sic_link_id)) != NULL) {
3969815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev_tmp);
3979815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
3989815SRishi.Srivatsavai@Sun.COM kmem_free(sdev, sizeof (*sdev));
3999815SRishi.Srivatsavai@Sun.COM return (EEXIST);
4009815SRishi.Srivatsavai@Sun.COM }
4019815SRishi.Srivatsavai@Sun.COM
4029815SRishi.Srivatsavai@Sun.COM sdev->sd_type = create_arg->sic_type;
4039815SRishi.Srivatsavai@Sun.COM sdev->sd_link_id = create_arg->sic_link_id;
40410616SSebastien.Roy@Sun.COM sdev->sd_zoneid = crgetzoneid(cred);
4059815SRishi.Srivatsavai@Sun.COM sdev->sd_refcount++;
4069815SRishi.Srivatsavai@Sun.COM mutex_init(&sdev->sd_instlock, NULL, MUTEX_DRIVER, NULL);
4079815SRishi.Srivatsavai@Sun.COM cv_init(&sdev->sd_threadwait, NULL, CV_DRIVER, NULL);
4089815SRishi.Srivatsavai@Sun.COM simnet_count++;
4099815SRishi.Srivatsavai@Sun.COM
4109815SRishi.Srivatsavai@Sun.COM /* Simnets created from configuration on boot pass saved MAC address */
4119815SRishi.Srivatsavai@Sun.COM if (create_arg->sic_mac_len == 0) {
4129815SRishi.Srivatsavai@Sun.COM /* Generate random MAC address */
4139815SRishi.Srivatsavai@Sun.COM (void) random_get_pseudo_bytes(sdev->sd_mac_addr, ETHERADDRL);
4149815SRishi.Srivatsavai@Sun.COM /* Ensure MAC address is not multicast and is local */
4159815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_addr[0] = (sdev->sd_mac_addr[0] & ~1) | 2;
4169815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_len = ETHERADDRL;
4179815SRishi.Srivatsavai@Sun.COM } else {
4189815SRishi.Srivatsavai@Sun.COM (void) memcpy(sdev->sd_mac_addr, create_arg->sic_mac_addr,
4199815SRishi.Srivatsavai@Sun.COM create_arg->sic_mac_len);
4209815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_len = create_arg->sic_mac_len;
4219815SRishi.Srivatsavai@Sun.COM }
4229815SRishi.Srivatsavai@Sun.COM
4239815SRishi.Srivatsavai@Sun.COM if ((err = simnet_init_mac(sdev)) != 0) {
4249815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
4259815SRishi.Srivatsavai@Sun.COM goto exit;
4269815SRishi.Srivatsavai@Sun.COM }
4279815SRishi.Srivatsavai@Sun.COM
42810616SSebastien.Roy@Sun.COM if ((err = dls_devnet_create(sdev->sd_mh, sdev->sd_link_id,
42910616SSebastien.Roy@Sun.COM crgetzoneid(cred))) != 0) {
4309815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
4319815SRishi.Srivatsavai@Sun.COM goto exit;
4329815SRishi.Srivatsavai@Sun.COM }
4339815SRishi.Srivatsavai@Sun.COM
4349815SRishi.Srivatsavai@Sun.COM mac_link_update(sdev->sd_mh, LINK_STATE_UP);
4359815SRishi.Srivatsavai@Sun.COM mac_tx_update(sdev->sd_mh);
4369815SRishi.Srivatsavai@Sun.COM list_insert_tail(&simnet_dev_list, sdev);
4379815SRishi.Srivatsavai@Sun.COM
4389815SRishi.Srivatsavai@Sun.COM /* Always return MAC address back to caller */
4399815SRishi.Srivatsavai@Sun.COM (void) memcpy(create_arg->sic_mac_addr, sdev->sd_mac_addr,
4409815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_len);
4419815SRishi.Srivatsavai@Sun.COM create_arg->sic_mac_len = sdev->sd_mac_len;
4429815SRishi.Srivatsavai@Sun.COM exit:
4439815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
4449815SRishi.Srivatsavai@Sun.COM return (err);
4459815SRishi.Srivatsavai@Sun.COM }
4469815SRishi.Srivatsavai@Sun.COM
4479815SRishi.Srivatsavai@Sun.COM /* Caller must hold writer simnet_dev_lock */
4489815SRishi.Srivatsavai@Sun.COM static datalink_id_t
simnet_remove_peer(simnet_dev_t * sdev)4499815SRishi.Srivatsavai@Sun.COM simnet_remove_peer(simnet_dev_t *sdev)
4509815SRishi.Srivatsavai@Sun.COM {
4519815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_peer;
4529815SRishi.Srivatsavai@Sun.COM datalink_id_t peer_link_id = DATALINK_INVALID_LINKID;
4539815SRishi.Srivatsavai@Sun.COM
45410416SRishi.Srivatsavai@Sun.COM ASSERT(RW_WRITE_HELD(&simnet_dev_lock));
4559815SRishi.Srivatsavai@Sun.COM if ((sdev_peer = sdev->sd_peer_dev) != NULL) {
4569815SRishi.Srivatsavai@Sun.COM ASSERT(sdev == sdev_peer->sd_peer_dev);
4579815SRishi.Srivatsavai@Sun.COM sdev_peer->sd_peer_dev = NULL;
4589815SRishi.Srivatsavai@Sun.COM sdev->sd_peer_dev = NULL;
4599815SRishi.Srivatsavai@Sun.COM peer_link_id = sdev_peer->sd_link_id;
4609815SRishi.Srivatsavai@Sun.COM /* Release previous references held on both simnets */
4619815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev_peer);
4629815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
4639815SRishi.Srivatsavai@Sun.COM }
4649815SRishi.Srivatsavai@Sun.COM
4659815SRishi.Srivatsavai@Sun.COM return (peer_link_id);
4669815SRishi.Srivatsavai@Sun.COM }
4679815SRishi.Srivatsavai@Sun.COM
4689815SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
4699815SRishi.Srivatsavai@Sun.COM static int
simnet_ioc_modify(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)4709815SRishi.Srivatsavai@Sun.COM simnet_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
4719815SRishi.Srivatsavai@Sun.COM {
4729815SRishi.Srivatsavai@Sun.COM simnet_ioc_modify_t *modify_arg = karg;
4739815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev;
4749815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_peer = NULL;
4759815SRishi.Srivatsavai@Sun.COM
4769815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_WRITER);
4779815SRishi.Srivatsavai@Sun.COM if ((sdev = simnet_dev_lookup(modify_arg->sim_link_id)) == NULL) {
4789815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
4799815SRishi.Srivatsavai@Sun.COM return (ENOENT);
4809815SRishi.Srivatsavai@Sun.COM }
4819815SRishi.Srivatsavai@Sun.COM
48210616SSebastien.Roy@Sun.COM if (sdev->sd_zoneid != crgetzoneid(cred)) {
48310616SSebastien.Roy@Sun.COM rw_exit(&simnet_dev_lock);
48410616SSebastien.Roy@Sun.COM simnet_dev_unref(sdev);
48510616SSebastien.Roy@Sun.COM return (ENOENT);
48610616SSebastien.Roy@Sun.COM }
48710616SSebastien.Roy@Sun.COM
4889815SRishi.Srivatsavai@Sun.COM if (sdev->sd_link_id == modify_arg->sim_peer_link_id) {
4899815SRishi.Srivatsavai@Sun.COM /* Cannot peer with self */
4909815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
4919815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
4929815SRishi.Srivatsavai@Sun.COM return (EINVAL);
4939815SRishi.Srivatsavai@Sun.COM }
4949815SRishi.Srivatsavai@Sun.COM
4959815SRishi.Srivatsavai@Sun.COM if (sdev->sd_peer_dev != NULL && sdev->sd_peer_dev->sd_link_id ==
4969815SRishi.Srivatsavai@Sun.COM modify_arg->sim_peer_link_id) {
4979815SRishi.Srivatsavai@Sun.COM /* Nothing to modify */
4989815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
4999815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
5009815SRishi.Srivatsavai@Sun.COM return (0);
5019815SRishi.Srivatsavai@Sun.COM }
5029815SRishi.Srivatsavai@Sun.COM
50310616SSebastien.Roy@Sun.COM if (modify_arg->sim_peer_link_id != DATALINK_INVALID_LINKID) {
50410616SSebastien.Roy@Sun.COM sdev_peer = simnet_dev_lookup(modify_arg->sim_peer_link_id);
50510616SSebastien.Roy@Sun.COM if (sdev_peer == NULL) {
50610616SSebastien.Roy@Sun.COM /* Peer simnet device not available */
50710616SSebastien.Roy@Sun.COM rw_exit(&simnet_dev_lock);
50810616SSebastien.Roy@Sun.COM simnet_dev_unref(sdev);
50910616SSebastien.Roy@Sun.COM return (ENOENT);
51010616SSebastien.Roy@Sun.COM }
51110616SSebastien.Roy@Sun.COM if (sdev_peer->sd_zoneid != sdev->sd_zoneid) {
51210616SSebastien.Roy@Sun.COM /* The two peers must be in the same zone (for now). */
51310616SSebastien.Roy@Sun.COM rw_exit(&simnet_dev_lock);
51410616SSebastien.Roy@Sun.COM simnet_dev_unref(sdev);
51510616SSebastien.Roy@Sun.COM simnet_dev_unref(sdev_peer);
51610616SSebastien.Roy@Sun.COM return (EACCES);
51710616SSebastien.Roy@Sun.COM }
5189815SRishi.Srivatsavai@Sun.COM }
5199815SRishi.Srivatsavai@Sun.COM
5209815SRishi.Srivatsavai@Sun.COM /* First remove any previous peer */
5219815SRishi.Srivatsavai@Sun.COM (void) simnet_remove_peer(sdev);
5229815SRishi.Srivatsavai@Sun.COM
5239815SRishi.Srivatsavai@Sun.COM if (sdev_peer != NULL) {
5249815SRishi.Srivatsavai@Sun.COM /* Remove any previous peer of sdev_peer */
5259815SRishi.Srivatsavai@Sun.COM (void) simnet_remove_peer(sdev_peer);
5269815SRishi.Srivatsavai@Sun.COM /* Update both devices with the new peer */
5279815SRishi.Srivatsavai@Sun.COM sdev_peer->sd_peer_dev = sdev;
5289815SRishi.Srivatsavai@Sun.COM sdev->sd_peer_dev = sdev_peer;
5299815SRishi.Srivatsavai@Sun.COM /* Hold references on both devices */
5309815SRishi.Srivatsavai@Sun.COM } else {
5319815SRishi.Srivatsavai@Sun.COM /* Release sdev lookup reference */
5329815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
5339815SRishi.Srivatsavai@Sun.COM }
5349815SRishi.Srivatsavai@Sun.COM
5359815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
5369815SRishi.Srivatsavai@Sun.COM return (0);
5379815SRishi.Srivatsavai@Sun.COM }
5389815SRishi.Srivatsavai@Sun.COM
5399815SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
5409815SRishi.Srivatsavai@Sun.COM static int
simnet_ioc_delete(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)5419815SRishi.Srivatsavai@Sun.COM simnet_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
5429815SRishi.Srivatsavai@Sun.COM {
5439815SRishi.Srivatsavai@Sun.COM int err;
5449815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev;
5459815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_peer;
5469815SRishi.Srivatsavai@Sun.COM simnet_ioc_delete_t *delete_arg = karg;
5479815SRishi.Srivatsavai@Sun.COM datalink_id_t tmpid;
5489815SRishi.Srivatsavai@Sun.COM datalink_id_t peerid;
5499815SRishi.Srivatsavai@Sun.COM
5509815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_WRITER);
5519815SRishi.Srivatsavai@Sun.COM if ((sdev = simnet_dev_lookup(delete_arg->sid_link_id)) == NULL) {
5529815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
5539815SRishi.Srivatsavai@Sun.COM return (ENOENT);
5549815SRishi.Srivatsavai@Sun.COM }
5559815SRishi.Srivatsavai@Sun.COM
55610616SSebastien.Roy@Sun.COM if (sdev->sd_zoneid != crgetzoneid(cred)) {
55710616SSebastien.Roy@Sun.COM rw_exit(&simnet_dev_lock);
55810616SSebastien.Roy@Sun.COM simnet_dev_unref(sdev);
55910616SSebastien.Roy@Sun.COM return (ENOENT);
56010616SSebastien.Roy@Sun.COM }
56110616SSebastien.Roy@Sun.COM
5629815SRishi.Srivatsavai@Sun.COM if ((err = dls_devnet_destroy(sdev->sd_mh, &tmpid, B_TRUE)) != 0) {
5639815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
5649815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
5659815SRishi.Srivatsavai@Sun.COM return (err);
5669815SRishi.Srivatsavai@Sun.COM }
5679815SRishi.Srivatsavai@Sun.COM
5689815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_link_id == tmpid);
5699815SRishi.Srivatsavai@Sun.COM /* Remove any attached peer link */
5709815SRishi.Srivatsavai@Sun.COM peerid = simnet_remove_peer(sdev);
5719815SRishi.Srivatsavai@Sun.COM
5729815SRishi.Srivatsavai@Sun.COM /* Prevent new threads from using the instance */
5739815SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock);
5749815SRishi.Srivatsavai@Sun.COM sdev->sd_flags |= SDF_SHUTDOWN;
5759815SRishi.Srivatsavai@Sun.COM /* Wait until all active threads using the instance exit */
5769815SRishi.Srivatsavai@Sun.COM while (sdev->sd_threadcount > 0) {
5779815SRishi.Srivatsavai@Sun.COM if (cv_wait_sig(&sdev->sd_threadwait,
5789815SRishi.Srivatsavai@Sun.COM &sdev->sd_instlock) == 0) {
5799815SRishi.Srivatsavai@Sun.COM /* Signaled */
5809815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
5819815SRishi.Srivatsavai@Sun.COM err = EINTR;
5829815SRishi.Srivatsavai@Sun.COM goto fail;
5839815SRishi.Srivatsavai@Sun.COM }
5849815SRishi.Srivatsavai@Sun.COM }
5859815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
5869815SRishi.Srivatsavai@Sun.COM
5879815SRishi.Srivatsavai@Sun.COM /* Try disabling the MAC */
5889815SRishi.Srivatsavai@Sun.COM if ((err = mac_disable(sdev->sd_mh)) != 0)
5899815SRishi.Srivatsavai@Sun.COM goto fail;
5909815SRishi.Srivatsavai@Sun.COM
5919815SRishi.Srivatsavai@Sun.COM list_remove(&simnet_dev_list, sdev);
5929815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
5939815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev); /* Release lookup ref */
5949815SRishi.Srivatsavai@Sun.COM /* Releasing the last ref performs sdev/mem free */
5959815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
5969815SRishi.Srivatsavai@Sun.COM return (err);
5979815SRishi.Srivatsavai@Sun.COM fail:
5989815SRishi.Srivatsavai@Sun.COM /* Re-create simnet instance and add any previous peer */
59910616SSebastien.Roy@Sun.COM (void) dls_devnet_create(sdev->sd_mh, sdev->sd_link_id,
60010616SSebastien.Roy@Sun.COM crgetzoneid(cred));
6019815SRishi.Srivatsavai@Sun.COM sdev->sd_flags &= ~SDF_SHUTDOWN;
6029815SRishi.Srivatsavai@Sun.COM
6039815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_peer_dev == NULL);
6049815SRishi.Srivatsavai@Sun.COM if (peerid != DATALINK_INVALID_LINKID &&
6059815SRishi.Srivatsavai@Sun.COM ((sdev_peer = simnet_dev_lookup(peerid)) != NULL)) {
6069815SRishi.Srivatsavai@Sun.COM /* Attach peer device back */
6079815SRishi.Srivatsavai@Sun.COM ASSERT(sdev_peer->sd_peer_dev == NULL);
6089815SRishi.Srivatsavai@Sun.COM sdev_peer->sd_peer_dev = sdev;
6099815SRishi.Srivatsavai@Sun.COM sdev->sd_peer_dev = sdev_peer;
6109815SRishi.Srivatsavai@Sun.COM /* Hold reference on both devices */
6119815SRishi.Srivatsavai@Sun.COM } else {
6129815SRishi.Srivatsavai@Sun.COM /*
6139815SRishi.Srivatsavai@Sun.COM * No previous peer or previous peer no longer
6149815SRishi.Srivatsavai@Sun.COM * available so release lookup reference.
6159815SRishi.Srivatsavai@Sun.COM */
6169815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
6179815SRishi.Srivatsavai@Sun.COM }
6189815SRishi.Srivatsavai@Sun.COM
6199815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
6209815SRishi.Srivatsavai@Sun.COM return (err);
6219815SRishi.Srivatsavai@Sun.COM }
6229815SRishi.Srivatsavai@Sun.COM
6239815SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
6249815SRishi.Srivatsavai@Sun.COM static int
simnet_ioc_info(void * karg,intptr_t arg,int mode,cred_t * cred,int * rvalp)6259815SRishi.Srivatsavai@Sun.COM simnet_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
6269815SRishi.Srivatsavai@Sun.COM {
6279815SRishi.Srivatsavai@Sun.COM simnet_ioc_info_t *info_arg = karg;
6289815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev;
6299815SRishi.Srivatsavai@Sun.COM
63010616SSebastien.Roy@Sun.COM /* Make sure that the simnet link is visible from the caller's zone. */
63110616SSebastien.Roy@Sun.COM if (!dls_devnet_islinkvisible(info_arg->sii_link_id, crgetzoneid(cred)))
63210616SSebastien.Roy@Sun.COM return (ENOENT);
63310616SSebastien.Roy@Sun.COM
6349815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_READER);
6359815SRishi.Srivatsavai@Sun.COM if ((sdev = simnet_dev_lookup(info_arg->sii_link_id)) == NULL) {
6369815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
6379815SRishi.Srivatsavai@Sun.COM return (ENOENT);
6389815SRishi.Srivatsavai@Sun.COM }
6399815SRishi.Srivatsavai@Sun.COM
6409815SRishi.Srivatsavai@Sun.COM (void) memcpy(info_arg->sii_mac_addr, sdev->sd_mac_addr,
6419815SRishi.Srivatsavai@Sun.COM sdev->sd_mac_len);
6429815SRishi.Srivatsavai@Sun.COM info_arg->sii_mac_len = sdev->sd_mac_len;
6439815SRishi.Srivatsavai@Sun.COM info_arg->sii_type = sdev->sd_type;
6449815SRishi.Srivatsavai@Sun.COM if (sdev->sd_peer_dev != NULL)
6459815SRishi.Srivatsavai@Sun.COM info_arg->sii_peer_link_id = sdev->sd_peer_dev->sd_link_id;
6469815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
6479815SRishi.Srivatsavai@Sun.COM simnet_dev_unref(sdev);
6489815SRishi.Srivatsavai@Sun.COM return (0);
6499815SRishi.Srivatsavai@Sun.COM }
6509815SRishi.Srivatsavai@Sun.COM
65110416SRishi.Srivatsavai@Sun.COM static boolean_t
simnet_thread_ref(simnet_dev_t * sdev)65210416SRishi.Srivatsavai@Sun.COM simnet_thread_ref(simnet_dev_t *sdev)
65310416SRishi.Srivatsavai@Sun.COM {
65410416SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock);
65510416SRishi.Srivatsavai@Sun.COM if (sdev->sd_flags & SDF_SHUTDOWN ||
65610416SRishi.Srivatsavai@Sun.COM !(sdev->sd_flags & SDF_STARTED)) {
65710416SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
65810416SRishi.Srivatsavai@Sun.COM return (B_FALSE);
65910416SRishi.Srivatsavai@Sun.COM }
66010416SRishi.Srivatsavai@Sun.COM sdev->sd_threadcount++;
66110416SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
66210416SRishi.Srivatsavai@Sun.COM return (B_TRUE);
66310416SRishi.Srivatsavai@Sun.COM }
66410416SRishi.Srivatsavai@Sun.COM
6659815SRishi.Srivatsavai@Sun.COM static void
simnet_thread_unref(simnet_dev_t * sdev)66610416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(simnet_dev_t *sdev)
6679815SRishi.Srivatsavai@Sun.COM {
66810416SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock);
66910416SRishi.Srivatsavai@Sun.COM if (--sdev->sd_threadcount == 0)
67010416SRishi.Srivatsavai@Sun.COM cv_broadcast(&sdev->sd_threadwait);
67110416SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
67210416SRishi.Srivatsavai@Sun.COM }
67310416SRishi.Srivatsavai@Sun.COM
67410416SRishi.Srivatsavai@Sun.COM static void
simnet_rx(void * arg)67510416SRishi.Srivatsavai@Sun.COM simnet_rx(void *arg)
67610416SRishi.Srivatsavai@Sun.COM {
67710416SRishi.Srivatsavai@Sun.COM mblk_t *mp = arg;
6789815SRishi.Srivatsavai@Sun.COM mac_header_info_t hdr_info;
67910416SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev;
68010416SRishi.Srivatsavai@Sun.COM
68110416SRishi.Srivatsavai@Sun.COM sdev = (simnet_dev_t *)mp->b_next;
68210416SRishi.Srivatsavai@Sun.COM mp->b_next = NULL;
6839815SRishi.Srivatsavai@Sun.COM
6849815SRishi.Srivatsavai@Sun.COM /* Check for valid packet header */
6859815SRishi.Srivatsavai@Sun.COM if (mac_header_info(sdev->sd_mh, mp, &hdr_info) != 0) {
6869815SRishi.Srivatsavai@Sun.COM freemsg(mp);
6879815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.recv_errors++;
68810416SRishi.Srivatsavai@Sun.COM goto rx_done;
6899815SRishi.Srivatsavai@Sun.COM }
6909815SRishi.Srivatsavai@Sun.COM
6919815SRishi.Srivatsavai@Sun.COM /*
6929815SRishi.Srivatsavai@Sun.COM * When we are NOT in promiscuous mode we only receive
6939815SRishi.Srivatsavai@Sun.COM * unicast packets addressed to us and multicast packets that
6949815SRishi.Srivatsavai@Sun.COM * MAC clients have requested.
6959815SRishi.Srivatsavai@Sun.COM */
6969815SRishi.Srivatsavai@Sun.COM if (!sdev->sd_promisc &&
6979815SRishi.Srivatsavai@Sun.COM hdr_info.mhi_dsttype != MAC_ADDRTYPE_BROADCAST) {
6989815SRishi.Srivatsavai@Sun.COM if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_UNICAST &&
6999815SRishi.Srivatsavai@Sun.COM bcmp(hdr_info.mhi_daddr, sdev->sd_mac_addr,
7009815SRishi.Srivatsavai@Sun.COM ETHERADDRL) != 0) {
7019815SRishi.Srivatsavai@Sun.COM freemsg(mp);
70210416SRishi.Srivatsavai@Sun.COM goto rx_done;
7039815SRishi.Srivatsavai@Sun.COM } else if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) {
7049815SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock);
7059815SRishi.Srivatsavai@Sun.COM if (mcastaddr_lookup(sdev, hdr_info.mhi_daddr) ==
7069815SRishi.Srivatsavai@Sun.COM NULL) {
7079815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
7089815SRishi.Srivatsavai@Sun.COM freemsg(mp);
70910416SRishi.Srivatsavai@Sun.COM goto rx_done;
7109815SRishi.Srivatsavai@Sun.COM }
7119815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
7129815SRishi.Srivatsavai@Sun.COM }
7139815SRishi.Srivatsavai@Sun.COM }
7149815SRishi.Srivatsavai@Sun.COM
7159815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.recv_count++;
7169815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.rbytes += msgdsize(mp);
7179815SRishi.Srivatsavai@Sun.COM mac_rx(sdev->sd_mh, NULL, mp);
71810416SRishi.Srivatsavai@Sun.COM rx_done:
71910416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev);
7209815SRishi.Srivatsavai@Sun.COM }
7219815SRishi.Srivatsavai@Sun.COM
7229815SRishi.Srivatsavai@Sun.COM static mblk_t *
simnet_m_tx(void * arg,mblk_t * mp_chain)7239815SRishi.Srivatsavai@Sun.COM simnet_m_tx(void *arg, mblk_t *mp_chain)
7249815SRishi.Srivatsavai@Sun.COM {
7259815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
7269815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev_rx;
7279815SRishi.Srivatsavai@Sun.COM mblk_t *mpnext = mp_chain;
7289815SRishi.Srivatsavai@Sun.COM mblk_t *mp;
7299815SRishi.Srivatsavai@Sun.COM
7309815SRishi.Srivatsavai@Sun.COM rw_enter(&simnet_dev_lock, RW_READER);
7319815SRishi.Srivatsavai@Sun.COM if ((sdev_rx = sdev->sd_peer_dev) == NULL) {
7329815SRishi.Srivatsavai@Sun.COM /* Discard packets when no peer exists */
7339815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
7349815SRishi.Srivatsavai@Sun.COM freemsgchain(mp_chain);
7359815SRishi.Srivatsavai@Sun.COM return (NULL);
7369815SRishi.Srivatsavai@Sun.COM }
7379815SRishi.Srivatsavai@Sun.COM
7389815SRishi.Srivatsavai@Sun.COM /*
7399815SRishi.Srivatsavai@Sun.COM * Discard packets when either device is shutting down or not ready.
7409815SRishi.Srivatsavai@Sun.COM * Though MAC layer ensures a reference is held on the MAC while we
7419815SRishi.Srivatsavai@Sun.COM * process the packet chain, there is no guarantee the peer MAC will
7429815SRishi.Srivatsavai@Sun.COM * remain enabled. So we increment per-instance threadcount to ensure
7439815SRishi.Srivatsavai@Sun.COM * either MAC instance is not disabled while we handle the chain of
7449815SRishi.Srivatsavai@Sun.COM * packets. It is okay if the peer device is disconnected while we are
7459815SRishi.Srivatsavai@Sun.COM * here since we lookup the peer device while holding simnet_dev_lock
7469815SRishi.Srivatsavai@Sun.COM * (reader lock) and increment the threadcount of the peer, the peer
7479815SRishi.Srivatsavai@Sun.COM * MAC cannot be disabled in simnet_ioc_delete.
7489815SRishi.Srivatsavai@Sun.COM */
74910416SRishi.Srivatsavai@Sun.COM if (!simnet_thread_ref(sdev_rx)) {
7509815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
7519815SRishi.Srivatsavai@Sun.COM freemsgchain(mp_chain);
7529815SRishi.Srivatsavai@Sun.COM return (NULL);
7539815SRishi.Srivatsavai@Sun.COM }
7549815SRishi.Srivatsavai@Sun.COM rw_exit(&simnet_dev_lock);
7559815SRishi.Srivatsavai@Sun.COM
75610416SRishi.Srivatsavai@Sun.COM if (!simnet_thread_ref(sdev)) {
75710416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev_rx);
7589815SRishi.Srivatsavai@Sun.COM freemsgchain(mp_chain);
7599815SRishi.Srivatsavai@Sun.COM return (NULL);
7609815SRishi.Srivatsavai@Sun.COM }
7619815SRishi.Srivatsavai@Sun.COM
7629815SRishi.Srivatsavai@Sun.COM while ((mp = mpnext) != NULL) {
7639815SRishi.Srivatsavai@Sun.COM int len;
7649815SRishi.Srivatsavai@Sun.COM int size;
7659815SRishi.Srivatsavai@Sun.COM mblk_t *mp_new;
7669815SRishi.Srivatsavai@Sun.COM mblk_t *mp_tmp;
7679815SRishi.Srivatsavai@Sun.COM
7689815SRishi.Srivatsavai@Sun.COM mpnext = mp->b_next;
7699815SRishi.Srivatsavai@Sun.COM mp->b_next = NULL;
7709815SRishi.Srivatsavai@Sun.COM len = msgdsize(mp);
7719815SRishi.Srivatsavai@Sun.COM
7729815SRishi.Srivatsavai@Sun.COM /* Pad packet to minimum Ethernet frame size */
7739815SRishi.Srivatsavai@Sun.COM if (len < ETHERMIN) {
7749815SRishi.Srivatsavai@Sun.COM size = ETHERMIN - len;
7759815SRishi.Srivatsavai@Sun.COM mp_new = allocb(size, BPRI_HI);
7769815SRishi.Srivatsavai@Sun.COM if (mp_new == NULL) {
7779815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.xmit_errors++;
7789815SRishi.Srivatsavai@Sun.COM freemsg(mp);
7799815SRishi.Srivatsavai@Sun.COM continue;
7809815SRishi.Srivatsavai@Sun.COM }
7819815SRishi.Srivatsavai@Sun.COM bzero(mp_new->b_wptr, size);
7829815SRishi.Srivatsavai@Sun.COM mp_new->b_wptr += size;
7839815SRishi.Srivatsavai@Sun.COM
7849815SRishi.Srivatsavai@Sun.COM mp_tmp = mp;
7859815SRishi.Srivatsavai@Sun.COM while (mp_tmp->b_cont != NULL)
7869815SRishi.Srivatsavai@Sun.COM mp_tmp = mp_tmp->b_cont;
7879815SRishi.Srivatsavai@Sun.COM mp_tmp->b_cont = mp_new;
7889815SRishi.Srivatsavai@Sun.COM len += size;
7899815SRishi.Srivatsavai@Sun.COM }
7909815SRishi.Srivatsavai@Sun.COM
7919815SRishi.Srivatsavai@Sun.COM /* Pullup packet into a single mblk */
7929815SRishi.Srivatsavai@Sun.COM if (!pullupmsg(mp, -1)) {
7939815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.xmit_errors++;
7949815SRishi.Srivatsavai@Sun.COM freemsg(mp);
7959815SRishi.Srivatsavai@Sun.COM continue;
7969815SRishi.Srivatsavai@Sun.COM }
7979815SRishi.Srivatsavai@Sun.COM
7989815SRishi.Srivatsavai@Sun.COM /* Fix mblk checksum as the pkt dest is local */
7999815SRishi.Srivatsavai@Sun.COM if ((mp = mac_fix_cksum(mp)) == NULL) {
8009815SRishi.Srivatsavai@Sun.COM sdev->sd_stats.xmit_errors++;
8019815SRishi.Srivatsavai@Sun.COM continue;
8029815SRishi.Srivatsavai@Sun.COM }
8039815SRishi.Srivatsavai@Sun.COM
80410416SRishi.Srivatsavai@Sun.COM /* Hold reference for taskq receive processing per-pkt */
80510416SRishi.Srivatsavai@Sun.COM if (!simnet_thread_ref(sdev_rx)) {
80610416SRishi.Srivatsavai@Sun.COM freemsg(mp);
80710416SRishi.Srivatsavai@Sun.COM freemsgchain(mpnext);
80810416SRishi.Srivatsavai@Sun.COM break;
80910416SRishi.Srivatsavai@Sun.COM }
81010416SRishi.Srivatsavai@Sun.COM
81110416SRishi.Srivatsavai@Sun.COM /* Use taskq for pkt receive to avoid kernel stack explosion */
81210416SRishi.Srivatsavai@Sun.COM mp->b_next = (mblk_t *)sdev_rx;
81310416SRishi.Srivatsavai@Sun.COM if (ddi_taskq_dispatch(simnet_rxq, simnet_rx, mp,
81410416SRishi.Srivatsavai@Sun.COM DDI_NOSLEEP) == DDI_SUCCESS) {
81510416SRishi.Srivatsavai@Sun.COM sdev->sd_stats.xmit_count++;
81610416SRishi.Srivatsavai@Sun.COM sdev->sd_stats.obytes += len;
81710416SRishi.Srivatsavai@Sun.COM } else {
81810416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev_rx);
81910416SRishi.Srivatsavai@Sun.COM mp->b_next = NULL;
82010416SRishi.Srivatsavai@Sun.COM freemsg(mp);
82110416SRishi.Srivatsavai@Sun.COM sdev_rx->sd_stats.recv_errors++;
82210416SRishi.Srivatsavai@Sun.COM }
8239815SRishi.Srivatsavai@Sun.COM }
8249815SRishi.Srivatsavai@Sun.COM
82510416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev);
82610416SRishi.Srivatsavai@Sun.COM simnet_thread_unref(sdev_rx);
8279815SRishi.Srivatsavai@Sun.COM return (NULL);
8289815SRishi.Srivatsavai@Sun.COM }
8299815SRishi.Srivatsavai@Sun.COM
8309815SRishi.Srivatsavai@Sun.COM static int
simnet_wifi_ioctl(simnet_dev_t * sdev,mblk_t * mp)8319815SRishi.Srivatsavai@Sun.COM simnet_wifi_ioctl(simnet_dev_t *sdev, mblk_t *mp)
8329815SRishi.Srivatsavai@Sun.COM {
8339815SRishi.Srivatsavai@Sun.COM int rc = WL_SUCCESS;
8349815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev;
8359815SRishi.Srivatsavai@Sun.COM
8369815SRishi.Srivatsavai@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */
8379815SRishi.Srivatsavai@Sun.COM switch (((wldp_t *)mp->b_rptr)->wldp_id) {
8389815SRishi.Srivatsavai@Sun.COM case WL_DISASSOCIATE:
8399815SRishi.Srivatsavai@Sun.COM wdev->swd_linkstatus = WL_NOTCONNECTED;
8409815SRishi.Srivatsavai@Sun.COM break;
8419815SRishi.Srivatsavai@Sun.COM default:
8429815SRishi.Srivatsavai@Sun.COM break;
8439815SRishi.Srivatsavai@Sun.COM }
8449815SRishi.Srivatsavai@Sun.COM return (rc);
8459815SRishi.Srivatsavai@Sun.COM }
8469815SRishi.Srivatsavai@Sun.COM
8479815SRishi.Srivatsavai@Sun.COM static void
simnet_m_ioctl(void * arg,queue_t * q,mblk_t * mp)8489815SRishi.Srivatsavai@Sun.COM simnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
8499815SRishi.Srivatsavai@Sun.COM {
8509815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
8519815SRishi.Srivatsavai@Sun.COM struct iocblk *iocp;
8529815SRishi.Srivatsavai@Sun.COM mblk_t *mp1;
8539815SRishi.Srivatsavai@Sun.COM uint32_t cmd;
8549815SRishi.Srivatsavai@Sun.COM int rc;
8559815SRishi.Srivatsavai@Sun.COM
8569815SRishi.Srivatsavai@Sun.COM if (sdev->sd_type != DL_WIFI) {
8579815SRishi.Srivatsavai@Sun.COM miocnak(q, mp, 0, ENOTSUP);
8589815SRishi.Srivatsavai@Sun.COM return;
8599815SRishi.Srivatsavai@Sun.COM }
8609815SRishi.Srivatsavai@Sun.COM
8619815SRishi.Srivatsavai@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */
8629815SRishi.Srivatsavai@Sun.COM iocp = (struct iocblk *)mp->b_rptr;
8639815SRishi.Srivatsavai@Sun.COM if (iocp->ioc_count == 0) {
8649815SRishi.Srivatsavai@Sun.COM miocnak(q, mp, 0, EINVAL);
8659815SRishi.Srivatsavai@Sun.COM return;
8669815SRishi.Srivatsavai@Sun.COM }
8679815SRishi.Srivatsavai@Sun.COM
8689815SRishi.Srivatsavai@Sun.COM /* We only claim support for WiFi operation commands */
8699815SRishi.Srivatsavai@Sun.COM cmd = iocp->ioc_cmd;
8709815SRishi.Srivatsavai@Sun.COM switch (cmd) {
8719815SRishi.Srivatsavai@Sun.COM default:
8729815SRishi.Srivatsavai@Sun.COM miocnak(q, mp, 0, EINVAL);
8739815SRishi.Srivatsavai@Sun.COM return;
8749815SRishi.Srivatsavai@Sun.COM case WLAN_GET_PARAM:
8759815SRishi.Srivatsavai@Sun.COM case WLAN_SET_PARAM:
8769815SRishi.Srivatsavai@Sun.COM case WLAN_COMMAND:
8779815SRishi.Srivatsavai@Sun.COM break;
8789815SRishi.Srivatsavai@Sun.COM }
8799815SRishi.Srivatsavai@Sun.COM
8809815SRishi.Srivatsavai@Sun.COM mp1 = mp->b_cont;
8819815SRishi.Srivatsavai@Sun.COM freemsg(mp1->b_cont);
8829815SRishi.Srivatsavai@Sun.COM mp1->b_cont = NULL;
8839815SRishi.Srivatsavai@Sun.COM /* overwrite everything */
8849815SRishi.Srivatsavai@Sun.COM mp1->b_wptr = mp1->b_rptr;
8859815SRishi.Srivatsavai@Sun.COM rc = simnet_wifi_ioctl(sdev, mp1);
8869815SRishi.Srivatsavai@Sun.COM miocack(q, mp, msgdsize(mp1), rc);
8879815SRishi.Srivatsavai@Sun.COM }
8889815SRishi.Srivatsavai@Sun.COM
8899815SRishi.Srivatsavai@Sun.COM static int
simnet_m_stat(void * arg,uint_t stat,uint64_t * val)8909815SRishi.Srivatsavai@Sun.COM simnet_m_stat(void *arg, uint_t stat, uint64_t *val)
8919815SRishi.Srivatsavai@Sun.COM {
8929815SRishi.Srivatsavai@Sun.COM int rval = 0;
8939815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
8949815SRishi.Srivatsavai@Sun.COM
8959815SRishi.Srivatsavai@Sun.COM ASSERT(sdev->sd_mh != NULL);
8969815SRishi.Srivatsavai@Sun.COM
8979815SRishi.Srivatsavai@Sun.COM switch (stat) {
8989815SRishi.Srivatsavai@Sun.COM case MAC_STAT_IFSPEED:
8999815SRishi.Srivatsavai@Sun.COM *val = 100 * 1000000ull; /* 100 Mbps */
9009815SRishi.Srivatsavai@Sun.COM break;
9019815SRishi.Srivatsavai@Sun.COM case MAC_STAT_LINK_STATE:
9029815SRishi.Srivatsavai@Sun.COM *val = LINK_DUPLEX_FULL;
9039815SRishi.Srivatsavai@Sun.COM break;
9049815SRishi.Srivatsavai@Sun.COM case MAC_STAT_LINK_UP:
9059815SRishi.Srivatsavai@Sun.COM if (sdev->sd_flags & SDF_STARTED)
9069815SRishi.Srivatsavai@Sun.COM *val = LINK_STATE_UP;
9079815SRishi.Srivatsavai@Sun.COM else
9089815SRishi.Srivatsavai@Sun.COM *val = LINK_STATE_DOWN;
9099815SRishi.Srivatsavai@Sun.COM break;
9109815SRishi.Srivatsavai@Sun.COM case MAC_STAT_PROMISC:
9119815SRishi.Srivatsavai@Sun.COM case MAC_STAT_MULTIRCV:
9129815SRishi.Srivatsavai@Sun.COM case MAC_STAT_MULTIXMT:
9139815SRishi.Srivatsavai@Sun.COM case MAC_STAT_BRDCSTRCV:
9149815SRishi.Srivatsavai@Sun.COM case MAC_STAT_BRDCSTXMT:
9159815SRishi.Srivatsavai@Sun.COM rval = ENOTSUP;
9169815SRishi.Srivatsavai@Sun.COM break;
9179815SRishi.Srivatsavai@Sun.COM case MAC_STAT_OPACKETS:
9189815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.xmit_count;
9199815SRishi.Srivatsavai@Sun.COM break;
9209815SRishi.Srivatsavai@Sun.COM case MAC_STAT_OBYTES:
9219815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.obytes;
9229815SRishi.Srivatsavai@Sun.COM break;
9239815SRishi.Srivatsavai@Sun.COM case MAC_STAT_IERRORS:
9249815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.recv_errors;
9259815SRishi.Srivatsavai@Sun.COM break;
9269815SRishi.Srivatsavai@Sun.COM case MAC_STAT_OERRORS:
9279815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.xmit_errors;
9289815SRishi.Srivatsavai@Sun.COM break;
9299815SRishi.Srivatsavai@Sun.COM case MAC_STAT_RBYTES:
9309815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.rbytes;
9319815SRishi.Srivatsavai@Sun.COM break;
9329815SRishi.Srivatsavai@Sun.COM case MAC_STAT_IPACKETS:
9339815SRishi.Srivatsavai@Sun.COM *val = sdev->sd_stats.recv_count;
9349815SRishi.Srivatsavai@Sun.COM break;
9359815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_FCS_ERRORS:
9369815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_WEP_ERRORS:
9379815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_TX_FRAGS:
9389815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_MCAST_TX:
9399815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_RTS_SUCCESS:
9409815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_RTS_FAILURE:
9419815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_ACK_FAILURE:
9429815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_RX_FRAGS:
9439815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_MCAST_RX:
9449815SRishi.Srivatsavai@Sun.COM case WIFI_STAT_RX_DUPS:
9459815SRishi.Srivatsavai@Sun.COM rval = ENOTSUP;
9469815SRishi.Srivatsavai@Sun.COM break;
9479815SRishi.Srivatsavai@Sun.COM default:
9489815SRishi.Srivatsavai@Sun.COM rval = ENOTSUP;
9499815SRishi.Srivatsavai@Sun.COM break;
9509815SRishi.Srivatsavai@Sun.COM }
9519815SRishi.Srivatsavai@Sun.COM
9529815SRishi.Srivatsavai@Sun.COM return (rval);
9539815SRishi.Srivatsavai@Sun.COM }
9549815SRishi.Srivatsavai@Sun.COM
9559815SRishi.Srivatsavai@Sun.COM static int
simnet_m_start(void * arg)9569815SRishi.Srivatsavai@Sun.COM simnet_m_start(void *arg)
9579815SRishi.Srivatsavai@Sun.COM {
9589815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
9599815SRishi.Srivatsavai@Sun.COM
9609815SRishi.Srivatsavai@Sun.COM sdev->sd_flags |= SDF_STARTED;
9619815SRishi.Srivatsavai@Sun.COM return (0);
9629815SRishi.Srivatsavai@Sun.COM }
9639815SRishi.Srivatsavai@Sun.COM
9649815SRishi.Srivatsavai@Sun.COM static void
simnet_m_stop(void * arg)9659815SRishi.Srivatsavai@Sun.COM simnet_m_stop(void *arg)
9669815SRishi.Srivatsavai@Sun.COM {
9679815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
9689815SRishi.Srivatsavai@Sun.COM
9699815SRishi.Srivatsavai@Sun.COM sdev->sd_flags &= ~SDF_STARTED;
9709815SRishi.Srivatsavai@Sun.COM }
9719815SRishi.Srivatsavai@Sun.COM
9729815SRishi.Srivatsavai@Sun.COM static int
simnet_m_promisc(void * arg,boolean_t on)9739815SRishi.Srivatsavai@Sun.COM simnet_m_promisc(void *arg, boolean_t on)
9749815SRishi.Srivatsavai@Sun.COM {
9759815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
9769815SRishi.Srivatsavai@Sun.COM
9779815SRishi.Srivatsavai@Sun.COM sdev->sd_promisc = on;
9789815SRishi.Srivatsavai@Sun.COM return (0);
9799815SRishi.Srivatsavai@Sun.COM }
9809815SRishi.Srivatsavai@Sun.COM
9819815SRishi.Srivatsavai@Sun.COM /*
9829815SRishi.Srivatsavai@Sun.COM * Returns matching multicast address enabled on the simnet instance.
9839815SRishi.Srivatsavai@Sun.COM * Assumes simnet instance mutex lock is held.
9849815SRishi.Srivatsavai@Sun.COM */
9859815SRishi.Srivatsavai@Sun.COM static uint8_t *
mcastaddr_lookup(simnet_dev_t * sdev,const uint8_t * addrp)9869815SRishi.Srivatsavai@Sun.COM mcastaddr_lookup(simnet_dev_t *sdev, const uint8_t *addrp)
9879815SRishi.Srivatsavai@Sun.COM {
9889815SRishi.Srivatsavai@Sun.COM int idx;
9899815SRishi.Srivatsavai@Sun.COM uint8_t *maddrptr;
9909815SRishi.Srivatsavai@Sun.COM
99110416SRishi.Srivatsavai@Sun.COM ASSERT(MUTEX_HELD(&sdev->sd_instlock));
9929815SRishi.Srivatsavai@Sun.COM maddrptr = sdev->sd_mcastaddrs;
9939815SRishi.Srivatsavai@Sun.COM for (idx = 0; idx < sdev->sd_mcastaddr_count; idx++) {
9949815SRishi.Srivatsavai@Sun.COM if (bcmp(maddrptr, addrp, ETHERADDRL) == 0)
9959815SRishi.Srivatsavai@Sun.COM return (maddrptr);
9969815SRishi.Srivatsavai@Sun.COM maddrptr += ETHERADDRL;
9979815SRishi.Srivatsavai@Sun.COM }
9989815SRishi.Srivatsavai@Sun.COM
9999815SRishi.Srivatsavai@Sun.COM return (NULL);
10009815SRishi.Srivatsavai@Sun.COM }
10019815SRishi.Srivatsavai@Sun.COM
10029815SRishi.Srivatsavai@Sun.COM /* Add or remove Multicast addresses on simnet instance */
10039815SRishi.Srivatsavai@Sun.COM static int
simnet_m_multicst(void * arg,boolean_t add,const uint8_t * addrp)10049815SRishi.Srivatsavai@Sun.COM simnet_m_multicst(void *arg, boolean_t add, const uint8_t *addrp)
10059815SRishi.Srivatsavai@Sun.COM {
10069815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
10079815SRishi.Srivatsavai@Sun.COM uint8_t *maddrptr;
10089815SRishi.Srivatsavai@Sun.COM uint8_t *newbuf;
10099815SRishi.Srivatsavai@Sun.COM size_t prevsize;
10109815SRishi.Srivatsavai@Sun.COM size_t newsize;
10119815SRishi.Srivatsavai@Sun.COM ptrdiff_t len;
10129815SRishi.Srivatsavai@Sun.COM ptrdiff_t len2;
10139815SRishi.Srivatsavai@Sun.COM
10149815SRishi.Srivatsavai@Sun.COM alloc_retry:
10159815SRishi.Srivatsavai@Sun.COM prevsize = sdev->sd_mcastaddr_count * ETHERADDRL;
10169815SRishi.Srivatsavai@Sun.COM newsize = prevsize + (add ? ETHERADDRL:-ETHERADDRL);
10179815SRishi.Srivatsavai@Sun.COM newbuf = kmem_alloc(newsize, KM_SLEEP);
10189815SRishi.Srivatsavai@Sun.COM
10199815SRishi.Srivatsavai@Sun.COM mutex_enter(&sdev->sd_instlock);
10209815SRishi.Srivatsavai@Sun.COM if (prevsize != (sdev->sd_mcastaddr_count * ETHERADDRL)) {
10219815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
10229815SRishi.Srivatsavai@Sun.COM kmem_free(newbuf, newsize);
10239815SRishi.Srivatsavai@Sun.COM goto alloc_retry;
10249815SRishi.Srivatsavai@Sun.COM }
10259815SRishi.Srivatsavai@Sun.COM
10269815SRishi.Srivatsavai@Sun.COM maddrptr = mcastaddr_lookup(sdev, addrp);
10279815SRishi.Srivatsavai@Sun.COM if (!add && maddrptr != NULL) {
10289815SRishi.Srivatsavai@Sun.COM /* Removing a Multicast address */
10299815SRishi.Srivatsavai@Sun.COM if (newbuf != NULL) {
10309815SRishi.Srivatsavai@Sun.COM /* LINTED: E_PTRDIFF_OVERFLOW */
10319815SRishi.Srivatsavai@Sun.COM len = maddrptr - sdev->sd_mcastaddrs;
10329815SRishi.Srivatsavai@Sun.COM (void) memcpy(newbuf, sdev->sd_mcastaddrs, len);
10339815SRishi.Srivatsavai@Sun.COM len2 = prevsize - len - ETHERADDRL;
10349815SRishi.Srivatsavai@Sun.COM (void) memcpy(newbuf + len,
10359815SRishi.Srivatsavai@Sun.COM maddrptr + ETHERADDRL, len2);
10369815SRishi.Srivatsavai@Sun.COM }
10379815SRishi.Srivatsavai@Sun.COM sdev->sd_mcastaddr_count--;
10389815SRishi.Srivatsavai@Sun.COM } else if (add && maddrptr == NULL) {
10399815SRishi.Srivatsavai@Sun.COM /* Adding a new Multicast address */
10409815SRishi.Srivatsavai@Sun.COM (void) memcpy(newbuf, sdev->sd_mcastaddrs, prevsize);
10419815SRishi.Srivatsavai@Sun.COM (void) memcpy(newbuf + prevsize, addrp, ETHERADDRL);
10429815SRishi.Srivatsavai@Sun.COM sdev->sd_mcastaddr_count++;
10439815SRishi.Srivatsavai@Sun.COM } else {
10449815SRishi.Srivatsavai@Sun.COM /* Error: removing a non-existing Multicast address */
10459815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
10469815SRishi.Srivatsavai@Sun.COM kmem_free(newbuf, newsize);
10479815SRishi.Srivatsavai@Sun.COM cmn_err(CE_WARN, "simnet: MAC call to remove a "
10489815SRishi.Srivatsavai@Sun.COM "Multicast address failed");
10499815SRishi.Srivatsavai@Sun.COM return (EINVAL);
10509815SRishi.Srivatsavai@Sun.COM }
10519815SRishi.Srivatsavai@Sun.COM
10529815SRishi.Srivatsavai@Sun.COM kmem_free(sdev->sd_mcastaddrs, prevsize);
10539815SRishi.Srivatsavai@Sun.COM sdev->sd_mcastaddrs = newbuf;
10549815SRishi.Srivatsavai@Sun.COM mutex_exit(&sdev->sd_instlock);
10559815SRishi.Srivatsavai@Sun.COM return (0);
10569815SRishi.Srivatsavai@Sun.COM }
10579815SRishi.Srivatsavai@Sun.COM
10589815SRishi.Srivatsavai@Sun.COM static int
simnet_m_unicst(void * arg,const uint8_t * macaddr)10599815SRishi.Srivatsavai@Sun.COM simnet_m_unicst(void *arg, const uint8_t *macaddr)
10609815SRishi.Srivatsavai@Sun.COM {
10619815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
10629815SRishi.Srivatsavai@Sun.COM
10639815SRishi.Srivatsavai@Sun.COM (void) memcpy(sdev->sd_mac_addr, macaddr, ETHERADDRL);
10649815SRishi.Srivatsavai@Sun.COM return (0);
10659815SRishi.Srivatsavai@Sun.COM }
10669815SRishi.Srivatsavai@Sun.COM
10679815SRishi.Srivatsavai@Sun.COM /* Parse WiFi scan list entry arguments and return the arg count */
10689815SRishi.Srivatsavai@Sun.COM static int
parse_esslist_args(const void * pr_val,uint_t pr_valsize,char args[][MAX_ESSLIST_ARGLEN])10699815SRishi.Srivatsavai@Sun.COM parse_esslist_args(const void *pr_val, uint_t pr_valsize,
10709815SRishi.Srivatsavai@Sun.COM char args[][MAX_ESSLIST_ARGLEN])
10719815SRishi.Srivatsavai@Sun.COM {
10729815SRishi.Srivatsavai@Sun.COM char *sep;
10739815SRishi.Srivatsavai@Sun.COM ptrdiff_t len = pr_valsize;
10749815SRishi.Srivatsavai@Sun.COM const char *piece = pr_val;
10759815SRishi.Srivatsavai@Sun.COM const char *end = (const char *)pr_val + pr_valsize - 1;
10769815SRishi.Srivatsavai@Sun.COM int arg = 0;
10779815SRishi.Srivatsavai@Sun.COM
10789815SRishi.Srivatsavai@Sun.COM while (piece < end && (arg < MAX_ESSLIST_ARGS)) {
10799815SRishi.Srivatsavai@Sun.COM sep = strchr(piece, ',');
10809815SRishi.Srivatsavai@Sun.COM if (sep == NULL)
10819815SRishi.Srivatsavai@Sun.COM sep = (char *)end;
10829815SRishi.Srivatsavai@Sun.COM /* LINTED E_PTRDIFF_OVERFLOW */
10839815SRishi.Srivatsavai@Sun.COM len = sep - piece;
10849815SRishi.Srivatsavai@Sun.COM /* If first arg is zero then return none to delete all */
10859815SRishi.Srivatsavai@Sun.COM if (arg == 0 && strnlen(piece, len) == 1 && piece[0] == '0')
10869815SRishi.Srivatsavai@Sun.COM return (0);
10879815SRishi.Srivatsavai@Sun.COM if (len > MAX_ESSLIST_ARGLEN)
10889815SRishi.Srivatsavai@Sun.COM len = MAX_ESSLIST_ARGLEN - 1;
10899815SRishi.Srivatsavai@Sun.COM (void) memcpy(&args[arg][0], piece, len);
10909815SRishi.Srivatsavai@Sun.COM args[arg][len] = '\0';
10919815SRishi.Srivatsavai@Sun.COM piece = sep + 1;
10929815SRishi.Srivatsavai@Sun.COM arg++;
10939815SRishi.Srivatsavai@Sun.COM }
10949815SRishi.Srivatsavai@Sun.COM
10959815SRishi.Srivatsavai@Sun.COM return (arg);
10969815SRishi.Srivatsavai@Sun.COM }
10979815SRishi.Srivatsavai@Sun.COM
10989815SRishi.Srivatsavai@Sun.COM /* Set WiFi scan list entry from private property _wl_esslist */
10999815SRishi.Srivatsavai@Sun.COM static int
set_wl_esslist_priv_prop(simnet_wifidev_t * wdev,uint_t pr_valsize,const void * pr_val)11009815SRishi.Srivatsavai@Sun.COM set_wl_esslist_priv_prop(simnet_wifidev_t *wdev, uint_t pr_valsize,
11019815SRishi.Srivatsavai@Sun.COM const void *pr_val)
11029815SRishi.Srivatsavai@Sun.COM {
11039815SRishi.Srivatsavai@Sun.COM char essargs[MAX_ESSLIST_ARGS][MAX_ESSLIST_ARGLEN];
11049815SRishi.Srivatsavai@Sun.COM wl_ess_conf_t *wls;
11059815SRishi.Srivatsavai@Sun.COM long result;
11069815SRishi.Srivatsavai@Sun.COM int i;
11079815SRishi.Srivatsavai@Sun.COM
11089815SRishi.Srivatsavai@Sun.COM bzero(essargs, sizeof (essargs));
11099815SRishi.Srivatsavai@Sun.COM if (parse_esslist_args(pr_val, pr_valsize, essargs) == 0) {
11109815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) {
11119815SRishi.Srivatsavai@Sun.COM kmem_free(wdev->swd_esslist[i], sizeof (wl_ess_conf_t));
11129815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist[i] = NULL;
11139815SRishi.Srivatsavai@Sun.COM }
11149815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist_num = 0;
11159815SRishi.Srivatsavai@Sun.COM return (0);
11169815SRishi.Srivatsavai@Sun.COM }
11179815SRishi.Srivatsavai@Sun.COM
11189815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) {
11199815SRishi.Srivatsavai@Sun.COM wls = wdev->swd_esslist[i];
11209815SRishi.Srivatsavai@Sun.COM if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid,
11219815SRishi.Srivatsavai@Sun.COM essargs[0]) == 0)
11229815SRishi.Srivatsavai@Sun.COM return (EEXIST);
11239815SRishi.Srivatsavai@Sun.COM }
11249815SRishi.Srivatsavai@Sun.COM
11259815SRishi.Srivatsavai@Sun.COM if (wdev->swd_esslist_num >= MAX_SIMNET_ESSCONF)
11269815SRishi.Srivatsavai@Sun.COM return (EINVAL);
11279815SRishi.Srivatsavai@Sun.COM
11289815SRishi.Srivatsavai@Sun.COM wls = kmem_zalloc(sizeof (wl_ess_conf_t), KM_SLEEP);
11299815SRishi.Srivatsavai@Sun.COM (void) strlcpy(wls->wl_ess_conf_essid.wl_essid_essid,
11309815SRishi.Srivatsavai@Sun.COM essargs[0], sizeof (wls->wl_ess_conf_essid.wl_essid_essid));
11319815SRishi.Srivatsavai@Sun.COM wls->wl_ess_conf_essid.wl_essid_length =
11329815SRishi.Srivatsavai@Sun.COM strlen(wls->wl_ess_conf_essid.wl_essid_essid);
11339815SRishi.Srivatsavai@Sun.COM (void) random_get_pseudo_bytes((uint8_t *)
11349815SRishi.Srivatsavai@Sun.COM &wls->wl_ess_conf_bssid, sizeof (wl_bssid_t));
11359815SRishi.Srivatsavai@Sun.COM (void) ddi_strtol(essargs[1], (char **)NULL, 0, &result);
11369815SRishi.Srivatsavai@Sun.COM wls->wl_ess_conf_sl = (wl_rssi_t)
11379815SRishi.Srivatsavai@Sun.COM ((result > MAX_RSSI || result < 0) ? 0:result);
11389815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist[wdev->swd_esslist_num] = wls;
11399815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist_num++;
11409815SRishi.Srivatsavai@Sun.COM
11419815SRishi.Srivatsavai@Sun.COM return (0);
11429815SRishi.Srivatsavai@Sun.COM }
11439815SRishi.Srivatsavai@Sun.COM
11449815SRishi.Srivatsavai@Sun.COM static int
simnet_set_priv_prop(simnet_dev_t * sdev,const char * pr_name,uint_t pr_valsize,const void * pr_val)11459815SRishi.Srivatsavai@Sun.COM simnet_set_priv_prop(simnet_dev_t *sdev, const char *pr_name,
11469815SRishi.Srivatsavai@Sun.COM uint_t pr_valsize, const void *pr_val)
11479815SRishi.Srivatsavai@Sun.COM {
11489815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev;
11499815SRishi.Srivatsavai@Sun.COM long result;
11509815SRishi.Srivatsavai@Sun.COM
11519815SRishi.Srivatsavai@Sun.COM if (strcmp(pr_name, "_wl_esslist") == 0) {
11529815SRishi.Srivatsavai@Sun.COM if (pr_val == NULL)
11539815SRishi.Srivatsavai@Sun.COM return (EINVAL);
11549815SRishi.Srivatsavai@Sun.COM return (set_wl_esslist_priv_prop(wdev, pr_valsize, pr_val));
11559815SRishi.Srivatsavai@Sun.COM } else if (strcmp(pr_name, "_wl_connected") == 0) {
11569815SRishi.Srivatsavai@Sun.COM if (pr_val == NULL)
11579815SRishi.Srivatsavai@Sun.COM return (EINVAL);
11589815SRishi.Srivatsavai@Sun.COM (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
11599815SRishi.Srivatsavai@Sun.COM wdev->swd_linkstatus = ((result == 1) ?
11609815SRishi.Srivatsavai@Sun.COM WL_CONNECTED:WL_NOTCONNECTED);
11619815SRishi.Srivatsavai@Sun.COM return (0);
11629815SRishi.Srivatsavai@Sun.COM }
11639815SRishi.Srivatsavai@Sun.COM
11649815SRishi.Srivatsavai@Sun.COM return (EINVAL);
11659815SRishi.Srivatsavai@Sun.COM }
11669815SRishi.Srivatsavai@Sun.COM
11679815SRishi.Srivatsavai@Sun.COM static int
simnet_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)11689815SRishi.Srivatsavai@Sun.COM simnet_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
11699815SRishi.Srivatsavai@Sun.COM uint_t wldp_length, const void *wldp_buf)
11709815SRishi.Srivatsavai@Sun.COM {
11719815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
11729815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev;
11739815SRishi.Srivatsavai@Sun.COM int err = 0;
11749815SRishi.Srivatsavai@Sun.COM uint32_t mtu;
11759815SRishi.Srivatsavai@Sun.COM
11769815SRishi.Srivatsavai@Sun.COM switch (wldp_pr_num) {
11779815SRishi.Srivatsavai@Sun.COM case MAC_PROP_MTU:
11789815SRishi.Srivatsavai@Sun.COM (void) memcpy(&mtu, wldp_buf, sizeof (mtu));
11799815SRishi.Srivatsavai@Sun.COM if (mtu > ETHERMIN && mtu < SIMNET_MAX_MTU)
11809815SRishi.Srivatsavai@Sun.COM return (mac_maxsdu_update(sdev->sd_mh, mtu));
11819815SRishi.Srivatsavai@Sun.COM else
11829815SRishi.Srivatsavai@Sun.COM return (EINVAL);
11839815SRishi.Srivatsavai@Sun.COM default:
11849815SRishi.Srivatsavai@Sun.COM break;
11859815SRishi.Srivatsavai@Sun.COM }
11869815SRishi.Srivatsavai@Sun.COM
11879815SRishi.Srivatsavai@Sun.COM if (sdev->sd_type == DL_ETHER)
11889815SRishi.Srivatsavai@Sun.COM return (ENOTSUP);
11899815SRishi.Srivatsavai@Sun.COM
11909815SRishi.Srivatsavai@Sun.COM /* mac_prop_id */
11919815SRishi.Srivatsavai@Sun.COM switch (wldp_pr_num) {
11929815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ESSID: {
11939815SRishi.Srivatsavai@Sun.COM int i;
11949815SRishi.Srivatsavai@Sun.COM wl_ess_conf_t *wls;
11959815SRishi.Srivatsavai@Sun.COM
11969815SRishi.Srivatsavai@Sun.COM (void) memcpy(&wdev->swd_essid, wldp_buf,
11979815SRishi.Srivatsavai@Sun.COM sizeof (wl_essid_t));
11989815SRishi.Srivatsavai@Sun.COM wdev->swd_linkstatus = WL_CONNECTED;
11999815SRishi.Srivatsavai@Sun.COM
12009815SRishi.Srivatsavai@Sun.COM /* Lookup the signal strength of the connected ESSID */
12019815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) {
12029815SRishi.Srivatsavai@Sun.COM wls = wdev->swd_esslist[i];
12039815SRishi.Srivatsavai@Sun.COM if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid,
12049815SRishi.Srivatsavai@Sun.COM wdev->swd_essid.wl_essid_essid) == 0) {
12059815SRishi.Srivatsavai@Sun.COM wdev->swd_rssi = wls->wl_ess_conf_sl;
12069815SRishi.Srivatsavai@Sun.COM break;
12079815SRishi.Srivatsavai@Sun.COM }
12089815SRishi.Srivatsavai@Sun.COM }
12099815SRishi.Srivatsavai@Sun.COM break;
12109815SRishi.Srivatsavai@Sun.COM }
12119815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_BSSID: {
12129815SRishi.Srivatsavai@Sun.COM (void) memcpy(&wdev->swd_bssid, wldp_buf,
12139815SRishi.Srivatsavai@Sun.COM sizeof (wl_bssid_t));
12149815SRishi.Srivatsavai@Sun.COM break;
12159815SRishi.Srivatsavai@Sun.COM }
12169815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_PHY_CONFIG:
12179815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_KEY_TAB:
12189815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_AUTH_MODE:
12199815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ENCRYPTION:
12209815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_BSSTYPE:
12219815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_DESIRED_RATES:
12229815SRishi.Srivatsavai@Sun.COM break;
12239815SRishi.Srivatsavai@Sun.COM case MAC_PROP_PRIVATE:
12249815SRishi.Srivatsavai@Sun.COM err = simnet_set_priv_prop(sdev, pr_name,
12259815SRishi.Srivatsavai@Sun.COM wldp_length, wldp_buf);
12269815SRishi.Srivatsavai@Sun.COM break;
12279815SRishi.Srivatsavai@Sun.COM default:
12289815SRishi.Srivatsavai@Sun.COM break;
12299815SRishi.Srivatsavai@Sun.COM }
12309815SRishi.Srivatsavai@Sun.COM
12319815SRishi.Srivatsavai@Sun.COM return (err);
12329815SRishi.Srivatsavai@Sun.COM }
12339815SRishi.Srivatsavai@Sun.COM
12349815SRishi.Srivatsavai@Sun.COM static int
simnet_get_priv_prop(simnet_dev_t * sdev,const char * pr_name,uint_t pr_valsize,void * pr_val)1235*11878SVenu.Iyer@Sun.COM simnet_get_priv_prop(simnet_dev_t *sdev, const char *pr_name,
12369815SRishi.Srivatsavai@Sun.COM uint_t pr_valsize, void *pr_val)
12379815SRishi.Srivatsavai@Sun.COM {
12389815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev;
12399815SRishi.Srivatsavai@Sun.COM int err = 0;
12409815SRishi.Srivatsavai@Sun.COM int value;
12419815SRishi.Srivatsavai@Sun.COM
12429815SRishi.Srivatsavai@Sun.COM if (strcmp(pr_name, "_wl_esslist") == 0) {
12439815SRishi.Srivatsavai@Sun.COM /* Returns num of _wl_ess_conf_t that have been set */
1244*11878SVenu.Iyer@Sun.COM value = wdev->swd_esslist_num;
12459815SRishi.Srivatsavai@Sun.COM } else if (strcmp(pr_name, "_wl_connected") == 0) {
12469815SRishi.Srivatsavai@Sun.COM value = ((wdev->swd_linkstatus == WL_CONNECTED) ? 1:0);
12479815SRishi.Srivatsavai@Sun.COM } else {
12489815SRishi.Srivatsavai@Sun.COM err = ENOTSUP;
12499815SRishi.Srivatsavai@Sun.COM }
12509815SRishi.Srivatsavai@Sun.COM
12519815SRishi.Srivatsavai@Sun.COM if (err == 0)
12529815SRishi.Srivatsavai@Sun.COM (void) snprintf(pr_val, pr_valsize, "%d", value);
12539815SRishi.Srivatsavai@Sun.COM return (err);
12549815SRishi.Srivatsavai@Sun.COM }
12559815SRishi.Srivatsavai@Sun.COM
12569815SRishi.Srivatsavai@Sun.COM static int
simnet_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)12579815SRishi.Srivatsavai@Sun.COM simnet_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
1258*11878SVenu.Iyer@Sun.COM uint_t wldp_length, void *wldp_buf)
12599815SRishi.Srivatsavai@Sun.COM {
12609815SRishi.Srivatsavai@Sun.COM simnet_dev_t *sdev = arg;
12619815SRishi.Srivatsavai@Sun.COM simnet_wifidev_t *wdev = sdev->sd_wifidev;
12629815SRishi.Srivatsavai@Sun.COM int err = 0;
12639815SRishi.Srivatsavai@Sun.COM int i;
12649815SRishi.Srivatsavai@Sun.COM
12659815SRishi.Srivatsavai@Sun.COM if (sdev->sd_type == DL_ETHER)
12669815SRishi.Srivatsavai@Sun.COM return (ENOTSUP);
12679815SRishi.Srivatsavai@Sun.COM
12689815SRishi.Srivatsavai@Sun.COM /* mac_prop_id */
12699815SRishi.Srivatsavai@Sun.COM switch (wldp_pr_num) {
12709815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ESSID:
12719815SRishi.Srivatsavai@Sun.COM (void) memcpy(wldp_buf, &wdev->swd_essid,
12729815SRishi.Srivatsavai@Sun.COM sizeof (wl_essid_t));
12739815SRishi.Srivatsavai@Sun.COM break;
12749815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_BSSID:
12759815SRishi.Srivatsavai@Sun.COM (void) memcpy(wldp_buf, &wdev->swd_bssid,
12769815SRishi.Srivatsavai@Sun.COM sizeof (wl_bssid_t));
12779815SRishi.Srivatsavai@Sun.COM break;
12789815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_PHY_CONFIG:
12799815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_AUTH_MODE:
12809815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ENCRYPTION:
12819815SRishi.Srivatsavai@Sun.COM break;
12829815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_LINKSTATUS:
12839815SRishi.Srivatsavai@Sun.COM (void) memcpy(wldp_buf, &wdev->swd_linkstatus,
12849815SRishi.Srivatsavai@Sun.COM sizeof (wdev->swd_linkstatus));
12859815SRishi.Srivatsavai@Sun.COM break;
12869815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_ESS_LIST: {
12879815SRishi.Srivatsavai@Sun.COM wl_ess_conf_t *w_ess_conf;
12889815SRishi.Srivatsavai@Sun.COM
12899815SRishi.Srivatsavai@Sun.COM ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
12909815SRishi.Srivatsavai@Sun.COM wdev->swd_esslist_num;
12919815SRishi.Srivatsavai@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */
12929815SRishi.Srivatsavai@Sun.COM w_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
12939815SRishi.Srivatsavai@Sun.COM offsetof(wl_ess_list_t, wl_ess_list_ess));
12949815SRishi.Srivatsavai@Sun.COM for (i = 0; i < wdev->swd_esslist_num; i++) {
12959815SRishi.Srivatsavai@Sun.COM (void) memcpy(w_ess_conf, wdev->swd_esslist[i],
12969815SRishi.Srivatsavai@Sun.COM sizeof (wl_ess_conf_t));
12979815SRishi.Srivatsavai@Sun.COM w_ess_conf++;
12989815SRishi.Srivatsavai@Sun.COM }
12999815SRishi.Srivatsavai@Sun.COM break;
13009815SRishi.Srivatsavai@Sun.COM }
13019815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_RSSI:
13029815SRishi.Srivatsavai@Sun.COM *(wl_rssi_t *)wldp_buf = wdev->swd_rssi;
13039815SRishi.Srivatsavai@Sun.COM break;
13049815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_RADIO:
13059815SRishi.Srivatsavai@Sun.COM *(wl_radio_t *)wldp_buf = B_TRUE;
13069815SRishi.Srivatsavai@Sun.COM break;
13079815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_POWER_MODE:
13089815SRishi.Srivatsavai@Sun.COM break;
13099815SRishi.Srivatsavai@Sun.COM case MAC_PROP_WL_DESIRED_RATES:
13109815SRishi.Srivatsavai@Sun.COM break;
13119815SRishi.Srivatsavai@Sun.COM case MAC_PROP_PRIVATE:
1312*11878SVenu.Iyer@Sun.COM err = simnet_get_priv_prop(sdev, pr_name, wldp_length,
1313*11878SVenu.Iyer@Sun.COM wldp_buf);
13149815SRishi.Srivatsavai@Sun.COM break;
13159815SRishi.Srivatsavai@Sun.COM default:
13169815SRishi.Srivatsavai@Sun.COM err = ENOTSUP;
13179815SRishi.Srivatsavai@Sun.COM break;
13189815SRishi.Srivatsavai@Sun.COM }
13199815SRishi.Srivatsavai@Sun.COM
13209815SRishi.Srivatsavai@Sun.COM return (err);
13219815SRishi.Srivatsavai@Sun.COM }
1322*11878SVenu.Iyer@Sun.COM
1323*11878SVenu.Iyer@Sun.COM static void
simnet_priv_propinfo(const char * pr_name,mac_prop_info_handle_t prh)1324*11878SVenu.Iyer@Sun.COM simnet_priv_propinfo(const char *pr_name, mac_prop_info_handle_t prh)
1325*11878SVenu.Iyer@Sun.COM {
1326*11878SVenu.Iyer@Sun.COM char valstr[MAXNAMELEN];
1327*11878SVenu.Iyer@Sun.COM
1328*11878SVenu.Iyer@Sun.COM bzero(valstr, sizeof (valstr));
1329*11878SVenu.Iyer@Sun.COM
1330*11878SVenu.Iyer@Sun.COM if (strcmp(pr_name, "_wl_esslist") == 0) {
1331*11878SVenu.Iyer@Sun.COM (void) snprintf(valstr, sizeof (valstr), "%d", 0);
1332*11878SVenu.Iyer@Sun.COM }
1333*11878SVenu.Iyer@Sun.COM
1334*11878SVenu.Iyer@Sun.COM if (strlen(valstr) > 0)
1335*11878SVenu.Iyer@Sun.COM mac_prop_info_set_default_str(prh, valstr);
1336*11878SVenu.Iyer@Sun.COM }
1337*11878SVenu.Iyer@Sun.COM
1338*11878SVenu.Iyer@Sun.COM static void
simnet_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t prh)1339*11878SVenu.Iyer@Sun.COM simnet_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
1340*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t prh)
1341*11878SVenu.Iyer@Sun.COM {
1342*11878SVenu.Iyer@Sun.COM simnet_dev_t *sdev = arg;
1343*11878SVenu.Iyer@Sun.COM
1344*11878SVenu.Iyer@Sun.COM if (sdev->sd_type == DL_ETHER)
1345*11878SVenu.Iyer@Sun.COM return;
1346*11878SVenu.Iyer@Sun.COM
1347*11878SVenu.Iyer@Sun.COM switch (wldp_pr_num) {
1348*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_BSSTYPE:
1349*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_ESS_LIST:
1350*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_SUPPORTED_RATES:
1351*11878SVenu.Iyer@Sun.COM case MAC_PROP_WL_RSSI:
1352*11878SVenu.Iyer@Sun.COM mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1353*11878SVenu.Iyer@Sun.COM break;
1354*11878SVenu.Iyer@Sun.COM case MAC_PROP_PRIVATE:
1355*11878SVenu.Iyer@Sun.COM simnet_priv_propinfo(pr_name, prh);
1356*11878SVenu.Iyer@Sun.COM break;
1357*11878SVenu.Iyer@Sun.COM }
1358*11878SVenu.Iyer@Sun.COM }
1359