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 * Copyright 2019 Joyent, Inc. 26 */ 27 28 /* 29 * Simulated network device (simnet) driver: simulates a pseudo GLDv3 network 30 * device. Can simulate an Ethernet or WiFi network device. In addition, another 31 * simnet instance can be attached as a peer to create a point-to-point link on 32 * the same system. 33 */ 34 35 #include <sys/policy.h> 36 #include <sys/conf.h> 37 #include <sys/modctl.h> 38 #include <sys/priv_names.h> 39 #include <sys/dlpi.h> 40 #include <net/simnet.h> 41 #include <sys/ethernet.h> 42 #include <sys/mac.h> 43 #include <sys/dls.h> 44 #include <sys/mac_ether.h> 45 #include <sys/mac_provider.h> 46 #include <sys/mac_client_priv.h> 47 #include <sys/vlan.h> 48 #include <sys/random.h> 49 #include <sys/sysmacros.h> 50 #include <sys/list.h> 51 #include <sys/strsubr.h> 52 #include <sys/strsun.h> 53 #include <sys/atomic.h> 54 #include <sys/mac_wifi.h> 55 #include <sys/mac_impl.h> 56 #include <sys/pattr.h> 57 #include <inet/wifi_ioctl.h> 58 #include <sys/thread.h> 59 #include <sys/synch.h> 60 #include <sys/sunddi.h> 61 62 #include "simnet_impl.h" 63 64 #define SIMNETINFO "Simulated Network Driver" 65 66 static dev_info_t *simnet_dip; 67 static ddi_taskq_t *simnet_rxq; 68 69 static int simnet_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 70 static int simnet_attach(dev_info_t *, ddi_attach_cmd_t); 71 static int simnet_detach(dev_info_t *, ddi_detach_cmd_t); 72 static int simnet_ioc_create(void *, intptr_t, int, cred_t *, int *); 73 static int simnet_ioc_delete(void *, intptr_t, int, cred_t *, int *); 74 static int simnet_ioc_info(void *, intptr_t, int, cred_t *, int *); 75 static int simnet_ioc_modify(void *, intptr_t, int, cred_t *, int *); 76 static const struct ether_addr *mcastaddr_lookup(const simnet_dev_t *, 77 const uint8_t *); 78 79 static dld_ioc_info_t simnet_ioc_list[] = { 80 {SIMNET_IOC_CREATE, DLDCOPYINOUT, sizeof (simnet_ioc_create_t), 81 simnet_ioc_create, secpolicy_dl_config}, 82 {SIMNET_IOC_DELETE, DLDCOPYIN, sizeof (simnet_ioc_delete_t), 83 simnet_ioc_delete, secpolicy_dl_config}, 84 {SIMNET_IOC_INFO, DLDCOPYINOUT, sizeof (simnet_ioc_info_t), 85 simnet_ioc_info, NULL}, 86 {SIMNET_IOC_MODIFY, DLDCOPYIN, sizeof (simnet_ioc_modify_t), 87 simnet_ioc_modify, secpolicy_dl_config} 88 }; 89 90 DDI_DEFINE_STREAM_OPS(simnet_dev_ops, nulldev, nulldev, simnet_attach, 91 simnet_detach, nodev, simnet_getinfo, D_MP, NULL, 92 ddi_quiesce_not_supported); 93 94 static struct modldrv simnet_modldrv = { 95 &mod_driverops, /* Type of module. This one is a driver */ 96 SIMNETINFO, /* short description */ 97 &simnet_dev_ops /* driver specific ops */ 98 }; 99 100 static struct modlinkage modlinkage = { 101 MODREV_1, &simnet_modldrv, NULL 102 }; 103 104 /* MAC callback function declarations */ 105 static int simnet_m_start(void *); 106 static void simnet_m_stop(void *); 107 static int simnet_m_promisc(void *, boolean_t); 108 static int simnet_m_multicst(void *, boolean_t, const uint8_t *); 109 static int simnet_m_unicst(void *, const uint8_t *); 110 static int simnet_m_stat(void *, uint_t, uint64_t *); 111 static void simnet_m_ioctl(void *, queue_t *, mblk_t *); 112 static mblk_t *simnet_m_tx(void *, mblk_t *); 113 static int simnet_m_setprop(void *, const char *, mac_prop_id_t, 114 const uint_t, const void *); 115 static int simnet_m_getprop(void *, const char *, mac_prop_id_t, 116 uint_t, void *); 117 static void simnet_m_propinfo(void *, const char *, mac_prop_id_t, 118 mac_prop_info_handle_t); 119 static boolean_t simnet_m_getcapab(void *, mac_capab_t, void *); 120 121 static mac_callbacks_t simnet_m_callbacks = { 122 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO), 123 simnet_m_stat, 124 simnet_m_start, 125 simnet_m_stop, 126 simnet_m_promisc, 127 simnet_m_multicst, 128 simnet_m_unicst, 129 simnet_m_tx, 130 NULL, 131 simnet_m_ioctl, 132 simnet_m_getcapab, 133 NULL, 134 NULL, 135 simnet_m_setprop, 136 simnet_m_getprop, 137 simnet_m_propinfo 138 }; 139 140 /* 141 * simnet_dev_lock protects the simnet device list. 142 * sd_instlock in each simnet_dev_t protects access to 143 * a single simnet_dev_t. 144 */ 145 static krwlock_t simnet_dev_lock; 146 static list_t simnet_dev_list; 147 static int simnet_count; /* Num of simnet instances */ 148 149 int 150 _init(void) 151 { 152 int status; 153 154 mac_init_ops(&simnet_dev_ops, "simnet"); 155 status = mod_install(&modlinkage); 156 if (status != DDI_SUCCESS) 157 mac_fini_ops(&simnet_dev_ops); 158 159 return (status); 160 } 161 162 int 163 _fini(void) 164 { 165 int status; 166 167 status = mod_remove(&modlinkage); 168 if (status == DDI_SUCCESS) 169 mac_fini_ops(&simnet_dev_ops); 170 171 return (status); 172 } 173 174 int 175 _info(struct modinfo *modinfop) 176 { 177 return (mod_info(&modlinkage, modinfop)); 178 } 179 180 static boolean_t 181 simnet_init(void) 182 { 183 if ((simnet_rxq = ddi_taskq_create(simnet_dip, "simnet", 1, 184 TASKQ_DEFAULTPRI, 0)) == NULL) 185 return (B_FALSE); 186 rw_init(&simnet_dev_lock, NULL, RW_DEFAULT, NULL); 187 list_create(&simnet_dev_list, sizeof (simnet_dev_t), 188 offsetof(simnet_dev_t, sd_listnode)); 189 return (B_TRUE); 190 } 191 192 static void 193 simnet_fini(void) 194 { 195 ASSERT(simnet_count == 0); 196 rw_destroy(&simnet_dev_lock); 197 list_destroy(&simnet_dev_list); 198 ddi_taskq_destroy(simnet_rxq); 199 } 200 201 /*ARGSUSED*/ 202 static int 203 simnet_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 204 void **result) 205 { 206 switch (infocmd) { 207 case DDI_INFO_DEVT2DEVINFO: 208 *result = simnet_dip; 209 return (DDI_SUCCESS); 210 case DDI_INFO_DEVT2INSTANCE: 211 *result = NULL; 212 return (DDI_SUCCESS); 213 } 214 return (DDI_FAILURE); 215 } 216 217 static int 218 simnet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 219 { 220 switch (cmd) { 221 case DDI_ATTACH: 222 if (ddi_get_instance(dip) != 0) { 223 /* we only allow instance 0 to attach */ 224 return (DDI_FAILURE); 225 } 226 227 if (dld_ioc_register(SIMNET_IOC, simnet_ioc_list, 228 DLDIOCCNT(simnet_ioc_list)) != 0) 229 return (DDI_FAILURE); 230 231 simnet_dip = dip; 232 if (!simnet_init()) 233 return (DDI_FAILURE); 234 return (DDI_SUCCESS); 235 236 case DDI_RESUME: 237 return (DDI_SUCCESS); 238 239 default: 240 return (DDI_FAILURE); 241 } 242 } 243 244 /*ARGSUSED*/ 245 static int 246 simnet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 247 { 248 switch (cmd) { 249 case DDI_DETACH: 250 /* 251 * Allow the simnet instance to be detached only if there 252 * are no simnets configured. 253 */ 254 if (simnet_count > 0) 255 return (DDI_FAILURE); 256 257 dld_ioc_unregister(SIMNET_IOC); 258 simnet_fini(); 259 simnet_dip = NULL; 260 return (DDI_SUCCESS); 261 262 case DDI_SUSPEND: 263 return (DDI_SUCCESS); 264 265 default: 266 return (DDI_FAILURE); 267 } 268 } 269 270 /* Caller must hold simnet_dev_lock */ 271 static simnet_dev_t * 272 simnet_dev_lookup(datalink_id_t link_id) 273 { 274 simnet_dev_t *sdev; 275 276 ASSERT(RW_LOCK_HELD(&simnet_dev_lock)); 277 for (sdev = list_head(&simnet_dev_list); sdev != NULL; 278 sdev = list_next(&simnet_dev_list, sdev)) { 279 if (!(sdev->sd_flags & SDF_SHUTDOWN) && 280 (sdev->sd_link_id == link_id)) { 281 atomic_inc_32(&sdev->sd_refcount); 282 return (sdev); 283 } 284 } 285 286 return (NULL); 287 } 288 289 static void 290 simnet_wifidev_free(simnet_dev_t *sdev) 291 { 292 simnet_wifidev_t *wdev = sdev->sd_wifidev; 293 int i; 294 295 for (i = 0; i < wdev->swd_esslist_num; i++) { 296 kmem_free(wdev->swd_esslist[i], 297 sizeof (wl_ess_conf_t)); 298 } 299 kmem_free(wdev, sizeof (simnet_wifidev_t)); 300 } 301 302 static void 303 simnet_dev_unref(simnet_dev_t *sdev) 304 { 305 306 ASSERT(sdev->sd_refcount > 0); 307 if (atomic_dec_32_nv(&sdev->sd_refcount) != 0) 308 return; 309 310 if (sdev->sd_mh != NULL) 311 (void) mac_unregister(sdev->sd_mh); 312 313 if (sdev->sd_wifidev != NULL) { 314 ASSERT(sdev->sd_type == DL_WIFI); 315 simnet_wifidev_free(sdev); 316 } 317 318 mutex_destroy(&sdev->sd_instlock); 319 cv_destroy(&sdev->sd_threadwait); 320 kmem_free(sdev, sizeof (*sdev)); 321 simnet_count--; 322 } 323 324 static int 325 simnet_init_wifi(simnet_dev_t *sdev, mac_register_t *mac) 326 { 327 wifi_data_t wd = { 0 }; 328 int err; 329 330 sdev->sd_wifidev = kmem_zalloc(sizeof (simnet_wifidev_t), KM_NOSLEEP); 331 if (sdev->sd_wifidev == NULL) 332 return (ENOMEM); 333 334 sdev->sd_wifidev->swd_sdev = sdev; 335 sdev->sd_wifidev->swd_linkstatus = WL_NOTCONNECTED; 336 wd.wd_secalloc = WIFI_SEC_NONE; 337 wd.wd_opmode = IEEE80211_M_STA; 338 mac->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 339 mac->m_max_sdu = IEEE80211_MTU; 340 mac->m_pdata = &wd; 341 mac->m_pdata_size = sizeof (wd); 342 err = mac_register(mac, &sdev->sd_mh); 343 return (err); 344 } 345 346 static int 347 simnet_init_ether(simnet_dev_t *sdev, mac_register_t *mac) 348 { 349 int err; 350 351 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 352 mac->m_max_sdu = SIMNET_MAX_MTU; 353 mac->m_margin = VLAN_TAGSZ; 354 err = mac_register(mac, &sdev->sd_mh); 355 return (err); 356 } 357 358 static int 359 simnet_init_mac(simnet_dev_t *sdev) 360 { 361 mac_register_t *mac; 362 int err; 363 364 if ((mac = mac_alloc(MAC_VERSION)) == NULL) 365 return (ENOMEM); 366 367 mac->m_driver = sdev; 368 mac->m_dip = simnet_dip; 369 mac->m_instance = (uint_t)-1; 370 mac->m_src_addr = sdev->sd_mac_addr; 371 mac->m_callbacks = &simnet_m_callbacks; 372 mac->m_min_sdu = 0; 373 374 if (sdev->sd_type == DL_ETHER) 375 err = simnet_init_ether(sdev, mac); 376 else if (sdev->sd_type == DL_WIFI) 377 err = simnet_init_wifi(sdev, mac); 378 else 379 err = EINVAL; 380 381 mac_free(mac); 382 return (err); 383 } 384 385 /* ARGSUSED */ 386 static int 387 simnet_ioc_create(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 388 { 389 simnet_ioc_create_t *create_arg = karg; 390 simnet_dev_t *sdev; 391 simnet_dev_t *sdev_tmp; 392 int err = 0; 393 394 sdev = kmem_zalloc(sizeof (*sdev), KM_NOSLEEP); 395 if (sdev == NULL) 396 return (ENOMEM); 397 398 rw_enter(&simnet_dev_lock, RW_WRITER); 399 if ((sdev_tmp = simnet_dev_lookup(create_arg->sic_link_id)) != NULL) { 400 simnet_dev_unref(sdev_tmp); 401 rw_exit(&simnet_dev_lock); 402 kmem_free(sdev, sizeof (*sdev)); 403 return (EEXIST); 404 } 405 406 sdev->sd_type = create_arg->sic_type; 407 sdev->sd_link_id = create_arg->sic_link_id; 408 sdev->sd_zoneid = crgetzoneid(cred); 409 sdev->sd_refcount++; 410 mutex_init(&sdev->sd_instlock, NULL, MUTEX_DRIVER, NULL); 411 cv_init(&sdev->sd_threadwait, NULL, CV_DRIVER, NULL); 412 simnet_count++; 413 414 /* Simnets created from configuration on boot pass saved MAC address */ 415 if (create_arg->sic_mac_len == 0) { 416 /* Generate random MAC address */ 417 (void) random_get_pseudo_bytes(sdev->sd_mac_addr, ETHERADDRL); 418 /* Ensure MAC address is not multicast and is local */ 419 sdev->sd_mac_addr[0] = (sdev->sd_mac_addr[0] & ~1) | 2; 420 sdev->sd_mac_len = ETHERADDRL; 421 } else { 422 (void) memcpy(sdev->sd_mac_addr, create_arg->sic_mac_addr, 423 create_arg->sic_mac_len); 424 sdev->sd_mac_len = create_arg->sic_mac_len; 425 } 426 427 if ((err = simnet_init_mac(sdev)) != 0) { 428 simnet_dev_unref(sdev); 429 goto exit; 430 } 431 432 if ((err = dls_devnet_create(sdev->sd_mh, sdev->sd_link_id, 433 crgetzoneid(cred))) != 0) { 434 simnet_dev_unref(sdev); 435 goto exit; 436 } 437 438 mac_link_update(sdev->sd_mh, LINK_STATE_UP); 439 mac_tx_update(sdev->sd_mh); 440 list_insert_tail(&simnet_dev_list, sdev); 441 442 /* Always return MAC address back to caller */ 443 (void) memcpy(create_arg->sic_mac_addr, sdev->sd_mac_addr, 444 sdev->sd_mac_len); 445 create_arg->sic_mac_len = sdev->sd_mac_len; 446 exit: 447 rw_exit(&simnet_dev_lock); 448 return (err); 449 } 450 451 /* Caller must hold writer simnet_dev_lock */ 452 static datalink_id_t 453 simnet_remove_peer(simnet_dev_t *sdev) 454 { 455 simnet_dev_t *sdev_peer; 456 datalink_id_t peer_link_id = DATALINK_INVALID_LINKID; 457 458 ASSERT(RW_WRITE_HELD(&simnet_dev_lock)); 459 if ((sdev_peer = sdev->sd_peer_dev) != NULL) { 460 ASSERT(sdev == sdev_peer->sd_peer_dev); 461 sdev_peer->sd_peer_dev = NULL; 462 sdev->sd_peer_dev = NULL; 463 peer_link_id = sdev_peer->sd_link_id; 464 /* Release previous references held on both simnets */ 465 simnet_dev_unref(sdev_peer); 466 simnet_dev_unref(sdev); 467 } 468 469 return (peer_link_id); 470 } 471 472 /* ARGSUSED */ 473 static int 474 simnet_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 475 { 476 simnet_ioc_modify_t *modify_arg = karg; 477 simnet_dev_t *sdev; 478 simnet_dev_t *sdev_peer = NULL; 479 480 rw_enter(&simnet_dev_lock, RW_WRITER); 481 if ((sdev = simnet_dev_lookup(modify_arg->sim_link_id)) == NULL) { 482 rw_exit(&simnet_dev_lock); 483 return (ENOENT); 484 } 485 486 if (sdev->sd_zoneid != crgetzoneid(cred)) { 487 rw_exit(&simnet_dev_lock); 488 simnet_dev_unref(sdev); 489 return (ENOENT); 490 } 491 492 if (sdev->sd_link_id == modify_arg->sim_peer_link_id) { 493 /* Cannot peer with self */ 494 rw_exit(&simnet_dev_lock); 495 simnet_dev_unref(sdev); 496 return (EINVAL); 497 } 498 499 if (sdev->sd_peer_dev != NULL && sdev->sd_peer_dev->sd_link_id == 500 modify_arg->sim_peer_link_id) { 501 /* Nothing to modify */ 502 rw_exit(&simnet_dev_lock); 503 simnet_dev_unref(sdev); 504 return (0); 505 } 506 507 if (modify_arg->sim_peer_link_id != DATALINK_INVALID_LINKID) { 508 sdev_peer = simnet_dev_lookup(modify_arg->sim_peer_link_id); 509 if (sdev_peer == NULL) { 510 /* Peer simnet device not available */ 511 rw_exit(&simnet_dev_lock); 512 simnet_dev_unref(sdev); 513 return (ENOENT); 514 } 515 if (sdev_peer->sd_zoneid != sdev->sd_zoneid) { 516 /* The two peers must be in the same zone (for now). */ 517 rw_exit(&simnet_dev_lock); 518 simnet_dev_unref(sdev); 519 simnet_dev_unref(sdev_peer); 520 return (EACCES); 521 } 522 } 523 524 /* First remove any previous peer */ 525 (void) simnet_remove_peer(sdev); 526 527 if (sdev_peer != NULL) { 528 /* Remove any previous peer of sdev_peer */ 529 (void) simnet_remove_peer(sdev_peer); 530 /* Update both devices with the new peer */ 531 sdev_peer->sd_peer_dev = sdev; 532 sdev->sd_peer_dev = sdev_peer; 533 /* Hold references on both devices */ 534 } else { 535 /* Release sdev lookup reference */ 536 simnet_dev_unref(sdev); 537 } 538 539 rw_exit(&simnet_dev_lock); 540 return (0); 541 } 542 543 /* ARGSUSED */ 544 static int 545 simnet_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 546 { 547 int err; 548 simnet_dev_t *sdev; 549 simnet_dev_t *sdev_peer; 550 simnet_ioc_delete_t *delete_arg = karg; 551 datalink_id_t tmpid; 552 datalink_id_t peerid; 553 554 rw_enter(&simnet_dev_lock, RW_WRITER); 555 if ((sdev = simnet_dev_lookup(delete_arg->sid_link_id)) == NULL) { 556 rw_exit(&simnet_dev_lock); 557 return (ENOENT); 558 } 559 560 if (sdev->sd_zoneid != crgetzoneid(cred)) { 561 rw_exit(&simnet_dev_lock); 562 simnet_dev_unref(sdev); 563 return (ENOENT); 564 } 565 566 if ((err = dls_devnet_destroy(sdev->sd_mh, &tmpid, B_TRUE)) != 0) { 567 rw_exit(&simnet_dev_lock); 568 simnet_dev_unref(sdev); 569 return (err); 570 } 571 572 ASSERT(sdev->sd_link_id == tmpid); 573 /* Remove any attached peer link */ 574 peerid = simnet_remove_peer(sdev); 575 576 /* Prevent new threads from using the instance */ 577 mutex_enter(&sdev->sd_instlock); 578 sdev->sd_flags |= SDF_SHUTDOWN; 579 /* Wait until all active threads using the instance exit */ 580 while (sdev->sd_threadcount > 0) { 581 if (cv_wait_sig(&sdev->sd_threadwait, 582 &sdev->sd_instlock) == 0) { 583 /* Signaled */ 584 mutex_exit(&sdev->sd_instlock); 585 err = EINTR; 586 goto fail; 587 } 588 } 589 mutex_exit(&sdev->sd_instlock); 590 591 /* Try disabling the MAC */ 592 if ((err = mac_disable(sdev->sd_mh)) != 0) 593 goto fail; 594 595 list_remove(&simnet_dev_list, sdev); 596 rw_exit(&simnet_dev_lock); 597 simnet_dev_unref(sdev); /* Release lookup ref */ 598 /* Releasing the last ref performs sdev/mem free */ 599 simnet_dev_unref(sdev); 600 return (err); 601 fail: 602 /* Re-create simnet instance and add any previous peer */ 603 (void) dls_devnet_create(sdev->sd_mh, sdev->sd_link_id, 604 crgetzoneid(cred)); 605 sdev->sd_flags &= ~SDF_SHUTDOWN; 606 607 ASSERT(sdev->sd_peer_dev == NULL); 608 if (peerid != DATALINK_INVALID_LINKID && 609 ((sdev_peer = simnet_dev_lookup(peerid)) != NULL)) { 610 /* Attach peer device back */ 611 ASSERT(sdev_peer->sd_peer_dev == NULL); 612 sdev_peer->sd_peer_dev = sdev; 613 sdev->sd_peer_dev = sdev_peer; 614 /* Hold reference on both devices */ 615 } else { 616 /* 617 * No previous peer or previous peer no longer 618 * available so release lookup reference. 619 */ 620 simnet_dev_unref(sdev); 621 } 622 623 rw_exit(&simnet_dev_lock); 624 return (err); 625 } 626 627 /* ARGSUSED */ 628 static int 629 simnet_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 630 { 631 simnet_ioc_info_t *info_arg = karg; 632 simnet_dev_t *sdev; 633 634 /* Make sure that the simnet link is visible from the caller's zone. */ 635 if (!dls_devnet_islinkvisible(info_arg->sii_link_id, crgetzoneid(cred))) 636 return (ENOENT); 637 638 rw_enter(&simnet_dev_lock, RW_READER); 639 if ((sdev = simnet_dev_lookup(info_arg->sii_link_id)) == NULL) { 640 rw_exit(&simnet_dev_lock); 641 return (ENOENT); 642 } 643 644 (void) memcpy(info_arg->sii_mac_addr, sdev->sd_mac_addr, 645 sdev->sd_mac_len); 646 info_arg->sii_mac_len = sdev->sd_mac_len; 647 info_arg->sii_type = sdev->sd_type; 648 if (sdev->sd_peer_dev != NULL) 649 info_arg->sii_peer_link_id = sdev->sd_peer_dev->sd_link_id; 650 rw_exit(&simnet_dev_lock); 651 simnet_dev_unref(sdev); 652 return (0); 653 } 654 655 static boolean_t 656 simnet_thread_ref(simnet_dev_t *sdev) 657 { 658 mutex_enter(&sdev->sd_instlock); 659 if (sdev->sd_flags & SDF_SHUTDOWN || 660 !(sdev->sd_flags & SDF_STARTED)) { 661 mutex_exit(&sdev->sd_instlock); 662 return (B_FALSE); 663 } 664 sdev->sd_threadcount++; 665 mutex_exit(&sdev->sd_instlock); 666 return (B_TRUE); 667 } 668 669 static void 670 simnet_thread_unref(simnet_dev_t *sdev) 671 { 672 mutex_enter(&sdev->sd_instlock); 673 if (--sdev->sd_threadcount == 0) 674 cv_broadcast(&sdev->sd_threadwait); 675 mutex_exit(&sdev->sd_instlock); 676 } 677 678 /* 679 * TODO: Add properties to set Rx checksum flag behavior. 680 * 681 * o HCK_PARTIALCKSUM. 682 * o HCK_FULLCKSUM_OK. 683 */ 684 static void 685 simnet_rx(void *arg) 686 { 687 mblk_t *mp = arg; 688 mac_header_info_t hdr_info; 689 simnet_dev_t *sdev; 690 691 sdev = (simnet_dev_t *)mp->b_next; 692 mp->b_next = NULL; 693 694 /* Check for valid packet header */ 695 if (mac_header_info(sdev->sd_mh, mp, &hdr_info) != 0) { 696 mac_drop_pkt(mp, "invalid L2 header"); 697 sdev->sd_stats.recv_errors++; 698 goto rx_done; 699 } 700 701 /* 702 * When we are NOT in promiscuous mode we only receive 703 * unicast packets addressed to us and multicast packets that 704 * MAC clients have requested. 705 */ 706 if (!sdev->sd_promisc && 707 hdr_info.mhi_dsttype != MAC_ADDRTYPE_BROADCAST) { 708 if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_UNICAST && 709 bcmp(hdr_info.mhi_daddr, sdev->sd_mac_addr, 710 ETHERADDRL) != 0) { 711 freemsg(mp); 712 goto rx_done; 713 } else if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) { 714 mutex_enter(&sdev->sd_instlock); 715 if (mcastaddr_lookup(sdev, hdr_info.mhi_daddr) == 716 NULL) { 717 mutex_exit(&sdev->sd_instlock); 718 freemsg(mp); 719 goto rx_done; 720 } 721 mutex_exit(&sdev->sd_instlock); 722 } 723 } 724 725 /* 726 * We don't actually calculate and verify the IP header 727 * checksum because the nature of simnet makes it redundant to 728 * do so. The point is to test the presence of the flags. The 729 * Tx side will have already populated the checksum field. 730 */ 731 if ((sdev->sd_rx_cksum & HCKSUM_IPHDRCKSUM) != 0) { 732 mac_hcksum_set(mp, 0, 0, 0, 0, HCK_IPV4_HDRCKSUM_OK); 733 } 734 735 sdev->sd_stats.recv_count++; 736 sdev->sd_stats.rbytes += msgdsize(mp); 737 mac_rx(sdev->sd_mh, NULL, mp); 738 rx_done: 739 simnet_thread_unref(sdev); 740 } 741 742 #define SIMNET_ULP_CKSUM (HCKSUM_INET_FULL_V4 | HCKSUM_INET_PARTIAL) 743 744 static mblk_t * 745 simnet_m_tx(void *arg, mblk_t *mp_chain) 746 { 747 simnet_dev_t *sdev = arg; 748 simnet_dev_t *sdev_rx; 749 mblk_t *mpnext = mp_chain; 750 mblk_t *mp, *nmp; 751 mac_emul_t emul = 0; 752 753 rw_enter(&simnet_dev_lock, RW_READER); 754 if ((sdev_rx = sdev->sd_peer_dev) == NULL) { 755 /* Discard packets when no peer exists */ 756 rw_exit(&simnet_dev_lock); 757 mac_drop_chain(mp_chain, "no peer"); 758 return (NULL); 759 } 760 761 /* 762 * Discard packets when either device is shutting down or not ready. 763 * Though MAC layer ensures a reference is held on the MAC while we 764 * process the packet chain, there is no guarantee the peer MAC will 765 * remain enabled. So we increment per-instance threadcount to ensure 766 * either MAC instance is not disabled while we handle the chain of 767 * packets. It is okay if the peer device is disconnected while we are 768 * here since we lookup the peer device while holding simnet_dev_lock 769 * (reader lock) and increment the threadcount of the peer, the peer 770 * MAC cannot be disabled in simnet_ioc_delete. 771 */ 772 if (!simnet_thread_ref(sdev_rx)) { 773 rw_exit(&simnet_dev_lock); 774 mac_drop_chain(mp_chain, "simnet peer dev not ready"); 775 return (NULL); 776 } 777 rw_exit(&simnet_dev_lock); 778 779 if (!simnet_thread_ref(sdev)) { 780 simnet_thread_unref(sdev_rx); 781 mac_drop_chain(mp_chain, "simnet dev not ready"); 782 return (NULL); 783 } 784 785 while ((mp = mpnext) != NULL) { 786 size_t len; 787 size_t size; 788 mblk_t *mp_new; 789 mblk_t *mp_tmp; 790 791 mpnext = mp->b_next; 792 mp->b_next = NULL; 793 len = msgdsize(mp); 794 795 /* Pad packet to minimum Ethernet frame size */ 796 if (len < ETHERMIN) { 797 size = ETHERMIN - len; 798 mp_new = allocb(size, BPRI_HI); 799 if (mp_new == NULL) { 800 sdev->sd_stats.xmit_errors++; 801 mac_drop_pkt(mp, "allocb failed"); 802 continue; 803 } 804 bzero(mp_new->b_wptr, size); 805 mp_new->b_wptr += size; 806 807 mp_tmp = mp; 808 while (mp_tmp->b_cont != NULL) 809 mp_tmp = mp_tmp->b_cont; 810 mp_tmp->b_cont = mp_new; 811 len += size; 812 } 813 814 /* Pullup packet into a single mblk */ 815 if ((nmp = msgpullup(mp, -1)) == NULL) { 816 sdev->sd_stats.xmit_errors++; 817 mac_drop_pkt(mp, "msgpullup failed"); 818 continue; 819 } else { 820 mac_hcksum_clone(mp, nmp); 821 freemsg(mp); 822 mp = nmp; 823 } 824 825 /* Hold reference for taskq receive processing per-pkt */ 826 if (!simnet_thread_ref(sdev_rx)) { 827 mac_drop_pkt(mp, "failed to get thread ref"); 828 mac_drop_chain(mpnext, "failed to get thread ref"); 829 break; 830 } 831 832 if ((sdev->sd_tx_cksum & HCKSUM_IPHDRCKSUM) != 0) 833 emul |= MAC_IPCKSUM_EMUL; 834 if ((sdev->sd_tx_cksum & SIMNET_ULP_CKSUM) != 0) 835 emul |= MAC_HWCKSUM_EMUL; 836 if (sdev->sd_lso) 837 emul |= MAC_LSO_EMUL; 838 839 if (emul != 0) 840 mac_hw_emul(&mp, NULL, NULL, emul); 841 842 if (mp == NULL) { 843 sdev->sd_stats.xmit_errors++; 844 continue; 845 } 846 847 /* 848 * Remember, we are emulating a real NIC here; the 849 * checksum flags can't make the trip across the link. 850 */ 851 DB_CKSUMFLAGS(mp) = 0; 852 853 /* Use taskq for pkt receive to avoid kernel stack explosion */ 854 mp->b_next = (mblk_t *)sdev_rx; 855 if (ddi_taskq_dispatch(simnet_rxq, simnet_rx, mp, 856 DDI_NOSLEEP) == DDI_SUCCESS) { 857 sdev->sd_stats.xmit_count++; 858 sdev->sd_stats.obytes += len; 859 } else { 860 simnet_thread_unref(sdev_rx); 861 mp->b_next = NULL; 862 freemsg(mp); 863 sdev_rx->sd_stats.recv_errors++; 864 } 865 } 866 867 simnet_thread_unref(sdev); 868 simnet_thread_unref(sdev_rx); 869 return (NULL); 870 } 871 872 static int 873 simnet_wifi_ioctl(simnet_dev_t *sdev, mblk_t *mp) 874 { 875 int rc = WL_SUCCESS; 876 simnet_wifidev_t *wdev = sdev->sd_wifidev; 877 878 /* LINTED E_BAD_PTR_CAST_ALIGN */ 879 switch (((wldp_t *)mp->b_rptr)->wldp_id) { 880 case WL_DISASSOCIATE: 881 wdev->swd_linkstatus = WL_NOTCONNECTED; 882 break; 883 default: 884 break; 885 } 886 return (rc); 887 } 888 889 static void 890 simnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 891 { 892 simnet_dev_t *sdev = arg; 893 struct iocblk *iocp; 894 mblk_t *mp1; 895 uint32_t cmd; 896 int rc; 897 898 if (sdev->sd_type != DL_WIFI) { 899 miocnak(q, mp, 0, ENOTSUP); 900 return; 901 } 902 903 /* LINTED E_BAD_PTR_CAST_ALIGN */ 904 iocp = (struct iocblk *)mp->b_rptr; 905 if (iocp->ioc_count == 0) { 906 miocnak(q, mp, 0, EINVAL); 907 return; 908 } 909 910 /* We only claim support for WiFi operation commands */ 911 cmd = iocp->ioc_cmd; 912 switch (cmd) { 913 default: 914 miocnak(q, mp, 0, EINVAL); 915 return; 916 case WLAN_GET_PARAM: 917 case WLAN_SET_PARAM: 918 case WLAN_COMMAND: 919 break; 920 } 921 922 mp1 = mp->b_cont; 923 freemsg(mp1->b_cont); 924 mp1->b_cont = NULL; 925 /* overwrite everything */ 926 mp1->b_wptr = mp1->b_rptr; 927 rc = simnet_wifi_ioctl(sdev, mp1); 928 miocack(q, mp, msgdsize(mp1), rc); 929 } 930 931 static boolean_t 932 simnet_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 933 { 934 simnet_dev_t *sdev = arg; 935 const uint_t tcp_cksums = HCKSUM_INET_FULL_V4 | HCKSUM_INET_PARTIAL; 936 937 switch (cap) { 938 case MAC_CAPAB_HCKSUM: { 939 uint32_t *tx_cksum_flags = cap_data; 940 *tx_cksum_flags = sdev->sd_tx_cksum; 941 break; 942 } 943 case MAC_CAPAB_LSO: { 944 mac_capab_lso_t *cap_lso = cap_data; 945 946 if (sdev->sd_lso && 947 (sdev->sd_tx_cksum & HCKSUM_IPHDRCKSUM) != 0 && 948 (sdev->sd_tx_cksum & tcp_cksums) != 0) { 949 /* 950 * The LSO configuration is hardwried for now, 951 * but there's no reason we couldn't also make 952 * this configurable in the future. 953 */ 954 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; 955 cap_lso->lso_basic_tcp_ipv4.lso_max = SD_LSO_MAXLEN; 956 break; 957 } else { 958 return (B_FALSE); 959 } 960 } 961 default: 962 return (B_FALSE); 963 } 964 965 return (B_TRUE); 966 } 967 968 static int 969 simnet_m_stat(void *arg, uint_t stat, uint64_t *val) 970 { 971 int rval = 0; 972 simnet_dev_t *sdev = arg; 973 974 ASSERT(sdev->sd_mh != NULL); 975 976 switch (stat) { 977 case MAC_STAT_IFSPEED: 978 *val = 100 * 1000000ull; /* 100 Mbps */ 979 break; 980 case MAC_STAT_LINK_STATE: 981 *val = LINK_DUPLEX_FULL; 982 break; 983 case MAC_STAT_LINK_UP: 984 if (sdev->sd_flags & SDF_STARTED) 985 *val = LINK_STATE_UP; 986 else 987 *val = LINK_STATE_DOWN; 988 break; 989 case MAC_STAT_PROMISC: 990 case MAC_STAT_MULTIRCV: 991 case MAC_STAT_MULTIXMT: 992 case MAC_STAT_BRDCSTRCV: 993 case MAC_STAT_BRDCSTXMT: 994 rval = ENOTSUP; 995 break; 996 case MAC_STAT_OPACKETS: 997 *val = sdev->sd_stats.xmit_count; 998 break; 999 case MAC_STAT_OBYTES: 1000 *val = sdev->sd_stats.obytes; 1001 break; 1002 case MAC_STAT_IERRORS: 1003 *val = sdev->sd_stats.recv_errors; 1004 break; 1005 case MAC_STAT_OERRORS: 1006 *val = sdev->sd_stats.xmit_errors; 1007 break; 1008 case MAC_STAT_RBYTES: 1009 *val = sdev->sd_stats.rbytes; 1010 break; 1011 case MAC_STAT_IPACKETS: 1012 *val = sdev->sd_stats.recv_count; 1013 break; 1014 case WIFI_STAT_FCS_ERRORS: 1015 case WIFI_STAT_WEP_ERRORS: 1016 case WIFI_STAT_TX_FRAGS: 1017 case WIFI_STAT_MCAST_TX: 1018 case WIFI_STAT_RTS_SUCCESS: 1019 case WIFI_STAT_RTS_FAILURE: 1020 case WIFI_STAT_ACK_FAILURE: 1021 case WIFI_STAT_RX_FRAGS: 1022 case WIFI_STAT_MCAST_RX: 1023 case WIFI_STAT_RX_DUPS: 1024 rval = ENOTSUP; 1025 break; 1026 default: 1027 rval = ENOTSUP; 1028 break; 1029 } 1030 1031 return (rval); 1032 } 1033 1034 static int 1035 simnet_m_start(void *arg) 1036 { 1037 simnet_dev_t *sdev = arg; 1038 1039 sdev->sd_flags |= SDF_STARTED; 1040 return (0); 1041 } 1042 1043 static void 1044 simnet_m_stop(void *arg) 1045 { 1046 simnet_dev_t *sdev = arg; 1047 1048 sdev->sd_flags &= ~SDF_STARTED; 1049 } 1050 1051 static int 1052 simnet_m_promisc(void *arg, boolean_t on) 1053 { 1054 simnet_dev_t *sdev = arg; 1055 1056 sdev->sd_promisc = on; 1057 return (0); 1058 } 1059 1060 /* 1061 * Returns matching multicast address enabled on the simnet instance. 1062 * Assumes simnet instance mutex lock is held. 1063 */ 1064 static const struct ether_addr * 1065 mcastaddr_lookup(const simnet_dev_t *sdev, const uint8_t *addrp) 1066 { 1067 ASSERT(MUTEX_HELD(&sdev->sd_instlock)); 1068 for (uint_t i = 0; i < sdev->sd_mcastaddr_count; i++) { 1069 const struct ether_addr *maddrp = &sdev->sd_mcastaddrs[i]; 1070 1071 if (bcmp(maddrp->ether_addr_octet, addrp, 1072 sizeof (maddrp->ether_addr_octet)) == 0) { 1073 return (maddrp); 1074 } 1075 } 1076 1077 return (NULL); 1078 } 1079 1080 static int 1081 simnet_multicst_add(simnet_dev_t *sdev, const struct ether_addr *eap) 1082 { 1083 ASSERT(MUTEX_HELD(&sdev->sd_instlock)); 1084 1085 if ((eap->ether_addr_octet[0] & 01) == 0) { 1086 return (EINVAL); 1087 } 1088 1089 if (sdev->sd_mcastaddr_count == SM_MAX_NUM_MCAST_ADDRS) { 1090 return (ENOSPC); 1091 } 1092 1093 bcopy(eap, &sdev->sd_mcastaddrs[sdev->sd_mcastaddr_count], 1094 sizeof (*eap)); 1095 sdev->sd_mcastaddr_count++; 1096 return (0); 1097 } 1098 1099 static int 1100 simnet_multicst_rm(simnet_dev_t *sdev, const struct ether_addr *eap) 1101 { 1102 ASSERT(MUTEX_HELD(&sdev->sd_instlock)); 1103 1104 for (uint_t i = 0; i < sdev->sd_mcastaddr_count; i++) { 1105 if (bcmp(eap, &sdev->sd_mcastaddrs[i], sizeof (*eap)) == 0) { 1106 for (i++; i < sdev->sd_mcastaddr_count; i++) { 1107 sdev->sd_mcastaddrs[i - 1] = 1108 sdev->sd_mcastaddrs[i]; 1109 } 1110 1111 /* Zero-out the last entry as it is no longer valid. */ 1112 bzero(&sdev->sd_mcastaddrs[i - 1], 1113 sizeof (sdev->sd_mcastaddrs[0])); 1114 1115 sdev->sd_mcastaddr_count--; 1116 return (0); 1117 } 1118 } 1119 1120 return (EINVAL); 1121 } 1122 1123 /* Add or remove Multicast addresses on simnet instance */ 1124 static int 1125 simnet_m_multicst(void *arg, boolean_t add, const uint8_t *addrp) 1126 { 1127 simnet_dev_t *sdev = arg; 1128 struct ether_addr ea; 1129 int ret; 1130 1131 bcopy(addrp, ea.ether_addr_octet, sizeof (ea.ether_addr_octet)); 1132 mutex_enter(&sdev->sd_instlock); 1133 1134 if (add) { 1135 ret = simnet_multicst_add(sdev, &ea); 1136 } else { 1137 ret = simnet_multicst_rm(sdev, &ea); 1138 } 1139 1140 ASSERT3U(sdev->sd_mcastaddr_count, <=, SM_MAX_NUM_MCAST_ADDRS); 1141 mutex_exit(&sdev->sd_instlock); 1142 return (ret); 1143 } 1144 1145 static int 1146 simnet_m_unicst(void *arg, const uint8_t *macaddr) 1147 { 1148 simnet_dev_t *sdev = arg; 1149 1150 (void) memcpy(sdev->sd_mac_addr, macaddr, ETHERADDRL); 1151 return (0); 1152 } 1153 1154 /* Parse WiFi scan list entry arguments and return the arg count */ 1155 static int 1156 parse_esslist_args(const void *pr_val, uint_t pr_valsize, 1157 char args[][MAX_ESSLIST_ARGLEN]) 1158 { 1159 char *sep; 1160 ptrdiff_t len = pr_valsize; 1161 const char *piece = pr_val; 1162 const char *end = (const char *)pr_val + pr_valsize - 1; 1163 int arg = 0; 1164 1165 while (piece < end && (arg < MAX_ESSLIST_ARGS)) { 1166 sep = strchr(piece, ','); 1167 if (sep == NULL) 1168 sep = (char *)end; 1169 /* LINTED E_PTRDIFF_OVERFLOW */ 1170 len = sep - piece; 1171 /* If first arg is zero then return none to delete all */ 1172 if (arg == 0 && strnlen(piece, len) == 1 && piece[0] == '0') 1173 return (0); 1174 if (len > MAX_ESSLIST_ARGLEN) 1175 len = MAX_ESSLIST_ARGLEN - 1; 1176 (void) memcpy(&args[arg][0], piece, len); 1177 args[arg][len] = '\0'; 1178 piece = sep + 1; 1179 arg++; 1180 } 1181 1182 return (arg); 1183 } 1184 1185 /* Set WiFi scan list entry from private property _wl_esslist */ 1186 static int 1187 set_wl_esslist_priv_prop(simnet_wifidev_t *wdev, uint_t pr_valsize, 1188 const void *pr_val) 1189 { 1190 char essargs[MAX_ESSLIST_ARGS][MAX_ESSLIST_ARGLEN]; 1191 wl_ess_conf_t *wls; 1192 long result; 1193 int i; 1194 1195 bzero(essargs, sizeof (essargs)); 1196 if (parse_esslist_args(pr_val, pr_valsize, essargs) == 0) { 1197 for (i = 0; i < wdev->swd_esslist_num; i++) { 1198 kmem_free(wdev->swd_esslist[i], sizeof (wl_ess_conf_t)); 1199 wdev->swd_esslist[i] = NULL; 1200 } 1201 wdev->swd_esslist_num = 0; 1202 return (0); 1203 } 1204 1205 for (i = 0; i < wdev->swd_esslist_num; i++) { 1206 wls = wdev->swd_esslist[i]; 1207 if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid, 1208 essargs[0]) == 0) 1209 return (EEXIST); 1210 } 1211 1212 if (wdev->swd_esslist_num >= MAX_SIMNET_ESSCONF) 1213 return (EINVAL); 1214 1215 wls = kmem_zalloc(sizeof (wl_ess_conf_t), KM_SLEEP); 1216 (void) strlcpy(wls->wl_ess_conf_essid.wl_essid_essid, 1217 essargs[0], sizeof (wls->wl_ess_conf_essid.wl_essid_essid)); 1218 wls->wl_ess_conf_essid.wl_essid_length = 1219 strlen(wls->wl_ess_conf_essid.wl_essid_essid); 1220 (void) random_get_pseudo_bytes((uint8_t *) 1221 &wls->wl_ess_conf_bssid, sizeof (wl_bssid_t)); 1222 (void) ddi_strtol(essargs[1], (char **)NULL, 0, &result); 1223 wls->wl_ess_conf_sl = (wl_rssi_t) 1224 ((result > MAX_RSSI || result < 0) ? 0:result); 1225 wdev->swd_esslist[wdev->swd_esslist_num] = wls; 1226 wdev->swd_esslist_num++; 1227 1228 return (0); 1229 } 1230 1231 static int 1232 simnet_set_priv_prop_wifi(simnet_dev_t *sdev, const char *name, 1233 const uint_t len, const void *val) 1234 { 1235 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1236 long result; 1237 1238 if (strcmp(name, "_wl_esslist") == 0) { 1239 if (val == NULL) 1240 return (EINVAL); 1241 return (set_wl_esslist_priv_prop(wdev, len, val)); 1242 } else if (strcmp(name, "_wl_connected") == 0) { 1243 if (val == NULL) 1244 return (EINVAL); 1245 (void) ddi_strtol(val, (char **)NULL, 0, &result); 1246 wdev->swd_linkstatus = ((result == 1) ? 1247 WL_CONNECTED:WL_NOTCONNECTED); 1248 return (0); 1249 } 1250 1251 return (EINVAL); 1252 } 1253 1254 /* ARGSUSED */ 1255 static int 1256 simnet_set_priv_prop_ether(simnet_dev_t *sdev, const char *name, 1257 const uint_t len, const void *val) 1258 { 1259 if (strcmp(name, SD_PROP_RX_IP_CKSUM) == 0) { 1260 if (val == NULL) 1261 return (EINVAL); 1262 1263 if (strcmp(val, "off") == 0) { 1264 sdev->sd_rx_cksum &= ~HCKSUM_IPHDRCKSUM; 1265 } else if (strcmp(val, "on") == 0) { 1266 sdev->sd_rx_cksum |= HCKSUM_IPHDRCKSUM; 1267 } else { 1268 return (EINVAL); 1269 } 1270 1271 return (0); 1272 } else if (strcmp(name, SD_PROP_TX_ULP_CKSUM) == 0) { 1273 if (val == NULL) 1274 return (EINVAL); 1275 1276 /* 1277 * Remember, full and partial checksum are mutually 1278 * exclusive. 1279 */ 1280 if (strcmp(val, "none") == 0) { 1281 sdev->sd_tx_cksum &= ~HCKSUM_INET_FULL_V4; 1282 } else if (strcmp(val, "fullv4") == 0) { 1283 sdev->sd_tx_cksum &= ~HCKSUM_INET_PARTIAL; 1284 sdev->sd_tx_cksum |= HCKSUM_INET_FULL_V4; 1285 } else if (strcmp(val, "partial") == 0) { 1286 sdev->sd_tx_cksum &= HCKSUM_INET_FULL_V4; 1287 sdev->sd_tx_cksum |= HCKSUM_INET_PARTIAL; 1288 } else { 1289 return (EINVAL); 1290 } 1291 1292 return (0); 1293 } else if (strcmp(name, SD_PROP_TX_IP_CKSUM) == 0) { 1294 if (val == NULL) 1295 return (EINVAL); 1296 1297 if (strcmp(val, "off") == 0) { 1298 sdev->sd_tx_cksum &= ~HCKSUM_IPHDRCKSUM; 1299 } else if (strcmp(val, "on") == 0) { 1300 sdev->sd_tx_cksum |= HCKSUM_IPHDRCKSUM; 1301 } else { 1302 return (EINVAL); 1303 } 1304 1305 return (0); 1306 } else if (strcmp(name, SD_PROP_LSO) == 0) { 1307 if (val == NULL) 1308 return (EINVAL); 1309 1310 if (strcmp(val, "off") == 0) { 1311 sdev->sd_lso = B_FALSE; 1312 } else if (strcmp(val, "on") == 0) { 1313 sdev->sd_lso = B_TRUE; 1314 } else { 1315 return (EINVAL); 1316 } 1317 1318 return (0); 1319 } 1320 1321 return (ENOTSUP); 1322 } 1323 1324 static int 1325 simnet_setprop_wifi(simnet_dev_t *sdev, const char *name, 1326 const mac_prop_id_t num, const uint_t len, const void *val) 1327 { 1328 int err = 0; 1329 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1330 1331 switch (num) { 1332 case MAC_PROP_WL_ESSID: { 1333 int i; 1334 wl_ess_conf_t *wls; 1335 1336 (void) memcpy(&wdev->swd_essid, val, sizeof (wl_essid_t)); 1337 wdev->swd_linkstatus = WL_CONNECTED; 1338 1339 /* Lookup the signal strength of the connected ESSID */ 1340 for (i = 0; i < wdev->swd_esslist_num; i++) { 1341 wls = wdev->swd_esslist[i]; 1342 if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid, 1343 wdev->swd_essid.wl_essid_essid) == 0) { 1344 wdev->swd_rssi = wls->wl_ess_conf_sl; 1345 break; 1346 } 1347 } 1348 break; 1349 } 1350 case MAC_PROP_WL_BSSID: { 1351 (void) memcpy(&wdev->swd_bssid, val, sizeof (wl_bssid_t)); 1352 break; 1353 } 1354 case MAC_PROP_WL_PHY_CONFIG: 1355 case MAC_PROP_WL_KEY_TAB: 1356 case MAC_PROP_WL_AUTH_MODE: 1357 case MAC_PROP_WL_ENCRYPTION: 1358 case MAC_PROP_WL_BSSTYPE: 1359 case MAC_PROP_WL_DESIRED_RATES: 1360 break; 1361 case MAC_PROP_PRIVATE: 1362 err = simnet_set_priv_prop_wifi(sdev, name, len, val); 1363 break; 1364 default: 1365 err = EINVAL; 1366 break; 1367 } 1368 1369 return (err); 1370 } 1371 1372 static int 1373 simnet_setprop_ether(simnet_dev_t *sdev, const char *name, 1374 const mac_prop_id_t num, const uint_t len, const void *val) 1375 { 1376 int err = 0; 1377 1378 switch (num) { 1379 case MAC_PROP_PRIVATE: 1380 err = simnet_set_priv_prop_ether(sdev, name, len, val); 1381 break; 1382 default: 1383 err = EINVAL; 1384 break; 1385 } 1386 1387 return (err); 1388 } 1389 1390 static int 1391 simnet_m_setprop(void *arg, const char *name, mac_prop_id_t num, 1392 const uint_t len, const void *val) 1393 { 1394 simnet_dev_t *sdev = arg; 1395 int err = 0; 1396 uint32_t mtu; 1397 1398 switch (num) { 1399 case MAC_PROP_MTU: 1400 (void) memcpy(&mtu, val, sizeof (mtu)); 1401 if (mtu > ETHERMIN && mtu < SIMNET_MAX_MTU) 1402 return (mac_maxsdu_update(sdev->sd_mh, mtu)); 1403 else 1404 return (EINVAL); 1405 default: 1406 break; 1407 } 1408 1409 switch (sdev->sd_type) { 1410 case DL_ETHER: 1411 err = simnet_setprop_ether(sdev, name, num, len, val); 1412 break; 1413 case DL_WIFI: 1414 err = simnet_setprop_wifi(sdev, name, num, len, val); 1415 break; 1416 default: 1417 err = EINVAL; 1418 break; 1419 } 1420 1421 /* 1422 * We may have modified the configuration of hardware 1423 * offloads. Make sure to renegotiate capabilities with the 1424 * upstream clients. 1425 */ 1426 mac_capab_update(sdev->sd_mh); 1427 return (err); 1428 } 1429 1430 static int 1431 simnet_get_priv_prop_wifi(const simnet_dev_t *sdev, const char *name, 1432 const uint_t len, void *val) 1433 { 1434 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1435 int ret, value; 1436 1437 if (strcmp(name, "_wl_esslist") == 0) { 1438 /* Returns num of _wl_ess_conf_t that have been set */ 1439 value = wdev->swd_esslist_num; 1440 } else if (strcmp(name, "_wl_connected") == 0) { 1441 value = ((wdev->swd_linkstatus == WL_CONNECTED) ? 1:0); 1442 } else { 1443 return (ENOTSUP); 1444 } 1445 1446 ret = snprintf(val, len, "%d", value); 1447 1448 if (ret < 0 || ret >= len) 1449 return (EOVERFLOW); 1450 1451 return (0); 1452 } 1453 1454 static int 1455 simnet_get_priv_prop_ether(const simnet_dev_t *sdev, const char *name, 1456 const uint_t len, void *val) 1457 { 1458 int ret; 1459 char *value; 1460 1461 if (strcmp(name, SD_PROP_RX_IP_CKSUM) == 0) { 1462 if ((sdev->sd_rx_cksum & HCKSUM_IPHDRCKSUM) != 0) { 1463 value = "on"; 1464 } else { 1465 value = "off"; 1466 } 1467 } else if (strcmp(name, SD_PROP_TX_ULP_CKSUM) == 0) { 1468 if ((sdev->sd_tx_cksum & HCKSUM_INET_FULL_V4) != 0) { 1469 value = "fullv4"; 1470 } else if ((sdev->sd_tx_cksum & HCKSUM_INET_PARTIAL) != 0) { 1471 value = "partial"; 1472 } else { 1473 value = "none"; 1474 } 1475 } else if (strcmp(name, SD_PROP_TX_IP_CKSUM) == 0) { 1476 if ((sdev->sd_tx_cksum & HCKSUM_IPHDRCKSUM) != 0) { 1477 value = "on"; 1478 } else { 1479 value = "off"; 1480 } 1481 } else if (strcmp(name, SD_PROP_LSO) == 0) { 1482 value = sdev->sd_lso ? "on" : "off"; 1483 } else { 1484 return (ENOTSUP); 1485 } 1486 1487 ret = snprintf(val, len, "%s", value); 1488 1489 if (ret < 0 || ret >= len) { 1490 return (EOVERFLOW); 1491 } 1492 1493 return (0); 1494 } 1495 1496 static int 1497 simnet_getprop_wifi(const simnet_dev_t *sdev, const char *name, 1498 const mac_prop_id_t num, const uint_t len, void *val) 1499 { 1500 const simnet_wifidev_t *wdev = sdev->sd_wifidev; 1501 int err = 0; 1502 1503 switch (num) { 1504 case MAC_PROP_WL_ESSID: 1505 (void) memcpy(val, &wdev->swd_essid, sizeof (wl_essid_t)); 1506 break; 1507 case MAC_PROP_WL_BSSID: 1508 (void) memcpy(val, &wdev->swd_bssid, sizeof (wl_bssid_t)); 1509 break; 1510 case MAC_PROP_WL_PHY_CONFIG: 1511 case MAC_PROP_WL_AUTH_MODE: 1512 case MAC_PROP_WL_ENCRYPTION: 1513 break; 1514 case MAC_PROP_WL_LINKSTATUS: 1515 (void) memcpy(val, &wdev->swd_linkstatus, 1516 sizeof (wdev->swd_linkstatus)); 1517 break; 1518 case MAC_PROP_WL_ESS_LIST: { 1519 wl_ess_conf_t *w_ess_conf; 1520 1521 ((wl_ess_list_t *)val)->wl_ess_list_num = wdev->swd_esslist_num; 1522 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1523 w_ess_conf = (wl_ess_conf_t *)((char *)val + 1524 offsetof(wl_ess_list_t, wl_ess_list_ess)); 1525 for (uint_t i = 0; i < wdev->swd_esslist_num; i++) { 1526 (void) memcpy(w_ess_conf, wdev->swd_esslist[i], 1527 sizeof (wl_ess_conf_t)); 1528 w_ess_conf++; 1529 } 1530 break; 1531 } 1532 case MAC_PROP_WL_RSSI: 1533 *(wl_rssi_t *)val = wdev->swd_rssi; 1534 break; 1535 case MAC_PROP_WL_RADIO: 1536 *(wl_radio_t *)val = B_TRUE; 1537 break; 1538 case MAC_PROP_WL_POWER_MODE: 1539 break; 1540 case MAC_PROP_WL_DESIRED_RATES: 1541 break; 1542 case MAC_PROP_PRIVATE: 1543 err = simnet_get_priv_prop_wifi(sdev, name, len, val); 1544 break; 1545 default: 1546 err = ENOTSUP; 1547 break; 1548 } 1549 1550 return (err); 1551 } 1552 1553 static int 1554 simnet_getprop_ether(const simnet_dev_t *sdev, const char *name, 1555 const mac_prop_id_t num, const uint_t len, void *val) 1556 { 1557 int err = 0; 1558 1559 switch (num) { 1560 case MAC_PROP_PRIVATE: 1561 err = simnet_get_priv_prop_ether(sdev, name, len, val); 1562 break; 1563 default: 1564 err = ENOTSUP; 1565 break; 1566 } 1567 1568 return (err); 1569 } 1570 1571 static int 1572 simnet_m_getprop(void *arg, const char *name, const mac_prop_id_t num, 1573 const uint_t len, void *val) 1574 { 1575 const simnet_dev_t *sdev = arg; 1576 int err = 0; 1577 1578 switch (sdev->sd_type) { 1579 case DL_ETHER: 1580 err = simnet_getprop_ether(sdev, name, num, len, val); 1581 break; 1582 case DL_WIFI: 1583 err = simnet_getprop_wifi(sdev, name, num, len, val); 1584 break; 1585 default: 1586 err = EINVAL; 1587 break; 1588 } 1589 1590 return (err); 1591 } 1592 1593 static void 1594 simnet_priv_propinfo_wifi(const char *name, mac_prop_info_handle_t prh) 1595 { 1596 char valstr[MAXNAMELEN]; 1597 1598 bzero(valstr, sizeof (valstr)); 1599 1600 if (strcmp(name, "_wl_esslist") == 0) { 1601 (void) snprintf(valstr, sizeof (valstr), "%d", 0); 1602 } 1603 1604 if (strlen(valstr) > 0) 1605 mac_prop_info_set_default_str(prh, valstr); 1606 } 1607 1608 static void 1609 simnet_propinfo_wifi(const char *name, const mac_prop_id_t num, 1610 mac_prop_info_handle_t prh) 1611 { 1612 switch (num) { 1613 case MAC_PROP_WL_BSSTYPE: 1614 case MAC_PROP_WL_ESS_LIST: 1615 case MAC_PROP_WL_SUPPORTED_RATES: 1616 case MAC_PROP_WL_RSSI: 1617 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1618 break; 1619 case MAC_PROP_PRIVATE: 1620 simnet_priv_propinfo_wifi(name, prh); 1621 break; 1622 } 1623 } 1624 1625 static void 1626 simnet_priv_propinfo_ether(const char *name, mac_prop_info_handle_t prh) 1627 { 1628 if (strcmp(name, SD_PROP_RX_IP_CKSUM) == 0 || 1629 strcmp(name, SD_PROP_TX_ULP_CKSUM) == 0 || 1630 strcmp(name, SD_PROP_TX_IP_CKSUM) == 0 || 1631 strcmp(name, SD_PROP_LSO) == 0) { 1632 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 1633 } 1634 1635 if (strcmp(name, SD_PROP_TX_ULP_CKSUM) == 0) { 1636 mac_prop_info_set_default_str(prh, "none"); 1637 } 1638 1639 if (strcmp(name, SD_PROP_RX_IP_CKSUM) == 0 || 1640 strcmp(name, SD_PROP_TX_IP_CKSUM) == 0 || 1641 strcmp(name, SD_PROP_LSO) == 0) { 1642 mac_prop_info_set_default_str(prh, "off"); 1643 } 1644 } 1645 1646 static void 1647 simnet_propinfo_ether(const char *name, const mac_prop_id_t num, 1648 mac_prop_info_handle_t prh) 1649 { 1650 switch (num) { 1651 case MAC_PROP_PRIVATE: 1652 simnet_priv_propinfo_ether(name, prh); 1653 break; 1654 } 1655 } 1656 1657 static void 1658 simnet_m_propinfo(void *arg, const char *name, const mac_prop_id_t num, 1659 const mac_prop_info_handle_t prh) 1660 { 1661 simnet_dev_t *sdev = arg; 1662 1663 switch (sdev->sd_type) { 1664 case DL_ETHER: 1665 simnet_propinfo_ether(name, num, prh); 1666 break; 1667 case DL_WIFI: 1668 simnet_propinfo_wifi(name, num, prh); 1669 break; 1670 } 1671 } 1672