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