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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Datalink management routines. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/door.h> 32 #include <sys/zone.h> 33 #include <sys/modctl.h> 34 #include <sys/file.h> 35 #include <sys/modhash.h> 36 #include <sys/kstat.h> 37 #include <sys/vnode.h> 38 #include <sys/cmn_err.h> 39 #include <sys/softmac.h> 40 #include <sys/dls.h> 41 #include <sys/dls_impl.h> 42 43 /* 44 * This vanity name management module is treated as part of the GLD framework 45 * and we don't hold any GLD framework lock across a call to any mac 46 * function that needs to acquire the mac perimeter. The hierarchy is 47 * mac perimeter -> framework locks 48 */ 49 50 static kmem_cache_t *i_dls_devnet_cachep; 51 static kmutex_t i_dls_mgmt_lock; 52 static krwlock_t i_dls_devnet_lock; 53 static mod_hash_t *i_dls_devnet_id_hash; 54 static mod_hash_t *i_dls_devnet_hash; 55 56 boolean_t devnet_need_rebuild; 57 58 #define VLAN_HASHSZ 67 /* prime */ 59 60 /* Upcall door handle */ 61 static door_handle_t dls_mgmt_dh = NULL; 62 63 #define DD_CONDEMNED 0x1 64 #define DD_KSTAT_CHANGING 0x2 65 66 /* 67 * This structure is used to keep the <linkid, macname> mapping. 68 * This structure itself is not protected by the mac perimeter, but is 69 * protected by the dd_mutex and i_dls_devnet_lock. Thus most of the 70 * functions manipulating this structure such as dls_devnet_set/unset etc. 71 * may be called while not holding the mac perimeter. 72 */ 73 typedef struct dls_devnet_s { 74 datalink_id_t dd_linkid; 75 char dd_mac[MAXNAMELEN]; 76 kstat_t *dd_ksp; 77 uint32_t dd_ref; 78 79 kmutex_t dd_mutex; 80 kcondvar_t dd_cv; 81 uint32_t dd_tref; 82 uint_t dd_flags; 83 84 zoneid_t dd_zid; 85 86 boolean_t dd_prop_loaded; 87 taskqid_t dd_prop_taskid; 88 } dls_devnet_t; 89 90 91 /*ARGSUSED*/ 92 static int 93 i_dls_devnet_constructor(void *buf, void *arg, int kmflag) 94 { 95 dls_devnet_t *ddp = buf; 96 97 bzero(buf, sizeof (dls_devnet_t)); 98 mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL); 99 cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL); 100 return (0); 101 } 102 103 /*ARGSUSED*/ 104 static void 105 i_dls_devnet_destructor(void *buf, void *arg) 106 { 107 dls_devnet_t *ddp = buf; 108 109 ASSERT(ddp->dd_ksp == NULL); 110 ASSERT(ddp->dd_ref == 0); 111 ASSERT(ddp->dd_tref == 0); 112 mutex_destroy(&ddp->dd_mutex); 113 cv_destroy(&ddp->dd_cv); 114 } 115 116 /* 117 * Module initialization and finalization functions. 118 */ 119 void 120 dls_mgmt_init(void) 121 { 122 mutex_init(&i_dls_mgmt_lock, NULL, MUTEX_DEFAULT, NULL); 123 rw_init(&i_dls_devnet_lock, NULL, RW_DEFAULT, NULL); 124 125 /* 126 * Create a kmem_cache of dls_devnet_t structures. 127 */ 128 i_dls_devnet_cachep = kmem_cache_create("dls_devnet_cache", 129 sizeof (dls_devnet_t), 0, i_dls_devnet_constructor, 130 i_dls_devnet_destructor, NULL, NULL, NULL, 0); 131 ASSERT(i_dls_devnet_cachep != NULL); 132 133 /* 134 * Create a hash table, keyed by dd_linkid, of dls_devnet_t. 135 */ 136 i_dls_devnet_id_hash = mod_hash_create_idhash("dls_devnet_id_hash", 137 VLAN_HASHSZ, mod_hash_null_valdtor); 138 139 /* 140 * Create a hash table, keyed by dd_mac 141 */ 142 i_dls_devnet_hash = mod_hash_create_extended("dls_devnet_hash", 143 VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 144 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 145 146 devnet_need_rebuild = B_FALSE; 147 } 148 149 void 150 dls_mgmt_fini(void) 151 { 152 mod_hash_destroy_hash(i_dls_devnet_hash); 153 mod_hash_destroy_hash(i_dls_devnet_id_hash); 154 kmem_cache_destroy(i_dls_devnet_cachep); 155 rw_destroy(&i_dls_devnet_lock); 156 mutex_destroy(&i_dls_mgmt_lock); 157 } 158 159 int 160 dls_mgmt_door_set(boolean_t start) 161 { 162 int err; 163 164 /* handle daemon restart */ 165 mutex_enter(&i_dls_mgmt_lock); 166 if (dls_mgmt_dh != NULL) { 167 door_ki_rele(dls_mgmt_dh); 168 dls_mgmt_dh = NULL; 169 } 170 171 if (start && ((err = door_ki_open(DLMGMT_DOOR, &dls_mgmt_dh)) != 0)) { 172 mutex_exit(&i_dls_mgmt_lock); 173 return (err); 174 } 175 176 mutex_exit(&i_dls_mgmt_lock); 177 178 /* 179 * Create and associate <link name, linkid> mapping for network devices 180 * which are already attached before the daemon is started. 181 */ 182 if (start) 183 softmac_recreate(); 184 return (0); 185 } 186 187 static boolean_t 188 i_dls_mgmt_door_revoked(door_handle_t dh) 189 { 190 struct door_info info; 191 extern int sys_shutdown; 192 193 ASSERT(dh != NULL); 194 195 if (sys_shutdown) { 196 cmn_err(CE_NOTE, "dls_mgmt_door: shutdown observed\n"); 197 return (B_TRUE); 198 } 199 200 if (door_ki_info(dh, &info) != 0) 201 return (B_TRUE); 202 203 return ((info.di_attributes & DOOR_REVOKED) != 0); 204 } 205 206 /* 207 * Upcall to the datalink management daemon (dlmgmtd). 208 */ 209 static int 210 i_dls_mgmt_upcall(void *arg, size_t asize, void *rbuf, size_t rsize) 211 { 212 door_arg_t darg, save_arg; 213 door_handle_t dh; 214 int err; 215 int retry = 0; 216 217 #define MAXRETRYNUM 3 218 219 ASSERT(arg); 220 darg.data_ptr = arg; 221 darg.data_size = asize; 222 darg.desc_ptr = NULL; 223 darg.desc_num = 0; 224 darg.rbuf = rbuf; 225 darg.rsize = rsize; 226 save_arg = darg; 227 228 retry: 229 mutex_enter(&i_dls_mgmt_lock); 230 dh = dls_mgmt_dh; 231 if ((dh == NULL) || i_dls_mgmt_door_revoked(dh)) { 232 mutex_exit(&i_dls_mgmt_lock); 233 return (EBADF); 234 } 235 door_ki_hold(dh); 236 mutex_exit(&i_dls_mgmt_lock); 237 238 for (;;) { 239 retry++; 240 if ((err = door_ki_upcall_limited(dh, &darg, kcred, 241 SIZE_MAX, 0)) == 0) 242 break; 243 244 /* 245 * handle door call errors 246 */ 247 darg = save_arg; 248 switch (err) { 249 case EINTR: 250 /* 251 * If the operation which caused this door upcall gets 252 * interrupted, return directly. 253 */ 254 goto done; 255 case EAGAIN: 256 /* 257 * Repeat upcall if the maximum attempt limit has not 258 * been reached. 259 */ 260 if (retry < MAXRETRYNUM) { 261 delay(2 * hz); 262 break; 263 } 264 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err); 265 goto done; 266 default: 267 /* A fatal door error */ 268 if (i_dls_mgmt_door_revoked(dh)) { 269 cmn_err(CE_NOTE, 270 "dls: dlmgmtd door service revoked\n"); 271 272 if (retry < MAXRETRYNUM) { 273 door_ki_rele(dh); 274 goto retry; 275 } 276 } 277 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err); 278 goto done; 279 } 280 } 281 282 if (darg.rbuf != rbuf) { 283 /* 284 * The size of the input rbuf was not big enough, so the 285 * upcall allocated the rbuf itself. If this happens, assume 286 * that this was an invalid door call request. 287 */ 288 kmem_free(darg.rbuf, darg.rsize); 289 err = ENOSPC; 290 goto done; 291 } 292 293 if (darg.rsize != rsize) { 294 err = EINVAL; 295 goto done; 296 } 297 298 err = ((dlmgmt_retval_t *)rbuf)->lr_err; 299 300 done: 301 door_ki_rele(dh); 302 return (err); 303 } 304 305 /* 306 * Request the datalink management daemon to create a link with the attributes 307 * below. Upon success, zero is returned and linkidp contains the linkid for 308 * the new link; otherwise, an errno is returned. 309 * 310 * - dev physical dev_t. required for all physical links, 311 * including GLDv3 links. It will be used to force the 312 * attachment of a physical device, hence the 313 * registration of its mac 314 * - class datalink class 315 * - media type media type; DL_OTHER means unknown 316 * - persist whether to persist the datalink 317 */ 318 int 319 dls_mgmt_create(const char *devname, dev_t dev, datalink_class_t class, 320 uint32_t media, boolean_t persist, datalink_id_t *linkidp) 321 { 322 dlmgmt_upcall_arg_create_t create; 323 dlmgmt_create_retval_t retval; 324 int err; 325 326 create.ld_cmd = DLMGMT_CMD_DLS_CREATE; 327 create.ld_class = class; 328 create.ld_media = media; 329 create.ld_phymaj = getmajor(dev); 330 create.ld_phyinst = getminor(dev); 331 create.ld_persist = persist; 332 if (strlcpy(create.ld_devname, devname, MAXNAMELEN) >= MAXNAMELEN) 333 return (EINVAL); 334 335 if ((err = i_dls_mgmt_upcall(&create, sizeof (create), &retval, 336 sizeof (retval))) == 0) { 337 *linkidp = retval.lr_linkid; 338 } 339 return (err); 340 } 341 342 /* 343 * Request the datalink management daemon to destroy the specified link. 344 * Returns zero upon success, or an errno upon failure. 345 */ 346 int 347 dls_mgmt_destroy(datalink_id_t linkid, boolean_t persist) 348 { 349 dlmgmt_upcall_arg_destroy_t destroy; 350 dlmgmt_destroy_retval_t retval; 351 352 destroy.ld_cmd = DLMGMT_CMD_DLS_DESTROY; 353 destroy.ld_linkid = linkid; 354 destroy.ld_persist = persist; 355 356 return (i_dls_mgmt_upcall(&destroy, sizeof (destroy), 357 &retval, sizeof (retval))); 358 } 359 360 /* 361 * Request the datalink management daemon to verify/update the information 362 * for a physical link. Upon success, get its linkid. 363 * 364 * - media type media type 365 * - novanity whether this physical datalink supports vanity naming. 366 * physical links that do not use the GLDv3 MAC plugin 367 * cannot suport vanity naming 368 * 369 * This function could fail with ENOENT or EEXIST. Two cases return EEXIST: 370 * 371 * 1. A link with devname already exists, but the media type does not match. 372 * In this case, mediap will bee set to the media type of the existing link. 373 * 2. A link with devname already exists, but its link name does not match 374 * the device name, although this link does not support vanity naming. 375 */ 376 int 377 dls_mgmt_update(const char *devname, uint32_t media, boolean_t novanity, 378 uint32_t *mediap, datalink_id_t *linkidp) 379 { 380 dlmgmt_upcall_arg_update_t update; 381 dlmgmt_update_retval_t retval; 382 int err; 383 384 update.ld_cmd = DLMGMT_CMD_DLS_UPDATE; 385 386 if (strlcpy(update.ld_devname, devname, MAXNAMELEN) >= MAXNAMELEN) 387 return (EINVAL); 388 389 update.ld_media = media; 390 update.ld_novanity = novanity; 391 392 if ((err = i_dls_mgmt_upcall(&update, sizeof (update), &retval, 393 sizeof (retval))) == EEXIST) { 394 *linkidp = retval.lr_linkid; 395 *mediap = retval.lr_media; 396 } else if (err == 0) { 397 *linkidp = retval.lr_linkid; 398 } 399 400 return (err); 401 } 402 403 /* 404 * Request the datalink management daemon to get the information for a link. 405 * Returns zero upon success, or an errno upon failure. 406 * 407 * Only fills in information for argument pointers that are non-NULL. 408 * Note that the link argument is expected to be MAXLINKNAMELEN bytes. 409 */ 410 int 411 dls_mgmt_get_linkinfo(datalink_id_t linkid, char *link, 412 datalink_class_t *classp, uint32_t *mediap, uint32_t *flagsp) 413 { 414 dlmgmt_door_getname_t getname; 415 dlmgmt_getname_retval_t retval; 416 int err, len; 417 418 getname.ld_cmd = DLMGMT_CMD_GETNAME; 419 getname.ld_linkid = linkid; 420 421 if ((err = i_dls_mgmt_upcall(&getname, sizeof (getname), &retval, 422 sizeof (retval))) != 0) { 423 return (err); 424 } 425 426 len = strlen(retval.lr_link); 427 if (len <= 1 || len >= MAXLINKNAMELEN) 428 return (EINVAL); 429 430 if (link != NULL) 431 (void) strlcpy(link, retval.lr_link, MAXLINKNAMELEN); 432 if (classp != NULL) 433 *classp = retval.lr_class; 434 if (mediap != NULL) 435 *mediap = retval.lr_media; 436 if (flagsp != NULL) 437 *flagsp = retval.lr_flags; 438 return (0); 439 } 440 441 /* 442 * Request the datalink management daemon to get the linkid for a link. 443 * Returns a non-zero error code on failure. The linkid argument is only 444 * set on success (when zero is returned.) 445 */ 446 int 447 dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid) 448 { 449 dlmgmt_door_getlinkid_t getlinkid; 450 dlmgmt_getlinkid_retval_t retval; 451 int err; 452 453 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; 454 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); 455 456 if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval, 457 sizeof (retval))) == 0) { 458 *linkid = retval.lr_linkid; 459 } 460 return (err); 461 } 462 463 datalink_id_t 464 dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class, 465 datalink_media_t dmedia, uint32_t flags) 466 { 467 dlmgmt_door_getnext_t getnext; 468 dlmgmt_getnext_retval_t retval; 469 470 getnext.ld_cmd = DLMGMT_CMD_GETNEXT; 471 getnext.ld_class = class; 472 getnext.ld_dmedia = dmedia; 473 getnext.ld_flags = flags; 474 getnext.ld_linkid = linkid; 475 476 if (i_dls_mgmt_upcall(&getnext, sizeof (getnext), &retval, 477 sizeof (retval)) != 0) { 478 return (DATALINK_INVALID_LINKID); 479 } 480 481 return (retval.lr_linkid); 482 } 483 484 static int 485 i_dls_mgmt_get_linkattr(const datalink_id_t linkid, const char *attr, 486 void *attrval, size_t *attrszp) 487 { 488 dlmgmt_upcall_arg_getattr_t getattr; 489 dlmgmt_getattr_retval_t retval; 490 int err; 491 492 getattr.ld_cmd = DLMGMT_CMD_DLS_GETATTR; 493 getattr.ld_linkid = linkid; 494 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); 495 496 if ((err = i_dls_mgmt_upcall(&getattr, sizeof (getattr), &retval, 497 sizeof (retval))) == 0) { 498 if (*attrszp < retval.lr_attrsz) 499 return (EINVAL); 500 *attrszp = retval.lr_attrsz; 501 bcopy(retval.lr_attrval, attrval, retval.lr_attrsz); 502 } 503 504 return (err); 505 } 506 507 /* 508 * Note that this function can only get devp successfully for non-VLAN link. 509 */ 510 int 511 dls_mgmt_get_phydev(datalink_id_t linkid, dev_t *devp) 512 { 513 uint64_t maj, inst; 514 size_t attrsz = sizeof (uint64_t); 515 516 if (i_dls_mgmt_get_linkattr(linkid, FPHYMAJ, &maj, &attrsz) != 0 || 517 attrsz != sizeof (uint64_t) || 518 i_dls_mgmt_get_linkattr(linkid, FPHYINST, &inst, &attrsz) != 0 || 519 attrsz != sizeof (uint64_t)) { 520 return (EINVAL); 521 } 522 523 *devp = makedevice((major_t)maj, (minor_t)inst); 524 return (0); 525 } 526 527 /* 528 * Request the datalink management daemon to push in 529 * all properties associated with the link. 530 * Returns a non-zero error code on failure. 531 */ 532 int 533 dls_mgmt_linkprop_init(datalink_id_t linkid) 534 { 535 dlmgmt_door_linkprop_init_t li; 536 dlmgmt_linkprop_init_retval_t retval; 537 int err; 538 539 li.ld_cmd = DLMGMT_CMD_LINKPROP_INIT; 540 li.ld_linkid = linkid; 541 542 err = i_dls_mgmt_upcall(&li, sizeof (li), &retval, sizeof (retval)); 543 return (err); 544 } 545 546 static void 547 dls_devnet_prop_task(void *arg) 548 { 549 dls_devnet_t *ddp = arg; 550 551 (void) dls_mgmt_linkprop_init(ddp->dd_linkid); 552 553 mutex_enter(&ddp->dd_mutex); 554 ddp->dd_prop_loaded = B_TRUE; 555 ddp->dd_prop_taskid = NULL; 556 cv_broadcast(&ddp->dd_cv); 557 mutex_exit(&ddp->dd_mutex); 558 } 559 560 /* 561 * Ensure property loading task is completed. 562 */ 563 void 564 dls_devnet_prop_task_wait(dls_dl_handle_t ddp) 565 { 566 mutex_enter(&ddp->dd_mutex); 567 while (ddp->dd_prop_taskid != NULL) 568 cv_wait(&ddp->dd_cv, &ddp->dd_mutex); 569 mutex_exit(&ddp->dd_mutex); 570 } 571 572 void 573 dls_devnet_rele_tmp(dls_dl_handle_t dlh) 574 { 575 dls_devnet_t *ddp = dlh; 576 577 mutex_enter(&ddp->dd_mutex); 578 ASSERT(ddp->dd_tref != 0); 579 if (--ddp->dd_tref == 0) 580 cv_signal(&ddp->dd_cv); 581 mutex_exit(&ddp->dd_mutex); 582 } 583 584 int 585 dls_devnet_hold_link(datalink_id_t linkid, dls_dl_handle_t *ddhp, 586 dls_link_t **dlpp) 587 { 588 dls_dl_handle_t dlh; 589 dls_link_t *dlp; 590 int err; 591 592 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 593 return (err); 594 595 if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) { 596 dls_devnet_rele_tmp(dlh); 597 return (err); 598 } 599 600 ASSERT(MAC_PERIM_HELD(dlp->dl_mh)); 601 602 *ddhp = dlh; 603 *dlpp = dlp; 604 return (0); 605 } 606 607 void 608 dls_devnet_rele_link(dls_dl_handle_t dlh, dls_link_t *dlp) 609 { 610 ASSERT(MAC_PERIM_HELD(dlp->dl_mh)); 611 612 dls_link_rele(dlp); 613 dls_devnet_rele_tmp(dlh); 614 } 615 616 /* 617 * "link" kstats related functions. 618 */ 619 620 /* 621 * Query the "link" kstats. 622 * 623 * We may be called from the kstat subsystem in an arbitrary context. 624 * If the caller is the stack, the context could be an upcall data 625 * thread. Hence we can't acquire the mac perimeter in this function 626 * for fear of deadlock. 627 */ 628 static int 629 dls_devnet_stat_update(kstat_t *ksp, int rw) 630 { 631 dls_devnet_t *ddp = ksp->ks_private; 632 dls_link_t *dlp; 633 int err; 634 635 /* 636 * Check the link is being renamed or if the link is going away 637 * before incrementing dd_tref which in turn prevents the link 638 * from being renamed or deleted until we finish. 639 */ 640 mutex_enter(&ddp->dd_mutex); 641 if (ddp->dd_flags & (DD_CONDEMNED | DD_KSTAT_CHANGING)) { 642 mutex_exit(&ddp->dd_mutex); 643 return (ENOENT); 644 } 645 ddp->dd_tref++; 646 mutex_exit(&ddp->dd_mutex); 647 648 /* 649 * If a device detach happens at this time, it will block in 650 * dls_devnet_unset since the dd_tref has been bumped up above. So the 651 * access to 'dlp' is safe even though we don't hold the mac perimeter. 652 */ 653 if (mod_hash_find(i_dls_link_hash, (mod_hash_key_t)ddp->dd_mac, 654 (mod_hash_val_t *)&dlp) != 0) { 655 dls_devnet_rele_tmp(ddp); 656 return (ENOENT); 657 } 658 659 err = dls_stat_update(ksp, dlp, rw); 660 661 dls_devnet_rele_tmp(ddp); 662 return (err); 663 } 664 665 /* 666 * Create the "link" kstats. 667 */ 668 static void 669 dls_devnet_stat_create(dls_devnet_t *ddp) 670 { 671 char link[MAXLINKNAMELEN]; 672 kstat_t *ksp; 673 674 if ((dls_mgmt_get_linkinfo(ddp->dd_linkid, link, 675 NULL, NULL, NULL)) != 0) { 676 return; 677 } 678 679 if (dls_stat_create("link", 0, link, dls_devnet_stat_update, 680 ddp, &ksp) != 0) { 681 return; 682 } 683 684 ASSERT(ksp != NULL); 685 ddp->dd_ksp = ksp; 686 } 687 688 /* 689 * Destroy the "link" kstats. 690 */ 691 static void 692 dls_devnet_stat_destroy(dls_devnet_t *ddp) 693 { 694 if (ddp->dd_ksp == NULL) 695 return; 696 697 kstat_delete(ddp->dd_ksp); 698 ddp->dd_ksp = NULL; 699 } 700 701 /* 702 * The link has been renamed. Destroy the old non-legacy kstats ("link kstats") 703 * and create the new set using the new name. 704 */ 705 static void 706 dls_devnet_stat_rename(dls_devnet_t *ddp, const char *link) 707 { 708 kstat_t *ksp; 709 710 if (ddp->dd_ksp != NULL) { 711 kstat_delete(ddp->dd_ksp); 712 ddp->dd_ksp = NULL; 713 } 714 715 if (dls_stat_create("link", 0, link, dls_devnet_stat_update, 716 ddp, &ksp) != 0) { 717 return; 718 } 719 720 ASSERT(ksp != NULL); 721 ddp->dd_ksp = ksp; 722 } 723 724 /* 725 * Associate a linkid with a given link (identified by macname) 726 */ 727 static int 728 dls_devnet_set(const char *macname, datalink_id_t linkid, dls_devnet_t **ddpp) 729 { 730 dls_devnet_t *ddp = NULL; 731 datalink_class_t class; 732 int err; 733 boolean_t stat_create = B_FALSE; 734 735 rw_enter(&i_dls_devnet_lock, RW_WRITER); 736 if ((err = mod_hash_find(i_dls_devnet_hash, 737 (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) == 0) { 738 if (ddp->dd_linkid != DATALINK_INVALID_LINKID) { 739 err = EEXIST; 740 goto done; 741 } 742 743 /* 744 * This might be a physical link that has already 745 * been created, but which does not have a linkid 746 * because dlmgmtd was not running when it was created. 747 */ 748 if ((err = dls_mgmt_get_linkinfo(linkid, NULL, 749 &class, NULL, NULL)) != 0) { 750 goto done; 751 } 752 753 if (class != DATALINK_CLASS_PHYS) { 754 err = EINVAL; 755 goto done; 756 } 757 758 goto newphys; 759 } 760 ddp = kmem_cache_alloc(i_dls_devnet_cachep, KM_SLEEP); 761 ddp->dd_tref = 0; 762 ddp->dd_ref++; 763 ddp->dd_zid = GLOBAL_ZONEID; 764 (void) strncpy(ddp->dd_mac, macname, MAXNAMELEN); 765 VERIFY(mod_hash_insert(i_dls_devnet_hash, 766 (mod_hash_key_t)ddp->dd_mac, (mod_hash_val_t)ddp) == 0); 767 768 newphys: 769 if (linkid != DATALINK_INVALID_LINKID) { 770 ddp->dd_linkid = linkid; 771 VERIFY(mod_hash_insert(i_dls_devnet_id_hash, 772 (mod_hash_key_t)(uintptr_t)linkid, 773 (mod_hash_val_t)ddp) == 0); 774 devnet_need_rebuild = B_TRUE; 775 stat_create = B_TRUE; 776 mutex_enter(&ddp->dd_mutex); 777 if (!ddp->dd_prop_loaded && (ddp->dd_prop_taskid == NULL)) { 778 ddp->dd_prop_taskid = taskq_dispatch(system_taskq, 779 dls_devnet_prop_task, ddp, TQ_SLEEP); 780 } 781 mutex_exit(&ddp->dd_mutex); 782 } 783 784 err = 0; 785 done: 786 rw_exit(&i_dls_devnet_lock); 787 /* 788 * It is safe to drop the i_dls_devnet_lock at this point. In the case 789 * of physical devices, the softmac framework will fail the device 790 * detach based on the smac_state or smac_hold_cnt. Other cases like 791 * vnic and aggr use their own scheme to serialize creates and deletes 792 * and ensure that *ddp is valid. 793 * 794 * The kstat subsystem holds its own locks (rather perimeter) before 795 * calling the ks_update (dls_devnet_stat_update) entry point which 796 * in turn grabs the i_dls_devnet_lock. So the lock hierarchy is 797 * kstat locks -> i_dls_devnet_lock. 798 */ 799 if (stat_create) 800 dls_devnet_stat_create(ddp); 801 if (err == 0 && ddpp != NULL) 802 *ddpp = ddp; 803 return (err); 804 } 805 806 /* 807 * Disassociate a linkid with a given link (identified by macname) 808 * This waits until temporary references to the dls_devnet_t are gone. 809 */ 810 static int 811 dls_devnet_unset(const char *macname, datalink_id_t *id, boolean_t wait) 812 { 813 dls_devnet_t *ddp; 814 int err; 815 mod_hash_val_t val; 816 817 rw_enter(&i_dls_devnet_lock, RW_WRITER); 818 if ((err = mod_hash_find(i_dls_devnet_hash, 819 (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) != 0) { 820 ASSERT(err == MH_ERR_NOTFOUND); 821 rw_exit(&i_dls_devnet_lock); 822 return (ENOENT); 823 } 824 825 mutex_enter(&ddp->dd_mutex); 826 827 /* 828 * Make sure downcalls into softmac_create or softmac_destroy from 829 * devfs don't cv_wait on any devfs related condition for fear of 830 * deadlock. Return EBUSY if the asynchronous thread started for 831 * property loading as part of the post attach hasn't yet completed. 832 */ 833 ASSERT(ddp->dd_ref != 0); 834 if ((ddp->dd_ref != 1) || (!wait && 835 (ddp->dd_tref != 0 || ddp->dd_prop_taskid != NULL))) { 836 mutex_exit(&ddp->dd_mutex); 837 rw_exit(&i_dls_devnet_lock); 838 return (EBUSY); 839 } 840 841 ddp->dd_flags |= DD_CONDEMNED; 842 ddp->dd_ref--; 843 *id = ddp->dd_linkid; 844 845 /* 846 * Remove this dls_devnet_t from the hash table. 847 */ 848 VERIFY(mod_hash_remove(i_dls_devnet_hash, 849 (mod_hash_key_t)ddp->dd_mac, &val) == 0); 850 851 if (ddp->dd_linkid != DATALINK_INVALID_LINKID) { 852 VERIFY(mod_hash_remove(i_dls_devnet_id_hash, 853 (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, &val) == 0); 854 855 devnet_need_rebuild = B_TRUE; 856 } 857 rw_exit(&i_dls_devnet_lock); 858 859 if (wait) { 860 /* 861 * Wait until all temporary references are released. 862 */ 863 while ((ddp->dd_tref != 0) || (ddp->dd_prop_taskid != NULL)) 864 cv_wait(&ddp->dd_cv, &ddp->dd_mutex); 865 } else { 866 ASSERT(ddp->dd_tref == 0 && ddp->dd_prop_taskid == NULL); 867 } 868 869 if (ddp->dd_linkid != DATALINK_INVALID_LINKID) 870 dls_devnet_stat_destroy(ddp); 871 872 ddp->dd_prop_loaded = B_FALSE; 873 ddp->dd_linkid = DATALINK_INVALID_LINKID; 874 ddp->dd_zid = GLOBAL_ZONEID; 875 ddp->dd_flags = 0; 876 mutex_exit(&ddp->dd_mutex); 877 kmem_cache_free(i_dls_devnet_cachep, ddp); 878 879 return (0); 880 } 881 882 static int 883 dls_devnet_hold_common(datalink_id_t linkid, dls_devnet_t **ddpp, 884 boolean_t tmp_hold) 885 { 886 dls_devnet_t *ddp; 887 dev_t phydev = 0; 888 dls_dev_handle_t ddh = NULL; 889 int err; 890 891 /* 892 * Hold this link to prevent it being detached in case of a 893 * physical link. 894 */ 895 if (dls_mgmt_get_phydev(linkid, &phydev) == 0) 896 (void) softmac_hold_device(phydev, &ddh); 897 898 rw_enter(&i_dls_devnet_lock, RW_WRITER); 899 if ((err = mod_hash_find(i_dls_devnet_id_hash, 900 (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) { 901 ASSERT(err == MH_ERR_NOTFOUND); 902 rw_exit(&i_dls_devnet_lock); 903 softmac_rele_device(ddh); 904 return (ENOENT); 905 } 906 907 mutex_enter(&ddp->dd_mutex); 908 ASSERT(ddp->dd_ref > 0); 909 if (ddp->dd_flags & DD_CONDEMNED) { 910 mutex_exit(&ddp->dd_mutex); 911 rw_exit(&i_dls_devnet_lock); 912 softmac_rele_device(ddh); 913 return (ENOENT); 914 } 915 if (tmp_hold) 916 ddp->dd_tref++; 917 else 918 ddp->dd_ref++; 919 mutex_exit(&ddp->dd_mutex); 920 rw_exit(&i_dls_devnet_lock); 921 922 softmac_rele_device(ddh); 923 924 *ddpp = ddp; 925 return (0); 926 } 927 928 int 929 dls_devnet_hold(datalink_id_t linkid, dls_devnet_t **ddpp) 930 { 931 return (dls_devnet_hold_common(linkid, ddpp, B_FALSE)); 932 } 933 934 /* 935 * Hold the vanity naming structure (dls_devnet_t) temporarily. The request to 936 * delete the dls_devnet_t will wait until the temporary reference is released. 937 */ 938 int 939 dls_devnet_hold_tmp(datalink_id_t linkid, dls_devnet_t **ddpp) 940 { 941 return (dls_devnet_hold_common(linkid, ddpp, B_TRUE)); 942 } 943 944 /* 945 * This funtion is called when a DLS client tries to open a device node. 946 * This dev_t could a result of a /dev/net node access (returned by 947 * devnet_create_rvp->dls_devnet_open()) or a direct /dev node access. 948 * In both cases, this function bumps up the reference count of the 949 * dls_devnet_t structure. The reference is held as long as the device node 950 * is open. In the case of /dev/net while it is true that the initial reference 951 * is held when the devnet_create_rvp->dls_devnet_open call happens, this 952 * initial reference is released immediately in devnet_inactive_callback -> 953 * dls_devnet_close(). (Note that devnet_inactive_callback() is called right 954 * after dld_open completes, not when the /dev/net node is being closed). 955 * To undo this function, call dls_devnet_rele() 956 */ 957 int 958 dls_devnet_hold_by_dev(dev_t dev, dls_dl_handle_t *ddhp) 959 { 960 char name[MAXNAMELEN]; 961 char *drv; 962 dls_dev_handle_t ddh = NULL; 963 dls_devnet_t *ddp; 964 int err; 965 966 if ((drv = ddi_major_to_name(getmajor(dev))) == NULL) 967 return (EINVAL); 968 969 (void) snprintf(name, MAXNAMELEN, "%s%d", drv, getminor(dev) - 1); 970 971 /* 972 * Hold this link to prevent it being detached in case of a 973 * GLDv3 physical link. 974 */ 975 if (getminor(dev) - 1 < MAC_MAX_MINOR) 976 (void) softmac_hold_device(dev, &ddh); 977 978 rw_enter(&i_dls_devnet_lock, RW_WRITER); 979 if ((err = mod_hash_find(i_dls_devnet_hash, 980 (mod_hash_key_t)name, (mod_hash_val_t *)&ddp)) != 0) { 981 ASSERT(err == MH_ERR_NOTFOUND); 982 rw_exit(&i_dls_devnet_lock); 983 softmac_rele_device(ddh); 984 return (ENOENT); 985 } 986 mutex_enter(&ddp->dd_mutex); 987 ASSERT(ddp->dd_ref > 0); 988 if (ddp->dd_flags & DD_CONDEMNED) { 989 mutex_exit(&ddp->dd_mutex); 990 rw_exit(&i_dls_devnet_lock); 991 softmac_rele_device(ddh); 992 return (ENOENT); 993 } 994 ddp->dd_ref++; 995 mutex_exit(&ddp->dd_mutex); 996 rw_exit(&i_dls_devnet_lock); 997 998 softmac_rele_device(ddh); 999 1000 *ddhp = ddp; 1001 return (0); 1002 } 1003 1004 void 1005 dls_devnet_rele(dls_devnet_t *ddp) 1006 { 1007 mutex_enter(&ddp->dd_mutex); 1008 ASSERT(ddp->dd_ref > 1); 1009 ddp->dd_ref--; 1010 mutex_exit(&ddp->dd_mutex); 1011 } 1012 1013 static int 1014 dls_devnet_hold_by_name(const char *link, dls_devnet_t **ddpp) 1015 { 1016 char drv[MAXLINKNAMELEN]; 1017 uint_t ppa; 1018 major_t major; 1019 dev_t phy_dev, tmp_dev; 1020 datalink_id_t linkid; 1021 dls_dev_handle_t ddh; 1022 int err; 1023 1024 if ((err = dls_mgmt_get_linkid(link, &linkid)) == 0) 1025 return (dls_devnet_hold(linkid, ddpp)); 1026 1027 /* 1028 * If we failed to get the link's linkid because the dlmgmtd daemon 1029 * has not been started, return ENOENT so that the application can 1030 * fallback to open the /dev node. 1031 */ 1032 if (err == EBADF) 1033 return (ENOENT); 1034 1035 if (err != ENOENT) 1036 return (err); 1037 1038 if (ddi_parse(link, drv, &ppa) != DDI_SUCCESS) 1039 return (ENOENT); 1040 1041 /* 1042 * If this link: 1043 * (a) is a physical device, (b) this is the first boot, (c) the MAC 1044 * is not registered yet, and (d) we cannot find its linkid, then the 1045 * linkname is the same as the devname. 1046 * 1047 * First filter out invalid names. 1048 */ 1049 if ((major = ddi_name_to_major(drv)) == (major_t)-1) 1050 return (ENOENT); 1051 1052 phy_dev = makedevice(major, (minor_t)ppa + 1); 1053 if (softmac_hold_device(phy_dev, &ddh) != 0) 1054 return (ENOENT); 1055 1056 /* 1057 * At this time, the MAC should be registered, check its phy_dev using 1058 * the given name. 1059 */ 1060 if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0 || 1061 (err = dls_mgmt_get_phydev(linkid, &tmp_dev)) != 0) { 1062 softmac_rele_device(ddh); 1063 return (err); 1064 } 1065 if (tmp_dev != phy_dev) { 1066 softmac_rele_device(ddh); 1067 return (ENOENT); 1068 } 1069 1070 err = dls_devnet_hold(linkid, ddpp); 1071 softmac_rele_device(ddh); 1072 return (err); 1073 } 1074 1075 int 1076 dls_devnet_macname2linkid(const char *macname, datalink_id_t *linkidp) 1077 { 1078 dls_devnet_t *ddp; 1079 1080 rw_enter(&i_dls_devnet_lock, RW_READER); 1081 if (mod_hash_find(i_dls_devnet_hash, (mod_hash_key_t)macname, 1082 (mod_hash_val_t *)&ddp) != 0) { 1083 rw_exit(&i_dls_devnet_lock); 1084 return (ENOENT); 1085 } 1086 1087 *linkidp = ddp->dd_linkid; 1088 rw_exit(&i_dls_devnet_lock); 1089 return (0); 1090 } 1091 1092 1093 /* 1094 * Get linkid for the given dev. 1095 */ 1096 int 1097 dls_devnet_dev2linkid(dev_t dev, datalink_id_t *linkidp) 1098 { 1099 char macname[MAXNAMELEN]; 1100 char *drv; 1101 1102 if ((drv = ddi_major_to_name(getmajor(dev))) == NULL) 1103 return (EINVAL); 1104 1105 (void) snprintf(macname, MAXNAMELEN, "%s%d", drv, getminor(dev) - 1); 1106 return (dls_devnet_macname2linkid(macname, linkidp)); 1107 } 1108 1109 /* 1110 * Get the link's physical dev_t. It this is a VLAN, get the dev_t of the 1111 * link this VLAN is created on. 1112 */ 1113 int 1114 dls_devnet_phydev(datalink_id_t vlanid, dev_t *devp) 1115 { 1116 dls_devnet_t *ddp; 1117 int err; 1118 1119 if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0) 1120 return (err); 1121 1122 err = dls_mgmt_get_phydev(ddp->dd_linkid, devp); 1123 dls_devnet_rele_tmp(ddp); 1124 return (err); 1125 } 1126 1127 /* 1128 * Handle the renaming requests. There are two rename cases: 1129 * 1130 * 1. Request to rename a valid link (id1) to an non-existent link name 1131 * (id2). In this case id2 is DATALINK_INVALID_LINKID. Just check whether 1132 * id1 is held by any applications. 1133 * 1134 * In this case, the link's kstats need to be updated using the given name. 1135 * 1136 * 2. Request to rename a valid link (id1) to the name of a REMOVED 1137 * physical link (id2). In this case, check that id1 and its associated 1138 * mac is not held by any application, and update the link's linkid to id2. 1139 * 1140 * This case does not change the <link name, linkid> mapping, so the link's 1141 * kstats need to be updated with using name associated the given id2. 1142 */ 1143 int 1144 dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link) 1145 { 1146 dls_dev_handle_t ddh = NULL; 1147 char linkname[MAXLINKNAMELEN]; 1148 int err = 0; 1149 dev_t phydev = 0; 1150 dls_devnet_t *ddp; 1151 mac_perim_handle_t mph = NULL; 1152 mac_handle_t mh; 1153 mod_hash_val_t val; 1154 boolean_t clear_dd_flag = B_FALSE; 1155 1156 /* 1157 * In the second case, id2 must be a REMOVED physical link. 1158 */ 1159 if ((id2 != DATALINK_INVALID_LINKID) && 1160 (dls_mgmt_get_phydev(id2, &phydev) == 0) && 1161 softmac_hold_device(phydev, &ddh) == 0) { 1162 softmac_rele_device(ddh); 1163 return (EEXIST); 1164 } 1165 1166 /* 1167 * Hold id1 to prevent it from being detached (if a physical link). 1168 */ 1169 if (dls_mgmt_get_phydev(id1, &phydev) == 0) 1170 (void) softmac_hold_device(phydev, &ddh); 1171 1172 /* 1173 * The framework does not hold hold locks across calls to the 1174 * mac perimeter, hence enter the perimeter first. This also waits 1175 * for the property loading to finish. 1176 */ 1177 if ((err = mac_perim_enter_by_linkid(id1, &mph)) != 0) { 1178 softmac_rele_device(ddh); 1179 return (err); 1180 } 1181 1182 rw_enter(&i_dls_devnet_lock, RW_WRITER); 1183 if ((err = mod_hash_find(i_dls_devnet_id_hash, 1184 (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) { 1185 ASSERT(err == MH_ERR_NOTFOUND); 1186 err = ENOENT; 1187 goto done; 1188 } 1189 1190 /* 1191 * Return EBUSY if any applications have this link open or if any 1192 * thread is currently accessing the link kstats. Then set the 1193 * DD_KSTAT_CHANGING flag to prevent any access to the kstats 1194 * while we delete and recreate kstats below. 1195 */ 1196 mutex_enter(&ddp->dd_mutex); 1197 if (ddp->dd_ref > 1) { 1198 mutex_exit(&ddp->dd_mutex); 1199 err = EBUSY; 1200 goto done; 1201 } 1202 1203 ddp->dd_flags |= DD_KSTAT_CHANGING; 1204 clear_dd_flag = B_TRUE; 1205 mutex_exit(&ddp->dd_mutex); 1206 1207 if (id2 == DATALINK_INVALID_LINKID) { 1208 (void) strlcpy(linkname, link, sizeof (linkname)); 1209 1210 /* rename mac client name and its flow if exists */ 1211 if ((err = mac_open(ddp->dd_mac, &mh)) != 0) 1212 goto done; 1213 (void) mac_rename_primary(mh, link); 1214 mac_close(mh); 1215 goto done; 1216 } 1217 1218 /* 1219 * The second case, check whether the MAC is used by any MAC 1220 * user. This must be a physical link so ddh must not be NULL. 1221 */ 1222 if (ddh == NULL) { 1223 err = EINVAL; 1224 goto done; 1225 } 1226 1227 if ((err = mac_open(ddp->dd_mac, &mh)) != 0) 1228 goto done; 1229 1230 /* 1231 * We release the reference of the MAC which mac_open() is 1232 * holding. Note that this mac will not be unregistered 1233 * because the physical device is held. 1234 */ 1235 mac_close(mh); 1236 1237 /* 1238 * Check if there is any other MAC clients, if not, hold this mac 1239 * exclusively until we are done. 1240 */ 1241 if ((err = mac_mark_exclusive(mh)) != 0) 1242 goto done; 1243 1244 /* 1245 * Update the link's linkid. 1246 */ 1247 if ((err = mod_hash_find(i_dls_devnet_id_hash, 1248 (mod_hash_key_t)(uintptr_t)id2, &val)) != MH_ERR_NOTFOUND) { 1249 mac_unmark_exclusive(mh); 1250 err = EEXIST; 1251 goto done; 1252 } 1253 1254 err = dls_mgmt_get_linkinfo(id2, linkname, NULL, NULL, NULL); 1255 if (err != 0) { 1256 mac_unmark_exclusive(mh); 1257 goto done; 1258 } 1259 1260 (void) mod_hash_remove(i_dls_devnet_id_hash, 1261 (mod_hash_key_t)(uintptr_t)id1, &val); 1262 1263 ddp->dd_linkid = id2; 1264 (void) mod_hash_insert(i_dls_devnet_id_hash, 1265 (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, (mod_hash_val_t)ddp); 1266 1267 mac_unmark_exclusive(mh); 1268 1269 /* load properties for new id */ 1270 mutex_enter(&ddp->dd_mutex); 1271 ddp->dd_prop_loaded = B_FALSE; 1272 ddp->dd_prop_taskid = taskq_dispatch(system_taskq, 1273 dls_devnet_prop_task, ddp, TQ_SLEEP); 1274 mutex_exit(&ddp->dd_mutex); 1275 1276 done: 1277 /* 1278 * Change the name of the kstat based on the new link name. 1279 * We can't hold the i_dls_devnet_lock across calls to the kstat 1280 * subsystem. Instead the DD_KSTAT_CHANGING flag set above in this 1281 * function prevents any access to the dd_ksp while we delete and 1282 * recreate it below. 1283 */ 1284 rw_exit(&i_dls_devnet_lock); 1285 if (err == 0) 1286 dls_devnet_stat_rename(ddp, linkname); 1287 1288 if (clear_dd_flag) { 1289 mutex_enter(&ddp->dd_mutex); 1290 ddp->dd_flags &= ~DD_KSTAT_CHANGING; 1291 mutex_exit(&ddp->dd_mutex); 1292 } 1293 1294 if (mph != NULL) 1295 mac_perim_exit(mph); 1296 softmac_rele_device(ddh); 1297 return (err); 1298 } 1299 1300 int 1301 dls_devnet_setzid(const char *link, zoneid_t zid) 1302 { 1303 dls_devnet_t *ddp; 1304 int err; 1305 zoneid_t old_zid; 1306 mac_perim_handle_t mph; 1307 1308 if ((err = dls_devnet_hold_by_name(link, &ddp)) != 0) 1309 return (err); 1310 1311 err = mac_perim_enter_by_macname(ddp->dd_mac, &mph); 1312 if (err != 0) 1313 return (err); 1314 1315 if ((old_zid = ddp->dd_zid) == zid) { 1316 mac_perim_exit(mph); 1317 dls_devnet_rele(ddp); 1318 return (0); 1319 } 1320 1321 if ((err = dls_link_setzid(ddp->dd_mac, zid)) != 0) { 1322 mac_perim_exit(mph); 1323 dls_devnet_rele(ddp); 1324 return (err); 1325 } 1326 1327 ddp->dd_zid = zid; 1328 devnet_need_rebuild = B_TRUE; 1329 mac_perim_exit(mph); 1330 1331 /* 1332 * Keep this open reference only if it belonged to the global zone 1333 * and is now assigned to a non-global zone. 1334 */ 1335 if (old_zid != GLOBAL_ZONEID || zid == GLOBAL_ZONEID) 1336 dls_devnet_rele(ddp); 1337 1338 /* 1339 * Then release this link if it belonged to an non-global zone 1340 * but is now assigned back to the global zone. 1341 */ 1342 if (old_zid != GLOBAL_ZONEID && zid == GLOBAL_ZONEID) 1343 dls_devnet_rele(ddp); 1344 1345 return (0); 1346 } 1347 1348 int 1349 dls_devnet_getzid(datalink_id_t linkid, zoneid_t *zidp) 1350 { 1351 dls_devnet_t *ddp; 1352 int err; 1353 1354 if ((err = dls_devnet_hold_tmp(linkid, &ddp)) != 0) 1355 return (err); 1356 1357 *zidp = ddp->dd_zid; 1358 1359 dls_devnet_rele_tmp(ddp); 1360 return (0); 1361 } 1362 1363 /* 1364 * Access a vanity naming node. 1365 */ 1366 int 1367 dls_devnet_open(const char *link, dls_dl_handle_t *dhp, dev_t *devp) 1368 { 1369 dls_devnet_t *ddp; 1370 dls_link_t *dlp; 1371 zoneid_t zid = getzoneid(); 1372 int err; 1373 mac_perim_handle_t mph; 1374 1375 if ((err = dls_devnet_hold_by_name(link, &ddp)) != 0) 1376 return (err); 1377 1378 dls_devnet_prop_task_wait(ddp); 1379 1380 /* 1381 * Opening a link that does not belong to the current non-global zone 1382 * is not allowed. 1383 */ 1384 if (zid != GLOBAL_ZONEID && ddp->dd_zid != zid) { 1385 dls_devnet_rele(ddp); 1386 return (ENOENT); 1387 } 1388 1389 err = mac_perim_enter_by_macname(ddp->dd_mac, &mph); 1390 if (err != 0) { 1391 dls_devnet_rele(ddp); 1392 return (err); 1393 } 1394 1395 err = dls_link_hold_create(ddp->dd_mac, &dlp); 1396 mac_perim_exit(mph); 1397 1398 if (err != 0) { 1399 dls_devnet_rele(ddp); 1400 return (err); 1401 } 1402 1403 *dhp = ddp; 1404 *devp = dls_link_dev(dlp); 1405 return (0); 1406 } 1407 1408 /* 1409 * Close access to a vanity naming node. 1410 */ 1411 void 1412 dls_devnet_close(dls_dl_handle_t dlh) 1413 { 1414 dls_devnet_t *ddp = dlh; 1415 dls_link_t *dlp; 1416 mac_perim_handle_t mph; 1417 1418 VERIFY(mac_perim_enter_by_macname(ddp->dd_mac, &mph) == 0); 1419 VERIFY(dls_link_hold(ddp->dd_mac, &dlp) == 0); 1420 1421 /* 1422 * One rele for the hold placed in dls_devnet_open, another for 1423 * the hold done just above 1424 */ 1425 dls_link_rele(dlp); 1426 dls_link_rele(dlp); 1427 mac_perim_exit(mph); 1428 1429 dls_devnet_rele(ddp); 1430 } 1431 1432 /* 1433 * This is used by /dev/net to rebuild the nodes for readdir(). It is not 1434 * critical and no protection is needed. 1435 */ 1436 boolean_t 1437 dls_devnet_rebuild() 1438 { 1439 boolean_t updated = devnet_need_rebuild; 1440 1441 devnet_need_rebuild = B_FALSE; 1442 return (updated); 1443 } 1444 1445 int 1446 dls_devnet_create(mac_handle_t mh, datalink_id_t linkid) 1447 { 1448 dls_link_t *dlp; 1449 int err; 1450 mac_perim_handle_t mph; 1451 1452 /* 1453 * Holding the mac perimeter ensures that the downcall from the 1454 * dlmgmt daemon which does the property loading does not proceed 1455 * until we relinquish the perimeter. 1456 */ 1457 mac_perim_enter_by_mh(mh, &mph); 1458 1459 /* 1460 * Make this association before we call dls_link_hold_create as 1461 * we need to use the linkid to get the user name for the link 1462 * when we create the MAC client. 1463 */ 1464 if ((err = dls_devnet_set(mac_name(mh), linkid, NULL)) != 0) { 1465 mac_perim_exit(mph); 1466 return (err); 1467 } 1468 if ((err = dls_link_hold_create(mac_name(mh), &dlp)) != 0) { 1469 mac_perim_exit(mph); 1470 (void) dls_devnet_unset(mac_name(mh), &linkid, B_TRUE); 1471 return (err); 1472 } 1473 mac_perim_exit(mph); 1474 return (err); 1475 } 1476 1477 /* 1478 * Set the linkid of the dls_devnet_t and add it into the i_dls_devnet_id_hash. 1479 * This is called in the case that the dlmgmtd daemon is started later than 1480 * the physical devices get attached, and the linkid is only known after the 1481 * daemon starts. 1482 */ 1483 int 1484 dls_devnet_recreate(mac_handle_t mh, datalink_id_t linkid) 1485 { 1486 ASSERT(linkid != DATALINK_INVALID_LINKID); 1487 return (dls_devnet_set(mac_name(mh), linkid, NULL)); 1488 } 1489 1490 int 1491 dls_devnet_destroy(mac_handle_t mh, datalink_id_t *idp, boolean_t wait) 1492 { 1493 int err; 1494 mac_perim_handle_t mph; 1495 1496 *idp = DATALINK_INVALID_LINKID; 1497 err = dls_devnet_unset(mac_name(mh), idp, wait); 1498 if (err != 0 && err != ENOENT) 1499 return (err); 1500 1501 mac_perim_enter_by_mh(mh, &mph); 1502 err = dls_link_rele_by_name(mac_name(mh)); 1503 mac_perim_exit(mph); 1504 1505 if (err == 0) 1506 return (0); 1507 1508 (void) dls_devnet_set(mac_name(mh), *idp, NULL); 1509 return (err); 1510 } 1511 1512 const char * 1513 dls_devnet_mac(dls_dl_handle_t ddh) 1514 { 1515 return (ddh->dd_mac); 1516 } 1517 1518 datalink_id_t 1519 dls_devnet_linkid(dls_dl_handle_t ddh) 1520 { 1521 return (ddh->dd_linkid); 1522 } 1523