1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd 22168404Spjd/* 23219089Spjd * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 24168404Spjd */ 25168404Spjd 26168404Spjd#include <sys/debug.h> 27168404Spjd#include <sys/nvpair.h> 28168404Spjd#include <sys/nvpair_impl.h> 29168404Spjd#include <rpc/types.h> 30168404Spjd#include <rpc/xdr.h> 31168404Spjd 32168404Spjd#if defined(_KERNEL) && !defined(_BOOT) 33168404Spjd#include <sys/varargs.h> 34185029Spjd#include <sys/sunddi.h> 35168404Spjd#else 36168404Spjd#include <stdarg.h> 37185029Spjd#include <stdlib.h> 38185029Spjd#include <string.h> 39219089Spjd#include <strings.h> 40168404Spjd#endif 41168404Spjd 42168404Spjd#ifndef offsetof 43185029Spjd#define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 44168404Spjd#endif 45185029Spjd#define skip_whitespace(p) while ((*(p) == ' ') || (*(p) == '\t')) p++ 46168404Spjd 47292643Sngie#if defined(__FreeBSD__) && !defined(_KERNEL) 48168404Spjd/* 49292643Sngie * libnvpair is the lowest commen denominator for ZFS related libraries, 50292643Sngie * defining aok here makes it usable by all ZFS related libraries 51292643Sngie */ 52292643Sngieint aok; 53292643Sngie#endif 54292643Sngie 55292643Sngie/* 56168404Spjd * nvpair.c - Provides kernel & userland interfaces for manipulating 57168404Spjd * name-value pairs. 58168404Spjd * 59168404Spjd * Overview Diagram 60168404Spjd * 61168404Spjd * +--------------+ 62168404Spjd * | nvlist_t | 63168404Spjd * |--------------| 64168404Spjd * | nvl_version | 65168404Spjd * | nvl_nvflag | 66168404Spjd * | nvl_priv -+-+ 67168404Spjd * | nvl_flag | | 68168404Spjd * | nvl_pad | | 69168404Spjd * +--------------+ | 70168404Spjd * V 71168404Spjd * +--------------+ last i_nvp in list 72168404Spjd * | nvpriv_t | +---------------------> 73168404Spjd * |--------------| | 74168404Spjd * +--+- nvp_list | | +------------+ 75168404Spjd * | | nvp_last -+--+ + nv_alloc_t | 76168404Spjd * | | nvp_curr | |------------| 77168404Spjd * | | nvp_nva -+----> | nva_ops | 78168404Spjd * | | nvp_stat | | nva_arg | 79168404Spjd * | +--------------+ +------------+ 80168404Spjd * | 81168404Spjd * +-------+ 82168404Spjd * V 83168404Spjd * +---------------------+ +-------------------+ 84168404Spjd * | i_nvp_t | +-->| i_nvp_t | +--> 85168404Spjd * |---------------------| | |-------------------| | 86168404Spjd * | nvi_next -+--+ | nvi_next -+--+ 87168404Spjd * | nvi_prev (NULL) | <----+ nvi_prev | 88168404Spjd * | . . . . . . . . . . | | . . . . . . . . . | 89168404Spjd * | nvp (nvpair_t) | | nvp (nvpair_t) | 90168404Spjd * | - nvp_size | | - nvp_size | 91168404Spjd * | - nvp_name_sz | | - nvp_name_sz | 92168404Spjd * | - nvp_value_elem | | - nvp_value_elem | 93168404Spjd * | - nvp_type | | - nvp_type | 94168404Spjd * | - data ... | | - data ... | 95168404Spjd * +---------------------+ +-------------------+ 96168404Spjd * 97168404Spjd * 98168404Spjd * 99168404Spjd * +---------------------+ +---------------------+ 100168404Spjd * | i_nvp_t | +--> +-->| i_nvp_t (last) | 101168404Spjd * |---------------------| | | |---------------------| 102168404Spjd * | nvi_next -+--+ ... --+ | nvi_next (NULL) | 103168404Spjd * <-+- nvi_prev |<-- ... <----+ nvi_prev | 104168404Spjd * | . . . . . . . . . | | . . . . . . . . . | 105168404Spjd * | nvp (nvpair_t) | | nvp (nvpair_t) | 106168404Spjd * | - nvp_size | | - nvp_size | 107168404Spjd * | - nvp_name_sz | | - nvp_name_sz | 108168404Spjd * | - nvp_value_elem | | - nvp_value_elem | 109168404Spjd * | - DATA_TYPE_NVLIST | | - nvp_type | 110168404Spjd * | - data (embedded) | | - data ... | 111168404Spjd * | nvlist name | +---------------------+ 112168404Spjd * | +--------------+ | 113168404Spjd * | | nvlist_t | | 114168404Spjd * | |--------------| | 115168404Spjd * | | nvl_version | | 116168404Spjd * | | nvl_nvflag | | 117168404Spjd * | | nvl_priv --+---+----> 118168404Spjd * | | nvl_flag | | 119168404Spjd * | | nvl_pad | | 120168404Spjd * | +--------------+ | 121168404Spjd * +---------------------+ 122168404Spjd * 123168404Spjd * 124168404Spjd * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will 125168404Spjd * allow value to be aligned on 8 byte boundary 126168404Spjd * 127168404Spjd * name_len is the length of the name string including the null terminator 128168404Spjd * so it must be >= 1 129168404Spjd */ 130168404Spjd#define NVP_SIZE_CALC(name_len, data_len) \ 131168404Spjd (NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len)) 132168404Spjd 133168404Spjdstatic int i_get_value_size(data_type_t type, const void *data, uint_t nelem); 134168404Spjdstatic int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type, 135168404Spjd uint_t nelem, const void *data); 136168404Spjd 137168404Spjd#define NV_STAT_EMBEDDED 0x1 138168404Spjd#define EMBEDDED_NVL(nvp) ((nvlist_t *)(void *)NVP_VALUE(nvp)) 139168404Spjd#define EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp)) 140168404Spjd 141168404Spjd#define NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz)) 142168404Spjd#define NVPAIR2I_NVP(nvp) \ 143168404Spjd ((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp))) 144168404Spjd 145168404Spjd 146168404Spjdint 147168404Spjdnv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...) 148168404Spjd{ 149168404Spjd va_list valist; 150168404Spjd int err = 0; 151168404Spjd 152168404Spjd nva->nva_ops = nvo; 153168404Spjd nva->nva_arg = NULL; 154168404Spjd 155168404Spjd va_start(valist, nvo); 156168404Spjd if (nva->nva_ops->nv_ao_init != NULL) 157168404Spjd err = nva->nva_ops->nv_ao_init(nva, valist); 158168404Spjd va_end(valist); 159168404Spjd 160168404Spjd return (err); 161168404Spjd} 162168404Spjd 163168404Spjdvoid 164168404Spjdnv_alloc_reset(nv_alloc_t *nva) 165168404Spjd{ 166168404Spjd if (nva->nva_ops->nv_ao_reset != NULL) 167168404Spjd nva->nva_ops->nv_ao_reset(nva); 168168404Spjd} 169168404Spjd 170168404Spjdvoid 171168404Spjdnv_alloc_fini(nv_alloc_t *nva) 172168404Spjd{ 173168404Spjd if (nva->nva_ops->nv_ao_fini != NULL) 174168404Spjd nva->nva_ops->nv_ao_fini(nva); 175168404Spjd} 176168404Spjd 177168404Spjdnv_alloc_t * 178168404Spjdnvlist_lookup_nv_alloc(nvlist_t *nvl) 179168404Spjd{ 180168404Spjd nvpriv_t *priv; 181168404Spjd 182168404Spjd if (nvl == NULL || 183168404Spjd (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 184168404Spjd return (NULL); 185168404Spjd 186168404Spjd return (priv->nvp_nva); 187168404Spjd} 188168404Spjd 189168404Spjdstatic void * 190168404Spjdnv_mem_zalloc(nvpriv_t *nvp, size_t size) 191168404Spjd{ 192168404Spjd nv_alloc_t *nva = nvp->nvp_nva; 193168404Spjd void *buf; 194168404Spjd 195168404Spjd if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL) 196168404Spjd bzero(buf, size); 197168404Spjd 198168404Spjd return (buf); 199168404Spjd} 200168404Spjd 201168404Spjdstatic void 202168404Spjdnv_mem_free(nvpriv_t *nvp, void *buf, size_t size) 203168404Spjd{ 204168404Spjd nv_alloc_t *nva = nvp->nvp_nva; 205168404Spjd 206168404Spjd nva->nva_ops->nv_ao_free(nva, buf, size); 207168404Spjd} 208168404Spjd 209168404Spjdstatic void 210168404Spjdnv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat) 211168404Spjd{ 212185029Spjd bzero(priv, sizeof (nvpriv_t)); 213168404Spjd 214168404Spjd priv->nvp_nva = nva; 215168404Spjd priv->nvp_stat = stat; 216168404Spjd} 217168404Spjd 218168404Spjdstatic nvpriv_t * 219168404Spjdnv_priv_alloc(nv_alloc_t *nva) 220168404Spjd{ 221168404Spjd nvpriv_t *priv; 222168404Spjd 223168404Spjd /* 224168404Spjd * nv_mem_alloc() cannot called here because it needs the priv 225168404Spjd * argument. 226168404Spjd */ 227168404Spjd if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL) 228168404Spjd return (NULL); 229168404Spjd 230168404Spjd nv_priv_init(priv, nva, 0); 231168404Spjd 232168404Spjd return (priv); 233168404Spjd} 234168404Spjd 235168404Spjd/* 236168404Spjd * Embedded lists need their own nvpriv_t's. We create a new 237168404Spjd * nvpriv_t using the parameters and allocator from the parent 238168404Spjd * list's nvpriv_t. 239168404Spjd */ 240168404Spjdstatic nvpriv_t * 241168404Spjdnv_priv_alloc_embedded(nvpriv_t *priv) 242168404Spjd{ 243168404Spjd nvpriv_t *emb_priv; 244168404Spjd 245168404Spjd if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL) 246168404Spjd return (NULL); 247168404Spjd 248168404Spjd nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED); 249168404Spjd 250168404Spjd return (emb_priv); 251168404Spjd} 252168404Spjd 253168404Spjdstatic void 254168404Spjdnvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv) 255168404Spjd{ 256168404Spjd nvl->nvl_version = NV_VERSION; 257168404Spjd nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE); 258168404Spjd nvl->nvl_priv = (uint64_t)(uintptr_t)priv; 259168404Spjd nvl->nvl_flag = 0; 260168404Spjd nvl->nvl_pad = 0; 261168404Spjd} 262168404Spjd 263219089Spjduint_t 264219089Spjdnvlist_nvflag(nvlist_t *nvl) 265219089Spjd{ 266219089Spjd return (nvl->nvl_nvflag); 267219089Spjd} 268219089Spjd 269168404Spjd/* 270168404Spjd * nvlist_alloc - Allocate nvlist. 271168404Spjd */ 272168404Spjd/*ARGSUSED1*/ 273168404Spjdint 274168404Spjdnvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag) 275168404Spjd{ 276168404Spjd#if defined(_KERNEL) && !defined(_BOOT) 277168404Spjd return (nvlist_xalloc(nvlp, nvflag, 278168404Spjd (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 279168404Spjd#else 280168404Spjd return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep)); 281168404Spjd#endif 282168404Spjd} 283168404Spjd 284168404Spjdint 285168404Spjdnvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva) 286168404Spjd{ 287168404Spjd nvpriv_t *priv; 288168404Spjd 289168404Spjd if (nvlp == NULL || nva == NULL) 290168404Spjd return (EINVAL); 291168404Spjd 292168404Spjd if ((priv = nv_priv_alloc(nva)) == NULL) 293168404Spjd return (ENOMEM); 294168404Spjd 295168404Spjd if ((*nvlp = nv_mem_zalloc(priv, 296168404Spjd NV_ALIGN(sizeof (nvlist_t)))) == NULL) { 297168404Spjd nv_mem_free(priv, priv, sizeof (nvpriv_t)); 298168404Spjd return (ENOMEM); 299168404Spjd } 300168404Spjd 301168404Spjd nvlist_init(*nvlp, nvflag, priv); 302168404Spjd 303168404Spjd return (0); 304168404Spjd} 305168404Spjd 306168404Spjd/* 307168404Spjd * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair. 308168404Spjd */ 309168404Spjdstatic nvpair_t * 310168404Spjdnvp_buf_alloc(nvlist_t *nvl, size_t len) 311168404Spjd{ 312168404Spjd nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 313168404Spjd i_nvp_t *buf; 314168404Spjd nvpair_t *nvp; 315168404Spjd size_t nvsize; 316168404Spjd 317168404Spjd /* 318168404Spjd * Allocate the buffer 319168404Spjd */ 320168404Spjd nvsize = len + offsetof(i_nvp_t, nvi_nvp); 321168404Spjd 322168404Spjd if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL) 323168404Spjd return (NULL); 324168404Spjd 325168404Spjd nvp = &buf->nvi_nvp; 326168404Spjd nvp->nvp_size = len; 327168404Spjd 328168404Spjd return (nvp); 329168404Spjd} 330168404Spjd 331168404Spjd/* 332168404Spjd * nvp_buf_free - de-Allocate an i_nvp_t. 333168404Spjd */ 334168404Spjdstatic void 335168404Spjdnvp_buf_free(nvlist_t *nvl, nvpair_t *nvp) 336168404Spjd{ 337168404Spjd nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 338168404Spjd size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp); 339168404Spjd 340168404Spjd nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize); 341168404Spjd} 342168404Spjd 343168404Spjd/* 344168404Spjd * nvp_buf_link - link a new nv pair into the nvlist. 345168404Spjd */ 346168404Spjdstatic void 347168404Spjdnvp_buf_link(nvlist_t *nvl, nvpair_t *nvp) 348168404Spjd{ 349168404Spjd nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 350168404Spjd i_nvp_t *curr = NVPAIR2I_NVP(nvp); 351168404Spjd 352168404Spjd /* Put element at end of nvlist */ 353168404Spjd if (priv->nvp_list == NULL) { 354168404Spjd priv->nvp_list = priv->nvp_last = curr; 355168404Spjd } else { 356168404Spjd curr->nvi_prev = priv->nvp_last; 357168404Spjd priv->nvp_last->nvi_next = curr; 358168404Spjd priv->nvp_last = curr; 359168404Spjd } 360168404Spjd} 361168404Spjd 362168404Spjd/* 363168404Spjd * nvp_buf_unlink - unlink an removed nvpair out of the nvlist. 364168404Spjd */ 365168404Spjdstatic void 366168404Spjdnvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp) 367168404Spjd{ 368168404Spjd nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 369168404Spjd i_nvp_t *curr = NVPAIR2I_NVP(nvp); 370168404Spjd 371168404Spjd /* 372168404Spjd * protect nvlist_next_nvpair() against walking on freed memory. 373168404Spjd */ 374168404Spjd if (priv->nvp_curr == curr) 375168404Spjd priv->nvp_curr = curr->nvi_next; 376168404Spjd 377168404Spjd if (curr == priv->nvp_list) 378168404Spjd priv->nvp_list = curr->nvi_next; 379168404Spjd else 380168404Spjd curr->nvi_prev->nvi_next = curr->nvi_next; 381168404Spjd 382168404Spjd if (curr == priv->nvp_last) 383168404Spjd priv->nvp_last = curr->nvi_prev; 384168404Spjd else 385168404Spjd curr->nvi_next->nvi_prev = curr->nvi_prev; 386168404Spjd} 387168404Spjd 388168404Spjd/* 389168404Spjd * take a nvpair type and number of elements and make sure the are valid 390168404Spjd */ 391168404Spjdstatic int 392168404Spjdi_validate_type_nelem(data_type_t type, uint_t nelem) 393168404Spjd{ 394168404Spjd switch (type) { 395168404Spjd case DATA_TYPE_BOOLEAN: 396168404Spjd if (nelem != 0) 397168404Spjd return (EINVAL); 398168404Spjd break; 399168404Spjd case DATA_TYPE_BOOLEAN_VALUE: 400168404Spjd case DATA_TYPE_BYTE: 401168404Spjd case DATA_TYPE_INT8: 402168404Spjd case DATA_TYPE_UINT8: 403168404Spjd case DATA_TYPE_INT16: 404168404Spjd case DATA_TYPE_UINT16: 405168404Spjd case DATA_TYPE_INT32: 406168404Spjd case DATA_TYPE_UINT32: 407168404Spjd case DATA_TYPE_INT64: 408168404Spjd case DATA_TYPE_UINT64: 409168404Spjd case DATA_TYPE_STRING: 410168404Spjd case DATA_TYPE_HRTIME: 411168404Spjd case DATA_TYPE_NVLIST: 412185029Spjd#if !defined(_KERNEL) 413185029Spjd case DATA_TYPE_DOUBLE: 414185029Spjd#endif 415168404Spjd if (nelem != 1) 416168404Spjd return (EINVAL); 417168404Spjd break; 418168404Spjd case DATA_TYPE_BOOLEAN_ARRAY: 419168404Spjd case DATA_TYPE_BYTE_ARRAY: 420168404Spjd case DATA_TYPE_INT8_ARRAY: 421168404Spjd case DATA_TYPE_UINT8_ARRAY: 422168404Spjd case DATA_TYPE_INT16_ARRAY: 423168404Spjd case DATA_TYPE_UINT16_ARRAY: 424168404Spjd case DATA_TYPE_INT32_ARRAY: 425168404Spjd case DATA_TYPE_UINT32_ARRAY: 426168404Spjd case DATA_TYPE_INT64_ARRAY: 427168404Spjd case DATA_TYPE_UINT64_ARRAY: 428168404Spjd case DATA_TYPE_STRING_ARRAY: 429168404Spjd case DATA_TYPE_NVLIST_ARRAY: 430168404Spjd /* we allow arrays with 0 elements */ 431168404Spjd break; 432168404Spjd default: 433168404Spjd return (EINVAL); 434168404Spjd } 435168404Spjd return (0); 436168404Spjd} 437168404Spjd 438168404Spjd/* 439168404Spjd * Verify nvp_name_sz and check the name string length. 440168404Spjd */ 441168404Spjdstatic int 442168404Spjdi_validate_nvpair_name(nvpair_t *nvp) 443168404Spjd{ 444168404Spjd if ((nvp->nvp_name_sz <= 0) || 445168404Spjd (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0))) 446168404Spjd return (EFAULT); 447168404Spjd 448168404Spjd /* verify the name string, make sure its terminated */ 449168404Spjd if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0') 450168404Spjd return (EFAULT); 451168404Spjd 452168404Spjd return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT); 453168404Spjd} 454168404Spjd 455168404Spjdstatic int 456168404Spjdi_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data) 457168404Spjd{ 458168404Spjd switch (type) { 459168404Spjd case DATA_TYPE_BOOLEAN_VALUE: 460168404Spjd if (*(boolean_t *)data != B_TRUE && 461168404Spjd *(boolean_t *)data != B_FALSE) 462168404Spjd return (EINVAL); 463168404Spjd break; 464168404Spjd case DATA_TYPE_BOOLEAN_ARRAY: { 465168404Spjd int i; 466168404Spjd 467168404Spjd for (i = 0; i < nelem; i++) 468168404Spjd if (((boolean_t *)data)[i] != B_TRUE && 469168404Spjd ((boolean_t *)data)[i] != B_FALSE) 470168404Spjd return (EINVAL); 471168404Spjd break; 472168404Spjd } 473168404Spjd default: 474168404Spjd break; 475168404Spjd } 476168404Spjd 477168404Spjd return (0); 478168404Spjd} 479168404Spjd 480168404Spjd/* 481168404Spjd * This function takes a pointer to what should be a nvpair and it's size 482168404Spjd * and then verifies that all the nvpair fields make sense and can be 483168404Spjd * trusted. This function is used when decoding packed nvpairs. 484168404Spjd */ 485168404Spjdstatic int 486168404Spjdi_validate_nvpair(nvpair_t *nvp) 487168404Spjd{ 488168404Spjd data_type_t type = NVP_TYPE(nvp); 489168404Spjd int size1, size2; 490168404Spjd 491168404Spjd /* verify nvp_name_sz, check the name string length */ 492168404Spjd if (i_validate_nvpair_name(nvp) != 0) 493168404Spjd return (EFAULT); 494168404Spjd 495168404Spjd if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0) 496168404Spjd return (EFAULT); 497168404Spjd 498168404Spjd /* 499168404Spjd * verify nvp_type, nvp_value_elem, and also possibly 500168404Spjd * verify string values and get the value size. 501168404Spjd */ 502168404Spjd size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp)); 503168404Spjd size1 = nvp->nvp_size - NVP_VALOFF(nvp); 504168404Spjd if (size2 < 0 || size1 != NV_ALIGN(size2)) 505168404Spjd return (EFAULT); 506168404Spjd 507168404Spjd return (0); 508168404Spjd} 509168404Spjd 510168404Spjdstatic int 511168404Spjdnvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl) 512168404Spjd{ 513168404Spjd nvpriv_t *priv; 514168404Spjd i_nvp_t *curr; 515168404Spjd 516168404Spjd if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL) 517168404Spjd return (EINVAL); 518168404Spjd 519168404Spjd for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 520168404Spjd nvpair_t *nvp = &curr->nvi_nvp; 521168404Spjd int err; 522168404Spjd 523168404Spjd if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp), 524168404Spjd NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0) 525168404Spjd return (err); 526168404Spjd } 527168404Spjd 528168404Spjd return (0); 529168404Spjd} 530168404Spjd 531168404Spjd/* 532168404Spjd * Frees all memory allocated for an nvpair (like embedded lists) with 533168404Spjd * the exception of the nvpair buffer itself. 534168404Spjd */ 535168404Spjdstatic void 536168404Spjdnvpair_free(nvpair_t *nvp) 537168404Spjd{ 538168404Spjd switch (NVP_TYPE(nvp)) { 539168404Spjd case DATA_TYPE_NVLIST: 540168404Spjd nvlist_free(EMBEDDED_NVL(nvp)); 541168404Spjd break; 542168404Spjd case DATA_TYPE_NVLIST_ARRAY: { 543168404Spjd nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 544168404Spjd int i; 545168404Spjd 546168404Spjd for (i = 0; i < NVP_NELEM(nvp); i++) 547297115Smav nvlist_free(nvlp[i]); 548168404Spjd break; 549168404Spjd } 550168404Spjd default: 551168404Spjd break; 552168404Spjd } 553168404Spjd} 554168404Spjd 555168404Spjd/* 556168404Spjd * nvlist_free - free an unpacked nvlist 557168404Spjd */ 558168404Spjdvoid 559168404Spjdnvlist_free(nvlist_t *nvl) 560168404Spjd{ 561168404Spjd nvpriv_t *priv; 562168404Spjd i_nvp_t *curr; 563168404Spjd 564168404Spjd if (nvl == NULL || 565168404Spjd (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 566168404Spjd return; 567168404Spjd 568168404Spjd /* 569168404Spjd * Unpacked nvlist are linked through i_nvp_t 570168404Spjd */ 571168404Spjd curr = priv->nvp_list; 572168404Spjd while (curr != NULL) { 573168404Spjd nvpair_t *nvp = &curr->nvi_nvp; 574168404Spjd curr = curr->nvi_next; 575168404Spjd 576168404Spjd nvpair_free(nvp); 577168404Spjd nvp_buf_free(nvl, nvp); 578168404Spjd } 579168404Spjd 580168404Spjd if (!(priv->nvp_stat & NV_STAT_EMBEDDED)) 581168404Spjd nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t))); 582168404Spjd else 583168404Spjd nvl->nvl_priv = 0; 584168404Spjd 585168404Spjd nv_mem_free(priv, priv, sizeof (nvpriv_t)); 586168404Spjd} 587168404Spjd 588168404Spjdstatic int 589168404Spjdnvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp) 590168404Spjd{ 591168404Spjd nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 592168404Spjd i_nvp_t *curr; 593168404Spjd 594168404Spjd if (nvp == NULL) 595168404Spjd return (0); 596168404Spjd 597168404Spjd for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 598168404Spjd if (&curr->nvi_nvp == nvp) 599168404Spjd return (1); 600168404Spjd 601168404Spjd return (0); 602168404Spjd} 603168404Spjd 604168404Spjd/* 605168404Spjd * Make a copy of nvlist 606168404Spjd */ 607168404Spjd/*ARGSUSED1*/ 608168404Spjdint 609168404Spjdnvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag) 610168404Spjd{ 611168404Spjd#if defined(_KERNEL) && !defined(_BOOT) 612168404Spjd return (nvlist_xdup(nvl, nvlp, 613168404Spjd (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 614168404Spjd#else 615168404Spjd return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep)); 616168404Spjd#endif 617168404Spjd} 618168404Spjd 619168404Spjdint 620168404Spjdnvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva) 621168404Spjd{ 622168404Spjd int err; 623168404Spjd nvlist_t *ret; 624168404Spjd 625168404Spjd if (nvl == NULL || nvlp == NULL) 626168404Spjd return (EINVAL); 627168404Spjd 628168404Spjd if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0) 629168404Spjd return (err); 630168404Spjd 631168404Spjd if ((err = nvlist_copy_pairs(nvl, ret)) != 0) 632168404Spjd nvlist_free(ret); 633168404Spjd else 634168404Spjd *nvlp = ret; 635168404Spjd 636168404Spjd return (err); 637168404Spjd} 638168404Spjd 639168404Spjd/* 640168404Spjd * Remove all with matching name 641168404Spjd */ 642168404Spjdint 643168404Spjdnvlist_remove_all(nvlist_t *nvl, const char *name) 644168404Spjd{ 645168404Spjd nvpriv_t *priv; 646168404Spjd i_nvp_t *curr; 647168404Spjd int error = ENOENT; 648168404Spjd 649168404Spjd if (nvl == NULL || name == NULL || 650168404Spjd (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 651168404Spjd return (EINVAL); 652168404Spjd 653168404Spjd curr = priv->nvp_list; 654168404Spjd while (curr != NULL) { 655168404Spjd nvpair_t *nvp = &curr->nvi_nvp; 656168404Spjd 657168404Spjd curr = curr->nvi_next; 658168404Spjd if (strcmp(name, NVP_NAME(nvp)) != 0) 659168404Spjd continue; 660168404Spjd 661168404Spjd nvp_buf_unlink(nvl, nvp); 662168404Spjd nvpair_free(nvp); 663168404Spjd nvp_buf_free(nvl, nvp); 664168404Spjd 665168404Spjd error = 0; 666168404Spjd } 667168404Spjd 668168404Spjd return (error); 669168404Spjd} 670168404Spjd 671168404Spjd/* 672168404Spjd * Remove first one with matching name and type 673168404Spjd */ 674168404Spjdint 675168404Spjdnvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) 676168404Spjd{ 677168404Spjd nvpriv_t *priv; 678168404Spjd i_nvp_t *curr; 679168404Spjd 680168404Spjd if (nvl == NULL || name == NULL || 681168404Spjd (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 682168404Spjd return (EINVAL); 683168404Spjd 684168404Spjd curr = priv->nvp_list; 685168404Spjd while (curr != NULL) { 686168404Spjd nvpair_t *nvp = &curr->nvi_nvp; 687168404Spjd 688168404Spjd if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) { 689168404Spjd nvp_buf_unlink(nvl, nvp); 690168404Spjd nvpair_free(nvp); 691168404Spjd nvp_buf_free(nvl, nvp); 692168404Spjd 693168404Spjd return (0); 694168404Spjd } 695168404Spjd curr = curr->nvi_next; 696168404Spjd } 697168404Spjd 698168404Spjd return (ENOENT); 699168404Spjd} 700168404Spjd 701219089Spjdint 702219089Spjdnvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 703219089Spjd{ 704219089Spjd if (nvl == NULL || nvp == NULL) 705219089Spjd return (EINVAL); 706219089Spjd 707219089Spjd nvp_buf_unlink(nvl, nvp); 708219089Spjd nvpair_free(nvp); 709219089Spjd nvp_buf_free(nvl, nvp); 710219089Spjd return (0); 711219089Spjd} 712219089Spjd 713168404Spjd/* 714168404Spjd * This function calculates the size of an nvpair value. 715168404Spjd * 716168404Spjd * The data argument controls the behavior in case of the data types 717168404Spjd * DATA_TYPE_STRING and 718168404Spjd * DATA_TYPE_STRING_ARRAY 719168404Spjd * Is data == NULL then the size of the string(s) is excluded. 720168404Spjd */ 721168404Spjdstatic int 722168404Spjdi_get_value_size(data_type_t type, const void *data, uint_t nelem) 723168404Spjd{ 724168404Spjd uint64_t value_sz; 725168404Spjd 726168404Spjd if (i_validate_type_nelem(type, nelem) != 0) 727168404Spjd return (-1); 728168404Spjd 729168404Spjd /* Calculate required size for holding value */ 730168404Spjd switch (type) { 731168404Spjd case DATA_TYPE_BOOLEAN: 732168404Spjd value_sz = 0; 733168404Spjd break; 734168404Spjd case DATA_TYPE_BOOLEAN_VALUE: 735168404Spjd value_sz = sizeof (boolean_t); 736168404Spjd break; 737168404Spjd case DATA_TYPE_BYTE: 738168404Spjd value_sz = sizeof (uchar_t); 739168404Spjd break; 740168404Spjd case DATA_TYPE_INT8: 741168404Spjd value_sz = sizeof (int8_t); 742168404Spjd break; 743168404Spjd case DATA_TYPE_UINT8: 744168404Spjd value_sz = sizeof (uint8_t); 745168404Spjd break; 746168404Spjd case DATA_TYPE_INT16: 747168404Spjd value_sz = sizeof (int16_t); 748168404Spjd break; 749168404Spjd case DATA_TYPE_UINT16: 750168404Spjd value_sz = sizeof (uint16_t); 751168404Spjd break; 752168404Spjd case DATA_TYPE_INT32: 753168404Spjd value_sz = sizeof (int32_t); 754168404Spjd break; 755168404Spjd case DATA_TYPE_UINT32: 756168404Spjd value_sz = sizeof (uint32_t); 757168404Spjd break; 758168404Spjd case DATA_TYPE_INT64: 759168404Spjd value_sz = sizeof (int64_t); 760168404Spjd break; 761168404Spjd case DATA_TYPE_UINT64: 762168404Spjd value_sz = sizeof (uint64_t); 763168404Spjd break; 764185029Spjd#if !defined(_KERNEL) 765185029Spjd case DATA_TYPE_DOUBLE: 766185029Spjd value_sz = sizeof (double); 767185029Spjd break; 768185029Spjd#endif 769168404Spjd case DATA_TYPE_STRING: 770168404Spjd if (data == NULL) 771168404Spjd value_sz = 0; 772168404Spjd else 773168404Spjd value_sz = strlen(data) + 1; 774168404Spjd break; 775168404Spjd case DATA_TYPE_BOOLEAN_ARRAY: 776168404Spjd value_sz = (uint64_t)nelem * sizeof (boolean_t); 777168404Spjd break; 778168404Spjd case DATA_TYPE_BYTE_ARRAY: 779168404Spjd value_sz = (uint64_t)nelem * sizeof (uchar_t); 780168404Spjd break; 781168404Spjd case DATA_TYPE_INT8_ARRAY: 782168404Spjd value_sz = (uint64_t)nelem * sizeof (int8_t); 783168404Spjd break; 784168404Spjd case DATA_TYPE_UINT8_ARRAY: 785168404Spjd value_sz = (uint64_t)nelem * sizeof (uint8_t); 786168404Spjd break; 787168404Spjd case DATA_TYPE_INT16_ARRAY: 788168404Spjd value_sz = (uint64_t)nelem * sizeof (int16_t); 789168404Spjd break; 790168404Spjd case DATA_TYPE_UINT16_ARRAY: 791168404Spjd value_sz = (uint64_t)nelem * sizeof (uint16_t); 792168404Spjd break; 793168404Spjd case DATA_TYPE_INT32_ARRAY: 794168404Spjd value_sz = (uint64_t)nelem * sizeof (int32_t); 795168404Spjd break; 796168404Spjd case DATA_TYPE_UINT32_ARRAY: 797168404Spjd value_sz = (uint64_t)nelem * sizeof (uint32_t); 798168404Spjd break; 799168404Spjd case DATA_TYPE_INT64_ARRAY: 800168404Spjd value_sz = (uint64_t)nelem * sizeof (int64_t); 801168404Spjd break; 802168404Spjd case DATA_TYPE_UINT64_ARRAY: 803168404Spjd value_sz = (uint64_t)nelem * sizeof (uint64_t); 804168404Spjd break; 805168404Spjd case DATA_TYPE_STRING_ARRAY: 806168404Spjd value_sz = (uint64_t)nelem * sizeof (uint64_t); 807168404Spjd 808168404Spjd if (data != NULL) { 809168404Spjd char *const *strs = data; 810168404Spjd uint_t i; 811168404Spjd 812168404Spjd /* no alignment requirement for strings */ 813168404Spjd for (i = 0; i < nelem; i++) { 814168404Spjd if (strs[i] == NULL) 815168404Spjd return (-1); 816168404Spjd value_sz += strlen(strs[i]) + 1; 817168404Spjd } 818168404Spjd } 819168404Spjd break; 820168404Spjd case DATA_TYPE_HRTIME: 821168404Spjd value_sz = sizeof (hrtime_t); 822168404Spjd break; 823168404Spjd case DATA_TYPE_NVLIST: 824168404Spjd value_sz = NV_ALIGN(sizeof (nvlist_t)); 825168404Spjd break; 826168404Spjd case DATA_TYPE_NVLIST_ARRAY: 827168404Spjd value_sz = (uint64_t)nelem * sizeof (uint64_t) + 828168404Spjd (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t)); 829168404Spjd break; 830168404Spjd default: 831168404Spjd return (-1); 832168404Spjd } 833168404Spjd 834168404Spjd return (value_sz > INT32_MAX ? -1 : (int)value_sz); 835168404Spjd} 836168404Spjd 837168404Spjdstatic int 838168404Spjdnvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl) 839168404Spjd{ 840168404Spjd nvpriv_t *priv; 841168404Spjd int err; 842168404Spjd 843168404Spjd if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t) 844168404Spjd nvl->nvl_priv)) == NULL) 845168404Spjd return (ENOMEM); 846168404Spjd 847168404Spjd nvlist_init(emb_nvl, onvl->nvl_nvflag, priv); 848168404Spjd 849168404Spjd if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) { 850168404Spjd nvlist_free(emb_nvl); 851168404Spjd emb_nvl->nvl_priv = 0; 852168404Spjd } 853168404Spjd 854168404Spjd return (err); 855168404Spjd} 856168404Spjd 857168404Spjd/* 858168404Spjd * nvlist_add_common - Add new <name,value> pair to nvlist 859168404Spjd */ 860168404Spjdstatic int 861168404Spjdnvlist_add_common(nvlist_t *nvl, const char *name, 862168404Spjd data_type_t type, uint_t nelem, const void *data) 863168404Spjd{ 864168404Spjd nvpair_t *nvp; 865168404Spjd uint_t i; 866168404Spjd 867168404Spjd int nvp_sz, name_sz, value_sz; 868168404Spjd int err = 0; 869168404Spjd 870168404Spjd if (name == NULL || nvl == NULL || nvl->nvl_priv == 0) 871168404Spjd return (EINVAL); 872168404Spjd 873168404Spjd if (nelem != 0 && data == NULL) 874168404Spjd return (EINVAL); 875168404Spjd 876168404Spjd /* 877168404Spjd * Verify type and nelem and get the value size. 878168404Spjd * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 879168404Spjd * is the size of the string(s) included. 880168404Spjd */ 881168404Spjd if ((value_sz = i_get_value_size(type, data, nelem)) < 0) 882168404Spjd return (EINVAL); 883168404Spjd 884168404Spjd if (i_validate_nvpair_value(type, nelem, data) != 0) 885168404Spjd return (EINVAL); 886168404Spjd 887168404Spjd /* 888168404Spjd * If we're adding an nvlist or nvlist array, ensure that we are not 889168404Spjd * adding the input nvlist to itself, which would cause recursion, 890168404Spjd * and ensure that no NULL nvlist pointers are present. 891168404Spjd */ 892168404Spjd switch (type) { 893168404Spjd case DATA_TYPE_NVLIST: 894168404Spjd if (data == nvl || data == NULL) 895168404Spjd return (EINVAL); 896168404Spjd break; 897168404Spjd case DATA_TYPE_NVLIST_ARRAY: { 898168404Spjd nvlist_t **onvlp = (nvlist_t **)data; 899168404Spjd for (i = 0; i < nelem; i++) { 900168404Spjd if (onvlp[i] == nvl || onvlp[i] == NULL) 901168404Spjd return (EINVAL); 902168404Spjd } 903168404Spjd break; 904168404Spjd } 905168404Spjd default: 906168404Spjd break; 907168404Spjd } 908168404Spjd 909168404Spjd /* calculate sizes of the nvpair elements and the nvpair itself */ 910168404Spjd name_sz = strlen(name) + 1; 911168404Spjd 912168404Spjd nvp_sz = NVP_SIZE_CALC(name_sz, value_sz); 913168404Spjd 914168404Spjd if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL) 915168404Spjd return (ENOMEM); 916168404Spjd 917168404Spjd ASSERT(nvp->nvp_size == nvp_sz); 918168404Spjd nvp->nvp_name_sz = name_sz; 919168404Spjd nvp->nvp_value_elem = nelem; 920168404Spjd nvp->nvp_type = type; 921168404Spjd bcopy(name, NVP_NAME(nvp), name_sz); 922168404Spjd 923168404Spjd switch (type) { 924168404Spjd case DATA_TYPE_BOOLEAN: 925168404Spjd break; 926168404Spjd case DATA_TYPE_STRING_ARRAY: { 927168404Spjd char *const *strs = data; 928168404Spjd char *buf = NVP_VALUE(nvp); 929168404Spjd char **cstrs = (void *)buf; 930168404Spjd 931168404Spjd /* skip pre-allocated space for pointer array */ 932168404Spjd buf += nelem * sizeof (uint64_t); 933168404Spjd for (i = 0; i < nelem; i++) { 934168404Spjd int slen = strlen(strs[i]) + 1; 935168404Spjd bcopy(strs[i], buf, slen); 936168404Spjd cstrs[i] = buf; 937168404Spjd buf += slen; 938168404Spjd } 939168404Spjd break; 940168404Spjd } 941168404Spjd case DATA_TYPE_NVLIST: { 942168404Spjd nvlist_t *nnvl = EMBEDDED_NVL(nvp); 943168404Spjd nvlist_t *onvl = (nvlist_t *)data; 944168404Spjd 945168404Spjd if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) { 946168404Spjd nvp_buf_free(nvl, nvp); 947168404Spjd return (err); 948168404Spjd } 949168404Spjd break; 950168404Spjd } 951168404Spjd case DATA_TYPE_NVLIST_ARRAY: { 952168404Spjd nvlist_t **onvlp = (nvlist_t **)data; 953168404Spjd nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 954168404Spjd nvlist_t *embedded = (nvlist_t *) 955168404Spjd ((uintptr_t)nvlp + nelem * sizeof (uint64_t)); 956168404Spjd 957168404Spjd for (i = 0; i < nelem; i++) { 958168404Spjd if ((err = nvlist_copy_embedded(nvl, 959168404Spjd onvlp[i], embedded)) != 0) { 960168404Spjd /* 961168404Spjd * Free any successfully created lists 962168404Spjd */ 963168404Spjd nvpair_free(nvp); 964168404Spjd nvp_buf_free(nvl, nvp); 965168404Spjd return (err); 966168404Spjd } 967168404Spjd 968168404Spjd nvlp[i] = embedded++; 969168404Spjd } 970168404Spjd break; 971168404Spjd } 972168404Spjd default: 973168404Spjd bcopy(data, NVP_VALUE(nvp), value_sz); 974168404Spjd } 975168404Spjd 976168404Spjd /* if unique name, remove before add */ 977168404Spjd if (nvl->nvl_nvflag & NV_UNIQUE_NAME) 978168404Spjd (void) nvlist_remove_all(nvl, name); 979168404Spjd else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE) 980168404Spjd (void) nvlist_remove(nvl, name, type); 981168404Spjd 982168404Spjd nvp_buf_link(nvl, nvp); 983168404Spjd 984168404Spjd return (0); 985168404Spjd} 986168404Spjd 987168404Spjdint 988168404Spjdnvlist_add_boolean(nvlist_t *nvl, const char *name) 989168404Spjd{ 990168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL)); 991168404Spjd} 992168404Spjd 993168404Spjdint 994168404Spjdnvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val) 995168404Spjd{ 996168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val)); 997168404Spjd} 998168404Spjd 999168404Spjdint 1000168404Spjdnvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val) 1001168404Spjd{ 1002168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val)); 1003168404Spjd} 1004168404Spjd 1005168404Spjdint 1006168404Spjdnvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val) 1007168404Spjd{ 1008168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val)); 1009168404Spjd} 1010168404Spjd 1011168404Spjdint 1012168404Spjdnvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val) 1013168404Spjd{ 1014168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val)); 1015168404Spjd} 1016168404Spjd 1017168404Spjdint 1018168404Spjdnvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val) 1019168404Spjd{ 1020168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val)); 1021168404Spjd} 1022168404Spjd 1023168404Spjdint 1024168404Spjdnvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val) 1025168404Spjd{ 1026168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val)); 1027168404Spjd} 1028168404Spjd 1029168404Spjdint 1030168404Spjdnvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val) 1031168404Spjd{ 1032168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val)); 1033168404Spjd} 1034168404Spjd 1035168404Spjdint 1036168404Spjdnvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val) 1037168404Spjd{ 1038168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val)); 1039168404Spjd} 1040168404Spjd 1041168404Spjdint 1042168404Spjdnvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val) 1043168404Spjd{ 1044168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val)); 1045168404Spjd} 1046168404Spjd 1047168404Spjdint 1048168404Spjdnvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val) 1049168404Spjd{ 1050168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val)); 1051168404Spjd} 1052168404Spjd 1053185029Spjd#if !defined(_KERNEL) 1054168404Spjdint 1055185029Spjdnvlist_add_double(nvlist_t *nvl, const char *name, double val) 1056185029Spjd{ 1057185029Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val)); 1058185029Spjd} 1059185029Spjd#endif 1060185029Spjd 1061185029Spjdint 1062168404Spjdnvlist_add_string(nvlist_t *nvl, const char *name, const char *val) 1063168404Spjd{ 1064168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val)); 1065168404Spjd} 1066168404Spjd 1067168404Spjdint 1068168404Spjdnvlist_add_boolean_array(nvlist_t *nvl, const char *name, 1069168404Spjd boolean_t *a, uint_t n) 1070168404Spjd{ 1071168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1072168404Spjd} 1073168404Spjd 1074168404Spjdint 1075168404Spjdnvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *a, uint_t n) 1076168404Spjd{ 1077168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1078168404Spjd} 1079168404Spjd 1080168404Spjdint 1081168404Spjdnvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint_t n) 1082168404Spjd{ 1083168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1084168404Spjd} 1085168404Spjd 1086168404Spjdint 1087168404Spjdnvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint_t n) 1088168404Spjd{ 1089168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1090168404Spjd} 1091168404Spjd 1092168404Spjdint 1093168404Spjdnvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint_t n) 1094168404Spjd{ 1095168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1096168404Spjd} 1097168404Spjd 1098168404Spjdint 1099168404Spjdnvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, uint_t n) 1100168404Spjd{ 1101168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1102168404Spjd} 1103168404Spjd 1104168404Spjdint 1105168404Spjdnvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint_t n) 1106168404Spjd{ 1107168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1108168404Spjd} 1109168404Spjd 1110168404Spjdint 1111168404Spjdnvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, uint_t n) 1112168404Spjd{ 1113168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1114168404Spjd} 1115168404Spjd 1116168404Spjdint 1117168404Spjdnvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint_t n) 1118168404Spjd{ 1119168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1120168404Spjd} 1121168404Spjd 1122168404Spjdint 1123168404Spjdnvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, uint_t n) 1124168404Spjd{ 1125168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1126168404Spjd} 1127168404Spjd 1128168404Spjdint 1129168404Spjdnvlist_add_string_array(nvlist_t *nvl, const char *name, 1130168404Spjd char *const *a, uint_t n) 1131168404Spjd{ 1132168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1133168404Spjd} 1134168404Spjd 1135168404Spjdint 1136168404Spjdnvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val) 1137168404Spjd{ 1138168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val)); 1139168404Spjd} 1140168404Spjd 1141168404Spjdint 1142168404Spjdnvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) 1143168404Spjd{ 1144168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); 1145168404Spjd} 1146168404Spjd 1147168404Spjdint 1148168404Spjdnvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, uint_t n) 1149168404Spjd{ 1150168404Spjd return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1151168404Spjd} 1152168404Spjd 1153168404Spjd/* reading name-value pairs */ 1154168404Spjdnvpair_t * 1155168404Spjdnvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1156168404Spjd{ 1157168404Spjd nvpriv_t *priv; 1158168404Spjd i_nvp_t *curr; 1159168404Spjd 1160168404Spjd if (nvl == NULL || 1161168404Spjd (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1162168404Spjd return (NULL); 1163168404Spjd 1164168404Spjd curr = NVPAIR2I_NVP(nvp); 1165168404Spjd 1166168404Spjd /* 1167185029Spjd * Ensure that nvp is a valid nvpair on this nvlist. 1168185029Spjd * NB: nvp_curr is used only as a hint so that we don't always 1169185029Spjd * have to walk the list to determine if nvp is still on the list. 1170168404Spjd */ 1171168404Spjd if (nvp == NULL) 1172168404Spjd curr = priv->nvp_list; 1173185029Spjd else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp)) 1174168404Spjd curr = curr->nvi_next; 1175185029Spjd else 1176168404Spjd curr = NULL; 1177168404Spjd 1178168404Spjd priv->nvp_curr = curr; 1179168404Spjd 1180168404Spjd return (curr != NULL ? &curr->nvi_nvp : NULL); 1181168404Spjd} 1182168404Spjd 1183219089Spjdnvpair_t * 1184219089Spjdnvlist_prev_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1185219089Spjd{ 1186219089Spjd nvpriv_t *priv; 1187219089Spjd i_nvp_t *curr; 1188219089Spjd 1189219089Spjd if (nvl == NULL || 1190219089Spjd (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1191219089Spjd return (NULL); 1192219089Spjd 1193219089Spjd curr = NVPAIR2I_NVP(nvp); 1194219089Spjd 1195219089Spjd if (nvp == NULL) 1196219089Spjd curr = priv->nvp_last; 1197219089Spjd else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp)) 1198219089Spjd curr = curr->nvi_prev; 1199219089Spjd else 1200219089Spjd curr = NULL; 1201219089Spjd 1202219089Spjd priv->nvp_curr = curr; 1203219089Spjd 1204219089Spjd return (curr != NULL ? &curr->nvi_nvp : NULL); 1205219089Spjd} 1206219089Spjd 1207219089Spjdboolean_t 1208219089Spjdnvlist_empty(nvlist_t *nvl) 1209219089Spjd{ 1210219089Spjd nvpriv_t *priv; 1211219089Spjd 1212219089Spjd if (nvl == NULL || 1213219089Spjd (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1214219089Spjd return (B_TRUE); 1215219089Spjd 1216219089Spjd return (priv->nvp_list == NULL); 1217219089Spjd} 1218219089Spjd 1219168404Spjdchar * 1220168404Spjdnvpair_name(nvpair_t *nvp) 1221168404Spjd{ 1222168404Spjd return (NVP_NAME(nvp)); 1223168404Spjd} 1224168404Spjd 1225168404Spjddata_type_t 1226168404Spjdnvpair_type(nvpair_t *nvp) 1227168404Spjd{ 1228168404Spjd return (NVP_TYPE(nvp)); 1229168404Spjd} 1230168404Spjd 1231185029Spjdint 1232185029Spjdnvpair_type_is_array(nvpair_t *nvp) 1233185029Spjd{ 1234185029Spjd data_type_t type = NVP_TYPE(nvp); 1235185029Spjd 1236185029Spjd if ((type == DATA_TYPE_BYTE_ARRAY) || 1237282122Savg (type == DATA_TYPE_INT8_ARRAY) || 1238185029Spjd (type == DATA_TYPE_UINT8_ARRAY) || 1239185029Spjd (type == DATA_TYPE_INT16_ARRAY) || 1240185029Spjd (type == DATA_TYPE_UINT16_ARRAY) || 1241185029Spjd (type == DATA_TYPE_INT32_ARRAY) || 1242185029Spjd (type == DATA_TYPE_UINT32_ARRAY) || 1243185029Spjd (type == DATA_TYPE_INT64_ARRAY) || 1244185029Spjd (type == DATA_TYPE_UINT64_ARRAY) || 1245185029Spjd (type == DATA_TYPE_BOOLEAN_ARRAY) || 1246185029Spjd (type == DATA_TYPE_STRING_ARRAY) || 1247185029Spjd (type == DATA_TYPE_NVLIST_ARRAY)) 1248185029Spjd return (1); 1249185029Spjd return (0); 1250185029Spjd 1251185029Spjd} 1252185029Spjd 1253168404Spjdstatic int 1254168404Spjdnvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data) 1255168404Spjd{ 1256168404Spjd if (nvp == NULL || nvpair_type(nvp) != type) 1257168404Spjd return (EINVAL); 1258168404Spjd 1259168404Spjd /* 1260168404Spjd * For non-array types, we copy the data. 1261168404Spjd * For array types (including string), we set a pointer. 1262168404Spjd */ 1263168404Spjd switch (type) { 1264168404Spjd case DATA_TYPE_BOOLEAN: 1265168404Spjd if (nelem != NULL) 1266168404Spjd *nelem = 0; 1267168404Spjd break; 1268168404Spjd 1269168404Spjd case DATA_TYPE_BOOLEAN_VALUE: 1270168404Spjd case DATA_TYPE_BYTE: 1271168404Spjd case DATA_TYPE_INT8: 1272168404Spjd case DATA_TYPE_UINT8: 1273168404Spjd case DATA_TYPE_INT16: 1274168404Spjd case DATA_TYPE_UINT16: 1275168404Spjd case DATA_TYPE_INT32: 1276168404Spjd case DATA_TYPE_UINT32: 1277168404Spjd case DATA_TYPE_INT64: 1278168404Spjd case DATA_TYPE_UINT64: 1279168404Spjd case DATA_TYPE_HRTIME: 1280185029Spjd#if !defined(_KERNEL) 1281185029Spjd case DATA_TYPE_DOUBLE: 1282185029Spjd#endif 1283168404Spjd if (data == NULL) 1284168404Spjd return (EINVAL); 1285168404Spjd bcopy(NVP_VALUE(nvp), data, 1286168404Spjd (size_t)i_get_value_size(type, NULL, 1)); 1287168404Spjd if (nelem != NULL) 1288168404Spjd *nelem = 1; 1289168404Spjd break; 1290168404Spjd 1291168404Spjd case DATA_TYPE_NVLIST: 1292168404Spjd case DATA_TYPE_STRING: 1293168404Spjd if (data == NULL) 1294168404Spjd return (EINVAL); 1295168404Spjd *(void **)data = (void *)NVP_VALUE(nvp); 1296168404Spjd if (nelem != NULL) 1297168404Spjd *nelem = 1; 1298168404Spjd break; 1299168404Spjd 1300168404Spjd case DATA_TYPE_BOOLEAN_ARRAY: 1301168404Spjd case DATA_TYPE_BYTE_ARRAY: 1302168404Spjd case DATA_TYPE_INT8_ARRAY: 1303168404Spjd case DATA_TYPE_UINT8_ARRAY: 1304168404Spjd case DATA_TYPE_INT16_ARRAY: 1305168404Spjd case DATA_TYPE_UINT16_ARRAY: 1306168404Spjd case DATA_TYPE_INT32_ARRAY: 1307168404Spjd case DATA_TYPE_UINT32_ARRAY: 1308168404Spjd case DATA_TYPE_INT64_ARRAY: 1309168404Spjd case DATA_TYPE_UINT64_ARRAY: 1310168404Spjd case DATA_TYPE_STRING_ARRAY: 1311168404Spjd case DATA_TYPE_NVLIST_ARRAY: 1312168404Spjd if (nelem == NULL || data == NULL) 1313168404Spjd return (EINVAL); 1314168404Spjd if ((*nelem = NVP_NELEM(nvp)) != 0) 1315168404Spjd *(void **)data = (void *)NVP_VALUE(nvp); 1316168404Spjd else 1317168404Spjd *(void **)data = NULL; 1318168404Spjd break; 1319168404Spjd 1320168404Spjd default: 1321168404Spjd return (ENOTSUP); 1322168404Spjd } 1323168404Spjd 1324168404Spjd return (0); 1325168404Spjd} 1326168404Spjd 1327168404Spjdstatic int 1328168404Spjdnvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type, 1329168404Spjd uint_t *nelem, void *data) 1330168404Spjd{ 1331168404Spjd nvpriv_t *priv; 1332168404Spjd nvpair_t *nvp; 1333168404Spjd i_nvp_t *curr; 1334168404Spjd 1335168404Spjd if (name == NULL || nvl == NULL || 1336168404Spjd (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1337168404Spjd return (EINVAL); 1338168404Spjd 1339168404Spjd if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE))) 1340168404Spjd return (ENOTSUP); 1341168404Spjd 1342168404Spjd for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 1343168404Spjd nvp = &curr->nvi_nvp; 1344168404Spjd 1345168404Spjd if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) 1346168404Spjd return (nvpair_value_common(nvp, type, nelem, data)); 1347168404Spjd } 1348168404Spjd 1349168404Spjd return (ENOENT); 1350168404Spjd} 1351168404Spjd 1352168404Spjdint 1353168404Spjdnvlist_lookup_boolean(nvlist_t *nvl, const char *name) 1354168404Spjd{ 1355168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL)); 1356168404Spjd} 1357168404Spjd 1358168404Spjdint 1359168404Spjdnvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val) 1360168404Spjd{ 1361168404Spjd return (nvlist_lookup_common(nvl, name, 1362168404Spjd DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 1363168404Spjd} 1364168404Spjd 1365168404Spjdint 1366168404Spjdnvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val) 1367168404Spjd{ 1368168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val)); 1369168404Spjd} 1370168404Spjd 1371168404Spjdint 1372168404Spjdnvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val) 1373168404Spjd{ 1374168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val)); 1375168404Spjd} 1376168404Spjd 1377168404Spjdint 1378168404Spjdnvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val) 1379168404Spjd{ 1380168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val)); 1381168404Spjd} 1382168404Spjd 1383168404Spjdint 1384168404Spjdnvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val) 1385168404Spjd{ 1386168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val)); 1387168404Spjd} 1388168404Spjd 1389168404Spjdint 1390168404Spjdnvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val) 1391168404Spjd{ 1392168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val)); 1393168404Spjd} 1394168404Spjd 1395168404Spjdint 1396168404Spjdnvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val) 1397168404Spjd{ 1398168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val)); 1399168404Spjd} 1400168404Spjd 1401168404Spjdint 1402168404Spjdnvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val) 1403168404Spjd{ 1404168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val)); 1405168404Spjd} 1406168404Spjd 1407168404Spjdint 1408168404Spjdnvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val) 1409168404Spjd{ 1410168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val)); 1411168404Spjd} 1412168404Spjd 1413168404Spjdint 1414168404Spjdnvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val) 1415168404Spjd{ 1416168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val)); 1417168404Spjd} 1418168404Spjd 1419185029Spjd#if !defined(_KERNEL) 1420168404Spjdint 1421185029Spjdnvlist_lookup_double(nvlist_t *nvl, const char *name, double *val) 1422185029Spjd{ 1423185029Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val)); 1424185029Spjd} 1425185029Spjd#endif 1426185029Spjd 1427185029Spjdint 1428168404Spjdnvlist_lookup_string(nvlist_t *nvl, const char *name, char **val) 1429168404Spjd{ 1430168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val)); 1431168404Spjd} 1432168404Spjd 1433168404Spjdint 1434168404Spjdnvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val) 1435168404Spjd{ 1436168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val)); 1437168404Spjd} 1438168404Spjd 1439168404Spjdint 1440168404Spjdnvlist_lookup_boolean_array(nvlist_t *nvl, const char *name, 1441168404Spjd boolean_t **a, uint_t *n) 1442168404Spjd{ 1443168404Spjd return (nvlist_lookup_common(nvl, name, 1444168404Spjd DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1445168404Spjd} 1446168404Spjd 1447168404Spjdint 1448168404Spjdnvlist_lookup_byte_array(nvlist_t *nvl, const char *name, 1449168404Spjd uchar_t **a, uint_t *n) 1450168404Spjd{ 1451168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1452168404Spjd} 1453168404Spjd 1454168404Spjdint 1455168404Spjdnvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n) 1456168404Spjd{ 1457168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1458168404Spjd} 1459168404Spjd 1460168404Spjdint 1461168404Spjdnvlist_lookup_uint8_array(nvlist_t *nvl, const char *name, 1462168404Spjd uint8_t **a, uint_t *n) 1463168404Spjd{ 1464168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1465168404Spjd} 1466168404Spjd 1467168404Spjdint 1468168404Spjdnvlist_lookup_int16_array(nvlist_t *nvl, const char *name, 1469168404Spjd int16_t **a, uint_t *n) 1470168404Spjd{ 1471168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1472168404Spjd} 1473168404Spjd 1474168404Spjdint 1475168404Spjdnvlist_lookup_uint16_array(nvlist_t *nvl, const char *name, 1476168404Spjd uint16_t **a, uint_t *n) 1477168404Spjd{ 1478168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1479168404Spjd} 1480168404Spjd 1481168404Spjdint 1482168404Spjdnvlist_lookup_int32_array(nvlist_t *nvl, const char *name, 1483168404Spjd int32_t **a, uint_t *n) 1484168404Spjd{ 1485168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1486168404Spjd} 1487168404Spjd 1488168404Spjdint 1489168404Spjdnvlist_lookup_uint32_array(nvlist_t *nvl, const char *name, 1490168404Spjd uint32_t **a, uint_t *n) 1491168404Spjd{ 1492168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1493168404Spjd} 1494168404Spjd 1495168404Spjdint 1496168404Spjdnvlist_lookup_int64_array(nvlist_t *nvl, const char *name, 1497168404Spjd int64_t **a, uint_t *n) 1498168404Spjd{ 1499168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1500168404Spjd} 1501168404Spjd 1502168404Spjdint 1503168404Spjdnvlist_lookup_uint64_array(nvlist_t *nvl, const char *name, 1504168404Spjd uint64_t **a, uint_t *n) 1505168404Spjd{ 1506168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1507168404Spjd} 1508168404Spjd 1509168404Spjdint 1510168404Spjdnvlist_lookup_string_array(nvlist_t *nvl, const char *name, 1511168404Spjd char ***a, uint_t *n) 1512168404Spjd{ 1513168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1514168404Spjd} 1515168404Spjd 1516168404Spjdint 1517168404Spjdnvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name, 1518168404Spjd nvlist_t ***a, uint_t *n) 1519168404Spjd{ 1520168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1521168404Spjd} 1522168404Spjd 1523168404Spjdint 1524168404Spjdnvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val) 1525168404Spjd{ 1526168404Spjd return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val)); 1527168404Spjd} 1528168404Spjd 1529168404Spjdint 1530168404Spjdnvlist_lookup_pairs(nvlist_t *nvl, int flag, ...) 1531168404Spjd{ 1532168404Spjd va_list ap; 1533168404Spjd char *name; 1534168404Spjd int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0); 1535168404Spjd int ret = 0; 1536168404Spjd 1537168404Spjd va_start(ap, flag); 1538168404Spjd while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { 1539168404Spjd data_type_t type; 1540168404Spjd void *val; 1541168404Spjd uint_t *nelem; 1542168404Spjd 1543168404Spjd switch (type = va_arg(ap, data_type_t)) { 1544168404Spjd case DATA_TYPE_BOOLEAN: 1545168404Spjd ret = nvlist_lookup_common(nvl, name, type, NULL, NULL); 1546168404Spjd break; 1547168404Spjd 1548168404Spjd case DATA_TYPE_BOOLEAN_VALUE: 1549168404Spjd case DATA_TYPE_BYTE: 1550168404Spjd case DATA_TYPE_INT8: 1551168404Spjd case DATA_TYPE_UINT8: 1552168404Spjd case DATA_TYPE_INT16: 1553168404Spjd case DATA_TYPE_UINT16: 1554168404Spjd case DATA_TYPE_INT32: 1555168404Spjd case DATA_TYPE_UINT32: 1556168404Spjd case DATA_TYPE_INT64: 1557168404Spjd case DATA_TYPE_UINT64: 1558168404Spjd case DATA_TYPE_HRTIME: 1559168404Spjd case DATA_TYPE_STRING: 1560168404Spjd case DATA_TYPE_NVLIST: 1561185029Spjd#if !defined(_KERNEL) 1562185029Spjd case DATA_TYPE_DOUBLE: 1563185029Spjd#endif 1564168404Spjd val = va_arg(ap, void *); 1565168404Spjd ret = nvlist_lookup_common(nvl, name, type, NULL, val); 1566168404Spjd break; 1567168404Spjd 1568168404Spjd case DATA_TYPE_BYTE_ARRAY: 1569168404Spjd case DATA_TYPE_BOOLEAN_ARRAY: 1570168404Spjd case DATA_TYPE_INT8_ARRAY: 1571168404Spjd case DATA_TYPE_UINT8_ARRAY: 1572168404Spjd case DATA_TYPE_INT16_ARRAY: 1573168404Spjd case DATA_TYPE_UINT16_ARRAY: 1574168404Spjd case DATA_TYPE_INT32_ARRAY: 1575168404Spjd case DATA_TYPE_UINT32_ARRAY: 1576168404Spjd case DATA_TYPE_INT64_ARRAY: 1577168404Spjd case DATA_TYPE_UINT64_ARRAY: 1578168404Spjd case DATA_TYPE_STRING_ARRAY: 1579168404Spjd case DATA_TYPE_NVLIST_ARRAY: 1580168404Spjd val = va_arg(ap, void *); 1581168404Spjd nelem = va_arg(ap, uint_t *); 1582168404Spjd ret = nvlist_lookup_common(nvl, name, type, nelem, val); 1583168404Spjd break; 1584168404Spjd 1585168404Spjd default: 1586168404Spjd ret = EINVAL; 1587168404Spjd } 1588168404Spjd 1589168404Spjd if (ret == ENOENT && noentok) 1590168404Spjd ret = 0; 1591168404Spjd } 1592168404Spjd va_end(ap); 1593168404Spjd 1594168404Spjd return (ret); 1595168404Spjd} 1596168404Spjd 1597185029Spjd/* 1598185029Spjd * Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function 1599185029Spjd * returns zero and a pointer to the matching nvpair is returned in '*ret' 1600185029Spjd * (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate 1601185029Spjd * multiple levels of embedded nvlists, with 'sep' as the separator. As an 1602185029Spjd * example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or 1603185029Spjd * "a.d[3].e[1]". This matches the C syntax for array embed (for convience, 1604185029Spjd * code also supports "a.d[3]e[1]" syntax). 1605185029Spjd * 1606185029Spjd * If 'ip' is non-NULL and the last name component is an array, return the 1607185029Spjd * value of the "...[index]" array index in *ip. For an array reference that 1608185029Spjd * is not indexed, *ip will be returned as -1. If there is a syntax error in 1609185029Spjd * 'name', and 'ep' is non-NULL then *ep will be set to point to the location 1610185029Spjd * inside the 'name' string where the syntax error was detected. 1611185029Spjd */ 1612185029Spjdstatic int 1613185029Spjdnvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep, 1614185029Spjd nvpair_t **ret, int *ip, char **ep) 1615185029Spjd{ 1616185029Spjd nvpair_t *nvp; 1617185029Spjd const char *np; 1618185029Spjd char *sepp; 1619185029Spjd char *idxp, *idxep; 1620185029Spjd nvlist_t **nva; 1621185029Spjd long idx; 1622185029Spjd int n; 1623185029Spjd 1624185029Spjd if (ip) 1625185029Spjd *ip = -1; /* not indexed */ 1626185029Spjd if (ep) 1627185029Spjd *ep = NULL; 1628185029Spjd 1629185029Spjd if ((nvl == NULL) || (name == NULL)) 1630185029Spjd return (EINVAL); 1631185029Spjd 1632307124Smav sepp = NULL; 1633307124Smav idx = 0; 1634185029Spjd /* step through components of name */ 1635185029Spjd for (np = name; np && *np; np = sepp) { 1636185029Spjd /* ensure unique names */ 1637185029Spjd if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME)) 1638185029Spjd return (ENOTSUP); 1639185029Spjd 1640185029Spjd /* skip white space */ 1641185029Spjd skip_whitespace(np); 1642185029Spjd if (*np == 0) 1643185029Spjd break; 1644185029Spjd 1645185029Spjd /* set 'sepp' to end of current component 'np' */ 1646185029Spjd if (sep) 1647185029Spjd sepp = strchr(np, sep); 1648185029Spjd else 1649185029Spjd sepp = NULL; 1650185029Spjd 1651185029Spjd /* find start of next "[ index ]..." */ 1652185029Spjd idxp = strchr(np, '['); 1653185029Spjd 1654185029Spjd /* if sepp comes first, set idxp to NULL */ 1655185029Spjd if (sepp && idxp && (sepp < idxp)) 1656185029Spjd idxp = NULL; 1657185029Spjd 1658185029Spjd /* 1659185029Spjd * At this point 'idxp' is set if there is an index 1660185029Spjd * expected for the current component. 1661185029Spjd */ 1662185029Spjd if (idxp) { 1663185029Spjd /* set 'n' to length of current 'np' name component */ 1664185029Spjd n = idxp++ - np; 1665185029Spjd 1666185029Spjd /* keep sepp up to date for *ep use as we advance */ 1667185029Spjd skip_whitespace(idxp); 1668185029Spjd sepp = idxp; 1669185029Spjd 1670185029Spjd /* determine the index value */ 1671185029Spjd#if defined(_KERNEL) && !defined(_BOOT) 1672185029Spjd if (ddi_strtol(idxp, &idxep, 0, &idx)) 1673185029Spjd goto fail; 1674185029Spjd#else 1675185029Spjd idx = strtol(idxp, &idxep, 0); 1676185029Spjd#endif 1677185029Spjd if (idxep == idxp) 1678185029Spjd goto fail; 1679185029Spjd 1680185029Spjd /* keep sepp up to date for *ep use as we advance */ 1681185029Spjd sepp = idxep; 1682185029Spjd 1683185029Spjd /* skip white space index value and check for ']' */ 1684185029Spjd skip_whitespace(sepp); 1685185029Spjd if (*sepp++ != ']') 1686185029Spjd goto fail; 1687185029Spjd 1688185029Spjd /* for embedded arrays, support C syntax: "a[1].b" */ 1689185029Spjd skip_whitespace(sepp); 1690185029Spjd if (sep && (*sepp == sep)) 1691185029Spjd sepp++; 1692185029Spjd } else if (sepp) { 1693185029Spjd n = sepp++ - np; 1694185029Spjd } else { 1695185029Spjd n = strlen(np); 1696185029Spjd } 1697185029Spjd 1698185029Spjd /* trim trailing whitespace by reducing length of 'np' */ 1699185029Spjd if (n == 0) 1700185029Spjd goto fail; 1701185029Spjd for (n--; (np[n] == ' ') || (np[n] == '\t'); n--) 1702185029Spjd ; 1703185029Spjd n++; 1704185029Spjd 1705185029Spjd /* skip whitespace, and set sepp to NULL if complete */ 1706185029Spjd if (sepp) { 1707185029Spjd skip_whitespace(sepp); 1708185029Spjd if (*sepp == 0) 1709185029Spjd sepp = NULL; 1710185029Spjd } 1711185029Spjd 1712185029Spjd /* 1713185029Spjd * At this point: 1714185029Spjd * o 'n' is the length of current 'np' component. 1715185029Spjd * o 'idxp' is set if there was an index, and value 'idx'. 1716185029Spjd * o 'sepp' is set to the beginning of the next component, 1717185029Spjd * and set to NULL if we have no more components. 1718185029Spjd * 1719185029Spjd * Search for nvpair with matching component name. 1720185029Spjd */ 1721185029Spjd for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 1722185029Spjd nvp = nvlist_next_nvpair(nvl, nvp)) { 1723185029Spjd 1724185029Spjd /* continue if no match on name */ 1725185029Spjd if (strncmp(np, nvpair_name(nvp), n) || 1726185029Spjd (strlen(nvpair_name(nvp)) != n)) 1727185029Spjd continue; 1728185029Spjd 1729185029Spjd /* if indexed, verify type is array oriented */ 1730185029Spjd if (idxp && !nvpair_type_is_array(nvp)) 1731185029Spjd goto fail; 1732185029Spjd 1733185029Spjd /* 1734185029Spjd * Full match found, return nvp and idx if this 1735185029Spjd * was the last component. 1736185029Spjd */ 1737185029Spjd if (sepp == NULL) { 1738185029Spjd if (ret) 1739185029Spjd *ret = nvp; 1740185029Spjd if (ip && idxp) 1741185029Spjd *ip = (int)idx; /* return index */ 1742185029Spjd return (0); /* found */ 1743185029Spjd } 1744185029Spjd 1745185029Spjd /* 1746185029Spjd * More components: current match must be 1747185029Spjd * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY 1748185029Spjd * to support going deeper. 1749185029Spjd */ 1750185029Spjd if (nvpair_type(nvp) == DATA_TYPE_NVLIST) { 1751185029Spjd nvl = EMBEDDED_NVL(nvp); 1752185029Spjd break; 1753185029Spjd } else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) { 1754185029Spjd (void) nvpair_value_nvlist_array(nvp, 1755185029Spjd &nva, (uint_t *)&n); 1756185029Spjd if ((n < 0) || (idx >= n)) 1757185029Spjd goto fail; 1758185029Spjd nvl = nva[idx]; 1759185029Spjd break; 1760185029Spjd } 1761185029Spjd 1762185029Spjd /* type does not support more levels */ 1763185029Spjd goto fail; 1764185029Spjd } 1765185029Spjd if (nvp == NULL) 1766185029Spjd goto fail; /* 'name' not found */ 1767185029Spjd 1768185029Spjd /* search for match of next component in embedded 'nvl' list */ 1769185029Spjd } 1770185029Spjd 1771185029Spjdfail: if (ep && sepp) 1772185029Spjd *ep = sepp; 1773185029Spjd return (EINVAL); 1774185029Spjd} 1775185029Spjd 1776185029Spjd/* 1777185029Spjd * Return pointer to nvpair with specified 'name'. 1778185029Spjd */ 1779168404Spjdint 1780185029Spjdnvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret) 1781185029Spjd{ 1782185029Spjd return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL)); 1783185029Spjd} 1784185029Spjd 1785185029Spjd/* 1786185029Spjd * Determine if named nvpair exists in nvlist (use embedded separator of '.' 1787185029Spjd * and return array index). See nvlist_lookup_nvpair_ei_sep for more detailed 1788185029Spjd * description. 1789185029Spjd */ 1790185029Spjdint nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl, 1791185029Spjd const char *name, nvpair_t **ret, int *ip, char **ep) 1792185029Spjd{ 1793185029Spjd return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep)); 1794185029Spjd} 1795185029Spjd 1796185029Spjdboolean_t 1797185029Spjdnvlist_exists(nvlist_t *nvl, const char *name) 1798185029Spjd{ 1799185029Spjd nvpriv_t *priv; 1800185029Spjd nvpair_t *nvp; 1801185029Spjd i_nvp_t *curr; 1802185029Spjd 1803185029Spjd if (name == NULL || nvl == NULL || 1804185029Spjd (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1805185029Spjd return (B_FALSE); 1806185029Spjd 1807185029Spjd for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 1808185029Spjd nvp = &curr->nvi_nvp; 1809185029Spjd 1810185029Spjd if (strcmp(name, NVP_NAME(nvp)) == 0) 1811185029Spjd return (B_TRUE); 1812185029Spjd } 1813185029Spjd 1814185029Spjd return (B_FALSE); 1815185029Spjd} 1816185029Spjd 1817185029Spjdint 1818168404Spjdnvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val) 1819168404Spjd{ 1820168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 1821168404Spjd} 1822168404Spjd 1823168404Spjdint 1824168404Spjdnvpair_value_byte(nvpair_t *nvp, uchar_t *val) 1825168404Spjd{ 1826168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val)); 1827168404Spjd} 1828168404Spjd 1829168404Spjdint 1830168404Spjdnvpair_value_int8(nvpair_t *nvp, int8_t *val) 1831168404Spjd{ 1832168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val)); 1833168404Spjd} 1834168404Spjd 1835168404Spjdint 1836168404Spjdnvpair_value_uint8(nvpair_t *nvp, uint8_t *val) 1837168404Spjd{ 1838168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val)); 1839168404Spjd} 1840168404Spjd 1841168404Spjdint 1842168404Spjdnvpair_value_int16(nvpair_t *nvp, int16_t *val) 1843168404Spjd{ 1844168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val)); 1845168404Spjd} 1846168404Spjd 1847168404Spjdint 1848168404Spjdnvpair_value_uint16(nvpair_t *nvp, uint16_t *val) 1849168404Spjd{ 1850168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val)); 1851168404Spjd} 1852168404Spjd 1853168404Spjdint 1854168404Spjdnvpair_value_int32(nvpair_t *nvp, int32_t *val) 1855168404Spjd{ 1856168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val)); 1857168404Spjd} 1858168404Spjd 1859168404Spjdint 1860168404Spjdnvpair_value_uint32(nvpair_t *nvp, uint32_t *val) 1861168404Spjd{ 1862168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val)); 1863168404Spjd} 1864168404Spjd 1865168404Spjdint 1866168404Spjdnvpair_value_int64(nvpair_t *nvp, int64_t *val) 1867168404Spjd{ 1868168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val)); 1869168404Spjd} 1870168404Spjd 1871168404Spjdint 1872168404Spjdnvpair_value_uint64(nvpair_t *nvp, uint64_t *val) 1873168404Spjd{ 1874168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val)); 1875168404Spjd} 1876168404Spjd 1877185029Spjd#if !defined(_KERNEL) 1878168404Spjdint 1879185029Spjdnvpair_value_double(nvpair_t *nvp, double *val) 1880185029Spjd{ 1881185029Spjd return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val)); 1882185029Spjd} 1883185029Spjd#endif 1884185029Spjd 1885185029Spjdint 1886168404Spjdnvpair_value_string(nvpair_t *nvp, char **val) 1887168404Spjd{ 1888168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val)); 1889168404Spjd} 1890168404Spjd 1891168404Spjdint 1892168404Spjdnvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val) 1893168404Spjd{ 1894168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val)); 1895168404Spjd} 1896168404Spjd 1897168404Spjdint 1898168404Spjdnvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem) 1899168404Spjd{ 1900168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val)); 1901168404Spjd} 1902168404Spjd 1903168404Spjdint 1904168404Spjdnvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem) 1905168404Spjd{ 1906168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val)); 1907168404Spjd} 1908168404Spjd 1909168404Spjdint 1910168404Spjdnvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem) 1911168404Spjd{ 1912168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val)); 1913168404Spjd} 1914168404Spjd 1915168404Spjdint 1916168404Spjdnvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem) 1917168404Spjd{ 1918168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val)); 1919168404Spjd} 1920168404Spjd 1921168404Spjdint 1922168404Spjdnvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem) 1923168404Spjd{ 1924168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val)); 1925168404Spjd} 1926168404Spjd 1927168404Spjdint 1928168404Spjdnvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem) 1929168404Spjd{ 1930168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val)); 1931168404Spjd} 1932168404Spjd 1933168404Spjdint 1934168404Spjdnvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem) 1935168404Spjd{ 1936168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val)); 1937168404Spjd} 1938168404Spjd 1939168404Spjdint 1940168404Spjdnvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem) 1941168404Spjd{ 1942168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val)); 1943168404Spjd} 1944168404Spjd 1945168404Spjdint 1946168404Spjdnvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem) 1947168404Spjd{ 1948168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val)); 1949168404Spjd} 1950168404Spjd 1951168404Spjdint 1952168404Spjdnvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem) 1953168404Spjd{ 1954168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val)); 1955168404Spjd} 1956168404Spjd 1957168404Spjdint 1958168404Spjdnvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem) 1959168404Spjd{ 1960168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val)); 1961168404Spjd} 1962168404Spjd 1963168404Spjdint 1964168404Spjdnvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem) 1965168404Spjd{ 1966168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val)); 1967168404Spjd} 1968168404Spjd 1969168404Spjdint 1970168404Spjdnvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val) 1971168404Spjd{ 1972168404Spjd return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val)); 1973168404Spjd} 1974168404Spjd 1975168404Spjd/* 1976168404Spjd * Add specified pair to the list. 1977168404Spjd */ 1978168404Spjdint 1979168404Spjdnvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1980168404Spjd{ 1981168404Spjd if (nvl == NULL || nvp == NULL) 1982168404Spjd return (EINVAL); 1983168404Spjd 1984168404Spjd return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp), 1985168404Spjd NVP_NELEM(nvp), NVP_VALUE(nvp))); 1986168404Spjd} 1987168404Spjd 1988168404Spjd/* 1989168404Spjd * Merge the supplied nvlists and put the result in dst. 1990168404Spjd * The merged list will contain all names specified in both lists, 1991168404Spjd * the values are taken from nvl in the case of duplicates. 1992168404Spjd * Return 0 on success. 1993168404Spjd */ 1994168404Spjd/*ARGSUSED*/ 1995168404Spjdint 1996168404Spjdnvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag) 1997168404Spjd{ 1998168404Spjd if (nvl == NULL || dst == NULL) 1999168404Spjd return (EINVAL); 2000168404Spjd 2001168404Spjd if (dst != nvl) 2002168404Spjd return (nvlist_copy_pairs(nvl, dst)); 2003168404Spjd 2004168404Spjd return (0); 2005168404Spjd} 2006168404Spjd 2007168404Spjd/* 2008168404Spjd * Encoding related routines 2009168404Spjd */ 2010168404Spjd#define NVS_OP_ENCODE 0 2011168404Spjd#define NVS_OP_DECODE 1 2012168404Spjd#define NVS_OP_GETSIZE 2 2013168404Spjd 2014168404Spjdtypedef struct nvs_ops nvs_ops_t; 2015168404Spjd 2016168404Spjdtypedef struct { 2017168404Spjd int nvs_op; 2018168404Spjd const nvs_ops_t *nvs_ops; 2019168404Spjd void *nvs_private; 2020168404Spjd nvpriv_t *nvs_priv; 2021168404Spjd} nvstream_t; 2022168404Spjd 2023168404Spjd/* 2024168404Spjd * nvs operations are: 2025168404Spjd * - nvs_nvlist 2026168404Spjd * encoding / decoding of a nvlist header (nvlist_t) 2027168404Spjd * calculates the size used for header and end detection 2028168404Spjd * 2029168404Spjd * - nvs_nvpair 2030168404Spjd * responsible for the first part of encoding / decoding of an nvpair 2031168404Spjd * calculates the decoded size of an nvpair 2032168404Spjd * 2033168404Spjd * - nvs_nvp_op 2034168404Spjd * second part of encoding / decoding of an nvpair 2035168404Spjd * 2036168404Spjd * - nvs_nvp_size 2037168404Spjd * calculates the encoding size of an nvpair 2038168404Spjd * 2039168404Spjd * - nvs_nvl_fini 2040168404Spjd * encodes the end detection mark (zeros). 2041168404Spjd */ 2042168404Spjdstruct nvs_ops { 2043168404Spjd int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *); 2044168404Spjd int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *); 2045168404Spjd int (*nvs_nvp_op)(nvstream_t *, nvpair_t *); 2046168404Spjd int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *); 2047168404Spjd int (*nvs_nvl_fini)(nvstream_t *); 2048168404Spjd}; 2049168404Spjd 2050168404Spjdtypedef struct { 2051168404Spjd char nvh_encoding; /* nvs encoding method */ 2052168404Spjd char nvh_endian; /* nvs endian */ 2053168404Spjd char nvh_reserved1; /* reserved for future use */ 2054168404Spjd char nvh_reserved2; /* reserved for future use */ 2055168404Spjd} nvs_header_t; 2056168404Spjd 2057168404Spjdstatic int 2058168404Spjdnvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl) 2059168404Spjd{ 2060168404Spjd nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 2061168404Spjd i_nvp_t *curr; 2062168404Spjd 2063168404Spjd /* 2064168404Spjd * Walk nvpair in list and encode each nvpair 2065168404Spjd */ 2066168404Spjd for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 2067168404Spjd if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0) 2068168404Spjd return (EFAULT); 2069168404Spjd 2070168404Spjd return (nvs->nvs_ops->nvs_nvl_fini(nvs)); 2071168404Spjd} 2072168404Spjd 2073168404Spjdstatic int 2074168404Spjdnvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl) 2075168404Spjd{ 2076168404Spjd nvpair_t *nvp; 2077168404Spjd size_t nvsize; 2078168404Spjd int err; 2079168404Spjd 2080168404Spjd /* 2081168404Spjd * Get decoded size of next pair in stream, alloc 2082168404Spjd * memory for nvpair_t, then decode the nvpair 2083168404Spjd */ 2084168404Spjd while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) { 2085168404Spjd if (nvsize == 0) /* end of list */ 2086168404Spjd break; 2087168404Spjd 2088168404Spjd /* make sure len makes sense */ 2089168404Spjd if (nvsize < NVP_SIZE_CALC(1, 0)) 2090168404Spjd return (EFAULT); 2091168404Spjd 2092168404Spjd if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL) 2093168404Spjd return (ENOMEM); 2094168404Spjd 2095168404Spjd if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) { 2096168404Spjd nvp_buf_free(nvl, nvp); 2097168404Spjd return (err); 2098168404Spjd } 2099168404Spjd 2100168404Spjd if (i_validate_nvpair(nvp) != 0) { 2101168404Spjd nvpair_free(nvp); 2102168404Spjd nvp_buf_free(nvl, nvp); 2103168404Spjd return (EFAULT); 2104168404Spjd } 2105168404Spjd 2106168404Spjd nvp_buf_link(nvl, nvp); 2107168404Spjd } 2108168404Spjd return (err); 2109168404Spjd} 2110168404Spjd 2111168404Spjdstatic int 2112168404Spjdnvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 2113168404Spjd{ 2114168404Spjd nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 2115168404Spjd i_nvp_t *curr; 2116168404Spjd uint64_t nvsize = *buflen; 2117168404Spjd size_t size; 2118168404Spjd 2119168404Spjd /* 2120168404Spjd * Get encoded size of nvpairs in nvlist 2121168404Spjd */ 2122168404Spjd for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 2123168404Spjd if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0) 2124168404Spjd return (EINVAL); 2125168404Spjd 2126168404Spjd if ((nvsize += size) > INT32_MAX) 2127168404Spjd return (EINVAL); 2128168404Spjd } 2129168404Spjd 2130168404Spjd *buflen = nvsize; 2131168404Spjd return (0); 2132168404Spjd} 2133168404Spjd 2134168404Spjdstatic int 2135168404Spjdnvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 2136168404Spjd{ 2137168404Spjd int err; 2138168404Spjd 2139168404Spjd if (nvl->nvl_priv == 0) 2140168404Spjd return (EFAULT); 2141168404Spjd 2142168404Spjd /* 2143168404Spjd * Perform the operation, starting with header, then each nvpair 2144168404Spjd */ 2145168404Spjd if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0) 2146168404Spjd return (err); 2147168404Spjd 2148168404Spjd switch (nvs->nvs_op) { 2149168404Spjd case NVS_OP_ENCODE: 2150168404Spjd err = nvs_encode_pairs(nvs, nvl); 2151168404Spjd break; 2152168404Spjd 2153168404Spjd case NVS_OP_DECODE: 2154168404Spjd err = nvs_decode_pairs(nvs, nvl); 2155168404Spjd break; 2156168404Spjd 2157168404Spjd case NVS_OP_GETSIZE: 2158168404Spjd err = nvs_getsize_pairs(nvs, nvl, buflen); 2159168404Spjd break; 2160168404Spjd 2161168404Spjd default: 2162168404Spjd err = EINVAL; 2163168404Spjd } 2164168404Spjd 2165168404Spjd return (err); 2166168404Spjd} 2167168404Spjd 2168168404Spjdstatic int 2169168404Spjdnvs_embedded(nvstream_t *nvs, nvlist_t *embedded) 2170168404Spjd{ 2171168404Spjd switch (nvs->nvs_op) { 2172168404Spjd case NVS_OP_ENCODE: 2173168404Spjd return (nvs_operation(nvs, embedded, NULL)); 2174168404Spjd 2175168404Spjd case NVS_OP_DECODE: { 2176168404Spjd nvpriv_t *priv; 2177168404Spjd int err; 2178168404Spjd 2179168404Spjd if (embedded->nvl_version != NV_VERSION) 2180168404Spjd return (ENOTSUP); 2181168404Spjd 2182168404Spjd if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL) 2183168404Spjd return (ENOMEM); 2184168404Spjd 2185168404Spjd nvlist_init(embedded, embedded->nvl_nvflag, priv); 2186168404Spjd 2187168404Spjd if ((err = nvs_operation(nvs, embedded, NULL)) != 0) 2188168404Spjd nvlist_free(embedded); 2189168404Spjd return (err); 2190168404Spjd } 2191168404Spjd default: 2192168404Spjd break; 2193168404Spjd } 2194168404Spjd 2195168404Spjd return (EINVAL); 2196168404Spjd} 2197168404Spjd 2198168404Spjdstatic int 2199168404Spjdnvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2200168404Spjd{ 2201168404Spjd size_t nelem = NVP_NELEM(nvp); 2202168404Spjd nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 2203168404Spjd int i; 2204168404Spjd 2205168404Spjd switch (nvs->nvs_op) { 2206168404Spjd case NVS_OP_ENCODE: 2207168404Spjd for (i = 0; i < nelem; i++) 2208168404Spjd if (nvs_embedded(nvs, nvlp[i]) != 0) 2209168404Spjd return (EFAULT); 2210168404Spjd break; 2211168404Spjd 2212168404Spjd case NVS_OP_DECODE: { 2213168404Spjd size_t len = nelem * sizeof (uint64_t); 2214168404Spjd nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len); 2215168404Spjd 2216168404Spjd bzero(nvlp, len); /* don't trust packed data */ 2217168404Spjd for (i = 0; i < nelem; i++) { 2218168404Spjd if (nvs_embedded(nvs, embedded) != 0) { 2219168404Spjd nvpair_free(nvp); 2220168404Spjd return (EFAULT); 2221168404Spjd } 2222168404Spjd 2223168404Spjd nvlp[i] = embedded++; 2224168404Spjd } 2225168404Spjd break; 2226168404Spjd } 2227168404Spjd case NVS_OP_GETSIZE: { 2228168404Spjd uint64_t nvsize = 0; 2229168404Spjd 2230168404Spjd for (i = 0; i < nelem; i++) { 2231168404Spjd size_t nvp_sz = 0; 2232168404Spjd 2233168404Spjd if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0) 2234168404Spjd return (EINVAL); 2235168404Spjd 2236168404Spjd if ((nvsize += nvp_sz) > INT32_MAX) 2237168404Spjd return (EINVAL); 2238168404Spjd } 2239168404Spjd 2240168404Spjd *size = nvsize; 2241168404Spjd break; 2242168404Spjd } 2243168404Spjd default: 2244168404Spjd return (EINVAL); 2245168404Spjd } 2246168404Spjd 2247168404Spjd return (0); 2248168404Spjd} 2249168404Spjd 2250168404Spjdstatic int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *); 2251168404Spjdstatic int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *); 2252168404Spjd 2253168404Spjd/* 2254168404Spjd * Common routine for nvlist operations: 2255168404Spjd * encode, decode, getsize (encoded size). 2256168404Spjd */ 2257168404Spjdstatic int 2258168404Spjdnvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding, 2259168404Spjd int nvs_op) 2260168404Spjd{ 2261168404Spjd int err = 0; 2262168404Spjd nvstream_t nvs; 2263168404Spjd int nvl_endian; 2264174047Sjb#if BYTE_ORDER == _LITTLE_ENDIAN 2265168404Spjd int host_endian = 1; 2266168404Spjd#else 2267168404Spjd int host_endian = 0; 2268168404Spjd#endif /* _LITTLE_ENDIAN */ 2269168404Spjd nvs_header_t *nvh = (void *)buf; 2270168404Spjd 2271168404Spjd if (buflen == NULL || nvl == NULL || 2272168404Spjd (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 2273168404Spjd return (EINVAL); 2274168404Spjd 2275168404Spjd nvs.nvs_op = nvs_op; 2276168404Spjd 2277168404Spjd /* 2278168404Spjd * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and 2279168404Spjd * a buffer is allocated. The first 4 bytes in the buffer are 2280168404Spjd * used for encoding method and host endian. 2281168404Spjd */ 2282168404Spjd switch (nvs_op) { 2283168404Spjd case NVS_OP_ENCODE: 2284168404Spjd if (buf == NULL || *buflen < sizeof (nvs_header_t)) 2285168404Spjd return (EINVAL); 2286168404Spjd 2287168404Spjd nvh->nvh_encoding = encoding; 2288168404Spjd nvh->nvh_endian = nvl_endian = host_endian; 2289168404Spjd nvh->nvh_reserved1 = 0; 2290168404Spjd nvh->nvh_reserved2 = 0; 2291168404Spjd break; 2292168404Spjd 2293168404Spjd case NVS_OP_DECODE: 2294168404Spjd if (buf == NULL || *buflen < sizeof (nvs_header_t)) 2295168404Spjd return (EINVAL); 2296168404Spjd 2297168404Spjd /* get method of encoding from first byte */ 2298168404Spjd encoding = nvh->nvh_encoding; 2299168404Spjd nvl_endian = nvh->nvh_endian; 2300168404Spjd break; 2301168404Spjd 2302168404Spjd case NVS_OP_GETSIZE: 2303168404Spjd nvl_endian = host_endian; 2304168404Spjd 2305168404Spjd /* 2306168404Spjd * add the size for encoding 2307168404Spjd */ 2308168404Spjd *buflen = sizeof (nvs_header_t); 2309168404Spjd break; 2310168404Spjd 2311168404Spjd default: 2312168404Spjd return (ENOTSUP); 2313168404Spjd } 2314168404Spjd 2315168404Spjd /* 2316168404Spjd * Create an nvstream with proper encoding method 2317168404Spjd */ 2318168404Spjd switch (encoding) { 2319168404Spjd case NV_ENCODE_NATIVE: 2320168404Spjd /* 2321168404Spjd * check endianness, in case we are unpacking 2322168404Spjd * from a file 2323168404Spjd */ 2324168404Spjd if (nvl_endian != host_endian) 2325168404Spjd return (ENOTSUP); 2326168404Spjd err = nvs_native(&nvs, nvl, buf, buflen); 2327168404Spjd break; 2328168404Spjd case NV_ENCODE_XDR: 2329168404Spjd err = nvs_xdr(&nvs, nvl, buf, buflen); 2330168404Spjd break; 2331168404Spjd default: 2332168404Spjd err = ENOTSUP; 2333168404Spjd break; 2334168404Spjd } 2335168404Spjd 2336168404Spjd return (err); 2337168404Spjd} 2338168404Spjd 2339168404Spjdint 2340168404Spjdnvlist_size(nvlist_t *nvl, size_t *size, int encoding) 2341168404Spjd{ 2342168404Spjd return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE)); 2343168404Spjd} 2344168404Spjd 2345168404Spjd/* 2346168404Spjd * Pack nvlist into contiguous memory 2347168404Spjd */ 2348168404Spjd/*ARGSUSED1*/ 2349168404Spjdint 2350168404Spjdnvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 2351168404Spjd int kmflag) 2352168404Spjd{ 2353168404Spjd#if defined(_KERNEL) && !defined(_BOOT) 2354168404Spjd return (nvlist_xpack(nvl, bufp, buflen, encoding, 2355168404Spjd (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 2356168404Spjd#else 2357168404Spjd return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep)); 2358168404Spjd#endif 2359168404Spjd} 2360168404Spjd 2361168404Spjdint 2362168404Spjdnvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 2363168404Spjd nv_alloc_t *nva) 2364168404Spjd{ 2365168404Spjd nvpriv_t nvpriv; 2366168404Spjd size_t alloc_size; 2367168404Spjd char *buf; 2368168404Spjd int err; 2369168404Spjd 2370168404Spjd if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL) 2371168404Spjd return (EINVAL); 2372168404Spjd 2373168404Spjd if (*bufp != NULL) 2374168404Spjd return (nvlist_common(nvl, *bufp, buflen, encoding, 2375168404Spjd NVS_OP_ENCODE)); 2376168404Spjd 2377168404Spjd /* 2378168404Spjd * Here is a difficult situation: 2379168404Spjd * 1. The nvlist has fixed allocator properties. 2380168404Spjd * All other nvlist routines (like nvlist_add_*, ...) use 2381168404Spjd * these properties. 2382168404Spjd * 2. When using nvlist_pack() the user can specify his own 2383168404Spjd * allocator properties (e.g. by using KM_NOSLEEP). 2384168404Spjd * 2385168404Spjd * We use the user specified properties (2). A clearer solution 2386168404Spjd * will be to remove the kmflag from nvlist_pack(), but we will 2387168404Spjd * not change the interface. 2388168404Spjd */ 2389168404Spjd nv_priv_init(&nvpriv, nva, 0); 2390168404Spjd 2391307124Smav if ((err = nvlist_size(nvl, &alloc_size, encoding))) 2392168404Spjd return (err); 2393168404Spjd 2394168404Spjd if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL) 2395168404Spjd return (ENOMEM); 2396168404Spjd 2397168404Spjd if ((err = nvlist_common(nvl, buf, &alloc_size, encoding, 2398168404Spjd NVS_OP_ENCODE)) != 0) { 2399168404Spjd nv_mem_free(&nvpriv, buf, alloc_size); 2400168404Spjd } else { 2401168404Spjd *buflen = alloc_size; 2402168404Spjd *bufp = buf; 2403168404Spjd } 2404168404Spjd 2405168404Spjd return (err); 2406168404Spjd} 2407168404Spjd 2408168404Spjd/* 2409168404Spjd * Unpack buf into an nvlist_t 2410168404Spjd */ 2411168404Spjd/*ARGSUSED1*/ 2412168404Spjdint 2413168404Spjdnvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag) 2414168404Spjd{ 2415168404Spjd#if defined(_KERNEL) && !defined(_BOOT) 2416168404Spjd return (nvlist_xunpack(buf, buflen, nvlp, 2417168404Spjd (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 2418168404Spjd#else 2419168404Spjd return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep)); 2420168404Spjd#endif 2421168404Spjd} 2422168404Spjd 2423168404Spjdint 2424168404Spjdnvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva) 2425168404Spjd{ 2426168404Spjd nvlist_t *nvl; 2427168404Spjd int err; 2428168404Spjd 2429168404Spjd if (nvlp == NULL) 2430168404Spjd return (EINVAL); 2431168404Spjd 2432168404Spjd if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0) 2433168404Spjd return (err); 2434168404Spjd 2435168404Spjd if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0) 2436168404Spjd nvlist_free(nvl); 2437168404Spjd else 2438168404Spjd *nvlp = nvl; 2439168404Spjd 2440168404Spjd return (err); 2441168404Spjd} 2442168404Spjd 2443168404Spjd/* 2444168404Spjd * Native encoding functions 2445168404Spjd */ 2446168404Spjdtypedef struct { 2447168404Spjd /* 2448168404Spjd * This structure is used when decoding a packed nvpair in 2449168404Spjd * the native format. n_base points to a buffer containing the 2450168404Spjd * packed nvpair. n_end is a pointer to the end of the buffer. 2451168404Spjd * (n_end actually points to the first byte past the end of the 2452168404Spjd * buffer.) n_curr is a pointer that lies between n_base and n_end. 2453168404Spjd * It points to the current data that we are decoding. 2454168404Spjd * The amount of data left in the buffer is equal to n_end - n_curr. 2455168404Spjd * n_flag is used to recognize a packed embedded list. 2456168404Spjd */ 2457168404Spjd caddr_t n_base; 2458168404Spjd caddr_t n_end; 2459168404Spjd caddr_t n_curr; 2460168404Spjd uint_t n_flag; 2461168404Spjd} nvs_native_t; 2462168404Spjd 2463168404Spjdstatic int 2464168404Spjdnvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf, 2465168404Spjd size_t buflen) 2466168404Spjd{ 2467168404Spjd switch (nvs->nvs_op) { 2468168404Spjd case NVS_OP_ENCODE: 2469168404Spjd case NVS_OP_DECODE: 2470168404Spjd nvs->nvs_private = native; 2471168404Spjd native->n_curr = native->n_base = buf; 2472168404Spjd native->n_end = buf + buflen; 2473168404Spjd native->n_flag = 0; 2474168404Spjd return (0); 2475168404Spjd 2476168404Spjd case NVS_OP_GETSIZE: 2477168404Spjd nvs->nvs_private = native; 2478168404Spjd native->n_curr = native->n_base = native->n_end = NULL; 2479168404Spjd native->n_flag = 0; 2480168404Spjd return (0); 2481168404Spjd default: 2482168404Spjd return (EINVAL); 2483168404Spjd } 2484168404Spjd} 2485168404Spjd 2486168404Spjd/*ARGSUSED*/ 2487168404Spjdstatic void 2488168404Spjdnvs_native_destroy(nvstream_t *nvs) 2489168404Spjd{ 2490168404Spjd} 2491168404Spjd 2492168404Spjdstatic int 2493168404Spjdnative_cp(nvstream_t *nvs, void *buf, size_t size) 2494168404Spjd{ 2495168404Spjd nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2496168404Spjd 2497168404Spjd if (native->n_curr + size > native->n_end) 2498168404Spjd return (EFAULT); 2499168404Spjd 2500168404Spjd /* 2501168404Spjd * The bcopy() below eliminates alignment requirement 2502168404Spjd * on the buffer (stream) and is preferred over direct access. 2503168404Spjd */ 2504168404Spjd switch (nvs->nvs_op) { 2505168404Spjd case NVS_OP_ENCODE: 2506168404Spjd bcopy(buf, native->n_curr, size); 2507168404Spjd break; 2508168404Spjd case NVS_OP_DECODE: 2509168404Spjd bcopy(native->n_curr, buf, size); 2510168404Spjd break; 2511168404Spjd default: 2512168404Spjd return (EINVAL); 2513168404Spjd } 2514168404Spjd 2515168404Spjd native->n_curr += size; 2516168404Spjd return (0); 2517168404Spjd} 2518168404Spjd 2519168404Spjd/* 2520168404Spjd * operate on nvlist_t header 2521168404Spjd */ 2522168404Spjdstatic int 2523168404Spjdnvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 2524168404Spjd{ 2525168404Spjd nvs_native_t *native = nvs->nvs_private; 2526168404Spjd 2527168404Spjd switch (nvs->nvs_op) { 2528168404Spjd case NVS_OP_ENCODE: 2529168404Spjd case NVS_OP_DECODE: 2530168404Spjd if (native->n_flag) 2531168404Spjd return (0); /* packed embedded list */ 2532168404Spjd 2533168404Spjd native->n_flag = 1; 2534168404Spjd 2535168404Spjd /* copy version and nvflag of the nvlist_t */ 2536168404Spjd if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 || 2537168404Spjd native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0) 2538168404Spjd return (EFAULT); 2539168404Spjd 2540168404Spjd return (0); 2541168404Spjd 2542168404Spjd case NVS_OP_GETSIZE: 2543168404Spjd /* 2544168404Spjd * if calculate for packed embedded list 2545168404Spjd * 4 for end of the embedded list 2546168404Spjd * else 2547168404Spjd * 2 * sizeof (int32_t) for nvl_version and nvl_nvflag 2548168404Spjd * and 4 for end of the entire list 2549168404Spjd */ 2550168404Spjd if (native->n_flag) { 2551168404Spjd *size += 4; 2552168404Spjd } else { 2553168404Spjd native->n_flag = 1; 2554168404Spjd *size += 2 * sizeof (int32_t) + 4; 2555168404Spjd } 2556168404Spjd 2557168404Spjd return (0); 2558168404Spjd 2559168404Spjd default: 2560168404Spjd return (EINVAL); 2561168404Spjd } 2562168404Spjd} 2563168404Spjd 2564168404Spjdstatic int 2565168404Spjdnvs_native_nvl_fini(nvstream_t *nvs) 2566168404Spjd{ 2567168404Spjd if (nvs->nvs_op == NVS_OP_ENCODE) { 2568168404Spjd nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2569168404Spjd /* 2570168404Spjd * Add 4 zero bytes at end of nvlist. They are used 2571168404Spjd * for end detection by the decode routine. 2572168404Spjd */ 2573168404Spjd if (native->n_curr + sizeof (int) > native->n_end) 2574168404Spjd return (EFAULT); 2575168404Spjd 2576168404Spjd bzero(native->n_curr, sizeof (int)); 2577168404Spjd native->n_curr += sizeof (int); 2578168404Spjd } 2579168404Spjd 2580168404Spjd return (0); 2581168404Spjd} 2582168404Spjd 2583168404Spjdstatic int 2584168404Spjdnvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp) 2585168404Spjd{ 2586168404Spjd if (nvs->nvs_op == NVS_OP_ENCODE) { 2587168404Spjd nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2588196269Smarcel char *packed = (void *) 2589168404Spjd (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 2590168404Spjd /* 2591168404Spjd * Null out the pointer that is meaningless in the packed 2592168404Spjd * structure. The address may not be aligned, so we have 2593168404Spjd * to use bzero. 2594168404Spjd */ 2595196269Smarcel bzero(packed + offsetof(nvlist_t, nvl_priv), 2596196269Smarcel sizeof(((nvlist_t *)NULL)->nvl_priv)); 2597168404Spjd } 2598168404Spjd 2599168404Spjd return (nvs_embedded(nvs, EMBEDDED_NVL(nvp))); 2600168404Spjd} 2601168404Spjd 2602168404Spjdstatic int 2603168404Spjdnvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp) 2604168404Spjd{ 2605168404Spjd if (nvs->nvs_op == NVS_OP_ENCODE) { 2606168404Spjd nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2607168404Spjd char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp); 2608168404Spjd size_t len = NVP_NELEM(nvp) * sizeof (uint64_t); 2609168404Spjd int i; 2610168404Spjd /* 2611168404Spjd * Null out pointers that are meaningless in the packed 2612168404Spjd * structure. The addresses may not be aligned, so we have 2613168404Spjd * to use bzero. 2614168404Spjd */ 2615168404Spjd bzero(value, len); 2616168404Spjd 2617195627Smarcel value += len; 2618195627Smarcel for (i = 0; i < NVP_NELEM(nvp); i++) { 2619168404Spjd /* 2620168404Spjd * Null out the pointer that is meaningless in the 2621168404Spjd * packed structure. The address may not be aligned, 2622168404Spjd * so we have to use bzero. 2623168404Spjd */ 2624195627Smarcel bzero(value + offsetof(nvlist_t, nvl_priv), 2625195627Smarcel sizeof(((nvlist_t *)NULL)->nvl_priv)); 2626195627Smarcel value += sizeof(nvlist_t); 2627195627Smarcel } 2628168404Spjd } 2629168404Spjd 2630168404Spjd return (nvs_embedded_nvl_array(nvs, nvp, NULL)); 2631168404Spjd} 2632168404Spjd 2633168404Spjdstatic void 2634168404Spjdnvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp) 2635168404Spjd{ 2636168404Spjd switch (nvs->nvs_op) { 2637168404Spjd case NVS_OP_ENCODE: { 2638168404Spjd nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2639168404Spjd uint64_t *strp = (void *) 2640168404Spjd (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 2641168404Spjd /* 2642168404Spjd * Null out pointers that are meaningless in the packed 2643168404Spjd * structure. The addresses may not be aligned, so we have 2644168404Spjd * to use bzero. 2645168404Spjd */ 2646168404Spjd bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t)); 2647168404Spjd break; 2648168404Spjd } 2649168404Spjd case NVS_OP_DECODE: { 2650168404Spjd char **strp = (void *)NVP_VALUE(nvp); 2651168404Spjd char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t)); 2652168404Spjd int i; 2653168404Spjd 2654168404Spjd for (i = 0; i < NVP_NELEM(nvp); i++) { 2655168404Spjd strp[i] = buf; 2656168404Spjd buf += strlen(buf) + 1; 2657168404Spjd } 2658168404Spjd break; 2659168404Spjd } 2660168404Spjd } 2661168404Spjd} 2662168404Spjd 2663168404Spjdstatic int 2664168404Spjdnvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 2665168404Spjd{ 2666168404Spjd data_type_t type; 2667168404Spjd int value_sz; 2668168404Spjd int ret = 0; 2669168404Spjd 2670168404Spjd /* 2671168404Spjd * We do the initial bcopy of the data before we look at 2672168404Spjd * the nvpair type, because when we're decoding, we won't 2673168404Spjd * have the correct values for the pair until we do the bcopy. 2674168404Spjd */ 2675168404Spjd switch (nvs->nvs_op) { 2676168404Spjd case NVS_OP_ENCODE: 2677168404Spjd case NVS_OP_DECODE: 2678168404Spjd if (native_cp(nvs, nvp, nvp->nvp_size) != 0) 2679168404Spjd return (EFAULT); 2680168404Spjd break; 2681168404Spjd default: 2682168404Spjd return (EINVAL); 2683168404Spjd } 2684168404Spjd 2685168404Spjd /* verify nvp_name_sz, check the name string length */ 2686168404Spjd if (i_validate_nvpair_name(nvp) != 0) 2687168404Spjd return (EFAULT); 2688168404Spjd 2689168404Spjd type = NVP_TYPE(nvp); 2690168404Spjd 2691168404Spjd /* 2692168404Spjd * Verify type and nelem and get the value size. 2693168404Spjd * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 2694168404Spjd * is the size of the string(s) excluded. 2695168404Spjd */ 2696168404Spjd if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0) 2697168404Spjd return (EFAULT); 2698168404Spjd 2699168404Spjd if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size) 2700168404Spjd return (EFAULT); 2701168404Spjd 2702168404Spjd switch (type) { 2703168404Spjd case DATA_TYPE_NVLIST: 2704168404Spjd ret = nvpair_native_embedded(nvs, nvp); 2705168404Spjd break; 2706168404Spjd case DATA_TYPE_NVLIST_ARRAY: 2707168404Spjd ret = nvpair_native_embedded_array(nvs, nvp); 2708168404Spjd break; 2709168404Spjd case DATA_TYPE_STRING_ARRAY: 2710168404Spjd nvpair_native_string_array(nvs, nvp); 2711168404Spjd break; 2712168404Spjd default: 2713168404Spjd break; 2714168404Spjd } 2715168404Spjd 2716168404Spjd return (ret); 2717168404Spjd} 2718168404Spjd 2719168404Spjdstatic int 2720168404Spjdnvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2721168404Spjd{ 2722168404Spjd uint64_t nvp_sz = nvp->nvp_size; 2723168404Spjd 2724168404Spjd switch (NVP_TYPE(nvp)) { 2725168404Spjd case DATA_TYPE_NVLIST: { 2726168404Spjd size_t nvsize = 0; 2727168404Spjd 2728168404Spjd if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0) 2729168404Spjd return (EINVAL); 2730168404Spjd 2731168404Spjd nvp_sz += nvsize; 2732168404Spjd break; 2733168404Spjd } 2734168404Spjd case DATA_TYPE_NVLIST_ARRAY: { 2735168404Spjd size_t nvsize; 2736168404Spjd 2737168404Spjd if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0) 2738168404Spjd return (EINVAL); 2739168404Spjd 2740168404Spjd nvp_sz += nvsize; 2741168404Spjd break; 2742168404Spjd } 2743168404Spjd default: 2744168404Spjd break; 2745168404Spjd } 2746168404Spjd 2747168404Spjd if (nvp_sz > INT32_MAX) 2748168404Spjd return (EINVAL); 2749168404Spjd 2750168404Spjd *size = nvp_sz; 2751168404Spjd 2752168404Spjd return (0); 2753168404Spjd} 2754168404Spjd 2755168404Spjdstatic int 2756168404Spjdnvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2757168404Spjd{ 2758168404Spjd switch (nvs->nvs_op) { 2759168404Spjd case NVS_OP_ENCODE: 2760168404Spjd return (nvs_native_nvp_op(nvs, nvp)); 2761168404Spjd 2762168404Spjd case NVS_OP_DECODE: { 2763168404Spjd nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2764168404Spjd int32_t decode_len; 2765168404Spjd 2766168404Spjd /* try to read the size value from the stream */ 2767168404Spjd if (native->n_curr + sizeof (int32_t) > native->n_end) 2768168404Spjd return (EFAULT); 2769168404Spjd bcopy(native->n_curr, &decode_len, sizeof (int32_t)); 2770168404Spjd 2771168404Spjd /* sanity check the size value */ 2772168404Spjd if (decode_len < 0 || 2773168404Spjd decode_len > native->n_end - native->n_curr) 2774168404Spjd return (EFAULT); 2775168404Spjd 2776168404Spjd *size = decode_len; 2777168404Spjd 2778168404Spjd /* 2779168404Spjd * If at the end of the stream then move the cursor 2780168404Spjd * forward, otherwise nvpair_native_op() will read 2781168404Spjd * the entire nvpair at the same cursor position. 2782168404Spjd */ 2783168404Spjd if (*size == 0) 2784168404Spjd native->n_curr += sizeof (int32_t); 2785168404Spjd break; 2786168404Spjd } 2787168404Spjd 2788168404Spjd default: 2789168404Spjd return (EINVAL); 2790168404Spjd } 2791168404Spjd 2792168404Spjd return (0); 2793168404Spjd} 2794168404Spjd 2795168404Spjdstatic const nvs_ops_t nvs_native_ops = { 2796168404Spjd nvs_native_nvlist, 2797168404Spjd nvs_native_nvpair, 2798168404Spjd nvs_native_nvp_op, 2799168404Spjd nvs_native_nvp_size, 2800168404Spjd nvs_native_nvl_fini 2801168404Spjd}; 2802168404Spjd 2803168404Spjdstatic int 2804168404Spjdnvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen) 2805168404Spjd{ 2806168404Spjd nvs_native_t native; 2807168404Spjd int err; 2808168404Spjd 2809168404Spjd nvs->nvs_ops = &nvs_native_ops; 2810168404Spjd 2811168404Spjd if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t), 2812168404Spjd *buflen - sizeof (nvs_header_t))) != 0) 2813168404Spjd return (err); 2814168404Spjd 2815168404Spjd err = nvs_operation(nvs, nvl, buflen); 2816168404Spjd 2817168404Spjd nvs_native_destroy(nvs); 2818168404Spjd 2819168404Spjd return (err); 2820168404Spjd} 2821168404Spjd 2822168404Spjd/* 2823168404Spjd * XDR encoding functions 2824168404Spjd * 2825168404Spjd * An xdr packed nvlist is encoded as: 2826168404Spjd * 2827168404Spjd * - encoding methode and host endian (4 bytes) 2828168404Spjd * - nvl_version (4 bytes) 2829168404Spjd * - nvl_nvflag (4 bytes) 2830168404Spjd * 2831168404Spjd * - encoded nvpairs, the format of one xdr encoded nvpair is: 2832168404Spjd * - encoded size of the nvpair (4 bytes) 2833168404Spjd * - decoded size of the nvpair (4 bytes) 2834168404Spjd * - name string, (4 + sizeof(NV_ALIGN4(string)) 2835168404Spjd * a string is coded as size (4 bytes) and data 2836168404Spjd * - data type (4 bytes) 2837168404Spjd * - number of elements in the nvpair (4 bytes) 2838168404Spjd * - data 2839168404Spjd * 2840168404Spjd * - 2 zero's for end of the entire list (8 bytes) 2841168404Spjd */ 2842168404Spjdstatic int 2843168404Spjdnvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen) 2844168404Spjd{ 2845168404Spjd /* xdr data must be 4 byte aligned */ 2846168404Spjd if ((ulong_t)buf % 4 != 0) 2847168404Spjd return (EFAULT); 2848168404Spjd 2849168404Spjd switch (nvs->nvs_op) { 2850168404Spjd case NVS_OP_ENCODE: 2851168404Spjd xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE); 2852168404Spjd nvs->nvs_private = xdr; 2853168404Spjd return (0); 2854168404Spjd case NVS_OP_DECODE: 2855168404Spjd xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE); 2856168404Spjd nvs->nvs_private = xdr; 2857168404Spjd return (0); 2858168404Spjd case NVS_OP_GETSIZE: 2859168404Spjd nvs->nvs_private = NULL; 2860168404Spjd return (0); 2861168404Spjd default: 2862168404Spjd return (EINVAL); 2863168404Spjd } 2864168404Spjd} 2865168404Spjd 2866168404Spjdstatic void 2867168404Spjdnvs_xdr_destroy(nvstream_t *nvs) 2868168404Spjd{ 2869168404Spjd switch (nvs->nvs_op) { 2870168404Spjd case NVS_OP_ENCODE: 2871168404Spjd case NVS_OP_DECODE: 2872168404Spjd xdr_destroy((XDR *)nvs->nvs_private); 2873168404Spjd break; 2874168404Spjd default: 2875168404Spjd break; 2876168404Spjd } 2877168404Spjd} 2878168404Spjd 2879168404Spjdstatic int 2880168404Spjdnvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 2881168404Spjd{ 2882168404Spjd switch (nvs->nvs_op) { 2883168404Spjd case NVS_OP_ENCODE: 2884168404Spjd case NVS_OP_DECODE: { 2885168404Spjd XDR *xdr = nvs->nvs_private; 2886168404Spjd 2887168404Spjd if (!xdr_int(xdr, &nvl->nvl_version) || 2888168404Spjd !xdr_u_int(xdr, &nvl->nvl_nvflag)) 2889168404Spjd return (EFAULT); 2890168404Spjd break; 2891168404Spjd } 2892168404Spjd case NVS_OP_GETSIZE: { 2893168404Spjd /* 2894168404Spjd * 2 * 4 for nvl_version + nvl_nvflag 2895168404Spjd * and 8 for end of the entire list 2896168404Spjd */ 2897168404Spjd *size += 2 * 4 + 8; 2898168404Spjd break; 2899168404Spjd } 2900168404Spjd default: 2901168404Spjd return (EINVAL); 2902168404Spjd } 2903168404Spjd return (0); 2904168404Spjd} 2905168404Spjd 2906168404Spjdstatic int 2907168404Spjdnvs_xdr_nvl_fini(nvstream_t *nvs) 2908168404Spjd{ 2909168404Spjd if (nvs->nvs_op == NVS_OP_ENCODE) { 2910168404Spjd XDR *xdr = nvs->nvs_private; 2911168404Spjd int zero = 0; 2912168404Spjd 2913168404Spjd if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero)) 2914168404Spjd return (EFAULT); 2915168404Spjd } 2916168404Spjd 2917168404Spjd return (0); 2918168404Spjd} 2919168404Spjd 2920168404Spjd/* 2921168404Spjd * The format of xdr encoded nvpair is: 2922168404Spjd * encode_size, decode_size, name string, data type, nelem, data 2923168404Spjd */ 2924168404Spjdstatic int 2925168404Spjdnvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 2926168404Spjd{ 2927168404Spjd data_type_t type; 2928168404Spjd char *buf; 2929168404Spjd char *buf_end = (char *)nvp + nvp->nvp_size; 2930168404Spjd int value_sz; 2931168404Spjd uint_t nelem, buflen; 2932168404Spjd bool_t ret = FALSE; 2933168404Spjd XDR *xdr = nvs->nvs_private; 2934168404Spjd 2935168404Spjd ASSERT(xdr != NULL && nvp != NULL); 2936168404Spjd 2937168404Spjd /* name string */ 2938168404Spjd if ((buf = NVP_NAME(nvp)) >= buf_end) 2939168404Spjd return (EFAULT); 2940168404Spjd buflen = buf_end - buf; 2941168404Spjd 2942168404Spjd if (!xdr_string(xdr, &buf, buflen - 1)) 2943168404Spjd return (EFAULT); 2944168404Spjd nvp->nvp_name_sz = strlen(buf) + 1; 2945168404Spjd 2946168404Spjd /* type and nelem */ 2947168404Spjd if (!xdr_int(xdr, (int *)&nvp->nvp_type) || 2948168404Spjd !xdr_int(xdr, &nvp->nvp_value_elem)) 2949168404Spjd return (EFAULT); 2950168404Spjd 2951168404Spjd type = NVP_TYPE(nvp); 2952168404Spjd nelem = nvp->nvp_value_elem; 2953168404Spjd 2954168404Spjd /* 2955168404Spjd * Verify type and nelem and get the value size. 2956168404Spjd * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 2957168404Spjd * is the size of the string(s) excluded. 2958168404Spjd */ 2959168404Spjd if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0) 2960168404Spjd return (EFAULT); 2961168404Spjd 2962168404Spjd /* if there is no data to extract then return */ 2963168404Spjd if (nelem == 0) 2964168404Spjd return (0); 2965168404Spjd 2966168404Spjd /* value */ 2967168404Spjd if ((buf = NVP_VALUE(nvp)) >= buf_end) 2968168404Spjd return (EFAULT); 2969168404Spjd buflen = buf_end - buf; 2970168404Spjd 2971168404Spjd if (buflen < value_sz) 2972168404Spjd return (EFAULT); 2973168404Spjd 2974168404Spjd switch (type) { 2975168404Spjd case DATA_TYPE_NVLIST: 2976168404Spjd if (nvs_embedded(nvs, (void *)buf) == 0) 2977168404Spjd return (0); 2978168404Spjd break; 2979168404Spjd 2980168404Spjd case DATA_TYPE_NVLIST_ARRAY: 2981168404Spjd if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0) 2982168404Spjd return (0); 2983168404Spjd break; 2984168404Spjd 2985168404Spjd case DATA_TYPE_BOOLEAN: 2986168404Spjd ret = TRUE; 2987168404Spjd break; 2988168404Spjd 2989168404Spjd case DATA_TYPE_BYTE: 2990168404Spjd case DATA_TYPE_INT8: 2991168404Spjd case DATA_TYPE_UINT8: 2992168404Spjd ret = xdr_char(xdr, buf); 2993168404Spjd break; 2994168404Spjd 2995168404Spjd case DATA_TYPE_INT16: 2996168404Spjd ret = xdr_short(xdr, (void *)buf); 2997168404Spjd break; 2998168404Spjd 2999168404Spjd case DATA_TYPE_UINT16: 3000168404Spjd ret = xdr_u_short(xdr, (void *)buf); 3001168404Spjd break; 3002168404Spjd 3003168404Spjd case DATA_TYPE_BOOLEAN_VALUE: 3004168404Spjd case DATA_TYPE_INT32: 3005168404Spjd ret = xdr_int(xdr, (void *)buf); 3006168404Spjd break; 3007168404Spjd 3008168404Spjd case DATA_TYPE_UINT32: 3009168404Spjd ret = xdr_u_int(xdr, (void *)buf); 3010168404Spjd break; 3011168404Spjd 3012168404Spjd case DATA_TYPE_INT64: 3013168404Spjd ret = xdr_longlong_t(xdr, (void *)buf); 3014168404Spjd break; 3015168404Spjd 3016168404Spjd case DATA_TYPE_UINT64: 3017168404Spjd ret = xdr_u_longlong_t(xdr, (void *)buf); 3018168404Spjd break; 3019168404Spjd 3020168404Spjd case DATA_TYPE_HRTIME: 3021168404Spjd /* 3022168404Spjd * NOTE: must expose the definition of hrtime_t here 3023168404Spjd */ 3024168404Spjd ret = xdr_longlong_t(xdr, (void *)buf); 3025168404Spjd break; 3026185029Spjd#if !defined(_KERNEL) 3027185029Spjd case DATA_TYPE_DOUBLE: 3028185029Spjd ret = xdr_double(xdr, (void *)buf); 3029185029Spjd break; 3030185029Spjd#endif 3031168404Spjd case DATA_TYPE_STRING: 3032168404Spjd ret = xdr_string(xdr, &buf, buflen - 1); 3033168404Spjd break; 3034168404Spjd 3035168404Spjd case DATA_TYPE_BYTE_ARRAY: 3036168404Spjd ret = xdr_opaque(xdr, buf, nelem); 3037168404Spjd break; 3038168404Spjd 3039168404Spjd case DATA_TYPE_INT8_ARRAY: 3040168404Spjd case DATA_TYPE_UINT8_ARRAY: 3041168404Spjd ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t), 3042168404Spjd (xdrproc_t)xdr_char); 3043168404Spjd break; 3044168404Spjd 3045168404Spjd case DATA_TYPE_INT16_ARRAY: 3046168404Spjd ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t), 3047168404Spjd sizeof (int16_t), (xdrproc_t)xdr_short); 3048168404Spjd break; 3049168404Spjd 3050168404Spjd case DATA_TYPE_UINT16_ARRAY: 3051168404Spjd ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t), 3052168404Spjd sizeof (uint16_t), (xdrproc_t)xdr_u_short); 3053168404Spjd break; 3054168404Spjd 3055168404Spjd case DATA_TYPE_BOOLEAN_ARRAY: 3056168404Spjd case DATA_TYPE_INT32_ARRAY: 3057168404Spjd ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t), 3058168404Spjd sizeof (int32_t), (xdrproc_t)xdr_int); 3059168404Spjd break; 3060168404Spjd 3061168404Spjd case DATA_TYPE_UINT32_ARRAY: 3062168404Spjd ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t), 3063168404Spjd sizeof (uint32_t), (xdrproc_t)xdr_u_int); 3064168404Spjd break; 3065168404Spjd 3066168404Spjd case DATA_TYPE_INT64_ARRAY: 3067168404Spjd ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t), 3068168404Spjd sizeof (int64_t), (xdrproc_t)xdr_longlong_t); 3069168404Spjd break; 3070168404Spjd 3071168404Spjd case DATA_TYPE_UINT64_ARRAY: 3072168404Spjd ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t), 3073168404Spjd sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t); 3074168404Spjd break; 3075168404Spjd 3076168404Spjd case DATA_TYPE_STRING_ARRAY: { 3077168404Spjd size_t len = nelem * sizeof (uint64_t); 3078168404Spjd char **strp = (void *)buf; 3079168404Spjd int i; 3080168404Spjd 3081168404Spjd if (nvs->nvs_op == NVS_OP_DECODE) 3082168404Spjd bzero(buf, len); /* don't trust packed data */ 3083168404Spjd 3084168404Spjd for (i = 0; i < nelem; i++) { 3085168404Spjd if (buflen <= len) 3086168404Spjd return (EFAULT); 3087168404Spjd 3088168404Spjd buf += len; 3089168404Spjd buflen -= len; 3090168404Spjd 3091168404Spjd if (xdr_string(xdr, &buf, buflen - 1) != TRUE) 3092168404Spjd return (EFAULT); 3093168404Spjd 3094168404Spjd if (nvs->nvs_op == NVS_OP_DECODE) 3095168404Spjd strp[i] = buf; 3096168404Spjd len = strlen(buf) + 1; 3097168404Spjd } 3098168404Spjd ret = TRUE; 3099168404Spjd break; 3100168404Spjd } 3101168404Spjd default: 3102168404Spjd break; 3103168404Spjd } 3104168404Spjd 3105168404Spjd return (ret == TRUE ? 0 : EFAULT); 3106168404Spjd} 3107168404Spjd 3108168404Spjdstatic int 3109168404Spjdnvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 3110168404Spjd{ 3111168404Spjd data_type_t type = NVP_TYPE(nvp); 3112168404Spjd /* 3113168404Spjd * encode_size + decode_size + name string size + data type + nelem 3114168404Spjd * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) 3115168404Spjd */ 3116168404Spjd uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4; 3117168404Spjd 3118168404Spjd switch (type) { 3119168404Spjd case DATA_TYPE_BOOLEAN: 3120168404Spjd break; 3121168404Spjd 3122168404Spjd case DATA_TYPE_BOOLEAN_VALUE: 3123168404Spjd case DATA_TYPE_BYTE: 3124168404Spjd case DATA_TYPE_INT8: 3125168404Spjd case DATA_TYPE_UINT8: 3126168404Spjd case DATA_TYPE_INT16: 3127168404Spjd case DATA_TYPE_UINT16: 3128168404Spjd case DATA_TYPE_INT32: 3129168404Spjd case DATA_TYPE_UINT32: 3130168404Spjd nvp_sz += 4; /* 4 is the minimum xdr unit */ 3131168404Spjd break; 3132168404Spjd 3133168404Spjd case DATA_TYPE_INT64: 3134168404Spjd case DATA_TYPE_UINT64: 3135168404Spjd case DATA_TYPE_HRTIME: 3136185029Spjd#if !defined(_KERNEL) 3137185029Spjd case DATA_TYPE_DOUBLE: 3138185029Spjd#endif 3139168404Spjd nvp_sz += 8; 3140168404Spjd break; 3141168404Spjd 3142168404Spjd case DATA_TYPE_STRING: 3143168404Spjd nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp))); 3144168404Spjd break; 3145168404Spjd 3146168404Spjd case DATA_TYPE_BYTE_ARRAY: 3147168404Spjd nvp_sz += NV_ALIGN4(NVP_NELEM(nvp)); 3148168404Spjd break; 3149168404Spjd 3150168404Spjd case DATA_TYPE_BOOLEAN_ARRAY: 3151168404Spjd case DATA_TYPE_INT8_ARRAY: 3152168404Spjd case DATA_TYPE_UINT8_ARRAY: 3153168404Spjd case DATA_TYPE_INT16_ARRAY: 3154168404Spjd case DATA_TYPE_UINT16_ARRAY: 3155168404Spjd case DATA_TYPE_INT32_ARRAY: 3156168404Spjd case DATA_TYPE_UINT32_ARRAY: 3157168404Spjd nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp); 3158168404Spjd break; 3159168404Spjd 3160168404Spjd case DATA_TYPE_INT64_ARRAY: 3161168404Spjd case DATA_TYPE_UINT64_ARRAY: 3162168404Spjd nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp); 3163168404Spjd break; 3164168404Spjd 3165168404Spjd case DATA_TYPE_STRING_ARRAY: { 3166168404Spjd int i; 3167168404Spjd char **strs = (void *)NVP_VALUE(nvp); 3168168404Spjd 3169168404Spjd for (i = 0; i < NVP_NELEM(nvp); i++) 3170168404Spjd nvp_sz += 4 + NV_ALIGN4(strlen(strs[i])); 3171168404Spjd 3172168404Spjd break; 3173168404Spjd } 3174168404Spjd 3175168404Spjd case DATA_TYPE_NVLIST: 3176168404Spjd case DATA_TYPE_NVLIST_ARRAY: { 3177168404Spjd size_t nvsize = 0; 3178168404Spjd int old_nvs_op = nvs->nvs_op; 3179168404Spjd int err; 3180168404Spjd 3181168404Spjd nvs->nvs_op = NVS_OP_GETSIZE; 3182168404Spjd if (type == DATA_TYPE_NVLIST) 3183168404Spjd err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize); 3184168404Spjd else 3185168404Spjd err = nvs_embedded_nvl_array(nvs, nvp, &nvsize); 3186168404Spjd nvs->nvs_op = old_nvs_op; 3187168404Spjd 3188168404Spjd if (err != 0) 3189168404Spjd return (EINVAL); 3190168404Spjd 3191168404Spjd nvp_sz += nvsize; 3192168404Spjd break; 3193168404Spjd } 3194168404Spjd 3195168404Spjd default: 3196168404Spjd return (EINVAL); 3197168404Spjd } 3198168404Spjd 3199168404Spjd if (nvp_sz > INT32_MAX) 3200168404Spjd return (EINVAL); 3201168404Spjd 3202168404Spjd *size = nvp_sz; 3203168404Spjd 3204168404Spjd return (0); 3205168404Spjd} 3206168404Spjd 3207168404Spjd 3208168404Spjd/* 3209168404Spjd * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates 3210168404Spjd * the largest nvpair that could be encoded in the buffer. 3211168404Spjd * 3212168404Spjd * See comments above nvpair_xdr_op() for the format of xdr encoding. 3213168404Spjd * The size of a xdr packed nvpair without any data is 5 words. 3214168404Spjd * 3215168404Spjd * Using the size of the data directly as an estimate would be ok 3216168404Spjd * in all cases except one. If the data type is of DATA_TYPE_STRING_ARRAY 3217168404Spjd * then the actual nvpair has space for an array of pointers to index 3218168404Spjd * the strings. These pointers are not encoded into the packed xdr buffer. 3219168404Spjd * 3220168404Spjd * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are 3221168404Spjd * of length 0, then each string is endcoded in xdr format as a single word. 3222168404Spjd * Therefore when expanded to an nvpair there will be 2.25 word used for 3223168404Spjd * each string. (a int64_t allocated for pointer usage, and a single char 3224168404Spjd * for the null termination.) 3225168404Spjd * 3226168404Spjd * This is the calculation performed by the NVS_XDR_MAX_LEN macro. 3227168404Spjd */ 3228168404Spjd#define NVS_XDR_HDR_LEN ((size_t)(5 * 4)) 3229168404Spjd#define NVS_XDR_DATA_LEN(y) (((size_t)(y) <= NVS_XDR_HDR_LEN) ? \ 3230168404Spjd 0 : ((size_t)(y) - NVS_XDR_HDR_LEN)) 3231168404Spjd#define NVS_XDR_MAX_LEN(x) (NVP_SIZE_CALC(1, 0) + \ 3232168404Spjd (NVS_XDR_DATA_LEN(x) * 2) + \ 3233168404Spjd NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4))) 3234168404Spjd 3235168404Spjdstatic int 3236168404Spjdnvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 3237168404Spjd{ 3238168404Spjd XDR *xdr = nvs->nvs_private; 3239168404Spjd int32_t encode_len, decode_len; 3240168404Spjd 3241168404Spjd switch (nvs->nvs_op) { 3242168404Spjd case NVS_OP_ENCODE: { 3243168404Spjd size_t nvsize; 3244168404Spjd 3245168404Spjd if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0) 3246168404Spjd return (EFAULT); 3247168404Spjd 3248168404Spjd decode_len = nvp->nvp_size; 3249168404Spjd encode_len = nvsize; 3250168404Spjd if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len)) 3251168404Spjd return (EFAULT); 3252168404Spjd 3253168404Spjd return (nvs_xdr_nvp_op(nvs, nvp)); 3254168404Spjd } 3255168404Spjd case NVS_OP_DECODE: { 3256168404Spjd struct xdr_bytesrec bytesrec; 3257168404Spjd 3258168404Spjd /* get the encode and decode size */ 3259168404Spjd if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len)) 3260168404Spjd return (EFAULT); 3261168404Spjd *size = decode_len; 3262168404Spjd 3263168404Spjd /* are we at the end of the stream? */ 3264168404Spjd if (*size == 0) 3265168404Spjd return (0); 3266168404Spjd 3267168404Spjd /* sanity check the size parameter */ 3268168404Spjd if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec)) 3269168404Spjd return (EFAULT); 3270168404Spjd 3271168404Spjd if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail)) 3272168404Spjd return (EFAULT); 3273168404Spjd break; 3274168404Spjd } 3275168404Spjd 3276168404Spjd default: 3277168404Spjd return (EINVAL); 3278168404Spjd } 3279168404Spjd return (0); 3280168404Spjd} 3281168404Spjd 3282168404Spjdstatic const struct nvs_ops nvs_xdr_ops = { 3283168404Spjd nvs_xdr_nvlist, 3284168404Spjd nvs_xdr_nvpair, 3285168404Spjd nvs_xdr_nvp_op, 3286168404Spjd nvs_xdr_nvp_size, 3287168404Spjd nvs_xdr_nvl_fini 3288168404Spjd}; 3289168404Spjd 3290168404Spjdstatic int 3291168404Spjdnvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen) 3292168404Spjd{ 3293168404Spjd XDR xdr; 3294168404Spjd int err; 3295168404Spjd 3296168404Spjd nvs->nvs_ops = &nvs_xdr_ops; 3297168404Spjd 3298168404Spjd if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t), 3299168404Spjd *buflen - sizeof (nvs_header_t))) != 0) 3300168404Spjd return (err); 3301168404Spjd 3302168404Spjd err = nvs_operation(nvs, nvl, buflen); 3303168404Spjd 3304168404Spjd nvs_xdr_destroy(nvs); 3305168404Spjd 3306168404Spjd return (err); 3307168404Spjd} 3308