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