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