1d62bc4baSyz147064 /* 2d62bc4baSyz147064 * CDDL HEADER START 3d62bc4baSyz147064 * 4d62bc4baSyz147064 * The contents of this file are subject to the terms of the 5d62bc4baSyz147064 * Common Development and Distribution License (the "License"). 6d62bc4baSyz147064 * You may not use this file except in compliance with the License. 7d62bc4baSyz147064 * 8d62bc4baSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d62bc4baSyz147064 * or http://www.opensolaris.org/os/licensing. 10d62bc4baSyz147064 * See the License for the specific language governing permissions 11d62bc4baSyz147064 * and limitations under the License. 12d62bc4baSyz147064 * 13d62bc4baSyz147064 * When distributing Covered Code, include this CDDL HEADER in each 14d62bc4baSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d62bc4baSyz147064 * If applicable, add the following below this CDDL HEADER, with the 16d62bc4baSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying 17d62bc4baSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 18d62bc4baSyz147064 * 19d62bc4baSyz147064 * CDDL HEADER END 20d62bc4baSyz147064 */ 21d62bc4baSyz147064 22d62bc4baSyz147064 /* 23*32715170SCathy Zhou * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24d62bc4baSyz147064 */ 25d62bc4baSyz147064 26d62bc4baSyz147064 /* 27d62bc4baSyz147064 * Main door handler functions used by dlmgmtd to process the different door 28d62bc4baSyz147064 * call requests. Door call requests can come from the user-land applications, 29024b0a25Sseb * or from the kernel. 302b24ab6bSSebastien Roy * 312b24ab6bSSebastien Roy * Note on zones handling: 322b24ab6bSSebastien Roy * 332b24ab6bSSebastien Roy * There are two zoneid's associated with a link. One is the zoneid of the 342b24ab6bSSebastien Roy * zone in which the link was created (ll_zoneid in the dlmgmt_link_t), and 352b24ab6bSSebastien Roy * the other is the zoneid of the zone where the link is currently assigned 362b24ab6bSSebastien Roy * (the "zone" link property). The two can be different if a datalink is 372b24ab6bSSebastien Roy * created in the global zone and subsequently assigned to a non-global zone 382b24ab6bSSebastien Roy * via zonecfg or via explicitly setting the "zone" link property. 392b24ab6bSSebastien Roy * 402b24ab6bSSebastien Roy * Door clients can see links that were created in their zone, and links that 412b24ab6bSSebastien Roy * are currently assigned to their zone. Door clients in a zone can only 422b24ab6bSSebastien Roy * modify links that were created in their zone. 432b24ab6bSSebastien Roy * 442b24ab6bSSebastien Roy * The datalink ID space is global, while each zone has its own datalink name 452b24ab6bSSebastien Roy * space. This allows each zone to have complete freedom over the names that 462b24ab6bSSebastien Roy * they assign to links created within the zone. 47d62bc4baSyz147064 */ 48d62bc4baSyz147064 49d62bc4baSyz147064 #include <assert.h> 50d62bc4baSyz147064 #include <alloca.h> 51024b0a25Sseb #include <errno.h> 52024b0a25Sseb #include <priv_utils.h> 53024b0a25Sseb #include <stdlib.h> 54d62bc4baSyz147064 #include <strings.h> 550dc974a9SCathy Zhou #include <syslog.h> 560dc974a9SCathy Zhou #include <sys/sysevent/eventdefs.h> 572b24ab6bSSebastien Roy #include <zone.h> 580dc974a9SCathy Zhou #include <libsysevent.h> 59d62bc4baSyz147064 #include <libdlmgmt.h> 600dc974a9SCathy Zhou #include <librcm.h> 61d62bc4baSyz147064 #include "dlmgmt_impl.h" 62d62bc4baSyz147064 63*32715170SCathy Zhou typedef void dlmgmt_door_handler_t(void *, void *, size_t *, zoneid_t, 64*32715170SCathy Zhou ucred_t *); 65024b0a25Sseb 66024b0a25Sseb typedef struct dlmgmt_door_info_s { 67024b0a25Sseb uint_t di_cmd; 68024b0a25Sseb size_t di_reqsz; 69024b0a25Sseb size_t di_acksz; 70024b0a25Sseb dlmgmt_door_handler_t *di_handler; 71024b0a25Sseb } dlmgmt_door_info_t; 72024b0a25Sseb 732b24ab6bSSebastien Roy /* 742b24ab6bSSebastien Roy * Check if the caller has the required privileges to operate on a link of the 752b24ab6bSSebastien Roy * given class. 762b24ab6bSSebastien Roy */ 772b24ab6bSSebastien Roy static int 782b24ab6bSSebastien Roy dlmgmt_checkprivs(datalink_class_t class, ucred_t *cred) 792b24ab6bSSebastien Roy { 802b24ab6bSSebastien Roy const priv_set_t *eset; 812b24ab6bSSebastien Roy 822b24ab6bSSebastien Roy eset = ucred_getprivset(cred, PRIV_EFFECTIVE); 832b24ab6bSSebastien Roy if (eset != NULL && ((class == DATALINK_CLASS_IPTUN && 842b24ab6bSSebastien Roy priv_ismember(eset, PRIV_SYS_IPTUN_CONFIG)) || 852b24ab6bSSebastien Roy priv_ismember(eset, PRIV_SYS_DL_CONFIG) || 862b24ab6bSSebastien Roy priv_ismember(eset, PRIV_SYS_NET_CONFIG))) 872b24ab6bSSebastien Roy return (0); 882b24ab6bSSebastien Roy return (EACCES); 892b24ab6bSSebastien Roy } 90024b0a25Sseb 91d62bc4baSyz147064 static dlmgmt_link_t * 922b24ab6bSSebastien Roy dlmgmt_getlink_by_dev(char *devname, zoneid_t zoneid) 93d62bc4baSyz147064 { 94d62bc4baSyz147064 dlmgmt_link_t *linkp = avl_first(&dlmgmt_id_avl); 95d62bc4baSyz147064 96d62bc4baSyz147064 for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) { 972b24ab6bSSebastien Roy if (link_is_visible(linkp, zoneid) && 982b24ab6bSSebastien Roy (linkp->ll_class == DATALINK_CLASS_PHYS) && 99d62bc4baSyz147064 linkattr_equal(&(linkp->ll_head), FDEVNAME, devname, 100d62bc4baSyz147064 strlen(devname) + 1)) { 101d62bc4baSyz147064 return (linkp); 102d62bc4baSyz147064 } 103d62bc4baSyz147064 } 104d62bc4baSyz147064 return (NULL); 105d62bc4baSyz147064 } 106d62bc4baSyz147064 1070dc974a9SCathy Zhou /* 1080dc974a9SCathy Zhou * Post the EC_DATALINK sysevent for the given linkid. This sysevent will 1090dc974a9SCathy Zhou * be consumed by the datalink sysevent module. 1100dc974a9SCathy Zhou */ 1110dc974a9SCathy Zhou static void 1125093e103SCathy Zhou dlmgmt_post_sysevent(const char *subclass, datalink_id_t linkid, 1135093e103SCathy Zhou boolean_t reconfigured) 1140dc974a9SCathy Zhou { 1150dc974a9SCathy Zhou nvlist_t *nvl = NULL; 1160dc974a9SCathy Zhou sysevent_id_t eid; 1170dc974a9SCathy Zhou int err; 1180dc974a9SCathy Zhou 1190dc974a9SCathy Zhou if (((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0) || 1205093e103SCathy Zhou ((err = nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid)) != 0) || 1215093e103SCathy Zhou ((err = nvlist_add_boolean_value(nvl, RCM_NV_RECONFIGURED, 1225093e103SCathy Zhou reconfigured)) != 0)) { 1230dc974a9SCathy Zhou goto done; 1240dc974a9SCathy Zhou } 1250dc974a9SCathy Zhou 1260dc974a9SCathy Zhou if (sysevent_post_event(EC_DATALINK, (char *)subclass, SUNW_VENDOR, 1270dc974a9SCathy Zhou (char *)progname, nvl, &eid) == -1) { 1280dc974a9SCathy Zhou err = errno; 1290dc974a9SCathy Zhou } 1300dc974a9SCathy Zhou 1310dc974a9SCathy Zhou done: 1320dc974a9SCathy Zhou if (err != 0) { 1330dc974a9SCathy Zhou dlmgmt_log(LOG_WARNING, "dlmgmt_post_sysevent(%d) failed: %s", 1340dc974a9SCathy Zhou linkid, strerror(err)); 1350dc974a9SCathy Zhou } 1360dc974a9SCathy Zhou nvlist_free(nvl); 1370dc974a9SCathy Zhou } 1380dc974a9SCathy Zhou 139*32715170SCathy Zhou /* ARGSUSED */ 140d62bc4baSyz147064 static void 141*32715170SCathy Zhou dlmgmt_upcall_create(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 142*32715170SCathy Zhou ucred_t *cred) 143d62bc4baSyz147064 { 144024b0a25Sseb dlmgmt_upcall_arg_create_t *create = argp; 145024b0a25Sseb dlmgmt_create_retval_t *retvalp = retp; 146d62bc4baSyz147064 datalink_class_t class; 147d62bc4baSyz147064 uint32_t media; 148d62bc4baSyz147064 dlmgmt_link_t *linkp; 149d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 150d62bc4baSyz147064 uint32_t flags; 1518a1c9a22SCathy Zhou int err = 0; 152d62bc4baSyz147064 boolean_t created = B_FALSE; 1535093e103SCathy Zhou boolean_t reconfigured = B_FALSE; 154d62bc4baSyz147064 155d62bc4baSyz147064 /* 156d62bc4baSyz147064 * Determine whether this link is persistent. Note that this request 157d62bc4baSyz147064 * is coming from kernel so this link must be active. 158d62bc4baSyz147064 */ 159d62bc4baSyz147064 flags = DLMGMT_ACTIVE | (create->ld_persist ? DLMGMT_PERSIST : 0); 160d62bc4baSyz147064 161d62bc4baSyz147064 class = create->ld_class; 162d62bc4baSyz147064 media = create->ld_media; 163d62bc4baSyz147064 164d62bc4baSyz147064 /* 165d62bc4baSyz147064 * Hold the writer lock to update the link table. 166d62bc4baSyz147064 */ 167d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 168d62bc4baSyz147064 1692b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(class, cred)) != 0) 1702b24ab6bSSebastien Roy goto done; 1712b24ab6bSSebastien Roy 172d62bc4baSyz147064 /* 173d62bc4baSyz147064 * Check to see whether this is the reattachment of an existing 174d62bc4baSyz147064 * physical link. If so, return its linkid. 175d62bc4baSyz147064 */ 1762b24ab6bSSebastien Roy if ((class == DATALINK_CLASS_PHYS) && (linkp = 1772b24ab6bSSebastien Roy dlmgmt_getlink_by_dev(create->ld_devname, zoneid)) != NULL) { 1788a1c9a22SCathy Zhou if (linkattr_equal(&(linkp->ll_head), FPHYMAJ, 1798a1c9a22SCathy Zhou &create->ld_phymaj, sizeof (uint64_t)) && 1808a1c9a22SCathy Zhou linkattr_equal(&(linkp->ll_head), FPHYINST, 1818a1c9a22SCathy Zhou &create->ld_phyinst, sizeof (uint64_t)) && 1828a1c9a22SCathy Zhou (linkp->ll_flags & flags) == flags) { 1838a1c9a22SCathy Zhou /* 1848a1c9a22SCathy Zhou * If nothing has been changed, directly return. 1858a1c9a22SCathy Zhou */ 1868a1c9a22SCathy Zhou goto noupdate; 1878a1c9a22SCathy Zhou } 1888a1c9a22SCathy Zhou 189d62bc4baSyz147064 err = linkattr_set(&(linkp->ll_head), FPHYMAJ, 190d62bc4baSyz147064 &create->ld_phymaj, sizeof (uint64_t), DLADM_TYPE_UINT64); 191d62bc4baSyz147064 if (err != 0) 192d62bc4baSyz147064 goto done; 193d62bc4baSyz147064 194d62bc4baSyz147064 err = linkattr_set(&(linkp->ll_head), FPHYINST, 195d62bc4baSyz147064 &create->ld_phyinst, sizeof (uint64_t), DLADM_TYPE_UINT64); 196d62bc4baSyz147064 if (err != 0) 197d62bc4baSyz147064 goto done; 198d62bc4baSyz147064 1995093e103SCathy Zhou /* 2005093e103SCathy Zhou * This is a device that is dynamic reconfigured. 2015093e103SCathy Zhou */ 2025093e103SCathy Zhou if ((linkp->ll_flags & DLMGMT_ACTIVE) == 0) 2035093e103SCathy Zhou reconfigured = B_TRUE; 2045093e103SCathy Zhou 2052b24ab6bSSebastien Roy if ((err = link_activate(linkp)) != 0) 2062b24ab6bSSebastien Roy goto done; 207d62bc4baSyz147064 linkp->ll_flags |= flags; 208d62bc4baSyz147064 linkp->ll_gen++; 2095093e103SCathy Zhou 210d62bc4baSyz147064 goto done; 211d62bc4baSyz147064 } 212d62bc4baSyz147064 213d62bc4baSyz147064 if ((err = dlmgmt_create_common(create->ld_devname, class, media, 2142b24ab6bSSebastien Roy zoneid, flags, &linkp)) == EEXIST) { 215d62bc4baSyz147064 /* 216d62bc4baSyz147064 * The link name already exists. Return error if this is a 217d62bc4baSyz147064 * non-physical link (in that case, the link name must be 218d62bc4baSyz147064 * the same as the given name). 219d62bc4baSyz147064 */ 220d62bc4baSyz147064 if (class != DATALINK_CLASS_PHYS) 221d62bc4baSyz147064 goto done; 222d62bc4baSyz147064 223d62bc4baSyz147064 /* 224d62bc4baSyz147064 * The physical link's name already exists, request 225d62bc4baSyz147064 * a suggested link name: net<nextppa> 226d62bc4baSyz147064 */ 2272b24ab6bSSebastien Roy err = dlmgmt_generate_name("net", link, MAXLINKNAMELEN, zoneid); 228d62bc4baSyz147064 if (err != 0) 229d62bc4baSyz147064 goto done; 230d62bc4baSyz147064 2312b24ab6bSSebastien Roy err = dlmgmt_create_common(link, class, media, zoneid, flags, 2322b24ab6bSSebastien Roy &linkp); 233d62bc4baSyz147064 } 234d62bc4baSyz147064 235d62bc4baSyz147064 if (err != 0) 236d62bc4baSyz147064 goto done; 237d62bc4baSyz147064 238d62bc4baSyz147064 created = B_TRUE; 239d62bc4baSyz147064 240d62bc4baSyz147064 /* 241d62bc4baSyz147064 * This is a new link. Only need to persist link attributes for 242d62bc4baSyz147064 * physical links. 243d62bc4baSyz147064 */ 244d62bc4baSyz147064 if (class == DATALINK_CLASS_PHYS && 245d62bc4baSyz147064 (((err = linkattr_set(&linkp->ll_head, FDEVNAME, create->ld_devname, 246d62bc4baSyz147064 strlen(create->ld_devname) + 1, DLADM_TYPE_STR)) != 0) || 247d62bc4baSyz147064 ((err = linkattr_set(&linkp->ll_head, FPHYMAJ, &create->ld_phymaj, 248d62bc4baSyz147064 sizeof (uint64_t), DLADM_TYPE_UINT64)) != 0) || 249d62bc4baSyz147064 ((err = linkattr_set(&linkp->ll_head, FPHYINST, &create->ld_phyinst, 250d62bc4baSyz147064 sizeof (uint64_t), DLADM_TYPE_UINT64)) != 0))) { 251d62bc4baSyz147064 (void) dlmgmt_destroy_common(linkp, flags); 252d62bc4baSyz147064 } 253d62bc4baSyz147064 254d62bc4baSyz147064 done: 2552b24ab6bSSebastien Roy if ((err == 0) && ((err = dlmgmt_write_db_entry(linkp->ll_link, linkp, 256d62bc4baSyz147064 linkp->ll_flags)) != 0) && created) { 257d62bc4baSyz147064 (void) dlmgmt_destroy_common(linkp, flags); 258d62bc4baSyz147064 } 259d62bc4baSyz147064 2608a1c9a22SCathy Zhou noupdate: 261d62bc4baSyz147064 if (err == 0) 262d62bc4baSyz147064 retvalp->lr_linkid = linkp->ll_linkid; 263d62bc4baSyz147064 264d62bc4baSyz147064 dlmgmt_table_unlock(); 2650dc974a9SCathy Zhou 2668a1c9a22SCathy Zhou if ((err == 0) && (class == DATALINK_CLASS_PHYS)) { 2670dc974a9SCathy Zhou /* 2680dc974a9SCathy Zhou * Post the ESC_DATALINK_PHYS_ADD sysevent. This sysevent 2690dc974a9SCathy Zhou * is consumed by the datalink sysevent module which in 2700dc974a9SCathy Zhou * turn generates the RCM_RESOURCE_LINK_NEW RCM event. 2710dc974a9SCathy Zhou */ 2725093e103SCathy Zhou dlmgmt_post_sysevent(ESC_DATALINK_PHYS_ADD, 2735093e103SCathy Zhou retvalp->lr_linkid, reconfigured); 2740dc974a9SCathy Zhou } 2750dc974a9SCathy Zhou 2760dc974a9SCathy Zhou retvalp->lr_err = err; 277d62bc4baSyz147064 } 278d62bc4baSyz147064 279*32715170SCathy Zhou /* ARGSUSED */ 280d62bc4baSyz147064 static void 281*32715170SCathy Zhou dlmgmt_upcall_update(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 282*32715170SCathy Zhou ucred_t *cred) 283d62bc4baSyz147064 { 284024b0a25Sseb dlmgmt_upcall_arg_update_t *update = argp; 285024b0a25Sseb dlmgmt_update_retval_t *retvalp = retp; 286d62bc4baSyz147064 uint32_t media = update->ld_media; 287d62bc4baSyz147064 dlmgmt_link_t *linkp; 288d62bc4baSyz147064 int err = 0; 289d62bc4baSyz147064 290d62bc4baSyz147064 /* 291d62bc4baSyz147064 * Hold the writer lock to update the link table. 292d62bc4baSyz147064 */ 293d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 294d62bc4baSyz147064 295d62bc4baSyz147064 /* 296d62bc4baSyz147064 * Check to see whether this is the reattachment of an existing 297d62bc4baSyz147064 * physical link. If so, return its linkid. 298d62bc4baSyz147064 */ 2992b24ab6bSSebastien Roy if ((linkp = dlmgmt_getlink_by_dev(update->ld_devname, zoneid)) == 3002b24ab6bSSebastien Roy NULL) { 301d62bc4baSyz147064 err = ENOENT; 302d62bc4baSyz147064 goto done; 303d62bc4baSyz147064 } 304d62bc4baSyz147064 3052b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0) 3062b24ab6bSSebastien Roy goto done; 3072b24ab6bSSebastien Roy 308d62bc4baSyz147064 retvalp->lr_linkid = linkp->ll_linkid; 309d62bc4baSyz147064 retvalp->lr_media = media; 310d62bc4baSyz147064 if (linkp->ll_media != media && linkp->ll_media != DL_OTHER) { 311d62bc4baSyz147064 /* 312d62bc4baSyz147064 * Assume a DL_ETHER link ce0, a DL_WIFI link ath0 313d62bc4baSyz147064 * 1. # dladm rename-link ce0 net0 314d62bc4baSyz147064 * 2. DR out ce0. net0 is down. 315d62bc4baSyz147064 * 3. use rename-link to have the ath0 device inherit 316d62bc4baSyz147064 * the configuration from net0 317d62bc4baSyz147064 * # dladm rename-link ath0 net0 318d62bc4baSyz147064 * 4. DR in ath0. 319d62bc4baSyz147064 * As ath0 and ce0 do not have the same media type, ath0 320d62bc4baSyz147064 * cannot inherit the configuration of net0. 321d62bc4baSyz147064 */ 322d62bc4baSyz147064 err = EEXIST; 323d62bc4baSyz147064 324d62bc4baSyz147064 /* 325d62bc4baSyz147064 * Return the media type of the existing link to indicate the 326d62bc4baSyz147064 * reason for the name conflict. 327d62bc4baSyz147064 */ 328d62bc4baSyz147064 retvalp->lr_media = linkp->ll_media; 329d62bc4baSyz147064 goto done; 330d62bc4baSyz147064 } 331d62bc4baSyz147064 332d62bc4baSyz147064 if (update->ld_novanity && 333d62bc4baSyz147064 (strcmp(update->ld_devname, linkp->ll_link) != 0)) { 334d62bc4baSyz147064 /* 335d62bc4baSyz147064 * Return an error if this is a physical link that does not 336d62bc4baSyz147064 * support vanity naming, but the link name is not the same 337d62bc4baSyz147064 * as the given device name. 338d62bc4baSyz147064 */ 339d62bc4baSyz147064 err = EEXIST; 340d62bc4baSyz147064 goto done; 341d62bc4baSyz147064 } 342d62bc4baSyz147064 3438a1c9a22SCathy Zhou if (linkp->ll_media != media) { 344d62bc4baSyz147064 linkp->ll_media = media; 345d62bc4baSyz147064 linkp->ll_gen++; 3462b24ab6bSSebastien Roy (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, 3472b24ab6bSSebastien Roy linkp->ll_flags); 3488a1c9a22SCathy Zhou } 349d62bc4baSyz147064 350d62bc4baSyz147064 done: 351d62bc4baSyz147064 dlmgmt_table_unlock(); 352d62bc4baSyz147064 retvalp->lr_err = err; 353d62bc4baSyz147064 } 354d62bc4baSyz147064 355*32715170SCathy Zhou /* ARGSUSED */ 356d62bc4baSyz147064 static void 357*32715170SCathy Zhou dlmgmt_upcall_destroy(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 358*32715170SCathy Zhou ucred_t *cred) 359d62bc4baSyz147064 { 360024b0a25Sseb dlmgmt_upcall_arg_destroy_t *destroy = argp; 361024b0a25Sseb dlmgmt_destroy_retval_t *retvalp = retp; 362d62bc4baSyz147064 datalink_id_t linkid = destroy->ld_linkid; 363d62bc4baSyz147064 dlmgmt_link_t *linkp = NULL; 364d62bc4baSyz147064 uint32_t flags, dflags = 0; 365d62bc4baSyz147064 int err = 0; 366d62bc4baSyz147064 367d62bc4baSyz147064 flags = DLMGMT_ACTIVE | (destroy->ld_persist ? DLMGMT_PERSIST : 0); 368d62bc4baSyz147064 369d62bc4baSyz147064 /* 370d62bc4baSyz147064 * Hold the writer lock to update the link table. 371d62bc4baSyz147064 */ 372d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 373d62bc4baSyz147064 3742b24ab6bSSebastien Roy if ((linkp = link_by_id(linkid, zoneid)) == NULL) { 375d62bc4baSyz147064 err = ENOENT; 376d62bc4baSyz147064 goto done; 377d62bc4baSyz147064 } 378d62bc4baSyz147064 3792b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0) 3802b24ab6bSSebastien Roy goto done; 3812b24ab6bSSebastien Roy 382a73e6fc1SCathy Zhou if (((linkp->ll_flags & flags) & DLMGMT_ACTIVE) != 0) { 3832b24ab6bSSebastien Roy if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE)) != 0) 384d62bc4baSyz147064 goto done; 385a73e6fc1SCathy Zhou dflags |= DLMGMT_ACTIVE; 386d62bc4baSyz147064 } 387d62bc4baSyz147064 388a73e6fc1SCathy Zhou if (((linkp->ll_flags & flags) & DLMGMT_PERSIST) != 0) { 3892b24ab6bSSebastien Roy if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_PERSIST)) != 0) 390a73e6fc1SCathy Zhou goto done; 391d62bc4baSyz147064 dflags |= DLMGMT_PERSIST; 392d62bc4baSyz147064 } 393d62bc4baSyz147064 394a73e6fc1SCathy Zhou err = dlmgmt_destroy_common(linkp, flags); 395a73e6fc1SCathy Zhou done: 396a73e6fc1SCathy Zhou if (err != 0 && dflags != 0) 3972b24ab6bSSebastien Roy (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, dflags); 398d62bc4baSyz147064 399d62bc4baSyz147064 dlmgmt_table_unlock(); 400d62bc4baSyz147064 retvalp->lr_err = err; 401d62bc4baSyz147064 } 402d62bc4baSyz147064 4032b24ab6bSSebastien Roy /* ARGSUSED */ 404d62bc4baSyz147064 static void 405*32715170SCathy Zhou dlmgmt_getname(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 406*32715170SCathy Zhou ucred_t *cred) 407d62bc4baSyz147064 { 408024b0a25Sseb dlmgmt_door_getname_t *getname = argp; 409024b0a25Sseb dlmgmt_getname_retval_t *retvalp = retp; 410d62bc4baSyz147064 dlmgmt_link_t *linkp; 411d62bc4baSyz147064 int err = 0; 412d62bc4baSyz147064 413d62bc4baSyz147064 /* 414d62bc4baSyz147064 * Hold the reader lock to access the link 415d62bc4baSyz147064 */ 416d62bc4baSyz147064 dlmgmt_table_lock(B_FALSE); 4172b24ab6bSSebastien Roy if ((linkp = link_by_id(getname->ld_linkid, zoneid)) == NULL) { 418d62bc4baSyz147064 err = ENOENT; 4192b24ab6bSSebastien Roy } else if (strlcpy(retvalp->lr_link, linkp->ll_link, MAXLINKNAMELEN) >= 420d62bc4baSyz147064 MAXLINKNAMELEN) { 421d62bc4baSyz147064 err = ENOSPC; 4222b24ab6bSSebastien Roy } else { 423d62bc4baSyz147064 retvalp->lr_flags = linkp->ll_flags; 424d62bc4baSyz147064 retvalp->lr_class = linkp->ll_class; 425d62bc4baSyz147064 retvalp->lr_media = linkp->ll_media; 4262b24ab6bSSebastien Roy } 427d62bc4baSyz147064 428d62bc4baSyz147064 dlmgmt_table_unlock(); 429d62bc4baSyz147064 retvalp->lr_err = err; 430d62bc4baSyz147064 } 431d62bc4baSyz147064 4322b24ab6bSSebastien Roy /* ARGSUSED */ 433d62bc4baSyz147064 static void 434*32715170SCathy Zhou dlmgmt_getlinkid(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 435*32715170SCathy Zhou ucred_t *cred) 436d62bc4baSyz147064 { 437024b0a25Sseb dlmgmt_door_getlinkid_t *getlinkid = argp; 438024b0a25Sseb dlmgmt_getlinkid_retval_t *retvalp = retp; 439d62bc4baSyz147064 dlmgmt_link_t *linkp; 440d62bc4baSyz147064 int err = 0; 441d62bc4baSyz147064 442d62bc4baSyz147064 /* 443d62bc4baSyz147064 * Hold the reader lock to access the link 444d62bc4baSyz147064 */ 445d62bc4baSyz147064 dlmgmt_table_lock(B_FALSE); 4462b24ab6bSSebastien Roy 4472b24ab6bSSebastien Roy if ((linkp = link_by_name(getlinkid->ld_link, zoneid)) == NULL) { 448d62bc4baSyz147064 /* 4492b24ab6bSSebastien Roy * The link does not exist in this zone. 450d62bc4baSyz147064 */ 451d62bc4baSyz147064 err = ENOENT; 452d62bc4baSyz147064 goto done; 453d62bc4baSyz147064 } 454d62bc4baSyz147064 455d62bc4baSyz147064 retvalp->lr_linkid = linkp->ll_linkid; 456d62bc4baSyz147064 retvalp->lr_flags = linkp->ll_flags; 457d62bc4baSyz147064 retvalp->lr_class = linkp->ll_class; 458d62bc4baSyz147064 retvalp->lr_media = linkp->ll_media; 459d62bc4baSyz147064 460d62bc4baSyz147064 done: 461d62bc4baSyz147064 dlmgmt_table_unlock(); 462d62bc4baSyz147064 retvalp->lr_err = err; 463d62bc4baSyz147064 } 464d62bc4baSyz147064 4652b24ab6bSSebastien Roy /* ARGSUSED */ 466d62bc4baSyz147064 static void 467*32715170SCathy Zhou dlmgmt_getnext(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 468*32715170SCathy Zhou ucred_t *cred) 469d62bc4baSyz147064 { 470024b0a25Sseb dlmgmt_door_getnext_t *getnext = argp; 471024b0a25Sseb dlmgmt_getnext_retval_t *retvalp = retp; 472d62bc4baSyz147064 dlmgmt_link_t link, *linkp; 473d62bc4baSyz147064 avl_index_t where; 474d62bc4baSyz147064 int err = 0; 475d62bc4baSyz147064 476d62bc4baSyz147064 /* 477d62bc4baSyz147064 * Hold the reader lock to access the link 478d62bc4baSyz147064 */ 479d62bc4baSyz147064 dlmgmt_table_lock(B_FALSE); 480d62bc4baSyz147064 4812b24ab6bSSebastien Roy link.ll_linkid = (getnext->ld_linkid + 1); 4822b24ab6bSSebastien Roy if ((linkp = avl_find(&dlmgmt_id_avl, &link, &where)) == NULL) 483d62bc4baSyz147064 linkp = avl_nearest(&dlmgmt_id_avl, where, AVL_AFTER); 484d62bc4baSyz147064 485d62bc4baSyz147064 for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) { 4862b24ab6bSSebastien Roy if (!link_is_visible(linkp, zoneid)) 4872b24ab6bSSebastien Roy continue; 488d62bc4baSyz147064 if ((linkp->ll_class & getnext->ld_class) && 489d62bc4baSyz147064 (linkp->ll_flags & getnext->ld_flags) && 490d62bc4baSyz147064 DATALINK_MEDIA_ACCEPTED(getnext->ld_dmedia, 491d62bc4baSyz147064 linkp->ll_media)) 492d62bc4baSyz147064 break; 493d62bc4baSyz147064 } 494d62bc4baSyz147064 495d62bc4baSyz147064 if (linkp == NULL) { 496d62bc4baSyz147064 err = ENOENT; 497d62bc4baSyz147064 } else { 498d62bc4baSyz147064 retvalp->lr_linkid = linkp->ll_linkid; 499d62bc4baSyz147064 retvalp->lr_class = linkp->ll_class; 500d62bc4baSyz147064 retvalp->lr_media = linkp->ll_media; 501d62bc4baSyz147064 retvalp->lr_flags = linkp->ll_flags; 502d62bc4baSyz147064 } 503d62bc4baSyz147064 504d62bc4baSyz147064 dlmgmt_table_unlock(); 505d62bc4baSyz147064 retvalp->lr_err = err; 506d62bc4baSyz147064 } 507d62bc4baSyz147064 5082b24ab6bSSebastien Roy /* ARGSUSED */ 509024b0a25Sseb static void 510*32715170SCathy Zhou dlmgmt_upcall_getattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 511*32715170SCathy Zhou ucred_t *cred) 512d62bc4baSyz147064 { 513024b0a25Sseb dlmgmt_upcall_arg_getattr_t *getattr = argp; 514024b0a25Sseb dlmgmt_getattr_retval_t *retvalp = retp; 515d62bc4baSyz147064 dlmgmt_link_t *linkp; 516d62bc4baSyz147064 517d62bc4baSyz147064 /* 518d62bc4baSyz147064 * Hold the reader lock to access the link 519d62bc4baSyz147064 */ 520d62bc4baSyz147064 dlmgmt_table_lock(B_FALSE); 5212b24ab6bSSebastien Roy if ((linkp = link_by_id(getattr->ld_linkid, zoneid)) == NULL) { 522f1956ffeSCathy Zhou retvalp->lr_err = ENOENT; 5232b24ab6bSSebastien Roy } else { 5242b24ab6bSSebastien Roy retvalp->lr_err = dlmgmt_getattr_common(&linkp->ll_head, 5252b24ab6bSSebastien Roy getattr->ld_attr, retvalp); 526d62bc4baSyz147064 } 527d62bc4baSyz147064 dlmgmt_table_unlock(); 528d62bc4baSyz147064 } 529d62bc4baSyz147064 530*32715170SCathy Zhou /* ARGSUSED */ 531d62bc4baSyz147064 static void 532*32715170SCathy Zhou dlmgmt_createid(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 533*32715170SCathy Zhou ucred_t *cred) 534d62bc4baSyz147064 { 535024b0a25Sseb dlmgmt_door_createid_t *createid = argp; 536024b0a25Sseb dlmgmt_createid_retval_t *retvalp = retp; 537d62bc4baSyz147064 dlmgmt_link_t *linkp; 538d62bc4baSyz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID; 539d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 540d62bc4baSyz147064 int err; 541d62bc4baSyz147064 542d62bc4baSyz147064 /* 543d62bc4baSyz147064 * Hold the writer lock to update the dlconf table. 544d62bc4baSyz147064 */ 545d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 546d62bc4baSyz147064 5472b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(createid->ld_class, cred)) != 0) 5482b24ab6bSSebastien Roy goto done; 5492b24ab6bSSebastien Roy 550d62bc4baSyz147064 if (createid->ld_prefix) { 551d62bc4baSyz147064 err = dlmgmt_generate_name(createid->ld_link, link, 5522b24ab6bSSebastien Roy MAXLINKNAMELEN, zoneid); 553d62bc4baSyz147064 if (err != 0) 554d62bc4baSyz147064 goto done; 555d62bc4baSyz147064 556d62bc4baSyz147064 err = dlmgmt_create_common(link, createid->ld_class, 5572b24ab6bSSebastien Roy createid->ld_media, zoneid, createid->ld_flags, &linkp); 558d62bc4baSyz147064 } else { 559d62bc4baSyz147064 err = dlmgmt_create_common(createid->ld_link, 5602b24ab6bSSebastien Roy createid->ld_class, createid->ld_media, zoneid, 5612b24ab6bSSebastien Roy createid->ld_flags, &linkp); 562d62bc4baSyz147064 } 563d62bc4baSyz147064 564d62bc4baSyz147064 if (err == 0) { 565d62bc4baSyz147064 /* 566d62bc4baSyz147064 * Keep the active mapping. 567d62bc4baSyz147064 */ 568d62bc4baSyz147064 linkid = linkp->ll_linkid; 5692b24ab6bSSebastien Roy if (createid->ld_flags & DLMGMT_ACTIVE) { 5702b24ab6bSSebastien Roy (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, 5712b24ab6bSSebastien Roy DLMGMT_ACTIVE); 5722b24ab6bSSebastien Roy } 573d62bc4baSyz147064 } 574d62bc4baSyz147064 575d62bc4baSyz147064 done: 576d62bc4baSyz147064 dlmgmt_table_unlock(); 577d62bc4baSyz147064 retvalp->lr_linkid = linkid; 578d62bc4baSyz147064 retvalp->lr_err = err; 579d62bc4baSyz147064 } 580d62bc4baSyz147064 581*32715170SCathy Zhou /* ARGSUSED */ 582d62bc4baSyz147064 static void 583*32715170SCathy Zhou dlmgmt_destroyid(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 584*32715170SCathy Zhou ucred_t *cred) 585d62bc4baSyz147064 { 586024b0a25Sseb dlmgmt_door_destroyid_t *destroyid = argp; 587024b0a25Sseb dlmgmt_destroyid_retval_t *retvalp = retp; 588d62bc4baSyz147064 datalink_id_t linkid = destroyid->ld_linkid; 589d62bc4baSyz147064 uint32_t flags = destroyid->ld_flags; 590d62bc4baSyz147064 dlmgmt_link_t *linkp = NULL; 591d62bc4baSyz147064 int err = 0; 592d62bc4baSyz147064 593d62bc4baSyz147064 /* 594d62bc4baSyz147064 * Hold the writer lock to update the link table. 595d62bc4baSyz147064 */ 596d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 5972b24ab6bSSebastien Roy if ((linkp = link_by_id(linkid, zoneid)) == NULL) { 598d62bc4baSyz147064 err = ENOENT; 599d62bc4baSyz147064 goto done; 600d62bc4baSyz147064 } 601d62bc4baSyz147064 6022b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0) 603d62bc4baSyz147064 goto done; 604d62bc4baSyz147064 605d62bc4baSyz147064 /* 606d62bc4baSyz147064 * Delete the active mapping. 607d62bc4baSyz147064 */ 608d62bc4baSyz147064 if (flags & DLMGMT_ACTIVE) 6092b24ab6bSSebastien Roy err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE); 6102b24ab6bSSebastien Roy if (err == 0) 6112b24ab6bSSebastien Roy err = dlmgmt_destroy_common(linkp, flags); 612d62bc4baSyz147064 done: 613d62bc4baSyz147064 dlmgmt_table_unlock(); 614d62bc4baSyz147064 retvalp->lr_err = err; 615d62bc4baSyz147064 } 616d62bc4baSyz147064 617d62bc4baSyz147064 /* 618d62bc4baSyz147064 * Remap a linkid to a given link name, i.e., rename an existing link1 619d62bc4baSyz147064 * (ld_linkid) to a non-existent link2 (ld_link): rename link1's name to 620d62bc4baSyz147064 * the given link name. 621d62bc4baSyz147064 */ 622*32715170SCathy Zhou /* ARGSUSED */ 623d62bc4baSyz147064 static void 624*32715170SCathy Zhou dlmgmt_remapid(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 625*32715170SCathy Zhou ucred_t *cred) 626d62bc4baSyz147064 { 627024b0a25Sseb dlmgmt_door_remapid_t *remapid = argp; 628024b0a25Sseb dlmgmt_remapid_retval_t *retvalp = retp; 6292b24ab6bSSebastien Roy dlmgmt_link_t *linkp; 6302b24ab6bSSebastien Roy char oldname[MAXLINKNAMELEN]; 6312b24ab6bSSebastien Roy boolean_t renamed = B_FALSE; 632d62bc4baSyz147064 int err = 0; 633d62bc4baSyz147064 634d62bc4baSyz147064 if (!dladm_valid_linkname(remapid->ld_link)) { 635d62bc4baSyz147064 retvalp->lr_err = EINVAL; 636d62bc4baSyz147064 return; 637d62bc4baSyz147064 } 638d62bc4baSyz147064 639d62bc4baSyz147064 /* 640d62bc4baSyz147064 * Hold the writer lock to update the link table. 641d62bc4baSyz147064 */ 642d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 6432b24ab6bSSebastien Roy if ((linkp = link_by_id(remapid->ld_linkid, zoneid)) == NULL) { 644d62bc4baSyz147064 err = ENOENT; 645d62bc4baSyz147064 goto done; 646d62bc4baSyz147064 } 647d62bc4baSyz147064 6482b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0) 6492b24ab6bSSebastien Roy goto done; 6502b24ab6bSSebastien Roy 6512b24ab6bSSebastien Roy if (link_by_name(remapid->ld_link, linkp->ll_zoneid) != NULL) { 652d62bc4baSyz147064 err = EEXIST; 653d62bc4baSyz147064 goto done; 654d62bc4baSyz147064 } 655d62bc4baSyz147064 6562b24ab6bSSebastien Roy (void) strlcpy(oldname, linkp->ll_link, MAXLINKNAMELEN); 6572b24ab6bSSebastien Roy avl_remove(&dlmgmt_name_avl, linkp); 6582b24ab6bSSebastien Roy (void) strlcpy(linkp->ll_link, remapid->ld_link, MAXLINKNAMELEN); 6592b24ab6bSSebastien Roy avl_add(&dlmgmt_name_avl, linkp); 6602b24ab6bSSebastien Roy renamed = B_TRUE; 661d62bc4baSyz147064 6622b24ab6bSSebastien Roy if (linkp->ll_flags & DLMGMT_ACTIVE) { 6632b24ab6bSSebastien Roy err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_ACTIVE); 6642b24ab6bSSebastien Roy if (err != 0) 6652b24ab6bSSebastien Roy goto done; 6662b24ab6bSSebastien Roy } 6672b24ab6bSSebastien Roy if (linkp->ll_flags & DLMGMT_PERSIST) { 6682b24ab6bSSebastien Roy err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_PERSIST); 6692b24ab6bSSebastien Roy if (err != 0) { 6702b24ab6bSSebastien Roy if (linkp->ll_flags & DLMGMT_ACTIVE) { 6712b24ab6bSSebastien Roy (void) dlmgmt_write_db_entry(remapid->ld_link, 6722b24ab6bSSebastien Roy linkp, DLMGMT_ACTIVE); 6732b24ab6bSSebastien Roy } 6742b24ab6bSSebastien Roy goto done; 6752b24ab6bSSebastien Roy } 6762b24ab6bSSebastien Roy } 6772b24ab6bSSebastien Roy 6782b24ab6bSSebastien Roy dlmgmt_advance(linkp); 6792b24ab6bSSebastien Roy linkp->ll_gen++; 680d62bc4baSyz147064 done: 6812b24ab6bSSebastien Roy if (err != 0 && renamed) { 6822b24ab6bSSebastien Roy avl_remove(&dlmgmt_name_avl, linkp); 6832b24ab6bSSebastien Roy (void) strlcpy(linkp->ll_link, oldname, MAXLINKNAMELEN); 6842b24ab6bSSebastien Roy avl_add(&dlmgmt_name_avl, linkp); 6852b24ab6bSSebastien Roy } 686d62bc4baSyz147064 dlmgmt_table_unlock(); 687d62bc4baSyz147064 retvalp->lr_err = err; 688d62bc4baSyz147064 } 689d62bc4baSyz147064 690*32715170SCathy Zhou /* ARGSUSED */ 691d62bc4baSyz147064 static void 692*32715170SCathy Zhou dlmgmt_upid(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 693*32715170SCathy Zhou ucred_t *cred) 694d62bc4baSyz147064 { 695024b0a25Sseb dlmgmt_door_upid_t *upid = argp; 696024b0a25Sseb dlmgmt_upid_retval_t *retvalp = retp; 697d62bc4baSyz147064 dlmgmt_link_t *linkp; 698d62bc4baSyz147064 int err = 0; 699d62bc4baSyz147064 700d62bc4baSyz147064 /* 701d62bc4baSyz147064 * Hold the writer lock to update the link table. 702d62bc4baSyz147064 */ 703d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 7042b24ab6bSSebastien Roy if ((linkp = link_by_id(upid->ld_linkid, zoneid)) == NULL) { 705d62bc4baSyz147064 err = ENOENT; 706d62bc4baSyz147064 goto done; 707d62bc4baSyz147064 } 708d62bc4baSyz147064 7092b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0) 7102b24ab6bSSebastien Roy goto done; 7112b24ab6bSSebastien Roy 712d62bc4baSyz147064 if (linkp->ll_flags & DLMGMT_ACTIVE) { 713d62bc4baSyz147064 err = EINVAL; 714d62bc4baSyz147064 goto done; 715d62bc4baSyz147064 } 716d62bc4baSyz147064 7172b24ab6bSSebastien Roy if ((err = link_activate(linkp)) == 0) { 7182b24ab6bSSebastien Roy (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, 7192b24ab6bSSebastien Roy DLMGMT_ACTIVE); 7202b24ab6bSSebastien Roy } 721d62bc4baSyz147064 done: 722d62bc4baSyz147064 dlmgmt_table_unlock(); 723d62bc4baSyz147064 retvalp->lr_err = err; 724d62bc4baSyz147064 } 725d62bc4baSyz147064 726*32715170SCathy Zhou /* ARGSUSED */ 727d62bc4baSyz147064 static void 728*32715170SCathy Zhou dlmgmt_createconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 729*32715170SCathy Zhou ucred_t *cred) 730d62bc4baSyz147064 { 731024b0a25Sseb dlmgmt_door_createconf_t *createconf = argp; 732024b0a25Sseb dlmgmt_createconf_retval_t *retvalp = retp; 7332b24ab6bSSebastien Roy dlmgmt_dlconf_t *dlconfp; 734d62bc4baSyz147064 int err; 735d62bc4baSyz147064 736d62bc4baSyz147064 /* 737d62bc4baSyz147064 * Hold the writer lock to update the dlconf table. 738d62bc4baSyz147064 */ 739d62bc4baSyz147064 dlmgmt_dlconf_table_lock(B_TRUE); 740d62bc4baSyz147064 7412b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(createconf->ld_class, cred)) != 0) 742d62bc4baSyz147064 goto done; 743d62bc4baSyz147064 7442b24ab6bSSebastien Roy err = dlconf_create(createconf->ld_link, createconf->ld_linkid, 7452b24ab6bSSebastien Roy createconf->ld_class, createconf->ld_media, zoneid, &dlconfp); 7462b24ab6bSSebastien Roy if (err == 0) { 7472b24ab6bSSebastien Roy avl_add(&dlmgmt_dlconf_avl, dlconfp); 748d62bc4baSyz147064 dlmgmt_advance_dlconfid(dlconfp); 749*32715170SCathy Zhou retvalp->lr_confid = dlconfp->ld_id; 7502b24ab6bSSebastien Roy } 751d62bc4baSyz147064 done: 752d62bc4baSyz147064 dlmgmt_dlconf_table_unlock(); 753d62bc4baSyz147064 retvalp->lr_err = err; 754d62bc4baSyz147064 } 755d62bc4baSyz147064 756*32715170SCathy Zhou /* ARGSUSED */ 757d62bc4baSyz147064 static void 758*32715170SCathy Zhou dlmgmt_setattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 759*32715170SCathy Zhou ucred_t *cred) 760d62bc4baSyz147064 { 761024b0a25Sseb dlmgmt_door_setattr_t *setattr = argp; 762024b0a25Sseb dlmgmt_setattr_retval_t *retvalp = retp; 763d62bc4baSyz147064 dlmgmt_dlconf_t dlconf, *dlconfp; 764d62bc4baSyz147064 int err = 0; 765d62bc4baSyz147064 766d62bc4baSyz147064 /* 767d62bc4baSyz147064 * Hold the writer lock to update the dlconf table. 768d62bc4baSyz147064 */ 769d62bc4baSyz147064 dlmgmt_dlconf_table_lock(B_TRUE); 770d62bc4baSyz147064 771*32715170SCathy Zhou dlconf.ld_id = setattr->ld_confid; 772d62bc4baSyz147064 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL); 7732b24ab6bSSebastien Roy if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) { 774d62bc4baSyz147064 err = ENOENT; 775d62bc4baSyz147064 goto done; 776d62bc4baSyz147064 } 777d62bc4baSyz147064 7782b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0) 7792b24ab6bSSebastien Roy goto done; 7802b24ab6bSSebastien Roy 781d62bc4baSyz147064 err = linkattr_set(&(dlconfp->ld_head), setattr->ld_attr, 782d62bc4baSyz147064 &setattr->ld_attrval, setattr->ld_attrsz, setattr->ld_type); 783d62bc4baSyz147064 784d62bc4baSyz147064 done: 785d62bc4baSyz147064 dlmgmt_dlconf_table_unlock(); 786d62bc4baSyz147064 retvalp->lr_err = err; 787d62bc4baSyz147064 } 788d62bc4baSyz147064 789*32715170SCathy Zhou /* ARGSUSED */ 790d62bc4baSyz147064 static void 791*32715170SCathy Zhou dlmgmt_unsetconfattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 792*32715170SCathy Zhou ucred_t *cred) 793d62bc4baSyz147064 { 794024b0a25Sseb dlmgmt_door_unsetattr_t *unsetattr = argp; 795024b0a25Sseb dlmgmt_unsetattr_retval_t *retvalp = retp; 796d62bc4baSyz147064 dlmgmt_dlconf_t dlconf, *dlconfp; 797d62bc4baSyz147064 int err = 0; 798d62bc4baSyz147064 799d62bc4baSyz147064 /* 800d62bc4baSyz147064 * Hold the writer lock to update the dlconf table. 801d62bc4baSyz147064 */ 802d62bc4baSyz147064 dlmgmt_dlconf_table_lock(B_TRUE); 803d62bc4baSyz147064 804*32715170SCathy Zhou dlconf.ld_id = unsetattr->ld_confid; 805d62bc4baSyz147064 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL); 8062b24ab6bSSebastien Roy if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) { 807d62bc4baSyz147064 err = ENOENT; 808d62bc4baSyz147064 goto done; 809d62bc4baSyz147064 } 810d62bc4baSyz147064 8112b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0) 8122b24ab6bSSebastien Roy goto done; 8132b24ab6bSSebastien Roy 8142b24ab6bSSebastien Roy linkattr_unset(&(dlconfp->ld_head), unsetattr->ld_attr); 815d62bc4baSyz147064 816d62bc4baSyz147064 done: 817d62bc4baSyz147064 dlmgmt_dlconf_table_unlock(); 818d62bc4baSyz147064 retvalp->lr_err = err; 819d62bc4baSyz147064 } 820d62bc4baSyz147064 821d62bc4baSyz147064 /* 822*32715170SCathy Zhou * Note that dlmgmt_openconf() returns a conf ID of a conf AVL tree entry, 823d62bc4baSyz147064 * which is managed by dlmgmtd. The ID is used to find the conf entry when 824d62bc4baSyz147064 * dlmgmt_write_conf() is called. The conf entry contains an ld_gen value 825d62bc4baSyz147064 * (which is the generation number - ll_gen) of the dlmgmt_link_t at the time 826*32715170SCathy Zhou * of dlmgmt_openconf(), and ll_gen changes every time the dlmgmt_link_t 827d62bc4baSyz147064 * changes its attributes. Therefore, dlmgmt_write_conf() can compare ld_gen 828d62bc4baSyz147064 * in the conf entry against the latest dlmgmt_link_t ll_gen value to see if 829*32715170SCathy Zhou * anything has changed between the dlmgmt_openconf() and dlmgmt_writeconf() 830d62bc4baSyz147064 * calls. If so, EAGAIN is returned. This mechanism can ensures atomicity 831d62bc4baSyz147064 * across the pair of dladm_read_conf() and dladm_write_conf() calls. 832d62bc4baSyz147064 */ 833*32715170SCathy Zhou /* ARGSUSED */ 834d62bc4baSyz147064 static void 835*32715170SCathy Zhou dlmgmt_writeconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 836*32715170SCathy Zhou ucred_t *cred) 837d62bc4baSyz147064 { 838024b0a25Sseb dlmgmt_door_writeconf_t *writeconf = argp; 839024b0a25Sseb dlmgmt_writeconf_retval_t *retvalp = retp; 840d62bc4baSyz147064 dlmgmt_dlconf_t dlconf, *dlconfp; 841d62bc4baSyz147064 dlmgmt_link_t *linkp; 842d62bc4baSyz147064 dlmgmt_linkattr_t *attrp, *next; 843d62bc4baSyz147064 int err = 0; 844d62bc4baSyz147064 845d62bc4baSyz147064 /* 846*32715170SCathy Zhou * Hold the lock to access the dlconf table. 847d62bc4baSyz147064 */ 848d62bc4baSyz147064 dlmgmt_dlconf_table_lock(B_TRUE); 849d62bc4baSyz147064 850*32715170SCathy Zhou dlconf.ld_id = writeconf->ld_confid; 851d62bc4baSyz147064 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL); 8522b24ab6bSSebastien Roy if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) { 853d62bc4baSyz147064 err = ENOENT; 854d62bc4baSyz147064 goto done; 855d62bc4baSyz147064 } 856d62bc4baSyz147064 8572b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0) 8582b24ab6bSSebastien Roy goto done; 8592b24ab6bSSebastien Roy 860d62bc4baSyz147064 /* 861d62bc4baSyz147064 * Hold the writer lock to update the link table. 862d62bc4baSyz147064 */ 863d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 8642b24ab6bSSebastien Roy linkp = link_by_id(dlconfp->ld_linkid, zoneid); 865d62bc4baSyz147064 if ((linkp == NULL) || (linkp->ll_class != dlconfp->ld_class) || 866d62bc4baSyz147064 (linkp->ll_media != dlconfp->ld_media) || 867d62bc4baSyz147064 (strcmp(linkp->ll_link, dlconfp->ld_link) != 0)) { 868d62bc4baSyz147064 /* 869d62bc4baSyz147064 * The link does not exist. 870d62bc4baSyz147064 */ 871d62bc4baSyz147064 dlmgmt_table_unlock(); 872d62bc4baSyz147064 err = ENOENT; 873d62bc4baSyz147064 goto done; 874d62bc4baSyz147064 } 875d62bc4baSyz147064 876d62bc4baSyz147064 if (linkp->ll_gen != dlconfp->ld_gen) { 877d62bc4baSyz147064 /* 878d62bc4baSyz147064 * Something has changed the link configuration; try again. 879d62bc4baSyz147064 */ 880d62bc4baSyz147064 dlmgmt_table_unlock(); 881d62bc4baSyz147064 err = EAGAIN; 882d62bc4baSyz147064 goto done; 883d62bc4baSyz147064 } 884d62bc4baSyz147064 885d62bc4baSyz147064 /* 886d62bc4baSyz147064 * Delete the old attribute list. 887d62bc4baSyz147064 */ 888d62bc4baSyz147064 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) { 889d62bc4baSyz147064 next = attrp->lp_next; 890d62bc4baSyz147064 free(attrp->lp_val); 891d62bc4baSyz147064 free(attrp); 892d62bc4baSyz147064 } 893d62bc4baSyz147064 linkp->ll_head = NULL; 894d62bc4baSyz147064 895d62bc4baSyz147064 /* 896d62bc4baSyz147064 * Set the new attribute. 897d62bc4baSyz147064 */ 898d62bc4baSyz147064 for (attrp = dlconfp->ld_head; attrp != NULL; attrp = attrp->lp_next) { 899d62bc4baSyz147064 if ((err = linkattr_set(&(linkp->ll_head), attrp->lp_name, 900d62bc4baSyz147064 attrp->lp_val, attrp->lp_sz, attrp->lp_type)) != 0) { 901d62bc4baSyz147064 dlmgmt_table_unlock(); 902d62bc4baSyz147064 goto done; 903d62bc4baSyz147064 } 904d62bc4baSyz147064 } 905d62bc4baSyz147064 906d62bc4baSyz147064 linkp->ll_gen++; 9072b24ab6bSSebastien Roy err = dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_PERSIST); 908d62bc4baSyz147064 dlmgmt_table_unlock(); 909d62bc4baSyz147064 done: 910d62bc4baSyz147064 dlmgmt_dlconf_table_unlock(); 911d62bc4baSyz147064 retvalp->lr_err = err; 912d62bc4baSyz147064 } 913d62bc4baSyz147064 914*32715170SCathy Zhou /* ARGSUSED */ 915d62bc4baSyz147064 static void 916*32715170SCathy Zhou dlmgmt_removeconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 917*32715170SCathy Zhou ucred_t *cred) 918d62bc4baSyz147064 { 919024b0a25Sseb dlmgmt_door_removeconf_t *removeconf = argp; 920024b0a25Sseb dlmgmt_removeconf_retval_t *retvalp = retp; 9212b24ab6bSSebastien Roy dlmgmt_link_t *linkp; 922d62bc4baSyz147064 int err; 923d62bc4baSyz147064 924d62bc4baSyz147064 dlmgmt_table_lock(B_TRUE); 9252b24ab6bSSebastien Roy if ((linkp = link_by_id(removeconf->ld_linkid, zoneid)) == NULL) { 9262b24ab6bSSebastien Roy err = ENOENT; 9272b24ab6bSSebastien Roy goto done; 9282b24ab6bSSebastien Roy } 9292b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && linkp->ll_onloan) { 9302b24ab6bSSebastien Roy /* 9312b24ab6bSSebastien Roy * A non-global zone cannot remove the persistent 9322b24ab6bSSebastien Roy * configuration of a link that is on loan from the global 9332b24ab6bSSebastien Roy * zone. 9342b24ab6bSSebastien Roy */ 9352b24ab6bSSebastien Roy err = EACCES; 9362b24ab6bSSebastien Roy goto done; 9372b24ab6bSSebastien Roy } 9382b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0) 9392b24ab6bSSebastien Roy goto done; 9402b24ab6bSSebastien Roy 9412b24ab6bSSebastien Roy err = dlmgmt_delete_db_entry(linkp, DLMGMT_PERSIST); 9422b24ab6bSSebastien Roy done: 943d62bc4baSyz147064 dlmgmt_table_unlock(); 944d62bc4baSyz147064 retvalp->lr_err = err; 945d62bc4baSyz147064 } 946d62bc4baSyz147064 947*32715170SCathy Zhou /* ARGSUSED */ 948d62bc4baSyz147064 static void 949*32715170SCathy Zhou dlmgmt_destroyconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 950*32715170SCathy Zhou ucred_t *cred) 951d62bc4baSyz147064 { 952024b0a25Sseb dlmgmt_door_destroyconf_t *destroyconf = argp; 953024b0a25Sseb dlmgmt_destroyconf_retval_t *retvalp = retp; 954d62bc4baSyz147064 dlmgmt_dlconf_t dlconf, *dlconfp; 955d62bc4baSyz147064 int err = 0; 956d62bc4baSyz147064 957d62bc4baSyz147064 /* 958d62bc4baSyz147064 * Hold the writer lock to update the dlconf table. 959d62bc4baSyz147064 */ 960d62bc4baSyz147064 dlmgmt_dlconf_table_lock(B_TRUE); 961d62bc4baSyz147064 962*32715170SCathy Zhou dlconf.ld_id = destroyconf->ld_confid; 963d62bc4baSyz147064 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL); 9642b24ab6bSSebastien Roy if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) { 965d62bc4baSyz147064 err = ENOENT; 966d62bc4baSyz147064 goto done; 967d62bc4baSyz147064 } 968d62bc4baSyz147064 9692b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0) 9702b24ab6bSSebastien Roy goto done; 9712b24ab6bSSebastien Roy 972d62bc4baSyz147064 avl_remove(&dlmgmt_dlconf_avl, dlconfp); 973d62bc4baSyz147064 dlconf_destroy(dlconfp); 974d62bc4baSyz147064 975d62bc4baSyz147064 done: 976d62bc4baSyz147064 dlmgmt_dlconf_table_unlock(); 977d62bc4baSyz147064 retvalp->lr_err = err; 978d62bc4baSyz147064 } 979d62bc4baSyz147064 980d62bc4baSyz147064 /* 981*32715170SCathy Zhou * dlmgmt_openconf() returns a handle of the current configuration, which 982*32715170SCathy Zhou * is then used to update the configuration by dlmgmt_writeconf(). Therefore, 983*32715170SCathy Zhou * it requires privileges. 984*32715170SCathy Zhou * 985*32715170SCathy Zhou * Further, please see the comments above dladm_write_conf() to see how 986*32715170SCathy Zhou * ld_gen is used to ensure atomicity across the {dlmgmt_openconf(), 987*32715170SCathy Zhou * dlmgmt_writeconf()} pair. 988d62bc4baSyz147064 */ 9892b24ab6bSSebastien Roy /* ARGSUSED */ 990d62bc4baSyz147064 static void 991*32715170SCathy Zhou dlmgmt_openconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 992*32715170SCathy Zhou ucred_t *cred) 993d62bc4baSyz147064 { 994*32715170SCathy Zhou dlmgmt_door_openconf_t *openconf = argp; 995*32715170SCathy Zhou dlmgmt_openconf_retval_t *retvalp = retp; 996d62bc4baSyz147064 dlmgmt_link_t *linkp; 997*32715170SCathy Zhou datalink_id_t linkid = openconf->ld_linkid; 9982b24ab6bSSebastien Roy dlmgmt_dlconf_t *dlconfp; 999d62bc4baSyz147064 dlmgmt_linkattr_t *attrp; 1000d62bc4baSyz147064 int err = 0; 1001d62bc4baSyz147064 1002d62bc4baSyz147064 /* 1003d62bc4baSyz147064 * Hold the writer lock to update the dlconf table. 1004d62bc4baSyz147064 */ 1005d62bc4baSyz147064 dlmgmt_dlconf_table_lock(B_TRUE); 1006d62bc4baSyz147064 1007d62bc4baSyz147064 /* 1008d62bc4baSyz147064 * Hold the reader lock to access the link 1009d62bc4baSyz147064 */ 1010d62bc4baSyz147064 dlmgmt_table_lock(B_FALSE); 10112b24ab6bSSebastien Roy linkp = link_by_id(linkid, zoneid); 1012d62bc4baSyz147064 if ((linkp == NULL) || !(linkp->ll_flags & DLMGMT_PERSIST)) { 10132b24ab6bSSebastien Roy /* The persistent link configuration does not exist. */ 1014d62bc4baSyz147064 err = ENOENT; 1015d62bc4baSyz147064 goto done; 1016d62bc4baSyz147064 } 10172b24ab6bSSebastien Roy if (linkp->ll_onloan && zoneid != GLOBAL_ZONEID) { 10182b24ab6bSSebastien Roy /* 10192b24ab6bSSebastien Roy * The caller is in a non-global zone and the persistent 10202b24ab6bSSebastien Roy * configuration belongs to the global zone. 10212b24ab6bSSebastien Roy */ 10222b24ab6bSSebastien Roy err = EACCES; 10232b24ab6bSSebastien Roy goto done; 10242b24ab6bSSebastien Roy } 1025d62bc4baSyz147064 1026*32715170SCathy Zhou if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0) 1027*32715170SCathy Zhou goto done; 1028*32715170SCathy Zhou 1029d62bc4baSyz147064 if ((err = dlconf_create(linkp->ll_link, linkp->ll_linkid, 10302b24ab6bSSebastien Roy linkp->ll_class, linkp->ll_media, zoneid, &dlconfp)) != 0) 1031d62bc4baSyz147064 goto done; 1032d62bc4baSyz147064 1033d62bc4baSyz147064 for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) { 1034d62bc4baSyz147064 if ((err = linkattr_set(&(dlconfp->ld_head), attrp->lp_name, 1035d62bc4baSyz147064 attrp->lp_val, attrp->lp_sz, attrp->lp_type)) != 0) { 1036d62bc4baSyz147064 dlconf_destroy(dlconfp); 1037d62bc4baSyz147064 goto done; 1038d62bc4baSyz147064 } 1039d62bc4baSyz147064 } 1040d62bc4baSyz147064 dlconfp->ld_gen = linkp->ll_gen; 10412b24ab6bSSebastien Roy avl_add(&dlmgmt_dlconf_avl, dlconfp); 1042d62bc4baSyz147064 dlmgmt_advance_dlconfid(dlconfp); 1043d62bc4baSyz147064 1044*32715170SCathy Zhou retvalp->lr_confid = dlconfp->ld_id; 1045d62bc4baSyz147064 done: 1046d62bc4baSyz147064 dlmgmt_table_unlock(); 1047d62bc4baSyz147064 dlmgmt_dlconf_table_unlock(); 1048d62bc4baSyz147064 retvalp->lr_err = err; 1049d62bc4baSyz147064 } 1050d62bc4baSyz147064 1051d62bc4baSyz147064 /* 1052*32715170SCathy Zhou * dlmgmt_getconfsnapshot() returns a read-only snapshot of all the 1053*32715170SCathy Zhou * configuration, and requires no privileges. 1054*32715170SCathy Zhou * 1055*32715170SCathy Zhou * If the given size cannot hold all the configuration, set the size 1056*32715170SCathy Zhou * that is needed, and return ENOSPC. 1057d62bc4baSyz147064 */ 10582b24ab6bSSebastien Roy /* ARGSUSED */ 1059024b0a25Sseb static void 1060*32715170SCathy Zhou dlmgmt_getconfsnapshot(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 1061*32715170SCathy Zhou ucred_t *cred) 1062*32715170SCathy Zhou { 1063*32715170SCathy Zhou dlmgmt_door_getconfsnapshot_t *snapshot = argp; 1064*32715170SCathy Zhou dlmgmt_getconfsnapshot_retval_t *retvalp = retp; 1065*32715170SCathy Zhou dlmgmt_link_t *linkp; 1066*32715170SCathy Zhou datalink_id_t linkid = snapshot->ld_linkid; 1067*32715170SCathy Zhou dlmgmt_linkattr_t *attrp; 1068*32715170SCathy Zhou char *buf; 1069*32715170SCathy Zhou size_t nvlsz; 1070*32715170SCathy Zhou nvlist_t *nvl = NULL; 1071*32715170SCathy Zhou int err = 0; 1072*32715170SCathy Zhou 1073*32715170SCathy Zhou assert(*sz >= sizeof (dlmgmt_getconfsnapshot_retval_t)); 1074*32715170SCathy Zhou 1075*32715170SCathy Zhou /* 1076*32715170SCathy Zhou * Hold the reader lock to access the link 1077*32715170SCathy Zhou */ 1078*32715170SCathy Zhou dlmgmt_table_lock(B_FALSE); 1079*32715170SCathy Zhou linkp = link_by_id(linkid, zoneid); 1080*32715170SCathy Zhou if ((linkp == NULL) || !(linkp->ll_flags & DLMGMT_PERSIST)) { 1081*32715170SCathy Zhou /* The persistent link configuration does not exist. */ 1082*32715170SCathy Zhou err = ENOENT; 1083*32715170SCathy Zhou goto done; 1084*32715170SCathy Zhou } 1085*32715170SCathy Zhou if (linkp->ll_onloan && zoneid != GLOBAL_ZONEID) { 1086*32715170SCathy Zhou /* 1087*32715170SCathy Zhou * The caller is in a non-global zone and the persistent 1088*32715170SCathy Zhou * configuration belongs to the global zone. 1089*32715170SCathy Zhou */ 1090*32715170SCathy Zhou err = EACCES; 1091*32715170SCathy Zhou goto done; 1092*32715170SCathy Zhou } 1093*32715170SCathy Zhou 1094*32715170SCathy Zhou err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0); 1095*32715170SCathy Zhou if (err != 0) 1096*32715170SCathy Zhou goto done; 1097*32715170SCathy Zhou 1098*32715170SCathy Zhou for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) { 1099*32715170SCathy Zhou if ((err = nvlist_add_byte_array(nvl, attrp->lp_name, 1100*32715170SCathy Zhou attrp->lp_val, attrp->lp_sz)) != 0) { 1101*32715170SCathy Zhou goto done; 1102*32715170SCathy Zhou } 1103*32715170SCathy Zhou } 1104*32715170SCathy Zhou 1105*32715170SCathy Zhou if ((err = nvlist_size(nvl, &nvlsz, NV_ENCODE_NATIVE)) != 0) 1106*32715170SCathy Zhou goto done; 1107*32715170SCathy Zhou 1108*32715170SCathy Zhou if (nvlsz + sizeof (dlmgmt_getconfsnapshot_retval_t) > *sz) { 1109*32715170SCathy Zhou *sz = nvlsz + sizeof (dlmgmt_getconfsnapshot_retval_t); 1110*32715170SCathy Zhou err = ENOSPC; 1111*32715170SCathy Zhou goto done; 1112*32715170SCathy Zhou } 1113*32715170SCathy Zhou 1114*32715170SCathy Zhou /* 1115*32715170SCathy Zhou * pack the the nvlist into the return value. 1116*32715170SCathy Zhou */ 1117*32715170SCathy Zhou *sz = nvlsz + sizeof (dlmgmt_getconfsnapshot_retval_t); 1118*32715170SCathy Zhou retvalp->lr_nvlsz = nvlsz; 1119*32715170SCathy Zhou buf = (char *)retvalp + sizeof (dlmgmt_getconfsnapshot_retval_t); 1120*32715170SCathy Zhou err = nvlist_pack(nvl, &buf, &nvlsz, NV_ENCODE_NATIVE, 0); 1121*32715170SCathy Zhou 1122*32715170SCathy Zhou done: 1123*32715170SCathy Zhou dlmgmt_table_unlock(); 1124*32715170SCathy Zhou nvlist_free(nvl); 1125*32715170SCathy Zhou retvalp->lr_err = err; 1126*32715170SCathy Zhou } 1127*32715170SCathy Zhou 1128*32715170SCathy Zhou /* ARGSUSED */ 1129*32715170SCathy Zhou static void 1130*32715170SCathy Zhou dlmgmt_getattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 1131*32715170SCathy Zhou ucred_t *cred) 1132d62bc4baSyz147064 { 1133024b0a25Sseb dlmgmt_door_getattr_t *getattr = argp; 1134024b0a25Sseb dlmgmt_getattr_retval_t *retvalp = retp; 1135d62bc4baSyz147064 dlmgmt_dlconf_t dlconf, *dlconfp; 1136*32715170SCathy Zhou int err; 1137d62bc4baSyz147064 1138d62bc4baSyz147064 /* 1139024b0a25Sseb * Hold the read lock to access the dlconf table. 1140d62bc4baSyz147064 */ 1141d62bc4baSyz147064 dlmgmt_dlconf_table_lock(B_FALSE); 1142d62bc4baSyz147064 1143*32715170SCathy Zhou dlconf.ld_id = getattr->ld_confid; 11442b24ab6bSSebastien Roy if ((dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL)) == NULL || 11452b24ab6bSSebastien Roy zoneid != dlconfp->ld_zoneid) { 1146024b0a25Sseb retvalp->lr_err = ENOENT; 11472b24ab6bSSebastien Roy } else { 1148*32715170SCathy Zhou if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0) { 1149*32715170SCathy Zhou retvalp->lr_err = err; 1150*32715170SCathy Zhou } else { 1151*32715170SCathy Zhou retvalp->lr_err = dlmgmt_getattr_common( 1152*32715170SCathy Zhou &dlconfp->ld_head, getattr->ld_attr, retvalp); 1153*32715170SCathy Zhou } 1154d62bc4baSyz147064 } 1155d62bc4baSyz147064 1156d62bc4baSyz147064 dlmgmt_dlconf_table_unlock(); 1157d62bc4baSyz147064 } 1158d62bc4baSyz147064 1159*32715170SCathy Zhou /* ARGSUSED */ 116030890389Sartem static void 1161*32715170SCathy Zhou dlmgmt_upcall_linkprop_init(void *argp, void *retp, size_t *sz, 1162*32715170SCathy Zhou zoneid_t zoneid, ucred_t *cred) 116330890389Sartem { 116430890389Sartem dlmgmt_door_linkprop_init_t *lip = argp; 116530890389Sartem dlmgmt_linkprop_init_retval_t *retvalp = retp; 11662b24ab6bSSebastien Roy dlmgmt_link_t *linkp; 11672b24ab6bSSebastien Roy int err; 116830890389Sartem 116930890389Sartem dlmgmt_table_lock(B_FALSE); 11702b24ab6bSSebastien Roy if ((linkp = link_by_id(lip->ld_linkid, zoneid)) == NULL) 11712b24ab6bSSebastien Roy err = ENOENT; 117230890389Sartem else 11732b24ab6bSSebastien Roy err = dlmgmt_checkprivs(linkp->ll_class, cred); 117430890389Sartem dlmgmt_table_unlock(); 117530890389Sartem 11768d4cf8d8S if (err == 0) { 11778d4cf8d8S dladm_status_t s; 11788d4cf8d8S char buf[DLADM_STRSIZE]; 11798d4cf8d8S 11808d4cf8d8S s = dladm_init_linkprop(dld_handle, lip->ld_linkid, B_TRUE); 11818d4cf8d8S if (s != DLADM_STATUS_OK) { 11828d4cf8d8S dlmgmt_log(LOG_WARNING, 11838d4cf8d8S "linkprop initialization failed on link %d: %s", 11848d4cf8d8S lip->ld_linkid, dladm_status2str(s, buf)); 11858d4cf8d8S err = EINVAL; 11868d4cf8d8S } 11878d4cf8d8S } 11882b24ab6bSSebastien Roy retvalp->lr_err = err; 118930890389Sartem } 119030890389Sartem 11912b24ab6bSSebastien Roy /* ARGSUSED */ 119262ee1d25SArtem Kachitchkine static void 1193*32715170SCathy Zhou dlmgmt_setzoneid(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 1194*32715170SCathy Zhou ucred_t *cred) 11952b24ab6bSSebastien Roy { 11962b24ab6bSSebastien Roy dlmgmt_door_setzoneid_t *setzoneid = argp; 11972b24ab6bSSebastien Roy dlmgmt_setzoneid_retval_t *retvalp = retp; 11982b24ab6bSSebastien Roy dlmgmt_link_t *linkp; 11992b24ab6bSSebastien Roy datalink_id_t linkid = setzoneid->ld_linkid; 12002b24ab6bSSebastien Roy zoneid_t oldzoneid, newzoneid; 12012b24ab6bSSebastien Roy int err = 0; 12022b24ab6bSSebastien Roy 12032b24ab6bSSebastien Roy dlmgmt_table_lock(B_TRUE); 12042b24ab6bSSebastien Roy 12052b24ab6bSSebastien Roy /* We currently only allow changing zoneid's from the global zone. */ 12062b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) { 12072b24ab6bSSebastien Roy err = EACCES; 12082b24ab6bSSebastien Roy goto done; 12092b24ab6bSSebastien Roy } 12102b24ab6bSSebastien Roy 12112b24ab6bSSebastien Roy if ((linkp = link_by_id(linkid, zoneid)) == NULL) { 12122b24ab6bSSebastien Roy err = ENOENT; 12132b24ab6bSSebastien Roy goto done; 12142b24ab6bSSebastien Roy } 12152b24ab6bSSebastien Roy 12162b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0) 12172b24ab6bSSebastien Roy goto done; 12182b24ab6bSSebastien Roy 12192b24ab6bSSebastien Roy /* We can only assign an active link to a zone. */ 12202b24ab6bSSebastien Roy if (!(linkp->ll_flags & DLMGMT_ACTIVE)) { 12212b24ab6bSSebastien Roy err = EINVAL; 12222b24ab6bSSebastien Roy goto done; 12232b24ab6bSSebastien Roy } 12242b24ab6bSSebastien Roy 12252b24ab6bSSebastien Roy oldzoneid = linkp->ll_zoneid; 12262b24ab6bSSebastien Roy newzoneid = setzoneid->ld_zoneid; 12272b24ab6bSSebastien Roy 12282b24ab6bSSebastien Roy if (oldzoneid == newzoneid) 12292b24ab6bSSebastien Roy goto done; 12302b24ab6bSSebastien Roy 12312b24ab6bSSebastien Roy /* 12322b24ab6bSSebastien Roy * Before we remove the link from its current zone, make sure that 12332b24ab6bSSebastien Roy * there isn't a link with the same name in the destination zone. 12342b24ab6bSSebastien Roy */ 12352b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID && 12362b24ab6bSSebastien Roy link_by_name(linkp->ll_link, newzoneid) != NULL) { 12372b24ab6bSSebastien Roy err = EEXIST; 12382b24ab6bSSebastien Roy goto done; 12392b24ab6bSSebastien Roy } 12402b24ab6bSSebastien Roy 12412b24ab6bSSebastien Roy if (oldzoneid != GLOBAL_ZONEID) { 12422b24ab6bSSebastien Roy if (zone_remove_datalink(oldzoneid, linkid) != 0) { 12432b24ab6bSSebastien Roy err = errno; 12442b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "unable to remove link %d from " 12452b24ab6bSSebastien Roy "zone %d: %s", linkid, oldzoneid, strerror(err)); 12462b24ab6bSSebastien Roy goto done; 12472b24ab6bSSebastien Roy } 12482b24ab6bSSebastien Roy avl_remove(&dlmgmt_loan_avl, linkp); 12492b24ab6bSSebastien Roy linkp->ll_onloan = B_FALSE; 12502b24ab6bSSebastien Roy } 12512b24ab6bSSebastien Roy if (newzoneid != GLOBAL_ZONEID) { 12522b24ab6bSSebastien Roy if (zone_add_datalink(newzoneid, linkid) != 0) { 12532b24ab6bSSebastien Roy err = errno; 12542b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "unable to add link %d to zone " 12552b24ab6bSSebastien Roy "%d: %s", linkid, newzoneid, strerror(err)); 12562b24ab6bSSebastien Roy (void) zone_add_datalink(oldzoneid, linkid); 12572b24ab6bSSebastien Roy goto done; 12582b24ab6bSSebastien Roy } 12592b24ab6bSSebastien Roy avl_add(&dlmgmt_loan_avl, linkp); 12602b24ab6bSSebastien Roy linkp->ll_onloan = B_TRUE; 12612b24ab6bSSebastien Roy } 12622b24ab6bSSebastien Roy 12632b24ab6bSSebastien Roy avl_remove(&dlmgmt_name_avl, linkp); 12642b24ab6bSSebastien Roy linkp->ll_zoneid = newzoneid; 12652b24ab6bSSebastien Roy avl_add(&dlmgmt_name_avl, linkp); 12662b24ab6bSSebastien Roy 12672b24ab6bSSebastien Roy done: 12682b24ab6bSSebastien Roy dlmgmt_table_unlock(); 12692b24ab6bSSebastien Roy retvalp->lr_err = err; 12702b24ab6bSSebastien Roy } 12712b24ab6bSSebastien Roy 1272*32715170SCathy Zhou /* ARGSUSED */ 12732b24ab6bSSebastien Roy static void 1274*32715170SCathy Zhou dlmgmt_zoneboot(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 1275*32715170SCathy Zhou ucred_t *cred) 12762b24ab6bSSebastien Roy { 12772b24ab6bSSebastien Roy int err; 12782b24ab6bSSebastien Roy dlmgmt_door_zoneboot_t *zoneboot = argp; 12792b24ab6bSSebastien Roy dlmgmt_zoneboot_retval_t *retvalp = retp; 12802b24ab6bSSebastien Roy 12812b24ab6bSSebastien Roy dlmgmt_table_lock(B_TRUE); 12822b24ab6bSSebastien Roy 12832b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(0, cred)) != 0) 12842b24ab6bSSebastien Roy goto done; 12852b24ab6bSSebastien Roy 12862b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) { 12872b24ab6bSSebastien Roy err = EACCES; 12882b24ab6bSSebastien Roy goto done; 12892b24ab6bSSebastien Roy } 12902b24ab6bSSebastien Roy if (zoneboot->ld_zoneid == GLOBAL_ZONEID) { 12912b24ab6bSSebastien Roy err = EINVAL; 12922b24ab6bSSebastien Roy goto done; 12932b24ab6bSSebastien Roy } 12942b24ab6bSSebastien Roy 12952b24ab6bSSebastien Roy if ((err = dlmgmt_elevate_privileges()) == 0) { 12962b24ab6bSSebastien Roy err = dlmgmt_zone_init(zoneboot->ld_zoneid); 12972b24ab6bSSebastien Roy (void) dlmgmt_drop_privileges(); 12982b24ab6bSSebastien Roy } 12992b24ab6bSSebastien Roy done: 13002b24ab6bSSebastien Roy dlmgmt_table_unlock(); 13012b24ab6bSSebastien Roy retvalp->lr_err = err; 13022b24ab6bSSebastien Roy } 13032b24ab6bSSebastien Roy 1304*32715170SCathy Zhou /* ARGSUSED */ 13052b24ab6bSSebastien Roy static void 1306*32715170SCathy Zhou dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid, 1307*32715170SCathy Zhou ucred_t *cred) 13082b24ab6bSSebastien Roy { 13092b24ab6bSSebastien Roy int err = 0; 13102b24ab6bSSebastien Roy dlmgmt_door_zonehalt_t *zonehalt = argp; 13112b24ab6bSSebastien Roy dlmgmt_zonehalt_retval_t *retvalp = retp; 13122b24ab6bSSebastien Roy 13132b24ab6bSSebastien Roy if ((err = dlmgmt_checkprivs(0, cred)) == 0) { 13142b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID) { 13152b24ab6bSSebastien Roy err = EACCES; 13162b24ab6bSSebastien Roy } else if (zonehalt->ld_zoneid == GLOBAL_ZONEID) { 13172b24ab6bSSebastien Roy err = EINVAL; 13182b24ab6bSSebastien Roy } else { 13192b24ab6bSSebastien Roy dlmgmt_table_lock(B_TRUE); 13202b24ab6bSSebastien Roy dlmgmt_db_fini(zonehalt->ld_zoneid); 13212b24ab6bSSebastien Roy dlmgmt_table_unlock(); 13222b24ab6bSSebastien Roy } 13232b24ab6bSSebastien Roy } 13242b24ab6bSSebastien Roy retvalp->lr_err = err; 13252b24ab6bSSebastien Roy } 13262b24ab6bSSebastien Roy 1327024b0a25Sseb static dlmgmt_door_info_t i_dlmgmt_door_info_tbl[] = { 13282b24ab6bSSebastien Roy { DLMGMT_CMD_DLS_CREATE, sizeof (dlmgmt_upcall_arg_create_t), 1329024b0a25Sseb sizeof (dlmgmt_create_retval_t), dlmgmt_upcall_create }, 13302b24ab6bSSebastien Roy { DLMGMT_CMD_DLS_GETATTR, sizeof (dlmgmt_upcall_arg_getattr_t), 1331024b0a25Sseb sizeof (dlmgmt_getattr_retval_t), dlmgmt_upcall_getattr }, 13322b24ab6bSSebastien Roy { DLMGMT_CMD_DLS_DESTROY, sizeof (dlmgmt_upcall_arg_destroy_t), 1333024b0a25Sseb sizeof (dlmgmt_destroy_retval_t), dlmgmt_upcall_destroy }, 13342b24ab6bSSebastien Roy { DLMGMT_CMD_GETNAME, sizeof (dlmgmt_door_getname_t), 1335024b0a25Sseb sizeof (dlmgmt_getname_retval_t), dlmgmt_getname }, 13362b24ab6bSSebastien Roy { DLMGMT_CMD_GETLINKID, sizeof (dlmgmt_door_getlinkid_t), 1337024b0a25Sseb sizeof (dlmgmt_getlinkid_retval_t), dlmgmt_getlinkid }, 13382b24ab6bSSebastien Roy { DLMGMT_CMD_GETNEXT, sizeof (dlmgmt_door_getnext_t), 1339024b0a25Sseb sizeof (dlmgmt_getnext_retval_t), dlmgmt_getnext }, 13402b24ab6bSSebastien Roy { DLMGMT_CMD_DLS_UPDATE, sizeof (dlmgmt_upcall_arg_update_t), 1341024b0a25Sseb sizeof (dlmgmt_update_retval_t), dlmgmt_upcall_update }, 13422b24ab6bSSebastien Roy { DLMGMT_CMD_CREATE_LINKID, sizeof (dlmgmt_door_createid_t), 1343024b0a25Sseb sizeof (dlmgmt_createid_retval_t), dlmgmt_createid }, 13442b24ab6bSSebastien Roy { DLMGMT_CMD_DESTROY_LINKID, sizeof (dlmgmt_door_destroyid_t), 1345024b0a25Sseb sizeof (dlmgmt_destroyid_retval_t), dlmgmt_destroyid }, 13462b24ab6bSSebastien Roy { DLMGMT_CMD_REMAP_LINKID, sizeof (dlmgmt_door_remapid_t), 1347024b0a25Sseb sizeof (dlmgmt_remapid_retval_t), dlmgmt_remapid }, 13482b24ab6bSSebastien Roy { DLMGMT_CMD_CREATECONF, sizeof (dlmgmt_door_createconf_t), 1349024b0a25Sseb sizeof (dlmgmt_createconf_retval_t), dlmgmt_createconf }, 1350*32715170SCathy Zhou { DLMGMT_CMD_OPENCONF, sizeof (dlmgmt_door_openconf_t), 1351*32715170SCathy Zhou sizeof (dlmgmt_openconf_retval_t), dlmgmt_openconf }, 13522b24ab6bSSebastien Roy { DLMGMT_CMD_WRITECONF, sizeof (dlmgmt_door_writeconf_t), 1353024b0a25Sseb sizeof (dlmgmt_writeconf_retval_t), dlmgmt_writeconf }, 13542b24ab6bSSebastien Roy { DLMGMT_CMD_UP_LINKID, sizeof (dlmgmt_door_upid_t), 1355024b0a25Sseb sizeof (dlmgmt_upid_retval_t), dlmgmt_upid }, 13562b24ab6bSSebastien Roy { DLMGMT_CMD_SETATTR, sizeof (dlmgmt_door_setattr_t), 1357024b0a25Sseb sizeof (dlmgmt_setattr_retval_t), dlmgmt_setattr }, 13582b24ab6bSSebastien Roy { DLMGMT_CMD_UNSETATTR, sizeof (dlmgmt_door_unsetattr_t), 1359024b0a25Sseb sizeof (dlmgmt_unsetattr_retval_t), dlmgmt_unsetconfattr }, 13602b24ab6bSSebastien Roy { DLMGMT_CMD_REMOVECONF, sizeof (dlmgmt_door_removeconf_t), 1361024b0a25Sseb sizeof (dlmgmt_removeconf_retval_t), dlmgmt_removeconf }, 13622b24ab6bSSebastien Roy { DLMGMT_CMD_DESTROYCONF, sizeof (dlmgmt_door_destroyconf_t), 1363024b0a25Sseb sizeof (dlmgmt_destroyconf_retval_t), dlmgmt_destroyconf }, 13642b24ab6bSSebastien Roy { DLMGMT_CMD_GETATTR, sizeof (dlmgmt_door_getattr_t), 136530890389Sartem sizeof (dlmgmt_getattr_retval_t), dlmgmt_getattr }, 1366*32715170SCathy Zhou { DLMGMT_CMD_GETCONFSNAPSHOT, sizeof (dlmgmt_door_getconfsnapshot_t), 1367*32715170SCathy Zhou sizeof (dlmgmt_getconfsnapshot_retval_t), dlmgmt_getconfsnapshot }, 13682b24ab6bSSebastien Roy { DLMGMT_CMD_LINKPROP_INIT, sizeof (dlmgmt_door_linkprop_init_t), 136930890389Sartem sizeof (dlmgmt_linkprop_init_retval_t), 137062ee1d25SArtem Kachitchkine dlmgmt_upcall_linkprop_init }, 13712b24ab6bSSebastien Roy { DLMGMT_CMD_SETZONEID, sizeof (dlmgmt_door_setzoneid_t), 13722b24ab6bSSebastien Roy sizeof (dlmgmt_setzoneid_retval_t), dlmgmt_setzoneid }, 13732b24ab6bSSebastien Roy { DLMGMT_CMD_ZONEBOOT, sizeof (dlmgmt_door_zoneboot_t), 13742b24ab6bSSebastien Roy sizeof (dlmgmt_zoneboot_retval_t), dlmgmt_zoneboot }, 13752b24ab6bSSebastien Roy { DLMGMT_CMD_ZONEHALT, sizeof (dlmgmt_door_zonehalt_t), 13762b24ab6bSSebastien Roy sizeof (dlmgmt_zonehalt_retval_t), dlmgmt_zonehalt }, 13772b24ab6bSSebastien Roy { 0, 0, 0, NULL } 1378024b0a25Sseb }; 1379d62bc4baSyz147064 13802b24ab6bSSebastien Roy static dlmgmt_door_info_t * 13812b24ab6bSSebastien Roy dlmgmt_getcmdinfo(int cmd) 13822b24ab6bSSebastien Roy { 13832b24ab6bSSebastien Roy dlmgmt_door_info_t *infop = i_dlmgmt_door_info_tbl; 13842b24ab6bSSebastien Roy 13852b24ab6bSSebastien Roy while (infop->di_handler != NULL) { 13862b24ab6bSSebastien Roy if (infop->di_cmd == cmd) 13872b24ab6bSSebastien Roy break; 13882b24ab6bSSebastien Roy infop++; 13892b24ab6bSSebastien Roy } 13902b24ab6bSSebastien Roy return (infop); 13912b24ab6bSSebastien Roy } 1392d62bc4baSyz147064 1393d62bc4baSyz147064 /* ARGSUSED */ 1394d62bc4baSyz147064 void 1395d62bc4baSyz147064 dlmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp, 1396d62bc4baSyz147064 uint_t n_desc) 1397d62bc4baSyz147064 { 13982b24ab6bSSebastien Roy dlmgmt_door_arg_t *door_arg = (dlmgmt_door_arg_t *)(void *)argp; 1399024b0a25Sseb dlmgmt_door_info_t *infop = NULL; 1400024b0a25Sseb dlmgmt_retval_t retval; 14012b24ab6bSSebastien Roy ucred_t *cred = NULL; 14022b24ab6bSSebastien Roy zoneid_t zoneid; 1403*32715170SCathy Zhou void *retvalp = NULL; 1404*32715170SCathy Zhou size_t sz, acksz; 1405eae72b5bSSebastien Roy int err = 0; 1406d62bc4baSyz147064 14072b24ab6bSSebastien Roy infop = dlmgmt_getcmdinfo(door_arg->ld_cmd); 1408024b0a25Sseb if (infop == NULL || argsz != infop->di_reqsz) { 1409024b0a25Sseb err = EINVAL; 14102b24ab6bSSebastien Roy goto done; 1411024b0a25Sseb } 1412024b0a25Sseb 14132b24ab6bSSebastien Roy if (door_ucred(&cred) != 0 || (zoneid = ucred_getzoneid(cred)) == -1) { 1414024b0a25Sseb err = errno; 14152b24ab6bSSebastien Roy goto done; 1416024b0a25Sseb } 1417024b0a25Sseb 1418024b0a25Sseb /* 1419*32715170SCathy Zhou * Note that malloc() cannot be used here because door_return 1420*32715170SCathy Zhou * never returns, and memory allocated by malloc() would get leaked. 1421*32715170SCathy Zhou * Use alloca() instead. 1422024b0a25Sseb */ 1423*32715170SCathy Zhou acksz = infop->di_acksz; 1424*32715170SCathy Zhou 1425*32715170SCathy Zhou again: 1426*32715170SCathy Zhou retvalp = alloca(acksz); 1427*32715170SCathy Zhou sz = acksz; 1428*32715170SCathy Zhou infop->di_handler(argp, retvalp, &acksz, zoneid, cred); 1429*32715170SCathy Zhou if (acksz > sz) { 1430*32715170SCathy Zhou /* 1431*32715170SCathy Zhou * If the specified buffer size is not big enough to hold the 1432*32715170SCathy Zhou * return value, reallocate the buffer and try to get the 1433*32715170SCathy Zhou * result one more time. 1434*32715170SCathy Zhou */ 1435*32715170SCathy Zhou assert(((dlmgmt_retval_t *)retvalp)->lr_err == ENOSPC); 1436*32715170SCathy Zhou goto again; 1437*32715170SCathy Zhou } 1438024b0a25Sseb 14392b24ab6bSSebastien Roy done: 14402b24ab6bSSebastien Roy if (cred != NULL) 14412b24ab6bSSebastien Roy ucred_free(cred); 14422b24ab6bSSebastien Roy if (err == 0) { 1443*32715170SCathy Zhou (void) door_return(retvalp, acksz, NULL, 0); 14442b24ab6bSSebastien Roy } else { 1445024b0a25Sseb retval.lr_err = err; 1446024b0a25Sseb (void) door_return((char *)&retval, sizeof (retval), NULL, 0); 1447024b0a25Sseb } 14482b24ab6bSSebastien Roy } 1449