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/strsun.h> 35 #include <sys/vlan.h> 36 #include <sys/mac.h> 37 #include <sys/dld_impl.h> 38 #include <sys/dls_impl.h> 39 #include <sys/softmac.h> 40 #include <sys/vlan.h> 41 #include <inet/common.h> 42 43 /* 44 * dld control node state, one per open control node session. 45 */ 46 typedef struct dld_ctl_str_s { 47 minor_t cs_minor; 48 queue_t *cs_wq; 49 } dld_ctl_str_t; 50 51 static void drv_init(void); 52 static int drv_fini(void); 53 54 static int drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 55 static int drv_attach(dev_info_t *, ddi_attach_cmd_t); 56 static int drv_detach(dev_info_t *, ddi_detach_cmd_t); 57 58 /* 59 * Secure objects declarations 60 */ 61 #define SECOBJ_WEP_HASHSZ 67 62 static krwlock_t drv_secobj_lock; 63 static kmem_cache_t *drv_secobj_cachep; 64 static mod_hash_t *drv_secobj_hash; 65 static void drv_secobj_init(void); 66 static void drv_secobj_fini(void); 67 static void drv_ioc_secobj_set(dld_ctl_str_t *, mblk_t *); 68 static void drv_ioc_secobj_get(dld_ctl_str_t *, mblk_t *); 69 static void drv_ioc_secobj_unset(dld_ctl_str_t *, mblk_t *); 70 static int drv_ioc_setap(datalink_id_t, struct dlautopush *); 71 static int drv_ioc_getap(datalink_id_t, struct dlautopush *); 72 static int drv_ioc_clrap(datalink_id_t); 73 74 /* 75 * The following entry points are private to dld and are used for control 76 * operations only. The entry points exported to mac drivers are defined 77 * in dld_str.c. Refer to the comment on top of dld_str.c for details. 78 */ 79 static int drv_open(queue_t *, dev_t *, int, int, cred_t *); 80 static int drv_close(queue_t *); 81 82 static void drv_uw_put(queue_t *, mblk_t *); 83 static void drv_uw_srv(queue_t *); 84 85 dev_info_t *dld_dip; /* dev_info_t for the driver */ 86 uint32_t dld_opt = 0; /* Global options */ 87 static vmem_t *dld_ctl_vmem; /* for control minor numbers */ 88 89 #define NAUTOPUSH 32 90 static mod_hash_t *dld_ap_hashp; 91 static krwlock_t dld_ap_hash_lock; 92 93 static struct module_info drv_info = { 94 0, /* mi_idnum */ 95 DLD_DRIVER_NAME, /* mi_idname */ 96 0, /* mi_minpsz */ 97 (64 * 1024), /* mi_maxpsz */ 98 1, /* mi_hiwat */ 99 0 /* mi_lowat */ 100 }; 101 102 static struct qinit drv_ur_init = { 103 NULL, /* qi_putp */ 104 NULL, /* qi_srvp */ 105 drv_open, /* qi_qopen */ 106 drv_close, /* qi_qclose */ 107 NULL, /* qi_qadmin */ 108 &drv_info, /* qi_minfo */ 109 NULL /* qi_mstat */ 110 }; 111 112 static struct qinit drv_uw_init = { 113 (pfi_t)drv_uw_put, /* qi_putp */ 114 (pfi_t)drv_uw_srv, /* qi_srvp */ 115 NULL, /* qi_qopen */ 116 NULL, /* qi_qclose */ 117 NULL, /* qi_qadmin */ 118 &drv_info, /* qi_minfo */ 119 NULL /* qi_mstat */ 120 }; 121 122 static struct streamtab drv_stream = { 123 &drv_ur_init, /* st_rdinit */ 124 &drv_uw_init, /* st_wrinit */ 125 NULL, /* st_muxrinit */ 126 NULL /* st_muxwinit */ 127 }; 128 129 DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach, 130 nodev, drv_getinfo, D_MP, &drv_stream); 131 132 /* 133 * Module linkage information for the kernel. 134 */ 135 136 extern struct mod_ops mod_driverops; 137 138 static struct modldrv drv_modldrv = { 139 &mod_driverops, 140 DLD_INFO, 141 &drv_ops 142 }; 143 144 static struct modlinkage drv_modlinkage = { 145 MODREV_1, 146 &drv_modldrv, 147 NULL 148 }; 149 150 int 151 _init(void) 152 { 153 int err; 154 155 drv_init(); 156 157 if ((err = mod_install(&drv_modlinkage)) != 0) 158 return (err); 159 160 return (0); 161 } 162 163 int 164 _fini(void) 165 { 166 int err; 167 168 if ((err = mod_remove(&drv_modlinkage)) != 0) 169 return (err); 170 171 if (drv_fini() != 0) { 172 (void) mod_install(&drv_modlinkage); 173 return (DDI_FAILURE); 174 } 175 176 return (err); 177 } 178 179 int 180 _info(struct modinfo *modinfop) 181 { 182 return (mod_info(&drv_modlinkage, modinfop)); 183 } 184 185 /* 186 * Initialize component modules. 187 */ 188 static void 189 drv_init(void) 190 { 191 dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1, 192 NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER); 193 drv_secobj_init(); 194 dld_str_init(); 195 /* 196 * Create a hash table for autopush configuration. 197 */ 198 dld_ap_hashp = mod_hash_create_idhash("dld_autopush_hash", 199 NAUTOPUSH, mod_hash_null_valdtor); 200 201 ASSERT(dld_ap_hashp != NULL); 202 rw_init(&dld_ap_hash_lock, NULL, RW_DRIVER, NULL); 203 } 204 205 /* ARGSUSED */ 206 static uint_t 207 drv_ap_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 208 { 209 boolean_t *pexist = arg; 210 211 *pexist = B_TRUE; 212 return (MH_WALK_TERMINATE); 213 } 214 215 static int 216 drv_fini(void) 217 { 218 int err; 219 boolean_t exist = B_FALSE; 220 221 rw_enter(&dld_ap_hash_lock, RW_READER); 222 mod_hash_walk(dld_ap_hashp, drv_ap_exist, &exist); 223 rw_exit(&dld_ap_hash_lock); 224 225 if (exist) 226 return (EBUSY); 227 228 if ((err = dld_str_fini()) != 0) 229 return (err); 230 231 drv_secobj_fini(); 232 vmem_destroy(dld_ctl_vmem); 233 mod_hash_destroy_idhash(dld_ap_hashp); 234 rw_destroy(&dld_ap_hash_lock); 235 return (0); 236 } 237 238 /* 239 * devo_getinfo: getinfo(9e) 240 */ 241 /*ARGSUSED*/ 242 static int 243 drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp) 244 { 245 if (dld_dip == NULL) 246 return (DDI_FAILURE); 247 248 switch (cmd) { 249 case DDI_INFO_DEVT2INSTANCE: 250 *resp = (void *)0; 251 break; 252 case DDI_INFO_DEVT2DEVINFO: 253 *resp = (void *)dld_dip; 254 break; 255 default: 256 return (DDI_FAILURE); 257 } 258 259 return (DDI_SUCCESS); 260 } 261 262 /* 263 * Check properties to set options. (See dld.h for property definitions). 264 */ 265 static void 266 drv_set_opt(dev_info_t *dip) 267 { 268 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 269 DLD_PROP_NO_FASTPATH, 0) != 0) { 270 dld_opt |= DLD_OPT_NO_FASTPATH; 271 } 272 273 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 274 DLD_PROP_NO_POLL, 0) != 0) { 275 dld_opt |= DLD_OPT_NO_POLL; 276 } 277 278 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 279 DLD_PROP_NO_ZEROCOPY, 0) != 0) { 280 dld_opt |= DLD_OPT_NO_ZEROCOPY; 281 } 282 283 if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 284 DLD_PROP_NO_SOFTRING, 0) != 0) { 285 dld_opt |= DLD_OPT_NO_SOFTRING; 286 } 287 } 288 289 /* 290 * devo_attach: attach(9e) 291 */ 292 static int 293 drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 294 { 295 if (cmd != DDI_ATTACH) 296 return (DDI_FAILURE); 297 298 ASSERT(ddi_get_instance(dip) == 0); 299 300 drv_set_opt(dip); 301 302 /* 303 * Create control node. DLPI provider nodes will be created on demand. 304 */ 305 if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR, 306 DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS) 307 return (DDI_FAILURE); 308 309 dld_dip = dip; 310 311 /* 312 * Log the fact that the driver is now attached. 313 */ 314 ddi_report_dev(dip); 315 return (DDI_SUCCESS); 316 } 317 318 /* 319 * devo_detach: detach(9e) 320 */ 321 static int 322 drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 323 { 324 if (cmd != DDI_DETACH) 325 return (DDI_FAILURE); 326 327 ASSERT(dld_dip == dip); 328 329 /* 330 * Remove the control node. 331 */ 332 ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME); 333 dld_dip = NULL; 334 335 return (DDI_SUCCESS); 336 } 337 338 /* 339 * dld control node open procedure. 340 */ 341 /*ARGSUSED*/ 342 static int 343 drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 344 { 345 dld_ctl_str_t *ctls; 346 minor_t minor; 347 queue_t *oq = OTHERQ(rq); 348 349 if (sflag == MODOPEN) 350 return (ENOTSUP); 351 352 /* 353 * This is a cloning driver and therefore each queue should only 354 * ever get opened once. 355 */ 356 if (rq->q_ptr != NULL) 357 return (EBUSY); 358 359 minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP); 360 if (minor == 0) 361 return (ENOMEM); 362 363 ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP); 364 if (ctls == NULL) { 365 vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1); 366 return (ENOMEM); 367 } 368 369 ctls->cs_minor = minor; 370 ctls->cs_wq = WR(rq); 371 372 rq->q_ptr = ctls; 373 oq->q_ptr = ctls; 374 375 /* 376 * Enable the queue srv(9e) routine. 377 */ 378 qprocson(rq); 379 380 /* 381 * Construct a cloned dev_t to hand back. 382 */ 383 *devp = makedevice(getmajor(*devp), ctls->cs_minor); 384 return (0); 385 } 386 387 /* 388 * dld control node close procedure. 389 */ 390 static int 391 drv_close(queue_t *rq) 392 { 393 dld_ctl_str_t *ctls; 394 395 ctls = rq->q_ptr; 396 ASSERT(ctls != NULL); 397 398 /* 399 * Disable the queue srv(9e) routine. 400 */ 401 qprocsoff(rq); 402 403 vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1); 404 405 kmem_free(ctls, sizeof (dld_ctl_str_t)); 406 407 return (0); 408 } 409 410 /* 411 * DLDIOC_ATTR 412 */ 413 static void 414 drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp) 415 { 416 dld_ioc_attr_t *diap; 417 dls_dl_handle_t dlh; 418 dls_vlan_t *dvp; 419 int err; 420 queue_t *q = ctls->cs_wq; 421 422 if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0) 423 goto failed; 424 425 diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr; 426 427 if ((err = dls_devnet_hold_tmp(diap->dia_linkid, &dlh)) != 0) 428 goto failed; 429 430 if ((err = dls_vlan_hold(dls_devnet_mac(dlh), 431 dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) { 432 dls_devnet_rele_tmp(dlh); 433 goto failed; 434 } 435 mac_sdu_get(dvp->dv_dlp->dl_mh, NULL, &diap->dia_max_sdu); 436 437 dls_vlan_rele(dvp); 438 dls_devnet_rele_tmp(dlh); 439 440 miocack(q, mp, sizeof (dld_ioc_attr_t), 0); 441 return; 442 443 failed: 444 ASSERT(err != 0); 445 miocnak(q, mp, 0, err); 446 } 447 448 /* 449 * DLDIOC_PHYS_ATTR 450 */ 451 static void 452 drv_ioc_phys_attr(dld_ctl_str_t *ctls, mblk_t *mp) 453 { 454 dld_ioc_phys_attr_t *dipp; 455 int err; 456 dls_dl_handle_t dlh; 457 dls_dev_handle_t ddh; 458 dev_t phydev; 459 queue_t *q = ctls->cs_wq; 460 461 if ((err = miocpullup(mp, sizeof (dld_ioc_phys_attr_t))) != 0) 462 goto failed; 463 464 dipp = (dld_ioc_phys_attr_t *)mp->b_cont->b_rptr; 465 466 /* 467 * Every physical link should have its physical dev_t kept in the 468 * daemon. If not, it is not a valid physical link. 469 */ 470 if (dls_mgmt_get_phydev(dipp->dip_linkid, &phydev) != 0) { 471 err = EINVAL; 472 goto failed; 473 } 474 475 /* 476 * Although this is a valid physical link, it might already be removed 477 * by DR or during system shutdown. softmac_hold_device() would return 478 * ENOENT in this case. 479 */ 480 if ((err = softmac_hold_device(phydev, &ddh)) != 0) 481 goto failed; 482 483 if (dls_devnet_hold_tmp(dipp->dip_linkid, &dlh) != 0) { 484 /* 485 * Although this is an active physical link, its link type is 486 * not supported by GLDv3, and therefore it does not have 487 * vanity naming support. 488 */ 489 dipp->dip_novanity = B_TRUE; 490 } else { 491 dipp->dip_novanity = B_FALSE; 492 dls_devnet_rele_tmp(dlh); 493 } 494 /* 495 * Get the physical device name from the major number and the instance 496 * number derived from phydev. 497 */ 498 (void) snprintf(dipp->dip_dev, MAXLINKNAMELEN, "%s%d", 499 ddi_major_to_name(getmajor(phydev)), getminor(phydev) - 1); 500 501 softmac_rele_device(ddh); 502 503 miocack(q, mp, sizeof (dld_ioc_phys_attr_t), 0); 504 return; 505 506 failed: 507 miocnak(q, mp, 0, err); 508 } 509 510 /* 511 * DLDIOC_SETPROP 512 */ 513 static void 514 drv_ioc_prop_common(dld_ctl_str_t *ctls, mblk_t *mp, boolean_t set) 515 { 516 int err = EINVAL, dsize; 517 queue_t *q = ctls->cs_wq; 518 dld_ioc_macprop_t *dipp; 519 dls_dl_handle_t dlh; 520 dls_vlan_t *dvp; 521 datalink_id_t linkid; 522 mac_prop_t macprop; 523 uchar_t *cp; 524 struct dlautopush *dlap; 525 dld_ioc_zid_t *dzp; 526 527 if ((err = miocpullup(mp, sizeof (dld_ioc_macprop_t) - 1)) != 0) 528 goto done; 529 dipp = (dld_ioc_macprop_t *)mp->b_cont->b_rptr; 530 531 dsize = sizeof (dld_ioc_macprop_t) + dipp->pr_valsize - 1; 532 if ((err = miocpullup(mp, dsize)) != 0) 533 goto done; 534 dipp = (dld_ioc_macprop_t *)mp->b_cont->b_rptr; 535 536 linkid = dipp->pr_linkid; 537 538 switch (dipp->pr_num) { 539 case MAC_PROP_ZONE: 540 if (set) { 541 dzp = (dld_ioc_zid_t *)dipp->pr_val; 542 err = dls_devnet_setzid(dzp->diz_link, dzp->diz_zid); 543 goto done; 544 } else { 545 cp = (uchar_t *)dipp->pr_val; 546 err = dls_devnet_getzid(linkid, (zoneid_t *)cp); 547 goto done; 548 } 549 case MAC_PROP_AUTOPUSH: 550 if (set) { 551 if (dipp->pr_valsize != 0) { 552 dlap = (struct dlautopush *)dipp->pr_val; 553 err = drv_ioc_setap(linkid, dlap); 554 goto done; 555 } else { 556 err = drv_ioc_clrap(linkid); 557 goto done; 558 } 559 } else { 560 dlap = (struct dlautopush *)dipp->pr_val; 561 err = drv_ioc_getap(linkid, dlap); 562 goto done; 563 } 564 565 default: 566 break; 567 } 568 569 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 570 goto done; 571 572 if ((err = dls_vlan_hold(dls_devnet_mac(dlh), 573 dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) { 574 dls_devnet_rele_tmp(dlh); 575 goto done; 576 } 577 578 macprop.mp_name = dipp->pr_name; 579 macprop.mp_id = dipp->pr_num; 580 macprop.mp_flags = dipp->pr_flags; 581 582 if (set) 583 err = mac_set_prop(dvp->dv_dlp->dl_mh, &macprop, 584 dipp->pr_val, dipp->pr_valsize); 585 else 586 err = mac_get_prop(dvp->dv_dlp->dl_mh, &macprop, 587 dipp->pr_val, dipp->pr_valsize); 588 589 dls_vlan_rele(dvp); 590 dls_devnet_rele_tmp(dlh); 591 done: 592 if (err == 0) 593 miocack(q, mp, dsize, 0); 594 else 595 miocnak(q, mp, 0, err); 596 } 597 598 static void 599 drv_ioc_setprop(dld_ctl_str_t *ctls, mblk_t *mp) 600 { 601 drv_ioc_prop_common(ctls, mp, B_TRUE); 602 } 603 604 static void 605 drv_ioc_getprop(dld_ctl_str_t *ctls, mblk_t *mp) 606 { 607 drv_ioc_prop_common(ctls, mp, B_FALSE); 608 } 609 610 /* 611 * DLDIOC_CREATE_VLAN 612 */ 613 static void 614 drv_ioc_create_vlan(dld_ctl_str_t *ctls, mblk_t *mp) 615 { 616 dld_ioc_create_vlan_t *dicp; 617 int err; 618 queue_t *q = ctls->cs_wq; 619 620 if ((err = miocpullup(mp, sizeof (dld_ioc_create_vlan_t))) != 0) 621 goto failed; 622 623 dicp = (dld_ioc_create_vlan_t *)mp->b_cont->b_rptr; 624 625 if ((err = dls_devnet_create_vlan(dicp->dic_vlanid, 626 dicp->dic_linkid, dicp->dic_vid, dicp->dic_force)) != 0) { 627 goto failed; 628 } 629 630 miocack(q, mp, 0, 0); 631 return; 632 633 failed: 634 miocnak(q, mp, 0, err); 635 } 636 637 /* 638 * DLDIOC_DELETE_VLAN 639 */ 640 static void 641 drv_ioc_delete_vlan(dld_ctl_str_t *ctls, mblk_t *mp) 642 { 643 dld_ioc_delete_vlan_t *didp; 644 int err; 645 queue_t *q = ctls->cs_wq; 646 647 if ((err = miocpullup(mp, sizeof (dld_ioc_delete_vlan_t))) != 0) 648 goto done; 649 650 didp = (dld_ioc_delete_vlan_t *)mp->b_cont->b_rptr; 651 err = dls_devnet_destroy_vlan(didp->did_linkid); 652 653 done: 654 if (err == 0) 655 miocack(q, mp, 0, 0); 656 else 657 miocnak(q, mp, 0, err); 658 } 659 660 /* 661 * DLDIOC_VLAN_ATTR 662 */ 663 static void 664 drv_ioc_vlan_attr(dld_ctl_str_t *ctls, mblk_t *mp) 665 { 666 dld_ioc_vlan_attr_t *divp; 667 dls_dl_handle_t dlh; 668 uint16_t vid; 669 dls_vlan_t *dvp; 670 int err; 671 queue_t *q = ctls->cs_wq; 672 673 if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_attr_t))) != 0) 674 goto failed; 675 676 divp = (dld_ioc_vlan_attr_t *)mp->b_cont->b_rptr; 677 678 /* 679 * Hold this link to prevent it from being deleted. 680 */ 681 err = dls_devnet_hold_tmp(divp->div_vlanid, &dlh); 682 if (err != 0) 683 goto failed; 684 685 if ((vid = dls_devnet_vid(dlh)) == VLAN_ID_NONE) { 686 dls_devnet_rele_tmp(dlh); 687 err = EINVAL; 688 goto failed; 689 } 690 691 err = dls_vlan_hold(dls_devnet_mac(dlh), vid, &dvp, B_FALSE, B_FALSE); 692 if (err != 0) { 693 dls_devnet_rele_tmp(dlh); 694 err = EINVAL; 695 goto failed; 696 } 697 698 divp->div_linkid = dls_devnet_linkid(dlh); 699 divp->div_implicit = !dls_devnet_is_explicit(dlh); 700 divp->div_vid = vid; 701 divp->div_force = dvp->dv_force; 702 703 dls_vlan_rele(dvp); 704 dls_devnet_rele_tmp(dlh); 705 miocack(q, mp, sizeof (dld_ioc_vlan_attr_t), 0); 706 return; 707 708 failed: 709 miocnak(q, mp, 0, err); 710 } 711 712 /* 713 * DLDIOC_RENAME. 714 * 715 * This function handles two cases of link renaming. See more in comments above 716 * dls_datalink_rename(). 717 */ 718 static void 719 drv_ioc_rename(dld_ctl_str_t *ctls, mblk_t *mp) 720 { 721 dld_ioc_rename_t *dir; 722 mod_hash_key_t key; 723 mod_hash_val_t val; 724 int err; 725 queue_t *q = ctls->cs_wq; 726 727 if ((err = miocpullup(mp, sizeof (dld_ioc_rename_t))) != 0) 728 goto done; 729 730 dir = (dld_ioc_rename_t *)mp->b_cont->b_rptr; 731 if ((err = dls_devnet_rename(dir->dir_linkid1, dir->dir_linkid2, 732 dir->dir_link)) != 0) { 733 goto done; 734 } 735 736 if (dir->dir_linkid2 == DATALINK_INVALID_LINKID) 737 goto done; 738 739 /* 740 * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this 741 * renaming request is to rename a valid physical link (dir_linkid1) 742 * to a "removed" physical link (dir_linkid2, which is removed by DR 743 * or during system shutdown). In this case, the link (specified by 744 * dir_linkid1) would inherit all the configuration of dir_linkid2, 745 * and dir_linkid1 and its configuration would be lost. 746 * 747 * Remove per-link autopush configuration of dir_linkid1 in this case. 748 */ 749 key = (mod_hash_key_t)(uintptr_t)dir->dir_linkid1; 750 rw_enter(&dld_ap_hash_lock, RW_WRITER); 751 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 752 rw_exit(&dld_ap_hash_lock); 753 goto done; 754 } 755 756 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 757 kmem_free(val, sizeof (dld_ap_t)); 758 rw_exit(&dld_ap_hash_lock); 759 760 done: 761 if (err == 0) 762 miocack(q, mp, 0, 0); 763 else 764 miocnak(q, mp, 0, err); 765 } 766 767 static int 768 drv_ioc_setap(datalink_id_t linkid, struct dlautopush *dlap) 769 { 770 dld_ap_t *dap; 771 int i, err; 772 mod_hash_key_t key; 773 774 if (dlap->dap_npush == 0 || dlap->dap_npush > MAXAPUSH) { 775 err = EINVAL; 776 goto failed; 777 } 778 779 /* 780 * Validate that the specified list of modules exist. 781 */ 782 for (i = 0; i < dlap->dap_npush; i++) { 783 if (fmodsw_find(dlap->dap_aplist[i], FMODSW_LOAD) == NULL) { 784 err = EINVAL; 785 goto failed; 786 } 787 } 788 789 key = (mod_hash_key_t)(uintptr_t)linkid; 790 791 rw_enter(&dld_ap_hash_lock, RW_WRITER); 792 if (mod_hash_find(dld_ap_hashp, key, (mod_hash_val_t *)&dap) != 0) { 793 dap = kmem_zalloc(sizeof (dld_ap_t), KM_NOSLEEP); 794 if (dap == NULL) { 795 rw_exit(&dld_ap_hash_lock); 796 err = ENOMEM; 797 goto failed; 798 } 799 800 dap->da_linkid = linkid; 801 err = mod_hash_insert(dld_ap_hashp, key, (mod_hash_val_t)dap); 802 ASSERT(err == 0); 803 } 804 805 /* 806 * Update the configuration. 807 */ 808 dap->da_anchor = dlap->dap_anchor; 809 dap->da_npush = dlap->dap_npush; 810 for (i = 0; i < dlap->dap_npush; i++) { 811 (void) strlcpy(dap->da_aplist[i], dlap->dap_aplist[i], 812 FMNAMESZ + 1); 813 } 814 rw_exit(&dld_ap_hash_lock); 815 816 return (0); 817 818 failed: 819 return (err); 820 } 821 822 static int 823 drv_ioc_getap(datalink_id_t linkid, struct dlautopush *dlap) 824 { 825 dld_ap_t *dap; 826 int i, err; 827 828 rw_enter(&dld_ap_hash_lock, RW_READER); 829 if (mod_hash_find(dld_ap_hashp, 830 (mod_hash_key_t)(uintptr_t)linkid, 831 (mod_hash_val_t *)&dap) != 0) { 832 err = ENOENT; 833 rw_exit(&dld_ap_hash_lock); 834 goto failed; 835 } 836 837 /* 838 * Retrieve the configuration. 839 */ 840 dlap->dap_anchor = dap->da_anchor; 841 dlap->dap_npush = dap->da_npush; 842 for (i = 0; i < dap->da_npush; i++) { 843 (void) strlcpy(dlap->dap_aplist[i], dap->da_aplist[i], 844 FMNAMESZ + 1); 845 } 846 rw_exit(&dld_ap_hash_lock); 847 848 return (0); 849 850 failed: 851 return (err); 852 } 853 854 static int 855 drv_ioc_clrap(datalink_id_t linkid) 856 { 857 mod_hash_val_t val; 858 mod_hash_key_t key; 859 860 key = (mod_hash_key_t)(uintptr_t)linkid; 861 862 rw_enter(&dld_ap_hash_lock, RW_WRITER); 863 if (mod_hash_find(dld_ap_hashp, key, &val) != 0) { 864 rw_exit(&dld_ap_hash_lock); 865 return (0); 866 } 867 868 VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0); 869 kmem_free(val, sizeof (dld_ap_t)); 870 rw_exit(&dld_ap_hash_lock); 871 return (0); 872 } 873 874 /* 875 * DLDIOC_DOORSERVER 876 */ 877 static void 878 drv_ioc_doorserver(dld_ctl_str_t *ctls, mblk_t *mp) 879 { 880 queue_t *q = ctls->cs_wq; 881 dld_ioc_door_t *did; 882 int err; 883 884 if ((err = miocpullup(mp, sizeof (dld_ioc_door_t))) != 0) 885 goto done; 886 887 did = (dld_ioc_door_t *)mp->b_cont->b_rptr; 888 err = dls_mgmt_door_set(did->did_start_door); 889 890 done: 891 if (err == 0) 892 miocack(q, mp, 0, 0); 893 else 894 miocnak(q, mp, 0, err); 895 } 896 897 /* 898 * Process an IOCTL message received by the control node. 899 */ 900 static void 901 drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp) 902 { 903 uint_t cmd; 904 905 cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd; 906 switch (cmd) { 907 case DLDIOC_ATTR: 908 drv_ioc_attr(ctls, mp); 909 return; 910 case DLDIOC_PHYS_ATTR: 911 drv_ioc_phys_attr(ctls, mp); 912 return; 913 case DLDIOC_SECOBJ_SET: 914 drv_ioc_secobj_set(ctls, mp); 915 return; 916 case DLDIOC_SECOBJ_GET: 917 drv_ioc_secobj_get(ctls, mp); 918 return; 919 case DLDIOC_SECOBJ_UNSET: 920 drv_ioc_secobj_unset(ctls, mp); 921 return; 922 case DLDIOC_SETMACPROP: 923 drv_ioc_setprop(ctls, mp); 924 return; 925 case DLDIOC_GETMACPROP: 926 drv_ioc_getprop(ctls, mp); 927 return; 928 case DLDIOC_CREATE_VLAN: 929 drv_ioc_create_vlan(ctls, mp); 930 return; 931 case DLDIOC_DELETE_VLAN: 932 drv_ioc_delete_vlan(ctls, mp); 933 return; 934 case DLDIOC_VLAN_ATTR: 935 drv_ioc_vlan_attr(ctls, mp); 936 return; 937 case DLDIOC_DOORSERVER: 938 drv_ioc_doorserver(ctls, mp); 939 return; 940 case DLDIOC_RENAME: 941 drv_ioc_rename(ctls, mp); 942 return; 943 default: 944 miocnak(ctls->cs_wq, mp, 0, ENOTSUP); 945 return; 946 } 947 } 948 949 /* 950 * Write side put routine of the dld control node. 951 */ 952 static void 953 drv_uw_put(queue_t *q, mblk_t *mp) 954 { 955 dld_ctl_str_t *ctls = q->q_ptr; 956 957 switch (mp->b_datap->db_type) { 958 case M_IOCTL: 959 drv_ioc(ctls, mp); 960 break; 961 default: 962 freemsg(mp); 963 break; 964 } 965 } 966 967 /* 968 * Write-side service procedure. 969 */ 970 void 971 drv_uw_srv(queue_t *q) 972 { 973 mblk_t *mp; 974 975 while (mp = getq(q)) 976 drv_uw_put(q, mp); 977 } 978 979 /* 980 * Check for GLDv3 autopush information. There are three cases: 981 * 982 * 1. If devp points to a GLDv3 datalink and it has autopush configuration, 983 * fill dlap in with that information and return 0. 984 * 985 * 2. If devp points to a GLDv3 datalink but it doesn't have autopush 986 * configuration, then replace devp with the physical device (if one 987 * exists) and return 1. This allows stropen() to find the old-school 988 * per-driver autopush configuration. (For softmac, the result is that 989 * the softmac dev_t is replaced with the legacy device's dev_t). 990 * 991 * 3. If neither of the above apply, don't touch the args and return -1. 992 */ 993 int 994 dld_autopush(dev_t *devp, struct dlautopush *dlap) 995 { 996 dld_ap_t *dap; 997 datalink_id_t linkid; 998 dev_t phydev; 999 1000 if (!GLDV3_DRV(getmajor(*devp))) 1001 return (-1); 1002 1003 /* 1004 * Find the linkid by the link's dev_t. 1005 */ 1006 if (dls_devnet_dev2linkid(*devp, &linkid) != 0) 1007 return (-1); 1008 1009 /* 1010 * Find the autopush configuration associated with the linkid. 1011 */ 1012 rw_enter(&dld_ap_hash_lock, RW_READER); 1013 if (mod_hash_find(dld_ap_hashp, (mod_hash_key_t)(uintptr_t)linkid, 1014 (mod_hash_val_t *)&dap) == 0) { 1015 *dlap = dap->da_ap; 1016 rw_exit(&dld_ap_hash_lock); 1017 return (0); 1018 } 1019 rw_exit(&dld_ap_hash_lock); 1020 1021 if (dls_devnet_phydev(linkid, &phydev) != 0) 1022 return (-1); 1023 1024 *devp = phydev; 1025 return (1); 1026 } 1027 1028 /* 1029 * Secure objects implementation 1030 */ 1031 1032 /* ARGSUSED */ 1033 static int 1034 drv_secobj_ctor(void *buf, void *arg, int kmflag) 1035 { 1036 bzero(buf, sizeof (dld_secobj_t)); 1037 return (0); 1038 } 1039 1040 static void 1041 drv_secobj_init(void) 1042 { 1043 rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL); 1044 drv_secobj_cachep = kmem_cache_create("drv_secobj_cache", 1045 sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL, 1046 NULL, NULL, NULL, 0); 1047 drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash", 1048 SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 1049 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 1050 } 1051 1052 static void 1053 drv_secobj_fini(void) 1054 { 1055 mod_hash_destroy_hash(drv_secobj_hash); 1056 kmem_cache_destroy(drv_secobj_cachep); 1057 rw_destroy(&drv_secobj_lock); 1058 } 1059 1060 static void 1061 drv_ioc_secobj_set(dld_ctl_str_t *ctls, mblk_t *mp) 1062 { 1063 dld_ioc_secobj_set_t *ssp; 1064 dld_secobj_t *sobjp, *objp; 1065 int err = EINVAL; 1066 queue_t *q = ctls->cs_wq; 1067 1068 if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_set_t))) != 0) 1069 goto failed; 1070 1071 ssp = (dld_ioc_secobj_set_t *)mp->b_cont->b_rptr; 1072 sobjp = &ssp->ss_obj; 1073 1074 if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP && 1075 sobjp->so_class != DLD_SECOBJ_CLASS_WPA) 1076 goto failed; 1077 1078 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' || 1079 sobjp->so_len > DLD_SECOBJ_VAL_MAX) 1080 goto failed; 1081 1082 rw_enter(&drv_secobj_lock, RW_WRITER); 1083 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name, 1084 (mod_hash_val_t *)&objp); 1085 if (err == 0) { 1086 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) { 1087 err = EEXIST; 1088 rw_exit(&drv_secobj_lock); 1089 goto failed; 1090 } 1091 } else { 1092 ASSERT(err == MH_ERR_NOTFOUND); 1093 if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) { 1094 err = ENOENT; 1095 rw_exit(&drv_secobj_lock); 1096 goto failed; 1097 } 1098 objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP); 1099 (void) strlcpy(objp->so_name, sobjp->so_name, 1100 DLD_SECOBJ_NAME_MAX); 1101 1102 err = mod_hash_insert(drv_secobj_hash, 1103 (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp); 1104 ASSERT(err == 0); 1105 } 1106 bcopy(sobjp->so_val, objp->so_val, sobjp->so_len); 1107 objp->so_len = sobjp->so_len; 1108 objp->so_class = sobjp->so_class; 1109 rw_exit(&drv_secobj_lock); 1110 miocack(q, mp, 0, 0); 1111 return; 1112 1113 failed: 1114 ASSERT(err != 0); 1115 miocnak(q, mp, 0, err); 1116 } 1117 1118 typedef struct dld_secobj_state { 1119 uint_t ss_free; 1120 uint_t ss_count; 1121 int ss_rc; 1122 dld_secobj_t *ss_objp; 1123 } dld_secobj_state_t; 1124 1125 /* ARGSUSED */ 1126 static uint_t 1127 drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1128 { 1129 dld_secobj_state_t *statep = arg; 1130 dld_secobj_t *sobjp = (dld_secobj_t *)val; 1131 1132 if (statep->ss_free < sizeof (dld_secobj_t)) { 1133 statep->ss_rc = ENOSPC; 1134 return (MH_WALK_TERMINATE); 1135 } 1136 bcopy(sobjp, statep->ss_objp, sizeof (dld_secobj_t)); 1137 statep->ss_objp++; 1138 statep->ss_free -= sizeof (dld_secobj_t); 1139 statep->ss_count++; 1140 return (MH_WALK_CONTINUE); 1141 } 1142 1143 static void 1144 drv_ioc_secobj_get(dld_ctl_str_t *ctls, mblk_t *mp) 1145 { 1146 dld_ioc_secobj_get_t *sgp; 1147 dld_secobj_t *sobjp, *objp; 1148 int err = EINVAL; 1149 uint_t extra = 0; 1150 queue_t *q = ctls->cs_wq; 1151 mblk_t *bp; 1152 1153 if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_get_t))) != 0) 1154 goto failed; 1155 1156 if ((bp = msgpullup(mp->b_cont, -1)) == NULL) 1157 goto failed; 1158 1159 freemsg(mp->b_cont); 1160 mp->b_cont = bp; 1161 sgp = (dld_ioc_secobj_get_t *)bp->b_rptr; 1162 sobjp = &sgp->sg_obj; 1163 1164 if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 1165 goto failed; 1166 1167 rw_enter(&drv_secobj_lock, RW_READER); 1168 if (sobjp->so_name[0] != '\0') { 1169 err = mod_hash_find(drv_secobj_hash, 1170 (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp); 1171 if (err != 0) { 1172 ASSERT(err == MH_ERR_NOTFOUND); 1173 err = ENOENT; 1174 rw_exit(&drv_secobj_lock); 1175 goto failed; 1176 } 1177 bcopy(objp->so_val, sobjp->so_val, objp->so_len); 1178 sobjp->so_len = objp->so_len; 1179 sobjp->so_class = objp->so_class; 1180 sgp->sg_count = 1; 1181 } else { 1182 dld_secobj_state_t state; 1183 1184 state.ss_free = MBLKL(bp) - sizeof (dld_ioc_secobj_get_t); 1185 state.ss_count = 0; 1186 state.ss_rc = 0; 1187 state.ss_objp = (dld_secobj_t *)(sgp + 1); 1188 mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state); 1189 if (state.ss_rc != 0) { 1190 err = state.ss_rc; 1191 rw_exit(&drv_secobj_lock); 1192 goto failed; 1193 } 1194 sgp->sg_count = state.ss_count; 1195 extra = state.ss_count * sizeof (dld_secobj_t); 1196 } 1197 rw_exit(&drv_secobj_lock); 1198 miocack(q, mp, sizeof (dld_ioc_secobj_get_t) + extra, 0); 1199 return; 1200 1201 failed: 1202 ASSERT(err != 0); 1203 miocnak(q, mp, 0, err); 1204 1205 } 1206 1207 static void 1208 drv_ioc_secobj_unset(dld_ctl_str_t *ctls, mblk_t *mp) 1209 { 1210 dld_ioc_secobj_unset_t *sup; 1211 dld_secobj_t *objp; 1212 mod_hash_val_t val; 1213 int err = EINVAL; 1214 queue_t *q = ctls->cs_wq; 1215 1216 if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_unset_t))) != 0) 1217 goto failed; 1218 1219 sup = (dld_ioc_secobj_unset_t *)mp->b_cont->b_rptr; 1220 if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0') 1221 goto failed; 1222 1223 rw_enter(&drv_secobj_lock, RW_WRITER); 1224 err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 1225 (mod_hash_val_t *)&objp); 1226 if (err != 0) { 1227 ASSERT(err == MH_ERR_NOTFOUND); 1228 err = ENOENT; 1229 rw_exit(&drv_secobj_lock); 1230 goto failed; 1231 } 1232 err = mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name, 1233 (mod_hash_val_t *)&val); 1234 ASSERT(err == 0); 1235 ASSERT(objp == (dld_secobj_t *)val); 1236 1237 kmem_cache_free(drv_secobj_cachep, objp); 1238 rw_exit(&drv_secobj_lock); 1239 miocack(q, mp, 0, 0); 1240 return; 1241 1242 failed: 1243 ASSERT(err != 0); 1244 miocnak(q, mp, 0, err); 1245 } 1246