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.
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.
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]
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Main door handler functions used by dlmgmtd to process the different door
28 * call requests. Door call requests can come from the user-land applications,
31 * Note on zones handling:
33 * There are two zoneid's associated with a link. One is the zoneid of the
34 * zone in which the link was created (ll_zoneid in the dlmgmt_link_t), and
35 * the other is the zoneid of the zone where the link is currently assigned
36 * (the "zone" link property). The two can be different if a datalink is
37 * created in the global zone and subsequently assigned to a non-global zone
38 * via zonecfg or via explicitly setting the "zone" link property.
40 * Door clients can see links that were created in their zone, and links that
41 * are currently assigned to their zone. Door clients in a zone can only
42 * modify links that were created in their zone.
44 * The datalink ID space is global, while each zone has its own datalink name
45 * space. This allows each zone to have complete freedom over the names that
46 * they assign to links created within the zone.
52 #include <priv_utils.h>
56 #include <sys/sysevent/eventdefs.h>
58 #include <libsysevent.h>
59 #include <libdlmgmt.h>
61 #include "dlmgmt_impl.h"
63 typedef void dlmgmt_door_handler_t(void *, void *, size_t *, zoneid_t
,
66 typedef struct dlmgmt_door_info_s
{
70 dlmgmt_door_handler_t
*di_handler
;
74 * Check if the caller has the required privileges to operate on a link of the
78 dlmgmt_checkprivs(datalink_class_t
class, ucred_t
*cred
)
80 const priv_set_t
*eset
;
82 eset
= ucred_getprivset(cred
, PRIV_EFFECTIVE
);
83 if (eset
!= NULL
&& ((class == DATALINK_CLASS_IPTUN
&&
84 priv_ismember(eset
, PRIV_SYS_IPTUN_CONFIG
)) ||
85 priv_ismember(eset
, PRIV_SYS_DL_CONFIG
) ||
86 priv_ismember(eset
, PRIV_SYS_NET_CONFIG
)))
91 static dlmgmt_link_t
*
92 dlmgmt_getlink_by_dev(char *devname
, zoneid_t zoneid
)
94 dlmgmt_link_t
*linkp
= avl_first(&dlmgmt_id_avl
);
96 for (; linkp
!= NULL
; linkp
= AVL_NEXT(&dlmgmt_id_avl
, linkp
)) {
97 if (link_is_visible(linkp
, zoneid
) &&
98 (linkp
->ll_class
== DATALINK_CLASS_PHYS
) &&
99 linkattr_equal(&(linkp
->ll_head
), FDEVNAME
, devname
,
100 strlen(devname
) + 1)) {
108 * Post the EC_DATALINK sysevent for the given linkid. This sysevent will
109 * be consumed by the datalink sysevent module.
112 dlmgmt_post_sysevent(const char *subclass
, datalink_id_t linkid
,
113 boolean_t reconfigured
)
115 nvlist_t
*nvl
= NULL
;
119 if (((err
= nvlist_alloc(&nvl
, NV_UNIQUE_NAME_TYPE
, 0)) != 0) ||
120 ((err
= nvlist_add_uint64(nvl
, RCM_NV_LINKID
, linkid
)) != 0) ||
121 ((err
= nvlist_add_boolean_value(nvl
, RCM_NV_RECONFIGURED
,
122 reconfigured
)) != 0)) {
126 if (sysevent_post_event(EC_DATALINK
, (char *)subclass
, SUNW_VENDOR
,
127 (char *)progname
, nvl
, &eid
) == -1) {
133 dlmgmt_log(LOG_WARNING
, "dlmgmt_post_sysevent(%d) failed: %s",
134 linkid
, strerror(err
));
141 dlmgmt_upcall_create(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
144 dlmgmt_upcall_arg_create_t
*create
= argp
;
145 dlmgmt_create_retval_t
*retvalp
= retp
;
146 datalink_class_t
class;
148 dlmgmt_link_t
*linkp
;
149 char link
[MAXLINKNAMELEN
];
152 boolean_t created
= B_FALSE
;
153 boolean_t reconfigured
= B_FALSE
;
156 * Determine whether this link is persistent. Note that this request
157 * is coming from kernel so this link must be active.
159 flags
= DLMGMT_ACTIVE
| (create
->ld_persist
? DLMGMT_PERSIST
: 0);
161 class = create
->ld_class
;
162 media
= create
->ld_media
;
165 * Hold the writer lock to update the link table.
167 dlmgmt_table_lock(B_TRUE
);
169 if ((err
= dlmgmt_checkprivs(class, cred
)) != 0)
173 * Check to see whether this is the reattachment of an existing
174 * physical link. If so, return its linkid.
176 if ((class == DATALINK_CLASS_PHYS
) && (linkp
=
177 dlmgmt_getlink_by_dev(create
->ld_devname
, zoneid
)) != NULL
) {
178 if (linkattr_equal(&(linkp
->ll_head
), FPHYMAJ
,
179 &create
->ld_phymaj
, sizeof (uint64_t)) &&
180 linkattr_equal(&(linkp
->ll_head
), FPHYINST
,
181 &create
->ld_phyinst
, sizeof (uint64_t)) &&
182 (linkp
->ll_flags
& flags
) == flags
) {
184 * If nothing has been changed, directly return.
189 err
= linkattr_set(&(linkp
->ll_head
), FPHYMAJ
,
190 &create
->ld_phymaj
, sizeof (uint64_t), DLADM_TYPE_UINT64
);
194 err
= linkattr_set(&(linkp
->ll_head
), FPHYINST
,
195 &create
->ld_phyinst
, sizeof (uint64_t), DLADM_TYPE_UINT64
);
200 * This is a device that is dynamic reconfigured.
202 if ((linkp
->ll_flags
& DLMGMT_ACTIVE
) == 0)
203 reconfigured
= B_TRUE
;
205 if ((err
= link_activate(linkp
)) != 0)
207 linkp
->ll_flags
|= flags
;
213 if ((err
= dlmgmt_create_common(create
->ld_devname
, class, media
,
214 zoneid
, flags
, &linkp
)) == EEXIST
) {
216 * The link name already exists. Return error if this is a
217 * non-physical link (in that case, the link name must be
218 * the same as the given name).
220 if (class != DATALINK_CLASS_PHYS
)
224 * The physical link's name already exists, request
225 * a suggested link name: net<nextppa>
227 err
= dlmgmt_generate_name("net", link
, MAXLINKNAMELEN
, zoneid
);
231 err
= dlmgmt_create_common(link
, class, media
, zoneid
, flags
,
241 * This is a new link. Only need to persist link attributes for
244 if (class == DATALINK_CLASS_PHYS
&&
245 (((err
= linkattr_set(&linkp
->ll_head
, FDEVNAME
, create
->ld_devname
,
246 strlen(create
->ld_devname
) + 1, DLADM_TYPE_STR
)) != 0) ||
247 ((err
= linkattr_set(&linkp
->ll_head
, FPHYMAJ
, &create
->ld_phymaj
,
248 sizeof (uint64_t), DLADM_TYPE_UINT64
)) != 0) ||
249 ((err
= linkattr_set(&linkp
->ll_head
, FPHYINST
, &create
->ld_phyinst
,
250 sizeof (uint64_t), DLADM_TYPE_UINT64
)) != 0))) {
251 (void) dlmgmt_destroy_common(linkp
, flags
);
255 if ((err
== 0) && ((err
= dlmgmt_write_db_entry(linkp
->ll_link
, linkp
,
256 linkp
->ll_flags
)) != 0) && created
) {
257 (void) dlmgmt_destroy_common(linkp
, flags
);
262 retvalp
->lr_linkid
= linkp
->ll_linkid
;
264 dlmgmt_table_unlock();
266 if ((err
== 0) && (class == DATALINK_CLASS_PHYS
)) {
268 * Post the ESC_DATALINK_PHYS_ADD sysevent. This sysevent
269 * is consumed by the datalink sysevent module which in
270 * turn generates the RCM_RESOURCE_LINK_NEW RCM event.
272 dlmgmt_post_sysevent(ESC_DATALINK_PHYS_ADD
,
273 retvalp
->lr_linkid
, reconfigured
);
276 retvalp
->lr_err
= err
;
281 dlmgmt_upcall_update(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
284 dlmgmt_upcall_arg_update_t
*update
= argp
;
285 dlmgmt_update_retval_t
*retvalp
= retp
;
286 uint32_t media
= update
->ld_media
;
287 dlmgmt_link_t
*linkp
;
291 * Hold the writer lock to update the link table.
293 dlmgmt_table_lock(B_TRUE
);
296 * Check to see whether this is the reattachment of an existing
297 * physical link. If so, return its linkid.
299 if ((linkp
= dlmgmt_getlink_by_dev(update
->ld_devname
, zoneid
)) ==
305 if ((err
= dlmgmt_checkprivs(linkp
->ll_class
, cred
)) != 0)
308 retvalp
->lr_linkid
= linkp
->ll_linkid
;
309 retvalp
->lr_media
= media
;
310 if (linkp
->ll_media
!= media
&& linkp
->ll_media
!= DL_OTHER
) {
312 * Assume a DL_ETHER link ce0, a DL_WIFI link ath0
313 * 1. # dladm rename-link ce0 net0
314 * 2. DR out ce0. net0 is down.
315 * 3. use rename-link to have the ath0 device inherit
316 * the configuration from net0
317 * # dladm rename-link ath0 net0
319 * As ath0 and ce0 do not have the same media type, ath0
320 * cannot inherit the configuration of net0.
325 * Return the media type of the existing link to indicate the
326 * reason for the name conflict.
328 retvalp
->lr_media
= linkp
->ll_media
;
332 if (update
->ld_novanity
&&
333 (strcmp(update
->ld_devname
, linkp
->ll_link
) != 0)) {
335 * Return an error if this is a physical link that does not
336 * support vanity naming, but the link name is not the same
337 * as the given device name.
343 if (linkp
->ll_media
!= media
) {
344 linkp
->ll_media
= media
;
346 (void) dlmgmt_write_db_entry(linkp
->ll_link
, linkp
,
351 dlmgmt_table_unlock();
352 retvalp
->lr_err
= err
;
357 dlmgmt_upcall_destroy(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
360 dlmgmt_upcall_arg_destroy_t
*destroy
= argp
;
361 dlmgmt_destroy_retval_t
*retvalp
= retp
;
362 datalink_id_t linkid
= destroy
->ld_linkid
;
363 dlmgmt_link_t
*linkp
= NULL
;
364 uint32_t flags
, dflags
= 0;
367 flags
= DLMGMT_ACTIVE
| (destroy
->ld_persist
? DLMGMT_PERSIST
: 0);
370 * Hold the writer lock to update the link table.
372 dlmgmt_table_lock(B_TRUE
);
374 if ((linkp
= link_by_id(linkid
, zoneid
)) == NULL
) {
379 if ((err
= dlmgmt_checkprivs(linkp
->ll_class
, cred
)) != 0)
382 if (((linkp
->ll_flags
& flags
) & DLMGMT_ACTIVE
) != 0) {
383 if ((err
= dlmgmt_delete_db_entry(linkp
, DLMGMT_ACTIVE
)) != 0)
385 dflags
|= DLMGMT_ACTIVE
;
388 if (((linkp
->ll_flags
& flags
) & DLMGMT_PERSIST
) != 0) {
389 if ((err
= dlmgmt_delete_db_entry(linkp
, DLMGMT_PERSIST
)) != 0)
391 dflags
|= DLMGMT_PERSIST
;
394 err
= dlmgmt_destroy_common(linkp
, flags
);
396 if (err
!= 0 && dflags
!= 0)
397 (void) dlmgmt_write_db_entry(linkp
->ll_link
, linkp
, dflags
);
399 dlmgmt_table_unlock();
400 retvalp
->lr_err
= err
;
405 dlmgmt_getname(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
408 dlmgmt_door_getname_t
*getname
= argp
;
409 dlmgmt_getname_retval_t
*retvalp
= retp
;
410 dlmgmt_link_t
*linkp
;
414 * Hold the reader lock to access the link
416 dlmgmt_table_lock(B_FALSE
);
417 if ((linkp
= link_by_id(getname
->ld_linkid
, zoneid
)) == NULL
) {
419 } else if (strlcpy(retvalp
->lr_link
, linkp
->ll_link
, MAXLINKNAMELEN
) >=
423 retvalp
->lr_flags
= linkp
->ll_flags
;
424 retvalp
->lr_class
= linkp
->ll_class
;
425 retvalp
->lr_media
= linkp
->ll_media
;
428 dlmgmt_table_unlock();
429 retvalp
->lr_err
= err
;
434 dlmgmt_getlinkid(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
437 dlmgmt_door_getlinkid_t
*getlinkid
= argp
;
438 dlmgmt_getlinkid_retval_t
*retvalp
= retp
;
439 dlmgmt_link_t
*linkp
;
443 * Hold the reader lock to access the link
445 dlmgmt_table_lock(B_FALSE
);
447 if ((linkp
= link_by_name(getlinkid
->ld_link
, zoneid
)) == NULL
) {
449 * The link does not exist in this zone.
455 retvalp
->lr_linkid
= linkp
->ll_linkid
;
456 retvalp
->lr_flags
= linkp
->ll_flags
;
457 retvalp
->lr_class
= linkp
->ll_class
;
458 retvalp
->lr_media
= linkp
->ll_media
;
461 dlmgmt_table_unlock();
462 retvalp
->lr_err
= err
;
467 dlmgmt_getnext(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
470 dlmgmt_door_getnext_t
*getnext
= argp
;
471 dlmgmt_getnext_retval_t
*retvalp
= retp
;
472 dlmgmt_link_t link
, *linkp
;
477 * Hold the reader lock to access the link
479 dlmgmt_table_lock(B_FALSE
);
481 link
.ll_linkid
= (getnext
->ld_linkid
+ 1);
482 if ((linkp
= avl_find(&dlmgmt_id_avl
, &link
, &where
)) == NULL
)
483 linkp
= avl_nearest(&dlmgmt_id_avl
, where
, AVL_AFTER
);
485 for (; linkp
!= NULL
; linkp
= AVL_NEXT(&dlmgmt_id_avl
, linkp
)) {
486 if (!link_is_visible(linkp
, zoneid
))
488 if ((linkp
->ll_class
& getnext
->ld_class
) &&
489 (linkp
->ll_flags
& getnext
->ld_flags
) &&
490 DATALINK_MEDIA_ACCEPTED(getnext
->ld_dmedia
,
498 retvalp
->lr_linkid
= linkp
->ll_linkid
;
499 retvalp
->lr_class
= linkp
->ll_class
;
500 retvalp
->lr_media
= linkp
->ll_media
;
501 retvalp
->lr_flags
= linkp
->ll_flags
;
504 dlmgmt_table_unlock();
505 retvalp
->lr_err
= err
;
510 dlmgmt_upcall_getattr(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
513 dlmgmt_upcall_arg_getattr_t
*getattr
= argp
;
514 dlmgmt_getattr_retval_t
*retvalp
= retp
;
515 dlmgmt_link_t
*linkp
;
518 * Hold the reader lock to access the link
520 dlmgmt_table_lock(B_FALSE
);
521 if ((linkp
= link_by_id(getattr
->ld_linkid
, zoneid
)) == NULL
) {
522 retvalp
->lr_err
= ENOENT
;
524 retvalp
->lr_err
= dlmgmt_getattr_common(&linkp
->ll_head
,
525 getattr
->ld_attr
, retvalp
);
527 dlmgmt_table_unlock();
532 dlmgmt_createid(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
535 dlmgmt_door_createid_t
*createid
= argp
;
536 dlmgmt_createid_retval_t
*retvalp
= retp
;
537 dlmgmt_link_t
*linkp
;
538 datalink_id_t linkid
= DATALINK_INVALID_LINKID
;
539 char link
[MAXLINKNAMELEN
];
543 * Hold the writer lock to update the dlconf table.
545 dlmgmt_table_lock(B_TRUE
);
547 if ((err
= dlmgmt_checkprivs(createid
->ld_class
, cred
)) != 0)
550 if (createid
->ld_prefix
) {
551 err
= dlmgmt_generate_name(createid
->ld_link
, link
,
552 MAXLINKNAMELEN
, zoneid
);
556 err
= dlmgmt_create_common(link
, createid
->ld_class
,
557 createid
->ld_media
, zoneid
, createid
->ld_flags
, &linkp
);
559 err
= dlmgmt_create_common(createid
->ld_link
,
560 createid
->ld_class
, createid
->ld_media
, zoneid
,
561 createid
->ld_flags
, &linkp
);
566 * Keep the active mapping.
568 linkid
= linkp
->ll_linkid
;
569 if (createid
->ld_flags
& DLMGMT_ACTIVE
) {
570 (void) dlmgmt_write_db_entry(linkp
->ll_link
, linkp
,
576 dlmgmt_table_unlock();
577 retvalp
->lr_linkid
= linkid
;
578 retvalp
->lr_err
= err
;
583 dlmgmt_destroyid(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
586 dlmgmt_door_destroyid_t
*destroyid
= argp
;
587 dlmgmt_destroyid_retval_t
*retvalp
= retp
;
588 datalink_id_t linkid
= destroyid
->ld_linkid
;
589 uint32_t flags
= destroyid
->ld_flags
;
590 dlmgmt_link_t
*linkp
= NULL
;
594 * Hold the writer lock to update the link table.
596 dlmgmt_table_lock(B_TRUE
);
597 if ((linkp
= link_by_id(linkid
, zoneid
)) == NULL
) {
602 if ((err
= dlmgmt_checkprivs(linkp
->ll_class
, cred
)) != 0)
606 * Delete the active mapping.
608 if (flags
& DLMGMT_ACTIVE
)
609 err
= dlmgmt_delete_db_entry(linkp
, DLMGMT_ACTIVE
);
611 err
= dlmgmt_destroy_common(linkp
, flags
);
613 dlmgmt_table_unlock();
614 retvalp
->lr_err
= err
;
618 * Remap a linkid to a given link name, i.e., rename an existing link1
619 * (ld_linkid) to a non-existent link2 (ld_link): rename link1's name to
620 * the given link name.
624 dlmgmt_remapid(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
627 dlmgmt_door_remapid_t
*remapid
= argp
;
628 dlmgmt_remapid_retval_t
*retvalp
= retp
;
629 dlmgmt_link_t
*linkp
;
630 char oldname
[MAXLINKNAMELEN
];
631 boolean_t renamed
= B_FALSE
;
634 if (!dladm_valid_linkname(remapid
->ld_link
)) {
635 retvalp
->lr_err
= EINVAL
;
640 * Hold the writer lock to update the link table.
642 dlmgmt_table_lock(B_TRUE
);
643 if ((linkp
= link_by_id(remapid
->ld_linkid
, zoneid
)) == NULL
) {
648 if ((err
= dlmgmt_checkprivs(linkp
->ll_class
, cred
)) != 0)
651 if (link_by_name(remapid
->ld_link
, linkp
->ll_zoneid
) != NULL
) {
656 (void) strlcpy(oldname
, linkp
->ll_link
, MAXLINKNAMELEN
);
657 avl_remove(&dlmgmt_name_avl
, linkp
);
658 (void) strlcpy(linkp
->ll_link
, remapid
->ld_link
, MAXLINKNAMELEN
);
659 avl_add(&dlmgmt_name_avl
, linkp
);
662 if (linkp
->ll_flags
& DLMGMT_ACTIVE
) {
663 err
= dlmgmt_write_db_entry(oldname
, linkp
, DLMGMT_ACTIVE
);
667 if (linkp
->ll_flags
& DLMGMT_PERSIST
) {
668 err
= dlmgmt_write_db_entry(oldname
, linkp
, DLMGMT_PERSIST
);
670 if (linkp
->ll_flags
& DLMGMT_ACTIVE
) {
671 (void) dlmgmt_write_db_entry(remapid
->ld_link
,
672 linkp
, DLMGMT_ACTIVE
);
678 dlmgmt_advance(linkp
);
681 if (err
!= 0 && renamed
) {
682 avl_remove(&dlmgmt_name_avl
, linkp
);
683 (void) strlcpy(linkp
->ll_link
, oldname
, MAXLINKNAMELEN
);
684 avl_add(&dlmgmt_name_avl
, linkp
);
686 dlmgmt_table_unlock();
687 retvalp
->lr_err
= err
;
692 dlmgmt_upid(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
695 dlmgmt_door_upid_t
*upid
= argp
;
696 dlmgmt_upid_retval_t
*retvalp
= retp
;
697 dlmgmt_link_t
*linkp
;
701 * Hold the writer lock to update the link table.
703 dlmgmt_table_lock(B_TRUE
);
704 if ((linkp
= link_by_id(upid
->ld_linkid
, zoneid
)) == NULL
) {
709 if ((err
= dlmgmt_checkprivs(linkp
->ll_class
, cred
)) != 0)
712 if (linkp
->ll_flags
& DLMGMT_ACTIVE
) {
717 if ((err
= link_activate(linkp
)) == 0) {
718 (void) dlmgmt_write_db_entry(linkp
->ll_link
, linkp
,
722 dlmgmt_table_unlock();
723 retvalp
->lr_err
= err
;
728 dlmgmt_createconf(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
731 dlmgmt_door_createconf_t
*createconf
= argp
;
732 dlmgmt_createconf_retval_t
*retvalp
= retp
;
733 dlmgmt_dlconf_t
*dlconfp
;
737 * Hold the writer lock to update the dlconf table.
739 dlmgmt_dlconf_table_lock(B_TRUE
);
741 if ((err
= dlmgmt_checkprivs(createconf
->ld_class
, cred
)) != 0)
744 err
= dlconf_create(createconf
->ld_link
, createconf
->ld_linkid
,
745 createconf
->ld_class
, createconf
->ld_media
, zoneid
, &dlconfp
);
747 avl_add(&dlmgmt_dlconf_avl
, dlconfp
);
748 dlmgmt_advance_dlconfid(dlconfp
);
749 retvalp
->lr_confid
= dlconfp
->ld_id
;
752 dlmgmt_dlconf_table_unlock();
753 retvalp
->lr_err
= err
;
758 dlmgmt_setattr(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
761 dlmgmt_door_setattr_t
*setattr
= argp
;
762 dlmgmt_setattr_retval_t
*retvalp
= retp
;
763 dlmgmt_dlconf_t dlconf
, *dlconfp
;
767 * Hold the writer lock to update the dlconf table.
769 dlmgmt_dlconf_table_lock(B_TRUE
);
771 dlconf
.ld_id
= setattr
->ld_confid
;
772 dlconfp
= avl_find(&dlmgmt_dlconf_avl
, &dlconf
, NULL
);
773 if (dlconfp
== NULL
|| zoneid
!= dlconfp
->ld_zoneid
) {
778 if ((err
= dlmgmt_checkprivs(dlconfp
->ld_class
, cred
)) != 0)
781 err
= linkattr_set(&(dlconfp
->ld_head
), setattr
->ld_attr
,
782 &setattr
->ld_attrval
, setattr
->ld_attrsz
, setattr
->ld_type
);
785 dlmgmt_dlconf_table_unlock();
786 retvalp
->lr_err
= err
;
791 dlmgmt_unsetconfattr(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
794 dlmgmt_door_unsetattr_t
*unsetattr
= argp
;
795 dlmgmt_unsetattr_retval_t
*retvalp
= retp
;
796 dlmgmt_dlconf_t dlconf
, *dlconfp
;
800 * Hold the writer lock to update the dlconf table.
802 dlmgmt_dlconf_table_lock(B_TRUE
);
804 dlconf
.ld_id
= unsetattr
->ld_confid
;
805 dlconfp
= avl_find(&dlmgmt_dlconf_avl
, &dlconf
, NULL
);
806 if (dlconfp
== NULL
|| zoneid
!= dlconfp
->ld_zoneid
) {
811 if ((err
= dlmgmt_checkprivs(dlconfp
->ld_class
, cred
)) != 0)
814 linkattr_unset(&(dlconfp
->ld_head
), unsetattr
->ld_attr
);
817 dlmgmt_dlconf_table_unlock();
818 retvalp
->lr_err
= err
;
822 * Note that dlmgmt_openconf() returns a conf ID of a conf AVL tree entry,
823 * which is managed by dlmgmtd. The ID is used to find the conf entry when
824 * dlmgmt_write_conf() is called. The conf entry contains an ld_gen value
825 * (which is the generation number - ll_gen) of the dlmgmt_link_t at the time
826 * of dlmgmt_openconf(), and ll_gen changes every time the dlmgmt_link_t
827 * changes its attributes. Therefore, dlmgmt_write_conf() can compare ld_gen
828 * in the conf entry against the latest dlmgmt_link_t ll_gen value to see if
829 * anything has changed between the dlmgmt_openconf() and dlmgmt_writeconf()
830 * calls. If so, EAGAIN is returned. This mechanism can ensures atomicity
831 * across the pair of dladm_read_conf() and dladm_write_conf() calls.
835 dlmgmt_writeconf(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
838 dlmgmt_door_writeconf_t
*writeconf
= argp
;
839 dlmgmt_writeconf_retval_t
*retvalp
= retp
;
840 dlmgmt_dlconf_t dlconf
, *dlconfp
;
841 dlmgmt_link_t
*linkp
;
842 dlmgmt_linkattr_t
*attrp
, *next
;
846 * Hold the lock to access the dlconf table.
848 dlmgmt_dlconf_table_lock(B_TRUE
);
850 dlconf
.ld_id
= writeconf
->ld_confid
;
851 dlconfp
= avl_find(&dlmgmt_dlconf_avl
, &dlconf
, NULL
);
852 if (dlconfp
== NULL
|| zoneid
!= dlconfp
->ld_zoneid
) {
857 if ((err
= dlmgmt_checkprivs(dlconfp
->ld_class
, cred
)) != 0)
861 * Hold the writer lock to update the link table.
863 dlmgmt_table_lock(B_TRUE
);
864 linkp
= link_by_id(dlconfp
->ld_linkid
, zoneid
);
865 if ((linkp
== NULL
) || (linkp
->ll_class
!= dlconfp
->ld_class
) ||
866 (linkp
->ll_media
!= dlconfp
->ld_media
) ||
867 (strcmp(linkp
->ll_link
, dlconfp
->ld_link
) != 0)) {
869 * The link does not exist.
871 dlmgmt_table_unlock();
876 if (linkp
->ll_gen
!= dlconfp
->ld_gen
) {
878 * Something has changed the link configuration; try again.
880 dlmgmt_table_unlock();
886 * Delete the old attribute list.
888 for (attrp
= linkp
->ll_head
; attrp
!= NULL
; attrp
= next
) {
889 next
= attrp
->lp_next
;
893 linkp
->ll_head
= NULL
;
896 * Set the new attribute.
898 for (attrp
= dlconfp
->ld_head
; attrp
!= NULL
; attrp
= attrp
->lp_next
) {
899 if ((err
= linkattr_set(&(linkp
->ll_head
), attrp
->lp_name
,
900 attrp
->lp_val
, attrp
->lp_sz
, attrp
->lp_type
)) != 0) {
901 dlmgmt_table_unlock();
907 err
= dlmgmt_write_db_entry(linkp
->ll_link
, linkp
, DLMGMT_PERSIST
);
908 dlmgmt_table_unlock();
910 dlmgmt_dlconf_table_unlock();
911 retvalp
->lr_err
= err
;
916 dlmgmt_removeconf(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
919 dlmgmt_door_removeconf_t
*removeconf
= argp
;
920 dlmgmt_removeconf_retval_t
*retvalp
= retp
;
921 dlmgmt_link_t
*linkp
;
924 dlmgmt_table_lock(B_TRUE
);
925 if ((linkp
= link_by_id(removeconf
->ld_linkid
, zoneid
)) == NULL
) {
929 if (zoneid
!= GLOBAL_ZONEID
&& linkp
->ll_onloan
) {
931 * A non-global zone cannot remove the persistent
932 * configuration of a link that is on loan from the global
938 if ((err
= dlmgmt_checkprivs(linkp
->ll_class
, cred
)) != 0)
941 err
= dlmgmt_delete_db_entry(linkp
, DLMGMT_PERSIST
);
943 dlmgmt_table_unlock();
944 retvalp
->lr_err
= err
;
949 dlmgmt_destroyconf(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
952 dlmgmt_door_destroyconf_t
*destroyconf
= argp
;
953 dlmgmt_destroyconf_retval_t
*retvalp
= retp
;
954 dlmgmt_dlconf_t dlconf
, *dlconfp
;
958 * Hold the writer lock to update the dlconf table.
960 dlmgmt_dlconf_table_lock(B_TRUE
);
962 dlconf
.ld_id
= destroyconf
->ld_confid
;
963 dlconfp
= avl_find(&dlmgmt_dlconf_avl
, &dlconf
, NULL
);
964 if (dlconfp
== NULL
|| zoneid
!= dlconfp
->ld_zoneid
) {
969 if ((err
= dlmgmt_checkprivs(dlconfp
->ld_class
, cred
)) != 0)
972 avl_remove(&dlmgmt_dlconf_avl
, dlconfp
);
973 dlconf_destroy(dlconfp
);
976 dlmgmt_dlconf_table_unlock();
977 retvalp
->lr_err
= err
;
981 * dlmgmt_openconf() returns a handle of the current configuration, which
982 * is then used to update the configuration by dlmgmt_writeconf(). Therefore,
983 * it requires privileges.
985 * Further, please see the comments above dladm_write_conf() to see how
986 * ld_gen is used to ensure atomicity across the {dlmgmt_openconf(),
987 * dlmgmt_writeconf()} pair.
991 dlmgmt_openconf(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
994 dlmgmt_door_openconf_t
*openconf
= argp
;
995 dlmgmt_openconf_retval_t
*retvalp
= retp
;
996 dlmgmt_link_t
*linkp
;
997 datalink_id_t linkid
= openconf
->ld_linkid
;
998 dlmgmt_dlconf_t
*dlconfp
;
999 dlmgmt_linkattr_t
*attrp
;
1003 * Hold the writer lock to update the dlconf table.
1005 dlmgmt_dlconf_table_lock(B_TRUE
);
1008 * Hold the reader lock to access the link
1010 dlmgmt_table_lock(B_FALSE
);
1011 linkp
= link_by_id(linkid
, zoneid
);
1012 if ((linkp
== NULL
) || !(linkp
->ll_flags
& DLMGMT_PERSIST
)) {
1013 /* The persistent link configuration does not exist. */
1017 if (linkp
->ll_onloan
&& zoneid
!= GLOBAL_ZONEID
) {
1019 * The caller is in a non-global zone and the persistent
1020 * configuration belongs to the global zone.
1026 if ((err
= dlmgmt_checkprivs(linkp
->ll_class
, cred
)) != 0)
1029 if ((err
= dlconf_create(linkp
->ll_link
, linkp
->ll_linkid
,
1030 linkp
->ll_class
, linkp
->ll_media
, zoneid
, &dlconfp
)) != 0)
1033 for (attrp
= linkp
->ll_head
; attrp
!= NULL
; attrp
= attrp
->lp_next
) {
1034 if ((err
= linkattr_set(&(dlconfp
->ld_head
), attrp
->lp_name
,
1035 attrp
->lp_val
, attrp
->lp_sz
, attrp
->lp_type
)) != 0) {
1036 dlconf_destroy(dlconfp
);
1040 dlconfp
->ld_gen
= linkp
->ll_gen
;
1041 avl_add(&dlmgmt_dlconf_avl
, dlconfp
);
1042 dlmgmt_advance_dlconfid(dlconfp
);
1044 retvalp
->lr_confid
= dlconfp
->ld_id
;
1046 dlmgmt_table_unlock();
1047 dlmgmt_dlconf_table_unlock();
1048 retvalp
->lr_err
= err
;
1052 * dlmgmt_getconfsnapshot() returns a read-only snapshot of all the
1053 * configuration, and requires no privileges.
1055 * If the given size cannot hold all the configuration, set the size
1056 * that is needed, and return ENOSPC.
1060 dlmgmt_getconfsnapshot(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
1063 dlmgmt_door_getconfsnapshot_t
*snapshot
= argp
;
1064 dlmgmt_getconfsnapshot_retval_t
*retvalp
= retp
;
1065 dlmgmt_link_t
*linkp
;
1066 datalink_id_t linkid
= snapshot
->ld_linkid
;
1067 dlmgmt_linkattr_t
*attrp
;
1070 nvlist_t
*nvl
= NULL
;
1073 assert(*sz
>= sizeof (dlmgmt_getconfsnapshot_retval_t
));
1076 * Hold the reader lock to access the link
1078 dlmgmt_table_lock(B_FALSE
);
1079 linkp
= link_by_id(linkid
, zoneid
);
1080 if ((linkp
== NULL
) || !(linkp
->ll_flags
& DLMGMT_PERSIST
)) {
1081 /* The persistent link configuration does not exist. */
1085 if (linkp
->ll_onloan
&& zoneid
!= GLOBAL_ZONEID
) {
1087 * The caller is in a non-global zone and the persistent
1088 * configuration belongs to the global zone.
1094 err
= nvlist_alloc(&nvl
, NV_UNIQUE_NAME_TYPE
, 0);
1098 for (attrp
= linkp
->ll_head
; attrp
!= NULL
; attrp
= attrp
->lp_next
) {
1099 if ((err
= nvlist_add_byte_array(nvl
, attrp
->lp_name
,
1100 attrp
->lp_val
, attrp
->lp_sz
)) != 0) {
1105 if ((err
= nvlist_size(nvl
, &nvlsz
, NV_ENCODE_NATIVE
)) != 0)
1108 if (nvlsz
+ sizeof (dlmgmt_getconfsnapshot_retval_t
) > *sz
) {
1109 *sz
= nvlsz
+ sizeof (dlmgmt_getconfsnapshot_retval_t
);
1115 * pack the the nvlist into the return value.
1117 *sz
= nvlsz
+ sizeof (dlmgmt_getconfsnapshot_retval_t
);
1118 retvalp
->lr_nvlsz
= nvlsz
;
1119 buf
= (char *)retvalp
+ sizeof (dlmgmt_getconfsnapshot_retval_t
);
1120 err
= nvlist_pack(nvl
, &buf
, &nvlsz
, NV_ENCODE_NATIVE
, 0);
1123 dlmgmt_table_unlock();
1125 retvalp
->lr_err
= err
;
1130 dlmgmt_getattr(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
1133 dlmgmt_door_getattr_t
*getattr
= argp
;
1134 dlmgmt_getattr_retval_t
*retvalp
= retp
;
1135 dlmgmt_dlconf_t dlconf
, *dlconfp
;
1139 * Hold the read lock to access the dlconf table.
1141 dlmgmt_dlconf_table_lock(B_FALSE
);
1143 dlconf
.ld_id
= getattr
->ld_confid
;
1144 if ((dlconfp
= avl_find(&dlmgmt_dlconf_avl
, &dlconf
, NULL
)) == NULL
||
1145 zoneid
!= dlconfp
->ld_zoneid
) {
1146 retvalp
->lr_err
= ENOENT
;
1148 if ((err
= dlmgmt_checkprivs(dlconfp
->ld_class
, cred
)) != 0) {
1149 retvalp
->lr_err
= err
;
1151 retvalp
->lr_err
= dlmgmt_getattr_common(
1152 &dlconfp
->ld_head
, getattr
->ld_attr
, retvalp
);
1156 dlmgmt_dlconf_table_unlock();
1161 dlmgmt_upcall_linkprop_init(void *argp
, void *retp
, size_t *sz
,
1162 zoneid_t zoneid
, ucred_t
*cred
)
1164 dlmgmt_door_linkprop_init_t
*lip
= argp
;
1165 dlmgmt_linkprop_init_retval_t
*retvalp
= retp
;
1166 dlmgmt_link_t
*linkp
;
1169 dlmgmt_table_lock(B_FALSE
);
1170 if ((linkp
= link_by_id(lip
->ld_linkid
, zoneid
)) == NULL
)
1173 err
= dlmgmt_checkprivs(linkp
->ll_class
, cred
);
1174 dlmgmt_table_unlock();
1178 char buf
[DLADM_STRSIZE
];
1180 s
= dladm_init_linkprop(dld_handle
, lip
->ld_linkid
, B_TRUE
);
1181 if (s
!= DLADM_STATUS_OK
) {
1182 dlmgmt_log(LOG_WARNING
,
1183 "linkprop initialization failed on link %d: %s",
1184 lip
->ld_linkid
, dladm_status2str(s
, buf
));
1188 retvalp
->lr_err
= err
;
1193 dlmgmt_setzoneid(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
1196 dlmgmt_door_setzoneid_t
*setzoneid
= argp
;
1197 dlmgmt_setzoneid_retval_t
*retvalp
= retp
;
1198 dlmgmt_link_t
*linkp
;
1199 datalink_id_t linkid
= setzoneid
->ld_linkid
;
1200 zoneid_t oldzoneid
, newzoneid
;
1203 dlmgmt_table_lock(B_TRUE
);
1205 /* We currently only allow changing zoneid's from the global zone. */
1206 if (zoneid
!= GLOBAL_ZONEID
) {
1211 if ((linkp
= link_by_id(linkid
, zoneid
)) == NULL
) {
1216 if ((err
= dlmgmt_checkprivs(linkp
->ll_class
, cred
)) != 0)
1219 /* We can only assign an active link to a zone. */
1220 if (!(linkp
->ll_flags
& DLMGMT_ACTIVE
)) {
1225 oldzoneid
= linkp
->ll_zoneid
;
1226 newzoneid
= setzoneid
->ld_zoneid
;
1228 if (oldzoneid
== newzoneid
)
1232 * Before we remove the link from its current zone, make sure that
1233 * there isn't a link with the same name in the destination zone.
1235 if (zoneid
!= GLOBAL_ZONEID
&&
1236 link_by_name(linkp
->ll_link
, newzoneid
) != NULL
) {
1241 if (oldzoneid
!= GLOBAL_ZONEID
) {
1242 if (zone_remove_datalink(oldzoneid
, linkid
) != 0) {
1244 dlmgmt_log(LOG_WARNING
, "unable to remove link %d from "
1245 "zone %d: %s", linkid
, oldzoneid
, strerror(err
));
1248 avl_remove(&dlmgmt_loan_avl
, linkp
);
1249 linkp
->ll_onloan
= B_FALSE
;
1251 if (newzoneid
!= GLOBAL_ZONEID
) {
1252 if (zone_add_datalink(newzoneid
, linkid
) != 0) {
1254 dlmgmt_log(LOG_WARNING
, "unable to add link %d to zone "
1255 "%d: %s", linkid
, newzoneid
, strerror(err
));
1256 (void) zone_add_datalink(oldzoneid
, linkid
);
1259 avl_add(&dlmgmt_loan_avl
, linkp
);
1260 linkp
->ll_onloan
= B_TRUE
;
1263 avl_remove(&dlmgmt_name_avl
, linkp
);
1264 linkp
->ll_zoneid
= newzoneid
;
1265 avl_add(&dlmgmt_name_avl
, linkp
);
1268 dlmgmt_table_unlock();
1269 retvalp
->lr_err
= err
;
1274 dlmgmt_zoneboot(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
1278 dlmgmt_door_zoneboot_t
*zoneboot
= argp
;
1279 dlmgmt_zoneboot_retval_t
*retvalp
= retp
;
1281 dlmgmt_table_lock(B_TRUE
);
1283 if ((err
= dlmgmt_checkprivs(0, cred
)) != 0)
1286 if (zoneid
!= GLOBAL_ZONEID
) {
1290 if (zoneboot
->ld_zoneid
== GLOBAL_ZONEID
) {
1295 if ((err
= dlmgmt_elevate_privileges()) == 0) {
1296 err
= dlmgmt_zone_init(zoneboot
->ld_zoneid
);
1297 (void) dlmgmt_drop_privileges();
1300 dlmgmt_table_unlock();
1301 retvalp
->lr_err
= err
;
1306 dlmgmt_zonehalt(void *argp
, void *retp
, size_t *sz
, zoneid_t zoneid
,
1310 dlmgmt_door_zonehalt_t
*zonehalt
= argp
;
1311 dlmgmt_zonehalt_retval_t
*retvalp
= retp
;
1313 if ((err
= dlmgmt_checkprivs(0, cred
)) == 0) {
1314 if (zoneid
!= GLOBAL_ZONEID
) {
1316 } else if (zonehalt
->ld_zoneid
== GLOBAL_ZONEID
) {
1319 dlmgmt_table_lock(B_TRUE
);
1320 dlmgmt_db_fini(zonehalt
->ld_zoneid
);
1321 dlmgmt_table_unlock();
1324 retvalp
->lr_err
= err
;
1327 static dlmgmt_door_info_t i_dlmgmt_door_info_tbl
[] = {
1328 { DLMGMT_CMD_DLS_CREATE
, sizeof (dlmgmt_upcall_arg_create_t
),
1329 sizeof (dlmgmt_create_retval_t
), dlmgmt_upcall_create
},
1330 { DLMGMT_CMD_DLS_GETATTR
, sizeof (dlmgmt_upcall_arg_getattr_t
),
1331 sizeof (dlmgmt_getattr_retval_t
), dlmgmt_upcall_getattr
},
1332 { DLMGMT_CMD_DLS_DESTROY
, sizeof (dlmgmt_upcall_arg_destroy_t
),
1333 sizeof (dlmgmt_destroy_retval_t
), dlmgmt_upcall_destroy
},
1334 { DLMGMT_CMD_GETNAME
, sizeof (dlmgmt_door_getname_t
),
1335 sizeof (dlmgmt_getname_retval_t
), dlmgmt_getname
},
1336 { DLMGMT_CMD_GETLINKID
, sizeof (dlmgmt_door_getlinkid_t
),
1337 sizeof (dlmgmt_getlinkid_retval_t
), dlmgmt_getlinkid
},
1338 { DLMGMT_CMD_GETNEXT
, sizeof (dlmgmt_door_getnext_t
),
1339 sizeof (dlmgmt_getnext_retval_t
), dlmgmt_getnext
},
1340 { DLMGMT_CMD_DLS_UPDATE
, sizeof (dlmgmt_upcall_arg_update_t
),
1341 sizeof (dlmgmt_update_retval_t
), dlmgmt_upcall_update
},
1342 { DLMGMT_CMD_CREATE_LINKID
, sizeof (dlmgmt_door_createid_t
),
1343 sizeof (dlmgmt_createid_retval_t
), dlmgmt_createid
},
1344 { DLMGMT_CMD_DESTROY_LINKID
, sizeof (dlmgmt_door_destroyid_t
),
1345 sizeof (dlmgmt_destroyid_retval_t
), dlmgmt_destroyid
},
1346 { DLMGMT_CMD_REMAP_LINKID
, sizeof (dlmgmt_door_remapid_t
),
1347 sizeof (dlmgmt_remapid_retval_t
), dlmgmt_remapid
},
1348 { DLMGMT_CMD_CREATECONF
, sizeof (dlmgmt_door_createconf_t
),
1349 sizeof (dlmgmt_createconf_retval_t
), dlmgmt_createconf
},
1350 { DLMGMT_CMD_OPENCONF
, sizeof (dlmgmt_door_openconf_t
),
1351 sizeof (dlmgmt_openconf_retval_t
), dlmgmt_openconf
},
1352 { DLMGMT_CMD_WRITECONF
, sizeof (dlmgmt_door_writeconf_t
),
1353 sizeof (dlmgmt_writeconf_retval_t
), dlmgmt_writeconf
},
1354 { DLMGMT_CMD_UP_LINKID
, sizeof (dlmgmt_door_upid_t
),
1355 sizeof (dlmgmt_upid_retval_t
), dlmgmt_upid
},
1356 { DLMGMT_CMD_SETATTR
, sizeof (dlmgmt_door_setattr_t
),
1357 sizeof (dlmgmt_setattr_retval_t
), dlmgmt_setattr
},
1358 { DLMGMT_CMD_UNSETATTR
, sizeof (dlmgmt_door_unsetattr_t
),
1359 sizeof (dlmgmt_unsetattr_retval_t
), dlmgmt_unsetconfattr
},
1360 { DLMGMT_CMD_REMOVECONF
, sizeof (dlmgmt_door_removeconf_t
),
1361 sizeof (dlmgmt_removeconf_retval_t
), dlmgmt_removeconf
},
1362 { DLMGMT_CMD_DESTROYCONF
, sizeof (dlmgmt_door_destroyconf_t
),
1363 sizeof (dlmgmt_destroyconf_retval_t
), dlmgmt_destroyconf
},
1364 { DLMGMT_CMD_GETATTR
, sizeof (dlmgmt_door_getattr_t
),
1365 sizeof (dlmgmt_getattr_retval_t
), dlmgmt_getattr
},
1366 { DLMGMT_CMD_GETCONFSNAPSHOT
, sizeof (dlmgmt_door_getconfsnapshot_t
),
1367 sizeof (dlmgmt_getconfsnapshot_retval_t
), dlmgmt_getconfsnapshot
},
1368 { DLMGMT_CMD_LINKPROP_INIT
, sizeof (dlmgmt_door_linkprop_init_t
),
1369 sizeof (dlmgmt_linkprop_init_retval_t
),
1370 dlmgmt_upcall_linkprop_init
},
1371 { DLMGMT_CMD_SETZONEID
, sizeof (dlmgmt_door_setzoneid_t
),
1372 sizeof (dlmgmt_setzoneid_retval_t
), dlmgmt_setzoneid
},
1373 { DLMGMT_CMD_ZONEBOOT
, sizeof (dlmgmt_door_zoneboot_t
),
1374 sizeof (dlmgmt_zoneboot_retval_t
), dlmgmt_zoneboot
},
1375 { DLMGMT_CMD_ZONEHALT
, sizeof (dlmgmt_door_zonehalt_t
),
1376 sizeof (dlmgmt_zonehalt_retval_t
), dlmgmt_zonehalt
},
1380 static dlmgmt_door_info_t
*
1381 dlmgmt_getcmdinfo(int cmd
)
1383 dlmgmt_door_info_t
*infop
= i_dlmgmt_door_info_tbl
;
1385 while (infop
->di_handler
!= NULL
) {
1386 if (infop
->di_cmd
== cmd
)
1395 dlmgmt_handler(void *cookie
, char *argp
, size_t argsz
, door_desc_t
*dp
,
1398 dlmgmt_door_arg_t
*door_arg
= (dlmgmt_door_arg_t
*)(void *)argp
;
1399 dlmgmt_door_info_t
*infop
= NULL
;
1400 dlmgmt_retval_t retval
;
1401 ucred_t
*cred
= NULL
;
1403 void *retvalp
= NULL
;
1407 infop
= dlmgmt_getcmdinfo(door_arg
->ld_cmd
);
1408 if (infop
== NULL
|| argsz
!= infop
->di_reqsz
) {
1413 if (door_ucred(&cred
) != 0 || (zoneid
= ucred_getzoneid(cred
)) == -1) {
1419 * Note that malloc() cannot be used here because door_return
1420 * never returns, and memory allocated by malloc() would get leaked.
1421 * Use alloca() instead.
1423 acksz
= infop
->di_acksz
;
1426 retvalp
= alloca(acksz
);
1428 infop
->di_handler(argp
, retvalp
, &acksz
, zoneid
, cred
);
1431 * If the specified buffer size is not big enough to hold the
1432 * return value, reallocate the buffer and try to get the
1433 * result one more time.
1435 assert(((dlmgmt_retval_t
*)retvalp
)->lr_err
== ENOSPC
);
1443 (void) door_return(retvalp
, acksz
, NULL
, 0);
1445 retval
.lr_err
= err
;
1446 (void) door_return((char *)&retval
, sizeof (retval
), NULL
, 0);