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