17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53bb79becSeschrock * Common Development and Distribution License (the "License").
63bb79becSeschrock * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21d9638e54Smws
227c478bd9Sstevel@tonic-gate /*
23f6e214c7SGavin Maltby * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
24843c2111SMatthew Ahrens * Copyright (c) 2015, 2017 by Delphix. All rights reserved.
25b8a5bee1SAndrew Stormont * Copyright 2018 RackTop Systems.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
297c478bd9Sstevel@tonic-gate #include <sys/debug.h>
307c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
317c478bd9Sstevel@tonic-gate #include <sys/int_limits.h>
327c478bd9Sstevel@tonic-gate #include <sys/nvpair.h>
337c478bd9Sstevel@tonic-gate #include <sys/nvpair_impl.h>
347c478bd9Sstevel@tonic-gate #include <rpc/types.h>
357c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
387c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
39602ca9eaScth #include <sys/ddi.h>
40602ca9eaScth #include <sys/sunddi.h>
415c5f1371SRichard Lowe #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #else
437c478bd9Sstevel@tonic-gate #include <stdarg.h>
44602ca9eaScth #include <stdlib.h>
45602ca9eaScth #include <string.h>
467c478bd9Sstevel@tonic-gate #include <strings.h>
475c5f1371SRichard Lowe #include <stddef.h>
487c478bd9Sstevel@tonic-gate #endif
497c478bd9Sstevel@tonic-gate
50602ca9eaScth #define skip_whitespace(p) while ((*(p) == ' ') || (*(p) == '\t')) p++
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate * nvpair.c - Provides kernel & userland interfaces for manipulating
547c478bd9Sstevel@tonic-gate * name-value pairs.
557c478bd9Sstevel@tonic-gate *
567c478bd9Sstevel@tonic-gate * Overview Diagram
577c478bd9Sstevel@tonic-gate *
587c478bd9Sstevel@tonic-gate * +--------------+
597c478bd9Sstevel@tonic-gate * | nvlist_t |
607c478bd9Sstevel@tonic-gate * |--------------|
617c478bd9Sstevel@tonic-gate * | nvl_version |
627c478bd9Sstevel@tonic-gate * | nvl_nvflag |
637c478bd9Sstevel@tonic-gate * | nvl_priv -+-+
647c478bd9Sstevel@tonic-gate * | nvl_flag | |
657c478bd9Sstevel@tonic-gate * | nvl_pad | |
667c478bd9Sstevel@tonic-gate * +--------------+ |
677c478bd9Sstevel@tonic-gate * V
687c478bd9Sstevel@tonic-gate * +--------------+ last i_nvp in list
697c478bd9Sstevel@tonic-gate * | nvpriv_t | +--------------------->
707c478bd9Sstevel@tonic-gate * |--------------| |
717c478bd9Sstevel@tonic-gate * +--+- nvp_list | | +------------+
727c478bd9Sstevel@tonic-gate * | | nvp_last -+--+ + nv_alloc_t |
737c478bd9Sstevel@tonic-gate * | | nvp_curr | |------------|
747c478bd9Sstevel@tonic-gate * | | nvp_nva -+----> | nva_ops |
757c478bd9Sstevel@tonic-gate * | | nvp_stat | | nva_arg |
767c478bd9Sstevel@tonic-gate * | +--------------+ +------------+
777c478bd9Sstevel@tonic-gate * |
787c478bd9Sstevel@tonic-gate * +-------+
797c478bd9Sstevel@tonic-gate * V
807c478bd9Sstevel@tonic-gate * +---------------------+ +-------------------+
817c478bd9Sstevel@tonic-gate * | i_nvp_t | +-->| i_nvp_t | +-->
827c478bd9Sstevel@tonic-gate * |---------------------| | |-------------------| |
837c478bd9Sstevel@tonic-gate * | nvi_next -+--+ | nvi_next -+--+
847c478bd9Sstevel@tonic-gate * | nvi_prev (NULL) | <----+ nvi_prev |
857c478bd9Sstevel@tonic-gate * | . . . . . . . . . . | | . . . . . . . . . |
867c478bd9Sstevel@tonic-gate * | nvp (nvpair_t) | | nvp (nvpair_t) |
877c478bd9Sstevel@tonic-gate * | - nvp_size | | - nvp_size |
887c478bd9Sstevel@tonic-gate * | - nvp_name_sz | | - nvp_name_sz |
897c478bd9Sstevel@tonic-gate * | - nvp_value_elem | | - nvp_value_elem |
907c478bd9Sstevel@tonic-gate * | - nvp_type | | - nvp_type |
917c478bd9Sstevel@tonic-gate * | - data ... | | - data ... |
927c478bd9Sstevel@tonic-gate * +---------------------+ +-------------------+
937c478bd9Sstevel@tonic-gate *
947c478bd9Sstevel@tonic-gate *
957c478bd9Sstevel@tonic-gate *
967c478bd9Sstevel@tonic-gate * +---------------------+ +---------------------+
977c478bd9Sstevel@tonic-gate * | i_nvp_t | +--> +-->| i_nvp_t (last) |
987c478bd9Sstevel@tonic-gate * |---------------------| | | |---------------------|
997c478bd9Sstevel@tonic-gate * | nvi_next -+--+ ... --+ | nvi_next (NULL) |
1007c478bd9Sstevel@tonic-gate * <-+- nvi_prev |<-- ... <----+ nvi_prev |
1017c478bd9Sstevel@tonic-gate * | . . . . . . . . . | | . . . . . . . . . |
1027c478bd9Sstevel@tonic-gate * | nvp (nvpair_t) | | nvp (nvpair_t) |
1037c478bd9Sstevel@tonic-gate * | - nvp_size | | - nvp_size |
1047c478bd9Sstevel@tonic-gate * | - nvp_name_sz | | - nvp_name_sz |
1057c478bd9Sstevel@tonic-gate * | - nvp_value_elem | | - nvp_value_elem |
1067c478bd9Sstevel@tonic-gate * | - DATA_TYPE_NVLIST | | - nvp_type |
1077c478bd9Sstevel@tonic-gate * | - data (embedded) | | - data ... |
1087c478bd9Sstevel@tonic-gate * | nvlist name | +---------------------+
1097c478bd9Sstevel@tonic-gate * | +--------------+ |
1107c478bd9Sstevel@tonic-gate * | | nvlist_t | |
1117c478bd9Sstevel@tonic-gate * | |--------------| |
1127c478bd9Sstevel@tonic-gate * | | nvl_version | |
1137c478bd9Sstevel@tonic-gate * | | nvl_nvflag | |
1147c478bd9Sstevel@tonic-gate * | | nvl_priv --+---+---->
1157c478bd9Sstevel@tonic-gate * | | nvl_flag | |
1167c478bd9Sstevel@tonic-gate * | | nvl_pad | |
1177c478bd9Sstevel@tonic-gate * | +--------------+ |
1187c478bd9Sstevel@tonic-gate * +---------------------+
1197c478bd9Sstevel@tonic-gate *
1207c478bd9Sstevel@tonic-gate *
1217c478bd9Sstevel@tonic-gate * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will
1227c478bd9Sstevel@tonic-gate * allow value to be aligned on 8 byte boundary
1237c478bd9Sstevel@tonic-gate *
1247c478bd9Sstevel@tonic-gate * name_len is the length of the name string including the null terminator
1257c478bd9Sstevel@tonic-gate * so it must be >= 1
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate #define NVP_SIZE_CALC(name_len, data_len) \
1287c478bd9Sstevel@tonic-gate (NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate static int i_get_value_size(data_type_t type, const void *data, uint_t nelem);
1317c478bd9Sstevel@tonic-gate static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1327c478bd9Sstevel@tonic-gate uint_t nelem, const void *data);
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate #define NV_STAT_EMBEDDED 0x1
1357c478bd9Sstevel@tonic-gate #define EMBEDDED_NVL(nvp) ((nvlist_t *)(void *)NVP_VALUE(nvp))
1367c478bd9Sstevel@tonic-gate #define EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp))
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate #define NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))
1397c478bd9Sstevel@tonic-gate #define NVPAIR2I_NVP(nvp) \
1407c478bd9Sstevel@tonic-gate ((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))
1417c478bd9Sstevel@tonic-gate
1429ca527c3SMatthew Ahrens #ifdef _KERNEL
1439ca527c3SMatthew Ahrens int nvpair_max_recursion = 20;
1449ca527c3SMatthew Ahrens #else
1459ca527c3SMatthew Ahrens int nvpair_max_recursion = 100;
1469ca527c3SMatthew Ahrens #endif
1477c478bd9Sstevel@tonic-gate
1482ec7644aSSerapheim Dimitropoulos uint64_t nvlist_hashtable_init_size = (1 << 4);
1492ec7644aSSerapheim Dimitropoulos
1507c478bd9Sstevel@tonic-gate int
nv_alloc_init(nv_alloc_t * nva,const nv_alloc_ops_t * nvo,...)1517c478bd9Sstevel@tonic-gate nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate va_list valist;
1547c478bd9Sstevel@tonic-gate int err = 0;
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate nva->nva_ops = nvo;
1577c478bd9Sstevel@tonic-gate nva->nva_arg = NULL;
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate va_start(valist, nvo);
1607c478bd9Sstevel@tonic-gate if (nva->nva_ops->nv_ao_init != NULL)
1617c478bd9Sstevel@tonic-gate err = nva->nva_ops->nv_ao_init(nva, valist);
1627c478bd9Sstevel@tonic-gate va_end(valist);
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate return (err);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate void
nv_alloc_reset(nv_alloc_t * nva)1687c478bd9Sstevel@tonic-gate nv_alloc_reset(nv_alloc_t *nva)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate if (nva->nva_ops->nv_ao_reset != NULL)
1717c478bd9Sstevel@tonic-gate nva->nva_ops->nv_ao_reset(nva);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate void
nv_alloc_fini(nv_alloc_t * nva)1757c478bd9Sstevel@tonic-gate nv_alloc_fini(nv_alloc_t *nva)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate if (nva->nva_ops->nv_ao_fini != NULL)
1787c478bd9Sstevel@tonic-gate nva->nva_ops->nv_ao_fini(nva);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate nv_alloc_t *
nvlist_lookup_nv_alloc(nvlist_t * nvl)1827c478bd9Sstevel@tonic-gate nvlist_lookup_nv_alloc(nvlist_t *nvl)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate nvpriv_t *priv;
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate if (nvl == NULL ||
1877c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1887c478bd9Sstevel@tonic-gate return (NULL);
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate return (priv->nvp_nva);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate static void *
nv_mem_zalloc(nvpriv_t * nvp,size_t size)1947c478bd9Sstevel@tonic-gate nv_mem_zalloc(nvpriv_t *nvp, size_t size)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate nv_alloc_t *nva = nvp->nvp_nva;
1977c478bd9Sstevel@tonic-gate void *buf;
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)
2007c478bd9Sstevel@tonic-gate bzero(buf, size);
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate return (buf);
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate static void
nv_mem_free(nvpriv_t * nvp,void * buf,size_t size)2067c478bd9Sstevel@tonic-gate nv_mem_free(nvpriv_t *nvp, void *buf, size_t size)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate nv_alloc_t *nva = nvp->nvp_nva;
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate nva->nva_ops->nv_ao_free(nva, buf, size);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate static void
nv_priv_init(nvpriv_t * priv,nv_alloc_t * nva,uint32_t stat)2147c478bd9Sstevel@tonic-gate nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)
2157c478bd9Sstevel@tonic-gate {
216c5904d13Seschrock bzero(priv, sizeof (nvpriv_t));
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate priv->nvp_nva = nva;
2197c478bd9Sstevel@tonic-gate priv->nvp_stat = stat;
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate static nvpriv_t *
nv_priv_alloc(nv_alloc_t * nva)2237c478bd9Sstevel@tonic-gate nv_priv_alloc(nv_alloc_t *nva)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate nvpriv_t *priv;
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate /*
2287c478bd9Sstevel@tonic-gate * nv_mem_alloc() cannot called here because it needs the priv
2297c478bd9Sstevel@tonic-gate * argument.
2307c478bd9Sstevel@tonic-gate */
2317c478bd9Sstevel@tonic-gate if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)
2327c478bd9Sstevel@tonic-gate return (NULL);
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate nv_priv_init(priv, nva, 0);
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate return (priv);
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate /*
2407c478bd9Sstevel@tonic-gate * Embedded lists need their own nvpriv_t's. We create a new
2417c478bd9Sstevel@tonic-gate * nvpriv_t using the parameters and allocator from the parent
2427c478bd9Sstevel@tonic-gate * list's nvpriv_t.
2437c478bd9Sstevel@tonic-gate */
2447c478bd9Sstevel@tonic-gate static nvpriv_t *
nv_priv_alloc_embedded(nvpriv_t * priv)2457c478bd9Sstevel@tonic-gate nv_priv_alloc_embedded(nvpriv_t *priv)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate nvpriv_t *emb_priv;
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)
2507c478bd9Sstevel@tonic-gate return (NULL);
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate return (emb_priv);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate
2572ec7644aSSerapheim Dimitropoulos static int
nvt_tab_alloc(nvpriv_t * priv,uint64_t buckets)2582ec7644aSSerapheim Dimitropoulos nvt_tab_alloc(nvpriv_t *priv, uint64_t buckets)
2592ec7644aSSerapheim Dimitropoulos {
2602ec7644aSSerapheim Dimitropoulos ASSERT3P(priv->nvp_hashtable, ==, NULL);
2612ec7644aSSerapheim Dimitropoulos ASSERT0(priv->nvp_nbuckets);
2622ec7644aSSerapheim Dimitropoulos ASSERT0(priv->nvp_nentries);
2632ec7644aSSerapheim Dimitropoulos
2642ec7644aSSerapheim Dimitropoulos i_nvp_t **tab = nv_mem_zalloc(priv, buckets * sizeof (i_nvp_t *));
2652ec7644aSSerapheim Dimitropoulos if (tab == NULL)
2662ec7644aSSerapheim Dimitropoulos return (ENOMEM);
2672ec7644aSSerapheim Dimitropoulos
2682ec7644aSSerapheim Dimitropoulos priv->nvp_hashtable = tab;
2692ec7644aSSerapheim Dimitropoulos priv->nvp_nbuckets = buckets;
2702ec7644aSSerapheim Dimitropoulos return (0);
2712ec7644aSSerapheim Dimitropoulos }
2722ec7644aSSerapheim Dimitropoulos
2732ec7644aSSerapheim Dimitropoulos static void
nvt_tab_free(nvpriv_t * priv)2742ec7644aSSerapheim Dimitropoulos nvt_tab_free(nvpriv_t *priv)
2752ec7644aSSerapheim Dimitropoulos {
2762ec7644aSSerapheim Dimitropoulos i_nvp_t **tab = priv->nvp_hashtable;
2772ec7644aSSerapheim Dimitropoulos if (tab == NULL) {
2782ec7644aSSerapheim Dimitropoulos ASSERT0(priv->nvp_nbuckets);
2792ec7644aSSerapheim Dimitropoulos ASSERT0(priv->nvp_nentries);
2802ec7644aSSerapheim Dimitropoulos return;
2812ec7644aSSerapheim Dimitropoulos }
2822ec7644aSSerapheim Dimitropoulos
2832ec7644aSSerapheim Dimitropoulos nv_mem_free(priv, tab, priv->nvp_nbuckets * sizeof (i_nvp_t *));
2842ec7644aSSerapheim Dimitropoulos
2852ec7644aSSerapheim Dimitropoulos priv->nvp_hashtable = NULL;
2862ec7644aSSerapheim Dimitropoulos priv->nvp_nbuckets = 0;
2872ec7644aSSerapheim Dimitropoulos priv->nvp_nentries = 0;
2882ec7644aSSerapheim Dimitropoulos }
2892ec7644aSSerapheim Dimitropoulos
2902ec7644aSSerapheim Dimitropoulos static uint32_t
nvt_hash(const char * p)2912ec7644aSSerapheim Dimitropoulos nvt_hash(const char *p)
2922ec7644aSSerapheim Dimitropoulos {
2932ec7644aSSerapheim Dimitropoulos uint32_t g, hval = 0;
2942ec7644aSSerapheim Dimitropoulos
2952ec7644aSSerapheim Dimitropoulos while (*p) {
2962ec7644aSSerapheim Dimitropoulos hval = (hval << 4) + *p++;
2972ec7644aSSerapheim Dimitropoulos if ((g = (hval & 0xf0000000)) != 0)
2982ec7644aSSerapheim Dimitropoulos hval ^= g >> 24;
2992ec7644aSSerapheim Dimitropoulos hval &= ~g;
3002ec7644aSSerapheim Dimitropoulos }
3012ec7644aSSerapheim Dimitropoulos return (hval);
3022ec7644aSSerapheim Dimitropoulos }
3032ec7644aSSerapheim Dimitropoulos
3042ec7644aSSerapheim Dimitropoulos static boolean_t
nvt_nvpair_match(nvpair_t * nvp1,nvpair_t * nvp2,uint32_t nvflag)3052ec7644aSSerapheim Dimitropoulos nvt_nvpair_match(nvpair_t *nvp1, nvpair_t *nvp2, uint32_t nvflag)
3062ec7644aSSerapheim Dimitropoulos {
3072ec7644aSSerapheim Dimitropoulos boolean_t match = B_FALSE;
3082ec7644aSSerapheim Dimitropoulos if (nvflag & NV_UNIQUE_NAME_TYPE) {
3092ec7644aSSerapheim Dimitropoulos if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0 &&
3102ec7644aSSerapheim Dimitropoulos NVP_TYPE(nvp1) == NVP_TYPE(nvp2))
3112ec7644aSSerapheim Dimitropoulos match = B_TRUE;
3122ec7644aSSerapheim Dimitropoulos } else {
3132ec7644aSSerapheim Dimitropoulos ASSERT(nvflag == 0 || nvflag & NV_UNIQUE_NAME);
3142ec7644aSSerapheim Dimitropoulos if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0)
3152ec7644aSSerapheim Dimitropoulos match = B_TRUE;
3162ec7644aSSerapheim Dimitropoulos }
3172ec7644aSSerapheim Dimitropoulos return (match);
3182ec7644aSSerapheim Dimitropoulos }
3192ec7644aSSerapheim Dimitropoulos
3202ec7644aSSerapheim Dimitropoulos static nvpair_t *
nvt_lookup_name_type(nvlist_t * nvl,const char * name,data_type_t type)3212ec7644aSSerapheim Dimitropoulos nvt_lookup_name_type(nvlist_t *nvl, const char *name, data_type_t type)
3222ec7644aSSerapheim Dimitropoulos {
3232ec7644aSSerapheim Dimitropoulos nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
3242ec7644aSSerapheim Dimitropoulos ASSERT(priv != NULL);
3252ec7644aSSerapheim Dimitropoulos
3262ec7644aSSerapheim Dimitropoulos i_nvp_t **tab = priv->nvp_hashtable;
3272ec7644aSSerapheim Dimitropoulos
3282ec7644aSSerapheim Dimitropoulos if (tab == NULL) {
3292ec7644aSSerapheim Dimitropoulos ASSERT3P(priv->nvp_list, ==, NULL);
3302ec7644aSSerapheim Dimitropoulos ASSERT0(priv->nvp_nbuckets);
3312ec7644aSSerapheim Dimitropoulos ASSERT0(priv->nvp_nentries);
3322ec7644aSSerapheim Dimitropoulos return (NULL);
3332ec7644aSSerapheim Dimitropoulos } else {
3342ec7644aSSerapheim Dimitropoulos ASSERT(priv->nvp_nbuckets != 0);
3352ec7644aSSerapheim Dimitropoulos }
3362ec7644aSSerapheim Dimitropoulos
3372ec7644aSSerapheim Dimitropoulos uint64_t hash = nvt_hash(name);
3382ec7644aSSerapheim Dimitropoulos uint64_t index = hash & (priv->nvp_nbuckets - 1);
3392ec7644aSSerapheim Dimitropoulos
3402ec7644aSSerapheim Dimitropoulos ASSERT3U(index, <, priv->nvp_nbuckets);
3412ec7644aSSerapheim Dimitropoulos i_nvp_t *entry = tab[index];
3422ec7644aSSerapheim Dimitropoulos
3432ec7644aSSerapheim Dimitropoulos for (i_nvp_t *e = entry; e != NULL; e = e->nvi_hashtable_next) {
3442ec7644aSSerapheim Dimitropoulos if (strcmp(NVP_NAME(&e->nvi_nvp), name) == 0 &&
3452ec7644aSSerapheim Dimitropoulos (type == DATA_TYPE_DONTCARE ||
3462ec7644aSSerapheim Dimitropoulos NVP_TYPE(&e->nvi_nvp) == type))
3472ec7644aSSerapheim Dimitropoulos return (&e->nvi_nvp);
3482ec7644aSSerapheim Dimitropoulos }
3492ec7644aSSerapheim Dimitropoulos return (NULL);
3502ec7644aSSerapheim Dimitropoulos }
3512ec7644aSSerapheim Dimitropoulos
3522ec7644aSSerapheim Dimitropoulos static nvpair_t *
nvt_lookup_name(nvlist_t * nvl,const char * name)3532ec7644aSSerapheim Dimitropoulos nvt_lookup_name(nvlist_t *nvl, const char *name)
3542ec7644aSSerapheim Dimitropoulos {
3552ec7644aSSerapheim Dimitropoulos return (nvt_lookup_name_type(nvl, name, DATA_TYPE_DONTCARE));
3562ec7644aSSerapheim Dimitropoulos }
3572ec7644aSSerapheim Dimitropoulos
3582ec7644aSSerapheim Dimitropoulos static int
nvt_resize(nvpriv_t * priv,uint32_t new_size)3592ec7644aSSerapheim Dimitropoulos nvt_resize(nvpriv_t *priv, uint32_t new_size)
3602ec7644aSSerapheim Dimitropoulos {
3612ec7644aSSerapheim Dimitropoulos i_nvp_t **tab = priv->nvp_hashtable;
3622ec7644aSSerapheim Dimitropoulos
3632ec7644aSSerapheim Dimitropoulos /*
3642ec7644aSSerapheim Dimitropoulos * Migrate all the entries from the current table
3652ec7644aSSerapheim Dimitropoulos * to a newly-allocated table with the new size by
3662ec7644aSSerapheim Dimitropoulos * re-adjusting the pointers of their entries.
3672ec7644aSSerapheim Dimitropoulos */
3682ec7644aSSerapheim Dimitropoulos uint32_t size = priv->nvp_nbuckets;
3692ec7644aSSerapheim Dimitropoulos uint32_t new_mask = new_size - 1;
3702ec7644aSSerapheim Dimitropoulos ASSERT(ISP2(new_size));
3712ec7644aSSerapheim Dimitropoulos
3722ec7644aSSerapheim Dimitropoulos i_nvp_t **new_tab = nv_mem_zalloc(priv, new_size * sizeof (i_nvp_t *));
3732ec7644aSSerapheim Dimitropoulos if (new_tab == NULL)
3742ec7644aSSerapheim Dimitropoulos return (ENOMEM);
3752ec7644aSSerapheim Dimitropoulos
3762ec7644aSSerapheim Dimitropoulos uint32_t nentries = 0;
3772ec7644aSSerapheim Dimitropoulos for (uint32_t i = 0; i < size; i++) {
3782ec7644aSSerapheim Dimitropoulos i_nvp_t *next, *e = tab[i];
3792ec7644aSSerapheim Dimitropoulos
3802ec7644aSSerapheim Dimitropoulos while (e != NULL) {
3812ec7644aSSerapheim Dimitropoulos next = e->nvi_hashtable_next;
3822ec7644aSSerapheim Dimitropoulos
3832ec7644aSSerapheim Dimitropoulos uint32_t hash = nvt_hash(NVP_NAME(&e->nvi_nvp));
3842ec7644aSSerapheim Dimitropoulos uint32_t index = hash & new_mask;
3852ec7644aSSerapheim Dimitropoulos
3862ec7644aSSerapheim Dimitropoulos e->nvi_hashtable_next = new_tab[index];
3872ec7644aSSerapheim Dimitropoulos new_tab[index] = e;
3882ec7644aSSerapheim Dimitropoulos nentries++;
3892ec7644aSSerapheim Dimitropoulos
3902ec7644aSSerapheim Dimitropoulos e = next;
3912ec7644aSSerapheim Dimitropoulos }
3922ec7644aSSerapheim Dimitropoulos tab[i] = NULL;
3932ec7644aSSerapheim Dimitropoulos }
3942ec7644aSSerapheim Dimitropoulos ASSERT3U(nentries, ==, priv->nvp_nentries);
3952ec7644aSSerapheim Dimitropoulos
3962ec7644aSSerapheim Dimitropoulos nvt_tab_free(priv);
3972ec7644aSSerapheim Dimitropoulos
3982ec7644aSSerapheim Dimitropoulos priv->nvp_hashtable = new_tab;
3992ec7644aSSerapheim Dimitropoulos priv->nvp_nbuckets = new_size;
4002ec7644aSSerapheim Dimitropoulos priv->nvp_nentries = nentries;
4012ec7644aSSerapheim Dimitropoulos
4022ec7644aSSerapheim Dimitropoulos return (0);
4032ec7644aSSerapheim Dimitropoulos }
4042ec7644aSSerapheim Dimitropoulos
4052ec7644aSSerapheim Dimitropoulos static boolean_t
nvt_needs_togrow(nvpriv_t * priv)4062ec7644aSSerapheim Dimitropoulos nvt_needs_togrow(nvpriv_t *priv)
4072ec7644aSSerapheim Dimitropoulos {
4082ec7644aSSerapheim Dimitropoulos /*
4092ec7644aSSerapheim Dimitropoulos * Grow only when we have more elements than buckets
4102ec7644aSSerapheim Dimitropoulos * and the # of buckets doesn't overflow.
4112ec7644aSSerapheim Dimitropoulos */
4122ec7644aSSerapheim Dimitropoulos return (priv->nvp_nentries > priv->nvp_nbuckets &&
4132ec7644aSSerapheim Dimitropoulos (UINT32_MAX >> 1) >= priv->nvp_nbuckets);
4142ec7644aSSerapheim Dimitropoulos }
4152ec7644aSSerapheim Dimitropoulos
4162ec7644aSSerapheim Dimitropoulos /*
4172ec7644aSSerapheim Dimitropoulos * Allocate a new table that's twice the size of the old one,
4182ec7644aSSerapheim Dimitropoulos * and migrate all the entries from the old one to the new
4192ec7644aSSerapheim Dimitropoulos * one by re-adjusting their pointers.
4202ec7644aSSerapheim Dimitropoulos */
4212ec7644aSSerapheim Dimitropoulos static int
nvt_grow(nvpriv_t * priv)4222ec7644aSSerapheim Dimitropoulos nvt_grow(nvpriv_t *priv)
4232ec7644aSSerapheim Dimitropoulos {
4242ec7644aSSerapheim Dimitropoulos uint32_t current_size = priv->nvp_nbuckets;
4252ec7644aSSerapheim Dimitropoulos /* ensure we won't overflow */
4262ec7644aSSerapheim Dimitropoulos ASSERT3U(UINT32_MAX >> 1, >=, current_size);
4272ec7644aSSerapheim Dimitropoulos return (nvt_resize(priv, current_size << 1));
4282ec7644aSSerapheim Dimitropoulos }
4292ec7644aSSerapheim Dimitropoulos
4302ec7644aSSerapheim Dimitropoulos static boolean_t
nvt_needs_toshrink(nvpriv_t * priv)4312ec7644aSSerapheim Dimitropoulos nvt_needs_toshrink(nvpriv_t *priv)
4322ec7644aSSerapheim Dimitropoulos {
4332ec7644aSSerapheim Dimitropoulos /*
4342ec7644aSSerapheim Dimitropoulos * Shrink only when the # of elements is less than or
4352ec7644aSSerapheim Dimitropoulos * equal to 1/4 the # of buckets. Never shrink less than
4362ec7644aSSerapheim Dimitropoulos * nvlist_hashtable_init_size.
4372ec7644aSSerapheim Dimitropoulos */
4382ec7644aSSerapheim Dimitropoulos ASSERT3U(priv->nvp_nbuckets, >=, nvlist_hashtable_init_size);
4392ec7644aSSerapheim Dimitropoulos if (priv->nvp_nbuckets == nvlist_hashtable_init_size)
4402ec7644aSSerapheim Dimitropoulos return (B_FALSE);
4412ec7644aSSerapheim Dimitropoulos return (priv->nvp_nentries <= (priv->nvp_nbuckets >> 2));
4422ec7644aSSerapheim Dimitropoulos }
4432ec7644aSSerapheim Dimitropoulos
4442ec7644aSSerapheim Dimitropoulos /*
4452ec7644aSSerapheim Dimitropoulos * Allocate a new table that's half the size of the old one,
4462ec7644aSSerapheim Dimitropoulos * and migrate all the entries from the old one to the new
4472ec7644aSSerapheim Dimitropoulos * one by re-adjusting their pointers.
4482ec7644aSSerapheim Dimitropoulos */
4492ec7644aSSerapheim Dimitropoulos static int
nvt_shrink(nvpriv_t * priv)4502ec7644aSSerapheim Dimitropoulos nvt_shrink(nvpriv_t *priv)
4512ec7644aSSerapheim Dimitropoulos {
4522ec7644aSSerapheim Dimitropoulos uint32_t current_size = priv->nvp_nbuckets;
4532ec7644aSSerapheim Dimitropoulos /* ensure we won't overflow */
4542ec7644aSSerapheim Dimitropoulos ASSERT3U(current_size, >=, nvlist_hashtable_init_size);
4552ec7644aSSerapheim Dimitropoulos return (nvt_resize(priv, current_size >> 1));
4562ec7644aSSerapheim Dimitropoulos }
4572ec7644aSSerapheim Dimitropoulos
4582ec7644aSSerapheim Dimitropoulos static int
nvt_remove_nvpair(nvlist_t * nvl,nvpair_t * nvp)4592ec7644aSSerapheim Dimitropoulos nvt_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
4602ec7644aSSerapheim Dimitropoulos {
4612ec7644aSSerapheim Dimitropoulos nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
4622ec7644aSSerapheim Dimitropoulos
4632ec7644aSSerapheim Dimitropoulos if (nvt_needs_toshrink(priv)) {
4642ec7644aSSerapheim Dimitropoulos int err = nvt_shrink(priv);
4652ec7644aSSerapheim Dimitropoulos if (err != 0)
4662ec7644aSSerapheim Dimitropoulos return (err);
4672ec7644aSSerapheim Dimitropoulos }
4682ec7644aSSerapheim Dimitropoulos i_nvp_t **tab = priv->nvp_hashtable;
4692ec7644aSSerapheim Dimitropoulos
4702ec7644aSSerapheim Dimitropoulos char *name = NVP_NAME(nvp);
4712ec7644aSSerapheim Dimitropoulos uint64_t hash = nvt_hash(name);
4722ec7644aSSerapheim Dimitropoulos uint64_t index = hash & (priv->nvp_nbuckets - 1);
4732ec7644aSSerapheim Dimitropoulos
4742ec7644aSSerapheim Dimitropoulos ASSERT3U(index, <, priv->nvp_nbuckets);
4752ec7644aSSerapheim Dimitropoulos i_nvp_t *bucket = tab[index];
4762ec7644aSSerapheim Dimitropoulos
4772ec7644aSSerapheim Dimitropoulos for (i_nvp_t *prev = NULL, *e = bucket;
4782ec7644aSSerapheim Dimitropoulos e != NULL; prev = e, e = e->nvi_hashtable_next) {
479b8a5bee1SAndrew Stormont if (nvt_nvpair_match(&e->nvi_nvp, nvp, nvl->nvl_nvflag)) {
4802ec7644aSSerapheim Dimitropoulos if (prev != NULL) {
4812ec7644aSSerapheim Dimitropoulos prev->nvi_hashtable_next =
4822ec7644aSSerapheim Dimitropoulos e->nvi_hashtable_next;
4832ec7644aSSerapheim Dimitropoulos } else {
4842ec7644aSSerapheim Dimitropoulos ASSERT3P(e, ==, bucket);
4852ec7644aSSerapheim Dimitropoulos tab[index] = e->nvi_hashtable_next;
4862ec7644aSSerapheim Dimitropoulos }
4872ec7644aSSerapheim Dimitropoulos e->nvi_hashtable_next = NULL;
4882ec7644aSSerapheim Dimitropoulos priv->nvp_nentries--;
4892ec7644aSSerapheim Dimitropoulos break;
4902ec7644aSSerapheim Dimitropoulos }
4912ec7644aSSerapheim Dimitropoulos }
4922ec7644aSSerapheim Dimitropoulos
4932ec7644aSSerapheim Dimitropoulos return (0);
4942ec7644aSSerapheim Dimitropoulos }
4952ec7644aSSerapheim Dimitropoulos
4962ec7644aSSerapheim Dimitropoulos static int
nvt_add_nvpair(nvlist_t * nvl,nvpair_t * nvp)4972ec7644aSSerapheim Dimitropoulos nvt_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
4982ec7644aSSerapheim Dimitropoulos {
4992ec7644aSSerapheim Dimitropoulos nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
5002ec7644aSSerapheim Dimitropoulos
5012ec7644aSSerapheim Dimitropoulos /* initialize nvpair table now if it doesn't exist. */
5022ec7644aSSerapheim Dimitropoulos if (priv->nvp_hashtable == NULL) {
5032ec7644aSSerapheim Dimitropoulos int err = nvt_tab_alloc(priv, nvlist_hashtable_init_size);
5042ec7644aSSerapheim Dimitropoulos if (err != 0)
5052ec7644aSSerapheim Dimitropoulos return (err);
5062ec7644aSSerapheim Dimitropoulos }
5072ec7644aSSerapheim Dimitropoulos
5082ec7644aSSerapheim Dimitropoulos /*
5092ec7644aSSerapheim Dimitropoulos * if we don't allow duplicate entries, make sure to
5102ec7644aSSerapheim Dimitropoulos * unlink any existing entries from the table.
5112ec7644aSSerapheim Dimitropoulos */
5122ec7644aSSerapheim Dimitropoulos if (nvl->nvl_nvflag != 0) {
5132ec7644aSSerapheim Dimitropoulos int err = nvt_remove_nvpair(nvl, nvp);
5142ec7644aSSerapheim Dimitropoulos if (err != 0)
5152ec7644aSSerapheim Dimitropoulos return (err);
5162ec7644aSSerapheim Dimitropoulos }
5172ec7644aSSerapheim Dimitropoulos
5182ec7644aSSerapheim Dimitropoulos if (nvt_needs_togrow(priv)) {
5192ec7644aSSerapheim Dimitropoulos int err = nvt_grow(priv);
5202ec7644aSSerapheim Dimitropoulos if (err != 0)
5212ec7644aSSerapheim Dimitropoulos return (err);
5222ec7644aSSerapheim Dimitropoulos }
5232ec7644aSSerapheim Dimitropoulos i_nvp_t **tab = priv->nvp_hashtable;
5242ec7644aSSerapheim Dimitropoulos
5252ec7644aSSerapheim Dimitropoulos char *name = NVP_NAME(nvp);
5262ec7644aSSerapheim Dimitropoulos uint64_t hash = nvt_hash(name);
5272ec7644aSSerapheim Dimitropoulos uint64_t index = hash & (priv->nvp_nbuckets - 1);
5282ec7644aSSerapheim Dimitropoulos
5292ec7644aSSerapheim Dimitropoulos ASSERT3U(index, <, priv->nvp_nbuckets);
5302ec7644aSSerapheim Dimitropoulos i_nvp_t *bucket = tab[index];
5312ec7644aSSerapheim Dimitropoulos
5322ec7644aSSerapheim Dimitropoulos /* insert link at the beginning of the bucket */
5332ec7644aSSerapheim Dimitropoulos i_nvp_t *new_entry = NVPAIR2I_NVP(nvp);
5342ec7644aSSerapheim Dimitropoulos ASSERT3P(new_entry->nvi_hashtable_next, ==, NULL);
5352ec7644aSSerapheim Dimitropoulos new_entry->nvi_hashtable_next = bucket;
5362ec7644aSSerapheim Dimitropoulos tab[index] = new_entry;
5372ec7644aSSerapheim Dimitropoulos
5382ec7644aSSerapheim Dimitropoulos priv->nvp_nentries++;
5392ec7644aSSerapheim Dimitropoulos return (0);
5402ec7644aSSerapheim Dimitropoulos }
5412ec7644aSSerapheim Dimitropoulos
5427c478bd9Sstevel@tonic-gate static void
nvlist_init(nvlist_t * nvl,uint32_t nvflag,nvpriv_t * priv)5437c478bd9Sstevel@tonic-gate nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate nvl->nvl_version = NV_VERSION;
5467c478bd9Sstevel@tonic-gate nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);
5477c478bd9Sstevel@tonic-gate nvl->nvl_priv = (uint64_t)(uintptr_t)priv;
5487c478bd9Sstevel@tonic-gate nvl->nvl_flag = 0;
5497c478bd9Sstevel@tonic-gate nvl->nvl_pad = 0;
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate
552f6e214c7SGavin Maltby uint_t
nvlist_nvflag(nvlist_t * nvl)553f6e214c7SGavin Maltby nvlist_nvflag(nvlist_t *nvl)
554f6e214c7SGavin Maltby {
555f6e214c7SGavin Maltby return (nvl->nvl_nvflag);
556f6e214c7SGavin Maltby }
557f6e214c7SGavin Maltby
5587c478bd9Sstevel@tonic-gate /*
5597c478bd9Sstevel@tonic-gate * nvlist_alloc - Allocate nvlist.
5607c478bd9Sstevel@tonic-gate */
5617c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
5627c478bd9Sstevel@tonic-gate int
nvlist_alloc(nvlist_t ** nvlp,uint_t nvflag,int kmflag)5637c478bd9Sstevel@tonic-gate nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
5667c478bd9Sstevel@tonic-gate return (nvlist_xalloc(nvlp, nvflag,
5677c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
5687c478bd9Sstevel@tonic-gate #else
5697c478bd9Sstevel@tonic-gate return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep));
5707c478bd9Sstevel@tonic-gate #endif
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate int
nvlist_xalloc(nvlist_t ** nvlp,uint_t nvflag,nv_alloc_t * nva)5747c478bd9Sstevel@tonic-gate nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate nvpriv_t *priv;
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate if (nvlp == NULL || nva == NULL)
5797c478bd9Sstevel@tonic-gate return (EINVAL);
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate if ((priv = nv_priv_alloc(nva)) == NULL)
5827c478bd9Sstevel@tonic-gate return (ENOMEM);
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate if ((*nvlp = nv_mem_zalloc(priv,
5857c478bd9Sstevel@tonic-gate NV_ALIGN(sizeof (nvlist_t)))) == NULL) {
5867c478bd9Sstevel@tonic-gate nv_mem_free(priv, priv, sizeof (nvpriv_t));
5877c478bd9Sstevel@tonic-gate return (ENOMEM);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate nvlist_init(*nvlp, nvflag, priv);
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate return (0);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
5977c478bd9Sstevel@tonic-gate */
5987c478bd9Sstevel@tonic-gate static nvpair_t *
nvp_buf_alloc(nvlist_t * nvl,size_t len)5997c478bd9Sstevel@tonic-gate nvp_buf_alloc(nvlist_t *nvl, size_t len)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6027c478bd9Sstevel@tonic-gate i_nvp_t *buf;
6037c478bd9Sstevel@tonic-gate nvpair_t *nvp;
6047c478bd9Sstevel@tonic-gate size_t nvsize;
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate /*
6077c478bd9Sstevel@tonic-gate * Allocate the buffer
6087c478bd9Sstevel@tonic-gate */
6097c478bd9Sstevel@tonic-gate nvsize = len + offsetof(i_nvp_t, nvi_nvp);
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)
6127c478bd9Sstevel@tonic-gate return (NULL);
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate nvp = &buf->nvi_nvp;
6157c478bd9Sstevel@tonic-gate nvp->nvp_size = len;
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate return (nvp);
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate /*
6217c478bd9Sstevel@tonic-gate * nvp_buf_free - de-Allocate an i_nvp_t.
6227c478bd9Sstevel@tonic-gate */
6237c478bd9Sstevel@tonic-gate static void
nvp_buf_free(nvlist_t * nvl,nvpair_t * nvp)6247c478bd9Sstevel@tonic-gate nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)
6257c478bd9Sstevel@tonic-gate {
6267c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6277c478bd9Sstevel@tonic-gate size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate /*
6337c478bd9Sstevel@tonic-gate * nvp_buf_link - link a new nv pair into the nvlist.
6347c478bd9Sstevel@tonic-gate */
6357c478bd9Sstevel@tonic-gate static void
nvp_buf_link(nvlist_t * nvl,nvpair_t * nvp)6367c478bd9Sstevel@tonic-gate nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6397c478bd9Sstevel@tonic-gate i_nvp_t *curr = NVPAIR2I_NVP(nvp);
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate /* Put element at end of nvlist */
6427c478bd9Sstevel@tonic-gate if (priv->nvp_list == NULL) {
6437c478bd9Sstevel@tonic-gate priv->nvp_list = priv->nvp_last = curr;
6447c478bd9Sstevel@tonic-gate } else {
6457c478bd9Sstevel@tonic-gate curr->nvi_prev = priv->nvp_last;
6467c478bd9Sstevel@tonic-gate priv->nvp_last->nvi_next = curr;
6477c478bd9Sstevel@tonic-gate priv->nvp_last = curr;
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate * nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
6537c478bd9Sstevel@tonic-gate */
6547c478bd9Sstevel@tonic-gate static void
nvp_buf_unlink(nvlist_t * nvl,nvpair_t * nvp)6557c478bd9Sstevel@tonic-gate nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6587c478bd9Sstevel@tonic-gate i_nvp_t *curr = NVPAIR2I_NVP(nvp);
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate * protect nvlist_next_nvpair() against walking on freed memory.
6627c478bd9Sstevel@tonic-gate */
6637c478bd9Sstevel@tonic-gate if (priv->nvp_curr == curr)
6647c478bd9Sstevel@tonic-gate priv->nvp_curr = curr->nvi_next;
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate if (curr == priv->nvp_list)
6677c478bd9Sstevel@tonic-gate priv->nvp_list = curr->nvi_next;
6687c478bd9Sstevel@tonic-gate else
6697c478bd9Sstevel@tonic-gate curr->nvi_prev->nvi_next = curr->nvi_next;
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate if (curr == priv->nvp_last)
6727c478bd9Sstevel@tonic-gate priv->nvp_last = curr->nvi_prev;
6737c478bd9Sstevel@tonic-gate else
6747c478bd9Sstevel@tonic-gate curr->nvi_next->nvi_prev = curr->nvi_prev;
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate /*
6787c478bd9Sstevel@tonic-gate * take a nvpair type and number of elements and make sure the are valid
6797c478bd9Sstevel@tonic-gate */
6807c478bd9Sstevel@tonic-gate static int
i_validate_type_nelem(data_type_t type,uint_t nelem)6817c478bd9Sstevel@tonic-gate i_validate_type_nelem(data_type_t type, uint_t nelem)
6827c478bd9Sstevel@tonic-gate {
6837c478bd9Sstevel@tonic-gate switch (type) {
6847c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
6857c478bd9Sstevel@tonic-gate if (nelem != 0)
6867c478bd9Sstevel@tonic-gate return (EINVAL);
6877c478bd9Sstevel@tonic-gate break;
6887c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE:
6897c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE:
6907c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8:
6917c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8:
6927c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16:
6937c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16:
6947c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32:
6957c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32:
6967c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64:
6977c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64:
6987c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING:
6997c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME:
7007c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST:
701825ba0f2Srobj #if !defined(_KERNEL)
702825ba0f2Srobj case DATA_TYPE_DOUBLE:
703825ba0f2Srobj #endif
7047c478bd9Sstevel@tonic-gate if (nelem != 1)
7057c478bd9Sstevel@tonic-gate return (EINVAL);
7067c478bd9Sstevel@tonic-gate break;
7077c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY:
7087c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY:
7097c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY:
7107c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY:
7117c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY:
7127c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY:
7137c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY:
7147c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY:
7157c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY:
7167c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY:
7177c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY:
7187c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY:
7197c478bd9Sstevel@tonic-gate /* we allow arrays with 0 elements */
7207c478bd9Sstevel@tonic-gate break;
7217c478bd9Sstevel@tonic-gate default:
7227c478bd9Sstevel@tonic-gate return (EINVAL);
7237c478bd9Sstevel@tonic-gate }
7247c478bd9Sstevel@tonic-gate return (0);
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate * Verify nvp_name_sz and check the name string length.
7297c478bd9Sstevel@tonic-gate */
7307c478bd9Sstevel@tonic-gate static int
i_validate_nvpair_name(nvpair_t * nvp)7317c478bd9Sstevel@tonic-gate i_validate_nvpair_name(nvpair_t *nvp)
7327c478bd9Sstevel@tonic-gate {
7337c478bd9Sstevel@tonic-gate if ((nvp->nvp_name_sz <= 0) ||
7347c478bd9Sstevel@tonic-gate (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))
7357c478bd9Sstevel@tonic-gate return (EFAULT);
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate /* verify the name string, make sure its terminated */
7387c478bd9Sstevel@tonic-gate if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')
7397c478bd9Sstevel@tonic-gate return (EFAULT);
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate static int
i_validate_nvpair_value(data_type_t type,uint_t nelem,const void * data)7457c478bd9Sstevel@tonic-gate i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)
7467c478bd9Sstevel@tonic-gate {
7477c478bd9Sstevel@tonic-gate switch (type) {
7487c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE:
7497c478bd9Sstevel@tonic-gate if (*(boolean_t *)data != B_TRUE &&
7507c478bd9Sstevel@tonic-gate *(boolean_t *)data != B_FALSE)
7517c478bd9Sstevel@tonic-gate return (EINVAL);
7527c478bd9Sstevel@tonic-gate break;
7537c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY: {
7547c478bd9Sstevel@tonic-gate int i;
7557c478bd9Sstevel@tonic-gate
7567c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++)
7577c478bd9Sstevel@tonic-gate if (((boolean_t *)data)[i] != B_TRUE &&
7587c478bd9Sstevel@tonic-gate ((boolean_t *)data)[i] != B_FALSE)
7597c478bd9Sstevel@tonic-gate return (EINVAL);
7607c478bd9Sstevel@tonic-gate break;
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate default:
7637c478bd9Sstevel@tonic-gate break;
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate return (0);
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate /*
7707c478bd9Sstevel@tonic-gate * This function takes a pointer to what should be a nvpair and it's size
7717c478bd9Sstevel@tonic-gate * and then verifies that all the nvpair fields make sense and can be
7727c478bd9Sstevel@tonic-gate * trusted. This function is used when decoding packed nvpairs.
7737c478bd9Sstevel@tonic-gate */
7747c478bd9Sstevel@tonic-gate static int
i_validate_nvpair(nvpair_t * nvp)7757c478bd9Sstevel@tonic-gate i_validate_nvpair(nvpair_t *nvp)
7767c478bd9Sstevel@tonic-gate {
7777c478bd9Sstevel@tonic-gate data_type_t type = NVP_TYPE(nvp);
7787c478bd9Sstevel@tonic-gate int size1, size2;
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate /* verify nvp_name_sz, check the name string length */
7817c478bd9Sstevel@tonic-gate if (i_validate_nvpair_name(nvp) != 0)
7827c478bd9Sstevel@tonic-gate return (EFAULT);
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)
7857c478bd9Sstevel@tonic-gate return (EFAULT);
7867c478bd9Sstevel@tonic-gate
7877c478bd9Sstevel@tonic-gate /*
7887c478bd9Sstevel@tonic-gate * verify nvp_type, nvp_value_elem, and also possibly
7897c478bd9Sstevel@tonic-gate * verify string values and get the value size.
7907c478bd9Sstevel@tonic-gate */
7917c478bd9Sstevel@tonic-gate size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));
7927c478bd9Sstevel@tonic-gate size1 = nvp->nvp_size - NVP_VALOFF(nvp);
7937c478bd9Sstevel@tonic-gate if (size2 < 0 || size1 != NV_ALIGN(size2))
7947c478bd9Sstevel@tonic-gate return (EFAULT);
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate return (0);
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate static int
nvlist_copy_pairs(nvlist_t * snvl,nvlist_t * dnvl)8007c478bd9Sstevel@tonic-gate nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl)
8017c478bd9Sstevel@tonic-gate {
8027c478bd9Sstevel@tonic-gate nvpriv_t *priv;
8037c478bd9Sstevel@tonic-gate i_nvp_t *curr;
8047c478bd9Sstevel@tonic-gate
8057c478bd9Sstevel@tonic-gate if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)
8067c478bd9Sstevel@tonic-gate return (EINVAL);
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
8097c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp;
8107c478bd9Sstevel@tonic-gate int err;
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),
8137c478bd9Sstevel@tonic-gate NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)
8147c478bd9Sstevel@tonic-gate return (err);
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate
8177c478bd9Sstevel@tonic-gate return (0);
8187c478bd9Sstevel@tonic-gate }
8197c478bd9Sstevel@tonic-gate
8207c478bd9Sstevel@tonic-gate /*
8217c478bd9Sstevel@tonic-gate * Frees all memory allocated for an nvpair (like embedded lists) with
8227c478bd9Sstevel@tonic-gate * the exception of the nvpair buffer itself.
8237c478bd9Sstevel@tonic-gate */
8247c478bd9Sstevel@tonic-gate static void
nvpair_free(nvpair_t * nvp)8257c478bd9Sstevel@tonic-gate nvpair_free(nvpair_t *nvp)
8267c478bd9Sstevel@tonic-gate {
8277c478bd9Sstevel@tonic-gate switch (NVP_TYPE(nvp)) {
8287c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST:
8297c478bd9Sstevel@tonic-gate nvlist_free(EMBEDDED_NVL(nvp));
8307c478bd9Sstevel@tonic-gate break;
8317c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: {
8327c478bd9Sstevel@tonic-gate nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
8337c478bd9Sstevel@tonic-gate int i;
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++)
8367c478bd9Sstevel@tonic-gate nvlist_free(nvlp[i]);
8377c478bd9Sstevel@tonic-gate break;
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate default:
8407c478bd9Sstevel@tonic-gate break;
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate
8447c478bd9Sstevel@tonic-gate /*
8457c478bd9Sstevel@tonic-gate * nvlist_free - free an unpacked nvlist
8467c478bd9Sstevel@tonic-gate */
8477c478bd9Sstevel@tonic-gate void
nvlist_free(nvlist_t * nvl)8487c478bd9Sstevel@tonic-gate nvlist_free(nvlist_t *nvl)
8497c478bd9Sstevel@tonic-gate {
8507c478bd9Sstevel@tonic-gate nvpriv_t *priv;
8517c478bd9Sstevel@tonic-gate i_nvp_t *curr;
8527c478bd9Sstevel@tonic-gate
8537c478bd9Sstevel@tonic-gate if (nvl == NULL ||
8547c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
8557c478bd9Sstevel@tonic-gate return;
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate /*
8587c478bd9Sstevel@tonic-gate * Unpacked nvlist are linked through i_nvp_t
8597c478bd9Sstevel@tonic-gate */
8607c478bd9Sstevel@tonic-gate curr = priv->nvp_list;
8617c478bd9Sstevel@tonic-gate while (curr != NULL) {
8627c478bd9Sstevel@tonic-gate nvpair_t *nvp = &curr->nvi_nvp;
8637c478bd9Sstevel@tonic-gate curr = curr->nvi_next;
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate nvpair_free(nvp);
8667c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp);
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate if (!(priv->nvp_stat & NV_STAT_EMBEDDED))
8707c478bd9Sstevel@tonic-gate nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));
8717c478bd9Sstevel@tonic-gate else
8725ad82045Snd150628 nvl->nvl_priv = 0;
8737c478bd9Sstevel@tonic-gate
8742ec7644aSSerapheim Dimitropoulos nvt_tab_free(priv);
8757c478bd9Sstevel@tonic-gate nv_mem_free(priv, priv, sizeof (nvpriv_t));
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate static int
nvlist_contains_nvp(nvlist_t * nvl,nvpair_t * nvp)8797c478bd9Sstevel@tonic-gate nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
8827c478bd9Sstevel@tonic-gate i_nvp_t *curr;
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate if (nvp == NULL)
8857c478bd9Sstevel@tonic-gate return (0);
8867c478bd9Sstevel@tonic-gate
8877c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
8887c478bd9Sstevel@tonic-gate if (&curr->nvi_nvp == nvp)
8897c478bd9Sstevel@tonic-gate return (1);
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate return (0);
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate /*
8957c478bd9Sstevel@tonic-gate * Make a copy of nvlist
8967c478bd9Sstevel@tonic-gate */
8977c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
8987c478bd9Sstevel@tonic-gate int
nvlist_dup(nvlist_t * nvl,nvlist_t ** nvlp,int kmflag)8997c478bd9Sstevel@tonic-gate nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag)
9007c478bd9Sstevel@tonic-gate {
9017c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
9027c478bd9Sstevel@tonic-gate return (nvlist_xdup(nvl, nvlp,
9037c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
9047c478bd9Sstevel@tonic-gate #else
9057c478bd9Sstevel@tonic-gate return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep));
9067c478bd9Sstevel@tonic-gate #endif
9077c478bd9Sstevel@tonic-gate }
9087c478bd9Sstevel@tonic-gate
9097c478bd9Sstevel@tonic-gate int
nvlist_xdup(nvlist_t * nvl,nvlist_t ** nvlp,nv_alloc_t * nva)9107c478bd9Sstevel@tonic-gate nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)
9117c478bd9Sstevel@tonic-gate {
9127c478bd9Sstevel@tonic-gate int err;
9133bb79becSeschrock nvlist_t *ret;
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate if (nvl == NULL || nvlp == NULL)
9167c478bd9Sstevel@tonic-gate return (EINVAL);
9177c478bd9Sstevel@tonic-gate
9183bb79becSeschrock if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0)
9197c478bd9Sstevel@tonic-gate return (err);
9207c478bd9Sstevel@tonic-gate
9213bb79becSeschrock if ((err = nvlist_copy_pairs(nvl, ret)) != 0)
9223bb79becSeschrock nvlist_free(ret);
9233bb79becSeschrock else
9243bb79becSeschrock *nvlp = ret;
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate return (err);
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate
9297c478bd9Sstevel@tonic-gate /*
9307c478bd9Sstevel@tonic-gate * Remove all with matching name
9317c478bd9Sstevel@tonic-gate */
9327c478bd9Sstevel@tonic-gate int
nvlist_remove_all(nvlist_t * nvl,const char * name)9337c478bd9Sstevel@tonic-gate nvlist_remove_all(nvlist_t *nvl, const char *name)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate int error = ENOENT;
9367c478bd9Sstevel@tonic-gate
9372ec7644aSSerapheim Dimitropoulos if (nvl == NULL || name == NULL || nvl->nvl_priv == 0)
9387c478bd9Sstevel@tonic-gate return (EINVAL);
9397c478bd9Sstevel@tonic-gate
9402ec7644aSSerapheim Dimitropoulos nvpair_t *nvp;
9412ec7644aSSerapheim Dimitropoulos while ((nvp = nvt_lookup_name(nvl, name)) != NULL) {
9422ec7644aSSerapheim Dimitropoulos VERIFY0(nvlist_remove_nvpair(nvl, nvp));
9437c478bd9Sstevel@tonic-gate error = 0;
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate
9467c478bd9Sstevel@tonic-gate return (error);
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate /*
9507c478bd9Sstevel@tonic-gate * Remove first one with matching name and type
9517c478bd9Sstevel@tonic-gate */
9527c478bd9Sstevel@tonic-gate int
nvlist_remove(nvlist_t * nvl,const char * name,data_type_t type)9537c478bd9Sstevel@tonic-gate nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
9547c478bd9Sstevel@tonic-gate {
9552ec7644aSSerapheim Dimitropoulos if (nvl == NULL || name == NULL || nvl->nvl_priv == 0)
9567c478bd9Sstevel@tonic-gate return (EINVAL);
9577c478bd9Sstevel@tonic-gate
9582ec7644aSSerapheim Dimitropoulos nvpair_t *nvp = nvt_lookup_name_type(nvl, name, type);
9592ec7644aSSerapheim Dimitropoulos if (nvp == NULL)
9607c478bd9Sstevel@tonic-gate return (ENOENT);
9612ec7644aSSerapheim Dimitropoulos
9622ec7644aSSerapheim Dimitropoulos return (nvlist_remove_nvpair(nvl, nvp));
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate
96592241e0bSTom Erickson int
nvlist_remove_nvpair(nvlist_t * nvl,nvpair_t * nvp)96692241e0bSTom Erickson nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
96792241e0bSTom Erickson {
96892241e0bSTom Erickson if (nvl == NULL || nvp == NULL)
96992241e0bSTom Erickson return (EINVAL);
97092241e0bSTom Erickson
9712ec7644aSSerapheim Dimitropoulos int err = nvt_remove_nvpair(nvl, nvp);
9722ec7644aSSerapheim Dimitropoulos if (err != 0)
9732ec7644aSSerapheim Dimitropoulos return (err);
9742ec7644aSSerapheim Dimitropoulos
97592241e0bSTom Erickson nvp_buf_unlink(nvl, nvp);
97692241e0bSTom Erickson nvpair_free(nvp);
97792241e0bSTom Erickson nvp_buf_free(nvl, nvp);
97892241e0bSTom Erickson return (0);
97992241e0bSTom Erickson }
98092241e0bSTom Erickson
9817c478bd9Sstevel@tonic-gate /*
9827c478bd9Sstevel@tonic-gate * This function calculates the size of an nvpair value.
9837c478bd9Sstevel@tonic-gate *
9847c478bd9Sstevel@tonic-gate * The data argument controls the behavior in case of the data types
9857c478bd9Sstevel@tonic-gate * DATA_TYPE_STRING and
9867c478bd9Sstevel@tonic-gate * DATA_TYPE_STRING_ARRAY
9877c478bd9Sstevel@tonic-gate * Is data == NULL then the size of the string(s) is excluded.
9887c478bd9Sstevel@tonic-gate */
9897c478bd9Sstevel@tonic-gate static int
i_get_value_size(data_type_t type,const void * data,uint_t nelem)9907c478bd9Sstevel@tonic-gate i_get_value_size(data_type_t type, const void *data, uint_t nelem)
9917c478bd9Sstevel@tonic-gate {
9927c478bd9Sstevel@tonic-gate uint64_t value_sz;
9937c478bd9Sstevel@tonic-gate
9947c478bd9Sstevel@tonic-gate if (i_validate_type_nelem(type, nelem) != 0)
9957c478bd9Sstevel@tonic-gate return (-1);
9967c478bd9Sstevel@tonic-gate
9977c478bd9Sstevel@tonic-gate /* Calculate required size for holding value */
9987c478bd9Sstevel@tonic-gate switch (type) {
9997c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
10007c478bd9Sstevel@tonic-gate value_sz = 0;
10017c478bd9Sstevel@tonic-gate break;
10027c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE:
10037c478bd9Sstevel@tonic-gate value_sz = sizeof (boolean_t);
10047c478bd9Sstevel@tonic-gate break;
10057c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE:
10067c478bd9Sstevel@tonic-gate value_sz = sizeof (uchar_t);
10077c478bd9Sstevel@tonic-gate break;
10087c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8:
10097c478bd9Sstevel@tonic-gate value_sz = sizeof (int8_t);
10107c478bd9Sstevel@tonic-gate break;
10117c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8:
10127c478bd9Sstevel@tonic-gate value_sz = sizeof (uint8_t);
10137c478bd9Sstevel@tonic-gate break;
10147c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16:
10157c478bd9Sstevel@tonic-gate value_sz = sizeof (int16_t);
10167c478bd9Sstevel@tonic-gate break;
10177c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16:
10187c478bd9Sstevel@tonic-gate value_sz = sizeof (uint16_t);
10197c478bd9Sstevel@tonic-gate break;
10207c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32:
10217c478bd9Sstevel@tonic-gate value_sz = sizeof (int32_t);
10227c478bd9Sstevel@tonic-gate break;
10237c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32:
10247c478bd9Sstevel@tonic-gate value_sz = sizeof (uint32_t);
10257c478bd9Sstevel@tonic-gate break;
10267c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64:
10277c478bd9Sstevel@tonic-gate value_sz = sizeof (int64_t);
10287c478bd9Sstevel@tonic-gate break;
10297c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64:
10307c478bd9Sstevel@tonic-gate value_sz = sizeof (uint64_t);
10317c478bd9Sstevel@tonic-gate break;
1032825ba0f2Srobj #if !defined(_KERNEL)
1033825ba0f2Srobj case DATA_TYPE_DOUBLE:
1034825ba0f2Srobj value_sz = sizeof (double);
1035825ba0f2Srobj break;
1036825ba0f2Srobj #endif
10377c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING:
10387c478bd9Sstevel@tonic-gate if (data == NULL)
10397c478bd9Sstevel@tonic-gate value_sz = 0;
10407c478bd9Sstevel@tonic-gate else
10417c478bd9Sstevel@tonic-gate value_sz = strlen(data) + 1;
10427c478bd9Sstevel@tonic-gate break;
10437c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY:
10447c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (boolean_t);
10457c478bd9Sstevel@tonic-gate break;
10467c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY:
10477c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uchar_t);
10487c478bd9Sstevel@tonic-gate break;
10497c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY:
10507c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int8_t);
10517c478bd9Sstevel@tonic-gate break;
10527c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY:
10537c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint8_t);
10547c478bd9Sstevel@tonic-gate break;
10557c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY:
10567c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int16_t);
10577c478bd9Sstevel@tonic-gate break;
10587c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY:
10597c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint16_t);
10607c478bd9Sstevel@tonic-gate break;
10617c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY:
10627c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int32_t);
10637c478bd9Sstevel@tonic-gate break;
10647c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY:
10657c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint32_t);
10667c478bd9Sstevel@tonic-gate break;
10677c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY:
10687c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (int64_t);
10697c478bd9Sstevel@tonic-gate break;
10707c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY:
10717c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint64_t);
10727c478bd9Sstevel@tonic-gate break;
10737c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY:
10747c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint64_t);
10757c478bd9Sstevel@tonic-gate
10767c478bd9Sstevel@tonic-gate if (data != NULL) {
10777c478bd9Sstevel@tonic-gate char *const *strs = data;
10787c478bd9Sstevel@tonic-gate uint_t i;
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate /* no alignment requirement for strings */
10817c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) {
10827c478bd9Sstevel@tonic-gate if (strs[i] == NULL)
10837c478bd9Sstevel@tonic-gate return (-1);
10847c478bd9Sstevel@tonic-gate value_sz += strlen(strs[i]) + 1;
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate }
10877c478bd9Sstevel@tonic-gate break;
10887c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME:
10897c478bd9Sstevel@tonic-gate value_sz = sizeof (hrtime_t);
10907c478bd9Sstevel@tonic-gate break;
10917c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST:
10927c478bd9Sstevel@tonic-gate value_sz = NV_ALIGN(sizeof (nvlist_t));
10937c478bd9Sstevel@tonic-gate break;
10947c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY:
10957c478bd9Sstevel@tonic-gate value_sz = (uint64_t)nelem * sizeof (uint64_t) +
10967c478bd9Sstevel@tonic-gate (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
10977c478bd9Sstevel@tonic-gate break;
10987c478bd9Sstevel@tonic-gate default:
10997c478bd9Sstevel@tonic-gate return (-1);
11007c478bd9Sstevel@tonic-gate }
11017c478bd9Sstevel@tonic-gate
11027c478bd9Sstevel@tonic-gate return (value_sz > INT32_MAX ? -1 : (int)value_sz);
11037c478bd9Sstevel@tonic-gate }
11047c478bd9Sstevel@tonic-gate
11057c478bd9Sstevel@tonic-gate static int
nvlist_copy_embedded(nvlist_t * nvl,nvlist_t * onvl,nvlist_t * emb_nvl)11067c478bd9Sstevel@tonic-gate nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl)
11077c478bd9Sstevel@tonic-gate {
11087c478bd9Sstevel@tonic-gate nvpriv_t *priv;
11097c478bd9Sstevel@tonic-gate int err;
11107c478bd9Sstevel@tonic-gate
11117c478bd9Sstevel@tonic-gate if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t)
11127c478bd9Sstevel@tonic-gate nvl->nvl_priv)) == NULL)
11137c478bd9Sstevel@tonic-gate return (ENOMEM);
11147c478bd9Sstevel@tonic-gate
11157c478bd9Sstevel@tonic-gate nvlist_init(emb_nvl, onvl->nvl_nvflag, priv);
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) {
11187c478bd9Sstevel@tonic-gate nvlist_free(emb_nvl);
11197c478bd9Sstevel@tonic-gate emb_nvl->nvl_priv = 0;
11207c478bd9Sstevel@tonic-gate }
11217c478bd9Sstevel@tonic-gate
11227c478bd9Sstevel@tonic-gate return (err);
11237c478bd9Sstevel@tonic-gate }
11247c478bd9Sstevel@tonic-gate
11257c478bd9Sstevel@tonic-gate /*
11267c478bd9Sstevel@tonic-gate * nvlist_add_common - Add new <name,value> pair to nvlist
11277c478bd9Sstevel@tonic-gate */
11287c478bd9Sstevel@tonic-gate static int
nvlist_add_common(nvlist_t * nvl,const char * name,data_type_t type,uint_t nelem,const void * data)11297c478bd9Sstevel@tonic-gate nvlist_add_common(nvlist_t *nvl, const char *name,
11307c478bd9Sstevel@tonic-gate data_type_t type, uint_t nelem, const void *data)
11317c478bd9Sstevel@tonic-gate {
11327c478bd9Sstevel@tonic-gate nvpair_t *nvp;
1133d9638e54Smws uint_t i;
1134d9638e54Smws
11357c478bd9Sstevel@tonic-gate int nvp_sz, name_sz, value_sz;
11367c478bd9Sstevel@tonic-gate int err = 0;
11377c478bd9Sstevel@tonic-gate
11387c478bd9Sstevel@tonic-gate if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
11397c478bd9Sstevel@tonic-gate return (EINVAL);
11407c478bd9Sstevel@tonic-gate
11417c478bd9Sstevel@tonic-gate if (nelem != 0 && data == NULL)
11427c478bd9Sstevel@tonic-gate return (EINVAL);
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate * Verify type and nelem and get the value size.
11467c478bd9Sstevel@tonic-gate * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
11477c478bd9Sstevel@tonic-gate * is the size of the string(s) included.
11487c478bd9Sstevel@tonic-gate */
11497c478bd9Sstevel@tonic-gate if ((value_sz = i_get_value_size(type, data, nelem)) < 0)
11507c478bd9Sstevel@tonic-gate return (EINVAL);
11517c478bd9Sstevel@tonic-gate
11527c478bd9Sstevel@tonic-gate if (i_validate_nvpair_value(type, nelem, data) != 0)
11537c478bd9Sstevel@tonic-gate return (EINVAL);
11547c478bd9Sstevel@tonic-gate
1155d9638e54Smws /*
1156d9638e54Smws * If we're adding an nvlist or nvlist array, ensure that we are not
1157d9638e54Smws * adding the input nvlist to itself, which would cause recursion,
1158d9638e54Smws * and ensure that no NULL nvlist pointers are present.
1159d9638e54Smws */
11607c478bd9Sstevel@tonic-gate switch (type) {
11617c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST:
1162d9638e54Smws if (data == nvl || data == NULL)
11637c478bd9Sstevel@tonic-gate return (EINVAL);
11647c478bd9Sstevel@tonic-gate break;
11657c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: {
1166d9638e54Smws nvlist_t **onvlp = (nvlist_t **)data;
1167d9638e54Smws for (i = 0; i < nelem; i++) {
1168d9638e54Smws if (onvlp[i] == nvl || onvlp[i] == NULL)
11697c478bd9Sstevel@tonic-gate return (EINVAL);
11707c478bd9Sstevel@tonic-gate }
11717c478bd9Sstevel@tonic-gate break;
1172d9638e54Smws }
11735ad82045Snd150628 default:
11745ad82045Snd150628 break;
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate /* calculate sizes of the nvpair elements and the nvpair itself */
11787c478bd9Sstevel@tonic-gate name_sz = strlen(name) + 1;
117948dd5e63SMatthew Ahrens if (name_sz >= 1ULL << (sizeof (nvp->nvp_name_sz) * NBBY - 1))
118048dd5e63SMatthew Ahrens return (EINVAL);
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate nvp_sz = NVP_SIZE_CALC(name_sz, value_sz);
11837c478bd9Sstevel@tonic-gate
11847c478bd9Sstevel@tonic-gate if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL)
11857c478bd9Sstevel@tonic-gate return (ENOMEM);
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate ASSERT(nvp->nvp_size == nvp_sz);
11887c478bd9Sstevel@tonic-gate nvp->nvp_name_sz = name_sz;
11897c478bd9Sstevel@tonic-gate nvp->nvp_value_elem = nelem;
11907c478bd9Sstevel@tonic-gate nvp->nvp_type = type;
11917c478bd9Sstevel@tonic-gate bcopy(name, NVP_NAME(nvp), name_sz);
11927c478bd9Sstevel@tonic-gate
11937c478bd9Sstevel@tonic-gate switch (type) {
11947c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
11957c478bd9Sstevel@tonic-gate break;
11967c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: {
11977c478bd9Sstevel@tonic-gate char *const *strs = data;
11987c478bd9Sstevel@tonic-gate char *buf = NVP_VALUE(nvp);
11997c478bd9Sstevel@tonic-gate char **cstrs = (void *)buf;
12007c478bd9Sstevel@tonic-gate
12017c478bd9Sstevel@tonic-gate /* skip pre-allocated space for pointer array */
12027c478bd9Sstevel@tonic-gate buf += nelem * sizeof (uint64_t);
12037c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) {
12047c478bd9Sstevel@tonic-gate int slen = strlen(strs[i]) + 1;
12057c478bd9Sstevel@tonic-gate bcopy(strs[i], buf, slen);
12067c478bd9Sstevel@tonic-gate cstrs[i] = buf;
12077c478bd9Sstevel@tonic-gate buf += slen;
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate break;
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: {
12127c478bd9Sstevel@tonic-gate nvlist_t *nnvl = EMBEDDED_NVL(nvp);
12137c478bd9Sstevel@tonic-gate nvlist_t *onvl = (nvlist_t *)data;
12147c478bd9Sstevel@tonic-gate
12157c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) {
12167c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp);
12177c478bd9Sstevel@tonic-gate return (err);
12187c478bd9Sstevel@tonic-gate }
12197c478bd9Sstevel@tonic-gate break;
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: {
12227c478bd9Sstevel@tonic-gate nvlist_t **onvlp = (nvlist_t **)data;
12237c478bd9Sstevel@tonic-gate nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
12247c478bd9Sstevel@tonic-gate nvlist_t *embedded = (nvlist_t *)
12257c478bd9Sstevel@tonic-gate ((uintptr_t)nvlp + nelem * sizeof (uint64_t));
12267c478bd9Sstevel@tonic-gate
12277c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) {
12287c478bd9Sstevel@tonic-gate if ((err = nvlist_copy_embedded(nvl,
12297c478bd9Sstevel@tonic-gate onvlp[i], embedded)) != 0) {
12307c478bd9Sstevel@tonic-gate /*
12317c478bd9Sstevel@tonic-gate * Free any successfully created lists
12327c478bd9Sstevel@tonic-gate */
12337c478bd9Sstevel@tonic-gate nvpair_free(nvp);
12347c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp);
12357c478bd9Sstevel@tonic-gate return (err);
12367c478bd9Sstevel@tonic-gate }
12377c478bd9Sstevel@tonic-gate
12387c478bd9Sstevel@tonic-gate nvlp[i] = embedded++;
12397c478bd9Sstevel@tonic-gate }
12407c478bd9Sstevel@tonic-gate break;
12417c478bd9Sstevel@tonic-gate }
12427c478bd9Sstevel@tonic-gate default:
12437c478bd9Sstevel@tonic-gate bcopy(data, NVP_VALUE(nvp), value_sz);
12447c478bd9Sstevel@tonic-gate }
12457c478bd9Sstevel@tonic-gate
12467c478bd9Sstevel@tonic-gate /* if unique name, remove before add */
12477c478bd9Sstevel@tonic-gate if (nvl->nvl_nvflag & NV_UNIQUE_NAME)
12487c478bd9Sstevel@tonic-gate (void) nvlist_remove_all(nvl, name);
12497c478bd9Sstevel@tonic-gate else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE)
12507c478bd9Sstevel@tonic-gate (void) nvlist_remove(nvl, name, type);
12517c478bd9Sstevel@tonic-gate
12522ec7644aSSerapheim Dimitropoulos err = nvt_add_nvpair(nvl, nvp);
12532ec7644aSSerapheim Dimitropoulos if (err != 0) {
12542ec7644aSSerapheim Dimitropoulos nvpair_free(nvp);
12552ec7644aSSerapheim Dimitropoulos nvp_buf_free(nvl, nvp);
12562ec7644aSSerapheim Dimitropoulos return (err);
12572ec7644aSSerapheim Dimitropoulos }
12587c478bd9Sstevel@tonic-gate nvp_buf_link(nvl, nvp);
12597c478bd9Sstevel@tonic-gate
12607c478bd9Sstevel@tonic-gate return (0);
12617c478bd9Sstevel@tonic-gate }
12627c478bd9Sstevel@tonic-gate
12637c478bd9Sstevel@tonic-gate int
nvlist_add_boolean(nvlist_t * nvl,const char * name)12647c478bd9Sstevel@tonic-gate nvlist_add_boolean(nvlist_t *nvl, const char *name)
12657c478bd9Sstevel@tonic-gate {
12667c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL));
12677c478bd9Sstevel@tonic-gate }
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate int
nvlist_add_boolean_value(nvlist_t * nvl,const char * name,boolean_t val)12707c478bd9Sstevel@tonic-gate nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
12717c478bd9Sstevel@tonic-gate {
12727c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val));
12737c478bd9Sstevel@tonic-gate }
12747c478bd9Sstevel@tonic-gate
12757c478bd9Sstevel@tonic-gate int
nvlist_add_byte(nvlist_t * nvl,const char * name,uchar_t val)12767c478bd9Sstevel@tonic-gate nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
12777c478bd9Sstevel@tonic-gate {
12787c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val));
12797c478bd9Sstevel@tonic-gate }
12807c478bd9Sstevel@tonic-gate
12817c478bd9Sstevel@tonic-gate int
nvlist_add_int8(nvlist_t * nvl,const char * name,int8_t val)12827c478bd9Sstevel@tonic-gate nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
12837c478bd9Sstevel@tonic-gate {
12847c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val));
12857c478bd9Sstevel@tonic-gate }
12867c478bd9Sstevel@tonic-gate
12877c478bd9Sstevel@tonic-gate int
nvlist_add_uint8(nvlist_t * nvl,const char * name,uint8_t val)12887c478bd9Sstevel@tonic-gate nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
12897c478bd9Sstevel@tonic-gate {
12907c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val));
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate
12937c478bd9Sstevel@tonic-gate int
nvlist_add_int16(nvlist_t * nvl,const char * name,int16_t val)12947c478bd9Sstevel@tonic-gate nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
12957c478bd9Sstevel@tonic-gate {
12967c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val));
12977c478bd9Sstevel@tonic-gate }
12987c478bd9Sstevel@tonic-gate
12997c478bd9Sstevel@tonic-gate int
nvlist_add_uint16(nvlist_t * nvl,const char * name,uint16_t val)13007c478bd9Sstevel@tonic-gate nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
13017c478bd9Sstevel@tonic-gate {
13027c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val));
13037c478bd9Sstevel@tonic-gate }
13047c478bd9Sstevel@tonic-gate
13057c478bd9Sstevel@tonic-gate int
nvlist_add_int32(nvlist_t * nvl,const char * name,int32_t val)13067c478bd9Sstevel@tonic-gate nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
13077c478bd9Sstevel@tonic-gate {
13087c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val));
13097c478bd9Sstevel@tonic-gate }
13107c478bd9Sstevel@tonic-gate
13117c478bd9Sstevel@tonic-gate int
nvlist_add_uint32(nvlist_t * nvl,const char * name,uint32_t val)13127c478bd9Sstevel@tonic-gate nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
13137c478bd9Sstevel@tonic-gate {
13147c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val));
13157c478bd9Sstevel@tonic-gate }
13167c478bd9Sstevel@tonic-gate
13177c478bd9Sstevel@tonic-gate int
nvlist_add_int64(nvlist_t * nvl,const char * name,int64_t val)13187c478bd9Sstevel@tonic-gate nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
13197c478bd9Sstevel@tonic-gate {
13207c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val));
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate
13237c478bd9Sstevel@tonic-gate int
nvlist_add_uint64(nvlist_t * nvl,const char * name,uint64_t val)13247c478bd9Sstevel@tonic-gate nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
13257c478bd9Sstevel@tonic-gate {
13267c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val));
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate
1329825ba0f2Srobj #if !defined(_KERNEL)
1330825ba0f2Srobj int
nvlist_add_double(nvlist_t * nvl,const char * name,double val)1331825ba0f2Srobj nvlist_add_double(nvlist_t *nvl, const char *name, double val)
1332825ba0f2Srobj {
1333825ba0f2Srobj return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val));
1334825ba0f2Srobj }
1335825ba0f2Srobj #endif
1336825ba0f2Srobj
13377c478bd9Sstevel@tonic-gate int
nvlist_add_string(nvlist_t * nvl,const char * name,const char * val)13387c478bd9Sstevel@tonic-gate nvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
13397c478bd9Sstevel@tonic-gate {
13407c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val));
13417c478bd9Sstevel@tonic-gate }
13427c478bd9Sstevel@tonic-gate
13437c478bd9Sstevel@tonic-gate int
nvlist_add_boolean_array(nvlist_t * nvl,const char * name,boolean_t * a,uint_t n)13447c478bd9Sstevel@tonic-gate nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
13457c478bd9Sstevel@tonic-gate boolean_t *a, uint_t n)
13467c478bd9Sstevel@tonic-gate {
13477c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
13487c478bd9Sstevel@tonic-gate }
13497c478bd9Sstevel@tonic-gate
13507c478bd9Sstevel@tonic-gate int
nvlist_add_byte_array(nvlist_t * nvl,const char * name,uchar_t * a,uint_t n)13517c478bd9Sstevel@tonic-gate nvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *a, uint_t n)
13527c478bd9Sstevel@tonic-gate {
13537c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate
13567c478bd9Sstevel@tonic-gate int
nvlist_add_int8_array(nvlist_t * nvl,const char * name,int8_t * a,uint_t n)13577c478bd9Sstevel@tonic-gate nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint_t n)
13587c478bd9Sstevel@tonic-gate {
13597c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate
13627c478bd9Sstevel@tonic-gate int
nvlist_add_uint8_array(nvlist_t * nvl,const char * name,uint8_t * a,uint_t n)13637c478bd9Sstevel@tonic-gate nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint_t n)
13647c478bd9Sstevel@tonic-gate {
13657c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
13667c478bd9Sstevel@tonic-gate }
13677c478bd9Sstevel@tonic-gate
13687c478bd9Sstevel@tonic-gate int
nvlist_add_int16_array(nvlist_t * nvl,const char * name,int16_t * a,uint_t n)13697c478bd9Sstevel@tonic-gate nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint_t n)
13707c478bd9Sstevel@tonic-gate {
13717c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
13727c478bd9Sstevel@tonic-gate }
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate int
nvlist_add_uint16_array(nvlist_t * nvl,const char * name,uint16_t * a,uint_t n)13757c478bd9Sstevel@tonic-gate nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, uint_t n)
13767c478bd9Sstevel@tonic-gate {
13777c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate
13807c478bd9Sstevel@tonic-gate int
nvlist_add_int32_array(nvlist_t * nvl,const char * name,int32_t * a,uint_t n)13817c478bd9Sstevel@tonic-gate nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint_t n)
13827c478bd9Sstevel@tonic-gate {
13837c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
13847c478bd9Sstevel@tonic-gate }
13857c478bd9Sstevel@tonic-gate
13867c478bd9Sstevel@tonic-gate int
nvlist_add_uint32_array(nvlist_t * nvl,const char * name,uint32_t * a,uint_t n)13877c478bd9Sstevel@tonic-gate nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, uint_t n)
13887c478bd9Sstevel@tonic-gate {
13897c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
13907c478bd9Sstevel@tonic-gate }
13917c478bd9Sstevel@tonic-gate
13927c478bd9Sstevel@tonic-gate int
nvlist_add_int64_array(nvlist_t * nvl,const char * name,int64_t * a,uint_t n)13937c478bd9Sstevel@tonic-gate nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint_t n)
13947c478bd9Sstevel@tonic-gate {
13957c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate
13987c478bd9Sstevel@tonic-gate int
nvlist_add_uint64_array(nvlist_t * nvl,const char * name,uint64_t * a,uint_t n)13997c478bd9Sstevel@tonic-gate nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, uint_t n)
14007c478bd9Sstevel@tonic-gate {
14017c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
14027c478bd9Sstevel@tonic-gate }
14037c478bd9Sstevel@tonic-gate
14047c478bd9Sstevel@tonic-gate int
nvlist_add_string_array(nvlist_t * nvl,const char * name,char * const * a,uint_t n)14057c478bd9Sstevel@tonic-gate nvlist_add_string_array(nvlist_t *nvl, const char *name,
14067c478bd9Sstevel@tonic-gate char *const *a, uint_t n)
14077c478bd9Sstevel@tonic-gate {
14087c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
14097c478bd9Sstevel@tonic-gate }
14107c478bd9Sstevel@tonic-gate
14117c478bd9Sstevel@tonic-gate int
nvlist_add_hrtime(nvlist_t * nvl,const char * name,hrtime_t val)14127c478bd9Sstevel@tonic-gate nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val)
14137c478bd9Sstevel@tonic-gate {
14147c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val));
14157c478bd9Sstevel@tonic-gate }
14167c478bd9Sstevel@tonic-gate
14177c478bd9Sstevel@tonic-gate int
nvlist_add_nvlist(nvlist_t * nvl,const char * name,nvlist_t * val)14187c478bd9Sstevel@tonic-gate nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
14197c478bd9Sstevel@tonic-gate {
14207c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
14217c478bd9Sstevel@tonic-gate }
14227c478bd9Sstevel@tonic-gate
14237c478bd9Sstevel@tonic-gate int
nvlist_add_nvlist_array(nvlist_t * nvl,const char * name,nvlist_t ** a,uint_t n)14247c478bd9Sstevel@tonic-gate nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, uint_t n)
14257c478bd9Sstevel@tonic-gate {
14267c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
14277c478bd9Sstevel@tonic-gate }
14287c478bd9Sstevel@tonic-gate
14297c478bd9Sstevel@tonic-gate /* reading name-value pairs */
14307c478bd9Sstevel@tonic-gate nvpair_t *
nvlist_next_nvpair(nvlist_t * nvl,nvpair_t * nvp)14317c478bd9Sstevel@tonic-gate nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp)
14327c478bd9Sstevel@tonic-gate {
14337c478bd9Sstevel@tonic-gate nvpriv_t *priv;
14347c478bd9Sstevel@tonic-gate i_nvp_t *curr;
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate if (nvl == NULL ||
14377c478bd9Sstevel@tonic-gate (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
14387c478bd9Sstevel@tonic-gate return (NULL);
14397c478bd9Sstevel@tonic-gate
14407c478bd9Sstevel@tonic-gate curr = NVPAIR2I_NVP(nvp);
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate /*
14433cb34c60Sahrens * Ensure that nvp is a valid nvpair on this nvlist.
14443cb34c60Sahrens * NB: nvp_curr is used only as a hint so that we don't always
14453cb34c60Sahrens * have to walk the list to determine if nvp is still on the list.
14467c478bd9Sstevel@tonic-gate */
14477c478bd9Sstevel@tonic-gate if (nvp == NULL)
14487c478bd9Sstevel@tonic-gate curr = priv->nvp_list;
14493cb34c60Sahrens else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
14507c478bd9Sstevel@tonic-gate curr = curr->nvi_next;
14513cb34c60Sahrens else
14527c478bd9Sstevel@tonic-gate curr = NULL;
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate priv->nvp_curr = curr;
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate return (curr != NULL ? &curr->nvi_nvp : NULL);
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate
145992241e0bSTom Erickson nvpair_t *
nvlist_prev_nvpair(nvlist_t * nvl,nvpair_t * nvp)146092241e0bSTom Erickson nvlist_prev_nvpair(nvlist_t *nvl, nvpair_t *nvp)
146192241e0bSTom Erickson {
146292241e0bSTom Erickson nvpriv_t *priv;
146392241e0bSTom Erickson i_nvp_t *curr;
146492241e0bSTom Erickson
146592241e0bSTom Erickson if (nvl == NULL ||
146692241e0bSTom Erickson (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
146792241e0bSTom Erickson return (NULL);
146892241e0bSTom Erickson
146992241e0bSTom Erickson curr = NVPAIR2I_NVP(nvp);
147092241e0bSTom Erickson
147192241e0bSTom Erickson if (nvp == NULL)
147292241e0bSTom Erickson curr = priv->nvp_last;
147392241e0bSTom Erickson else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
147492241e0bSTom Erickson curr = curr->nvi_prev;
147592241e0bSTom Erickson else
147692241e0bSTom Erickson curr = NULL;
147792241e0bSTom Erickson
147892241e0bSTom Erickson priv->nvp_curr = curr;
147992241e0bSTom Erickson
148092241e0bSTom Erickson return (curr != NULL ? &curr->nvi_nvp : NULL);
148192241e0bSTom Erickson }
148292241e0bSTom Erickson
148392241e0bSTom Erickson boolean_t
nvlist_empty(nvlist_t * nvl)148492241e0bSTom Erickson nvlist_empty(nvlist_t *nvl)
148592241e0bSTom Erickson {
148692241e0bSTom Erickson nvpriv_t *priv;
148792241e0bSTom Erickson
148892241e0bSTom Erickson if (nvl == NULL ||
148992241e0bSTom Erickson (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
149092241e0bSTom Erickson return (B_TRUE);
149192241e0bSTom Erickson
149292241e0bSTom Erickson return (priv->nvp_list == NULL);
149392241e0bSTom Erickson }
149492241e0bSTom Erickson
14957c478bd9Sstevel@tonic-gate char *
nvpair_name(nvpair_t * nvp)14967c478bd9Sstevel@tonic-gate nvpair_name(nvpair_t *nvp)
14977c478bd9Sstevel@tonic-gate {
14987c478bd9Sstevel@tonic-gate return (NVP_NAME(nvp));
14997c478bd9Sstevel@tonic-gate }
15007c478bd9Sstevel@tonic-gate
15017c478bd9Sstevel@tonic-gate data_type_t
nvpair_type(nvpair_t * nvp)15027c478bd9Sstevel@tonic-gate nvpair_type(nvpair_t *nvp)
15037c478bd9Sstevel@tonic-gate {
15047c478bd9Sstevel@tonic-gate return (NVP_TYPE(nvp));
15057c478bd9Sstevel@tonic-gate }
15067c478bd9Sstevel@tonic-gate
1507602ca9eaScth int
nvpair_type_is_array(nvpair_t * nvp)1508602ca9eaScth nvpair_type_is_array(nvpair_t *nvp)
1509602ca9eaScth {
1510602ca9eaScth data_type_t type = NVP_TYPE(nvp);
1511602ca9eaScth
1512602ca9eaScth if ((type == DATA_TYPE_BYTE_ARRAY) ||
1513bf4d553bSAndriy Gapon (type == DATA_TYPE_INT8_ARRAY) ||
1514602ca9eaScth (type == DATA_TYPE_UINT8_ARRAY) ||
1515602ca9eaScth (type == DATA_TYPE_INT16_ARRAY) ||
1516602ca9eaScth (type == DATA_TYPE_UINT16_ARRAY) ||
1517602ca9eaScth (type == DATA_TYPE_INT32_ARRAY) ||
1518602ca9eaScth (type == DATA_TYPE_UINT32_ARRAY) ||
1519602ca9eaScth (type == DATA_TYPE_INT64_ARRAY) ||
1520602ca9eaScth (type == DATA_TYPE_UINT64_ARRAY) ||
1521602ca9eaScth (type == DATA_TYPE_BOOLEAN_ARRAY) ||
1522602ca9eaScth (type == DATA_TYPE_STRING_ARRAY) ||
1523602ca9eaScth (type == DATA_TYPE_NVLIST_ARRAY))
1524602ca9eaScth return (1);
1525602ca9eaScth return (0);
1526602ca9eaScth
1527602ca9eaScth }
1528602ca9eaScth
15297c478bd9Sstevel@tonic-gate static int
nvpair_value_common(nvpair_t * nvp,data_type_t type,uint_t * nelem,void * data)15307c478bd9Sstevel@tonic-gate nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data)
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate if (nvp == NULL || nvpair_type(nvp) != type)
15337c478bd9Sstevel@tonic-gate return (EINVAL);
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate /*
15367c478bd9Sstevel@tonic-gate * For non-array types, we copy the data.
15377c478bd9Sstevel@tonic-gate * For array types (including string), we set a pointer.
15387c478bd9Sstevel@tonic-gate */
15397c478bd9Sstevel@tonic-gate switch (type) {
15407c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
15417c478bd9Sstevel@tonic-gate if (nelem != NULL)
15427c478bd9Sstevel@tonic-gate *nelem = 0;
15437c478bd9Sstevel@tonic-gate break;
15447c478bd9Sstevel@tonic-gate
15457c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE:
15467c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE:
15477c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8:
15487c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8:
15497c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16:
15507c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16:
15517c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32:
15527c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32:
15537c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64:
15547c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64:
15557c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME:
1556825ba0f2Srobj #if !defined(_KERNEL)
1557825ba0f2Srobj case DATA_TYPE_DOUBLE:
1558825ba0f2Srobj #endif
15597c478bd9Sstevel@tonic-gate if (data == NULL)
15607c478bd9Sstevel@tonic-gate return (EINVAL);
15617c478bd9Sstevel@tonic-gate bcopy(NVP_VALUE(nvp), data,
15627c478bd9Sstevel@tonic-gate (size_t)i_get_value_size(type, NULL, 1));
15637c478bd9Sstevel@tonic-gate if (nelem != NULL)
15647c478bd9Sstevel@tonic-gate *nelem = 1;
15657c478bd9Sstevel@tonic-gate break;
15667c478bd9Sstevel@tonic-gate
15677c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST:
15687c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING:
15697c478bd9Sstevel@tonic-gate if (data == NULL)
15707c478bd9Sstevel@tonic-gate return (EINVAL);
15717c478bd9Sstevel@tonic-gate *(void **)data = (void *)NVP_VALUE(nvp);
15727c478bd9Sstevel@tonic-gate if (nelem != NULL)
15737c478bd9Sstevel@tonic-gate *nelem = 1;
15747c478bd9Sstevel@tonic-gate break;
15757c478bd9Sstevel@tonic-gate
15767c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY:
15777c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY:
15787c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY:
15797c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY:
15807c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY:
15817c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY:
15827c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY:
15837c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY:
15847c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY:
15857c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY:
15867c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY:
15877c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY:
15887c478bd9Sstevel@tonic-gate if (nelem == NULL || data == NULL)
15897c478bd9Sstevel@tonic-gate return (EINVAL);
15907c478bd9Sstevel@tonic-gate if ((*nelem = NVP_NELEM(nvp)) != 0)
15917c478bd9Sstevel@tonic-gate *(void **)data = (void *)NVP_VALUE(nvp);
15927c478bd9Sstevel@tonic-gate else
15937c478bd9Sstevel@tonic-gate *(void **)data = NULL;
15947c478bd9Sstevel@tonic-gate break;
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate default:
15977c478bd9Sstevel@tonic-gate return (ENOTSUP);
15987c478bd9Sstevel@tonic-gate }
15997c478bd9Sstevel@tonic-gate
16007c478bd9Sstevel@tonic-gate return (0);
16017c478bd9Sstevel@tonic-gate }
16027c478bd9Sstevel@tonic-gate
16037c478bd9Sstevel@tonic-gate static int
nvlist_lookup_common(nvlist_t * nvl,const char * name,data_type_t type,uint_t * nelem,void * data)16047c478bd9Sstevel@tonic-gate nvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type,
16057c478bd9Sstevel@tonic-gate uint_t *nelem, void *data)
16067c478bd9Sstevel@tonic-gate {
16072ec7644aSSerapheim Dimitropoulos if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
16087c478bd9Sstevel@tonic-gate return (EINVAL);
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE)))
16117c478bd9Sstevel@tonic-gate return (ENOTSUP);
16127c478bd9Sstevel@tonic-gate
16132ec7644aSSerapheim Dimitropoulos nvpair_t *nvp = nvt_lookup_name_type(nvl, name, type);
16142ec7644aSSerapheim Dimitropoulos if (nvp == NULL)
16157c478bd9Sstevel@tonic-gate return (ENOENT);
16162ec7644aSSerapheim Dimitropoulos
16172ec7644aSSerapheim Dimitropoulos return (nvpair_value_common(nvp, type, nelem, data));
16187c478bd9Sstevel@tonic-gate }
16197c478bd9Sstevel@tonic-gate
16207c478bd9Sstevel@tonic-gate int
nvlist_lookup_boolean(nvlist_t * nvl,const char * name)16217c478bd9Sstevel@tonic-gate nvlist_lookup_boolean(nvlist_t *nvl, const char *name)
16227c478bd9Sstevel@tonic-gate {
16237c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL));
16247c478bd9Sstevel@tonic-gate }
16257c478bd9Sstevel@tonic-gate
16267c478bd9Sstevel@tonic-gate int
nvlist_lookup_boolean_value(nvlist_t * nvl,const char * name,boolean_t * val)16277c478bd9Sstevel@tonic-gate nvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val)
16287c478bd9Sstevel@tonic-gate {
16297c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name,
16307c478bd9Sstevel@tonic-gate DATA_TYPE_BOOLEAN_VALUE, NULL, val));
16317c478bd9Sstevel@tonic-gate }
16327c478bd9Sstevel@tonic-gate
16337c478bd9Sstevel@tonic-gate int
nvlist_lookup_byte(nvlist_t * nvl,const char * name,uchar_t * val)16347c478bd9Sstevel@tonic-gate nvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val)
16357c478bd9Sstevel@tonic-gate {
16367c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val));
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate
16397c478bd9Sstevel@tonic-gate int
nvlist_lookup_int8(nvlist_t * nvl,const char * name,int8_t * val)16407c478bd9Sstevel@tonic-gate nvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val)
16417c478bd9Sstevel@tonic-gate {
16427c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val));
16437c478bd9Sstevel@tonic-gate }
16447c478bd9Sstevel@tonic-gate
16457c478bd9Sstevel@tonic-gate int
nvlist_lookup_uint8(nvlist_t * nvl,const char * name,uint8_t * val)16467c478bd9Sstevel@tonic-gate nvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val)
16477c478bd9Sstevel@tonic-gate {
16487c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val));
16497c478bd9Sstevel@tonic-gate }
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate int
nvlist_lookup_int16(nvlist_t * nvl,const char * name,int16_t * val)16527c478bd9Sstevel@tonic-gate nvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val)
16537c478bd9Sstevel@tonic-gate {
16547c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val));
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate
16577c478bd9Sstevel@tonic-gate int
nvlist_lookup_uint16(nvlist_t * nvl,const char * name,uint16_t * val)16587c478bd9Sstevel@tonic-gate nvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val)
16597c478bd9Sstevel@tonic-gate {
16607c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val));
16617c478bd9Sstevel@tonic-gate }
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate int
nvlist_lookup_int32(nvlist_t * nvl,const char * name,int32_t * val)16647c478bd9Sstevel@tonic-gate nvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val)
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val));
16677c478bd9Sstevel@tonic-gate }
16687c478bd9Sstevel@tonic-gate
16697c478bd9Sstevel@tonic-gate int
nvlist_lookup_uint32(nvlist_t * nvl,const char * name,uint32_t * val)16707c478bd9Sstevel@tonic-gate nvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val)
16717c478bd9Sstevel@tonic-gate {
16727c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val));
16737c478bd9Sstevel@tonic-gate }
16747c478bd9Sstevel@tonic-gate
16757c478bd9Sstevel@tonic-gate int
nvlist_lookup_int64(nvlist_t * nvl,const char * name,int64_t * val)16767c478bd9Sstevel@tonic-gate nvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val)
16777c478bd9Sstevel@tonic-gate {
16787c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val));
16797c478bd9Sstevel@tonic-gate }
16807c478bd9Sstevel@tonic-gate
16817c478bd9Sstevel@tonic-gate int
nvlist_lookup_uint64(nvlist_t * nvl,const char * name,uint64_t * val)16827c478bd9Sstevel@tonic-gate nvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val)
16837c478bd9Sstevel@tonic-gate {
16847c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val));
16857c478bd9Sstevel@tonic-gate }
16867c478bd9Sstevel@tonic-gate
1687825ba0f2Srobj #if !defined(_KERNEL)
1688825ba0f2Srobj int
nvlist_lookup_double(nvlist_t * nvl,const char * name,double * val)1689825ba0f2Srobj nvlist_lookup_double(nvlist_t *nvl, const char *name, double *val)
1690825ba0f2Srobj {
1691825ba0f2Srobj return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val));
1692825ba0f2Srobj }
1693825ba0f2Srobj #endif
1694825ba0f2Srobj
16957c478bd9Sstevel@tonic-gate int
nvlist_lookup_string(nvlist_t * nvl,const char * name,char ** val)16967c478bd9Sstevel@tonic-gate nvlist_lookup_string(nvlist_t *nvl, const char *name, char **val)
16977c478bd9Sstevel@tonic-gate {
16987c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val));
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate
17017c478bd9Sstevel@tonic-gate int
nvlist_lookup_nvlist(nvlist_t * nvl,const char * name,nvlist_t ** val)17027c478bd9Sstevel@tonic-gate nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val));
17057c478bd9Sstevel@tonic-gate }
17067c478bd9Sstevel@tonic-gate
17077c478bd9Sstevel@tonic-gate int
nvlist_lookup_boolean_array(nvlist_t * nvl,const char * name,boolean_t ** a,uint_t * n)17087c478bd9Sstevel@tonic-gate nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name,
17097c478bd9Sstevel@tonic-gate boolean_t **a, uint_t *n)
17107c478bd9Sstevel@tonic-gate {
17117c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name,
17127c478bd9Sstevel@tonic-gate DATA_TYPE_BOOLEAN_ARRAY, n, a));
17137c478bd9Sstevel@tonic-gate }
17147c478bd9Sstevel@tonic-gate
17157c478bd9Sstevel@tonic-gate int
nvlist_lookup_byte_array(nvlist_t * nvl,const char * name,uchar_t ** a,uint_t * n)17167c478bd9Sstevel@tonic-gate nvlist_lookup_byte_array(nvlist_t *nvl, const char *name,
17177c478bd9Sstevel@tonic-gate uchar_t **a, uint_t *n)
17187c478bd9Sstevel@tonic-gate {
17197c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
17207c478bd9Sstevel@tonic-gate }
17217c478bd9Sstevel@tonic-gate
17227c478bd9Sstevel@tonic-gate int
nvlist_lookup_int8_array(nvlist_t * nvl,const char * name,int8_t ** a,uint_t * n)17237c478bd9Sstevel@tonic-gate nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n)
17247c478bd9Sstevel@tonic-gate {
17257c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate
17287c478bd9Sstevel@tonic-gate int
nvlist_lookup_uint8_array(nvlist_t * nvl,const char * name,uint8_t ** a,uint_t * n)17297c478bd9Sstevel@tonic-gate nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name,
17307c478bd9Sstevel@tonic-gate uint8_t **a, uint_t *n)
17317c478bd9Sstevel@tonic-gate {
17327c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
17337c478bd9Sstevel@tonic-gate }
17347c478bd9Sstevel@tonic-gate
17357c478bd9Sstevel@tonic-gate int
nvlist_lookup_int16_array(nvlist_t * nvl,const char * name,int16_t ** a,uint_t * n)17367c478bd9Sstevel@tonic-gate nvlist_lookup_int16_array(nvlist_t *nvl, const char *name,
17377c478bd9Sstevel@tonic-gate int16_t **a, uint_t *n)
17387c478bd9Sstevel@tonic-gate {
17397c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
17407c478bd9Sstevel@tonic-gate }
17417c478bd9Sstevel@tonic-gate
17427c478bd9Sstevel@tonic-gate int
nvlist_lookup_uint16_array(nvlist_t * nvl,const char * name,uint16_t ** a,uint_t * n)17437c478bd9Sstevel@tonic-gate nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name,
17447c478bd9Sstevel@tonic-gate uint16_t **a, uint_t *n)
17457c478bd9Sstevel@tonic-gate {
17467c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
17477c478bd9Sstevel@tonic-gate }
17487c478bd9Sstevel@tonic-gate
17497c478bd9Sstevel@tonic-gate int
nvlist_lookup_int32_array(nvlist_t * nvl,const char * name,int32_t ** a,uint_t * n)17507c478bd9Sstevel@tonic-gate nvlist_lookup_int32_array(nvlist_t *nvl, const char *name,
17517c478bd9Sstevel@tonic-gate int32_t **a, uint_t *n)
17527c478bd9Sstevel@tonic-gate {
17537c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
17547c478bd9Sstevel@tonic-gate }
17557c478bd9Sstevel@tonic-gate
17567c478bd9Sstevel@tonic-gate int
nvlist_lookup_uint32_array(nvlist_t * nvl,const char * name,uint32_t ** a,uint_t * n)17577c478bd9Sstevel@tonic-gate nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name,
17587c478bd9Sstevel@tonic-gate uint32_t **a, uint_t *n)
17597c478bd9Sstevel@tonic-gate {
17607c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
17617c478bd9Sstevel@tonic-gate }
17627c478bd9Sstevel@tonic-gate
17637c478bd9Sstevel@tonic-gate int
nvlist_lookup_int64_array(nvlist_t * nvl,const char * name,int64_t ** a,uint_t * n)17647c478bd9Sstevel@tonic-gate nvlist_lookup_int64_array(nvlist_t *nvl, const char *name,
17657c478bd9Sstevel@tonic-gate int64_t **a, uint_t *n)
17667c478bd9Sstevel@tonic-gate {
17677c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
17687c478bd9Sstevel@tonic-gate }
17697c478bd9Sstevel@tonic-gate
17707c478bd9Sstevel@tonic-gate int
nvlist_lookup_uint64_array(nvlist_t * nvl,const char * name,uint64_t ** a,uint_t * n)17717c478bd9Sstevel@tonic-gate nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name,
17727c478bd9Sstevel@tonic-gate uint64_t **a, uint_t *n)
17737c478bd9Sstevel@tonic-gate {
17747c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
17757c478bd9Sstevel@tonic-gate }
17767c478bd9Sstevel@tonic-gate
17777c478bd9Sstevel@tonic-gate int
nvlist_lookup_string_array(nvlist_t * nvl,const char * name,char *** a,uint_t * n)17787c478bd9Sstevel@tonic-gate nvlist_lookup_string_array(nvlist_t *nvl, const char *name,
17797c478bd9Sstevel@tonic-gate char ***a, uint_t *n)
17807c478bd9Sstevel@tonic-gate {
17817c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
17827c478bd9Sstevel@tonic-gate }
17837c478bd9Sstevel@tonic-gate
17847c478bd9Sstevel@tonic-gate int
nvlist_lookup_nvlist_array(nvlist_t * nvl,const char * name,nvlist_t *** a,uint_t * n)17857c478bd9Sstevel@tonic-gate nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name,
17867c478bd9Sstevel@tonic-gate nvlist_t ***a, uint_t *n)
17877c478bd9Sstevel@tonic-gate {
17887c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
17897c478bd9Sstevel@tonic-gate }
17907c478bd9Sstevel@tonic-gate
17917c478bd9Sstevel@tonic-gate int
nvlist_lookup_hrtime(nvlist_t * nvl,const char * name,hrtime_t * val)17927c478bd9Sstevel@tonic-gate nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val)
17937c478bd9Sstevel@tonic-gate {
17947c478bd9Sstevel@tonic-gate return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val));
17957c478bd9Sstevel@tonic-gate }
17967c478bd9Sstevel@tonic-gate
17977c478bd9Sstevel@tonic-gate int
nvlist_lookup_pairs(nvlist_t * nvl,int flag,...)17987c478bd9Sstevel@tonic-gate nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...)
17997c478bd9Sstevel@tonic-gate {
18007c478bd9Sstevel@tonic-gate va_list ap;
18017c478bd9Sstevel@tonic-gate char *name;
18027c478bd9Sstevel@tonic-gate int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0);
18037c478bd9Sstevel@tonic-gate int ret = 0;
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate va_start(ap, flag);
18067c478bd9Sstevel@tonic-gate while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
18077c478bd9Sstevel@tonic-gate data_type_t type;
18087c478bd9Sstevel@tonic-gate void *val;
18097c478bd9Sstevel@tonic-gate uint_t *nelem;
18107c478bd9Sstevel@tonic-gate
18117c478bd9Sstevel@tonic-gate switch (type = va_arg(ap, data_type_t)) {
18127c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
18137c478bd9Sstevel@tonic-gate ret = nvlist_lookup_common(nvl, name, type, NULL, NULL);
18147c478bd9Sstevel@tonic-gate break;
18157c478bd9Sstevel@tonic-gate
18167c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE:
18177c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE:
18187c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8:
18197c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8:
18207c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16:
18217c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16:
18227c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32:
18237c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32:
18247c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64:
18257c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64:
18267c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME:
18277c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING:
18287c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST:
1829825ba0f2Srobj #if !defined(_KERNEL)
1830825ba0f2Srobj case DATA_TYPE_DOUBLE:
1831825ba0f2Srobj #endif
18327c478bd9Sstevel@tonic-gate val = va_arg(ap, void *);
18337c478bd9Sstevel@tonic-gate ret = nvlist_lookup_common(nvl, name, type, NULL, val);
18347c478bd9Sstevel@tonic-gate break;
18357c478bd9Sstevel@tonic-gate
18367c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY:
18377c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY:
18387c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY:
18397c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY:
18407c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY:
18417c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY:
18427c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY:
18437c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY:
18447c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY:
18457c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY:
18467c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY:
18477c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY:
18487c478bd9Sstevel@tonic-gate val = va_arg(ap, void *);
18497c478bd9Sstevel@tonic-gate nelem = va_arg(ap, uint_t *);
18507c478bd9Sstevel@tonic-gate ret = nvlist_lookup_common(nvl, name, type, nelem, val);
18517c478bd9Sstevel@tonic-gate break;
18527c478bd9Sstevel@tonic-gate
18537c478bd9Sstevel@tonic-gate default:
18547c478bd9Sstevel@tonic-gate ret = EINVAL;
18557c478bd9Sstevel@tonic-gate }
18567c478bd9Sstevel@tonic-gate
18577c478bd9Sstevel@tonic-gate if (ret == ENOENT && noentok)
18587c478bd9Sstevel@tonic-gate ret = 0;
18597c478bd9Sstevel@tonic-gate }
18607c478bd9Sstevel@tonic-gate va_end(ap);
18617c478bd9Sstevel@tonic-gate
18627c478bd9Sstevel@tonic-gate return (ret);
18637c478bd9Sstevel@tonic-gate }
18647c478bd9Sstevel@tonic-gate
1865602ca9eaScth /*
1866602ca9eaScth * Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function
1867602ca9eaScth * returns zero and a pointer to the matching nvpair is returned in '*ret'
1868602ca9eaScth * (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate
1869602ca9eaScth * multiple levels of embedded nvlists, with 'sep' as the separator. As an
1870602ca9eaScth * example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or
1871602ca9eaScth * "a.d[3].e[1]". This matches the C syntax for array embed (for convience,
1872602ca9eaScth * code also supports "a.d[3]e[1]" syntax).
1873602ca9eaScth *
1874602ca9eaScth * If 'ip' is non-NULL and the last name component is an array, return the
1875602ca9eaScth * value of the "...[index]" array index in *ip. For an array reference that
1876602ca9eaScth * is not indexed, *ip will be returned as -1. If there is a syntax error in
1877602ca9eaScth * 'name', and 'ep' is non-NULL then *ep will be set to point to the location
1878602ca9eaScth * inside the 'name' string where the syntax error was detected.
1879602ca9eaScth */
1880602ca9eaScth static int
nvlist_lookup_nvpair_ei_sep(nvlist_t * nvl,const char * name,const char sep,nvpair_t ** ret,int * ip,char ** ep)1881602ca9eaScth nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep,
1882602ca9eaScth nvpair_t **ret, int *ip, char **ep)
18831af98250Seschrock {
18841af98250Seschrock nvpair_t *nvp;
1885602ca9eaScth const char *np;
1886602ca9eaScth char *sepp;
1887602ca9eaScth char *idxp, *idxep;
1888602ca9eaScth nvlist_t **nva;
1889602ca9eaScth long idx;
1890602ca9eaScth int n;
18911af98250Seschrock
1892602ca9eaScth if (ip)
1893602ca9eaScth *ip = -1; /* not indexed */
1894602ca9eaScth if (ep)
1895602ca9eaScth *ep = NULL;
1896602ca9eaScth
1897602ca9eaScth if ((nvl == NULL) || (name == NULL))
18981af98250Seschrock return (EINVAL);
18991af98250Seschrock
1900759e89beSSteve Dougherty sepp = NULL;
1901759e89beSSteve Dougherty idx = 0;
1902602ca9eaScth /* step through components of name */
1903602ca9eaScth for (np = name; np && *np; np = sepp) {
1904602ca9eaScth /* ensure unique names */
19051af98250Seschrock if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
19061af98250Seschrock return (ENOTSUP);
19071af98250Seschrock
1908602ca9eaScth /* skip white space */
1909602ca9eaScth skip_whitespace(np);
1910602ca9eaScth if (*np == 0)
1911602ca9eaScth break;
19121af98250Seschrock
1913602ca9eaScth /* set 'sepp' to end of current component 'np' */
1914602ca9eaScth if (sep)
1915602ca9eaScth sepp = strchr(np, sep);
1916602ca9eaScth else
1917602ca9eaScth sepp = NULL;
1918602ca9eaScth
1919602ca9eaScth /* find start of next "[ index ]..." */
1920602ca9eaScth idxp = strchr(np, '[');
1921602ca9eaScth
1922602ca9eaScth /* if sepp comes first, set idxp to NULL */
1923602ca9eaScth if (sepp && idxp && (sepp < idxp))
1924602ca9eaScth idxp = NULL;
1925602ca9eaScth
1926602ca9eaScth /*
1927602ca9eaScth * At this point 'idxp' is set if there is an index
1928602ca9eaScth * expected for the current component.
1929602ca9eaScth */
1930602ca9eaScth if (idxp) {
1931602ca9eaScth /* set 'n' to length of current 'np' name component */
1932602ca9eaScth n = idxp++ - np;
1933602ca9eaScth
1934602ca9eaScth /* keep sepp up to date for *ep use as we advance */
1935602ca9eaScth skip_whitespace(idxp);
1936602ca9eaScth sepp = idxp;
1937602ca9eaScth
1938602ca9eaScth /* determine the index value */
1939602ca9eaScth #if defined(_KERNEL) && !defined(_BOOT)
1940602ca9eaScth if (ddi_strtol(idxp, &idxep, 0, &idx))
1941602ca9eaScth goto fail;
1942602ca9eaScth #else
1943602ca9eaScth idx = strtol(idxp, &idxep, 0);
1944602ca9eaScth #endif
1945602ca9eaScth if (idxep == idxp)
1946602ca9eaScth goto fail;
1947602ca9eaScth
1948602ca9eaScth /* keep sepp up to date for *ep use as we advance */
1949602ca9eaScth sepp = idxep;
1950602ca9eaScth
1951602ca9eaScth /* skip white space index value and check for ']' */
1952602ca9eaScth skip_whitespace(sepp);
1953602ca9eaScth if (*sepp++ != ']')
1954602ca9eaScth goto fail;
1955602ca9eaScth
1956602ca9eaScth /* for embedded arrays, support C syntax: "a[1].b" */
1957602ca9eaScth skip_whitespace(sepp);
1958602ca9eaScth if (sep && (*sepp == sep))
1959602ca9eaScth sepp++;
1960602ca9eaScth } else if (sepp) {
1961602ca9eaScth n = sepp++ - np;
1962602ca9eaScth } else {
1963602ca9eaScth n = strlen(np);
1964602ca9eaScth }
1965602ca9eaScth
1966602ca9eaScth /* trim trailing whitespace by reducing length of 'np' */
1967602ca9eaScth if (n == 0)
1968602ca9eaScth goto fail;
1969602ca9eaScth for (n--; (np[n] == ' ') || (np[n] == '\t'); n--)
1970602ca9eaScth ;
1971602ca9eaScth n++;
1972602ca9eaScth
1973602ca9eaScth /* skip whitespace, and set sepp to NULL if complete */
1974602ca9eaScth if (sepp) {
1975602ca9eaScth skip_whitespace(sepp);
1976602ca9eaScth if (*sepp == 0)
1977602ca9eaScth sepp = NULL;
1978602ca9eaScth }
1979602ca9eaScth
1980602ca9eaScth /*
1981602ca9eaScth * At this point:
1982602ca9eaScth * o 'n' is the length of current 'np' component.
1983602ca9eaScth * o 'idxp' is set if there was an index, and value 'idx'.
1984602ca9eaScth * o 'sepp' is set to the beginning of the next component,
1985602ca9eaScth * and set to NULL if we have no more components.
1986602ca9eaScth *
1987602ca9eaScth * Search for nvpair with matching component name.
1988602ca9eaScth */
1989602ca9eaScth for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
1990602ca9eaScth nvp = nvlist_next_nvpair(nvl, nvp)) {
1991602ca9eaScth
1992602ca9eaScth /* continue if no match on name */
1993602ca9eaScth if (strncmp(np, nvpair_name(nvp), n) ||
1994602ca9eaScth (strlen(nvpair_name(nvp)) != n))
1995602ca9eaScth continue;
1996602ca9eaScth
1997602ca9eaScth /* if indexed, verify type is array oriented */
1998602ca9eaScth if (idxp && !nvpair_type_is_array(nvp))
1999602ca9eaScth goto fail;
2000602ca9eaScth
2001602ca9eaScth /*
2002602ca9eaScth * Full match found, return nvp and idx if this
2003602ca9eaScth * was the last component.
2004602ca9eaScth */
2005602ca9eaScth if (sepp == NULL) {
2006602ca9eaScth if (ret)
20071af98250Seschrock *ret = nvp;
2008602ca9eaScth if (ip && idxp)
2009602ca9eaScth *ip = (int)idx; /* return index */
2010602ca9eaScth return (0); /* found */
20111af98250Seschrock }
20121af98250Seschrock
2013602ca9eaScth /*
2014602ca9eaScth * More components: current match must be
2015602ca9eaScth * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY
2016602ca9eaScth * to support going deeper.
2017602ca9eaScth */
2018602ca9eaScth if (nvpair_type(nvp) == DATA_TYPE_NVLIST) {
2019602ca9eaScth nvl = EMBEDDED_NVL(nvp);
2020602ca9eaScth break;
2021602ca9eaScth } else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {
2022602ca9eaScth (void) nvpair_value_nvlist_array(nvp,
2023602ca9eaScth &nva, (uint_t *)&n);
2024602ca9eaScth if ((n < 0) || (idx >= n))
2025602ca9eaScth goto fail;
2026602ca9eaScth nvl = nva[idx];
2027602ca9eaScth break;
2028602ca9eaScth }
2029602ca9eaScth
2030602ca9eaScth /* type does not support more levels */
2031602ca9eaScth goto fail;
2032602ca9eaScth }
2033602ca9eaScth if (nvp == NULL)
2034602ca9eaScth goto fail; /* 'name' not found */
2035602ca9eaScth
2036602ca9eaScth /* search for match of next component in embedded 'nvl' list */
2037602ca9eaScth }
2038602ca9eaScth
2039602ca9eaScth fail: if (ep && sepp)
2040602ca9eaScth *ep = sepp;
2041*eca3956cSToomas Soome return (ENOENT);
2042602ca9eaScth }
2043602ca9eaScth
2044602ca9eaScth /*
2045602ca9eaScth * Return pointer to nvpair with specified 'name'.
2046602ca9eaScth */
2047602ca9eaScth int
nvlist_lookup_nvpair(nvlist_t * nvl,const char * name,nvpair_t ** ret)2048602ca9eaScth nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
2049602ca9eaScth {
2050602ca9eaScth return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL));
2051602ca9eaScth }
2052602ca9eaScth
2053602ca9eaScth /*
2054602ca9eaScth * Determine if named nvpair exists in nvlist (use embedded separator of '.'
2055602ca9eaScth * and return array index). See nvlist_lookup_nvpair_ei_sep for more detailed
2056602ca9eaScth * description.
2057602ca9eaScth */
nvlist_lookup_nvpair_embedded_index(nvlist_t * nvl,const char * name,nvpair_t ** ret,int * ip,char ** ep)2058602ca9eaScth int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl,
2059602ca9eaScth const char *name, nvpair_t **ret, int *ip, char **ep)
2060602ca9eaScth {
2061602ca9eaScth return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep));
20621af98250Seschrock }
20631af98250Seschrock
20641af98250Seschrock boolean_t
nvlist_exists(nvlist_t * nvl,const char * name)20651af98250Seschrock nvlist_exists(nvlist_t *nvl, const char *name)
20661af98250Seschrock {
20671af98250Seschrock nvpriv_t *priv;
20681af98250Seschrock nvpair_t *nvp;
20691af98250Seschrock i_nvp_t *curr;
20701af98250Seschrock
20711af98250Seschrock if (name == NULL || nvl == NULL ||
20721af98250Seschrock (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
20731af98250Seschrock return (B_FALSE);
20741af98250Seschrock
20751af98250Seschrock for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
20761af98250Seschrock nvp = &curr->nvi_nvp;
20771af98250Seschrock
20781af98250Seschrock if (strcmp(name, NVP_NAME(nvp)) == 0)
20791af98250Seschrock return (B_TRUE);
20801af98250Seschrock }
20811af98250Seschrock
20821af98250Seschrock return (B_FALSE);
20831af98250Seschrock }
20841af98250Seschrock
20851af98250Seschrock int
nvpair_value_boolean_value(nvpair_t * nvp,boolean_t * val)20867c478bd9Sstevel@tonic-gate nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val)
20877c478bd9Sstevel@tonic-gate {
20887c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));
20897c478bd9Sstevel@tonic-gate }
20907c478bd9Sstevel@tonic-gate
20917c478bd9Sstevel@tonic-gate int
nvpair_value_byte(nvpair_t * nvp,uchar_t * val)20927c478bd9Sstevel@tonic-gate nvpair_value_byte(nvpair_t *nvp, uchar_t *val)
20937c478bd9Sstevel@tonic-gate {
20947c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val));
20957c478bd9Sstevel@tonic-gate }
20967c478bd9Sstevel@tonic-gate
20977c478bd9Sstevel@tonic-gate int
nvpair_value_int8(nvpair_t * nvp,int8_t * val)20987c478bd9Sstevel@tonic-gate nvpair_value_int8(nvpair_t *nvp, int8_t *val)
20997c478bd9Sstevel@tonic-gate {
21007c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val));
21017c478bd9Sstevel@tonic-gate }
21027c478bd9Sstevel@tonic-gate
21037c478bd9Sstevel@tonic-gate int
nvpair_value_uint8(nvpair_t * nvp,uint8_t * val)21047c478bd9Sstevel@tonic-gate nvpair_value_uint8(nvpair_t *nvp, uint8_t *val)
21057c478bd9Sstevel@tonic-gate {
21067c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val));
21077c478bd9Sstevel@tonic-gate }
21087c478bd9Sstevel@tonic-gate
21097c478bd9Sstevel@tonic-gate int
nvpair_value_int16(nvpair_t * nvp,int16_t * val)21107c478bd9Sstevel@tonic-gate nvpair_value_int16(nvpair_t *nvp, int16_t *val)
21117c478bd9Sstevel@tonic-gate {
21127c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val));
21137c478bd9Sstevel@tonic-gate }
21147c478bd9Sstevel@tonic-gate
21157c478bd9Sstevel@tonic-gate int
nvpair_value_uint16(nvpair_t * nvp,uint16_t * val)21167c478bd9Sstevel@tonic-gate nvpair_value_uint16(nvpair_t *nvp, uint16_t *val)
21177c478bd9Sstevel@tonic-gate {
21187c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val));
21197c478bd9Sstevel@tonic-gate }
21207c478bd9Sstevel@tonic-gate
21217c478bd9Sstevel@tonic-gate int
nvpair_value_int32(nvpair_t * nvp,int32_t * val)21227c478bd9Sstevel@tonic-gate nvpair_value_int32(nvpair_t *nvp, int32_t *val)
21237c478bd9Sstevel@tonic-gate {
21247c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val));
21257c478bd9Sstevel@tonic-gate }
21267c478bd9Sstevel@tonic-gate
21277c478bd9Sstevel@tonic-gate int
nvpair_value_uint32(nvpair_t * nvp,uint32_t * val)21287c478bd9Sstevel@tonic-gate nvpair_value_uint32(nvpair_t *nvp, uint32_t *val)
21297c478bd9Sstevel@tonic-gate {
21307c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val));
21317c478bd9Sstevel@tonic-gate }
21327c478bd9Sstevel@tonic-gate
21337c478bd9Sstevel@tonic-gate int
nvpair_value_int64(nvpair_t * nvp,int64_t * val)21347c478bd9Sstevel@tonic-gate nvpair_value_int64(nvpair_t *nvp, int64_t *val)
21357c478bd9Sstevel@tonic-gate {
21367c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val));
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate
21397c478bd9Sstevel@tonic-gate int
nvpair_value_uint64(nvpair_t * nvp,uint64_t * val)21407c478bd9Sstevel@tonic-gate nvpair_value_uint64(nvpair_t *nvp, uint64_t *val)
21417c478bd9Sstevel@tonic-gate {
21427c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val));
21437c478bd9Sstevel@tonic-gate }
21447c478bd9Sstevel@tonic-gate
2145825ba0f2Srobj #if !defined(_KERNEL)
2146825ba0f2Srobj int
nvpair_value_double(nvpair_t * nvp,double * val)2147825ba0f2Srobj nvpair_value_double(nvpair_t *nvp, double *val)
2148825ba0f2Srobj {
2149825ba0f2Srobj return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val));
2150825ba0f2Srobj }
2151825ba0f2Srobj #endif
2152825ba0f2Srobj
21537c478bd9Sstevel@tonic-gate int
nvpair_value_string(nvpair_t * nvp,char ** val)21547c478bd9Sstevel@tonic-gate nvpair_value_string(nvpair_t *nvp, char **val)
21557c478bd9Sstevel@tonic-gate {
21567c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val));
21577c478bd9Sstevel@tonic-gate }
21587c478bd9Sstevel@tonic-gate
21597c478bd9Sstevel@tonic-gate int
nvpair_value_nvlist(nvpair_t * nvp,nvlist_t ** val)21607c478bd9Sstevel@tonic-gate nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val)
21617c478bd9Sstevel@tonic-gate {
21627c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val));
21637c478bd9Sstevel@tonic-gate }
21647c478bd9Sstevel@tonic-gate
21657c478bd9Sstevel@tonic-gate int
nvpair_value_boolean_array(nvpair_t * nvp,boolean_t ** val,uint_t * nelem)21667c478bd9Sstevel@tonic-gate nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem)
21677c478bd9Sstevel@tonic-gate {
21687c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val));
21697c478bd9Sstevel@tonic-gate }
21707c478bd9Sstevel@tonic-gate
21717c478bd9Sstevel@tonic-gate int
nvpair_value_byte_array(nvpair_t * nvp,uchar_t ** val,uint_t * nelem)21727c478bd9Sstevel@tonic-gate nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem)
21737c478bd9Sstevel@tonic-gate {
21747c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val));
21757c478bd9Sstevel@tonic-gate }
21767c478bd9Sstevel@tonic-gate
21777c478bd9Sstevel@tonic-gate int
nvpair_value_int8_array(nvpair_t * nvp,int8_t ** val,uint_t * nelem)21787c478bd9Sstevel@tonic-gate nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem)
21797c478bd9Sstevel@tonic-gate {
21807c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val));
21817c478bd9Sstevel@tonic-gate }
21827c478bd9Sstevel@tonic-gate
21837c478bd9Sstevel@tonic-gate int
nvpair_value_uint8_array(nvpair_t * nvp,uint8_t ** val,uint_t * nelem)21847c478bd9Sstevel@tonic-gate nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem)
21857c478bd9Sstevel@tonic-gate {
21867c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val));
21877c478bd9Sstevel@tonic-gate }
21887c478bd9Sstevel@tonic-gate
21897c478bd9Sstevel@tonic-gate int
nvpair_value_int16_array(nvpair_t * nvp,int16_t ** val,uint_t * nelem)21907c478bd9Sstevel@tonic-gate nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem)
21917c478bd9Sstevel@tonic-gate {
21927c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val));
21937c478bd9Sstevel@tonic-gate }
21947c478bd9Sstevel@tonic-gate
21957c478bd9Sstevel@tonic-gate int
nvpair_value_uint16_array(nvpair_t * nvp,uint16_t ** val,uint_t * nelem)21967c478bd9Sstevel@tonic-gate nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem)
21977c478bd9Sstevel@tonic-gate {
21987c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val));
21997c478bd9Sstevel@tonic-gate }
22007c478bd9Sstevel@tonic-gate
22017c478bd9Sstevel@tonic-gate int
nvpair_value_int32_array(nvpair_t * nvp,int32_t ** val,uint_t * nelem)22027c478bd9Sstevel@tonic-gate nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem)
22037c478bd9Sstevel@tonic-gate {
22047c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val));
22057c478bd9Sstevel@tonic-gate }
22067c478bd9Sstevel@tonic-gate
22077c478bd9Sstevel@tonic-gate int
nvpair_value_uint32_array(nvpair_t * nvp,uint32_t ** val,uint_t * nelem)22087c478bd9Sstevel@tonic-gate nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem)
22097c478bd9Sstevel@tonic-gate {
22107c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val));
22117c478bd9Sstevel@tonic-gate }
22127c478bd9Sstevel@tonic-gate
22137c478bd9Sstevel@tonic-gate int
nvpair_value_int64_array(nvpair_t * nvp,int64_t ** val,uint_t * nelem)22147c478bd9Sstevel@tonic-gate nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem)
22157c478bd9Sstevel@tonic-gate {
22167c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val));
22177c478bd9Sstevel@tonic-gate }
22187c478bd9Sstevel@tonic-gate
22197c478bd9Sstevel@tonic-gate int
nvpair_value_uint64_array(nvpair_t * nvp,uint64_t ** val,uint_t * nelem)22207c478bd9Sstevel@tonic-gate nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem)
22217c478bd9Sstevel@tonic-gate {
22227c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val));
22237c478bd9Sstevel@tonic-gate }
22247c478bd9Sstevel@tonic-gate
22257c478bd9Sstevel@tonic-gate int
nvpair_value_string_array(nvpair_t * nvp,char *** val,uint_t * nelem)22267c478bd9Sstevel@tonic-gate nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem)
22277c478bd9Sstevel@tonic-gate {
22287c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val));
22297c478bd9Sstevel@tonic-gate }
22307c478bd9Sstevel@tonic-gate
22317c478bd9Sstevel@tonic-gate int
nvpair_value_nvlist_array(nvpair_t * nvp,nvlist_t *** val,uint_t * nelem)22327c478bd9Sstevel@tonic-gate nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem)
22337c478bd9Sstevel@tonic-gate {
22347c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val));
22357c478bd9Sstevel@tonic-gate }
22367c478bd9Sstevel@tonic-gate
22377c478bd9Sstevel@tonic-gate int
nvpair_value_hrtime(nvpair_t * nvp,hrtime_t * val)22387c478bd9Sstevel@tonic-gate nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val)
22397c478bd9Sstevel@tonic-gate {
22407c478bd9Sstevel@tonic-gate return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val));
22417c478bd9Sstevel@tonic-gate }
22427c478bd9Sstevel@tonic-gate
22437c478bd9Sstevel@tonic-gate /*
22447c478bd9Sstevel@tonic-gate * Add specified pair to the list.
22457c478bd9Sstevel@tonic-gate */
22467c478bd9Sstevel@tonic-gate int
nvlist_add_nvpair(nvlist_t * nvl,nvpair_t * nvp)22477c478bd9Sstevel@tonic-gate nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
22487c478bd9Sstevel@tonic-gate {
22497c478bd9Sstevel@tonic-gate if (nvl == NULL || nvp == NULL)
22507c478bd9Sstevel@tonic-gate return (EINVAL);
22517c478bd9Sstevel@tonic-gate
22527c478bd9Sstevel@tonic-gate return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp),
22537c478bd9Sstevel@tonic-gate NVP_NELEM(nvp), NVP_VALUE(nvp)));
22547c478bd9Sstevel@tonic-gate }
22557c478bd9Sstevel@tonic-gate
22567c478bd9Sstevel@tonic-gate /*
22577c478bd9Sstevel@tonic-gate * Merge the supplied nvlists and put the result in dst.
22587c478bd9Sstevel@tonic-gate * The merged list will contain all names specified in both lists,
22597c478bd9Sstevel@tonic-gate * the values are taken from nvl in the case of duplicates.
22607c478bd9Sstevel@tonic-gate * Return 0 on success.
22617c478bd9Sstevel@tonic-gate */
22627c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22637c478bd9Sstevel@tonic-gate int
nvlist_merge(nvlist_t * dst,nvlist_t * nvl,int flag)22647c478bd9Sstevel@tonic-gate nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)
22657c478bd9Sstevel@tonic-gate {
22667c478bd9Sstevel@tonic-gate if (nvl == NULL || dst == NULL)
22677c478bd9Sstevel@tonic-gate return (EINVAL);
22687c478bd9Sstevel@tonic-gate
22697c478bd9Sstevel@tonic-gate if (dst != nvl)
22707c478bd9Sstevel@tonic-gate return (nvlist_copy_pairs(nvl, dst));
22717c478bd9Sstevel@tonic-gate
22727c478bd9Sstevel@tonic-gate return (0);
22737c478bd9Sstevel@tonic-gate }
22747c478bd9Sstevel@tonic-gate
22757c478bd9Sstevel@tonic-gate /*
22767c478bd9Sstevel@tonic-gate * Encoding related routines
22777c478bd9Sstevel@tonic-gate */
22787c478bd9Sstevel@tonic-gate #define NVS_OP_ENCODE 0
22797c478bd9Sstevel@tonic-gate #define NVS_OP_DECODE 1
22807c478bd9Sstevel@tonic-gate #define NVS_OP_GETSIZE 2
22817c478bd9Sstevel@tonic-gate
22827c478bd9Sstevel@tonic-gate typedef struct nvs_ops nvs_ops_t;
22837c478bd9Sstevel@tonic-gate
22847c478bd9Sstevel@tonic-gate typedef struct {
22857c478bd9Sstevel@tonic-gate int nvs_op;
22867c478bd9Sstevel@tonic-gate const nvs_ops_t *nvs_ops;
22877c478bd9Sstevel@tonic-gate void *nvs_private;
22887c478bd9Sstevel@tonic-gate nvpriv_t *nvs_priv;
22899ca527c3SMatthew Ahrens int nvs_recursion;
22907c478bd9Sstevel@tonic-gate } nvstream_t;
22917c478bd9Sstevel@tonic-gate
22927c478bd9Sstevel@tonic-gate /*
22937c478bd9Sstevel@tonic-gate * nvs operations are:
22947c478bd9Sstevel@tonic-gate * - nvs_nvlist
22957c478bd9Sstevel@tonic-gate * encoding / decoding of a nvlist header (nvlist_t)
22967c478bd9Sstevel@tonic-gate * calculates the size used for header and end detection
22977c478bd9Sstevel@tonic-gate *
22987c478bd9Sstevel@tonic-gate * - nvs_nvpair
22997c478bd9Sstevel@tonic-gate * responsible for the first part of encoding / decoding of an nvpair
23007c478bd9Sstevel@tonic-gate * calculates the decoded size of an nvpair
23017c478bd9Sstevel@tonic-gate *
23027c478bd9Sstevel@tonic-gate * - nvs_nvp_op
23037c478bd9Sstevel@tonic-gate * second part of encoding / decoding of an nvpair
23047c478bd9Sstevel@tonic-gate *
23057c478bd9Sstevel@tonic-gate * - nvs_nvp_size
23067c478bd9Sstevel@tonic-gate * calculates the encoding size of an nvpair
23077c478bd9Sstevel@tonic-gate *
23087c478bd9Sstevel@tonic-gate * - nvs_nvl_fini
23097c478bd9Sstevel@tonic-gate * encodes the end detection mark (zeros).
23107c478bd9Sstevel@tonic-gate */
23117c478bd9Sstevel@tonic-gate struct nvs_ops {
23127c478bd9Sstevel@tonic-gate int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *);
23137c478bd9Sstevel@tonic-gate int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *);
23147c478bd9Sstevel@tonic-gate int (*nvs_nvp_op)(nvstream_t *, nvpair_t *);
23157c478bd9Sstevel@tonic-gate int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *);
23167c478bd9Sstevel@tonic-gate int (*nvs_nvl_fini)(nvstream_t *);
23177c478bd9Sstevel@tonic-gate };
23187c478bd9Sstevel@tonic-gate
23197c478bd9Sstevel@tonic-gate typedef struct {
23207c478bd9Sstevel@tonic-gate char nvh_encoding; /* nvs encoding method */
23217c478bd9Sstevel@tonic-gate char nvh_endian; /* nvs endian */
23227c478bd9Sstevel@tonic-gate char nvh_reserved1; /* reserved for future use */
23237c478bd9Sstevel@tonic-gate char nvh_reserved2; /* reserved for future use */
23247c478bd9Sstevel@tonic-gate } nvs_header_t;
23257c478bd9Sstevel@tonic-gate
23267c478bd9Sstevel@tonic-gate static int
nvs_encode_pairs(nvstream_t * nvs,nvlist_t * nvl)23277c478bd9Sstevel@tonic-gate nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl)
23287c478bd9Sstevel@tonic-gate {
23297c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
23307c478bd9Sstevel@tonic-gate i_nvp_t *curr;
23317c478bd9Sstevel@tonic-gate
23327c478bd9Sstevel@tonic-gate /*
23337c478bd9Sstevel@tonic-gate * Walk nvpair in list and encode each nvpair
23347c478bd9Sstevel@tonic-gate */
23357c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
23367c478bd9Sstevel@tonic-gate if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0)
23377c478bd9Sstevel@tonic-gate return (EFAULT);
23387c478bd9Sstevel@tonic-gate
23397c478bd9Sstevel@tonic-gate return (nvs->nvs_ops->nvs_nvl_fini(nvs));
23407c478bd9Sstevel@tonic-gate }
23417c478bd9Sstevel@tonic-gate
23427c478bd9Sstevel@tonic-gate static int
nvs_decode_pairs(nvstream_t * nvs,nvlist_t * nvl)23437c478bd9Sstevel@tonic-gate nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl)
23447c478bd9Sstevel@tonic-gate {
23457c478bd9Sstevel@tonic-gate nvpair_t *nvp;
23467c478bd9Sstevel@tonic-gate size_t nvsize;
23477c478bd9Sstevel@tonic-gate int err;
23487c478bd9Sstevel@tonic-gate
23497c478bd9Sstevel@tonic-gate /*
23507c478bd9Sstevel@tonic-gate * Get decoded size of next pair in stream, alloc
23517c478bd9Sstevel@tonic-gate * memory for nvpair_t, then decode the nvpair
23527c478bd9Sstevel@tonic-gate */
23537c478bd9Sstevel@tonic-gate while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) {
23547c478bd9Sstevel@tonic-gate if (nvsize == 0) /* end of list */
23557c478bd9Sstevel@tonic-gate break;
23567c478bd9Sstevel@tonic-gate
23577c478bd9Sstevel@tonic-gate /* make sure len makes sense */
23587c478bd9Sstevel@tonic-gate if (nvsize < NVP_SIZE_CALC(1, 0))
23597c478bd9Sstevel@tonic-gate return (EFAULT);
23607c478bd9Sstevel@tonic-gate
23617c478bd9Sstevel@tonic-gate if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL)
23627c478bd9Sstevel@tonic-gate return (ENOMEM);
23637c478bd9Sstevel@tonic-gate
23647c478bd9Sstevel@tonic-gate if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) {
23657c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp);
23667c478bd9Sstevel@tonic-gate return (err);
23677c478bd9Sstevel@tonic-gate }
23687c478bd9Sstevel@tonic-gate
23697c478bd9Sstevel@tonic-gate if (i_validate_nvpair(nvp) != 0) {
23707c478bd9Sstevel@tonic-gate nvpair_free(nvp);
23717c478bd9Sstevel@tonic-gate nvp_buf_free(nvl, nvp);
23727c478bd9Sstevel@tonic-gate return (EFAULT);
23737c478bd9Sstevel@tonic-gate }
23747c478bd9Sstevel@tonic-gate
23752ec7644aSSerapheim Dimitropoulos err = nvt_add_nvpair(nvl, nvp);
23762ec7644aSSerapheim Dimitropoulos if (err != 0) {
23772ec7644aSSerapheim Dimitropoulos nvpair_free(nvp);
23782ec7644aSSerapheim Dimitropoulos nvp_buf_free(nvl, nvp);
23792ec7644aSSerapheim Dimitropoulos return (err);
23802ec7644aSSerapheim Dimitropoulos }
23817c478bd9Sstevel@tonic-gate nvp_buf_link(nvl, nvp);
23827c478bd9Sstevel@tonic-gate }
23837c478bd9Sstevel@tonic-gate return (err);
23847c478bd9Sstevel@tonic-gate }
23857c478bd9Sstevel@tonic-gate
23867c478bd9Sstevel@tonic-gate static int
nvs_getsize_pairs(nvstream_t * nvs,nvlist_t * nvl,size_t * buflen)23877c478bd9Sstevel@tonic-gate nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
23887c478bd9Sstevel@tonic-gate {
23897c478bd9Sstevel@tonic-gate nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
23907c478bd9Sstevel@tonic-gate i_nvp_t *curr;
23917c478bd9Sstevel@tonic-gate uint64_t nvsize = *buflen;
23927c478bd9Sstevel@tonic-gate size_t size;
23937c478bd9Sstevel@tonic-gate
23947c478bd9Sstevel@tonic-gate /*
23957c478bd9Sstevel@tonic-gate * Get encoded size of nvpairs in nvlist
23967c478bd9Sstevel@tonic-gate */
23977c478bd9Sstevel@tonic-gate for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
23987c478bd9Sstevel@tonic-gate if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0)
23997c478bd9Sstevel@tonic-gate return (EINVAL);
24007c478bd9Sstevel@tonic-gate
24017c478bd9Sstevel@tonic-gate if ((nvsize += size) > INT32_MAX)
24027c478bd9Sstevel@tonic-gate return (EINVAL);
24037c478bd9Sstevel@tonic-gate }
24047c478bd9Sstevel@tonic-gate
24057c478bd9Sstevel@tonic-gate *buflen = nvsize;
24067c478bd9Sstevel@tonic-gate return (0);
24077c478bd9Sstevel@tonic-gate }
24087c478bd9Sstevel@tonic-gate
24097c478bd9Sstevel@tonic-gate static int
nvs_operation(nvstream_t * nvs,nvlist_t * nvl,size_t * buflen)24107c478bd9Sstevel@tonic-gate nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
24117c478bd9Sstevel@tonic-gate {
24127c478bd9Sstevel@tonic-gate int err;
24137c478bd9Sstevel@tonic-gate
24145ad82045Snd150628 if (nvl->nvl_priv == 0)
24157c478bd9Sstevel@tonic-gate return (EFAULT);
24167c478bd9Sstevel@tonic-gate
24177c478bd9Sstevel@tonic-gate /*
24187c478bd9Sstevel@tonic-gate * Perform the operation, starting with header, then each nvpair
24197c478bd9Sstevel@tonic-gate */
24207c478bd9Sstevel@tonic-gate if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0)
24217c478bd9Sstevel@tonic-gate return (err);
24227c478bd9Sstevel@tonic-gate
24237c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
24247c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
24257c478bd9Sstevel@tonic-gate err = nvs_encode_pairs(nvs, nvl);
24267c478bd9Sstevel@tonic-gate break;
24277c478bd9Sstevel@tonic-gate
24287c478bd9Sstevel@tonic-gate case NVS_OP_DECODE:
24297c478bd9Sstevel@tonic-gate err = nvs_decode_pairs(nvs, nvl);
24307c478bd9Sstevel@tonic-gate break;
24317c478bd9Sstevel@tonic-gate
24327c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE:
24337c478bd9Sstevel@tonic-gate err = nvs_getsize_pairs(nvs, nvl, buflen);
24347c478bd9Sstevel@tonic-gate break;
24357c478bd9Sstevel@tonic-gate
24367c478bd9Sstevel@tonic-gate default:
24377c478bd9Sstevel@tonic-gate err = EINVAL;
24387c478bd9Sstevel@tonic-gate }
24397c478bd9Sstevel@tonic-gate
24407c478bd9Sstevel@tonic-gate return (err);
24417c478bd9Sstevel@tonic-gate }
24427c478bd9Sstevel@tonic-gate
24437c478bd9Sstevel@tonic-gate static int
nvs_embedded(nvstream_t * nvs,nvlist_t * embedded)24447c478bd9Sstevel@tonic-gate nvs_embedded(nvstream_t *nvs, nvlist_t *embedded)
24457c478bd9Sstevel@tonic-gate {
24467c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
24479ca527c3SMatthew Ahrens case NVS_OP_ENCODE: {
24489ca527c3SMatthew Ahrens int err;
24497c478bd9Sstevel@tonic-gate
24509ca527c3SMatthew Ahrens if (nvs->nvs_recursion >= nvpair_max_recursion)
24519ca527c3SMatthew Ahrens return (EINVAL);
24529ca527c3SMatthew Ahrens nvs->nvs_recursion++;
24539ca527c3SMatthew Ahrens err = nvs_operation(nvs, embedded, NULL);
24549ca527c3SMatthew Ahrens nvs->nvs_recursion--;
24559ca527c3SMatthew Ahrens return (err);
24569ca527c3SMatthew Ahrens }
24577c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: {
24587c478bd9Sstevel@tonic-gate nvpriv_t *priv;
24597c478bd9Sstevel@tonic-gate int err;
24607c478bd9Sstevel@tonic-gate
24617c478bd9Sstevel@tonic-gate if (embedded->nvl_version != NV_VERSION)
24627c478bd9Sstevel@tonic-gate return (ENOTSUP);
24637c478bd9Sstevel@tonic-gate
24647c478bd9Sstevel@tonic-gate if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL)
24657c478bd9Sstevel@tonic-gate return (ENOMEM);
24667c478bd9Sstevel@tonic-gate
24677c478bd9Sstevel@tonic-gate nvlist_init(embedded, embedded->nvl_nvflag, priv);
24687c478bd9Sstevel@tonic-gate
2469843c2111SMatthew Ahrens if (nvs->nvs_recursion >= nvpair_max_recursion) {
2470843c2111SMatthew Ahrens nvlist_free(embedded);
24719ca527c3SMatthew Ahrens return (EINVAL);
2472843c2111SMatthew Ahrens }
24739ca527c3SMatthew Ahrens nvs->nvs_recursion++;
24747c478bd9Sstevel@tonic-gate if ((err = nvs_operation(nvs, embedded, NULL)) != 0)
24757c478bd9Sstevel@tonic-gate nvlist_free(embedded);
24769ca527c3SMatthew Ahrens nvs->nvs_recursion--;
24777c478bd9Sstevel@tonic-gate return (err);
24787c478bd9Sstevel@tonic-gate }
24797c478bd9Sstevel@tonic-gate default:
24807c478bd9Sstevel@tonic-gate break;
24817c478bd9Sstevel@tonic-gate }
24827c478bd9Sstevel@tonic-gate
24837c478bd9Sstevel@tonic-gate return (EINVAL);
24847c478bd9Sstevel@tonic-gate }
24857c478bd9Sstevel@tonic-gate
24867c478bd9Sstevel@tonic-gate static int
nvs_embedded_nvl_array(nvstream_t * nvs,nvpair_t * nvp,size_t * size)24877c478bd9Sstevel@tonic-gate nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
24887c478bd9Sstevel@tonic-gate {
24897c478bd9Sstevel@tonic-gate size_t nelem = NVP_NELEM(nvp);
24907c478bd9Sstevel@tonic-gate nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
24917c478bd9Sstevel@tonic-gate int i;
24927c478bd9Sstevel@tonic-gate
24937c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
24947c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
24957c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++)
24967c478bd9Sstevel@tonic-gate if (nvs_embedded(nvs, nvlp[i]) != 0)
24977c478bd9Sstevel@tonic-gate return (EFAULT);
24987c478bd9Sstevel@tonic-gate break;
24997c478bd9Sstevel@tonic-gate
25007c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: {
25017c478bd9Sstevel@tonic-gate size_t len = nelem * sizeof (uint64_t);
25027c478bd9Sstevel@tonic-gate nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len);
25037c478bd9Sstevel@tonic-gate
25047c478bd9Sstevel@tonic-gate bzero(nvlp, len); /* don't trust packed data */
25057c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) {
25067c478bd9Sstevel@tonic-gate if (nvs_embedded(nvs, embedded) != 0) {
25077c478bd9Sstevel@tonic-gate nvpair_free(nvp);
25087c478bd9Sstevel@tonic-gate return (EFAULT);
25097c478bd9Sstevel@tonic-gate }
25107c478bd9Sstevel@tonic-gate
25117c478bd9Sstevel@tonic-gate nvlp[i] = embedded++;
25127c478bd9Sstevel@tonic-gate }
25137c478bd9Sstevel@tonic-gate break;
25147c478bd9Sstevel@tonic-gate }
25157c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: {
25167c478bd9Sstevel@tonic-gate uint64_t nvsize = 0;
25177c478bd9Sstevel@tonic-gate
25187c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) {
25197c478bd9Sstevel@tonic-gate size_t nvp_sz = 0;
25207c478bd9Sstevel@tonic-gate
25217c478bd9Sstevel@tonic-gate if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0)
25227c478bd9Sstevel@tonic-gate return (EINVAL);
25237c478bd9Sstevel@tonic-gate
25247c478bd9Sstevel@tonic-gate if ((nvsize += nvp_sz) > INT32_MAX)
25257c478bd9Sstevel@tonic-gate return (EINVAL);
25267c478bd9Sstevel@tonic-gate }
25277c478bd9Sstevel@tonic-gate
25287c478bd9Sstevel@tonic-gate *size = nvsize;
25297c478bd9Sstevel@tonic-gate break;
25307c478bd9Sstevel@tonic-gate }
25317c478bd9Sstevel@tonic-gate default:
25327c478bd9Sstevel@tonic-gate return (EINVAL);
25337c478bd9Sstevel@tonic-gate }
25347c478bd9Sstevel@tonic-gate
25357c478bd9Sstevel@tonic-gate return (0);
25367c478bd9Sstevel@tonic-gate }
25377c478bd9Sstevel@tonic-gate
25387c478bd9Sstevel@tonic-gate static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *);
25397c478bd9Sstevel@tonic-gate static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *);
25407c478bd9Sstevel@tonic-gate
25417c478bd9Sstevel@tonic-gate /*
25427c478bd9Sstevel@tonic-gate * Common routine for nvlist operations:
25437c478bd9Sstevel@tonic-gate * encode, decode, getsize (encoded size).
25447c478bd9Sstevel@tonic-gate */
25457c478bd9Sstevel@tonic-gate static int
nvlist_common(nvlist_t * nvl,char * buf,size_t * buflen,int encoding,int nvs_op)25467c478bd9Sstevel@tonic-gate nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
25477c478bd9Sstevel@tonic-gate int nvs_op)
25487c478bd9Sstevel@tonic-gate {
25497c478bd9Sstevel@tonic-gate int err = 0;
25507c478bd9Sstevel@tonic-gate nvstream_t nvs;
25517c478bd9Sstevel@tonic-gate int nvl_endian;
25527c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
25537c478bd9Sstevel@tonic-gate int host_endian = 1;
25547c478bd9Sstevel@tonic-gate #else
25557c478bd9Sstevel@tonic-gate int host_endian = 0;
25567c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
25577c478bd9Sstevel@tonic-gate nvs_header_t *nvh = (void *)buf;
25587c478bd9Sstevel@tonic-gate
25597c478bd9Sstevel@tonic-gate if (buflen == NULL || nvl == NULL ||
25607c478bd9Sstevel@tonic-gate (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
25617c478bd9Sstevel@tonic-gate return (EINVAL);
25627c478bd9Sstevel@tonic-gate
25637c478bd9Sstevel@tonic-gate nvs.nvs_op = nvs_op;
25649ca527c3SMatthew Ahrens nvs.nvs_recursion = 0;
25657c478bd9Sstevel@tonic-gate
25667c478bd9Sstevel@tonic-gate /*
25677c478bd9Sstevel@tonic-gate * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and
25687c478bd9Sstevel@tonic-gate * a buffer is allocated. The first 4 bytes in the buffer are
25697c478bd9Sstevel@tonic-gate * used for encoding method and host endian.
25707c478bd9Sstevel@tonic-gate */
25717c478bd9Sstevel@tonic-gate switch (nvs_op) {
25727c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
25737c478bd9Sstevel@tonic-gate if (buf == NULL || *buflen < sizeof (nvs_header_t))
25747c478bd9Sstevel@tonic-gate return (EINVAL);
25757c478bd9Sstevel@tonic-gate
25767c478bd9Sstevel@tonic-gate nvh->nvh_encoding = encoding;
25777c478bd9Sstevel@tonic-gate nvh->nvh_endian = nvl_endian = host_endian;
25787c478bd9Sstevel@tonic-gate nvh->nvh_reserved1 = 0;
25797c478bd9Sstevel@tonic-gate nvh->nvh_reserved2 = 0;
25807c478bd9Sstevel@tonic-gate break;
25817c478bd9Sstevel@tonic-gate
25827c478bd9Sstevel@tonic-gate case NVS_OP_DECODE:
25837c478bd9Sstevel@tonic-gate if (buf == NULL || *buflen < sizeof (nvs_header_t))
25847c478bd9Sstevel@tonic-gate return (EINVAL);
25857c478bd9Sstevel@tonic-gate
25867c478bd9Sstevel@tonic-gate /* get method of encoding from first byte */
25877c478bd9Sstevel@tonic-gate encoding = nvh->nvh_encoding;
25887c478bd9Sstevel@tonic-gate nvl_endian = nvh->nvh_endian;
25897c478bd9Sstevel@tonic-gate break;
25907c478bd9Sstevel@tonic-gate
25917c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE:
25927c478bd9Sstevel@tonic-gate nvl_endian = host_endian;
25937c478bd9Sstevel@tonic-gate
25947c478bd9Sstevel@tonic-gate /*
25957c478bd9Sstevel@tonic-gate * add the size for encoding
25967c478bd9Sstevel@tonic-gate */
25977c478bd9Sstevel@tonic-gate *buflen = sizeof (nvs_header_t);
25987c478bd9Sstevel@tonic-gate break;
25997c478bd9Sstevel@tonic-gate
26007c478bd9Sstevel@tonic-gate default:
26017c478bd9Sstevel@tonic-gate return (ENOTSUP);
26027c478bd9Sstevel@tonic-gate }
26037c478bd9Sstevel@tonic-gate
26047c478bd9Sstevel@tonic-gate /*
26057c478bd9Sstevel@tonic-gate * Create an nvstream with proper encoding method
26067c478bd9Sstevel@tonic-gate */
26077c478bd9Sstevel@tonic-gate switch (encoding) {
26087c478bd9Sstevel@tonic-gate case NV_ENCODE_NATIVE:
26097c478bd9Sstevel@tonic-gate /*
26107c478bd9Sstevel@tonic-gate * check endianness, in case we are unpacking
26117c478bd9Sstevel@tonic-gate * from a file
26127c478bd9Sstevel@tonic-gate */
26137c478bd9Sstevel@tonic-gate if (nvl_endian != host_endian)
26147c478bd9Sstevel@tonic-gate return (ENOTSUP);
26157c478bd9Sstevel@tonic-gate err = nvs_native(&nvs, nvl, buf, buflen);
26167c478bd9Sstevel@tonic-gate break;
26177c478bd9Sstevel@tonic-gate case NV_ENCODE_XDR:
26187c478bd9Sstevel@tonic-gate err = nvs_xdr(&nvs, nvl, buf, buflen);
26197c478bd9Sstevel@tonic-gate break;
26207c478bd9Sstevel@tonic-gate default:
26217c478bd9Sstevel@tonic-gate err = ENOTSUP;
26227c478bd9Sstevel@tonic-gate break;
26237c478bd9Sstevel@tonic-gate }
26247c478bd9Sstevel@tonic-gate
26257c478bd9Sstevel@tonic-gate return (err);
26267c478bd9Sstevel@tonic-gate }
26277c478bd9Sstevel@tonic-gate
26287c478bd9Sstevel@tonic-gate int
nvlist_size(nvlist_t * nvl,size_t * size,int encoding)26297c478bd9Sstevel@tonic-gate nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
26307c478bd9Sstevel@tonic-gate {
26317c478bd9Sstevel@tonic-gate return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
26327c478bd9Sstevel@tonic-gate }
26337c478bd9Sstevel@tonic-gate
26347c478bd9Sstevel@tonic-gate /*
26357c478bd9Sstevel@tonic-gate * Pack nvlist into contiguous memory
26367c478bd9Sstevel@tonic-gate */
26377c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
26387c478bd9Sstevel@tonic-gate int
nvlist_pack(nvlist_t * nvl,char ** bufp,size_t * buflen,int encoding,int kmflag)26397c478bd9Sstevel@tonic-gate nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
26407c478bd9Sstevel@tonic-gate int kmflag)
26417c478bd9Sstevel@tonic-gate {
26427c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
26437c478bd9Sstevel@tonic-gate return (nvlist_xpack(nvl, bufp, buflen, encoding,
26447c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
26457c478bd9Sstevel@tonic-gate #else
26467c478bd9Sstevel@tonic-gate return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep));
26477c478bd9Sstevel@tonic-gate #endif
26487c478bd9Sstevel@tonic-gate }
26497c478bd9Sstevel@tonic-gate
26507c478bd9Sstevel@tonic-gate int
nvlist_xpack(nvlist_t * nvl,char ** bufp,size_t * buflen,int encoding,nv_alloc_t * nva)26517c478bd9Sstevel@tonic-gate nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
26527c478bd9Sstevel@tonic-gate nv_alloc_t *nva)
26537c478bd9Sstevel@tonic-gate {
26547c478bd9Sstevel@tonic-gate nvpriv_t nvpriv;
26557c478bd9Sstevel@tonic-gate size_t alloc_size;
26567c478bd9Sstevel@tonic-gate char *buf;
26577c478bd9Sstevel@tonic-gate int err;
26587c478bd9Sstevel@tonic-gate
26597c478bd9Sstevel@tonic-gate if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL)
26607c478bd9Sstevel@tonic-gate return (EINVAL);
26617c478bd9Sstevel@tonic-gate
26627c478bd9Sstevel@tonic-gate if (*bufp != NULL)
26637c478bd9Sstevel@tonic-gate return (nvlist_common(nvl, *bufp, buflen, encoding,
26647c478bd9Sstevel@tonic-gate NVS_OP_ENCODE));
26657c478bd9Sstevel@tonic-gate
26667c478bd9Sstevel@tonic-gate /*
26677c478bd9Sstevel@tonic-gate * Here is a difficult situation:
26687c478bd9Sstevel@tonic-gate * 1. The nvlist has fixed allocator properties.
26697c478bd9Sstevel@tonic-gate * All other nvlist routines (like nvlist_add_*, ...) use
26707c478bd9Sstevel@tonic-gate * these properties.
267148bbca81SDaniel Hoffman * 2. When using nvlist_pack() the user can specify their own
26727c478bd9Sstevel@tonic-gate * allocator properties (e.g. by using KM_NOSLEEP).
26737c478bd9Sstevel@tonic-gate *
26747c478bd9Sstevel@tonic-gate * We use the user specified properties (2). A clearer solution
26757c478bd9Sstevel@tonic-gate * will be to remove the kmflag from nvlist_pack(), but we will
26767c478bd9Sstevel@tonic-gate * not change the interface.
26777c478bd9Sstevel@tonic-gate */
26787c478bd9Sstevel@tonic-gate nv_priv_init(&nvpriv, nva, 0);
26797c478bd9Sstevel@tonic-gate
2680759e89beSSteve Dougherty if ((err = nvlist_size(nvl, &alloc_size, encoding)))
26817c478bd9Sstevel@tonic-gate return (err);
26827c478bd9Sstevel@tonic-gate
26837c478bd9Sstevel@tonic-gate if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL)
26847c478bd9Sstevel@tonic-gate return (ENOMEM);
26857c478bd9Sstevel@tonic-gate
26867c478bd9Sstevel@tonic-gate if ((err = nvlist_common(nvl, buf, &alloc_size, encoding,
26877c478bd9Sstevel@tonic-gate NVS_OP_ENCODE)) != 0) {
26887c478bd9Sstevel@tonic-gate nv_mem_free(&nvpriv, buf, alloc_size);
26897c478bd9Sstevel@tonic-gate } else {
26907c478bd9Sstevel@tonic-gate *buflen = alloc_size;
26917c478bd9Sstevel@tonic-gate *bufp = buf;
26927c478bd9Sstevel@tonic-gate }
26937c478bd9Sstevel@tonic-gate
26947c478bd9Sstevel@tonic-gate return (err);
26957c478bd9Sstevel@tonic-gate }
26967c478bd9Sstevel@tonic-gate
26977c478bd9Sstevel@tonic-gate /*
26987c478bd9Sstevel@tonic-gate * Unpack buf into an nvlist_t
26997c478bd9Sstevel@tonic-gate */
27007c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
27017c478bd9Sstevel@tonic-gate int
nvlist_unpack(char * buf,size_t buflen,nvlist_t ** nvlp,int kmflag)27027c478bd9Sstevel@tonic-gate nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag)
27037c478bd9Sstevel@tonic-gate {
27047c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
27057c478bd9Sstevel@tonic-gate return (nvlist_xunpack(buf, buflen, nvlp,
27067c478bd9Sstevel@tonic-gate (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
27077c478bd9Sstevel@tonic-gate #else
27087c478bd9Sstevel@tonic-gate return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep));
27097c478bd9Sstevel@tonic-gate #endif
27107c478bd9Sstevel@tonic-gate }
27117c478bd9Sstevel@tonic-gate
27127c478bd9Sstevel@tonic-gate int
nvlist_xunpack(char * buf,size_t buflen,nvlist_t ** nvlp,nv_alloc_t * nva)27137c478bd9Sstevel@tonic-gate nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva)
27147c478bd9Sstevel@tonic-gate {
27157c478bd9Sstevel@tonic-gate nvlist_t *nvl;
27167c478bd9Sstevel@tonic-gate int err;
27177c478bd9Sstevel@tonic-gate
27187c478bd9Sstevel@tonic-gate if (nvlp == NULL)
27197c478bd9Sstevel@tonic-gate return (EINVAL);
27207c478bd9Sstevel@tonic-gate
27217c478bd9Sstevel@tonic-gate if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0)
27227c478bd9Sstevel@tonic-gate return (err);
27237c478bd9Sstevel@tonic-gate
27247c478bd9Sstevel@tonic-gate if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0)
27257c478bd9Sstevel@tonic-gate nvlist_free(nvl);
27267c478bd9Sstevel@tonic-gate else
27277c478bd9Sstevel@tonic-gate *nvlp = nvl;
27287c478bd9Sstevel@tonic-gate
27297c478bd9Sstevel@tonic-gate return (err);
27307c478bd9Sstevel@tonic-gate }
27317c478bd9Sstevel@tonic-gate
27327c478bd9Sstevel@tonic-gate /*
27337c478bd9Sstevel@tonic-gate * Native encoding functions
27347c478bd9Sstevel@tonic-gate */
27357c478bd9Sstevel@tonic-gate typedef struct {
27367c478bd9Sstevel@tonic-gate /*
27377c478bd9Sstevel@tonic-gate * This structure is used when decoding a packed nvpair in
27387c478bd9Sstevel@tonic-gate * the native format. n_base points to a buffer containing the
27397c478bd9Sstevel@tonic-gate * packed nvpair. n_end is a pointer to the end of the buffer.
27407c478bd9Sstevel@tonic-gate * (n_end actually points to the first byte past the end of the
27417c478bd9Sstevel@tonic-gate * buffer.) n_curr is a pointer that lies between n_base and n_end.
27427c478bd9Sstevel@tonic-gate * It points to the current data that we are decoding.
27437c478bd9Sstevel@tonic-gate * The amount of data left in the buffer is equal to n_end - n_curr.
27447c478bd9Sstevel@tonic-gate * n_flag is used to recognize a packed embedded list.
27457c478bd9Sstevel@tonic-gate */
27467c478bd9Sstevel@tonic-gate caddr_t n_base;
27477c478bd9Sstevel@tonic-gate caddr_t n_end;
27487c478bd9Sstevel@tonic-gate caddr_t n_curr;
27497c478bd9Sstevel@tonic-gate uint_t n_flag;
27507c478bd9Sstevel@tonic-gate } nvs_native_t;
27517c478bd9Sstevel@tonic-gate
27527c478bd9Sstevel@tonic-gate static int
nvs_native_create(nvstream_t * nvs,nvs_native_t * native,char * buf,size_t buflen)27537c478bd9Sstevel@tonic-gate nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf,
27547c478bd9Sstevel@tonic-gate size_t buflen)
27557c478bd9Sstevel@tonic-gate {
27567c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
27577c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
27587c478bd9Sstevel@tonic-gate case NVS_OP_DECODE:
27597c478bd9Sstevel@tonic-gate nvs->nvs_private = native;
27607c478bd9Sstevel@tonic-gate native->n_curr = native->n_base = buf;
27617c478bd9Sstevel@tonic-gate native->n_end = buf + buflen;
27627c478bd9Sstevel@tonic-gate native->n_flag = 0;
27637c478bd9Sstevel@tonic-gate return (0);
27647c478bd9Sstevel@tonic-gate
27657c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE:
27667c478bd9Sstevel@tonic-gate nvs->nvs_private = native;
27677c478bd9Sstevel@tonic-gate native->n_curr = native->n_base = native->n_end = NULL;
27687c478bd9Sstevel@tonic-gate native->n_flag = 0;
27697c478bd9Sstevel@tonic-gate return (0);
27707c478bd9Sstevel@tonic-gate default:
27717c478bd9Sstevel@tonic-gate return (EINVAL);
27727c478bd9Sstevel@tonic-gate }
27737c478bd9Sstevel@tonic-gate }
27747c478bd9Sstevel@tonic-gate
27757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
27767c478bd9Sstevel@tonic-gate static void
nvs_native_destroy(nvstream_t * nvs)27777c478bd9Sstevel@tonic-gate nvs_native_destroy(nvstream_t *nvs)
27787c478bd9Sstevel@tonic-gate {
27797c478bd9Sstevel@tonic-gate }
27807c478bd9Sstevel@tonic-gate
27817c478bd9Sstevel@tonic-gate static int
native_cp(nvstream_t * nvs,void * buf,size_t size)27827c478bd9Sstevel@tonic-gate native_cp(nvstream_t *nvs, void *buf, size_t size)
27837c478bd9Sstevel@tonic-gate {
27847c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
27857c478bd9Sstevel@tonic-gate
27867c478bd9Sstevel@tonic-gate if (native->n_curr + size > native->n_end)
27877c478bd9Sstevel@tonic-gate return (EFAULT);
27887c478bd9Sstevel@tonic-gate
27897c478bd9Sstevel@tonic-gate /*
27907c478bd9Sstevel@tonic-gate * The bcopy() below eliminates alignment requirement
27917c478bd9Sstevel@tonic-gate * on the buffer (stream) and is preferred over direct access.
27927c478bd9Sstevel@tonic-gate */
27937c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
27947c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
27957c478bd9Sstevel@tonic-gate bcopy(buf, native->n_curr, size);
27967c478bd9Sstevel@tonic-gate break;
27977c478bd9Sstevel@tonic-gate case NVS_OP_DECODE:
27987c478bd9Sstevel@tonic-gate bcopy(native->n_curr, buf, size);
27997c478bd9Sstevel@tonic-gate break;
28007c478bd9Sstevel@tonic-gate default:
28017c478bd9Sstevel@tonic-gate return (EINVAL);
28027c478bd9Sstevel@tonic-gate }
28037c478bd9Sstevel@tonic-gate
28047c478bd9Sstevel@tonic-gate native->n_curr += size;
28057c478bd9Sstevel@tonic-gate return (0);
28067c478bd9Sstevel@tonic-gate }
28077c478bd9Sstevel@tonic-gate
28087c478bd9Sstevel@tonic-gate /*
28097c478bd9Sstevel@tonic-gate * operate on nvlist_t header
28107c478bd9Sstevel@tonic-gate */
28117c478bd9Sstevel@tonic-gate static int
nvs_native_nvlist(nvstream_t * nvs,nvlist_t * nvl,size_t * size)28127c478bd9Sstevel@tonic-gate nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
28137c478bd9Sstevel@tonic-gate {
28147c478bd9Sstevel@tonic-gate nvs_native_t *native = nvs->nvs_private;
28157c478bd9Sstevel@tonic-gate
28167c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
28177c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
28187c478bd9Sstevel@tonic-gate case NVS_OP_DECODE:
28197c478bd9Sstevel@tonic-gate if (native->n_flag)
28207c478bd9Sstevel@tonic-gate return (0); /* packed embedded list */
28217c478bd9Sstevel@tonic-gate
28227c478bd9Sstevel@tonic-gate native->n_flag = 1;
28237c478bd9Sstevel@tonic-gate
28247c478bd9Sstevel@tonic-gate /* copy version and nvflag of the nvlist_t */
28257c478bd9Sstevel@tonic-gate if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 ||
28267c478bd9Sstevel@tonic-gate native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0)
28277c478bd9Sstevel@tonic-gate return (EFAULT);
28287c478bd9Sstevel@tonic-gate
28297c478bd9Sstevel@tonic-gate return (0);
28307c478bd9Sstevel@tonic-gate
28317c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE:
28327c478bd9Sstevel@tonic-gate /*
28337c478bd9Sstevel@tonic-gate * if calculate for packed embedded list
28347c478bd9Sstevel@tonic-gate * 4 for end of the embedded list
28357c478bd9Sstevel@tonic-gate * else
28367c478bd9Sstevel@tonic-gate * 2 * sizeof (int32_t) for nvl_version and nvl_nvflag
28377c478bd9Sstevel@tonic-gate * and 4 for end of the entire list
28387c478bd9Sstevel@tonic-gate */
28397c478bd9Sstevel@tonic-gate if (native->n_flag) {
28407c478bd9Sstevel@tonic-gate *size += 4;
28417c478bd9Sstevel@tonic-gate } else {
28427c478bd9Sstevel@tonic-gate native->n_flag = 1;
28437c478bd9Sstevel@tonic-gate *size += 2 * sizeof (int32_t) + 4;
28447c478bd9Sstevel@tonic-gate }
28457c478bd9Sstevel@tonic-gate
28467c478bd9Sstevel@tonic-gate return (0);
28477c478bd9Sstevel@tonic-gate
28487c478bd9Sstevel@tonic-gate default:
28497c478bd9Sstevel@tonic-gate return (EINVAL);
28507c478bd9Sstevel@tonic-gate }
28517c478bd9Sstevel@tonic-gate }
28527c478bd9Sstevel@tonic-gate
28537c478bd9Sstevel@tonic-gate static int
nvs_native_nvl_fini(nvstream_t * nvs)28547c478bd9Sstevel@tonic-gate nvs_native_nvl_fini(nvstream_t *nvs)
28557c478bd9Sstevel@tonic-gate {
28567c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) {
28577c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
28587c478bd9Sstevel@tonic-gate /*
28597c478bd9Sstevel@tonic-gate * Add 4 zero bytes at end of nvlist. They are used
28607c478bd9Sstevel@tonic-gate * for end detection by the decode routine.
28617c478bd9Sstevel@tonic-gate */
28627c478bd9Sstevel@tonic-gate if (native->n_curr + sizeof (int) > native->n_end)
28637c478bd9Sstevel@tonic-gate return (EFAULT);
28647c478bd9Sstevel@tonic-gate
28657c478bd9Sstevel@tonic-gate bzero(native->n_curr, sizeof (int));
28667c478bd9Sstevel@tonic-gate native->n_curr += sizeof (int);
28677c478bd9Sstevel@tonic-gate }
28687c478bd9Sstevel@tonic-gate
28697c478bd9Sstevel@tonic-gate return (0);
28707c478bd9Sstevel@tonic-gate }
28717c478bd9Sstevel@tonic-gate
28727c478bd9Sstevel@tonic-gate static int
nvpair_native_embedded(nvstream_t * nvs,nvpair_t * nvp)28737c478bd9Sstevel@tonic-gate nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp)
28747c478bd9Sstevel@tonic-gate {
28757c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) {
28767c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
28777c478bd9Sstevel@tonic-gate nvlist_t *packed = (void *)
28787c478bd9Sstevel@tonic-gate (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
28797c478bd9Sstevel@tonic-gate /*
28807c478bd9Sstevel@tonic-gate * Null out the pointer that is meaningless in the packed
28817c478bd9Sstevel@tonic-gate * structure. The address may not be aligned, so we have
28827c478bd9Sstevel@tonic-gate * to use bzero.
28837c478bd9Sstevel@tonic-gate */
28847c478bd9Sstevel@tonic-gate bzero(&packed->nvl_priv, sizeof (packed->nvl_priv));
28857c478bd9Sstevel@tonic-gate }
28867c478bd9Sstevel@tonic-gate
28877c478bd9Sstevel@tonic-gate return (nvs_embedded(nvs, EMBEDDED_NVL(nvp)));
28887c478bd9Sstevel@tonic-gate }
28897c478bd9Sstevel@tonic-gate
28907c478bd9Sstevel@tonic-gate static int
nvpair_native_embedded_array(nvstream_t * nvs,nvpair_t * nvp)28917c478bd9Sstevel@tonic-gate nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp)
28927c478bd9Sstevel@tonic-gate {
28937c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) {
28947c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
28957c478bd9Sstevel@tonic-gate char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp);
28967c478bd9Sstevel@tonic-gate size_t len = NVP_NELEM(nvp) * sizeof (uint64_t);
28977c478bd9Sstevel@tonic-gate nvlist_t *packed = (nvlist_t *)((uintptr_t)value + len);
28987c478bd9Sstevel@tonic-gate int i;
28997c478bd9Sstevel@tonic-gate /*
29007c478bd9Sstevel@tonic-gate * Null out pointers that are meaningless in the packed
29017c478bd9Sstevel@tonic-gate * structure. The addresses may not be aligned, so we have
29027c478bd9Sstevel@tonic-gate * to use bzero.
29037c478bd9Sstevel@tonic-gate */
29047c478bd9Sstevel@tonic-gate bzero(value, len);
29057c478bd9Sstevel@tonic-gate
29067c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++, packed++)
29077c478bd9Sstevel@tonic-gate /*
29087c478bd9Sstevel@tonic-gate * Null out the pointer that is meaningless in the
29097c478bd9Sstevel@tonic-gate * packed structure. The address may not be aligned,
29107c478bd9Sstevel@tonic-gate * so we have to use bzero.
29117c478bd9Sstevel@tonic-gate */
29127c478bd9Sstevel@tonic-gate bzero(&packed->nvl_priv, sizeof (packed->nvl_priv));
29137c478bd9Sstevel@tonic-gate }
29147c478bd9Sstevel@tonic-gate
29157c478bd9Sstevel@tonic-gate return (nvs_embedded_nvl_array(nvs, nvp, NULL));
29167c478bd9Sstevel@tonic-gate }
29177c478bd9Sstevel@tonic-gate
29187c478bd9Sstevel@tonic-gate static void
nvpair_native_string_array(nvstream_t * nvs,nvpair_t * nvp)29197c478bd9Sstevel@tonic-gate nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp)
29207c478bd9Sstevel@tonic-gate {
29217c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
29227c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: {
29237c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
29247c478bd9Sstevel@tonic-gate uint64_t *strp = (void *)
29257c478bd9Sstevel@tonic-gate (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
29267c478bd9Sstevel@tonic-gate /*
29277c478bd9Sstevel@tonic-gate * Null out pointers that are meaningless in the packed
29287c478bd9Sstevel@tonic-gate * structure. The addresses may not be aligned, so we have
29297c478bd9Sstevel@tonic-gate * to use bzero.
29307c478bd9Sstevel@tonic-gate */
29317c478bd9Sstevel@tonic-gate bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t));
29327c478bd9Sstevel@tonic-gate break;
29337c478bd9Sstevel@tonic-gate }
29347c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: {
29357c478bd9Sstevel@tonic-gate char **strp = (void *)NVP_VALUE(nvp);
29367c478bd9Sstevel@tonic-gate char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t));
29377c478bd9Sstevel@tonic-gate int i;
29387c478bd9Sstevel@tonic-gate
29397c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++) {
29407c478bd9Sstevel@tonic-gate strp[i] = buf;
29417c478bd9Sstevel@tonic-gate buf += strlen(buf) + 1;
29427c478bd9Sstevel@tonic-gate }
29437c478bd9Sstevel@tonic-gate break;
29447c478bd9Sstevel@tonic-gate }
29457c478bd9Sstevel@tonic-gate }
29467c478bd9Sstevel@tonic-gate }
29477c478bd9Sstevel@tonic-gate
29487c478bd9Sstevel@tonic-gate static int
nvs_native_nvp_op(nvstream_t * nvs,nvpair_t * nvp)29497c478bd9Sstevel@tonic-gate nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
29507c478bd9Sstevel@tonic-gate {
29517c478bd9Sstevel@tonic-gate data_type_t type;
29527c478bd9Sstevel@tonic-gate int value_sz;
29537c478bd9Sstevel@tonic-gate int ret = 0;
29547c478bd9Sstevel@tonic-gate
29557c478bd9Sstevel@tonic-gate /*
29567c478bd9Sstevel@tonic-gate * We do the initial bcopy of the data before we look at
29577c478bd9Sstevel@tonic-gate * the nvpair type, because when we're decoding, we won't
29587c478bd9Sstevel@tonic-gate * have the correct values for the pair until we do the bcopy.
29597c478bd9Sstevel@tonic-gate */
29607c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
29617c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
29627c478bd9Sstevel@tonic-gate case NVS_OP_DECODE:
29637c478bd9Sstevel@tonic-gate if (native_cp(nvs, nvp, nvp->nvp_size) != 0)
29647c478bd9Sstevel@tonic-gate return (EFAULT);
29657c478bd9Sstevel@tonic-gate break;
29667c478bd9Sstevel@tonic-gate default:
29677c478bd9Sstevel@tonic-gate return (EINVAL);
29687c478bd9Sstevel@tonic-gate }
29697c478bd9Sstevel@tonic-gate
29707c478bd9Sstevel@tonic-gate /* verify nvp_name_sz, check the name string length */
29717c478bd9Sstevel@tonic-gate if (i_validate_nvpair_name(nvp) != 0)
29727c478bd9Sstevel@tonic-gate return (EFAULT);
29737c478bd9Sstevel@tonic-gate
29747c478bd9Sstevel@tonic-gate type = NVP_TYPE(nvp);
29757c478bd9Sstevel@tonic-gate
29767c478bd9Sstevel@tonic-gate /*
29777c478bd9Sstevel@tonic-gate * Verify type and nelem and get the value size.
29787c478bd9Sstevel@tonic-gate * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
29797c478bd9Sstevel@tonic-gate * is the size of the string(s) excluded.
29807c478bd9Sstevel@tonic-gate */
29817c478bd9Sstevel@tonic-gate if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0)
29827c478bd9Sstevel@tonic-gate return (EFAULT);
29837c478bd9Sstevel@tonic-gate
29847c478bd9Sstevel@tonic-gate if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size)
29857c478bd9Sstevel@tonic-gate return (EFAULT);
29867c478bd9Sstevel@tonic-gate
29877c478bd9Sstevel@tonic-gate switch (type) {
29887c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST:
29897c478bd9Sstevel@tonic-gate ret = nvpair_native_embedded(nvs, nvp);
29907c478bd9Sstevel@tonic-gate break;
29917c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY:
29927c478bd9Sstevel@tonic-gate ret = nvpair_native_embedded_array(nvs, nvp);
29937c478bd9Sstevel@tonic-gate break;
29947c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY:
29957c478bd9Sstevel@tonic-gate nvpair_native_string_array(nvs, nvp);
29967c478bd9Sstevel@tonic-gate break;
29977c478bd9Sstevel@tonic-gate default:
29987c478bd9Sstevel@tonic-gate break;
29997c478bd9Sstevel@tonic-gate }
30007c478bd9Sstevel@tonic-gate
30017c478bd9Sstevel@tonic-gate return (ret);
30027c478bd9Sstevel@tonic-gate }
30037c478bd9Sstevel@tonic-gate
30047c478bd9Sstevel@tonic-gate static int
nvs_native_nvp_size(nvstream_t * nvs,nvpair_t * nvp,size_t * size)30057c478bd9Sstevel@tonic-gate nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
30067c478bd9Sstevel@tonic-gate {
30077c478bd9Sstevel@tonic-gate uint64_t nvp_sz = nvp->nvp_size;
30087c478bd9Sstevel@tonic-gate
30097c478bd9Sstevel@tonic-gate switch (NVP_TYPE(nvp)) {
30107c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST: {
30117c478bd9Sstevel@tonic-gate size_t nvsize = 0;
30127c478bd9Sstevel@tonic-gate
30137c478bd9Sstevel@tonic-gate if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0)
30147c478bd9Sstevel@tonic-gate return (EINVAL);
30157c478bd9Sstevel@tonic-gate
30167c478bd9Sstevel@tonic-gate nvp_sz += nvsize;
30177c478bd9Sstevel@tonic-gate break;
30187c478bd9Sstevel@tonic-gate }
30197c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: {
30207c478bd9Sstevel@tonic-gate size_t nvsize;
30217c478bd9Sstevel@tonic-gate
30227c478bd9Sstevel@tonic-gate if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0)
30237c478bd9Sstevel@tonic-gate return (EINVAL);
30247c478bd9Sstevel@tonic-gate
30257c478bd9Sstevel@tonic-gate nvp_sz += nvsize;
30267c478bd9Sstevel@tonic-gate break;
30277c478bd9Sstevel@tonic-gate }
30287c478bd9Sstevel@tonic-gate default:
30297c478bd9Sstevel@tonic-gate break;
30307c478bd9Sstevel@tonic-gate }
30317c478bd9Sstevel@tonic-gate
30327c478bd9Sstevel@tonic-gate if (nvp_sz > INT32_MAX)
30337c478bd9Sstevel@tonic-gate return (EINVAL);
30347c478bd9Sstevel@tonic-gate
30357c478bd9Sstevel@tonic-gate *size = nvp_sz;
30367c478bd9Sstevel@tonic-gate
30377c478bd9Sstevel@tonic-gate return (0);
30387c478bd9Sstevel@tonic-gate }
30397c478bd9Sstevel@tonic-gate
30407c478bd9Sstevel@tonic-gate static int
nvs_native_nvpair(nvstream_t * nvs,nvpair_t * nvp,size_t * size)30417c478bd9Sstevel@tonic-gate nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
30427c478bd9Sstevel@tonic-gate {
30437c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
30447c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
30457c478bd9Sstevel@tonic-gate return (nvs_native_nvp_op(nvs, nvp));
30467c478bd9Sstevel@tonic-gate
30477c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: {
30487c478bd9Sstevel@tonic-gate nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
30497c478bd9Sstevel@tonic-gate int32_t decode_len;
30507c478bd9Sstevel@tonic-gate
30517c478bd9Sstevel@tonic-gate /* try to read the size value from the stream */
30527c478bd9Sstevel@tonic-gate if (native->n_curr + sizeof (int32_t) > native->n_end)
30537c478bd9Sstevel@tonic-gate return (EFAULT);
30547c478bd9Sstevel@tonic-gate bcopy(native->n_curr, &decode_len, sizeof (int32_t));
30557c478bd9Sstevel@tonic-gate
30567c478bd9Sstevel@tonic-gate /* sanity check the size value */
30577c478bd9Sstevel@tonic-gate if (decode_len < 0 ||
30587c478bd9Sstevel@tonic-gate decode_len > native->n_end - native->n_curr)
30597c478bd9Sstevel@tonic-gate return (EFAULT);
30607c478bd9Sstevel@tonic-gate
30617c478bd9Sstevel@tonic-gate *size = decode_len;
30627c478bd9Sstevel@tonic-gate
30637c478bd9Sstevel@tonic-gate /*
30647c478bd9Sstevel@tonic-gate * If at the end of the stream then move the cursor
30657c478bd9Sstevel@tonic-gate * forward, otherwise nvpair_native_op() will read
30667c478bd9Sstevel@tonic-gate * the entire nvpair at the same cursor position.
30677c478bd9Sstevel@tonic-gate */
30687c478bd9Sstevel@tonic-gate if (*size == 0)
30697c478bd9Sstevel@tonic-gate native->n_curr += sizeof (int32_t);
30707c478bd9Sstevel@tonic-gate break;
30717c478bd9Sstevel@tonic-gate }
30727c478bd9Sstevel@tonic-gate
30737c478bd9Sstevel@tonic-gate default:
30747c478bd9Sstevel@tonic-gate return (EINVAL);
30757c478bd9Sstevel@tonic-gate }
30767c478bd9Sstevel@tonic-gate
30777c478bd9Sstevel@tonic-gate return (0);
30787c478bd9Sstevel@tonic-gate }
30797c478bd9Sstevel@tonic-gate
30807c478bd9Sstevel@tonic-gate static const nvs_ops_t nvs_native_ops = {
30817c478bd9Sstevel@tonic-gate nvs_native_nvlist,
30827c478bd9Sstevel@tonic-gate nvs_native_nvpair,
30837c478bd9Sstevel@tonic-gate nvs_native_nvp_op,
30847c478bd9Sstevel@tonic-gate nvs_native_nvp_size,
30857c478bd9Sstevel@tonic-gate nvs_native_nvl_fini
30867c478bd9Sstevel@tonic-gate };
30877c478bd9Sstevel@tonic-gate
30887c478bd9Sstevel@tonic-gate static int
nvs_native(nvstream_t * nvs,nvlist_t * nvl,char * buf,size_t * buflen)30897c478bd9Sstevel@tonic-gate nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
30907c478bd9Sstevel@tonic-gate {
30917c478bd9Sstevel@tonic-gate nvs_native_t native;
30927c478bd9Sstevel@tonic-gate int err;
30937c478bd9Sstevel@tonic-gate
30947c478bd9Sstevel@tonic-gate nvs->nvs_ops = &nvs_native_ops;
30957c478bd9Sstevel@tonic-gate
30967c478bd9Sstevel@tonic-gate if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t),
30977c478bd9Sstevel@tonic-gate *buflen - sizeof (nvs_header_t))) != 0)
30987c478bd9Sstevel@tonic-gate return (err);
30997c478bd9Sstevel@tonic-gate
31007c478bd9Sstevel@tonic-gate err = nvs_operation(nvs, nvl, buflen);
31017c478bd9Sstevel@tonic-gate
31027c478bd9Sstevel@tonic-gate nvs_native_destroy(nvs);
31037c478bd9Sstevel@tonic-gate
31047c478bd9Sstevel@tonic-gate return (err);
31057c478bd9Sstevel@tonic-gate }
31067c478bd9Sstevel@tonic-gate
31077c478bd9Sstevel@tonic-gate /*
31087c478bd9Sstevel@tonic-gate * XDR encoding functions
31097c478bd9Sstevel@tonic-gate *
31107c478bd9Sstevel@tonic-gate * An xdr packed nvlist is encoded as:
31117c478bd9Sstevel@tonic-gate *
31127c478bd9Sstevel@tonic-gate * - encoding methode and host endian (4 bytes)
31137c478bd9Sstevel@tonic-gate * - nvl_version (4 bytes)
31147c478bd9Sstevel@tonic-gate * - nvl_nvflag (4 bytes)
31157c478bd9Sstevel@tonic-gate *
31167c478bd9Sstevel@tonic-gate * - encoded nvpairs, the format of one xdr encoded nvpair is:
31177c478bd9Sstevel@tonic-gate * - encoded size of the nvpair (4 bytes)
31187c478bd9Sstevel@tonic-gate * - decoded size of the nvpair (4 bytes)
31197c478bd9Sstevel@tonic-gate * - name string, (4 + sizeof(NV_ALIGN4(string))
31207c478bd9Sstevel@tonic-gate * a string is coded as size (4 bytes) and data
31217c478bd9Sstevel@tonic-gate * - data type (4 bytes)
31227c478bd9Sstevel@tonic-gate * - number of elements in the nvpair (4 bytes)
31237c478bd9Sstevel@tonic-gate * - data
31247c478bd9Sstevel@tonic-gate *
31257c478bd9Sstevel@tonic-gate * - 2 zero's for end of the entire list (8 bytes)
31267c478bd9Sstevel@tonic-gate */
31277c478bd9Sstevel@tonic-gate static int
nvs_xdr_create(nvstream_t * nvs,XDR * xdr,char * buf,size_t buflen)31287c478bd9Sstevel@tonic-gate nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen)
31297c478bd9Sstevel@tonic-gate {
31307c478bd9Sstevel@tonic-gate /* xdr data must be 4 byte aligned */
31317c478bd9Sstevel@tonic-gate if ((ulong_t)buf % 4 != 0)
31327c478bd9Sstevel@tonic-gate return (EFAULT);
31337c478bd9Sstevel@tonic-gate
31347c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
31357c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
31367c478bd9Sstevel@tonic-gate xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE);
31377c478bd9Sstevel@tonic-gate nvs->nvs_private = xdr;
31387c478bd9Sstevel@tonic-gate return (0);
31397c478bd9Sstevel@tonic-gate case NVS_OP_DECODE:
31407c478bd9Sstevel@tonic-gate xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE);
31417c478bd9Sstevel@tonic-gate nvs->nvs_private = xdr;
31427c478bd9Sstevel@tonic-gate return (0);
31437c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE:
31447c478bd9Sstevel@tonic-gate nvs->nvs_private = NULL;
31457c478bd9Sstevel@tonic-gate return (0);
31467c478bd9Sstevel@tonic-gate default:
31477c478bd9Sstevel@tonic-gate return (EINVAL);
31487c478bd9Sstevel@tonic-gate }
31497c478bd9Sstevel@tonic-gate }
31507c478bd9Sstevel@tonic-gate
31517c478bd9Sstevel@tonic-gate static void
nvs_xdr_destroy(nvstream_t * nvs)31527c478bd9Sstevel@tonic-gate nvs_xdr_destroy(nvstream_t *nvs)
31537c478bd9Sstevel@tonic-gate {
31547c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
31557c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
31567c478bd9Sstevel@tonic-gate case NVS_OP_DECODE:
31577c478bd9Sstevel@tonic-gate xdr_destroy((XDR *)nvs->nvs_private);
31587c478bd9Sstevel@tonic-gate break;
31597c478bd9Sstevel@tonic-gate default:
31607c478bd9Sstevel@tonic-gate break;
31617c478bd9Sstevel@tonic-gate }
31627c478bd9Sstevel@tonic-gate }
31637c478bd9Sstevel@tonic-gate
31647c478bd9Sstevel@tonic-gate static int
nvs_xdr_nvlist(nvstream_t * nvs,nvlist_t * nvl,size_t * size)31657c478bd9Sstevel@tonic-gate nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
31667c478bd9Sstevel@tonic-gate {
31677c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
31687c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE:
31697c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: {
31707c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private;
31717c478bd9Sstevel@tonic-gate
31727c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &nvl->nvl_version) ||
31737c478bd9Sstevel@tonic-gate !xdr_u_int(xdr, &nvl->nvl_nvflag))
31747c478bd9Sstevel@tonic-gate return (EFAULT);
31757c478bd9Sstevel@tonic-gate break;
31767c478bd9Sstevel@tonic-gate }
31777c478bd9Sstevel@tonic-gate case NVS_OP_GETSIZE: {
31787c478bd9Sstevel@tonic-gate /*
31797c478bd9Sstevel@tonic-gate * 2 * 4 for nvl_version + nvl_nvflag
31807c478bd9Sstevel@tonic-gate * and 8 for end of the entire list
31817c478bd9Sstevel@tonic-gate */
31827c478bd9Sstevel@tonic-gate *size += 2 * 4 + 8;
31837c478bd9Sstevel@tonic-gate break;
31847c478bd9Sstevel@tonic-gate }
31857c478bd9Sstevel@tonic-gate default:
31867c478bd9Sstevel@tonic-gate return (EINVAL);
31877c478bd9Sstevel@tonic-gate }
31887c478bd9Sstevel@tonic-gate return (0);
31897c478bd9Sstevel@tonic-gate }
31907c478bd9Sstevel@tonic-gate
31917c478bd9Sstevel@tonic-gate static int
nvs_xdr_nvl_fini(nvstream_t * nvs)31927c478bd9Sstevel@tonic-gate nvs_xdr_nvl_fini(nvstream_t *nvs)
31937c478bd9Sstevel@tonic-gate {
31947c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_ENCODE) {
31957c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private;
31967c478bd9Sstevel@tonic-gate int zero = 0;
31977c478bd9Sstevel@tonic-gate
31987c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero))
31997c478bd9Sstevel@tonic-gate return (EFAULT);
32007c478bd9Sstevel@tonic-gate }
32017c478bd9Sstevel@tonic-gate
32027c478bd9Sstevel@tonic-gate return (0);
32037c478bd9Sstevel@tonic-gate }
32047c478bd9Sstevel@tonic-gate
32057c478bd9Sstevel@tonic-gate /*
32067c478bd9Sstevel@tonic-gate * The format of xdr encoded nvpair is:
32077c478bd9Sstevel@tonic-gate * encode_size, decode_size, name string, data type, nelem, data
32087c478bd9Sstevel@tonic-gate */
32097c478bd9Sstevel@tonic-gate static int
nvs_xdr_nvp_op(nvstream_t * nvs,nvpair_t * nvp)32107c478bd9Sstevel@tonic-gate nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
32117c478bd9Sstevel@tonic-gate {
32127c478bd9Sstevel@tonic-gate data_type_t type;
32137c478bd9Sstevel@tonic-gate char *buf;
32147c478bd9Sstevel@tonic-gate char *buf_end = (char *)nvp + nvp->nvp_size;
32157c478bd9Sstevel@tonic-gate int value_sz;
32167c478bd9Sstevel@tonic-gate uint_t nelem, buflen;
32177c478bd9Sstevel@tonic-gate bool_t ret = FALSE;
32187c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private;
32197c478bd9Sstevel@tonic-gate
32207c478bd9Sstevel@tonic-gate ASSERT(xdr != NULL && nvp != NULL);
32217c478bd9Sstevel@tonic-gate
32227c478bd9Sstevel@tonic-gate /* name string */
32237c478bd9Sstevel@tonic-gate if ((buf = NVP_NAME(nvp)) >= buf_end)
32247c478bd9Sstevel@tonic-gate return (EFAULT);
32257c478bd9Sstevel@tonic-gate buflen = buf_end - buf;
32267c478bd9Sstevel@tonic-gate
32277c478bd9Sstevel@tonic-gate if (!xdr_string(xdr, &buf, buflen - 1))
32287c478bd9Sstevel@tonic-gate return (EFAULT);
32297c478bd9Sstevel@tonic-gate nvp->nvp_name_sz = strlen(buf) + 1;
32307c478bd9Sstevel@tonic-gate
32317c478bd9Sstevel@tonic-gate /* type and nelem */
32327c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, (int *)&nvp->nvp_type) ||
32337c478bd9Sstevel@tonic-gate !xdr_int(xdr, &nvp->nvp_value_elem))
32347c478bd9Sstevel@tonic-gate return (EFAULT);
32357c478bd9Sstevel@tonic-gate
32367c478bd9Sstevel@tonic-gate type = NVP_TYPE(nvp);
32377c478bd9Sstevel@tonic-gate nelem = nvp->nvp_value_elem;
32387c478bd9Sstevel@tonic-gate
32397c478bd9Sstevel@tonic-gate /*
32407c478bd9Sstevel@tonic-gate * Verify type and nelem and get the value size.
32417c478bd9Sstevel@tonic-gate * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
32427c478bd9Sstevel@tonic-gate * is the size of the string(s) excluded.
32437c478bd9Sstevel@tonic-gate */
32447c478bd9Sstevel@tonic-gate if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0)
32457c478bd9Sstevel@tonic-gate return (EFAULT);
32467c478bd9Sstevel@tonic-gate
32477c478bd9Sstevel@tonic-gate /* if there is no data to extract then return */
32487c478bd9Sstevel@tonic-gate if (nelem == 0)
32497c478bd9Sstevel@tonic-gate return (0);
32507c478bd9Sstevel@tonic-gate
32517c478bd9Sstevel@tonic-gate /* value */
32527c478bd9Sstevel@tonic-gate if ((buf = NVP_VALUE(nvp)) >= buf_end)
32537c478bd9Sstevel@tonic-gate return (EFAULT);
32547c478bd9Sstevel@tonic-gate buflen = buf_end - buf;
32557c478bd9Sstevel@tonic-gate
32567c478bd9Sstevel@tonic-gate if (buflen < value_sz)
32577c478bd9Sstevel@tonic-gate return (EFAULT);
32587c478bd9Sstevel@tonic-gate
32597c478bd9Sstevel@tonic-gate switch (type) {
32607c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST:
32617c478bd9Sstevel@tonic-gate if (nvs_embedded(nvs, (void *)buf) == 0)
32627c478bd9Sstevel@tonic-gate return (0);
32637c478bd9Sstevel@tonic-gate break;
32647c478bd9Sstevel@tonic-gate
32657c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY:
32667c478bd9Sstevel@tonic-gate if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0)
32677c478bd9Sstevel@tonic-gate return (0);
32687c478bd9Sstevel@tonic-gate break;
32697c478bd9Sstevel@tonic-gate
32707c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
32717c478bd9Sstevel@tonic-gate ret = TRUE;
32727c478bd9Sstevel@tonic-gate break;
32737c478bd9Sstevel@tonic-gate
32747c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE:
32757c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8:
32767c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8:
32777c478bd9Sstevel@tonic-gate ret = xdr_char(xdr, buf);
32787c478bd9Sstevel@tonic-gate break;
32797c478bd9Sstevel@tonic-gate
32807c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16:
32817c478bd9Sstevel@tonic-gate ret = xdr_short(xdr, (void *)buf);
32827c478bd9Sstevel@tonic-gate break;
32837c478bd9Sstevel@tonic-gate
32847c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16:
32857c478bd9Sstevel@tonic-gate ret = xdr_u_short(xdr, (void *)buf);
32867c478bd9Sstevel@tonic-gate break;
32877c478bd9Sstevel@tonic-gate
32887c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE:
32897c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32:
32907c478bd9Sstevel@tonic-gate ret = xdr_int(xdr, (void *)buf);
32917c478bd9Sstevel@tonic-gate break;
32927c478bd9Sstevel@tonic-gate
32937c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32:
32947c478bd9Sstevel@tonic-gate ret = xdr_u_int(xdr, (void *)buf);
32957c478bd9Sstevel@tonic-gate break;
32967c478bd9Sstevel@tonic-gate
32977c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64:
32987c478bd9Sstevel@tonic-gate ret = xdr_longlong_t(xdr, (void *)buf);
32997c478bd9Sstevel@tonic-gate break;
33007c478bd9Sstevel@tonic-gate
33017c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64:
33027c478bd9Sstevel@tonic-gate ret = xdr_u_longlong_t(xdr, (void *)buf);
33037c478bd9Sstevel@tonic-gate break;
33047c478bd9Sstevel@tonic-gate
33057c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME:
33067c478bd9Sstevel@tonic-gate /*
33077c478bd9Sstevel@tonic-gate * NOTE: must expose the definition of hrtime_t here
33087c478bd9Sstevel@tonic-gate */
33097c478bd9Sstevel@tonic-gate ret = xdr_longlong_t(xdr, (void *)buf);
33107c478bd9Sstevel@tonic-gate break;
3311825ba0f2Srobj #if !defined(_KERNEL)
3312825ba0f2Srobj case DATA_TYPE_DOUBLE:
3313825ba0f2Srobj ret = xdr_double(xdr, (void *)buf);
3314825ba0f2Srobj break;
3315825ba0f2Srobj #endif
33167c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING:
33177c478bd9Sstevel@tonic-gate ret = xdr_string(xdr, &buf, buflen - 1);
33187c478bd9Sstevel@tonic-gate break;
33197c478bd9Sstevel@tonic-gate
33207c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY:
33217c478bd9Sstevel@tonic-gate ret = xdr_opaque(xdr, buf, nelem);
33227c478bd9Sstevel@tonic-gate break;
33237c478bd9Sstevel@tonic-gate
33247c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY:
33257c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY:
33267c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t),
33277c478bd9Sstevel@tonic-gate (xdrproc_t)xdr_char);
33287c478bd9Sstevel@tonic-gate break;
33297c478bd9Sstevel@tonic-gate
33307c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY:
33317c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t),
33327c478bd9Sstevel@tonic-gate sizeof (int16_t), (xdrproc_t)xdr_short);
33337c478bd9Sstevel@tonic-gate break;
33347c478bd9Sstevel@tonic-gate
33357c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY:
33367c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t),
33377c478bd9Sstevel@tonic-gate sizeof (uint16_t), (xdrproc_t)xdr_u_short);
33387c478bd9Sstevel@tonic-gate break;
33397c478bd9Sstevel@tonic-gate
33407c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY:
33417c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY:
33427c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t),
33437c478bd9Sstevel@tonic-gate sizeof (int32_t), (xdrproc_t)xdr_int);
33447c478bd9Sstevel@tonic-gate break;
33457c478bd9Sstevel@tonic-gate
33467c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY:
33477c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t),
33487c478bd9Sstevel@tonic-gate sizeof (uint32_t), (xdrproc_t)xdr_u_int);
33497c478bd9Sstevel@tonic-gate break;
33507c478bd9Sstevel@tonic-gate
33517c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY:
33527c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t),
33537c478bd9Sstevel@tonic-gate sizeof (int64_t), (xdrproc_t)xdr_longlong_t);
33547c478bd9Sstevel@tonic-gate break;
33557c478bd9Sstevel@tonic-gate
33567c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY:
33577c478bd9Sstevel@tonic-gate ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t),
33587c478bd9Sstevel@tonic-gate sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t);
33597c478bd9Sstevel@tonic-gate break;
33607c478bd9Sstevel@tonic-gate
33617c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: {
33627c478bd9Sstevel@tonic-gate size_t len = nelem * sizeof (uint64_t);
33637c478bd9Sstevel@tonic-gate char **strp = (void *)buf;
33647c478bd9Sstevel@tonic-gate int i;
33657c478bd9Sstevel@tonic-gate
33667c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_DECODE)
33677c478bd9Sstevel@tonic-gate bzero(buf, len); /* don't trust packed data */
33687c478bd9Sstevel@tonic-gate
33697c478bd9Sstevel@tonic-gate for (i = 0; i < nelem; i++) {
33707c478bd9Sstevel@tonic-gate if (buflen <= len)
33717c478bd9Sstevel@tonic-gate return (EFAULT);
33727c478bd9Sstevel@tonic-gate
33737c478bd9Sstevel@tonic-gate buf += len;
33747c478bd9Sstevel@tonic-gate buflen -= len;
33757c478bd9Sstevel@tonic-gate
33767c478bd9Sstevel@tonic-gate if (xdr_string(xdr, &buf, buflen - 1) != TRUE)
33777c478bd9Sstevel@tonic-gate return (EFAULT);
33787c478bd9Sstevel@tonic-gate
33797c478bd9Sstevel@tonic-gate if (nvs->nvs_op == NVS_OP_DECODE)
33807c478bd9Sstevel@tonic-gate strp[i] = buf;
33817c478bd9Sstevel@tonic-gate len = strlen(buf) + 1;
33827c478bd9Sstevel@tonic-gate }
33837c478bd9Sstevel@tonic-gate ret = TRUE;
33847c478bd9Sstevel@tonic-gate break;
33857c478bd9Sstevel@tonic-gate }
33867c478bd9Sstevel@tonic-gate default:
33877c478bd9Sstevel@tonic-gate break;
33887c478bd9Sstevel@tonic-gate }
33897c478bd9Sstevel@tonic-gate
33907c478bd9Sstevel@tonic-gate return (ret == TRUE ? 0 : EFAULT);
33917c478bd9Sstevel@tonic-gate }
33927c478bd9Sstevel@tonic-gate
33937c478bd9Sstevel@tonic-gate static int
nvs_xdr_nvp_size(nvstream_t * nvs,nvpair_t * nvp,size_t * size)33947c478bd9Sstevel@tonic-gate nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
33957c478bd9Sstevel@tonic-gate {
33967c478bd9Sstevel@tonic-gate data_type_t type = NVP_TYPE(nvp);
33977c478bd9Sstevel@tonic-gate /*
33987c478bd9Sstevel@tonic-gate * encode_size + decode_size + name string size + data type + nelem
33997c478bd9Sstevel@tonic-gate * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))
34007c478bd9Sstevel@tonic-gate */
34017c478bd9Sstevel@tonic-gate uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4;
34027c478bd9Sstevel@tonic-gate
34037c478bd9Sstevel@tonic-gate switch (type) {
34047c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN:
34057c478bd9Sstevel@tonic-gate break;
34067c478bd9Sstevel@tonic-gate
34077c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_VALUE:
34087c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE:
34097c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8:
34107c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8:
34117c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16:
34127c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16:
34137c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32:
34147c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32:
34157c478bd9Sstevel@tonic-gate nvp_sz += 4; /* 4 is the minimum xdr unit */
34167c478bd9Sstevel@tonic-gate break;
34177c478bd9Sstevel@tonic-gate
34187c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64:
34197c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64:
34207c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME:
3421825ba0f2Srobj #if !defined(_KERNEL)
3422825ba0f2Srobj case DATA_TYPE_DOUBLE:
3423825ba0f2Srobj #endif
34247c478bd9Sstevel@tonic-gate nvp_sz += 8;
34257c478bd9Sstevel@tonic-gate break;
34267c478bd9Sstevel@tonic-gate
34277c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING:
34287c478bd9Sstevel@tonic-gate nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp)));
34297c478bd9Sstevel@tonic-gate break;
34307c478bd9Sstevel@tonic-gate
34317c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY:
34327c478bd9Sstevel@tonic-gate nvp_sz += NV_ALIGN4(NVP_NELEM(nvp));
34337c478bd9Sstevel@tonic-gate break;
34347c478bd9Sstevel@tonic-gate
34357c478bd9Sstevel@tonic-gate case DATA_TYPE_BOOLEAN_ARRAY:
34367c478bd9Sstevel@tonic-gate case DATA_TYPE_INT8_ARRAY:
34377c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT8_ARRAY:
34387c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16_ARRAY:
34397c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16_ARRAY:
34407c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32_ARRAY:
34417c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32_ARRAY:
34427c478bd9Sstevel@tonic-gate nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp);
34437c478bd9Sstevel@tonic-gate break;
34447c478bd9Sstevel@tonic-gate
34457c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64_ARRAY:
34467c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64_ARRAY:
34477c478bd9Sstevel@tonic-gate nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp);
34487c478bd9Sstevel@tonic-gate break;
34497c478bd9Sstevel@tonic-gate
34507c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING_ARRAY: {
34517c478bd9Sstevel@tonic-gate int i;
34527c478bd9Sstevel@tonic-gate char **strs = (void *)NVP_VALUE(nvp);
34537c478bd9Sstevel@tonic-gate
34547c478bd9Sstevel@tonic-gate for (i = 0; i < NVP_NELEM(nvp); i++)
34557c478bd9Sstevel@tonic-gate nvp_sz += 4 + NV_ALIGN4(strlen(strs[i]));
34567c478bd9Sstevel@tonic-gate
34577c478bd9Sstevel@tonic-gate break;
34587c478bd9Sstevel@tonic-gate }
34597c478bd9Sstevel@tonic-gate
34607c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST:
34617c478bd9Sstevel@tonic-gate case DATA_TYPE_NVLIST_ARRAY: {
34627c478bd9Sstevel@tonic-gate size_t nvsize = 0;
34637c478bd9Sstevel@tonic-gate int old_nvs_op = nvs->nvs_op;
34647c478bd9Sstevel@tonic-gate int err;
34657c478bd9Sstevel@tonic-gate
34667c478bd9Sstevel@tonic-gate nvs->nvs_op = NVS_OP_GETSIZE;
34677c478bd9Sstevel@tonic-gate if (type == DATA_TYPE_NVLIST)
34687c478bd9Sstevel@tonic-gate err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize);
34697c478bd9Sstevel@tonic-gate else
34707c478bd9Sstevel@tonic-gate err = nvs_embedded_nvl_array(nvs, nvp, &nvsize);
34717c478bd9Sstevel@tonic-gate nvs->nvs_op = old_nvs_op;
34727c478bd9Sstevel@tonic-gate
34737c478bd9Sstevel@tonic-gate if (err != 0)
34747c478bd9Sstevel@tonic-gate return (EINVAL);
34757c478bd9Sstevel@tonic-gate
34767c478bd9Sstevel@tonic-gate nvp_sz += nvsize;
34777c478bd9Sstevel@tonic-gate break;
34787c478bd9Sstevel@tonic-gate }
34797c478bd9Sstevel@tonic-gate
34807c478bd9Sstevel@tonic-gate default:
34817c478bd9Sstevel@tonic-gate return (EINVAL);
34827c478bd9Sstevel@tonic-gate }
34837c478bd9Sstevel@tonic-gate
34847c478bd9Sstevel@tonic-gate if (nvp_sz > INT32_MAX)
34857c478bd9Sstevel@tonic-gate return (EINVAL);
34867c478bd9Sstevel@tonic-gate
34877c478bd9Sstevel@tonic-gate *size = nvp_sz;
34887c478bd9Sstevel@tonic-gate
34897c478bd9Sstevel@tonic-gate return (0);
34907c478bd9Sstevel@tonic-gate }
34917c478bd9Sstevel@tonic-gate
34927c478bd9Sstevel@tonic-gate
34937c478bd9Sstevel@tonic-gate /*
34947c478bd9Sstevel@tonic-gate * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates
34957c478bd9Sstevel@tonic-gate * the largest nvpair that could be encoded in the buffer.
34967c478bd9Sstevel@tonic-gate *
34977c478bd9Sstevel@tonic-gate * See comments above nvpair_xdr_op() for the format of xdr encoding.
34987c478bd9Sstevel@tonic-gate * The size of a xdr packed nvpair without any data is 5 words.
34997c478bd9Sstevel@tonic-gate *
35007c478bd9Sstevel@tonic-gate * Using the size of the data directly as an estimate would be ok
35017c478bd9Sstevel@tonic-gate * in all cases except one. If the data type is of DATA_TYPE_STRING_ARRAY
35027c478bd9Sstevel@tonic-gate * then the actual nvpair has space for an array of pointers to index
35037c478bd9Sstevel@tonic-gate * the strings. These pointers are not encoded into the packed xdr buffer.
35047c478bd9Sstevel@tonic-gate *
35057c478bd9Sstevel@tonic-gate * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are
35067c478bd9Sstevel@tonic-gate * of length 0, then each string is endcoded in xdr format as a single word.
35077c478bd9Sstevel@tonic-gate * Therefore when expanded to an nvpair there will be 2.25 word used for
35087c478bd9Sstevel@tonic-gate * each string. (a int64_t allocated for pointer usage, and a single char
35097c478bd9Sstevel@tonic-gate * for the null termination.)
35107c478bd9Sstevel@tonic-gate *
35117c478bd9Sstevel@tonic-gate * This is the calculation performed by the NVS_XDR_MAX_LEN macro.
35127c478bd9Sstevel@tonic-gate */
35137c478bd9Sstevel@tonic-gate #define NVS_XDR_HDR_LEN ((size_t)(5 * 4))
35147c478bd9Sstevel@tonic-gate #define NVS_XDR_DATA_LEN(y) (((size_t)(y) <= NVS_XDR_HDR_LEN) ? \
35157c478bd9Sstevel@tonic-gate 0 : ((size_t)(y) - NVS_XDR_HDR_LEN))
35167c478bd9Sstevel@tonic-gate #define NVS_XDR_MAX_LEN(x) (NVP_SIZE_CALC(1, 0) + \
35177c478bd9Sstevel@tonic-gate (NVS_XDR_DATA_LEN(x) * 2) + \
35187c478bd9Sstevel@tonic-gate NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4)))
35197c478bd9Sstevel@tonic-gate
35207c478bd9Sstevel@tonic-gate static int
nvs_xdr_nvpair(nvstream_t * nvs,nvpair_t * nvp,size_t * size)35217c478bd9Sstevel@tonic-gate nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
35227c478bd9Sstevel@tonic-gate {
35237c478bd9Sstevel@tonic-gate XDR *xdr = nvs->nvs_private;
35247c478bd9Sstevel@tonic-gate int32_t encode_len, decode_len;
35257c478bd9Sstevel@tonic-gate
35267c478bd9Sstevel@tonic-gate switch (nvs->nvs_op) {
35277c478bd9Sstevel@tonic-gate case NVS_OP_ENCODE: {
35287c478bd9Sstevel@tonic-gate size_t nvsize;
35297c478bd9Sstevel@tonic-gate
35307c478bd9Sstevel@tonic-gate if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0)
35317c478bd9Sstevel@tonic-gate return (EFAULT);
35327c478bd9Sstevel@tonic-gate
35337c478bd9Sstevel@tonic-gate decode_len = nvp->nvp_size;
35347c478bd9Sstevel@tonic-gate encode_len = nvsize;
35357c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
35367c478bd9Sstevel@tonic-gate return (EFAULT);
35377c478bd9Sstevel@tonic-gate
35387c478bd9Sstevel@tonic-gate return (nvs_xdr_nvp_op(nvs, nvp));
35397c478bd9Sstevel@tonic-gate }
35407c478bd9Sstevel@tonic-gate case NVS_OP_DECODE: {
35417c478bd9Sstevel@tonic-gate struct xdr_bytesrec bytesrec;
35427c478bd9Sstevel@tonic-gate
35437c478bd9Sstevel@tonic-gate /* get the encode and decode size */
35447c478bd9Sstevel@tonic-gate if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
35457c478bd9Sstevel@tonic-gate return (EFAULT);
35467c478bd9Sstevel@tonic-gate *size = decode_len;
35477c478bd9Sstevel@tonic-gate
35487c478bd9Sstevel@tonic-gate /* are we at the end of the stream? */
35497c478bd9Sstevel@tonic-gate if (*size == 0)
35507c478bd9Sstevel@tonic-gate return (0);
35517c478bd9Sstevel@tonic-gate
35527c478bd9Sstevel@tonic-gate /* sanity check the size parameter */
35537c478bd9Sstevel@tonic-gate if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec))
35547c478bd9Sstevel@tonic-gate return (EFAULT);
35557c478bd9Sstevel@tonic-gate
35567c478bd9Sstevel@tonic-gate if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail))
35577c478bd9Sstevel@tonic-gate return (EFAULT);
35587c478bd9Sstevel@tonic-gate break;
35597c478bd9Sstevel@tonic-gate }
35607c478bd9Sstevel@tonic-gate
35617c478bd9Sstevel@tonic-gate default:
35627c478bd9Sstevel@tonic-gate return (EINVAL);
35637c478bd9Sstevel@tonic-gate }
35647c478bd9Sstevel@tonic-gate return (0);
35657c478bd9Sstevel@tonic-gate }
35667c478bd9Sstevel@tonic-gate
35677c478bd9Sstevel@tonic-gate static const struct nvs_ops nvs_xdr_ops = {
35687c478bd9Sstevel@tonic-gate nvs_xdr_nvlist,
35697c478bd9Sstevel@tonic-gate nvs_xdr_nvpair,
35707c478bd9Sstevel@tonic-gate nvs_xdr_nvp_op,
35717c478bd9Sstevel@tonic-gate nvs_xdr_nvp_size,
35727c478bd9Sstevel@tonic-gate nvs_xdr_nvl_fini
35737c478bd9Sstevel@tonic-gate };
35747c478bd9Sstevel@tonic-gate
35757c478bd9Sstevel@tonic-gate static int
nvs_xdr(nvstream_t * nvs,nvlist_t * nvl,char * buf,size_t * buflen)35767c478bd9Sstevel@tonic-gate nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
35777c478bd9Sstevel@tonic-gate {
35787c478bd9Sstevel@tonic-gate XDR xdr;
35797c478bd9Sstevel@tonic-gate int err;
35807c478bd9Sstevel@tonic-gate
35817c478bd9Sstevel@tonic-gate nvs->nvs_ops = &nvs_xdr_ops;
35827c478bd9Sstevel@tonic-gate
35837c478bd9Sstevel@tonic-gate if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t),
35847c478bd9Sstevel@tonic-gate *buflen - sizeof (nvs_header_t))) != 0)
35857c478bd9Sstevel@tonic-gate return (err);
35867c478bd9Sstevel@tonic-gate
35877c478bd9Sstevel@tonic-gate err = nvs_operation(nvs, nvl, buflen);
35887c478bd9Sstevel@tonic-gate
35897c478bd9Sstevel@tonic-gate nvs_xdr_destroy(nvs);
35907c478bd9Sstevel@tonic-gate
35917c478bd9Sstevel@tonic-gate return (err);
35927c478bd9Sstevel@tonic-gate }
3593