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