1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Simulated network device (simnet) driver: simulates a pseudo GLDv3 network 28 * device. Can simulate an Ethernet or WiFi network device. In addition, another 29 * simnet instance can be attached as a peer to create a point-to-point link on 30 * the same system. 31 */ 32 33 #include <sys/policy.h> 34 #include <sys/conf.h> 35 #include <sys/modctl.h> 36 #include <sys/priv_names.h> 37 #include <sys/dlpi.h> 38 #include <net/simnet.h> 39 #include <sys/ethernet.h> 40 #include <sys/mac.h> 41 #include <sys/dls.h> 42 #include <sys/mac_ether.h> 43 #include <sys/mac_provider.h> 44 #include <sys/mac_client_priv.h> 45 #include <sys/vlan.h> 46 #include <sys/random.h> 47 #include <sys/sysmacros.h> 48 #include <sys/list.h> 49 #include <sys/strsubr.h> 50 #include <sys/strsun.h> 51 #include <sys/atomic.h> 52 #include <sys/mac_wifi.h> 53 #include <sys/mac_impl.h> 54 #include <inet/wifi_ioctl.h> 55 #include <sys/thread.h> 56 #include <sys/synch.h> 57 #include <sys/sunddi.h> 58 59 #include "simnet_impl.h" 60 61 #define SIMNETINFO "Simulated Network Driver" 62 63 static dev_info_t *simnet_dip; 64 static ddi_taskq_t *simnet_rxq; 65 66 static int simnet_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 67 static int simnet_attach(dev_info_t *, ddi_attach_cmd_t); 68 static int simnet_detach(dev_info_t *, ddi_detach_cmd_t); 69 static int simnet_ioc_create(void *, intptr_t, int, cred_t *, int *); 70 static int simnet_ioc_delete(void *, intptr_t, int, cred_t *, int *); 71 static int simnet_ioc_info(void *, intptr_t, int, cred_t *, int *); 72 static int simnet_ioc_modify(void *, intptr_t, int, cred_t *, int *); 73 static uint8_t *mcastaddr_lookup(simnet_dev_t *, const uint8_t *); 74 75 static dld_ioc_info_t simnet_ioc_list[] = { 76 {SIMNET_IOC_CREATE, DLDCOPYINOUT, sizeof (simnet_ioc_create_t), 77 simnet_ioc_create, secpolicy_dl_config}, 78 {SIMNET_IOC_DELETE, DLDCOPYIN, sizeof (simnet_ioc_delete_t), 79 simnet_ioc_delete, secpolicy_dl_config}, 80 {SIMNET_IOC_INFO, DLDCOPYINOUT, sizeof (simnet_ioc_info_t), 81 simnet_ioc_info, NULL}, 82 {SIMNET_IOC_MODIFY, DLDCOPYIN, sizeof (simnet_ioc_modify_t), 83 simnet_ioc_modify, secpolicy_dl_config} 84 }; 85 86 DDI_DEFINE_STREAM_OPS(simnet_dev_ops, nulldev, nulldev, simnet_attach, 87 simnet_detach, nodev, simnet_getinfo, D_MP, NULL, 88 ddi_quiesce_not_supported); 89 90 static struct modldrv simnet_modldrv = { 91 &mod_driverops, /* Type of module. This one is a driver */ 92 SIMNETINFO, /* short description */ 93 &simnet_dev_ops /* driver specific ops */ 94 }; 95 96 static struct modlinkage modlinkage = { 97 MODREV_1, &simnet_modldrv, NULL 98 }; 99 100 /* MAC callback function declarations */ 101 static int simnet_m_start(void *); 102 static void simnet_m_stop(void *); 103 static int simnet_m_promisc(void *, boolean_t); 104 static int simnet_m_multicst(void *, boolean_t, const uint8_t *); 105 static int simnet_m_unicst(void *, const uint8_t *); 106 static int simnet_m_stat(void *, uint_t, uint64_t *); 107 static void simnet_m_ioctl(void *, queue_t *, mblk_t *); 108 static mblk_t *simnet_m_tx(void *, mblk_t *); 109 static int simnet_m_setprop(void *, const char *, mac_prop_id_t, 110 uint_t, const void *); 111 static int simnet_m_getprop(void *, const char *, mac_prop_id_t, 112 uint_t, void *); 113 static void simnet_m_propinfo(void *, const char *, mac_prop_id_t, 114 mac_prop_info_handle_t); 115 116 static mac_callbacks_t simnet_m_callbacks = { 117 (MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO), 118 simnet_m_stat, 119 simnet_m_start, 120 simnet_m_stop, 121 simnet_m_promisc, 122 simnet_m_multicst, 123 simnet_m_unicst, 124 simnet_m_tx, 125 NULL, 126 simnet_m_ioctl, 127 NULL, 128 NULL, 129 NULL, 130 simnet_m_setprop, 131 simnet_m_getprop, 132 simnet_m_propinfo 133 }; 134 135 /* 136 * simnet_dev_lock protects the simnet device list. 137 * sd_instlock in each simnet_dev_t protects access to 138 * a single simnet_dev_t. 139 */ 140 static krwlock_t simnet_dev_lock; 141 static list_t simnet_dev_list; 142 static int simnet_count; /* Num of simnet instances */ 143 144 int 145 _init(void) 146 { 147 int status; 148 149 mac_init_ops(&simnet_dev_ops, "simnet"); 150 status = mod_install(&modlinkage); 151 if (status != DDI_SUCCESS) 152 mac_fini_ops(&simnet_dev_ops); 153 154 return (status); 155 } 156 157 int 158 _fini(void) 159 { 160 int status; 161 162 status = mod_remove(&modlinkage); 163 if (status == DDI_SUCCESS) 164 mac_fini_ops(&simnet_dev_ops); 165 166 return (status); 167 } 168 169 int 170 _info(struct modinfo *modinfop) 171 { 172 return (mod_info(&modlinkage, modinfop)); 173 } 174 175 static boolean_t 176 simnet_init(void) 177 { 178 if ((simnet_rxq = ddi_taskq_create(simnet_dip, "simnet", 1, 179 TASKQ_DEFAULTPRI, 0)) == NULL) 180 return (B_FALSE); 181 rw_init(&simnet_dev_lock, NULL, RW_DEFAULT, NULL); 182 list_create(&simnet_dev_list, sizeof (simnet_dev_t), 183 offsetof(simnet_dev_t, sd_listnode)); 184 return (B_TRUE); 185 } 186 187 static void 188 simnet_fini(void) 189 { 190 ASSERT(simnet_count == 0); 191 rw_destroy(&simnet_dev_lock); 192 list_destroy(&simnet_dev_list); 193 ddi_taskq_destroy(simnet_rxq); 194 } 195 196 /*ARGSUSED*/ 197 static int 198 simnet_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 199 void **result) 200 { 201 switch (infocmd) { 202 case DDI_INFO_DEVT2DEVINFO: 203 *result = simnet_dip; 204 return (DDI_SUCCESS); 205 case DDI_INFO_DEVT2INSTANCE: 206 *result = NULL; 207 return (DDI_SUCCESS); 208 } 209 return (DDI_FAILURE); 210 } 211 212 static int 213 simnet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 214 { 215 switch (cmd) { 216 case DDI_ATTACH: 217 if (ddi_get_instance(dip) != 0) { 218 /* we only allow instance 0 to attach */ 219 return (DDI_FAILURE); 220 } 221 222 if (dld_ioc_register(SIMNET_IOC, simnet_ioc_list, 223 DLDIOCCNT(simnet_ioc_list)) != 0) 224 return (DDI_FAILURE); 225 226 simnet_dip = dip; 227 if (!simnet_init()) 228 return (DDI_FAILURE); 229 return (DDI_SUCCESS); 230 231 case DDI_RESUME: 232 return (DDI_SUCCESS); 233 234 default: 235 return (DDI_FAILURE); 236 } 237 } 238 239 /*ARGSUSED*/ 240 static int 241 simnet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 242 { 243 switch (cmd) { 244 case DDI_DETACH: 245 /* 246 * Allow the simnet instance to be detached only if there 247 * are no simnets configured. 248 */ 249 if (simnet_count > 0) 250 return (DDI_FAILURE); 251 252 dld_ioc_unregister(SIMNET_IOC); 253 simnet_fini(); 254 simnet_dip = NULL; 255 return (DDI_SUCCESS); 256 257 case DDI_SUSPEND: 258 return (DDI_SUCCESS); 259 260 default: 261 return (DDI_FAILURE); 262 } 263 } 264 265 /* Caller must hold simnet_dev_lock */ 266 static simnet_dev_t * 267 simnet_dev_lookup(datalink_id_t link_id) 268 { 269 simnet_dev_t *sdev; 270 271 ASSERT(RW_LOCK_HELD(&simnet_dev_lock)); 272 for (sdev = list_head(&simnet_dev_list); sdev != NULL; 273 sdev = list_next(&simnet_dev_list, sdev)) { 274 if (!(sdev->sd_flags & SDF_SHUTDOWN) && 275 (sdev->sd_link_id == link_id)) { 276 atomic_inc_32(&sdev->sd_refcount); 277 return (sdev); 278 } 279 } 280 281 return (NULL); 282 } 283 284 static void 285 simnet_wifidev_free(simnet_dev_t *sdev) 286 { 287 simnet_wifidev_t *wdev = sdev->sd_wifidev; 288 int i; 289 290 for (i = 0; i < wdev->swd_esslist_num; i++) { 291 kmem_free(wdev->swd_esslist[i], 292 sizeof (wl_ess_conf_t)); 293 } 294 kmem_free(wdev, sizeof (simnet_wifidev_t)); 295 } 296 297 static void 298 simnet_dev_unref(simnet_dev_t *sdev) 299 { 300 301 ASSERT(sdev->sd_refcount > 0); 302 if (atomic_dec_32_nv(&sdev->sd_refcount) != 0) 303 return; 304 305 if (sdev->sd_mh != NULL) 306 (void) mac_unregister(sdev->sd_mh); 307 308 if (sdev->sd_wifidev != NULL) { 309 ASSERT(sdev->sd_type == DL_WIFI); 310 simnet_wifidev_free(sdev); 311 } 312 313 mutex_destroy(&sdev->sd_instlock); 314 cv_destroy(&sdev->sd_threadwait); 315 kmem_free(sdev->sd_mcastaddrs, ETHERADDRL * sdev->sd_mcastaddr_count); 316 kmem_free(sdev, sizeof (*sdev)); 317 simnet_count--; 318 } 319 320 static int 321 simnet_init_wifi(simnet_dev_t *sdev, mac_register_t *mac) 322 { 323 wifi_data_t wd = { 0 }; 324 int err; 325 326 sdev->sd_wifidev = kmem_zalloc(sizeof (simnet_wifidev_t), KM_NOSLEEP); 327 if (sdev->sd_wifidev == NULL) 328 return (ENOMEM); 329 330 sdev->sd_wifidev->swd_sdev = sdev; 331 sdev->sd_wifidev->swd_linkstatus = WL_NOTCONNECTED; 332 wd.wd_secalloc = WIFI_SEC_NONE; 333 wd.wd_opmode = IEEE80211_M_STA; 334 mac->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 335 mac->m_max_sdu = IEEE80211_MTU; 336 mac->m_pdata = &wd; 337 mac->m_pdata_size = sizeof (wd); 338 err = mac_register(mac, &sdev->sd_mh); 339 return (err); 340 } 341 342 static int 343 simnet_init_ether(simnet_dev_t *sdev, mac_register_t *mac) 344 { 345 int err; 346 347 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 348 mac->m_max_sdu = SIMNET_MAX_MTU; 349 mac->m_margin = VLAN_TAGSZ; 350 err = mac_register(mac, &sdev->sd_mh); 351 return (err); 352 } 353 354 static int 355 simnet_init_mac(simnet_dev_t *sdev) 356 { 357 mac_register_t *mac; 358 int err; 359 360 if ((mac = mac_alloc(MAC_VERSION)) == NULL) 361 return (ENOMEM); 362 363 mac->m_driver = sdev; 364 mac->m_dip = simnet_dip; 365 mac->m_instance = (uint_t)-1; 366 mac->m_src_addr = sdev->sd_mac_addr; 367 mac->m_callbacks = &simnet_m_callbacks; 368 mac->m_min_sdu = 0; 369 370 if (sdev->sd_type == DL_ETHER) 371 err = simnet_init_ether(sdev, mac); 372 else if (sdev->sd_type == DL_WIFI) 373 err = simnet_init_wifi(sdev, mac); 374 else 375 err = EINVAL; 376 377 mac_free(mac); 378 return (err); 379 } 380 381 /* ARGSUSED */ 382 static int 383 simnet_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 384 { 385 simnet_ioc_create_t *create_arg = karg; 386 simnet_dev_t *sdev; 387 simnet_dev_t *sdev_tmp; 388 int err = 0; 389 390 sdev = kmem_zalloc(sizeof (*sdev), KM_NOSLEEP); 391 if (sdev == NULL) 392 return (ENOMEM); 393 394 rw_enter(&simnet_dev_lock, RW_WRITER); 395 if ((sdev_tmp = simnet_dev_lookup(create_arg->sic_link_id)) != NULL) { 396 simnet_dev_unref(sdev_tmp); 397 rw_exit(&simnet_dev_lock); 398 kmem_free(sdev, sizeof (*sdev)); 399 return (EEXIST); 400 } 401 402 sdev->sd_type = create_arg->sic_type; 403 sdev->sd_link_id = create_arg->sic_link_id; 404 sdev->sd_zoneid = crgetzoneid(cred); 405 sdev->sd_refcount++; 406 mutex_init(&sdev->sd_instlock, NULL, MUTEX_DRIVER, NULL); 407 cv_init(&sdev->sd_threadwait, NULL, CV_DRIVER, NULL); 408 simnet_count++; 409 410 /* Simnets created from configuration on boot pass saved MAC address */ 411 if (create_arg->sic_mac_len == 0) { 412 /* Generate random MAC address */ 413 (void) random_get_pseudo_bytes(sdev->sd_mac_addr, ETHERADDRL); 414 /* Ensure MAC address is not multicast and is local */ 415 sdev->sd_mac_addr[0] = (sdev->sd_mac_addr[0] & ~1) | 2; 416 sdev->sd_mac_len = ETHERADDRL; 417 } else { 418 (void) memcpy(sdev->sd_mac_addr, create_arg->sic_mac_addr, 419 create_arg->sic_mac_len); 420 sdev->sd_mac_len = create_arg->sic_mac_len; 421 } 422 423 if ((err = simnet_init_mac(sdev)) != 0) { 424 simnet_dev_unref(sdev); 425 goto exit; 426 } 427 428 if ((err = dls_devnet_create(sdev->sd_mh, sdev->sd_link_id, 429 crgetzoneid(cred))) != 0) { 430 simnet_dev_unref(sdev); 431 goto exit; 432 } 433 434 mac_link_update(sdev->sd_mh, LINK_STATE_UP); 435 mac_tx_update(sdev->sd_mh); 436 list_insert_tail(&simnet_dev_list, sdev); 437 438 /* Always return MAC address back to caller */ 439 (void) memcpy(create_arg->sic_mac_addr, sdev->sd_mac_addr, 440 sdev->sd_mac_len); 441 create_arg->sic_mac_len = sdev->sd_mac_len; 442 exit: 443 rw_exit(&simnet_dev_lock); 444 return (err); 445 } 446 447 /* Caller must hold writer simnet_dev_lock */ 448 static datalink_id_t 449 simnet_remove_peer(simnet_dev_t *sdev) 450 { 451 simnet_dev_t *sdev_peer; 452 datalink_id_t peer_link_id = DATALINK_INVALID_LINKID; 453 454 ASSERT(RW_WRITE_HELD(&simnet_dev_lock)); 455 if ((sdev_peer = sdev->sd_peer_dev) != NULL) { 456 ASSERT(sdev == sdev_peer->sd_peer_dev); 457 sdev_peer->sd_peer_dev = NULL; 458 sdev->sd_peer_dev = NULL; 459 peer_link_id = sdev_peer->sd_link_id; 460 /* Release previous references held on both simnets */ 461 simnet_dev_unref(sdev_peer); 462 simnet_dev_unref(sdev); 463 } 464 465 return (peer_link_id); 466 } 467 468 /* ARGSUSED */ 469 static int 470 simnet_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 471 { 472 simnet_ioc_modify_t *modify_arg = karg; 473 simnet_dev_t *sdev; 474 simnet_dev_t *sdev_peer = NULL; 475 476 rw_enter(&simnet_dev_lock, RW_WRITER); 477 if ((sdev = simnet_dev_lookup(modify_arg->sim_link_id)) == NULL) { 478 rw_exit(&simnet_dev_lock); 479 return (ENOENT); 480 } 481 482 if (sdev->sd_zoneid != crgetzoneid(cred)) { 483 rw_exit(&simnet_dev_lock); 484 simnet_dev_unref(sdev); 485 return (ENOENT); 486 } 487 488 if (sdev->sd_link_id == modify_arg->sim_peer_link_id) { 489 /* Cannot peer with self */ 490 rw_exit(&simnet_dev_lock); 491 simnet_dev_unref(sdev); 492 return (EINVAL); 493 } 494 495 if (sdev->sd_peer_dev != NULL && sdev->sd_peer_dev->sd_link_id == 496 modify_arg->sim_peer_link_id) { 497 /* Nothing to modify */ 498 rw_exit(&simnet_dev_lock); 499 simnet_dev_unref(sdev); 500 return (0); 501 } 502 503 if (modify_arg->sim_peer_link_id != DATALINK_INVALID_LINKID) { 504 sdev_peer = simnet_dev_lookup(modify_arg->sim_peer_link_id); 505 if (sdev_peer == NULL) { 506 /* Peer simnet device not available */ 507 rw_exit(&simnet_dev_lock); 508 simnet_dev_unref(sdev); 509 return (ENOENT); 510 } 511 if (sdev_peer->sd_zoneid != sdev->sd_zoneid) { 512 /* The two peers must be in the same zone (for now). */ 513 rw_exit(&simnet_dev_lock); 514 simnet_dev_unref(sdev); 515 simnet_dev_unref(sdev_peer); 516 return (EACCES); 517 } 518 } 519 520 /* First remove any previous peer */ 521 (void) simnet_remove_peer(sdev); 522 523 if (sdev_peer != NULL) { 524 /* Remove any previous peer of sdev_peer */ 525 (void) simnet_remove_peer(sdev_peer); 526 /* Update both devices with the new peer */ 527 sdev_peer->sd_peer_dev = sdev; 528 sdev->sd_peer_dev = sdev_peer; 529 /* Hold references on both devices */ 530 } else { 531 /* Release sdev lookup reference */ 532 simnet_dev_unref(sdev); 533 } 534 535 rw_exit(&simnet_dev_lock); 536 return (0); 537 } 538 539 /* ARGSUSED */ 540 static int 541 simnet_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 542 { 543 int err; 544 simnet_dev_t *sdev; 545 simnet_dev_t *sdev_peer; 546 simnet_ioc_delete_t *delete_arg = karg; 547 datalink_id_t tmpid; 548 datalink_id_t peerid; 549 550 rw_enter(&simnet_dev_lock, RW_WRITER); 551 if ((sdev = simnet_dev_lookup(delete_arg->sid_link_id)) == NULL) { 552 rw_exit(&simnet_dev_lock); 553 return (ENOENT); 554 } 555 556 if (sdev->sd_zoneid != crgetzoneid(cred)) { 557 rw_exit(&simnet_dev_lock); 558 simnet_dev_unref(sdev); 559 return (ENOENT); 560 } 561 562 if ((err = dls_devnet_destroy(sdev->sd_mh, &tmpid, B_TRUE)) != 0) { 563 rw_exit(&simnet_dev_lock); 564 simnet_dev_unref(sdev); 565 return (err); 566 } 567 568 ASSERT(sdev->sd_link_id == tmpid); 569 /* Remove any attached peer link */ 570 peerid = simnet_remove_peer(sdev); 571 572 /* Prevent new threads from using the instance */ 573 mutex_enter(&sdev->sd_instlock); 574 sdev->sd_flags |= SDF_SHUTDOWN; 575 /* Wait until all active threads using the instance exit */ 576 while (sdev->sd_threadcount > 0) { 577 if (cv_wait_sig(&sdev->sd_threadwait, 578 &sdev->sd_instlock) == 0) { 579 /* Signaled */ 580 mutex_exit(&sdev->sd_instlock); 581 err = EINTR; 582 goto fail; 583 } 584 } 585 mutex_exit(&sdev->sd_instlock); 586 587 /* Try disabling the MAC */ 588 if ((err = mac_disable(sdev->sd_mh)) != 0) 589 goto fail; 590 591 list_remove(&simnet_dev_list, sdev); 592 rw_exit(&simnet_dev_lock); 593 simnet_dev_unref(sdev); /* Release lookup ref */ 594 /* Releasing the last ref performs sdev/mem free */ 595 simnet_dev_unref(sdev); 596 return (err); 597 fail: 598 /* Re-create simnet instance and add any previous peer */ 599 (void) dls_devnet_create(sdev->sd_mh, sdev->sd_link_id, 600 crgetzoneid(cred)); 601 sdev->sd_flags &= ~SDF_SHUTDOWN; 602 603 ASSERT(sdev->sd_peer_dev == NULL); 604 if (peerid != DATALINK_INVALID_LINKID && 605 ((sdev_peer = simnet_dev_lookup(peerid)) != NULL)) { 606 /* Attach peer device back */ 607 ASSERT(sdev_peer->sd_peer_dev == NULL); 608 sdev_peer->sd_peer_dev = sdev; 609 sdev->sd_peer_dev = sdev_peer; 610 /* Hold reference on both devices */ 611 } else { 612 /* 613 * No previous peer or previous peer no longer 614 * available so release lookup reference. 615 */ 616 simnet_dev_unref(sdev); 617 } 618 619 rw_exit(&simnet_dev_lock); 620 return (err); 621 } 622 623 /* ARGSUSED */ 624 static int 625 simnet_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 626 { 627 simnet_ioc_info_t *info_arg = karg; 628 simnet_dev_t *sdev; 629 630 /* Make sure that the simnet link is visible from the caller's zone. */ 631 if (!dls_devnet_islinkvisible(info_arg->sii_link_id, crgetzoneid(cred))) 632 return (ENOENT); 633 634 rw_enter(&simnet_dev_lock, RW_READER); 635 if ((sdev = simnet_dev_lookup(info_arg->sii_link_id)) == NULL) { 636 rw_exit(&simnet_dev_lock); 637 return (ENOENT); 638 } 639 640 (void) memcpy(info_arg->sii_mac_addr, sdev->sd_mac_addr, 641 sdev->sd_mac_len); 642 info_arg->sii_mac_len = sdev->sd_mac_len; 643 info_arg->sii_type = sdev->sd_type; 644 if (sdev->sd_peer_dev != NULL) 645 info_arg->sii_peer_link_id = sdev->sd_peer_dev->sd_link_id; 646 rw_exit(&simnet_dev_lock); 647 simnet_dev_unref(sdev); 648 return (0); 649 } 650 651 static boolean_t 652 simnet_thread_ref(simnet_dev_t *sdev) 653 { 654 mutex_enter(&sdev->sd_instlock); 655 if (sdev->sd_flags & SDF_SHUTDOWN || 656 !(sdev->sd_flags & SDF_STARTED)) { 657 mutex_exit(&sdev->sd_instlock); 658 return (B_FALSE); 659 } 660 sdev->sd_threadcount++; 661 mutex_exit(&sdev->sd_instlock); 662 return (B_TRUE); 663 } 664 665 static void 666 simnet_thread_unref(simnet_dev_t *sdev) 667 { 668 mutex_enter(&sdev->sd_instlock); 669 if (--sdev->sd_threadcount == 0) 670 cv_broadcast(&sdev->sd_threadwait); 671 mutex_exit(&sdev->sd_instlock); 672 } 673 674 static void 675 simnet_rx(void *arg) 676 { 677 mblk_t *mp = arg; 678 mac_header_info_t hdr_info; 679 simnet_dev_t *sdev; 680 681 sdev = (simnet_dev_t *)mp->b_next; 682 mp->b_next = NULL; 683 684 /* Check for valid packet header */ 685 if (mac_header_info(sdev->sd_mh, mp, &hdr_info) != 0) { 686 freemsg(mp); 687 sdev->sd_stats.recv_errors++; 688 goto rx_done; 689 } 690 691 /* 692 * When we are NOT in promiscuous mode we only receive 693 * unicast packets addressed to us and multicast packets that 694 * MAC clients have requested. 695 */ 696 if (!sdev->sd_promisc && 697 hdr_info.mhi_dsttype != MAC_ADDRTYPE_BROADCAST) { 698 if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_UNICAST && 699 bcmp(hdr_info.mhi_daddr, sdev->sd_mac_addr, 700 ETHERADDRL) != 0) { 701 freemsg(mp); 702 goto rx_done; 703 } else if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) { 704 mutex_enter(&sdev->sd_instlock); 705 if (mcastaddr_lookup(sdev, hdr_info.mhi_daddr) == 706 NULL) { 707 mutex_exit(&sdev->sd_instlock); 708 freemsg(mp); 709 goto rx_done; 710 } 711 mutex_exit(&sdev->sd_instlock); 712 } 713 } 714 715 sdev->sd_stats.recv_count++; 716 sdev->sd_stats.rbytes += msgdsize(mp); 717 mac_rx(sdev->sd_mh, NULL, mp); 718 rx_done: 719 simnet_thread_unref(sdev); 720 } 721 722 static mblk_t * 723 simnet_m_tx(void *arg, mblk_t *mp_chain) 724 { 725 simnet_dev_t *sdev = arg; 726 simnet_dev_t *sdev_rx; 727 mblk_t *mpnext = mp_chain; 728 mblk_t *mp; 729 730 rw_enter(&simnet_dev_lock, RW_READER); 731 if ((sdev_rx = sdev->sd_peer_dev) == NULL) { 732 /* Discard packets when no peer exists */ 733 rw_exit(&simnet_dev_lock); 734 freemsgchain(mp_chain); 735 return (NULL); 736 } 737 738 /* 739 * Discard packets when either device is shutting down or not ready. 740 * Though MAC layer ensures a reference is held on the MAC while we 741 * process the packet chain, there is no guarantee the peer MAC will 742 * remain enabled. So we increment per-instance threadcount to ensure 743 * either MAC instance is not disabled while we handle the chain of 744 * packets. It is okay if the peer device is disconnected while we are 745 * here since we lookup the peer device while holding simnet_dev_lock 746 * (reader lock) and increment the threadcount of the peer, the peer 747 * MAC cannot be disabled in simnet_ioc_delete. 748 */ 749 if (!simnet_thread_ref(sdev_rx)) { 750 rw_exit(&simnet_dev_lock); 751 freemsgchain(mp_chain); 752 return (NULL); 753 } 754 rw_exit(&simnet_dev_lock); 755 756 if (!simnet_thread_ref(sdev)) { 757 simnet_thread_unref(sdev_rx); 758 freemsgchain(mp_chain); 759 return (NULL); 760 } 761 762 while ((mp = mpnext) != NULL) { 763 int len; 764 int size; 765 mblk_t *mp_new; 766 mblk_t *mp_tmp; 767 768 mpnext = mp->b_next; 769 mp->b_next = NULL; 770 len = msgdsize(mp); 771 772 /* Pad packet to minimum Ethernet frame size */ 773 if (len < ETHERMIN) { 774 size = ETHERMIN - len; 775 mp_new = allocb(size, BPRI_HI); 776 if (mp_new == NULL) { 777 sdev->sd_stats.xmit_errors++; 778 freemsg(mp); 779 continue; 780 } 781 bzero(mp_new->b_wptr, size); 782 mp_new->b_wptr += size; 783 784 mp_tmp = mp; 785 while (mp_tmp->b_cont != NULL) 786 mp_tmp = mp_tmp->b_cont; 787 mp_tmp->b_cont = mp_new; 788 len += size; 789 } 790 791 /* Pullup packet into a single mblk */ 792 if (!pullupmsg(mp, -1)) { 793 sdev->sd_stats.xmit_errors++; 794 freemsg(mp); 795 continue; 796 } 797 798 /* Fix mblk checksum as the pkt dest is local */ 799 if ((mp = mac_fix_cksum(mp)) == NULL) { 800 sdev->sd_stats.xmit_errors++; 801 continue; 802 } 803 804 /* Hold reference for taskq receive processing per-pkt */ 805 if (!simnet_thread_ref(sdev_rx)) { 806 freemsg(mp); 807 freemsgchain(mpnext); 808 break; 809 } 810 811 /* Use taskq for pkt receive to avoid kernel stack explosion */ 812 mp->b_next = (mblk_t *)sdev_rx; 813 if (ddi_taskq_dispatch(simnet_rxq, simnet_rx, mp, 814 DDI_NOSLEEP) == DDI_SUCCESS) { 815 sdev->sd_stats.xmit_count++; 816 sdev->sd_stats.obytes += len; 817 } else { 818 simnet_thread_unref(sdev_rx); 819 mp->b_next = NULL; 820 freemsg(mp); 821 sdev_rx->sd_stats.recv_errors++; 822 } 823 } 824 825 simnet_thread_unref(sdev); 826 simnet_thread_unref(sdev_rx); 827 return (NULL); 828 } 829 830 static int 831 simnet_wifi_ioctl(simnet_dev_t *sdev, mblk_t *mp) 832 { 833 int rc = WL_SUCCESS; 834 simnet_wifidev_t *wdev = sdev->sd_wifidev; 835 836 /* LINTED E_BAD_PTR_CAST_ALIGN */ 837 switch (((wldp_t *)mp->b_rptr)->wldp_id) { 838 case WL_DISASSOCIATE: 839 wdev->swd_linkstatus = WL_NOTCONNECTED; 840 break; 841 default: 842 break; 843 } 844 return (rc); 845 } 846 847 static void 848 simnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 849 { 850 simnet_dev_t *sdev = arg; 851 struct iocblk *iocp; 852 mblk_t *mp1; 853 uint32_t cmd; 854 int rc; 855 856 if (sdev->sd_type != DL_WIFI) { 857 miocnak(q, mp, 0, ENOTSUP); 858 return; 859 } 860 861 /* LINTED E_BAD_PTR_CAST_ALIGN */ 862 iocp = (struct iocblk *)mp->b_rptr; 863 if (iocp->ioc_count == 0) { 864 miocnak(q, mp, 0, EINVAL); 865 return; 866 } 867 868 /* We only claim support for WiFi operation commands */ 869 cmd = iocp->ioc_cmd; 870 switch (cmd) { 871 default: 872 miocnak(q, mp, 0, EINVAL); 873 return; 874 case WLAN_GET_PARAM: 875 case WLAN_SET_PARAM: 876 case WLAN_COMMAND: 877 break; 878 } 879 880 mp1 = mp->b_cont; 881 freemsg(mp1->b_cont); 882 mp1->b_cont = NULL; 883 /* overwrite everything */ 884 mp1->b_wptr = mp1->b_rptr; 885 rc = simnet_wifi_ioctl(sdev, mp1); 886 miocack(q, mp, msgdsize(mp1), rc); 887 } 888 889 static int 890 simnet_m_stat(void *arg, uint_t stat, uint64_t *val) 891 { 892 int rval = 0; 893 simnet_dev_t *sdev = arg; 894 895 ASSERT(sdev->sd_mh != NULL); 896 897 switch (stat) { 898 case MAC_STAT_IFSPEED: 899 *val = 100 * 1000000ull; /* 100 Mbps */ 900 break; 901 case MAC_STAT_LINK_STATE: 902 *val = LINK_DUPLEX_FULL; 903 break; 904 case MAC_STAT_LINK_UP: 905 if (sdev->sd_flags & SDF_STARTED) 906 *val = LINK_STATE_UP; 907 else 908 *val = LINK_STATE_DOWN; 909 break; 910 case MAC_STAT_PROMISC: 911 case MAC_STAT_MULTIRCV: 912 case MAC_STAT_MULTIXMT: 913 case MAC_STAT_BRDCSTRCV: 914 case MAC_STAT_BRDCSTXMT: 915 rval = ENOTSUP; 916 break; 917 case MAC_STAT_OPACKETS: 918 *val = sdev->sd_stats.xmit_count; 919 break; 920 case MAC_STAT_OBYTES: 921 *val = sdev->sd_stats.obytes; 922 break; 923 case MAC_STAT_IERRORS: 924 *val = sdev->sd_stats.recv_errors; 925 break; 926 case MAC_STAT_OERRORS: 927 *val = sdev->sd_stats.xmit_errors; 928 break; 929 case MAC_STAT_RBYTES: 930 *val = sdev->sd_stats.rbytes; 931 break; 932 case MAC_STAT_IPACKETS: 933 *val = sdev->sd_stats.recv_count; 934 break; 935 case WIFI_STAT_FCS_ERRORS: 936 case WIFI_STAT_WEP_ERRORS: 937 case WIFI_STAT_TX_FRAGS: 938 case WIFI_STAT_MCAST_TX: 939 case WIFI_STAT_RTS_SUCCESS: 940 case WIFI_STAT_RTS_FAILURE: 941 case WIFI_STAT_ACK_FAILURE: 942 case WIFI_STAT_RX_FRAGS: 943 case WIFI_STAT_MCAST_RX: 944 case WIFI_STAT_RX_DUPS: 945 rval = ENOTSUP; 946 break; 947 default: 948 rval = ENOTSUP; 949 break; 950 } 951 952 return (rval); 953 } 954 955 static int 956 simnet_m_start(void *arg) 957 { 958 simnet_dev_t *sdev = arg; 959 960 sdev->sd_flags |= SDF_STARTED; 961 return (0); 962 } 963 964 static void 965 simnet_m_stop(void *arg) 966 { 967 simnet_dev_t *sdev = arg; 968 969 sdev->sd_flags &= ~SDF_STARTED; 970 } 971 972 static int 973 simnet_m_promisc(void *arg, boolean_t on) 974 { 975 simnet_dev_t *sdev = arg; 976 977 sdev->sd_promisc = on; 978 return (0); 979 } 980 981 /* 982 * Returns matching multicast address enabled on the simnet instance. 983 * Assumes simnet instance mutex lock is held. 984 */ 985 static uint8_t * 986 mcastaddr_lookup(simnet_dev_t *sdev, const uint8_t *addrp) 987 { 988 int idx; 989 uint8_t *maddrptr; 990 991 ASSERT(MUTEX_HELD(&sdev->sd_instlock)); 992 maddrptr = sdev->sd_mcastaddrs; 993 for (idx = 0; idx < sdev->sd_mcastaddr_count; idx++) { 994 if (bcmp(maddrptr, addrp, ETHERADDRL) == 0) 995 return (maddrptr); 996 maddrptr += ETHERADDRL; 997 } 998 999 return (NULL); 1000 } 1001 1002 /* Add or remove Multicast addresses on simnet instance */ 1003 static int 1004 simnet_m_multicst(void *arg, boolean_t add, const uint8_t *addrp) 1005 { 1006 simnet_dev_t *sdev = arg; 1007 uint8_t *maddrptr; 1008 uint8_t *newbuf; 1009 size_t prevsize; 1010 size_t newsize; 1011 ptrdiff_t len; 1012 ptrdiff_t len2; 1013 1014 alloc_retry: 1015 prevsize = sdev->sd_mcastaddr_count * ETHERADDRL; 1016 newsize = prevsize + (add ? ETHERADDRL:-ETHERADDRL); 1017 newbuf = kmem_alloc(newsize, KM_SLEEP); 1018 1019 mutex_enter(&sdev->sd_instlock); 1020 if (prevsize != (sdev->sd_mcastaddr_count * ETHERADDRL)) { 1021 mutex_exit(&sdev->sd_instlock); 1022 kmem_free(newbuf, newsize); 1023 goto alloc_retry; 1024 } 1025 1026 maddrptr = mcastaddr_lookup(sdev, addrp); 1027 if (!add && maddrptr != NULL) { 1028 /* Removing a Multicast address */ 1029 if (newbuf != NULL) { 1030 /* LINTED: E_PTRDIFF_OVERFLOW */ 1031 len = maddrptr - sdev->sd_mcastaddrs; 1032 (void) memcpy(newbuf, sdev->sd_mcastaddrs, len); 1033 len2 = prevsize - len - ETHERADDRL; 1034 (void) memcpy(newbuf + len, 1035 maddrptr + ETHERADDRL, len2); 1036 } 1037 sdev->sd_mcastaddr_count--; 1038 } else if (add && maddrptr == NULL) { 1039 /* Adding a new Multicast address */ 1040 (void) memcpy(newbuf, sdev->sd_mcastaddrs, prevsize); 1041 (void) memcpy(newbuf + prevsize, addrp, ETHERADDRL); 1042 sdev->sd_mcastaddr_count++; 1043 } else { 1044 /* Error: removing a non-existing Multicast address */ 1045 mutex_exit(&sdev->sd_instlock); 1046 kmem_free(newbuf, newsize); 1047 cmn_err(CE_WARN, "simnet: MAC call to remove a " 1048 "Multicast address failed"); 1049 return (EINVAL); 1050 } 1051 1052 kmem_free(sdev->sd_mcastaddrs, prevsize); 1053 sdev->sd_mcastaddrs = newbuf; 1054 mutex_exit(&sdev->sd_instlock); 1055 return (0); 1056 } 1057 1058 static int 1059 simnet_m_unicst(void *arg, const uint8_t *macaddr) 1060 { 1061 simnet_dev_t *sdev = arg; 1062 1063 (void) memcpy(sdev->sd_mac_addr, macaddr, ETHERADDRL); 1064 return (0); 1065 } 1066 1067 /* Parse WiFi scan list entry arguments and return the arg count */ 1068 static int 1069 parse_esslist_args(const void *pr_val, uint_t pr_valsize, 1070 char args[][MAX_ESSLIST_ARGLEN]) 1071 { 1072 char *sep; 1073 ptrdiff_t len = pr_valsize; 1074 const char *piece = pr_val; 1075 const char *end = (const char *)pr_val + pr_valsize - 1; 1076 int arg = 0; 1077 1078 while (piece < end && (arg < MAX_ESSLIST_ARGS)) { 1079 sep = strchr(piece, ','); 1080 if (sep == NULL) 1081 sep = (char *)end; 1082 /* LINTED E_PTRDIFF_OVERFLOW */ 1083 len = sep - piece; 1084 /* If first arg is zero then return none to delete all */ 1085 if (arg == 0 && strnlen(piece, len) == 1 && piece[0] == '0') 1086 return (0); 1087 if (len > MAX_ESSLIST_ARGLEN) 1088 len = MAX_ESSLIST_ARGLEN - 1; 1089 (void) memcpy(&args[arg][0], piece, len); 1090 args[arg][len] = '\0'; 1091 piece = sep + 1; 1092 arg++; 1093 } 1094 1095 return (arg); 1096 } 1097 1098 /* Set WiFi scan list entry from private property _wl_esslist */ 1099 static int 1100 set_wl_esslist_priv_prop(simnet_wifidev_t *wdev, uint_t pr_valsize, 1101 const void *pr_val) 1102 { 1103 char essargs[MAX_ESSLIST_ARGS][MAX_ESSLIST_ARGLEN]; 1104 wl_ess_conf_t *wls; 1105 long result; 1106 int i; 1107 1108 bzero(essargs, sizeof (essargs)); 1109 if (parse_esslist_args(pr_val, pr_valsize, essargs) == 0) { 1110 for (i = 0; i < wdev->swd_esslist_num; i++) { 1111 kmem_free(wdev->swd_esslist[i], sizeof (wl_ess_conf_t)); 1112 wdev->swd_esslist[i] = NULL; 1113 } 1114 wdev->swd_esslist_num = 0; 1115 return (0); 1116 } 1117 1118 for (i = 0; i < wdev->swd_esslist_num; i++) { 1119 wls = wdev->swd_esslist[i]; 1120 if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid, 1121 essargs[0]) == 0) 1122 return (EEXIST); 1123 } 1124 1125 if (wdev->swd_esslist_num >= MAX_SIMNET_ESSCONF) 1126 return (EINVAL); 1127 1128 wls = kmem_zalloc(sizeof (wl_ess_conf_t), KM_SLEEP); 1129 (void) strlcpy(wls->wl_ess_conf_essid.wl_essid_essid, 1130 essargs[0], sizeof (wls->wl_ess_conf_essid.wl_essid_essid)); 1131 wls->wl_ess_conf_essid.wl_essid_length = 1132 strlen(wls->wl_ess_conf_essid.wl_essid_essid); 1133 (void) random_get_pseudo_bytes((uint8_t *) 1134 &wls->wl_ess_conf_bssid, sizeof (wl_bssid_t)); 1135 (void) ddi_strtol(essargs[1], (char **)NULL, 0, &result); 1136 wls->wl_ess_conf_sl = (wl_rssi_t) 1137 ((result > MAX_RSSI || result < 0) ? 0:result); 1138 wdev->swd_esslist[wdev->swd_esslist_num] = wls; 1139 wdev->swd_esslist_num++; 1140 1141 return (0); 1142 } 1143 1144 static int 1145 simnet_set_priv_prop(simnet_dev_t *sdev, const char *pr_name, 1146 uint_t pr_valsize, const void *pr_val) 1147 { 1148 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1149 long result; 1150 1151 if (strcmp(pr_name, "_wl_esslist") == 0) { 1152 if (pr_val == NULL) 1153 return (EINVAL); 1154 return (set_wl_esslist_priv_prop(wdev, pr_valsize, pr_val)); 1155 } else if (strcmp(pr_name, "_wl_connected") == 0) { 1156 if (pr_val == NULL) 1157 return (EINVAL); 1158 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 1159 wdev->swd_linkstatus = ((result == 1) ? 1160 WL_CONNECTED:WL_NOTCONNECTED); 1161 return (0); 1162 } 1163 1164 return (EINVAL); 1165 } 1166 1167 static int 1168 simnet_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 1169 uint_t wldp_length, const void *wldp_buf) 1170 { 1171 simnet_dev_t *sdev = arg; 1172 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1173 int err = 0; 1174 uint32_t mtu; 1175 1176 switch (wldp_pr_num) { 1177 case MAC_PROP_MTU: 1178 (void) memcpy(&mtu, wldp_buf, sizeof (mtu)); 1179 if (mtu > ETHERMIN && mtu < SIMNET_MAX_MTU) 1180 return (mac_maxsdu_update(sdev->sd_mh, mtu)); 1181 else 1182 return (EINVAL); 1183 default: 1184 break; 1185 } 1186 1187 if (sdev->sd_type == DL_ETHER) 1188 return (ENOTSUP); 1189 1190 /* mac_prop_id */ 1191 switch (wldp_pr_num) { 1192 case MAC_PROP_WL_ESSID: { 1193 int i; 1194 wl_ess_conf_t *wls; 1195 1196 (void) memcpy(&wdev->swd_essid, wldp_buf, 1197 sizeof (wl_essid_t)); 1198 wdev->swd_linkstatus = WL_CONNECTED; 1199 1200 /* Lookup the signal strength of the connected ESSID */ 1201 for (i = 0; i < wdev->swd_esslist_num; i++) { 1202 wls = wdev->swd_esslist[i]; 1203 if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid, 1204 wdev->swd_essid.wl_essid_essid) == 0) { 1205 wdev->swd_rssi = wls->wl_ess_conf_sl; 1206 break; 1207 } 1208 } 1209 break; 1210 } 1211 case MAC_PROP_WL_BSSID: { 1212 (void) memcpy(&wdev->swd_bssid, wldp_buf, 1213 sizeof (wl_bssid_t)); 1214 break; 1215 } 1216 case MAC_PROP_WL_PHY_CONFIG: 1217 case MAC_PROP_WL_KEY_TAB: 1218 case MAC_PROP_WL_AUTH_MODE: 1219 case MAC_PROP_WL_ENCRYPTION: 1220 case MAC_PROP_WL_BSSTYPE: 1221 case MAC_PROP_WL_DESIRED_RATES: 1222 break; 1223 case MAC_PROP_PRIVATE: 1224 err = simnet_set_priv_prop(sdev, pr_name, 1225 wldp_length, wldp_buf); 1226 break; 1227 default: 1228 break; 1229 } 1230 1231 return (err); 1232 } 1233 1234 static int 1235 simnet_get_priv_prop(simnet_dev_t *sdev, const char *pr_name, 1236 uint_t pr_valsize, void *pr_val) 1237 { 1238 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1239 int err = 0; 1240 int value; 1241 1242 if (strcmp(pr_name, "_wl_esslist") == 0) { 1243 /* Returns num of _wl_ess_conf_t that have been set */ 1244 value = wdev->swd_esslist_num; 1245 } else if (strcmp(pr_name, "_wl_connected") == 0) { 1246 value = ((wdev->swd_linkstatus == WL_CONNECTED) ? 1:0); 1247 } else { 1248 err = ENOTSUP; 1249 } 1250 1251 if (err == 0) 1252 (void) snprintf(pr_val, pr_valsize, "%d", value); 1253 return (err); 1254 } 1255 1256 static int 1257 simnet_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 1258 uint_t wldp_length, void *wldp_buf) 1259 { 1260 simnet_dev_t *sdev = arg; 1261 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1262 int err = 0; 1263 int i; 1264 1265 if (sdev->sd_type == DL_ETHER) 1266 return (ENOTSUP); 1267 1268 /* mac_prop_id */ 1269 switch (wldp_pr_num) { 1270 case MAC_PROP_WL_ESSID: 1271 (void) memcpy(wldp_buf, &wdev->swd_essid, 1272 sizeof (wl_essid_t)); 1273 break; 1274 case MAC_PROP_WL_BSSID: 1275 (void) memcpy(wldp_buf, &wdev->swd_bssid, 1276 sizeof (wl_bssid_t)); 1277 break; 1278 case MAC_PROP_WL_PHY_CONFIG: 1279 case MAC_PROP_WL_AUTH_MODE: 1280 case MAC_PROP_WL_ENCRYPTION: 1281 break; 1282 case MAC_PROP_WL_LINKSTATUS: 1283 (void) memcpy(wldp_buf, &wdev->swd_linkstatus, 1284 sizeof (wdev->swd_linkstatus)); 1285 break; 1286 case MAC_PROP_WL_ESS_LIST: { 1287 wl_ess_conf_t *w_ess_conf; 1288 1289 ((wl_ess_list_t *)wldp_buf)->wl_ess_list_num = 1290 wdev->swd_esslist_num; 1291 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1292 w_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf + 1293 offsetof(wl_ess_list_t, wl_ess_list_ess)); 1294 for (i = 0; i < wdev->swd_esslist_num; i++) { 1295 (void) memcpy(w_ess_conf, wdev->swd_esslist[i], 1296 sizeof (wl_ess_conf_t)); 1297 w_ess_conf++; 1298 } 1299 break; 1300 } 1301 case MAC_PROP_WL_RSSI: 1302 *(wl_rssi_t *)wldp_buf = wdev->swd_rssi; 1303 break; 1304 case MAC_PROP_WL_RADIO: 1305 *(wl_radio_t *)wldp_buf = B_TRUE; 1306 break; 1307 case MAC_PROP_WL_POWER_MODE: 1308 break; 1309 case MAC_PROP_WL_DESIRED_RATES: 1310 break; 1311 case MAC_PROP_PRIVATE: 1312 err = simnet_get_priv_prop(sdev, pr_name, wldp_length, 1313 wldp_buf); 1314 break; 1315 default: 1316 err = ENOTSUP; 1317 break; 1318 } 1319 1320 return (err); 1321 } 1322 1323 static void 1324 simnet_priv_propinfo(const char *pr_name, mac_prop_info_handle_t prh) 1325 { 1326 char valstr[MAXNAMELEN]; 1327 1328 bzero(valstr, sizeof (valstr)); 1329 1330 if (strcmp(pr_name, "_wl_esslist") == 0) { 1331 (void) snprintf(valstr, sizeof (valstr), "%d", 0); 1332 } 1333 1334 if (strlen(valstr) > 0) 1335 mac_prop_info_set_default_str(prh, valstr); 1336 } 1337 1338 static void 1339 simnet_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 1340 mac_prop_info_handle_t prh) 1341 { 1342 simnet_dev_t *sdev = arg; 1343 1344 if (sdev->sd_type == DL_ETHER) 1345 return; 1346 1347 switch (wldp_pr_num) { 1348 case MAC_PROP_WL_BSSTYPE: 1349 case MAC_PROP_WL_ESS_LIST: 1350 case MAC_PROP_WL_SUPPORTED_RATES: 1351 case MAC_PROP_WL_RSSI: 1352 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1353 break; 1354 case MAC_PROP_PRIVATE: 1355 simnet_priv_propinfo(pr_name, prh); 1356 break; 1357 } 1358 }