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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Data-Link Driver 28 */ 29 30 #include <sys/conf.h> 31 #include <sys/mkdev.h> 32 #include <sys/modctl.h> 33 #include <sys/stat.h> 34 #include <sys/vlan.h> 35 #include <sys/mac.h> 36 #include <sys/dld_impl.h> 37 #include <sys/dls_impl.h> 38 #include <sys/softmac.h> 39 #include <sys/vlan.h> 40 #include <sys/policy.h> 41 #include <inet/common.h> 42 43 static void drv_init(void); 44 static int drv_fini(void); 45 46 static int drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 47 static int drv_attach(dev_info_t *, ddi_attach_cmd_t); 48 static int drv_detach(dev_info_t *, ddi_detach_cmd_t); 49 50 /* 51 * Secure objects declarations 52 */ 53 #define SECOBJ_WEP_HASHSZ 67 54 static krwlock_t drv_secobj_lock; 55 static kmem_cache_t *drv_secobj_cachep; 56 static mod_hash_t *drv_secobj_hash; 57 static void drv_secobj_init(void); 58 static void drv_secobj_fini(void); 59 static int drv_ioc_setap(datalink_id_t, struct dlautopush *); 60 static int drv_ioc_getap(datalink_id_t, struct dlautopush *); 61 static int drv_ioc_clrap(datalink_id_t); 62 63 64 /* 65 * The following entry points are private to dld and are used for control 66 * operations only. The entry points exported to mac drivers are defined 67 * in dld_str.c. Refer to the comment on top of dld_str.c for details. 68 */ 69 static int drv_open(dev_t *, int, int, cred_t *); 70 static int drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 71 72 static dev_info_t *dld_dip; /* dev_info_t for the driver */ 73 uint32_t dld_opt = 0; /* Global options */ 74 75 #define NAUTOPUSH 32 76 static mod_hash_t *dld_ap_hashp; 77 static krwlock_t dld_ap_hash_lock; 78 79 static struct cb_ops drv_cb_ops = { 80 drv_open, /* open */ 81 nulldev, /* close */ 82 nulldev, /* strategy */ 83 nulldev, /* print */ 84 nodev, /* dump */ 85 nodev, /* read */ 86 nodev, /* write */ 87 drv_ioctl, /* ioctl */ 88 nodev, /* devmap */ 89 nodev, /* mmap */ 90 nodev, /* segmap */ 91 nochpoll, /* poll */ 92 ddi_prop_op, /* cb_prop_op */ 93 0, /* streamtab */ 94 D_MP /* Driver compatibility flag */ 95 }; 96 97 static struct dev_ops drv_ops = { 98 DEVO_REV, /* devo_rev */ 99 0, /* refcnt */ 100 drv_getinfo, /* get_dev_info */ 101 nulldev, /* identify */ 102 nulldev, /* probe */ 103 drv_attach, /* attach */ 104 drv_detach, /* detach */ 105 nodev, /* reset */ 106 &drv_cb_ops, /* driver operations */ 107 NULL, /* bus operations */ 108 nodev /* dev power */ 109 }; 110 111 /* 112 * Module linkage information for the kernel. 113 */ 114 static struct modldrv drv_modldrv = { 115 &mod_driverops, 116 DLD_INFO, 117 &drv_ops 118 }; 119 120 static struct modlinkage drv_modlinkage = { 121 MODREV_1, 122 &drv_modldrv, 123 NULL 124 }; 125 126 int 127 _init(void) 128 { 129 return (mod_install(&drv_modlinkage)); 130 } 131 132 int 133 _fini(void) 134 { 135 return (mod_remove(&drv_modlinkage)); 136 } 137 138 int 139 _info(struct modinfo *modinfop) 140 { 141 return (mod_info(&drv_modlinkage, modinfop)); 142 } 143 144 /* 145 * Initialize component modules. 146 */ 147 static void 148 drv_init(void) 149 { 150 drv_secobj_init(); 151 dld_str_init(); 152 /* 153 * Create a hash table for autopush configuration. 154 */ 155 dld_ap_hashp = mod_hash_create_idhash("dld_autopush_hash", 156 NAUTOPUSH, mod_hash_null_valdtor); 157 158 ASSERT(dld_ap_hashp != NULL); 159 rw_init(&dld_ap_hash_lock, NULL, RW_DRIVER, NULL); 160 } 161 162 /* ARGSUSED */ 163 static uint_t 164 drv_ap_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 165 { 166 boolean_t *pexist = arg; 167 168 *pexist = B_TRUE; 169 return (MH_WALK_TERMINATE); 170 } 171 172 static int 173 drv_fini(void) 174 { 175 int err; 176 boolean_t exist = B_FALSE; 177 178 rw_enter(&dld_ap_hash_lock, RW_READER); 179 mod_hash_walk(dld_ap_hashp, drv_ap_exist, &exist); 180 rw_exit(&dld_ap_hash_lock); 181 182 if (exist) 183 return (EBUSY); 184 185 if ((err = dld_str_fini()) != 0) 186 return (err); 187 188 drv_secobj_fini(); 189 mod_hash_destroy_idhash(dld_ap_hashp); 190 rw_destroy(&dld_ap_hash_lock); 191 return (0); 192 } 193 194 /* 195 * devo_getinfo: getinfo(9e) 196 */ 197 /*ARGSUSED*/ 198 static int 199 drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp) 200 { 201 if (dld_dip == NULL) 202 return (DDI_FAILURE); 203 204 switch (cmd) { 205 case DDI_INFO_DEVT2INSTANCE: 206 *resp = 0; 207 break; 208 case DDI_INFO_DEVT2DEVINFO: 209 *resp = dld_dip; 210 break; 211 default: 212 return (DDI_FAILURE); 213 } 214 215 return (DDI_SUCCESS); 216 } 217 218 /* 219 * Check properties to set options. (See dld.h for property definitions). 220 */ 221 static void 222 drv_set_opt(dev_info_t *dip) 223 { 224 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 225 DLD_PROP_NO_FASTPATH, 0) != 0) { 226 dld_opt |= DLD_OPT_NO_FASTPATH; 227 } 228 229 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 230 DLD_PROP_NO_POLL, 0) != 0) { 231 dld_opt |= DLD_OPT_NO_POLL; 232 } 233 234 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 235 DLD_PROP_NO_ZEROCOPY, 0) != 0) { 236 dld_opt |= DLD_OPT_NO_ZEROCOPY; 237 } 238 239 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 240 DLD_PROP_NO_SOFTRING, 0) != 0) { 241 dld_opt |= DLD_OPT_NO_SOFTRING; 242 } 243 } 244 245 /* 246 * devo_attach: attach(9e) 247 */ 248 static int 249 drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 250 { 251 if (cmd != DDI_ATTACH) 252 return (DDI_FAILURE); 253 254 ASSERT(ddi_get_instance(dip) == 0); 255 drv_init(); 256 drv_set_opt(dip); 257 258 /* 259 * Create control node. DLPI provider nodes will be created on demand. 260 */ 261 if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR, 262 DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS) 263 return (DDI_FAILURE); 264 265 dld_dip = dip; 266 267 /* 268 * Log the fact that the driver is now attached. 269 */ 270 ddi_report_dev(dip); 271 return (DDI_SUCCESS); 272 } 273 274 /* 275 * devo_detach: detach(9e) 276 */ 277 static int 278 drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 279 { 280 if (cmd != DDI_DETACH) 281 return (DDI_FAILURE); 282 283 ASSERT(dld_dip == dip); 284 if (drv_fini() != 0) 285 return (DDI_FAILURE); 286 287 /* 288 * Remove the control node. 289 */ 290 ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME); 291 dld_dip = NULL; 292 293 return (DDI_SUCCESS); 294 } 295 296 /* 297 * dld control node open procedure. 298 */ 299 /*ARGSUSED*/ 300 static int 301 drv_open(dev_t *devp, int flag, int sflag, cred_t *credp) 302 { 303 /* 304 * Only the control node can be opened. 305 */ 306 if (getminor(*devp) != DLD_CONTROL_MINOR) 307 return (ENODEV); 308 return (0); 309 } 310 311 /* 312 * DLDIOC_ATTR 313 */ 314 /* ARGSUSED */ 315 static int 316 drv_ioc_attr(void *karg, intptr_t arg, int mode, cred_t *cred) 317 { 318 dld_ioc_attr_t *diap = karg; 319 dls_dl_handle_t dlh; 320 dls_vlan_t *dvp; 321 int err; 322 323 if ((err = dls_devnet_hold_tmp(diap->dia_linkid, &dlh)) != 0) 324 return (err); 325 326 if ((err = dls_vlan_hold(dls_devnet_mac(dlh), 327 dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) { 328 dls_devnet_rele_tmp(dlh); 329 return (err); 330 } 331 mac_sdu_get(dvp->dv_dlp->dl_mh, NULL, &diap->dia_max_sdu); 332 333 dls_vlan_rele(dvp); 334 dls_devnet_rele_tmp(dlh); 335 336 return (0); 337 } 338 339 /* 340 * DLDIOC_PHYS_ATTR 341 */ 342 /* ARGSUSED */ 343 static int 344 drv_ioc_phys_attr(void *karg, intptr_t arg, int mode, cred_t *cred) 345 { 346 dld_ioc_phys_attr_t *dipp = karg; 347 int err; 348 dls_dl_handle_t dlh; 349 dls_dev_handle_t ddh; 350 dev_t phydev; 351 352 /* 353 * Every physical link should have its physical dev_t kept in the 354 * daemon. If not, it is not a valid physical link. 355 */ 356 if (dls_mgmt_get_phydev(dipp->dip_linkid, &phydev) != 0) 357 return (EINVAL); 358 359 /* 360 * Although this is a valid physical link, it might already be removed 361 * by DR or during system shutdown. softmac_hold_device() would return 362 * ENOENT in this case. 363 */ 364 if ((err = softmac_hold_device(phydev, &ddh)) != 0) 365 return (err); 366 367 if (dls_devnet_hold_tmp(dipp->dip_linkid, &dlh) != 0) { 368 /* 369 * Although this is an active physical link, its link type is 370 * not supported by GLDv3, and therefore it does not have 371 * vanity naming support. 372 */ 373 dipp->dip_novanity = B_TRUE; 374 } else { 375 dipp->dip_novanity = B_FALSE; 376 dls_devnet_rele_tmp(dlh); 377 } 378 /* 379 * Get the physical device name from the major number and the instance 380 * number derived from phydev. 381 */ 382 (void) snprintf(dipp->dip_dev, MAXLINKNAMELEN, "%s%d", 383 ddi_major_to_name(getmajor(phydev)), getminor(phydev) - 1); 384 385 softmac_rele_device(ddh); 386 return (0); 387 } 388 389 /* 390 * DLDIOC_SETPROP 391 */ 392 static int 393 drv_ioc_prop_common(dld_ioc_macprop_t *dipp, intptr_t arg, boolean_t set, 394 int mode) 395 { 396 int err = EINVAL; 397 size_t dsize; 398 dld_ioc_macprop_t *kdipp; 399 dls_dl_handle_t dlh; 400 dls_vlan_t *dvp; 401 datalink_id_t linkid; 402 mac_prop_t macprop; 403 uchar_t *cp; 404 struct dlautopush *dlap; 405 dld_ioc_zid_t *dzp; 406 407 /* 408 * We only use pr_valsize from dipp, as the caller only did a 409 * copyin() for sizeof (dld_ioc_prop_t), which doesn't cover 410 * the property data. We copyin the full dld_ioc_prop_t 411 * including the data into kdipp down below. 412 */ 413 dsize = sizeof (dld_ioc_macprop_t) + dipp->pr_valsize - 1; 414 if (dsize < dipp->pr_valsize) 415 return (EINVAL); 416 417 /* 418 * The property data is variable size, so we need to allocate 419 * a buffer for kernel use as this data was not part of the 420 * dipp allocation and copyin() done by the framework. 421 */ 422 if ((kdipp = kmem_alloc(dsize, KM_NOSLEEP)) == NULL) 423 return (ENOMEM); 424 if (ddi_copyin((void *)arg, kdipp, dsize, mode) != 0) { 425 err = EFAULT; 426 goto done; 427 } 428 429 linkid = kdipp->pr_linkid; 430 431 switch (dipp->pr_num) { 432 case MAC_PROP_ZONE: 433 if (set) { 434 dzp = (dld_ioc_zid_t *)kdipp->pr_val; 435 err = dls_devnet_setzid(dzp->diz_link, dzp->diz_zid); 436 goto done; 437 } else { 438 cp = (uchar_t *)kdipp->pr_val; 439 err = dls_devnet_getzid(linkid, (zoneid_t *)cp); 440 goto done; 441 } 442 case MAC_PROP_AUTOPUSH: 443 if (set) { 444 if (dipp->pr_valsize != 0) { 445 dlap = (struct dlautopush *)kdipp->pr_val; 446 err = drv_ioc_setap(linkid, dlap); 447 goto done; 448 } else { 449 err = drv_ioc_clrap(linkid); 450 goto done; 451 } 452 } else { 453 dlap = (struct dlautopush *)kdipp->pr_val; 454 err = drv_ioc_getap(linkid, dlap); 455 goto done; 456 } 457 458 default: 459 break; 460 } 461 462 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 463 goto done; 464 465 if ((err = dls_vlan_hold(dls_devnet_mac(dlh), 466 dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) { 467 dls_devnet_rele_tmp(dlh); 468 goto done; 469 } 470 471 macprop.mp_name = kdipp->pr_name; 472 macprop.mp_id = kdipp->pr_num; 473 macprop.mp_flags = kdipp->pr_flags; 474 475 if (set) { 476 err = mac_set_prop(dvp->dv_dlp->dl_mh, &macprop, 477 kdipp->pr_val, kdipp->pr_valsize); 478 } else { 479 err = mac_get_prop(dvp->dv_dlp->dl_mh, &macprop, 480 kdipp->pr_val, kdipp->pr_valsize); 481 } 482 483 dls_vlan_rele(dvp); 484 dls_devnet_rele_tmp(dlh); 485 done: 486 if (!set && err == 0 && 487 ddi_copyout(kdipp, (void *)arg, dsize, mode) != 0) 488 err = EFAULT; 489 kmem_free(kdipp, dsize); 490 return (err); 491 } 492 493 /* ARGSUSED */ 494 static int 495 drv_ioc_setprop(void *karg, intptr_t arg, int mode, cred_t *cred) 496 { 497 return (drv_ioc_prop_common(karg, arg, B_TRUE, mode)); 498 } 499 500 /* ARGSUSED */ 501 static int 502 drv_ioc_getprop(void *karg, intptr_t arg, int mode, cred_t *cred) 503 { 504 return (drv_ioc_prop_common(karg, arg, B_FALSE, mode)); 505 } 506 507 /* 508 * DLDIOC_CREATE_VLAN 509 */ 510 /* ARGSUSED */ 511 static int 512 drv_ioc_create_vlan(void *karg, intptr_t arg, int mode, cred_t *cred) 513 { 514 dld_ioc_create_vlan_t *dicp = karg; 515 516 return (dls_devnet_create_vlan(dicp->dic_vlanid, dicp->dic_linkid, 517 dicp->dic_vid, dicp->dic_force)); 518 } 519 520 /* 521 * DLDIOC_DELETE_VLAN 522 */ 523 /* ARGSUSED */ 524 static int 525 drv_ioc_delete_vlan(void *karg, intptr_t arg, int mode, cred_t *cred) 526 { 527 dld_ioc_delete_vlan_t *didp = karg; 528 529 return (dls_devnet_destroy_vlan(didp->did_linkid)); 530 } 531 532 /* 533 * DLDIOC_VLAN_ATTR 534 */ 535 /* ARGSUSED */ 536 static int 537 drv_ioc_vlan_attr(void *karg, intptr_t arg, int mode, cred_t *cred) 538 { 539 dld_ioc_vlan_attr_t *divp = karg; 540 dls_dl_handle_t dlh; 541 uint16_t vid; 542 dls_vlan_t *dvp; 543 int err; 544 545 /* 546 * Hold this link to prevent it from being deleted. 547 */ 548 if ((err = dls_devnet_hold_tmp(divp->div_vlanid, &dlh)) != 0) 549 return (err); 550 551 if ((vid = dls_devnet_vid(dlh)) == VLAN_ID_NONE) { 552 dls_devnet_rele_tmp(dlh); 553 return (EINVAL); 554 } 555 556 err = dls_vlan_hold(dls_devnet_mac(dlh), vid, &dvp, B_FALSE, B_FALSE); 557 if (err != 0) { 558 dls_devnet_rele_tmp(dlh); 559 return (err); 560 } 561 562 divp->div_linkid = dls_devnet_linkid(dlh); 563 divp->div_implicit = !dls_devnet_is_explicit(dlh); 564 divp->div_vid = vid; 565 divp->div_force = dvp->dv_force; 566 567 dls_vlan_rele(dvp); 568 dls_devnet_rele_tmp(dlh); 569 return (0); 570 } 571 572 /* 573 * DLDIOC_RENAME. 574 * 575 * This function handles two cases of link renaming. See more in comments above 576 * dls_datalink_rename(). 577 */ 578 /* ARGSUSED */ 579 static int 580 drv_ioc_rename(void *karg, intptr_t arg, int mode, cred_t *cred) 581 { 582 dld_ioc_rename_t *dir = karg; 583 mod_hash_key_t key; 584 mod_hash_val_t val; 585 int err; 586 587 if ((err = dls_devnet_rename(dir->dir_linkid1, dir->dir_linkid2, 588 dir->dir_link)) != 0) 589 return (err); 590 591 if (dir->dir_linkid2 == DATALINK_INVALID_LINKID) 592 return (0); 593 594 /* 595 * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this 596 * renaming request is to rename a valid physical link (dir_linkid1) 597 * to a "removed" physical link (dir_linkid2, which is removed by DR 598 * or during system shutdown). In this case, the link (specified by 599 * dir_linkid1) would inherit all the configuration of dir_linkid2, 600 * and dir_linkid1 and its configuration would be lost. 601 * 602 * Remove per-link autopush configuration of dir_linkid1 in this case. 603 */ 604 key = (mod_hash_key_t)(uintptr_t)dir->dir_linkid1; 605 rw_enter(&dld_ap_hash_lock, RW_WRITER); 606 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 607 rw_exit(&dld_ap_hash_lock); 608 return (0); 609 } 610 611 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 612 kmem_free(val, sizeof (dld_ap_t)); 613 rw_exit(&dld_ap_hash_lock); 614 return (0); 615 } 616 617 static int 618 drv_ioc_setap(datalink_id_t linkid, struct dlautopush *dlap) 619 { 620 dld_ap_t *dap; 621 int i; 622 mod_hash_key_t key; 623 624 if (dlap->dap_npush == 0 || dlap->dap_npush > MAXAPUSH) 625 return (EINVAL); 626 627 /* 628 * Validate that the specified list of modules exist. 629 */ 630 for (i = 0; i < dlap->dap_npush; i++) { 631 if (fmodsw_find(dlap->dap_aplist[i], FMODSW_LOAD) == NULL) 632 return (EINVAL); 633 } 634 635 636 key = (mod_hash_key_t)(uintptr_t)linkid; 637 638 rw_enter(&dld_ap_hash_lock, RW_WRITER); 639 if (mod_hash_find(dld_ap_hashp, key, (mod_hash_val_t *)&dap) != 0) { 640 dap = kmem_zalloc(sizeof (dld_ap_t), KM_NOSLEEP); 641 if (dap == NULL) { 642 rw_exit(&dld_ap_hash_lock); 643 return (ENOMEM); 644 } 645 646 dap->da_linkid = linkid; 647 VERIFY(mod_hash_insert(dld_ap_hashp, key, 648 (mod_hash_val_t)dap) == 0); 649 } 650 651 /* 652 * Update the configuration. 653 */ 654 dap->da_anchor = dlap->dap_anchor; 655 dap->da_npush = dlap->dap_npush; 656 for (i = 0; i < dlap->dap_npush; i++) { 657 (void) strlcpy(dap->da_aplist[i], dlap->dap_aplist[i], 658 FMNAMESZ + 1); 659 } 660 rw_exit(&dld_ap_hash_lock); 661 662 return (0); 663 } 664 665 static int 666 drv_ioc_getap(datalink_id_t linkid, struct dlautopush *dlap) 667 { 668 dld_ap_t *dap; 669 int i; 670 671 rw_enter(&dld_ap_hash_lock, RW_READER); 672 if (mod_hash_find(dld_ap_hashp, 673 (mod_hash_key_t)(uintptr_t)linkid, 674 (mod_hash_val_t *)&dap) != 0) { 675 rw_exit(&dld_ap_hash_lock); 676 return (ENOENT); 677 } 678 679 /* 680 * Retrieve the configuration. 681 */ 682 dlap->dap_anchor = dap->da_anchor; 683 dlap->dap_npush = dap->da_npush; 684 for (i = 0; i < dap->da_npush; i++) { 685 (void) strlcpy(dlap->dap_aplist[i], dap->da_aplist[i], 686 FMNAMESZ + 1); 687 } 688 rw_exit(&dld_ap_hash_lock); 689 690 return (0); 691 } 692 693 static int 694 drv_ioc_clrap(datalink_id_t linkid) 695 { 696 mod_hash_val_t val; 697 mod_hash_key_t key; 698 699 key = (mod_hash_key_t)(uintptr_t)linkid; 700 701 rw_enter(&dld_ap_hash_lock, RW_WRITER); 702 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 703 rw_exit(&dld_ap_hash_lock); 704 return (0); 705 } 706 707 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 708 kmem_free(val, sizeof (dld_ap_t)); 709 rw_exit(&dld_ap_hash_lock); 710 return (0); 711 } 712 713 /* 714 * DLDIOC_DOORSERVER 715 */ 716 /* ARGSUSED */ 717 static int 718 drv_ioc_doorserver(void *karg, intptr_t arg, int mode, cred_t *cred) 719 { 720 dld_ioc_door_t *did = karg; 721 722 return (dls_mgmt_door_set(did->did_start_door)); 723 } 724 725 /* 726 * Check for GLDv3 autopush information. There are three cases: 727 * 728 * 1. If devp points to a GLDv3 datalink and it has autopush configuration, 729 * fill dlap in with that information and return 0. 730 * 731 * 2. If devp points to a GLDv3 datalink but it doesn't have autopush 732 * configuration, then replace devp with the physical device (if one 733 * exists) and return 1. This allows stropen() to find the old-school 734 * per-driver autopush configuration. (For softmac, the result is that 735 * the softmac dev_t is replaced with the legacy device's dev_t). 736 * 737 * 3. If neither of the above apply, don't touch the args and return -1. 738 */ 739 int 740 dld_autopush(dev_t *devp, struct dlautopush *dlap) 741 { 742 dld_ap_t *dap; 743 datalink_id_t linkid; 744 dev_t phydev; 745 746 if (!GLDV3_DRV(getmajor(*devp))) 747 return (-1); 748 749 /* 750 * Find the linkid by the link's dev_t. 751 */ 752 if (dls_devnet_dev2linkid(*devp, &linkid) != 0) 753 return (-1); 754 755 /* 756 * Find the autopush configuration associated with the linkid. 757 */ 758 rw_enter(&dld_ap_hash_lock, RW_READER); 759 if (mod_hash_find(dld_ap_hashp, (mod_hash_key_t)(uintptr_t)linkid, 760 (mod_hash_val_t *)&dap) == 0) { 761 *dlap = dap->da_ap; 762 rw_exit(&dld_ap_hash_lock); 763 return (0); 764 } 765 rw_exit(&dld_ap_hash_lock); 766 767 if (dls_devnet_phydev(linkid, &phydev) != 0) 768 return (-1); 769 770 *devp = phydev; 771 return (1); 772 } 773 774 /* 775 * Secure objects implementation 776 */ 777 778 /* ARGSUSED */ 779 static int 780 drv_secobj_ctor(void *buf, void *arg, int kmflag) 781 { 782 bzero(buf, sizeof (dld_secobj_t)); 783 return (0); 784 } 785 786 static void 787 drv_secobj_init(void) 788 { 789 rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL); 790 drv_secobj_cachep = kmem_cache_create("drv_secobj_cache", 791 sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL, 792 NULL, NULL, NULL, 0); 793 drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash", 794 SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 795 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 796 } 797 798 static void 799 drv_secobj_fini(void) 800 { 801 mod_hash_destroy_hash(drv_secobj_hash); 802 kmem_cache_destroy(drv_secobj_cachep); 803 rw_destroy(&drv_secobj_lock); 804 } 805 806 /* ARGSUSED */ 807 static int 808 drv_ioc_secobj_set(void *karg, intptr_t arg, int mode, cred_t *cred) 809 { 810 dld_ioc_secobj_set_t *ssp = karg; 811 dld_secobj_t *sobjp, *objp; 812 int err; 813 814 sobjp = &ssp->ss_obj; 815 816 if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP && 817 sobjp->so_class != DLD_SECOBJ_CLASS_WPA) 818 return (EINVAL); 819 820 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' || 821 sobjp->so_len > DLD_SECOBJ_VAL_MAX) 822 return (EINVAL); 823 824 rw_enter(&drv_secobj_lock, RW_WRITER); 825 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name, 826 (mod_hash_val_t *)&objp); 827 if (err == 0) { 828 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) { 829 rw_exit(&drv_secobj_lock); 830 return (EEXIST); 831 } 832 } else { 833 ASSERT(err == MH_ERR_NOTFOUND); 834 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) { 835 rw_exit(&drv_secobj_lock); 836 return (ENOENT); 837 } 838 objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP); 839 (void) strlcpy(objp->so_name, sobjp->so_name, 840 DLD_SECOBJ_NAME_MAX); 841 842 VERIFY(mod_hash_insert(drv_secobj_hash, 843 (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp) == 0); 844 } 845 bcopy(sobjp->so_val, objp->so_val, sobjp->so_len); 846 objp->so_len = sobjp->so_len; 847 objp->so_class = sobjp->so_class; 848 rw_exit(&drv_secobj_lock); 849 return (0); 850 } 851 852 typedef struct dld_secobj_state { 853 uint_t ss_free; 854 uint_t ss_count; 855 int ss_rc; 856 int ss_mode; 857 dld_secobj_t *ss_objp; 858 } dld_secobj_state_t; 859 860 /* ARGSUSED */ 861 static uint_t 862 drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 863 { 864 dld_secobj_state_t *statep = arg; 865 dld_secobj_t *sobjp = (dld_secobj_t *)val; 866 867 if (statep->ss_free < sizeof (dld_secobj_t)) { 868 statep->ss_rc = ENOSPC; 869 return (MH_WALK_TERMINATE); 870 } 871 if (ddi_copyout(sobjp, statep->ss_objp, sizeof (*sobjp), 872 statep->ss_mode) != 0) { 873 statep->ss_rc = EFAULT; 874 return (MH_WALK_TERMINATE); 875 } 876 statep->ss_objp++; 877 statep->ss_free -= sizeof (dld_secobj_t); 878 statep->ss_count++; 879 return (MH_WALK_CONTINUE); 880 } 881 882 /* ARGSUSED */ 883 static int 884 drv_ioc_secobj_get(void *karg, intptr_t arg, int mode, cred_t *cred) 885 { 886 dld_ioc_secobj_get_t *sgp = karg; 887 dld_secobj_t *sobjp, *objp; 888 int err; 889 890 sobjp = &sgp->sg_obj; 891 892 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 893 return (EINVAL); 894 895 rw_enter(&drv_secobj_lock, RW_READER); 896 if (sobjp->so_name[0] != '\0') { 897 err = mod_hash_find(drv_secobj_hash, 898 (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp); 899 if (err != 0) { 900 ASSERT(err == MH_ERR_NOTFOUND); 901 rw_exit(&drv_secobj_lock); 902 return (ENOENT); 903 } 904 bcopy(objp->so_val, sobjp->so_val, objp->so_len); 905 sobjp->so_len = objp->so_len; 906 sobjp->so_class = objp->so_class; 907 sgp->sg_count = 1; 908 } else { 909 dld_secobj_state_t state; 910 911 state.ss_free = sgp->sg_size - sizeof (dld_ioc_secobj_get_t); 912 state.ss_count = 0; 913 state.ss_rc = 0; 914 state.ss_mode = mode; 915 state.ss_objp = (dld_secobj_t *)((uchar_t *)arg + 916 sizeof (dld_ioc_secobj_get_t)); 917 918 mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state); 919 if (state.ss_rc != 0) { 920 rw_exit(&drv_secobj_lock); 921 return (state.ss_rc); 922 } 923 sgp->sg_count = state.ss_count; 924 } 925 rw_exit(&drv_secobj_lock); 926 return (0); 927 } 928 929 /* ARGSUSED */ 930 static int 931 drv_ioc_secobj_unset(void *karg, intptr_t arg, int mode, cred_t *cred) 932 { 933 dld_ioc_secobj_unset_t *sup = karg; 934 dld_secobj_t *objp; 935 mod_hash_val_t val; 936 int err; 937 938 if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 939 return (EINVAL); 940 941 rw_enter(&drv_secobj_lock, RW_WRITER); 942 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 943 (mod_hash_val_t *)&objp); 944 if (err != 0) { 945 ASSERT(err == MH_ERR_NOTFOUND); 946 rw_exit(&drv_secobj_lock); 947 return (ENOENT); 948 } 949 VERIFY(mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 950 (mod_hash_val_t *)&val) == 0); 951 ASSERT(objp == (dld_secobj_t *)val); 952 953 kmem_cache_free(drv_secobj_cachep, objp); 954 rw_exit(&drv_secobj_lock); 955 return (0); 956 } 957 958 static dld_ioc_info_t drv_ioc_list[] = { 959 {DLDIOC_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_attr_t), 960 drv_ioc_attr}, 961 {DLDIOC_PHYS_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_phys_attr_t), 962 drv_ioc_phys_attr}, 963 {DLDIOC_SECOBJ_SET, DLDCOPYIN | DLDDLCONFIG, 964 sizeof (dld_ioc_secobj_set_t), drv_ioc_secobj_set}, 965 {DLDIOC_SECOBJ_GET, DLDCOPYINOUT | DLDDLCONFIG, 966 sizeof (dld_ioc_secobj_get_t), drv_ioc_secobj_get}, 967 {DLDIOC_SECOBJ_UNSET, DLDCOPYIN | DLDDLCONFIG, 968 sizeof (dld_ioc_secobj_unset_t), drv_ioc_secobj_unset}, 969 {DLDIOC_CREATE_VLAN, DLDCOPYIN | DLDDLCONFIG, 970 sizeof (dld_ioc_create_vlan_t), drv_ioc_create_vlan}, 971 {DLDIOC_DELETE_VLAN, DLDCOPYIN | DLDDLCONFIG, 972 sizeof (dld_ioc_delete_vlan_t), 973 drv_ioc_delete_vlan}, 974 {DLDIOC_VLAN_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_vlan_attr_t), 975 drv_ioc_vlan_attr}, 976 {DLDIOC_DOORSERVER, DLDCOPYIN | DLDDLCONFIG, sizeof (dld_ioc_door_t), 977 drv_ioc_doorserver}, 978 {DLDIOC_RENAME, DLDCOPYIN | DLDDLCONFIG, sizeof (dld_ioc_rename_t), 979 drv_ioc_rename}, 980 {DLDIOC_GETMACPROP, DLDCOPYIN, sizeof (dld_ioc_macprop_t), 981 drv_ioc_getprop}, 982 {DLDIOC_SETMACPROP, DLDCOPYIN | DLDDLCONFIG, sizeof (dld_ioc_macprop_t), 983 drv_ioc_setprop} 984 }; 985 986 typedef struct dld_ioc_modentry { 987 uint16_t dim_modid; /* Top 16 bits of ioctl command */ 988 char *dim_modname; /* Module to be loaded */ 989 dld_ioc_info_t *dim_list; /* array of ioctl structures */ 990 uint_t dim_count; /* number of elements in dim_list */ 991 } dld_ioc_modentry_t; 992 993 /* 994 * For all modules except for dld, dim_list and dim_count are assigned 995 * when the modules register their ioctls in dld_ioc_register(). We 996 * can statically initialize dld's ioctls in-line here; there's no 997 * need for it to call dld_ioc_register() itself. 998 */ 999 static dld_ioc_modentry_t dld_ioc_modtable[] = { 1000 {DLD_IOC, "dld", drv_ioc_list, DLDIOCCNT(drv_ioc_list)}, 1001 {AGGR_IOC, "aggr", NULL, 0}, 1002 {VNIC_IOC, "vnic", NULL, 0} 1003 }; 1004 #define DLDIOC_CNT \ 1005 (sizeof (dld_ioc_modtable) / sizeof (dld_ioc_modentry_t)) 1006 1007 static dld_ioc_modentry_t * 1008 dld_ioc_findmod(uint16_t modid) 1009 { 1010 int i; 1011 1012 for (i = 0; i < DLDIOC_CNT; i++) { 1013 if (modid == dld_ioc_modtable[i].dim_modid) 1014 return (&dld_ioc_modtable[i]); 1015 } 1016 return (NULL); 1017 } 1018 1019 int 1020 dld_ioc_register(uint16_t modid, dld_ioc_info_t *list, uint_t count) 1021 { 1022 dld_ioc_modentry_t *dim = dld_ioc_findmod(modid); 1023 1024 if (dim == NULL) 1025 return (ENOENT); 1026 1027 dim->dim_list = list; 1028 dim->dim_count = count; 1029 return (0); 1030 } 1031 1032 void 1033 dld_ioc_unregister(uint16_t modid) 1034 { 1035 VERIFY(dld_ioc_register(modid, NULL, 0) == 0); 1036 } 1037 1038 /* 1039 * The general design with GLDv3 ioctls is that all ioctls issued 1040 * through /dev/dld go through this drv_ioctl() function. This 1041 * function handles all ioctls on behalf of modules listed in 1042 * dld_ioc_modtable. 1043 * 1044 * When an ioctl is received, this function looks for the associated 1045 * module-id-specific ioctl information using dld_ioc_findmod(). The 1046 * call to ddi_hold_devi_by_instance() on the associated device will 1047 * cause the kernel module responsible for the ioctl to be loaded if 1048 * it's not already loaded, which should result in that module calling 1049 * dld_ioc_register(), thereby filling in the dim_list containing the 1050 * details for the ioctl being processed. 1051 * 1052 * This function can then perform operations such as copyin() data and 1053 * do credential checks based on the registered ioctl information, 1054 * then issue the callback function di_func() registered by the 1055 * responsible module. Upon return, the appropriate copyout() 1056 * operation can be performed and the operation completes. 1057 */ 1058 /* ARGSUSED */ 1059 static int 1060 drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp) 1061 { 1062 dld_ioc_modentry_t *dim; 1063 dld_ioc_info_t *info; 1064 dev_info_t *dip = NULL; 1065 void *buf = NULL; 1066 size_t sz; 1067 int i, err; 1068 1069 if ((dim = dld_ioc_findmod(DLD_IOC_MODID(cmd))) == NULL) 1070 return (ENOTSUP); 1071 1072 dip = ddi_hold_devi_by_instance(ddi_name_to_major(dim->dim_modname), 1073 0, 0); 1074 if (dip == NULL || dim->dim_list == NULL) { 1075 err = ENODEV; 1076 goto done; 1077 } 1078 1079 for (i = 0; i < dim->dim_count; i++) { 1080 if (cmd == dim->dim_list[i].di_cmd) 1081 break; 1082 } 1083 if (i == dim->dim_count) { 1084 err = ENOTSUP; 1085 goto done; 1086 } 1087 1088 info = &dim->dim_list[i]; 1089 1090 if ((info->di_flags & DLDDLCONFIG) && secpolicy_dl_config(cred) != 0) { 1091 err = EPERM; 1092 goto done; 1093 } 1094 1095 sz = info->di_argsize; 1096 if ((buf = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) { 1097 err = ENOMEM; 1098 goto done; 1099 } 1100 1101 if ((info->di_flags & DLDCOPYIN) && 1102 ddi_copyin((void *)arg, buf, sz, mode) != 0) { 1103 err = EFAULT; 1104 goto done; 1105 } 1106 1107 err = info->di_func(buf, arg, mode, cred); 1108 1109 if ((info->di_flags & DLDCOPYOUT) && 1110 ddi_copyout(buf, (void *)arg, sz, mode) != 0 && err == 0) 1111 err = EFAULT; 1112 1113 done: 1114 if (buf != NULL) 1115 kmem_free(buf, sz); 1116 if (dip != NULL) 1117 ddi_release_devi(dip); 1118 return (err); 1119 } 1120