1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/int_limits.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/nvpair.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/nvpair_impl.h> 35*7c478bd9Sstevel@tonic-gate #include <rpc/types.h> 36*7c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 39*7c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 40*7c478bd9Sstevel@tonic-gate #else 41*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 42*7c478bd9Sstevel@tonic-gate #include <strings.h> 43*7c478bd9Sstevel@tonic-gate #endif 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate #ifndef offsetof 46*7c478bd9Sstevel@tonic-gate #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 47*7c478bd9Sstevel@tonic-gate #endif 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* 51*7c478bd9Sstevel@tonic-gate * nvpair.c - Provides kernel & userland interfaces for manipulating 52*7c478bd9Sstevel@tonic-gate * name-value pairs. 53*7c478bd9Sstevel@tonic-gate * 54*7c478bd9Sstevel@tonic-gate * Overview Diagram 55*7c478bd9Sstevel@tonic-gate * 56*7c478bd9Sstevel@tonic-gate * +--------------+ 57*7c478bd9Sstevel@tonic-gate * | nvlist_t | 58*7c478bd9Sstevel@tonic-gate * |--------------| 59*7c478bd9Sstevel@tonic-gate * | nvl_version | 60*7c478bd9Sstevel@tonic-gate * | nvl_nvflag | 61*7c478bd9Sstevel@tonic-gate * | nvl_priv -+-+ 62*7c478bd9Sstevel@tonic-gate * | nvl_flag | | 63*7c478bd9Sstevel@tonic-gate * | nvl_pad | | 64*7c478bd9Sstevel@tonic-gate * +--------------+ | 65*7c478bd9Sstevel@tonic-gate * V 66*7c478bd9Sstevel@tonic-gate * +--------------+ last i_nvp in list 67*7c478bd9Sstevel@tonic-gate * | nvpriv_t | +---------------------> 68*7c478bd9Sstevel@tonic-gate * |--------------| | 69*7c478bd9Sstevel@tonic-gate * +--+- nvp_list | | +------------+ 70*7c478bd9Sstevel@tonic-gate * | | nvp_last -+--+ + nv_alloc_t | 71*7c478bd9Sstevel@tonic-gate * | | nvp_curr | |------------| 72*7c478bd9Sstevel@tonic-gate * | | nvp_nva -+----> | nva_ops | 73*7c478bd9Sstevel@tonic-gate * | | nvp_stat | | nva_arg | 74*7c478bd9Sstevel@tonic-gate * | +--------------+ +------------+ 75*7c478bd9Sstevel@tonic-gate * | 76*7c478bd9Sstevel@tonic-gate * +-------+ 77*7c478bd9Sstevel@tonic-gate * V 78*7c478bd9Sstevel@tonic-gate * +---------------------+ +-------------------+ 79*7c478bd9Sstevel@tonic-gate * | i_nvp_t | +-->| i_nvp_t | +--> 80*7c478bd9Sstevel@tonic-gate * |---------------------| | |-------------------| | 81*7c478bd9Sstevel@tonic-gate * | nvi_next -+--+ | nvi_next -+--+ 82*7c478bd9Sstevel@tonic-gate * | nvi_prev (NULL) | <----+ nvi_prev | 83*7c478bd9Sstevel@tonic-gate * | . . . . . . . . . . | | . . . . . . . . . | 84*7c478bd9Sstevel@tonic-gate * | nvp (nvpair_t) | | nvp (nvpair_t) | 85*7c478bd9Sstevel@tonic-gate * | - nvp_size | | - nvp_size | 86*7c478bd9Sstevel@tonic-gate * | - nvp_name_sz | | - nvp_name_sz | 87*7c478bd9Sstevel@tonic-gate * | - nvp_value_elem | | - nvp_value_elem | 88*7c478bd9Sstevel@tonic-gate * | - nvp_type | | - nvp_type | 89*7c478bd9Sstevel@tonic-gate * | - data ... | | - data ... | 90*7c478bd9Sstevel@tonic-gate * +---------------------+ +-------------------+ 91*7c478bd9Sstevel@tonic-gate * 92*7c478bd9Sstevel@tonic-gate * 93*7c478bd9Sstevel@tonic-gate * 94*7c478bd9Sstevel@tonic-gate * +---------------------+ +---------------------+ 95*7c478bd9Sstevel@tonic-gate * | i_nvp_t | +--> +-->| i_nvp_t (last) | 96*7c478bd9Sstevel@tonic-gate * |---------------------| | | |---------------------| 97*7c478bd9Sstevel@tonic-gate * | nvi_next -+--+ ... --+ | nvi_next (NULL) | 98*7c478bd9Sstevel@tonic-gate * <-+- nvi_prev |<-- ... <----+ nvi_prev | 99*7c478bd9Sstevel@tonic-gate * | . . . . . . . . . | | . . . . . . . . . | 100*7c478bd9Sstevel@tonic-gate * | nvp (nvpair_t) | | nvp (nvpair_t) | 101*7c478bd9Sstevel@tonic-gate * | - nvp_size | | - nvp_size | 102*7c478bd9Sstevel@tonic-gate * | - nvp_name_sz | | - nvp_name_sz | 103*7c478bd9Sstevel@tonic-gate * | - nvp_value_elem | | - nvp_value_elem | 104*7c478bd9Sstevel@tonic-gate * | - DATA_TYPE_NVLIST | | - nvp_type | 105*7c478bd9Sstevel@tonic-gate * | - data (embedded) | | - data ... | 106*7c478bd9Sstevel@tonic-gate * | nvlist name | +---------------------+ 107*7c478bd9Sstevel@tonic-gate * | +--------------+ | 108*7c478bd9Sstevel@tonic-gate * | | nvlist_t | | 109*7c478bd9Sstevel@tonic-gate * | |--------------| | 110*7c478bd9Sstevel@tonic-gate * | | nvl_version | | 111*7c478bd9Sstevel@tonic-gate * | | nvl_nvflag | | 112*7c478bd9Sstevel@tonic-gate * | | nvl_priv --+---+----> 113*7c478bd9Sstevel@tonic-gate * | | nvl_flag | | 114*7c478bd9Sstevel@tonic-gate * | | nvl_pad | | 115*7c478bd9Sstevel@tonic-gate * | +--------------+ | 116*7c478bd9Sstevel@tonic-gate * +---------------------+ 117*7c478bd9Sstevel@tonic-gate * 118*7c478bd9Sstevel@tonic-gate * 119*7c478bd9Sstevel@tonic-gate * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will 120*7c478bd9Sstevel@tonic-gate * allow value to be aligned on 8 byte boundary 121*7c478bd9Sstevel@tonic-gate * 122*7c478bd9Sstevel@tonic-gate * name_len is the length of the name string including the null terminator 123*7c478bd9Sstevel@tonic-gate * so it must be >= 1 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate #define NVP_SIZE_CALC(name_len, data_len) \ 126*7c478bd9Sstevel@tonic-gate (NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len)) 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate static int i_get_value_size(data_type_t type, const void *data, uint_t nelem); 129*7c478bd9Sstevel@tonic-gate static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type, 130*7c478bd9Sstevel@tonic-gate uint_t nelem, const void *data); 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate #define NV_STAT_EMBEDDED 0x1 133*7c478bd9Sstevel@tonic-gate #define EMBEDDED_NVL(nvp) ((nvlist_t *)(void *)NVP_VALUE(nvp)) 134*7c478bd9Sstevel@tonic-gate #define EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp)) 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate #define NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz)) 137*7c478bd9Sstevel@tonic-gate #define NVPAIR2I_NVP(nvp) \ 138*7c478bd9Sstevel@tonic-gate ((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp))) 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate int 142*7c478bd9Sstevel@tonic-gate nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...) 143*7c478bd9Sstevel@tonic-gate { 144*7c478bd9Sstevel@tonic-gate va_list valist; 145*7c478bd9Sstevel@tonic-gate int err = 0; 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate nva->nva_ops = nvo; 148*7c478bd9Sstevel@tonic-gate nva->nva_arg = NULL; 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate va_start(valist, nvo); 151*7c478bd9Sstevel@tonic-gate if (nva->nva_ops->nv_ao_init != NULL) 152*7c478bd9Sstevel@tonic-gate err = nva->nva_ops->nv_ao_init(nva, valist); 153*7c478bd9Sstevel@tonic-gate va_end(valist); 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate return (err); 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate void 159*7c478bd9Sstevel@tonic-gate nv_alloc_reset(nv_alloc_t *nva) 160*7c478bd9Sstevel@tonic-gate { 161*7c478bd9Sstevel@tonic-gate if (nva->nva_ops->nv_ao_reset != NULL) 162*7c478bd9Sstevel@tonic-gate nva->nva_ops->nv_ao_reset(nva); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate void 166*7c478bd9Sstevel@tonic-gate nv_alloc_fini(nv_alloc_t *nva) 167*7c478bd9Sstevel@tonic-gate { 168*7c478bd9Sstevel@tonic-gate if (nva->nva_ops->nv_ao_fini != NULL) 169*7c478bd9Sstevel@tonic-gate nva->nva_ops->nv_ao_fini(nva); 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate nv_alloc_t * 173*7c478bd9Sstevel@tonic-gate nvlist_lookup_nv_alloc(nvlist_t *nvl) 174*7c478bd9Sstevel@tonic-gate { 175*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate if (nvl == NULL || 178*7c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 179*7c478bd9Sstevel@tonic-gate return (NULL); 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate return (priv->nvp_nva); 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate static void * 185*7c478bd9Sstevel@tonic-gate nv_mem_zalloc(nvpriv_t *nvp, size_t size) 186*7c478bd9Sstevel@tonic-gate { 187*7c478bd9Sstevel@tonic-gate nv_alloc_t *nva = nvp->nvp_nva; 188*7c478bd9Sstevel@tonic-gate void *buf; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL) 191*7c478bd9Sstevel@tonic-gate bzero(buf, size); 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate return (buf); 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate static void 197*7c478bd9Sstevel@tonic-gate nv_mem_free(nvpriv_t *nvp, void *buf, size_t size) 198*7c478bd9Sstevel@tonic-gate { 199*7c478bd9Sstevel@tonic-gate nv_alloc_t *nva = nvp->nvp_nva; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate nva->nva_ops->nv_ao_free(nva, buf, size); 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate static void 205*7c478bd9Sstevel@tonic-gate nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat) 206*7c478bd9Sstevel@tonic-gate { 207*7c478bd9Sstevel@tonic-gate bzero(priv, sizeof (priv)); 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate priv->nvp_nva = nva; 210*7c478bd9Sstevel@tonic-gate priv->nvp_stat = stat; 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate static nvpriv_t * 214*7c478bd9Sstevel@tonic-gate nv_priv_alloc(nv_alloc_t *nva) 215*7c478bd9Sstevel@tonic-gate { 216*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate /* 219*7c478bd9Sstevel@tonic-gate * nv_mem_alloc() cannot called here because it needs the priv 220*7c478bd9Sstevel@tonic-gate * argument. 221*7c478bd9Sstevel@tonic-gate */ 222*7c478bd9Sstevel@tonic-gate if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL) 223*7c478bd9Sstevel@tonic-gate return (NULL); 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate nv_priv_init(priv, nva, 0); 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate return (priv); 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate * Embedded lists need their own nvpriv_t's. We create a new 232*7c478bd9Sstevel@tonic-gate * nvpriv_t using the parameters and allocator from the parent 233*7c478bd9Sstevel@tonic-gate * list's nvpriv_t. 234*7c478bd9Sstevel@tonic-gate */ 235*7c478bd9Sstevel@tonic-gate static nvpriv_t * 236*7c478bd9Sstevel@tonic-gate nv_priv_alloc_embedded(nvpriv_t *priv) 237*7c478bd9Sstevel@tonic-gate { 238*7c478bd9Sstevel@tonic-gate nvpriv_t *emb_priv; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL) 241*7c478bd9Sstevel@tonic-gate return (NULL); 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED); 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate return (emb_priv); 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate static void 249*7c478bd9Sstevel@tonic-gate nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv) 250*7c478bd9Sstevel@tonic-gate { 251*7c478bd9Sstevel@tonic-gate nvl->nvl_version = NV_VERSION; 252*7c478bd9Sstevel@tonic-gate nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE); 253*7c478bd9Sstevel@tonic-gate nvl->nvl_priv = (uint64_t)(uintptr_t)priv; 254*7c478bd9Sstevel@tonic-gate nvl->nvl_flag = 0; 255*7c478bd9Sstevel@tonic-gate nvl->nvl_pad = 0; 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* 259*7c478bd9Sstevel@tonic-gate * nvlist_alloc - Allocate nvlist. 260*7c478bd9Sstevel@tonic-gate */ 261*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 262*7c478bd9Sstevel@tonic-gate int 263*7c478bd9Sstevel@tonic-gate nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag) 264*7c478bd9Sstevel@tonic-gate { 265*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 266*7c478bd9Sstevel@tonic-gate return (nvlist_xalloc(nvlp, nvflag, 267*7c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 268*7c478bd9Sstevel@tonic-gate #else 269*7c478bd9Sstevel@tonic-gate return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep)); 270*7c478bd9Sstevel@tonic-gate #endif 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate int 274*7c478bd9Sstevel@tonic-gate nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva) 275*7c478bd9Sstevel@tonic-gate { 276*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate if (nvlp == NULL || nva == NULL) 279*7c478bd9Sstevel@tonic-gate return (EINVAL); 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate if ((priv = nv_priv_alloc(nva)) == NULL) 282*7c478bd9Sstevel@tonic-gate return (ENOMEM); 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate if ((*nvlp = nv_mem_zalloc(priv, 285*7c478bd9Sstevel@tonic-gate NV_ALIGN(sizeof (nvlist_t)))) == NULL) { 286*7c478bd9Sstevel@tonic-gate nv_mem_free(priv, priv, sizeof (nvpriv_t)); 287*7c478bd9Sstevel@tonic-gate return (ENOMEM); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate nvlist_init(*nvlp, nvflag, priv); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate return (0); 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate /* 296*7c478bd9Sstevel@tonic-gate * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair. 297*7c478bd9Sstevel@tonic-gate */ 298*7c478bd9Sstevel@tonic-gate static nvpair_t * 299*7c478bd9Sstevel@tonic-gate nvp_buf_alloc(nvlist_t *nvl, size_t len) 300*7c478bd9Sstevel@tonic-gate { 301*7c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 302*7c478bd9Sstevel@tonic-gate i_nvp_t *buf; 303*7c478bd9Sstevel@tonic-gate nvpair_t *nvp; 304*7c478bd9Sstevel@tonic-gate size_t nvsize; 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate /* 307*7c478bd9Sstevel@tonic-gate * Allocate the buffer 308*7c478bd9Sstevel@tonic-gate */ 309*7c478bd9Sstevel@tonic-gate nvsize = len + offsetof(i_nvp_t, nvi_nvp); 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL) 312*7c478bd9Sstevel@tonic-gate return (NULL); 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate nvp = &buf->nvi_nvp; 315*7c478bd9Sstevel@tonic-gate nvp->nvp_size = len; 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate return (nvp); 318*7c478bd9Sstevel@tonic-gate } 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate /* 321*7c478bd9Sstevel@tonic-gate * nvp_buf_free - de-Allocate an i_nvp_t. 322*7c478bd9Sstevel@tonic-gate */ 323*7c478bd9Sstevel@tonic-gate static void 324*7c478bd9Sstevel@tonic-gate nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp) 325*7c478bd9Sstevel@tonic-gate { 326*7c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 327*7c478bd9Sstevel@tonic-gate size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp); 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * nvp_buf_link - link a new nv pair into the nvlist. 334*7c478bd9Sstevel@tonic-gate */ 335*7c478bd9Sstevel@tonic-gate static void 336*7c478bd9Sstevel@tonic-gate nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp) 337*7c478bd9Sstevel@tonic-gate { 338*7c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 339*7c478bd9Sstevel@tonic-gate i_nvp_t *curr = NVPAIR2I_NVP(nvp); 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate /* Put element at end of nvlist */ 342*7c478bd9Sstevel@tonic-gate if (priv->nvp_list == NULL) { 343*7c478bd9Sstevel@tonic-gate priv->nvp_list = priv->nvp_last = curr; 344*7c478bd9Sstevel@tonic-gate } else { 345*7c478bd9Sstevel@tonic-gate curr->nvi_prev = priv->nvp_last; 346*7c478bd9Sstevel@tonic-gate priv->nvp_last->nvi_next = curr; 347*7c478bd9Sstevel@tonic-gate priv->nvp_last = curr; 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate /* 352*7c478bd9Sstevel@tonic-gate * nvp_buf_unlink - unlink an removed nvpair out of the nvlist. 353*7c478bd9Sstevel@tonic-gate */ 354*7c478bd9Sstevel@tonic-gate static void 355*7c478bd9Sstevel@tonic-gate nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp) 356*7c478bd9Sstevel@tonic-gate { 357*7c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 358*7c478bd9Sstevel@tonic-gate i_nvp_t *curr = NVPAIR2I_NVP(nvp); 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate /* 361*7c478bd9Sstevel@tonic-gate * protect nvlist_next_nvpair() against walking on freed memory. 362*7c478bd9Sstevel@tonic-gate */ 363*7c478bd9Sstevel@tonic-gate if (priv->nvp_curr == curr) 364*7c478bd9Sstevel@tonic-gate priv->nvp_curr = curr->nvi_next; 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate if (curr == priv->nvp_list) 367*7c478bd9Sstevel@tonic-gate priv->nvp_list = curr->nvi_next; 368*7c478bd9Sstevel@tonic-gate else 369*7c478bd9Sstevel@tonic-gate curr->nvi_prev->nvi_next = curr->nvi_next; 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate if (curr == priv->nvp_last) 372*7c478bd9Sstevel@tonic-gate priv->nvp_last = curr->nvi_prev; 373*7c478bd9Sstevel@tonic-gate else 374*7c478bd9Sstevel@tonic-gate curr->nvi_next->nvi_prev = curr->nvi_prev; 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate /* 378*7c478bd9Sstevel@tonic-gate * take a nvpair type and number of elements and make sure the are valid 379*7c478bd9Sstevel@tonic-gate */ 380*7c478bd9Sstevel@tonic-gate static int 381*7c478bd9Sstevel@tonic-gate i_validate_type_nelem(data_type_t type, uint_t nelem) 382*7c478bd9Sstevel@tonic-gate { 383*7c478bd9Sstevel@tonic-gate switch (type) { 384*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 385*7c478bd9Sstevel@tonic-gate if (nelem != 0) 386*7c478bd9Sstevel@tonic-gate return (EINVAL); 387*7c478bd9Sstevel@tonic-gate break; 388*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 389*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 390*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 391*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 392*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 393*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 394*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 395*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 396*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 397*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 398*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 399*7c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 400*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 401*7c478bd9Sstevel@tonic-gate if (nelem != 1) 402*7c478bd9Sstevel@tonic-gate return (EINVAL); 403*7c478bd9Sstevel@tonic-gate break; 404*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 405*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 406*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 407*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 408*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 409*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 410*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 411*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 412*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 413*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 414*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 415*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 416*7c478bd9Sstevel@tonic-gate /* we allow arrays with 0 elements */ 417*7c478bd9Sstevel@tonic-gate break; 418*7c478bd9Sstevel@tonic-gate default: 419*7c478bd9Sstevel@tonic-gate return (EINVAL); 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate return (0); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate /* 425*7c478bd9Sstevel@tonic-gate * Verify nvp_name_sz and check the name string length. 426*7c478bd9Sstevel@tonic-gate */ 427*7c478bd9Sstevel@tonic-gate static int 428*7c478bd9Sstevel@tonic-gate i_validate_nvpair_name(nvpair_t *nvp) 429*7c478bd9Sstevel@tonic-gate { 430*7c478bd9Sstevel@tonic-gate if ((nvp->nvp_name_sz <= 0) || 431*7c478bd9Sstevel@tonic-gate (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0))) 432*7c478bd9Sstevel@tonic-gate return (EFAULT); 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate /* verify the name string, make sure its terminated */ 435*7c478bd9Sstevel@tonic-gate if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0') 436*7c478bd9Sstevel@tonic-gate return (EFAULT); 437*7c478bd9Sstevel@tonic-gate 438*7c478bd9Sstevel@tonic-gate return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT); 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate static int 442*7c478bd9Sstevel@tonic-gate i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data) 443*7c478bd9Sstevel@tonic-gate { 444*7c478bd9Sstevel@tonic-gate switch (type) { 445*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 446*7c478bd9Sstevel@tonic-gate if (*(boolean_t *)data != B_TRUE && 447*7c478bd9Sstevel@tonic-gate *(boolean_t *)data != B_FALSE) 448*7c478bd9Sstevel@tonic-gate return (EINVAL); 449*7c478bd9Sstevel@tonic-gate break; 450*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: { 451*7c478bd9Sstevel@tonic-gate int i; 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) 454*7c478bd9Sstevel@tonic-gate if (((boolean_t *)data)[i] != B_TRUE && 455*7c478bd9Sstevel@tonic-gate ((boolean_t *)data)[i] != B_FALSE) 456*7c478bd9Sstevel@tonic-gate return (EINVAL); 457*7c478bd9Sstevel@tonic-gate break; 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate default: 460*7c478bd9Sstevel@tonic-gate break; 461*7c478bd9Sstevel@tonic-gate } 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate return (0); 464*7c478bd9Sstevel@tonic-gate } 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate /* 467*7c478bd9Sstevel@tonic-gate * This function takes a pointer to what should be a nvpair and it's size 468*7c478bd9Sstevel@tonic-gate * and then verifies that all the nvpair fields make sense and can be 469*7c478bd9Sstevel@tonic-gate * trusted. This function is used when decoding packed nvpairs. 470*7c478bd9Sstevel@tonic-gate */ 471*7c478bd9Sstevel@tonic-gate static int 472*7c478bd9Sstevel@tonic-gate i_validate_nvpair(nvpair_t *nvp) 473*7c478bd9Sstevel@tonic-gate { 474*7c478bd9Sstevel@tonic-gate data_type_t type = NVP_TYPE(nvp); 475*7c478bd9Sstevel@tonic-gate int size1, size2; 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate /* verify nvp_name_sz, check the name string length */ 478*7c478bd9Sstevel@tonic-gate if (i_validate_nvpair_name(nvp) != 0) 479*7c478bd9Sstevel@tonic-gate return (EFAULT); 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0) 482*7c478bd9Sstevel@tonic-gate return (EFAULT); 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate /* 485*7c478bd9Sstevel@tonic-gate * verify nvp_type, nvp_value_elem, and also possibly 486*7c478bd9Sstevel@tonic-gate * verify string values and get the value size. 487*7c478bd9Sstevel@tonic-gate */ 488*7c478bd9Sstevel@tonic-gate size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp)); 489*7c478bd9Sstevel@tonic-gate size1 = nvp->nvp_size - NVP_VALOFF(nvp); 490*7c478bd9Sstevel@tonic-gate if (size2 < 0 || size1 != NV_ALIGN(size2)) 491*7c478bd9Sstevel@tonic-gate return (EFAULT); 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate return (0); 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate static int 497*7c478bd9Sstevel@tonic-gate nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl) 498*7c478bd9Sstevel@tonic-gate { 499*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 500*7c478bd9Sstevel@tonic-gate i_nvp_t *curr; 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL) 503*7c478bd9Sstevel@tonic-gate return (EINVAL); 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 506*7c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp; 507*7c478bd9Sstevel@tonic-gate int err; 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp), 510*7c478bd9Sstevel@tonic-gate NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0) 511*7c478bd9Sstevel@tonic-gate return (err); 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate return (0); 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate /* 518*7c478bd9Sstevel@tonic-gate * Frees all memory allocated for an nvpair (like embedded lists) with 519*7c478bd9Sstevel@tonic-gate * the exception of the nvpair buffer itself. 520*7c478bd9Sstevel@tonic-gate */ 521*7c478bd9Sstevel@tonic-gate static void 522*7c478bd9Sstevel@tonic-gate nvpair_free(nvpair_t *nvp) 523*7c478bd9Sstevel@tonic-gate { 524*7c478bd9Sstevel@tonic-gate switch (NVP_TYPE(nvp)) { 525*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 526*7c478bd9Sstevel@tonic-gate nvlist_free(EMBEDDED_NVL(nvp)); 527*7c478bd9Sstevel@tonic-gate break; 528*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 529*7c478bd9Sstevel@tonic-gate nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 530*7c478bd9Sstevel@tonic-gate int i; 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++) 533*7c478bd9Sstevel@tonic-gate if (nvlp[i] != NULL) 534*7c478bd9Sstevel@tonic-gate nvlist_free(nvlp[i]); 535*7c478bd9Sstevel@tonic-gate break; 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate default: 538*7c478bd9Sstevel@tonic-gate break; 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate /* 543*7c478bd9Sstevel@tonic-gate * nvlist_free - free an unpacked nvlist 544*7c478bd9Sstevel@tonic-gate */ 545*7c478bd9Sstevel@tonic-gate void 546*7c478bd9Sstevel@tonic-gate nvlist_free(nvlist_t *nvl) 547*7c478bd9Sstevel@tonic-gate { 548*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 549*7c478bd9Sstevel@tonic-gate i_nvp_t *curr; 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate if (nvl == NULL || 552*7c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 553*7c478bd9Sstevel@tonic-gate return; 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate /* 556*7c478bd9Sstevel@tonic-gate * Unpacked nvlist are linked through i_nvp_t 557*7c478bd9Sstevel@tonic-gate */ 558*7c478bd9Sstevel@tonic-gate curr = priv->nvp_list; 559*7c478bd9Sstevel@tonic-gate while (curr != NULL) { 560*7c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp; 561*7c478bd9Sstevel@tonic-gate curr = curr->nvi_next; 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate nvpair_free(nvp); 564*7c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate if (!(priv->nvp_stat & NV_STAT_EMBEDDED)) 568*7c478bd9Sstevel@tonic-gate nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t))); 569*7c478bd9Sstevel@tonic-gate else 570*7c478bd9Sstevel@tonic-gate nvl->nvl_priv = NULL; 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate nv_mem_free(priv, priv, sizeof (nvpriv_t)); 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate static int 576*7c478bd9Sstevel@tonic-gate nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp) 577*7c478bd9Sstevel@tonic-gate { 578*7c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 579*7c478bd9Sstevel@tonic-gate i_nvp_t *curr; 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate if (nvp == NULL) 582*7c478bd9Sstevel@tonic-gate return (0); 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 585*7c478bd9Sstevel@tonic-gate if (&curr->nvi_nvp == nvp) 586*7c478bd9Sstevel@tonic-gate return (1); 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate return (0); 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * Make a copy of nvlist 593*7c478bd9Sstevel@tonic-gate */ 594*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 595*7c478bd9Sstevel@tonic-gate int 596*7c478bd9Sstevel@tonic-gate nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag) 597*7c478bd9Sstevel@tonic-gate { 598*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 599*7c478bd9Sstevel@tonic-gate return (nvlist_xdup(nvl, nvlp, 600*7c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 601*7c478bd9Sstevel@tonic-gate #else 602*7c478bd9Sstevel@tonic-gate return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep)); 603*7c478bd9Sstevel@tonic-gate #endif 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate int 607*7c478bd9Sstevel@tonic-gate nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva) 608*7c478bd9Sstevel@tonic-gate { 609*7c478bd9Sstevel@tonic-gate int err; 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate if (nvl == NULL || nvlp == NULL) 612*7c478bd9Sstevel@tonic-gate return (EINVAL); 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate if ((err = nvlist_xalloc(nvlp, nvl->nvl_nvflag, nva)) != 0) 615*7c478bd9Sstevel@tonic-gate return (err); 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_pairs(nvl, *nvlp)) != 0) 618*7c478bd9Sstevel@tonic-gate nvlist_free(*nvlp); 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate return (err); 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate /* 624*7c478bd9Sstevel@tonic-gate * Remove all with matching name 625*7c478bd9Sstevel@tonic-gate */ 626*7c478bd9Sstevel@tonic-gate int 627*7c478bd9Sstevel@tonic-gate nvlist_remove_all(nvlist_t *nvl, const char *name) 628*7c478bd9Sstevel@tonic-gate { 629*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 630*7c478bd9Sstevel@tonic-gate i_nvp_t *curr; 631*7c478bd9Sstevel@tonic-gate int error = ENOENT; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate if (nvl == NULL || name == NULL || 634*7c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 635*7c478bd9Sstevel@tonic-gate return (EINVAL); 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate curr = priv->nvp_list; 638*7c478bd9Sstevel@tonic-gate while (curr != NULL) { 639*7c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate curr = curr->nvi_next; 642*7c478bd9Sstevel@tonic-gate if (strcmp(name, NVP_NAME(nvp)) != 0) 643*7c478bd9Sstevel@tonic-gate continue; 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate nvp_buf_unlink(nvl, nvp); 646*7c478bd9Sstevel@tonic-gate nvpair_free(nvp); 647*7c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate error = 0; 650*7c478bd9Sstevel@tonic-gate } 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate return (error); 653*7c478bd9Sstevel@tonic-gate } 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate /* 656*7c478bd9Sstevel@tonic-gate * Remove first one with matching name and type 657*7c478bd9Sstevel@tonic-gate */ 658*7c478bd9Sstevel@tonic-gate int 659*7c478bd9Sstevel@tonic-gate nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) 660*7c478bd9Sstevel@tonic-gate { 661*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 662*7c478bd9Sstevel@tonic-gate i_nvp_t *curr; 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate if (nvl == NULL || name == NULL || 665*7c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 666*7c478bd9Sstevel@tonic-gate return (EINVAL); 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate curr = priv->nvp_list; 669*7c478bd9Sstevel@tonic-gate while (curr != NULL) { 670*7c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp; 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) { 673*7c478bd9Sstevel@tonic-gate nvp_buf_unlink(nvl, nvp); 674*7c478bd9Sstevel@tonic-gate nvpair_free(nvp); 675*7c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate return (0); 678*7c478bd9Sstevel@tonic-gate } 679*7c478bd9Sstevel@tonic-gate curr = curr->nvi_next; 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate return (ENOENT); 683*7c478bd9Sstevel@tonic-gate } 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate /* 686*7c478bd9Sstevel@tonic-gate * This function calculates the size of an nvpair value. 687*7c478bd9Sstevel@tonic-gate * 688*7c478bd9Sstevel@tonic-gate * The data argument controls the behavior in case of the data types 689*7c478bd9Sstevel@tonic-gate * DATA_TYPE_STRING and 690*7c478bd9Sstevel@tonic-gate * DATA_TYPE_STRING_ARRAY 691*7c478bd9Sstevel@tonic-gate * Is data == NULL then the size of the string(s) is excluded. 692*7c478bd9Sstevel@tonic-gate */ 693*7c478bd9Sstevel@tonic-gate static int 694*7c478bd9Sstevel@tonic-gate i_get_value_size(data_type_t type, const void *data, uint_t nelem) 695*7c478bd9Sstevel@tonic-gate { 696*7c478bd9Sstevel@tonic-gate uint64_t value_sz; 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate if (i_validate_type_nelem(type, nelem) != 0) 699*7c478bd9Sstevel@tonic-gate return (-1); 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate /* Calculate required size for holding value */ 702*7c478bd9Sstevel@tonic-gate switch (type) { 703*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 704*7c478bd9Sstevel@tonic-gate value_sz = 0; 705*7c478bd9Sstevel@tonic-gate break; 706*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 707*7c478bd9Sstevel@tonic-gate value_sz = sizeof (boolean_t); 708*7c478bd9Sstevel@tonic-gate break; 709*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 710*7c478bd9Sstevel@tonic-gate value_sz = sizeof (uchar_t); 711*7c478bd9Sstevel@tonic-gate break; 712*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 713*7c478bd9Sstevel@tonic-gate value_sz = sizeof (int8_t); 714*7c478bd9Sstevel@tonic-gate break; 715*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 716*7c478bd9Sstevel@tonic-gate value_sz = sizeof (uint8_t); 717*7c478bd9Sstevel@tonic-gate break; 718*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 719*7c478bd9Sstevel@tonic-gate value_sz = sizeof (int16_t); 720*7c478bd9Sstevel@tonic-gate break; 721*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 722*7c478bd9Sstevel@tonic-gate value_sz = sizeof (uint16_t); 723*7c478bd9Sstevel@tonic-gate break; 724*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 725*7c478bd9Sstevel@tonic-gate value_sz = sizeof (int32_t); 726*7c478bd9Sstevel@tonic-gate break; 727*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 728*7c478bd9Sstevel@tonic-gate value_sz = sizeof (uint32_t); 729*7c478bd9Sstevel@tonic-gate break; 730*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 731*7c478bd9Sstevel@tonic-gate value_sz = sizeof (int64_t); 732*7c478bd9Sstevel@tonic-gate break; 733*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 734*7c478bd9Sstevel@tonic-gate value_sz = sizeof (uint64_t); 735*7c478bd9Sstevel@tonic-gate break; 736*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 737*7c478bd9Sstevel@tonic-gate if (data == NULL) 738*7c478bd9Sstevel@tonic-gate value_sz = 0; 739*7c478bd9Sstevel@tonic-gate else 740*7c478bd9Sstevel@tonic-gate value_sz = strlen(data) + 1; 741*7c478bd9Sstevel@tonic-gate break; 742*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 743*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (boolean_t); 744*7c478bd9Sstevel@tonic-gate break; 745*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 746*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uchar_t); 747*7c478bd9Sstevel@tonic-gate break; 748*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 749*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int8_t); 750*7c478bd9Sstevel@tonic-gate break; 751*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 752*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint8_t); 753*7c478bd9Sstevel@tonic-gate break; 754*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 755*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int16_t); 756*7c478bd9Sstevel@tonic-gate break; 757*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 758*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint16_t); 759*7c478bd9Sstevel@tonic-gate break; 760*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 761*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int32_t); 762*7c478bd9Sstevel@tonic-gate break; 763*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 764*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint32_t); 765*7c478bd9Sstevel@tonic-gate break; 766*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 767*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int64_t); 768*7c478bd9Sstevel@tonic-gate break; 769*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 770*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint64_t); 771*7c478bd9Sstevel@tonic-gate break; 772*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 773*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint64_t); 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate if (data != NULL) { 776*7c478bd9Sstevel@tonic-gate char *const *strs = data; 777*7c478bd9Sstevel@tonic-gate uint_t i; 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate /* no alignment requirement for strings */ 780*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 781*7c478bd9Sstevel@tonic-gate if (strs[i] == NULL) 782*7c478bd9Sstevel@tonic-gate return (-1); 783*7c478bd9Sstevel@tonic-gate value_sz += strlen(strs[i]) + 1; 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate } 786*7c478bd9Sstevel@tonic-gate break; 787*7c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 788*7c478bd9Sstevel@tonic-gate value_sz = sizeof (hrtime_t); 789*7c478bd9Sstevel@tonic-gate break; 790*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 791*7c478bd9Sstevel@tonic-gate value_sz = NV_ALIGN(sizeof (nvlist_t)); 792*7c478bd9Sstevel@tonic-gate break; 793*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 794*7c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint64_t) + 795*7c478bd9Sstevel@tonic-gate (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t)); 796*7c478bd9Sstevel@tonic-gate break; 797*7c478bd9Sstevel@tonic-gate default: 798*7c478bd9Sstevel@tonic-gate return (-1); 799*7c478bd9Sstevel@tonic-gate } 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate return (value_sz > INT32_MAX ? -1 : (int)value_sz); 802*7c478bd9Sstevel@tonic-gate } 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate static int 805*7c478bd9Sstevel@tonic-gate nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl) 806*7c478bd9Sstevel@tonic-gate { 807*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 808*7c478bd9Sstevel@tonic-gate int err; 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t) 811*7c478bd9Sstevel@tonic-gate nvl->nvl_priv)) == NULL) 812*7c478bd9Sstevel@tonic-gate return (ENOMEM); 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate nvlist_init(emb_nvl, onvl->nvl_nvflag, priv); 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) { 817*7c478bd9Sstevel@tonic-gate nvlist_free(emb_nvl); 818*7c478bd9Sstevel@tonic-gate emb_nvl->nvl_priv = 0; 819*7c478bd9Sstevel@tonic-gate } 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate return (err); 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate /* 825*7c478bd9Sstevel@tonic-gate * nvlist_add_common - Add new <name,value> pair to nvlist 826*7c478bd9Sstevel@tonic-gate */ 827*7c478bd9Sstevel@tonic-gate static int 828*7c478bd9Sstevel@tonic-gate nvlist_add_common(nvlist_t *nvl, const char *name, 829*7c478bd9Sstevel@tonic-gate data_type_t type, uint_t nelem, const void *data) 830*7c478bd9Sstevel@tonic-gate { 831*7c478bd9Sstevel@tonic-gate nvpair_t *nvp; 832*7c478bd9Sstevel@tonic-gate int nvp_sz, name_sz, value_sz; 833*7c478bd9Sstevel@tonic-gate int err = 0; 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate /* sanity check input params */ 836*7c478bd9Sstevel@tonic-gate if (name == NULL || nvl == NULL || nvl->nvl_priv == 0) 837*7c478bd9Sstevel@tonic-gate return (EINVAL); 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate if (nelem != 0 && data == NULL) 840*7c478bd9Sstevel@tonic-gate return (EINVAL); 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate /* 843*7c478bd9Sstevel@tonic-gate * Verify type and nelem and get the value size. 844*7c478bd9Sstevel@tonic-gate * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 845*7c478bd9Sstevel@tonic-gate * is the size of the string(s) included. 846*7c478bd9Sstevel@tonic-gate */ 847*7c478bd9Sstevel@tonic-gate if ((value_sz = i_get_value_size(type, data, nelem)) < 0) 848*7c478bd9Sstevel@tonic-gate return (EINVAL); 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate if (i_validate_nvpair_value(type, nelem, data) != 0) 851*7c478bd9Sstevel@tonic-gate return (EINVAL); 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate switch (type) { 854*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 855*7c478bd9Sstevel@tonic-gate /* 856*7c478bd9Sstevel@tonic-gate * Disallow adding oneself to oneself, avoid infinite recursion 857*7c478bd9Sstevel@tonic-gate */ 858*7c478bd9Sstevel@tonic-gate if ((nvlist_t *)data == nvl) 859*7c478bd9Sstevel@tonic-gate return (EINVAL); 860*7c478bd9Sstevel@tonic-gate break; 861*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 862*7c478bd9Sstevel@tonic-gate nvlist_t **lists = (nvlist_t **)data; 863*7c478bd9Sstevel@tonic-gate uint_t l; 864*7c478bd9Sstevel@tonic-gate for (l = 0; l < nelem; l++) 865*7c478bd9Sstevel@tonic-gate if (*lists++ == nvl) 866*7c478bd9Sstevel@tonic-gate return (EINVAL); 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate break; 869*7c478bd9Sstevel@tonic-gate default: 870*7c478bd9Sstevel@tonic-gate break; 871*7c478bd9Sstevel@tonic-gate } 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate /* calculate sizes of the nvpair elements and the nvpair itself */ 874*7c478bd9Sstevel@tonic-gate name_sz = strlen(name) + 1; 875*7c478bd9Sstevel@tonic-gate 876*7c478bd9Sstevel@tonic-gate nvp_sz = NVP_SIZE_CALC(name_sz, value_sz); 877*7c478bd9Sstevel@tonic-gate 878*7c478bd9Sstevel@tonic-gate if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL) 879*7c478bd9Sstevel@tonic-gate return (ENOMEM); 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate ASSERT(nvp->nvp_size == nvp_sz); 882*7c478bd9Sstevel@tonic-gate nvp->nvp_name_sz = name_sz; 883*7c478bd9Sstevel@tonic-gate nvp->nvp_value_elem = nelem; 884*7c478bd9Sstevel@tonic-gate nvp->nvp_type = type; 885*7c478bd9Sstevel@tonic-gate bcopy(name, NVP_NAME(nvp), name_sz); 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate switch (type) { 888*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 889*7c478bd9Sstevel@tonic-gate break; 890*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: { 891*7c478bd9Sstevel@tonic-gate int i; 892*7c478bd9Sstevel@tonic-gate char *const *strs = data; 893*7c478bd9Sstevel@tonic-gate char *buf = NVP_VALUE(nvp); 894*7c478bd9Sstevel@tonic-gate char **cstrs = (void *)buf; 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate /* skip pre-allocated space for pointer array */ 897*7c478bd9Sstevel@tonic-gate buf += nelem * sizeof (uint64_t); 898*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 899*7c478bd9Sstevel@tonic-gate int slen = strlen(strs[i]) + 1; 900*7c478bd9Sstevel@tonic-gate bcopy(strs[i], buf, slen); 901*7c478bd9Sstevel@tonic-gate cstrs[i] = buf; 902*7c478bd9Sstevel@tonic-gate buf += slen; 903*7c478bd9Sstevel@tonic-gate } 904*7c478bd9Sstevel@tonic-gate break; 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: { 907*7c478bd9Sstevel@tonic-gate nvlist_t *nnvl = EMBEDDED_NVL(nvp); 908*7c478bd9Sstevel@tonic-gate nvlist_t *onvl = (nvlist_t *)data; 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) { 911*7c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 912*7c478bd9Sstevel@tonic-gate return (err); 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate break; 915*7c478bd9Sstevel@tonic-gate } 916*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 917*7c478bd9Sstevel@tonic-gate nvlist_t **onvlp = (nvlist_t **)data; 918*7c478bd9Sstevel@tonic-gate nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 919*7c478bd9Sstevel@tonic-gate nvlist_t *embedded = (nvlist_t *) 920*7c478bd9Sstevel@tonic-gate ((uintptr_t)nvlp + nelem * sizeof (uint64_t)); 921*7c478bd9Sstevel@tonic-gate int i; 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 924*7c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_embedded(nvl, 925*7c478bd9Sstevel@tonic-gate onvlp[i], embedded)) != 0) { 926*7c478bd9Sstevel@tonic-gate /* 927*7c478bd9Sstevel@tonic-gate * Free any successfully created lists 928*7c478bd9Sstevel@tonic-gate */ 929*7c478bd9Sstevel@tonic-gate nvpair_free(nvp); 930*7c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 931*7c478bd9Sstevel@tonic-gate return (err); 932*7c478bd9Sstevel@tonic-gate } 933*7c478bd9Sstevel@tonic-gate 934*7c478bd9Sstevel@tonic-gate nvlp[i] = embedded++; 935*7c478bd9Sstevel@tonic-gate } 936*7c478bd9Sstevel@tonic-gate break; 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate default: 939*7c478bd9Sstevel@tonic-gate bcopy(data, NVP_VALUE(nvp), value_sz); 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate /* if unique name, remove before add */ 943*7c478bd9Sstevel@tonic-gate if (nvl->nvl_nvflag & NV_UNIQUE_NAME) 944*7c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(nvl, name); 945*7c478bd9Sstevel@tonic-gate else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE) 946*7c478bd9Sstevel@tonic-gate (void) nvlist_remove(nvl, name, type); 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate nvp_buf_link(nvl, nvp); 949*7c478bd9Sstevel@tonic-gate 950*7c478bd9Sstevel@tonic-gate return (0); 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate int 954*7c478bd9Sstevel@tonic-gate nvlist_add_boolean(nvlist_t *nvl, const char *name) 955*7c478bd9Sstevel@tonic-gate { 956*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL)); 957*7c478bd9Sstevel@tonic-gate } 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate int 960*7c478bd9Sstevel@tonic-gate nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val) 961*7c478bd9Sstevel@tonic-gate { 962*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val)); 963*7c478bd9Sstevel@tonic-gate } 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate int 966*7c478bd9Sstevel@tonic-gate nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val) 967*7c478bd9Sstevel@tonic-gate { 968*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val)); 969*7c478bd9Sstevel@tonic-gate } 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate int 972*7c478bd9Sstevel@tonic-gate nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val) 973*7c478bd9Sstevel@tonic-gate { 974*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val)); 975*7c478bd9Sstevel@tonic-gate } 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate int 978*7c478bd9Sstevel@tonic-gate nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val) 979*7c478bd9Sstevel@tonic-gate { 980*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val)); 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate int 984*7c478bd9Sstevel@tonic-gate nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val) 985*7c478bd9Sstevel@tonic-gate { 986*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val)); 987*7c478bd9Sstevel@tonic-gate } 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate int 990*7c478bd9Sstevel@tonic-gate nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val) 991*7c478bd9Sstevel@tonic-gate { 992*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val)); 993*7c478bd9Sstevel@tonic-gate } 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate int 996*7c478bd9Sstevel@tonic-gate nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val) 997*7c478bd9Sstevel@tonic-gate { 998*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val)); 999*7c478bd9Sstevel@tonic-gate } 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate int 1002*7c478bd9Sstevel@tonic-gate nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val) 1003*7c478bd9Sstevel@tonic-gate { 1004*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val)); 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate int 1008*7c478bd9Sstevel@tonic-gate nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val) 1009*7c478bd9Sstevel@tonic-gate { 1010*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val)); 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate 1013*7c478bd9Sstevel@tonic-gate int 1014*7c478bd9Sstevel@tonic-gate nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val) 1015*7c478bd9Sstevel@tonic-gate { 1016*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val)); 1017*7c478bd9Sstevel@tonic-gate } 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate int 1020*7c478bd9Sstevel@tonic-gate nvlist_add_string(nvlist_t *nvl, const char *name, const char *val) 1021*7c478bd9Sstevel@tonic-gate { 1022*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val)); 1023*7c478bd9Sstevel@tonic-gate } 1024*7c478bd9Sstevel@tonic-gate 1025*7c478bd9Sstevel@tonic-gate int 1026*7c478bd9Sstevel@tonic-gate nvlist_add_boolean_array(nvlist_t *nvl, const char *name, 1027*7c478bd9Sstevel@tonic-gate boolean_t *a, uint_t n) 1028*7c478bd9Sstevel@tonic-gate { 1029*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1030*7c478bd9Sstevel@tonic-gate } 1031*7c478bd9Sstevel@tonic-gate 1032*7c478bd9Sstevel@tonic-gate int 1033*7c478bd9Sstevel@tonic-gate nvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *a, uint_t n) 1034*7c478bd9Sstevel@tonic-gate { 1035*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate int 1039*7c478bd9Sstevel@tonic-gate nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint_t n) 1040*7c478bd9Sstevel@tonic-gate { 1041*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1042*7c478bd9Sstevel@tonic-gate } 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate int 1045*7c478bd9Sstevel@tonic-gate nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint_t n) 1046*7c478bd9Sstevel@tonic-gate { 1047*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1048*7c478bd9Sstevel@tonic-gate } 1049*7c478bd9Sstevel@tonic-gate 1050*7c478bd9Sstevel@tonic-gate int 1051*7c478bd9Sstevel@tonic-gate nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint_t n) 1052*7c478bd9Sstevel@tonic-gate { 1053*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1054*7c478bd9Sstevel@tonic-gate } 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate int 1057*7c478bd9Sstevel@tonic-gate nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, uint_t n) 1058*7c478bd9Sstevel@tonic-gate { 1059*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1060*7c478bd9Sstevel@tonic-gate } 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate int 1063*7c478bd9Sstevel@tonic-gate nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint_t n) 1064*7c478bd9Sstevel@tonic-gate { 1065*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1066*7c478bd9Sstevel@tonic-gate } 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate int 1069*7c478bd9Sstevel@tonic-gate nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, uint_t n) 1070*7c478bd9Sstevel@tonic-gate { 1071*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1072*7c478bd9Sstevel@tonic-gate } 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate int 1075*7c478bd9Sstevel@tonic-gate nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint_t n) 1076*7c478bd9Sstevel@tonic-gate { 1077*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1078*7c478bd9Sstevel@tonic-gate } 1079*7c478bd9Sstevel@tonic-gate 1080*7c478bd9Sstevel@tonic-gate int 1081*7c478bd9Sstevel@tonic-gate nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, uint_t n) 1082*7c478bd9Sstevel@tonic-gate { 1083*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1084*7c478bd9Sstevel@tonic-gate } 1085*7c478bd9Sstevel@tonic-gate 1086*7c478bd9Sstevel@tonic-gate int 1087*7c478bd9Sstevel@tonic-gate nvlist_add_string_array(nvlist_t *nvl, const char *name, 1088*7c478bd9Sstevel@tonic-gate char *const *a, uint_t n) 1089*7c478bd9Sstevel@tonic-gate { 1090*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1091*7c478bd9Sstevel@tonic-gate } 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate int 1094*7c478bd9Sstevel@tonic-gate nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val) 1095*7c478bd9Sstevel@tonic-gate { 1096*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val)); 1097*7c478bd9Sstevel@tonic-gate } 1098*7c478bd9Sstevel@tonic-gate 1099*7c478bd9Sstevel@tonic-gate int 1100*7c478bd9Sstevel@tonic-gate nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) 1101*7c478bd9Sstevel@tonic-gate { 1102*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); 1103*7c478bd9Sstevel@tonic-gate } 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate int 1106*7c478bd9Sstevel@tonic-gate nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, uint_t n) 1107*7c478bd9Sstevel@tonic-gate { 1108*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate /* reading name-value pairs */ 1112*7c478bd9Sstevel@tonic-gate nvpair_t * 1113*7c478bd9Sstevel@tonic-gate nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1114*7c478bd9Sstevel@tonic-gate { 1115*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 1116*7c478bd9Sstevel@tonic-gate i_nvp_t *curr; 1117*7c478bd9Sstevel@tonic-gate 1118*7c478bd9Sstevel@tonic-gate if (nvl == NULL || 1119*7c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1120*7c478bd9Sstevel@tonic-gate return (NULL); 1121*7c478bd9Sstevel@tonic-gate 1122*7c478bd9Sstevel@tonic-gate curr = NVPAIR2I_NVP(nvp); 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate /* 1125*7c478bd9Sstevel@tonic-gate * Ensure that nvp is an valid pointer. 1126*7c478bd9Sstevel@tonic-gate */ 1127*7c478bd9Sstevel@tonic-gate if (nvp == NULL) 1128*7c478bd9Sstevel@tonic-gate curr = priv->nvp_list; 1129*7c478bd9Sstevel@tonic-gate else if (priv->nvp_curr == curr) 1130*7c478bd9Sstevel@tonic-gate curr = curr->nvi_next; 1131*7c478bd9Sstevel@tonic-gate else if (nvlist_contains_nvp(nvl, nvp) == 0) 1132*7c478bd9Sstevel@tonic-gate curr = NULL; 1133*7c478bd9Sstevel@tonic-gate 1134*7c478bd9Sstevel@tonic-gate priv->nvp_curr = curr; 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate return (curr != NULL ? &curr->nvi_nvp : NULL); 1137*7c478bd9Sstevel@tonic-gate } 1138*7c478bd9Sstevel@tonic-gate 1139*7c478bd9Sstevel@tonic-gate char * 1140*7c478bd9Sstevel@tonic-gate nvpair_name(nvpair_t *nvp) 1141*7c478bd9Sstevel@tonic-gate { 1142*7c478bd9Sstevel@tonic-gate return (NVP_NAME(nvp)); 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate data_type_t 1146*7c478bd9Sstevel@tonic-gate nvpair_type(nvpair_t *nvp) 1147*7c478bd9Sstevel@tonic-gate { 1148*7c478bd9Sstevel@tonic-gate return (NVP_TYPE(nvp)); 1149*7c478bd9Sstevel@tonic-gate } 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate static int 1152*7c478bd9Sstevel@tonic-gate nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data) 1153*7c478bd9Sstevel@tonic-gate { 1154*7c478bd9Sstevel@tonic-gate if (nvp == NULL || nvpair_type(nvp) != type) 1155*7c478bd9Sstevel@tonic-gate return (EINVAL); 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate /* 1158*7c478bd9Sstevel@tonic-gate * For non-array types, we copy the data. 1159*7c478bd9Sstevel@tonic-gate * For array types (including string), we set a pointer. 1160*7c478bd9Sstevel@tonic-gate */ 1161*7c478bd9Sstevel@tonic-gate switch (type) { 1162*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 1163*7c478bd9Sstevel@tonic-gate if (nelem != NULL) 1164*7c478bd9Sstevel@tonic-gate *nelem = 0; 1165*7c478bd9Sstevel@tonic-gate break; 1166*7c478bd9Sstevel@tonic-gate 1167*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 1168*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 1169*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 1170*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 1171*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 1172*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 1173*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 1174*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 1175*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 1176*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 1177*7c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 1178*7c478bd9Sstevel@tonic-gate if (data == NULL) 1179*7c478bd9Sstevel@tonic-gate return (EINVAL); 1180*7c478bd9Sstevel@tonic-gate bcopy(NVP_VALUE(nvp), data, 1181*7c478bd9Sstevel@tonic-gate (size_t)i_get_value_size(type, NULL, 1)); 1182*7c478bd9Sstevel@tonic-gate if (nelem != NULL) 1183*7c478bd9Sstevel@tonic-gate *nelem = 1; 1184*7c478bd9Sstevel@tonic-gate break; 1185*7c478bd9Sstevel@tonic-gate 1186*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 1187*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 1188*7c478bd9Sstevel@tonic-gate if (data == NULL) 1189*7c478bd9Sstevel@tonic-gate return (EINVAL); 1190*7c478bd9Sstevel@tonic-gate *(void **)data = (void *)NVP_VALUE(nvp); 1191*7c478bd9Sstevel@tonic-gate if (nelem != NULL) 1192*7c478bd9Sstevel@tonic-gate *nelem = 1; 1193*7c478bd9Sstevel@tonic-gate break; 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 1196*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 1197*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 1198*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 1199*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 1200*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 1201*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 1202*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 1203*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 1204*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 1205*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 1206*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 1207*7c478bd9Sstevel@tonic-gate if (nelem == NULL || data == NULL) 1208*7c478bd9Sstevel@tonic-gate return (EINVAL); 1209*7c478bd9Sstevel@tonic-gate if ((*nelem = NVP_NELEM(nvp)) != 0) 1210*7c478bd9Sstevel@tonic-gate *(void **)data = (void *)NVP_VALUE(nvp); 1211*7c478bd9Sstevel@tonic-gate else 1212*7c478bd9Sstevel@tonic-gate *(void **)data = NULL; 1213*7c478bd9Sstevel@tonic-gate break; 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate default: 1216*7c478bd9Sstevel@tonic-gate return (ENOTSUP); 1217*7c478bd9Sstevel@tonic-gate } 1218*7c478bd9Sstevel@tonic-gate 1219*7c478bd9Sstevel@tonic-gate return (0); 1220*7c478bd9Sstevel@tonic-gate } 1221*7c478bd9Sstevel@tonic-gate 1222*7c478bd9Sstevel@tonic-gate static int 1223*7c478bd9Sstevel@tonic-gate nvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type, 1224*7c478bd9Sstevel@tonic-gate uint_t *nelem, void *data) 1225*7c478bd9Sstevel@tonic-gate { 1226*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 1227*7c478bd9Sstevel@tonic-gate nvpair_t *nvp; 1228*7c478bd9Sstevel@tonic-gate i_nvp_t *curr; 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate if (name == NULL || nvl == NULL || 1231*7c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1232*7c478bd9Sstevel@tonic-gate return (EINVAL); 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE))) 1235*7c478bd9Sstevel@tonic-gate return (ENOTSUP); 1236*7c478bd9Sstevel@tonic-gate 1237*7c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 1238*7c478bd9Sstevel@tonic-gate nvp = &curr->nvi_nvp; 1239*7c478bd9Sstevel@tonic-gate 1240*7c478bd9Sstevel@tonic-gate if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) 1241*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, type, nelem, data)); 1242*7c478bd9Sstevel@tonic-gate } 1243*7c478bd9Sstevel@tonic-gate 1244*7c478bd9Sstevel@tonic-gate return (ENOENT); 1245*7c478bd9Sstevel@tonic-gate } 1246*7c478bd9Sstevel@tonic-gate 1247*7c478bd9Sstevel@tonic-gate int 1248*7c478bd9Sstevel@tonic-gate nvlist_lookup_boolean(nvlist_t *nvl, const char *name) 1249*7c478bd9Sstevel@tonic-gate { 1250*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL)); 1251*7c478bd9Sstevel@tonic-gate } 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate int 1254*7c478bd9Sstevel@tonic-gate nvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val) 1255*7c478bd9Sstevel@tonic-gate { 1256*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, 1257*7c478bd9Sstevel@tonic-gate DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 1258*7c478bd9Sstevel@tonic-gate } 1259*7c478bd9Sstevel@tonic-gate 1260*7c478bd9Sstevel@tonic-gate int 1261*7c478bd9Sstevel@tonic-gate nvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val) 1262*7c478bd9Sstevel@tonic-gate { 1263*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val)); 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate 1266*7c478bd9Sstevel@tonic-gate int 1267*7c478bd9Sstevel@tonic-gate nvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val) 1268*7c478bd9Sstevel@tonic-gate { 1269*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val)); 1270*7c478bd9Sstevel@tonic-gate } 1271*7c478bd9Sstevel@tonic-gate 1272*7c478bd9Sstevel@tonic-gate int 1273*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val) 1274*7c478bd9Sstevel@tonic-gate { 1275*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val)); 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate int 1279*7c478bd9Sstevel@tonic-gate nvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val) 1280*7c478bd9Sstevel@tonic-gate { 1281*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val)); 1282*7c478bd9Sstevel@tonic-gate } 1283*7c478bd9Sstevel@tonic-gate 1284*7c478bd9Sstevel@tonic-gate int 1285*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val) 1286*7c478bd9Sstevel@tonic-gate { 1287*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val)); 1288*7c478bd9Sstevel@tonic-gate } 1289*7c478bd9Sstevel@tonic-gate 1290*7c478bd9Sstevel@tonic-gate int 1291*7c478bd9Sstevel@tonic-gate nvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val) 1292*7c478bd9Sstevel@tonic-gate { 1293*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val)); 1294*7c478bd9Sstevel@tonic-gate } 1295*7c478bd9Sstevel@tonic-gate 1296*7c478bd9Sstevel@tonic-gate int 1297*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val) 1298*7c478bd9Sstevel@tonic-gate { 1299*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val)); 1300*7c478bd9Sstevel@tonic-gate } 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate int 1303*7c478bd9Sstevel@tonic-gate nvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val) 1304*7c478bd9Sstevel@tonic-gate { 1305*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val)); 1306*7c478bd9Sstevel@tonic-gate } 1307*7c478bd9Sstevel@tonic-gate 1308*7c478bd9Sstevel@tonic-gate int 1309*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val) 1310*7c478bd9Sstevel@tonic-gate { 1311*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val)); 1312*7c478bd9Sstevel@tonic-gate } 1313*7c478bd9Sstevel@tonic-gate 1314*7c478bd9Sstevel@tonic-gate int 1315*7c478bd9Sstevel@tonic-gate nvlist_lookup_string(nvlist_t *nvl, const char *name, char **val) 1316*7c478bd9Sstevel@tonic-gate { 1317*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val)); 1318*7c478bd9Sstevel@tonic-gate } 1319*7c478bd9Sstevel@tonic-gate 1320*7c478bd9Sstevel@tonic-gate int 1321*7c478bd9Sstevel@tonic-gate nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val) 1322*7c478bd9Sstevel@tonic-gate { 1323*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val)); 1324*7c478bd9Sstevel@tonic-gate } 1325*7c478bd9Sstevel@tonic-gate 1326*7c478bd9Sstevel@tonic-gate int 1327*7c478bd9Sstevel@tonic-gate nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name, 1328*7c478bd9Sstevel@tonic-gate boolean_t **a, uint_t *n) 1329*7c478bd9Sstevel@tonic-gate { 1330*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, 1331*7c478bd9Sstevel@tonic-gate DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1332*7c478bd9Sstevel@tonic-gate } 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate int 1335*7c478bd9Sstevel@tonic-gate nvlist_lookup_byte_array(nvlist_t *nvl, const char *name, 1336*7c478bd9Sstevel@tonic-gate uchar_t **a, uint_t *n) 1337*7c478bd9Sstevel@tonic-gate { 1338*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1339*7c478bd9Sstevel@tonic-gate } 1340*7c478bd9Sstevel@tonic-gate 1341*7c478bd9Sstevel@tonic-gate int 1342*7c478bd9Sstevel@tonic-gate nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n) 1343*7c478bd9Sstevel@tonic-gate { 1344*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1345*7c478bd9Sstevel@tonic-gate } 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate int 1348*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name, 1349*7c478bd9Sstevel@tonic-gate uint8_t **a, uint_t *n) 1350*7c478bd9Sstevel@tonic-gate { 1351*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1352*7c478bd9Sstevel@tonic-gate } 1353*7c478bd9Sstevel@tonic-gate 1354*7c478bd9Sstevel@tonic-gate int 1355*7c478bd9Sstevel@tonic-gate nvlist_lookup_int16_array(nvlist_t *nvl, const char *name, 1356*7c478bd9Sstevel@tonic-gate int16_t **a, uint_t *n) 1357*7c478bd9Sstevel@tonic-gate { 1358*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate int 1362*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name, 1363*7c478bd9Sstevel@tonic-gate uint16_t **a, uint_t *n) 1364*7c478bd9Sstevel@tonic-gate { 1365*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1366*7c478bd9Sstevel@tonic-gate } 1367*7c478bd9Sstevel@tonic-gate 1368*7c478bd9Sstevel@tonic-gate int 1369*7c478bd9Sstevel@tonic-gate nvlist_lookup_int32_array(nvlist_t *nvl, const char *name, 1370*7c478bd9Sstevel@tonic-gate int32_t **a, uint_t *n) 1371*7c478bd9Sstevel@tonic-gate { 1372*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1373*7c478bd9Sstevel@tonic-gate } 1374*7c478bd9Sstevel@tonic-gate 1375*7c478bd9Sstevel@tonic-gate int 1376*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name, 1377*7c478bd9Sstevel@tonic-gate uint32_t **a, uint_t *n) 1378*7c478bd9Sstevel@tonic-gate { 1379*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1380*7c478bd9Sstevel@tonic-gate } 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate int 1383*7c478bd9Sstevel@tonic-gate nvlist_lookup_int64_array(nvlist_t *nvl, const char *name, 1384*7c478bd9Sstevel@tonic-gate int64_t **a, uint_t *n) 1385*7c478bd9Sstevel@tonic-gate { 1386*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1387*7c478bd9Sstevel@tonic-gate } 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate int 1390*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name, 1391*7c478bd9Sstevel@tonic-gate uint64_t **a, uint_t *n) 1392*7c478bd9Sstevel@tonic-gate { 1393*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1394*7c478bd9Sstevel@tonic-gate } 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate int 1397*7c478bd9Sstevel@tonic-gate nvlist_lookup_string_array(nvlist_t *nvl, const char *name, 1398*7c478bd9Sstevel@tonic-gate char ***a, uint_t *n) 1399*7c478bd9Sstevel@tonic-gate { 1400*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate int 1404*7c478bd9Sstevel@tonic-gate nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name, 1405*7c478bd9Sstevel@tonic-gate nvlist_t ***a, uint_t *n) 1406*7c478bd9Sstevel@tonic-gate { 1407*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1408*7c478bd9Sstevel@tonic-gate } 1409*7c478bd9Sstevel@tonic-gate 1410*7c478bd9Sstevel@tonic-gate int 1411*7c478bd9Sstevel@tonic-gate nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val) 1412*7c478bd9Sstevel@tonic-gate { 1413*7c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val)); 1414*7c478bd9Sstevel@tonic-gate } 1415*7c478bd9Sstevel@tonic-gate 1416*7c478bd9Sstevel@tonic-gate int 1417*7c478bd9Sstevel@tonic-gate nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...) 1418*7c478bd9Sstevel@tonic-gate { 1419*7c478bd9Sstevel@tonic-gate va_list ap; 1420*7c478bd9Sstevel@tonic-gate char *name; 1421*7c478bd9Sstevel@tonic-gate int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0); 1422*7c478bd9Sstevel@tonic-gate int ret = 0; 1423*7c478bd9Sstevel@tonic-gate 1424*7c478bd9Sstevel@tonic-gate va_start(ap, flag); 1425*7c478bd9Sstevel@tonic-gate while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { 1426*7c478bd9Sstevel@tonic-gate data_type_t type; 1427*7c478bd9Sstevel@tonic-gate void *val; 1428*7c478bd9Sstevel@tonic-gate uint_t *nelem; 1429*7c478bd9Sstevel@tonic-gate 1430*7c478bd9Sstevel@tonic-gate switch (type = va_arg(ap, data_type_t)) { 1431*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 1432*7c478bd9Sstevel@tonic-gate ret = nvlist_lookup_common(nvl, name, type, NULL, NULL); 1433*7c478bd9Sstevel@tonic-gate break; 1434*7c478bd9Sstevel@tonic-gate 1435*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 1436*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 1437*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 1438*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 1439*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 1440*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 1441*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 1442*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 1443*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 1444*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 1445*7c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 1446*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 1447*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 1448*7c478bd9Sstevel@tonic-gate val = va_arg(ap, void *); 1449*7c478bd9Sstevel@tonic-gate ret = nvlist_lookup_common(nvl, name, type, NULL, val); 1450*7c478bd9Sstevel@tonic-gate break; 1451*7c478bd9Sstevel@tonic-gate 1452*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 1453*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 1454*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 1455*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 1456*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 1457*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 1458*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 1459*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 1460*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 1461*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 1462*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 1463*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 1464*7c478bd9Sstevel@tonic-gate val = va_arg(ap, void *); 1465*7c478bd9Sstevel@tonic-gate nelem = va_arg(ap, uint_t *); 1466*7c478bd9Sstevel@tonic-gate ret = nvlist_lookup_common(nvl, name, type, nelem, val); 1467*7c478bd9Sstevel@tonic-gate break; 1468*7c478bd9Sstevel@tonic-gate 1469*7c478bd9Sstevel@tonic-gate default: 1470*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate if (ret == ENOENT && noentok) 1474*7c478bd9Sstevel@tonic-gate ret = 0; 1475*7c478bd9Sstevel@tonic-gate } 1476*7c478bd9Sstevel@tonic-gate va_end(ap); 1477*7c478bd9Sstevel@tonic-gate 1478*7c478bd9Sstevel@tonic-gate return (ret); 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate int 1482*7c478bd9Sstevel@tonic-gate nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val) 1483*7c478bd9Sstevel@tonic-gate { 1484*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 1485*7c478bd9Sstevel@tonic-gate } 1486*7c478bd9Sstevel@tonic-gate 1487*7c478bd9Sstevel@tonic-gate int 1488*7c478bd9Sstevel@tonic-gate nvpair_value_byte(nvpair_t *nvp, uchar_t *val) 1489*7c478bd9Sstevel@tonic-gate { 1490*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val)); 1491*7c478bd9Sstevel@tonic-gate } 1492*7c478bd9Sstevel@tonic-gate 1493*7c478bd9Sstevel@tonic-gate int 1494*7c478bd9Sstevel@tonic-gate nvpair_value_int8(nvpair_t *nvp, int8_t *val) 1495*7c478bd9Sstevel@tonic-gate { 1496*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val)); 1497*7c478bd9Sstevel@tonic-gate } 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate int 1500*7c478bd9Sstevel@tonic-gate nvpair_value_uint8(nvpair_t *nvp, uint8_t *val) 1501*7c478bd9Sstevel@tonic-gate { 1502*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val)); 1503*7c478bd9Sstevel@tonic-gate } 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate int 1506*7c478bd9Sstevel@tonic-gate nvpair_value_int16(nvpair_t *nvp, int16_t *val) 1507*7c478bd9Sstevel@tonic-gate { 1508*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val)); 1509*7c478bd9Sstevel@tonic-gate } 1510*7c478bd9Sstevel@tonic-gate 1511*7c478bd9Sstevel@tonic-gate int 1512*7c478bd9Sstevel@tonic-gate nvpair_value_uint16(nvpair_t *nvp, uint16_t *val) 1513*7c478bd9Sstevel@tonic-gate { 1514*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val)); 1515*7c478bd9Sstevel@tonic-gate } 1516*7c478bd9Sstevel@tonic-gate 1517*7c478bd9Sstevel@tonic-gate int 1518*7c478bd9Sstevel@tonic-gate nvpair_value_int32(nvpair_t *nvp, int32_t *val) 1519*7c478bd9Sstevel@tonic-gate { 1520*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val)); 1521*7c478bd9Sstevel@tonic-gate } 1522*7c478bd9Sstevel@tonic-gate 1523*7c478bd9Sstevel@tonic-gate int 1524*7c478bd9Sstevel@tonic-gate nvpair_value_uint32(nvpair_t *nvp, uint32_t *val) 1525*7c478bd9Sstevel@tonic-gate { 1526*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val)); 1527*7c478bd9Sstevel@tonic-gate } 1528*7c478bd9Sstevel@tonic-gate 1529*7c478bd9Sstevel@tonic-gate int 1530*7c478bd9Sstevel@tonic-gate nvpair_value_int64(nvpair_t *nvp, int64_t *val) 1531*7c478bd9Sstevel@tonic-gate { 1532*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val)); 1533*7c478bd9Sstevel@tonic-gate } 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate int 1536*7c478bd9Sstevel@tonic-gate nvpair_value_uint64(nvpair_t *nvp, uint64_t *val) 1537*7c478bd9Sstevel@tonic-gate { 1538*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val)); 1539*7c478bd9Sstevel@tonic-gate } 1540*7c478bd9Sstevel@tonic-gate 1541*7c478bd9Sstevel@tonic-gate int 1542*7c478bd9Sstevel@tonic-gate nvpair_value_string(nvpair_t *nvp, char **val) 1543*7c478bd9Sstevel@tonic-gate { 1544*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val)); 1545*7c478bd9Sstevel@tonic-gate } 1546*7c478bd9Sstevel@tonic-gate 1547*7c478bd9Sstevel@tonic-gate int 1548*7c478bd9Sstevel@tonic-gate nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val) 1549*7c478bd9Sstevel@tonic-gate { 1550*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val)); 1551*7c478bd9Sstevel@tonic-gate } 1552*7c478bd9Sstevel@tonic-gate 1553*7c478bd9Sstevel@tonic-gate int 1554*7c478bd9Sstevel@tonic-gate nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem) 1555*7c478bd9Sstevel@tonic-gate { 1556*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val)); 1557*7c478bd9Sstevel@tonic-gate } 1558*7c478bd9Sstevel@tonic-gate 1559*7c478bd9Sstevel@tonic-gate int 1560*7c478bd9Sstevel@tonic-gate nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem) 1561*7c478bd9Sstevel@tonic-gate { 1562*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val)); 1563*7c478bd9Sstevel@tonic-gate } 1564*7c478bd9Sstevel@tonic-gate 1565*7c478bd9Sstevel@tonic-gate int 1566*7c478bd9Sstevel@tonic-gate nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem) 1567*7c478bd9Sstevel@tonic-gate { 1568*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val)); 1569*7c478bd9Sstevel@tonic-gate } 1570*7c478bd9Sstevel@tonic-gate 1571*7c478bd9Sstevel@tonic-gate int 1572*7c478bd9Sstevel@tonic-gate nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem) 1573*7c478bd9Sstevel@tonic-gate { 1574*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val)); 1575*7c478bd9Sstevel@tonic-gate } 1576*7c478bd9Sstevel@tonic-gate 1577*7c478bd9Sstevel@tonic-gate int 1578*7c478bd9Sstevel@tonic-gate nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem) 1579*7c478bd9Sstevel@tonic-gate { 1580*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val)); 1581*7c478bd9Sstevel@tonic-gate } 1582*7c478bd9Sstevel@tonic-gate 1583*7c478bd9Sstevel@tonic-gate int 1584*7c478bd9Sstevel@tonic-gate nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem) 1585*7c478bd9Sstevel@tonic-gate { 1586*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val)); 1587*7c478bd9Sstevel@tonic-gate } 1588*7c478bd9Sstevel@tonic-gate 1589*7c478bd9Sstevel@tonic-gate int 1590*7c478bd9Sstevel@tonic-gate nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem) 1591*7c478bd9Sstevel@tonic-gate { 1592*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val)); 1593*7c478bd9Sstevel@tonic-gate } 1594*7c478bd9Sstevel@tonic-gate 1595*7c478bd9Sstevel@tonic-gate int 1596*7c478bd9Sstevel@tonic-gate nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem) 1597*7c478bd9Sstevel@tonic-gate { 1598*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val)); 1599*7c478bd9Sstevel@tonic-gate } 1600*7c478bd9Sstevel@tonic-gate 1601*7c478bd9Sstevel@tonic-gate int 1602*7c478bd9Sstevel@tonic-gate nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem) 1603*7c478bd9Sstevel@tonic-gate { 1604*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val)); 1605*7c478bd9Sstevel@tonic-gate } 1606*7c478bd9Sstevel@tonic-gate 1607*7c478bd9Sstevel@tonic-gate int 1608*7c478bd9Sstevel@tonic-gate nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem) 1609*7c478bd9Sstevel@tonic-gate { 1610*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val)); 1611*7c478bd9Sstevel@tonic-gate } 1612*7c478bd9Sstevel@tonic-gate 1613*7c478bd9Sstevel@tonic-gate int 1614*7c478bd9Sstevel@tonic-gate nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem) 1615*7c478bd9Sstevel@tonic-gate { 1616*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val)); 1617*7c478bd9Sstevel@tonic-gate } 1618*7c478bd9Sstevel@tonic-gate 1619*7c478bd9Sstevel@tonic-gate int 1620*7c478bd9Sstevel@tonic-gate nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem) 1621*7c478bd9Sstevel@tonic-gate { 1622*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val)); 1623*7c478bd9Sstevel@tonic-gate } 1624*7c478bd9Sstevel@tonic-gate 1625*7c478bd9Sstevel@tonic-gate int 1626*7c478bd9Sstevel@tonic-gate nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val) 1627*7c478bd9Sstevel@tonic-gate { 1628*7c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val)); 1629*7c478bd9Sstevel@tonic-gate } 1630*7c478bd9Sstevel@tonic-gate 1631*7c478bd9Sstevel@tonic-gate /* 1632*7c478bd9Sstevel@tonic-gate * Add specified pair to the list. 1633*7c478bd9Sstevel@tonic-gate */ 1634*7c478bd9Sstevel@tonic-gate int 1635*7c478bd9Sstevel@tonic-gate nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1636*7c478bd9Sstevel@tonic-gate { 1637*7c478bd9Sstevel@tonic-gate if (nvl == NULL || nvp == NULL) 1638*7c478bd9Sstevel@tonic-gate return (EINVAL); 1639*7c478bd9Sstevel@tonic-gate 1640*7c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp), 1641*7c478bd9Sstevel@tonic-gate NVP_NELEM(nvp), NVP_VALUE(nvp))); 1642*7c478bd9Sstevel@tonic-gate } 1643*7c478bd9Sstevel@tonic-gate 1644*7c478bd9Sstevel@tonic-gate /* 1645*7c478bd9Sstevel@tonic-gate * Merge the supplied nvlists and put the result in dst. 1646*7c478bd9Sstevel@tonic-gate * The merged list will contain all names specified in both lists, 1647*7c478bd9Sstevel@tonic-gate * the values are taken from nvl in the case of duplicates. 1648*7c478bd9Sstevel@tonic-gate * Return 0 on success. 1649*7c478bd9Sstevel@tonic-gate */ 1650*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1651*7c478bd9Sstevel@tonic-gate int 1652*7c478bd9Sstevel@tonic-gate nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag) 1653*7c478bd9Sstevel@tonic-gate { 1654*7c478bd9Sstevel@tonic-gate if (nvl == NULL || dst == NULL) 1655*7c478bd9Sstevel@tonic-gate return (EINVAL); 1656*7c478bd9Sstevel@tonic-gate 1657*7c478bd9Sstevel@tonic-gate if (dst != nvl) 1658*7c478bd9Sstevel@tonic-gate return (nvlist_copy_pairs(nvl, dst)); 1659*7c478bd9Sstevel@tonic-gate 1660*7c478bd9Sstevel@tonic-gate return (0); 1661*7c478bd9Sstevel@tonic-gate } 1662*7c478bd9Sstevel@tonic-gate 1663*7c478bd9Sstevel@tonic-gate /* 1664*7c478bd9Sstevel@tonic-gate * Encoding related routines 1665*7c478bd9Sstevel@tonic-gate */ 1666*7c478bd9Sstevel@tonic-gate #define NVS_OP_ENCODE 0 1667*7c478bd9Sstevel@tonic-gate #define NVS_OP_DECODE 1 1668*7c478bd9Sstevel@tonic-gate #define NVS_OP_GETSIZE 2 1669*7c478bd9Sstevel@tonic-gate 1670*7c478bd9Sstevel@tonic-gate typedef struct nvs_ops nvs_ops_t; 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate typedef struct { 1673*7c478bd9Sstevel@tonic-gate int nvs_op; 1674*7c478bd9Sstevel@tonic-gate const nvs_ops_t *nvs_ops; 1675*7c478bd9Sstevel@tonic-gate void *nvs_private; 1676*7c478bd9Sstevel@tonic-gate nvpriv_t *nvs_priv; 1677*7c478bd9Sstevel@tonic-gate } nvstream_t; 1678*7c478bd9Sstevel@tonic-gate 1679*7c478bd9Sstevel@tonic-gate /* 1680*7c478bd9Sstevel@tonic-gate * nvs operations are: 1681*7c478bd9Sstevel@tonic-gate * - nvs_nvlist 1682*7c478bd9Sstevel@tonic-gate * encoding / decoding of a nvlist header (nvlist_t) 1683*7c478bd9Sstevel@tonic-gate * calculates the size used for header and end detection 1684*7c478bd9Sstevel@tonic-gate * 1685*7c478bd9Sstevel@tonic-gate * - nvs_nvpair 1686*7c478bd9Sstevel@tonic-gate * responsible for the first part of encoding / decoding of an nvpair 1687*7c478bd9Sstevel@tonic-gate * calculates the decoded size of an nvpair 1688*7c478bd9Sstevel@tonic-gate * 1689*7c478bd9Sstevel@tonic-gate * - nvs_nvp_op 1690*7c478bd9Sstevel@tonic-gate * second part of encoding / decoding of an nvpair 1691*7c478bd9Sstevel@tonic-gate * 1692*7c478bd9Sstevel@tonic-gate * - nvs_nvp_size 1693*7c478bd9Sstevel@tonic-gate * calculates the encoding size of an nvpair 1694*7c478bd9Sstevel@tonic-gate * 1695*7c478bd9Sstevel@tonic-gate * - nvs_nvl_fini 1696*7c478bd9Sstevel@tonic-gate * encodes the end detection mark (zeros). 1697*7c478bd9Sstevel@tonic-gate */ 1698*7c478bd9Sstevel@tonic-gate struct nvs_ops { 1699*7c478bd9Sstevel@tonic-gate int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *); 1700*7c478bd9Sstevel@tonic-gate int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *); 1701*7c478bd9Sstevel@tonic-gate int (*nvs_nvp_op)(nvstream_t *, nvpair_t *); 1702*7c478bd9Sstevel@tonic-gate int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *); 1703*7c478bd9Sstevel@tonic-gate int (*nvs_nvl_fini)(nvstream_t *); 1704*7c478bd9Sstevel@tonic-gate }; 1705*7c478bd9Sstevel@tonic-gate 1706*7c478bd9Sstevel@tonic-gate typedef struct { 1707*7c478bd9Sstevel@tonic-gate char nvh_encoding; /* nvs encoding method */ 1708*7c478bd9Sstevel@tonic-gate char nvh_endian; /* nvs endian */ 1709*7c478bd9Sstevel@tonic-gate char nvh_reserved1; /* reserved for future use */ 1710*7c478bd9Sstevel@tonic-gate char nvh_reserved2; /* reserved for future use */ 1711*7c478bd9Sstevel@tonic-gate } nvs_header_t; 1712*7c478bd9Sstevel@tonic-gate 1713*7c478bd9Sstevel@tonic-gate static int 1714*7c478bd9Sstevel@tonic-gate nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl) 1715*7c478bd9Sstevel@tonic-gate { 1716*7c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 1717*7c478bd9Sstevel@tonic-gate i_nvp_t *curr; 1718*7c478bd9Sstevel@tonic-gate 1719*7c478bd9Sstevel@tonic-gate /* 1720*7c478bd9Sstevel@tonic-gate * Walk nvpair in list and encode each nvpair 1721*7c478bd9Sstevel@tonic-gate */ 1722*7c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 1723*7c478bd9Sstevel@tonic-gate if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0) 1724*7c478bd9Sstevel@tonic-gate return (EFAULT); 1725*7c478bd9Sstevel@tonic-gate 1726*7c478bd9Sstevel@tonic-gate return (nvs->nvs_ops->nvs_nvl_fini(nvs)); 1727*7c478bd9Sstevel@tonic-gate } 1728*7c478bd9Sstevel@tonic-gate 1729*7c478bd9Sstevel@tonic-gate static int 1730*7c478bd9Sstevel@tonic-gate nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl) 1731*7c478bd9Sstevel@tonic-gate { 1732*7c478bd9Sstevel@tonic-gate nvpair_t *nvp; 1733*7c478bd9Sstevel@tonic-gate size_t nvsize; 1734*7c478bd9Sstevel@tonic-gate int err; 1735*7c478bd9Sstevel@tonic-gate 1736*7c478bd9Sstevel@tonic-gate /* 1737*7c478bd9Sstevel@tonic-gate * Get decoded size of next pair in stream, alloc 1738*7c478bd9Sstevel@tonic-gate * memory for nvpair_t, then decode the nvpair 1739*7c478bd9Sstevel@tonic-gate */ 1740*7c478bd9Sstevel@tonic-gate while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) { 1741*7c478bd9Sstevel@tonic-gate if (nvsize == 0) /* end of list */ 1742*7c478bd9Sstevel@tonic-gate break; 1743*7c478bd9Sstevel@tonic-gate 1744*7c478bd9Sstevel@tonic-gate /* make sure len makes sense */ 1745*7c478bd9Sstevel@tonic-gate if (nvsize < NVP_SIZE_CALC(1, 0)) 1746*7c478bd9Sstevel@tonic-gate return (EFAULT); 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL) 1749*7c478bd9Sstevel@tonic-gate return (ENOMEM); 1750*7c478bd9Sstevel@tonic-gate 1751*7c478bd9Sstevel@tonic-gate if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) { 1752*7c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 1753*7c478bd9Sstevel@tonic-gate return (err); 1754*7c478bd9Sstevel@tonic-gate } 1755*7c478bd9Sstevel@tonic-gate 1756*7c478bd9Sstevel@tonic-gate if (i_validate_nvpair(nvp) != 0) { 1757*7c478bd9Sstevel@tonic-gate nvpair_free(nvp); 1758*7c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp); 1759*7c478bd9Sstevel@tonic-gate return (EFAULT); 1760*7c478bd9Sstevel@tonic-gate } 1761*7c478bd9Sstevel@tonic-gate 1762*7c478bd9Sstevel@tonic-gate nvp_buf_link(nvl, nvp); 1763*7c478bd9Sstevel@tonic-gate } 1764*7c478bd9Sstevel@tonic-gate return (err); 1765*7c478bd9Sstevel@tonic-gate } 1766*7c478bd9Sstevel@tonic-gate 1767*7c478bd9Sstevel@tonic-gate static int 1768*7c478bd9Sstevel@tonic-gate nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 1769*7c478bd9Sstevel@tonic-gate { 1770*7c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 1771*7c478bd9Sstevel@tonic-gate i_nvp_t *curr; 1772*7c478bd9Sstevel@tonic-gate uint64_t nvsize = *buflen; 1773*7c478bd9Sstevel@tonic-gate size_t size; 1774*7c478bd9Sstevel@tonic-gate 1775*7c478bd9Sstevel@tonic-gate /* 1776*7c478bd9Sstevel@tonic-gate * Get encoded size of nvpairs in nvlist 1777*7c478bd9Sstevel@tonic-gate */ 1778*7c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 1779*7c478bd9Sstevel@tonic-gate if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0) 1780*7c478bd9Sstevel@tonic-gate return (EINVAL); 1781*7c478bd9Sstevel@tonic-gate 1782*7c478bd9Sstevel@tonic-gate if ((nvsize += size) > INT32_MAX) 1783*7c478bd9Sstevel@tonic-gate return (EINVAL); 1784*7c478bd9Sstevel@tonic-gate } 1785*7c478bd9Sstevel@tonic-gate 1786*7c478bd9Sstevel@tonic-gate *buflen = nvsize; 1787*7c478bd9Sstevel@tonic-gate return (0); 1788*7c478bd9Sstevel@tonic-gate } 1789*7c478bd9Sstevel@tonic-gate 1790*7c478bd9Sstevel@tonic-gate static int 1791*7c478bd9Sstevel@tonic-gate nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 1792*7c478bd9Sstevel@tonic-gate { 1793*7c478bd9Sstevel@tonic-gate int err; 1794*7c478bd9Sstevel@tonic-gate 1795*7c478bd9Sstevel@tonic-gate if (nvl->nvl_priv == NULL) 1796*7c478bd9Sstevel@tonic-gate return (EFAULT); 1797*7c478bd9Sstevel@tonic-gate 1798*7c478bd9Sstevel@tonic-gate /* 1799*7c478bd9Sstevel@tonic-gate * Perform the operation, starting with header, then each nvpair 1800*7c478bd9Sstevel@tonic-gate */ 1801*7c478bd9Sstevel@tonic-gate if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0) 1802*7c478bd9Sstevel@tonic-gate return (err); 1803*7c478bd9Sstevel@tonic-gate 1804*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 1805*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 1806*7c478bd9Sstevel@tonic-gate err = nvs_encode_pairs(nvs, nvl); 1807*7c478bd9Sstevel@tonic-gate break; 1808*7c478bd9Sstevel@tonic-gate 1809*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 1810*7c478bd9Sstevel@tonic-gate err = nvs_decode_pairs(nvs, nvl); 1811*7c478bd9Sstevel@tonic-gate break; 1812*7c478bd9Sstevel@tonic-gate 1813*7c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 1814*7c478bd9Sstevel@tonic-gate err = nvs_getsize_pairs(nvs, nvl, buflen); 1815*7c478bd9Sstevel@tonic-gate break; 1816*7c478bd9Sstevel@tonic-gate 1817*7c478bd9Sstevel@tonic-gate default: 1818*7c478bd9Sstevel@tonic-gate err = EINVAL; 1819*7c478bd9Sstevel@tonic-gate } 1820*7c478bd9Sstevel@tonic-gate 1821*7c478bd9Sstevel@tonic-gate return (err); 1822*7c478bd9Sstevel@tonic-gate } 1823*7c478bd9Sstevel@tonic-gate 1824*7c478bd9Sstevel@tonic-gate static int 1825*7c478bd9Sstevel@tonic-gate nvs_embedded(nvstream_t *nvs, nvlist_t *embedded) 1826*7c478bd9Sstevel@tonic-gate { 1827*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 1828*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 1829*7c478bd9Sstevel@tonic-gate return (nvs_operation(nvs, embedded, NULL)); 1830*7c478bd9Sstevel@tonic-gate 1831*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 1832*7c478bd9Sstevel@tonic-gate nvpriv_t *priv; 1833*7c478bd9Sstevel@tonic-gate int err; 1834*7c478bd9Sstevel@tonic-gate 1835*7c478bd9Sstevel@tonic-gate if (embedded->nvl_version != NV_VERSION) 1836*7c478bd9Sstevel@tonic-gate return (ENOTSUP); 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL) 1839*7c478bd9Sstevel@tonic-gate return (ENOMEM); 1840*7c478bd9Sstevel@tonic-gate 1841*7c478bd9Sstevel@tonic-gate nvlist_init(embedded, embedded->nvl_nvflag, priv); 1842*7c478bd9Sstevel@tonic-gate 1843*7c478bd9Sstevel@tonic-gate if ((err = nvs_operation(nvs, embedded, NULL)) != 0) 1844*7c478bd9Sstevel@tonic-gate nvlist_free(embedded); 1845*7c478bd9Sstevel@tonic-gate return (err); 1846*7c478bd9Sstevel@tonic-gate } 1847*7c478bd9Sstevel@tonic-gate default: 1848*7c478bd9Sstevel@tonic-gate break; 1849*7c478bd9Sstevel@tonic-gate } 1850*7c478bd9Sstevel@tonic-gate 1851*7c478bd9Sstevel@tonic-gate return (EINVAL); 1852*7c478bd9Sstevel@tonic-gate } 1853*7c478bd9Sstevel@tonic-gate 1854*7c478bd9Sstevel@tonic-gate static int 1855*7c478bd9Sstevel@tonic-gate nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 1856*7c478bd9Sstevel@tonic-gate { 1857*7c478bd9Sstevel@tonic-gate size_t nelem = NVP_NELEM(nvp); 1858*7c478bd9Sstevel@tonic-gate nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 1859*7c478bd9Sstevel@tonic-gate int i; 1860*7c478bd9Sstevel@tonic-gate 1861*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 1862*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 1863*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) 1864*7c478bd9Sstevel@tonic-gate if (nvs_embedded(nvs, nvlp[i]) != 0) 1865*7c478bd9Sstevel@tonic-gate return (EFAULT); 1866*7c478bd9Sstevel@tonic-gate break; 1867*7c478bd9Sstevel@tonic-gate 1868*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 1869*7c478bd9Sstevel@tonic-gate size_t len = nelem * sizeof (uint64_t); 1870*7c478bd9Sstevel@tonic-gate nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len); 1871*7c478bd9Sstevel@tonic-gate 1872*7c478bd9Sstevel@tonic-gate bzero(nvlp, len); /* don't trust packed data */ 1873*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 1874*7c478bd9Sstevel@tonic-gate if (nvs_embedded(nvs, embedded) != 0) { 1875*7c478bd9Sstevel@tonic-gate nvpair_free(nvp); 1876*7c478bd9Sstevel@tonic-gate return (EFAULT); 1877*7c478bd9Sstevel@tonic-gate } 1878*7c478bd9Sstevel@tonic-gate 1879*7c478bd9Sstevel@tonic-gate nvlp[i] = embedded++; 1880*7c478bd9Sstevel@tonic-gate } 1881*7c478bd9Sstevel@tonic-gate break; 1882*7c478bd9Sstevel@tonic-gate } 1883*7c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: { 1884*7c478bd9Sstevel@tonic-gate uint64_t nvsize = 0; 1885*7c478bd9Sstevel@tonic-gate 1886*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 1887*7c478bd9Sstevel@tonic-gate size_t nvp_sz = 0; 1888*7c478bd9Sstevel@tonic-gate 1889*7c478bd9Sstevel@tonic-gate if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0) 1890*7c478bd9Sstevel@tonic-gate return (EINVAL); 1891*7c478bd9Sstevel@tonic-gate 1892*7c478bd9Sstevel@tonic-gate if ((nvsize += nvp_sz) > INT32_MAX) 1893*7c478bd9Sstevel@tonic-gate return (EINVAL); 1894*7c478bd9Sstevel@tonic-gate } 1895*7c478bd9Sstevel@tonic-gate 1896*7c478bd9Sstevel@tonic-gate *size = nvsize; 1897*7c478bd9Sstevel@tonic-gate break; 1898*7c478bd9Sstevel@tonic-gate } 1899*7c478bd9Sstevel@tonic-gate default: 1900*7c478bd9Sstevel@tonic-gate return (EINVAL); 1901*7c478bd9Sstevel@tonic-gate } 1902*7c478bd9Sstevel@tonic-gate 1903*7c478bd9Sstevel@tonic-gate return (0); 1904*7c478bd9Sstevel@tonic-gate } 1905*7c478bd9Sstevel@tonic-gate 1906*7c478bd9Sstevel@tonic-gate static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *); 1907*7c478bd9Sstevel@tonic-gate static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *); 1908*7c478bd9Sstevel@tonic-gate 1909*7c478bd9Sstevel@tonic-gate /* 1910*7c478bd9Sstevel@tonic-gate * Common routine for nvlist operations: 1911*7c478bd9Sstevel@tonic-gate * encode, decode, getsize (encoded size). 1912*7c478bd9Sstevel@tonic-gate */ 1913*7c478bd9Sstevel@tonic-gate static int 1914*7c478bd9Sstevel@tonic-gate nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding, 1915*7c478bd9Sstevel@tonic-gate int nvs_op) 1916*7c478bd9Sstevel@tonic-gate { 1917*7c478bd9Sstevel@tonic-gate int err = 0; 1918*7c478bd9Sstevel@tonic-gate nvstream_t nvs; 1919*7c478bd9Sstevel@tonic-gate int nvl_endian; 1920*7c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 1921*7c478bd9Sstevel@tonic-gate int host_endian = 1; 1922*7c478bd9Sstevel@tonic-gate #else 1923*7c478bd9Sstevel@tonic-gate int host_endian = 0; 1924*7c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */ 1925*7c478bd9Sstevel@tonic-gate nvs_header_t *nvh = (void *)buf; 1926*7c478bd9Sstevel@tonic-gate 1927*7c478bd9Sstevel@tonic-gate if (buflen == NULL || nvl == NULL || 1928*7c478bd9Sstevel@tonic-gate (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1929*7c478bd9Sstevel@tonic-gate return (EINVAL); 1930*7c478bd9Sstevel@tonic-gate 1931*7c478bd9Sstevel@tonic-gate nvs.nvs_op = nvs_op; 1932*7c478bd9Sstevel@tonic-gate 1933*7c478bd9Sstevel@tonic-gate /* 1934*7c478bd9Sstevel@tonic-gate * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and 1935*7c478bd9Sstevel@tonic-gate * a buffer is allocated. The first 4 bytes in the buffer are 1936*7c478bd9Sstevel@tonic-gate * used for encoding method and host endian. 1937*7c478bd9Sstevel@tonic-gate */ 1938*7c478bd9Sstevel@tonic-gate switch (nvs_op) { 1939*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 1940*7c478bd9Sstevel@tonic-gate if (buf == NULL || *buflen < sizeof (nvs_header_t)) 1941*7c478bd9Sstevel@tonic-gate return (EINVAL); 1942*7c478bd9Sstevel@tonic-gate 1943*7c478bd9Sstevel@tonic-gate nvh->nvh_encoding = encoding; 1944*7c478bd9Sstevel@tonic-gate nvh->nvh_endian = nvl_endian = host_endian; 1945*7c478bd9Sstevel@tonic-gate nvh->nvh_reserved1 = 0; 1946*7c478bd9Sstevel@tonic-gate nvh->nvh_reserved2 = 0; 1947*7c478bd9Sstevel@tonic-gate break; 1948*7c478bd9Sstevel@tonic-gate 1949*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 1950*7c478bd9Sstevel@tonic-gate if (buf == NULL || *buflen < sizeof (nvs_header_t)) 1951*7c478bd9Sstevel@tonic-gate return (EINVAL); 1952*7c478bd9Sstevel@tonic-gate 1953*7c478bd9Sstevel@tonic-gate /* get method of encoding from first byte */ 1954*7c478bd9Sstevel@tonic-gate encoding = nvh->nvh_encoding; 1955*7c478bd9Sstevel@tonic-gate nvl_endian = nvh->nvh_endian; 1956*7c478bd9Sstevel@tonic-gate break; 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 1959*7c478bd9Sstevel@tonic-gate nvl_endian = host_endian; 1960*7c478bd9Sstevel@tonic-gate 1961*7c478bd9Sstevel@tonic-gate /* 1962*7c478bd9Sstevel@tonic-gate * add the size for encoding 1963*7c478bd9Sstevel@tonic-gate */ 1964*7c478bd9Sstevel@tonic-gate *buflen = sizeof (nvs_header_t); 1965*7c478bd9Sstevel@tonic-gate break; 1966*7c478bd9Sstevel@tonic-gate 1967*7c478bd9Sstevel@tonic-gate default: 1968*7c478bd9Sstevel@tonic-gate return (ENOTSUP); 1969*7c478bd9Sstevel@tonic-gate } 1970*7c478bd9Sstevel@tonic-gate 1971*7c478bd9Sstevel@tonic-gate /* 1972*7c478bd9Sstevel@tonic-gate * Create an nvstream with proper encoding method 1973*7c478bd9Sstevel@tonic-gate */ 1974*7c478bd9Sstevel@tonic-gate switch (encoding) { 1975*7c478bd9Sstevel@tonic-gate case NV_ENCODE_NATIVE: 1976*7c478bd9Sstevel@tonic-gate /* 1977*7c478bd9Sstevel@tonic-gate * check endianness, in case we are unpacking 1978*7c478bd9Sstevel@tonic-gate * from a file 1979*7c478bd9Sstevel@tonic-gate */ 1980*7c478bd9Sstevel@tonic-gate if (nvl_endian != host_endian) 1981*7c478bd9Sstevel@tonic-gate return (ENOTSUP); 1982*7c478bd9Sstevel@tonic-gate err = nvs_native(&nvs, nvl, buf, buflen); 1983*7c478bd9Sstevel@tonic-gate break; 1984*7c478bd9Sstevel@tonic-gate case NV_ENCODE_XDR: 1985*7c478bd9Sstevel@tonic-gate err = nvs_xdr(&nvs, nvl, buf, buflen); 1986*7c478bd9Sstevel@tonic-gate break; 1987*7c478bd9Sstevel@tonic-gate default: 1988*7c478bd9Sstevel@tonic-gate err = ENOTSUP; 1989*7c478bd9Sstevel@tonic-gate break; 1990*7c478bd9Sstevel@tonic-gate } 1991*7c478bd9Sstevel@tonic-gate 1992*7c478bd9Sstevel@tonic-gate return (err); 1993*7c478bd9Sstevel@tonic-gate } 1994*7c478bd9Sstevel@tonic-gate 1995*7c478bd9Sstevel@tonic-gate int 1996*7c478bd9Sstevel@tonic-gate nvlist_size(nvlist_t *nvl, size_t *size, int encoding) 1997*7c478bd9Sstevel@tonic-gate { 1998*7c478bd9Sstevel@tonic-gate return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE)); 1999*7c478bd9Sstevel@tonic-gate } 2000*7c478bd9Sstevel@tonic-gate 2001*7c478bd9Sstevel@tonic-gate /* 2002*7c478bd9Sstevel@tonic-gate * Pack nvlist into contiguous memory 2003*7c478bd9Sstevel@tonic-gate */ 2004*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 2005*7c478bd9Sstevel@tonic-gate int 2006*7c478bd9Sstevel@tonic-gate nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 2007*7c478bd9Sstevel@tonic-gate int kmflag) 2008*7c478bd9Sstevel@tonic-gate { 2009*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 2010*7c478bd9Sstevel@tonic-gate return (nvlist_xpack(nvl, bufp, buflen, encoding, 2011*7c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 2012*7c478bd9Sstevel@tonic-gate #else 2013*7c478bd9Sstevel@tonic-gate return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep)); 2014*7c478bd9Sstevel@tonic-gate #endif 2015*7c478bd9Sstevel@tonic-gate } 2016*7c478bd9Sstevel@tonic-gate 2017*7c478bd9Sstevel@tonic-gate int 2018*7c478bd9Sstevel@tonic-gate nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 2019*7c478bd9Sstevel@tonic-gate nv_alloc_t *nva) 2020*7c478bd9Sstevel@tonic-gate { 2021*7c478bd9Sstevel@tonic-gate nvpriv_t nvpriv; 2022*7c478bd9Sstevel@tonic-gate size_t alloc_size; 2023*7c478bd9Sstevel@tonic-gate char *buf; 2024*7c478bd9Sstevel@tonic-gate int err; 2025*7c478bd9Sstevel@tonic-gate 2026*7c478bd9Sstevel@tonic-gate if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL) 2027*7c478bd9Sstevel@tonic-gate return (EINVAL); 2028*7c478bd9Sstevel@tonic-gate 2029*7c478bd9Sstevel@tonic-gate if (*bufp != NULL) 2030*7c478bd9Sstevel@tonic-gate return (nvlist_common(nvl, *bufp, buflen, encoding, 2031*7c478bd9Sstevel@tonic-gate NVS_OP_ENCODE)); 2032*7c478bd9Sstevel@tonic-gate 2033*7c478bd9Sstevel@tonic-gate /* 2034*7c478bd9Sstevel@tonic-gate * Here is a difficult situation: 2035*7c478bd9Sstevel@tonic-gate * 1. The nvlist has fixed allocator properties. 2036*7c478bd9Sstevel@tonic-gate * All other nvlist routines (like nvlist_add_*, ...) use 2037*7c478bd9Sstevel@tonic-gate * these properties. 2038*7c478bd9Sstevel@tonic-gate * 2. When using nvlist_pack() the user can specify his own 2039*7c478bd9Sstevel@tonic-gate * allocator properties (e.g. by using KM_NOSLEEP). 2040*7c478bd9Sstevel@tonic-gate * 2041*7c478bd9Sstevel@tonic-gate * We use the user specified properties (2). A clearer solution 2042*7c478bd9Sstevel@tonic-gate * will be to remove the kmflag from nvlist_pack(), but we will 2043*7c478bd9Sstevel@tonic-gate * not change the interface. 2044*7c478bd9Sstevel@tonic-gate */ 2045*7c478bd9Sstevel@tonic-gate nv_priv_init(&nvpriv, nva, 0); 2046*7c478bd9Sstevel@tonic-gate 2047*7c478bd9Sstevel@tonic-gate if (err = nvlist_size(nvl, &alloc_size, encoding)) 2048*7c478bd9Sstevel@tonic-gate return (err); 2049*7c478bd9Sstevel@tonic-gate 2050*7c478bd9Sstevel@tonic-gate if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL) 2051*7c478bd9Sstevel@tonic-gate return (ENOMEM); 2052*7c478bd9Sstevel@tonic-gate 2053*7c478bd9Sstevel@tonic-gate if ((err = nvlist_common(nvl, buf, &alloc_size, encoding, 2054*7c478bd9Sstevel@tonic-gate NVS_OP_ENCODE)) != 0) { 2055*7c478bd9Sstevel@tonic-gate nv_mem_free(&nvpriv, buf, alloc_size); 2056*7c478bd9Sstevel@tonic-gate } else { 2057*7c478bd9Sstevel@tonic-gate *buflen = alloc_size; 2058*7c478bd9Sstevel@tonic-gate *bufp = buf; 2059*7c478bd9Sstevel@tonic-gate } 2060*7c478bd9Sstevel@tonic-gate 2061*7c478bd9Sstevel@tonic-gate return (err); 2062*7c478bd9Sstevel@tonic-gate } 2063*7c478bd9Sstevel@tonic-gate 2064*7c478bd9Sstevel@tonic-gate /* 2065*7c478bd9Sstevel@tonic-gate * Unpack buf into an nvlist_t 2066*7c478bd9Sstevel@tonic-gate */ 2067*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 2068*7c478bd9Sstevel@tonic-gate int 2069*7c478bd9Sstevel@tonic-gate nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag) 2070*7c478bd9Sstevel@tonic-gate { 2071*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT) 2072*7c478bd9Sstevel@tonic-gate return (nvlist_xunpack(buf, buflen, nvlp, 2073*7c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 2074*7c478bd9Sstevel@tonic-gate #else 2075*7c478bd9Sstevel@tonic-gate return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep)); 2076*7c478bd9Sstevel@tonic-gate #endif 2077*7c478bd9Sstevel@tonic-gate } 2078*7c478bd9Sstevel@tonic-gate 2079*7c478bd9Sstevel@tonic-gate int 2080*7c478bd9Sstevel@tonic-gate nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva) 2081*7c478bd9Sstevel@tonic-gate { 2082*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 2083*7c478bd9Sstevel@tonic-gate int err; 2084*7c478bd9Sstevel@tonic-gate 2085*7c478bd9Sstevel@tonic-gate if (nvlp == NULL) 2086*7c478bd9Sstevel@tonic-gate return (EINVAL); 2087*7c478bd9Sstevel@tonic-gate 2088*7c478bd9Sstevel@tonic-gate if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0) 2089*7c478bd9Sstevel@tonic-gate return (err); 2090*7c478bd9Sstevel@tonic-gate 2091*7c478bd9Sstevel@tonic-gate if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0) 2092*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 2093*7c478bd9Sstevel@tonic-gate else 2094*7c478bd9Sstevel@tonic-gate *nvlp = nvl; 2095*7c478bd9Sstevel@tonic-gate 2096*7c478bd9Sstevel@tonic-gate return (err); 2097*7c478bd9Sstevel@tonic-gate } 2098*7c478bd9Sstevel@tonic-gate 2099*7c478bd9Sstevel@tonic-gate /* 2100*7c478bd9Sstevel@tonic-gate * Native encoding functions 2101*7c478bd9Sstevel@tonic-gate */ 2102*7c478bd9Sstevel@tonic-gate typedef struct { 2103*7c478bd9Sstevel@tonic-gate /* 2104*7c478bd9Sstevel@tonic-gate * This structure is used when decoding a packed nvpair in 2105*7c478bd9Sstevel@tonic-gate * the native format. n_base points to a buffer containing the 2106*7c478bd9Sstevel@tonic-gate * packed nvpair. n_end is a pointer to the end of the buffer. 2107*7c478bd9Sstevel@tonic-gate * (n_end actually points to the first byte past the end of the 2108*7c478bd9Sstevel@tonic-gate * buffer.) n_curr is a pointer that lies between n_base and n_end. 2109*7c478bd9Sstevel@tonic-gate * It points to the current data that we are decoding. 2110*7c478bd9Sstevel@tonic-gate * The amount of data left in the buffer is equal to n_end - n_curr. 2111*7c478bd9Sstevel@tonic-gate * n_flag is used to recognize a packed embedded list. 2112*7c478bd9Sstevel@tonic-gate */ 2113*7c478bd9Sstevel@tonic-gate caddr_t n_base; 2114*7c478bd9Sstevel@tonic-gate caddr_t n_end; 2115*7c478bd9Sstevel@tonic-gate caddr_t n_curr; 2116*7c478bd9Sstevel@tonic-gate uint_t n_flag; 2117*7c478bd9Sstevel@tonic-gate } nvs_native_t; 2118*7c478bd9Sstevel@tonic-gate 2119*7c478bd9Sstevel@tonic-gate static int 2120*7c478bd9Sstevel@tonic-gate nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf, 2121*7c478bd9Sstevel@tonic-gate size_t buflen) 2122*7c478bd9Sstevel@tonic-gate { 2123*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2124*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 2125*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 2126*7c478bd9Sstevel@tonic-gate nvs->nvs_private = native; 2127*7c478bd9Sstevel@tonic-gate native->n_curr = native->n_base = buf; 2128*7c478bd9Sstevel@tonic-gate native->n_end = buf + buflen; 2129*7c478bd9Sstevel@tonic-gate native->n_flag = 0; 2130*7c478bd9Sstevel@tonic-gate return (0); 2131*7c478bd9Sstevel@tonic-gate 2132*7c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 2133*7c478bd9Sstevel@tonic-gate nvs->nvs_private = native; 2134*7c478bd9Sstevel@tonic-gate native->n_curr = native->n_base = native->n_end = NULL; 2135*7c478bd9Sstevel@tonic-gate native->n_flag = 0; 2136*7c478bd9Sstevel@tonic-gate return (0); 2137*7c478bd9Sstevel@tonic-gate default: 2138*7c478bd9Sstevel@tonic-gate return (EINVAL); 2139*7c478bd9Sstevel@tonic-gate } 2140*7c478bd9Sstevel@tonic-gate } 2141*7c478bd9Sstevel@tonic-gate 2142*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2143*7c478bd9Sstevel@tonic-gate static void 2144*7c478bd9Sstevel@tonic-gate nvs_native_destroy(nvstream_t *nvs) 2145*7c478bd9Sstevel@tonic-gate { 2146*7c478bd9Sstevel@tonic-gate } 2147*7c478bd9Sstevel@tonic-gate 2148*7c478bd9Sstevel@tonic-gate static int 2149*7c478bd9Sstevel@tonic-gate native_cp(nvstream_t *nvs, void *buf, size_t size) 2150*7c478bd9Sstevel@tonic-gate { 2151*7c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2152*7c478bd9Sstevel@tonic-gate 2153*7c478bd9Sstevel@tonic-gate if (native->n_curr + size > native->n_end) 2154*7c478bd9Sstevel@tonic-gate return (EFAULT); 2155*7c478bd9Sstevel@tonic-gate 2156*7c478bd9Sstevel@tonic-gate /* 2157*7c478bd9Sstevel@tonic-gate * The bcopy() below eliminates alignment requirement 2158*7c478bd9Sstevel@tonic-gate * on the buffer (stream) and is preferred over direct access. 2159*7c478bd9Sstevel@tonic-gate */ 2160*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2161*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 2162*7c478bd9Sstevel@tonic-gate bcopy(buf, native->n_curr, size); 2163*7c478bd9Sstevel@tonic-gate break; 2164*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 2165*7c478bd9Sstevel@tonic-gate bcopy(native->n_curr, buf, size); 2166*7c478bd9Sstevel@tonic-gate break; 2167*7c478bd9Sstevel@tonic-gate default: 2168*7c478bd9Sstevel@tonic-gate return (EINVAL); 2169*7c478bd9Sstevel@tonic-gate } 2170*7c478bd9Sstevel@tonic-gate 2171*7c478bd9Sstevel@tonic-gate native->n_curr += size; 2172*7c478bd9Sstevel@tonic-gate return (0); 2173*7c478bd9Sstevel@tonic-gate } 2174*7c478bd9Sstevel@tonic-gate 2175*7c478bd9Sstevel@tonic-gate /* 2176*7c478bd9Sstevel@tonic-gate * operate on nvlist_t header 2177*7c478bd9Sstevel@tonic-gate */ 2178*7c478bd9Sstevel@tonic-gate static int 2179*7c478bd9Sstevel@tonic-gate nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 2180*7c478bd9Sstevel@tonic-gate { 2181*7c478bd9Sstevel@tonic-gate nvs_native_t *native = nvs->nvs_private; 2182*7c478bd9Sstevel@tonic-gate 2183*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2184*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 2185*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 2186*7c478bd9Sstevel@tonic-gate if (native->n_flag) 2187*7c478bd9Sstevel@tonic-gate return (0); /* packed embedded list */ 2188*7c478bd9Sstevel@tonic-gate 2189*7c478bd9Sstevel@tonic-gate native->n_flag = 1; 2190*7c478bd9Sstevel@tonic-gate 2191*7c478bd9Sstevel@tonic-gate /* copy version and nvflag of the nvlist_t */ 2192*7c478bd9Sstevel@tonic-gate if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 || 2193*7c478bd9Sstevel@tonic-gate native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0) 2194*7c478bd9Sstevel@tonic-gate return (EFAULT); 2195*7c478bd9Sstevel@tonic-gate 2196*7c478bd9Sstevel@tonic-gate return (0); 2197*7c478bd9Sstevel@tonic-gate 2198*7c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 2199*7c478bd9Sstevel@tonic-gate /* 2200*7c478bd9Sstevel@tonic-gate * if calculate for packed embedded list 2201*7c478bd9Sstevel@tonic-gate * 4 for end of the embedded list 2202*7c478bd9Sstevel@tonic-gate * else 2203*7c478bd9Sstevel@tonic-gate * 2 * sizeof (int32_t) for nvl_version and nvl_nvflag 2204*7c478bd9Sstevel@tonic-gate * and 4 for end of the entire list 2205*7c478bd9Sstevel@tonic-gate */ 2206*7c478bd9Sstevel@tonic-gate if (native->n_flag) { 2207*7c478bd9Sstevel@tonic-gate *size += 4; 2208*7c478bd9Sstevel@tonic-gate } else { 2209*7c478bd9Sstevel@tonic-gate native->n_flag = 1; 2210*7c478bd9Sstevel@tonic-gate *size += 2 * sizeof (int32_t) + 4; 2211*7c478bd9Sstevel@tonic-gate } 2212*7c478bd9Sstevel@tonic-gate 2213*7c478bd9Sstevel@tonic-gate return (0); 2214*7c478bd9Sstevel@tonic-gate 2215*7c478bd9Sstevel@tonic-gate default: 2216*7c478bd9Sstevel@tonic-gate return (EINVAL); 2217*7c478bd9Sstevel@tonic-gate } 2218*7c478bd9Sstevel@tonic-gate } 2219*7c478bd9Sstevel@tonic-gate 2220*7c478bd9Sstevel@tonic-gate static int 2221*7c478bd9Sstevel@tonic-gate nvs_native_nvl_fini(nvstream_t *nvs) 2222*7c478bd9Sstevel@tonic-gate { 2223*7c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) { 2224*7c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2225*7c478bd9Sstevel@tonic-gate /* 2226*7c478bd9Sstevel@tonic-gate * Add 4 zero bytes at end of nvlist. They are used 2227*7c478bd9Sstevel@tonic-gate * for end detection by the decode routine. 2228*7c478bd9Sstevel@tonic-gate */ 2229*7c478bd9Sstevel@tonic-gate if (native->n_curr + sizeof (int) > native->n_end) 2230*7c478bd9Sstevel@tonic-gate return (EFAULT); 2231*7c478bd9Sstevel@tonic-gate 2232*7c478bd9Sstevel@tonic-gate bzero(native->n_curr, sizeof (int)); 2233*7c478bd9Sstevel@tonic-gate native->n_curr += sizeof (int); 2234*7c478bd9Sstevel@tonic-gate } 2235*7c478bd9Sstevel@tonic-gate 2236*7c478bd9Sstevel@tonic-gate return (0); 2237*7c478bd9Sstevel@tonic-gate } 2238*7c478bd9Sstevel@tonic-gate 2239*7c478bd9Sstevel@tonic-gate static int 2240*7c478bd9Sstevel@tonic-gate nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp) 2241*7c478bd9Sstevel@tonic-gate { 2242*7c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) { 2243*7c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2244*7c478bd9Sstevel@tonic-gate nvlist_t *packed = (void *) 2245*7c478bd9Sstevel@tonic-gate (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 2246*7c478bd9Sstevel@tonic-gate /* 2247*7c478bd9Sstevel@tonic-gate * Null out the pointer that is meaningless in the packed 2248*7c478bd9Sstevel@tonic-gate * structure. The address may not be aligned, so we have 2249*7c478bd9Sstevel@tonic-gate * to use bzero. 2250*7c478bd9Sstevel@tonic-gate */ 2251*7c478bd9Sstevel@tonic-gate bzero(&packed->nvl_priv, sizeof (packed->nvl_priv)); 2252*7c478bd9Sstevel@tonic-gate } 2253*7c478bd9Sstevel@tonic-gate 2254*7c478bd9Sstevel@tonic-gate return (nvs_embedded(nvs, EMBEDDED_NVL(nvp))); 2255*7c478bd9Sstevel@tonic-gate } 2256*7c478bd9Sstevel@tonic-gate 2257*7c478bd9Sstevel@tonic-gate static int 2258*7c478bd9Sstevel@tonic-gate nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp) 2259*7c478bd9Sstevel@tonic-gate { 2260*7c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) { 2261*7c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2262*7c478bd9Sstevel@tonic-gate char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp); 2263*7c478bd9Sstevel@tonic-gate size_t len = NVP_NELEM(nvp) * sizeof (uint64_t); 2264*7c478bd9Sstevel@tonic-gate nvlist_t *packed = (nvlist_t *)((uintptr_t)value + len); 2265*7c478bd9Sstevel@tonic-gate int i; 2266*7c478bd9Sstevel@tonic-gate /* 2267*7c478bd9Sstevel@tonic-gate * Null out pointers that are meaningless in the packed 2268*7c478bd9Sstevel@tonic-gate * structure. The addresses may not be aligned, so we have 2269*7c478bd9Sstevel@tonic-gate * to use bzero. 2270*7c478bd9Sstevel@tonic-gate */ 2271*7c478bd9Sstevel@tonic-gate bzero(value, len); 2272*7c478bd9Sstevel@tonic-gate 2273*7c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++, packed++) 2274*7c478bd9Sstevel@tonic-gate /* 2275*7c478bd9Sstevel@tonic-gate * Null out the pointer that is meaningless in the 2276*7c478bd9Sstevel@tonic-gate * packed structure. The address may not be aligned, 2277*7c478bd9Sstevel@tonic-gate * so we have to use bzero. 2278*7c478bd9Sstevel@tonic-gate */ 2279*7c478bd9Sstevel@tonic-gate bzero(&packed->nvl_priv, sizeof (packed->nvl_priv)); 2280*7c478bd9Sstevel@tonic-gate } 2281*7c478bd9Sstevel@tonic-gate 2282*7c478bd9Sstevel@tonic-gate return (nvs_embedded_nvl_array(nvs, nvp, NULL)); 2283*7c478bd9Sstevel@tonic-gate } 2284*7c478bd9Sstevel@tonic-gate 2285*7c478bd9Sstevel@tonic-gate static void 2286*7c478bd9Sstevel@tonic-gate nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp) 2287*7c478bd9Sstevel@tonic-gate { 2288*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2289*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: { 2290*7c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2291*7c478bd9Sstevel@tonic-gate uint64_t *strp = (void *) 2292*7c478bd9Sstevel@tonic-gate (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 2293*7c478bd9Sstevel@tonic-gate /* 2294*7c478bd9Sstevel@tonic-gate * Null out pointers that are meaningless in the packed 2295*7c478bd9Sstevel@tonic-gate * structure. The addresses may not be aligned, so we have 2296*7c478bd9Sstevel@tonic-gate * to use bzero. 2297*7c478bd9Sstevel@tonic-gate */ 2298*7c478bd9Sstevel@tonic-gate bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t)); 2299*7c478bd9Sstevel@tonic-gate break; 2300*7c478bd9Sstevel@tonic-gate } 2301*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 2302*7c478bd9Sstevel@tonic-gate char **strp = (void *)NVP_VALUE(nvp); 2303*7c478bd9Sstevel@tonic-gate char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t)); 2304*7c478bd9Sstevel@tonic-gate int i; 2305*7c478bd9Sstevel@tonic-gate 2306*7c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++) { 2307*7c478bd9Sstevel@tonic-gate strp[i] = buf; 2308*7c478bd9Sstevel@tonic-gate buf += strlen(buf) + 1; 2309*7c478bd9Sstevel@tonic-gate } 2310*7c478bd9Sstevel@tonic-gate break; 2311*7c478bd9Sstevel@tonic-gate } 2312*7c478bd9Sstevel@tonic-gate } 2313*7c478bd9Sstevel@tonic-gate } 2314*7c478bd9Sstevel@tonic-gate 2315*7c478bd9Sstevel@tonic-gate static int 2316*7c478bd9Sstevel@tonic-gate nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 2317*7c478bd9Sstevel@tonic-gate { 2318*7c478bd9Sstevel@tonic-gate data_type_t type; 2319*7c478bd9Sstevel@tonic-gate int value_sz; 2320*7c478bd9Sstevel@tonic-gate int ret = 0; 2321*7c478bd9Sstevel@tonic-gate 2322*7c478bd9Sstevel@tonic-gate /* 2323*7c478bd9Sstevel@tonic-gate * We do the initial bcopy of the data before we look at 2324*7c478bd9Sstevel@tonic-gate * the nvpair type, because when we're decoding, we won't 2325*7c478bd9Sstevel@tonic-gate * have the correct values for the pair until we do the bcopy. 2326*7c478bd9Sstevel@tonic-gate */ 2327*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2328*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 2329*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 2330*7c478bd9Sstevel@tonic-gate if (native_cp(nvs, nvp, nvp->nvp_size) != 0) 2331*7c478bd9Sstevel@tonic-gate return (EFAULT); 2332*7c478bd9Sstevel@tonic-gate break; 2333*7c478bd9Sstevel@tonic-gate default: 2334*7c478bd9Sstevel@tonic-gate return (EINVAL); 2335*7c478bd9Sstevel@tonic-gate } 2336*7c478bd9Sstevel@tonic-gate 2337*7c478bd9Sstevel@tonic-gate /* verify nvp_name_sz, check the name string length */ 2338*7c478bd9Sstevel@tonic-gate if (i_validate_nvpair_name(nvp) != 0) 2339*7c478bd9Sstevel@tonic-gate return (EFAULT); 2340*7c478bd9Sstevel@tonic-gate 2341*7c478bd9Sstevel@tonic-gate type = NVP_TYPE(nvp); 2342*7c478bd9Sstevel@tonic-gate 2343*7c478bd9Sstevel@tonic-gate /* 2344*7c478bd9Sstevel@tonic-gate * Verify type and nelem and get the value size. 2345*7c478bd9Sstevel@tonic-gate * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 2346*7c478bd9Sstevel@tonic-gate * is the size of the string(s) excluded. 2347*7c478bd9Sstevel@tonic-gate */ 2348*7c478bd9Sstevel@tonic-gate if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0) 2349*7c478bd9Sstevel@tonic-gate return (EFAULT); 2350*7c478bd9Sstevel@tonic-gate 2351*7c478bd9Sstevel@tonic-gate if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size) 2352*7c478bd9Sstevel@tonic-gate return (EFAULT); 2353*7c478bd9Sstevel@tonic-gate 2354*7c478bd9Sstevel@tonic-gate switch (type) { 2355*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 2356*7c478bd9Sstevel@tonic-gate ret = nvpair_native_embedded(nvs, nvp); 2357*7c478bd9Sstevel@tonic-gate break; 2358*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 2359*7c478bd9Sstevel@tonic-gate ret = nvpair_native_embedded_array(nvs, nvp); 2360*7c478bd9Sstevel@tonic-gate break; 2361*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: 2362*7c478bd9Sstevel@tonic-gate nvpair_native_string_array(nvs, nvp); 2363*7c478bd9Sstevel@tonic-gate break; 2364*7c478bd9Sstevel@tonic-gate default: 2365*7c478bd9Sstevel@tonic-gate break; 2366*7c478bd9Sstevel@tonic-gate } 2367*7c478bd9Sstevel@tonic-gate 2368*7c478bd9Sstevel@tonic-gate return (ret); 2369*7c478bd9Sstevel@tonic-gate } 2370*7c478bd9Sstevel@tonic-gate 2371*7c478bd9Sstevel@tonic-gate static int 2372*7c478bd9Sstevel@tonic-gate nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2373*7c478bd9Sstevel@tonic-gate { 2374*7c478bd9Sstevel@tonic-gate uint64_t nvp_sz = nvp->nvp_size; 2375*7c478bd9Sstevel@tonic-gate 2376*7c478bd9Sstevel@tonic-gate switch (NVP_TYPE(nvp)) { 2377*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: { 2378*7c478bd9Sstevel@tonic-gate size_t nvsize = 0; 2379*7c478bd9Sstevel@tonic-gate 2380*7c478bd9Sstevel@tonic-gate if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0) 2381*7c478bd9Sstevel@tonic-gate return (EINVAL); 2382*7c478bd9Sstevel@tonic-gate 2383*7c478bd9Sstevel@tonic-gate nvp_sz += nvsize; 2384*7c478bd9Sstevel@tonic-gate break; 2385*7c478bd9Sstevel@tonic-gate } 2386*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 2387*7c478bd9Sstevel@tonic-gate size_t nvsize; 2388*7c478bd9Sstevel@tonic-gate 2389*7c478bd9Sstevel@tonic-gate if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0) 2390*7c478bd9Sstevel@tonic-gate return (EINVAL); 2391*7c478bd9Sstevel@tonic-gate 2392*7c478bd9Sstevel@tonic-gate nvp_sz += nvsize; 2393*7c478bd9Sstevel@tonic-gate break; 2394*7c478bd9Sstevel@tonic-gate } 2395*7c478bd9Sstevel@tonic-gate default: 2396*7c478bd9Sstevel@tonic-gate break; 2397*7c478bd9Sstevel@tonic-gate } 2398*7c478bd9Sstevel@tonic-gate 2399*7c478bd9Sstevel@tonic-gate if (nvp_sz > INT32_MAX) 2400*7c478bd9Sstevel@tonic-gate return (EINVAL); 2401*7c478bd9Sstevel@tonic-gate 2402*7c478bd9Sstevel@tonic-gate *size = nvp_sz; 2403*7c478bd9Sstevel@tonic-gate 2404*7c478bd9Sstevel@tonic-gate return (0); 2405*7c478bd9Sstevel@tonic-gate } 2406*7c478bd9Sstevel@tonic-gate 2407*7c478bd9Sstevel@tonic-gate static int 2408*7c478bd9Sstevel@tonic-gate nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2409*7c478bd9Sstevel@tonic-gate { 2410*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2411*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 2412*7c478bd9Sstevel@tonic-gate return (nvs_native_nvp_op(nvs, nvp)); 2413*7c478bd9Sstevel@tonic-gate 2414*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 2415*7c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2416*7c478bd9Sstevel@tonic-gate int32_t decode_len; 2417*7c478bd9Sstevel@tonic-gate 2418*7c478bd9Sstevel@tonic-gate /* try to read the size value from the stream */ 2419*7c478bd9Sstevel@tonic-gate if (native->n_curr + sizeof (int32_t) > native->n_end) 2420*7c478bd9Sstevel@tonic-gate return (EFAULT); 2421*7c478bd9Sstevel@tonic-gate bcopy(native->n_curr, &decode_len, sizeof (int32_t)); 2422*7c478bd9Sstevel@tonic-gate 2423*7c478bd9Sstevel@tonic-gate /* sanity check the size value */ 2424*7c478bd9Sstevel@tonic-gate if (decode_len < 0 || 2425*7c478bd9Sstevel@tonic-gate decode_len > native->n_end - native->n_curr) 2426*7c478bd9Sstevel@tonic-gate return (EFAULT); 2427*7c478bd9Sstevel@tonic-gate 2428*7c478bd9Sstevel@tonic-gate *size = decode_len; 2429*7c478bd9Sstevel@tonic-gate 2430*7c478bd9Sstevel@tonic-gate /* 2431*7c478bd9Sstevel@tonic-gate * If at the end of the stream then move the cursor 2432*7c478bd9Sstevel@tonic-gate * forward, otherwise nvpair_native_op() will read 2433*7c478bd9Sstevel@tonic-gate * the entire nvpair at the same cursor position. 2434*7c478bd9Sstevel@tonic-gate */ 2435*7c478bd9Sstevel@tonic-gate if (*size == 0) 2436*7c478bd9Sstevel@tonic-gate native->n_curr += sizeof (int32_t); 2437*7c478bd9Sstevel@tonic-gate break; 2438*7c478bd9Sstevel@tonic-gate } 2439*7c478bd9Sstevel@tonic-gate 2440*7c478bd9Sstevel@tonic-gate default: 2441*7c478bd9Sstevel@tonic-gate return (EINVAL); 2442*7c478bd9Sstevel@tonic-gate } 2443*7c478bd9Sstevel@tonic-gate 2444*7c478bd9Sstevel@tonic-gate return (0); 2445*7c478bd9Sstevel@tonic-gate } 2446*7c478bd9Sstevel@tonic-gate 2447*7c478bd9Sstevel@tonic-gate static const nvs_ops_t nvs_native_ops = { 2448*7c478bd9Sstevel@tonic-gate nvs_native_nvlist, 2449*7c478bd9Sstevel@tonic-gate nvs_native_nvpair, 2450*7c478bd9Sstevel@tonic-gate nvs_native_nvp_op, 2451*7c478bd9Sstevel@tonic-gate nvs_native_nvp_size, 2452*7c478bd9Sstevel@tonic-gate nvs_native_nvl_fini 2453*7c478bd9Sstevel@tonic-gate }; 2454*7c478bd9Sstevel@tonic-gate 2455*7c478bd9Sstevel@tonic-gate static int 2456*7c478bd9Sstevel@tonic-gate nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen) 2457*7c478bd9Sstevel@tonic-gate { 2458*7c478bd9Sstevel@tonic-gate nvs_native_t native; 2459*7c478bd9Sstevel@tonic-gate int err; 2460*7c478bd9Sstevel@tonic-gate 2461*7c478bd9Sstevel@tonic-gate nvs->nvs_ops = &nvs_native_ops; 2462*7c478bd9Sstevel@tonic-gate 2463*7c478bd9Sstevel@tonic-gate if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t), 2464*7c478bd9Sstevel@tonic-gate *buflen - sizeof (nvs_header_t))) != 0) 2465*7c478bd9Sstevel@tonic-gate return (err); 2466*7c478bd9Sstevel@tonic-gate 2467*7c478bd9Sstevel@tonic-gate err = nvs_operation(nvs, nvl, buflen); 2468*7c478bd9Sstevel@tonic-gate 2469*7c478bd9Sstevel@tonic-gate nvs_native_destroy(nvs); 2470*7c478bd9Sstevel@tonic-gate 2471*7c478bd9Sstevel@tonic-gate return (err); 2472*7c478bd9Sstevel@tonic-gate } 2473*7c478bd9Sstevel@tonic-gate 2474*7c478bd9Sstevel@tonic-gate /* 2475*7c478bd9Sstevel@tonic-gate * XDR encoding functions 2476*7c478bd9Sstevel@tonic-gate * 2477*7c478bd9Sstevel@tonic-gate * An xdr packed nvlist is encoded as: 2478*7c478bd9Sstevel@tonic-gate * 2479*7c478bd9Sstevel@tonic-gate * - encoding methode and host endian (4 bytes) 2480*7c478bd9Sstevel@tonic-gate * - nvl_version (4 bytes) 2481*7c478bd9Sstevel@tonic-gate * - nvl_nvflag (4 bytes) 2482*7c478bd9Sstevel@tonic-gate * 2483*7c478bd9Sstevel@tonic-gate * - encoded nvpairs, the format of one xdr encoded nvpair is: 2484*7c478bd9Sstevel@tonic-gate * - encoded size of the nvpair (4 bytes) 2485*7c478bd9Sstevel@tonic-gate * - decoded size of the nvpair (4 bytes) 2486*7c478bd9Sstevel@tonic-gate * - name string, (4 + sizeof(NV_ALIGN4(string)) 2487*7c478bd9Sstevel@tonic-gate * a string is coded as size (4 bytes) and data 2488*7c478bd9Sstevel@tonic-gate * - data type (4 bytes) 2489*7c478bd9Sstevel@tonic-gate * - number of elements in the nvpair (4 bytes) 2490*7c478bd9Sstevel@tonic-gate * - data 2491*7c478bd9Sstevel@tonic-gate * 2492*7c478bd9Sstevel@tonic-gate * - 2 zero's for end of the entire list (8 bytes) 2493*7c478bd9Sstevel@tonic-gate */ 2494*7c478bd9Sstevel@tonic-gate static int 2495*7c478bd9Sstevel@tonic-gate nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen) 2496*7c478bd9Sstevel@tonic-gate { 2497*7c478bd9Sstevel@tonic-gate /* xdr data must be 4 byte aligned */ 2498*7c478bd9Sstevel@tonic-gate if ((ulong_t)buf % 4 != 0) 2499*7c478bd9Sstevel@tonic-gate return (EFAULT); 2500*7c478bd9Sstevel@tonic-gate 2501*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2502*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 2503*7c478bd9Sstevel@tonic-gate xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE); 2504*7c478bd9Sstevel@tonic-gate nvs->nvs_private = xdr; 2505*7c478bd9Sstevel@tonic-gate return (0); 2506*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 2507*7c478bd9Sstevel@tonic-gate xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE); 2508*7c478bd9Sstevel@tonic-gate nvs->nvs_private = xdr; 2509*7c478bd9Sstevel@tonic-gate return (0); 2510*7c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: 2511*7c478bd9Sstevel@tonic-gate nvs->nvs_private = NULL; 2512*7c478bd9Sstevel@tonic-gate return (0); 2513*7c478bd9Sstevel@tonic-gate default: 2514*7c478bd9Sstevel@tonic-gate return (EINVAL); 2515*7c478bd9Sstevel@tonic-gate } 2516*7c478bd9Sstevel@tonic-gate } 2517*7c478bd9Sstevel@tonic-gate 2518*7c478bd9Sstevel@tonic-gate static void 2519*7c478bd9Sstevel@tonic-gate nvs_xdr_destroy(nvstream_t *nvs) 2520*7c478bd9Sstevel@tonic-gate { 2521*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2522*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 2523*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: 2524*7c478bd9Sstevel@tonic-gate xdr_destroy((XDR *)nvs->nvs_private); 2525*7c478bd9Sstevel@tonic-gate break; 2526*7c478bd9Sstevel@tonic-gate default: 2527*7c478bd9Sstevel@tonic-gate break; 2528*7c478bd9Sstevel@tonic-gate } 2529*7c478bd9Sstevel@tonic-gate } 2530*7c478bd9Sstevel@tonic-gate 2531*7c478bd9Sstevel@tonic-gate static int 2532*7c478bd9Sstevel@tonic-gate nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 2533*7c478bd9Sstevel@tonic-gate { 2534*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2535*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: 2536*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 2537*7c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private; 2538*7c478bd9Sstevel@tonic-gate 2539*7c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &nvl->nvl_version) || 2540*7c478bd9Sstevel@tonic-gate !xdr_u_int(xdr, &nvl->nvl_nvflag)) 2541*7c478bd9Sstevel@tonic-gate return (EFAULT); 2542*7c478bd9Sstevel@tonic-gate break; 2543*7c478bd9Sstevel@tonic-gate } 2544*7c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: { 2545*7c478bd9Sstevel@tonic-gate /* 2546*7c478bd9Sstevel@tonic-gate * 2 * 4 for nvl_version + nvl_nvflag 2547*7c478bd9Sstevel@tonic-gate * and 8 for end of the entire list 2548*7c478bd9Sstevel@tonic-gate */ 2549*7c478bd9Sstevel@tonic-gate *size += 2 * 4 + 8; 2550*7c478bd9Sstevel@tonic-gate break; 2551*7c478bd9Sstevel@tonic-gate } 2552*7c478bd9Sstevel@tonic-gate default: 2553*7c478bd9Sstevel@tonic-gate return (EINVAL); 2554*7c478bd9Sstevel@tonic-gate } 2555*7c478bd9Sstevel@tonic-gate return (0); 2556*7c478bd9Sstevel@tonic-gate } 2557*7c478bd9Sstevel@tonic-gate 2558*7c478bd9Sstevel@tonic-gate static int 2559*7c478bd9Sstevel@tonic-gate nvs_xdr_nvl_fini(nvstream_t *nvs) 2560*7c478bd9Sstevel@tonic-gate { 2561*7c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) { 2562*7c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private; 2563*7c478bd9Sstevel@tonic-gate int zero = 0; 2564*7c478bd9Sstevel@tonic-gate 2565*7c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero)) 2566*7c478bd9Sstevel@tonic-gate return (EFAULT); 2567*7c478bd9Sstevel@tonic-gate } 2568*7c478bd9Sstevel@tonic-gate 2569*7c478bd9Sstevel@tonic-gate return (0); 2570*7c478bd9Sstevel@tonic-gate } 2571*7c478bd9Sstevel@tonic-gate 2572*7c478bd9Sstevel@tonic-gate /* 2573*7c478bd9Sstevel@tonic-gate * The format of xdr encoded nvpair is: 2574*7c478bd9Sstevel@tonic-gate * encode_size, decode_size, name string, data type, nelem, data 2575*7c478bd9Sstevel@tonic-gate */ 2576*7c478bd9Sstevel@tonic-gate static int 2577*7c478bd9Sstevel@tonic-gate nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 2578*7c478bd9Sstevel@tonic-gate { 2579*7c478bd9Sstevel@tonic-gate data_type_t type; 2580*7c478bd9Sstevel@tonic-gate char *buf; 2581*7c478bd9Sstevel@tonic-gate char *buf_end = (char *)nvp + nvp->nvp_size; 2582*7c478bd9Sstevel@tonic-gate int value_sz; 2583*7c478bd9Sstevel@tonic-gate uint_t nelem, buflen; 2584*7c478bd9Sstevel@tonic-gate bool_t ret = FALSE; 2585*7c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private; 2586*7c478bd9Sstevel@tonic-gate 2587*7c478bd9Sstevel@tonic-gate ASSERT(xdr != NULL && nvp != NULL); 2588*7c478bd9Sstevel@tonic-gate 2589*7c478bd9Sstevel@tonic-gate /* name string */ 2590*7c478bd9Sstevel@tonic-gate if ((buf = NVP_NAME(nvp)) >= buf_end) 2591*7c478bd9Sstevel@tonic-gate return (EFAULT); 2592*7c478bd9Sstevel@tonic-gate buflen = buf_end - buf; 2593*7c478bd9Sstevel@tonic-gate 2594*7c478bd9Sstevel@tonic-gate if (!xdr_string(xdr, &buf, buflen - 1)) 2595*7c478bd9Sstevel@tonic-gate return (EFAULT); 2596*7c478bd9Sstevel@tonic-gate nvp->nvp_name_sz = strlen(buf) + 1; 2597*7c478bd9Sstevel@tonic-gate 2598*7c478bd9Sstevel@tonic-gate /* type and nelem */ 2599*7c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, (int *)&nvp->nvp_type) || 2600*7c478bd9Sstevel@tonic-gate !xdr_int(xdr, &nvp->nvp_value_elem)) 2601*7c478bd9Sstevel@tonic-gate return (EFAULT); 2602*7c478bd9Sstevel@tonic-gate 2603*7c478bd9Sstevel@tonic-gate type = NVP_TYPE(nvp); 2604*7c478bd9Sstevel@tonic-gate nelem = nvp->nvp_value_elem; 2605*7c478bd9Sstevel@tonic-gate 2606*7c478bd9Sstevel@tonic-gate /* 2607*7c478bd9Sstevel@tonic-gate * Verify type and nelem and get the value size. 2608*7c478bd9Sstevel@tonic-gate * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 2609*7c478bd9Sstevel@tonic-gate * is the size of the string(s) excluded. 2610*7c478bd9Sstevel@tonic-gate */ 2611*7c478bd9Sstevel@tonic-gate if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0) 2612*7c478bd9Sstevel@tonic-gate return (EFAULT); 2613*7c478bd9Sstevel@tonic-gate 2614*7c478bd9Sstevel@tonic-gate /* if there is no data to extract then return */ 2615*7c478bd9Sstevel@tonic-gate if (nelem == 0) 2616*7c478bd9Sstevel@tonic-gate return (0); 2617*7c478bd9Sstevel@tonic-gate 2618*7c478bd9Sstevel@tonic-gate /* value */ 2619*7c478bd9Sstevel@tonic-gate if ((buf = NVP_VALUE(nvp)) >= buf_end) 2620*7c478bd9Sstevel@tonic-gate return (EFAULT); 2621*7c478bd9Sstevel@tonic-gate buflen = buf_end - buf; 2622*7c478bd9Sstevel@tonic-gate 2623*7c478bd9Sstevel@tonic-gate if (buflen < value_sz) 2624*7c478bd9Sstevel@tonic-gate return (EFAULT); 2625*7c478bd9Sstevel@tonic-gate 2626*7c478bd9Sstevel@tonic-gate switch (type) { 2627*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 2628*7c478bd9Sstevel@tonic-gate if (nvs_embedded(nvs, (void *)buf) == 0) 2629*7c478bd9Sstevel@tonic-gate return (0); 2630*7c478bd9Sstevel@tonic-gate break; 2631*7c478bd9Sstevel@tonic-gate 2632*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: 2633*7c478bd9Sstevel@tonic-gate if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0) 2634*7c478bd9Sstevel@tonic-gate return (0); 2635*7c478bd9Sstevel@tonic-gate break; 2636*7c478bd9Sstevel@tonic-gate 2637*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 2638*7c478bd9Sstevel@tonic-gate ret = TRUE; 2639*7c478bd9Sstevel@tonic-gate break; 2640*7c478bd9Sstevel@tonic-gate 2641*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 2642*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 2643*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 2644*7c478bd9Sstevel@tonic-gate ret = xdr_char(xdr, buf); 2645*7c478bd9Sstevel@tonic-gate break; 2646*7c478bd9Sstevel@tonic-gate 2647*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 2648*7c478bd9Sstevel@tonic-gate ret = xdr_short(xdr, (void *)buf); 2649*7c478bd9Sstevel@tonic-gate break; 2650*7c478bd9Sstevel@tonic-gate 2651*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 2652*7c478bd9Sstevel@tonic-gate ret = xdr_u_short(xdr, (void *)buf); 2653*7c478bd9Sstevel@tonic-gate break; 2654*7c478bd9Sstevel@tonic-gate 2655*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 2656*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 2657*7c478bd9Sstevel@tonic-gate ret = xdr_int(xdr, (void *)buf); 2658*7c478bd9Sstevel@tonic-gate break; 2659*7c478bd9Sstevel@tonic-gate 2660*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 2661*7c478bd9Sstevel@tonic-gate ret = xdr_u_int(xdr, (void *)buf); 2662*7c478bd9Sstevel@tonic-gate break; 2663*7c478bd9Sstevel@tonic-gate 2664*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 2665*7c478bd9Sstevel@tonic-gate ret = xdr_longlong_t(xdr, (void *)buf); 2666*7c478bd9Sstevel@tonic-gate break; 2667*7c478bd9Sstevel@tonic-gate 2668*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 2669*7c478bd9Sstevel@tonic-gate ret = xdr_u_longlong_t(xdr, (void *)buf); 2670*7c478bd9Sstevel@tonic-gate break; 2671*7c478bd9Sstevel@tonic-gate 2672*7c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 2673*7c478bd9Sstevel@tonic-gate /* 2674*7c478bd9Sstevel@tonic-gate * NOTE: must expose the definition of hrtime_t here 2675*7c478bd9Sstevel@tonic-gate */ 2676*7c478bd9Sstevel@tonic-gate ret = xdr_longlong_t(xdr, (void *)buf); 2677*7c478bd9Sstevel@tonic-gate break; 2678*7c478bd9Sstevel@tonic-gate 2679*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 2680*7c478bd9Sstevel@tonic-gate ret = xdr_string(xdr, &buf, buflen - 1); 2681*7c478bd9Sstevel@tonic-gate break; 2682*7c478bd9Sstevel@tonic-gate 2683*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 2684*7c478bd9Sstevel@tonic-gate ret = xdr_opaque(xdr, buf, nelem); 2685*7c478bd9Sstevel@tonic-gate break; 2686*7c478bd9Sstevel@tonic-gate 2687*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 2688*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 2689*7c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t), 2690*7c478bd9Sstevel@tonic-gate (xdrproc_t)xdr_char); 2691*7c478bd9Sstevel@tonic-gate break; 2692*7c478bd9Sstevel@tonic-gate 2693*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 2694*7c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t), 2695*7c478bd9Sstevel@tonic-gate sizeof (int16_t), (xdrproc_t)xdr_short); 2696*7c478bd9Sstevel@tonic-gate break; 2697*7c478bd9Sstevel@tonic-gate 2698*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 2699*7c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t), 2700*7c478bd9Sstevel@tonic-gate sizeof (uint16_t), (xdrproc_t)xdr_u_short); 2701*7c478bd9Sstevel@tonic-gate break; 2702*7c478bd9Sstevel@tonic-gate 2703*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 2704*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 2705*7c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t), 2706*7c478bd9Sstevel@tonic-gate sizeof (int32_t), (xdrproc_t)xdr_int); 2707*7c478bd9Sstevel@tonic-gate break; 2708*7c478bd9Sstevel@tonic-gate 2709*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 2710*7c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t), 2711*7c478bd9Sstevel@tonic-gate sizeof (uint32_t), (xdrproc_t)xdr_u_int); 2712*7c478bd9Sstevel@tonic-gate break; 2713*7c478bd9Sstevel@tonic-gate 2714*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 2715*7c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t), 2716*7c478bd9Sstevel@tonic-gate sizeof (int64_t), (xdrproc_t)xdr_longlong_t); 2717*7c478bd9Sstevel@tonic-gate break; 2718*7c478bd9Sstevel@tonic-gate 2719*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 2720*7c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t), 2721*7c478bd9Sstevel@tonic-gate sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t); 2722*7c478bd9Sstevel@tonic-gate break; 2723*7c478bd9Sstevel@tonic-gate 2724*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: { 2725*7c478bd9Sstevel@tonic-gate size_t len = nelem * sizeof (uint64_t); 2726*7c478bd9Sstevel@tonic-gate char **strp = (void *)buf; 2727*7c478bd9Sstevel@tonic-gate int i; 2728*7c478bd9Sstevel@tonic-gate 2729*7c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_DECODE) 2730*7c478bd9Sstevel@tonic-gate bzero(buf, len); /* don't trust packed data */ 2731*7c478bd9Sstevel@tonic-gate 2732*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) { 2733*7c478bd9Sstevel@tonic-gate if (buflen <= len) 2734*7c478bd9Sstevel@tonic-gate return (EFAULT); 2735*7c478bd9Sstevel@tonic-gate 2736*7c478bd9Sstevel@tonic-gate buf += len; 2737*7c478bd9Sstevel@tonic-gate buflen -= len; 2738*7c478bd9Sstevel@tonic-gate 2739*7c478bd9Sstevel@tonic-gate if (xdr_string(xdr, &buf, buflen - 1) != TRUE) 2740*7c478bd9Sstevel@tonic-gate return (EFAULT); 2741*7c478bd9Sstevel@tonic-gate 2742*7c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_DECODE) 2743*7c478bd9Sstevel@tonic-gate strp[i] = buf; 2744*7c478bd9Sstevel@tonic-gate len = strlen(buf) + 1; 2745*7c478bd9Sstevel@tonic-gate } 2746*7c478bd9Sstevel@tonic-gate ret = TRUE; 2747*7c478bd9Sstevel@tonic-gate break; 2748*7c478bd9Sstevel@tonic-gate } 2749*7c478bd9Sstevel@tonic-gate default: 2750*7c478bd9Sstevel@tonic-gate break; 2751*7c478bd9Sstevel@tonic-gate } 2752*7c478bd9Sstevel@tonic-gate 2753*7c478bd9Sstevel@tonic-gate return (ret == TRUE ? 0 : EFAULT); 2754*7c478bd9Sstevel@tonic-gate } 2755*7c478bd9Sstevel@tonic-gate 2756*7c478bd9Sstevel@tonic-gate static int 2757*7c478bd9Sstevel@tonic-gate nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2758*7c478bd9Sstevel@tonic-gate { 2759*7c478bd9Sstevel@tonic-gate data_type_t type = NVP_TYPE(nvp); 2760*7c478bd9Sstevel@tonic-gate /* 2761*7c478bd9Sstevel@tonic-gate * encode_size + decode_size + name string size + data type + nelem 2762*7c478bd9Sstevel@tonic-gate * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) 2763*7c478bd9Sstevel@tonic-gate */ 2764*7c478bd9Sstevel@tonic-gate uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4; 2765*7c478bd9Sstevel@tonic-gate 2766*7c478bd9Sstevel@tonic-gate switch (type) { 2767*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN: 2768*7c478bd9Sstevel@tonic-gate break; 2769*7c478bd9Sstevel@tonic-gate 2770*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE: 2771*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 2772*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8: 2773*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8: 2774*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 2775*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 2776*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 2777*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 2778*7c478bd9Sstevel@tonic-gate nvp_sz += 4; /* 4 is the minimum xdr unit */ 2779*7c478bd9Sstevel@tonic-gate break; 2780*7c478bd9Sstevel@tonic-gate 2781*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 2782*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 2783*7c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 2784*7c478bd9Sstevel@tonic-gate nvp_sz += 8; 2785*7c478bd9Sstevel@tonic-gate break; 2786*7c478bd9Sstevel@tonic-gate 2787*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 2788*7c478bd9Sstevel@tonic-gate nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp))); 2789*7c478bd9Sstevel@tonic-gate break; 2790*7c478bd9Sstevel@tonic-gate 2791*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 2792*7c478bd9Sstevel@tonic-gate nvp_sz += NV_ALIGN4(NVP_NELEM(nvp)); 2793*7c478bd9Sstevel@tonic-gate break; 2794*7c478bd9Sstevel@tonic-gate 2795*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: 2796*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY: 2797*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY: 2798*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY: 2799*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY: 2800*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY: 2801*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY: 2802*7c478bd9Sstevel@tonic-gate nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp); 2803*7c478bd9Sstevel@tonic-gate break; 2804*7c478bd9Sstevel@tonic-gate 2805*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY: 2806*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY: 2807*7c478bd9Sstevel@tonic-gate nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp); 2808*7c478bd9Sstevel@tonic-gate break; 2809*7c478bd9Sstevel@tonic-gate 2810*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: { 2811*7c478bd9Sstevel@tonic-gate int i; 2812*7c478bd9Sstevel@tonic-gate char **strs = (void *)NVP_VALUE(nvp); 2813*7c478bd9Sstevel@tonic-gate 2814*7c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++) 2815*7c478bd9Sstevel@tonic-gate nvp_sz += 4 + NV_ALIGN4(strlen(strs[i])); 2816*7c478bd9Sstevel@tonic-gate 2817*7c478bd9Sstevel@tonic-gate break; 2818*7c478bd9Sstevel@tonic-gate } 2819*7c478bd9Sstevel@tonic-gate 2820*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: 2821*7c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: { 2822*7c478bd9Sstevel@tonic-gate size_t nvsize = 0; 2823*7c478bd9Sstevel@tonic-gate int old_nvs_op = nvs->nvs_op; 2824*7c478bd9Sstevel@tonic-gate int err; 2825*7c478bd9Sstevel@tonic-gate 2826*7c478bd9Sstevel@tonic-gate nvs->nvs_op = NVS_OP_GETSIZE; 2827*7c478bd9Sstevel@tonic-gate if (type == DATA_TYPE_NVLIST) 2828*7c478bd9Sstevel@tonic-gate err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize); 2829*7c478bd9Sstevel@tonic-gate else 2830*7c478bd9Sstevel@tonic-gate err = nvs_embedded_nvl_array(nvs, nvp, &nvsize); 2831*7c478bd9Sstevel@tonic-gate nvs->nvs_op = old_nvs_op; 2832*7c478bd9Sstevel@tonic-gate 2833*7c478bd9Sstevel@tonic-gate if (err != 0) 2834*7c478bd9Sstevel@tonic-gate return (EINVAL); 2835*7c478bd9Sstevel@tonic-gate 2836*7c478bd9Sstevel@tonic-gate nvp_sz += nvsize; 2837*7c478bd9Sstevel@tonic-gate break; 2838*7c478bd9Sstevel@tonic-gate } 2839*7c478bd9Sstevel@tonic-gate 2840*7c478bd9Sstevel@tonic-gate default: 2841*7c478bd9Sstevel@tonic-gate return (EINVAL); 2842*7c478bd9Sstevel@tonic-gate } 2843*7c478bd9Sstevel@tonic-gate 2844*7c478bd9Sstevel@tonic-gate if (nvp_sz > INT32_MAX) 2845*7c478bd9Sstevel@tonic-gate return (EINVAL); 2846*7c478bd9Sstevel@tonic-gate 2847*7c478bd9Sstevel@tonic-gate *size = nvp_sz; 2848*7c478bd9Sstevel@tonic-gate 2849*7c478bd9Sstevel@tonic-gate return (0); 2850*7c478bd9Sstevel@tonic-gate } 2851*7c478bd9Sstevel@tonic-gate 2852*7c478bd9Sstevel@tonic-gate 2853*7c478bd9Sstevel@tonic-gate /* 2854*7c478bd9Sstevel@tonic-gate * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates 2855*7c478bd9Sstevel@tonic-gate * the largest nvpair that could be encoded in the buffer. 2856*7c478bd9Sstevel@tonic-gate * 2857*7c478bd9Sstevel@tonic-gate * See comments above nvpair_xdr_op() for the format of xdr encoding. 2858*7c478bd9Sstevel@tonic-gate * The size of a xdr packed nvpair without any data is 5 words. 2859*7c478bd9Sstevel@tonic-gate * 2860*7c478bd9Sstevel@tonic-gate * Using the size of the data directly as an estimate would be ok 2861*7c478bd9Sstevel@tonic-gate * in all cases except one. If the data type is of DATA_TYPE_STRING_ARRAY 2862*7c478bd9Sstevel@tonic-gate * then the actual nvpair has space for an array of pointers to index 2863*7c478bd9Sstevel@tonic-gate * the strings. These pointers are not encoded into the packed xdr buffer. 2864*7c478bd9Sstevel@tonic-gate * 2865*7c478bd9Sstevel@tonic-gate * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are 2866*7c478bd9Sstevel@tonic-gate * of length 0, then each string is endcoded in xdr format as a single word. 2867*7c478bd9Sstevel@tonic-gate * Therefore when expanded to an nvpair there will be 2.25 word used for 2868*7c478bd9Sstevel@tonic-gate * each string. (a int64_t allocated for pointer usage, and a single char 2869*7c478bd9Sstevel@tonic-gate * for the null termination.) 2870*7c478bd9Sstevel@tonic-gate * 2871*7c478bd9Sstevel@tonic-gate * This is the calculation performed by the NVS_XDR_MAX_LEN macro. 2872*7c478bd9Sstevel@tonic-gate */ 2873*7c478bd9Sstevel@tonic-gate #define NVS_XDR_HDR_LEN ((size_t)(5 * 4)) 2874*7c478bd9Sstevel@tonic-gate #define NVS_XDR_DATA_LEN(y) (((size_t)(y) <= NVS_XDR_HDR_LEN) ? \ 2875*7c478bd9Sstevel@tonic-gate 0 : ((size_t)(y) - NVS_XDR_HDR_LEN)) 2876*7c478bd9Sstevel@tonic-gate #define NVS_XDR_MAX_LEN(x) (NVP_SIZE_CALC(1, 0) + \ 2877*7c478bd9Sstevel@tonic-gate (NVS_XDR_DATA_LEN(x) * 2) + \ 2878*7c478bd9Sstevel@tonic-gate NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4))) 2879*7c478bd9Sstevel@tonic-gate 2880*7c478bd9Sstevel@tonic-gate static int 2881*7c478bd9Sstevel@tonic-gate nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2882*7c478bd9Sstevel@tonic-gate { 2883*7c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private; 2884*7c478bd9Sstevel@tonic-gate int32_t encode_len, decode_len; 2885*7c478bd9Sstevel@tonic-gate 2886*7c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) { 2887*7c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: { 2888*7c478bd9Sstevel@tonic-gate size_t nvsize; 2889*7c478bd9Sstevel@tonic-gate 2890*7c478bd9Sstevel@tonic-gate if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0) 2891*7c478bd9Sstevel@tonic-gate return (EFAULT); 2892*7c478bd9Sstevel@tonic-gate 2893*7c478bd9Sstevel@tonic-gate decode_len = nvp->nvp_size; 2894*7c478bd9Sstevel@tonic-gate encode_len = nvsize; 2895*7c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len)) 2896*7c478bd9Sstevel@tonic-gate return (EFAULT); 2897*7c478bd9Sstevel@tonic-gate 2898*7c478bd9Sstevel@tonic-gate return (nvs_xdr_nvp_op(nvs, nvp)); 2899*7c478bd9Sstevel@tonic-gate } 2900*7c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: { 2901*7c478bd9Sstevel@tonic-gate struct xdr_bytesrec bytesrec; 2902*7c478bd9Sstevel@tonic-gate 2903*7c478bd9Sstevel@tonic-gate /* get the encode and decode size */ 2904*7c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len)) 2905*7c478bd9Sstevel@tonic-gate return (EFAULT); 2906*7c478bd9Sstevel@tonic-gate *size = decode_len; 2907*7c478bd9Sstevel@tonic-gate 2908*7c478bd9Sstevel@tonic-gate /* are we at the end of the stream? */ 2909*7c478bd9Sstevel@tonic-gate if (*size == 0) 2910*7c478bd9Sstevel@tonic-gate return (0); 2911*7c478bd9Sstevel@tonic-gate 2912*7c478bd9Sstevel@tonic-gate /* sanity check the size parameter */ 2913*7c478bd9Sstevel@tonic-gate if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec)) 2914*7c478bd9Sstevel@tonic-gate return (EFAULT); 2915*7c478bd9Sstevel@tonic-gate 2916*7c478bd9Sstevel@tonic-gate if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail)) 2917*7c478bd9Sstevel@tonic-gate return (EFAULT); 2918*7c478bd9Sstevel@tonic-gate break; 2919*7c478bd9Sstevel@tonic-gate } 2920*7c478bd9Sstevel@tonic-gate 2921*7c478bd9Sstevel@tonic-gate default: 2922*7c478bd9Sstevel@tonic-gate return (EINVAL); 2923*7c478bd9Sstevel@tonic-gate } 2924*7c478bd9Sstevel@tonic-gate return (0); 2925*7c478bd9Sstevel@tonic-gate } 2926*7c478bd9Sstevel@tonic-gate 2927*7c478bd9Sstevel@tonic-gate static const struct nvs_ops nvs_xdr_ops = { 2928*7c478bd9Sstevel@tonic-gate nvs_xdr_nvlist, 2929*7c478bd9Sstevel@tonic-gate nvs_xdr_nvpair, 2930*7c478bd9Sstevel@tonic-gate nvs_xdr_nvp_op, 2931*7c478bd9Sstevel@tonic-gate nvs_xdr_nvp_size, 2932*7c478bd9Sstevel@tonic-gate nvs_xdr_nvl_fini 2933*7c478bd9Sstevel@tonic-gate }; 2934*7c478bd9Sstevel@tonic-gate 2935*7c478bd9Sstevel@tonic-gate static int 2936*7c478bd9Sstevel@tonic-gate nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen) 2937*7c478bd9Sstevel@tonic-gate { 2938*7c478bd9Sstevel@tonic-gate XDR xdr; 2939*7c478bd9Sstevel@tonic-gate int err; 2940*7c478bd9Sstevel@tonic-gate 2941*7c478bd9Sstevel@tonic-gate nvs->nvs_ops = &nvs_xdr_ops; 2942*7c478bd9Sstevel@tonic-gate 2943*7c478bd9Sstevel@tonic-gate if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t), 2944*7c478bd9Sstevel@tonic-gate *buflen - sizeof (nvs_header_t))) != 0) 2945*7c478bd9Sstevel@tonic-gate return (err); 2946*7c478bd9Sstevel@tonic-gate 2947*7c478bd9Sstevel@tonic-gate err = nvs_operation(nvs, nvl, buflen); 2948*7c478bd9Sstevel@tonic-gate 2949*7c478bd9Sstevel@tonic-gate nvs_xdr_destroy(nvs); 2950*7c478bd9Sstevel@tonic-gate 2951*7c478bd9Sstevel@tonic-gate return (err); 2952*7c478bd9Sstevel@tonic-gate } 2953