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