xref: /titanic_53/usr/src/common/nvpair/nvpair.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/int_limits.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/nvpair.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/nvpair_impl.h>
35*7c478bd9Sstevel@tonic-gate #include <rpc/types.h>
36*7c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
39*7c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
40*7c478bd9Sstevel@tonic-gate #else
41*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
42*7c478bd9Sstevel@tonic-gate #include <strings.h>
43*7c478bd9Sstevel@tonic-gate #endif
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #ifndef	offsetof
46*7c478bd9Sstevel@tonic-gate #define	offsetof(s, m)	((size_t)(&(((s *)0)->m)))
47*7c478bd9Sstevel@tonic-gate #endif
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate /*
51*7c478bd9Sstevel@tonic-gate  * nvpair.c - Provides kernel & userland interfaces for manipulating
52*7c478bd9Sstevel@tonic-gate  *	name-value pairs.
53*7c478bd9Sstevel@tonic-gate  *
54*7c478bd9Sstevel@tonic-gate  * Overview Diagram
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  *  +--------------+
57*7c478bd9Sstevel@tonic-gate  *  |  nvlist_t    |
58*7c478bd9Sstevel@tonic-gate  *  |--------------|
59*7c478bd9Sstevel@tonic-gate  *  | nvl_version  |
60*7c478bd9Sstevel@tonic-gate  *  | nvl_nvflag   |
61*7c478bd9Sstevel@tonic-gate  *  | nvl_priv    -+-+
62*7c478bd9Sstevel@tonic-gate  *  | nvl_flag     | |
63*7c478bd9Sstevel@tonic-gate  *  | nvl_pad      | |
64*7c478bd9Sstevel@tonic-gate  *  +--------------+ |
65*7c478bd9Sstevel@tonic-gate  *                   V
66*7c478bd9Sstevel@tonic-gate  *      +--------------+      last i_nvp in list
67*7c478bd9Sstevel@tonic-gate  *      | nvpriv_t     |  +--------------------->
68*7c478bd9Sstevel@tonic-gate  *      |--------------|  |
69*7c478bd9Sstevel@tonic-gate  *   +--+- nvp_list    |  |   +------------+
70*7c478bd9Sstevel@tonic-gate  *   |  |  nvp_last   -+--+   + nv_alloc_t |
71*7c478bd9Sstevel@tonic-gate  *   |  |  nvp_curr    |      |------------|
72*7c478bd9Sstevel@tonic-gate  *   |  |  nvp_nva    -+----> | nva_ops    |
73*7c478bd9Sstevel@tonic-gate  *   |  |  nvp_stat    |      | nva_arg    |
74*7c478bd9Sstevel@tonic-gate  *   |  +--------------+      +------------+
75*7c478bd9Sstevel@tonic-gate  *   |
76*7c478bd9Sstevel@tonic-gate  *   +-------+
77*7c478bd9Sstevel@tonic-gate  *           V
78*7c478bd9Sstevel@tonic-gate  *   +---------------------+      +-------------------+
79*7c478bd9Sstevel@tonic-gate  *   |  i_nvp_t            |  +-->|  i_nvp_t          |  +-->
80*7c478bd9Sstevel@tonic-gate  *   |---------------------|  |   |-------------------|  |
81*7c478bd9Sstevel@tonic-gate  *   | nvi_next           -+--+   | nvi_next         -+--+
82*7c478bd9Sstevel@tonic-gate  *   | nvi_prev (NULL)     | <----+ nvi_prev          |
83*7c478bd9Sstevel@tonic-gate  *   | . . . . . . . . . . |      | . . . . . . . . . |
84*7c478bd9Sstevel@tonic-gate  *   | nvp (nvpair_t)      |      | nvp (nvpair_t)    |
85*7c478bd9Sstevel@tonic-gate  *   |  - nvp_size         |      |  - nvp_size       |
86*7c478bd9Sstevel@tonic-gate  *   |  - nvp_name_sz      |      |  - nvp_name_sz    |
87*7c478bd9Sstevel@tonic-gate  *   |  - nvp_value_elem   |      |  - nvp_value_elem |
88*7c478bd9Sstevel@tonic-gate  *   |  - nvp_type         |      |  - nvp_type       |
89*7c478bd9Sstevel@tonic-gate  *   |  - data ...         |      |  - data ...       |
90*7c478bd9Sstevel@tonic-gate  *   +---------------------+      +-------------------+
91*7c478bd9Sstevel@tonic-gate  *
92*7c478bd9Sstevel@tonic-gate  *
93*7c478bd9Sstevel@tonic-gate  *
94*7c478bd9Sstevel@tonic-gate  *   +---------------------+              +---------------------+
95*7c478bd9Sstevel@tonic-gate  *   |  i_nvp_t            |  +-->    +-->|  i_nvp_t (last)     |
96*7c478bd9Sstevel@tonic-gate  *   |---------------------|  |       |   |---------------------|
97*7c478bd9Sstevel@tonic-gate  *   |  nvi_next          -+--+ ... --+   | nvi_next (NULL)     |
98*7c478bd9Sstevel@tonic-gate  * <-+- nvi_prev           |<-- ...  <----+ nvi_prev            |
99*7c478bd9Sstevel@tonic-gate  *   | . . . . . . . . .   |              | . . . . . . . . .   |
100*7c478bd9Sstevel@tonic-gate  *   | nvp (nvpair_t)      |              | nvp (nvpair_t)      |
101*7c478bd9Sstevel@tonic-gate  *   |  - nvp_size         |              |  - nvp_size         |
102*7c478bd9Sstevel@tonic-gate  *   |  - nvp_name_sz      |              |  - nvp_name_sz      |
103*7c478bd9Sstevel@tonic-gate  *   |  - nvp_value_elem   |              |  - nvp_value_elem   |
104*7c478bd9Sstevel@tonic-gate  *   |  - DATA_TYPE_NVLIST |              |  - nvp_type         |
105*7c478bd9Sstevel@tonic-gate  *   |  - data (embedded)  |              |  - data ...         |
106*7c478bd9Sstevel@tonic-gate  *   |    nvlist name      |              +---------------------+
107*7c478bd9Sstevel@tonic-gate  *   |  +--------------+   |
108*7c478bd9Sstevel@tonic-gate  *   |  |  nvlist_t    |   |
109*7c478bd9Sstevel@tonic-gate  *   |  |--------------|   |
110*7c478bd9Sstevel@tonic-gate  *   |  | nvl_version  |   |
111*7c478bd9Sstevel@tonic-gate  *   |  | nvl_nvflag   |   |
112*7c478bd9Sstevel@tonic-gate  *   |  | nvl_priv   --+---+---->
113*7c478bd9Sstevel@tonic-gate  *   |  | nvl_flag     |   |
114*7c478bd9Sstevel@tonic-gate  *   |  | nvl_pad      |   |
115*7c478bd9Sstevel@tonic-gate  *   |  +--------------+   |
116*7c478bd9Sstevel@tonic-gate  *   +---------------------+
117*7c478bd9Sstevel@tonic-gate  *
118*7c478bd9Sstevel@tonic-gate  *
119*7c478bd9Sstevel@tonic-gate  * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will
120*7c478bd9Sstevel@tonic-gate  * allow value to be aligned on 8 byte boundary
121*7c478bd9Sstevel@tonic-gate  *
122*7c478bd9Sstevel@tonic-gate  * name_len is the length of the name string including the null terminator
123*7c478bd9Sstevel@tonic-gate  * so it must be >= 1
124*7c478bd9Sstevel@tonic-gate  */
125*7c478bd9Sstevel@tonic-gate #define	NVP_SIZE_CALC(name_len, data_len) \
126*7c478bd9Sstevel@tonic-gate 	(NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate static int i_get_value_size(data_type_t type, const void *data, uint_t nelem);
129*7c478bd9Sstevel@tonic-gate static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
130*7c478bd9Sstevel@tonic-gate     uint_t nelem, const void *data);
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate #define	NV_STAT_EMBEDDED	0x1
133*7c478bd9Sstevel@tonic-gate #define	EMBEDDED_NVL(nvp)	((nvlist_t *)(void *)NVP_VALUE(nvp))
134*7c478bd9Sstevel@tonic-gate #define	EMBEDDED_NVL_ARRAY(nvp)	((nvlist_t **)(void *)NVP_VALUE(nvp))
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate #define	NVP_VALOFF(nvp)	(NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))
137*7c478bd9Sstevel@tonic-gate #define	NVPAIR2I_NVP(nvp) \
138*7c478bd9Sstevel@tonic-gate 	((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate int
142*7c478bd9Sstevel@tonic-gate nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)
143*7c478bd9Sstevel@tonic-gate {
144*7c478bd9Sstevel@tonic-gate 	va_list valist;
145*7c478bd9Sstevel@tonic-gate 	int err = 0;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	nva->nva_ops = nvo;
148*7c478bd9Sstevel@tonic-gate 	nva->nva_arg = NULL;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	va_start(valist, nvo);
151*7c478bd9Sstevel@tonic-gate 	if (nva->nva_ops->nv_ao_init != NULL)
152*7c478bd9Sstevel@tonic-gate 		err = nva->nva_ops->nv_ao_init(nva, valist);
153*7c478bd9Sstevel@tonic-gate 	va_end(valist);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	return (err);
156*7c478bd9Sstevel@tonic-gate }
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate void
159*7c478bd9Sstevel@tonic-gate nv_alloc_reset(nv_alloc_t *nva)
160*7c478bd9Sstevel@tonic-gate {
161*7c478bd9Sstevel@tonic-gate 	if (nva->nva_ops->nv_ao_reset != NULL)
162*7c478bd9Sstevel@tonic-gate 		nva->nva_ops->nv_ao_reset(nva);
163*7c478bd9Sstevel@tonic-gate }
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate void
166*7c478bd9Sstevel@tonic-gate nv_alloc_fini(nv_alloc_t *nva)
167*7c478bd9Sstevel@tonic-gate {
168*7c478bd9Sstevel@tonic-gate 	if (nva->nva_ops->nv_ao_fini != NULL)
169*7c478bd9Sstevel@tonic-gate 		nva->nva_ops->nv_ao_fini(nva);
170*7c478bd9Sstevel@tonic-gate }
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate nv_alloc_t *
173*7c478bd9Sstevel@tonic-gate nvlist_lookup_nv_alloc(nvlist_t *nvl)
174*7c478bd9Sstevel@tonic-gate {
175*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL ||
178*7c478bd9Sstevel@tonic-gate 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
179*7c478bd9Sstevel@tonic-gate 		return (NULL);
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	return (priv->nvp_nva);
182*7c478bd9Sstevel@tonic-gate }
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate static void *
185*7c478bd9Sstevel@tonic-gate nv_mem_zalloc(nvpriv_t *nvp, size_t size)
186*7c478bd9Sstevel@tonic-gate {
187*7c478bd9Sstevel@tonic-gate 	nv_alloc_t *nva = nvp->nvp_nva;
188*7c478bd9Sstevel@tonic-gate 	void *buf;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)
191*7c478bd9Sstevel@tonic-gate 		bzero(buf, size);
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	return (buf);
194*7c478bd9Sstevel@tonic-gate }
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate static void
197*7c478bd9Sstevel@tonic-gate nv_mem_free(nvpriv_t *nvp, void *buf, size_t size)
198*7c478bd9Sstevel@tonic-gate {
199*7c478bd9Sstevel@tonic-gate 	nv_alloc_t *nva = nvp->nvp_nva;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	nva->nva_ops->nv_ao_free(nva, buf, size);
202*7c478bd9Sstevel@tonic-gate }
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate static void
205*7c478bd9Sstevel@tonic-gate nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)
206*7c478bd9Sstevel@tonic-gate {
207*7c478bd9Sstevel@tonic-gate 	bzero(priv, sizeof (priv));
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	priv->nvp_nva = nva;
210*7c478bd9Sstevel@tonic-gate 	priv->nvp_stat = stat;
211*7c478bd9Sstevel@tonic-gate }
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate static nvpriv_t *
214*7c478bd9Sstevel@tonic-gate nv_priv_alloc(nv_alloc_t *nva)
215*7c478bd9Sstevel@tonic-gate {
216*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	/*
219*7c478bd9Sstevel@tonic-gate 	 * nv_mem_alloc() cannot called here because it needs the priv
220*7c478bd9Sstevel@tonic-gate 	 * argument.
221*7c478bd9Sstevel@tonic-gate 	 */
222*7c478bd9Sstevel@tonic-gate 	if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)
223*7c478bd9Sstevel@tonic-gate 		return (NULL);
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	nv_priv_init(priv, nva, 0);
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	return (priv);
228*7c478bd9Sstevel@tonic-gate }
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate /*
231*7c478bd9Sstevel@tonic-gate  * Embedded lists need their own nvpriv_t's.  We create a new
232*7c478bd9Sstevel@tonic-gate  * nvpriv_t using the parameters and allocator from the parent
233*7c478bd9Sstevel@tonic-gate  * list's nvpriv_t.
234*7c478bd9Sstevel@tonic-gate  */
235*7c478bd9Sstevel@tonic-gate static nvpriv_t *
236*7c478bd9Sstevel@tonic-gate nv_priv_alloc_embedded(nvpriv_t *priv)
237*7c478bd9Sstevel@tonic-gate {
238*7c478bd9Sstevel@tonic-gate 	nvpriv_t *emb_priv;
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)
241*7c478bd9Sstevel@tonic-gate 		return (NULL);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	return (emb_priv);
246*7c478bd9Sstevel@tonic-gate }
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate static void
249*7c478bd9Sstevel@tonic-gate nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)
250*7c478bd9Sstevel@tonic-gate {
251*7c478bd9Sstevel@tonic-gate 	nvl->nvl_version = NV_VERSION;
252*7c478bd9Sstevel@tonic-gate 	nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);
253*7c478bd9Sstevel@tonic-gate 	nvl->nvl_priv = (uint64_t)(uintptr_t)priv;
254*7c478bd9Sstevel@tonic-gate 	nvl->nvl_flag = 0;
255*7c478bd9Sstevel@tonic-gate 	nvl->nvl_pad = 0;
256*7c478bd9Sstevel@tonic-gate }
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate /*
259*7c478bd9Sstevel@tonic-gate  * nvlist_alloc - Allocate nvlist.
260*7c478bd9Sstevel@tonic-gate  */
261*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
262*7c478bd9Sstevel@tonic-gate int
263*7c478bd9Sstevel@tonic-gate nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)
264*7c478bd9Sstevel@tonic-gate {
265*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
266*7c478bd9Sstevel@tonic-gate 	return (nvlist_xalloc(nvlp, nvflag,
267*7c478bd9Sstevel@tonic-gate 	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
268*7c478bd9Sstevel@tonic-gate #else
269*7c478bd9Sstevel@tonic-gate 	return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep));
270*7c478bd9Sstevel@tonic-gate #endif
271*7c478bd9Sstevel@tonic-gate }
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate int
274*7c478bd9Sstevel@tonic-gate nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)
275*7c478bd9Sstevel@tonic-gate {
276*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	if (nvlp == NULL || nva == NULL)
279*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	if ((priv = nv_priv_alloc(nva)) == NULL)
282*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	if ((*nvlp = nv_mem_zalloc(priv,
285*7c478bd9Sstevel@tonic-gate 	    NV_ALIGN(sizeof (nvlist_t)))) == NULL) {
286*7c478bd9Sstevel@tonic-gate 		nv_mem_free(priv, priv, sizeof (nvpriv_t));
287*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	nvlist_init(*nvlp, nvflag, priv);
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	return (0);
293*7c478bd9Sstevel@tonic-gate }
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate /*
296*7c478bd9Sstevel@tonic-gate  * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
297*7c478bd9Sstevel@tonic-gate  */
298*7c478bd9Sstevel@tonic-gate static nvpair_t *
299*7c478bd9Sstevel@tonic-gate nvp_buf_alloc(nvlist_t *nvl, size_t len)
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
302*7c478bd9Sstevel@tonic-gate 	i_nvp_t *buf;
303*7c478bd9Sstevel@tonic-gate 	nvpair_t *nvp;
304*7c478bd9Sstevel@tonic-gate 	size_t nvsize;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	/*
307*7c478bd9Sstevel@tonic-gate 	 * Allocate the buffer
308*7c478bd9Sstevel@tonic-gate 	 */
309*7c478bd9Sstevel@tonic-gate 	nvsize = len + offsetof(i_nvp_t, nvi_nvp);
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)
312*7c478bd9Sstevel@tonic-gate 		return (NULL);
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	nvp = &buf->nvi_nvp;
315*7c478bd9Sstevel@tonic-gate 	nvp->nvp_size = len;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	return (nvp);
318*7c478bd9Sstevel@tonic-gate }
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate /*
321*7c478bd9Sstevel@tonic-gate  * nvp_buf_free - de-Allocate an i_nvp_t.
322*7c478bd9Sstevel@tonic-gate  */
323*7c478bd9Sstevel@tonic-gate static void
324*7c478bd9Sstevel@tonic-gate nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)
325*7c478bd9Sstevel@tonic-gate {
326*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
327*7c478bd9Sstevel@tonic-gate 	size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);
330*7c478bd9Sstevel@tonic-gate }
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate /*
333*7c478bd9Sstevel@tonic-gate  * nvp_buf_link - link a new nv pair into the nvlist.
334*7c478bd9Sstevel@tonic-gate  */
335*7c478bd9Sstevel@tonic-gate static void
336*7c478bd9Sstevel@tonic-gate nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)
337*7c478bd9Sstevel@tonic-gate {
338*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
339*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	/* Put element at end of nvlist */
342*7c478bd9Sstevel@tonic-gate 	if (priv->nvp_list == NULL) {
343*7c478bd9Sstevel@tonic-gate 		priv->nvp_list = priv->nvp_last = curr;
344*7c478bd9Sstevel@tonic-gate 	} else {
345*7c478bd9Sstevel@tonic-gate 		curr->nvi_prev = priv->nvp_last;
346*7c478bd9Sstevel@tonic-gate 		priv->nvp_last->nvi_next = curr;
347*7c478bd9Sstevel@tonic-gate 		priv->nvp_last = curr;
348*7c478bd9Sstevel@tonic-gate 	}
349*7c478bd9Sstevel@tonic-gate }
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate /*
352*7c478bd9Sstevel@tonic-gate  * nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate static void
355*7c478bd9Sstevel@tonic-gate nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)
356*7c478bd9Sstevel@tonic-gate {
357*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
358*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	/*
361*7c478bd9Sstevel@tonic-gate 	 * protect nvlist_next_nvpair() against walking on freed memory.
362*7c478bd9Sstevel@tonic-gate 	 */
363*7c478bd9Sstevel@tonic-gate 	if (priv->nvp_curr == curr)
364*7c478bd9Sstevel@tonic-gate 		priv->nvp_curr = curr->nvi_next;
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	if (curr == priv->nvp_list)
367*7c478bd9Sstevel@tonic-gate 		priv->nvp_list = curr->nvi_next;
368*7c478bd9Sstevel@tonic-gate 	else
369*7c478bd9Sstevel@tonic-gate 		curr->nvi_prev->nvi_next = curr->nvi_next;
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	if (curr == priv->nvp_last)
372*7c478bd9Sstevel@tonic-gate 		priv->nvp_last = curr->nvi_prev;
373*7c478bd9Sstevel@tonic-gate 	else
374*7c478bd9Sstevel@tonic-gate 		curr->nvi_next->nvi_prev = curr->nvi_prev;
375*7c478bd9Sstevel@tonic-gate }
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate /*
378*7c478bd9Sstevel@tonic-gate  * take a nvpair type and number of elements and make sure the are valid
379*7c478bd9Sstevel@tonic-gate  */
380*7c478bd9Sstevel@tonic-gate static int
381*7c478bd9Sstevel@tonic-gate i_validate_type_nelem(data_type_t type, uint_t nelem)
382*7c478bd9Sstevel@tonic-gate {
383*7c478bd9Sstevel@tonic-gate 	switch (type) {
384*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN:
385*7c478bd9Sstevel@tonic-gate 		if (nelem != 0)
386*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
387*7c478bd9Sstevel@tonic-gate 		break;
388*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_VALUE:
389*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE:
390*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8:
391*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8:
392*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16:
393*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16:
394*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32:
395*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32:
396*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64:
397*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64:
398*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING:
399*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_HRTIME:
400*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
401*7c478bd9Sstevel@tonic-gate 		if (nelem != 1)
402*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
403*7c478bd9Sstevel@tonic-gate 		break;
404*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_ARRAY:
405*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY:
406*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8_ARRAY:
407*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8_ARRAY:
408*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16_ARRAY:
409*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16_ARRAY:
410*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32_ARRAY:
411*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32_ARRAY:
412*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64_ARRAY:
413*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64_ARRAY:
414*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING_ARRAY:
415*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY:
416*7c478bd9Sstevel@tonic-gate 		/* we allow arrays with 0 elements */
417*7c478bd9Sstevel@tonic-gate 		break;
418*7c478bd9Sstevel@tonic-gate 	default:
419*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
420*7c478bd9Sstevel@tonic-gate 	}
421*7c478bd9Sstevel@tonic-gate 	return (0);
422*7c478bd9Sstevel@tonic-gate }
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate /*
425*7c478bd9Sstevel@tonic-gate  * Verify nvp_name_sz and check the name string length.
426*7c478bd9Sstevel@tonic-gate  */
427*7c478bd9Sstevel@tonic-gate static int
428*7c478bd9Sstevel@tonic-gate i_validate_nvpair_name(nvpair_t *nvp)
429*7c478bd9Sstevel@tonic-gate {
430*7c478bd9Sstevel@tonic-gate 	if ((nvp->nvp_name_sz <= 0) ||
431*7c478bd9Sstevel@tonic-gate 	    (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))
432*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	/* verify the name string, make sure its terminated */
435*7c478bd9Sstevel@tonic-gate 	if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')
436*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);
439*7c478bd9Sstevel@tonic-gate }
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate static int
442*7c478bd9Sstevel@tonic-gate i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)
443*7c478bd9Sstevel@tonic-gate {
444*7c478bd9Sstevel@tonic-gate 	switch (type) {
445*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_VALUE:
446*7c478bd9Sstevel@tonic-gate 		if (*(boolean_t *)data != B_TRUE &&
447*7c478bd9Sstevel@tonic-gate 		    *(boolean_t *)data != B_FALSE)
448*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
449*7c478bd9Sstevel@tonic-gate 		break;
450*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_ARRAY: {
451*7c478bd9Sstevel@tonic-gate 		int i;
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem; i++)
454*7c478bd9Sstevel@tonic-gate 			if (((boolean_t *)data)[i] != B_TRUE &&
455*7c478bd9Sstevel@tonic-gate 			    ((boolean_t *)data)[i] != B_FALSE)
456*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
457*7c478bd9Sstevel@tonic-gate 		break;
458*7c478bd9Sstevel@tonic-gate 	}
459*7c478bd9Sstevel@tonic-gate 	default:
460*7c478bd9Sstevel@tonic-gate 		break;
461*7c478bd9Sstevel@tonic-gate 	}
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	return (0);
464*7c478bd9Sstevel@tonic-gate }
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate /*
467*7c478bd9Sstevel@tonic-gate  * This function takes a pointer to what should be a nvpair and it's size
468*7c478bd9Sstevel@tonic-gate  * and then verifies that all the nvpair fields make sense and can be
469*7c478bd9Sstevel@tonic-gate  * trusted.  This function is used when decoding packed nvpairs.
470*7c478bd9Sstevel@tonic-gate  */
471*7c478bd9Sstevel@tonic-gate static int
472*7c478bd9Sstevel@tonic-gate i_validate_nvpair(nvpair_t *nvp)
473*7c478bd9Sstevel@tonic-gate {
474*7c478bd9Sstevel@tonic-gate 	data_type_t type = NVP_TYPE(nvp);
475*7c478bd9Sstevel@tonic-gate 	int size1, size2;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	/* verify nvp_name_sz, check the name string length */
478*7c478bd9Sstevel@tonic-gate 	if (i_validate_nvpair_name(nvp) != 0)
479*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)
482*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	/*
485*7c478bd9Sstevel@tonic-gate 	 * verify nvp_type, nvp_value_elem, and also possibly
486*7c478bd9Sstevel@tonic-gate 	 * verify string values and get the value size.
487*7c478bd9Sstevel@tonic-gate 	 */
488*7c478bd9Sstevel@tonic-gate 	size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));
489*7c478bd9Sstevel@tonic-gate 	size1 = nvp->nvp_size - NVP_VALOFF(nvp);
490*7c478bd9Sstevel@tonic-gate 	if (size2 < 0 || size1 != NV_ALIGN(size2))
491*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	return (0);
494*7c478bd9Sstevel@tonic-gate }
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate static int
497*7c478bd9Sstevel@tonic-gate nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl)
498*7c478bd9Sstevel@tonic-gate {
499*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
500*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)
503*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
506*7c478bd9Sstevel@tonic-gate 		nvpair_t *nvp = &curr->nvi_nvp;
507*7c478bd9Sstevel@tonic-gate 		int err;
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 		if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),
510*7c478bd9Sstevel@tonic-gate 		    NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)
511*7c478bd9Sstevel@tonic-gate 			return (err);
512*7c478bd9Sstevel@tonic-gate 	}
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	return (0);
515*7c478bd9Sstevel@tonic-gate }
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate /*
518*7c478bd9Sstevel@tonic-gate  * Frees all memory allocated for an nvpair (like embedded lists) with
519*7c478bd9Sstevel@tonic-gate  * the exception of the nvpair buffer itself.
520*7c478bd9Sstevel@tonic-gate  */
521*7c478bd9Sstevel@tonic-gate static void
522*7c478bd9Sstevel@tonic-gate nvpair_free(nvpair_t *nvp)
523*7c478bd9Sstevel@tonic-gate {
524*7c478bd9Sstevel@tonic-gate 	switch (NVP_TYPE(nvp)) {
525*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
526*7c478bd9Sstevel@tonic-gate 		nvlist_free(EMBEDDED_NVL(nvp));
527*7c478bd9Sstevel@tonic-gate 		break;
528*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY: {
529*7c478bd9Sstevel@tonic-gate 		nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
530*7c478bd9Sstevel@tonic-gate 		int i;
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < NVP_NELEM(nvp); i++)
533*7c478bd9Sstevel@tonic-gate 			if (nvlp[i] != NULL)
534*7c478bd9Sstevel@tonic-gate 				nvlist_free(nvlp[i]);
535*7c478bd9Sstevel@tonic-gate 		break;
536*7c478bd9Sstevel@tonic-gate 	}
537*7c478bd9Sstevel@tonic-gate 	default:
538*7c478bd9Sstevel@tonic-gate 		break;
539*7c478bd9Sstevel@tonic-gate 	}
540*7c478bd9Sstevel@tonic-gate }
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate /*
543*7c478bd9Sstevel@tonic-gate  * nvlist_free - free an unpacked nvlist
544*7c478bd9Sstevel@tonic-gate  */
545*7c478bd9Sstevel@tonic-gate void
546*7c478bd9Sstevel@tonic-gate nvlist_free(nvlist_t *nvl)
547*7c478bd9Sstevel@tonic-gate {
548*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
549*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL ||
552*7c478bd9Sstevel@tonic-gate 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
553*7c478bd9Sstevel@tonic-gate 		return;
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	/*
556*7c478bd9Sstevel@tonic-gate 	 * Unpacked nvlist are linked through i_nvp_t
557*7c478bd9Sstevel@tonic-gate 	 */
558*7c478bd9Sstevel@tonic-gate 	curr = priv->nvp_list;
559*7c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
560*7c478bd9Sstevel@tonic-gate 		nvpair_t *nvp = &curr->nvi_nvp;
561*7c478bd9Sstevel@tonic-gate 		curr = curr->nvi_next;
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 		nvpair_free(nvp);
564*7c478bd9Sstevel@tonic-gate 		nvp_buf_free(nvl, nvp);
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 	if (!(priv->nvp_stat & NV_STAT_EMBEDDED))
568*7c478bd9Sstevel@tonic-gate 		nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));
569*7c478bd9Sstevel@tonic-gate 	else
570*7c478bd9Sstevel@tonic-gate 		nvl->nvl_priv = NULL;
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	nv_mem_free(priv, priv, sizeof (nvpriv_t));
573*7c478bd9Sstevel@tonic-gate }
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate static int
576*7c478bd9Sstevel@tonic-gate nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp)
577*7c478bd9Sstevel@tonic-gate {
578*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
579*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	if (nvp == NULL)
582*7c478bd9Sstevel@tonic-gate 		return (0);
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
585*7c478bd9Sstevel@tonic-gate 		if (&curr->nvi_nvp == nvp)
586*7c478bd9Sstevel@tonic-gate 			return (1);
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	return (0);
589*7c478bd9Sstevel@tonic-gate }
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate /*
592*7c478bd9Sstevel@tonic-gate  * Make a copy of nvlist
593*7c478bd9Sstevel@tonic-gate  */
594*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
595*7c478bd9Sstevel@tonic-gate int
596*7c478bd9Sstevel@tonic-gate nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag)
597*7c478bd9Sstevel@tonic-gate {
598*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
599*7c478bd9Sstevel@tonic-gate 	return (nvlist_xdup(nvl, nvlp,
600*7c478bd9Sstevel@tonic-gate 	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
601*7c478bd9Sstevel@tonic-gate #else
602*7c478bd9Sstevel@tonic-gate 	return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep));
603*7c478bd9Sstevel@tonic-gate #endif
604*7c478bd9Sstevel@tonic-gate }
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate int
607*7c478bd9Sstevel@tonic-gate nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)
608*7c478bd9Sstevel@tonic-gate {
609*7c478bd9Sstevel@tonic-gate 	int err;
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL || nvlp == NULL)
612*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	if ((err = nvlist_xalloc(nvlp, nvl->nvl_nvflag, nva)) != 0)
615*7c478bd9Sstevel@tonic-gate 		return (err);
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	if ((err = nvlist_copy_pairs(nvl, *nvlp)) != 0)
618*7c478bd9Sstevel@tonic-gate 		nvlist_free(*nvlp);
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 	return (err);
621*7c478bd9Sstevel@tonic-gate }
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate /*
624*7c478bd9Sstevel@tonic-gate  * Remove all with matching name
625*7c478bd9Sstevel@tonic-gate  */
626*7c478bd9Sstevel@tonic-gate int
627*7c478bd9Sstevel@tonic-gate nvlist_remove_all(nvlist_t *nvl, const char *name)
628*7c478bd9Sstevel@tonic-gate {
629*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
630*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
631*7c478bd9Sstevel@tonic-gate 	int error = ENOENT;
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL || name == NULL ||
634*7c478bd9Sstevel@tonic-gate 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
635*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	curr = priv->nvp_list;
638*7c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
639*7c478bd9Sstevel@tonic-gate 		nvpair_t *nvp = &curr->nvi_nvp;
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 		curr = curr->nvi_next;
642*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, NVP_NAME(nvp)) != 0)
643*7c478bd9Sstevel@tonic-gate 			continue;
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 		nvp_buf_unlink(nvl, nvp);
646*7c478bd9Sstevel@tonic-gate 		nvpair_free(nvp);
647*7c478bd9Sstevel@tonic-gate 		nvp_buf_free(nvl, nvp);
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 		error = 0;
650*7c478bd9Sstevel@tonic-gate 	}
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	return (error);
653*7c478bd9Sstevel@tonic-gate }
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate /*
656*7c478bd9Sstevel@tonic-gate  * Remove first one with matching name and type
657*7c478bd9Sstevel@tonic-gate  */
658*7c478bd9Sstevel@tonic-gate int
659*7c478bd9Sstevel@tonic-gate nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
660*7c478bd9Sstevel@tonic-gate {
661*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
662*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL || name == NULL ||
665*7c478bd9Sstevel@tonic-gate 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
666*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	curr = priv->nvp_list;
669*7c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
670*7c478bd9Sstevel@tonic-gate 		nvpair_t *nvp = &curr->nvi_nvp;
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) {
673*7c478bd9Sstevel@tonic-gate 			nvp_buf_unlink(nvl, nvp);
674*7c478bd9Sstevel@tonic-gate 			nvpair_free(nvp);
675*7c478bd9Sstevel@tonic-gate 			nvp_buf_free(nvl, nvp);
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 			return (0);
678*7c478bd9Sstevel@tonic-gate 		}
679*7c478bd9Sstevel@tonic-gate 		curr = curr->nvi_next;
680*7c478bd9Sstevel@tonic-gate 	}
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 	return (ENOENT);
683*7c478bd9Sstevel@tonic-gate }
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate /*
686*7c478bd9Sstevel@tonic-gate  * This function calculates the size of an nvpair value.
687*7c478bd9Sstevel@tonic-gate  *
688*7c478bd9Sstevel@tonic-gate  * The data argument controls the behavior in case of the data types
689*7c478bd9Sstevel@tonic-gate  * 	DATA_TYPE_STRING    	and
690*7c478bd9Sstevel@tonic-gate  *	DATA_TYPE_STRING_ARRAY
691*7c478bd9Sstevel@tonic-gate  * Is data == NULL then the size of the string(s) is excluded.
692*7c478bd9Sstevel@tonic-gate  */
693*7c478bd9Sstevel@tonic-gate static int
694*7c478bd9Sstevel@tonic-gate i_get_value_size(data_type_t type, const void *data, uint_t nelem)
695*7c478bd9Sstevel@tonic-gate {
696*7c478bd9Sstevel@tonic-gate 	uint64_t value_sz;
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	if (i_validate_type_nelem(type, nelem) != 0)
699*7c478bd9Sstevel@tonic-gate 		return (-1);
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	/* Calculate required size for holding value */
702*7c478bd9Sstevel@tonic-gate 	switch (type) {
703*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN:
704*7c478bd9Sstevel@tonic-gate 		value_sz = 0;
705*7c478bd9Sstevel@tonic-gate 		break;
706*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_VALUE:
707*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (boolean_t);
708*7c478bd9Sstevel@tonic-gate 		break;
709*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE:
710*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (uchar_t);
711*7c478bd9Sstevel@tonic-gate 		break;
712*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8:
713*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (int8_t);
714*7c478bd9Sstevel@tonic-gate 		break;
715*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8:
716*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (uint8_t);
717*7c478bd9Sstevel@tonic-gate 		break;
718*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16:
719*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (int16_t);
720*7c478bd9Sstevel@tonic-gate 		break;
721*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16:
722*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (uint16_t);
723*7c478bd9Sstevel@tonic-gate 		break;
724*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32:
725*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (int32_t);
726*7c478bd9Sstevel@tonic-gate 		break;
727*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32:
728*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (uint32_t);
729*7c478bd9Sstevel@tonic-gate 		break;
730*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64:
731*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (int64_t);
732*7c478bd9Sstevel@tonic-gate 		break;
733*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64:
734*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (uint64_t);
735*7c478bd9Sstevel@tonic-gate 		break;
736*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING:
737*7c478bd9Sstevel@tonic-gate 		if (data == NULL)
738*7c478bd9Sstevel@tonic-gate 			value_sz = 0;
739*7c478bd9Sstevel@tonic-gate 		else
740*7c478bd9Sstevel@tonic-gate 			value_sz = strlen(data) + 1;
741*7c478bd9Sstevel@tonic-gate 		break;
742*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_ARRAY:
743*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (boolean_t);
744*7c478bd9Sstevel@tonic-gate 		break;
745*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY:
746*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (uchar_t);
747*7c478bd9Sstevel@tonic-gate 		break;
748*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8_ARRAY:
749*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (int8_t);
750*7c478bd9Sstevel@tonic-gate 		break;
751*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8_ARRAY:
752*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (uint8_t);
753*7c478bd9Sstevel@tonic-gate 		break;
754*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16_ARRAY:
755*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (int16_t);
756*7c478bd9Sstevel@tonic-gate 		break;
757*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16_ARRAY:
758*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (uint16_t);
759*7c478bd9Sstevel@tonic-gate 		break;
760*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32_ARRAY:
761*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (int32_t);
762*7c478bd9Sstevel@tonic-gate 		break;
763*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32_ARRAY:
764*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (uint32_t);
765*7c478bd9Sstevel@tonic-gate 		break;
766*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64_ARRAY:
767*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (int64_t);
768*7c478bd9Sstevel@tonic-gate 		break;
769*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64_ARRAY:
770*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (uint64_t);
771*7c478bd9Sstevel@tonic-gate 		break;
772*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING_ARRAY:
773*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (uint64_t);
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 		if (data != NULL) {
776*7c478bd9Sstevel@tonic-gate 			char *const *strs = data;
777*7c478bd9Sstevel@tonic-gate 			uint_t i;
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 			/* no alignment requirement for strings */
780*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelem; i++) {
781*7c478bd9Sstevel@tonic-gate 				if (strs[i] == NULL)
782*7c478bd9Sstevel@tonic-gate 					return (-1);
783*7c478bd9Sstevel@tonic-gate 				value_sz += strlen(strs[i]) + 1;
784*7c478bd9Sstevel@tonic-gate 			}
785*7c478bd9Sstevel@tonic-gate 		}
786*7c478bd9Sstevel@tonic-gate 		break;
787*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_HRTIME:
788*7c478bd9Sstevel@tonic-gate 		value_sz = sizeof (hrtime_t);
789*7c478bd9Sstevel@tonic-gate 		break;
790*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
791*7c478bd9Sstevel@tonic-gate 		value_sz = NV_ALIGN(sizeof (nvlist_t));
792*7c478bd9Sstevel@tonic-gate 		break;
793*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY:
794*7c478bd9Sstevel@tonic-gate 		value_sz = (uint64_t)nelem * sizeof (uint64_t) +
795*7c478bd9Sstevel@tonic-gate 		    (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
796*7c478bd9Sstevel@tonic-gate 		break;
797*7c478bd9Sstevel@tonic-gate 	default:
798*7c478bd9Sstevel@tonic-gate 		return (-1);
799*7c478bd9Sstevel@tonic-gate 	}
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
802*7c478bd9Sstevel@tonic-gate }
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate static int
805*7c478bd9Sstevel@tonic-gate nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl)
806*7c478bd9Sstevel@tonic-gate {
807*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
808*7c478bd9Sstevel@tonic-gate 	int err;
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t)
811*7c478bd9Sstevel@tonic-gate 	    nvl->nvl_priv)) == NULL)
812*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	nvlist_init(emb_nvl, onvl->nvl_nvflag, priv);
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) {
817*7c478bd9Sstevel@tonic-gate 		nvlist_free(emb_nvl);
818*7c478bd9Sstevel@tonic-gate 		emb_nvl->nvl_priv = 0;
819*7c478bd9Sstevel@tonic-gate 	}
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 	return (err);
822*7c478bd9Sstevel@tonic-gate }
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate /*
825*7c478bd9Sstevel@tonic-gate  * nvlist_add_common - Add new <name,value> pair to nvlist
826*7c478bd9Sstevel@tonic-gate  */
827*7c478bd9Sstevel@tonic-gate static int
828*7c478bd9Sstevel@tonic-gate nvlist_add_common(nvlist_t *nvl, const char *name,
829*7c478bd9Sstevel@tonic-gate     data_type_t type, uint_t nelem, const void *data)
830*7c478bd9Sstevel@tonic-gate {
831*7c478bd9Sstevel@tonic-gate 	nvpair_t *nvp;
832*7c478bd9Sstevel@tonic-gate 	int nvp_sz, name_sz, value_sz;
833*7c478bd9Sstevel@tonic-gate 	int err = 0;
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	/* sanity check input params */
836*7c478bd9Sstevel@tonic-gate 	if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
837*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	if (nelem != 0 && data == NULL)
840*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	/*
843*7c478bd9Sstevel@tonic-gate 	 * Verify type and nelem and get the value size.
844*7c478bd9Sstevel@tonic-gate 	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
845*7c478bd9Sstevel@tonic-gate 	 * is the size of the string(s) included.
846*7c478bd9Sstevel@tonic-gate 	 */
847*7c478bd9Sstevel@tonic-gate 	if ((value_sz = i_get_value_size(type, data, nelem)) < 0)
848*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	if (i_validate_nvpair_value(type, nelem, data) != 0)
851*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 	switch (type) {
854*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
855*7c478bd9Sstevel@tonic-gate 		/*
856*7c478bd9Sstevel@tonic-gate 		 * Disallow adding oneself to oneself, avoid infinite recursion
857*7c478bd9Sstevel@tonic-gate 		 */
858*7c478bd9Sstevel@tonic-gate 		if ((nvlist_t *)data == nvl)
859*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
860*7c478bd9Sstevel@tonic-gate 		break;
861*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY: {
862*7c478bd9Sstevel@tonic-gate 		nvlist_t **lists = (nvlist_t **)data;
863*7c478bd9Sstevel@tonic-gate 		uint_t l;
864*7c478bd9Sstevel@tonic-gate 		for (l = 0; l < nelem; l++)
865*7c478bd9Sstevel@tonic-gate 			if (*lists++ == nvl)
866*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
867*7c478bd9Sstevel@tonic-gate 		}
868*7c478bd9Sstevel@tonic-gate 		break;
869*7c478bd9Sstevel@tonic-gate 	default:
870*7c478bd9Sstevel@tonic-gate 		break;
871*7c478bd9Sstevel@tonic-gate 	}
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	/* calculate sizes of the nvpair elements and the nvpair itself */
874*7c478bd9Sstevel@tonic-gate 	name_sz = strlen(name) + 1;
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 	nvp_sz = NVP_SIZE_CALC(name_sz, value_sz);
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 	if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL)
879*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 	ASSERT(nvp->nvp_size == nvp_sz);
882*7c478bd9Sstevel@tonic-gate 	nvp->nvp_name_sz = name_sz;
883*7c478bd9Sstevel@tonic-gate 	nvp->nvp_value_elem = nelem;
884*7c478bd9Sstevel@tonic-gate 	nvp->nvp_type = type;
885*7c478bd9Sstevel@tonic-gate 	bcopy(name, NVP_NAME(nvp), name_sz);
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	switch (type) {
888*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN:
889*7c478bd9Sstevel@tonic-gate 		break;
890*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING_ARRAY: {
891*7c478bd9Sstevel@tonic-gate 		int i;
892*7c478bd9Sstevel@tonic-gate 		char *const *strs = data;
893*7c478bd9Sstevel@tonic-gate 		char *buf = NVP_VALUE(nvp);
894*7c478bd9Sstevel@tonic-gate 		char **cstrs = (void *)buf;
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate 		/* skip pre-allocated space for pointer array */
897*7c478bd9Sstevel@tonic-gate 		buf += nelem * sizeof (uint64_t);
898*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem; i++) {
899*7c478bd9Sstevel@tonic-gate 			int slen = strlen(strs[i]) + 1;
900*7c478bd9Sstevel@tonic-gate 			bcopy(strs[i], buf, slen);
901*7c478bd9Sstevel@tonic-gate 			cstrs[i] = buf;
902*7c478bd9Sstevel@tonic-gate 			buf += slen;
903*7c478bd9Sstevel@tonic-gate 		}
904*7c478bd9Sstevel@tonic-gate 		break;
905*7c478bd9Sstevel@tonic-gate 	}
906*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST: {
907*7c478bd9Sstevel@tonic-gate 		nvlist_t *nnvl = EMBEDDED_NVL(nvp);
908*7c478bd9Sstevel@tonic-gate 		nvlist_t *onvl = (nvlist_t *)data;
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 		if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) {
911*7c478bd9Sstevel@tonic-gate 			nvp_buf_free(nvl, nvp);
912*7c478bd9Sstevel@tonic-gate 			return (err);
913*7c478bd9Sstevel@tonic-gate 		}
914*7c478bd9Sstevel@tonic-gate 		break;
915*7c478bd9Sstevel@tonic-gate 	}
916*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY: {
917*7c478bd9Sstevel@tonic-gate 		nvlist_t **onvlp = (nvlist_t **)data;
918*7c478bd9Sstevel@tonic-gate 		nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
919*7c478bd9Sstevel@tonic-gate 		nvlist_t *embedded = (nvlist_t *)
920*7c478bd9Sstevel@tonic-gate 		    ((uintptr_t)nvlp + nelem * sizeof (uint64_t));
921*7c478bd9Sstevel@tonic-gate 		int i;
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem; i++) {
924*7c478bd9Sstevel@tonic-gate 			if ((err = nvlist_copy_embedded(nvl,
925*7c478bd9Sstevel@tonic-gate 			    onvlp[i], embedded)) != 0) {
926*7c478bd9Sstevel@tonic-gate 				/*
927*7c478bd9Sstevel@tonic-gate 				 * Free any successfully created lists
928*7c478bd9Sstevel@tonic-gate 				 */
929*7c478bd9Sstevel@tonic-gate 				nvpair_free(nvp);
930*7c478bd9Sstevel@tonic-gate 				nvp_buf_free(nvl, nvp);
931*7c478bd9Sstevel@tonic-gate 				return (err);
932*7c478bd9Sstevel@tonic-gate 			}
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 			nvlp[i] = embedded++;
935*7c478bd9Sstevel@tonic-gate 		}
936*7c478bd9Sstevel@tonic-gate 		break;
937*7c478bd9Sstevel@tonic-gate 	}
938*7c478bd9Sstevel@tonic-gate 	default:
939*7c478bd9Sstevel@tonic-gate 		bcopy(data, NVP_VALUE(nvp), value_sz);
940*7c478bd9Sstevel@tonic-gate 	}
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	/* if unique name, remove before add */
943*7c478bd9Sstevel@tonic-gate 	if (nvl->nvl_nvflag & NV_UNIQUE_NAME)
944*7c478bd9Sstevel@tonic-gate 		(void) nvlist_remove_all(nvl, name);
945*7c478bd9Sstevel@tonic-gate 	else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE)
946*7c478bd9Sstevel@tonic-gate 		(void) nvlist_remove(nvl, name, type);
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 	nvp_buf_link(nvl, nvp);
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	return (0);
951*7c478bd9Sstevel@tonic-gate }
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate int
954*7c478bd9Sstevel@tonic-gate nvlist_add_boolean(nvlist_t *nvl, const char *name)
955*7c478bd9Sstevel@tonic-gate {
956*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL));
957*7c478bd9Sstevel@tonic-gate }
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate int
960*7c478bd9Sstevel@tonic-gate nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
961*7c478bd9Sstevel@tonic-gate {
962*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val));
963*7c478bd9Sstevel@tonic-gate }
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate int
966*7c478bd9Sstevel@tonic-gate nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
967*7c478bd9Sstevel@tonic-gate {
968*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val));
969*7c478bd9Sstevel@tonic-gate }
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate int
972*7c478bd9Sstevel@tonic-gate nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
973*7c478bd9Sstevel@tonic-gate {
974*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val));
975*7c478bd9Sstevel@tonic-gate }
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate int
978*7c478bd9Sstevel@tonic-gate nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
979*7c478bd9Sstevel@tonic-gate {
980*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val));
981*7c478bd9Sstevel@tonic-gate }
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate int
984*7c478bd9Sstevel@tonic-gate nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
985*7c478bd9Sstevel@tonic-gate {
986*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val));
987*7c478bd9Sstevel@tonic-gate }
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate int
990*7c478bd9Sstevel@tonic-gate nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
991*7c478bd9Sstevel@tonic-gate {
992*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val));
993*7c478bd9Sstevel@tonic-gate }
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate int
996*7c478bd9Sstevel@tonic-gate nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
997*7c478bd9Sstevel@tonic-gate {
998*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val));
999*7c478bd9Sstevel@tonic-gate }
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate int
1002*7c478bd9Sstevel@tonic-gate nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
1003*7c478bd9Sstevel@tonic-gate {
1004*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val));
1005*7c478bd9Sstevel@tonic-gate }
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate int
1008*7c478bd9Sstevel@tonic-gate nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
1009*7c478bd9Sstevel@tonic-gate {
1010*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val));
1011*7c478bd9Sstevel@tonic-gate }
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate int
1014*7c478bd9Sstevel@tonic-gate nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
1015*7c478bd9Sstevel@tonic-gate {
1016*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val));
1017*7c478bd9Sstevel@tonic-gate }
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate int
1020*7c478bd9Sstevel@tonic-gate nvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
1021*7c478bd9Sstevel@tonic-gate {
1022*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val));
1023*7c478bd9Sstevel@tonic-gate }
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate int
1026*7c478bd9Sstevel@tonic-gate nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
1027*7c478bd9Sstevel@tonic-gate     boolean_t *a, uint_t n)
1028*7c478bd9Sstevel@tonic-gate {
1029*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1030*7c478bd9Sstevel@tonic-gate }
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate int
1033*7c478bd9Sstevel@tonic-gate nvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *a, uint_t n)
1034*7c478bd9Sstevel@tonic-gate {
1035*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1036*7c478bd9Sstevel@tonic-gate }
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate int
1039*7c478bd9Sstevel@tonic-gate nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint_t n)
1040*7c478bd9Sstevel@tonic-gate {
1041*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1042*7c478bd9Sstevel@tonic-gate }
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate int
1045*7c478bd9Sstevel@tonic-gate nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint_t n)
1046*7c478bd9Sstevel@tonic-gate {
1047*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1048*7c478bd9Sstevel@tonic-gate }
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate int
1051*7c478bd9Sstevel@tonic-gate nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint_t n)
1052*7c478bd9Sstevel@tonic-gate {
1053*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1054*7c478bd9Sstevel@tonic-gate }
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate int
1057*7c478bd9Sstevel@tonic-gate nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, uint_t n)
1058*7c478bd9Sstevel@tonic-gate {
1059*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1060*7c478bd9Sstevel@tonic-gate }
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate int
1063*7c478bd9Sstevel@tonic-gate nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint_t n)
1064*7c478bd9Sstevel@tonic-gate {
1065*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1066*7c478bd9Sstevel@tonic-gate }
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate int
1069*7c478bd9Sstevel@tonic-gate nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, uint_t n)
1070*7c478bd9Sstevel@tonic-gate {
1071*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1072*7c478bd9Sstevel@tonic-gate }
1073*7c478bd9Sstevel@tonic-gate 
1074*7c478bd9Sstevel@tonic-gate int
1075*7c478bd9Sstevel@tonic-gate nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint_t n)
1076*7c478bd9Sstevel@tonic-gate {
1077*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1078*7c478bd9Sstevel@tonic-gate }
1079*7c478bd9Sstevel@tonic-gate 
1080*7c478bd9Sstevel@tonic-gate int
1081*7c478bd9Sstevel@tonic-gate nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, uint_t n)
1082*7c478bd9Sstevel@tonic-gate {
1083*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1084*7c478bd9Sstevel@tonic-gate }
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate int
1087*7c478bd9Sstevel@tonic-gate nvlist_add_string_array(nvlist_t *nvl, const char *name,
1088*7c478bd9Sstevel@tonic-gate     char *const *a, uint_t n)
1089*7c478bd9Sstevel@tonic-gate {
1090*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1091*7c478bd9Sstevel@tonic-gate }
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate int
1094*7c478bd9Sstevel@tonic-gate nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val)
1095*7c478bd9Sstevel@tonic-gate {
1096*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val));
1097*7c478bd9Sstevel@tonic-gate }
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate int
1100*7c478bd9Sstevel@tonic-gate nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
1101*7c478bd9Sstevel@tonic-gate {
1102*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1103*7c478bd9Sstevel@tonic-gate }
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate int
1106*7c478bd9Sstevel@tonic-gate nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, uint_t n)
1107*7c478bd9Sstevel@tonic-gate {
1108*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1109*7c478bd9Sstevel@tonic-gate }
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate /* reading name-value pairs */
1112*7c478bd9Sstevel@tonic-gate nvpair_t *
1113*7c478bd9Sstevel@tonic-gate nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1114*7c478bd9Sstevel@tonic-gate {
1115*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
1116*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL ||
1119*7c478bd9Sstevel@tonic-gate 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1120*7c478bd9Sstevel@tonic-gate 		return (NULL);
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	curr = NVPAIR2I_NVP(nvp);
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate 	/*
1125*7c478bd9Sstevel@tonic-gate 	 * Ensure that nvp is an valid pointer.
1126*7c478bd9Sstevel@tonic-gate 	 */
1127*7c478bd9Sstevel@tonic-gate 	if (nvp == NULL)
1128*7c478bd9Sstevel@tonic-gate 		curr = priv->nvp_list;
1129*7c478bd9Sstevel@tonic-gate 	else if (priv->nvp_curr == curr)
1130*7c478bd9Sstevel@tonic-gate 		curr = curr->nvi_next;
1131*7c478bd9Sstevel@tonic-gate 	else if (nvlist_contains_nvp(nvl, nvp) == 0)
1132*7c478bd9Sstevel@tonic-gate 		curr = NULL;
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate 	priv->nvp_curr = curr;
1135*7c478bd9Sstevel@tonic-gate 
1136*7c478bd9Sstevel@tonic-gate 	return (curr != NULL ? &curr->nvi_nvp : NULL);
1137*7c478bd9Sstevel@tonic-gate }
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate char *
1140*7c478bd9Sstevel@tonic-gate nvpair_name(nvpair_t *nvp)
1141*7c478bd9Sstevel@tonic-gate {
1142*7c478bd9Sstevel@tonic-gate 	return (NVP_NAME(nvp));
1143*7c478bd9Sstevel@tonic-gate }
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate data_type_t
1146*7c478bd9Sstevel@tonic-gate nvpair_type(nvpair_t *nvp)
1147*7c478bd9Sstevel@tonic-gate {
1148*7c478bd9Sstevel@tonic-gate 	return (NVP_TYPE(nvp));
1149*7c478bd9Sstevel@tonic-gate }
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate static int
1152*7c478bd9Sstevel@tonic-gate nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data)
1153*7c478bd9Sstevel@tonic-gate {
1154*7c478bd9Sstevel@tonic-gate 	if (nvp == NULL || nvpair_type(nvp) != type)
1155*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	/*
1158*7c478bd9Sstevel@tonic-gate 	 * For non-array types, we copy the data.
1159*7c478bd9Sstevel@tonic-gate 	 * For array types (including string), we set a pointer.
1160*7c478bd9Sstevel@tonic-gate 	 */
1161*7c478bd9Sstevel@tonic-gate 	switch (type) {
1162*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN:
1163*7c478bd9Sstevel@tonic-gate 		if (nelem != NULL)
1164*7c478bd9Sstevel@tonic-gate 			*nelem = 0;
1165*7c478bd9Sstevel@tonic-gate 		break;
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_VALUE:
1168*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE:
1169*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8:
1170*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8:
1171*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16:
1172*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16:
1173*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32:
1174*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32:
1175*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64:
1176*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64:
1177*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_HRTIME:
1178*7c478bd9Sstevel@tonic-gate 		if (data == NULL)
1179*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1180*7c478bd9Sstevel@tonic-gate 		bcopy(NVP_VALUE(nvp), data,
1181*7c478bd9Sstevel@tonic-gate 		    (size_t)i_get_value_size(type, NULL, 1));
1182*7c478bd9Sstevel@tonic-gate 		if (nelem != NULL)
1183*7c478bd9Sstevel@tonic-gate 			*nelem = 1;
1184*7c478bd9Sstevel@tonic-gate 		break;
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
1187*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING:
1188*7c478bd9Sstevel@tonic-gate 		if (data == NULL)
1189*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1190*7c478bd9Sstevel@tonic-gate 		*(void **)data = (void *)NVP_VALUE(nvp);
1191*7c478bd9Sstevel@tonic-gate 		if (nelem != NULL)
1192*7c478bd9Sstevel@tonic-gate 			*nelem = 1;
1193*7c478bd9Sstevel@tonic-gate 		break;
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_ARRAY:
1196*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY:
1197*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8_ARRAY:
1198*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8_ARRAY:
1199*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16_ARRAY:
1200*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16_ARRAY:
1201*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32_ARRAY:
1202*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32_ARRAY:
1203*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64_ARRAY:
1204*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64_ARRAY:
1205*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING_ARRAY:
1206*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY:
1207*7c478bd9Sstevel@tonic-gate 		if (nelem == NULL || data == NULL)
1208*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1209*7c478bd9Sstevel@tonic-gate 		if ((*nelem = NVP_NELEM(nvp)) != 0)
1210*7c478bd9Sstevel@tonic-gate 			*(void **)data = (void *)NVP_VALUE(nvp);
1211*7c478bd9Sstevel@tonic-gate 		else
1212*7c478bd9Sstevel@tonic-gate 			*(void **)data = NULL;
1213*7c478bd9Sstevel@tonic-gate 		break;
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 	default:
1216*7c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
1217*7c478bd9Sstevel@tonic-gate 	}
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 	return (0);
1220*7c478bd9Sstevel@tonic-gate }
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate static int
1223*7c478bd9Sstevel@tonic-gate nvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type,
1224*7c478bd9Sstevel@tonic-gate     uint_t *nelem, void *data)
1225*7c478bd9Sstevel@tonic-gate {
1226*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
1227*7c478bd9Sstevel@tonic-gate 	nvpair_t *nvp;
1228*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 	if (name == NULL || nvl == NULL ||
1231*7c478bd9Sstevel@tonic-gate 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1232*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate 	if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE)))
1235*7c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
1238*7c478bd9Sstevel@tonic-gate 		nvp = &curr->nvi_nvp;
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type)
1241*7c478bd9Sstevel@tonic-gate 			return (nvpair_value_common(nvp, type, nelem, data));
1242*7c478bd9Sstevel@tonic-gate 	}
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	return (ENOENT);
1245*7c478bd9Sstevel@tonic-gate }
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate int
1248*7c478bd9Sstevel@tonic-gate nvlist_lookup_boolean(nvlist_t *nvl, const char *name)
1249*7c478bd9Sstevel@tonic-gate {
1250*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL));
1251*7c478bd9Sstevel@tonic-gate }
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate int
1254*7c478bd9Sstevel@tonic-gate nvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val)
1255*7c478bd9Sstevel@tonic-gate {
1256*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name,
1257*7c478bd9Sstevel@tonic-gate 	    DATA_TYPE_BOOLEAN_VALUE, NULL, val));
1258*7c478bd9Sstevel@tonic-gate }
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate int
1261*7c478bd9Sstevel@tonic-gate nvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val)
1262*7c478bd9Sstevel@tonic-gate {
1263*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val));
1264*7c478bd9Sstevel@tonic-gate }
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate int
1267*7c478bd9Sstevel@tonic-gate nvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val)
1268*7c478bd9Sstevel@tonic-gate {
1269*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val));
1270*7c478bd9Sstevel@tonic-gate }
1271*7c478bd9Sstevel@tonic-gate 
1272*7c478bd9Sstevel@tonic-gate int
1273*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val)
1274*7c478bd9Sstevel@tonic-gate {
1275*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val));
1276*7c478bd9Sstevel@tonic-gate }
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate int
1279*7c478bd9Sstevel@tonic-gate nvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val)
1280*7c478bd9Sstevel@tonic-gate {
1281*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val));
1282*7c478bd9Sstevel@tonic-gate }
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate int
1285*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val)
1286*7c478bd9Sstevel@tonic-gate {
1287*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val));
1288*7c478bd9Sstevel@tonic-gate }
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate int
1291*7c478bd9Sstevel@tonic-gate nvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val)
1292*7c478bd9Sstevel@tonic-gate {
1293*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val));
1294*7c478bd9Sstevel@tonic-gate }
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate int
1297*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val)
1298*7c478bd9Sstevel@tonic-gate {
1299*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val));
1300*7c478bd9Sstevel@tonic-gate }
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate int
1303*7c478bd9Sstevel@tonic-gate nvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val)
1304*7c478bd9Sstevel@tonic-gate {
1305*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val));
1306*7c478bd9Sstevel@tonic-gate }
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate int
1309*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val)
1310*7c478bd9Sstevel@tonic-gate {
1311*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val));
1312*7c478bd9Sstevel@tonic-gate }
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate int
1315*7c478bd9Sstevel@tonic-gate nvlist_lookup_string(nvlist_t *nvl, const char *name, char **val)
1316*7c478bd9Sstevel@tonic-gate {
1317*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val));
1318*7c478bd9Sstevel@tonic-gate }
1319*7c478bd9Sstevel@tonic-gate 
1320*7c478bd9Sstevel@tonic-gate int
1321*7c478bd9Sstevel@tonic-gate nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val)
1322*7c478bd9Sstevel@tonic-gate {
1323*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val));
1324*7c478bd9Sstevel@tonic-gate }
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate int
1327*7c478bd9Sstevel@tonic-gate nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name,
1328*7c478bd9Sstevel@tonic-gate     boolean_t **a, uint_t *n)
1329*7c478bd9Sstevel@tonic-gate {
1330*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name,
1331*7c478bd9Sstevel@tonic-gate 	    DATA_TYPE_BOOLEAN_ARRAY, n, a));
1332*7c478bd9Sstevel@tonic-gate }
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate int
1335*7c478bd9Sstevel@tonic-gate nvlist_lookup_byte_array(nvlist_t *nvl, const char *name,
1336*7c478bd9Sstevel@tonic-gate     uchar_t **a, uint_t *n)
1337*7c478bd9Sstevel@tonic-gate {
1338*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1339*7c478bd9Sstevel@tonic-gate }
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate int
1342*7c478bd9Sstevel@tonic-gate nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n)
1343*7c478bd9Sstevel@tonic-gate {
1344*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1345*7c478bd9Sstevel@tonic-gate }
1346*7c478bd9Sstevel@tonic-gate 
1347*7c478bd9Sstevel@tonic-gate int
1348*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name,
1349*7c478bd9Sstevel@tonic-gate     uint8_t **a, uint_t *n)
1350*7c478bd9Sstevel@tonic-gate {
1351*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1352*7c478bd9Sstevel@tonic-gate }
1353*7c478bd9Sstevel@tonic-gate 
1354*7c478bd9Sstevel@tonic-gate int
1355*7c478bd9Sstevel@tonic-gate nvlist_lookup_int16_array(nvlist_t *nvl, const char *name,
1356*7c478bd9Sstevel@tonic-gate     int16_t **a, uint_t *n)
1357*7c478bd9Sstevel@tonic-gate {
1358*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1359*7c478bd9Sstevel@tonic-gate }
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate int
1362*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name,
1363*7c478bd9Sstevel@tonic-gate     uint16_t **a, uint_t *n)
1364*7c478bd9Sstevel@tonic-gate {
1365*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1366*7c478bd9Sstevel@tonic-gate }
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate int
1369*7c478bd9Sstevel@tonic-gate nvlist_lookup_int32_array(nvlist_t *nvl, const char *name,
1370*7c478bd9Sstevel@tonic-gate     int32_t **a, uint_t *n)
1371*7c478bd9Sstevel@tonic-gate {
1372*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1373*7c478bd9Sstevel@tonic-gate }
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate int
1376*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name,
1377*7c478bd9Sstevel@tonic-gate     uint32_t **a, uint_t *n)
1378*7c478bd9Sstevel@tonic-gate {
1379*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1380*7c478bd9Sstevel@tonic-gate }
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate int
1383*7c478bd9Sstevel@tonic-gate nvlist_lookup_int64_array(nvlist_t *nvl, const char *name,
1384*7c478bd9Sstevel@tonic-gate     int64_t **a, uint_t *n)
1385*7c478bd9Sstevel@tonic-gate {
1386*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1387*7c478bd9Sstevel@tonic-gate }
1388*7c478bd9Sstevel@tonic-gate 
1389*7c478bd9Sstevel@tonic-gate int
1390*7c478bd9Sstevel@tonic-gate nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name,
1391*7c478bd9Sstevel@tonic-gate     uint64_t **a, uint_t *n)
1392*7c478bd9Sstevel@tonic-gate {
1393*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1394*7c478bd9Sstevel@tonic-gate }
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate int
1397*7c478bd9Sstevel@tonic-gate nvlist_lookup_string_array(nvlist_t *nvl, const char *name,
1398*7c478bd9Sstevel@tonic-gate     char ***a, uint_t *n)
1399*7c478bd9Sstevel@tonic-gate {
1400*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1401*7c478bd9Sstevel@tonic-gate }
1402*7c478bd9Sstevel@tonic-gate 
1403*7c478bd9Sstevel@tonic-gate int
1404*7c478bd9Sstevel@tonic-gate nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name,
1405*7c478bd9Sstevel@tonic-gate     nvlist_t ***a, uint_t *n)
1406*7c478bd9Sstevel@tonic-gate {
1407*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1408*7c478bd9Sstevel@tonic-gate }
1409*7c478bd9Sstevel@tonic-gate 
1410*7c478bd9Sstevel@tonic-gate int
1411*7c478bd9Sstevel@tonic-gate nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val)
1412*7c478bd9Sstevel@tonic-gate {
1413*7c478bd9Sstevel@tonic-gate 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val));
1414*7c478bd9Sstevel@tonic-gate }
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate int
1417*7c478bd9Sstevel@tonic-gate nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...)
1418*7c478bd9Sstevel@tonic-gate {
1419*7c478bd9Sstevel@tonic-gate 	va_list ap;
1420*7c478bd9Sstevel@tonic-gate 	char *name;
1421*7c478bd9Sstevel@tonic-gate 	int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0);
1422*7c478bd9Sstevel@tonic-gate 	int ret = 0;
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 	va_start(ap, flag);
1425*7c478bd9Sstevel@tonic-gate 	while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
1426*7c478bd9Sstevel@tonic-gate 		data_type_t type;
1427*7c478bd9Sstevel@tonic-gate 		void *val;
1428*7c478bd9Sstevel@tonic-gate 		uint_t *nelem;
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate 		switch (type = va_arg(ap, data_type_t)) {
1431*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_BOOLEAN:
1432*7c478bd9Sstevel@tonic-gate 			ret = nvlist_lookup_common(nvl, name, type, NULL, NULL);
1433*7c478bd9Sstevel@tonic-gate 			break;
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_BOOLEAN_VALUE:
1436*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_BYTE:
1437*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_INT8:
1438*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_UINT8:
1439*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_INT16:
1440*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_UINT16:
1441*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_INT32:
1442*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_UINT32:
1443*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_INT64:
1444*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_UINT64:
1445*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_HRTIME:
1446*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_STRING:
1447*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_NVLIST:
1448*7c478bd9Sstevel@tonic-gate 			val = va_arg(ap, void *);
1449*7c478bd9Sstevel@tonic-gate 			ret = nvlist_lookup_common(nvl, name, type, NULL, val);
1450*7c478bd9Sstevel@tonic-gate 			break;
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_BYTE_ARRAY:
1453*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_BOOLEAN_ARRAY:
1454*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_INT8_ARRAY:
1455*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_UINT8_ARRAY:
1456*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_INT16_ARRAY:
1457*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_UINT16_ARRAY:
1458*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_INT32_ARRAY:
1459*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_UINT32_ARRAY:
1460*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_INT64_ARRAY:
1461*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_UINT64_ARRAY:
1462*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_STRING_ARRAY:
1463*7c478bd9Sstevel@tonic-gate 		case DATA_TYPE_NVLIST_ARRAY:
1464*7c478bd9Sstevel@tonic-gate 			val = va_arg(ap, void *);
1465*7c478bd9Sstevel@tonic-gate 			nelem = va_arg(ap, uint_t *);
1466*7c478bd9Sstevel@tonic-gate 			ret = nvlist_lookup_common(nvl, name, type, nelem, val);
1467*7c478bd9Sstevel@tonic-gate 			break;
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate 		default:
1470*7c478bd9Sstevel@tonic-gate 			ret = EINVAL;
1471*7c478bd9Sstevel@tonic-gate 		}
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate 		if (ret == ENOENT && noentok)
1474*7c478bd9Sstevel@tonic-gate 			ret = 0;
1475*7c478bd9Sstevel@tonic-gate 	}
1476*7c478bd9Sstevel@tonic-gate 	va_end(ap);
1477*7c478bd9Sstevel@tonic-gate 
1478*7c478bd9Sstevel@tonic-gate 	return (ret);
1479*7c478bd9Sstevel@tonic-gate }
1480*7c478bd9Sstevel@tonic-gate 
1481*7c478bd9Sstevel@tonic-gate int
1482*7c478bd9Sstevel@tonic-gate nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val)
1483*7c478bd9Sstevel@tonic-gate {
1484*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));
1485*7c478bd9Sstevel@tonic-gate }
1486*7c478bd9Sstevel@tonic-gate 
1487*7c478bd9Sstevel@tonic-gate int
1488*7c478bd9Sstevel@tonic-gate nvpair_value_byte(nvpair_t *nvp, uchar_t *val)
1489*7c478bd9Sstevel@tonic-gate {
1490*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val));
1491*7c478bd9Sstevel@tonic-gate }
1492*7c478bd9Sstevel@tonic-gate 
1493*7c478bd9Sstevel@tonic-gate int
1494*7c478bd9Sstevel@tonic-gate nvpair_value_int8(nvpair_t *nvp, int8_t *val)
1495*7c478bd9Sstevel@tonic-gate {
1496*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val));
1497*7c478bd9Sstevel@tonic-gate }
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate int
1500*7c478bd9Sstevel@tonic-gate nvpair_value_uint8(nvpair_t *nvp, uint8_t *val)
1501*7c478bd9Sstevel@tonic-gate {
1502*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val));
1503*7c478bd9Sstevel@tonic-gate }
1504*7c478bd9Sstevel@tonic-gate 
1505*7c478bd9Sstevel@tonic-gate int
1506*7c478bd9Sstevel@tonic-gate nvpair_value_int16(nvpair_t *nvp, int16_t *val)
1507*7c478bd9Sstevel@tonic-gate {
1508*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val));
1509*7c478bd9Sstevel@tonic-gate }
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate int
1512*7c478bd9Sstevel@tonic-gate nvpair_value_uint16(nvpair_t *nvp, uint16_t *val)
1513*7c478bd9Sstevel@tonic-gate {
1514*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val));
1515*7c478bd9Sstevel@tonic-gate }
1516*7c478bd9Sstevel@tonic-gate 
1517*7c478bd9Sstevel@tonic-gate int
1518*7c478bd9Sstevel@tonic-gate nvpair_value_int32(nvpair_t *nvp, int32_t *val)
1519*7c478bd9Sstevel@tonic-gate {
1520*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val));
1521*7c478bd9Sstevel@tonic-gate }
1522*7c478bd9Sstevel@tonic-gate 
1523*7c478bd9Sstevel@tonic-gate int
1524*7c478bd9Sstevel@tonic-gate nvpair_value_uint32(nvpair_t *nvp, uint32_t *val)
1525*7c478bd9Sstevel@tonic-gate {
1526*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val));
1527*7c478bd9Sstevel@tonic-gate }
1528*7c478bd9Sstevel@tonic-gate 
1529*7c478bd9Sstevel@tonic-gate int
1530*7c478bd9Sstevel@tonic-gate nvpair_value_int64(nvpair_t *nvp, int64_t *val)
1531*7c478bd9Sstevel@tonic-gate {
1532*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val));
1533*7c478bd9Sstevel@tonic-gate }
1534*7c478bd9Sstevel@tonic-gate 
1535*7c478bd9Sstevel@tonic-gate int
1536*7c478bd9Sstevel@tonic-gate nvpair_value_uint64(nvpair_t *nvp, uint64_t *val)
1537*7c478bd9Sstevel@tonic-gate {
1538*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val));
1539*7c478bd9Sstevel@tonic-gate }
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate int
1542*7c478bd9Sstevel@tonic-gate nvpair_value_string(nvpair_t *nvp, char **val)
1543*7c478bd9Sstevel@tonic-gate {
1544*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val));
1545*7c478bd9Sstevel@tonic-gate }
1546*7c478bd9Sstevel@tonic-gate 
1547*7c478bd9Sstevel@tonic-gate int
1548*7c478bd9Sstevel@tonic-gate nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val)
1549*7c478bd9Sstevel@tonic-gate {
1550*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val));
1551*7c478bd9Sstevel@tonic-gate }
1552*7c478bd9Sstevel@tonic-gate 
1553*7c478bd9Sstevel@tonic-gate int
1554*7c478bd9Sstevel@tonic-gate nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem)
1555*7c478bd9Sstevel@tonic-gate {
1556*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val));
1557*7c478bd9Sstevel@tonic-gate }
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate int
1560*7c478bd9Sstevel@tonic-gate nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem)
1561*7c478bd9Sstevel@tonic-gate {
1562*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val));
1563*7c478bd9Sstevel@tonic-gate }
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate int
1566*7c478bd9Sstevel@tonic-gate nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem)
1567*7c478bd9Sstevel@tonic-gate {
1568*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val));
1569*7c478bd9Sstevel@tonic-gate }
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate int
1572*7c478bd9Sstevel@tonic-gate nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem)
1573*7c478bd9Sstevel@tonic-gate {
1574*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val));
1575*7c478bd9Sstevel@tonic-gate }
1576*7c478bd9Sstevel@tonic-gate 
1577*7c478bd9Sstevel@tonic-gate int
1578*7c478bd9Sstevel@tonic-gate nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem)
1579*7c478bd9Sstevel@tonic-gate {
1580*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val));
1581*7c478bd9Sstevel@tonic-gate }
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate int
1584*7c478bd9Sstevel@tonic-gate nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem)
1585*7c478bd9Sstevel@tonic-gate {
1586*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val));
1587*7c478bd9Sstevel@tonic-gate }
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate int
1590*7c478bd9Sstevel@tonic-gate nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem)
1591*7c478bd9Sstevel@tonic-gate {
1592*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val));
1593*7c478bd9Sstevel@tonic-gate }
1594*7c478bd9Sstevel@tonic-gate 
1595*7c478bd9Sstevel@tonic-gate int
1596*7c478bd9Sstevel@tonic-gate nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem)
1597*7c478bd9Sstevel@tonic-gate {
1598*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val));
1599*7c478bd9Sstevel@tonic-gate }
1600*7c478bd9Sstevel@tonic-gate 
1601*7c478bd9Sstevel@tonic-gate int
1602*7c478bd9Sstevel@tonic-gate nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem)
1603*7c478bd9Sstevel@tonic-gate {
1604*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val));
1605*7c478bd9Sstevel@tonic-gate }
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate int
1608*7c478bd9Sstevel@tonic-gate nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem)
1609*7c478bd9Sstevel@tonic-gate {
1610*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val));
1611*7c478bd9Sstevel@tonic-gate }
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate int
1614*7c478bd9Sstevel@tonic-gate nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem)
1615*7c478bd9Sstevel@tonic-gate {
1616*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val));
1617*7c478bd9Sstevel@tonic-gate }
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate int
1620*7c478bd9Sstevel@tonic-gate nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem)
1621*7c478bd9Sstevel@tonic-gate {
1622*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val));
1623*7c478bd9Sstevel@tonic-gate }
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate int
1626*7c478bd9Sstevel@tonic-gate nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val)
1627*7c478bd9Sstevel@tonic-gate {
1628*7c478bd9Sstevel@tonic-gate 	return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val));
1629*7c478bd9Sstevel@tonic-gate }
1630*7c478bd9Sstevel@tonic-gate 
1631*7c478bd9Sstevel@tonic-gate /*
1632*7c478bd9Sstevel@tonic-gate  * Add specified pair to the list.
1633*7c478bd9Sstevel@tonic-gate  */
1634*7c478bd9Sstevel@tonic-gate int
1635*7c478bd9Sstevel@tonic-gate nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1636*7c478bd9Sstevel@tonic-gate {
1637*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL || nvp == NULL)
1638*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1639*7c478bd9Sstevel@tonic-gate 
1640*7c478bd9Sstevel@tonic-gate 	return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp),
1641*7c478bd9Sstevel@tonic-gate 	    NVP_NELEM(nvp), NVP_VALUE(nvp)));
1642*7c478bd9Sstevel@tonic-gate }
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate /*
1645*7c478bd9Sstevel@tonic-gate  * Merge the supplied nvlists and put the result in dst.
1646*7c478bd9Sstevel@tonic-gate  * The merged list will contain all names specified in both lists,
1647*7c478bd9Sstevel@tonic-gate  * the values are taken from nvl in the case of duplicates.
1648*7c478bd9Sstevel@tonic-gate  * Return 0 on success.
1649*7c478bd9Sstevel@tonic-gate  */
1650*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1651*7c478bd9Sstevel@tonic-gate int
1652*7c478bd9Sstevel@tonic-gate nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)
1653*7c478bd9Sstevel@tonic-gate {
1654*7c478bd9Sstevel@tonic-gate 	if (nvl == NULL || dst == NULL)
1655*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1656*7c478bd9Sstevel@tonic-gate 
1657*7c478bd9Sstevel@tonic-gate 	if (dst != nvl)
1658*7c478bd9Sstevel@tonic-gate 		return (nvlist_copy_pairs(nvl, dst));
1659*7c478bd9Sstevel@tonic-gate 
1660*7c478bd9Sstevel@tonic-gate 	return (0);
1661*7c478bd9Sstevel@tonic-gate }
1662*7c478bd9Sstevel@tonic-gate 
1663*7c478bd9Sstevel@tonic-gate /*
1664*7c478bd9Sstevel@tonic-gate  * Encoding related routines
1665*7c478bd9Sstevel@tonic-gate  */
1666*7c478bd9Sstevel@tonic-gate #define	NVS_OP_ENCODE	0
1667*7c478bd9Sstevel@tonic-gate #define	NVS_OP_DECODE	1
1668*7c478bd9Sstevel@tonic-gate #define	NVS_OP_GETSIZE	2
1669*7c478bd9Sstevel@tonic-gate 
1670*7c478bd9Sstevel@tonic-gate typedef struct nvs_ops nvs_ops_t;
1671*7c478bd9Sstevel@tonic-gate 
1672*7c478bd9Sstevel@tonic-gate typedef struct {
1673*7c478bd9Sstevel@tonic-gate 	int		nvs_op;
1674*7c478bd9Sstevel@tonic-gate 	const nvs_ops_t	*nvs_ops;
1675*7c478bd9Sstevel@tonic-gate 	void		*nvs_private;
1676*7c478bd9Sstevel@tonic-gate 	nvpriv_t	*nvs_priv;
1677*7c478bd9Sstevel@tonic-gate } nvstream_t;
1678*7c478bd9Sstevel@tonic-gate 
1679*7c478bd9Sstevel@tonic-gate /*
1680*7c478bd9Sstevel@tonic-gate  * nvs operations are:
1681*7c478bd9Sstevel@tonic-gate  *   - nvs_nvlist
1682*7c478bd9Sstevel@tonic-gate  *     encoding / decoding of a nvlist header (nvlist_t)
1683*7c478bd9Sstevel@tonic-gate  *     calculates the size used for header and end detection
1684*7c478bd9Sstevel@tonic-gate  *
1685*7c478bd9Sstevel@tonic-gate  *   - nvs_nvpair
1686*7c478bd9Sstevel@tonic-gate  *     responsible for the first part of encoding / decoding of an nvpair
1687*7c478bd9Sstevel@tonic-gate  *     calculates the decoded size of an nvpair
1688*7c478bd9Sstevel@tonic-gate  *
1689*7c478bd9Sstevel@tonic-gate  *   - nvs_nvp_op
1690*7c478bd9Sstevel@tonic-gate  *     second part of encoding / decoding of an nvpair
1691*7c478bd9Sstevel@tonic-gate  *
1692*7c478bd9Sstevel@tonic-gate  *   - nvs_nvp_size
1693*7c478bd9Sstevel@tonic-gate  *     calculates the encoding size of an nvpair
1694*7c478bd9Sstevel@tonic-gate  *
1695*7c478bd9Sstevel@tonic-gate  *   - nvs_nvl_fini
1696*7c478bd9Sstevel@tonic-gate  *     encodes the end detection mark (zeros).
1697*7c478bd9Sstevel@tonic-gate  */
1698*7c478bd9Sstevel@tonic-gate struct nvs_ops {
1699*7c478bd9Sstevel@tonic-gate 	int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *);
1700*7c478bd9Sstevel@tonic-gate 	int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *);
1701*7c478bd9Sstevel@tonic-gate 	int (*nvs_nvp_op)(nvstream_t *, nvpair_t *);
1702*7c478bd9Sstevel@tonic-gate 	int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *);
1703*7c478bd9Sstevel@tonic-gate 	int (*nvs_nvl_fini)(nvstream_t *);
1704*7c478bd9Sstevel@tonic-gate };
1705*7c478bd9Sstevel@tonic-gate 
1706*7c478bd9Sstevel@tonic-gate typedef struct {
1707*7c478bd9Sstevel@tonic-gate 	char	nvh_encoding;	/* nvs encoding method */
1708*7c478bd9Sstevel@tonic-gate 	char	nvh_endian;	/* nvs endian */
1709*7c478bd9Sstevel@tonic-gate 	char	nvh_reserved1;	/* reserved for future use */
1710*7c478bd9Sstevel@tonic-gate 	char	nvh_reserved2;	/* reserved for future use */
1711*7c478bd9Sstevel@tonic-gate } nvs_header_t;
1712*7c478bd9Sstevel@tonic-gate 
1713*7c478bd9Sstevel@tonic-gate static int
1714*7c478bd9Sstevel@tonic-gate nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl)
1715*7c478bd9Sstevel@tonic-gate {
1716*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
1717*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate 	/*
1720*7c478bd9Sstevel@tonic-gate 	 * Walk nvpair in list and encode each nvpair
1721*7c478bd9Sstevel@tonic-gate 	 */
1722*7c478bd9Sstevel@tonic-gate 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
1723*7c478bd9Sstevel@tonic-gate 		if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0)
1724*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1725*7c478bd9Sstevel@tonic-gate 
1726*7c478bd9Sstevel@tonic-gate 	return (nvs->nvs_ops->nvs_nvl_fini(nvs));
1727*7c478bd9Sstevel@tonic-gate }
1728*7c478bd9Sstevel@tonic-gate 
1729*7c478bd9Sstevel@tonic-gate static int
1730*7c478bd9Sstevel@tonic-gate nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl)
1731*7c478bd9Sstevel@tonic-gate {
1732*7c478bd9Sstevel@tonic-gate 	nvpair_t *nvp;
1733*7c478bd9Sstevel@tonic-gate 	size_t nvsize;
1734*7c478bd9Sstevel@tonic-gate 	int err;
1735*7c478bd9Sstevel@tonic-gate 
1736*7c478bd9Sstevel@tonic-gate 	/*
1737*7c478bd9Sstevel@tonic-gate 	 * Get decoded size of next pair in stream, alloc
1738*7c478bd9Sstevel@tonic-gate 	 * memory for nvpair_t, then decode the nvpair
1739*7c478bd9Sstevel@tonic-gate 	 */
1740*7c478bd9Sstevel@tonic-gate 	while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) {
1741*7c478bd9Sstevel@tonic-gate 		if (nvsize == 0) /* end of list */
1742*7c478bd9Sstevel@tonic-gate 			break;
1743*7c478bd9Sstevel@tonic-gate 
1744*7c478bd9Sstevel@tonic-gate 		/* make sure len makes sense */
1745*7c478bd9Sstevel@tonic-gate 		if (nvsize < NVP_SIZE_CALC(1, 0))
1746*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1747*7c478bd9Sstevel@tonic-gate 
1748*7c478bd9Sstevel@tonic-gate 		if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL)
1749*7c478bd9Sstevel@tonic-gate 			return (ENOMEM);
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate 		if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) {
1752*7c478bd9Sstevel@tonic-gate 			nvp_buf_free(nvl, nvp);
1753*7c478bd9Sstevel@tonic-gate 			return (err);
1754*7c478bd9Sstevel@tonic-gate 		}
1755*7c478bd9Sstevel@tonic-gate 
1756*7c478bd9Sstevel@tonic-gate 		if (i_validate_nvpair(nvp) != 0) {
1757*7c478bd9Sstevel@tonic-gate 			nvpair_free(nvp);
1758*7c478bd9Sstevel@tonic-gate 			nvp_buf_free(nvl, nvp);
1759*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1760*7c478bd9Sstevel@tonic-gate 		}
1761*7c478bd9Sstevel@tonic-gate 
1762*7c478bd9Sstevel@tonic-gate 		nvp_buf_link(nvl, nvp);
1763*7c478bd9Sstevel@tonic-gate 	}
1764*7c478bd9Sstevel@tonic-gate 	return (err);
1765*7c478bd9Sstevel@tonic-gate }
1766*7c478bd9Sstevel@tonic-gate 
1767*7c478bd9Sstevel@tonic-gate static int
1768*7c478bd9Sstevel@tonic-gate nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
1769*7c478bd9Sstevel@tonic-gate {
1770*7c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
1771*7c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
1772*7c478bd9Sstevel@tonic-gate 	uint64_t nvsize = *buflen;
1773*7c478bd9Sstevel@tonic-gate 	size_t size;
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate 	/*
1776*7c478bd9Sstevel@tonic-gate 	 * Get encoded size of nvpairs in nvlist
1777*7c478bd9Sstevel@tonic-gate 	 */
1778*7c478bd9Sstevel@tonic-gate 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
1779*7c478bd9Sstevel@tonic-gate 		if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0)
1780*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1781*7c478bd9Sstevel@tonic-gate 
1782*7c478bd9Sstevel@tonic-gate 		if ((nvsize += size) > INT32_MAX)
1783*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1784*7c478bd9Sstevel@tonic-gate 	}
1785*7c478bd9Sstevel@tonic-gate 
1786*7c478bd9Sstevel@tonic-gate 	*buflen = nvsize;
1787*7c478bd9Sstevel@tonic-gate 	return (0);
1788*7c478bd9Sstevel@tonic-gate }
1789*7c478bd9Sstevel@tonic-gate 
1790*7c478bd9Sstevel@tonic-gate static int
1791*7c478bd9Sstevel@tonic-gate nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
1792*7c478bd9Sstevel@tonic-gate {
1793*7c478bd9Sstevel@tonic-gate 	int err;
1794*7c478bd9Sstevel@tonic-gate 
1795*7c478bd9Sstevel@tonic-gate 	if (nvl->nvl_priv == NULL)
1796*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1797*7c478bd9Sstevel@tonic-gate 
1798*7c478bd9Sstevel@tonic-gate 	/*
1799*7c478bd9Sstevel@tonic-gate 	 * Perform the operation, starting with header, then each nvpair
1800*7c478bd9Sstevel@tonic-gate 	 */
1801*7c478bd9Sstevel@tonic-gate 	if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0)
1802*7c478bd9Sstevel@tonic-gate 		return (err);
1803*7c478bd9Sstevel@tonic-gate 
1804*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
1805*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
1806*7c478bd9Sstevel@tonic-gate 		err = nvs_encode_pairs(nvs, nvl);
1807*7c478bd9Sstevel@tonic-gate 		break;
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE:
1810*7c478bd9Sstevel@tonic-gate 		err = nvs_decode_pairs(nvs, nvl);
1811*7c478bd9Sstevel@tonic-gate 		break;
1812*7c478bd9Sstevel@tonic-gate 
1813*7c478bd9Sstevel@tonic-gate 	case NVS_OP_GETSIZE:
1814*7c478bd9Sstevel@tonic-gate 		err = nvs_getsize_pairs(nvs, nvl, buflen);
1815*7c478bd9Sstevel@tonic-gate 		break;
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate 	default:
1818*7c478bd9Sstevel@tonic-gate 		err = EINVAL;
1819*7c478bd9Sstevel@tonic-gate 	}
1820*7c478bd9Sstevel@tonic-gate 
1821*7c478bd9Sstevel@tonic-gate 	return (err);
1822*7c478bd9Sstevel@tonic-gate }
1823*7c478bd9Sstevel@tonic-gate 
1824*7c478bd9Sstevel@tonic-gate static int
1825*7c478bd9Sstevel@tonic-gate nvs_embedded(nvstream_t *nvs, nvlist_t *embedded)
1826*7c478bd9Sstevel@tonic-gate {
1827*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
1828*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
1829*7c478bd9Sstevel@tonic-gate 		return (nvs_operation(nvs, embedded, NULL));
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE: {
1832*7c478bd9Sstevel@tonic-gate 		nvpriv_t *priv;
1833*7c478bd9Sstevel@tonic-gate 		int err;
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate 		if (embedded->nvl_version != NV_VERSION)
1836*7c478bd9Sstevel@tonic-gate 			return (ENOTSUP);
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate 		if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL)
1839*7c478bd9Sstevel@tonic-gate 			return (ENOMEM);
1840*7c478bd9Sstevel@tonic-gate 
1841*7c478bd9Sstevel@tonic-gate 		nvlist_init(embedded, embedded->nvl_nvflag, priv);
1842*7c478bd9Sstevel@tonic-gate 
1843*7c478bd9Sstevel@tonic-gate 		if ((err = nvs_operation(nvs, embedded, NULL)) != 0)
1844*7c478bd9Sstevel@tonic-gate 			nvlist_free(embedded);
1845*7c478bd9Sstevel@tonic-gate 		return (err);
1846*7c478bd9Sstevel@tonic-gate 	}
1847*7c478bd9Sstevel@tonic-gate 	default:
1848*7c478bd9Sstevel@tonic-gate 		break;
1849*7c478bd9Sstevel@tonic-gate 	}
1850*7c478bd9Sstevel@tonic-gate 
1851*7c478bd9Sstevel@tonic-gate 	return (EINVAL);
1852*7c478bd9Sstevel@tonic-gate }
1853*7c478bd9Sstevel@tonic-gate 
1854*7c478bd9Sstevel@tonic-gate static int
1855*7c478bd9Sstevel@tonic-gate nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
1856*7c478bd9Sstevel@tonic-gate {
1857*7c478bd9Sstevel@tonic-gate 	size_t nelem = NVP_NELEM(nvp);
1858*7c478bd9Sstevel@tonic-gate 	nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
1859*7c478bd9Sstevel@tonic-gate 	int i;
1860*7c478bd9Sstevel@tonic-gate 
1861*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
1862*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
1863*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem; i++)
1864*7c478bd9Sstevel@tonic-gate 			if (nvs_embedded(nvs, nvlp[i]) != 0)
1865*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
1866*7c478bd9Sstevel@tonic-gate 		break;
1867*7c478bd9Sstevel@tonic-gate 
1868*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE: {
1869*7c478bd9Sstevel@tonic-gate 		size_t len = nelem * sizeof (uint64_t);
1870*7c478bd9Sstevel@tonic-gate 		nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len);
1871*7c478bd9Sstevel@tonic-gate 
1872*7c478bd9Sstevel@tonic-gate 		bzero(nvlp, len);	/* don't trust packed data */
1873*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem; i++) {
1874*7c478bd9Sstevel@tonic-gate 			if (nvs_embedded(nvs, embedded) != 0) {
1875*7c478bd9Sstevel@tonic-gate 				nvpair_free(nvp);
1876*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
1877*7c478bd9Sstevel@tonic-gate 			}
1878*7c478bd9Sstevel@tonic-gate 
1879*7c478bd9Sstevel@tonic-gate 			nvlp[i] = embedded++;
1880*7c478bd9Sstevel@tonic-gate 		}
1881*7c478bd9Sstevel@tonic-gate 		break;
1882*7c478bd9Sstevel@tonic-gate 	}
1883*7c478bd9Sstevel@tonic-gate 	case NVS_OP_GETSIZE: {
1884*7c478bd9Sstevel@tonic-gate 		uint64_t nvsize = 0;
1885*7c478bd9Sstevel@tonic-gate 
1886*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem; i++) {
1887*7c478bd9Sstevel@tonic-gate 			size_t nvp_sz = 0;
1888*7c478bd9Sstevel@tonic-gate 
1889*7c478bd9Sstevel@tonic-gate 			if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0)
1890*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
1891*7c478bd9Sstevel@tonic-gate 
1892*7c478bd9Sstevel@tonic-gate 			if ((nvsize += nvp_sz) > INT32_MAX)
1893*7c478bd9Sstevel@tonic-gate 				return (EINVAL);
1894*7c478bd9Sstevel@tonic-gate 		}
1895*7c478bd9Sstevel@tonic-gate 
1896*7c478bd9Sstevel@tonic-gate 		*size = nvsize;
1897*7c478bd9Sstevel@tonic-gate 		break;
1898*7c478bd9Sstevel@tonic-gate 	}
1899*7c478bd9Sstevel@tonic-gate 	default:
1900*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1901*7c478bd9Sstevel@tonic-gate 	}
1902*7c478bd9Sstevel@tonic-gate 
1903*7c478bd9Sstevel@tonic-gate 	return (0);
1904*7c478bd9Sstevel@tonic-gate }
1905*7c478bd9Sstevel@tonic-gate 
1906*7c478bd9Sstevel@tonic-gate static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *);
1907*7c478bd9Sstevel@tonic-gate static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *);
1908*7c478bd9Sstevel@tonic-gate 
1909*7c478bd9Sstevel@tonic-gate /*
1910*7c478bd9Sstevel@tonic-gate  * Common routine for nvlist operations:
1911*7c478bd9Sstevel@tonic-gate  * encode, decode, getsize (encoded size).
1912*7c478bd9Sstevel@tonic-gate  */
1913*7c478bd9Sstevel@tonic-gate static int
1914*7c478bd9Sstevel@tonic-gate nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
1915*7c478bd9Sstevel@tonic-gate     int nvs_op)
1916*7c478bd9Sstevel@tonic-gate {
1917*7c478bd9Sstevel@tonic-gate 	int err = 0;
1918*7c478bd9Sstevel@tonic-gate 	nvstream_t nvs;
1919*7c478bd9Sstevel@tonic-gate 	int nvl_endian;
1920*7c478bd9Sstevel@tonic-gate #ifdef	_LITTLE_ENDIAN
1921*7c478bd9Sstevel@tonic-gate 	int host_endian = 1;
1922*7c478bd9Sstevel@tonic-gate #else
1923*7c478bd9Sstevel@tonic-gate 	int host_endian = 0;
1924*7c478bd9Sstevel@tonic-gate #endif	/* _LITTLE_ENDIAN */
1925*7c478bd9Sstevel@tonic-gate 	nvs_header_t *nvh = (void *)buf;
1926*7c478bd9Sstevel@tonic-gate 
1927*7c478bd9Sstevel@tonic-gate 	if (buflen == NULL || nvl == NULL ||
1928*7c478bd9Sstevel@tonic-gate 	    (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1929*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1930*7c478bd9Sstevel@tonic-gate 
1931*7c478bd9Sstevel@tonic-gate 	nvs.nvs_op = nvs_op;
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate 	/*
1934*7c478bd9Sstevel@tonic-gate 	 * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and
1935*7c478bd9Sstevel@tonic-gate 	 * a buffer is allocated.  The first 4 bytes in the buffer are
1936*7c478bd9Sstevel@tonic-gate 	 * used for encoding method and host endian.
1937*7c478bd9Sstevel@tonic-gate 	 */
1938*7c478bd9Sstevel@tonic-gate 	switch (nvs_op) {
1939*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
1940*7c478bd9Sstevel@tonic-gate 		if (buf == NULL || *buflen < sizeof (nvs_header_t))
1941*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1942*7c478bd9Sstevel@tonic-gate 
1943*7c478bd9Sstevel@tonic-gate 		nvh->nvh_encoding = encoding;
1944*7c478bd9Sstevel@tonic-gate 		nvh->nvh_endian = nvl_endian = host_endian;
1945*7c478bd9Sstevel@tonic-gate 		nvh->nvh_reserved1 = 0;
1946*7c478bd9Sstevel@tonic-gate 		nvh->nvh_reserved2 = 0;
1947*7c478bd9Sstevel@tonic-gate 		break;
1948*7c478bd9Sstevel@tonic-gate 
1949*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE:
1950*7c478bd9Sstevel@tonic-gate 		if (buf == NULL || *buflen < sizeof (nvs_header_t))
1951*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1952*7c478bd9Sstevel@tonic-gate 
1953*7c478bd9Sstevel@tonic-gate 		/* get method of encoding from first byte */
1954*7c478bd9Sstevel@tonic-gate 		encoding = nvh->nvh_encoding;
1955*7c478bd9Sstevel@tonic-gate 		nvl_endian = nvh->nvh_endian;
1956*7c478bd9Sstevel@tonic-gate 		break;
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate 	case NVS_OP_GETSIZE:
1959*7c478bd9Sstevel@tonic-gate 		nvl_endian = host_endian;
1960*7c478bd9Sstevel@tonic-gate 
1961*7c478bd9Sstevel@tonic-gate 		/*
1962*7c478bd9Sstevel@tonic-gate 		 * add the size for encoding
1963*7c478bd9Sstevel@tonic-gate 		 */
1964*7c478bd9Sstevel@tonic-gate 		*buflen = sizeof (nvs_header_t);
1965*7c478bd9Sstevel@tonic-gate 		break;
1966*7c478bd9Sstevel@tonic-gate 
1967*7c478bd9Sstevel@tonic-gate 	default:
1968*7c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
1969*7c478bd9Sstevel@tonic-gate 	}
1970*7c478bd9Sstevel@tonic-gate 
1971*7c478bd9Sstevel@tonic-gate 	/*
1972*7c478bd9Sstevel@tonic-gate 	 * Create an nvstream with proper encoding method
1973*7c478bd9Sstevel@tonic-gate 	 */
1974*7c478bd9Sstevel@tonic-gate 	switch (encoding) {
1975*7c478bd9Sstevel@tonic-gate 	case NV_ENCODE_NATIVE:
1976*7c478bd9Sstevel@tonic-gate 		/*
1977*7c478bd9Sstevel@tonic-gate 		 * check endianness, in case we are unpacking
1978*7c478bd9Sstevel@tonic-gate 		 * from a file
1979*7c478bd9Sstevel@tonic-gate 		 */
1980*7c478bd9Sstevel@tonic-gate 		if (nvl_endian != host_endian)
1981*7c478bd9Sstevel@tonic-gate 			return (ENOTSUP);
1982*7c478bd9Sstevel@tonic-gate 		err = nvs_native(&nvs, nvl, buf, buflen);
1983*7c478bd9Sstevel@tonic-gate 		break;
1984*7c478bd9Sstevel@tonic-gate 	case NV_ENCODE_XDR:
1985*7c478bd9Sstevel@tonic-gate 		err = nvs_xdr(&nvs, nvl, buf, buflen);
1986*7c478bd9Sstevel@tonic-gate 		break;
1987*7c478bd9Sstevel@tonic-gate 	default:
1988*7c478bd9Sstevel@tonic-gate 		err = ENOTSUP;
1989*7c478bd9Sstevel@tonic-gate 		break;
1990*7c478bd9Sstevel@tonic-gate 	}
1991*7c478bd9Sstevel@tonic-gate 
1992*7c478bd9Sstevel@tonic-gate 	return (err);
1993*7c478bd9Sstevel@tonic-gate }
1994*7c478bd9Sstevel@tonic-gate 
1995*7c478bd9Sstevel@tonic-gate int
1996*7c478bd9Sstevel@tonic-gate nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
1997*7c478bd9Sstevel@tonic-gate {
1998*7c478bd9Sstevel@tonic-gate 	return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
1999*7c478bd9Sstevel@tonic-gate }
2000*7c478bd9Sstevel@tonic-gate 
2001*7c478bd9Sstevel@tonic-gate /*
2002*7c478bd9Sstevel@tonic-gate  * Pack nvlist into contiguous memory
2003*7c478bd9Sstevel@tonic-gate  */
2004*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
2005*7c478bd9Sstevel@tonic-gate int
2006*7c478bd9Sstevel@tonic-gate nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
2007*7c478bd9Sstevel@tonic-gate     int kmflag)
2008*7c478bd9Sstevel@tonic-gate {
2009*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
2010*7c478bd9Sstevel@tonic-gate 	return (nvlist_xpack(nvl, bufp, buflen, encoding,
2011*7c478bd9Sstevel@tonic-gate 	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
2012*7c478bd9Sstevel@tonic-gate #else
2013*7c478bd9Sstevel@tonic-gate 	return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep));
2014*7c478bd9Sstevel@tonic-gate #endif
2015*7c478bd9Sstevel@tonic-gate }
2016*7c478bd9Sstevel@tonic-gate 
2017*7c478bd9Sstevel@tonic-gate int
2018*7c478bd9Sstevel@tonic-gate nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
2019*7c478bd9Sstevel@tonic-gate     nv_alloc_t *nva)
2020*7c478bd9Sstevel@tonic-gate {
2021*7c478bd9Sstevel@tonic-gate 	nvpriv_t nvpriv;
2022*7c478bd9Sstevel@tonic-gate 	size_t alloc_size;
2023*7c478bd9Sstevel@tonic-gate 	char *buf;
2024*7c478bd9Sstevel@tonic-gate 	int err;
2025*7c478bd9Sstevel@tonic-gate 
2026*7c478bd9Sstevel@tonic-gate 	if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL)
2027*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate 	if (*bufp != NULL)
2030*7c478bd9Sstevel@tonic-gate 		return (nvlist_common(nvl, *bufp, buflen, encoding,
2031*7c478bd9Sstevel@tonic-gate 		    NVS_OP_ENCODE));
2032*7c478bd9Sstevel@tonic-gate 
2033*7c478bd9Sstevel@tonic-gate 	/*
2034*7c478bd9Sstevel@tonic-gate 	 * Here is a difficult situation:
2035*7c478bd9Sstevel@tonic-gate 	 * 1. The nvlist has fixed allocator properties.
2036*7c478bd9Sstevel@tonic-gate 	 *    All other nvlist routines (like nvlist_add_*, ...) use
2037*7c478bd9Sstevel@tonic-gate 	 *    these properties.
2038*7c478bd9Sstevel@tonic-gate 	 * 2. When using nvlist_pack() the user can specify his own
2039*7c478bd9Sstevel@tonic-gate 	 *    allocator properties (e.g. by using KM_NOSLEEP).
2040*7c478bd9Sstevel@tonic-gate 	 *
2041*7c478bd9Sstevel@tonic-gate 	 * We use the user specified properties (2). A clearer solution
2042*7c478bd9Sstevel@tonic-gate 	 * will be to remove the kmflag from nvlist_pack(), but we will
2043*7c478bd9Sstevel@tonic-gate 	 * not change the interface.
2044*7c478bd9Sstevel@tonic-gate 	 */
2045*7c478bd9Sstevel@tonic-gate 	nv_priv_init(&nvpriv, nva, 0);
2046*7c478bd9Sstevel@tonic-gate 
2047*7c478bd9Sstevel@tonic-gate 	if (err = nvlist_size(nvl, &alloc_size, encoding))
2048*7c478bd9Sstevel@tonic-gate 		return (err);
2049*7c478bd9Sstevel@tonic-gate 
2050*7c478bd9Sstevel@tonic-gate 	if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL)
2051*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
2052*7c478bd9Sstevel@tonic-gate 
2053*7c478bd9Sstevel@tonic-gate 	if ((err = nvlist_common(nvl, buf, &alloc_size, encoding,
2054*7c478bd9Sstevel@tonic-gate 	    NVS_OP_ENCODE)) != 0) {
2055*7c478bd9Sstevel@tonic-gate 		nv_mem_free(&nvpriv, buf, alloc_size);
2056*7c478bd9Sstevel@tonic-gate 	} else {
2057*7c478bd9Sstevel@tonic-gate 		*buflen = alloc_size;
2058*7c478bd9Sstevel@tonic-gate 		*bufp = buf;
2059*7c478bd9Sstevel@tonic-gate 	}
2060*7c478bd9Sstevel@tonic-gate 
2061*7c478bd9Sstevel@tonic-gate 	return (err);
2062*7c478bd9Sstevel@tonic-gate }
2063*7c478bd9Sstevel@tonic-gate 
2064*7c478bd9Sstevel@tonic-gate /*
2065*7c478bd9Sstevel@tonic-gate  * Unpack buf into an nvlist_t
2066*7c478bd9Sstevel@tonic-gate  */
2067*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
2068*7c478bd9Sstevel@tonic-gate int
2069*7c478bd9Sstevel@tonic-gate nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag)
2070*7c478bd9Sstevel@tonic-gate {
2071*7c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
2072*7c478bd9Sstevel@tonic-gate 	return (nvlist_xunpack(buf, buflen, nvlp,
2073*7c478bd9Sstevel@tonic-gate 	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
2074*7c478bd9Sstevel@tonic-gate #else
2075*7c478bd9Sstevel@tonic-gate 	return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep));
2076*7c478bd9Sstevel@tonic-gate #endif
2077*7c478bd9Sstevel@tonic-gate }
2078*7c478bd9Sstevel@tonic-gate 
2079*7c478bd9Sstevel@tonic-gate int
2080*7c478bd9Sstevel@tonic-gate nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva)
2081*7c478bd9Sstevel@tonic-gate {
2082*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
2083*7c478bd9Sstevel@tonic-gate 	int err;
2084*7c478bd9Sstevel@tonic-gate 
2085*7c478bd9Sstevel@tonic-gate 	if (nvlp == NULL)
2086*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2087*7c478bd9Sstevel@tonic-gate 
2088*7c478bd9Sstevel@tonic-gate 	if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0)
2089*7c478bd9Sstevel@tonic-gate 		return (err);
2090*7c478bd9Sstevel@tonic-gate 
2091*7c478bd9Sstevel@tonic-gate 	if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0)
2092*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
2093*7c478bd9Sstevel@tonic-gate 	else
2094*7c478bd9Sstevel@tonic-gate 		*nvlp = nvl;
2095*7c478bd9Sstevel@tonic-gate 
2096*7c478bd9Sstevel@tonic-gate 	return (err);
2097*7c478bd9Sstevel@tonic-gate }
2098*7c478bd9Sstevel@tonic-gate 
2099*7c478bd9Sstevel@tonic-gate /*
2100*7c478bd9Sstevel@tonic-gate  * Native encoding functions
2101*7c478bd9Sstevel@tonic-gate  */
2102*7c478bd9Sstevel@tonic-gate typedef struct {
2103*7c478bd9Sstevel@tonic-gate 	/*
2104*7c478bd9Sstevel@tonic-gate 	 * This structure is used when decoding a packed nvpair in
2105*7c478bd9Sstevel@tonic-gate 	 * the native format.  n_base points to a buffer containing the
2106*7c478bd9Sstevel@tonic-gate 	 * packed nvpair.  n_end is a pointer to the end of the buffer.
2107*7c478bd9Sstevel@tonic-gate 	 * (n_end actually points to the first byte past the end of the
2108*7c478bd9Sstevel@tonic-gate 	 * buffer.)  n_curr is a pointer that lies between n_base and n_end.
2109*7c478bd9Sstevel@tonic-gate 	 * It points to the current data that we are decoding.
2110*7c478bd9Sstevel@tonic-gate 	 * The amount of data left in the buffer is equal to n_end - n_curr.
2111*7c478bd9Sstevel@tonic-gate 	 * n_flag is used to recognize a packed embedded list.
2112*7c478bd9Sstevel@tonic-gate 	 */
2113*7c478bd9Sstevel@tonic-gate 	caddr_t n_base;
2114*7c478bd9Sstevel@tonic-gate 	caddr_t n_end;
2115*7c478bd9Sstevel@tonic-gate 	caddr_t n_curr;
2116*7c478bd9Sstevel@tonic-gate 	uint_t  n_flag;
2117*7c478bd9Sstevel@tonic-gate } nvs_native_t;
2118*7c478bd9Sstevel@tonic-gate 
2119*7c478bd9Sstevel@tonic-gate static int
2120*7c478bd9Sstevel@tonic-gate nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf,
2121*7c478bd9Sstevel@tonic-gate     size_t buflen)
2122*7c478bd9Sstevel@tonic-gate {
2123*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2124*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
2125*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE:
2126*7c478bd9Sstevel@tonic-gate 		nvs->nvs_private = native;
2127*7c478bd9Sstevel@tonic-gate 		native->n_curr = native->n_base = buf;
2128*7c478bd9Sstevel@tonic-gate 		native->n_end = buf + buflen;
2129*7c478bd9Sstevel@tonic-gate 		native->n_flag = 0;
2130*7c478bd9Sstevel@tonic-gate 		return (0);
2131*7c478bd9Sstevel@tonic-gate 
2132*7c478bd9Sstevel@tonic-gate 	case NVS_OP_GETSIZE:
2133*7c478bd9Sstevel@tonic-gate 		nvs->nvs_private = native;
2134*7c478bd9Sstevel@tonic-gate 		native->n_curr = native->n_base = native->n_end = NULL;
2135*7c478bd9Sstevel@tonic-gate 		native->n_flag = 0;
2136*7c478bd9Sstevel@tonic-gate 		return (0);
2137*7c478bd9Sstevel@tonic-gate 	default:
2138*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2139*7c478bd9Sstevel@tonic-gate 	}
2140*7c478bd9Sstevel@tonic-gate }
2141*7c478bd9Sstevel@tonic-gate 
2142*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2143*7c478bd9Sstevel@tonic-gate static void
2144*7c478bd9Sstevel@tonic-gate nvs_native_destroy(nvstream_t *nvs)
2145*7c478bd9Sstevel@tonic-gate {
2146*7c478bd9Sstevel@tonic-gate }
2147*7c478bd9Sstevel@tonic-gate 
2148*7c478bd9Sstevel@tonic-gate static int
2149*7c478bd9Sstevel@tonic-gate native_cp(nvstream_t *nvs, void *buf, size_t size)
2150*7c478bd9Sstevel@tonic-gate {
2151*7c478bd9Sstevel@tonic-gate 	nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2152*7c478bd9Sstevel@tonic-gate 
2153*7c478bd9Sstevel@tonic-gate 	if (native->n_curr + size > native->n_end)
2154*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2155*7c478bd9Sstevel@tonic-gate 
2156*7c478bd9Sstevel@tonic-gate 	/*
2157*7c478bd9Sstevel@tonic-gate 	 * The bcopy() below eliminates alignment requirement
2158*7c478bd9Sstevel@tonic-gate 	 * on the buffer (stream) and is preferred over direct access.
2159*7c478bd9Sstevel@tonic-gate 	 */
2160*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2161*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
2162*7c478bd9Sstevel@tonic-gate 		bcopy(buf, native->n_curr, size);
2163*7c478bd9Sstevel@tonic-gate 		break;
2164*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE:
2165*7c478bd9Sstevel@tonic-gate 		bcopy(native->n_curr, buf, size);
2166*7c478bd9Sstevel@tonic-gate 		break;
2167*7c478bd9Sstevel@tonic-gate 	default:
2168*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2169*7c478bd9Sstevel@tonic-gate 	}
2170*7c478bd9Sstevel@tonic-gate 
2171*7c478bd9Sstevel@tonic-gate 	native->n_curr += size;
2172*7c478bd9Sstevel@tonic-gate 	return (0);
2173*7c478bd9Sstevel@tonic-gate }
2174*7c478bd9Sstevel@tonic-gate 
2175*7c478bd9Sstevel@tonic-gate /*
2176*7c478bd9Sstevel@tonic-gate  * operate on nvlist_t header
2177*7c478bd9Sstevel@tonic-gate  */
2178*7c478bd9Sstevel@tonic-gate static int
2179*7c478bd9Sstevel@tonic-gate nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
2180*7c478bd9Sstevel@tonic-gate {
2181*7c478bd9Sstevel@tonic-gate 	nvs_native_t *native = nvs->nvs_private;
2182*7c478bd9Sstevel@tonic-gate 
2183*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2184*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
2185*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE:
2186*7c478bd9Sstevel@tonic-gate 		if (native->n_flag)
2187*7c478bd9Sstevel@tonic-gate 			return (0);	/* packed embedded list */
2188*7c478bd9Sstevel@tonic-gate 
2189*7c478bd9Sstevel@tonic-gate 		native->n_flag = 1;
2190*7c478bd9Sstevel@tonic-gate 
2191*7c478bd9Sstevel@tonic-gate 		/* copy version and nvflag of the nvlist_t */
2192*7c478bd9Sstevel@tonic-gate 		if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 ||
2193*7c478bd9Sstevel@tonic-gate 		    native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0)
2194*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2195*7c478bd9Sstevel@tonic-gate 
2196*7c478bd9Sstevel@tonic-gate 		return (0);
2197*7c478bd9Sstevel@tonic-gate 
2198*7c478bd9Sstevel@tonic-gate 	case NVS_OP_GETSIZE:
2199*7c478bd9Sstevel@tonic-gate 		/*
2200*7c478bd9Sstevel@tonic-gate 		 * if calculate for packed embedded list
2201*7c478bd9Sstevel@tonic-gate 		 * 	4 for end of the embedded list
2202*7c478bd9Sstevel@tonic-gate 		 * else
2203*7c478bd9Sstevel@tonic-gate 		 * 	2 * sizeof (int32_t) for nvl_version and nvl_nvflag
2204*7c478bd9Sstevel@tonic-gate 		 * 	and 4 for end of the entire list
2205*7c478bd9Sstevel@tonic-gate 		 */
2206*7c478bd9Sstevel@tonic-gate 		if (native->n_flag) {
2207*7c478bd9Sstevel@tonic-gate 			*size += 4;
2208*7c478bd9Sstevel@tonic-gate 		} else {
2209*7c478bd9Sstevel@tonic-gate 			native->n_flag = 1;
2210*7c478bd9Sstevel@tonic-gate 			*size += 2 * sizeof (int32_t) + 4;
2211*7c478bd9Sstevel@tonic-gate 		}
2212*7c478bd9Sstevel@tonic-gate 
2213*7c478bd9Sstevel@tonic-gate 		return (0);
2214*7c478bd9Sstevel@tonic-gate 
2215*7c478bd9Sstevel@tonic-gate 	default:
2216*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2217*7c478bd9Sstevel@tonic-gate 	}
2218*7c478bd9Sstevel@tonic-gate }
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate static int
2221*7c478bd9Sstevel@tonic-gate nvs_native_nvl_fini(nvstream_t *nvs)
2222*7c478bd9Sstevel@tonic-gate {
2223*7c478bd9Sstevel@tonic-gate 	if (nvs->nvs_op == NVS_OP_ENCODE) {
2224*7c478bd9Sstevel@tonic-gate 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2225*7c478bd9Sstevel@tonic-gate 		/*
2226*7c478bd9Sstevel@tonic-gate 		 * Add 4 zero bytes at end of nvlist. They are used
2227*7c478bd9Sstevel@tonic-gate 		 * for end detection by the decode routine.
2228*7c478bd9Sstevel@tonic-gate 		 */
2229*7c478bd9Sstevel@tonic-gate 		if (native->n_curr + sizeof (int) > native->n_end)
2230*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2231*7c478bd9Sstevel@tonic-gate 
2232*7c478bd9Sstevel@tonic-gate 		bzero(native->n_curr, sizeof (int));
2233*7c478bd9Sstevel@tonic-gate 		native->n_curr += sizeof (int);
2234*7c478bd9Sstevel@tonic-gate 	}
2235*7c478bd9Sstevel@tonic-gate 
2236*7c478bd9Sstevel@tonic-gate 	return (0);
2237*7c478bd9Sstevel@tonic-gate }
2238*7c478bd9Sstevel@tonic-gate 
2239*7c478bd9Sstevel@tonic-gate static int
2240*7c478bd9Sstevel@tonic-gate nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp)
2241*7c478bd9Sstevel@tonic-gate {
2242*7c478bd9Sstevel@tonic-gate 	if (nvs->nvs_op == NVS_OP_ENCODE) {
2243*7c478bd9Sstevel@tonic-gate 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2244*7c478bd9Sstevel@tonic-gate 		nvlist_t *packed = (void *)
2245*7c478bd9Sstevel@tonic-gate 		    (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
2246*7c478bd9Sstevel@tonic-gate 		/*
2247*7c478bd9Sstevel@tonic-gate 		 * Null out the pointer that is meaningless in the packed
2248*7c478bd9Sstevel@tonic-gate 		 * structure. The address may not be aligned, so we have
2249*7c478bd9Sstevel@tonic-gate 		 * to use bzero.
2250*7c478bd9Sstevel@tonic-gate 		 */
2251*7c478bd9Sstevel@tonic-gate 		bzero(&packed->nvl_priv, sizeof (packed->nvl_priv));
2252*7c478bd9Sstevel@tonic-gate 	}
2253*7c478bd9Sstevel@tonic-gate 
2254*7c478bd9Sstevel@tonic-gate 	return (nvs_embedded(nvs, EMBEDDED_NVL(nvp)));
2255*7c478bd9Sstevel@tonic-gate }
2256*7c478bd9Sstevel@tonic-gate 
2257*7c478bd9Sstevel@tonic-gate static int
2258*7c478bd9Sstevel@tonic-gate nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp)
2259*7c478bd9Sstevel@tonic-gate {
2260*7c478bd9Sstevel@tonic-gate 	if (nvs->nvs_op == NVS_OP_ENCODE) {
2261*7c478bd9Sstevel@tonic-gate 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2262*7c478bd9Sstevel@tonic-gate 		char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp);
2263*7c478bd9Sstevel@tonic-gate 		size_t len = NVP_NELEM(nvp) * sizeof (uint64_t);
2264*7c478bd9Sstevel@tonic-gate 		nvlist_t *packed = (nvlist_t *)((uintptr_t)value + len);
2265*7c478bd9Sstevel@tonic-gate 		int i;
2266*7c478bd9Sstevel@tonic-gate 		/*
2267*7c478bd9Sstevel@tonic-gate 		 * Null out pointers that are meaningless in the packed
2268*7c478bd9Sstevel@tonic-gate 		 * structure. The addresses may not be aligned, so we have
2269*7c478bd9Sstevel@tonic-gate 		 * to use bzero.
2270*7c478bd9Sstevel@tonic-gate 		 */
2271*7c478bd9Sstevel@tonic-gate 		bzero(value, len);
2272*7c478bd9Sstevel@tonic-gate 
2273*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < NVP_NELEM(nvp); i++, packed++)
2274*7c478bd9Sstevel@tonic-gate 			/*
2275*7c478bd9Sstevel@tonic-gate 			 * Null out the pointer that is meaningless in the
2276*7c478bd9Sstevel@tonic-gate 			 * packed structure. The address may not be aligned,
2277*7c478bd9Sstevel@tonic-gate 			 * so we have to use bzero.
2278*7c478bd9Sstevel@tonic-gate 			 */
2279*7c478bd9Sstevel@tonic-gate 			bzero(&packed->nvl_priv, sizeof (packed->nvl_priv));
2280*7c478bd9Sstevel@tonic-gate 	}
2281*7c478bd9Sstevel@tonic-gate 
2282*7c478bd9Sstevel@tonic-gate 	return (nvs_embedded_nvl_array(nvs, nvp, NULL));
2283*7c478bd9Sstevel@tonic-gate }
2284*7c478bd9Sstevel@tonic-gate 
2285*7c478bd9Sstevel@tonic-gate static void
2286*7c478bd9Sstevel@tonic-gate nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp)
2287*7c478bd9Sstevel@tonic-gate {
2288*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2289*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE: {
2290*7c478bd9Sstevel@tonic-gate 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2291*7c478bd9Sstevel@tonic-gate 		uint64_t *strp = (void *)
2292*7c478bd9Sstevel@tonic-gate 		    (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
2293*7c478bd9Sstevel@tonic-gate 		/*
2294*7c478bd9Sstevel@tonic-gate 		 * Null out pointers that are meaningless in the packed
2295*7c478bd9Sstevel@tonic-gate 		 * structure. The addresses may not be aligned, so we have
2296*7c478bd9Sstevel@tonic-gate 		 * to use bzero.
2297*7c478bd9Sstevel@tonic-gate 		 */
2298*7c478bd9Sstevel@tonic-gate 		bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t));
2299*7c478bd9Sstevel@tonic-gate 		break;
2300*7c478bd9Sstevel@tonic-gate 	}
2301*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE: {
2302*7c478bd9Sstevel@tonic-gate 		char **strp = (void *)NVP_VALUE(nvp);
2303*7c478bd9Sstevel@tonic-gate 		char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t));
2304*7c478bd9Sstevel@tonic-gate 		int i;
2305*7c478bd9Sstevel@tonic-gate 
2306*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < NVP_NELEM(nvp); i++) {
2307*7c478bd9Sstevel@tonic-gate 			strp[i] = buf;
2308*7c478bd9Sstevel@tonic-gate 			buf += strlen(buf) + 1;
2309*7c478bd9Sstevel@tonic-gate 		}
2310*7c478bd9Sstevel@tonic-gate 		break;
2311*7c478bd9Sstevel@tonic-gate 	}
2312*7c478bd9Sstevel@tonic-gate 	}
2313*7c478bd9Sstevel@tonic-gate }
2314*7c478bd9Sstevel@tonic-gate 
2315*7c478bd9Sstevel@tonic-gate static int
2316*7c478bd9Sstevel@tonic-gate nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
2317*7c478bd9Sstevel@tonic-gate {
2318*7c478bd9Sstevel@tonic-gate 	data_type_t type;
2319*7c478bd9Sstevel@tonic-gate 	int value_sz;
2320*7c478bd9Sstevel@tonic-gate 	int ret = 0;
2321*7c478bd9Sstevel@tonic-gate 
2322*7c478bd9Sstevel@tonic-gate 	/*
2323*7c478bd9Sstevel@tonic-gate 	 * We do the initial bcopy of the data before we look at
2324*7c478bd9Sstevel@tonic-gate 	 * the nvpair type, because when we're decoding, we won't
2325*7c478bd9Sstevel@tonic-gate 	 * have the correct values for the pair until we do the bcopy.
2326*7c478bd9Sstevel@tonic-gate 	 */
2327*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2328*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
2329*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE:
2330*7c478bd9Sstevel@tonic-gate 		if (native_cp(nvs, nvp, nvp->nvp_size) != 0)
2331*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2332*7c478bd9Sstevel@tonic-gate 		break;
2333*7c478bd9Sstevel@tonic-gate 	default:
2334*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2335*7c478bd9Sstevel@tonic-gate 	}
2336*7c478bd9Sstevel@tonic-gate 
2337*7c478bd9Sstevel@tonic-gate 	/* verify nvp_name_sz, check the name string length */
2338*7c478bd9Sstevel@tonic-gate 	if (i_validate_nvpair_name(nvp) != 0)
2339*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2340*7c478bd9Sstevel@tonic-gate 
2341*7c478bd9Sstevel@tonic-gate 	type = NVP_TYPE(nvp);
2342*7c478bd9Sstevel@tonic-gate 
2343*7c478bd9Sstevel@tonic-gate 	/*
2344*7c478bd9Sstevel@tonic-gate 	 * Verify type and nelem and get the value size.
2345*7c478bd9Sstevel@tonic-gate 	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
2346*7c478bd9Sstevel@tonic-gate 	 * is the size of the string(s) excluded.
2347*7c478bd9Sstevel@tonic-gate 	 */
2348*7c478bd9Sstevel@tonic-gate 	if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0)
2349*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2350*7c478bd9Sstevel@tonic-gate 
2351*7c478bd9Sstevel@tonic-gate 	if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size)
2352*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2353*7c478bd9Sstevel@tonic-gate 
2354*7c478bd9Sstevel@tonic-gate 	switch (type) {
2355*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
2356*7c478bd9Sstevel@tonic-gate 		ret = nvpair_native_embedded(nvs, nvp);
2357*7c478bd9Sstevel@tonic-gate 		break;
2358*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY:
2359*7c478bd9Sstevel@tonic-gate 		ret = nvpair_native_embedded_array(nvs, nvp);
2360*7c478bd9Sstevel@tonic-gate 		break;
2361*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING_ARRAY:
2362*7c478bd9Sstevel@tonic-gate 		nvpair_native_string_array(nvs, nvp);
2363*7c478bd9Sstevel@tonic-gate 		break;
2364*7c478bd9Sstevel@tonic-gate 	default:
2365*7c478bd9Sstevel@tonic-gate 		break;
2366*7c478bd9Sstevel@tonic-gate 	}
2367*7c478bd9Sstevel@tonic-gate 
2368*7c478bd9Sstevel@tonic-gate 	return (ret);
2369*7c478bd9Sstevel@tonic-gate }
2370*7c478bd9Sstevel@tonic-gate 
2371*7c478bd9Sstevel@tonic-gate static int
2372*7c478bd9Sstevel@tonic-gate nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2373*7c478bd9Sstevel@tonic-gate {
2374*7c478bd9Sstevel@tonic-gate 	uint64_t nvp_sz = nvp->nvp_size;
2375*7c478bd9Sstevel@tonic-gate 
2376*7c478bd9Sstevel@tonic-gate 	switch (NVP_TYPE(nvp)) {
2377*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST: {
2378*7c478bd9Sstevel@tonic-gate 		size_t nvsize = 0;
2379*7c478bd9Sstevel@tonic-gate 
2380*7c478bd9Sstevel@tonic-gate 		if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0)
2381*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
2382*7c478bd9Sstevel@tonic-gate 
2383*7c478bd9Sstevel@tonic-gate 		nvp_sz += nvsize;
2384*7c478bd9Sstevel@tonic-gate 		break;
2385*7c478bd9Sstevel@tonic-gate 	}
2386*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY: {
2387*7c478bd9Sstevel@tonic-gate 		size_t nvsize;
2388*7c478bd9Sstevel@tonic-gate 
2389*7c478bd9Sstevel@tonic-gate 		if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0)
2390*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
2391*7c478bd9Sstevel@tonic-gate 
2392*7c478bd9Sstevel@tonic-gate 		nvp_sz += nvsize;
2393*7c478bd9Sstevel@tonic-gate 		break;
2394*7c478bd9Sstevel@tonic-gate 	}
2395*7c478bd9Sstevel@tonic-gate 	default:
2396*7c478bd9Sstevel@tonic-gate 		break;
2397*7c478bd9Sstevel@tonic-gate 	}
2398*7c478bd9Sstevel@tonic-gate 
2399*7c478bd9Sstevel@tonic-gate 	if (nvp_sz > INT32_MAX)
2400*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2401*7c478bd9Sstevel@tonic-gate 
2402*7c478bd9Sstevel@tonic-gate 	*size = nvp_sz;
2403*7c478bd9Sstevel@tonic-gate 
2404*7c478bd9Sstevel@tonic-gate 	return (0);
2405*7c478bd9Sstevel@tonic-gate }
2406*7c478bd9Sstevel@tonic-gate 
2407*7c478bd9Sstevel@tonic-gate static int
2408*7c478bd9Sstevel@tonic-gate nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2409*7c478bd9Sstevel@tonic-gate {
2410*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2411*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
2412*7c478bd9Sstevel@tonic-gate 		return (nvs_native_nvp_op(nvs, nvp));
2413*7c478bd9Sstevel@tonic-gate 
2414*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE: {
2415*7c478bd9Sstevel@tonic-gate 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2416*7c478bd9Sstevel@tonic-gate 		int32_t decode_len;
2417*7c478bd9Sstevel@tonic-gate 
2418*7c478bd9Sstevel@tonic-gate 		/* try to read the size value from the stream */
2419*7c478bd9Sstevel@tonic-gate 		if (native->n_curr + sizeof (int32_t) > native->n_end)
2420*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2421*7c478bd9Sstevel@tonic-gate 		bcopy(native->n_curr, &decode_len, sizeof (int32_t));
2422*7c478bd9Sstevel@tonic-gate 
2423*7c478bd9Sstevel@tonic-gate 		/* sanity check the size value */
2424*7c478bd9Sstevel@tonic-gate 		if (decode_len < 0 ||
2425*7c478bd9Sstevel@tonic-gate 		    decode_len > native->n_end - native->n_curr)
2426*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2427*7c478bd9Sstevel@tonic-gate 
2428*7c478bd9Sstevel@tonic-gate 		*size = decode_len;
2429*7c478bd9Sstevel@tonic-gate 
2430*7c478bd9Sstevel@tonic-gate 		/*
2431*7c478bd9Sstevel@tonic-gate 		 * If at the end of the stream then move the cursor
2432*7c478bd9Sstevel@tonic-gate 		 * forward, otherwise nvpair_native_op() will read
2433*7c478bd9Sstevel@tonic-gate 		 * the entire nvpair at the same cursor position.
2434*7c478bd9Sstevel@tonic-gate 		 */
2435*7c478bd9Sstevel@tonic-gate 		if (*size == 0)
2436*7c478bd9Sstevel@tonic-gate 			native->n_curr += sizeof (int32_t);
2437*7c478bd9Sstevel@tonic-gate 		break;
2438*7c478bd9Sstevel@tonic-gate 	}
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate 	default:
2441*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2442*7c478bd9Sstevel@tonic-gate 	}
2443*7c478bd9Sstevel@tonic-gate 
2444*7c478bd9Sstevel@tonic-gate 	return (0);
2445*7c478bd9Sstevel@tonic-gate }
2446*7c478bd9Sstevel@tonic-gate 
2447*7c478bd9Sstevel@tonic-gate static const nvs_ops_t nvs_native_ops = {
2448*7c478bd9Sstevel@tonic-gate 	nvs_native_nvlist,
2449*7c478bd9Sstevel@tonic-gate 	nvs_native_nvpair,
2450*7c478bd9Sstevel@tonic-gate 	nvs_native_nvp_op,
2451*7c478bd9Sstevel@tonic-gate 	nvs_native_nvp_size,
2452*7c478bd9Sstevel@tonic-gate 	nvs_native_nvl_fini
2453*7c478bd9Sstevel@tonic-gate };
2454*7c478bd9Sstevel@tonic-gate 
2455*7c478bd9Sstevel@tonic-gate static int
2456*7c478bd9Sstevel@tonic-gate nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
2457*7c478bd9Sstevel@tonic-gate {
2458*7c478bd9Sstevel@tonic-gate 	nvs_native_t native;
2459*7c478bd9Sstevel@tonic-gate 	int err;
2460*7c478bd9Sstevel@tonic-gate 
2461*7c478bd9Sstevel@tonic-gate 	nvs->nvs_ops = &nvs_native_ops;
2462*7c478bd9Sstevel@tonic-gate 
2463*7c478bd9Sstevel@tonic-gate 	if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t),
2464*7c478bd9Sstevel@tonic-gate 	    *buflen - sizeof (nvs_header_t))) != 0)
2465*7c478bd9Sstevel@tonic-gate 		return (err);
2466*7c478bd9Sstevel@tonic-gate 
2467*7c478bd9Sstevel@tonic-gate 	err = nvs_operation(nvs, nvl, buflen);
2468*7c478bd9Sstevel@tonic-gate 
2469*7c478bd9Sstevel@tonic-gate 	nvs_native_destroy(nvs);
2470*7c478bd9Sstevel@tonic-gate 
2471*7c478bd9Sstevel@tonic-gate 	return (err);
2472*7c478bd9Sstevel@tonic-gate }
2473*7c478bd9Sstevel@tonic-gate 
2474*7c478bd9Sstevel@tonic-gate /*
2475*7c478bd9Sstevel@tonic-gate  * XDR encoding functions
2476*7c478bd9Sstevel@tonic-gate  *
2477*7c478bd9Sstevel@tonic-gate  * An xdr packed nvlist is encoded as:
2478*7c478bd9Sstevel@tonic-gate  *
2479*7c478bd9Sstevel@tonic-gate  *  - encoding methode and host endian (4 bytes)
2480*7c478bd9Sstevel@tonic-gate  *  - nvl_version (4 bytes)
2481*7c478bd9Sstevel@tonic-gate  *  - nvl_nvflag (4 bytes)
2482*7c478bd9Sstevel@tonic-gate  *
2483*7c478bd9Sstevel@tonic-gate  *  - encoded nvpairs, the format of one xdr encoded nvpair is:
2484*7c478bd9Sstevel@tonic-gate  *	- encoded size of the nvpair (4 bytes)
2485*7c478bd9Sstevel@tonic-gate  *	- decoded size of the nvpair (4 bytes)
2486*7c478bd9Sstevel@tonic-gate  *	- name string, (4 + sizeof(NV_ALIGN4(string))
2487*7c478bd9Sstevel@tonic-gate  *	  a string is coded as size (4 bytes) and data
2488*7c478bd9Sstevel@tonic-gate  *	- data type (4 bytes)
2489*7c478bd9Sstevel@tonic-gate  *	- number of elements in the nvpair (4 bytes)
2490*7c478bd9Sstevel@tonic-gate  *	- data
2491*7c478bd9Sstevel@tonic-gate  *
2492*7c478bd9Sstevel@tonic-gate  *  - 2 zero's for end of the entire list (8 bytes)
2493*7c478bd9Sstevel@tonic-gate  */
2494*7c478bd9Sstevel@tonic-gate static int
2495*7c478bd9Sstevel@tonic-gate nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen)
2496*7c478bd9Sstevel@tonic-gate {
2497*7c478bd9Sstevel@tonic-gate 	/* xdr data must be 4 byte aligned */
2498*7c478bd9Sstevel@tonic-gate 	if ((ulong_t)buf % 4 != 0)
2499*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2500*7c478bd9Sstevel@tonic-gate 
2501*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2502*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
2503*7c478bd9Sstevel@tonic-gate 		xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE);
2504*7c478bd9Sstevel@tonic-gate 		nvs->nvs_private = xdr;
2505*7c478bd9Sstevel@tonic-gate 		return (0);
2506*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE:
2507*7c478bd9Sstevel@tonic-gate 		xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE);
2508*7c478bd9Sstevel@tonic-gate 		nvs->nvs_private = xdr;
2509*7c478bd9Sstevel@tonic-gate 		return (0);
2510*7c478bd9Sstevel@tonic-gate 	case NVS_OP_GETSIZE:
2511*7c478bd9Sstevel@tonic-gate 		nvs->nvs_private = NULL;
2512*7c478bd9Sstevel@tonic-gate 		return (0);
2513*7c478bd9Sstevel@tonic-gate 	default:
2514*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2515*7c478bd9Sstevel@tonic-gate 	}
2516*7c478bd9Sstevel@tonic-gate }
2517*7c478bd9Sstevel@tonic-gate 
2518*7c478bd9Sstevel@tonic-gate static void
2519*7c478bd9Sstevel@tonic-gate nvs_xdr_destroy(nvstream_t *nvs)
2520*7c478bd9Sstevel@tonic-gate {
2521*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2522*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
2523*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE:
2524*7c478bd9Sstevel@tonic-gate 		xdr_destroy((XDR *)nvs->nvs_private);
2525*7c478bd9Sstevel@tonic-gate 		break;
2526*7c478bd9Sstevel@tonic-gate 	default:
2527*7c478bd9Sstevel@tonic-gate 		break;
2528*7c478bd9Sstevel@tonic-gate 	}
2529*7c478bd9Sstevel@tonic-gate }
2530*7c478bd9Sstevel@tonic-gate 
2531*7c478bd9Sstevel@tonic-gate static int
2532*7c478bd9Sstevel@tonic-gate nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
2533*7c478bd9Sstevel@tonic-gate {
2534*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2535*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE:
2536*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE: {
2537*7c478bd9Sstevel@tonic-gate 		XDR 	*xdr = nvs->nvs_private;
2538*7c478bd9Sstevel@tonic-gate 
2539*7c478bd9Sstevel@tonic-gate 		if (!xdr_int(xdr, &nvl->nvl_version) ||
2540*7c478bd9Sstevel@tonic-gate 		    !xdr_u_int(xdr, &nvl->nvl_nvflag))
2541*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2542*7c478bd9Sstevel@tonic-gate 		break;
2543*7c478bd9Sstevel@tonic-gate 	}
2544*7c478bd9Sstevel@tonic-gate 	case NVS_OP_GETSIZE: {
2545*7c478bd9Sstevel@tonic-gate 		/*
2546*7c478bd9Sstevel@tonic-gate 		 * 2 * 4 for nvl_version + nvl_nvflag
2547*7c478bd9Sstevel@tonic-gate 		 * and 8 for end of the entire list
2548*7c478bd9Sstevel@tonic-gate 		 */
2549*7c478bd9Sstevel@tonic-gate 		*size += 2 * 4 + 8;
2550*7c478bd9Sstevel@tonic-gate 		break;
2551*7c478bd9Sstevel@tonic-gate 	}
2552*7c478bd9Sstevel@tonic-gate 	default:
2553*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2554*7c478bd9Sstevel@tonic-gate 	}
2555*7c478bd9Sstevel@tonic-gate 	return (0);
2556*7c478bd9Sstevel@tonic-gate }
2557*7c478bd9Sstevel@tonic-gate 
2558*7c478bd9Sstevel@tonic-gate static int
2559*7c478bd9Sstevel@tonic-gate nvs_xdr_nvl_fini(nvstream_t *nvs)
2560*7c478bd9Sstevel@tonic-gate {
2561*7c478bd9Sstevel@tonic-gate 	if (nvs->nvs_op == NVS_OP_ENCODE) {
2562*7c478bd9Sstevel@tonic-gate 		XDR *xdr = nvs->nvs_private;
2563*7c478bd9Sstevel@tonic-gate 		int zero = 0;
2564*7c478bd9Sstevel@tonic-gate 
2565*7c478bd9Sstevel@tonic-gate 		if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero))
2566*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2567*7c478bd9Sstevel@tonic-gate 	}
2568*7c478bd9Sstevel@tonic-gate 
2569*7c478bd9Sstevel@tonic-gate 	return (0);
2570*7c478bd9Sstevel@tonic-gate }
2571*7c478bd9Sstevel@tonic-gate 
2572*7c478bd9Sstevel@tonic-gate /*
2573*7c478bd9Sstevel@tonic-gate  * The format of xdr encoded nvpair is:
2574*7c478bd9Sstevel@tonic-gate  * encode_size, decode_size, name string, data type, nelem, data
2575*7c478bd9Sstevel@tonic-gate  */
2576*7c478bd9Sstevel@tonic-gate static int
2577*7c478bd9Sstevel@tonic-gate nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
2578*7c478bd9Sstevel@tonic-gate {
2579*7c478bd9Sstevel@tonic-gate 	data_type_t type;
2580*7c478bd9Sstevel@tonic-gate 	char	*buf;
2581*7c478bd9Sstevel@tonic-gate 	char	*buf_end = (char *)nvp + nvp->nvp_size;
2582*7c478bd9Sstevel@tonic-gate 	int	value_sz;
2583*7c478bd9Sstevel@tonic-gate 	uint_t	nelem, buflen;
2584*7c478bd9Sstevel@tonic-gate 	bool_t	ret = FALSE;
2585*7c478bd9Sstevel@tonic-gate 	XDR	*xdr = nvs->nvs_private;
2586*7c478bd9Sstevel@tonic-gate 
2587*7c478bd9Sstevel@tonic-gate 	ASSERT(xdr != NULL && nvp != NULL);
2588*7c478bd9Sstevel@tonic-gate 
2589*7c478bd9Sstevel@tonic-gate 	/* name string */
2590*7c478bd9Sstevel@tonic-gate 	if ((buf = NVP_NAME(nvp)) >= buf_end)
2591*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2592*7c478bd9Sstevel@tonic-gate 	buflen = buf_end - buf;
2593*7c478bd9Sstevel@tonic-gate 
2594*7c478bd9Sstevel@tonic-gate 	if (!xdr_string(xdr, &buf, buflen - 1))
2595*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2596*7c478bd9Sstevel@tonic-gate 	nvp->nvp_name_sz = strlen(buf) + 1;
2597*7c478bd9Sstevel@tonic-gate 
2598*7c478bd9Sstevel@tonic-gate 	/* type and nelem */
2599*7c478bd9Sstevel@tonic-gate 	if (!xdr_int(xdr, (int *)&nvp->nvp_type) ||
2600*7c478bd9Sstevel@tonic-gate 	    !xdr_int(xdr, &nvp->nvp_value_elem))
2601*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2602*7c478bd9Sstevel@tonic-gate 
2603*7c478bd9Sstevel@tonic-gate 	type = NVP_TYPE(nvp);
2604*7c478bd9Sstevel@tonic-gate 	nelem = nvp->nvp_value_elem;
2605*7c478bd9Sstevel@tonic-gate 
2606*7c478bd9Sstevel@tonic-gate 	/*
2607*7c478bd9Sstevel@tonic-gate 	 * Verify type and nelem and get the value size.
2608*7c478bd9Sstevel@tonic-gate 	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
2609*7c478bd9Sstevel@tonic-gate 	 * is the size of the string(s) excluded.
2610*7c478bd9Sstevel@tonic-gate 	 */
2611*7c478bd9Sstevel@tonic-gate 	if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0)
2612*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2613*7c478bd9Sstevel@tonic-gate 
2614*7c478bd9Sstevel@tonic-gate 	/* if there is no data to extract then return */
2615*7c478bd9Sstevel@tonic-gate 	if (nelem == 0)
2616*7c478bd9Sstevel@tonic-gate 		return (0);
2617*7c478bd9Sstevel@tonic-gate 
2618*7c478bd9Sstevel@tonic-gate 	/* value */
2619*7c478bd9Sstevel@tonic-gate 	if ((buf = NVP_VALUE(nvp)) >= buf_end)
2620*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2621*7c478bd9Sstevel@tonic-gate 	buflen = buf_end - buf;
2622*7c478bd9Sstevel@tonic-gate 
2623*7c478bd9Sstevel@tonic-gate 	if (buflen < value_sz)
2624*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
2625*7c478bd9Sstevel@tonic-gate 
2626*7c478bd9Sstevel@tonic-gate 	switch (type) {
2627*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
2628*7c478bd9Sstevel@tonic-gate 		if (nvs_embedded(nvs, (void *)buf) == 0)
2629*7c478bd9Sstevel@tonic-gate 			return (0);
2630*7c478bd9Sstevel@tonic-gate 		break;
2631*7c478bd9Sstevel@tonic-gate 
2632*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY:
2633*7c478bd9Sstevel@tonic-gate 		if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0)
2634*7c478bd9Sstevel@tonic-gate 			return (0);
2635*7c478bd9Sstevel@tonic-gate 		break;
2636*7c478bd9Sstevel@tonic-gate 
2637*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN:
2638*7c478bd9Sstevel@tonic-gate 		ret = TRUE;
2639*7c478bd9Sstevel@tonic-gate 		break;
2640*7c478bd9Sstevel@tonic-gate 
2641*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE:
2642*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8:
2643*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8:
2644*7c478bd9Sstevel@tonic-gate 		ret = xdr_char(xdr, buf);
2645*7c478bd9Sstevel@tonic-gate 		break;
2646*7c478bd9Sstevel@tonic-gate 
2647*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16:
2648*7c478bd9Sstevel@tonic-gate 		ret = xdr_short(xdr, (void *)buf);
2649*7c478bd9Sstevel@tonic-gate 		break;
2650*7c478bd9Sstevel@tonic-gate 
2651*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16:
2652*7c478bd9Sstevel@tonic-gate 		ret = xdr_u_short(xdr, (void *)buf);
2653*7c478bd9Sstevel@tonic-gate 		break;
2654*7c478bd9Sstevel@tonic-gate 
2655*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_VALUE:
2656*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32:
2657*7c478bd9Sstevel@tonic-gate 		ret = xdr_int(xdr, (void *)buf);
2658*7c478bd9Sstevel@tonic-gate 		break;
2659*7c478bd9Sstevel@tonic-gate 
2660*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32:
2661*7c478bd9Sstevel@tonic-gate 		ret = xdr_u_int(xdr, (void *)buf);
2662*7c478bd9Sstevel@tonic-gate 		break;
2663*7c478bd9Sstevel@tonic-gate 
2664*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64:
2665*7c478bd9Sstevel@tonic-gate 		ret = xdr_longlong_t(xdr, (void *)buf);
2666*7c478bd9Sstevel@tonic-gate 		break;
2667*7c478bd9Sstevel@tonic-gate 
2668*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64:
2669*7c478bd9Sstevel@tonic-gate 		ret = xdr_u_longlong_t(xdr, (void *)buf);
2670*7c478bd9Sstevel@tonic-gate 		break;
2671*7c478bd9Sstevel@tonic-gate 
2672*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_HRTIME:
2673*7c478bd9Sstevel@tonic-gate 		/*
2674*7c478bd9Sstevel@tonic-gate 		 * NOTE: must expose the definition of hrtime_t here
2675*7c478bd9Sstevel@tonic-gate 		 */
2676*7c478bd9Sstevel@tonic-gate 		ret = xdr_longlong_t(xdr, (void *)buf);
2677*7c478bd9Sstevel@tonic-gate 		break;
2678*7c478bd9Sstevel@tonic-gate 
2679*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING:
2680*7c478bd9Sstevel@tonic-gate 		ret = xdr_string(xdr, &buf, buflen - 1);
2681*7c478bd9Sstevel@tonic-gate 		break;
2682*7c478bd9Sstevel@tonic-gate 
2683*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY:
2684*7c478bd9Sstevel@tonic-gate 		ret = xdr_opaque(xdr, buf, nelem);
2685*7c478bd9Sstevel@tonic-gate 		break;
2686*7c478bd9Sstevel@tonic-gate 
2687*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8_ARRAY:
2688*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8_ARRAY:
2689*7c478bd9Sstevel@tonic-gate 		ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t),
2690*7c478bd9Sstevel@tonic-gate 		    (xdrproc_t)xdr_char);
2691*7c478bd9Sstevel@tonic-gate 		break;
2692*7c478bd9Sstevel@tonic-gate 
2693*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16_ARRAY:
2694*7c478bd9Sstevel@tonic-gate 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t),
2695*7c478bd9Sstevel@tonic-gate 		    sizeof (int16_t), (xdrproc_t)xdr_short);
2696*7c478bd9Sstevel@tonic-gate 		break;
2697*7c478bd9Sstevel@tonic-gate 
2698*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16_ARRAY:
2699*7c478bd9Sstevel@tonic-gate 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t),
2700*7c478bd9Sstevel@tonic-gate 		    sizeof (uint16_t), (xdrproc_t)xdr_u_short);
2701*7c478bd9Sstevel@tonic-gate 		break;
2702*7c478bd9Sstevel@tonic-gate 
2703*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_ARRAY:
2704*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32_ARRAY:
2705*7c478bd9Sstevel@tonic-gate 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t),
2706*7c478bd9Sstevel@tonic-gate 		    sizeof (int32_t), (xdrproc_t)xdr_int);
2707*7c478bd9Sstevel@tonic-gate 		break;
2708*7c478bd9Sstevel@tonic-gate 
2709*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32_ARRAY:
2710*7c478bd9Sstevel@tonic-gate 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t),
2711*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), (xdrproc_t)xdr_u_int);
2712*7c478bd9Sstevel@tonic-gate 		break;
2713*7c478bd9Sstevel@tonic-gate 
2714*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64_ARRAY:
2715*7c478bd9Sstevel@tonic-gate 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t),
2716*7c478bd9Sstevel@tonic-gate 		    sizeof (int64_t), (xdrproc_t)xdr_longlong_t);
2717*7c478bd9Sstevel@tonic-gate 		break;
2718*7c478bd9Sstevel@tonic-gate 
2719*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64_ARRAY:
2720*7c478bd9Sstevel@tonic-gate 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t),
2721*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t);
2722*7c478bd9Sstevel@tonic-gate 		break;
2723*7c478bd9Sstevel@tonic-gate 
2724*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING_ARRAY: {
2725*7c478bd9Sstevel@tonic-gate 		size_t len = nelem * sizeof (uint64_t);
2726*7c478bd9Sstevel@tonic-gate 		char **strp = (void *)buf;
2727*7c478bd9Sstevel@tonic-gate 		int i;
2728*7c478bd9Sstevel@tonic-gate 
2729*7c478bd9Sstevel@tonic-gate 		if (nvs->nvs_op == NVS_OP_DECODE)
2730*7c478bd9Sstevel@tonic-gate 			bzero(buf, len);	/* don't trust packed data */
2731*7c478bd9Sstevel@tonic-gate 
2732*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem; i++) {
2733*7c478bd9Sstevel@tonic-gate 			if (buflen <= len)
2734*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
2735*7c478bd9Sstevel@tonic-gate 
2736*7c478bd9Sstevel@tonic-gate 			buf += len;
2737*7c478bd9Sstevel@tonic-gate 			buflen -= len;
2738*7c478bd9Sstevel@tonic-gate 
2739*7c478bd9Sstevel@tonic-gate 			if (xdr_string(xdr, &buf, buflen - 1) != TRUE)
2740*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
2741*7c478bd9Sstevel@tonic-gate 
2742*7c478bd9Sstevel@tonic-gate 			if (nvs->nvs_op == NVS_OP_DECODE)
2743*7c478bd9Sstevel@tonic-gate 				strp[i] = buf;
2744*7c478bd9Sstevel@tonic-gate 			len = strlen(buf) + 1;
2745*7c478bd9Sstevel@tonic-gate 		}
2746*7c478bd9Sstevel@tonic-gate 		ret = TRUE;
2747*7c478bd9Sstevel@tonic-gate 		break;
2748*7c478bd9Sstevel@tonic-gate 	}
2749*7c478bd9Sstevel@tonic-gate 	default:
2750*7c478bd9Sstevel@tonic-gate 		break;
2751*7c478bd9Sstevel@tonic-gate 	}
2752*7c478bd9Sstevel@tonic-gate 
2753*7c478bd9Sstevel@tonic-gate 	return (ret == TRUE ? 0 : EFAULT);
2754*7c478bd9Sstevel@tonic-gate }
2755*7c478bd9Sstevel@tonic-gate 
2756*7c478bd9Sstevel@tonic-gate static int
2757*7c478bd9Sstevel@tonic-gate nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2758*7c478bd9Sstevel@tonic-gate {
2759*7c478bd9Sstevel@tonic-gate 	data_type_t type = NVP_TYPE(nvp);
2760*7c478bd9Sstevel@tonic-gate 	/*
2761*7c478bd9Sstevel@tonic-gate 	 * encode_size + decode_size + name string size + data type + nelem
2762*7c478bd9Sstevel@tonic-gate 	 * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))
2763*7c478bd9Sstevel@tonic-gate 	 */
2764*7c478bd9Sstevel@tonic-gate 	uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4;
2765*7c478bd9Sstevel@tonic-gate 
2766*7c478bd9Sstevel@tonic-gate 	switch (type) {
2767*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN:
2768*7c478bd9Sstevel@tonic-gate 		break;
2769*7c478bd9Sstevel@tonic-gate 
2770*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_VALUE:
2771*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE:
2772*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8:
2773*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8:
2774*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16:
2775*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16:
2776*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32:
2777*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32:
2778*7c478bd9Sstevel@tonic-gate 		nvp_sz += 4;	/* 4 is the minimum xdr unit */
2779*7c478bd9Sstevel@tonic-gate 		break;
2780*7c478bd9Sstevel@tonic-gate 
2781*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64:
2782*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64:
2783*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_HRTIME:
2784*7c478bd9Sstevel@tonic-gate 		nvp_sz += 8;
2785*7c478bd9Sstevel@tonic-gate 		break;
2786*7c478bd9Sstevel@tonic-gate 
2787*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING:
2788*7c478bd9Sstevel@tonic-gate 		nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp)));
2789*7c478bd9Sstevel@tonic-gate 		break;
2790*7c478bd9Sstevel@tonic-gate 
2791*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY:
2792*7c478bd9Sstevel@tonic-gate 		nvp_sz += NV_ALIGN4(NVP_NELEM(nvp));
2793*7c478bd9Sstevel@tonic-gate 		break;
2794*7c478bd9Sstevel@tonic-gate 
2795*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_ARRAY:
2796*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8_ARRAY:
2797*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8_ARRAY:
2798*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16_ARRAY:
2799*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16_ARRAY:
2800*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32_ARRAY:
2801*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32_ARRAY:
2802*7c478bd9Sstevel@tonic-gate 		nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp);
2803*7c478bd9Sstevel@tonic-gate 		break;
2804*7c478bd9Sstevel@tonic-gate 
2805*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64_ARRAY:
2806*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64_ARRAY:
2807*7c478bd9Sstevel@tonic-gate 		nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp);
2808*7c478bd9Sstevel@tonic-gate 		break;
2809*7c478bd9Sstevel@tonic-gate 
2810*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING_ARRAY: {
2811*7c478bd9Sstevel@tonic-gate 		int i;
2812*7c478bd9Sstevel@tonic-gate 		char **strs = (void *)NVP_VALUE(nvp);
2813*7c478bd9Sstevel@tonic-gate 
2814*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < NVP_NELEM(nvp); i++)
2815*7c478bd9Sstevel@tonic-gate 			nvp_sz += 4 + NV_ALIGN4(strlen(strs[i]));
2816*7c478bd9Sstevel@tonic-gate 
2817*7c478bd9Sstevel@tonic-gate 		break;
2818*7c478bd9Sstevel@tonic-gate 	}
2819*7c478bd9Sstevel@tonic-gate 
2820*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
2821*7c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY: {
2822*7c478bd9Sstevel@tonic-gate 		size_t nvsize = 0;
2823*7c478bd9Sstevel@tonic-gate 		int old_nvs_op = nvs->nvs_op;
2824*7c478bd9Sstevel@tonic-gate 		int err;
2825*7c478bd9Sstevel@tonic-gate 
2826*7c478bd9Sstevel@tonic-gate 		nvs->nvs_op = NVS_OP_GETSIZE;
2827*7c478bd9Sstevel@tonic-gate 		if (type == DATA_TYPE_NVLIST)
2828*7c478bd9Sstevel@tonic-gate 			err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize);
2829*7c478bd9Sstevel@tonic-gate 		else
2830*7c478bd9Sstevel@tonic-gate 			err = nvs_embedded_nvl_array(nvs, nvp, &nvsize);
2831*7c478bd9Sstevel@tonic-gate 		nvs->nvs_op = old_nvs_op;
2832*7c478bd9Sstevel@tonic-gate 
2833*7c478bd9Sstevel@tonic-gate 		if (err != 0)
2834*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
2835*7c478bd9Sstevel@tonic-gate 
2836*7c478bd9Sstevel@tonic-gate 		nvp_sz += nvsize;
2837*7c478bd9Sstevel@tonic-gate 		break;
2838*7c478bd9Sstevel@tonic-gate 	}
2839*7c478bd9Sstevel@tonic-gate 
2840*7c478bd9Sstevel@tonic-gate 	default:
2841*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2842*7c478bd9Sstevel@tonic-gate 	}
2843*7c478bd9Sstevel@tonic-gate 
2844*7c478bd9Sstevel@tonic-gate 	if (nvp_sz > INT32_MAX)
2845*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2846*7c478bd9Sstevel@tonic-gate 
2847*7c478bd9Sstevel@tonic-gate 	*size = nvp_sz;
2848*7c478bd9Sstevel@tonic-gate 
2849*7c478bd9Sstevel@tonic-gate 	return (0);
2850*7c478bd9Sstevel@tonic-gate }
2851*7c478bd9Sstevel@tonic-gate 
2852*7c478bd9Sstevel@tonic-gate 
2853*7c478bd9Sstevel@tonic-gate /*
2854*7c478bd9Sstevel@tonic-gate  * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates
2855*7c478bd9Sstevel@tonic-gate  * the largest nvpair that could be encoded in the buffer.
2856*7c478bd9Sstevel@tonic-gate  *
2857*7c478bd9Sstevel@tonic-gate  * See comments above nvpair_xdr_op() for the format of xdr encoding.
2858*7c478bd9Sstevel@tonic-gate  * The size of a xdr packed nvpair without any data is 5 words.
2859*7c478bd9Sstevel@tonic-gate  *
2860*7c478bd9Sstevel@tonic-gate  * Using the size of the data directly as an estimate would be ok
2861*7c478bd9Sstevel@tonic-gate  * in all cases except one.  If the data type is of DATA_TYPE_STRING_ARRAY
2862*7c478bd9Sstevel@tonic-gate  * then the actual nvpair has space for an array of pointers to index
2863*7c478bd9Sstevel@tonic-gate  * the strings.  These pointers are not encoded into the packed xdr buffer.
2864*7c478bd9Sstevel@tonic-gate  *
2865*7c478bd9Sstevel@tonic-gate  * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are
2866*7c478bd9Sstevel@tonic-gate  * of length 0, then each string is endcoded in xdr format as a single word.
2867*7c478bd9Sstevel@tonic-gate  * Therefore when expanded to an nvpair there will be 2.25 word used for
2868*7c478bd9Sstevel@tonic-gate  * each string.  (a int64_t allocated for pointer usage, and a single char
2869*7c478bd9Sstevel@tonic-gate  * for the null termination.)
2870*7c478bd9Sstevel@tonic-gate  *
2871*7c478bd9Sstevel@tonic-gate  * This is the calculation performed by the NVS_XDR_MAX_LEN macro.
2872*7c478bd9Sstevel@tonic-gate  */
2873*7c478bd9Sstevel@tonic-gate #define	NVS_XDR_HDR_LEN		((size_t)(5 * 4))
2874*7c478bd9Sstevel@tonic-gate #define	NVS_XDR_DATA_LEN(y)	(((size_t)(y) <= NVS_XDR_HDR_LEN) ? \
2875*7c478bd9Sstevel@tonic-gate 					0 : ((size_t)(y) - NVS_XDR_HDR_LEN))
2876*7c478bd9Sstevel@tonic-gate #define	NVS_XDR_MAX_LEN(x)	(NVP_SIZE_CALC(1, 0) + \
2877*7c478bd9Sstevel@tonic-gate 					(NVS_XDR_DATA_LEN(x) * 2) + \
2878*7c478bd9Sstevel@tonic-gate 					NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4)))
2879*7c478bd9Sstevel@tonic-gate 
2880*7c478bd9Sstevel@tonic-gate static int
2881*7c478bd9Sstevel@tonic-gate nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2882*7c478bd9Sstevel@tonic-gate {
2883*7c478bd9Sstevel@tonic-gate 	XDR 	*xdr = nvs->nvs_private;
2884*7c478bd9Sstevel@tonic-gate 	int32_t	encode_len, decode_len;
2885*7c478bd9Sstevel@tonic-gate 
2886*7c478bd9Sstevel@tonic-gate 	switch (nvs->nvs_op) {
2887*7c478bd9Sstevel@tonic-gate 	case NVS_OP_ENCODE: {
2888*7c478bd9Sstevel@tonic-gate 		size_t nvsize;
2889*7c478bd9Sstevel@tonic-gate 
2890*7c478bd9Sstevel@tonic-gate 		if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0)
2891*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 		decode_len = nvp->nvp_size;
2894*7c478bd9Sstevel@tonic-gate 		encode_len = nvsize;
2895*7c478bd9Sstevel@tonic-gate 		if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
2896*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2897*7c478bd9Sstevel@tonic-gate 
2898*7c478bd9Sstevel@tonic-gate 		return (nvs_xdr_nvp_op(nvs, nvp));
2899*7c478bd9Sstevel@tonic-gate 	}
2900*7c478bd9Sstevel@tonic-gate 	case NVS_OP_DECODE: {
2901*7c478bd9Sstevel@tonic-gate 		struct xdr_bytesrec bytesrec;
2902*7c478bd9Sstevel@tonic-gate 
2903*7c478bd9Sstevel@tonic-gate 		/* get the encode and decode size */
2904*7c478bd9Sstevel@tonic-gate 		if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
2905*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2906*7c478bd9Sstevel@tonic-gate 		*size = decode_len;
2907*7c478bd9Sstevel@tonic-gate 
2908*7c478bd9Sstevel@tonic-gate 		/* are we at the end of the stream? */
2909*7c478bd9Sstevel@tonic-gate 		if (*size == 0)
2910*7c478bd9Sstevel@tonic-gate 			return (0);
2911*7c478bd9Sstevel@tonic-gate 
2912*7c478bd9Sstevel@tonic-gate 		/* sanity check the size parameter */
2913*7c478bd9Sstevel@tonic-gate 		if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec))
2914*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2915*7c478bd9Sstevel@tonic-gate 
2916*7c478bd9Sstevel@tonic-gate 		if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail))
2917*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
2918*7c478bd9Sstevel@tonic-gate 		break;
2919*7c478bd9Sstevel@tonic-gate 	}
2920*7c478bd9Sstevel@tonic-gate 
2921*7c478bd9Sstevel@tonic-gate 	default:
2922*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
2923*7c478bd9Sstevel@tonic-gate 	}
2924*7c478bd9Sstevel@tonic-gate 	return (0);
2925*7c478bd9Sstevel@tonic-gate }
2926*7c478bd9Sstevel@tonic-gate 
2927*7c478bd9Sstevel@tonic-gate static const struct nvs_ops nvs_xdr_ops = {
2928*7c478bd9Sstevel@tonic-gate 	nvs_xdr_nvlist,
2929*7c478bd9Sstevel@tonic-gate 	nvs_xdr_nvpair,
2930*7c478bd9Sstevel@tonic-gate 	nvs_xdr_nvp_op,
2931*7c478bd9Sstevel@tonic-gate 	nvs_xdr_nvp_size,
2932*7c478bd9Sstevel@tonic-gate 	nvs_xdr_nvl_fini
2933*7c478bd9Sstevel@tonic-gate };
2934*7c478bd9Sstevel@tonic-gate 
2935*7c478bd9Sstevel@tonic-gate static int
2936*7c478bd9Sstevel@tonic-gate nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
2937*7c478bd9Sstevel@tonic-gate {
2938*7c478bd9Sstevel@tonic-gate 	XDR xdr;
2939*7c478bd9Sstevel@tonic-gate 	int err;
2940*7c478bd9Sstevel@tonic-gate 
2941*7c478bd9Sstevel@tonic-gate 	nvs->nvs_ops = &nvs_xdr_ops;
2942*7c478bd9Sstevel@tonic-gate 
2943*7c478bd9Sstevel@tonic-gate 	if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t),
2944*7c478bd9Sstevel@tonic-gate 	    *buflen - sizeof (nvs_header_t))) != 0)
2945*7c478bd9Sstevel@tonic-gate 		return (err);
2946*7c478bd9Sstevel@tonic-gate 
2947*7c478bd9Sstevel@tonic-gate 	err = nvs_operation(nvs, nvl, buflen);
2948*7c478bd9Sstevel@tonic-gate 
2949*7c478bd9Sstevel@tonic-gate 	nvs_xdr_destroy(nvs);
2950*7c478bd9Sstevel@tonic-gate 
2951*7c478bd9Sstevel@tonic-gate 	return (err);
2952*7c478bd9Sstevel@tonic-gate }
2953