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 /* 2232715170SCathy Zhou * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23d62bc4baSyz147064 */ 24d62bc4baSyz147064 25d62bc4baSyz147064 #include <door.h> 26d62bc4baSyz147064 #include <errno.h> 27d62bc4baSyz147064 #include <assert.h> 28d62bc4baSyz147064 #include <stdio.h> 29d62bc4baSyz147064 #include <stdlib.h> 30d62bc4baSyz147064 #include <unistd.h> 31d62bc4baSyz147064 #include <string.h> 32d62bc4baSyz147064 #include <strings.h> 332b24ab6bSSebastien Roy #include <zone.h> 34d62bc4baSyz147064 #include <sys/types.h> 35d62bc4baSyz147064 #include <sys/stat.h> 36d62bc4baSyz147064 #include <sys/aggr.h> 3782a2fc47SJames Carlson #include <sys/mman.h> 38d62bc4baSyz147064 #include <fcntl.h> 39d62bc4baSyz147064 #include <libdladm.h> 40d62bc4baSyz147064 #include <libdladm_impl.h> 41d62bc4baSyz147064 #include <libdllink.h> 42d62bc4baSyz147064 #include <libdlmgmt.h> 43d62bc4baSyz147064 44d62bc4baSyz147064 /* 45d62bc4baSyz147064 * Table of data type sizes indexed by dladm_datatype_t. 46d62bc4baSyz147064 */ 47d62bc4baSyz147064 static size_t dladm_datatype_size[] = { 48d62bc4baSyz147064 0, /* DLADM_TYPE_STR, use strnlen() */ 49d62bc4baSyz147064 sizeof (boolean_t), /* DLADM_TYPE_BOOLEAN */ 50d62bc4baSyz147064 sizeof (uint64_t) /* DLADM_TYPE_UINT64 */ 51d62bc4baSyz147064 }; 52d62bc4baSyz147064 53d62bc4baSyz147064 static dladm_status_t 544ac67f02SAnurag S. Maskey dladm_door_call(dladm_handle_t handle, void *arg, size_t asize, void *rbuf, 5532715170SCathy Zhou size_t *rsizep) 56d62bc4baSyz147064 { 57d62bc4baSyz147064 door_arg_t darg; 584ac67f02SAnurag S. Maskey int door_fd; 59*f689bed1SRishi Srivatsavai dladm_status_t status; 60*f689bed1SRishi Srivatsavai boolean_t reopen = B_FALSE; 61d62bc4baSyz147064 62d62bc4baSyz147064 darg.data_ptr = arg; 63d62bc4baSyz147064 darg.data_size = asize; 64d62bc4baSyz147064 darg.desc_ptr = NULL; 65d62bc4baSyz147064 darg.desc_num = 0; 66d62bc4baSyz147064 darg.rbuf = rbuf; 6732715170SCathy Zhou darg.rsize = *rsizep; 68d62bc4baSyz147064 69*f689bed1SRishi Srivatsavai reopen: 704ac67f02SAnurag S. Maskey /* The door descriptor is opened if it isn't already */ 714ac67f02SAnurag S. Maskey if ((status = dladm_door_fd(handle, &door_fd)) != DLADM_STATUS_OK) 724ac67f02SAnurag S. Maskey return (status); 73*f689bed1SRishi Srivatsavai if (door_call(door_fd, &darg) == -1) { 74*f689bed1SRishi Srivatsavai /* 75*f689bed1SRishi Srivatsavai * Stale door descriptor is possible if dlmgmtd was re-started 76*f689bed1SRishi Srivatsavai * since last door_fd open so try re-opening door file. 77*f689bed1SRishi Srivatsavai */ 78*f689bed1SRishi Srivatsavai if (!reopen && errno == EBADF) { 79*f689bed1SRishi Srivatsavai (void) close(handle->door_fd); 80*f689bed1SRishi Srivatsavai handle->door_fd = -1; 81*f689bed1SRishi Srivatsavai reopen = B_TRUE; 82*f689bed1SRishi Srivatsavai goto reopen; 83*f689bed1SRishi Srivatsavai } 84d62bc4baSyz147064 status = dladm_errno2status(errno); 85*f689bed1SRishi Srivatsavai } 86d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 87d62bc4baSyz147064 return (status); 88d62bc4baSyz147064 89d62bc4baSyz147064 if (darg.rbuf != rbuf) { 90d62bc4baSyz147064 /* 91d62bc4baSyz147064 * The size of the input rbuf is not big enough so that 9232715170SCathy Zhou * the door allocate the rbuf itself. In this case, return 9332715170SCathy Zhou * the required size to the caller. 94d62bc4baSyz147064 */ 95d62bc4baSyz147064 (void) munmap(darg.rbuf, darg.rsize); 9632715170SCathy Zhou *rsizep = darg.rsize; 97d62bc4baSyz147064 return (DLADM_STATUS_TOOSMALL); 9832715170SCathy Zhou } else if (darg.rsize != *rsizep) { 99d62bc4baSyz147064 return (DLADM_STATUS_FAILED); 10032715170SCathy Zhou } 101d62bc4baSyz147064 102024b0a25Sseb return (dladm_errno2status(((dlmgmt_retval_t *)rbuf)->lr_err)); 103d62bc4baSyz147064 } 104d62bc4baSyz147064 105d62bc4baSyz147064 /* 106d62bc4baSyz147064 * Allocate a new linkid with the given name. Return the new linkid. 107d62bc4baSyz147064 */ 108d62bc4baSyz147064 dladm_status_t 1094ac67f02SAnurag S. Maskey dladm_create_datalink_id(dladm_handle_t handle, const char *link, 1104ac67f02SAnurag S. Maskey datalink_class_t class, uint32_t media, uint32_t flags, 1114ac67f02SAnurag S. Maskey datalink_id_t *linkidp) 112d62bc4baSyz147064 { 113d62bc4baSyz147064 dlmgmt_door_createid_t createid; 114d62bc4baSyz147064 dlmgmt_createid_retval_t retval; 115d62bc4baSyz147064 uint32_t dlmgmt_flags; 116d62bc4baSyz147064 dladm_status_t status; 11732715170SCathy Zhou size_t sz = sizeof (retval); 118d62bc4baSyz147064 119024b0a25Sseb if (link == NULL || class == DATALINK_CLASS_ALL || 120d62bc4baSyz147064 !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) || 121d62bc4baSyz147064 linkidp == NULL) { 122d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 123d62bc4baSyz147064 } 124d62bc4baSyz147064 125d62bc4baSyz147064 dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; 126d62bc4baSyz147064 dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0; 127d62bc4baSyz147064 128d62bc4baSyz147064 (void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN); 129d62bc4baSyz147064 createid.ld_class = class; 130d62bc4baSyz147064 createid.ld_media = media; 131d62bc4baSyz147064 createid.ld_flags = dlmgmt_flags; 132d62bc4baSyz147064 createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID; 133d62bc4baSyz147064 createid.ld_prefix = (flags & DLADM_OPT_PREFIX); 134d62bc4baSyz147064 1354ac67f02SAnurag S. Maskey if ((status = dladm_door_call(handle, &createid, sizeof (createid), 13632715170SCathy Zhou &retval, &sz)) == DLADM_STATUS_OK) { 137d62bc4baSyz147064 *linkidp = retval.lr_linkid; 138024b0a25Sseb } 139024b0a25Sseb return (status); 140d62bc4baSyz147064 } 141d62bc4baSyz147064 142d62bc4baSyz147064 /* 143d62bc4baSyz147064 * Destroy the given link ID. 144d62bc4baSyz147064 */ 145d62bc4baSyz147064 dladm_status_t 1464ac67f02SAnurag S. Maskey dladm_destroy_datalink_id(dladm_handle_t handle, datalink_id_t linkid, 1474ac67f02SAnurag S. Maskey uint32_t flags) 148d62bc4baSyz147064 { 149d62bc4baSyz147064 dlmgmt_door_destroyid_t destroyid; 150d62bc4baSyz147064 dlmgmt_destroyid_retval_t retval; 151d62bc4baSyz147064 uint32_t dlmgmt_flags; 15232715170SCathy Zhou size_t sz = sizeof (retval); 153d62bc4baSyz147064 154d62bc4baSyz147064 dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; 155d62bc4baSyz147064 dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); 156d62bc4baSyz147064 157d62bc4baSyz147064 destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID; 158d62bc4baSyz147064 destroyid.ld_linkid = linkid; 159d62bc4baSyz147064 destroyid.ld_flags = dlmgmt_flags; 160d62bc4baSyz147064 16132715170SCathy Zhou return (dladm_door_call(handle, &destroyid, sizeof (destroyid), 16232715170SCathy Zhou &retval, &sz)); 163d62bc4baSyz147064 } 164d62bc4baSyz147064 165d62bc4baSyz147064 /* 166d62bc4baSyz147064 * Remap a given link ID to a new name. 167d62bc4baSyz147064 */ 168d62bc4baSyz147064 dladm_status_t 1694ac67f02SAnurag S. Maskey dladm_remap_datalink_id(dladm_handle_t handle, datalink_id_t linkid, 1704ac67f02SAnurag S. Maskey const char *link) 171d62bc4baSyz147064 { 172d62bc4baSyz147064 dlmgmt_door_remapid_t remapid; 173d62bc4baSyz147064 dlmgmt_remapid_retval_t retval; 17432715170SCathy Zhou size_t sz = sizeof (retval); 175d62bc4baSyz147064 176d62bc4baSyz147064 remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID; 177d62bc4baSyz147064 remapid.ld_linkid = linkid; 178d62bc4baSyz147064 (void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN); 179d62bc4baSyz147064 18032715170SCathy Zhou return (dladm_door_call(handle, &remapid, sizeof (remapid), 18132715170SCathy Zhou &retval, &sz)); 182d62bc4baSyz147064 } 183d62bc4baSyz147064 184d62bc4baSyz147064 /* 185d62bc4baSyz147064 * Make a given link ID active. 186d62bc4baSyz147064 */ 187d62bc4baSyz147064 dladm_status_t 1884ac67f02SAnurag S. Maskey dladm_up_datalink_id(dladm_handle_t handle, datalink_id_t linkid) 189d62bc4baSyz147064 { 190d62bc4baSyz147064 dlmgmt_door_upid_t upid; 191d62bc4baSyz147064 dlmgmt_upid_retval_t retval; 19232715170SCathy Zhou size_t sz = sizeof (retval); 193d62bc4baSyz147064 194d62bc4baSyz147064 upid.ld_cmd = DLMGMT_CMD_UP_LINKID; 195d62bc4baSyz147064 upid.ld_linkid = linkid; 196d62bc4baSyz147064 19732715170SCathy Zhou return (dladm_door_call(handle, &upid, sizeof (upid), &retval, &sz)); 198d62bc4baSyz147064 } 199d62bc4baSyz147064 200d62bc4baSyz147064 /* 201d62bc4baSyz147064 * Create a new link with the given name. Return the new link's handle 202d62bc4baSyz147064 */ 203d62bc4baSyz147064 dladm_status_t 2044ac67f02SAnurag S. Maskey dladm_create_conf(dladm_handle_t handle, const char *link, datalink_id_t linkid, 205d62bc4baSyz147064 datalink_class_t class, uint32_t media, dladm_conf_t *confp) 206d62bc4baSyz147064 { 207d62bc4baSyz147064 dlmgmt_door_createconf_t createconf; 208d62bc4baSyz147064 dlmgmt_createconf_retval_t retval; 209d62bc4baSyz147064 dladm_status_t status; 21032715170SCathy Zhou size_t sz = sizeof (retval); 211d62bc4baSyz147064 212024b0a25Sseb if (link == NULL || confp == NULL) 213d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 214d62bc4baSyz147064 215d62bc4baSyz147064 (void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN); 216d62bc4baSyz147064 createconf.ld_class = class; 217d62bc4baSyz147064 createconf.ld_media = media; 218d62bc4baSyz147064 createconf.ld_linkid = linkid; 219d62bc4baSyz147064 createconf.ld_cmd = DLMGMT_CMD_CREATECONF; 22032715170SCathy Zhou confp->ds_confid = DLADM_INVALID_CONF; 221d62bc4baSyz147064 2224ac67f02SAnurag S. Maskey if ((status = dladm_door_call(handle, &createconf, sizeof (createconf), 22332715170SCathy Zhou &retval, &sz)) == DLADM_STATUS_OK) { 22432715170SCathy Zhou confp->ds_readonly = B_FALSE; 22532715170SCathy Zhou confp->ds_confid = retval.lr_confid; 226024b0a25Sseb } 227024b0a25Sseb return (status); 228d62bc4baSyz147064 } 229d62bc4baSyz147064 230d62bc4baSyz147064 /* 231d62bc4baSyz147064 * An active physical link reported by the dlmgmtd daemon might not be active 232d62bc4baSyz147064 * anymore as this link might be removed during system shutdown. Check its 233d62bc4baSyz147064 * real status by calling dladm_phys_info(). 234d62bc4baSyz147064 */ 235d62bc4baSyz147064 dladm_status_t 2364ac67f02SAnurag S. Maskey i_dladm_phys_status(dladm_handle_t handle, datalink_id_t linkid, 2374ac67f02SAnurag S. Maskey uint32_t *flagsp) 238d62bc4baSyz147064 { 239d62bc4baSyz147064 dladm_phys_attr_t dpa; 240d62bc4baSyz147064 dladm_status_t status; 241d62bc4baSyz147064 242d62bc4baSyz147064 assert((*flagsp) & DLMGMT_ACTIVE); 243d62bc4baSyz147064 2444ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE); 245d62bc4baSyz147064 if (status == DLADM_STATUS_NOTFOUND) { 246d62bc4baSyz147064 /* 247d62bc4baSyz147064 * No active status, this link was removed. Update its status 248d62bc4baSyz147064 * in the daemon and delete all active linkprops. 2492d4eecfaSCathy Zhou * 2502d4eecfaSCathy Zhou * Note that the operation could fail. If it does, return 2512d4eecfaSCathy Zhou * failure now since otherwise dladm_set_linkprop() might 2522d4eecfaSCathy Zhou * call back to i_dladm_phys_status() recursively. 253d62bc4baSyz147064 */ 2544ac67f02SAnurag S. Maskey if ((status = dladm_destroy_datalink_id(handle, linkid, 2554ac67f02SAnurag S. Maskey DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) 2562d4eecfaSCathy Zhou return (status); 2572d4eecfaSCathy Zhou 2584ac67f02SAnurag S. Maskey (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 259d62bc4baSyz147064 DLADM_OPT_ACTIVE); 260d62bc4baSyz147064 261d62bc4baSyz147064 (*flagsp) &= ~DLMGMT_ACTIVE; 262d62bc4baSyz147064 status = DLADM_STATUS_OK; 263d62bc4baSyz147064 } 264d62bc4baSyz147064 return (status); 265d62bc4baSyz147064 } 266d62bc4baSyz147064 267d62bc4baSyz147064 /* 268d62bc4baSyz147064 * Walk each entry in the data link configuration repository and 269d62bc4baSyz147064 * call fn on the linkid and arg. 270d62bc4baSyz147064 */ 271d62bc4baSyz147064 dladm_status_t 2724ac67f02SAnurag S. Maskey dladm_walk_datalink_id(int (*fn)(dladm_handle_t, datalink_id_t, void *), 2734ac67f02SAnurag S. Maskey dladm_handle_t handle, void *argp, datalink_class_t class, 2744ac67f02SAnurag S. Maskey datalink_media_t dmedia, uint32_t flags) 275d62bc4baSyz147064 { 276d62bc4baSyz147064 dlmgmt_door_getnext_t getnext; 277d62bc4baSyz147064 dlmgmt_getnext_retval_t retval; 278d62bc4baSyz147064 uint32_t dlmgmt_flags; 279d62bc4baSyz147064 datalink_id_t linkid = DATALINK_INVALID_LINKID; 280d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 28132715170SCathy Zhou size_t sz = sizeof (retval); 282d62bc4baSyz147064 283d62bc4baSyz147064 if (fn == NULL) 284d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 285d62bc4baSyz147064 286d62bc4baSyz147064 dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; 287d62bc4baSyz147064 dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); 288d62bc4baSyz147064 289d62bc4baSyz147064 getnext.ld_cmd = DLMGMT_CMD_GETNEXT; 290d62bc4baSyz147064 getnext.ld_class = class; 291d62bc4baSyz147064 getnext.ld_dmedia = dmedia; 292d62bc4baSyz147064 getnext.ld_flags = dlmgmt_flags; 293d62bc4baSyz147064 294d62bc4baSyz147064 do { 295d62bc4baSyz147064 getnext.ld_linkid = linkid; 2964ac67f02SAnurag S. Maskey if ((status = dladm_door_call(handle, &getnext, 29732715170SCathy Zhou sizeof (getnext), &retval, &sz)) != DLADM_STATUS_OK) { 298d62bc4baSyz147064 /* 2997363c184SCathy Zhou * Done with walking. If no next datalink is found, 3007363c184SCathy Zhou * return success. 301d62bc4baSyz147064 */ 3027363c184SCathy Zhou if (status == DLADM_STATUS_NOTFOUND) 3037363c184SCathy Zhou status = DLADM_STATUS_OK; 304d62bc4baSyz147064 break; 305d62bc4baSyz147064 } 306d62bc4baSyz147064 307d62bc4baSyz147064 linkid = retval.lr_linkid; 308d62bc4baSyz147064 if ((retval.lr_class == DATALINK_CLASS_PHYS) && 309d62bc4baSyz147064 (retval.lr_flags & DLMGMT_ACTIVE)) { 310d62bc4baSyz147064 /* 311d62bc4baSyz147064 * An active physical link reported by the dlmgmtd 312d62bc4baSyz147064 * daemon might not be active anymore. Check its 313d62bc4baSyz147064 * real status. 314d62bc4baSyz147064 */ 3154ac67f02SAnurag S. Maskey if (i_dladm_phys_status(handle, linkid, 3164ac67f02SAnurag S. Maskey &retval.lr_flags) != DLADM_STATUS_OK) { 317d62bc4baSyz147064 continue; 318d62bc4baSyz147064 } 319d62bc4baSyz147064 320d62bc4baSyz147064 if (!(dlmgmt_flags & retval.lr_flags)) 321d62bc4baSyz147064 continue; 322d62bc4baSyz147064 } 323d62bc4baSyz147064 3244ac67f02SAnurag S. Maskey if (fn(handle, linkid, argp) == DLADM_WALK_TERMINATE) 325d62bc4baSyz147064 break; 326d62bc4baSyz147064 } while (linkid != DATALINK_INVALID_LINKID); 327d62bc4baSyz147064 328d62bc4baSyz147064 return (status); 329d62bc4baSyz147064 } 330d62bc4baSyz147064 331d62bc4baSyz147064 /* 33232715170SCathy Zhou * Get a handle of a copy of the link configuration (kept in the daemon) 33332715170SCathy Zhou * for the given link so it can be updated later by dladm_write_conf(). 334d62bc4baSyz147064 */ 335d62bc4baSyz147064 dladm_status_t 33632715170SCathy Zhou dladm_open_conf(dladm_handle_t handle, datalink_id_t linkid, 3374ac67f02SAnurag S. Maskey dladm_conf_t *confp) 338d62bc4baSyz147064 { 33932715170SCathy Zhou dlmgmt_door_openconf_t openconf; 34032715170SCathy Zhou dlmgmt_openconf_retval_t retval; 341d62bc4baSyz147064 dladm_status_t status; 34232715170SCathy Zhou size_t sz; 343d62bc4baSyz147064 344d62bc4baSyz147064 if (linkid == DATALINK_INVALID_LINKID || confp == NULL) 345d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 346d62bc4baSyz147064 34732715170SCathy Zhou sz = sizeof (retval); 34832715170SCathy Zhou openconf.ld_linkid = linkid; 34932715170SCathy Zhou openconf.ld_cmd = DLMGMT_CMD_OPENCONF; 35032715170SCathy Zhou confp->ds_confid = DLADM_INVALID_CONF; 35132715170SCathy Zhou if ((status = dladm_door_call(handle, &openconf, 35232715170SCathy Zhou sizeof (openconf), &retval, &sz)) == DLADM_STATUS_OK) { 35332715170SCathy Zhou confp->ds_readonly = B_FALSE; 35432715170SCathy Zhou confp->ds_confid = retval.lr_confid; 355024b0a25Sseb } 35632715170SCathy Zhou 35732715170SCathy Zhou return (status); 35832715170SCathy Zhou } 35932715170SCathy Zhou 36032715170SCathy Zhou /* 36132715170SCathy Zhou * Get the handle of a local snapshot of the link configuration. Note that 36232715170SCathy Zhou * any operations with this handle are read-only, i.e., one can not update 36332715170SCathy Zhou * the configuration with this handle. 36432715170SCathy Zhou */ 36532715170SCathy Zhou dladm_status_t 36632715170SCathy Zhou dladm_getsnap_conf(dladm_handle_t handle, datalink_id_t linkid, 36732715170SCathy Zhou dladm_conf_t *confp) 36832715170SCathy Zhou { 36932715170SCathy Zhou dlmgmt_door_getconfsnapshot_t snapshot; 37032715170SCathy Zhou dlmgmt_getconfsnapshot_retval_t *retvalp; 37132715170SCathy Zhou char *nvlbuf; 37232715170SCathy Zhou dladm_status_t status; 37332715170SCathy Zhou int err; 37432715170SCathy Zhou size_t sz; 37532715170SCathy Zhou 37632715170SCathy Zhou if (linkid == DATALINK_INVALID_LINKID || confp == NULL) 37732715170SCathy Zhou return (DLADM_STATUS_BADARG); 37832715170SCathy Zhou 37932715170SCathy Zhou sz = sizeof (dlmgmt_getconfsnapshot_retval_t); 38032715170SCathy Zhou snapshot.ld_linkid = linkid; 38132715170SCathy Zhou snapshot.ld_cmd = DLMGMT_CMD_GETCONFSNAPSHOT; 38232715170SCathy Zhou again: 38332715170SCathy Zhou if ((retvalp = malloc(sz)) == NULL) 38432715170SCathy Zhou return (DLADM_STATUS_NOMEM); 38532715170SCathy Zhou 38632715170SCathy Zhou if ((status = dladm_door_call(handle, &snapshot, sizeof (snapshot), 38732715170SCathy Zhou retvalp, &sz)) == DLADM_STATUS_TOOSMALL) { 38832715170SCathy Zhou free(retvalp); 38932715170SCathy Zhou goto again; 39032715170SCathy Zhou } 39132715170SCathy Zhou 39232715170SCathy Zhou if (status != DLADM_STATUS_OK) { 39332715170SCathy Zhou free(retvalp); 39432715170SCathy Zhou return (status); 39532715170SCathy Zhou } 39632715170SCathy Zhou 39732715170SCathy Zhou confp->ds_readonly = B_TRUE; 39832715170SCathy Zhou nvlbuf = (char *)retvalp + sizeof (dlmgmt_getconfsnapshot_retval_t); 39932715170SCathy Zhou if ((err = nvlist_unpack(nvlbuf, retvalp->lr_nvlsz, 40032715170SCathy Zhou &(confp->ds_nvl), NV_ENCODE_NATIVE)) != 0) { 40132715170SCathy Zhou status = dladm_errno2status(err); 40232715170SCathy Zhou } 40332715170SCathy Zhou free(retvalp); 404024b0a25Sseb return (status); 405d62bc4baSyz147064 } 406d62bc4baSyz147064 407d62bc4baSyz147064 /* 408d62bc4baSyz147064 * Commit the given link to the data link configuration repository so 409d62bc4baSyz147064 * that it will persist across reboots. 410d62bc4baSyz147064 */ 411d62bc4baSyz147064 dladm_status_t 4124ac67f02SAnurag S. Maskey dladm_write_conf(dladm_handle_t handle, dladm_conf_t conf) 413d62bc4baSyz147064 { 414d62bc4baSyz147064 dlmgmt_door_writeconf_t writeconf; 415d62bc4baSyz147064 dlmgmt_writeconf_retval_t retval; 41632715170SCathy Zhou size_t sz = sizeof (retval); 417d62bc4baSyz147064 41832715170SCathy Zhou if (conf.ds_confid == DLADM_INVALID_CONF) 419d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 420d62bc4baSyz147064 42132715170SCathy Zhou if (conf.ds_readonly) 42232715170SCathy Zhou return (DLADM_STATUS_DENIED); 423d62bc4baSyz147064 42432715170SCathy Zhou writeconf.ld_cmd = DLMGMT_CMD_WRITECONF; 42532715170SCathy Zhou writeconf.ld_confid = conf.ds_confid; 42632715170SCathy Zhou 42732715170SCathy Zhou return (dladm_door_call(handle, &writeconf, sizeof (writeconf), 42832715170SCathy Zhou &retval, &sz)); 429d62bc4baSyz147064 } 430d62bc4baSyz147064 431d62bc4baSyz147064 /* 43232715170SCathy Zhou * Given a dladm_conf_t, get the specific configuration field 43332715170SCathy Zhou * 43432715170SCathy Zhou * If the specified dladm_conf_t is a read-only snapshot of the configuration, 43532715170SCathy Zhou * get a specific link propertie from that snapshot (nvl), otherwise, get 43632715170SCathy Zhou * the link protperty from the dlmgmtd daemon using the given confid. 437d62bc4baSyz147064 */ 438d62bc4baSyz147064 dladm_status_t 4394ac67f02SAnurag S. Maskey dladm_get_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr, 4404ac67f02SAnurag S. Maskey void *attrval, size_t attrsz) 441d62bc4baSyz147064 { 44232715170SCathy Zhou dladm_status_t status = DLADM_STATUS_OK; 44332715170SCathy Zhou 44432715170SCathy Zhou if (attrval == NULL || attrsz == 0 || attr == NULL) 44532715170SCathy Zhou return (DLADM_STATUS_BADARG); 44632715170SCathy Zhou 44732715170SCathy Zhou if (conf.ds_readonly) { 44832715170SCathy Zhou uchar_t *oattrval; 44932715170SCathy Zhou uint32_t oattrsz; 45032715170SCathy Zhou int err; 45132715170SCathy Zhou 45232715170SCathy Zhou if ((err = nvlist_lookup_byte_array(conf.ds_nvl, (char *)attr, 45332715170SCathy Zhou &oattrval, &oattrsz)) != 0) { 45432715170SCathy Zhou return (dladm_errno2status(err)); 45532715170SCathy Zhou } 45632715170SCathy Zhou if (oattrsz > attrsz) 45732715170SCathy Zhou return (DLADM_STATUS_TOOSMALL); 45832715170SCathy Zhou 45932715170SCathy Zhou bcopy(oattrval, attrval, oattrsz); 46032715170SCathy Zhou } else { 461d62bc4baSyz147064 dlmgmt_door_getattr_t getattr; 462024b0a25Sseb dlmgmt_getattr_retval_t retval; 46332715170SCathy Zhou size_t sz = sizeof (retval); 464d62bc4baSyz147064 46532715170SCathy Zhou if (conf.ds_confid == DLADM_INVALID_CONF) 466d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 467d62bc4baSyz147064 468d62bc4baSyz147064 getattr.ld_cmd = DLMGMT_CMD_GETATTR; 46932715170SCathy Zhou getattr.ld_confid = conf.ds_confid; 470d62bc4baSyz147064 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); 471d62bc4baSyz147064 47232715170SCathy Zhou if ((status = dladm_door_call(handle, &getattr, 47332715170SCathy Zhou sizeof (getattr), &retval, &sz)) != DLADM_STATUS_OK) { 474d62bc4baSyz147064 return (status); 475d62bc4baSyz147064 } 476d62bc4baSyz147064 477024b0a25Sseb if (retval.lr_attrsz > attrsz) 478024b0a25Sseb return (DLADM_STATUS_TOOSMALL); 479024b0a25Sseb 480024b0a25Sseb bcopy(retval.lr_attrval, attrval, retval.lr_attrsz); 48132715170SCathy Zhou } 48232715170SCathy Zhou return (status); 483024b0a25Sseb } 484024b0a25Sseb 485d62bc4baSyz147064 /* 48662ee1d25SArtem Kachitchkine * Get next property attribute from data link configuration repository. 48732715170SCathy Zhou * If last_attr is "", return the first property. 48862ee1d25SArtem Kachitchkine */ 48932715170SCathy Zhou /* ARGSUSED */ 49062ee1d25SArtem Kachitchkine dladm_status_t 49162ee1d25SArtem Kachitchkine dladm_getnext_conf_linkprop(dladm_handle_t handle, dladm_conf_t conf, 49262ee1d25SArtem Kachitchkine const char *last_attr, char *attr, void *attrval, size_t attrsz, 49362ee1d25SArtem Kachitchkine size_t *attrszp) 49462ee1d25SArtem Kachitchkine { 49532715170SCathy Zhou nvlist_t *nvl = conf.ds_nvl; 49632715170SCathy Zhou nvpair_t *last = NULL, *nvp; 49732715170SCathy Zhou uchar_t *oattrval; 49832715170SCathy Zhou uint32_t oattrsz; 49932715170SCathy Zhou int err; 50062ee1d25SArtem Kachitchkine 50132715170SCathy Zhou if (nvl == NULL || attrval == NULL || attrsz == 0 || attr == NULL || 50232715170SCathy Zhou !conf.ds_readonly) 50362ee1d25SArtem Kachitchkine return (DLADM_STATUS_BADARG); 50432715170SCathy Zhou 50532715170SCathy Zhou while ((nvp = nvlist_next_nvpair(nvl, last)) != NULL) { 50632715170SCathy Zhou if (last_attr[0] == '\0') 50732715170SCathy Zhou break; 50832715170SCathy Zhou if (last != NULL && strcmp(last_attr, nvpair_name(last)) == 0) 50932715170SCathy Zhou break; 51032715170SCathy Zhou last = nvp; 51162ee1d25SArtem Kachitchkine } 51262ee1d25SArtem Kachitchkine 51332715170SCathy Zhou if (nvp == NULL) 51432715170SCathy Zhou return (DLADM_STATUS_NOTFOUND); 51562ee1d25SArtem Kachitchkine 51632715170SCathy Zhou if ((err = nvpair_value_byte_array(nvp, (uchar_t **)&oattrval, 51732715170SCathy Zhou &oattrsz)) != NULL) { 51832715170SCathy Zhou return (dladm_errno2status(err)); 51962ee1d25SArtem Kachitchkine } 52062ee1d25SArtem Kachitchkine 52132715170SCathy Zhou *attrszp = oattrsz; 52232715170SCathy Zhou if (oattrsz > attrsz) 52362ee1d25SArtem Kachitchkine return (DLADM_STATUS_TOOSMALL); 52462ee1d25SArtem Kachitchkine 52532715170SCathy Zhou (void) strlcpy(attr, nvpair_name(nvp), MAXLINKATTRLEN); 52632715170SCathy Zhou bcopy(oattrval, attrval, oattrsz); 52762ee1d25SArtem Kachitchkine return (DLADM_STATUS_OK); 52862ee1d25SArtem Kachitchkine } 52962ee1d25SArtem Kachitchkine 53062ee1d25SArtem Kachitchkine /* 531d62bc4baSyz147064 * Get the link ID that is associated with the given name. 532d62bc4baSyz147064 */ 533d62bc4baSyz147064 dladm_status_t 5344ac67f02SAnurag S. Maskey dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp, 5354ac67f02SAnurag S. Maskey uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap) 536d62bc4baSyz147064 { 537d62bc4baSyz147064 dlmgmt_door_getlinkid_t getlinkid; 538d62bc4baSyz147064 dlmgmt_getlinkid_retval_t retval; 539d62bc4baSyz147064 datalink_id_t linkid; 540d62bc4baSyz147064 dladm_status_t status; 54132715170SCathy Zhou size_t sz = sizeof (retval); 542d62bc4baSyz147064 543d62bc4baSyz147064 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; 544d62bc4baSyz147064 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); 545d62bc4baSyz147064 5464ac67f02SAnurag S. Maskey if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid), 54732715170SCathy Zhou &retval, &sz)) != DLADM_STATUS_OK) { 548d62bc4baSyz147064 return (status); 549024b0a25Sseb } 550d62bc4baSyz147064 551d62bc4baSyz147064 linkid = retval.lr_linkid; 552d62bc4baSyz147064 if (retval.lr_class == DATALINK_CLASS_PHYS && 553d62bc4baSyz147064 retval.lr_flags & DLMGMT_ACTIVE) { 554d62bc4baSyz147064 /* 555d62bc4baSyz147064 * An active physical link reported by the dlmgmtd daemon 556d62bc4baSyz147064 * might not be active anymore. Check and set its real status. 557d62bc4baSyz147064 */ 5584ac67f02SAnurag S. Maskey status = i_dladm_phys_status(handle, linkid, &retval.lr_flags); 559d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 560d62bc4baSyz147064 return (status); 561d62bc4baSyz147064 } 562d62bc4baSyz147064 563d62bc4baSyz147064 if (linkidp != NULL) 564d62bc4baSyz147064 *linkidp = linkid; 565d62bc4baSyz147064 if (flagp != NULL) { 566d62bc4baSyz147064 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0; 567d62bc4baSyz147064 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 568d62bc4baSyz147064 DLADM_OPT_PERSIST : 0; 569d62bc4baSyz147064 } 570d62bc4baSyz147064 if (classp != NULL) 571d62bc4baSyz147064 *classp = retval.lr_class; 572d62bc4baSyz147064 if (mediap != NULL) 573d62bc4baSyz147064 *mediap = retval.lr_media; 574d62bc4baSyz147064 575d62bc4baSyz147064 return (DLADM_STATUS_OK); 576d62bc4baSyz147064 } 577d62bc4baSyz147064 578d62bc4baSyz147064 /* 579d62bc4baSyz147064 * Get the link name that is associated with the given id. 580d62bc4baSyz147064 */ 581d62bc4baSyz147064 dladm_status_t 5824ac67f02SAnurag S. Maskey dladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid, 5834ac67f02SAnurag S. Maskey uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link, 5844ac67f02SAnurag S. Maskey size_t len) 585d62bc4baSyz147064 { 586d62bc4baSyz147064 dlmgmt_door_getname_t getname; 587d62bc4baSyz147064 dlmgmt_getname_retval_t retval; 588d62bc4baSyz147064 dladm_status_t status; 58932715170SCathy Zhou size_t sz = sizeof (retval); 590d62bc4baSyz147064 591d62bc4baSyz147064 if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) || 592d62bc4baSyz147064 (link == NULL && len != 0)) { 593d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 594d62bc4baSyz147064 } 595d62bc4baSyz147064 596d62bc4baSyz147064 getname.ld_cmd = DLMGMT_CMD_GETNAME; 597d62bc4baSyz147064 getname.ld_linkid = linkid; 5984ac67f02SAnurag S. Maskey if ((status = dladm_door_call(handle, &getname, sizeof (getname), 59932715170SCathy Zhou &retval, &sz)) != DLADM_STATUS_OK) { 600d62bc4baSyz147064 return (status); 601d62bc4baSyz147064 } 602d62bc4baSyz147064 603024b0a25Sseb if (len != 0 && (strlen(retval.lr_link) + 1 > len)) 604024b0a25Sseb return (DLADM_STATUS_TOOSMALL); 605024b0a25Sseb 606d62bc4baSyz147064 if (retval.lr_class == DATALINK_CLASS_PHYS && 607d62bc4baSyz147064 retval.lr_flags & DLMGMT_ACTIVE) { 608d62bc4baSyz147064 /* 609d62bc4baSyz147064 * An active physical link reported by the dlmgmtd daemon 610d62bc4baSyz147064 * might not be active anymore. Check and set its real status. 611d62bc4baSyz147064 */ 6124ac67f02SAnurag S. Maskey status = i_dladm_phys_status(handle, linkid, &retval.lr_flags); 613d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 614d62bc4baSyz147064 return (status); 615d62bc4baSyz147064 } 616d62bc4baSyz147064 617d62bc4baSyz147064 if (link != NULL) 618d62bc4baSyz147064 (void) strlcpy(link, retval.lr_link, len); 619d62bc4baSyz147064 if (classp != NULL) 620d62bc4baSyz147064 *classp = retval.lr_class; 621d62bc4baSyz147064 if (mediap != NULL) 622d62bc4baSyz147064 *mediap = retval.lr_media; 623d62bc4baSyz147064 if (flagp != NULL) { 624d62bc4baSyz147064 *flagp = retval.lr_flags & DLMGMT_ACTIVE ? 625d62bc4baSyz147064 DLADM_OPT_ACTIVE : 0; 626d62bc4baSyz147064 *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? 627d62bc4baSyz147064 DLADM_OPT_PERSIST : 0; 628d62bc4baSyz147064 } 629d62bc4baSyz147064 return (DLADM_STATUS_OK); 630d62bc4baSyz147064 } 631d62bc4baSyz147064 632d62bc4baSyz147064 /* 633d62bc4baSyz147064 * Set the given attr with the given attrval for the given link. 634d62bc4baSyz147064 */ 635d62bc4baSyz147064 dladm_status_t 6364ac67f02SAnurag S. Maskey dladm_set_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr, 637d62bc4baSyz147064 dladm_datatype_t type, const void *attrval) 638d62bc4baSyz147064 { 639024b0a25Sseb dlmgmt_door_setattr_t setattr; 640d62bc4baSyz147064 dlmgmt_setattr_retval_t retval; 641024b0a25Sseb size_t attrsz; 64232715170SCathy Zhou size_t sz = sizeof (retval); 643d62bc4baSyz147064 644024b0a25Sseb if (attr == NULL || attrval == NULL) 645d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 646d62bc4baSyz147064 64732715170SCathy Zhou if (conf.ds_readonly) 64832715170SCathy Zhou return (DLADM_STATUS_DENIED); 64932715170SCathy Zhou 650d62bc4baSyz147064 if (type == DLADM_TYPE_STR) 651d62bc4baSyz147064 attrsz = strlen(attrval) + 1; 652d62bc4baSyz147064 else 653d62bc4baSyz147064 attrsz = dladm_datatype_size[type]; 654d62bc4baSyz147064 655024b0a25Sseb if (attrsz > MAXLINKATTRVALLEN) 656024b0a25Sseb return (DLADM_STATUS_TOOSMALL); 657d62bc4baSyz147064 658024b0a25Sseb setattr.ld_cmd = DLMGMT_CMD_SETATTR; 65932715170SCathy Zhou setattr.ld_confid = conf.ds_confid; 660024b0a25Sseb (void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN); 661024b0a25Sseb setattr.ld_attrsz = attrsz; 662024b0a25Sseb setattr.ld_type = type; 663024b0a25Sseb bcopy(attrval, &setattr.ld_attrval, attrsz); 664d62bc4baSyz147064 66532715170SCathy Zhou return (dladm_door_call(handle, &setattr, sizeof (setattr), 66632715170SCathy Zhou &retval, &sz)); 667d62bc4baSyz147064 } 668d62bc4baSyz147064 669d62bc4baSyz147064 /* 670d62bc4baSyz147064 * Unset the given attr the given link. 671d62bc4baSyz147064 */ 672d62bc4baSyz147064 dladm_status_t 6734ac67f02SAnurag S. Maskey dladm_unset_conf_field(dladm_handle_t handle, dladm_conf_t conf, 6744ac67f02SAnurag S. Maskey const char *attr) 675d62bc4baSyz147064 { 676d62bc4baSyz147064 dlmgmt_door_unsetattr_t unsetattr; 677d62bc4baSyz147064 dlmgmt_unsetattr_retval_t retval; 67832715170SCathy Zhou size_t sz = sizeof (retval); 679d62bc4baSyz147064 680024b0a25Sseb if (attr == NULL) 681d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 682d62bc4baSyz147064 68332715170SCathy Zhou if (conf.ds_readonly) 68432715170SCathy Zhou return (DLADM_STATUS_DENIED); 68532715170SCathy Zhou 686d62bc4baSyz147064 unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR; 68732715170SCathy Zhou unsetattr.ld_confid = conf.ds_confid; 688d62bc4baSyz147064 (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN); 689d62bc4baSyz147064 69032715170SCathy Zhou return (dladm_door_call(handle, &unsetattr, sizeof (unsetattr), 69132715170SCathy Zhou &retval, &sz)); 692d62bc4baSyz147064 } 693d62bc4baSyz147064 694d62bc4baSyz147064 /* 695d62bc4baSyz147064 * Remove the given link ID and its entry from the data link configuration 696d62bc4baSyz147064 * repository. 697d62bc4baSyz147064 */ 698d62bc4baSyz147064 dladm_status_t 6994ac67f02SAnurag S. Maskey dladm_remove_conf(dladm_handle_t handle, datalink_id_t linkid) 700d62bc4baSyz147064 { 701d62bc4baSyz147064 dlmgmt_door_removeconf_t removeconf; 702d62bc4baSyz147064 dlmgmt_removeconf_retval_t retval; 70332715170SCathy Zhou size_t sz = sizeof (retval); 704d62bc4baSyz147064 705d62bc4baSyz147064 removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF; 706d62bc4baSyz147064 removeconf.ld_linkid = linkid; 707d62bc4baSyz147064 7084ac67f02SAnurag S. Maskey return (dladm_door_call(handle, &removeconf, sizeof (removeconf), 70932715170SCathy Zhou &retval, &sz)); 710d62bc4baSyz147064 } 711d62bc4baSyz147064 712d62bc4baSyz147064 /* 713d62bc4baSyz147064 * Free the contents of the link structure. 714d62bc4baSyz147064 */ 715d62bc4baSyz147064 void 7164ac67f02SAnurag S. Maskey dladm_destroy_conf(dladm_handle_t handle, dladm_conf_t conf) 717d62bc4baSyz147064 { 71832715170SCathy Zhou dlmgmt_door_destroyconf_t dconf; 719d62bc4baSyz147064 dlmgmt_destroyconf_retval_t retval; 72032715170SCathy Zhou size_t sz = sizeof (retval); 721d62bc4baSyz147064 72232715170SCathy Zhou if (conf.ds_readonly) { 72332715170SCathy Zhou nvlist_free(conf.ds_nvl); 72432715170SCathy Zhou } else { 72532715170SCathy Zhou if (conf.ds_confid == DLADM_INVALID_CONF) 726d62bc4baSyz147064 return; 727d62bc4baSyz147064 72832715170SCathy Zhou dconf.ld_cmd = DLMGMT_CMD_DESTROYCONF; 72932715170SCathy Zhou dconf.ld_confid = conf.ds_confid; 730d62bc4baSyz147064 73132715170SCathy Zhou (void) dladm_door_call(handle, &dconf, sizeof (dconf), 73232715170SCathy Zhou &retval, &sz); 73332715170SCathy Zhou } 734d62bc4baSyz147064 } 7352b24ab6bSSebastien Roy 7362b24ab6bSSebastien Roy dladm_status_t 7372b24ab6bSSebastien Roy dladm_zone_boot(dladm_handle_t handle, zoneid_t zoneid) 7382b24ab6bSSebastien Roy { 7392b24ab6bSSebastien Roy dlmgmt_door_zoneboot_t zoneboot; 7402b24ab6bSSebastien Roy dlmgmt_zoneboot_retval_t retval; 74132715170SCathy Zhou size_t sz = sizeof (retval); 7422b24ab6bSSebastien Roy 7432b24ab6bSSebastien Roy zoneboot.ld_cmd = DLMGMT_CMD_ZONEBOOT; 7442b24ab6bSSebastien Roy zoneboot.ld_zoneid = zoneid; 74532715170SCathy Zhou return (dladm_door_call(handle, &zoneboot, sizeof (zoneboot), 74632715170SCathy Zhou &retval, &sz)); 7472b24ab6bSSebastien Roy } 7482b24ab6bSSebastien Roy 7492b24ab6bSSebastien Roy dladm_status_t 7502b24ab6bSSebastien Roy dladm_zone_halt(dladm_handle_t handle, zoneid_t zoneid) 7512b24ab6bSSebastien Roy { 7522b24ab6bSSebastien Roy dlmgmt_door_zonehalt_t zonehalt; 7532b24ab6bSSebastien Roy dlmgmt_zonehalt_retval_t retval; 75432715170SCathy Zhou size_t sz = sizeof (retval); 7552b24ab6bSSebastien Roy 7562b24ab6bSSebastien Roy zonehalt.ld_cmd = DLMGMT_CMD_ZONEHALT; 7572b24ab6bSSebastien Roy zonehalt.ld_zoneid = zoneid; 75832715170SCathy Zhou return (dladm_door_call(handle, &zonehalt, sizeof (zonehalt), 75932715170SCathy Zhou &retval, &sz)); 7602b24ab6bSSebastien Roy } 761