xref: /illumos-gate/usr/src/lib/libdladm/common/libdlmgmt.c (revision 2a8bcb4efb45d99ac41c94a75c396b362c414f7f)
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), 0)) != 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 dladm_status_t
490 dladm_getnext_conf_linkprop(dladm_handle_t handle __unused, dladm_conf_t conf,
491     const char *last_attr, char *attr, void *attrval, size_t attrsz,
492     size_t *attrszp)
493 {
494 	nvlist_t	*nvl = conf.ds_nvl;
495 	nvpair_t	*last = NULL, *nvp;
496 	uchar_t		*oattrval;
497 	uint32_t	oattrsz;
498 	int		err;
499 
500 	if (nvl == NULL || attrval == NULL || attrsz == 0 || attr == NULL ||
501 	    !conf.ds_readonly)
502 		return (DLADM_STATUS_BADARG);
503 
504 	while ((nvp = nvlist_next_nvpair(nvl, last)) != NULL) {
505 		if (last_attr[0] == '\0')
506 			break;
507 		if (last != NULL && strcmp(last_attr, nvpair_name(last)) == 0)
508 			break;
509 		last = nvp;
510 	}
511 
512 	if (nvp == NULL)
513 		return (DLADM_STATUS_NOTFOUND);
514 
515 	if ((err = nvpair_value_byte_array(nvp, (uchar_t **)&oattrval,
516 	    &oattrsz)) != 0) {
517 		return (dladm_errno2status(err));
518 	}
519 
520 	*attrszp = oattrsz;
521 	if (oattrsz > attrsz)
522 		return (DLADM_STATUS_TOOSMALL);
523 
524 	(void) strlcpy(attr, nvpair_name(nvp), MAXLINKATTRLEN);
525 	bcopy(oattrval, attrval, oattrsz);
526 	return (DLADM_STATUS_OK);
527 }
528 
529 /*
530  * Get the link ID that is associated with the given name.
531  */
532 dladm_status_t
533 dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp,
534     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap)
535 {
536 	dlmgmt_door_getlinkid_t		getlinkid;
537 	dlmgmt_getlinkid_retval_t	retval;
538 	datalink_id_t			linkid;
539 	dladm_status_t			status;
540 	size_t				sz = sizeof (retval);
541 
542 	getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
543 	(void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
544 
545 	if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid),
546 	    &retval, &sz)) != DLADM_STATUS_OK) {
547 		return (status);
548 	}
549 
550 	linkid = retval.lr_linkid;
551 	if (retval.lr_class == DATALINK_CLASS_PHYS &&
552 	    retval.lr_flags & DLMGMT_ACTIVE) {
553 		/*
554 		 * An active physical link reported by the dlmgmtd daemon
555 		 * might not be active anymore. Check and set its real status.
556 		 */
557 		status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
558 		if (status != DLADM_STATUS_OK)
559 			return (status);
560 	}
561 
562 	if (linkidp != NULL)
563 		*linkidp = linkid;
564 	if (flagp != NULL) {
565 		*flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0;
566 		*flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
567 		    DLADM_OPT_PERSIST : 0;
568 	}
569 	if (classp != NULL)
570 		*classp = retval.lr_class;
571 	if (mediap != NULL)
572 		*mediap = retval.lr_media;
573 
574 	return (DLADM_STATUS_OK);
575 }
576 
577 /*
578  * Get the link name that is associated with the given id.
579  */
580 dladm_status_t
581 dladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid,
582     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link,
583     size_t len)
584 {
585 	dlmgmt_door_getname_t	getname;
586 	dlmgmt_getname_retval_t	retval;
587 	dladm_status_t		status;
588 	size_t			sz = sizeof (retval);
589 
590 	if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) ||
591 	    (link == NULL && len != 0)) {
592 		return (DLADM_STATUS_BADARG);
593 	}
594 
595 	getname.ld_cmd = DLMGMT_CMD_GETNAME;
596 	getname.ld_linkid = linkid;
597 	if ((status = dladm_door_call(handle, &getname, sizeof (getname),
598 	    &retval, &sz)) != DLADM_STATUS_OK) {
599 		return (status);
600 	}
601 
602 	if (len != 0 && (strlen(retval.lr_link) + 1 > len))
603 		return (DLADM_STATUS_TOOSMALL);
604 
605 	if (retval.lr_class == DATALINK_CLASS_PHYS &&
606 	    retval.lr_flags & DLMGMT_ACTIVE) {
607 		/*
608 		 * An active physical link reported by the dlmgmtd daemon
609 		 * might not be active anymore. Check and set its real status.
610 		 */
611 		status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
612 		if (status != DLADM_STATUS_OK)
613 			return (status);
614 	}
615 
616 	if (link != NULL)
617 		(void) strlcpy(link, retval.lr_link, len);
618 	if (classp != NULL)
619 		*classp = retval.lr_class;
620 	if (mediap != NULL)
621 		*mediap = retval.lr_media;
622 	if (flagp != NULL) {
623 		*flagp = retval.lr_flags & DLMGMT_ACTIVE ?
624 		    DLADM_OPT_ACTIVE : 0;
625 		*flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
626 		    DLADM_OPT_PERSIST : 0;
627 	}
628 	return (DLADM_STATUS_OK);
629 }
630 
631 /*
632  * Set the given attr with the given attrval for the given link.
633  */
634 dladm_status_t
635 dladm_set_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
636     dladm_datatype_t type, const void *attrval)
637 {
638 	dlmgmt_door_setattr_t	setattr;
639 	dlmgmt_setattr_retval_t	retval;
640 	size_t			attrsz;
641 	size_t			sz = sizeof (retval);
642 
643 	if (attr == NULL || attrval == NULL)
644 		return (DLADM_STATUS_BADARG);
645 
646 	if (conf.ds_readonly)
647 		return (DLADM_STATUS_DENIED);
648 
649 	if (type == DLADM_TYPE_STR)
650 		attrsz = strlen(attrval) + 1;
651 	else
652 		attrsz = dladm_datatype_size[type];
653 
654 	if (attrsz > MAXLINKATTRVALLEN)
655 		return (DLADM_STATUS_TOOSMALL);
656 
657 	setattr.ld_cmd = DLMGMT_CMD_SETATTR;
658 	setattr.ld_confid = conf.ds_confid;
659 	(void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN);
660 	setattr.ld_attrsz = (uint32_t)attrsz;
661 	setattr.ld_type = type;
662 	bcopy(attrval, &setattr.ld_attrval, attrsz);
663 
664 	return (dladm_door_call(handle, &setattr, sizeof (setattr),
665 	    &retval, &sz));
666 }
667 
668 /*
669  * Unset the given attr the given link.
670  */
671 dladm_status_t
672 dladm_unset_conf_field(dladm_handle_t handle, dladm_conf_t conf,
673     const char *attr)
674 {
675 	dlmgmt_door_unsetattr_t		unsetattr;
676 	dlmgmt_unsetattr_retval_t	retval;
677 	size_t				sz = sizeof (retval);
678 
679 	if (attr == NULL)
680 		return (DLADM_STATUS_BADARG);
681 
682 	if (conf.ds_readonly)
683 		return (DLADM_STATUS_DENIED);
684 
685 	unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR;
686 	unsetattr.ld_confid = conf.ds_confid;
687 	(void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN);
688 
689 	return (dladm_door_call(handle, &unsetattr, sizeof (unsetattr),
690 	    &retval, &sz));
691 }
692 
693 /*
694  * Remove the given link ID and its entry from the data link configuration
695  * repository.
696  */
697 dladm_status_t
698 dladm_remove_conf(dladm_handle_t handle, datalink_id_t linkid)
699 {
700 	dlmgmt_door_removeconf_t	removeconf;
701 	dlmgmt_removeconf_retval_t	retval;
702 	size_t				sz = sizeof (retval);
703 
704 	removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF;
705 	removeconf.ld_linkid = linkid;
706 
707 	return (dladm_door_call(handle, &removeconf, sizeof (removeconf),
708 	    &retval, &sz));
709 }
710 
711 /*
712  * Free the contents of the link structure.
713  */
714 void
715 dladm_destroy_conf(dladm_handle_t handle, dladm_conf_t conf)
716 {
717 	dlmgmt_door_destroyconf_t	dconf;
718 	dlmgmt_destroyconf_retval_t	retval;
719 	size_t				sz = sizeof (retval);
720 
721 	if (conf.ds_readonly) {
722 		nvlist_free(conf.ds_nvl);
723 	} else {
724 		if (conf.ds_confid == DLADM_INVALID_CONF)
725 			return;
726 
727 		dconf.ld_cmd = DLMGMT_CMD_DESTROYCONF;
728 		dconf.ld_confid = conf.ds_confid;
729 
730 		(void) dladm_door_call(handle, &dconf, sizeof (dconf),
731 		    &retval, &sz);
732 	}
733 }
734 
735 dladm_status_t
736 dladm_zone_boot(dladm_handle_t handle, zoneid_t zoneid)
737 {
738 	dlmgmt_door_zoneboot_t		zoneboot;
739 	dlmgmt_zoneboot_retval_t	retval;
740 	size_t				sz = sizeof (retval);
741 
742 	zoneboot.ld_cmd = DLMGMT_CMD_ZONEBOOT;
743 	zoneboot.ld_zoneid = zoneid;
744 	return (dladm_door_call(handle, &zoneboot, sizeof (zoneboot),
745 	    &retval, &sz));
746 }
747 
748 dladm_status_t
749 dladm_zone_halt(dladm_handle_t handle, zoneid_t zoneid)
750 {
751 	dlmgmt_door_zonehalt_t		zonehalt;
752 	dlmgmt_zonehalt_retval_t	retval;
753 	size_t				sz = sizeof (retval);
754 
755 	zonehalt.ld_cmd = DLMGMT_CMD_ZONEHALT;
756 	zonehalt.ld_zoneid = zoneid;
757 	return (dladm_door_call(handle, &zonehalt, sizeof (zonehalt),
758 	    &retval, &sz));
759 }
760