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_ls = LINK_STATE_UNKNOWN; 407 sdev->sd_type = create_arg->sic_type; 408 sdev->sd_link_id = create_arg->sic_link_id; 409 sdev->sd_zoneid = crgetzoneid(cred); 410 sdev->sd_refcount++; 411 mutex_init(&sdev->sd_instlock, NULL, MUTEX_DRIVER, NULL); 412 cv_init(&sdev->sd_threadwait, NULL, CV_DRIVER, NULL); 413 simnet_count++; 414 415 /* Simnets created from configuration on boot pass saved MAC address */ 416 if (create_arg->sic_mac_len == 0) { 417 /* Generate random MAC address */ 418 (void) random_get_pseudo_bytes(sdev->sd_mac_addr, ETHERADDRL); 419 /* Ensure MAC address is not multicast and is local */ 420 sdev->sd_mac_addr[0] = (sdev->sd_mac_addr[0] & ~1) | 2; 421 sdev->sd_mac_len = ETHERADDRL; 422 } else { 423 (void) memcpy(sdev->sd_mac_addr, create_arg->sic_mac_addr, 424 create_arg->sic_mac_len); 425 sdev->sd_mac_len = create_arg->sic_mac_len; 426 } 427 428 if ((err = simnet_init_mac(sdev)) != 0) { 429 simnet_dev_unref(sdev); 430 goto exit; 431 } 432 433 if ((err = dls_devnet_create(sdev->sd_mh, sdev->sd_link_id, 434 crgetzoneid(cred))) != 0) { 435 simnet_dev_unref(sdev); 436 goto exit; 437 } 438 439 sdev->sd_ls = LINK_STATE_UP; 440 mac_link_update(sdev->sd_mh, LINK_STATE_UP); 441 mac_tx_update(sdev->sd_mh); 442 list_insert_tail(&simnet_dev_list, sdev); 443 444 /* Always return MAC address back to caller */ 445 (void) memcpy(create_arg->sic_mac_addr, sdev->sd_mac_addr, 446 sdev->sd_mac_len); 447 create_arg->sic_mac_len = sdev->sd_mac_len; 448 exit: 449 rw_exit(&simnet_dev_lock); 450 return (err); 451 } 452 453 /* Caller must hold writer simnet_dev_lock */ 454 static datalink_id_t 455 simnet_remove_peer(simnet_dev_t *sdev) 456 { 457 simnet_dev_t *sdev_peer; 458 datalink_id_t peer_link_id = DATALINK_INVALID_LINKID; 459 460 ASSERT(RW_WRITE_HELD(&simnet_dev_lock)); 461 if ((sdev_peer = sdev->sd_peer_dev) != NULL) { 462 ASSERT(sdev == sdev_peer->sd_peer_dev); 463 sdev_peer->sd_peer_dev = NULL; 464 sdev->sd_peer_dev = NULL; 465 peer_link_id = sdev_peer->sd_link_id; 466 /* Release previous references held on both simnets */ 467 simnet_dev_unref(sdev_peer); 468 simnet_dev_unref(sdev); 469 } 470 471 return (peer_link_id); 472 } 473 474 /* ARGSUSED */ 475 static int 476 simnet_ioc_modify(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 477 { 478 simnet_ioc_modify_t *modify_arg = karg; 479 simnet_dev_t *sdev; 480 simnet_dev_t *sdev_peer = NULL; 481 482 rw_enter(&simnet_dev_lock, RW_WRITER); 483 if ((sdev = simnet_dev_lookup(modify_arg->sim_link_id)) == NULL) { 484 rw_exit(&simnet_dev_lock); 485 return (ENOENT); 486 } 487 488 if (sdev->sd_zoneid != crgetzoneid(cred)) { 489 rw_exit(&simnet_dev_lock); 490 simnet_dev_unref(sdev); 491 return (ENOENT); 492 } 493 494 if (sdev->sd_link_id == modify_arg->sim_peer_link_id) { 495 /* Cannot peer with self */ 496 rw_exit(&simnet_dev_lock); 497 simnet_dev_unref(sdev); 498 return (EINVAL); 499 } 500 501 if (sdev->sd_peer_dev != NULL && sdev->sd_peer_dev->sd_link_id == 502 modify_arg->sim_peer_link_id) { 503 /* Nothing to modify */ 504 rw_exit(&simnet_dev_lock); 505 simnet_dev_unref(sdev); 506 return (0); 507 } 508 509 if (modify_arg->sim_peer_link_id != DATALINK_INVALID_LINKID) { 510 sdev_peer = simnet_dev_lookup(modify_arg->sim_peer_link_id); 511 if (sdev_peer == NULL) { 512 /* Peer simnet device not available */ 513 rw_exit(&simnet_dev_lock); 514 simnet_dev_unref(sdev); 515 return (ENOENT); 516 } 517 if (sdev_peer->sd_zoneid != sdev->sd_zoneid) { 518 /* The two peers must be in the same zone (for now). */ 519 rw_exit(&simnet_dev_lock); 520 simnet_dev_unref(sdev); 521 simnet_dev_unref(sdev_peer); 522 return (EACCES); 523 } 524 } 525 526 /* First remove any previous peer */ 527 (void) simnet_remove_peer(sdev); 528 529 if (sdev_peer != NULL) { 530 /* Remove any previous peer of sdev_peer */ 531 (void) simnet_remove_peer(sdev_peer); 532 /* Update both devices with the new peer */ 533 sdev_peer->sd_peer_dev = sdev; 534 sdev->sd_peer_dev = sdev_peer; 535 /* Hold references on both devices */ 536 } else { 537 /* Release sdev lookup reference */ 538 simnet_dev_unref(sdev); 539 } 540 541 rw_exit(&simnet_dev_lock); 542 return (0); 543 } 544 545 /* ARGSUSED */ 546 static int 547 simnet_ioc_delete(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 548 { 549 int err; 550 simnet_dev_t *sdev; 551 simnet_dev_t *sdev_peer; 552 simnet_ioc_delete_t *delete_arg = karg; 553 datalink_id_t tmpid; 554 datalink_id_t peerid; 555 556 rw_enter(&simnet_dev_lock, RW_WRITER); 557 if ((sdev = simnet_dev_lookup(delete_arg->sid_link_id)) == NULL) { 558 rw_exit(&simnet_dev_lock); 559 return (ENOENT); 560 } 561 562 if (sdev->sd_zoneid != crgetzoneid(cred)) { 563 rw_exit(&simnet_dev_lock); 564 simnet_dev_unref(sdev); 565 return (ENOENT); 566 } 567 568 if ((err = dls_devnet_destroy(sdev->sd_mh, &tmpid, B_TRUE)) != 0) { 569 rw_exit(&simnet_dev_lock); 570 simnet_dev_unref(sdev); 571 return (err); 572 } 573 574 ASSERT(sdev->sd_link_id == tmpid); 575 /* Remove any attached peer link */ 576 peerid = simnet_remove_peer(sdev); 577 578 /* Prevent new threads from using the instance */ 579 mutex_enter(&sdev->sd_instlock); 580 sdev->sd_flags |= SDF_SHUTDOWN; 581 /* Wait until all active threads using the instance exit */ 582 while (sdev->sd_threadcount > 0) { 583 if (cv_wait_sig(&sdev->sd_threadwait, 584 &sdev->sd_instlock) == 0) { 585 /* Signaled */ 586 mutex_exit(&sdev->sd_instlock); 587 err = EINTR; 588 goto fail; 589 } 590 } 591 mutex_exit(&sdev->sd_instlock); 592 593 /* Try disabling the MAC */ 594 if ((err = mac_disable(sdev->sd_mh)) != 0) 595 goto fail; 596 597 list_remove(&simnet_dev_list, sdev); 598 rw_exit(&simnet_dev_lock); 599 simnet_dev_unref(sdev); /* Release lookup ref */ 600 /* Releasing the last ref performs sdev/mem free */ 601 simnet_dev_unref(sdev); 602 return (err); 603 fail: 604 /* Re-create simnet instance and add any previous peer */ 605 (void) dls_devnet_create(sdev->sd_mh, sdev->sd_link_id, 606 crgetzoneid(cred)); 607 sdev->sd_flags &= ~SDF_SHUTDOWN; 608 609 ASSERT(sdev->sd_peer_dev == NULL); 610 if (peerid != DATALINK_INVALID_LINKID && 611 ((sdev_peer = simnet_dev_lookup(peerid)) != NULL)) { 612 /* Attach peer device back */ 613 ASSERT(sdev_peer->sd_peer_dev == NULL); 614 sdev_peer->sd_peer_dev = sdev; 615 sdev->sd_peer_dev = sdev_peer; 616 /* Hold reference on both devices */ 617 } else { 618 /* 619 * No previous peer or previous peer no longer 620 * available so release lookup reference. 621 */ 622 simnet_dev_unref(sdev); 623 } 624 625 rw_exit(&simnet_dev_lock); 626 return (err); 627 } 628 629 /* ARGSUSED */ 630 static int 631 simnet_ioc_info(void *karg, intptr_t arg, int mode, cred_t *cred, int *rvalp) 632 { 633 simnet_ioc_info_t *info_arg = karg; 634 simnet_dev_t *sdev; 635 636 /* Make sure that the simnet link is visible from the caller's zone. */ 637 if (!dls_devnet_islinkvisible(info_arg->sii_link_id, crgetzoneid(cred))) 638 return (ENOENT); 639 640 rw_enter(&simnet_dev_lock, RW_READER); 641 if ((sdev = simnet_dev_lookup(info_arg->sii_link_id)) == NULL) { 642 rw_exit(&simnet_dev_lock); 643 return (ENOENT); 644 } 645 646 (void) memcpy(info_arg->sii_mac_addr, sdev->sd_mac_addr, 647 sdev->sd_mac_len); 648 info_arg->sii_mac_len = sdev->sd_mac_len; 649 info_arg->sii_type = sdev->sd_type; 650 if (sdev->sd_peer_dev != NULL) 651 info_arg->sii_peer_link_id = sdev->sd_peer_dev->sd_link_id; 652 rw_exit(&simnet_dev_lock); 653 simnet_dev_unref(sdev); 654 return (0); 655 } 656 657 static boolean_t 658 simnet_thread_ref(simnet_dev_t *sdev) 659 { 660 mutex_enter(&sdev->sd_instlock); 661 if (sdev->sd_flags & SDF_SHUTDOWN || 662 !(sdev->sd_flags & SDF_STARTED)) { 663 mutex_exit(&sdev->sd_instlock); 664 return (B_FALSE); 665 } 666 sdev->sd_threadcount++; 667 mutex_exit(&sdev->sd_instlock); 668 return (B_TRUE); 669 } 670 671 static void 672 simnet_thread_unref(simnet_dev_t *sdev) 673 { 674 mutex_enter(&sdev->sd_instlock); 675 if (--sdev->sd_threadcount == 0) 676 cv_broadcast(&sdev->sd_threadwait); 677 mutex_exit(&sdev->sd_instlock); 678 } 679 680 /* 681 * TODO: Add properties to set Rx checksum flag behavior. 682 * 683 * o HCK_PARTIALCKSUM. 684 * o HCK_FULLCKSUM_OK. 685 */ 686 static void 687 simnet_rx(void *arg) 688 { 689 mblk_t *mp = arg; 690 mac_header_info_t hdr_info; 691 simnet_dev_t *sdev; 692 693 sdev = (simnet_dev_t *)mp->b_next; 694 mp->b_next = NULL; 695 696 /* Check for valid packet header */ 697 if (mac_header_info(sdev->sd_mh, mp, &hdr_info) != 0) { 698 mac_drop_pkt(mp, "invalid L2 header"); 699 sdev->sd_stats.recv_errors++; 700 goto rx_done; 701 } 702 703 /* 704 * When we are NOT in promiscuous mode we only receive 705 * unicast packets addressed to us and multicast packets that 706 * MAC clients have requested. 707 */ 708 if (!sdev->sd_promisc && 709 hdr_info.mhi_dsttype != MAC_ADDRTYPE_BROADCAST) { 710 if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_UNICAST && 711 bcmp(hdr_info.mhi_daddr, sdev->sd_mac_addr, 712 ETHERADDRL) != 0) { 713 freemsg(mp); 714 goto rx_done; 715 } else if (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST) { 716 mutex_enter(&sdev->sd_instlock); 717 if (mcastaddr_lookup(sdev, hdr_info.mhi_daddr) == 718 NULL) { 719 mutex_exit(&sdev->sd_instlock); 720 freemsg(mp); 721 goto rx_done; 722 } 723 mutex_exit(&sdev->sd_instlock); 724 } 725 } 726 727 /* 728 * We don't actually calculate and verify the IP header 729 * checksum because the nature of simnet makes it redundant to 730 * do so. The point is to test the presence of the flags. The 731 * Tx side will have already populated the checksum field. 732 */ 733 if ((sdev->sd_rx_cksum & HCKSUM_IPHDRCKSUM) != 0) { 734 mac_hcksum_set(mp, 0, 0, 0, 0, HCK_IPV4_HDRCKSUM_OK); 735 } 736 737 sdev->sd_stats.recv_count++; 738 sdev->sd_stats.rbytes += msgdsize(mp); 739 mac_rx(sdev->sd_mh, NULL, mp); 740 rx_done: 741 simnet_thread_unref(sdev); 742 } 743 744 #define SIMNET_ULP_CKSUM (HCKSUM_INET_FULL_V4 | HCKSUM_INET_PARTIAL) 745 746 static mblk_t * 747 simnet_m_tx(void *arg, mblk_t *mp_chain) 748 { 749 simnet_dev_t *sdev = arg; 750 simnet_dev_t *sdev_rx; 751 mblk_t *mpnext = mp_chain; 752 mblk_t *mp, *nmp; 753 mac_emul_t emul = 0; 754 755 rw_enter(&simnet_dev_lock, RW_READER); 756 if ((sdev_rx = sdev->sd_peer_dev) == NULL) { 757 /* Discard packets when no peer exists */ 758 rw_exit(&simnet_dev_lock); 759 mac_drop_chain(mp_chain, "no peer"); 760 return (NULL); 761 } 762 763 /* 764 * Discard packets when either device is shutting down or not ready. 765 * Though MAC layer ensures a reference is held on the MAC while we 766 * process the packet chain, there is no guarantee the peer MAC will 767 * remain enabled. So we increment per-instance threadcount to ensure 768 * either MAC instance is not disabled while we handle the chain of 769 * packets. It is okay if the peer device is disconnected while we are 770 * here since we lookup the peer device while holding simnet_dev_lock 771 * (reader lock) and increment the threadcount of the peer, the peer 772 * MAC cannot be disabled in simnet_ioc_delete. 773 */ 774 if (!simnet_thread_ref(sdev_rx)) { 775 rw_exit(&simnet_dev_lock); 776 mac_drop_chain(mp_chain, "simnet peer dev not ready"); 777 return (NULL); 778 } 779 rw_exit(&simnet_dev_lock); 780 781 if (!simnet_thread_ref(sdev)) { 782 simnet_thread_unref(sdev_rx); 783 mac_drop_chain(mp_chain, "simnet dev not ready"); 784 return (NULL); 785 } 786 787 while ((mp = mpnext) != NULL) { 788 size_t len; 789 size_t size; 790 mblk_t *mp_new; 791 mblk_t *mp_tmp; 792 793 mpnext = mp->b_next; 794 mp->b_next = NULL; 795 len = msgdsize(mp); 796 797 /* Pad packet to minimum Ethernet frame size */ 798 if (len < ETHERMIN) { 799 size = ETHERMIN - len; 800 mp_new = allocb(size, BPRI_HI); 801 if (mp_new == NULL) { 802 sdev->sd_stats.xmit_errors++; 803 mac_drop_pkt(mp, "allocb failed"); 804 continue; 805 } 806 bzero(mp_new->b_wptr, size); 807 mp_new->b_wptr += size; 808 809 mp_tmp = mp; 810 while (mp_tmp->b_cont != NULL) 811 mp_tmp = mp_tmp->b_cont; 812 mp_tmp->b_cont = mp_new; 813 len += size; 814 } 815 816 /* Pullup packet into a single mblk */ 817 if ((nmp = msgpullup(mp, -1)) == NULL) { 818 sdev->sd_stats.xmit_errors++; 819 mac_drop_pkt(mp, "msgpullup failed"); 820 continue; 821 } else { 822 mac_hcksum_clone(mp, nmp); 823 freemsg(mp); 824 mp = nmp; 825 } 826 827 /* Hold reference for taskq receive processing per-pkt */ 828 if (!simnet_thread_ref(sdev_rx)) { 829 mac_drop_pkt(mp, "failed to get thread ref"); 830 mac_drop_chain(mpnext, "failed to get thread ref"); 831 break; 832 } 833 834 if ((sdev->sd_tx_cksum & HCKSUM_IPHDRCKSUM) != 0) 835 emul |= MAC_IPCKSUM_EMUL; 836 if ((sdev->sd_tx_cksum & SIMNET_ULP_CKSUM) != 0) 837 emul |= MAC_HWCKSUM_EMUL; 838 if (sdev->sd_lso) 839 emul |= MAC_LSO_EMUL; 840 841 if (emul != 0) 842 mac_hw_emul(&mp, NULL, NULL, emul); 843 844 if (mp == NULL) { 845 sdev->sd_stats.xmit_errors++; 846 continue; 847 } 848 849 /* 850 * Remember, we are emulating a real NIC here; the 851 * checksum flags can't make the trip across the link. 852 */ 853 DB_CKSUMFLAGS(mp) = 0; 854 855 /* Use taskq for pkt receive to avoid kernel stack explosion */ 856 mp->b_next = (mblk_t *)sdev_rx; 857 if (ddi_taskq_dispatch(simnet_rxq, simnet_rx, mp, 858 DDI_NOSLEEP) == DDI_SUCCESS) { 859 sdev->sd_stats.xmit_count++; 860 sdev->sd_stats.obytes += len; 861 } else { 862 simnet_thread_unref(sdev_rx); 863 mp->b_next = NULL; 864 freemsg(mp); 865 sdev_rx->sd_stats.recv_errors++; 866 } 867 } 868 869 simnet_thread_unref(sdev); 870 simnet_thread_unref(sdev_rx); 871 return (NULL); 872 } 873 874 static int 875 simnet_wifi_ioctl(simnet_dev_t *sdev, mblk_t *mp) 876 { 877 int rc = WL_SUCCESS; 878 simnet_wifidev_t *wdev = sdev->sd_wifidev; 879 880 /* LINTED E_BAD_PTR_CAST_ALIGN */ 881 switch (((wldp_t *)mp->b_rptr)->wldp_id) { 882 case WL_DISASSOCIATE: 883 wdev->swd_linkstatus = WL_NOTCONNECTED; 884 break; 885 default: 886 break; 887 } 888 return (rc); 889 } 890 891 static void 892 simnet_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 893 { 894 simnet_dev_t *sdev = arg; 895 struct iocblk *iocp; 896 mblk_t *mp1; 897 uint32_t cmd; 898 int rc; 899 900 if (sdev->sd_type != DL_WIFI) { 901 miocnak(q, mp, 0, ENOTSUP); 902 return; 903 } 904 905 /* LINTED E_BAD_PTR_CAST_ALIGN */ 906 iocp = (struct iocblk *)mp->b_rptr; 907 if (iocp->ioc_count == 0) { 908 miocnak(q, mp, 0, EINVAL); 909 return; 910 } 911 912 /* We only claim support for WiFi operation commands */ 913 cmd = iocp->ioc_cmd; 914 switch (cmd) { 915 default: 916 miocnak(q, mp, 0, EINVAL); 917 return; 918 case WLAN_GET_PARAM: 919 case WLAN_SET_PARAM: 920 case WLAN_COMMAND: 921 break; 922 } 923 924 mp1 = mp->b_cont; 925 freemsg(mp1->b_cont); 926 mp1->b_cont = NULL; 927 /* overwrite everything */ 928 mp1->b_wptr = mp1->b_rptr; 929 rc = simnet_wifi_ioctl(sdev, mp1); 930 miocack(q, mp, msgdsize(mp1), rc); 931 } 932 933 static boolean_t 934 simnet_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 935 { 936 simnet_dev_t *sdev = arg; 937 const uint_t tcp_cksums = HCKSUM_INET_FULL_V4 | HCKSUM_INET_PARTIAL; 938 939 switch (cap) { 940 case MAC_CAPAB_HCKSUM: { 941 uint32_t *tx_cksum_flags = cap_data; 942 *tx_cksum_flags = sdev->sd_tx_cksum; 943 break; 944 } 945 case MAC_CAPAB_LSO: { 946 mac_capab_lso_t *cap_lso = cap_data; 947 948 if (sdev->sd_lso && 949 (sdev->sd_tx_cksum & HCKSUM_IPHDRCKSUM) != 0 && 950 (sdev->sd_tx_cksum & tcp_cksums) != 0) { 951 /* 952 * The LSO configuration is hardwried for now, 953 * but there's no reason we couldn't also make 954 * this configurable in the future. 955 */ 956 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; 957 cap_lso->lso_basic_tcp_ipv4.lso_max = SD_LSO_MAXLEN; 958 break; 959 } else { 960 return (B_FALSE); 961 } 962 } 963 default: 964 return (B_FALSE); 965 } 966 967 return (B_TRUE); 968 } 969 970 static int 971 simnet_m_stat(void *arg, uint_t stat, uint64_t *val) 972 { 973 int rval = 0; 974 simnet_dev_t *sdev = arg; 975 976 ASSERT(sdev->sd_mh != NULL); 977 978 switch (stat) { 979 case MAC_STAT_IFSPEED: 980 *val = 100 * 1000000ull; /* 100 Mbps */ 981 break; 982 case MAC_STAT_LINK_STATE: 983 *val = LINK_DUPLEX_FULL; 984 break; 985 case MAC_STAT_LINK_UP: 986 if (sdev->sd_flags & SDF_STARTED) 987 *val = LINK_STATE_UP; 988 else 989 *val = LINK_STATE_DOWN; 990 break; 991 case MAC_STAT_PROMISC: 992 case MAC_STAT_MULTIRCV: 993 case MAC_STAT_MULTIXMT: 994 case MAC_STAT_BRDCSTRCV: 995 case MAC_STAT_BRDCSTXMT: 996 rval = ENOTSUP; 997 break; 998 case MAC_STAT_OPACKETS: 999 *val = sdev->sd_stats.xmit_count; 1000 break; 1001 case MAC_STAT_OBYTES: 1002 *val = sdev->sd_stats.obytes; 1003 break; 1004 case MAC_STAT_IERRORS: 1005 *val = sdev->sd_stats.recv_errors; 1006 break; 1007 case MAC_STAT_OERRORS: 1008 *val = sdev->sd_stats.xmit_errors; 1009 break; 1010 case MAC_STAT_RBYTES: 1011 *val = sdev->sd_stats.rbytes; 1012 break; 1013 case MAC_STAT_IPACKETS: 1014 *val = sdev->sd_stats.recv_count; 1015 break; 1016 case WIFI_STAT_FCS_ERRORS: 1017 case WIFI_STAT_WEP_ERRORS: 1018 case WIFI_STAT_TX_FRAGS: 1019 case WIFI_STAT_MCAST_TX: 1020 case WIFI_STAT_RTS_SUCCESS: 1021 case WIFI_STAT_RTS_FAILURE: 1022 case WIFI_STAT_ACK_FAILURE: 1023 case WIFI_STAT_RX_FRAGS: 1024 case WIFI_STAT_MCAST_RX: 1025 case WIFI_STAT_RX_DUPS: 1026 rval = ENOTSUP; 1027 break; 1028 default: 1029 rval = ENOTSUP; 1030 break; 1031 } 1032 1033 return (rval); 1034 } 1035 1036 static int 1037 simnet_m_start(void *arg) 1038 { 1039 simnet_dev_t *sdev = arg; 1040 1041 sdev->sd_flags |= SDF_STARTED; 1042 return (0); 1043 } 1044 1045 static void 1046 simnet_m_stop(void *arg) 1047 { 1048 simnet_dev_t *sdev = arg; 1049 1050 sdev->sd_flags &= ~SDF_STARTED; 1051 } 1052 1053 static int 1054 simnet_m_promisc(void *arg, boolean_t on) 1055 { 1056 simnet_dev_t *sdev = arg; 1057 1058 sdev->sd_promisc = on; 1059 return (0); 1060 } 1061 1062 /* 1063 * Returns matching multicast address enabled on the simnet instance. 1064 * Assumes simnet instance mutex lock is held. 1065 */ 1066 static const struct ether_addr * 1067 mcastaddr_lookup(const simnet_dev_t *sdev, const uint8_t *addrp) 1068 { 1069 ASSERT(MUTEX_HELD(&sdev->sd_instlock)); 1070 for (uint_t i = 0; i < sdev->sd_mcastaddr_count; i++) { 1071 const struct ether_addr *maddrp = &sdev->sd_mcastaddrs[i]; 1072 1073 if (bcmp(maddrp->ether_addr_octet, addrp, 1074 sizeof (maddrp->ether_addr_octet)) == 0) { 1075 return (maddrp); 1076 } 1077 } 1078 1079 return (NULL); 1080 } 1081 1082 static int 1083 simnet_multicst_add(simnet_dev_t *sdev, const struct ether_addr *eap) 1084 { 1085 ASSERT(MUTEX_HELD(&sdev->sd_instlock)); 1086 1087 if ((eap->ether_addr_octet[0] & 01) == 0) { 1088 return (EINVAL); 1089 } 1090 1091 if (sdev->sd_mcastaddr_count == SM_MAX_NUM_MCAST_ADDRS) { 1092 return (ENOSPC); 1093 } 1094 1095 bcopy(eap, &sdev->sd_mcastaddrs[sdev->sd_mcastaddr_count], 1096 sizeof (*eap)); 1097 sdev->sd_mcastaddr_count++; 1098 return (0); 1099 } 1100 1101 static int 1102 simnet_multicst_rm(simnet_dev_t *sdev, const struct ether_addr *eap) 1103 { 1104 ASSERT(MUTEX_HELD(&sdev->sd_instlock)); 1105 1106 for (uint_t i = 0; i < sdev->sd_mcastaddr_count; i++) { 1107 if (bcmp(eap, &sdev->sd_mcastaddrs[i], sizeof (*eap)) == 0) { 1108 for (i++; i < sdev->sd_mcastaddr_count; i++) { 1109 sdev->sd_mcastaddrs[i - 1] = 1110 sdev->sd_mcastaddrs[i]; 1111 } 1112 1113 /* Zero-out the last entry as it is no longer valid. */ 1114 bzero(&sdev->sd_mcastaddrs[i - 1], 1115 sizeof (sdev->sd_mcastaddrs[0])); 1116 1117 sdev->sd_mcastaddr_count--; 1118 return (0); 1119 } 1120 } 1121 1122 return (EINVAL); 1123 } 1124 1125 /* Add or remove Multicast addresses on simnet instance */ 1126 static int 1127 simnet_m_multicst(void *arg, boolean_t add, const uint8_t *addrp) 1128 { 1129 simnet_dev_t *sdev = arg; 1130 struct ether_addr ea; 1131 int ret; 1132 1133 bcopy(addrp, ea.ether_addr_octet, sizeof (ea.ether_addr_octet)); 1134 mutex_enter(&sdev->sd_instlock); 1135 1136 if (add) { 1137 ret = simnet_multicst_add(sdev, &ea); 1138 } else { 1139 ret = simnet_multicst_rm(sdev, &ea); 1140 } 1141 1142 ASSERT3U(sdev->sd_mcastaddr_count, <=, SM_MAX_NUM_MCAST_ADDRS); 1143 mutex_exit(&sdev->sd_instlock); 1144 return (ret); 1145 } 1146 1147 static int 1148 simnet_m_unicst(void *arg, const uint8_t *macaddr) 1149 { 1150 simnet_dev_t *sdev = arg; 1151 1152 (void) memcpy(sdev->sd_mac_addr, macaddr, ETHERADDRL); 1153 return (0); 1154 } 1155 1156 /* Parse WiFi scan list entry arguments and return the arg count */ 1157 static int 1158 parse_esslist_args(const void *pr_val, uint_t pr_valsize, 1159 char args[][MAX_ESSLIST_ARGLEN]) 1160 { 1161 char *sep; 1162 ptrdiff_t len = pr_valsize; 1163 const char *piece = pr_val; 1164 const char *end = (const char *)pr_val + pr_valsize - 1; 1165 int arg = 0; 1166 1167 while (piece < end && (arg < MAX_ESSLIST_ARGS)) { 1168 sep = strchr(piece, ','); 1169 if (sep == NULL) 1170 sep = (char *)end; 1171 /* LINTED E_PTRDIFF_OVERFLOW */ 1172 len = sep - piece; 1173 /* If first arg is zero then return none to delete all */ 1174 if (arg == 0 && strnlen(piece, len) == 1 && piece[0] == '0') 1175 return (0); 1176 if (len > MAX_ESSLIST_ARGLEN) 1177 len = MAX_ESSLIST_ARGLEN - 1; 1178 (void) memcpy(&args[arg][0], piece, len); 1179 args[arg][len] = '\0'; 1180 piece = sep + 1; 1181 arg++; 1182 } 1183 1184 return (arg); 1185 } 1186 1187 /* Set WiFi scan list entry from private property _wl_esslist */ 1188 static int 1189 set_wl_esslist_priv_prop(simnet_wifidev_t *wdev, uint_t pr_valsize, 1190 const void *pr_val) 1191 { 1192 char essargs[MAX_ESSLIST_ARGS][MAX_ESSLIST_ARGLEN]; 1193 wl_ess_conf_t *wls; 1194 long result; 1195 int i; 1196 1197 bzero(essargs, sizeof (essargs)); 1198 if (parse_esslist_args(pr_val, pr_valsize, essargs) == 0) { 1199 for (i = 0; i < wdev->swd_esslist_num; i++) { 1200 kmem_free(wdev->swd_esslist[i], sizeof (wl_ess_conf_t)); 1201 wdev->swd_esslist[i] = NULL; 1202 } 1203 wdev->swd_esslist_num = 0; 1204 return (0); 1205 } 1206 1207 for (i = 0; i < wdev->swd_esslist_num; i++) { 1208 wls = wdev->swd_esslist[i]; 1209 if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid, 1210 essargs[0]) == 0) 1211 return (EEXIST); 1212 } 1213 1214 if (wdev->swd_esslist_num >= MAX_SIMNET_ESSCONF) 1215 return (EINVAL); 1216 1217 wls = kmem_zalloc(sizeof (wl_ess_conf_t), KM_SLEEP); 1218 (void) strlcpy(wls->wl_ess_conf_essid.wl_essid_essid, 1219 essargs[0], sizeof (wls->wl_ess_conf_essid.wl_essid_essid)); 1220 wls->wl_ess_conf_essid.wl_essid_length = 1221 strlen(wls->wl_ess_conf_essid.wl_essid_essid); 1222 (void) random_get_pseudo_bytes((uint8_t *) 1223 &wls->wl_ess_conf_bssid, sizeof (wl_bssid_t)); 1224 (void) ddi_strtol(essargs[1], (char **)NULL, 0, &result); 1225 wls->wl_ess_conf_sl = (wl_rssi_t) 1226 ((result > MAX_RSSI || result < 0) ? 0:result); 1227 wdev->swd_esslist[wdev->swd_esslist_num] = wls; 1228 wdev->swd_esslist_num++; 1229 1230 return (0); 1231 } 1232 1233 static int 1234 simnet_set_priv_prop_wifi(simnet_dev_t *sdev, const char *name, 1235 const uint_t len, const void *val) 1236 { 1237 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1238 long result; 1239 1240 if (strcmp(name, "_wl_esslist") == 0) { 1241 if (val == NULL) 1242 return (EINVAL); 1243 return (set_wl_esslist_priv_prop(wdev, len, val)); 1244 } else if (strcmp(name, "_wl_connected") == 0) { 1245 if (val == NULL) 1246 return (EINVAL); 1247 (void) ddi_strtol(val, (char **)NULL, 0, &result); 1248 wdev->swd_linkstatus = ((result == 1) ? 1249 WL_CONNECTED:WL_NOTCONNECTED); 1250 return (0); 1251 } 1252 1253 return (EINVAL); 1254 } 1255 1256 /* ARGSUSED */ 1257 static int 1258 simnet_set_priv_prop_ether(simnet_dev_t *sdev, const char *name, 1259 const uint_t len, const void *val) 1260 { 1261 if (strcmp(name, SD_PROP_RX_IP_CKSUM) == 0) { 1262 if (val == NULL) 1263 return (EINVAL); 1264 1265 if (strcmp(val, "off") == 0) { 1266 sdev->sd_rx_cksum &= ~HCKSUM_IPHDRCKSUM; 1267 } else if (strcmp(val, "on") == 0) { 1268 sdev->sd_rx_cksum |= HCKSUM_IPHDRCKSUM; 1269 } else { 1270 return (EINVAL); 1271 } 1272 1273 return (0); 1274 } else if (strcmp(name, SD_PROP_TX_ULP_CKSUM) == 0) { 1275 if (val == NULL) 1276 return (EINVAL); 1277 1278 /* 1279 * Remember, full and partial checksum are mutually 1280 * exclusive. 1281 */ 1282 if (strcmp(val, "none") == 0) { 1283 sdev->sd_tx_cksum &= ~HCKSUM_INET_FULL_V4; 1284 } else if (strcmp(val, "fullv4") == 0) { 1285 sdev->sd_tx_cksum &= ~HCKSUM_INET_PARTIAL; 1286 sdev->sd_tx_cksum |= HCKSUM_INET_FULL_V4; 1287 } else if (strcmp(val, "partial") == 0) { 1288 sdev->sd_tx_cksum &= HCKSUM_INET_FULL_V4; 1289 sdev->sd_tx_cksum |= HCKSUM_INET_PARTIAL; 1290 } else { 1291 return (EINVAL); 1292 } 1293 1294 return (0); 1295 } else if (strcmp(name, SD_PROP_TX_IP_CKSUM) == 0) { 1296 if (val == NULL) 1297 return (EINVAL); 1298 1299 if (strcmp(val, "off") == 0) { 1300 sdev->sd_tx_cksum &= ~HCKSUM_IPHDRCKSUM; 1301 } else if (strcmp(val, "on") == 0) { 1302 sdev->sd_tx_cksum |= HCKSUM_IPHDRCKSUM; 1303 } else { 1304 return (EINVAL); 1305 } 1306 1307 return (0); 1308 } else if (strcmp(name, SD_PROP_LSO) == 0) { 1309 if (val == NULL) 1310 return (EINVAL); 1311 1312 if (strcmp(val, "off") == 0) { 1313 sdev->sd_lso = B_FALSE; 1314 } else if (strcmp(val, "on") == 0) { 1315 sdev->sd_lso = B_TRUE; 1316 } else { 1317 return (EINVAL); 1318 } 1319 1320 return (0); 1321 } else if (strcmp(name, SD_PROP_LINKSTATE) == 0) { 1322 if (val == NULL) 1323 return (EINVAL); 1324 1325 if (strcmp(val, "up") == 0) { 1326 sdev->sd_ls = LINK_STATE_UP; 1327 } else if (strcmp(val, "down") == 0) { 1328 sdev->sd_ls = LINK_STATE_DOWN; 1329 } else if (strcmp(val, "unknown") == 0) { 1330 sdev->sd_ls = LINK_STATE_UNKNOWN; 1331 } else { 1332 return (EINVAL); 1333 } 1334 mac_link_update(sdev->sd_mh, sdev->sd_ls); 1335 1336 return (0); 1337 } 1338 1339 return (ENOTSUP); 1340 } 1341 1342 static int 1343 simnet_setprop_wifi(simnet_dev_t *sdev, const char *name, 1344 const mac_prop_id_t num, const uint_t len, const void *val) 1345 { 1346 int err = 0; 1347 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1348 1349 switch (num) { 1350 case MAC_PROP_WL_ESSID: { 1351 int i; 1352 wl_ess_conf_t *wls; 1353 1354 (void) memcpy(&wdev->swd_essid, val, sizeof (wl_essid_t)); 1355 wdev->swd_linkstatus = WL_CONNECTED; 1356 1357 /* Lookup the signal strength of the connected ESSID */ 1358 for (i = 0; i < wdev->swd_esslist_num; i++) { 1359 wls = wdev->swd_esslist[i]; 1360 if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid, 1361 wdev->swd_essid.wl_essid_essid) == 0) { 1362 wdev->swd_rssi = wls->wl_ess_conf_sl; 1363 break; 1364 } 1365 } 1366 break; 1367 } 1368 case MAC_PROP_WL_BSSID: { 1369 (void) memcpy(&wdev->swd_bssid, val, sizeof (wl_bssid_t)); 1370 break; 1371 } 1372 case MAC_PROP_WL_PHY_CONFIG: 1373 case MAC_PROP_WL_KEY_TAB: 1374 case MAC_PROP_WL_AUTH_MODE: 1375 case MAC_PROP_WL_ENCRYPTION: 1376 case MAC_PROP_WL_BSSTYPE: 1377 case MAC_PROP_WL_DESIRED_RATES: 1378 break; 1379 case MAC_PROP_PRIVATE: 1380 err = simnet_set_priv_prop_wifi(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_setprop_ether(simnet_dev_t *sdev, const char *name, 1392 const mac_prop_id_t num, const uint_t len, const void *val) 1393 { 1394 int err = 0; 1395 1396 switch (num) { 1397 case MAC_PROP_PRIVATE: 1398 err = simnet_set_priv_prop_ether(sdev, name, len, val); 1399 break; 1400 default: 1401 err = EINVAL; 1402 break; 1403 } 1404 1405 return (err); 1406 } 1407 1408 static int 1409 simnet_m_setprop(void *arg, const char *name, mac_prop_id_t num, 1410 const uint_t len, const void *val) 1411 { 1412 simnet_dev_t *sdev = arg; 1413 int err = 0; 1414 uint32_t mtu; 1415 1416 switch (num) { 1417 case MAC_PROP_MTU: 1418 (void) memcpy(&mtu, val, sizeof (mtu)); 1419 if (mtu > ETHERMIN && mtu < SIMNET_MAX_MTU) 1420 return (mac_maxsdu_update(sdev->sd_mh, mtu)); 1421 else 1422 return (EINVAL); 1423 default: 1424 break; 1425 } 1426 1427 switch (sdev->sd_type) { 1428 case DL_ETHER: 1429 err = simnet_setprop_ether(sdev, name, num, len, val); 1430 break; 1431 case DL_WIFI: 1432 err = simnet_setprop_wifi(sdev, name, num, len, val); 1433 break; 1434 default: 1435 err = EINVAL; 1436 break; 1437 } 1438 1439 /* 1440 * We may have modified the configuration of hardware 1441 * offloads. Make sure to renegotiate capabilities with the 1442 * upstream clients. 1443 */ 1444 mac_capab_update(sdev->sd_mh); 1445 return (err); 1446 } 1447 1448 static int 1449 simnet_get_priv_prop_wifi(const simnet_dev_t *sdev, const char *name, 1450 const uint_t len, void *val) 1451 { 1452 simnet_wifidev_t *wdev = sdev->sd_wifidev; 1453 int ret, value; 1454 1455 if (strcmp(name, "_wl_esslist") == 0) { 1456 /* Returns num of _wl_ess_conf_t that have been set */ 1457 value = wdev->swd_esslist_num; 1458 } else if (strcmp(name, "_wl_connected") == 0) { 1459 value = ((wdev->swd_linkstatus == WL_CONNECTED) ? 1:0); 1460 } else { 1461 return (ENOTSUP); 1462 } 1463 1464 ret = snprintf(val, len, "%d", value); 1465 1466 if (ret < 0 || ret >= len) 1467 return (EOVERFLOW); 1468 1469 return (0); 1470 } 1471 1472 static int 1473 simnet_get_priv_prop_ether(const simnet_dev_t *sdev, const char *name, 1474 const uint_t len, void *val) 1475 { 1476 int ret; 1477 char *value; 1478 1479 if (strcmp(name, SD_PROP_RX_IP_CKSUM) == 0) { 1480 if ((sdev->sd_rx_cksum & HCKSUM_IPHDRCKSUM) != 0) { 1481 value = "on"; 1482 } else { 1483 value = "off"; 1484 } 1485 } else if (strcmp(name, SD_PROP_TX_ULP_CKSUM) == 0) { 1486 if ((sdev->sd_tx_cksum & HCKSUM_INET_FULL_V4) != 0) { 1487 value = "fullv4"; 1488 } else if ((sdev->sd_tx_cksum & HCKSUM_INET_PARTIAL) != 0) { 1489 value = "partial"; 1490 } else { 1491 value = "none"; 1492 } 1493 } else if (strcmp(name, SD_PROP_TX_IP_CKSUM) == 0) { 1494 if ((sdev->sd_tx_cksum & HCKSUM_IPHDRCKSUM) != 0) { 1495 value = "on"; 1496 } else { 1497 value = "off"; 1498 } 1499 } else if (strcmp(name, SD_PROP_LSO) == 0) { 1500 value = sdev->sd_lso ? "on" : "off"; 1501 } else if (strcmp(name, SD_PROP_LINKSTATE) == 0) { 1502 if (sdev->sd_ls == LINK_STATE_UP) { 1503 value = "up"; 1504 } else if (sdev->sd_ls == LINK_STATE_DOWN) { 1505 value = "down"; 1506 } else { 1507 value = "unknown"; 1508 } 1509 } else { 1510 return (ENOTSUP); 1511 } 1512 1513 ret = snprintf(val, len, "%s", value); 1514 1515 if (ret < 0 || ret >= len) { 1516 return (EOVERFLOW); 1517 } 1518 1519 return (0); 1520 } 1521 1522 static int 1523 simnet_getprop_wifi(const simnet_dev_t *sdev, const char *name, 1524 const mac_prop_id_t num, const uint_t len, void *val) 1525 { 1526 const simnet_wifidev_t *wdev = sdev->sd_wifidev; 1527 int err = 0; 1528 1529 switch (num) { 1530 case MAC_PROP_WL_ESSID: 1531 (void) memcpy(val, &wdev->swd_essid, sizeof (wl_essid_t)); 1532 break; 1533 case MAC_PROP_WL_BSSID: 1534 (void) memcpy(val, &wdev->swd_bssid, sizeof (wl_bssid_t)); 1535 break; 1536 case MAC_PROP_WL_PHY_CONFIG: 1537 case MAC_PROP_WL_AUTH_MODE: 1538 case MAC_PROP_WL_ENCRYPTION: 1539 break; 1540 case MAC_PROP_WL_LINKSTATUS: 1541 (void) memcpy(val, &wdev->swd_linkstatus, 1542 sizeof (wdev->swd_linkstatus)); 1543 break; 1544 case MAC_PROP_WL_ESS_LIST: { 1545 wl_ess_conf_t *w_ess_conf; 1546 1547 ((wl_ess_list_t *)val)->wl_ess_list_num = wdev->swd_esslist_num; 1548 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1549 w_ess_conf = (wl_ess_conf_t *)((char *)val + 1550 offsetof(wl_ess_list_t, wl_ess_list_ess)); 1551 for (uint_t i = 0; i < wdev->swd_esslist_num; i++) { 1552 (void) memcpy(w_ess_conf, wdev->swd_esslist[i], 1553 sizeof (wl_ess_conf_t)); 1554 w_ess_conf++; 1555 } 1556 break; 1557 } 1558 case MAC_PROP_WL_RSSI: 1559 *(wl_rssi_t *)val = wdev->swd_rssi; 1560 break; 1561 case MAC_PROP_WL_RADIO: 1562 *(wl_radio_t *)val = B_TRUE; 1563 break; 1564 case MAC_PROP_WL_POWER_MODE: 1565 break; 1566 case MAC_PROP_WL_DESIRED_RATES: 1567 break; 1568 case MAC_PROP_PRIVATE: 1569 err = simnet_get_priv_prop_wifi(sdev, name, len, val); 1570 break; 1571 default: 1572 err = ENOTSUP; 1573 break; 1574 } 1575 1576 return (err); 1577 } 1578 1579 static int 1580 simnet_getprop_ether(const simnet_dev_t *sdev, const char *name, 1581 const mac_prop_id_t num, const uint_t len, void *val) 1582 { 1583 int err = 0; 1584 1585 switch (num) { 1586 case MAC_PROP_PRIVATE: 1587 err = simnet_get_priv_prop_ether(sdev, name, len, val); 1588 break; 1589 default: 1590 err = ENOTSUP; 1591 break; 1592 } 1593 1594 return (err); 1595 } 1596 1597 static int 1598 simnet_m_getprop(void *arg, const char *name, const mac_prop_id_t num, 1599 const uint_t len, void *val) 1600 { 1601 const simnet_dev_t *sdev = arg; 1602 int err = 0; 1603 1604 switch (sdev->sd_type) { 1605 case DL_ETHER: 1606 err = simnet_getprop_ether(sdev, name, num, len, val); 1607 break; 1608 case DL_WIFI: 1609 err = simnet_getprop_wifi(sdev, name, num, len, val); 1610 break; 1611 default: 1612 err = EINVAL; 1613 break; 1614 } 1615 1616 return (err); 1617 } 1618 1619 static void 1620 simnet_priv_propinfo_wifi(const char *name, mac_prop_info_handle_t prh) 1621 { 1622 char valstr[MAXNAMELEN]; 1623 1624 bzero(valstr, sizeof (valstr)); 1625 1626 if (strcmp(name, "_wl_esslist") == 0) { 1627 (void) snprintf(valstr, sizeof (valstr), "%d", 0); 1628 } 1629 1630 if (strlen(valstr) > 0) 1631 mac_prop_info_set_default_str(prh, valstr); 1632 } 1633 1634 static void 1635 simnet_propinfo_wifi(const char *name, const mac_prop_id_t num, 1636 mac_prop_info_handle_t prh) 1637 { 1638 switch (num) { 1639 case MAC_PROP_WL_BSSTYPE: 1640 case MAC_PROP_WL_ESS_LIST: 1641 case MAC_PROP_WL_SUPPORTED_RATES: 1642 case MAC_PROP_WL_RSSI: 1643 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1644 break; 1645 case MAC_PROP_PRIVATE: 1646 simnet_priv_propinfo_wifi(name, prh); 1647 break; 1648 } 1649 } 1650 1651 static void 1652 simnet_priv_propinfo_ether(const char *name, mac_prop_info_handle_t prh) 1653 { 1654 if (strcmp(name, SD_PROP_RX_IP_CKSUM) == 0 || 1655 strcmp(name, SD_PROP_TX_ULP_CKSUM) == 0 || 1656 strcmp(name, SD_PROP_TX_IP_CKSUM) == 0 || 1657 strcmp(name, SD_PROP_LSO) == 0) { 1658 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 1659 } 1660 1661 if (strcmp(name, SD_PROP_TX_ULP_CKSUM) == 0) { 1662 mac_prop_info_set_default_str(prh, "none"); 1663 } 1664 1665 if (strcmp(name, SD_PROP_RX_IP_CKSUM) == 0 || 1666 strcmp(name, SD_PROP_TX_IP_CKSUM) == 0 || 1667 strcmp(name, SD_PROP_LSO) == 0) { 1668 mac_prop_info_set_default_str(prh, "off"); 1669 } 1670 if (strcmp(name, SD_PROP_LINKSTATE) == 0) { 1671 mac_prop_info_set_default_str(prh, "unknown"); 1672 } 1673 } 1674 1675 static void 1676 simnet_propinfo_ether(const char *name, const mac_prop_id_t num, 1677 mac_prop_info_handle_t prh) 1678 { 1679 switch (num) { 1680 case MAC_PROP_PRIVATE: 1681 simnet_priv_propinfo_ether(name, prh); 1682 break; 1683 } 1684 } 1685 1686 static void 1687 simnet_m_propinfo(void *arg, const char *name, const mac_prop_id_t num, 1688 const mac_prop_info_handle_t prh) 1689 { 1690 simnet_dev_t *sdev = arg; 1691 1692 switch (sdev->sd_type) { 1693 case DL_ETHER: 1694 simnet_propinfo_ether(name, num, prh); 1695 break; 1696 case DL_WIFI: 1697 simnet_propinfo_wifi(name, num, prh); 1698 break; 1699 } 1700 } 1701