1*61145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0 2eda14cbcSMatt Macy /* 3eda14cbcSMatt Macy * CDDL HEADER START 4eda14cbcSMatt Macy * 5eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 6eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 7eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 8eda14cbcSMatt Macy * 9eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 11eda14cbcSMatt Macy * See the License for the specific language governing permissions 12eda14cbcSMatt Macy * and limitations under the License. 13eda14cbcSMatt Macy * 14eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 15eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 17eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 18eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 19eda14cbcSMatt Macy * 20eda14cbcSMatt Macy * CDDL HEADER END 21eda14cbcSMatt Macy */ 22eda14cbcSMatt Macy 23eda14cbcSMatt Macy /* 24eda14cbcSMatt Macy * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 25eda14cbcSMatt Macy * Copyright (c) 2015, 2017 by Delphix. All rights reserved. 26eda14cbcSMatt Macy * Copyright 2018 RackTop Systems. 27eda14cbcSMatt Macy */ 28eda14cbcSMatt Macy 29eac7052fSMatt Macy /* 30eac7052fSMatt Macy * Links to Illumos.org for more information on Interface Libraries: 31eac7052fSMatt Macy * [1] https://illumos.org/man/3lib/libnvpair 32eac7052fSMatt Macy * [2] https://illumos.org/man/3nvpair/nvlist_alloc 33eac7052fSMatt Macy * [3] https://illumos.org/man/9f/nvlist_alloc 34eac7052fSMatt Macy * [4] https://illumos.org/man/9f/nvlist_next_nvpair 35eac7052fSMatt Macy * [5] https://illumos.org/man/9f/nvpair_value_byte 36eac7052fSMatt Macy */ 37eac7052fSMatt Macy 38eda14cbcSMatt Macy #include <sys/debug.h> 39eda14cbcSMatt Macy #include <sys/isa_defs.h> 40eda14cbcSMatt Macy #include <sys/nvpair.h> 41eda14cbcSMatt Macy #include <sys/nvpair_impl.h> 42eda14cbcSMatt Macy #include <sys/types.h> 43eda14cbcSMatt Macy #include <sys/param.h> 44da5137abSMartin Matuska #include <sys/string.h> 451719886fSMartin Matuska #include <rpc/types.h> 46eda14cbcSMatt Macy #include <rpc/xdr.h> 47eda14cbcSMatt Macy #include <sys/mod.h> 48eda14cbcSMatt Macy 49eda14cbcSMatt Macy #if defined(_KERNEL) 50eda14cbcSMatt Macy #include <sys/sunddi.h> 51eda14cbcSMatt Macy #include <sys/sysmacros.h> 52eda14cbcSMatt Macy #else 53eda14cbcSMatt Macy #include <stdarg.h> 54eda14cbcSMatt Macy #include <stdlib.h> 55eda14cbcSMatt Macy #include <stddef.h> 56eda14cbcSMatt Macy #endif 57eda14cbcSMatt Macy 58da5137abSMartin Matuska #define skip_whitespace(p) while ((*(p) == ' ') || (*(p) == '\t')) (p)++ 59eda14cbcSMatt Macy 60eda14cbcSMatt Macy /* 61eda14cbcSMatt Macy * nvpair.c - Provides kernel & userland interfaces for manipulating 62eda14cbcSMatt Macy * name-value pairs. 63eda14cbcSMatt Macy * 64eda14cbcSMatt Macy * Overview Diagram 65eda14cbcSMatt Macy * 66eda14cbcSMatt Macy * +--------------+ 67eda14cbcSMatt Macy * | nvlist_t | 68eda14cbcSMatt Macy * |--------------| 69eda14cbcSMatt Macy * | nvl_version | 70eda14cbcSMatt Macy * | nvl_nvflag | 71eda14cbcSMatt Macy * | nvl_priv -+-+ 72eda14cbcSMatt Macy * | nvl_flag | | 73eda14cbcSMatt Macy * | nvl_pad | | 74eda14cbcSMatt Macy * +--------------+ | 75eda14cbcSMatt Macy * V 76eda14cbcSMatt Macy * +--------------+ last i_nvp in list 77eda14cbcSMatt Macy * | nvpriv_t | +---------------------> 78eda14cbcSMatt Macy * |--------------| | 79eda14cbcSMatt Macy * +--+- nvp_list | | +------------+ 80eda14cbcSMatt Macy * | | nvp_last -+--+ + nv_alloc_t | 81eda14cbcSMatt Macy * | | nvp_curr | |------------| 82eda14cbcSMatt Macy * | | nvp_nva -+----> | nva_ops | 83eda14cbcSMatt Macy * | | nvp_stat | | nva_arg | 84eda14cbcSMatt Macy * | +--------------+ +------------+ 85eda14cbcSMatt Macy * | 86eda14cbcSMatt Macy * +-------+ 87eda14cbcSMatt Macy * V 88eda14cbcSMatt Macy * +---------------------+ +-------------------+ 89eda14cbcSMatt Macy * | i_nvp_t | +-->| i_nvp_t | +--> 90eda14cbcSMatt Macy * |---------------------| | |-------------------| | 91eda14cbcSMatt Macy * | nvi_next -+--+ | nvi_next -+--+ 92eda14cbcSMatt Macy * | nvi_prev (NULL) | <----+ nvi_prev | 93eda14cbcSMatt Macy * | . . . . . . . . . . | | . . . . . . . . . | 94eda14cbcSMatt Macy * | nvp (nvpair_t) | | nvp (nvpair_t) | 95eda14cbcSMatt Macy * | - nvp_size | | - nvp_size | 96eda14cbcSMatt Macy * | - nvp_name_sz | | - nvp_name_sz | 97eda14cbcSMatt Macy * | - nvp_value_elem | | - nvp_value_elem | 98eda14cbcSMatt Macy * | - nvp_type | | - nvp_type | 99eda14cbcSMatt Macy * | - data ... | | - data ... | 100eda14cbcSMatt Macy * +---------------------+ +-------------------+ 101eda14cbcSMatt Macy * 102eda14cbcSMatt Macy * 103eda14cbcSMatt Macy * 104eda14cbcSMatt Macy * +---------------------+ +---------------------+ 105eda14cbcSMatt Macy * | i_nvp_t | +--> +-->| i_nvp_t (last) | 106eda14cbcSMatt Macy * |---------------------| | | |---------------------| 107eda14cbcSMatt Macy * | nvi_next -+--+ ... --+ | nvi_next (NULL) | 108eda14cbcSMatt Macy * <-+- nvi_prev |<-- ... <----+ nvi_prev | 109eda14cbcSMatt Macy * | . . . . . . . . . | | . . . . . . . . . | 110eda14cbcSMatt Macy * | nvp (nvpair_t) | | nvp (nvpair_t) | 111eda14cbcSMatt Macy * | - nvp_size | | - nvp_size | 112eda14cbcSMatt Macy * | - nvp_name_sz | | - nvp_name_sz | 113eda14cbcSMatt Macy * | - nvp_value_elem | | - nvp_value_elem | 114eda14cbcSMatt Macy * | - DATA_TYPE_NVLIST | | - nvp_type | 115eda14cbcSMatt Macy * | - data (embedded) | | - data ... | 116eda14cbcSMatt Macy * | nvlist name | +---------------------+ 117eda14cbcSMatt Macy * | +--------------+ | 118eda14cbcSMatt Macy * | | nvlist_t | | 119eda14cbcSMatt Macy * | |--------------| | 120eda14cbcSMatt Macy * | | nvl_version | | 121eda14cbcSMatt Macy * | | nvl_nvflag | | 122eda14cbcSMatt Macy * | | nvl_priv --+---+----> 123eda14cbcSMatt Macy * | | nvl_flag | | 124eda14cbcSMatt Macy * | | nvl_pad | | 125eda14cbcSMatt Macy * | +--------------+ | 126eda14cbcSMatt Macy * +---------------------+ 127eda14cbcSMatt Macy * 128eda14cbcSMatt Macy * 129eda14cbcSMatt Macy * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will 130eda14cbcSMatt Macy * allow value to be aligned on 8 byte boundary 131eda14cbcSMatt Macy * 132eda14cbcSMatt Macy * name_len is the length of the name string including the null terminator 133eda14cbcSMatt Macy * so it must be >= 1 134eda14cbcSMatt Macy */ 135eda14cbcSMatt Macy #define NVP_SIZE_CALC(name_len, data_len) \ 136eda14cbcSMatt Macy (NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len)) 137eda14cbcSMatt Macy 138eda14cbcSMatt Macy static int i_get_value_size(data_type_t type, const void *data, uint_t nelem); 139eda14cbcSMatt Macy static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type, 140eda14cbcSMatt Macy uint_t nelem, const void *data); 141eda14cbcSMatt Macy 142eda14cbcSMatt Macy #define NV_STAT_EMBEDDED 0x1 143eda14cbcSMatt Macy #define EMBEDDED_NVL(nvp) ((nvlist_t *)(void *)NVP_VALUE(nvp)) 144eda14cbcSMatt Macy #define EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp)) 145eda14cbcSMatt Macy 146eda14cbcSMatt Macy #define NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz)) 147eda14cbcSMatt Macy #define NVPAIR2I_NVP(nvp) \ 148eda14cbcSMatt Macy ((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp))) 149eda14cbcSMatt Macy 150eda14cbcSMatt Macy #ifdef _KERNEL 151e92ffd9bSMartin Matuska static const int nvpair_max_recursion = 20; 152eda14cbcSMatt Macy #else 153e92ffd9bSMartin Matuska static const int nvpair_max_recursion = 100; 154eda14cbcSMatt Macy #endif 155eda14cbcSMatt Macy 156e92ffd9bSMartin Matuska static const uint64_t nvlist_hashtable_init_size = (1 << 4); 157eda14cbcSMatt Macy 158eda14cbcSMatt Macy int 159eda14cbcSMatt Macy nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...) 160eda14cbcSMatt Macy { 161eda14cbcSMatt Macy va_list valist; 162eda14cbcSMatt Macy int err = 0; 163eda14cbcSMatt Macy 164eda14cbcSMatt Macy nva->nva_ops = nvo; 165eda14cbcSMatt Macy nva->nva_arg = NULL; 166eda14cbcSMatt Macy 167eda14cbcSMatt Macy va_start(valist, nvo); 168eda14cbcSMatt Macy if (nva->nva_ops->nv_ao_init != NULL) 169eda14cbcSMatt Macy err = nva->nva_ops->nv_ao_init(nva, valist); 170eda14cbcSMatt Macy va_end(valist); 171eda14cbcSMatt Macy 172eda14cbcSMatt Macy return (err); 173eda14cbcSMatt Macy } 174eda14cbcSMatt Macy 175eda14cbcSMatt Macy void 176eda14cbcSMatt Macy nv_alloc_reset(nv_alloc_t *nva) 177eda14cbcSMatt Macy { 178eda14cbcSMatt Macy if (nva->nva_ops->nv_ao_reset != NULL) 179eda14cbcSMatt Macy nva->nva_ops->nv_ao_reset(nva); 180eda14cbcSMatt Macy } 181eda14cbcSMatt Macy 182eda14cbcSMatt Macy void 183eda14cbcSMatt Macy nv_alloc_fini(nv_alloc_t *nva) 184eda14cbcSMatt Macy { 185eda14cbcSMatt Macy if (nva->nva_ops->nv_ao_fini != NULL) 186eda14cbcSMatt Macy nva->nva_ops->nv_ao_fini(nva); 187eda14cbcSMatt Macy } 188eda14cbcSMatt Macy 189eda14cbcSMatt Macy nv_alloc_t * 190eda14cbcSMatt Macy nvlist_lookup_nv_alloc(nvlist_t *nvl) 191eda14cbcSMatt Macy { 192eda14cbcSMatt Macy nvpriv_t *priv; 193eda14cbcSMatt Macy 194eda14cbcSMatt Macy if (nvl == NULL || 195eda14cbcSMatt Macy (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 196eda14cbcSMatt Macy return (NULL); 197eda14cbcSMatt Macy 198eda14cbcSMatt Macy return (priv->nvp_nva); 199eda14cbcSMatt Macy } 200eda14cbcSMatt Macy 201eda14cbcSMatt Macy static void * 202eda14cbcSMatt Macy nv_mem_zalloc(nvpriv_t *nvp, size_t size) 203eda14cbcSMatt Macy { 204eda14cbcSMatt Macy nv_alloc_t *nva = nvp->nvp_nva; 205eda14cbcSMatt Macy void *buf; 206eda14cbcSMatt Macy 207eda14cbcSMatt Macy if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL) 208da5137abSMartin Matuska memset(buf, 0, size); 209eda14cbcSMatt Macy 210eda14cbcSMatt Macy return (buf); 211eda14cbcSMatt Macy } 212eda14cbcSMatt Macy 213eda14cbcSMatt Macy static void 214eda14cbcSMatt Macy nv_mem_free(nvpriv_t *nvp, void *buf, size_t size) 215eda14cbcSMatt Macy { 216eda14cbcSMatt Macy nv_alloc_t *nva = nvp->nvp_nva; 217eda14cbcSMatt Macy 218eda14cbcSMatt Macy nva->nva_ops->nv_ao_free(nva, buf, size); 219eda14cbcSMatt Macy } 220eda14cbcSMatt Macy 221eda14cbcSMatt Macy static void 222eda14cbcSMatt Macy nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat) 223eda14cbcSMatt Macy { 224da5137abSMartin Matuska memset(priv, 0, sizeof (nvpriv_t)); 225eda14cbcSMatt Macy 226eda14cbcSMatt Macy priv->nvp_nva = nva; 227eda14cbcSMatt Macy priv->nvp_stat = stat; 228eda14cbcSMatt Macy } 229eda14cbcSMatt Macy 230eda14cbcSMatt Macy static nvpriv_t * 231eda14cbcSMatt Macy nv_priv_alloc(nv_alloc_t *nva) 232eda14cbcSMatt Macy { 233eda14cbcSMatt Macy nvpriv_t *priv; 234eda14cbcSMatt Macy 235eda14cbcSMatt Macy /* 236eda14cbcSMatt Macy * nv_mem_alloc() cannot called here because it needs the priv 237eda14cbcSMatt Macy * argument. 238eda14cbcSMatt Macy */ 239eda14cbcSMatt Macy if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL) 240eda14cbcSMatt Macy return (NULL); 241eda14cbcSMatt Macy 242eda14cbcSMatt Macy nv_priv_init(priv, nva, 0); 243eda14cbcSMatt Macy 244eda14cbcSMatt Macy return (priv); 245eda14cbcSMatt Macy } 246eda14cbcSMatt Macy 247eda14cbcSMatt Macy /* 248eda14cbcSMatt Macy * Embedded lists need their own nvpriv_t's. We create a new 249eda14cbcSMatt Macy * nvpriv_t using the parameters and allocator from the parent 250eda14cbcSMatt Macy * list's nvpriv_t. 251eda14cbcSMatt Macy */ 252eda14cbcSMatt Macy static nvpriv_t * 253eda14cbcSMatt Macy nv_priv_alloc_embedded(nvpriv_t *priv) 254eda14cbcSMatt Macy { 255eda14cbcSMatt Macy nvpriv_t *emb_priv; 256eda14cbcSMatt Macy 257eda14cbcSMatt Macy if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL) 258eda14cbcSMatt Macy return (NULL); 259eda14cbcSMatt Macy 260eda14cbcSMatt Macy nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED); 261eda14cbcSMatt Macy 262eda14cbcSMatt Macy return (emb_priv); 263eda14cbcSMatt Macy } 264eda14cbcSMatt Macy 265eda14cbcSMatt Macy static int 266eda14cbcSMatt Macy nvt_tab_alloc(nvpriv_t *priv, uint64_t buckets) 267eda14cbcSMatt Macy { 268eda14cbcSMatt Macy ASSERT3P(priv->nvp_hashtable, ==, NULL); 269eda14cbcSMatt Macy ASSERT0(priv->nvp_nbuckets); 270eda14cbcSMatt Macy ASSERT0(priv->nvp_nentries); 271eda14cbcSMatt Macy 272eda14cbcSMatt Macy i_nvp_t **tab = nv_mem_zalloc(priv, buckets * sizeof (i_nvp_t *)); 273eda14cbcSMatt Macy if (tab == NULL) 274eda14cbcSMatt Macy return (ENOMEM); 275eda14cbcSMatt Macy 276eda14cbcSMatt Macy priv->nvp_hashtable = tab; 277eda14cbcSMatt Macy priv->nvp_nbuckets = buckets; 278eda14cbcSMatt Macy return (0); 279eda14cbcSMatt Macy } 280eda14cbcSMatt Macy 281eda14cbcSMatt Macy static void 282eda14cbcSMatt Macy nvt_tab_free(nvpriv_t *priv) 283eda14cbcSMatt Macy { 284eda14cbcSMatt Macy i_nvp_t **tab = priv->nvp_hashtable; 285eda14cbcSMatt Macy if (tab == NULL) { 286eda14cbcSMatt Macy ASSERT0(priv->nvp_nbuckets); 287eda14cbcSMatt Macy ASSERT0(priv->nvp_nentries); 288eda14cbcSMatt Macy return; 289eda14cbcSMatt Macy } 290eda14cbcSMatt Macy 291eda14cbcSMatt Macy nv_mem_free(priv, tab, priv->nvp_nbuckets * sizeof (i_nvp_t *)); 292eda14cbcSMatt Macy 293eda14cbcSMatt Macy priv->nvp_hashtable = NULL; 294eda14cbcSMatt Macy priv->nvp_nbuckets = 0; 295eda14cbcSMatt Macy priv->nvp_nentries = 0; 296eda14cbcSMatt Macy } 297eda14cbcSMatt Macy 298eda14cbcSMatt Macy static uint32_t 299eda14cbcSMatt Macy nvt_hash(const char *p) 300eda14cbcSMatt Macy { 301eda14cbcSMatt Macy uint32_t g, hval = 0; 302eda14cbcSMatt Macy 303eda14cbcSMatt Macy while (*p) { 304eda14cbcSMatt Macy hval = (hval << 4) + *p++; 305eda14cbcSMatt Macy if ((g = (hval & 0xf0000000)) != 0) 306eda14cbcSMatt Macy hval ^= g >> 24; 307eda14cbcSMatt Macy hval &= ~g; 308eda14cbcSMatt Macy } 309eda14cbcSMatt Macy return (hval); 310eda14cbcSMatt Macy } 311eda14cbcSMatt Macy 312eda14cbcSMatt Macy static boolean_t 313681ce946SMartin Matuska nvt_nvpair_match(const nvpair_t *nvp1, const nvpair_t *nvp2, uint32_t nvflag) 314eda14cbcSMatt Macy { 315eda14cbcSMatt Macy boolean_t match = B_FALSE; 316eda14cbcSMatt Macy if (nvflag & NV_UNIQUE_NAME_TYPE) { 317eda14cbcSMatt Macy if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0 && 318eda14cbcSMatt Macy NVP_TYPE(nvp1) == NVP_TYPE(nvp2)) 319eda14cbcSMatt Macy match = B_TRUE; 320eda14cbcSMatt Macy } else { 321eda14cbcSMatt Macy ASSERT(nvflag == 0 || nvflag & NV_UNIQUE_NAME); 322eda14cbcSMatt Macy if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0) 323eda14cbcSMatt Macy match = B_TRUE; 324eda14cbcSMatt Macy } 325eda14cbcSMatt Macy return (match); 326eda14cbcSMatt Macy } 327eda14cbcSMatt Macy 328eda14cbcSMatt Macy static nvpair_t * 329681ce946SMartin Matuska nvt_lookup_name_type(const nvlist_t *nvl, const char *name, data_type_t type) 330eda14cbcSMatt Macy { 331681ce946SMartin Matuska const nvpriv_t *priv = (const nvpriv_t *)(uintptr_t)nvl->nvl_priv; 332eda14cbcSMatt Macy ASSERT(priv != NULL); 333eda14cbcSMatt Macy 334eda14cbcSMatt Macy i_nvp_t **tab = priv->nvp_hashtable; 335eda14cbcSMatt Macy 336eda14cbcSMatt Macy if (tab == NULL) { 337eda14cbcSMatt Macy ASSERT3P(priv->nvp_list, ==, NULL); 338eda14cbcSMatt Macy ASSERT0(priv->nvp_nbuckets); 339eda14cbcSMatt Macy ASSERT0(priv->nvp_nentries); 340eda14cbcSMatt Macy return (NULL); 341eda14cbcSMatt Macy } else { 342eda14cbcSMatt Macy ASSERT(priv->nvp_nbuckets != 0); 343eda14cbcSMatt Macy } 344eda14cbcSMatt Macy 345eda14cbcSMatt Macy uint64_t hash = nvt_hash(name); 346eda14cbcSMatt Macy uint64_t index = hash & (priv->nvp_nbuckets - 1); 347eda14cbcSMatt Macy 348eda14cbcSMatt Macy ASSERT3U(index, <, priv->nvp_nbuckets); 349eda14cbcSMatt Macy i_nvp_t *entry = tab[index]; 350eda14cbcSMatt Macy 351eda14cbcSMatt Macy for (i_nvp_t *e = entry; e != NULL; e = e->nvi_hashtable_next) { 352eda14cbcSMatt Macy if (strcmp(NVP_NAME(&e->nvi_nvp), name) == 0 && 353eda14cbcSMatt Macy (type == DATA_TYPE_DONTCARE || 354eda14cbcSMatt Macy NVP_TYPE(&e->nvi_nvp) == type)) 355eda14cbcSMatt Macy return (&e->nvi_nvp); 356eda14cbcSMatt Macy } 357eda14cbcSMatt Macy return (NULL); 358eda14cbcSMatt Macy } 359eda14cbcSMatt Macy 360eda14cbcSMatt Macy static nvpair_t * 361681ce946SMartin Matuska nvt_lookup_name(const nvlist_t *nvl, const char *name) 362eda14cbcSMatt Macy { 363eda14cbcSMatt Macy return (nvt_lookup_name_type(nvl, name, DATA_TYPE_DONTCARE)); 364eda14cbcSMatt Macy } 365eda14cbcSMatt Macy 366eda14cbcSMatt Macy static int 367eda14cbcSMatt Macy nvt_resize(nvpriv_t *priv, uint32_t new_size) 368eda14cbcSMatt Macy { 369eda14cbcSMatt Macy i_nvp_t **tab = priv->nvp_hashtable; 370eda14cbcSMatt Macy 371eda14cbcSMatt Macy /* 372eda14cbcSMatt Macy * Migrate all the entries from the current table 373eda14cbcSMatt Macy * to a newly-allocated table with the new size by 374eda14cbcSMatt Macy * re-adjusting the pointers of their entries. 375eda14cbcSMatt Macy */ 376eda14cbcSMatt Macy uint32_t size = priv->nvp_nbuckets; 377eda14cbcSMatt Macy uint32_t new_mask = new_size - 1; 378eda14cbcSMatt Macy ASSERT(ISP2(new_size)); 379eda14cbcSMatt Macy 380eda14cbcSMatt Macy i_nvp_t **new_tab = nv_mem_zalloc(priv, new_size * sizeof (i_nvp_t *)); 381eda14cbcSMatt Macy if (new_tab == NULL) 382eda14cbcSMatt Macy return (ENOMEM); 383eda14cbcSMatt Macy 384eda14cbcSMatt Macy uint32_t nentries = 0; 385eda14cbcSMatt Macy for (uint32_t i = 0; i < size; i++) { 386eda14cbcSMatt Macy i_nvp_t *next, *e = tab[i]; 387eda14cbcSMatt Macy 388eda14cbcSMatt Macy while (e != NULL) { 389eda14cbcSMatt Macy next = e->nvi_hashtable_next; 390eda14cbcSMatt Macy 391eda14cbcSMatt Macy uint32_t hash = nvt_hash(NVP_NAME(&e->nvi_nvp)); 392eda14cbcSMatt Macy uint32_t index = hash & new_mask; 393eda14cbcSMatt Macy 394eda14cbcSMatt Macy e->nvi_hashtable_next = new_tab[index]; 395eda14cbcSMatt Macy new_tab[index] = e; 396eda14cbcSMatt Macy nentries++; 397eda14cbcSMatt Macy 398eda14cbcSMatt Macy e = next; 399eda14cbcSMatt Macy } 400eda14cbcSMatt Macy tab[i] = NULL; 401eda14cbcSMatt Macy } 402eda14cbcSMatt Macy ASSERT3U(nentries, ==, priv->nvp_nentries); 403eda14cbcSMatt Macy 404eda14cbcSMatt Macy nvt_tab_free(priv); 405eda14cbcSMatt Macy 406eda14cbcSMatt Macy priv->nvp_hashtable = new_tab; 407eda14cbcSMatt Macy priv->nvp_nbuckets = new_size; 408eda14cbcSMatt Macy priv->nvp_nentries = nentries; 409eda14cbcSMatt Macy 410eda14cbcSMatt Macy return (0); 411eda14cbcSMatt Macy } 412eda14cbcSMatt Macy 413eda14cbcSMatt Macy static boolean_t 414eda14cbcSMatt Macy nvt_needs_togrow(nvpriv_t *priv) 415eda14cbcSMatt Macy { 416eda14cbcSMatt Macy /* 417eda14cbcSMatt Macy * Grow only when we have more elements than buckets 418eda14cbcSMatt Macy * and the # of buckets doesn't overflow. 419eda14cbcSMatt Macy */ 420eda14cbcSMatt Macy return (priv->nvp_nentries > priv->nvp_nbuckets && 421eda14cbcSMatt Macy (UINT32_MAX >> 1) >= priv->nvp_nbuckets); 422eda14cbcSMatt Macy } 423eda14cbcSMatt Macy 424eda14cbcSMatt Macy /* 425eda14cbcSMatt Macy * Allocate a new table that's twice the size of the old one, 426eda14cbcSMatt Macy * and migrate all the entries from the old one to the new 427eda14cbcSMatt Macy * one by re-adjusting their pointers. 428eda14cbcSMatt Macy */ 429eda14cbcSMatt Macy static int 430eda14cbcSMatt Macy nvt_grow(nvpriv_t *priv) 431eda14cbcSMatt Macy { 432eda14cbcSMatt Macy uint32_t current_size = priv->nvp_nbuckets; 433eda14cbcSMatt Macy /* ensure we won't overflow */ 434eda14cbcSMatt Macy ASSERT3U(UINT32_MAX >> 1, >=, current_size); 435eda14cbcSMatt Macy return (nvt_resize(priv, current_size << 1)); 436eda14cbcSMatt Macy } 437eda14cbcSMatt Macy 438eda14cbcSMatt Macy static boolean_t 439eda14cbcSMatt Macy nvt_needs_toshrink(nvpriv_t *priv) 440eda14cbcSMatt Macy { 441eda14cbcSMatt Macy /* 442eda14cbcSMatt Macy * Shrink only when the # of elements is less than or 443eda14cbcSMatt Macy * equal to 1/4 the # of buckets. Never shrink less than 444eda14cbcSMatt Macy * nvlist_hashtable_init_size. 445eda14cbcSMatt Macy */ 446eda14cbcSMatt Macy ASSERT3U(priv->nvp_nbuckets, >=, nvlist_hashtable_init_size); 447eda14cbcSMatt Macy if (priv->nvp_nbuckets == nvlist_hashtable_init_size) 448eda14cbcSMatt Macy return (B_FALSE); 449eda14cbcSMatt Macy return (priv->nvp_nentries <= (priv->nvp_nbuckets >> 2)); 450eda14cbcSMatt Macy } 451eda14cbcSMatt Macy 452eda14cbcSMatt Macy /* 453eda14cbcSMatt Macy * Allocate a new table that's half the size of the old one, 454eda14cbcSMatt Macy * and migrate all the entries from the old one to the new 455eda14cbcSMatt Macy * one by re-adjusting their pointers. 456eda14cbcSMatt Macy */ 457eda14cbcSMatt Macy static int 458eda14cbcSMatt Macy nvt_shrink(nvpriv_t *priv) 459eda14cbcSMatt Macy { 460eda14cbcSMatt Macy uint32_t current_size = priv->nvp_nbuckets; 461eda14cbcSMatt Macy /* ensure we won't overflow */ 462eda14cbcSMatt Macy ASSERT3U(current_size, >=, nvlist_hashtable_init_size); 463eda14cbcSMatt Macy return (nvt_resize(priv, current_size >> 1)); 464eda14cbcSMatt Macy } 465eda14cbcSMatt Macy 466eda14cbcSMatt Macy static int 467681ce946SMartin Matuska nvt_remove_nvpair(nvlist_t *nvl, const nvpair_t *nvp) 468eda14cbcSMatt Macy { 469eda14cbcSMatt Macy nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 470eda14cbcSMatt Macy 471eda14cbcSMatt Macy if (nvt_needs_toshrink(priv)) { 472eda14cbcSMatt Macy int err = nvt_shrink(priv); 473eda14cbcSMatt Macy if (err != 0) 474eda14cbcSMatt Macy return (err); 475eda14cbcSMatt Macy } 476eda14cbcSMatt Macy i_nvp_t **tab = priv->nvp_hashtable; 477eda14cbcSMatt Macy 4782a58b312SMartin Matuska const char *name = NVP_NAME(nvp); 479eda14cbcSMatt Macy uint64_t hash = nvt_hash(name); 480eda14cbcSMatt Macy uint64_t index = hash & (priv->nvp_nbuckets - 1); 481eda14cbcSMatt Macy 482eda14cbcSMatt Macy ASSERT3U(index, <, priv->nvp_nbuckets); 483eda14cbcSMatt Macy i_nvp_t *bucket = tab[index]; 484eda14cbcSMatt Macy 485eda14cbcSMatt Macy for (i_nvp_t *prev = NULL, *e = bucket; 486eda14cbcSMatt Macy e != NULL; prev = e, e = e->nvi_hashtable_next) { 487eda14cbcSMatt Macy if (nvt_nvpair_match(&e->nvi_nvp, nvp, nvl->nvl_nvflag)) { 488eda14cbcSMatt Macy if (prev != NULL) { 489eda14cbcSMatt Macy prev->nvi_hashtable_next = 490eda14cbcSMatt Macy e->nvi_hashtable_next; 491eda14cbcSMatt Macy } else { 492eda14cbcSMatt Macy ASSERT3P(e, ==, bucket); 493eda14cbcSMatt Macy tab[index] = e->nvi_hashtable_next; 494eda14cbcSMatt Macy } 495eda14cbcSMatt Macy e->nvi_hashtable_next = NULL; 496eda14cbcSMatt Macy priv->nvp_nentries--; 497eda14cbcSMatt Macy break; 498eda14cbcSMatt Macy } 499eda14cbcSMatt Macy } 500eda14cbcSMatt Macy 501eda14cbcSMatt Macy return (0); 502eda14cbcSMatt Macy } 503eda14cbcSMatt Macy 504eda14cbcSMatt Macy static int 505eda14cbcSMatt Macy nvt_add_nvpair(nvlist_t *nvl, nvpair_t *nvp) 506eda14cbcSMatt Macy { 507eda14cbcSMatt Macy nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 508eda14cbcSMatt Macy 509eda14cbcSMatt Macy /* initialize nvpair table now if it doesn't exist. */ 510eda14cbcSMatt Macy if (priv->nvp_hashtable == NULL) { 511eda14cbcSMatt Macy int err = nvt_tab_alloc(priv, nvlist_hashtable_init_size); 512eda14cbcSMatt Macy if (err != 0) 513eda14cbcSMatt Macy return (err); 514eda14cbcSMatt Macy } 515eda14cbcSMatt Macy 516eda14cbcSMatt Macy /* 517eda14cbcSMatt Macy * if we don't allow duplicate entries, make sure to 518eda14cbcSMatt Macy * unlink any existing entries from the table. 519eda14cbcSMatt Macy */ 520eda14cbcSMatt Macy if (nvl->nvl_nvflag != 0) { 521eda14cbcSMatt Macy int err = nvt_remove_nvpair(nvl, nvp); 522eda14cbcSMatt Macy if (err != 0) 523eda14cbcSMatt Macy return (err); 524eda14cbcSMatt Macy } 525eda14cbcSMatt Macy 526eda14cbcSMatt Macy if (nvt_needs_togrow(priv)) { 527eda14cbcSMatt Macy int err = nvt_grow(priv); 528eda14cbcSMatt Macy if (err != 0) 529eda14cbcSMatt Macy return (err); 530eda14cbcSMatt Macy } 531eda14cbcSMatt Macy i_nvp_t **tab = priv->nvp_hashtable; 532eda14cbcSMatt Macy 5332a58b312SMartin Matuska const char *name = NVP_NAME(nvp); 534eda14cbcSMatt Macy uint64_t hash = nvt_hash(name); 535eda14cbcSMatt Macy uint64_t index = hash & (priv->nvp_nbuckets - 1); 536eda14cbcSMatt Macy 537eda14cbcSMatt Macy ASSERT3U(index, <, priv->nvp_nbuckets); 53881b22a98SMartin Matuska // cppcheck-suppress nullPointerRedundantCheck 539eda14cbcSMatt Macy i_nvp_t *bucket = tab[index]; 540eda14cbcSMatt Macy 541eda14cbcSMatt Macy /* insert link at the beginning of the bucket */ 542eda14cbcSMatt Macy i_nvp_t *new_entry = NVPAIR2I_NVP(nvp); 543eda14cbcSMatt Macy ASSERT3P(new_entry->nvi_hashtable_next, ==, NULL); 544eda14cbcSMatt Macy new_entry->nvi_hashtable_next = bucket; 54581b22a98SMartin Matuska // cppcheck-suppress nullPointerRedundantCheck 546eda14cbcSMatt Macy tab[index] = new_entry; 547eda14cbcSMatt Macy 548eda14cbcSMatt Macy priv->nvp_nentries++; 549eda14cbcSMatt Macy return (0); 550eda14cbcSMatt Macy } 551eda14cbcSMatt Macy 552eda14cbcSMatt Macy static void 553eda14cbcSMatt Macy nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv) 554eda14cbcSMatt Macy { 555eda14cbcSMatt Macy nvl->nvl_version = NV_VERSION; 556eda14cbcSMatt Macy nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE); 557eda14cbcSMatt Macy nvl->nvl_priv = (uint64_t)(uintptr_t)priv; 558eda14cbcSMatt Macy nvl->nvl_flag = 0; 559eda14cbcSMatt Macy nvl->nvl_pad = 0; 560eda14cbcSMatt Macy } 561eda14cbcSMatt Macy 562eda14cbcSMatt Macy uint_t 563eda14cbcSMatt Macy nvlist_nvflag(nvlist_t *nvl) 564eda14cbcSMatt Macy { 565eda14cbcSMatt Macy return (nvl->nvl_nvflag); 566eda14cbcSMatt Macy } 567eda14cbcSMatt Macy 568eda14cbcSMatt Macy static nv_alloc_t * 569eda14cbcSMatt Macy nvlist_nv_alloc(int kmflag) 570eda14cbcSMatt Macy { 571eda14cbcSMatt Macy #if defined(_KERNEL) 572eda14cbcSMatt Macy switch (kmflag) { 573eda14cbcSMatt Macy case KM_SLEEP: 574eda14cbcSMatt Macy return (nv_alloc_sleep); 575eda14cbcSMatt Macy case KM_NOSLEEP: 576eda14cbcSMatt Macy return (nv_alloc_nosleep); 577eda14cbcSMatt Macy default: 578eda14cbcSMatt Macy return (nv_alloc_pushpage); 579eda14cbcSMatt Macy } 580eda14cbcSMatt Macy #else 581e92ffd9bSMartin Matuska (void) kmflag; 582eda14cbcSMatt Macy return (nv_alloc_nosleep); 583eda14cbcSMatt Macy #endif /* _KERNEL */ 584eda14cbcSMatt Macy } 585eda14cbcSMatt Macy 586eda14cbcSMatt Macy /* 587eda14cbcSMatt Macy * nvlist_alloc - Allocate nvlist. 588eda14cbcSMatt Macy */ 589eda14cbcSMatt Macy int 590eda14cbcSMatt Macy nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag) 591eda14cbcSMatt Macy { 592eda14cbcSMatt Macy return (nvlist_xalloc(nvlp, nvflag, nvlist_nv_alloc(kmflag))); 593eda14cbcSMatt Macy } 594eda14cbcSMatt Macy 595eda14cbcSMatt Macy int 596eda14cbcSMatt Macy nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva) 597eda14cbcSMatt Macy { 598eda14cbcSMatt Macy nvpriv_t *priv; 599eda14cbcSMatt Macy 600eda14cbcSMatt Macy if (nvlp == NULL || nva == NULL) 601eda14cbcSMatt Macy return (EINVAL); 602eda14cbcSMatt Macy 603eda14cbcSMatt Macy if ((priv = nv_priv_alloc(nva)) == NULL) 604eda14cbcSMatt Macy return (ENOMEM); 605eda14cbcSMatt Macy 606eda14cbcSMatt Macy if ((*nvlp = nv_mem_zalloc(priv, 607eda14cbcSMatt Macy NV_ALIGN(sizeof (nvlist_t)))) == NULL) { 608eda14cbcSMatt Macy nv_mem_free(priv, priv, sizeof (nvpriv_t)); 609eda14cbcSMatt Macy return (ENOMEM); 610eda14cbcSMatt Macy } 611eda14cbcSMatt Macy 612eda14cbcSMatt Macy nvlist_init(*nvlp, nvflag, priv); 613eda14cbcSMatt Macy 614eda14cbcSMatt Macy return (0); 615eda14cbcSMatt Macy } 616eda14cbcSMatt Macy 617eda14cbcSMatt Macy /* 618eda14cbcSMatt Macy * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair. 619eda14cbcSMatt Macy */ 620eda14cbcSMatt Macy static nvpair_t * 621eda14cbcSMatt Macy nvp_buf_alloc(nvlist_t *nvl, size_t len) 622eda14cbcSMatt Macy { 623eda14cbcSMatt Macy nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 624eda14cbcSMatt Macy i_nvp_t *buf; 625eda14cbcSMatt Macy nvpair_t *nvp; 626eda14cbcSMatt Macy size_t nvsize; 627eda14cbcSMatt Macy 628eda14cbcSMatt Macy /* 629eda14cbcSMatt Macy * Allocate the buffer 630eda14cbcSMatt Macy */ 631eda14cbcSMatt Macy nvsize = len + offsetof(i_nvp_t, nvi_nvp); 632eda14cbcSMatt Macy 633eda14cbcSMatt Macy if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL) 634eda14cbcSMatt Macy return (NULL); 635eda14cbcSMatt Macy 636eda14cbcSMatt Macy nvp = &buf->nvi_nvp; 637eda14cbcSMatt Macy nvp->nvp_size = len; 638eda14cbcSMatt Macy 639eda14cbcSMatt Macy return (nvp); 640eda14cbcSMatt Macy } 641eda14cbcSMatt Macy 642eda14cbcSMatt Macy /* 643eda14cbcSMatt Macy * nvp_buf_free - de-Allocate an i_nvp_t. 644eda14cbcSMatt Macy */ 645eda14cbcSMatt Macy static void 646eda14cbcSMatt Macy nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp) 647eda14cbcSMatt Macy { 648eda14cbcSMatt Macy nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 649eda14cbcSMatt Macy size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp); 650eda14cbcSMatt Macy 651eda14cbcSMatt Macy nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize); 652eda14cbcSMatt Macy } 653eda14cbcSMatt Macy 654eda14cbcSMatt Macy /* 655eda14cbcSMatt Macy * nvp_buf_link - link a new nv pair into the nvlist. 656eda14cbcSMatt Macy */ 657eda14cbcSMatt Macy static void 658eda14cbcSMatt Macy nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp) 659eda14cbcSMatt Macy { 660eda14cbcSMatt Macy nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 661eda14cbcSMatt Macy i_nvp_t *curr = NVPAIR2I_NVP(nvp); 662eda14cbcSMatt Macy 663eda14cbcSMatt Macy /* Put element at end of nvlist */ 664eda14cbcSMatt Macy if (priv->nvp_list == NULL) { 665eda14cbcSMatt Macy priv->nvp_list = priv->nvp_last = curr; 666eda14cbcSMatt Macy } else { 667eda14cbcSMatt Macy curr->nvi_prev = priv->nvp_last; 668eda14cbcSMatt Macy priv->nvp_last->nvi_next = curr; 669eda14cbcSMatt Macy priv->nvp_last = curr; 670eda14cbcSMatt Macy } 671eda14cbcSMatt Macy } 672eda14cbcSMatt Macy 673eda14cbcSMatt Macy /* 674eda14cbcSMatt Macy * nvp_buf_unlink - unlink an removed nvpair out of the nvlist. 675eda14cbcSMatt Macy */ 676eda14cbcSMatt Macy static void 677eda14cbcSMatt Macy nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp) 678eda14cbcSMatt Macy { 679eda14cbcSMatt Macy nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 680eda14cbcSMatt Macy i_nvp_t *curr = NVPAIR2I_NVP(nvp); 681eda14cbcSMatt Macy 682eda14cbcSMatt Macy /* 683eda14cbcSMatt Macy * protect nvlist_next_nvpair() against walking on freed memory. 684eda14cbcSMatt Macy */ 685eda14cbcSMatt Macy if (priv->nvp_curr == curr) 686eda14cbcSMatt Macy priv->nvp_curr = curr->nvi_next; 687eda14cbcSMatt Macy 688eda14cbcSMatt Macy if (curr == priv->nvp_list) 689eda14cbcSMatt Macy priv->nvp_list = curr->nvi_next; 690eda14cbcSMatt Macy else 691eda14cbcSMatt Macy curr->nvi_prev->nvi_next = curr->nvi_next; 692eda14cbcSMatt Macy 693eda14cbcSMatt Macy if (curr == priv->nvp_last) 694eda14cbcSMatt Macy priv->nvp_last = curr->nvi_prev; 695eda14cbcSMatt Macy else 696eda14cbcSMatt Macy curr->nvi_next->nvi_prev = curr->nvi_prev; 697eda14cbcSMatt Macy } 698eda14cbcSMatt Macy 699eda14cbcSMatt Macy /* 700eda14cbcSMatt Macy * take a nvpair type and number of elements and make sure the are valid 701eda14cbcSMatt Macy */ 702eda14cbcSMatt Macy static int 703eda14cbcSMatt Macy i_validate_type_nelem(data_type_t type, uint_t nelem) 704eda14cbcSMatt Macy { 705eda14cbcSMatt Macy switch (type) { 706eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN: 707eda14cbcSMatt Macy if (nelem != 0) 708eda14cbcSMatt Macy return (EINVAL); 709eda14cbcSMatt Macy break; 710eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_VALUE: 711eda14cbcSMatt Macy case DATA_TYPE_BYTE: 712eda14cbcSMatt Macy case DATA_TYPE_INT8: 713eda14cbcSMatt Macy case DATA_TYPE_UINT8: 714eda14cbcSMatt Macy case DATA_TYPE_INT16: 715eda14cbcSMatt Macy case DATA_TYPE_UINT16: 716eda14cbcSMatt Macy case DATA_TYPE_INT32: 717eda14cbcSMatt Macy case DATA_TYPE_UINT32: 718eda14cbcSMatt Macy case DATA_TYPE_INT64: 719eda14cbcSMatt Macy case DATA_TYPE_UINT64: 720eda14cbcSMatt Macy case DATA_TYPE_STRING: 721eda14cbcSMatt Macy case DATA_TYPE_HRTIME: 722eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 723eda14cbcSMatt Macy #if !defined(_KERNEL) 724eda14cbcSMatt Macy case DATA_TYPE_DOUBLE: 725eda14cbcSMatt Macy #endif 726eda14cbcSMatt Macy if (nelem != 1) 727eda14cbcSMatt Macy return (EINVAL); 728eda14cbcSMatt Macy break; 729eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_ARRAY: 730eda14cbcSMatt Macy case DATA_TYPE_BYTE_ARRAY: 731eda14cbcSMatt Macy case DATA_TYPE_INT8_ARRAY: 732eda14cbcSMatt Macy case DATA_TYPE_UINT8_ARRAY: 733eda14cbcSMatt Macy case DATA_TYPE_INT16_ARRAY: 734eda14cbcSMatt Macy case DATA_TYPE_UINT16_ARRAY: 735eda14cbcSMatt Macy case DATA_TYPE_INT32_ARRAY: 736eda14cbcSMatt Macy case DATA_TYPE_UINT32_ARRAY: 737eda14cbcSMatt Macy case DATA_TYPE_INT64_ARRAY: 738eda14cbcSMatt Macy case DATA_TYPE_UINT64_ARRAY: 739eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: 740eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: 741eda14cbcSMatt Macy /* we allow arrays with 0 elements */ 742eda14cbcSMatt Macy break; 743eda14cbcSMatt Macy default: 744eda14cbcSMatt Macy return (EINVAL); 745eda14cbcSMatt Macy } 746eda14cbcSMatt Macy return (0); 747eda14cbcSMatt Macy } 748eda14cbcSMatt Macy 749eda14cbcSMatt Macy /* 750eda14cbcSMatt Macy * Verify nvp_name_sz and check the name string length. 751eda14cbcSMatt Macy */ 752eda14cbcSMatt Macy static int 753eda14cbcSMatt Macy i_validate_nvpair_name(nvpair_t *nvp) 754eda14cbcSMatt Macy { 755eda14cbcSMatt Macy if ((nvp->nvp_name_sz <= 0) || 756eda14cbcSMatt Macy (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0))) 757eda14cbcSMatt Macy return (EFAULT); 758eda14cbcSMatt Macy 759eda14cbcSMatt Macy /* verify the name string, make sure its terminated */ 760eda14cbcSMatt Macy if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0') 761eda14cbcSMatt Macy return (EFAULT); 762eda14cbcSMatt Macy 763eda14cbcSMatt Macy return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT); 764eda14cbcSMatt Macy } 765eda14cbcSMatt Macy 766eda14cbcSMatt Macy static int 767eda14cbcSMatt Macy i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data) 768eda14cbcSMatt Macy { 769eda14cbcSMatt Macy switch (type) { 770eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_VALUE: 771eda14cbcSMatt Macy if (*(boolean_t *)data != B_TRUE && 772eda14cbcSMatt Macy *(boolean_t *)data != B_FALSE) 773eda14cbcSMatt Macy return (EINVAL); 774eda14cbcSMatt Macy break; 775eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_ARRAY: { 776eda14cbcSMatt Macy int i; 777eda14cbcSMatt Macy 778eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 779eda14cbcSMatt Macy if (((boolean_t *)data)[i] != B_TRUE && 780eda14cbcSMatt Macy ((boolean_t *)data)[i] != B_FALSE) 781eda14cbcSMatt Macy return (EINVAL); 782eda14cbcSMatt Macy break; 783eda14cbcSMatt Macy } 784eda14cbcSMatt Macy default: 785eda14cbcSMatt Macy break; 786eda14cbcSMatt Macy } 787eda14cbcSMatt Macy 788eda14cbcSMatt Macy return (0); 789eda14cbcSMatt Macy } 790eda14cbcSMatt Macy 791eda14cbcSMatt Macy /* 792eda14cbcSMatt Macy * This function takes a pointer to what should be a nvpair and it's size 793eda14cbcSMatt Macy * and then verifies that all the nvpair fields make sense and can be 794eda14cbcSMatt Macy * trusted. This function is used when decoding packed nvpairs. 795eda14cbcSMatt Macy */ 796eda14cbcSMatt Macy static int 797eda14cbcSMatt Macy i_validate_nvpair(nvpair_t *nvp) 798eda14cbcSMatt Macy { 799eda14cbcSMatt Macy data_type_t type = NVP_TYPE(nvp); 800eda14cbcSMatt Macy int size1, size2; 801eda14cbcSMatt Macy 802eda14cbcSMatt Macy /* verify nvp_name_sz, check the name string length */ 803eda14cbcSMatt Macy if (i_validate_nvpair_name(nvp) != 0) 804eda14cbcSMatt Macy return (EFAULT); 805eda14cbcSMatt Macy 806eda14cbcSMatt Macy if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0) 807eda14cbcSMatt Macy return (EFAULT); 808eda14cbcSMatt Macy 809eda14cbcSMatt Macy /* 810eda14cbcSMatt Macy * verify nvp_type, nvp_value_elem, and also possibly 811eda14cbcSMatt Macy * verify string values and get the value size. 812eda14cbcSMatt Macy */ 813eda14cbcSMatt Macy size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp)); 814eda14cbcSMatt Macy size1 = nvp->nvp_size - NVP_VALOFF(nvp); 815eda14cbcSMatt Macy if (size2 < 0 || size1 != NV_ALIGN(size2)) 816eda14cbcSMatt Macy return (EFAULT); 817eda14cbcSMatt Macy 818eda14cbcSMatt Macy return (0); 819eda14cbcSMatt Macy } 820eda14cbcSMatt Macy 821eda14cbcSMatt Macy static int 822681ce946SMartin Matuska nvlist_copy_pairs(const nvlist_t *snvl, nvlist_t *dnvl) 823eda14cbcSMatt Macy { 824681ce946SMartin Matuska const nvpriv_t *priv; 825681ce946SMartin Matuska const i_nvp_t *curr; 826eda14cbcSMatt Macy 827681ce946SMartin Matuska if ((priv = (const nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL) 828eda14cbcSMatt Macy return (EINVAL); 829eda14cbcSMatt Macy 830eda14cbcSMatt Macy for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 831681ce946SMartin Matuska const nvpair_t *nvp = &curr->nvi_nvp; 832eda14cbcSMatt Macy int err; 833eda14cbcSMatt Macy 834eda14cbcSMatt Macy if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp), 835eda14cbcSMatt Macy NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0) 836eda14cbcSMatt Macy return (err); 837eda14cbcSMatt Macy } 838eda14cbcSMatt Macy 839eda14cbcSMatt Macy return (0); 840eda14cbcSMatt Macy } 841eda14cbcSMatt Macy 842eda14cbcSMatt Macy /* 843eda14cbcSMatt Macy * Frees all memory allocated for an nvpair (like embedded lists) with 844eda14cbcSMatt Macy * the exception of the nvpair buffer itself. 845eda14cbcSMatt Macy */ 846eda14cbcSMatt Macy static void 847eda14cbcSMatt Macy nvpair_free(nvpair_t *nvp) 848eda14cbcSMatt Macy { 849eda14cbcSMatt Macy switch (NVP_TYPE(nvp)) { 850eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 851eda14cbcSMatt Macy nvlist_free(EMBEDDED_NVL(nvp)); 852eda14cbcSMatt Macy break; 853eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: { 854eda14cbcSMatt Macy nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 855eda14cbcSMatt Macy int i; 856eda14cbcSMatt Macy 857eda14cbcSMatt Macy for (i = 0; i < NVP_NELEM(nvp); i++) 858eda14cbcSMatt Macy if (nvlp[i] != NULL) 859eda14cbcSMatt Macy nvlist_free(nvlp[i]); 860eda14cbcSMatt Macy break; 861eda14cbcSMatt Macy } 862eda14cbcSMatt Macy default: 863eda14cbcSMatt Macy break; 864eda14cbcSMatt Macy } 865eda14cbcSMatt Macy } 866eda14cbcSMatt Macy 867eda14cbcSMatt Macy /* 868eda14cbcSMatt Macy * nvlist_free - free an unpacked nvlist 869eda14cbcSMatt Macy */ 870eda14cbcSMatt Macy void 871eda14cbcSMatt Macy nvlist_free(nvlist_t *nvl) 872eda14cbcSMatt Macy { 873eda14cbcSMatt Macy nvpriv_t *priv; 874eda14cbcSMatt Macy i_nvp_t *curr; 875eda14cbcSMatt Macy 876eda14cbcSMatt Macy if (nvl == NULL || 877eda14cbcSMatt Macy (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 878eda14cbcSMatt Macy return; 879eda14cbcSMatt Macy 880eda14cbcSMatt Macy /* 881eda14cbcSMatt Macy * Unpacked nvlist are linked through i_nvp_t 882eda14cbcSMatt Macy */ 883eda14cbcSMatt Macy curr = priv->nvp_list; 884eda14cbcSMatt Macy while (curr != NULL) { 885eda14cbcSMatt Macy nvpair_t *nvp = &curr->nvi_nvp; 886eda14cbcSMatt Macy curr = curr->nvi_next; 887eda14cbcSMatt Macy 888eda14cbcSMatt Macy nvpair_free(nvp); 889eda14cbcSMatt Macy nvp_buf_free(nvl, nvp); 890eda14cbcSMatt Macy } 891eda14cbcSMatt Macy 892eda14cbcSMatt Macy if (!(priv->nvp_stat & NV_STAT_EMBEDDED)) 893eda14cbcSMatt Macy nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t))); 894eda14cbcSMatt Macy else 895eda14cbcSMatt Macy nvl->nvl_priv = 0; 896eda14cbcSMatt Macy 897eda14cbcSMatt Macy nvt_tab_free(priv); 898eda14cbcSMatt Macy nv_mem_free(priv, priv, sizeof (nvpriv_t)); 899eda14cbcSMatt Macy } 900eda14cbcSMatt Macy 901eda14cbcSMatt Macy static int 902681ce946SMartin Matuska nvlist_contains_nvp(const nvlist_t *nvl, const nvpair_t *nvp) 903eda14cbcSMatt Macy { 904681ce946SMartin Matuska const nvpriv_t *priv = (const nvpriv_t *)(uintptr_t)nvl->nvl_priv; 905681ce946SMartin Matuska const i_nvp_t *curr; 906eda14cbcSMatt Macy 907eda14cbcSMatt Macy if (nvp == NULL) 908eda14cbcSMatt Macy return (0); 909eda14cbcSMatt Macy 910eda14cbcSMatt Macy for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 911eda14cbcSMatt Macy if (&curr->nvi_nvp == nvp) 912eda14cbcSMatt Macy return (1); 913eda14cbcSMatt Macy 914eda14cbcSMatt Macy return (0); 915eda14cbcSMatt Macy } 916eda14cbcSMatt Macy 917eda14cbcSMatt Macy /* 918eda14cbcSMatt Macy * Make a copy of nvlist 919eda14cbcSMatt Macy */ 920eda14cbcSMatt Macy int 921681ce946SMartin Matuska nvlist_dup(const nvlist_t *nvl, nvlist_t **nvlp, int kmflag) 922eda14cbcSMatt Macy { 923eda14cbcSMatt Macy return (nvlist_xdup(nvl, nvlp, nvlist_nv_alloc(kmflag))); 924eda14cbcSMatt Macy } 925eda14cbcSMatt Macy 926eda14cbcSMatt Macy int 927681ce946SMartin Matuska nvlist_xdup(const nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva) 928eda14cbcSMatt Macy { 929eda14cbcSMatt Macy int err; 930eda14cbcSMatt Macy nvlist_t *ret; 931eda14cbcSMatt Macy 932eda14cbcSMatt Macy if (nvl == NULL || nvlp == NULL) 933eda14cbcSMatt Macy return (EINVAL); 934eda14cbcSMatt Macy 935eda14cbcSMatt Macy if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0) 936eda14cbcSMatt Macy return (err); 937eda14cbcSMatt Macy 938eda14cbcSMatt Macy if ((err = nvlist_copy_pairs(nvl, ret)) != 0) 939eda14cbcSMatt Macy nvlist_free(ret); 940eda14cbcSMatt Macy else 941eda14cbcSMatt Macy *nvlp = ret; 942eda14cbcSMatt Macy 943eda14cbcSMatt Macy return (err); 944eda14cbcSMatt Macy } 945eda14cbcSMatt Macy 946eda14cbcSMatt Macy /* 947eda14cbcSMatt Macy * Remove all with matching name 948eda14cbcSMatt Macy */ 949eda14cbcSMatt Macy int 950eda14cbcSMatt Macy nvlist_remove_all(nvlist_t *nvl, const char *name) 951eda14cbcSMatt Macy { 952eda14cbcSMatt Macy int error = ENOENT; 953eda14cbcSMatt Macy 954eda14cbcSMatt Macy if (nvl == NULL || name == NULL || nvl->nvl_priv == 0) 955eda14cbcSMatt Macy return (EINVAL); 956eda14cbcSMatt Macy 957eda14cbcSMatt Macy nvpair_t *nvp; 958eda14cbcSMatt Macy while ((nvp = nvt_lookup_name(nvl, name)) != NULL) { 959eda14cbcSMatt Macy VERIFY0(nvlist_remove_nvpair(nvl, nvp)); 960eda14cbcSMatt Macy error = 0; 961eda14cbcSMatt Macy } 962eda14cbcSMatt Macy 963eda14cbcSMatt Macy return (error); 964eda14cbcSMatt Macy } 965eda14cbcSMatt Macy 966eda14cbcSMatt Macy /* 967eda14cbcSMatt Macy * Remove first one with matching name and type 968eda14cbcSMatt Macy */ 969eda14cbcSMatt Macy int 970eda14cbcSMatt Macy nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) 971eda14cbcSMatt Macy { 972eda14cbcSMatt Macy if (nvl == NULL || name == NULL || nvl->nvl_priv == 0) 973eda14cbcSMatt Macy return (EINVAL); 974eda14cbcSMatt Macy 975eda14cbcSMatt Macy nvpair_t *nvp = nvt_lookup_name_type(nvl, name, type); 976eda14cbcSMatt Macy if (nvp == NULL) 977eda14cbcSMatt Macy return (ENOENT); 978eda14cbcSMatt Macy 979eda14cbcSMatt Macy return (nvlist_remove_nvpair(nvl, nvp)); 980eda14cbcSMatt Macy } 981eda14cbcSMatt Macy 982eda14cbcSMatt Macy int 983eda14cbcSMatt Macy nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 984eda14cbcSMatt Macy { 985eda14cbcSMatt Macy if (nvl == NULL || nvp == NULL) 986eda14cbcSMatt Macy return (EINVAL); 987eda14cbcSMatt Macy 988eda14cbcSMatt Macy int err = nvt_remove_nvpair(nvl, nvp); 989eda14cbcSMatt Macy if (err != 0) 990eda14cbcSMatt Macy return (err); 991eda14cbcSMatt Macy 992eda14cbcSMatt Macy nvp_buf_unlink(nvl, nvp); 993eda14cbcSMatt Macy nvpair_free(nvp); 994eda14cbcSMatt Macy nvp_buf_free(nvl, nvp); 995eda14cbcSMatt Macy return (0); 996eda14cbcSMatt Macy } 997eda14cbcSMatt Macy 998eda14cbcSMatt Macy /* 999eda14cbcSMatt Macy * This function calculates the size of an nvpair value. 1000eda14cbcSMatt Macy * 1001eda14cbcSMatt Macy * The data argument controls the behavior in case of the data types 1002eda14cbcSMatt Macy * DATA_TYPE_STRING and 1003eda14cbcSMatt Macy * DATA_TYPE_STRING_ARRAY 1004eda14cbcSMatt Macy * Is data == NULL then the size of the string(s) is excluded. 1005eda14cbcSMatt Macy */ 1006eda14cbcSMatt Macy static int 1007eda14cbcSMatt Macy i_get_value_size(data_type_t type, const void *data, uint_t nelem) 1008eda14cbcSMatt Macy { 1009eda14cbcSMatt Macy uint64_t value_sz; 1010eda14cbcSMatt Macy 1011eda14cbcSMatt Macy if (i_validate_type_nelem(type, nelem) != 0) 1012eda14cbcSMatt Macy return (-1); 1013eda14cbcSMatt Macy 1014eda14cbcSMatt Macy /* Calculate required size for holding value */ 1015eda14cbcSMatt Macy switch (type) { 1016eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN: 1017eda14cbcSMatt Macy value_sz = 0; 1018eda14cbcSMatt Macy break; 1019eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_VALUE: 1020eda14cbcSMatt Macy value_sz = sizeof (boolean_t); 1021eda14cbcSMatt Macy break; 1022eda14cbcSMatt Macy case DATA_TYPE_BYTE: 1023eda14cbcSMatt Macy value_sz = sizeof (uchar_t); 1024eda14cbcSMatt Macy break; 1025eda14cbcSMatt Macy case DATA_TYPE_INT8: 1026eda14cbcSMatt Macy value_sz = sizeof (int8_t); 1027eda14cbcSMatt Macy break; 1028eda14cbcSMatt Macy case DATA_TYPE_UINT8: 1029eda14cbcSMatt Macy value_sz = sizeof (uint8_t); 1030eda14cbcSMatt Macy break; 1031eda14cbcSMatt Macy case DATA_TYPE_INT16: 1032eda14cbcSMatt Macy value_sz = sizeof (int16_t); 1033eda14cbcSMatt Macy break; 1034eda14cbcSMatt Macy case DATA_TYPE_UINT16: 1035eda14cbcSMatt Macy value_sz = sizeof (uint16_t); 1036eda14cbcSMatt Macy break; 1037eda14cbcSMatt Macy case DATA_TYPE_INT32: 1038eda14cbcSMatt Macy value_sz = sizeof (int32_t); 1039eda14cbcSMatt Macy break; 1040eda14cbcSMatt Macy case DATA_TYPE_UINT32: 1041eda14cbcSMatt Macy value_sz = sizeof (uint32_t); 1042eda14cbcSMatt Macy break; 1043eda14cbcSMatt Macy case DATA_TYPE_INT64: 1044eda14cbcSMatt Macy value_sz = sizeof (int64_t); 1045eda14cbcSMatt Macy break; 1046eda14cbcSMatt Macy case DATA_TYPE_UINT64: 1047eda14cbcSMatt Macy value_sz = sizeof (uint64_t); 1048eda14cbcSMatt Macy break; 1049eda14cbcSMatt Macy #if !defined(_KERNEL) 1050eda14cbcSMatt Macy case DATA_TYPE_DOUBLE: 1051eda14cbcSMatt Macy value_sz = sizeof (double); 1052eda14cbcSMatt Macy break; 1053eda14cbcSMatt Macy #endif 1054eda14cbcSMatt Macy case DATA_TYPE_STRING: 1055eda14cbcSMatt Macy if (data == NULL) 1056eda14cbcSMatt Macy value_sz = 0; 1057eda14cbcSMatt Macy else 1058eda14cbcSMatt Macy value_sz = strlen(data) + 1; 1059eda14cbcSMatt Macy break; 1060eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_ARRAY: 1061eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (boolean_t); 1062eda14cbcSMatt Macy break; 1063eda14cbcSMatt Macy case DATA_TYPE_BYTE_ARRAY: 1064eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (uchar_t); 1065eda14cbcSMatt Macy break; 1066eda14cbcSMatt Macy case DATA_TYPE_INT8_ARRAY: 1067eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (int8_t); 1068eda14cbcSMatt Macy break; 1069eda14cbcSMatt Macy case DATA_TYPE_UINT8_ARRAY: 1070eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (uint8_t); 1071eda14cbcSMatt Macy break; 1072eda14cbcSMatt Macy case DATA_TYPE_INT16_ARRAY: 1073eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (int16_t); 1074eda14cbcSMatt Macy break; 1075eda14cbcSMatt Macy case DATA_TYPE_UINT16_ARRAY: 1076eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (uint16_t); 1077eda14cbcSMatt Macy break; 1078eda14cbcSMatt Macy case DATA_TYPE_INT32_ARRAY: 1079eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (int32_t); 1080eda14cbcSMatt Macy break; 1081eda14cbcSMatt Macy case DATA_TYPE_UINT32_ARRAY: 1082eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (uint32_t); 1083eda14cbcSMatt Macy break; 1084eda14cbcSMatt Macy case DATA_TYPE_INT64_ARRAY: 1085eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (int64_t); 1086eda14cbcSMatt Macy break; 1087eda14cbcSMatt Macy case DATA_TYPE_UINT64_ARRAY: 1088eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (uint64_t); 1089eda14cbcSMatt Macy break; 1090eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: 1091eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (uint64_t); 1092eda14cbcSMatt Macy 1093eda14cbcSMatt Macy if (data != NULL) { 1094eda14cbcSMatt Macy char *const *strs = data; 1095eda14cbcSMatt Macy uint_t i; 1096eda14cbcSMatt Macy 1097eda14cbcSMatt Macy /* no alignment requirement for strings */ 1098eda14cbcSMatt Macy for (i = 0; i < nelem; i++) { 1099eda14cbcSMatt Macy if (strs[i] == NULL) 1100eda14cbcSMatt Macy return (-1); 1101eda14cbcSMatt Macy value_sz += strlen(strs[i]) + 1; 1102eda14cbcSMatt Macy } 1103eda14cbcSMatt Macy } 1104eda14cbcSMatt Macy break; 1105eda14cbcSMatt Macy case DATA_TYPE_HRTIME: 1106eda14cbcSMatt Macy value_sz = sizeof (hrtime_t); 1107eda14cbcSMatt Macy break; 1108eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 1109eda14cbcSMatt Macy value_sz = NV_ALIGN(sizeof (nvlist_t)); 1110eda14cbcSMatt Macy break; 1111eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: 1112eda14cbcSMatt Macy value_sz = (uint64_t)nelem * sizeof (uint64_t) + 1113eda14cbcSMatt Macy (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t)); 1114eda14cbcSMatt Macy break; 1115eda14cbcSMatt Macy default: 1116eda14cbcSMatt Macy return (-1); 1117eda14cbcSMatt Macy } 1118eda14cbcSMatt Macy 1119eda14cbcSMatt Macy return (value_sz > INT32_MAX ? -1 : (int)value_sz); 1120eda14cbcSMatt Macy } 1121eda14cbcSMatt Macy 1122eda14cbcSMatt Macy static int 1123eda14cbcSMatt Macy nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl) 1124eda14cbcSMatt Macy { 1125eda14cbcSMatt Macy nvpriv_t *priv; 1126eda14cbcSMatt Macy int err; 1127eda14cbcSMatt Macy 1128eda14cbcSMatt Macy if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t) 1129eda14cbcSMatt Macy nvl->nvl_priv)) == NULL) 1130eda14cbcSMatt Macy return (ENOMEM); 1131eda14cbcSMatt Macy 1132eda14cbcSMatt Macy nvlist_init(emb_nvl, onvl->nvl_nvflag, priv); 1133eda14cbcSMatt Macy 1134eda14cbcSMatt Macy if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) { 1135eda14cbcSMatt Macy nvlist_free(emb_nvl); 1136eda14cbcSMatt Macy emb_nvl->nvl_priv = 0; 1137eda14cbcSMatt Macy } 1138eda14cbcSMatt Macy 1139eda14cbcSMatt Macy return (err); 1140eda14cbcSMatt Macy } 1141eda14cbcSMatt Macy 1142eda14cbcSMatt Macy /* 1143eda14cbcSMatt Macy * nvlist_add_common - Add new <name,value> pair to nvlist 1144eda14cbcSMatt Macy */ 1145eda14cbcSMatt Macy static int 1146eda14cbcSMatt Macy nvlist_add_common(nvlist_t *nvl, const char *name, 1147eda14cbcSMatt Macy data_type_t type, uint_t nelem, const void *data) 1148eda14cbcSMatt Macy { 1149eda14cbcSMatt Macy nvpair_t *nvp; 1150eda14cbcSMatt Macy uint_t i; 1151eda14cbcSMatt Macy 1152eda14cbcSMatt Macy int nvp_sz, name_sz, value_sz; 1153eda14cbcSMatt Macy int err = 0; 1154eda14cbcSMatt Macy 1155eda14cbcSMatt Macy if (name == NULL || nvl == NULL || nvl->nvl_priv == 0) 1156eda14cbcSMatt Macy return (EINVAL); 1157eda14cbcSMatt Macy 1158eda14cbcSMatt Macy if (nelem != 0 && data == NULL) 1159eda14cbcSMatt Macy return (EINVAL); 1160eda14cbcSMatt Macy 1161eda14cbcSMatt Macy /* 1162eda14cbcSMatt Macy * Verify type and nelem and get the value size. 1163eda14cbcSMatt Macy * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 1164eda14cbcSMatt Macy * is the size of the string(s) included. 1165eda14cbcSMatt Macy */ 1166eda14cbcSMatt Macy if ((value_sz = i_get_value_size(type, data, nelem)) < 0) 1167eda14cbcSMatt Macy return (EINVAL); 1168eda14cbcSMatt Macy 1169eda14cbcSMatt Macy if (i_validate_nvpair_value(type, nelem, data) != 0) 1170eda14cbcSMatt Macy return (EINVAL); 1171eda14cbcSMatt Macy 1172eda14cbcSMatt Macy /* 1173eda14cbcSMatt Macy * If we're adding an nvlist or nvlist array, ensure that we are not 1174eda14cbcSMatt Macy * adding the input nvlist to itself, which would cause recursion, 1175eda14cbcSMatt Macy * and ensure that no NULL nvlist pointers are present. 1176eda14cbcSMatt Macy */ 1177eda14cbcSMatt Macy switch (type) { 1178eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 1179eda14cbcSMatt Macy if (data == nvl || data == NULL) 1180eda14cbcSMatt Macy return (EINVAL); 1181eda14cbcSMatt Macy break; 1182eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: { 1183eda14cbcSMatt Macy nvlist_t **onvlp = (nvlist_t **)data; 1184eda14cbcSMatt Macy for (i = 0; i < nelem; i++) { 1185eda14cbcSMatt Macy if (onvlp[i] == nvl || onvlp[i] == NULL) 1186eda14cbcSMatt Macy return (EINVAL); 1187eda14cbcSMatt Macy } 1188eda14cbcSMatt Macy break; 1189eda14cbcSMatt Macy } 1190eda14cbcSMatt Macy default: 1191eda14cbcSMatt Macy break; 1192eda14cbcSMatt Macy } 1193eda14cbcSMatt Macy 1194eda14cbcSMatt Macy /* calculate sizes of the nvpair elements and the nvpair itself */ 1195eda14cbcSMatt Macy name_sz = strlen(name) + 1; 1196eda14cbcSMatt Macy if (name_sz >= 1ULL << (sizeof (nvp->nvp_name_sz) * NBBY - 1)) 1197eda14cbcSMatt Macy return (EINVAL); 1198eda14cbcSMatt Macy 1199eda14cbcSMatt Macy nvp_sz = NVP_SIZE_CALC(name_sz, value_sz); 1200eda14cbcSMatt Macy 1201eda14cbcSMatt Macy if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL) 1202eda14cbcSMatt Macy return (ENOMEM); 1203eda14cbcSMatt Macy 1204eda14cbcSMatt Macy ASSERT(nvp->nvp_size == nvp_sz); 1205eda14cbcSMatt Macy nvp->nvp_name_sz = name_sz; 1206eda14cbcSMatt Macy nvp->nvp_value_elem = nelem; 1207eda14cbcSMatt Macy nvp->nvp_type = type; 1208da5137abSMartin Matuska memcpy(NVP_NAME(nvp), name, name_sz); 1209eda14cbcSMatt Macy 1210eda14cbcSMatt Macy switch (type) { 1211eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN: 1212eda14cbcSMatt Macy break; 1213eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: { 1214eda14cbcSMatt Macy char *const *strs = data; 1215eda14cbcSMatt Macy char *buf = NVP_VALUE(nvp); 1216eda14cbcSMatt Macy char **cstrs = (void *)buf; 1217eda14cbcSMatt Macy 1218eda14cbcSMatt Macy /* skip pre-allocated space for pointer array */ 1219eda14cbcSMatt Macy buf += nelem * sizeof (uint64_t); 1220eda14cbcSMatt Macy for (i = 0; i < nelem; i++) { 1221eda14cbcSMatt Macy int slen = strlen(strs[i]) + 1; 1222da5137abSMartin Matuska memcpy(buf, strs[i], slen); 1223eda14cbcSMatt Macy cstrs[i] = buf; 1224eda14cbcSMatt Macy buf += slen; 1225eda14cbcSMatt Macy } 1226eda14cbcSMatt Macy break; 1227eda14cbcSMatt Macy } 1228eda14cbcSMatt Macy case DATA_TYPE_NVLIST: { 1229eda14cbcSMatt Macy nvlist_t *nnvl = EMBEDDED_NVL(nvp); 1230eda14cbcSMatt Macy nvlist_t *onvl = (nvlist_t *)data; 1231eda14cbcSMatt Macy 1232eda14cbcSMatt Macy if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) { 1233eda14cbcSMatt Macy nvp_buf_free(nvl, nvp); 1234eda14cbcSMatt Macy return (err); 1235eda14cbcSMatt Macy } 1236eda14cbcSMatt Macy break; 1237eda14cbcSMatt Macy } 1238eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: { 1239eda14cbcSMatt Macy nvlist_t **onvlp = (nvlist_t **)data; 1240eda14cbcSMatt Macy nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 1241eda14cbcSMatt Macy nvlist_t *embedded = (nvlist_t *) 1242eda14cbcSMatt Macy ((uintptr_t)nvlp + nelem * sizeof (uint64_t)); 1243eda14cbcSMatt Macy 1244eda14cbcSMatt Macy for (i = 0; i < nelem; i++) { 1245eda14cbcSMatt Macy if ((err = nvlist_copy_embedded(nvl, 1246eda14cbcSMatt Macy onvlp[i], embedded)) != 0) { 1247eda14cbcSMatt Macy /* 1248eda14cbcSMatt Macy * Free any successfully created lists 1249eda14cbcSMatt Macy */ 1250eda14cbcSMatt Macy nvpair_free(nvp); 1251eda14cbcSMatt Macy nvp_buf_free(nvl, nvp); 1252eda14cbcSMatt Macy return (err); 1253eda14cbcSMatt Macy } 1254eda14cbcSMatt Macy 1255eda14cbcSMatt Macy nvlp[i] = embedded++; 1256eda14cbcSMatt Macy } 1257eda14cbcSMatt Macy break; 1258eda14cbcSMatt Macy } 1259eda14cbcSMatt Macy default: 1260da5137abSMartin Matuska memcpy(NVP_VALUE(nvp), data, value_sz); 1261eda14cbcSMatt Macy } 1262eda14cbcSMatt Macy 1263eda14cbcSMatt Macy /* if unique name, remove before add */ 1264eda14cbcSMatt Macy if (nvl->nvl_nvflag & NV_UNIQUE_NAME) 1265eda14cbcSMatt Macy (void) nvlist_remove_all(nvl, name); 1266eda14cbcSMatt Macy else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE) 1267eda14cbcSMatt Macy (void) nvlist_remove(nvl, name, type); 1268eda14cbcSMatt Macy 1269eda14cbcSMatt Macy err = nvt_add_nvpair(nvl, nvp); 1270eda14cbcSMatt Macy if (err != 0) { 1271eda14cbcSMatt Macy nvpair_free(nvp); 1272eda14cbcSMatt Macy nvp_buf_free(nvl, nvp); 1273eda14cbcSMatt Macy return (err); 1274eda14cbcSMatt Macy } 1275eda14cbcSMatt Macy nvp_buf_link(nvl, nvp); 1276eda14cbcSMatt Macy 1277eda14cbcSMatt Macy return (0); 1278eda14cbcSMatt Macy } 1279eda14cbcSMatt Macy 1280eda14cbcSMatt Macy int 1281eda14cbcSMatt Macy nvlist_add_boolean(nvlist_t *nvl, const char *name) 1282eda14cbcSMatt Macy { 1283eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL)); 1284eda14cbcSMatt Macy } 1285eda14cbcSMatt Macy 1286eda14cbcSMatt Macy int 1287eda14cbcSMatt Macy nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val) 1288eda14cbcSMatt Macy { 1289eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val)); 1290eda14cbcSMatt Macy } 1291eda14cbcSMatt Macy 1292eda14cbcSMatt Macy int 1293eda14cbcSMatt Macy nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val) 1294eda14cbcSMatt Macy { 1295eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val)); 1296eda14cbcSMatt Macy } 1297eda14cbcSMatt Macy 1298eda14cbcSMatt Macy int 1299eda14cbcSMatt Macy nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val) 1300eda14cbcSMatt Macy { 1301eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val)); 1302eda14cbcSMatt Macy } 1303eda14cbcSMatt Macy 1304eda14cbcSMatt Macy int 1305eda14cbcSMatt Macy nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val) 1306eda14cbcSMatt Macy { 1307eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val)); 1308eda14cbcSMatt Macy } 1309eda14cbcSMatt Macy 1310eda14cbcSMatt Macy int 1311eda14cbcSMatt Macy nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val) 1312eda14cbcSMatt Macy { 1313eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val)); 1314eda14cbcSMatt Macy } 1315eda14cbcSMatt Macy 1316eda14cbcSMatt Macy int 1317eda14cbcSMatt Macy nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val) 1318eda14cbcSMatt Macy { 1319eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val)); 1320eda14cbcSMatt Macy } 1321eda14cbcSMatt Macy 1322eda14cbcSMatt Macy int 1323eda14cbcSMatt Macy nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val) 1324eda14cbcSMatt Macy { 1325eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val)); 1326eda14cbcSMatt Macy } 1327eda14cbcSMatt Macy 1328eda14cbcSMatt Macy int 1329eda14cbcSMatt Macy nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val) 1330eda14cbcSMatt Macy { 1331eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val)); 1332eda14cbcSMatt Macy } 1333eda14cbcSMatt Macy 1334eda14cbcSMatt Macy int 1335eda14cbcSMatt Macy nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val) 1336eda14cbcSMatt Macy { 1337eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val)); 1338eda14cbcSMatt Macy } 1339eda14cbcSMatt Macy 1340eda14cbcSMatt Macy int 1341eda14cbcSMatt Macy nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val) 1342eda14cbcSMatt Macy { 1343eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val)); 1344eda14cbcSMatt Macy } 1345eda14cbcSMatt Macy 1346eda14cbcSMatt Macy #if !defined(_KERNEL) 1347eda14cbcSMatt Macy int 1348eda14cbcSMatt Macy nvlist_add_double(nvlist_t *nvl, const char *name, double val) 1349eda14cbcSMatt Macy { 1350eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val)); 1351eda14cbcSMatt Macy } 1352eda14cbcSMatt Macy #endif 1353eda14cbcSMatt Macy 1354eda14cbcSMatt Macy int 1355eda14cbcSMatt Macy nvlist_add_string(nvlist_t *nvl, const char *name, const char *val) 1356eda14cbcSMatt Macy { 1357eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val)); 1358eda14cbcSMatt Macy } 1359eda14cbcSMatt Macy 1360eda14cbcSMatt Macy int 1361eda14cbcSMatt Macy nvlist_add_boolean_array(nvlist_t *nvl, const char *name, 1362681ce946SMartin Matuska const boolean_t *a, uint_t n) 1363eda14cbcSMatt Macy { 1364eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1365eda14cbcSMatt Macy } 1366eda14cbcSMatt Macy 1367eda14cbcSMatt Macy int 1368681ce946SMartin Matuska nvlist_add_byte_array(nvlist_t *nvl, const char *name, const uchar_t *a, 1369681ce946SMartin Matuska uint_t n) 1370eda14cbcSMatt Macy { 1371eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1372eda14cbcSMatt Macy } 1373eda14cbcSMatt Macy 1374eda14cbcSMatt Macy int 1375681ce946SMartin Matuska nvlist_add_int8_array(nvlist_t *nvl, const char *name, const int8_t *a, 1376681ce946SMartin Matuska uint_t n) 1377eda14cbcSMatt Macy { 1378eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1379eda14cbcSMatt Macy } 1380eda14cbcSMatt Macy 1381eda14cbcSMatt Macy int 1382681ce946SMartin Matuska nvlist_add_uint8_array(nvlist_t *nvl, const char *name, const uint8_t *a, 1383681ce946SMartin Matuska uint_t n) 1384eda14cbcSMatt Macy { 1385eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1386eda14cbcSMatt Macy } 1387eda14cbcSMatt Macy 1388eda14cbcSMatt Macy int 1389681ce946SMartin Matuska nvlist_add_int16_array(nvlist_t *nvl, const char *name, const int16_t *a, 1390681ce946SMartin Matuska uint_t n) 1391eda14cbcSMatt Macy { 1392eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1393eda14cbcSMatt Macy } 1394eda14cbcSMatt Macy 1395eda14cbcSMatt Macy int 1396681ce946SMartin Matuska nvlist_add_uint16_array(nvlist_t *nvl, const char *name, const uint16_t *a, 1397681ce946SMartin Matuska uint_t n) 1398eda14cbcSMatt Macy { 1399eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1400eda14cbcSMatt Macy } 1401eda14cbcSMatt Macy 1402eda14cbcSMatt Macy int 1403681ce946SMartin Matuska nvlist_add_int32_array(nvlist_t *nvl, const char *name, const int32_t *a, 1404681ce946SMartin Matuska uint_t n) 1405eda14cbcSMatt Macy { 1406eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1407eda14cbcSMatt Macy } 1408eda14cbcSMatt Macy 1409eda14cbcSMatt Macy int 1410681ce946SMartin Matuska nvlist_add_uint32_array(nvlist_t *nvl, const char *name, const uint32_t *a, 1411681ce946SMartin Matuska uint_t n) 1412eda14cbcSMatt Macy { 1413eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1414eda14cbcSMatt Macy } 1415eda14cbcSMatt Macy 1416eda14cbcSMatt Macy int 1417681ce946SMartin Matuska nvlist_add_int64_array(nvlist_t *nvl, const char *name, const int64_t *a, 1418681ce946SMartin Matuska uint_t n) 1419eda14cbcSMatt Macy { 1420eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1421eda14cbcSMatt Macy } 1422eda14cbcSMatt Macy 1423eda14cbcSMatt Macy int 1424681ce946SMartin Matuska nvlist_add_uint64_array(nvlist_t *nvl, const char *name, const uint64_t *a, 1425681ce946SMartin Matuska uint_t n) 1426eda14cbcSMatt Macy { 1427eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1428eda14cbcSMatt Macy } 1429eda14cbcSMatt Macy 1430eda14cbcSMatt Macy int 1431eda14cbcSMatt Macy nvlist_add_string_array(nvlist_t *nvl, const char *name, 1432681ce946SMartin Matuska const char *const *a, uint_t n) 1433eda14cbcSMatt Macy { 1434eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1435eda14cbcSMatt Macy } 1436eda14cbcSMatt Macy 1437eda14cbcSMatt Macy int 1438eda14cbcSMatt Macy nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val) 1439eda14cbcSMatt Macy { 1440eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val)); 1441eda14cbcSMatt Macy } 1442eda14cbcSMatt Macy 1443eda14cbcSMatt Macy int 1444681ce946SMartin Matuska nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *val) 1445eda14cbcSMatt Macy { 1446eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); 1447eda14cbcSMatt Macy } 1448eda14cbcSMatt Macy 1449eda14cbcSMatt Macy int 1450681ce946SMartin Matuska nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, 1451681ce946SMartin Matuska const nvlist_t * const *a, uint_t n) 1452eda14cbcSMatt Macy { 1453eda14cbcSMatt Macy return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1454eda14cbcSMatt Macy } 1455eda14cbcSMatt Macy 1456eda14cbcSMatt Macy /* reading name-value pairs */ 1457eda14cbcSMatt Macy nvpair_t * 1458681ce946SMartin Matuska nvlist_next_nvpair(nvlist_t *nvl, const nvpair_t *nvp) 1459eda14cbcSMatt Macy { 1460eda14cbcSMatt Macy nvpriv_t *priv; 1461eda14cbcSMatt Macy i_nvp_t *curr; 1462eda14cbcSMatt Macy 1463eda14cbcSMatt Macy if (nvl == NULL || 1464eda14cbcSMatt Macy (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1465eda14cbcSMatt Macy return (NULL); 1466eda14cbcSMatt Macy 1467eda14cbcSMatt Macy curr = NVPAIR2I_NVP(nvp); 1468eda14cbcSMatt Macy 1469eda14cbcSMatt Macy /* 1470eda14cbcSMatt Macy * Ensure that nvp is a valid nvpair on this nvlist. 1471eda14cbcSMatt Macy * NB: nvp_curr is used only as a hint so that we don't always 1472eda14cbcSMatt Macy * have to walk the list to determine if nvp is still on the list. 1473eda14cbcSMatt Macy */ 1474eda14cbcSMatt Macy if (nvp == NULL) 1475eda14cbcSMatt Macy curr = priv->nvp_list; 1476eda14cbcSMatt Macy else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp)) 1477eda14cbcSMatt Macy curr = curr->nvi_next; 1478eda14cbcSMatt Macy else 1479eda14cbcSMatt Macy curr = NULL; 1480eda14cbcSMatt Macy 1481eda14cbcSMatt Macy priv->nvp_curr = curr; 1482eda14cbcSMatt Macy 1483eda14cbcSMatt Macy return (curr != NULL ? &curr->nvi_nvp : NULL); 1484eda14cbcSMatt Macy } 1485eda14cbcSMatt Macy 1486eda14cbcSMatt Macy nvpair_t * 1487681ce946SMartin Matuska nvlist_prev_nvpair(nvlist_t *nvl, const nvpair_t *nvp) 1488eda14cbcSMatt Macy { 1489eda14cbcSMatt Macy nvpriv_t *priv; 1490eda14cbcSMatt Macy i_nvp_t *curr; 1491eda14cbcSMatt Macy 1492eda14cbcSMatt Macy if (nvl == NULL || 1493eda14cbcSMatt Macy (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1494eda14cbcSMatt Macy return (NULL); 1495eda14cbcSMatt Macy 1496eda14cbcSMatt Macy curr = NVPAIR2I_NVP(nvp); 1497eda14cbcSMatt Macy 1498eda14cbcSMatt Macy if (nvp == NULL) 1499eda14cbcSMatt Macy curr = priv->nvp_last; 1500eda14cbcSMatt Macy else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp)) 1501eda14cbcSMatt Macy curr = curr->nvi_prev; 1502eda14cbcSMatt Macy else 1503eda14cbcSMatt Macy curr = NULL; 1504eda14cbcSMatt Macy 1505eda14cbcSMatt Macy priv->nvp_curr = curr; 1506eda14cbcSMatt Macy 1507eda14cbcSMatt Macy return (curr != NULL ? &curr->nvi_nvp : NULL); 1508eda14cbcSMatt Macy } 1509eda14cbcSMatt Macy 1510eda14cbcSMatt Macy boolean_t 1511681ce946SMartin Matuska nvlist_empty(const nvlist_t *nvl) 1512eda14cbcSMatt Macy { 1513681ce946SMartin Matuska const nvpriv_t *priv; 1514eda14cbcSMatt Macy 1515eda14cbcSMatt Macy if (nvl == NULL || 1516681ce946SMartin Matuska (priv = (const nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1517eda14cbcSMatt Macy return (B_TRUE); 1518eda14cbcSMatt Macy 1519eda14cbcSMatt Macy return (priv->nvp_list == NULL); 1520eda14cbcSMatt Macy } 1521eda14cbcSMatt Macy 15222a58b312SMartin Matuska const char * 1523681ce946SMartin Matuska nvpair_name(const nvpair_t *nvp) 1524eda14cbcSMatt Macy { 1525eda14cbcSMatt Macy return (NVP_NAME(nvp)); 1526eda14cbcSMatt Macy } 1527eda14cbcSMatt Macy 1528eda14cbcSMatt Macy data_type_t 1529681ce946SMartin Matuska nvpair_type(const nvpair_t *nvp) 1530eda14cbcSMatt Macy { 1531eda14cbcSMatt Macy return (NVP_TYPE(nvp)); 1532eda14cbcSMatt Macy } 1533eda14cbcSMatt Macy 1534eda14cbcSMatt Macy int 1535681ce946SMartin Matuska nvpair_type_is_array(const nvpair_t *nvp) 1536eda14cbcSMatt Macy { 1537eda14cbcSMatt Macy data_type_t type = NVP_TYPE(nvp); 1538eda14cbcSMatt Macy 1539eda14cbcSMatt Macy if ((type == DATA_TYPE_BYTE_ARRAY) || 1540eda14cbcSMatt Macy (type == DATA_TYPE_INT8_ARRAY) || 1541eda14cbcSMatt Macy (type == DATA_TYPE_UINT8_ARRAY) || 1542eda14cbcSMatt Macy (type == DATA_TYPE_INT16_ARRAY) || 1543eda14cbcSMatt Macy (type == DATA_TYPE_UINT16_ARRAY) || 1544eda14cbcSMatt Macy (type == DATA_TYPE_INT32_ARRAY) || 1545eda14cbcSMatt Macy (type == DATA_TYPE_UINT32_ARRAY) || 1546eda14cbcSMatt Macy (type == DATA_TYPE_INT64_ARRAY) || 1547eda14cbcSMatt Macy (type == DATA_TYPE_UINT64_ARRAY) || 1548eda14cbcSMatt Macy (type == DATA_TYPE_BOOLEAN_ARRAY) || 1549eda14cbcSMatt Macy (type == DATA_TYPE_STRING_ARRAY) || 1550eda14cbcSMatt Macy (type == DATA_TYPE_NVLIST_ARRAY)) 1551eda14cbcSMatt Macy return (1); 1552eda14cbcSMatt Macy return (0); 1553eda14cbcSMatt Macy 1554eda14cbcSMatt Macy } 1555eda14cbcSMatt Macy 1556eda14cbcSMatt Macy static int 1557681ce946SMartin Matuska nvpair_value_common(const nvpair_t *nvp, data_type_t type, uint_t *nelem, 1558681ce946SMartin Matuska void *data) 1559eda14cbcSMatt Macy { 1560eda14cbcSMatt Macy int value_sz; 1561eda14cbcSMatt Macy 1562eda14cbcSMatt Macy if (nvp == NULL || nvpair_type(nvp) != type) 1563eda14cbcSMatt Macy return (EINVAL); 1564eda14cbcSMatt Macy 1565eda14cbcSMatt Macy /* 1566eda14cbcSMatt Macy * For non-array types, we copy the data. 1567eda14cbcSMatt Macy * For array types (including string), we set a pointer. 1568eda14cbcSMatt Macy */ 1569eda14cbcSMatt Macy switch (type) { 1570eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN: 1571eda14cbcSMatt Macy if (nelem != NULL) 1572eda14cbcSMatt Macy *nelem = 0; 1573eda14cbcSMatt Macy break; 1574eda14cbcSMatt Macy 1575eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_VALUE: 1576eda14cbcSMatt Macy case DATA_TYPE_BYTE: 1577eda14cbcSMatt Macy case DATA_TYPE_INT8: 1578eda14cbcSMatt Macy case DATA_TYPE_UINT8: 1579eda14cbcSMatt Macy case DATA_TYPE_INT16: 1580eda14cbcSMatt Macy case DATA_TYPE_UINT16: 1581eda14cbcSMatt Macy case DATA_TYPE_INT32: 1582eda14cbcSMatt Macy case DATA_TYPE_UINT32: 1583eda14cbcSMatt Macy case DATA_TYPE_INT64: 1584eda14cbcSMatt Macy case DATA_TYPE_UINT64: 1585eda14cbcSMatt Macy case DATA_TYPE_HRTIME: 1586eda14cbcSMatt Macy #if !defined(_KERNEL) 1587eda14cbcSMatt Macy case DATA_TYPE_DOUBLE: 1588eda14cbcSMatt Macy #endif 1589eda14cbcSMatt Macy if (data == NULL) 1590eda14cbcSMatt Macy return (EINVAL); 1591eda14cbcSMatt Macy if ((value_sz = i_get_value_size(type, NULL, 1)) < 0) 1592eda14cbcSMatt Macy return (EINVAL); 1593da5137abSMartin Matuska memcpy(data, NVP_VALUE(nvp), (size_t)value_sz); 1594eda14cbcSMatt Macy if (nelem != NULL) 1595eda14cbcSMatt Macy *nelem = 1; 1596eda14cbcSMatt Macy break; 1597eda14cbcSMatt Macy 1598eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 1599eda14cbcSMatt Macy case DATA_TYPE_STRING: 1600eda14cbcSMatt Macy if (data == NULL) 1601eda14cbcSMatt Macy return (EINVAL); 1602681ce946SMartin Matuska /* 1603681ce946SMartin Matuska * This discards the const from nvp, so all callers for these 1604681ce946SMartin Matuska * types must not accept const nvpairs. 1605681ce946SMartin Matuska */ 1606eda14cbcSMatt Macy *(void **)data = (void *)NVP_VALUE(nvp); 1607eda14cbcSMatt Macy if (nelem != NULL) 1608eda14cbcSMatt Macy *nelem = 1; 1609eda14cbcSMatt Macy break; 1610eda14cbcSMatt Macy 1611eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_ARRAY: 1612eda14cbcSMatt Macy case DATA_TYPE_BYTE_ARRAY: 1613eda14cbcSMatt Macy case DATA_TYPE_INT8_ARRAY: 1614eda14cbcSMatt Macy case DATA_TYPE_UINT8_ARRAY: 1615eda14cbcSMatt Macy case DATA_TYPE_INT16_ARRAY: 1616eda14cbcSMatt Macy case DATA_TYPE_UINT16_ARRAY: 1617eda14cbcSMatt Macy case DATA_TYPE_INT32_ARRAY: 1618eda14cbcSMatt Macy case DATA_TYPE_UINT32_ARRAY: 1619eda14cbcSMatt Macy case DATA_TYPE_INT64_ARRAY: 1620eda14cbcSMatt Macy case DATA_TYPE_UINT64_ARRAY: 1621eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: 1622eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: 1623eda14cbcSMatt Macy if (nelem == NULL || data == NULL) 1624eda14cbcSMatt Macy return (EINVAL); 1625681ce946SMartin Matuska /* 1626681ce946SMartin Matuska * This discards the const from nvp, so all callers for these 1627681ce946SMartin Matuska * types must not accept const nvpairs. 1628681ce946SMartin Matuska */ 1629eda14cbcSMatt Macy if ((*nelem = NVP_NELEM(nvp)) != 0) 1630eda14cbcSMatt Macy *(void **)data = (void *)NVP_VALUE(nvp); 1631eda14cbcSMatt Macy else 1632eda14cbcSMatt Macy *(void **)data = NULL; 1633eda14cbcSMatt Macy break; 1634eda14cbcSMatt Macy 1635eda14cbcSMatt Macy default: 1636eda14cbcSMatt Macy return (ENOTSUP); 1637eda14cbcSMatt Macy } 1638eda14cbcSMatt Macy 1639eda14cbcSMatt Macy return (0); 1640eda14cbcSMatt Macy } 1641eda14cbcSMatt Macy 1642eda14cbcSMatt Macy static int 1643681ce946SMartin Matuska nvlist_lookup_common(const nvlist_t *nvl, const char *name, data_type_t type, 1644eda14cbcSMatt Macy uint_t *nelem, void *data) 1645eda14cbcSMatt Macy { 1646eda14cbcSMatt Macy if (name == NULL || nvl == NULL || nvl->nvl_priv == 0) 1647eda14cbcSMatt Macy return (EINVAL); 1648eda14cbcSMatt Macy 1649eda14cbcSMatt Macy if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE))) 1650eda14cbcSMatt Macy return (ENOTSUP); 1651eda14cbcSMatt Macy 1652eda14cbcSMatt Macy nvpair_t *nvp = nvt_lookup_name_type(nvl, name, type); 1653eda14cbcSMatt Macy if (nvp == NULL) 1654eda14cbcSMatt Macy return (ENOENT); 1655eda14cbcSMatt Macy 1656eda14cbcSMatt Macy return (nvpair_value_common(nvp, type, nelem, data)); 1657eda14cbcSMatt Macy } 1658eda14cbcSMatt Macy 1659eda14cbcSMatt Macy int 1660681ce946SMartin Matuska nvlist_lookup_boolean(const nvlist_t *nvl, const char *name) 1661eda14cbcSMatt Macy { 1662eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL)); 1663eda14cbcSMatt Macy } 1664eda14cbcSMatt Macy 1665eda14cbcSMatt Macy int 1666681ce946SMartin Matuska nvlist_lookup_boolean_value(const nvlist_t *nvl, const char *name, 1667681ce946SMartin Matuska boolean_t *val) 1668eda14cbcSMatt Macy { 1669eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, 1670eda14cbcSMatt Macy DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 1671eda14cbcSMatt Macy } 1672eda14cbcSMatt Macy 1673eda14cbcSMatt Macy int 1674681ce946SMartin Matuska nvlist_lookup_byte(const nvlist_t *nvl, const char *name, uchar_t *val) 1675eda14cbcSMatt Macy { 1676eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val)); 1677eda14cbcSMatt Macy } 1678eda14cbcSMatt Macy 1679eda14cbcSMatt Macy int 1680681ce946SMartin Matuska nvlist_lookup_int8(const nvlist_t *nvl, const char *name, int8_t *val) 1681eda14cbcSMatt Macy { 1682eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val)); 1683eda14cbcSMatt Macy } 1684eda14cbcSMatt Macy 1685eda14cbcSMatt Macy int 1686681ce946SMartin Matuska nvlist_lookup_uint8(const nvlist_t *nvl, const char *name, uint8_t *val) 1687eda14cbcSMatt Macy { 1688eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val)); 1689eda14cbcSMatt Macy } 1690eda14cbcSMatt Macy 1691eda14cbcSMatt Macy int 1692681ce946SMartin Matuska nvlist_lookup_int16(const nvlist_t *nvl, const char *name, int16_t *val) 1693eda14cbcSMatt Macy { 1694eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val)); 1695eda14cbcSMatt Macy } 1696eda14cbcSMatt Macy 1697eda14cbcSMatt Macy int 1698681ce946SMartin Matuska nvlist_lookup_uint16(const nvlist_t *nvl, const char *name, uint16_t *val) 1699eda14cbcSMatt Macy { 1700eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val)); 1701eda14cbcSMatt Macy } 1702eda14cbcSMatt Macy 1703eda14cbcSMatt Macy int 1704681ce946SMartin Matuska nvlist_lookup_int32(const nvlist_t *nvl, const char *name, int32_t *val) 1705eda14cbcSMatt Macy { 1706eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val)); 1707eda14cbcSMatt Macy } 1708eda14cbcSMatt Macy 1709eda14cbcSMatt Macy int 1710681ce946SMartin Matuska nvlist_lookup_uint32(const nvlist_t *nvl, const char *name, uint32_t *val) 1711eda14cbcSMatt Macy { 1712eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val)); 1713eda14cbcSMatt Macy } 1714eda14cbcSMatt Macy 1715eda14cbcSMatt Macy int 1716681ce946SMartin Matuska nvlist_lookup_int64(const nvlist_t *nvl, const char *name, int64_t *val) 1717eda14cbcSMatt Macy { 1718eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val)); 1719eda14cbcSMatt Macy } 1720eda14cbcSMatt Macy 1721eda14cbcSMatt Macy int 1722681ce946SMartin Matuska nvlist_lookup_uint64(const nvlist_t *nvl, const char *name, uint64_t *val) 1723eda14cbcSMatt Macy { 1724eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val)); 1725eda14cbcSMatt Macy } 1726eda14cbcSMatt Macy 1727eda14cbcSMatt Macy #if !defined(_KERNEL) 1728eda14cbcSMatt Macy int 1729681ce946SMartin Matuska nvlist_lookup_double(const nvlist_t *nvl, const char *name, double *val) 1730eda14cbcSMatt Macy { 1731eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val)); 1732eda14cbcSMatt Macy } 1733eda14cbcSMatt Macy #endif 1734eda14cbcSMatt Macy 1735eda14cbcSMatt Macy int 17362a58b312SMartin Matuska nvlist_lookup_string(const nvlist_t *nvl, const char *name, const char **val) 1737eda14cbcSMatt Macy { 1738eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val)); 1739eda14cbcSMatt Macy } 1740eda14cbcSMatt Macy 1741eda14cbcSMatt Macy int 1742eda14cbcSMatt Macy nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val) 1743eda14cbcSMatt Macy { 1744eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val)); 1745eda14cbcSMatt Macy } 1746eda14cbcSMatt Macy 1747eda14cbcSMatt Macy int 1748eda14cbcSMatt Macy nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name, 1749eda14cbcSMatt Macy boolean_t **a, uint_t *n) 1750eda14cbcSMatt Macy { 1751eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, 1752eda14cbcSMatt Macy DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1753eda14cbcSMatt Macy } 1754eda14cbcSMatt Macy 1755eda14cbcSMatt Macy int 1756eda14cbcSMatt Macy nvlist_lookup_byte_array(nvlist_t *nvl, const char *name, 1757eda14cbcSMatt Macy uchar_t **a, uint_t *n) 1758eda14cbcSMatt Macy { 1759eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1760eda14cbcSMatt Macy } 1761eda14cbcSMatt Macy 1762eda14cbcSMatt Macy int 1763eda14cbcSMatt Macy nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n) 1764eda14cbcSMatt Macy { 1765eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1766eda14cbcSMatt Macy } 1767eda14cbcSMatt Macy 1768eda14cbcSMatt Macy int 1769eda14cbcSMatt Macy nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name, 1770eda14cbcSMatt Macy uint8_t **a, uint_t *n) 1771eda14cbcSMatt Macy { 1772eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1773eda14cbcSMatt Macy } 1774eda14cbcSMatt Macy 1775eda14cbcSMatt Macy int 1776eda14cbcSMatt Macy nvlist_lookup_int16_array(nvlist_t *nvl, const char *name, 1777eda14cbcSMatt Macy int16_t **a, uint_t *n) 1778eda14cbcSMatt Macy { 1779eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1780eda14cbcSMatt Macy } 1781eda14cbcSMatt Macy 1782eda14cbcSMatt Macy int 1783eda14cbcSMatt Macy nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name, 1784eda14cbcSMatt Macy uint16_t **a, uint_t *n) 1785eda14cbcSMatt Macy { 1786eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1787eda14cbcSMatt Macy } 1788eda14cbcSMatt Macy 1789eda14cbcSMatt Macy int 1790eda14cbcSMatt Macy nvlist_lookup_int32_array(nvlist_t *nvl, const char *name, 1791eda14cbcSMatt Macy int32_t **a, uint_t *n) 1792eda14cbcSMatt Macy { 1793eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1794eda14cbcSMatt Macy } 1795eda14cbcSMatt Macy 1796eda14cbcSMatt Macy int 1797eda14cbcSMatt Macy nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name, 1798eda14cbcSMatt Macy uint32_t **a, uint_t *n) 1799eda14cbcSMatt Macy { 1800eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1801eda14cbcSMatt Macy } 1802eda14cbcSMatt Macy 1803eda14cbcSMatt Macy int 1804eda14cbcSMatt Macy nvlist_lookup_int64_array(nvlist_t *nvl, const char *name, 1805eda14cbcSMatt Macy int64_t **a, uint_t *n) 1806eda14cbcSMatt Macy { 1807eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1808eda14cbcSMatt Macy } 1809eda14cbcSMatt Macy 1810eda14cbcSMatt Macy int 1811eda14cbcSMatt Macy nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name, 1812eda14cbcSMatt Macy uint64_t **a, uint_t *n) 1813eda14cbcSMatt Macy { 1814eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1815eda14cbcSMatt Macy } 1816eda14cbcSMatt Macy 1817eda14cbcSMatt Macy int 1818eda14cbcSMatt Macy nvlist_lookup_string_array(nvlist_t *nvl, const char *name, 1819eda14cbcSMatt Macy char ***a, uint_t *n) 1820eda14cbcSMatt Macy { 1821eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1822eda14cbcSMatt Macy } 1823eda14cbcSMatt Macy 1824eda14cbcSMatt Macy int 1825eda14cbcSMatt Macy nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name, 1826eda14cbcSMatt Macy nvlist_t ***a, uint_t *n) 1827eda14cbcSMatt Macy { 1828eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1829eda14cbcSMatt Macy } 1830eda14cbcSMatt Macy 1831eda14cbcSMatt Macy int 1832eda14cbcSMatt Macy nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val) 1833eda14cbcSMatt Macy { 1834eda14cbcSMatt Macy return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val)); 1835eda14cbcSMatt Macy } 1836eda14cbcSMatt Macy 1837eda14cbcSMatt Macy int 1838eda14cbcSMatt Macy nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...) 1839eda14cbcSMatt Macy { 1840eda14cbcSMatt Macy va_list ap; 1841eda14cbcSMatt Macy char *name; 1842eda14cbcSMatt Macy int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0); 1843eda14cbcSMatt Macy int ret = 0; 1844eda14cbcSMatt Macy 1845eda14cbcSMatt Macy va_start(ap, flag); 1846eda14cbcSMatt Macy while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { 1847eda14cbcSMatt Macy data_type_t type; 1848eda14cbcSMatt Macy void *val; 1849eda14cbcSMatt Macy uint_t *nelem; 1850eda14cbcSMatt Macy 1851eda14cbcSMatt Macy switch (type = va_arg(ap, data_type_t)) { 1852eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN: 1853eda14cbcSMatt Macy ret = nvlist_lookup_common(nvl, name, type, NULL, NULL); 1854eda14cbcSMatt Macy break; 1855eda14cbcSMatt Macy 1856eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_VALUE: 1857eda14cbcSMatt Macy case DATA_TYPE_BYTE: 1858eda14cbcSMatt Macy case DATA_TYPE_INT8: 1859eda14cbcSMatt Macy case DATA_TYPE_UINT8: 1860eda14cbcSMatt Macy case DATA_TYPE_INT16: 1861eda14cbcSMatt Macy case DATA_TYPE_UINT16: 1862eda14cbcSMatt Macy case DATA_TYPE_INT32: 1863eda14cbcSMatt Macy case DATA_TYPE_UINT32: 1864eda14cbcSMatt Macy case DATA_TYPE_INT64: 1865eda14cbcSMatt Macy case DATA_TYPE_UINT64: 1866eda14cbcSMatt Macy case DATA_TYPE_HRTIME: 1867eda14cbcSMatt Macy case DATA_TYPE_STRING: 1868eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 1869eda14cbcSMatt Macy #if !defined(_KERNEL) 1870eda14cbcSMatt Macy case DATA_TYPE_DOUBLE: 1871eda14cbcSMatt Macy #endif 1872eda14cbcSMatt Macy val = va_arg(ap, void *); 1873eda14cbcSMatt Macy ret = nvlist_lookup_common(nvl, name, type, NULL, val); 1874eda14cbcSMatt Macy break; 1875eda14cbcSMatt Macy 1876eda14cbcSMatt Macy case DATA_TYPE_BYTE_ARRAY: 1877eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_ARRAY: 1878eda14cbcSMatt Macy case DATA_TYPE_INT8_ARRAY: 1879eda14cbcSMatt Macy case DATA_TYPE_UINT8_ARRAY: 1880eda14cbcSMatt Macy case DATA_TYPE_INT16_ARRAY: 1881eda14cbcSMatt Macy case DATA_TYPE_UINT16_ARRAY: 1882eda14cbcSMatt Macy case DATA_TYPE_INT32_ARRAY: 1883eda14cbcSMatt Macy case DATA_TYPE_UINT32_ARRAY: 1884eda14cbcSMatt Macy case DATA_TYPE_INT64_ARRAY: 1885eda14cbcSMatt Macy case DATA_TYPE_UINT64_ARRAY: 1886eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: 1887eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: 1888eda14cbcSMatt Macy val = va_arg(ap, void *); 1889eda14cbcSMatt Macy nelem = va_arg(ap, uint_t *); 1890eda14cbcSMatt Macy ret = nvlist_lookup_common(nvl, name, type, nelem, val); 1891eda14cbcSMatt Macy break; 1892eda14cbcSMatt Macy 1893eda14cbcSMatt Macy default: 1894eda14cbcSMatt Macy ret = EINVAL; 1895eda14cbcSMatt Macy } 1896eda14cbcSMatt Macy 1897eda14cbcSMatt Macy if (ret == ENOENT && noentok) 1898eda14cbcSMatt Macy ret = 0; 1899eda14cbcSMatt Macy } 1900eda14cbcSMatt Macy va_end(ap); 1901eda14cbcSMatt Macy 1902eda14cbcSMatt Macy return (ret); 1903eda14cbcSMatt Macy } 1904eda14cbcSMatt Macy 1905eda14cbcSMatt Macy /* 1906eda14cbcSMatt Macy * Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function 1907eda14cbcSMatt Macy * returns zero and a pointer to the matching nvpair is returned in '*ret' 1908eda14cbcSMatt Macy * (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate 1909eda14cbcSMatt Macy * multiple levels of embedded nvlists, with 'sep' as the separator. As an 1910eda14cbcSMatt Macy * example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or 1911eda14cbcSMatt Macy * "a.d[3].e[1]". This matches the C syntax for array embed (for convenience, 1912eda14cbcSMatt Macy * code also supports "a.d[3]e[1]" syntax). 1913eda14cbcSMatt Macy * 1914eda14cbcSMatt Macy * If 'ip' is non-NULL and the last name component is an array, return the 1915eda14cbcSMatt Macy * value of the "...[index]" array index in *ip. For an array reference that 1916eda14cbcSMatt Macy * is not indexed, *ip will be returned as -1. If there is a syntax error in 1917eda14cbcSMatt Macy * 'name', and 'ep' is non-NULL then *ep will be set to point to the location 1918eda14cbcSMatt Macy * inside the 'name' string where the syntax error was detected. 1919eda14cbcSMatt Macy */ 1920eda14cbcSMatt Macy static int 1921eda14cbcSMatt Macy nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep, 19222a58b312SMartin Matuska nvpair_t **ret, int *ip, const char **ep) 1923eda14cbcSMatt Macy { 1924eda14cbcSMatt Macy nvpair_t *nvp; 1925eda14cbcSMatt Macy const char *np; 1926eda14cbcSMatt Macy char *sepp = NULL; 1927eda14cbcSMatt Macy char *idxp, *idxep; 1928eda14cbcSMatt Macy nvlist_t **nva; 1929eda14cbcSMatt Macy long idx = 0; 1930eda14cbcSMatt Macy int n; 1931eda14cbcSMatt Macy 1932eda14cbcSMatt Macy if (ip) 1933eda14cbcSMatt Macy *ip = -1; /* not indexed */ 1934eda14cbcSMatt Macy if (ep) 1935eda14cbcSMatt Macy *ep = NULL; 1936eda14cbcSMatt Macy 1937eda14cbcSMatt Macy if ((nvl == NULL) || (name == NULL)) 1938eda14cbcSMatt Macy return (EINVAL); 1939eda14cbcSMatt Macy 1940eda14cbcSMatt Macy sepp = NULL; 1941eda14cbcSMatt Macy idx = 0; 1942eda14cbcSMatt Macy /* step through components of name */ 1943eda14cbcSMatt Macy for (np = name; np && *np; np = sepp) { 1944eda14cbcSMatt Macy /* ensure unique names */ 1945eda14cbcSMatt Macy if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME)) 1946eda14cbcSMatt Macy return (ENOTSUP); 1947eda14cbcSMatt Macy 1948eda14cbcSMatt Macy /* skip white space */ 1949eda14cbcSMatt Macy skip_whitespace(np); 1950eda14cbcSMatt Macy if (*np == 0) 1951eda14cbcSMatt Macy break; 1952eda14cbcSMatt Macy 1953eda14cbcSMatt Macy /* set 'sepp' to end of current component 'np' */ 1954eda14cbcSMatt Macy if (sep) 1955eda14cbcSMatt Macy sepp = strchr(np, sep); 1956eda14cbcSMatt Macy else 1957eda14cbcSMatt Macy sepp = NULL; 1958eda14cbcSMatt Macy 1959eda14cbcSMatt Macy /* find start of next "[ index ]..." */ 1960eda14cbcSMatt Macy idxp = strchr(np, '['); 1961eda14cbcSMatt Macy 1962eda14cbcSMatt Macy /* if sepp comes first, set idxp to NULL */ 1963eda14cbcSMatt Macy if (sepp && idxp && (sepp < idxp)) 1964eda14cbcSMatt Macy idxp = NULL; 1965eda14cbcSMatt Macy 1966eda14cbcSMatt Macy /* 1967eda14cbcSMatt Macy * At this point 'idxp' is set if there is an index 1968eda14cbcSMatt Macy * expected for the current component. 1969eda14cbcSMatt Macy */ 1970eda14cbcSMatt Macy if (idxp) { 1971eda14cbcSMatt Macy /* set 'n' to length of current 'np' name component */ 1972eda14cbcSMatt Macy n = idxp++ - np; 1973eda14cbcSMatt Macy 1974eda14cbcSMatt Macy /* keep sepp up to date for *ep use as we advance */ 1975eda14cbcSMatt Macy skip_whitespace(idxp); 1976eda14cbcSMatt Macy sepp = idxp; 1977eda14cbcSMatt Macy 1978eda14cbcSMatt Macy /* determine the index value */ 1979eda14cbcSMatt Macy #if defined(_KERNEL) 1980eda14cbcSMatt Macy if (ddi_strtol(idxp, &idxep, 0, &idx)) 1981eda14cbcSMatt Macy goto fail; 1982eda14cbcSMatt Macy #else 1983eda14cbcSMatt Macy idx = strtol(idxp, &idxep, 0); 1984eda14cbcSMatt Macy #endif 1985eda14cbcSMatt Macy if (idxep == idxp) 1986eda14cbcSMatt Macy goto fail; 1987eda14cbcSMatt Macy 1988eda14cbcSMatt Macy /* keep sepp up to date for *ep use as we advance */ 1989eda14cbcSMatt Macy sepp = idxep; 1990eda14cbcSMatt Macy 1991eda14cbcSMatt Macy /* skip white space index value and check for ']' */ 1992eda14cbcSMatt Macy skip_whitespace(sepp); 1993eda14cbcSMatt Macy if (*sepp++ != ']') 1994eda14cbcSMatt Macy goto fail; 1995eda14cbcSMatt Macy 1996eda14cbcSMatt Macy /* for embedded arrays, support C syntax: "a[1].b" */ 1997eda14cbcSMatt Macy skip_whitespace(sepp); 1998eda14cbcSMatt Macy if (sep && (*sepp == sep)) 1999eda14cbcSMatt Macy sepp++; 2000eda14cbcSMatt Macy } else if (sepp) { 2001eda14cbcSMatt Macy n = sepp++ - np; 2002eda14cbcSMatt Macy } else { 2003eda14cbcSMatt Macy n = strlen(np); 2004eda14cbcSMatt Macy } 2005eda14cbcSMatt Macy 2006eda14cbcSMatt Macy /* trim trailing whitespace by reducing length of 'np' */ 2007eda14cbcSMatt Macy if (n == 0) 2008eda14cbcSMatt Macy goto fail; 2009eda14cbcSMatt Macy for (n--; (np[n] == ' ') || (np[n] == '\t'); n--) 2010eda14cbcSMatt Macy ; 2011eda14cbcSMatt Macy n++; 2012eda14cbcSMatt Macy 2013eda14cbcSMatt Macy /* skip whitespace, and set sepp to NULL if complete */ 2014eda14cbcSMatt Macy if (sepp) { 2015eda14cbcSMatt Macy skip_whitespace(sepp); 2016eda14cbcSMatt Macy if (*sepp == 0) 2017eda14cbcSMatt Macy sepp = NULL; 2018eda14cbcSMatt Macy } 2019eda14cbcSMatt Macy 2020eda14cbcSMatt Macy /* 2021eda14cbcSMatt Macy * At this point: 2022eda14cbcSMatt Macy * o 'n' is the length of current 'np' component. 2023eda14cbcSMatt Macy * o 'idxp' is set if there was an index, and value 'idx'. 2024eda14cbcSMatt Macy * o 'sepp' is set to the beginning of the next component, 2025eda14cbcSMatt Macy * and set to NULL if we have no more components. 2026eda14cbcSMatt Macy * 2027eda14cbcSMatt Macy * Search for nvpair with matching component name. 2028eda14cbcSMatt Macy */ 2029eda14cbcSMatt Macy for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 2030eda14cbcSMatt Macy nvp = nvlist_next_nvpair(nvl, nvp)) { 2031eda14cbcSMatt Macy 2032eda14cbcSMatt Macy /* continue if no match on name */ 2033eda14cbcSMatt Macy if (strncmp(np, nvpair_name(nvp), n) || 2034eda14cbcSMatt Macy (strlen(nvpair_name(nvp)) != n)) 2035eda14cbcSMatt Macy continue; 2036eda14cbcSMatt Macy 2037eda14cbcSMatt Macy /* if indexed, verify type is array oriented */ 2038eda14cbcSMatt Macy if (idxp && !nvpair_type_is_array(nvp)) 2039eda14cbcSMatt Macy goto fail; 2040eda14cbcSMatt Macy 2041eda14cbcSMatt Macy /* 2042eda14cbcSMatt Macy * Full match found, return nvp and idx if this 2043eda14cbcSMatt Macy * was the last component. 2044eda14cbcSMatt Macy */ 2045eda14cbcSMatt Macy if (sepp == NULL) { 2046eda14cbcSMatt Macy if (ret) 2047eda14cbcSMatt Macy *ret = nvp; 2048eda14cbcSMatt Macy if (ip && idxp) 2049eda14cbcSMatt Macy *ip = (int)idx; /* return index */ 2050eda14cbcSMatt Macy return (0); /* found */ 2051eda14cbcSMatt Macy } 2052eda14cbcSMatt Macy 2053eda14cbcSMatt Macy /* 2054eda14cbcSMatt Macy * More components: current match must be 2055eda14cbcSMatt Macy * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY 2056eda14cbcSMatt Macy * to support going deeper. 2057eda14cbcSMatt Macy */ 2058eda14cbcSMatt Macy if (nvpair_type(nvp) == DATA_TYPE_NVLIST) { 2059eda14cbcSMatt Macy nvl = EMBEDDED_NVL(nvp); 2060eda14cbcSMatt Macy break; 2061eda14cbcSMatt Macy } else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) { 20622a58b312SMartin Matuska if (nvpair_value_nvlist_array(nvp, 20632a58b312SMartin Matuska &nva, (uint_t *)&n) != 0) 20642a58b312SMartin Matuska goto fail; 20652a58b312SMartin Matuska if (nva == NULL) 20662a58b312SMartin Matuska goto fail; 2067eda14cbcSMatt Macy if ((n < 0) || (idx >= n)) 2068eda14cbcSMatt Macy goto fail; 2069eda14cbcSMatt Macy nvl = nva[idx]; 2070eda14cbcSMatt Macy break; 2071eda14cbcSMatt Macy } 2072eda14cbcSMatt Macy 2073eda14cbcSMatt Macy /* type does not support more levels */ 2074eda14cbcSMatt Macy goto fail; 2075eda14cbcSMatt Macy } 2076eda14cbcSMatt Macy if (nvp == NULL) 2077eda14cbcSMatt Macy goto fail; /* 'name' not found */ 2078eda14cbcSMatt Macy 2079eda14cbcSMatt Macy /* search for match of next component in embedded 'nvl' list */ 2080eda14cbcSMatt Macy } 2081eda14cbcSMatt Macy 2082eda14cbcSMatt Macy fail: if (ep && sepp) 2083eda14cbcSMatt Macy *ep = sepp; 2084eda14cbcSMatt Macy return (EINVAL); 2085eda14cbcSMatt Macy } 2086eda14cbcSMatt Macy 2087eda14cbcSMatt Macy /* 2088eda14cbcSMatt Macy * Return pointer to nvpair with specified 'name'. 2089eda14cbcSMatt Macy */ 2090eda14cbcSMatt Macy int 2091eda14cbcSMatt Macy nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret) 2092eda14cbcSMatt Macy { 2093eda14cbcSMatt Macy return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL)); 2094eda14cbcSMatt Macy } 2095eda14cbcSMatt Macy 2096eda14cbcSMatt Macy /* 2097eda14cbcSMatt Macy * Determine if named nvpair exists in nvlist (use embedded separator of '.' 2098eda14cbcSMatt Macy * and return array index). See nvlist_lookup_nvpair_ei_sep for more detailed 2099eda14cbcSMatt Macy * description. 2100eda14cbcSMatt Macy */ 2101eda14cbcSMatt Macy int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl, 21022a58b312SMartin Matuska const char *name, nvpair_t **ret, int *ip, const char **ep) 2103eda14cbcSMatt Macy { 2104eda14cbcSMatt Macy return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep)); 2105eda14cbcSMatt Macy } 2106eda14cbcSMatt Macy 2107eda14cbcSMatt Macy boolean_t 2108681ce946SMartin Matuska nvlist_exists(const nvlist_t *nvl, const char *name) 2109eda14cbcSMatt Macy { 2110eda14cbcSMatt Macy nvpriv_t *priv; 2111eda14cbcSMatt Macy nvpair_t *nvp; 2112eda14cbcSMatt Macy i_nvp_t *curr; 2113eda14cbcSMatt Macy 2114eda14cbcSMatt Macy if (name == NULL || nvl == NULL || 2115eda14cbcSMatt Macy (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 2116eda14cbcSMatt Macy return (B_FALSE); 2117eda14cbcSMatt Macy 2118eda14cbcSMatt Macy for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 2119eda14cbcSMatt Macy nvp = &curr->nvi_nvp; 2120eda14cbcSMatt Macy 2121eda14cbcSMatt Macy if (strcmp(name, NVP_NAME(nvp)) == 0) 2122eda14cbcSMatt Macy return (B_TRUE); 2123eda14cbcSMatt Macy } 2124eda14cbcSMatt Macy 2125eda14cbcSMatt Macy return (B_FALSE); 2126eda14cbcSMatt Macy } 2127eda14cbcSMatt Macy 2128eda14cbcSMatt Macy int 2129681ce946SMartin Matuska nvpair_value_boolean_value(const nvpair_t *nvp, boolean_t *val) 2130eda14cbcSMatt Macy { 2131eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 2132eda14cbcSMatt Macy } 2133eda14cbcSMatt Macy 2134eda14cbcSMatt Macy int 2135681ce946SMartin Matuska nvpair_value_byte(const nvpair_t *nvp, uchar_t *val) 2136eda14cbcSMatt Macy { 2137eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val)); 2138eda14cbcSMatt Macy } 2139eda14cbcSMatt Macy 2140eda14cbcSMatt Macy int 2141681ce946SMartin Matuska nvpair_value_int8(const nvpair_t *nvp, int8_t *val) 2142eda14cbcSMatt Macy { 2143eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val)); 2144eda14cbcSMatt Macy } 2145eda14cbcSMatt Macy 2146eda14cbcSMatt Macy int 2147681ce946SMartin Matuska nvpair_value_uint8(const nvpair_t *nvp, uint8_t *val) 2148eda14cbcSMatt Macy { 2149eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val)); 2150eda14cbcSMatt Macy } 2151eda14cbcSMatt Macy 2152eda14cbcSMatt Macy int 2153681ce946SMartin Matuska nvpair_value_int16(const nvpair_t *nvp, int16_t *val) 2154eda14cbcSMatt Macy { 2155eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val)); 2156eda14cbcSMatt Macy } 2157eda14cbcSMatt Macy 2158eda14cbcSMatt Macy int 2159681ce946SMartin Matuska nvpair_value_uint16(const nvpair_t *nvp, uint16_t *val) 2160eda14cbcSMatt Macy { 2161eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val)); 2162eda14cbcSMatt Macy } 2163eda14cbcSMatt Macy 2164eda14cbcSMatt Macy int 2165681ce946SMartin Matuska nvpair_value_int32(const nvpair_t *nvp, int32_t *val) 2166eda14cbcSMatt Macy { 2167eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val)); 2168eda14cbcSMatt Macy } 2169eda14cbcSMatt Macy 2170eda14cbcSMatt Macy int 2171681ce946SMartin Matuska nvpair_value_uint32(const nvpair_t *nvp, uint32_t *val) 2172eda14cbcSMatt Macy { 2173eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val)); 2174eda14cbcSMatt Macy } 2175eda14cbcSMatt Macy 2176eda14cbcSMatt Macy int 2177681ce946SMartin Matuska nvpair_value_int64(const nvpair_t *nvp, int64_t *val) 2178eda14cbcSMatt Macy { 2179eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val)); 2180eda14cbcSMatt Macy } 2181eda14cbcSMatt Macy 2182eda14cbcSMatt Macy int 2183681ce946SMartin Matuska nvpair_value_uint64(const nvpair_t *nvp, uint64_t *val) 2184eda14cbcSMatt Macy { 2185eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val)); 2186eda14cbcSMatt Macy } 2187eda14cbcSMatt Macy 2188eda14cbcSMatt Macy #if !defined(_KERNEL) 2189eda14cbcSMatt Macy int 2190681ce946SMartin Matuska nvpair_value_double(const nvpair_t *nvp, double *val) 2191eda14cbcSMatt Macy { 2192eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val)); 2193eda14cbcSMatt Macy } 2194eda14cbcSMatt Macy #endif 2195eda14cbcSMatt Macy 2196eda14cbcSMatt Macy int 21972a58b312SMartin Matuska nvpair_value_string(const nvpair_t *nvp, const char **val) 2198eda14cbcSMatt Macy { 2199eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val)); 2200eda14cbcSMatt Macy } 2201eda14cbcSMatt Macy 2202eda14cbcSMatt Macy int 2203eda14cbcSMatt Macy nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val) 2204eda14cbcSMatt Macy { 2205eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val)); 2206eda14cbcSMatt Macy } 2207eda14cbcSMatt Macy 2208eda14cbcSMatt Macy int 2209eda14cbcSMatt Macy nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem) 2210eda14cbcSMatt Macy { 2211eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val)); 2212eda14cbcSMatt Macy } 2213eda14cbcSMatt Macy 2214eda14cbcSMatt Macy int 2215eda14cbcSMatt Macy nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem) 2216eda14cbcSMatt Macy { 2217eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val)); 2218eda14cbcSMatt Macy } 2219eda14cbcSMatt Macy 2220eda14cbcSMatt Macy int 2221eda14cbcSMatt Macy nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem) 2222eda14cbcSMatt Macy { 2223eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val)); 2224eda14cbcSMatt Macy } 2225eda14cbcSMatt Macy 2226eda14cbcSMatt Macy int 2227eda14cbcSMatt Macy nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem) 2228eda14cbcSMatt Macy { 2229eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val)); 2230eda14cbcSMatt Macy } 2231eda14cbcSMatt Macy 2232eda14cbcSMatt Macy int 2233eda14cbcSMatt Macy nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem) 2234eda14cbcSMatt Macy { 2235eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val)); 2236eda14cbcSMatt Macy } 2237eda14cbcSMatt Macy 2238eda14cbcSMatt Macy int 2239eda14cbcSMatt Macy nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem) 2240eda14cbcSMatt Macy { 2241eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val)); 2242eda14cbcSMatt Macy } 2243eda14cbcSMatt Macy 2244eda14cbcSMatt Macy int 2245eda14cbcSMatt Macy nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem) 2246eda14cbcSMatt Macy { 2247eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val)); 2248eda14cbcSMatt Macy } 2249eda14cbcSMatt Macy 2250eda14cbcSMatt Macy int 2251eda14cbcSMatt Macy nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem) 2252eda14cbcSMatt Macy { 2253eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val)); 2254eda14cbcSMatt Macy } 2255eda14cbcSMatt Macy 2256eda14cbcSMatt Macy int 2257eda14cbcSMatt Macy nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem) 2258eda14cbcSMatt Macy { 2259eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val)); 2260eda14cbcSMatt Macy } 2261eda14cbcSMatt Macy 2262eda14cbcSMatt Macy int 2263eda14cbcSMatt Macy nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem) 2264eda14cbcSMatt Macy { 2265eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val)); 2266eda14cbcSMatt Macy } 2267eda14cbcSMatt Macy 2268eda14cbcSMatt Macy int 22692a58b312SMartin Matuska nvpair_value_string_array(nvpair_t *nvp, const char ***val, uint_t *nelem) 2270eda14cbcSMatt Macy { 2271eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val)); 2272eda14cbcSMatt Macy } 2273eda14cbcSMatt Macy 2274eda14cbcSMatt Macy int 2275eda14cbcSMatt Macy nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem) 2276eda14cbcSMatt Macy { 2277eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val)); 2278eda14cbcSMatt Macy } 2279eda14cbcSMatt Macy 2280eda14cbcSMatt Macy int 2281eda14cbcSMatt Macy nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val) 2282eda14cbcSMatt Macy { 2283eda14cbcSMatt Macy return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val)); 2284eda14cbcSMatt Macy } 2285eda14cbcSMatt Macy 2286eda14cbcSMatt Macy /* 2287eda14cbcSMatt Macy * Add specified pair to the list. 2288eda14cbcSMatt Macy */ 2289eda14cbcSMatt Macy int 2290eda14cbcSMatt Macy nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp) 2291eda14cbcSMatt Macy { 2292eda14cbcSMatt Macy if (nvl == NULL || nvp == NULL) 2293eda14cbcSMatt Macy return (EINVAL); 2294eda14cbcSMatt Macy 2295eda14cbcSMatt Macy return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp), 2296eda14cbcSMatt Macy NVP_NELEM(nvp), NVP_VALUE(nvp))); 2297eda14cbcSMatt Macy } 2298eda14cbcSMatt Macy 2299eda14cbcSMatt Macy /* 2300eda14cbcSMatt Macy * Merge the supplied nvlists and put the result in dst. 2301eda14cbcSMatt Macy * The merged list will contain all names specified in both lists, 2302eda14cbcSMatt Macy * the values are taken from nvl in the case of duplicates. 2303eda14cbcSMatt Macy * Return 0 on success. 2304eda14cbcSMatt Macy */ 2305eda14cbcSMatt Macy int 2306eda14cbcSMatt Macy nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag) 2307eda14cbcSMatt Macy { 2308e92ffd9bSMartin Matuska (void) flag; 2309e92ffd9bSMartin Matuska 2310eda14cbcSMatt Macy if (nvl == NULL || dst == NULL) 2311eda14cbcSMatt Macy return (EINVAL); 2312eda14cbcSMatt Macy 2313eda14cbcSMatt Macy if (dst != nvl) 2314eda14cbcSMatt Macy return (nvlist_copy_pairs(nvl, dst)); 2315eda14cbcSMatt Macy 2316eda14cbcSMatt Macy return (0); 2317eda14cbcSMatt Macy } 2318eda14cbcSMatt Macy 2319eda14cbcSMatt Macy /* 2320eda14cbcSMatt Macy * Encoding related routines 2321eda14cbcSMatt Macy */ 2322eda14cbcSMatt Macy #define NVS_OP_ENCODE 0 2323eda14cbcSMatt Macy #define NVS_OP_DECODE 1 2324eda14cbcSMatt Macy #define NVS_OP_GETSIZE 2 2325eda14cbcSMatt Macy 2326eda14cbcSMatt Macy typedef struct nvs_ops nvs_ops_t; 2327eda14cbcSMatt Macy 2328eda14cbcSMatt Macy typedef struct { 2329eda14cbcSMatt Macy int nvs_op; 2330eda14cbcSMatt Macy const nvs_ops_t *nvs_ops; 2331eda14cbcSMatt Macy void *nvs_private; 2332eda14cbcSMatt Macy nvpriv_t *nvs_priv; 2333eda14cbcSMatt Macy int nvs_recursion; 2334eda14cbcSMatt Macy } nvstream_t; 2335eda14cbcSMatt Macy 2336eda14cbcSMatt Macy /* 2337eda14cbcSMatt Macy * nvs operations are: 2338eda14cbcSMatt Macy * - nvs_nvlist 2339eda14cbcSMatt Macy * encoding / decoding of an nvlist header (nvlist_t) 2340eda14cbcSMatt Macy * calculates the size used for header and end detection 2341eda14cbcSMatt Macy * 2342eda14cbcSMatt Macy * - nvs_nvpair 2343eda14cbcSMatt Macy * responsible for the first part of encoding / decoding of an nvpair 2344eda14cbcSMatt Macy * calculates the decoded size of an nvpair 2345eda14cbcSMatt Macy * 2346eda14cbcSMatt Macy * - nvs_nvp_op 2347eda14cbcSMatt Macy * second part of encoding / decoding of an nvpair 2348eda14cbcSMatt Macy * 2349eda14cbcSMatt Macy * - nvs_nvp_size 2350eda14cbcSMatt Macy * calculates the encoding size of an nvpair 2351eda14cbcSMatt Macy * 2352eda14cbcSMatt Macy * - nvs_nvl_fini 2353eda14cbcSMatt Macy * encodes the end detection mark (zeros). 2354eda14cbcSMatt Macy */ 2355eda14cbcSMatt Macy struct nvs_ops { 2356eda14cbcSMatt Macy int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *); 2357eda14cbcSMatt Macy int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *); 2358eda14cbcSMatt Macy int (*nvs_nvp_op)(nvstream_t *, nvpair_t *); 2359eda14cbcSMatt Macy int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *); 2360eda14cbcSMatt Macy int (*nvs_nvl_fini)(nvstream_t *); 2361eda14cbcSMatt Macy }; 2362eda14cbcSMatt Macy 2363eda14cbcSMatt Macy typedef struct { 2364eda14cbcSMatt Macy char nvh_encoding; /* nvs encoding method */ 2365eda14cbcSMatt Macy char nvh_endian; /* nvs endian */ 2366eda14cbcSMatt Macy char nvh_reserved1; /* reserved for future use */ 2367eda14cbcSMatt Macy char nvh_reserved2; /* reserved for future use */ 2368eda14cbcSMatt Macy } nvs_header_t; 2369eda14cbcSMatt Macy 2370eda14cbcSMatt Macy static int 2371eda14cbcSMatt Macy nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl) 2372eda14cbcSMatt Macy { 2373eda14cbcSMatt Macy nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 2374eda14cbcSMatt Macy i_nvp_t *curr; 2375eda14cbcSMatt Macy 2376eda14cbcSMatt Macy /* 2377eda14cbcSMatt Macy * Walk nvpair in list and encode each nvpair 2378eda14cbcSMatt Macy */ 2379eda14cbcSMatt Macy for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 2380eda14cbcSMatt Macy if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0) 2381eda14cbcSMatt Macy return (EFAULT); 2382eda14cbcSMatt Macy 2383eda14cbcSMatt Macy return (nvs->nvs_ops->nvs_nvl_fini(nvs)); 2384eda14cbcSMatt Macy } 2385eda14cbcSMatt Macy 2386eda14cbcSMatt Macy static int 2387eda14cbcSMatt Macy nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl) 2388eda14cbcSMatt Macy { 2389eda14cbcSMatt Macy nvpair_t *nvp; 2390eda14cbcSMatt Macy size_t nvsize; 2391eda14cbcSMatt Macy int err; 2392eda14cbcSMatt Macy 2393eda14cbcSMatt Macy /* 2394eda14cbcSMatt Macy * Get decoded size of next pair in stream, alloc 2395eda14cbcSMatt Macy * memory for nvpair_t, then decode the nvpair 2396eda14cbcSMatt Macy */ 2397eda14cbcSMatt Macy while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) { 2398eda14cbcSMatt Macy if (nvsize == 0) /* end of list */ 2399eda14cbcSMatt Macy break; 2400eda14cbcSMatt Macy 2401eda14cbcSMatt Macy /* make sure len makes sense */ 2402eda14cbcSMatt Macy if (nvsize < NVP_SIZE_CALC(1, 0)) 2403eda14cbcSMatt Macy return (EFAULT); 2404eda14cbcSMatt Macy 2405eda14cbcSMatt Macy if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL) 2406eda14cbcSMatt Macy return (ENOMEM); 2407eda14cbcSMatt Macy 2408eda14cbcSMatt Macy if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) { 2409eda14cbcSMatt Macy nvp_buf_free(nvl, nvp); 2410eda14cbcSMatt Macy return (err); 2411eda14cbcSMatt Macy } 2412eda14cbcSMatt Macy 2413eda14cbcSMatt Macy if (i_validate_nvpair(nvp) != 0) { 2414eda14cbcSMatt Macy nvpair_free(nvp); 2415eda14cbcSMatt Macy nvp_buf_free(nvl, nvp); 2416eda14cbcSMatt Macy return (EFAULT); 2417eda14cbcSMatt Macy } 2418eda14cbcSMatt Macy 2419eda14cbcSMatt Macy err = nvt_add_nvpair(nvl, nvp); 2420eda14cbcSMatt Macy if (err != 0) { 2421eda14cbcSMatt Macy nvpair_free(nvp); 2422eda14cbcSMatt Macy nvp_buf_free(nvl, nvp); 2423eda14cbcSMatt Macy return (err); 2424eda14cbcSMatt Macy } 2425eda14cbcSMatt Macy nvp_buf_link(nvl, nvp); 2426eda14cbcSMatt Macy } 2427eda14cbcSMatt Macy return (err); 2428eda14cbcSMatt Macy } 2429eda14cbcSMatt Macy 2430eda14cbcSMatt Macy static int 2431eda14cbcSMatt Macy nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 2432eda14cbcSMatt Macy { 2433eda14cbcSMatt Macy nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 2434eda14cbcSMatt Macy i_nvp_t *curr; 2435eda14cbcSMatt Macy uint64_t nvsize = *buflen; 2436eda14cbcSMatt Macy size_t size; 2437eda14cbcSMatt Macy 2438eda14cbcSMatt Macy /* 2439eda14cbcSMatt Macy * Get encoded size of nvpairs in nvlist 2440eda14cbcSMatt Macy */ 2441eda14cbcSMatt Macy for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 2442eda14cbcSMatt Macy if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0) 2443eda14cbcSMatt Macy return (EINVAL); 2444eda14cbcSMatt Macy 2445eda14cbcSMatt Macy if ((nvsize += size) > INT32_MAX) 2446eda14cbcSMatt Macy return (EINVAL); 2447eda14cbcSMatt Macy } 2448eda14cbcSMatt Macy 2449eda14cbcSMatt Macy *buflen = nvsize; 2450eda14cbcSMatt Macy return (0); 2451eda14cbcSMatt Macy } 2452eda14cbcSMatt Macy 2453eda14cbcSMatt Macy static int 2454eda14cbcSMatt Macy nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 2455eda14cbcSMatt Macy { 2456eda14cbcSMatt Macy int err; 2457eda14cbcSMatt Macy 2458eda14cbcSMatt Macy if (nvl->nvl_priv == 0) 2459eda14cbcSMatt Macy return (EFAULT); 2460eda14cbcSMatt Macy 2461eda14cbcSMatt Macy /* 2462eda14cbcSMatt Macy * Perform the operation, starting with header, then each nvpair 2463eda14cbcSMatt Macy */ 2464eda14cbcSMatt Macy if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0) 2465eda14cbcSMatt Macy return (err); 2466eda14cbcSMatt Macy 2467eda14cbcSMatt Macy switch (nvs->nvs_op) { 2468eda14cbcSMatt Macy case NVS_OP_ENCODE: 2469eda14cbcSMatt Macy err = nvs_encode_pairs(nvs, nvl); 2470eda14cbcSMatt Macy break; 2471eda14cbcSMatt Macy 2472eda14cbcSMatt Macy case NVS_OP_DECODE: 2473eda14cbcSMatt Macy err = nvs_decode_pairs(nvs, nvl); 2474eda14cbcSMatt Macy break; 2475eda14cbcSMatt Macy 2476eda14cbcSMatt Macy case NVS_OP_GETSIZE: 2477eda14cbcSMatt Macy err = nvs_getsize_pairs(nvs, nvl, buflen); 2478eda14cbcSMatt Macy break; 2479eda14cbcSMatt Macy 2480eda14cbcSMatt Macy default: 2481eda14cbcSMatt Macy err = EINVAL; 2482eda14cbcSMatt Macy } 2483eda14cbcSMatt Macy 2484eda14cbcSMatt Macy return (err); 2485eda14cbcSMatt Macy } 2486eda14cbcSMatt Macy 2487eda14cbcSMatt Macy static int 2488eda14cbcSMatt Macy nvs_embedded(nvstream_t *nvs, nvlist_t *embedded) 2489eda14cbcSMatt Macy { 2490eda14cbcSMatt Macy switch (nvs->nvs_op) { 2491eda14cbcSMatt Macy case NVS_OP_ENCODE: { 2492eda14cbcSMatt Macy int err; 2493eda14cbcSMatt Macy 2494eda14cbcSMatt Macy if (nvs->nvs_recursion >= nvpair_max_recursion) 2495eda14cbcSMatt Macy return (EINVAL); 2496eda14cbcSMatt Macy nvs->nvs_recursion++; 2497eda14cbcSMatt Macy err = nvs_operation(nvs, embedded, NULL); 2498eda14cbcSMatt Macy nvs->nvs_recursion--; 2499eda14cbcSMatt Macy return (err); 2500eda14cbcSMatt Macy } 2501eda14cbcSMatt Macy case NVS_OP_DECODE: { 2502eda14cbcSMatt Macy nvpriv_t *priv; 2503eda14cbcSMatt Macy int err; 2504eda14cbcSMatt Macy 2505eda14cbcSMatt Macy if (embedded->nvl_version != NV_VERSION) 2506eda14cbcSMatt Macy return (ENOTSUP); 2507eda14cbcSMatt Macy 2508eda14cbcSMatt Macy if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL) 2509eda14cbcSMatt Macy return (ENOMEM); 2510eda14cbcSMatt Macy 2511eda14cbcSMatt Macy nvlist_init(embedded, embedded->nvl_nvflag, priv); 2512eda14cbcSMatt Macy 2513eda14cbcSMatt Macy if (nvs->nvs_recursion >= nvpair_max_recursion) { 2514eda14cbcSMatt Macy nvlist_free(embedded); 2515eda14cbcSMatt Macy return (EINVAL); 2516eda14cbcSMatt Macy } 2517eda14cbcSMatt Macy nvs->nvs_recursion++; 2518eda14cbcSMatt Macy if ((err = nvs_operation(nvs, embedded, NULL)) != 0) 2519eda14cbcSMatt Macy nvlist_free(embedded); 2520eda14cbcSMatt Macy nvs->nvs_recursion--; 2521eda14cbcSMatt Macy return (err); 2522eda14cbcSMatt Macy } 2523eda14cbcSMatt Macy default: 2524eda14cbcSMatt Macy break; 2525eda14cbcSMatt Macy } 2526eda14cbcSMatt Macy 2527eda14cbcSMatt Macy return (EINVAL); 2528eda14cbcSMatt Macy } 2529eda14cbcSMatt Macy 2530eda14cbcSMatt Macy static int 2531eda14cbcSMatt Macy nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2532eda14cbcSMatt Macy { 2533eda14cbcSMatt Macy size_t nelem = NVP_NELEM(nvp); 2534eda14cbcSMatt Macy nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 2535eda14cbcSMatt Macy int i; 2536eda14cbcSMatt Macy 2537eda14cbcSMatt Macy switch (nvs->nvs_op) { 2538eda14cbcSMatt Macy case NVS_OP_ENCODE: 2539eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 2540eda14cbcSMatt Macy if (nvs_embedded(nvs, nvlp[i]) != 0) 2541eda14cbcSMatt Macy return (EFAULT); 2542eda14cbcSMatt Macy break; 2543eda14cbcSMatt Macy 2544eda14cbcSMatt Macy case NVS_OP_DECODE: { 2545eda14cbcSMatt Macy size_t len = nelem * sizeof (uint64_t); 2546eda14cbcSMatt Macy nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len); 2547eda14cbcSMatt Macy 2548da5137abSMartin Matuska memset(nvlp, 0, len); /* don't trust packed data */ 2549eda14cbcSMatt Macy for (i = 0; i < nelem; i++) { 2550eda14cbcSMatt Macy if (nvs_embedded(nvs, embedded) != 0) { 2551eda14cbcSMatt Macy nvpair_free(nvp); 2552eda14cbcSMatt Macy return (EFAULT); 2553eda14cbcSMatt Macy } 2554eda14cbcSMatt Macy 2555eda14cbcSMatt Macy nvlp[i] = embedded++; 2556eda14cbcSMatt Macy } 2557eda14cbcSMatt Macy break; 2558eda14cbcSMatt Macy } 2559eda14cbcSMatt Macy case NVS_OP_GETSIZE: { 2560eda14cbcSMatt Macy uint64_t nvsize = 0; 2561eda14cbcSMatt Macy 2562eda14cbcSMatt Macy for (i = 0; i < nelem; i++) { 2563eda14cbcSMatt Macy size_t nvp_sz = 0; 2564eda14cbcSMatt Macy 2565eda14cbcSMatt Macy if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0) 2566eda14cbcSMatt Macy return (EINVAL); 2567eda14cbcSMatt Macy 2568eda14cbcSMatt Macy if ((nvsize += nvp_sz) > INT32_MAX) 2569eda14cbcSMatt Macy return (EINVAL); 2570eda14cbcSMatt Macy } 2571eda14cbcSMatt Macy 2572eda14cbcSMatt Macy *size = nvsize; 2573eda14cbcSMatt Macy break; 2574eda14cbcSMatt Macy } 2575eda14cbcSMatt Macy default: 2576eda14cbcSMatt Macy return (EINVAL); 2577eda14cbcSMatt Macy } 2578eda14cbcSMatt Macy 2579eda14cbcSMatt Macy return (0); 2580eda14cbcSMatt Macy } 2581eda14cbcSMatt Macy 2582eda14cbcSMatt Macy static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *); 2583eda14cbcSMatt Macy static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *); 2584eda14cbcSMatt Macy 2585eda14cbcSMatt Macy /* 2586eda14cbcSMatt Macy * Common routine for nvlist operations: 2587eda14cbcSMatt Macy * encode, decode, getsize (encoded size). 2588eda14cbcSMatt Macy */ 2589eda14cbcSMatt Macy static int 2590eda14cbcSMatt Macy nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding, 2591eda14cbcSMatt Macy int nvs_op) 2592eda14cbcSMatt Macy { 2593eda14cbcSMatt Macy int err = 0; 2594eda14cbcSMatt Macy nvstream_t nvs; 2595eda14cbcSMatt Macy int nvl_endian; 2596eda14cbcSMatt Macy #if defined(_ZFS_LITTLE_ENDIAN) 2597eda14cbcSMatt Macy int host_endian = 1; 2598eda14cbcSMatt Macy #elif defined(_ZFS_BIG_ENDIAN) 2599eda14cbcSMatt Macy int host_endian = 0; 2600eda14cbcSMatt Macy #else 2601eda14cbcSMatt Macy #error "No endian defined!" 2602eda14cbcSMatt Macy #endif /* _ZFS_LITTLE_ENDIAN */ 2603eda14cbcSMatt Macy nvs_header_t *nvh; 2604eda14cbcSMatt Macy 2605eda14cbcSMatt Macy if (buflen == NULL || nvl == NULL || 2606eda14cbcSMatt Macy (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 2607eda14cbcSMatt Macy return (EINVAL); 2608eda14cbcSMatt Macy 2609eda14cbcSMatt Macy nvs.nvs_op = nvs_op; 2610eda14cbcSMatt Macy nvs.nvs_recursion = 0; 2611eda14cbcSMatt Macy 2612eda14cbcSMatt Macy /* 2613eda14cbcSMatt Macy * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and 2614eda14cbcSMatt Macy * a buffer is allocated. The first 4 bytes in the buffer are 2615eda14cbcSMatt Macy * used for encoding method and host endian. 2616eda14cbcSMatt Macy */ 2617eda14cbcSMatt Macy switch (nvs_op) { 2618eda14cbcSMatt Macy case NVS_OP_ENCODE: 2619eda14cbcSMatt Macy if (buf == NULL || *buflen < sizeof (nvs_header_t)) 2620eda14cbcSMatt Macy return (EINVAL); 2621eda14cbcSMatt Macy 2622eda14cbcSMatt Macy nvh = (void *)buf; 2623eda14cbcSMatt Macy nvh->nvh_encoding = encoding; 2624eda14cbcSMatt Macy nvh->nvh_endian = nvl_endian = host_endian; 2625eda14cbcSMatt Macy nvh->nvh_reserved1 = 0; 2626eda14cbcSMatt Macy nvh->nvh_reserved2 = 0; 2627eda14cbcSMatt Macy break; 2628eda14cbcSMatt Macy 2629eda14cbcSMatt Macy case NVS_OP_DECODE: 2630eda14cbcSMatt Macy if (buf == NULL || *buflen < sizeof (nvs_header_t)) 2631eda14cbcSMatt Macy return (EINVAL); 2632eda14cbcSMatt Macy 2633eda14cbcSMatt Macy /* get method of encoding from first byte */ 2634eda14cbcSMatt Macy nvh = (void *)buf; 2635eda14cbcSMatt Macy encoding = nvh->nvh_encoding; 2636eda14cbcSMatt Macy nvl_endian = nvh->nvh_endian; 2637eda14cbcSMatt Macy break; 2638eda14cbcSMatt Macy 2639eda14cbcSMatt Macy case NVS_OP_GETSIZE: 2640eda14cbcSMatt Macy nvl_endian = host_endian; 2641eda14cbcSMatt Macy 2642eda14cbcSMatt Macy /* 2643eda14cbcSMatt Macy * add the size for encoding 2644eda14cbcSMatt Macy */ 2645eda14cbcSMatt Macy *buflen = sizeof (nvs_header_t); 2646eda14cbcSMatt Macy break; 2647eda14cbcSMatt Macy 2648eda14cbcSMatt Macy default: 2649eda14cbcSMatt Macy return (ENOTSUP); 2650eda14cbcSMatt Macy } 2651eda14cbcSMatt Macy 2652eda14cbcSMatt Macy /* 2653eda14cbcSMatt Macy * Create an nvstream with proper encoding method 2654eda14cbcSMatt Macy */ 2655eda14cbcSMatt Macy switch (encoding) { 2656eda14cbcSMatt Macy case NV_ENCODE_NATIVE: 2657eda14cbcSMatt Macy /* 2658eda14cbcSMatt Macy * check endianness, in case we are unpacking 2659eda14cbcSMatt Macy * from a file 2660eda14cbcSMatt Macy */ 2661eda14cbcSMatt Macy if (nvl_endian != host_endian) 2662eda14cbcSMatt Macy return (ENOTSUP); 2663eda14cbcSMatt Macy err = nvs_native(&nvs, nvl, buf, buflen); 2664eda14cbcSMatt Macy break; 2665eda14cbcSMatt Macy case NV_ENCODE_XDR: 2666eda14cbcSMatt Macy err = nvs_xdr(&nvs, nvl, buf, buflen); 2667eda14cbcSMatt Macy break; 2668eda14cbcSMatt Macy default: 2669eda14cbcSMatt Macy err = ENOTSUP; 2670eda14cbcSMatt Macy break; 2671eda14cbcSMatt Macy } 2672eda14cbcSMatt Macy 2673eda14cbcSMatt Macy return (err); 2674eda14cbcSMatt Macy } 2675eda14cbcSMatt Macy 2676eda14cbcSMatt Macy int 2677eda14cbcSMatt Macy nvlist_size(nvlist_t *nvl, size_t *size, int encoding) 2678eda14cbcSMatt Macy { 2679eda14cbcSMatt Macy return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE)); 2680eda14cbcSMatt Macy } 2681eda14cbcSMatt Macy 2682eda14cbcSMatt Macy /* 2683eda14cbcSMatt Macy * Pack nvlist into contiguous memory 2684eda14cbcSMatt Macy */ 2685eda14cbcSMatt Macy int 2686eda14cbcSMatt Macy nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 2687eda14cbcSMatt Macy int kmflag) 2688eda14cbcSMatt Macy { 2689eda14cbcSMatt Macy return (nvlist_xpack(nvl, bufp, buflen, encoding, 2690eda14cbcSMatt Macy nvlist_nv_alloc(kmflag))); 2691eda14cbcSMatt Macy } 2692eda14cbcSMatt Macy 2693eda14cbcSMatt Macy int 2694eda14cbcSMatt Macy nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 2695eda14cbcSMatt Macy nv_alloc_t *nva) 2696eda14cbcSMatt Macy { 2697eda14cbcSMatt Macy nvpriv_t nvpriv; 2698eda14cbcSMatt Macy size_t alloc_size; 2699eda14cbcSMatt Macy char *buf; 2700eda14cbcSMatt Macy int err; 2701eda14cbcSMatt Macy 2702eda14cbcSMatt Macy if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL) 2703eda14cbcSMatt Macy return (EINVAL); 2704eda14cbcSMatt Macy 2705eda14cbcSMatt Macy if (*bufp != NULL) 2706eda14cbcSMatt Macy return (nvlist_common(nvl, *bufp, buflen, encoding, 2707eda14cbcSMatt Macy NVS_OP_ENCODE)); 2708eda14cbcSMatt Macy 2709eda14cbcSMatt Macy /* 2710eda14cbcSMatt Macy * Here is a difficult situation: 2711eda14cbcSMatt Macy * 1. The nvlist has fixed allocator properties. 2712eda14cbcSMatt Macy * All other nvlist routines (like nvlist_add_*, ...) use 2713eda14cbcSMatt Macy * these properties. 2714eda14cbcSMatt Macy * 2. When using nvlist_pack() the user can specify their own 2715eda14cbcSMatt Macy * allocator properties (e.g. by using KM_NOSLEEP). 2716eda14cbcSMatt Macy * 2717eda14cbcSMatt Macy * We use the user specified properties (2). A clearer solution 2718eda14cbcSMatt Macy * will be to remove the kmflag from nvlist_pack(), but we will 2719eda14cbcSMatt Macy * not change the interface. 2720eda14cbcSMatt Macy */ 2721eda14cbcSMatt Macy nv_priv_init(&nvpriv, nva, 0); 2722eda14cbcSMatt Macy 2723eda14cbcSMatt Macy if ((err = nvlist_size(nvl, &alloc_size, encoding))) 2724eda14cbcSMatt Macy return (err); 2725eda14cbcSMatt Macy 2726eda14cbcSMatt Macy if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL) 2727eda14cbcSMatt Macy return (ENOMEM); 2728eda14cbcSMatt Macy 2729eda14cbcSMatt Macy if ((err = nvlist_common(nvl, buf, &alloc_size, encoding, 2730eda14cbcSMatt Macy NVS_OP_ENCODE)) != 0) { 2731eda14cbcSMatt Macy nv_mem_free(&nvpriv, buf, alloc_size); 2732eda14cbcSMatt Macy } else { 2733eda14cbcSMatt Macy *buflen = alloc_size; 2734eda14cbcSMatt Macy *bufp = buf; 2735eda14cbcSMatt Macy } 2736eda14cbcSMatt Macy 2737eda14cbcSMatt Macy return (err); 2738eda14cbcSMatt Macy } 2739eda14cbcSMatt Macy 2740eda14cbcSMatt Macy /* 2741eda14cbcSMatt Macy * Unpack buf into an nvlist_t 2742eda14cbcSMatt Macy */ 2743eda14cbcSMatt Macy int 2744eda14cbcSMatt Macy nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag) 2745eda14cbcSMatt Macy { 2746eda14cbcSMatt Macy return (nvlist_xunpack(buf, buflen, nvlp, nvlist_nv_alloc(kmflag))); 2747eda14cbcSMatt Macy } 2748eda14cbcSMatt Macy 2749eda14cbcSMatt Macy int 2750eda14cbcSMatt Macy nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva) 2751eda14cbcSMatt Macy { 2752eda14cbcSMatt Macy nvlist_t *nvl; 2753eda14cbcSMatt Macy int err; 2754eda14cbcSMatt Macy 2755eda14cbcSMatt Macy if (nvlp == NULL) 2756eda14cbcSMatt Macy return (EINVAL); 2757eda14cbcSMatt Macy 2758eda14cbcSMatt Macy if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0) 2759eda14cbcSMatt Macy return (err); 2760eda14cbcSMatt Macy 2761eda14cbcSMatt Macy if ((err = nvlist_common(nvl, buf, &buflen, NV_ENCODE_NATIVE, 2762eda14cbcSMatt Macy NVS_OP_DECODE)) != 0) 2763eda14cbcSMatt Macy nvlist_free(nvl); 2764eda14cbcSMatt Macy else 2765eda14cbcSMatt Macy *nvlp = nvl; 2766eda14cbcSMatt Macy 2767eda14cbcSMatt Macy return (err); 2768eda14cbcSMatt Macy } 2769eda14cbcSMatt Macy 2770eda14cbcSMatt Macy /* 2771eda14cbcSMatt Macy * Native encoding functions 2772eda14cbcSMatt Macy */ 2773eda14cbcSMatt Macy typedef struct { 2774eda14cbcSMatt Macy /* 2775eda14cbcSMatt Macy * This structure is used when decoding a packed nvpair in 2776eda14cbcSMatt Macy * the native format. n_base points to a buffer containing the 2777eda14cbcSMatt Macy * packed nvpair. n_end is a pointer to the end of the buffer. 2778eda14cbcSMatt Macy * (n_end actually points to the first byte past the end of the 2779eda14cbcSMatt Macy * buffer.) n_curr is a pointer that lies between n_base and n_end. 2780eda14cbcSMatt Macy * It points to the current data that we are decoding. 2781eda14cbcSMatt Macy * The amount of data left in the buffer is equal to n_end - n_curr. 2782eda14cbcSMatt Macy * n_flag is used to recognize a packed embedded list. 2783eda14cbcSMatt Macy */ 2784eda14cbcSMatt Macy caddr_t n_base; 2785eda14cbcSMatt Macy caddr_t n_end; 2786eda14cbcSMatt Macy caddr_t n_curr; 2787eda14cbcSMatt Macy uint_t n_flag; 2788eda14cbcSMatt Macy } nvs_native_t; 2789eda14cbcSMatt Macy 2790eda14cbcSMatt Macy static int 2791eda14cbcSMatt Macy nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf, 2792eda14cbcSMatt Macy size_t buflen) 2793eda14cbcSMatt Macy { 2794eda14cbcSMatt Macy switch (nvs->nvs_op) { 2795eda14cbcSMatt Macy case NVS_OP_ENCODE: 2796eda14cbcSMatt Macy case NVS_OP_DECODE: 2797eda14cbcSMatt Macy nvs->nvs_private = native; 2798eda14cbcSMatt Macy native->n_curr = native->n_base = buf; 2799eda14cbcSMatt Macy native->n_end = buf + buflen; 2800eda14cbcSMatt Macy native->n_flag = 0; 2801eda14cbcSMatt Macy return (0); 2802eda14cbcSMatt Macy 2803eda14cbcSMatt Macy case NVS_OP_GETSIZE: 2804eda14cbcSMatt Macy nvs->nvs_private = native; 2805eda14cbcSMatt Macy native->n_curr = native->n_base = native->n_end = NULL; 2806eda14cbcSMatt Macy native->n_flag = 0; 2807eda14cbcSMatt Macy return (0); 2808eda14cbcSMatt Macy default: 2809eda14cbcSMatt Macy return (EINVAL); 2810eda14cbcSMatt Macy } 2811eda14cbcSMatt Macy } 2812eda14cbcSMatt Macy 2813eda14cbcSMatt Macy static void 2814eda14cbcSMatt Macy nvs_native_destroy(nvstream_t *nvs) 2815eda14cbcSMatt Macy { 28162a58b312SMartin Matuska nvs->nvs_private = NULL; 2817eda14cbcSMatt Macy } 2818eda14cbcSMatt Macy 2819eda14cbcSMatt Macy static int 2820eda14cbcSMatt Macy native_cp(nvstream_t *nvs, void *buf, size_t size) 2821eda14cbcSMatt Macy { 2822eda14cbcSMatt Macy nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2823eda14cbcSMatt Macy 2824eda14cbcSMatt Macy if (native->n_curr + size > native->n_end) 2825eda14cbcSMatt Macy return (EFAULT); 2826eda14cbcSMatt Macy 2827eda14cbcSMatt Macy /* 2828da5137abSMartin Matuska * The memcpy() below eliminates alignment requirement 2829eda14cbcSMatt Macy * on the buffer (stream) and is preferred over direct access. 2830eda14cbcSMatt Macy */ 2831eda14cbcSMatt Macy switch (nvs->nvs_op) { 2832eda14cbcSMatt Macy case NVS_OP_ENCODE: 2833da5137abSMartin Matuska memcpy(native->n_curr, buf, size); 2834eda14cbcSMatt Macy break; 2835eda14cbcSMatt Macy case NVS_OP_DECODE: 2836da5137abSMartin Matuska memcpy(buf, native->n_curr, size); 2837eda14cbcSMatt Macy break; 2838eda14cbcSMatt Macy default: 2839eda14cbcSMatt Macy return (EINVAL); 2840eda14cbcSMatt Macy } 2841eda14cbcSMatt Macy 2842eda14cbcSMatt Macy native->n_curr += size; 2843eda14cbcSMatt Macy return (0); 2844eda14cbcSMatt Macy } 2845eda14cbcSMatt Macy 2846eda14cbcSMatt Macy /* 2847eda14cbcSMatt Macy * operate on nvlist_t header 2848eda14cbcSMatt Macy */ 2849eda14cbcSMatt Macy static int 2850eda14cbcSMatt Macy nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 2851eda14cbcSMatt Macy { 2852eda14cbcSMatt Macy nvs_native_t *native = nvs->nvs_private; 2853eda14cbcSMatt Macy 2854eda14cbcSMatt Macy switch (nvs->nvs_op) { 2855eda14cbcSMatt Macy case NVS_OP_ENCODE: 2856eda14cbcSMatt Macy case NVS_OP_DECODE: 2857eda14cbcSMatt Macy if (native->n_flag) 2858eda14cbcSMatt Macy return (0); /* packed embedded list */ 2859eda14cbcSMatt Macy 2860eda14cbcSMatt Macy native->n_flag = 1; 2861eda14cbcSMatt Macy 2862eda14cbcSMatt Macy /* copy version and nvflag of the nvlist_t */ 2863eda14cbcSMatt Macy if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 || 2864eda14cbcSMatt Macy native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0) 2865eda14cbcSMatt Macy return (EFAULT); 2866eda14cbcSMatt Macy 2867eda14cbcSMatt Macy return (0); 2868eda14cbcSMatt Macy 2869eda14cbcSMatt Macy case NVS_OP_GETSIZE: 2870eda14cbcSMatt Macy /* 2871eda14cbcSMatt Macy * if calculate for packed embedded list 2872eda14cbcSMatt Macy * 4 for end of the embedded list 2873eda14cbcSMatt Macy * else 2874eda14cbcSMatt Macy * 2 * sizeof (int32_t) for nvl_version and nvl_nvflag 2875eda14cbcSMatt Macy * and 4 for end of the entire list 2876eda14cbcSMatt Macy */ 2877eda14cbcSMatt Macy if (native->n_flag) { 2878eda14cbcSMatt Macy *size += 4; 2879eda14cbcSMatt Macy } else { 2880eda14cbcSMatt Macy native->n_flag = 1; 2881eda14cbcSMatt Macy *size += 2 * sizeof (int32_t) + 4; 2882eda14cbcSMatt Macy } 2883eda14cbcSMatt Macy 2884eda14cbcSMatt Macy return (0); 2885eda14cbcSMatt Macy 2886eda14cbcSMatt Macy default: 2887eda14cbcSMatt Macy return (EINVAL); 2888eda14cbcSMatt Macy } 2889eda14cbcSMatt Macy } 2890eda14cbcSMatt Macy 2891eda14cbcSMatt Macy static int 2892eda14cbcSMatt Macy nvs_native_nvl_fini(nvstream_t *nvs) 2893eda14cbcSMatt Macy { 2894eda14cbcSMatt Macy if (nvs->nvs_op == NVS_OP_ENCODE) { 2895eda14cbcSMatt Macy nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2896eda14cbcSMatt Macy /* 2897eda14cbcSMatt Macy * Add 4 zero bytes at end of nvlist. They are used 2898eda14cbcSMatt Macy * for end detection by the decode routine. 2899eda14cbcSMatt Macy */ 2900eda14cbcSMatt Macy if (native->n_curr + sizeof (int) > native->n_end) 2901eda14cbcSMatt Macy return (EFAULT); 2902eda14cbcSMatt Macy 2903da5137abSMartin Matuska memset(native->n_curr, 0, sizeof (int)); 2904eda14cbcSMatt Macy native->n_curr += sizeof (int); 2905eda14cbcSMatt Macy } 2906eda14cbcSMatt Macy 2907eda14cbcSMatt Macy return (0); 2908eda14cbcSMatt Macy } 2909eda14cbcSMatt Macy 2910eda14cbcSMatt Macy static int 2911eda14cbcSMatt Macy nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp) 2912eda14cbcSMatt Macy { 2913eda14cbcSMatt Macy if (nvs->nvs_op == NVS_OP_ENCODE) { 2914eda14cbcSMatt Macy nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2915eda14cbcSMatt Macy nvlist_t *packed = (void *) 2916eda14cbcSMatt Macy (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 2917eda14cbcSMatt Macy /* 2918eda14cbcSMatt Macy * Null out the pointer that is meaningless in the packed 2919eda14cbcSMatt Macy * structure. The address may not be aligned, so we have 2920da5137abSMartin Matuska * to use memset. 2921eda14cbcSMatt Macy */ 2922da5137abSMartin Matuska memset((char *)packed + offsetof(nvlist_t, nvl_priv), 2923da5137abSMartin Matuska 0, sizeof (uint64_t)); 2924eda14cbcSMatt Macy } 2925eda14cbcSMatt Macy 2926eda14cbcSMatt Macy return (nvs_embedded(nvs, EMBEDDED_NVL(nvp))); 2927eda14cbcSMatt Macy } 2928eda14cbcSMatt Macy 2929eda14cbcSMatt Macy static int 2930eda14cbcSMatt Macy nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp) 2931eda14cbcSMatt Macy { 2932eda14cbcSMatt Macy if (nvs->nvs_op == NVS_OP_ENCODE) { 2933eda14cbcSMatt Macy nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2934eda14cbcSMatt Macy char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp); 2935eda14cbcSMatt Macy size_t len = NVP_NELEM(nvp) * sizeof (uint64_t); 2936eda14cbcSMatt Macy nvlist_t *packed = (nvlist_t *)((uintptr_t)value + len); 2937eda14cbcSMatt Macy int i; 2938eda14cbcSMatt Macy /* 2939eda14cbcSMatt Macy * Null out pointers that are meaningless in the packed 2940eda14cbcSMatt Macy * structure. The addresses may not be aligned, so we have 2941da5137abSMartin Matuska * to use memset. 2942eda14cbcSMatt Macy */ 2943da5137abSMartin Matuska memset(value, 0, len); 2944eda14cbcSMatt Macy 2945eda14cbcSMatt Macy for (i = 0; i < NVP_NELEM(nvp); i++, packed++) 2946eda14cbcSMatt Macy /* 2947eda14cbcSMatt Macy * Null out the pointer that is meaningless in the 2948eda14cbcSMatt Macy * packed structure. The address may not be aligned, 2949da5137abSMartin Matuska * so we have to use memset. 2950eda14cbcSMatt Macy */ 2951da5137abSMartin Matuska memset((char *)packed + offsetof(nvlist_t, nvl_priv), 2952da5137abSMartin Matuska 0, sizeof (uint64_t)); 2953eda14cbcSMatt Macy } 2954eda14cbcSMatt Macy 2955eda14cbcSMatt Macy return (nvs_embedded_nvl_array(nvs, nvp, NULL)); 2956eda14cbcSMatt Macy } 2957eda14cbcSMatt Macy 2958eda14cbcSMatt Macy static void 2959eda14cbcSMatt Macy nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp) 2960eda14cbcSMatt Macy { 2961eda14cbcSMatt Macy switch (nvs->nvs_op) { 2962eda14cbcSMatt Macy case NVS_OP_ENCODE: { 2963eda14cbcSMatt Macy nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2964eda14cbcSMatt Macy uint64_t *strp = (void *) 2965eda14cbcSMatt Macy (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 2966eda14cbcSMatt Macy /* 2967eda14cbcSMatt Macy * Null out pointers that are meaningless in the packed 2968eda14cbcSMatt Macy * structure. The addresses may not be aligned, so we have 2969da5137abSMartin Matuska * to use memset. 2970eda14cbcSMatt Macy */ 2971da5137abSMartin Matuska memset(strp, 0, NVP_NELEM(nvp) * sizeof (uint64_t)); 2972eda14cbcSMatt Macy break; 2973eda14cbcSMatt Macy } 2974eda14cbcSMatt Macy case NVS_OP_DECODE: { 2975eda14cbcSMatt Macy char **strp = (void *)NVP_VALUE(nvp); 2976eda14cbcSMatt Macy char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t)); 2977eda14cbcSMatt Macy int i; 2978eda14cbcSMatt Macy 2979eda14cbcSMatt Macy for (i = 0; i < NVP_NELEM(nvp); i++) { 2980eda14cbcSMatt Macy strp[i] = buf; 2981eda14cbcSMatt Macy buf += strlen(buf) + 1; 2982eda14cbcSMatt Macy } 2983eda14cbcSMatt Macy break; 2984eda14cbcSMatt Macy } 2985eda14cbcSMatt Macy } 2986eda14cbcSMatt Macy } 2987eda14cbcSMatt Macy 2988eda14cbcSMatt Macy static int 2989eda14cbcSMatt Macy nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 2990eda14cbcSMatt Macy { 2991eda14cbcSMatt Macy data_type_t type; 2992eda14cbcSMatt Macy int value_sz; 2993eda14cbcSMatt Macy int ret = 0; 2994eda14cbcSMatt Macy 2995eda14cbcSMatt Macy /* 2996da5137abSMartin Matuska * We do the initial memcpy of the data before we look at 2997eda14cbcSMatt Macy * the nvpair type, because when we're decoding, we won't 2998da5137abSMartin Matuska * have the correct values for the pair until we do the memcpy. 2999eda14cbcSMatt Macy */ 3000eda14cbcSMatt Macy switch (nvs->nvs_op) { 3001eda14cbcSMatt Macy case NVS_OP_ENCODE: 3002eda14cbcSMatt Macy case NVS_OP_DECODE: 3003eda14cbcSMatt Macy if (native_cp(nvs, nvp, nvp->nvp_size) != 0) 3004eda14cbcSMatt Macy return (EFAULT); 3005eda14cbcSMatt Macy break; 3006eda14cbcSMatt Macy default: 3007eda14cbcSMatt Macy return (EINVAL); 3008eda14cbcSMatt Macy } 3009eda14cbcSMatt Macy 3010eda14cbcSMatt Macy /* verify nvp_name_sz, check the name string length */ 3011eda14cbcSMatt Macy if (i_validate_nvpair_name(nvp) != 0) 3012eda14cbcSMatt Macy return (EFAULT); 3013eda14cbcSMatt Macy 3014eda14cbcSMatt Macy type = NVP_TYPE(nvp); 3015eda14cbcSMatt Macy 3016eda14cbcSMatt Macy /* 3017eda14cbcSMatt Macy * Verify type and nelem and get the value size. 3018eda14cbcSMatt Macy * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 3019eda14cbcSMatt Macy * is the size of the string(s) excluded. 3020eda14cbcSMatt Macy */ 3021eda14cbcSMatt Macy if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0) 3022eda14cbcSMatt Macy return (EFAULT); 3023eda14cbcSMatt Macy 3024eda14cbcSMatt Macy if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size) 3025eda14cbcSMatt Macy return (EFAULT); 3026eda14cbcSMatt Macy 3027eda14cbcSMatt Macy switch (type) { 3028eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 3029eda14cbcSMatt Macy ret = nvpair_native_embedded(nvs, nvp); 3030eda14cbcSMatt Macy break; 3031eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: 3032eda14cbcSMatt Macy ret = nvpair_native_embedded_array(nvs, nvp); 3033eda14cbcSMatt Macy break; 3034eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: 3035eda14cbcSMatt Macy nvpair_native_string_array(nvs, nvp); 3036eda14cbcSMatt Macy break; 3037eda14cbcSMatt Macy default: 3038eda14cbcSMatt Macy break; 3039eda14cbcSMatt Macy } 3040eda14cbcSMatt Macy 3041eda14cbcSMatt Macy return (ret); 3042eda14cbcSMatt Macy } 3043eda14cbcSMatt Macy 3044eda14cbcSMatt Macy static int 3045eda14cbcSMatt Macy nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 3046eda14cbcSMatt Macy { 3047eda14cbcSMatt Macy uint64_t nvp_sz = nvp->nvp_size; 3048eda14cbcSMatt Macy 3049eda14cbcSMatt Macy switch (NVP_TYPE(nvp)) { 3050eda14cbcSMatt Macy case DATA_TYPE_NVLIST: { 3051eda14cbcSMatt Macy size_t nvsize = 0; 3052eda14cbcSMatt Macy 3053eda14cbcSMatt Macy if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0) 3054eda14cbcSMatt Macy return (EINVAL); 3055eda14cbcSMatt Macy 3056eda14cbcSMatt Macy nvp_sz += nvsize; 3057eda14cbcSMatt Macy break; 3058eda14cbcSMatt Macy } 3059eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: { 3060eda14cbcSMatt Macy size_t nvsize; 3061eda14cbcSMatt Macy 3062eda14cbcSMatt Macy if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0) 3063eda14cbcSMatt Macy return (EINVAL); 3064eda14cbcSMatt Macy 3065eda14cbcSMatt Macy nvp_sz += nvsize; 3066eda14cbcSMatt Macy break; 3067eda14cbcSMatt Macy } 3068eda14cbcSMatt Macy default: 3069eda14cbcSMatt Macy break; 3070eda14cbcSMatt Macy } 3071eda14cbcSMatt Macy 3072eda14cbcSMatt Macy if (nvp_sz > INT32_MAX) 3073eda14cbcSMatt Macy return (EINVAL); 3074eda14cbcSMatt Macy 3075eda14cbcSMatt Macy *size = nvp_sz; 3076eda14cbcSMatt Macy 3077eda14cbcSMatt Macy return (0); 3078eda14cbcSMatt Macy } 3079eda14cbcSMatt Macy 3080eda14cbcSMatt Macy static int 3081eda14cbcSMatt Macy nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 3082eda14cbcSMatt Macy { 3083eda14cbcSMatt Macy switch (nvs->nvs_op) { 3084eda14cbcSMatt Macy case NVS_OP_ENCODE: 3085eda14cbcSMatt Macy return (nvs_native_nvp_op(nvs, nvp)); 3086eda14cbcSMatt Macy 3087eda14cbcSMatt Macy case NVS_OP_DECODE: { 3088eda14cbcSMatt Macy nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 3089eda14cbcSMatt Macy int32_t decode_len; 3090eda14cbcSMatt Macy 3091eda14cbcSMatt Macy /* try to read the size value from the stream */ 3092eda14cbcSMatt Macy if (native->n_curr + sizeof (int32_t) > native->n_end) 3093eda14cbcSMatt Macy return (EFAULT); 3094da5137abSMartin Matuska memcpy(&decode_len, native->n_curr, sizeof (int32_t)); 3095eda14cbcSMatt Macy 3096eda14cbcSMatt Macy /* sanity check the size value */ 3097eda14cbcSMatt Macy if (decode_len < 0 || 3098eda14cbcSMatt Macy decode_len > native->n_end - native->n_curr) 3099eda14cbcSMatt Macy return (EFAULT); 3100eda14cbcSMatt Macy 3101eda14cbcSMatt Macy *size = decode_len; 3102eda14cbcSMatt Macy 3103eda14cbcSMatt Macy /* 3104eda14cbcSMatt Macy * If at the end of the stream then move the cursor 3105eda14cbcSMatt Macy * forward, otherwise nvpair_native_op() will read 3106eda14cbcSMatt Macy * the entire nvpair at the same cursor position. 3107eda14cbcSMatt Macy */ 3108eda14cbcSMatt Macy if (*size == 0) 3109eda14cbcSMatt Macy native->n_curr += sizeof (int32_t); 3110eda14cbcSMatt Macy break; 3111eda14cbcSMatt Macy } 3112eda14cbcSMatt Macy 3113eda14cbcSMatt Macy default: 3114eda14cbcSMatt Macy return (EINVAL); 3115eda14cbcSMatt Macy } 3116eda14cbcSMatt Macy 3117eda14cbcSMatt Macy return (0); 3118eda14cbcSMatt Macy } 3119eda14cbcSMatt Macy 3120eda14cbcSMatt Macy static const nvs_ops_t nvs_native_ops = { 3121eda14cbcSMatt Macy .nvs_nvlist = nvs_native_nvlist, 3122eda14cbcSMatt Macy .nvs_nvpair = nvs_native_nvpair, 3123eda14cbcSMatt Macy .nvs_nvp_op = nvs_native_nvp_op, 3124eda14cbcSMatt Macy .nvs_nvp_size = nvs_native_nvp_size, 3125eda14cbcSMatt Macy .nvs_nvl_fini = nvs_native_nvl_fini 3126eda14cbcSMatt Macy }; 3127eda14cbcSMatt Macy 3128eda14cbcSMatt Macy static int 3129eda14cbcSMatt Macy nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen) 3130eda14cbcSMatt Macy { 3131eda14cbcSMatt Macy nvs_native_t native; 3132eda14cbcSMatt Macy int err; 3133eda14cbcSMatt Macy 3134eda14cbcSMatt Macy nvs->nvs_ops = &nvs_native_ops; 3135eda14cbcSMatt Macy 3136eda14cbcSMatt Macy if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t), 3137eda14cbcSMatt Macy *buflen - sizeof (nvs_header_t))) != 0) 3138eda14cbcSMatt Macy return (err); 3139eda14cbcSMatt Macy 3140eda14cbcSMatt Macy err = nvs_operation(nvs, nvl, buflen); 3141eda14cbcSMatt Macy 3142eda14cbcSMatt Macy nvs_native_destroy(nvs); 3143eda14cbcSMatt Macy 3144eda14cbcSMatt Macy return (err); 3145eda14cbcSMatt Macy } 3146eda14cbcSMatt Macy 3147eda14cbcSMatt Macy /* 3148eda14cbcSMatt Macy * XDR encoding functions 3149eda14cbcSMatt Macy * 3150eda14cbcSMatt Macy * An xdr packed nvlist is encoded as: 3151eda14cbcSMatt Macy * 3152eda14cbcSMatt Macy * - encoding method and host endian (4 bytes) 3153eda14cbcSMatt Macy * - nvl_version (4 bytes) 3154eda14cbcSMatt Macy * - nvl_nvflag (4 bytes) 3155eda14cbcSMatt Macy * 3156eda14cbcSMatt Macy * - encoded nvpairs, the format of one xdr encoded nvpair is: 3157eda14cbcSMatt Macy * - encoded size of the nvpair (4 bytes) 3158eda14cbcSMatt Macy * - decoded size of the nvpair (4 bytes) 3159eda14cbcSMatt Macy * - name string, (4 + sizeof(NV_ALIGN4(string)) 3160eda14cbcSMatt Macy * a string is coded as size (4 bytes) and data 3161eda14cbcSMatt Macy * - data type (4 bytes) 3162eda14cbcSMatt Macy * - number of elements in the nvpair (4 bytes) 3163eda14cbcSMatt Macy * - data 3164eda14cbcSMatt Macy * 3165eda14cbcSMatt Macy * - 2 zero's for end of the entire list (8 bytes) 3166eda14cbcSMatt Macy */ 3167eda14cbcSMatt Macy static int 3168eda14cbcSMatt Macy nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen) 3169eda14cbcSMatt Macy { 3170eda14cbcSMatt Macy /* xdr data must be 4 byte aligned */ 3171eda14cbcSMatt Macy if ((ulong_t)buf % 4 != 0) 3172eda14cbcSMatt Macy return (EFAULT); 3173eda14cbcSMatt Macy 3174eda14cbcSMatt Macy switch (nvs->nvs_op) { 3175eda14cbcSMatt Macy case NVS_OP_ENCODE: 3176eda14cbcSMatt Macy xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE); 3177eda14cbcSMatt Macy nvs->nvs_private = xdr; 3178eda14cbcSMatt Macy return (0); 3179eda14cbcSMatt Macy case NVS_OP_DECODE: 3180eda14cbcSMatt Macy xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE); 3181eda14cbcSMatt Macy nvs->nvs_private = xdr; 3182eda14cbcSMatt Macy return (0); 3183eda14cbcSMatt Macy case NVS_OP_GETSIZE: 3184eda14cbcSMatt Macy nvs->nvs_private = NULL; 3185eda14cbcSMatt Macy return (0); 3186eda14cbcSMatt Macy default: 3187eda14cbcSMatt Macy return (EINVAL); 3188eda14cbcSMatt Macy } 3189eda14cbcSMatt Macy } 3190eda14cbcSMatt Macy 3191eda14cbcSMatt Macy static void 3192eda14cbcSMatt Macy nvs_xdr_destroy(nvstream_t *nvs) 3193eda14cbcSMatt Macy { 3194eda14cbcSMatt Macy switch (nvs->nvs_op) { 3195eda14cbcSMatt Macy case NVS_OP_ENCODE: 3196eda14cbcSMatt Macy case NVS_OP_DECODE: 31972a58b312SMartin Matuska nvs->nvs_private = NULL; 3198eda14cbcSMatt Macy break; 3199eda14cbcSMatt Macy default: 3200eda14cbcSMatt Macy break; 3201eda14cbcSMatt Macy } 3202eda14cbcSMatt Macy } 3203eda14cbcSMatt Macy 3204eda14cbcSMatt Macy static int 3205eda14cbcSMatt Macy nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 3206eda14cbcSMatt Macy { 3207eda14cbcSMatt Macy switch (nvs->nvs_op) { 3208eda14cbcSMatt Macy case NVS_OP_ENCODE: 3209eda14cbcSMatt Macy case NVS_OP_DECODE: { 3210eda14cbcSMatt Macy XDR *xdr = nvs->nvs_private; 3211eda14cbcSMatt Macy 3212eda14cbcSMatt Macy if (!xdr_int(xdr, &nvl->nvl_version) || 3213eda14cbcSMatt Macy !xdr_u_int(xdr, &nvl->nvl_nvflag)) 3214eda14cbcSMatt Macy return (EFAULT); 3215eda14cbcSMatt Macy break; 3216eda14cbcSMatt Macy } 3217eda14cbcSMatt Macy case NVS_OP_GETSIZE: { 3218eda14cbcSMatt Macy /* 3219eda14cbcSMatt Macy * 2 * 4 for nvl_version + nvl_nvflag 3220eda14cbcSMatt Macy * and 8 for end of the entire list 3221eda14cbcSMatt Macy */ 3222eda14cbcSMatt Macy *size += 2 * 4 + 8; 3223eda14cbcSMatt Macy break; 3224eda14cbcSMatt Macy } 3225eda14cbcSMatt Macy default: 3226eda14cbcSMatt Macy return (EINVAL); 3227eda14cbcSMatt Macy } 3228eda14cbcSMatt Macy return (0); 3229eda14cbcSMatt Macy } 3230eda14cbcSMatt Macy 3231eda14cbcSMatt Macy static int 3232eda14cbcSMatt Macy nvs_xdr_nvl_fini(nvstream_t *nvs) 3233eda14cbcSMatt Macy { 3234eda14cbcSMatt Macy if (nvs->nvs_op == NVS_OP_ENCODE) { 3235eda14cbcSMatt Macy XDR *xdr = nvs->nvs_private; 3236eda14cbcSMatt Macy int zero = 0; 3237eda14cbcSMatt Macy 3238eda14cbcSMatt Macy if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero)) 3239eda14cbcSMatt Macy return (EFAULT); 3240eda14cbcSMatt Macy } 3241eda14cbcSMatt Macy 3242eda14cbcSMatt Macy return (0); 3243eda14cbcSMatt Macy } 3244eda14cbcSMatt Macy 3245eda14cbcSMatt Macy /* 32463f9d360cSMartin Matuska * xdrproc_t-compatible callbacks for xdr_array() 32473f9d360cSMartin Matuska */ 32483f9d360cSMartin Matuska 32493f9d360cSMartin Matuska #if defined(_KERNEL) && defined(__linux__) /* Linux kernel */ 32503f9d360cSMartin Matuska 32513f9d360cSMartin Matuska #define NVS_BUILD_XDRPROC_T(type) \ 32523f9d360cSMartin Matuska static bool_t \ 32533f9d360cSMartin Matuska nvs_xdr_nvp_##type(XDR *xdrs, void *ptr) \ 32543f9d360cSMartin Matuska { \ 32553f9d360cSMartin Matuska return (xdr_##type(xdrs, ptr)); \ 32563f9d360cSMartin Matuska } 32573f9d360cSMartin Matuska 32583f9d360cSMartin Matuska #elif !defined(_KERNEL) && defined(XDR_CONTROL) /* tirpc */ 32593f9d360cSMartin Matuska 32603f9d360cSMartin Matuska #define NVS_BUILD_XDRPROC_T(type) \ 32613f9d360cSMartin Matuska static bool_t \ 32623f9d360cSMartin Matuska nvs_xdr_nvp_##type(XDR *xdrs, ...) \ 32633f9d360cSMartin Matuska { \ 32643f9d360cSMartin Matuska va_list args; \ 32653f9d360cSMartin Matuska void *ptr; \ 32663f9d360cSMartin Matuska \ 32673f9d360cSMartin Matuska va_start(args, xdrs); \ 32683f9d360cSMartin Matuska ptr = va_arg(args, void *); \ 32693f9d360cSMartin Matuska va_end(args); \ 32703f9d360cSMartin Matuska \ 32713f9d360cSMartin Matuska return (xdr_##type(xdrs, ptr)); \ 32723f9d360cSMartin Matuska } 32733f9d360cSMartin Matuska 32743f9d360cSMartin Matuska #else /* FreeBSD, sunrpc */ 32753f9d360cSMartin Matuska 32763f9d360cSMartin Matuska #define NVS_BUILD_XDRPROC_T(type) \ 32773f9d360cSMartin Matuska static bool_t \ 32783f9d360cSMartin Matuska nvs_xdr_nvp_##type(XDR *xdrs, void *ptr, ...) \ 32793f9d360cSMartin Matuska { \ 32803f9d360cSMartin Matuska return (xdr_##type(xdrs, ptr)); \ 32813f9d360cSMartin Matuska } 32823f9d360cSMartin Matuska 32833f9d360cSMartin Matuska #endif 32843f9d360cSMartin Matuska 32853f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(char); 32863f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(short); 32873f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(u_short); 32883f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(int); 32893f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(u_int); 32903f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(longlong_t); 32913f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(u_longlong_t); 32923f9d360cSMartin Matuska 32933f9d360cSMartin Matuska /* 3294eda14cbcSMatt Macy * The format of xdr encoded nvpair is: 3295eda14cbcSMatt Macy * encode_size, decode_size, name string, data type, nelem, data 3296eda14cbcSMatt Macy */ 3297eda14cbcSMatt Macy static int 3298eda14cbcSMatt Macy nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 3299eda14cbcSMatt Macy { 330081b22a98SMartin Matuska ASSERT(nvs != NULL && nvp != NULL); 330181b22a98SMartin Matuska 3302eda14cbcSMatt Macy data_type_t type; 3303eda14cbcSMatt Macy char *buf; 3304eda14cbcSMatt Macy char *buf_end = (char *)nvp + nvp->nvp_size; 3305eda14cbcSMatt Macy int value_sz; 3306eda14cbcSMatt Macy uint_t nelem, buflen; 3307eda14cbcSMatt Macy bool_t ret = FALSE; 3308eda14cbcSMatt Macy XDR *xdr = nvs->nvs_private; 3309eda14cbcSMatt Macy 331081b22a98SMartin Matuska ASSERT(xdr != NULL); 3311eda14cbcSMatt Macy 3312eda14cbcSMatt Macy /* name string */ 3313eda14cbcSMatt Macy if ((buf = NVP_NAME(nvp)) >= buf_end) 3314eda14cbcSMatt Macy return (EFAULT); 3315eda14cbcSMatt Macy buflen = buf_end - buf; 3316eda14cbcSMatt Macy 3317eda14cbcSMatt Macy if (!xdr_string(xdr, &buf, buflen - 1)) 3318eda14cbcSMatt Macy return (EFAULT); 3319eda14cbcSMatt Macy nvp->nvp_name_sz = strlen(buf) + 1; 3320eda14cbcSMatt Macy 3321eda14cbcSMatt Macy /* type and nelem */ 3322eda14cbcSMatt Macy if (!xdr_int(xdr, (int *)&nvp->nvp_type) || 3323eda14cbcSMatt Macy !xdr_int(xdr, &nvp->nvp_value_elem)) 3324eda14cbcSMatt Macy return (EFAULT); 3325eda14cbcSMatt Macy 3326eda14cbcSMatt Macy type = NVP_TYPE(nvp); 3327eda14cbcSMatt Macy nelem = nvp->nvp_value_elem; 3328eda14cbcSMatt Macy 3329eda14cbcSMatt Macy /* 3330eda14cbcSMatt Macy * Verify type and nelem and get the value size. 3331eda14cbcSMatt Macy * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 3332eda14cbcSMatt Macy * is the size of the string(s) excluded. 3333eda14cbcSMatt Macy */ 3334eda14cbcSMatt Macy if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0) 3335eda14cbcSMatt Macy return (EFAULT); 3336eda14cbcSMatt Macy 3337eda14cbcSMatt Macy /* if there is no data to extract then return */ 3338eda14cbcSMatt Macy if (nelem == 0) 3339eda14cbcSMatt Macy return (0); 3340eda14cbcSMatt Macy 3341eda14cbcSMatt Macy /* value */ 3342eda14cbcSMatt Macy if ((buf = NVP_VALUE(nvp)) >= buf_end) 3343eda14cbcSMatt Macy return (EFAULT); 3344eda14cbcSMatt Macy buflen = buf_end - buf; 3345eda14cbcSMatt Macy 3346eda14cbcSMatt Macy if (buflen < value_sz) 3347eda14cbcSMatt Macy return (EFAULT); 3348eda14cbcSMatt Macy 3349eda14cbcSMatt Macy switch (type) { 3350eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 3351eda14cbcSMatt Macy if (nvs_embedded(nvs, (void *)buf) == 0) 3352eda14cbcSMatt Macy return (0); 3353eda14cbcSMatt Macy break; 3354eda14cbcSMatt Macy 3355eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: 3356eda14cbcSMatt Macy if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0) 3357eda14cbcSMatt Macy return (0); 3358eda14cbcSMatt Macy break; 3359eda14cbcSMatt Macy 3360eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN: 3361eda14cbcSMatt Macy ret = TRUE; 3362eda14cbcSMatt Macy break; 3363eda14cbcSMatt Macy 3364eda14cbcSMatt Macy case DATA_TYPE_BYTE: 3365eda14cbcSMatt Macy case DATA_TYPE_INT8: 3366eda14cbcSMatt Macy case DATA_TYPE_UINT8: 3367eda14cbcSMatt Macy ret = xdr_char(xdr, buf); 3368eda14cbcSMatt Macy break; 3369eda14cbcSMatt Macy 3370eda14cbcSMatt Macy case DATA_TYPE_INT16: 3371eda14cbcSMatt Macy ret = xdr_short(xdr, (void *)buf); 3372eda14cbcSMatt Macy break; 3373eda14cbcSMatt Macy 3374eda14cbcSMatt Macy case DATA_TYPE_UINT16: 3375eda14cbcSMatt Macy ret = xdr_u_short(xdr, (void *)buf); 3376eda14cbcSMatt Macy break; 3377eda14cbcSMatt Macy 3378eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_VALUE: 3379eda14cbcSMatt Macy case DATA_TYPE_INT32: 3380eda14cbcSMatt Macy ret = xdr_int(xdr, (void *)buf); 3381eda14cbcSMatt Macy break; 3382eda14cbcSMatt Macy 3383eda14cbcSMatt Macy case DATA_TYPE_UINT32: 3384eda14cbcSMatt Macy ret = xdr_u_int(xdr, (void *)buf); 3385eda14cbcSMatt Macy break; 3386eda14cbcSMatt Macy 3387eda14cbcSMatt Macy case DATA_TYPE_INT64: 3388eda14cbcSMatt Macy ret = xdr_longlong_t(xdr, (void *)buf); 3389eda14cbcSMatt Macy break; 3390eda14cbcSMatt Macy 3391eda14cbcSMatt Macy case DATA_TYPE_UINT64: 3392eda14cbcSMatt Macy ret = xdr_u_longlong_t(xdr, (void *)buf); 3393eda14cbcSMatt Macy break; 3394eda14cbcSMatt Macy 3395eda14cbcSMatt Macy case DATA_TYPE_HRTIME: 3396eda14cbcSMatt Macy /* 3397eda14cbcSMatt Macy * NOTE: must expose the definition of hrtime_t here 3398eda14cbcSMatt Macy */ 3399eda14cbcSMatt Macy ret = xdr_longlong_t(xdr, (void *)buf); 3400eda14cbcSMatt Macy break; 3401eda14cbcSMatt Macy #if !defined(_KERNEL) 3402eda14cbcSMatt Macy case DATA_TYPE_DOUBLE: 3403eda14cbcSMatt Macy ret = xdr_double(xdr, (void *)buf); 3404eda14cbcSMatt Macy break; 3405eda14cbcSMatt Macy #endif 3406eda14cbcSMatt Macy case DATA_TYPE_STRING: 3407eda14cbcSMatt Macy ret = xdr_string(xdr, &buf, buflen - 1); 3408eda14cbcSMatt Macy break; 3409eda14cbcSMatt Macy 3410eda14cbcSMatt Macy case DATA_TYPE_BYTE_ARRAY: 3411eda14cbcSMatt Macy ret = xdr_opaque(xdr, buf, nelem); 3412eda14cbcSMatt Macy break; 3413eda14cbcSMatt Macy 3414eda14cbcSMatt Macy case DATA_TYPE_INT8_ARRAY: 3415eda14cbcSMatt Macy case DATA_TYPE_UINT8_ARRAY: 3416eda14cbcSMatt Macy ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t), 34173f9d360cSMartin Matuska nvs_xdr_nvp_char); 3418eda14cbcSMatt Macy break; 3419eda14cbcSMatt Macy 3420eda14cbcSMatt Macy case DATA_TYPE_INT16_ARRAY: 3421eda14cbcSMatt Macy ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t), 34223f9d360cSMartin Matuska sizeof (int16_t), nvs_xdr_nvp_short); 3423eda14cbcSMatt Macy break; 3424eda14cbcSMatt Macy 3425eda14cbcSMatt Macy case DATA_TYPE_UINT16_ARRAY: 3426eda14cbcSMatt Macy ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t), 34273f9d360cSMartin Matuska sizeof (uint16_t), nvs_xdr_nvp_u_short); 3428eda14cbcSMatt Macy break; 3429eda14cbcSMatt Macy 3430eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_ARRAY: 3431eda14cbcSMatt Macy case DATA_TYPE_INT32_ARRAY: 3432eda14cbcSMatt Macy ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t), 34333f9d360cSMartin Matuska sizeof (int32_t), nvs_xdr_nvp_int); 3434eda14cbcSMatt Macy break; 3435eda14cbcSMatt Macy 3436eda14cbcSMatt Macy case DATA_TYPE_UINT32_ARRAY: 3437eda14cbcSMatt Macy ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t), 34383f9d360cSMartin Matuska sizeof (uint32_t), nvs_xdr_nvp_u_int); 3439eda14cbcSMatt Macy break; 3440eda14cbcSMatt Macy 3441eda14cbcSMatt Macy case DATA_TYPE_INT64_ARRAY: 3442eda14cbcSMatt Macy ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t), 34433f9d360cSMartin Matuska sizeof (int64_t), nvs_xdr_nvp_longlong_t); 3444eda14cbcSMatt Macy break; 3445eda14cbcSMatt Macy 3446eda14cbcSMatt Macy case DATA_TYPE_UINT64_ARRAY: 3447eda14cbcSMatt Macy ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t), 34483f9d360cSMartin Matuska sizeof (uint64_t), nvs_xdr_nvp_u_longlong_t); 3449eda14cbcSMatt Macy break; 3450eda14cbcSMatt Macy 3451eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: { 3452eda14cbcSMatt Macy size_t len = nelem * sizeof (uint64_t); 3453eda14cbcSMatt Macy char **strp = (void *)buf; 3454eda14cbcSMatt Macy int i; 3455eda14cbcSMatt Macy 3456eda14cbcSMatt Macy if (nvs->nvs_op == NVS_OP_DECODE) 3457da5137abSMartin Matuska memset(buf, 0, len); /* don't trust packed data */ 3458eda14cbcSMatt Macy 3459eda14cbcSMatt Macy for (i = 0; i < nelem; i++) { 3460eda14cbcSMatt Macy if (buflen <= len) 3461eda14cbcSMatt Macy return (EFAULT); 3462eda14cbcSMatt Macy 3463eda14cbcSMatt Macy buf += len; 3464eda14cbcSMatt Macy buflen -= len; 3465eda14cbcSMatt Macy 3466eda14cbcSMatt Macy if (xdr_string(xdr, &buf, buflen - 1) != TRUE) 3467eda14cbcSMatt Macy return (EFAULT); 3468eda14cbcSMatt Macy 3469eda14cbcSMatt Macy if (nvs->nvs_op == NVS_OP_DECODE) 3470eda14cbcSMatt Macy strp[i] = buf; 3471eda14cbcSMatt Macy len = strlen(buf) + 1; 3472eda14cbcSMatt Macy } 3473eda14cbcSMatt Macy ret = TRUE; 3474eda14cbcSMatt Macy break; 3475eda14cbcSMatt Macy } 3476eda14cbcSMatt Macy default: 3477eda14cbcSMatt Macy break; 3478eda14cbcSMatt Macy } 3479eda14cbcSMatt Macy 3480eda14cbcSMatt Macy return (ret == TRUE ? 0 : EFAULT); 3481eda14cbcSMatt Macy } 3482eda14cbcSMatt Macy 3483eda14cbcSMatt Macy static int 3484eda14cbcSMatt Macy nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 3485eda14cbcSMatt Macy { 3486eda14cbcSMatt Macy data_type_t type = NVP_TYPE(nvp); 3487eda14cbcSMatt Macy /* 3488eda14cbcSMatt Macy * encode_size + decode_size + name string size + data type + nelem 3489eda14cbcSMatt Macy * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) 3490eda14cbcSMatt Macy */ 3491eda14cbcSMatt Macy uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4; 3492eda14cbcSMatt Macy 3493eda14cbcSMatt Macy switch (type) { 3494eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN: 3495eda14cbcSMatt Macy break; 3496eda14cbcSMatt Macy 3497eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_VALUE: 3498eda14cbcSMatt Macy case DATA_TYPE_BYTE: 3499eda14cbcSMatt Macy case DATA_TYPE_INT8: 3500eda14cbcSMatt Macy case DATA_TYPE_UINT8: 3501eda14cbcSMatt Macy case DATA_TYPE_INT16: 3502eda14cbcSMatt Macy case DATA_TYPE_UINT16: 3503eda14cbcSMatt Macy case DATA_TYPE_INT32: 3504eda14cbcSMatt Macy case DATA_TYPE_UINT32: 3505eda14cbcSMatt Macy nvp_sz += 4; /* 4 is the minimum xdr unit */ 3506eda14cbcSMatt Macy break; 3507eda14cbcSMatt Macy 3508eda14cbcSMatt Macy case DATA_TYPE_INT64: 3509eda14cbcSMatt Macy case DATA_TYPE_UINT64: 3510eda14cbcSMatt Macy case DATA_TYPE_HRTIME: 3511eda14cbcSMatt Macy #if !defined(_KERNEL) 3512eda14cbcSMatt Macy case DATA_TYPE_DOUBLE: 3513eda14cbcSMatt Macy #endif 3514eda14cbcSMatt Macy nvp_sz += 8; 3515eda14cbcSMatt Macy break; 3516eda14cbcSMatt Macy 3517eda14cbcSMatt Macy case DATA_TYPE_STRING: 3518eda14cbcSMatt Macy nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp))); 3519eda14cbcSMatt Macy break; 3520eda14cbcSMatt Macy 3521eda14cbcSMatt Macy case DATA_TYPE_BYTE_ARRAY: 3522eda14cbcSMatt Macy nvp_sz += NV_ALIGN4(NVP_NELEM(nvp)); 3523eda14cbcSMatt Macy break; 3524eda14cbcSMatt Macy 3525eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_ARRAY: 3526eda14cbcSMatt Macy case DATA_TYPE_INT8_ARRAY: 3527eda14cbcSMatt Macy case DATA_TYPE_UINT8_ARRAY: 3528eda14cbcSMatt Macy case DATA_TYPE_INT16_ARRAY: 3529eda14cbcSMatt Macy case DATA_TYPE_UINT16_ARRAY: 3530eda14cbcSMatt Macy case DATA_TYPE_INT32_ARRAY: 3531eda14cbcSMatt Macy case DATA_TYPE_UINT32_ARRAY: 3532eda14cbcSMatt Macy nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp); 3533eda14cbcSMatt Macy break; 3534eda14cbcSMatt Macy 3535eda14cbcSMatt Macy case DATA_TYPE_INT64_ARRAY: 3536eda14cbcSMatt Macy case DATA_TYPE_UINT64_ARRAY: 3537eda14cbcSMatt Macy nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp); 3538eda14cbcSMatt Macy break; 3539eda14cbcSMatt Macy 3540eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: { 3541eda14cbcSMatt Macy int i; 3542eda14cbcSMatt Macy char **strs = (void *)NVP_VALUE(nvp); 3543eda14cbcSMatt Macy 3544eda14cbcSMatt Macy for (i = 0; i < NVP_NELEM(nvp); i++) 3545eda14cbcSMatt Macy nvp_sz += 4 + NV_ALIGN4(strlen(strs[i])); 3546eda14cbcSMatt Macy 3547eda14cbcSMatt Macy break; 3548eda14cbcSMatt Macy } 3549eda14cbcSMatt Macy 3550eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 3551eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: { 3552eda14cbcSMatt Macy size_t nvsize = 0; 3553eda14cbcSMatt Macy int old_nvs_op = nvs->nvs_op; 3554eda14cbcSMatt Macy int err; 3555eda14cbcSMatt Macy 3556eda14cbcSMatt Macy nvs->nvs_op = NVS_OP_GETSIZE; 3557eda14cbcSMatt Macy if (type == DATA_TYPE_NVLIST) 3558eda14cbcSMatt Macy err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize); 3559eda14cbcSMatt Macy else 3560eda14cbcSMatt Macy err = nvs_embedded_nvl_array(nvs, nvp, &nvsize); 3561eda14cbcSMatt Macy nvs->nvs_op = old_nvs_op; 3562eda14cbcSMatt Macy 3563eda14cbcSMatt Macy if (err != 0) 3564eda14cbcSMatt Macy return (EINVAL); 3565eda14cbcSMatt Macy 3566eda14cbcSMatt Macy nvp_sz += nvsize; 3567eda14cbcSMatt Macy break; 3568eda14cbcSMatt Macy } 3569eda14cbcSMatt Macy 3570eda14cbcSMatt Macy default: 3571eda14cbcSMatt Macy return (EINVAL); 3572eda14cbcSMatt Macy } 3573eda14cbcSMatt Macy 3574eda14cbcSMatt Macy if (nvp_sz > INT32_MAX) 3575eda14cbcSMatt Macy return (EINVAL); 3576eda14cbcSMatt Macy 3577eda14cbcSMatt Macy *size = nvp_sz; 3578eda14cbcSMatt Macy 3579eda14cbcSMatt Macy return (0); 3580eda14cbcSMatt Macy } 3581eda14cbcSMatt Macy 3582eda14cbcSMatt Macy 3583eda14cbcSMatt Macy /* 3584eda14cbcSMatt Macy * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates 3585eda14cbcSMatt Macy * the largest nvpair that could be encoded in the buffer. 3586eda14cbcSMatt Macy * 3587eda14cbcSMatt Macy * See comments above nvpair_xdr_op() for the format of xdr encoding. 3588eda14cbcSMatt Macy * The size of a xdr packed nvpair without any data is 5 words. 3589eda14cbcSMatt Macy * 3590eda14cbcSMatt Macy * Using the size of the data directly as an estimate would be ok 3591eda14cbcSMatt Macy * in all cases except one. If the data type is of DATA_TYPE_STRING_ARRAY 3592eda14cbcSMatt Macy * then the actual nvpair has space for an array of pointers to index 3593eda14cbcSMatt Macy * the strings. These pointers are not encoded into the packed xdr buffer. 3594eda14cbcSMatt Macy * 3595eda14cbcSMatt Macy * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are 3596eda14cbcSMatt Macy * of length 0, then each string is encoded in xdr format as a single word. 3597eda14cbcSMatt Macy * Therefore when expanded to an nvpair there will be 2.25 word used for 3598eda14cbcSMatt Macy * each string. (a int64_t allocated for pointer usage, and a single char 3599eda14cbcSMatt Macy * for the null termination.) 3600eda14cbcSMatt Macy * 3601eda14cbcSMatt Macy * This is the calculation performed by the NVS_XDR_MAX_LEN macro. 3602eda14cbcSMatt Macy */ 3603eda14cbcSMatt Macy #define NVS_XDR_HDR_LEN ((size_t)(5 * 4)) 3604eda14cbcSMatt Macy #define NVS_XDR_DATA_LEN(y) (((size_t)(y) <= NVS_XDR_HDR_LEN) ? \ 3605eda14cbcSMatt Macy 0 : ((size_t)(y) - NVS_XDR_HDR_LEN)) 3606eda14cbcSMatt Macy #define NVS_XDR_MAX_LEN(x) (NVP_SIZE_CALC(1, 0) + \ 3607eda14cbcSMatt Macy (NVS_XDR_DATA_LEN(x) * 2) + \ 3608eda14cbcSMatt Macy NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4))) 3609eda14cbcSMatt Macy 3610eda14cbcSMatt Macy static int 3611eda14cbcSMatt Macy nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 3612eda14cbcSMatt Macy { 3613eda14cbcSMatt Macy XDR *xdr = nvs->nvs_private; 3614eda14cbcSMatt Macy int32_t encode_len, decode_len; 3615eda14cbcSMatt Macy 3616eda14cbcSMatt Macy switch (nvs->nvs_op) { 3617eda14cbcSMatt Macy case NVS_OP_ENCODE: { 3618eda14cbcSMatt Macy size_t nvsize; 3619eda14cbcSMatt Macy 3620eda14cbcSMatt Macy if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0) 3621eda14cbcSMatt Macy return (EFAULT); 3622eda14cbcSMatt Macy 3623eda14cbcSMatt Macy decode_len = nvp->nvp_size; 3624eda14cbcSMatt Macy encode_len = nvsize; 3625eda14cbcSMatt Macy if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len)) 3626eda14cbcSMatt Macy return (EFAULT); 3627eda14cbcSMatt Macy 3628eda14cbcSMatt Macy return (nvs_xdr_nvp_op(nvs, nvp)); 3629eda14cbcSMatt Macy } 3630eda14cbcSMatt Macy case NVS_OP_DECODE: { 3631eda14cbcSMatt Macy struct xdr_bytesrec bytesrec; 3632eda14cbcSMatt Macy 3633eda14cbcSMatt Macy /* get the encode and decode size */ 3634eda14cbcSMatt Macy if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len)) 3635eda14cbcSMatt Macy return (EFAULT); 3636eda14cbcSMatt Macy *size = decode_len; 3637eda14cbcSMatt Macy 3638eda14cbcSMatt Macy /* are we at the end of the stream? */ 3639eda14cbcSMatt Macy if (*size == 0) 3640eda14cbcSMatt Macy return (0); 3641eda14cbcSMatt Macy 3642eda14cbcSMatt Macy /* sanity check the size parameter */ 3643eda14cbcSMatt Macy if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec)) 3644eda14cbcSMatt Macy return (EFAULT); 3645eda14cbcSMatt Macy 3646eda14cbcSMatt Macy if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail)) 3647eda14cbcSMatt Macy return (EFAULT); 3648eda14cbcSMatt Macy break; 3649eda14cbcSMatt Macy } 3650eda14cbcSMatt Macy 3651eda14cbcSMatt Macy default: 3652eda14cbcSMatt Macy return (EINVAL); 3653eda14cbcSMatt Macy } 3654eda14cbcSMatt Macy return (0); 3655eda14cbcSMatt Macy } 3656eda14cbcSMatt Macy 3657eda14cbcSMatt Macy static const struct nvs_ops nvs_xdr_ops = { 3658eda14cbcSMatt Macy .nvs_nvlist = nvs_xdr_nvlist, 3659eda14cbcSMatt Macy .nvs_nvpair = nvs_xdr_nvpair, 3660eda14cbcSMatt Macy .nvs_nvp_op = nvs_xdr_nvp_op, 3661eda14cbcSMatt Macy .nvs_nvp_size = nvs_xdr_nvp_size, 3662eda14cbcSMatt Macy .nvs_nvl_fini = nvs_xdr_nvl_fini 3663eda14cbcSMatt Macy }; 3664eda14cbcSMatt Macy 3665eda14cbcSMatt Macy static int 3666eda14cbcSMatt Macy nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen) 3667eda14cbcSMatt Macy { 3668eda14cbcSMatt Macy XDR xdr; 3669eda14cbcSMatt Macy int err; 3670eda14cbcSMatt Macy 3671eda14cbcSMatt Macy nvs->nvs_ops = &nvs_xdr_ops; 3672eda14cbcSMatt Macy 3673eda14cbcSMatt Macy if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t), 3674eda14cbcSMatt Macy *buflen - sizeof (nvs_header_t))) != 0) 3675eda14cbcSMatt Macy return (err); 3676eda14cbcSMatt Macy 3677eda14cbcSMatt Macy err = nvs_operation(nvs, nvl, buflen); 3678eda14cbcSMatt Macy 3679eda14cbcSMatt Macy nvs_xdr_destroy(nvs); 3680eda14cbcSMatt Macy 3681eda14cbcSMatt Macy return (err); 3682eda14cbcSMatt Macy } 3683eda14cbcSMatt Macy 3684eda14cbcSMatt Macy EXPORT_SYMBOL(nv_alloc_init); 3685eda14cbcSMatt Macy EXPORT_SYMBOL(nv_alloc_reset); 3686eda14cbcSMatt Macy EXPORT_SYMBOL(nv_alloc_fini); 3687eda14cbcSMatt Macy 3688eda14cbcSMatt Macy /* list management */ 3689eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_alloc); 3690eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_free); 3691eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_size); 3692eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_pack); 3693eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_unpack); 3694eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_dup); 3695eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_merge); 3696eda14cbcSMatt Macy 3697eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_xalloc); 3698eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_xpack); 3699eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_xunpack); 3700eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_xdup); 3701eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_nv_alloc); 3702eda14cbcSMatt Macy 3703eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_nvpair); 3704eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_boolean); 3705eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_boolean_value); 3706eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_byte); 3707eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int8); 3708eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint8); 3709eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int16); 3710eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint16); 3711eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int32); 3712eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint32); 3713eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int64); 3714eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint64); 3715eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_string); 3716eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_nvlist); 3717eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_boolean_array); 3718eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_byte_array); 3719eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int8_array); 3720eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint8_array); 3721eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int16_array); 3722eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint16_array); 3723eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int32_array); 3724eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint32_array); 3725eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int64_array); 3726eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint64_array); 3727eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_string_array); 3728eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_nvlist_array); 3729eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_next_nvpair); 3730eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_prev_nvpair); 3731eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_empty); 3732eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_hrtime); 3733eda14cbcSMatt Macy 3734eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_remove); 3735eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_remove_nvpair); 3736eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_remove_all); 3737eda14cbcSMatt Macy 3738eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_boolean); 3739eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_boolean_value); 3740eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_byte); 3741eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int8); 3742eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint8); 3743eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int16); 3744eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint16); 3745eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int32); 3746eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint32); 3747eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int64); 3748eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint64); 3749eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_string); 3750eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_nvlist); 3751eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_boolean_array); 3752eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_byte_array); 3753eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int8_array); 3754eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint8_array); 3755eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int16_array); 3756eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint16_array); 3757eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int32_array); 3758eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint32_array); 3759eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int64_array); 3760eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint64_array); 3761eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_string_array); 3762eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_nvlist_array); 3763eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_hrtime); 3764eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_pairs); 3765eda14cbcSMatt Macy 3766eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_nvpair); 3767eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_exists); 3768eda14cbcSMatt Macy 3769eda14cbcSMatt Macy /* processing nvpair */ 3770eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_name); 3771eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_type); 3772eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_boolean_value); 3773eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_byte); 3774eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int8); 3775eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint8); 3776eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int16); 3777eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint16); 3778eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int32); 3779eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint32); 3780eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int64); 3781eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint64); 3782eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_string); 3783eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_nvlist); 3784eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_boolean_array); 3785eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_byte_array); 3786eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int8_array); 3787eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint8_array); 3788eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int16_array); 3789eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint16_array); 3790eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int32_array); 3791eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint32_array); 3792eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int64_array); 3793eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint64_array); 3794eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_string_array); 3795eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_nvlist_array); 3796eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_hrtime); 3797