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 }