b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * CDDL HEADER START
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * The contents of this file are subject to the terms of the
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * Common Development and Distribution License (the "License").
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * You may not use this file except in compliance with the License.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * or http://www.opensolaris.org/os/licensing.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * See the License for the specific language governing permissions
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * and limitations under the License.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * When distributing Covered Code, include this CDDL HEADER in each
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * If applicable, add the following below this CDDL HEADER, with the
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * fields enclosed by brackets "[]" replaced with your own identifying
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * information: Portions Copyright [yyyy] [name of copyright owner]
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * CDDL HEADER END
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * Use is subject to license terms.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * Simulated network device (simnet) driver: simulates a pseudo GLDv3 network
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * device. Can simulate an Ethernet or WiFi network device. In addition, another
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * simnet instance can be attached as a peer to create a point-to-point link on
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * the same system.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai#define SIMNETINFO "Simulated Network Driver"
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_attach(dev_info_t *, ddi_attach_cmd_t);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_detach(dev_info_t *, ddi_detach_cmd_t);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_ioc_create(void *, intptr_t, int, cred_t *, int *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_ioc_delete(void *, intptr_t, int, cred_t *, int *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_ioc_info(void *, intptr_t, int, cred_t *, int *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_ioc_modify(void *, intptr_t, int, cred_t *, int *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic uint8_t *mcastaddr_lookup(simnet_dev_t *, const uint8_t *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic dld_ioc_info_t simnet_ioc_list[] = {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai {SIMNET_IOC_CREATE, DLDCOPYINOUT, sizeof (simnet_ioc_create_t),
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai {SIMNET_IOC_DELETE, DLDCOPYIN, sizeof (simnet_ioc_delete_t),
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai {SIMNET_IOC_INFO, DLDCOPYINOUT, sizeof (simnet_ioc_info_t),
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai {SIMNET_IOC_MODIFY, DLDCOPYIN, sizeof (simnet_ioc_modify_t),
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi SrivatsavaiDDI_DEFINE_STREAM_OPS(simnet_dev_ops, nulldev, nulldev, simnet_attach,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai simnet_detach, nodev, simnet_getinfo, D_MP, NULL,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai &mod_driverops, /* Type of module. This one is a driver */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai/* MAC callback function declarations */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_m_start(void *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic void simnet_m_stop(void *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_m_promisc(void *, boolean_t);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_m_multicst(void *, boolean_t, const uint8_t *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_m_unicst(void *, const uint8_t *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_m_stat(void *, uint_t, uint64_t *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic void simnet_m_ioctl(void *, queue_t *, mblk_t *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic mblk_t *simnet_m_tx(void *, mblk_t *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_m_setprop(void *, const char *, mac_prop_id_t,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai uint_t, const void *);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_m_getprop(void *, const char *, mac_prop_id_t,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyerstatic void simnet_m_propinfo(void *, const char *, mac_prop_id_t,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic mac_callbacks_t simnet_m_callbacks = {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer (MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO),
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * simnet_dev_lock protects the simnet device list.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * sd_instlock in each simnet_dev_t protects access to
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * a single simnet_dev_t.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaistatic int simnet_count; /* Num of simnet instances */
0f83d385c54b2d67790eb5ee77344de60f0966c8Rishi Srivatsavai if ((simnet_rxq = ddi_taskq_create(simnet_dip, "simnet", 1,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai rw_init(&simnet_dev_lock, NULL, RW_DEFAULT, NULL);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai list_create(&simnet_dev_list, sizeof (simnet_dev_t),
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* we only allow instance 0 to attach */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (dld_ioc_register(SIMNET_IOC, simnet_ioc_list,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * Allow the simnet instance to be detached only if there
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * are no simnets configured.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai/* Caller must hold simnet_dev_lock */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai for (sdev = list_head(&simnet_dev_list); sdev != NULL;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai sdev = list_next(&simnet_dev_list, sdev)) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai simnet_wifidev_t *wdev = sdev->sd_wifidev;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai for (i = 0; i < wdev->swd_esslist_num; i++) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai kmem_free(wdev, sizeof (simnet_wifidev_t));
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (atomic_dec_32_nv(&sdev->sd_refcount) != 0)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai kmem_free(sdev->sd_mcastaddrs, ETHERADDRL * sdev->sd_mcastaddr_count);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_init_wifi(simnet_dev_t *sdev, mac_register_t *mac)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai sdev->sd_wifidev = kmem_zalloc(sizeof (simnet_wifidev_t), KM_NOSLEEP);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai sdev->sd_wifidev->swd_linkstatus = WL_NOTCONNECTED;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai mac->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_init_ether(simnet_dev_t *sdev, mac_register_t *mac)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if ((mac = mac_alloc(MAC_VERSION)) == NULL)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai sdev = kmem_zalloc(sizeof (*sdev), KM_NOSLEEP);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if ((sdev_tmp = simnet_dev_lookup(create_arg->sic_link_id)) != NULL) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai sdev->sd_link_id = create_arg->sic_link_id;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai mutex_init(&sdev->sd_instlock, NULL, MUTEX_DRIVER, NULL);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai cv_init(&sdev->sd_threadwait, NULL, CV_DRIVER, NULL);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Simnets created from configuration on boot pass saved MAC address */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Generate random MAC address */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) random_get_pseudo_bytes(sdev->sd_mac_addr, ETHERADDRL);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Ensure MAC address is not multicast and is local */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai sdev->sd_mac_addr[0] = (sdev->sd_mac_addr[0] & ~1) | 2;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(sdev->sd_mac_addr, create_arg->sic_mac_addr,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai sdev->sd_mac_len = create_arg->sic_mac_len;
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if ((err = dls_devnet_create(sdev->sd_mh, sdev->sd_link_id,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai mac_link_update(sdev->sd_mh, LINK_STATE_UP);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Always return MAC address back to caller */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(create_arg->sic_mac_addr, sdev->sd_mac_addr,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai create_arg->sic_mac_len = sdev->sd_mac_len;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai/* Caller must hold writer simnet_dev_lock */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai datalink_id_t peer_link_id = DATALINK_INVALID_LINKID;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if ((sdev_peer = sdev->sd_peer_dev) != NULL) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Release previous references held on both simnets */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if ((sdev = simnet_dev_lookup(modify_arg->sim_link_id)) == NULL) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (sdev->sd_link_id == modify_arg->sim_peer_link_id) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Cannot peer with self */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (sdev->sd_peer_dev != NULL && sdev->sd_peer_dev->sd_link_id ==
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Nothing to modify */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (modify_arg->sim_peer_link_id != DATALINK_INVALID_LINKID) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy sdev_peer = simnet_dev_lookup(modify_arg->sim_peer_link_id);
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Peer simnet device not available */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (sdev_peer->sd_zoneid != sdev->sd_zoneid) {
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* The two peers must be in the same zone (for now). */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* First remove any previous peer */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Remove any previous peer of sdev_peer */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Update both devices with the new peer */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Hold references on both devices */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Release sdev lookup reference */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if ((sdev = simnet_dev_lookup(delete_arg->sid_link_id)) == NULL) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if ((err = dls_devnet_destroy(sdev->sd_mh, &tmpid, B_TRUE)) != 0) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Remove any attached peer link */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Prevent new threads from using the instance */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Wait until all active threads using the instance exit */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Signaled */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Try disabling the MAC */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if ((err = mac_disable(sdev->sd_mh)) != 0)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai simnet_dev_unref(sdev); /* Release lookup ref */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Releasing the last ref performs sdev/mem free */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Re-create simnet instance and add any previous peer */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy (void) dls_devnet_create(sdev->sd_mh, sdev->sd_link_id,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai ((sdev_peer = simnet_dev_lookup(peerid)) != NULL)) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Attach peer device back */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Hold reference on both devices */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * No previous peer or previous peer no longer
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * available so release lookup reference.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp)
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy /* Make sure that the simnet link is visible from the caller's zone. */
2b24ab6b3865caeede9eeb9db6b83e1d89dcd1eaSebastien Roy if (!dls_devnet_islinkvisible(info_arg->sii_link_id, crgetzoneid(cred)))
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if ((sdev = simnet_dev_lookup(info_arg->sii_link_id)) == NULL) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(info_arg->sii_mac_addr, sdev->sd_mac_addr,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai info_arg->sii_peer_link_id = sdev->sd_peer_dev->sd_link_id;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Check for valid packet header */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (mac_header_info(sdev->sd_mh, mp, &hdr_info) != 0) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * When we are NOT in promiscuous mode we only receive
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * unicast packets addressed to us and multicast packets that
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * MAC clients have requested.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai hdr_info.mhi_dsttype != MAC_ADDRTYPE_BROADCAST) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_UNICAST &&
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai bcmp(hdr_info.mhi_daddr, sdev->sd_mac_addr,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai } else if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (mcastaddr_lookup(sdev, hdr_info.mhi_daddr) ==
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if ((sdev_rx = sdev->sd_peer_dev) == NULL) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Discard packets when no peer exists */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * Discard packets when either device is shutting down or not ready.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * Though MAC layer ensures a reference is held on the MAC while we
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * process the packet chain, there is no guarantee the peer MAC will
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * remain enabled. So we increment per-instance threadcount to ensure
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * either MAC instance is not disabled while we handle the chain of
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * packets. It is okay if the peer device is disconnected while we are
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * here since we lookup the peer device while holding simnet_dev_lock
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * (reader lock) and increment the threadcount of the peer, the peer
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * MAC cannot be disabled in simnet_ioc_delete.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Pad packet to minimum Ethernet frame size */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Pullup packet into a single mblk */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Fix mblk checksum as the pkt dest is local */
0f83d385c54b2d67790eb5ee77344de60f0966c8Rishi Srivatsavai /* Hold reference for taskq receive processing per-pkt */
0f83d385c54b2d67790eb5ee77344de60f0966c8Rishi Srivatsavai /* Use taskq for pkt receive to avoid kernel stack explosion */
0f83d385c54b2d67790eb5ee77344de60f0966c8Rishi Srivatsavai if (ddi_taskq_dispatch(simnet_rxq, simnet_rx, mp,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_wifi_ioctl(simnet_dev_t *sdev, mblk_t *mp)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai simnet_wifidev_t *wdev = sdev->sd_wifidev;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* LINTED E_BAD_PTR_CAST_ALIGN */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai switch (((wldp_t *)mp->b_rptr)->wldp_id) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* LINTED E_BAD_PTR_CAST_ALIGN */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* We only claim support for WiFi operation commands */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* overwrite everything */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_m_stat(void *arg, uint_t stat, uint64_t *val)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * Returns matching multicast address enabled on the simnet instance.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai * Assumes simnet instance mutex lock is held.
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaimcastaddr_lookup(simnet_dev_t *sdev, const uint8_t *addrp)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai for (idx = 0; idx < sdev->sd_mcastaddr_count; idx++) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (bcmp(maddrptr, addrp, ETHERADDRL) == 0)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai/* Add or remove Multicast addresses on simnet instance */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_m_multicst(void *arg, boolean_t add, const uint8_t *addrp)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai prevsize = sdev->sd_mcastaddr_count * ETHERADDRL;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai newsize = prevsize + (add ? ETHERADDRL:-ETHERADDRL);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (prevsize != (sdev->sd_mcastaddr_count * ETHERADDRL)) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Removing a Multicast address */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* LINTED: E_PTRDIFF_OVERFLOW */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(newbuf, sdev->sd_mcastaddrs, len);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Adding a new Multicast address */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(newbuf, sdev->sd_mcastaddrs, prevsize);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(newbuf + prevsize, addrp, ETHERADDRL);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Error: removing a non-existing Multicast address */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai cmn_err(CE_WARN, "simnet: MAC call to remove a "
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai "Multicast address failed");
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_m_unicst(void *arg, const uint8_t *macaddr)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(sdev->sd_mac_addr, macaddr, ETHERADDRL);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai/* Parse WiFi scan list entry arguments and return the arg count */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaiparse_esslist_args(const void *pr_val, uint_t pr_valsize,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai const char *end = (const char *)pr_val + pr_valsize - 1;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai while (piece < end && (arg < MAX_ESSLIST_ARGS)) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* LINTED E_PTRDIFF_OVERFLOW */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* If first arg is zero then return none to delete all */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (arg == 0 && strnlen(piece, len) == 1 && piece[0] == '0')
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai/* Set WiFi scan list entry from private property _wl_esslist */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaiset_wl_esslist_priv_prop(simnet_wifidev_t *wdev, uint_t pr_valsize,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai char essargs[MAX_ESSLIST_ARGS][MAX_ESSLIST_ARGLEN];
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (parse_esslist_args(pr_val, pr_valsize, essargs) == 0) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai for (i = 0; i < wdev->swd_esslist_num; i++) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai kmem_free(wdev->swd_esslist[i], sizeof (wl_ess_conf_t));
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai for (i = 0; i < wdev->swd_esslist_num; i++) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (wdev->swd_esslist_num >= MAX_SIMNET_ESSCONF)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai wls = kmem_zalloc(sizeof (wl_ess_conf_t), KM_SLEEP);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) strlcpy(wls->wl_ess_conf_essid.wl_essid_essid,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai essargs[0], sizeof (wls->wl_ess_conf_essid.wl_essid_essid));
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai strlen(wls->wl_ess_conf_essid.wl_essid_essid);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) random_get_pseudo_bytes((uint8_t *)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai &wls->wl_ess_conf_bssid, sizeof (wl_bssid_t));
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) ddi_strtol(essargs[1], (char **)NULL, 0, &result);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai ((result > MAX_RSSI || result < 0) ? 0:result);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai wdev->swd_esslist[wdev->swd_esslist_num] = wls;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_set_priv_prop(simnet_dev_t *sdev, const char *pr_name,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai simnet_wifidev_t *wdev = sdev->sd_wifidev;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (strcmp(pr_name, "_wl_esslist") == 0) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai return (set_wl_esslist_priv_prop(wdev, pr_valsize, pr_val));
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai } else if (strcmp(pr_name, "_wl_connected") == 0) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai simnet_wifidev_t *wdev = sdev->sd_wifidev;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(&mtu, wldp_buf, sizeof (mtu));
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (mtu > ETHERMIN && mtu < SIMNET_MAX_MTU)
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai return (mac_maxsdu_update(sdev->sd_mh, mtu));
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* mac_prop_id */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Lookup the signal strength of the connected ESSID */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai for (i = 0; i < wdev->swd_esslist_num; i++) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyersimnet_get_priv_prop(simnet_dev_t *sdev, const char *pr_name,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai simnet_wifidev_t *wdev = sdev->sd_wifidev;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai if (strcmp(pr_name, "_wl_esslist") == 0) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* Returns num of _wl_ess_conf_t that have been set */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai } else if (strcmp(pr_name, "_wl_connected") == 0) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai value = ((wdev->swd_linkstatus == WL_CONNECTED) ? 1:0);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) snprintf(pr_val, pr_valsize, "%d", value);
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavaisimnet_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai simnet_wifidev_t *wdev = sdev->sd_wifidev;
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* mac_prop_id */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(wldp_buf, &wdev->swd_linkstatus,
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai /* LINTED E_BAD_PTR_CAST_ALIGN */
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai w_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai offsetof(wl_ess_list_t, wl_ess_list_ess));
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai for (i = 0; i < wdev->swd_esslist_num; i++) {
b509e89b2befbaa42939abad9da1d7f5a8c6aaaeRishi Srivatsavai (void) memcpy(w_ess_conf, wdev->swd_esslist[i],
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer err = simnet_get_priv_prop(sdev, pr_name, wldp_length,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyersimnet_priv_propinfo(const char *pr_name, mac_prop_info_handle_t prh)
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer (void) snprintf(valstr, sizeof (valstr), "%d", 0);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyersimnet_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,