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