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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2016 Joyent, Inc.
  24  * Copyright 2023 Oxide Computer Company
  25  */
  26 
  27 #include <door.h>
  28 #include <errno.h>
  29 #include <assert.h>
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <unistd.h>
  33 #include <string.h>
  34 #include <strings.h>
  35 #include <zone.h>
  36 #include <sys/types.h>
  37 #include <sys/stat.h>
  38 #include <sys/aggr.h>
  39 #include <sys/mman.h>
  40 #include <fcntl.h>
  41 #include <libdladm.h>
  42 #include <libdladm_impl.h>
  43 #include <libdllink.h>
  44 #include <libdlmgmt.h>
  45 
  46 /*
  47  * Table of data type sizes indexed by dladm_datatype_t.
  48  */
  49 static size_t dladm_datatype_size[] = {
  50         0,                              /* DLADM_TYPE_STR, use strnlen() */
  51         sizeof (boolean_t),             /* DLADM_TYPE_BOOLEAN */
  52         sizeof (uint64_t)               /* DLADM_TYPE_UINT64 */
  53 };
  54 
  55 static dladm_status_t
  56 dladm_door_call(dladm_handle_t handle, void *arg, size_t asize, void *rbuf,
  57     size_t *rsizep)
  58 {
  59         door_arg_t      darg;
  60         int             door_fd;
  61         dladm_status_t  status;
  62         boolean_t       reopen = B_FALSE;
  63 
  64         darg.data_ptr   = arg;
  65         darg.data_size  = asize;
  66         darg.desc_ptr   = NULL;
  67         darg.desc_num   = 0;
  68         darg.rbuf       = rbuf;
  69         darg.rsize      = *rsizep;
  70 
  71 reopen:
  72         /* The door descriptor is opened if it isn't already */
  73         if ((status = dladm_door_fd(handle, &door_fd)) != DLADM_STATUS_OK)
  74                 return (status);
  75         if (door_call(door_fd, &darg) == -1) {
  76                 /*
  77                  * Stale door descriptor is possible if dlmgmtd was re-started
  78                  * since last door_fd open so try re-opening door file.
  79                  */
  80                 if (!reopen && errno == EBADF) {
  81                         (void) close(handle->door_fd);
  82                         handle->door_fd = -1;
  83                         reopen = B_TRUE;
  84                         goto reopen;
  85                 }
  86                 status = dladm_errno2status(errno);
  87         }
  88         if (status != DLADM_STATUS_OK)
  89                 return (status);
  90 
  91         if (darg.rbuf != rbuf) {
  92                 /*
  93                  * The size of the input rbuf is not big enough so that
  94                  * the door allocate the rbuf itself. In this case, return
  95                  * the required size to the caller.
  96                  */
  97                 (void) munmap(darg.rbuf, darg.rsize);
  98                 *rsizep = darg.rsize;
  99                 return (DLADM_STATUS_TOOSMALL);
 100         } else if (darg.rsize != *rsizep) {
 101                 return (DLADM_STATUS_FAILED);
 102         }
 103 
 104         return (dladm_errno2status(((dlmgmt_retval_t *)rbuf)->lr_err));
 105 }
 106 
 107 /*
 108  * Allocate a new linkid with the given name. Return the new linkid.
 109  */
 110 dladm_status_t
 111 dladm_create_datalink_id(dladm_handle_t handle, const char *link,
 112     datalink_class_t class, uint32_t media, uint32_t flags,
 113     datalink_id_t *linkidp)
 114 {
 115         dlmgmt_door_createid_t  createid;
 116         dlmgmt_createid_retval_t retval;
 117         uint32_t                dlmgmt_flags;
 118         dladm_status_t          status;
 119         size_t                  sz = sizeof (retval);
 120 
 121         if (link == NULL || class == DATALINK_CLASS_ALL ||
 122             !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) ||
 123             linkidp == NULL) {
 124                 return (DLADM_STATUS_BADARG);
 125         }
 126 
 127         if (getzoneid() != GLOBAL_ZONEID) {
 128                 /*
 129                  * If we're creating this link in a non-global zone, then do
 130                  * not allow it to be persistent, and flag it as transient so
 131                  * that it will be automatically cleaned up on zone shutdown,
 132                  * rather than being moved to the GZ.
 133                  */
 134                 if (flags & DLADM_OPT_PERSIST)
 135                         return (DLADM_STATUS_TEMPONLY);
 136                 flags |= DLADM_OPT_TRANSIENT;
 137         }
 138 
 139         dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
 140         dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0;
 141         dlmgmt_flags |= (flags & DLADM_OPT_TRANSIENT) ? DLMGMT_TRANSIENT : 0;
 142 
 143         (void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN);
 144         createid.ld_class = class;
 145         createid.ld_media = media;
 146         createid.ld_flags = dlmgmt_flags;
 147         createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID;
 148         createid.ld_prefix = (flags & DLADM_OPT_PREFIX);
 149 
 150         if ((status = dladm_door_call(handle, &createid, sizeof (createid),
 151             &retval, &sz)) == DLADM_STATUS_OK) {
 152                 *linkidp = retval.lr_linkid;
 153         }
 154         return (status);
 155 }
 156 
 157 /*
 158  * Destroy the given link ID.
 159  */
 160 dladm_status_t
 161 dladm_destroy_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
 162     uint32_t flags)
 163 {
 164         dlmgmt_door_destroyid_t         destroyid;
 165         dlmgmt_destroyid_retval_t       retval;
 166         uint32_t                        dlmgmt_flags;
 167         size_t                          sz = sizeof (retval);
 168 
 169         dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
 170         dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
 171 
 172         destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID;
 173         destroyid.ld_linkid = linkid;
 174         destroyid.ld_flags = dlmgmt_flags;
 175 
 176         return (dladm_door_call(handle, &destroyid, sizeof (destroyid),
 177             &retval, &sz));
 178 }
 179 
 180 /*
 181  * Remap a given link ID to a new name.
 182  */
 183 dladm_status_t
 184 dladm_remap_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
 185     const char *link)
 186 {
 187         dlmgmt_door_remapid_t   remapid;
 188         dlmgmt_remapid_retval_t retval;
 189         size_t                  sz = sizeof (retval);
 190 
 191         remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID;
 192         remapid.ld_linkid = linkid;
 193         (void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN);
 194 
 195         return (dladm_door_call(handle, &remapid, sizeof (remapid),
 196             &retval, &sz));
 197 }
 198 
 199 /*
 200  * Make a given link ID active.
 201  */
 202 dladm_status_t
 203 dladm_up_datalink_id(dladm_handle_t handle, datalink_id_t linkid)
 204 {
 205         dlmgmt_door_upid_t      upid;
 206         dlmgmt_upid_retval_t    retval;
 207         size_t                  sz = sizeof (retval);
 208 
 209         upid.ld_cmd = DLMGMT_CMD_UP_LINKID;
 210         upid.ld_linkid = linkid;
 211 
 212         return (dladm_door_call(handle, &upid, sizeof (upid), &retval, &sz));
 213 }
 214 
 215 /*
 216  * Create a new link with the given name.  Return the new link's handle
 217  */
 218 dladm_status_t
 219 dladm_create_conf(dladm_handle_t handle, const char *link, datalink_id_t linkid,
 220     datalink_class_t class, uint32_t media, dladm_conf_t *confp)
 221 {
 222         dlmgmt_door_createconf_t        createconf;
 223         dlmgmt_createconf_retval_t      retval;
 224         dladm_status_t                  status;
 225         size_t                          sz = sizeof (retval);
 226 
 227         if (link == NULL || confp == NULL)
 228                 return (DLADM_STATUS_BADARG);
 229 
 230         (void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN);
 231         createconf.ld_class = class;
 232         createconf.ld_media = media;
 233         createconf.ld_linkid = linkid;
 234         createconf.ld_cmd = DLMGMT_CMD_CREATECONF;
 235         confp->ds_confid = DLADM_INVALID_CONF;
 236 
 237         if ((status = dladm_door_call(handle, &createconf, sizeof (createconf),
 238             &retval, &sz)) == DLADM_STATUS_OK) {
 239                 confp->ds_readonly = B_FALSE;
 240                 confp->ds_confid = retval.lr_confid;
 241         }
 242         return (status);
 243 }
 244 
 245 /*
 246  * An active physical link reported by the dlmgmtd daemon might not be active
 247  * anymore as this link might be removed during system shutdown. Check its
 248  * real status by calling dladm_phys_info().
 249  */
 250 dladm_status_t
 251 i_dladm_phys_status(dladm_handle_t handle, datalink_id_t linkid,
 252     uint32_t *flagsp)
 253 {
 254         dladm_phys_attr_t       dpa;
 255         dladm_status_t          status;
 256 
 257         assert((*flagsp) & DLMGMT_ACTIVE);
 258 
 259         status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE);
 260         if (status == DLADM_STATUS_NOTFOUND) {
 261                 /*
 262                  * No active status, this link was removed. Update its status
 263                  * in the daemon and delete all active linkprops.
 264                  *
 265                  * Note that the operation could fail. If it does, return
 266                  * failure now since otherwise dladm_set_linkprop() might
 267                  * call back to i_dladm_phys_status() recursively.
 268                  */
 269                 if ((status = dladm_destroy_datalink_id(handle, linkid,
 270                     DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK)
 271                         return (status);
 272 
 273                 (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
 274                     DLADM_OPT_ACTIVE);
 275 
 276                 (*flagsp) &= ~DLMGMT_ACTIVE;
 277                 status = DLADM_STATUS_OK;
 278         }
 279         return (status);
 280 }
 281 
 282 /*
 283  * Walk each entry in the data link configuration repository and
 284  * call fn on the linkid and arg.
 285  */
 286 dladm_status_t
 287 dladm_walk_datalink_id(int (*fn)(dladm_handle_t, datalink_id_t, void *),
 288     dladm_handle_t handle, void *argp, datalink_class_t class,
 289     datalink_media_t dmedia, uint32_t flags)
 290 {
 291         dlmgmt_door_getnext_t   getnext;
 292         dlmgmt_getnext_retval_t retval;
 293         uint32_t                dlmgmt_flags;
 294         datalink_id_t           linkid = DATALINK_INVALID_LINKID;
 295         dladm_status_t          status = DLADM_STATUS_OK;
 296         size_t                  sz = sizeof (retval);
 297 
 298         if (fn == NULL)
 299                 return (DLADM_STATUS_BADARG);
 300 
 301         dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
 302         dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
 303         dlmgmt_flags |= ((flags & DLADM_OPT_TRANSIENT) ? DLMGMT_TRANSIENT : 0);
 304 
 305         getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
 306         getnext.ld_class = class;
 307         getnext.ld_dmedia = dmedia;
 308         getnext.ld_flags = dlmgmt_flags;
 309 
 310         do {
 311                 getnext.ld_linkid = linkid;
 312                 if ((status = dladm_door_call(handle, &getnext,
 313                     sizeof (getnext), &retval, &sz)) != DLADM_STATUS_OK) {
 314                         /*
 315                          * Done with walking. If no next datalink is found,
 316                          * return success.
 317                          */
 318                         if (status == DLADM_STATUS_NOTFOUND)
 319                                 status = DLADM_STATUS_OK;
 320                         break;
 321                 }
 322 
 323                 linkid = retval.lr_linkid;
 324                 if ((retval.lr_class == DATALINK_CLASS_PHYS) &&
 325                     (retval.lr_flags & DLMGMT_ACTIVE)) {
 326                         /*
 327                          * An active physical link reported by the dlmgmtd
 328                          * daemon might not be active anymore. Check its
 329                          * real status.
 330                          */
 331                         if (i_dladm_phys_status(handle, linkid,
 332                             &retval.lr_flags) != DLADM_STATUS_OK) {
 333                                 continue;
 334                         }
 335 
 336                         if (!(dlmgmt_flags & retval.lr_flags))
 337                                 continue;
 338                 }
 339 
 340                 if (fn(handle, linkid, argp) == DLADM_WALK_TERMINATE)
 341                         break;
 342         } while (linkid != DATALINK_INVALID_LINKID);
 343 
 344         return (status);
 345 }
 346 
 347 /*
 348  * Get a handle of a copy of the link configuration (kept in the daemon)
 349  * for the given link so it can be updated later by dladm_write_conf().
 350  */
 351 dladm_status_t
 352 dladm_open_conf(dladm_handle_t handle, datalink_id_t linkid,
 353     dladm_conf_t *confp)
 354 {
 355         dlmgmt_door_openconf_t          openconf;
 356         dlmgmt_openconf_retval_t        retval;
 357         dladm_status_t                  status;
 358         size_t                          sz;
 359 
 360         if (linkid == DATALINK_INVALID_LINKID || confp == NULL)
 361                 return (DLADM_STATUS_BADARG);
 362 
 363         sz = sizeof (retval);
 364         openconf.ld_linkid = linkid;
 365         openconf.ld_cmd = DLMGMT_CMD_OPENCONF;
 366         confp->ds_confid = DLADM_INVALID_CONF;
 367         if ((status = dladm_door_call(handle, &openconf,
 368             sizeof (openconf), &retval, &sz)) == DLADM_STATUS_OK) {
 369                 confp->ds_readonly = B_FALSE;
 370                 confp->ds_confid = retval.lr_confid;
 371         }
 372 
 373         return (status);
 374 }
 375 
 376 /*
 377  * Get the handle of a local snapshot of the link configuration. Note that
 378  * any operations with this handle are read-only, i.e., one can not update
 379  * the configuration with this handle.
 380  */
 381 dladm_status_t
 382 dladm_getsnap_conf(dladm_handle_t handle, datalink_id_t linkid,
 383     dladm_conf_t *confp)
 384 {
 385         dlmgmt_door_getconfsnapshot_t   snapshot;
 386         dlmgmt_getconfsnapshot_retval_t *retvalp;
 387         char                            *nvlbuf;
 388         dladm_status_t                  status;
 389         int                             err;
 390         size_t                          sz;
 391 
 392         if (linkid == DATALINK_INVALID_LINKID || confp == NULL)
 393                 return (DLADM_STATUS_BADARG);
 394 
 395         sz = sizeof (dlmgmt_getconfsnapshot_retval_t);
 396         snapshot.ld_linkid = linkid;
 397         snapshot.ld_cmd = DLMGMT_CMD_GETCONFSNAPSHOT;
 398 again:
 399         if ((retvalp = malloc(sz)) == NULL)
 400                 return (DLADM_STATUS_NOMEM);
 401 
 402         if ((status = dladm_door_call(handle, &snapshot, sizeof (snapshot),
 403             retvalp, &sz)) == DLADM_STATUS_TOOSMALL) {
 404                 free(retvalp);
 405                 goto again;
 406         }
 407 
 408         if (status != DLADM_STATUS_OK) {
 409                 free(retvalp);
 410                 return (status);
 411         }
 412 
 413         confp->ds_readonly = B_TRUE;
 414         nvlbuf = (char *)retvalp + sizeof (dlmgmt_getconfsnapshot_retval_t);
 415         if ((err = nvlist_unpack(nvlbuf, retvalp->lr_nvlsz,
 416             &(confp->ds_nvl), 0)) != 0) {
 417                 status = dladm_errno2status(err);
 418         }
 419         free(retvalp);
 420         return (status);
 421 }
 422 
 423 /*
 424  * Commit the given link to the data link configuration repository so
 425  * that it will persist across reboots.
 426  */
 427 dladm_status_t
 428 dladm_write_conf(dladm_handle_t handle, dladm_conf_t conf)
 429 {
 430         dlmgmt_door_writeconf_t         writeconf;
 431         dlmgmt_writeconf_retval_t       retval;
 432         size_t                          sz = sizeof (retval);
 433 
 434         if (conf.ds_confid == DLADM_INVALID_CONF)
 435                 return (DLADM_STATUS_BADARG);
 436 
 437         if (conf.ds_readonly)
 438                 return (DLADM_STATUS_DENIED);
 439 
 440         writeconf.ld_cmd = DLMGMT_CMD_WRITECONF;
 441         writeconf.ld_confid = conf.ds_confid;
 442 
 443         return (dladm_door_call(handle, &writeconf, sizeof (writeconf),
 444             &retval, &sz));
 445 }
 446 
 447 /*
 448  * Given a dladm_conf_t, get the specific configuration field
 449  *
 450  * If the specified dladm_conf_t is a read-only snapshot of the configuration,
 451  * get a specific link propertie from that snapshot (nvl), otherwise, get
 452  * the link protperty from the dlmgmtd daemon using the given confid.
 453  */
 454 dladm_status_t
 455 dladm_get_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
 456     void *attrval, size_t attrsz)
 457 {
 458         dladm_status_t          status = DLADM_STATUS_OK;
 459 
 460         if (attrval == NULL || attrsz == 0 || attr == NULL)
 461                 return (DLADM_STATUS_BADARG);
 462 
 463         if (conf.ds_readonly) {
 464                 uchar_t         *oattrval;
 465                 uint32_t        oattrsz;
 466                 int             err;
 467 
 468                 if ((err = nvlist_lookup_byte_array(conf.ds_nvl, (char *)attr,
 469                     &oattrval, &oattrsz)) != 0) {
 470                         return (dladm_errno2status(err));
 471                 }
 472                 if (oattrsz > attrsz)
 473                         return (DLADM_STATUS_TOOSMALL);
 474 
 475                 bcopy(oattrval, attrval, oattrsz);
 476         } else {
 477                 dlmgmt_door_getattr_t   getattr;
 478                 dlmgmt_getattr_retval_t retval;
 479                 size_t                  sz = sizeof (retval);
 480 
 481                 if (conf.ds_confid == DLADM_INVALID_CONF)
 482                         return (DLADM_STATUS_BADARG);
 483 
 484                 getattr.ld_cmd = DLMGMT_CMD_GETATTR;
 485                 getattr.ld_confid = conf.ds_confid;
 486                 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
 487 
 488                 if ((status = dladm_door_call(handle, &getattr,
 489                     sizeof (getattr), &retval, &sz)) != DLADM_STATUS_OK) {
 490                         return (status);
 491                 }
 492 
 493                 if (retval.lr_attrsz > attrsz)
 494                         return (DLADM_STATUS_TOOSMALL);
 495 
 496                 bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
 497         }
 498         return (status);
 499 }
 500 
 501 /*
 502  * Get next property attribute from data link configuration repository.
 503  * If last_attr is "", return the first property.
 504  */
 505 dladm_status_t
 506 dladm_getnext_conf_linkprop(dladm_handle_t handle __unused, dladm_conf_t conf,
 507     const char *last_attr, char *attr, void *attrval, size_t attrsz,
 508     size_t *attrszp)
 509 {
 510         nvlist_t        *nvl = conf.ds_nvl;
 511         nvpair_t        *last = NULL, *nvp;
 512         uchar_t         *oattrval;
 513         uint32_t        oattrsz;
 514         int             err;
 515 
 516         if (nvl == NULL || attrval == NULL || attrsz == 0 || attr == NULL ||
 517             !conf.ds_readonly)
 518                 return (DLADM_STATUS_BADARG);
 519 
 520         while ((nvp = nvlist_next_nvpair(nvl, last)) != NULL) {
 521                 if (last_attr[0] == '\0')
 522                         break;
 523                 if (last != NULL && strcmp(last_attr, nvpair_name(last)) == 0)
 524                         break;
 525                 last = nvp;
 526         }
 527 
 528         if (nvp == NULL)
 529                 return (DLADM_STATUS_NOTFOUND);
 530 
 531         if ((err = nvpair_value_byte_array(nvp, (uchar_t **)&oattrval,
 532             &oattrsz)) != 0) {
 533                 return (dladm_errno2status(err));
 534         }
 535 
 536         *attrszp = oattrsz;
 537         if (oattrsz > attrsz)
 538                 return (DLADM_STATUS_TOOSMALL);
 539 
 540         (void) strlcpy(attr, nvpair_name(nvp), MAXLINKATTRLEN);
 541         bcopy(oattrval, attrval, oattrsz);
 542         return (DLADM_STATUS_OK);
 543 }
 544 
 545 /*
 546  * Get the link ID that is associated with the given name in the current zone.
 547  */
 548 dladm_status_t
 549 dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp,
 550     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap)
 551 {
 552         return (dladm_zname2info(handle, NULL, link, linkidp, flagp, classp,
 553            mediap));
 554 }
 555 
 556 /*
 557  * Get the link ID that is associated with the given zone/name pair.
 558  */
 559 dladm_status_t
 560 dladm_zname2info(dladm_handle_t handle, const char *zonename, const char *link,
 561     datalink_id_t *linkidp, uint32_t *flagp, datalink_class_t *classp,
 562     uint32_t *mediap)
 563 {
 564         dlmgmt_door_getlinkid_t         getlinkid;
 565         dlmgmt_getlinkid_retval_t       retval;
 566         datalink_id_t                   linkid;
 567         dladm_status_t                  status;
 568         size_t                          sz = sizeof (retval);
 569 
 570         getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
 571         (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
 572         if (zonename != NULL)
 573                 getlinkid.ld_zoneid = getzoneidbyname(zonename);
 574         else
 575                 getlinkid.ld_zoneid = -1;
 576 
 577         if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid),
 578             &retval, &sz)) != DLADM_STATUS_OK) {
 579                 return (status);
 580         }
 581 
 582         linkid = retval.lr_linkid;
 583         if (retval.lr_class == DATALINK_CLASS_PHYS &&
 584             retval.lr_flags & DLMGMT_ACTIVE) {
 585                 /*
 586                  * An active physical link reported by the dlmgmtd daemon
 587                  * might not be active anymore. Check and set its real status.
 588                  */
 589                 status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
 590                 if (status != DLADM_STATUS_OK)
 591                         return (status);
 592         }
 593 
 594         if (linkidp != NULL)
 595                 *linkidp = linkid;
 596         if (flagp != NULL) {
 597                 *flagp = (retval.lr_flags & DLMGMT_ACTIVE) ?
 598                     DLADM_OPT_ACTIVE : 0;
 599                 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
 600                     DLADM_OPT_PERSIST : 0;
 601                 *flagp |= (retval.lr_flags & DLMGMT_TRANSIENT) ?
 602                     DLADM_OPT_TRANSIENT : 0;
 603         }
 604         if (classp != NULL)
 605                 *classp = retval.lr_class;
 606         if (mediap != NULL)
 607                 *mediap = retval.lr_media;
 608 
 609         return (DLADM_STATUS_OK);
 610 }
 611 
 612 /*
 613  * Get the link name that is associated with the given id.
 614  */
 615 dladm_status_t
 616 dladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid,
 617     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link,
 618     size_t len)
 619 {
 620         dlmgmt_door_getname_t   getname;
 621         dlmgmt_getname_retval_t retval;
 622         dladm_status_t          status;
 623         size_t                  sz = sizeof (retval);
 624 
 625         if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) ||
 626             (link == NULL && len != 0)) {
 627                 return (DLADM_STATUS_BADARG);
 628         }
 629 
 630         getname.ld_cmd = DLMGMT_CMD_GETNAME;
 631         getname.ld_linkid = linkid;
 632         if ((status = dladm_door_call(handle, &getname, sizeof (getname),
 633             &retval, &sz)) != DLADM_STATUS_OK) {
 634                 return (status);
 635         }
 636 
 637         if (len != 0 && (strlen(retval.lr_link) + 1 > len))
 638                 return (DLADM_STATUS_TOOSMALL);
 639 
 640         if (retval.lr_class == DATALINK_CLASS_PHYS &&
 641             retval.lr_flags & DLMGMT_ACTIVE) {
 642                 /*
 643                  * An active physical link reported by the dlmgmtd daemon
 644                  * might not be active anymore. Check and set its real status.
 645                  */
 646                 status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
 647                 if (status != DLADM_STATUS_OK)
 648                         return (status);
 649         }
 650 
 651         if (link != NULL)
 652                 (void) strlcpy(link, retval.lr_link, len);
 653         if (classp != NULL)
 654                 *classp = retval.lr_class;
 655         if (mediap != NULL)
 656                 *mediap = retval.lr_media;
 657         if (flagp != NULL) {
 658                 *flagp = (retval.lr_flags & DLMGMT_ACTIVE) ?
 659                     DLADM_OPT_ACTIVE : 0;
 660                 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
 661                     DLADM_OPT_PERSIST : 0;
 662                 *flagp |= (retval.lr_flags & DLMGMT_TRANSIENT) ?
 663                     DLADM_OPT_TRANSIENT : 0;
 664         }
 665         return (DLADM_STATUS_OK);
 666 }
 667 
 668 /*
 669  * Set the given attr with the given attrval for the given link.
 670  */
 671 dladm_status_t
 672 dladm_set_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
 673     dladm_datatype_t type, const void *attrval)
 674 {
 675         dlmgmt_door_setattr_t   setattr;
 676         dlmgmt_setattr_retval_t retval;
 677         size_t                  attrsz;
 678         size_t                  sz = sizeof (retval);
 679 
 680         if (attr == NULL || attrval == NULL)
 681                 return (DLADM_STATUS_BADARG);
 682 
 683         if (conf.ds_readonly)
 684                 return (DLADM_STATUS_DENIED);
 685 
 686         if (type == DLADM_TYPE_STR)
 687                 attrsz = strlen(attrval) + 1;
 688         else
 689                 attrsz = dladm_datatype_size[type];
 690 
 691         if (attrsz > MAXLINKATTRVALLEN)
 692                 return (DLADM_STATUS_TOOSMALL);
 693 
 694         setattr.ld_cmd = DLMGMT_CMD_SETATTR;
 695         setattr.ld_confid = conf.ds_confid;
 696         (void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN);
 697         setattr.ld_attrsz = (uint32_t)attrsz;
 698         setattr.ld_type = type;
 699         bcopy(attrval, &setattr.ld_attrval, attrsz);
 700 
 701         return (dladm_door_call(handle, &setattr, sizeof (setattr),
 702             &retval, &sz));
 703 }
 704 
 705 /*
 706  * Unset the given attr the given link.
 707  */
 708 dladm_status_t
 709 dladm_unset_conf_field(dladm_handle_t handle, dladm_conf_t conf,
 710     const char *attr)
 711 {
 712         dlmgmt_door_unsetattr_t         unsetattr;
 713         dlmgmt_unsetattr_retval_t       retval;
 714         size_t                          sz = sizeof (retval);
 715 
 716         if (attr == NULL)
 717                 return (DLADM_STATUS_BADARG);
 718 
 719         if (conf.ds_readonly)
 720                 return (DLADM_STATUS_DENIED);
 721 
 722         unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR;
 723         unsetattr.ld_confid = conf.ds_confid;
 724         (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN);
 725 
 726         return (dladm_door_call(handle, &unsetattr, sizeof (unsetattr),
 727             &retval, &sz));
 728 }
 729 
 730 /*
 731  * Remove the given link ID and its entry from the data link configuration
 732  * repository.
 733  */
 734 dladm_status_t
 735 dladm_remove_conf(dladm_handle_t handle, datalink_id_t linkid)
 736 {
 737         dlmgmt_door_removeconf_t        removeconf;
 738         dlmgmt_removeconf_retval_t      retval;
 739         size_t                          sz = sizeof (retval);
 740 
 741         removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF;
 742         removeconf.ld_linkid = linkid;
 743 
 744         return (dladm_door_call(handle, &removeconf, sizeof (removeconf),
 745             &retval, &sz));
 746 }
 747 
 748 /*
 749  * Free the contents of the link structure.
 750  */
 751 void
 752 dladm_destroy_conf(dladm_handle_t handle, dladm_conf_t conf)
 753 {
 754         dlmgmt_door_destroyconf_t       dconf;
 755         dlmgmt_destroyconf_retval_t     retval;
 756         size_t                          sz = sizeof (retval);
 757 
 758         if (conf.ds_readonly) {
 759                 nvlist_free(conf.ds_nvl);
 760         } else {
 761                 if (conf.ds_confid == DLADM_INVALID_CONF)
 762                         return;
 763 
 764                 dconf.ld_cmd = DLMGMT_CMD_DESTROYCONF;
 765                 dconf.ld_confid = conf.ds_confid;
 766 
 767                 (void) dladm_door_call(handle, &dconf, sizeof (dconf),
 768                     &retval, &sz);
 769         }
 770 }
 771 
 772 dladm_status_t
 773 dladm_zone_boot(dladm_handle_t handle, zoneid_t zoneid)
 774 {
 775         dlmgmt_door_zoneboot_t          zoneboot;
 776         dlmgmt_zoneboot_retval_t        retval;
 777         size_t                          sz = sizeof (retval);
 778 
 779         zoneboot.ld_cmd = DLMGMT_CMD_ZONEBOOT;
 780         zoneboot.ld_zoneid = zoneid;
 781         return (dladm_door_call(handle, &zoneboot, sizeof (zoneboot),
 782             &retval, &sz));
 783 }
 784 
 785 dladm_status_t
 786 dladm_zone_halt(dladm_handle_t handle, zoneid_t zoneid)
 787 {
 788         dlmgmt_door_zonehalt_t          zonehalt;
 789         dlmgmt_zonehalt_retval_t        retval;
 790         size_t                          sz = sizeof (retval);
 791 
 792         zonehalt.ld_cmd = DLMGMT_CMD_ZONEHALT;
 793         zonehalt.ld_zoneid = zoneid;
 794         return (dladm_door_call(handle, &zonehalt, sizeof (zonehalt),
 795             &retval, &sz));
 796 }