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