xref: /illumos-gate/usr/src/boot/libsa/zfs/nvlist.c (revision 43075873)
1b713c91eSToomas Soome /*
2b713c91eSToomas Soome  * Copyright 2020 Toomas Soome <tsoome@me.com>
3b713c91eSToomas Soome  *
4b713c91eSToomas Soome  * Redistribution and use in source and binary forms, with or without
5b713c91eSToomas Soome  * modification, are permitted provided that the following conditions
6b713c91eSToomas Soome  * are met:
7b713c91eSToomas Soome  * 1. Redistributions of source code must retain the above copyright
8b713c91eSToomas Soome  *    notice, this list of conditions and the following disclaimer.
9b713c91eSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
10b713c91eSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
11b713c91eSToomas Soome  *    documentation and/or other materials provided with the distribution.
12b713c91eSToomas Soome  *
13b713c91eSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14b713c91eSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15b713c91eSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16b713c91eSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17b713c91eSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18b713c91eSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19b713c91eSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20b713c91eSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21b713c91eSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22b713c91eSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23b713c91eSToomas Soome  * SUCH DAMAGE.
24b713c91eSToomas Soome  */
25b713c91eSToomas Soome 
26b713c91eSToomas Soome #include <sys/cdefs.h>
27b713c91eSToomas Soome 
28b713c91eSToomas Soome #include <stand.h>
29b713c91eSToomas Soome #include <stdbool.h>
30b713c91eSToomas Soome #include <sys/endian.h>
31b713c91eSToomas Soome #include <sys/stdint.h>
32b713c91eSToomas Soome #include <sys/param.h>
33b713c91eSToomas Soome #include <zfsimpl.h>
34b713c91eSToomas Soome #include "libzfs.h"
35b713c91eSToomas Soome 
36b713c91eSToomas Soome enum xdr_op {
37b713c91eSToomas Soome 	XDR_OP_ENCODE = 1,
38b713c91eSToomas Soome 	XDR_OP_DECODE = 2
39b713c91eSToomas Soome };
40b713c91eSToomas Soome 
41b713c91eSToomas Soome typedef struct xdr {
42b713c91eSToomas Soome 	enum xdr_op xdr_op;
43b713c91eSToomas Soome 	int (*xdr_getint)(struct xdr *, int *);
44b713c91eSToomas Soome 	int (*xdr_putint)(struct xdr *, int);
45b713c91eSToomas Soome 	int (*xdr_getuint)(struct xdr *, unsigned *);
46b713c91eSToomas Soome 	int (*xdr_putuint)(struct xdr *, unsigned);
47b713c91eSToomas Soome 	const uint8_t *xdr_buf;
48b713c91eSToomas Soome 	uint8_t *xdr_idx;
49b713c91eSToomas Soome 	size_t xdr_buf_size;
50b713c91eSToomas Soome } xdr_t;
51b713c91eSToomas Soome 
52b713c91eSToomas Soome static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *);
53b713c91eSToomas Soome static bool nvlist_size_xdr(xdr_t *, size_t *);
54b713c91eSToomas Soome static bool nvlist_size_native(xdr_t *, size_t *);
55b713c91eSToomas Soome static bool xdr_int(xdr_t *, int *);
56b713c91eSToomas Soome static bool xdr_u_int(xdr_t *, unsigned *);
57b713c91eSToomas Soome 
5858b55f70SToomas Soome typedef bool (*xdrproc_t)(xdr_t *, void *);
59b713c91eSToomas Soome 
60b713c91eSToomas Soome /* Basic primitives for XDR translation operations, getint and putint. */
61b713c91eSToomas Soome static int
_getint(struct xdr * xdr,int * ip)62b713c91eSToomas Soome _getint(struct xdr *xdr, int *ip)
63b713c91eSToomas Soome {
64b713c91eSToomas Soome 	*ip = be32dec(xdr->xdr_idx);
65b713c91eSToomas Soome 	return (sizeof (int));
66b713c91eSToomas Soome }
67b713c91eSToomas Soome 
68b713c91eSToomas Soome static int
_putint(struct xdr * xdr,int i)69b713c91eSToomas Soome _putint(struct xdr *xdr, int i)
70b713c91eSToomas Soome {
71b713c91eSToomas Soome 	int *ip = (int *)xdr->xdr_idx;
72b713c91eSToomas Soome 
73b713c91eSToomas Soome 	*ip = htobe32(i);
74b713c91eSToomas Soome 	return (sizeof (int));
75b713c91eSToomas Soome }
76b713c91eSToomas Soome 
77b713c91eSToomas Soome static int
_getuint(struct xdr * xdr,unsigned * ip)78b713c91eSToomas Soome _getuint(struct xdr *xdr, unsigned *ip)
79b713c91eSToomas Soome {
80b713c91eSToomas Soome 	*ip = be32dec(xdr->xdr_idx);
81b713c91eSToomas Soome 	return (sizeof (unsigned));
82b713c91eSToomas Soome }
83b713c91eSToomas Soome 
84b713c91eSToomas Soome static int
_putuint(struct xdr * xdr,unsigned i)85b713c91eSToomas Soome _putuint(struct xdr *xdr, unsigned i)
86b713c91eSToomas Soome {
87b713c91eSToomas Soome 	unsigned *up = (unsigned *)xdr->xdr_idx;
88b713c91eSToomas Soome 
89b713c91eSToomas Soome 	*up = htobe32(i);
90b713c91eSToomas Soome 	return (sizeof (int));
91b713c91eSToomas Soome }
92b713c91eSToomas Soome 
930b14c199SToomas Soome static int
_getint_mem(struct xdr * xdr,int * ip)940b14c199SToomas Soome _getint_mem(struct xdr *xdr, int *ip)
950b14c199SToomas Soome {
960b14c199SToomas Soome 	*ip = *(int *)xdr->xdr_idx;
970b14c199SToomas Soome 	return (sizeof (int));
980b14c199SToomas Soome }
990b14c199SToomas Soome 
1000b14c199SToomas Soome static int
_putint_mem(struct xdr * xdr,int i)1010b14c199SToomas Soome _putint_mem(struct xdr *xdr, int i)
1020b14c199SToomas Soome {
1030b14c199SToomas Soome 	int *ip = (int *)xdr->xdr_idx;
1040b14c199SToomas Soome 
1050b14c199SToomas Soome 	*ip = i;
1060b14c199SToomas Soome 	return (sizeof (int));
1070b14c199SToomas Soome }
1080b14c199SToomas Soome 
1090b14c199SToomas Soome static int
_getuint_mem(struct xdr * xdr,unsigned * ip)1100b14c199SToomas Soome _getuint_mem(struct xdr *xdr, unsigned *ip)
1110b14c199SToomas Soome {
1120b14c199SToomas Soome 	*ip = *(unsigned *)xdr->xdr_idx;
1130b14c199SToomas Soome 	return (sizeof (unsigned));
1140b14c199SToomas Soome }
1150b14c199SToomas Soome 
1160b14c199SToomas Soome static int
_putuint_mem(struct xdr * xdr,unsigned i)1170b14c199SToomas Soome _putuint_mem(struct xdr *xdr, unsigned i)
1180b14c199SToomas Soome {
1190b14c199SToomas Soome 	unsigned *up = (unsigned *)xdr->xdr_idx;
1200b14c199SToomas Soome 
1210b14c199SToomas Soome 	*up = i;
1220b14c199SToomas Soome 	return (sizeof (int));
1230b14c199SToomas Soome }
1240b14c199SToomas Soome 
125b713c91eSToomas Soome /*
126b713c91eSToomas Soome  * XDR data translations.
127b713c91eSToomas Soome  */
128b713c91eSToomas Soome static bool
xdr_short(xdr_t * xdr,short * ip)129b713c91eSToomas Soome xdr_short(xdr_t *xdr, short *ip)
130b713c91eSToomas Soome {
131b713c91eSToomas Soome 	int i;
132b713c91eSToomas Soome 	bool rv;
133b713c91eSToomas Soome 
134b713c91eSToomas Soome 	i = *ip;
135b713c91eSToomas Soome 	if ((rv = xdr_int(xdr, &i))) {
136b713c91eSToomas Soome 		if (xdr->xdr_op == XDR_OP_DECODE)
137b713c91eSToomas Soome 			*ip = i;
138b713c91eSToomas Soome 	}
139b713c91eSToomas Soome 	return (rv);
140b713c91eSToomas Soome }
141b713c91eSToomas Soome 
142b713c91eSToomas Soome static bool
xdr_u_short(xdr_t * xdr,unsigned short * ip)143b713c91eSToomas Soome xdr_u_short(xdr_t *xdr, unsigned short *ip)
144b713c91eSToomas Soome {
145b713c91eSToomas Soome 	unsigned u;
146b713c91eSToomas Soome 	bool rv;
147b713c91eSToomas Soome 
148b713c91eSToomas Soome 	u = *ip;
149b713c91eSToomas Soome 	if ((rv = xdr_u_int(xdr, &u))) {
150b713c91eSToomas Soome 		if (xdr->xdr_op == XDR_OP_DECODE)
151b713c91eSToomas Soome 			*ip = u;
152b713c91eSToomas Soome 	}
153b713c91eSToomas Soome 	return (rv);
154b713c91eSToomas Soome }
155b713c91eSToomas Soome 
156b713c91eSToomas Soome /*
157b713c91eSToomas Soome  * translate xdr->xdr_idx, increment it by size of int.
158b713c91eSToomas Soome  */
159b713c91eSToomas Soome static bool
xdr_int(xdr_t * xdr,int * ip)160b713c91eSToomas Soome xdr_int(xdr_t *xdr, int *ip)
161b713c91eSToomas Soome {
162b713c91eSToomas Soome 	bool rv = false;
163b713c91eSToomas Soome 	int *i = (int *)xdr->xdr_idx;
164b713c91eSToomas Soome 
165b713c91eSToomas Soome 	if (xdr->xdr_idx + sizeof (int) > xdr->xdr_buf + xdr->xdr_buf_size)
166b713c91eSToomas Soome 		return (rv);
167b713c91eSToomas Soome 
168b713c91eSToomas Soome 	switch (xdr->xdr_op) {
169b713c91eSToomas Soome 	case XDR_OP_ENCODE:
170b713c91eSToomas Soome 		/* Encode value *ip, store to buf */
171b713c91eSToomas Soome 		xdr->xdr_idx += xdr->xdr_putint(xdr, *ip);
172b713c91eSToomas Soome 		rv = true;
173b713c91eSToomas Soome 		break;
174b713c91eSToomas Soome 
175b713c91eSToomas Soome 	case XDR_OP_DECODE:
176b713c91eSToomas Soome 		/* Decode buf, return value to *ip */
177b713c91eSToomas Soome 		xdr->xdr_idx += xdr->xdr_getint(xdr, i);
178b713c91eSToomas Soome 		*ip = *i;
179b713c91eSToomas Soome 		rv = true;
180b713c91eSToomas Soome 		break;
181b713c91eSToomas Soome 	}
182b713c91eSToomas Soome 	return (rv);
183b713c91eSToomas Soome }
184b713c91eSToomas Soome 
185b713c91eSToomas Soome /*
186b713c91eSToomas Soome  * translate xdr->xdr_idx, increment it by size of unsigned int.
187b713c91eSToomas Soome  */
188b713c91eSToomas Soome static bool
xdr_u_int(xdr_t * xdr,unsigned * ip)189b713c91eSToomas Soome xdr_u_int(xdr_t *xdr, unsigned *ip)
190b713c91eSToomas Soome {
191b713c91eSToomas Soome 	bool rv = false;
192b713c91eSToomas Soome 	unsigned *u = (unsigned *)xdr->xdr_idx;
193b713c91eSToomas Soome 
194b713c91eSToomas Soome 	if (xdr->xdr_idx + sizeof (unsigned) > xdr->xdr_buf + xdr->xdr_buf_size)
195b713c91eSToomas Soome 		return (rv);
196b713c91eSToomas Soome 
197b713c91eSToomas Soome 	switch (xdr->xdr_op) {
198b713c91eSToomas Soome 	case XDR_OP_ENCODE:
199b713c91eSToomas Soome 		/* Encode value *ip, store to buf */
200b713c91eSToomas Soome 		xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip);
201b713c91eSToomas Soome 		rv = true;
202b713c91eSToomas Soome 		break;
203b713c91eSToomas Soome 
204b713c91eSToomas Soome 	case XDR_OP_DECODE:
205b713c91eSToomas Soome 		/* Decode buf, return value to *ip */
206b713c91eSToomas Soome 		xdr->xdr_idx += xdr->xdr_getuint(xdr, u);
207b713c91eSToomas Soome 		*ip = *u;
208b713c91eSToomas Soome 		rv = true;
209b713c91eSToomas Soome 		break;
210b713c91eSToomas Soome 	}
211b713c91eSToomas Soome 	return (rv);
212b713c91eSToomas Soome }
213b713c91eSToomas Soome 
214b713c91eSToomas Soome static bool
xdr_int64(xdr_t * xdr,int64_t * lp)215b713c91eSToomas Soome xdr_int64(xdr_t *xdr, int64_t *lp)
216b713c91eSToomas Soome {
217b713c91eSToomas Soome 	bool rv = false;
218b713c91eSToomas Soome 
219b713c91eSToomas Soome 	if (xdr->xdr_idx + sizeof (int64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
220b713c91eSToomas Soome 		return (rv);
221b713c91eSToomas Soome 
222b713c91eSToomas Soome 	switch (xdr->xdr_op) {
223b713c91eSToomas Soome 	case XDR_OP_ENCODE:
224b713c91eSToomas Soome 		/* Encode value *lp, store to buf */
2250b14c199SToomas Soome 		if (xdr->xdr_putint == _putint)
2260b14c199SToomas Soome 			*(int64_t *)xdr->xdr_idx = htobe64(*lp);
2270b14c199SToomas Soome 		else
2280b14c199SToomas Soome 			*(int64_t *)xdr->xdr_idx = *lp;
2290b14c199SToomas Soome 		xdr->xdr_idx += sizeof (int64_t);
230b713c91eSToomas Soome 		rv = true;
231b713c91eSToomas Soome 		break;
232b713c91eSToomas Soome 
233b713c91eSToomas Soome 	case XDR_OP_DECODE:
234b713c91eSToomas Soome 		/* Decode buf, return value to *ip */
2350b14c199SToomas Soome 		if (xdr->xdr_getint == _getint)
2360b14c199SToomas Soome 			*lp = be64toh(*(int64_t *)xdr->xdr_idx);
2370b14c199SToomas Soome 		else
2380b14c199SToomas Soome 			*lp = *(int64_t *)xdr->xdr_idx;
2390b14c199SToomas Soome 		xdr->xdr_idx += sizeof (int64_t);
240b713c91eSToomas Soome 		rv = true;
241b713c91eSToomas Soome 	}
242b713c91eSToomas Soome 	return (rv);
243b713c91eSToomas Soome }
244b713c91eSToomas Soome 
245b713c91eSToomas Soome static bool
xdr_uint64(xdr_t * xdr,uint64_t * lp)246b713c91eSToomas Soome xdr_uint64(xdr_t *xdr, uint64_t *lp)
247b713c91eSToomas Soome {
248b713c91eSToomas Soome 	bool rv = false;
249b713c91eSToomas Soome 
250b713c91eSToomas Soome 	if (xdr->xdr_idx + sizeof (uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
251b713c91eSToomas Soome 		return (rv);
252b713c91eSToomas Soome 
253b713c91eSToomas Soome 	switch (xdr->xdr_op) {
254b713c91eSToomas Soome 	case XDR_OP_ENCODE:
255b713c91eSToomas Soome 		/* Encode value *ip, store to buf */
2560b14c199SToomas Soome 		if (xdr->xdr_putint == _putint)
2570b14c199SToomas Soome 			*(uint64_t *)xdr->xdr_idx = htobe64(*lp);
2580b14c199SToomas Soome 		else
2590b14c199SToomas Soome 			*(uint64_t *)xdr->xdr_idx = *lp;
2600b14c199SToomas Soome 		xdr->xdr_idx += sizeof (uint64_t);
261b713c91eSToomas Soome 		rv = true;
262b713c91eSToomas Soome 		break;
263b713c91eSToomas Soome 
264b713c91eSToomas Soome 	case XDR_OP_DECODE:
265b713c91eSToomas Soome 		/* Decode buf, return value to *ip */
2660b14c199SToomas Soome 		if (xdr->xdr_getuint == _getuint)
2670b14c199SToomas Soome 			*lp = be64toh(*(uint64_t *)xdr->xdr_idx);
2680b14c199SToomas Soome 		else
2690b14c199SToomas Soome 			*lp = *(uint64_t *)xdr->xdr_idx;
2700b14c199SToomas Soome 		xdr->xdr_idx += sizeof (uint64_t);
271b713c91eSToomas Soome 		rv = true;
272b713c91eSToomas Soome 	}
273b713c91eSToomas Soome 	return (rv);
274b713c91eSToomas Soome }
275b713c91eSToomas Soome 
276b713c91eSToomas Soome static bool
xdr_char(xdr_t * xdr,char * cp)277b713c91eSToomas Soome xdr_char(xdr_t *xdr, char *cp)
278b713c91eSToomas Soome {
279b713c91eSToomas Soome 	int i;
280b713c91eSToomas Soome 	bool rv = false;
281b713c91eSToomas Soome 
282b713c91eSToomas Soome 	i = *cp;
283b713c91eSToomas Soome 	if ((rv = xdr_int(xdr, &i))) {
284b713c91eSToomas Soome 		if (xdr->xdr_op == XDR_OP_DECODE)
285b713c91eSToomas Soome 			*cp = i;
286b713c91eSToomas Soome 	}
287b713c91eSToomas Soome 	return (rv);
288b713c91eSToomas Soome }
289b713c91eSToomas Soome 
290b713c91eSToomas Soome static bool
xdr_string(xdr_t * xdr,nv_string_t * s)291b713c91eSToomas Soome xdr_string(xdr_t *xdr, nv_string_t *s)
292b713c91eSToomas Soome {
293b713c91eSToomas Soome 	int size = 0;
294b713c91eSToomas Soome 	bool rv = false;
295b713c91eSToomas Soome 
296b713c91eSToomas Soome 	switch (xdr->xdr_op) {
297b713c91eSToomas Soome 	case XDR_OP_ENCODE:
298b713c91eSToomas Soome 		size = s->nv_size;
299b713c91eSToomas Soome 		if (xdr->xdr_idx + sizeof (unsigned) + NV_ALIGN4(size) >
300b713c91eSToomas Soome 		    xdr->xdr_buf + xdr->xdr_buf_size)
301b713c91eSToomas Soome 			break;
302b713c91eSToomas Soome 		xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size);
303b713c91eSToomas Soome 		xdr->xdr_idx += NV_ALIGN4(size);
304b713c91eSToomas Soome 		rv = true;
305b713c91eSToomas Soome 		break;
306b713c91eSToomas Soome 
307b713c91eSToomas Soome 	case XDR_OP_DECODE:
308b713c91eSToomas Soome 		if (xdr->xdr_idx + sizeof (unsigned) >
309b713c91eSToomas Soome 		    xdr->xdr_buf + xdr->xdr_buf_size)
310b713c91eSToomas Soome 			break;
311b713c91eSToomas Soome 		size = xdr->xdr_getuint(xdr, &s->nv_size);
312b713c91eSToomas Soome 		size = NV_ALIGN4(size + s->nv_size);
313b713c91eSToomas Soome 		if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size)
314b713c91eSToomas Soome 			break;
315b713c91eSToomas Soome 		xdr->xdr_idx += size;
316b713c91eSToomas Soome 		rv = true;
317b713c91eSToomas Soome 		break;
318b713c91eSToomas Soome 	}
319b713c91eSToomas Soome 	return (rv);
320b713c91eSToomas Soome }
321b713c91eSToomas Soome 
322b713c91eSToomas Soome static bool
xdr_array(xdr_t * xdr,const unsigned nelem,const xdrproc_t elproc)323b713c91eSToomas Soome xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc)
324b713c91eSToomas Soome {
325b713c91eSToomas Soome 	bool rv = true;
3260b14c199SToomas Soome 	unsigned c = nelem;
3270b14c199SToomas Soome 
3280b14c199SToomas Soome 	if (!xdr_u_int(xdr, &c))
3290b14c199SToomas Soome 		return (false);
330b713c91eSToomas Soome 
331b713c91eSToomas Soome 	for (unsigned i = 0; i < nelem; i++) {
332b713c91eSToomas Soome 		if (!elproc(xdr, xdr->xdr_idx))
333b713c91eSToomas Soome 			return (false);
334b713c91eSToomas Soome 	}
335b713c91eSToomas Soome 	return (rv);
336b713c91eSToomas Soome }
337b713c91eSToomas Soome 
338b713c91eSToomas Soome /*
339b713c91eSToomas Soome  * nvlist management functions.
340b713c91eSToomas Soome  */
341b713c91eSToomas Soome void
nvlist_destroy(nvlist_t * nvl)342b713c91eSToomas Soome nvlist_destroy(nvlist_t *nvl)
343b713c91eSToomas Soome {
344b713c91eSToomas Soome 	if (nvl != NULL) {
345b713c91eSToomas Soome 		/* Free data if it was allocated by us. */
346b713c91eSToomas Soome 		if (nvl->nv_asize > 0)
347b713c91eSToomas Soome 			free(nvl->nv_data);
348b713c91eSToomas Soome 	}
349b713c91eSToomas Soome 	free(nvl);
350b713c91eSToomas Soome }
351b713c91eSToomas Soome 
352b713c91eSToomas Soome char *
nvstring_get(nv_string_t * nvs)353b713c91eSToomas Soome nvstring_get(nv_string_t *nvs)
354b713c91eSToomas Soome {
355b713c91eSToomas Soome 	char *s;
356b713c91eSToomas Soome 
357b713c91eSToomas Soome 	s = malloc(nvs->nv_size + 1);
358b713c91eSToomas Soome 	if (s != NULL) {
359b713c91eSToomas Soome 		bcopy(nvs->nv_data, s, nvs->nv_size);
360b713c91eSToomas Soome 		s[nvs->nv_size] = '\0';
361b713c91eSToomas Soome 	}
362b713c91eSToomas Soome 	return (s);
363b713c91eSToomas Soome }
364b713c91eSToomas Soome 
365b713c91eSToomas Soome /*
366b713c91eSToomas Soome  * Create empty nvlist.
367b713c91eSToomas Soome  * The nvlist is terminated by 2x zeros (8 bytes).
368b713c91eSToomas Soome  */
369b713c91eSToomas Soome nvlist_t *
nvlist_create(int flag)370b713c91eSToomas Soome nvlist_create(int flag)
371b713c91eSToomas Soome {
372b713c91eSToomas Soome 	nvlist_t *nvl;
373b713c91eSToomas Soome 	nvs_data_t *nvs;
374b713c91eSToomas Soome 
375b713c91eSToomas Soome 	nvl = calloc(1, sizeof (*nvl));
376b713c91eSToomas Soome 	if (nvl == NULL)
377b713c91eSToomas Soome 		return (nvl);
378b713c91eSToomas Soome 
379b713c91eSToomas Soome 	nvl->nv_header.nvh_encoding = NV_ENCODE_XDR;
380b713c91eSToomas Soome 	nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN;
381b713c91eSToomas Soome 
382b713c91eSToomas Soome 	nvl->nv_asize = nvl->nv_size = sizeof (*nvs);
383b713c91eSToomas Soome 	nvs = calloc(1, nvl->nv_asize);
384b713c91eSToomas Soome 	if (nvs == NULL) {
385b713c91eSToomas Soome 		free(nvl);
386b713c91eSToomas Soome 		return (NULL);
387b713c91eSToomas Soome 	}
388b713c91eSToomas Soome 	/* data in nvlist is byte stream */
389b713c91eSToomas Soome 	nvl->nv_data = (uint8_t *)nvs;
390b713c91eSToomas Soome 
391b713c91eSToomas Soome 	nvs->nvl_version = NV_VERSION;
392b713c91eSToomas Soome 	nvs->nvl_nvflag = flag;
393b713c91eSToomas Soome 	return (nvl);
394b713c91eSToomas Soome }
395b713c91eSToomas Soome 
396b713c91eSToomas Soome static bool
nvlist_xdr_nvp(xdr_t * xdr,nvlist_t * nvl)397b713c91eSToomas Soome nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl)
398b713c91eSToomas Soome {
399b713c91eSToomas Soome 	nv_string_t *nv_string;
400b713c91eSToomas Soome 	nv_pair_data_t *nvp_data;
401b713c91eSToomas Soome 	nvlist_t nvlist;
402b713c91eSToomas Soome 	unsigned type, nelem;
403b713c91eSToomas Soome 	xdr_t nv_xdr;
404b713c91eSToomas Soome 
405b713c91eSToomas Soome 	nv_string = (nv_string_t *)xdr->xdr_idx;
406b713c91eSToomas Soome 	if (!xdr_string(xdr, nv_string)) {
407b713c91eSToomas Soome 		return (false);
408b713c91eSToomas Soome 	}
409b713c91eSToomas Soome 	nvp_data = (nv_pair_data_t *)xdr->xdr_idx;
410b713c91eSToomas Soome 
411b713c91eSToomas Soome 	type = nvp_data->nv_type;
412b713c91eSToomas Soome 	nelem = nvp_data->nv_nelem;
413b713c91eSToomas Soome 	if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem))
414b713c91eSToomas Soome 		return (false);
415b713c91eSToomas Soome 
416b713c91eSToomas Soome 	switch (type) {
417b713c91eSToomas Soome 	case DATA_TYPE_NVLIST:
418b713c91eSToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
419b713c91eSToomas Soome 		bzero(&nvlist, sizeof (nvlist));
420b713c91eSToomas Soome 		nvlist.nv_data = xdr->xdr_idx;
421b713c91eSToomas Soome 		nvlist.nv_idx = nvlist.nv_data;
422b713c91eSToomas Soome 
423b713c91eSToomas Soome 		/* Set up xdr for this nvlist. */
424b713c91eSToomas Soome 		nv_xdr = *xdr;
425b713c91eSToomas Soome 		nv_xdr.xdr_buf = nvlist.nv_data;
426b713c91eSToomas Soome 		nv_xdr.xdr_idx = nvlist.nv_data;
427b713c91eSToomas Soome 		nv_xdr.xdr_buf_size =
428b713c91eSToomas Soome 		    nvl->nv_data + nvl->nv_size - nvlist.nv_data;
429b713c91eSToomas Soome 
430b713c91eSToomas Soome 		for (unsigned i = 0; i < nelem; i++) {
431b713c91eSToomas Soome 			if (xdr->xdr_op == XDR_OP_ENCODE) {
432b713c91eSToomas Soome 				if (!nvlist_size_native(&nv_xdr,
433b713c91eSToomas Soome 				    &nvlist.nv_size))
434b713c91eSToomas Soome 					return (false);
435b713c91eSToomas Soome 			} else {
436b713c91eSToomas Soome 				if (!nvlist_size_xdr(&nv_xdr,
437b713c91eSToomas Soome 				    &nvlist.nv_size))
438b713c91eSToomas Soome 					return (false);
439b713c91eSToomas Soome 			}
440b713c91eSToomas Soome 			if (nvlist_xdr_nvlist(xdr, &nvlist) != 0)
441b713c91eSToomas Soome 				return (false);
442b713c91eSToomas Soome 
443b713c91eSToomas Soome 			nvlist.nv_data = nv_xdr.xdr_idx;
444b713c91eSToomas Soome 			nvlist.nv_idx = nv_xdr.xdr_idx;
445b713c91eSToomas Soome 
446b713c91eSToomas Soome 			nv_xdr.xdr_buf = nv_xdr.xdr_idx;
447b713c91eSToomas Soome 			nv_xdr.xdr_buf_size =
448b713c91eSToomas Soome 			    nvl->nv_data + nvl->nv_size - nvlist.nv_data;
449b713c91eSToomas Soome 		}
450b713c91eSToomas Soome 		break;
451b713c91eSToomas Soome 
452b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN:
453b713c91eSToomas Soome 		/* BOOLEAN does not take value space */
454b713c91eSToomas Soome 		break;
455b713c91eSToomas Soome 	case DATA_TYPE_BYTE:
456b713c91eSToomas Soome 	case DATA_TYPE_INT8:
457b713c91eSToomas Soome 	case DATA_TYPE_UINT8:
458b713c91eSToomas Soome 		if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0]))
459b713c91eSToomas Soome 			return (false);
460b713c91eSToomas Soome 		break;
461b713c91eSToomas Soome 
462b713c91eSToomas Soome 	case DATA_TYPE_INT16:
463b713c91eSToomas Soome 		if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0]))
464b713c91eSToomas Soome 			return (false);
465b713c91eSToomas Soome 		break;
466b713c91eSToomas Soome 
467b713c91eSToomas Soome 	case DATA_TYPE_UINT16:
468b713c91eSToomas Soome 		if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0]))
469b713c91eSToomas Soome 			return (false);
470b713c91eSToomas Soome 		break;
471b713c91eSToomas Soome 
472b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
473b713c91eSToomas Soome 	case DATA_TYPE_INT32:
474b713c91eSToomas Soome 		if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0]))
475b713c91eSToomas Soome 			return (false);
476b713c91eSToomas Soome 		break;
477b713c91eSToomas Soome 
478b713c91eSToomas Soome 	case DATA_TYPE_UINT32:
479b713c91eSToomas Soome 		if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0]))
480b713c91eSToomas Soome 			return (false);
481b713c91eSToomas Soome 		break;
482b713c91eSToomas Soome 
483b713c91eSToomas Soome 	case DATA_TYPE_HRTIME:
484b713c91eSToomas Soome 	case DATA_TYPE_INT64:
485b713c91eSToomas Soome 		if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0]))
486b713c91eSToomas Soome 			return (false);
487b713c91eSToomas Soome 		break;
488b713c91eSToomas Soome 
489b713c91eSToomas Soome 	case DATA_TYPE_UINT64:
490b713c91eSToomas Soome 		if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0]))
491b713c91eSToomas Soome 			return (false);
492b713c91eSToomas Soome 		break;
493b713c91eSToomas Soome 
494b713c91eSToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
495b713c91eSToomas Soome 	case DATA_TYPE_STRING:
496b713c91eSToomas Soome 		nv_string = (nv_string_t *)&nvp_data->nv_data[0];
497b713c91eSToomas Soome 		if (!xdr_string(xdr, nv_string))
498b713c91eSToomas Soome 			return (false);
499b713c91eSToomas Soome 		break;
500b713c91eSToomas Soome 
501b713c91eSToomas Soome 	case DATA_TYPE_STRING_ARRAY:
502b713c91eSToomas Soome 		nv_string = (nv_string_t *)&nvp_data->nv_data[0];
503b713c91eSToomas Soome 		for (unsigned i = 0; i < nelem; i++) {
504b713c91eSToomas Soome 			if (!xdr_string(xdr, nv_string))
505b713c91eSToomas Soome 				return (false);
506b713c91eSToomas Soome 			nv_string = (nv_string_t *)xdr->xdr_idx;
507b713c91eSToomas Soome 		}
508b713c91eSToomas Soome 		break;
509b713c91eSToomas Soome 
510b713c91eSToomas Soome 	case DATA_TYPE_INT8_ARRAY:
511b713c91eSToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
512b713c91eSToomas Soome 	case DATA_TYPE_INT16_ARRAY:
513b713c91eSToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
514b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
515b713c91eSToomas Soome 	case DATA_TYPE_INT32_ARRAY:
516b713c91eSToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
517b713c91eSToomas Soome 		if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int))
518b713c91eSToomas Soome 			return (false);
519b713c91eSToomas Soome 		break;
520b713c91eSToomas Soome 
521b713c91eSToomas Soome 	case DATA_TYPE_INT64_ARRAY:
522b713c91eSToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
523b713c91eSToomas Soome 		if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64))
524b713c91eSToomas Soome 			return (false);
525b713c91eSToomas Soome 		break;
526b713c91eSToomas Soome 	}
527b713c91eSToomas Soome 	return (true);
528b713c91eSToomas Soome }
529b713c91eSToomas Soome 
530b713c91eSToomas Soome static int
nvlist_xdr_nvlist(xdr_t * xdr,nvlist_t * nvl)531b713c91eSToomas Soome nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl)
532b713c91eSToomas Soome {
533b713c91eSToomas Soome 	nvp_header_t *nvph;
534b713c91eSToomas Soome 	nvs_data_t *nvs;
535b713c91eSToomas Soome 	unsigned encoded_size, decoded_size;
536b713c91eSToomas Soome 	int rv;
537b713c91eSToomas Soome 
538b713c91eSToomas Soome 	nvs = (nvs_data_t *)xdr->xdr_idx;
539b713c91eSToomas Soome 	nvph = &nvs->nvl_pair;
540b713c91eSToomas Soome 
541b713c91eSToomas Soome 	if (!xdr_u_int(xdr, &nvs->nvl_version))
542b713c91eSToomas Soome 		return (EINVAL);
543b713c91eSToomas Soome 	if (!xdr_u_int(xdr, &nvs->nvl_nvflag))
544b713c91eSToomas Soome 		return (EINVAL);
545b713c91eSToomas Soome 
546b713c91eSToomas Soome 	encoded_size = nvph->encoded_size;
547b713c91eSToomas Soome 	decoded_size = nvph->decoded_size;
548b713c91eSToomas Soome 
549b713c91eSToomas Soome 	if (xdr->xdr_op == XDR_OP_ENCODE) {
550b713c91eSToomas Soome 		if (!xdr_u_int(xdr, &nvph->encoded_size))
551b713c91eSToomas Soome 			return (EINVAL);
552b713c91eSToomas Soome 		if (!xdr_u_int(xdr, &nvph->decoded_size))
553b713c91eSToomas Soome 			return (EINVAL);
554b713c91eSToomas Soome 	} else {
555b713c91eSToomas Soome 		xdr->xdr_idx += 2 * sizeof (unsigned);
556b713c91eSToomas Soome 	}
557b713c91eSToomas Soome 
558b713c91eSToomas Soome 	rv = 0;
559b713c91eSToomas Soome 	while (encoded_size && decoded_size) {
560b713c91eSToomas Soome 		if (!nvlist_xdr_nvp(xdr, nvl))
561b713c91eSToomas Soome 			return (EINVAL);
562b713c91eSToomas Soome 
563b713c91eSToomas Soome 		nvph = (nvp_header_t *)(xdr->xdr_idx);
564b713c91eSToomas Soome 		encoded_size = nvph->encoded_size;
565b713c91eSToomas Soome 		decoded_size = nvph->decoded_size;
566b713c91eSToomas Soome 		if (xdr->xdr_op == XDR_OP_ENCODE) {
567b713c91eSToomas Soome 			if (!xdr_u_int(xdr, &nvph->encoded_size))
568b713c91eSToomas Soome 				return (EINVAL);
569b713c91eSToomas Soome 			if (!xdr_u_int(xdr, &nvph->decoded_size))
570b713c91eSToomas Soome 				return (EINVAL);
571b713c91eSToomas Soome 		} else {
572b713c91eSToomas Soome 			xdr->xdr_idx += 2 * sizeof (unsigned);
573b713c91eSToomas Soome 		}
574b713c91eSToomas Soome 	}
575b713c91eSToomas Soome 	return (rv);
576b713c91eSToomas Soome }
577b713c91eSToomas Soome 
578b713c91eSToomas Soome /*
579b713c91eSToomas Soome  * Calculate nvlist size, translating encoded_size and decoded_size.
580b713c91eSToomas Soome  */
581b713c91eSToomas Soome static bool
nvlist_size_xdr(xdr_t * xdr,size_t * size)582b713c91eSToomas Soome nvlist_size_xdr(xdr_t *xdr, size_t *size)
583b713c91eSToomas Soome {
584b713c91eSToomas Soome 	uint8_t *pair;
585b713c91eSToomas Soome 	unsigned encoded_size, decoded_size;
586b713c91eSToomas Soome 
587b713c91eSToomas Soome 	xdr->xdr_idx += 2 * sizeof (unsigned);
588b713c91eSToomas Soome 
589b713c91eSToomas Soome 	pair = xdr->xdr_idx;
590b713c91eSToomas Soome 	if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size))
591b713c91eSToomas Soome 		return (false);
592b713c91eSToomas Soome 
593b713c91eSToomas Soome 	while (encoded_size && decoded_size) {
594b713c91eSToomas Soome 		xdr->xdr_idx = pair + encoded_size;
595b713c91eSToomas Soome 		pair = xdr->xdr_idx;
596b713c91eSToomas Soome 		if (!xdr_u_int(xdr, &encoded_size) ||
597b713c91eSToomas Soome 		    !xdr_u_int(xdr, &decoded_size))
598b713c91eSToomas Soome 			return (false);
599b713c91eSToomas Soome 	}
600b713c91eSToomas Soome 	*size = xdr->xdr_idx - xdr->xdr_buf;
601b713c91eSToomas Soome 
602b713c91eSToomas Soome 	return (true);
603b713c91eSToomas Soome }
604b713c91eSToomas Soome 
605b713c91eSToomas Soome nvp_header_t *
nvlist_next_nvpair(nvlist_t * nvl,nvp_header_t * nvh)606b713c91eSToomas Soome nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh)
607b713c91eSToomas Soome {
608b713c91eSToomas Soome 	uint8_t *pair;
609b713c91eSToomas Soome 	unsigned encoded_size, decoded_size;
610b713c91eSToomas Soome 	xdr_t xdr;
611b713c91eSToomas Soome 
612b713c91eSToomas Soome 	if (nvl == NULL)
613b713c91eSToomas Soome 		return (NULL);
614b713c91eSToomas Soome 
615b713c91eSToomas Soome 	xdr.xdr_buf = nvl->nv_data;
616b713c91eSToomas Soome 	xdr.xdr_idx = nvl->nv_data;
617b713c91eSToomas Soome 	xdr.xdr_buf_size = nvl->nv_size;
618b713c91eSToomas Soome 
619b713c91eSToomas Soome 	xdr.xdr_idx += 2 * sizeof (unsigned);
620b713c91eSToomas Soome 
621b713c91eSToomas Soome 	/* Skip tp current pair */
622b713c91eSToomas Soome 	if (nvh != NULL) {
623b713c91eSToomas Soome 		xdr.xdr_idx = (uint8_t *)nvh;
624b713c91eSToomas Soome 	}
625b713c91eSToomas Soome 
626b713c91eSToomas Soome 	pair = xdr.xdr_idx;
627b713c91eSToomas Soome 	if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
628b713c91eSToomas Soome 		return (NULL);
629b713c91eSToomas Soome 
630b713c91eSToomas Soome 	encoded_size = *(unsigned *)xdr.xdr_idx;
631b713c91eSToomas Soome 	xdr.xdr_idx += sizeof (unsigned);
632b713c91eSToomas Soome 	if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
633b713c91eSToomas Soome 		return (NULL);
634b713c91eSToomas Soome 
635b713c91eSToomas Soome 	decoded_size = *(unsigned *)xdr.xdr_idx;
636b713c91eSToomas Soome 	xdr.xdr_idx += sizeof (unsigned);
637b713c91eSToomas Soome 	if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
638b713c91eSToomas Soome 		return (NULL);
639b713c91eSToomas Soome 
640b713c91eSToomas Soome 	while (encoded_size && decoded_size) {
641b713c91eSToomas Soome 		if (nvh == NULL)
642b713c91eSToomas Soome 			return ((nvp_header_t *)pair);
643b713c91eSToomas Soome 
644b713c91eSToomas Soome 		xdr.xdr_idx = pair + encoded_size;
645b713c91eSToomas Soome 		nvh = (nvp_header_t *)xdr.xdr_idx;
646b713c91eSToomas Soome 
647b713c91eSToomas Soome 		if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
648b713c91eSToomas Soome 			return (NULL);
649b713c91eSToomas Soome 
650b713c91eSToomas Soome 		encoded_size = *(unsigned *)xdr.xdr_idx;
651b713c91eSToomas Soome 		xdr.xdr_idx += sizeof (unsigned);
652b713c91eSToomas Soome 		if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
653b713c91eSToomas Soome 			return (NULL);
654b713c91eSToomas Soome 		decoded_size = *(unsigned *)xdr.xdr_idx;
655b713c91eSToomas Soome 		xdr.xdr_idx += sizeof (unsigned);
656b713c91eSToomas Soome 		if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
657b713c91eSToomas Soome 			return (NULL);
658b713c91eSToomas Soome 
659b713c91eSToomas Soome 		if (encoded_size != 0 && decoded_size != 0) {
660b713c91eSToomas Soome 			return (nvh);
661b713c91eSToomas Soome 		}
662b713c91eSToomas Soome 	}
663b713c91eSToomas Soome 	return (NULL);
664b713c91eSToomas Soome }
665b713c91eSToomas Soome 
666b713c91eSToomas Soome /*
667b713c91eSToomas Soome  * Calculate nvlist size by walking in memory data.
668b713c91eSToomas Soome  */
669b713c91eSToomas Soome static bool
nvlist_size_native(xdr_t * xdr,size_t * size)670b713c91eSToomas Soome nvlist_size_native(xdr_t *xdr, size_t *size)
671b713c91eSToomas Soome {
672b713c91eSToomas Soome 	uint8_t *pair;
673b713c91eSToomas Soome 	unsigned encoded_size, decoded_size;
674b713c91eSToomas Soome 
675b713c91eSToomas Soome 	xdr->xdr_idx += 2 * sizeof (unsigned);
676b713c91eSToomas Soome 
677b713c91eSToomas Soome 	pair = xdr->xdr_idx;
678b713c91eSToomas Soome 	if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
679b713c91eSToomas Soome 		return (false);
680b713c91eSToomas Soome 
681b713c91eSToomas Soome 	encoded_size = *(unsigned *)xdr->xdr_idx;
682b713c91eSToomas Soome 	xdr->xdr_idx += sizeof (unsigned);
683b713c91eSToomas Soome 	if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
684b713c91eSToomas Soome 		return (false);
685b713c91eSToomas Soome 	decoded_size = *(unsigned *)xdr->xdr_idx;
686b713c91eSToomas Soome 	xdr->xdr_idx += sizeof (unsigned);
687b713c91eSToomas Soome 	while (encoded_size && decoded_size) {
688b713c91eSToomas Soome 		xdr->xdr_idx = pair + encoded_size;
689b713c91eSToomas Soome 		pair = xdr->xdr_idx;
690b713c91eSToomas Soome 		if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
691b713c91eSToomas Soome 			return (false);
692b713c91eSToomas Soome 		encoded_size = *(unsigned *)xdr->xdr_idx;
693b713c91eSToomas Soome 		xdr->xdr_idx += sizeof (unsigned);
694b713c91eSToomas Soome 		if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
695b713c91eSToomas Soome 			return (false);
696b713c91eSToomas Soome 		decoded_size = *(unsigned *)xdr->xdr_idx;
697b713c91eSToomas Soome 		xdr->xdr_idx += sizeof (unsigned);
698b713c91eSToomas Soome 	}
699b713c91eSToomas Soome 	*size = xdr->xdr_idx - xdr->xdr_buf;
700b713c91eSToomas Soome 
701b713c91eSToomas Soome 	return (true);
702b713c91eSToomas Soome }
703b713c91eSToomas Soome 
704b713c91eSToomas Soome /*
705b713c91eSToomas Soome  * Export nvlist to byte stream format.
706b713c91eSToomas Soome  */
707b713c91eSToomas Soome int
nvlist_export(nvlist_t * nvl)708b713c91eSToomas Soome nvlist_export(nvlist_t *nvl)
709b713c91eSToomas Soome {
710b713c91eSToomas Soome 	int rv;
711b713c91eSToomas Soome 	xdr_t xdr = {
712b713c91eSToomas Soome 		.xdr_op = XDR_OP_ENCODE,
713b713c91eSToomas Soome 		.xdr_putint = _putint,
714b713c91eSToomas Soome 		.xdr_putuint = _putuint,
715b713c91eSToomas Soome 		.xdr_buf = nvl->nv_data,
716b713c91eSToomas Soome 		.xdr_idx = nvl->nv_data,
717b713c91eSToomas Soome 		.xdr_buf_size = nvl->nv_size
718b713c91eSToomas Soome 	};
719b713c91eSToomas Soome 
720b713c91eSToomas Soome 	if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR)
721b713c91eSToomas Soome 		return (ENOTSUP);
722b713c91eSToomas Soome 
723b713c91eSToomas Soome 	nvl->nv_idx = nvl->nv_data;
724b713c91eSToomas Soome 	rv = nvlist_xdr_nvlist(&xdr, nvl);
725b713c91eSToomas Soome 
726b713c91eSToomas Soome 	return (rv);
727b713c91eSToomas Soome }
728b713c91eSToomas Soome 
729b713c91eSToomas Soome /*
730b713c91eSToomas Soome  * Import nvlist from byte stream.
731b713c91eSToomas Soome  * Determine the stream size and allocate private copy.
732b713c91eSToomas Soome  * Then translate the data.
733b713c91eSToomas Soome  */
734b713c91eSToomas Soome nvlist_t *
nvlist_import(const char * stream,size_t size)735b713c91eSToomas Soome nvlist_import(const char *stream, size_t size)
736b713c91eSToomas Soome {
737b713c91eSToomas Soome 	nvlist_t *nvl;
738b713c91eSToomas Soome 	xdr_t xdr = {
739b713c91eSToomas Soome 		.xdr_op = XDR_OP_DECODE,
740b713c91eSToomas Soome 		.xdr_getint = _getint,
741b713c91eSToomas Soome 		.xdr_getuint = _getuint
742b713c91eSToomas Soome 	};
743b713c91eSToomas Soome 
744b713c91eSToomas Soome 	/* Check the nvlist head. */
745b713c91eSToomas Soome 	if (stream[0] != NV_ENCODE_XDR ||
746b713c91eSToomas Soome 	    (stream[1] != '\0' && stream[1] != '\1') ||
747b713c91eSToomas Soome 	    stream[2] != '\0' || stream[3] != '\0' ||
748b713c91eSToomas Soome 	    be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION ||
749b713c91eSToomas Soome 	    be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME)
750b713c91eSToomas Soome 		return (NULL);
751b713c91eSToomas Soome 
752b713c91eSToomas Soome 	nvl = malloc(sizeof (*nvl));
753b713c91eSToomas Soome 	if (nvl == NULL)
754b713c91eSToomas Soome 		return (nvl);
755b713c91eSToomas Soome 
756b713c91eSToomas Soome 	nvl->nv_header.nvh_encoding = stream[0];
757b713c91eSToomas Soome 	nvl->nv_header.nvh_endian = stream[1];
758b713c91eSToomas Soome 	nvl->nv_header.nvh_reserved1 = stream[2];
759b713c91eSToomas Soome 	nvl->nv_header.nvh_reserved2 = stream[3];
760b713c91eSToomas Soome 
761b713c91eSToomas Soome 	xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4;
762b713c91eSToomas Soome 	xdr.xdr_buf_size = size - 4;
763b713c91eSToomas Soome 
764b713c91eSToomas Soome 	if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) {
765b713c91eSToomas Soome 		free(nvl);
766b713c91eSToomas Soome 		return (NULL);
767b713c91eSToomas Soome 	}
768b713c91eSToomas Soome 	nvl->nv_size = nvl->nv_asize;
769b713c91eSToomas Soome 	nvl->nv_data = malloc(nvl->nv_asize);
770b713c91eSToomas Soome 	if (nvl->nv_data == NULL) {
771b713c91eSToomas Soome 		free(nvl);
772b713c91eSToomas Soome 		return (NULL);
773b713c91eSToomas Soome 	}
774b713c91eSToomas Soome 	nvl->nv_idx = nvl->nv_data;
775b713c91eSToomas Soome 	bcopy(stream + 4, nvl->nv_data, nvl->nv_asize);
776b713c91eSToomas Soome 
777b713c91eSToomas Soome 	xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data;
778b713c91eSToomas Soome 	xdr.xdr_buf_size = nvl->nv_asize;
779b713c91eSToomas Soome 
780b713c91eSToomas Soome 	if (nvlist_xdr_nvlist(&xdr, nvl) != 0) {
781b713c91eSToomas Soome 		free(nvl->nv_data);
782b713c91eSToomas Soome 		free(nvl);
783b713c91eSToomas Soome 		nvl = NULL;
784b713c91eSToomas Soome 	}
785b713c91eSToomas Soome 
786b713c91eSToomas Soome 	return (nvl);
787b713c91eSToomas Soome }
788b713c91eSToomas Soome 
789b713c91eSToomas Soome /*
790b713c91eSToomas Soome  * remove pair from this nvlist.
791b713c91eSToomas Soome  */
792b713c91eSToomas Soome int
nvlist_remove(nvlist_t * nvl,const char * name,data_type_t type)793b713c91eSToomas Soome nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
794b713c91eSToomas Soome {
795b713c91eSToomas Soome 	uint8_t *head, *tail;
796b713c91eSToomas Soome 	nvs_data_t *data;
797b713c91eSToomas Soome 	nvp_header_t *nvp;
798b713c91eSToomas Soome 	nv_string_t *nvp_name;
799b713c91eSToomas Soome 	nv_pair_data_t *nvp_data;
800b713c91eSToomas Soome 	size_t size;
801b713c91eSToomas Soome 	xdr_t xdr;
802b713c91eSToomas Soome 
803b713c91eSToomas Soome 	if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
804b713c91eSToomas Soome 		return (EINVAL);
805b713c91eSToomas Soome 
806b713c91eSToomas Soome 	/* Make sure the nvlist size is set correct */
807b713c91eSToomas Soome 	xdr.xdr_idx = nvl->nv_data;
808b713c91eSToomas Soome 	xdr.xdr_buf = xdr.xdr_idx;
809b713c91eSToomas Soome 	xdr.xdr_buf_size = nvl->nv_size;
810b713c91eSToomas Soome 	if (!nvlist_size_native(&xdr, &nvl->nv_size))
811b713c91eSToomas Soome 		return (EINVAL);
812b713c91eSToomas Soome 
813b713c91eSToomas Soome 	data = (nvs_data_t *)nvl->nv_data;
814b713c91eSToomas Soome 	nvp = &data->nvl_pair;	/* first pair in nvlist */
815b713c91eSToomas Soome 	head = (uint8_t *)nvp;
816b713c91eSToomas Soome 
817b713c91eSToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
818b713c91eSToomas Soome 		nvp_name = (nv_string_t *)(nvp + 1);
819b713c91eSToomas Soome 
820b713c91eSToomas Soome 		nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] +
821b713c91eSToomas Soome 		    NV_ALIGN4(nvp_name->nv_size));
822b713c91eSToomas Soome 
823b713c91eSToomas Soome 		if (strlen(name) == nvp_name->nv_size &&
824b713c91eSToomas Soome 		    memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
825b713c91eSToomas Soome 		    (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
826b713c91eSToomas Soome 			/*
827b713c91eSToomas Soome 			 * set tail to point to next nvpair and size
828b713c91eSToomas Soome 			 * is the length of the tail.
829b713c91eSToomas Soome 			 */
830b713c91eSToomas Soome 			tail = head + nvp->encoded_size;
831b713c91eSToomas Soome 			size = nvl->nv_size - (tail - nvl->nv_data);
832b713c91eSToomas Soome 
833b713c91eSToomas Soome 			/* adjust the size of the nvlist. */
834b713c91eSToomas Soome 			nvl->nv_size -= nvp->encoded_size;
835b713c91eSToomas Soome 			bcopy(tail, head, size);
836b713c91eSToomas Soome 			return (0);
837b713c91eSToomas Soome 		}
838b713c91eSToomas Soome 		/* Not our pair, skip to next. */
839b713c91eSToomas Soome 		head = head + nvp->encoded_size;
840b713c91eSToomas Soome 		nvp = (nvp_header_t *)head;
841b713c91eSToomas Soome 	}
842b713c91eSToomas Soome 	return (ENOENT);
843b713c91eSToomas Soome }
844b713c91eSToomas Soome 
845b713c91eSToomas Soome static int
clone_nvlist(const nvlist_t * nvl,const uint8_t * ptr,unsigned size,nvlist_t ** nvlist)846b713c91eSToomas Soome clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size,
847b713c91eSToomas Soome     nvlist_t **nvlist)
848b713c91eSToomas Soome {
849b713c91eSToomas Soome 	nvlist_t *nv;
850b713c91eSToomas Soome 
851b713c91eSToomas Soome 	nv = calloc(1, sizeof (*nv));
852b713c91eSToomas Soome 	if (nv == NULL)
853b713c91eSToomas Soome 		return (ENOMEM);
854b713c91eSToomas Soome 
855b713c91eSToomas Soome 	nv->nv_header = nvl->nv_header;
856b713c91eSToomas Soome 	nv->nv_asize = size;
857b713c91eSToomas Soome 	nv->nv_size = size;
858b713c91eSToomas Soome 	nv->nv_data = malloc(nv->nv_asize);
859b713c91eSToomas Soome 	if (nv->nv_data == NULL) {
860b713c91eSToomas Soome 		free(nv);
861b713c91eSToomas Soome 		return (ENOMEM);
862b713c91eSToomas Soome 	}
863b713c91eSToomas Soome 
864b713c91eSToomas Soome 	bcopy(ptr, nv->nv_data, nv->nv_asize);
865b713c91eSToomas Soome 	*nvlist = nv;
866b713c91eSToomas Soome 	return (0);
867b713c91eSToomas Soome }
868b713c91eSToomas Soome 
869b713c91eSToomas Soome /*
870b713c91eSToomas Soome  * Return the next nvlist in an nvlist array.
871b713c91eSToomas Soome  */
872b713c91eSToomas Soome static uint8_t *
nvlist_next(const uint8_t * ptr)873b713c91eSToomas Soome nvlist_next(const uint8_t *ptr)
874b713c91eSToomas Soome {
875b713c91eSToomas Soome 	nvs_data_t *data;
876b713c91eSToomas Soome 	nvp_header_t *nvp;
877b713c91eSToomas Soome 
878b713c91eSToomas Soome 	data = (nvs_data_t *)ptr;
879b713c91eSToomas Soome 	nvp = &data->nvl_pair;	/* first pair in nvlist */
880b713c91eSToomas Soome 
881b713c91eSToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
882b713c91eSToomas Soome 		nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
883b713c91eSToomas Soome 	}
884b713c91eSToomas Soome 	return ((uint8_t *)nvp + sizeof (*nvp));
885b713c91eSToomas Soome }
886b713c91eSToomas Soome 
887b713c91eSToomas Soome /*
888b713c91eSToomas Soome  * Note: nvlist and nvlist array must be freed by caller.
889b713c91eSToomas Soome  */
890b713c91eSToomas Soome int
nvlist_find(const nvlist_t * nvl,const char * name,data_type_t type,int * elementsp,void * valuep,int * sizep)891b713c91eSToomas Soome nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type,
892b713c91eSToomas Soome     int *elementsp, void *valuep, int *sizep)
893b713c91eSToomas Soome {
894b713c91eSToomas Soome 	nvs_data_t *data;
895b713c91eSToomas Soome 	nvp_header_t *nvp;
896b713c91eSToomas Soome 	nv_string_t *nvp_name;
897b713c91eSToomas Soome 	nv_pair_data_t *nvp_data;
898b713c91eSToomas Soome 	nvlist_t **nvlist, *nv;
899b713c91eSToomas Soome 	uint8_t *ptr;
900b713c91eSToomas Soome 	int rv;
901b713c91eSToomas Soome 
902b713c91eSToomas Soome 	if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
903b713c91eSToomas Soome 		return (EINVAL);
904b713c91eSToomas Soome 
905b713c91eSToomas Soome 	data = (nvs_data_t *)nvl->nv_data;
906b713c91eSToomas Soome 	nvp = &data->nvl_pair;	/* first pair in nvlist */
907b713c91eSToomas Soome 
908b713c91eSToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
909b713c91eSToomas Soome 		nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof (*nvp));
910b713c91eSToomas Soome 		if (nvl->nv_data + nvl->nv_size <
911b713c91eSToomas Soome 		    nvp_name->nv_data + nvp_name->nv_size)
912b713c91eSToomas Soome 			return (EIO);
913b713c91eSToomas Soome 
914b713c91eSToomas Soome 		nvp_data = (nv_pair_data_t *)
915b713c91eSToomas Soome 		    NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
916b713c91eSToomas Soome 		    nvp_name->nv_size);
917b713c91eSToomas Soome 
918b713c91eSToomas Soome 		if (strlen(name) == nvp_name->nv_size &&
919b713c91eSToomas Soome 		    memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
920b713c91eSToomas Soome 		    (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
921b713c91eSToomas Soome 			if (elementsp != NULL)
922b713c91eSToomas Soome 				*elementsp = nvp_data->nv_nelem;
923b713c91eSToomas Soome 			switch (nvp_data->nv_type) {
924b713c91eSToomas Soome 			case DATA_TYPE_UINT64:
925b713c91eSToomas Soome 				bcopy(nvp_data->nv_data, valuep,
926b713c91eSToomas Soome 				    sizeof (uint64_t));
927b713c91eSToomas Soome 				return (0);
928b713c91eSToomas Soome 			case DATA_TYPE_STRING:
929b713c91eSToomas Soome 				nvp_name = (nv_string_t *)nvp_data->nv_data;
930b713c91eSToomas Soome 				if (sizep != NULL) {
931b713c91eSToomas Soome 					*sizep = nvp_name->nv_size;
932b713c91eSToomas Soome 				}
933b713c91eSToomas Soome 				*(const uint8_t **)valuep =
934b713c91eSToomas Soome 				    &nvp_name->nv_data[0];
935b713c91eSToomas Soome 				return (0);
936b713c91eSToomas Soome 			case DATA_TYPE_NVLIST:
937b713c91eSToomas Soome 				ptr = &nvp_data->nv_data[0];
938b713c91eSToomas Soome 				rv = clone_nvlist(nvl, ptr,
939b713c91eSToomas Soome 				    nvlist_next(ptr) - ptr, &nv);
940b713c91eSToomas Soome 				if (rv == 0) {
941b713c91eSToomas Soome 					*(nvlist_t **)valuep = nv;
942b713c91eSToomas Soome 				}
943b713c91eSToomas Soome 				return (rv);
944b713c91eSToomas Soome 
945b713c91eSToomas Soome 			case DATA_TYPE_NVLIST_ARRAY:
946b713c91eSToomas Soome 				nvlist = calloc(nvp_data->nv_nelem,
947b713c91eSToomas Soome 				    sizeof (nvlist_t *));
948b713c91eSToomas Soome 				if (nvlist == NULL)
949b713c91eSToomas Soome 					return (ENOMEM);
950b713c91eSToomas Soome 				ptr = &nvp_data->nv_data[0];
951b713c91eSToomas Soome 				rv = 0;
952b713c91eSToomas Soome 				for (unsigned i = 0; i < nvp_data->nv_nelem;
953b713c91eSToomas Soome 				    i++) {
954b713c91eSToomas Soome 					rv = clone_nvlist(nvl, ptr,
955b713c91eSToomas Soome 					    nvlist_next(ptr) - ptr, &nvlist[i]);
956b713c91eSToomas Soome 					if (rv != 0)
957b713c91eSToomas Soome 						goto error;
958b713c91eSToomas Soome 					ptr = nvlist_next(ptr);
959b713c91eSToomas Soome 				}
960b713c91eSToomas Soome 				*(nvlist_t ***)valuep = nvlist;
961b713c91eSToomas Soome 				return (rv);
962b713c91eSToomas Soome 			}
963b713c91eSToomas Soome 			return (EIO);
964b713c91eSToomas Soome 		}
965b713c91eSToomas Soome 		/* Not our pair, skip to next. */
966b713c91eSToomas Soome 		nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
967b713c91eSToomas Soome 		if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp)
968b713c91eSToomas Soome 			return (EIO);
969b713c91eSToomas Soome 	}
970b713c91eSToomas Soome 	return (ENOENT);
971b713c91eSToomas Soome error:
972b713c91eSToomas Soome 	for (unsigned i = 0; i < nvp_data->nv_nelem; i++) {
973b713c91eSToomas Soome 		free(nvlist[i]->nv_data);
974b713c91eSToomas Soome 		free(nvlist[i]);
975b713c91eSToomas Soome 	}
976b713c91eSToomas Soome 	free(nvlist);
977b713c91eSToomas Soome 	return (rv);
978b713c91eSToomas Soome }
979b713c91eSToomas Soome 
980b713c91eSToomas Soome static int
get_value_size(data_type_t type,const void * data,uint32_t nelem)981b713c91eSToomas Soome get_value_size(data_type_t type, const void *data, uint32_t nelem)
982b713c91eSToomas Soome {
983b713c91eSToomas Soome 	uint64_t value_sz = 0;
984b713c91eSToomas Soome 
985b713c91eSToomas Soome 	switch (type) {
986b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN:
987b713c91eSToomas Soome 		value_sz = 0;
988b713c91eSToomas Soome 		break;
989b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
990b713c91eSToomas Soome 	case DATA_TYPE_BYTE:
991b713c91eSToomas Soome 	case DATA_TYPE_INT8:
992b713c91eSToomas Soome 	case DATA_TYPE_UINT8:
993b713c91eSToomas Soome 	case DATA_TYPE_INT16:
994b713c91eSToomas Soome 	case DATA_TYPE_UINT16:
995b713c91eSToomas Soome 	case DATA_TYPE_INT32:
996b713c91eSToomas Soome 	case DATA_TYPE_UINT32:
997b713c91eSToomas Soome 		/* Our smallest data unit is 32-bit */
998b713c91eSToomas Soome 		value_sz = sizeof (uint32_t);
999b713c91eSToomas Soome 		break;
1000b713c91eSToomas Soome 	case DATA_TYPE_HRTIME:
1001b713c91eSToomas Soome 	case DATA_TYPE_INT64:
1002b713c91eSToomas Soome 		value_sz = sizeof (int64_t);
1003b713c91eSToomas Soome 		break;
1004b713c91eSToomas Soome 	case DATA_TYPE_UINT64:
1005b713c91eSToomas Soome 		value_sz = sizeof (uint64_t);
1006b713c91eSToomas Soome 		break;
1007b713c91eSToomas Soome 	case DATA_TYPE_STRING:
1008b713c91eSToomas Soome 		if (data == NULL)
1009b713c91eSToomas Soome 			value_sz = 0;
1010b713c91eSToomas Soome 		else
1011b713c91eSToomas Soome 			value_sz = strlen(data) + 1;
1012b713c91eSToomas Soome 		break;
1013b713c91eSToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
1014b713c91eSToomas Soome 		value_sz = nelem * sizeof (uint8_t);
1015b713c91eSToomas Soome 		break;
1016b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
1017b713c91eSToomas Soome 	case DATA_TYPE_INT8_ARRAY:
1018b713c91eSToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
1019b713c91eSToomas Soome 	case DATA_TYPE_INT16_ARRAY:
1020b713c91eSToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
1021b713c91eSToomas Soome 	case DATA_TYPE_INT32_ARRAY:
1022b713c91eSToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
1023b713c91eSToomas Soome 		value_sz = (uint64_t)nelem * sizeof (uint32_t);
1024b713c91eSToomas Soome 		break;
1025b713c91eSToomas Soome 	case DATA_TYPE_INT64_ARRAY:
1026b713c91eSToomas Soome 		value_sz = (uint64_t)nelem * sizeof (int64_t);
1027b713c91eSToomas Soome 		break;
1028b713c91eSToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
1029b713c91eSToomas Soome 		value_sz = (uint64_t)nelem * sizeof (uint64_t);
1030b713c91eSToomas Soome 		break;
1031b713c91eSToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1032b713c91eSToomas Soome 		value_sz = (uint64_t)nelem * sizeof (uint64_t);
1033b713c91eSToomas Soome 
1034b713c91eSToomas Soome 		if (data != NULL) {
1035b713c91eSToomas Soome 			char *const *strs = data;
1036b713c91eSToomas Soome 			uint32_t i;
1037b713c91eSToomas Soome 
1038b713c91eSToomas Soome 			for (i = 0; i < nelem; i++) {
1039b713c91eSToomas Soome 				if (strs[i] == NULL)
1040b713c91eSToomas Soome 					return (-1);
1041b713c91eSToomas Soome 				value_sz += strlen(strs[i]) + 1;
1042b713c91eSToomas Soome 			}
1043b713c91eSToomas Soome 		}
1044b713c91eSToomas Soome 		break;
1045b713c91eSToomas Soome 	case DATA_TYPE_NVLIST:
1046b713c91eSToomas Soome 		/*
1047b713c91eSToomas Soome 		 * The decoded size of nvlist is constant.
1048b713c91eSToomas Soome 		 */
1049b713c91eSToomas Soome 		value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1050b713c91eSToomas Soome 		break;
1051b713c91eSToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
1052b713c91eSToomas Soome 		value_sz = (uint64_t)nelem * sizeof (uint64_t) +
1053b713c91eSToomas Soome 		    (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1054b713c91eSToomas Soome 		break;
1055b713c91eSToomas Soome 	default:
1056b713c91eSToomas Soome 		return (-1);
1057b713c91eSToomas Soome 	}
1058b713c91eSToomas Soome 
1059b713c91eSToomas Soome 	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1060b713c91eSToomas Soome }
1061b713c91eSToomas Soome 
1062b713c91eSToomas Soome static int
get_nvp_data_size(data_type_t type,const void * data,uint32_t nelem)1063b713c91eSToomas Soome get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem)
1064b713c91eSToomas Soome {
1065b713c91eSToomas Soome 	uint64_t value_sz = 0;
1066b713c91eSToomas Soome 	xdr_t xdr;
1067b713c91eSToomas Soome 	size_t size;
1068b713c91eSToomas Soome 
1069b713c91eSToomas Soome 	switch (type) {
1070b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN:
1071b713c91eSToomas Soome 		value_sz = 0;
1072b713c91eSToomas Soome 		break;
1073b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
1074b713c91eSToomas Soome 	case DATA_TYPE_BYTE:
1075b713c91eSToomas Soome 	case DATA_TYPE_INT8:
1076b713c91eSToomas Soome 	case DATA_TYPE_UINT8:
1077b713c91eSToomas Soome 	case DATA_TYPE_INT16:
1078b713c91eSToomas Soome 	case DATA_TYPE_UINT16:
1079b713c91eSToomas Soome 	case DATA_TYPE_INT32:
1080b713c91eSToomas Soome 	case DATA_TYPE_UINT32:
1081b713c91eSToomas Soome 		/* Our smallest data unit is 32-bit */
1082b713c91eSToomas Soome 		value_sz = sizeof (uint32_t);
1083b713c91eSToomas Soome 		break;
1084b713c91eSToomas Soome 	case DATA_TYPE_HRTIME:
1085b713c91eSToomas Soome 	case DATA_TYPE_INT64:
1086b713c91eSToomas Soome 	case DATA_TYPE_UINT64:
1087b713c91eSToomas Soome 		value_sz = sizeof (uint64_t);
1088b713c91eSToomas Soome 		break;
1089b713c91eSToomas Soome 	case DATA_TYPE_STRING:
1090b713c91eSToomas Soome 		value_sz = 4 + NV_ALIGN4(strlen(data));
1091b713c91eSToomas Soome 		break;
1092b713c91eSToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
1093b713c91eSToomas Soome 		value_sz = NV_ALIGN4(nelem);
1094b713c91eSToomas Soome 		break;
1095b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
1096b713c91eSToomas Soome 	case DATA_TYPE_INT8_ARRAY:
1097b713c91eSToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
1098b713c91eSToomas Soome 	case DATA_TYPE_INT16_ARRAY:
1099b713c91eSToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
1100b713c91eSToomas Soome 	case DATA_TYPE_INT32_ARRAY:
1101b713c91eSToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
1102b713c91eSToomas Soome 		value_sz = 4 + (uint64_t)nelem * sizeof (uint32_t);
1103b713c91eSToomas Soome 		break;
1104b713c91eSToomas Soome 	case DATA_TYPE_INT64_ARRAY:
1105b713c91eSToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
1106b713c91eSToomas Soome 		value_sz = 4 + (uint64_t)nelem * sizeof (uint64_t);
1107b713c91eSToomas Soome 		break;
1108b713c91eSToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1109b713c91eSToomas Soome 		if (data != NULL) {
1110b713c91eSToomas Soome 			char *const *strs = data;
1111b713c91eSToomas Soome 			uint32_t i;
1112b713c91eSToomas Soome 
1113b713c91eSToomas Soome 			for (i = 0; i < nelem; i++) {
1114b713c91eSToomas Soome 				value_sz += 4 + NV_ALIGN4(strlen(strs[i]));
1115b713c91eSToomas Soome 			}
1116b713c91eSToomas Soome 		}
1117b713c91eSToomas Soome 		break;
1118b713c91eSToomas Soome 	case DATA_TYPE_NVLIST:
1119b713c91eSToomas Soome 		xdr.xdr_idx = ((nvlist_t *)data)->nv_data;
1120b713c91eSToomas Soome 		xdr.xdr_buf = xdr.xdr_idx;
1121b713c91eSToomas Soome 		xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size;
1122b713c91eSToomas Soome 
1123b713c91eSToomas Soome 		if (!nvlist_size_native(&xdr, &size))
1124b713c91eSToomas Soome 			return (-1);
1125b713c91eSToomas Soome 
1126b713c91eSToomas Soome 		value_sz = size;
1127b713c91eSToomas Soome 		break;
1128b713c91eSToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
1129b713c91eSToomas Soome 		value_sz = 0;
1130b713c91eSToomas Soome 		for (uint32_t i = 0; i < nelem; i++) {
1131b713c91eSToomas Soome 			xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1132b713c91eSToomas Soome 			xdr.xdr_buf = xdr.xdr_idx;
1133b713c91eSToomas Soome 			xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1134b713c91eSToomas Soome 
1135b713c91eSToomas Soome 			if (!nvlist_size_native(&xdr, &size))
1136b713c91eSToomas Soome 				return (-1);
1137b713c91eSToomas Soome 			value_sz += size;
1138b713c91eSToomas Soome 		}
1139b713c91eSToomas Soome 		break;
1140b713c91eSToomas Soome 	default:
1141b713c91eSToomas Soome 		return (-1);
1142b713c91eSToomas Soome 	}
1143b713c91eSToomas Soome 
1144b713c91eSToomas Soome 	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1145b713c91eSToomas Soome }
1146b713c91eSToomas Soome 
1147b713c91eSToomas Soome #define	NVPE_SIZE(name_len, data_len) \
1148b713c91eSToomas Soome 	(4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len)
1149b713c91eSToomas Soome #define	NVP_SIZE(name_len, data_len) \
1150b713c91eSToomas Soome 	(NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len))
1151b713c91eSToomas Soome 
1152b713c91eSToomas Soome static int
nvlist_add_common(nvlist_t * nvl,const char * name,data_type_t type,uint32_t nelem,const void * data)1153b713c91eSToomas Soome nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1154b713c91eSToomas Soome     uint32_t nelem, const void *data)
1155b713c91eSToomas Soome {
1156b713c91eSToomas Soome 	nvs_data_t *nvs;
1157b713c91eSToomas Soome 	nvp_header_t head, *hp;
1158b713c91eSToomas Soome 	uint8_t *ptr;
1159b713c91eSToomas Soome 	size_t namelen;
1160b713c91eSToomas Soome 	int decoded_size, encoded_size;
11610b14c199SToomas Soome 	xdr_t xdr = {
11620b14c199SToomas Soome 		.xdr_op = XDR_OP_ENCODE,
11630b14c199SToomas Soome 		.xdr_putint = _putint_mem,
11640b14c199SToomas Soome 		.xdr_putuint = _putuint_mem,
11650b14c199SToomas Soome 		.xdr_buf = nvl->nv_data,
11660b14c199SToomas Soome 		.xdr_idx = nvl->nv_data,
11670b14c199SToomas Soome 		.xdr_buf_size = nvl->nv_size
11680b14c199SToomas Soome 	};
1169b713c91eSToomas Soome 
1170b713c91eSToomas Soome 	nvs = (nvs_data_t *)nvl->nv_data;
1171b713c91eSToomas Soome 	if (nvs->nvl_nvflag & NV_UNIQUE_NAME)
1172b713c91eSToomas Soome 		(void) nvlist_remove(nvl, name, type);
1173b713c91eSToomas Soome 
1174b713c91eSToomas Soome 	if (!nvlist_size_native(&xdr, &nvl->nv_size))
1175b713c91eSToomas Soome 		return (EINVAL);
1176b713c91eSToomas Soome 
1177b713c91eSToomas Soome 	namelen = strlen(name);
1178b713c91eSToomas Soome 	if ((decoded_size = get_value_size(type, data, nelem)) < 0)
1179b713c91eSToomas Soome 		return (EINVAL);
1180b713c91eSToomas Soome 	if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0)
1181b713c91eSToomas Soome 		return (EINVAL);
1182b713c91eSToomas Soome 
1183b713c91eSToomas Soome 	/*
1184b713c91eSToomas Soome 	 * The encoded size is calculated as:
1185b713c91eSToomas Soome 	 * encode_size (4) + decode_size (4) +
1186b713c91eSToomas Soome 	 * name string size  (4 + NV_ALIGN4(namelen) +
1187b713c91eSToomas Soome 	 * data type (4) + nelem size (4) + datalen
1188b713c91eSToomas Soome 	 *
1189b713c91eSToomas Soome 	 * The decoded size is calculated as:
1190b713c91eSToomas Soome 	 * Note: namelen is with terminating 0.
1191b713c91eSToomas Soome 	 * NV_ALIGN(sizeof (nvpair_t) (4 * 4) + namelen + 1) +
1192b713c91eSToomas Soome 	 * NV_ALIGN(data_len)
1193b713c91eSToomas Soome 	 */
1194b713c91eSToomas Soome 
1195b713c91eSToomas Soome 	head.encoded_size = NVPE_SIZE(namelen, encoded_size);
1196b713c91eSToomas Soome 	head.decoded_size = NVP_SIZE(namelen + 1, decoded_size);
1197b713c91eSToomas Soome 
1198b713c91eSToomas Soome 	if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) {
1199b713c91eSToomas Soome 		ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size);
1200b713c91eSToomas Soome 		if (ptr == NULL)
1201b713c91eSToomas Soome 			return (ENOMEM);
1202b713c91eSToomas Soome 		nvl->nv_data = ptr;
1203b713c91eSToomas Soome 		nvl->nv_asize += head.encoded_size;
1204b713c91eSToomas Soome 	}
1205b713c91eSToomas Soome 	nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof (*hp);
1206b713c91eSToomas Soome 	bzero(nvl->nv_idx, head.encoded_size + 8);
1207b713c91eSToomas Soome 	hp = (nvp_header_t *)nvl->nv_idx;
1208b713c91eSToomas Soome 	*hp = head;
1209b713c91eSToomas Soome 	nvl->nv_idx += sizeof (*hp);
12100b14c199SToomas Soome 
12110b14c199SToomas Soome 	xdr.xdr_buf = nvl->nv_data;
1212*43075873SMark Johnston 	xdr.xdr_buf_size = nvl->nv_asize;
12130b14c199SToomas Soome 	xdr.xdr_idx = nvl->nv_idx;
12140b14c199SToomas Soome 
12150b14c199SToomas Soome 	xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen);
12160b14c199SToomas Soome 	strlcpy((char *)xdr.xdr_idx, name, namelen + 1);
12170b14c199SToomas Soome 	xdr.xdr_idx += NV_ALIGN4(namelen);
12180b14c199SToomas Soome 	xdr.xdr_idx += xdr.xdr_putuint(&xdr, type);
12190b14c199SToomas Soome 	xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem);
1220b713c91eSToomas Soome 
1221b713c91eSToomas Soome 	switch (type) {
1222b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN:
1223b713c91eSToomas Soome 		break;
12240b14c199SToomas Soome 
1225b713c91eSToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
12269a2cc6e2SToomas Soome 		xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12279a2cc6e2SToomas Soome 		bcopy(data, xdr.xdr_idx, nelem);
12289a2cc6e2SToomas Soome 		xdr.xdr_idx += NV_ALIGN4(encoded_size);
1229b713c91eSToomas Soome 		break;
12300b14c199SToomas Soome 
1231b713c91eSToomas Soome 	case DATA_TYPE_STRING:
1232b713c91eSToomas Soome 		encoded_size = strlen(data);
12330b14c199SToomas Soome 		xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12340b14c199SToomas Soome 		strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1);
12350b14c199SToomas Soome 		xdr.xdr_idx += NV_ALIGN4(encoded_size);
1236b713c91eSToomas Soome 		break;
12370b14c199SToomas Soome 
1238b713c91eSToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1239b713c91eSToomas Soome 		for (uint32_t i = 0; i < nelem; i++) {
1240b713c91eSToomas Soome 			encoded_size = strlen(((char **)data)[i]);
12410b14c199SToomas Soome 			xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12420b14c199SToomas Soome 			strlcpy((char *)xdr.xdr_idx, ((char **)data)[i],
1243b713c91eSToomas Soome 			    encoded_size + 1);
12440b14c199SToomas Soome 			xdr.xdr_idx += NV_ALIGN4(encoded_size);
1245b713c91eSToomas Soome 		}
1246b713c91eSToomas Soome 		break;
12470b14c199SToomas Soome 
1248b713c91eSToomas Soome 	case DATA_TYPE_BYTE:
1249b713c91eSToomas Soome 	case DATA_TYPE_INT8:
1250b713c91eSToomas Soome 	case DATA_TYPE_UINT8:
12510b14c199SToomas Soome 		xdr_char(&xdr, (char *)data);
12520b14c199SToomas Soome 		break;
12530b14c199SToomas Soome 
1254b713c91eSToomas Soome 	case DATA_TYPE_INT8_ARRAY:
1255b713c91eSToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
12560b14c199SToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_char);
1257b713c91eSToomas Soome 		break;
12580b14c199SToomas Soome 
1259b713c91eSToomas Soome 	case DATA_TYPE_INT16:
12600b14c199SToomas Soome 		xdr_short(&xdr, (short *)data);
12610b14c199SToomas Soome 		break;
12620b14c199SToomas Soome 
1263b713c91eSToomas Soome 	case DATA_TYPE_UINT16:
12640b14c199SToomas Soome 		xdr_u_short(&xdr, (unsigned short *)data);
12650b14c199SToomas Soome 		break;
12660b14c199SToomas Soome 
1267b713c91eSToomas Soome 	case DATA_TYPE_INT16_ARRAY:
12680b14c199SToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_short);
12690b14c199SToomas Soome 		break;
12700b14c199SToomas Soome 
1271b713c91eSToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
12720b14c199SToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short);
12730b14c199SToomas Soome 		break;
12740b14c199SToomas Soome 
12750b14c199SToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
12760b14c199SToomas Soome 	case DATA_TYPE_INT32:
12770b14c199SToomas Soome 		xdr_int(&xdr, (int *)data);
12780b14c199SToomas Soome 		break;
12790b14c199SToomas Soome 
12800b14c199SToomas Soome 	case DATA_TYPE_UINT32:
12810b14c199SToomas Soome 		xdr_u_int(&xdr, (unsigned int *)data);
12820b14c199SToomas Soome 		break;
12830b14c199SToomas Soome 
12840b14c199SToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
12850b14c199SToomas Soome 	case DATA_TYPE_INT32_ARRAY:
12860b14c199SToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_int);
12870b14c199SToomas Soome 		break;
12880b14c199SToomas Soome 
12890b14c199SToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
12900b14c199SToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int);
12910b14c199SToomas Soome 		break;
12920b14c199SToomas Soome 
12930b14c199SToomas Soome 	case DATA_TYPE_INT64:
12940b14c199SToomas Soome 		xdr_int64(&xdr, (int64_t *)data);
12950b14c199SToomas Soome 		break;
12960b14c199SToomas Soome 
12970b14c199SToomas Soome 	case DATA_TYPE_UINT64:
12980b14c199SToomas Soome 		xdr_uint64(&xdr, (uint64_t *)data);
12990b14c199SToomas Soome 		break;
13000b14c199SToomas Soome 
13010b14c199SToomas Soome 	case DATA_TYPE_INT64_ARRAY:
13020b14c199SToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64);
1303b713c91eSToomas Soome 		break;
13040b14c199SToomas Soome 
13050b14c199SToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
13060b14c199SToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64);
13070b14c199SToomas Soome 		break;
13080b14c199SToomas Soome 
1309b713c91eSToomas Soome 	case DATA_TYPE_NVLIST:
13100b14c199SToomas Soome 		bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size);
1311b713c91eSToomas Soome 		break;
13120b14c199SToomas Soome 
1313b713c91eSToomas Soome 	case DATA_TYPE_NVLIST_ARRAY: {
1314b713c91eSToomas Soome 		size_t size;
13159a2cc6e2SToomas Soome 		xdr_t xdr_nv;
1316b713c91eSToomas Soome 
1317b713c91eSToomas Soome 		for (uint32_t i = 0; i < nelem; i++) {
13189a2cc6e2SToomas Soome 			xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
13199a2cc6e2SToomas Soome 			xdr_nv.xdr_buf = xdr_nv.xdr_idx;
13209a2cc6e2SToomas Soome 			xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1321b713c91eSToomas Soome 
13229a2cc6e2SToomas Soome 			if (!nvlist_size_native(&xdr_nv, &size))
1323b713c91eSToomas Soome 				return (EINVAL);
1324b713c91eSToomas Soome 
13259a2cc6e2SToomas Soome 			bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx,
13269a2cc6e2SToomas Soome 			    size);
13279a2cc6e2SToomas Soome 			xdr.xdr_idx += size;
1328b713c91eSToomas Soome 		}
1329b713c91eSToomas Soome 		break;
1330b713c91eSToomas Soome 	}
13310b14c199SToomas Soome 
1332b713c91eSToomas Soome 	default:
13330b14c199SToomas Soome 		bcopy(data, xdr.xdr_idx, encoded_size);
1334b713c91eSToomas Soome 	}
1335b713c91eSToomas Soome 
1336b713c91eSToomas Soome 	nvl->nv_size += head.encoded_size;
1337b713c91eSToomas Soome 
1338b713c91eSToomas Soome 	return (0);
1339b713c91eSToomas Soome }
1340b713c91eSToomas Soome 
1341b713c91eSToomas Soome int
nvlist_add_boolean_value(nvlist_t * nvl,const char * name,boolean_t value)1342b713c91eSToomas Soome nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t value)
1343b713c91eSToomas Soome {
1344b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1,
1345b713c91eSToomas Soome 	    &value));
1346b713c91eSToomas Soome }
1347b713c91eSToomas Soome 
1348b713c91eSToomas Soome int
nvlist_add_byte(nvlist_t * nvl,const char * name,uint8_t value)1349b713c91eSToomas Soome nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value)
1350b713c91eSToomas Soome {
1351b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value));
1352b713c91eSToomas Soome }
1353b713c91eSToomas Soome 
1354b713c91eSToomas Soome int
nvlist_add_int8(nvlist_t * nvl,const char * name,int8_t value)1355b713c91eSToomas Soome nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value)
1356b713c91eSToomas Soome {
1357b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value));
1358b713c91eSToomas Soome }
1359b713c91eSToomas Soome 
1360b713c91eSToomas Soome int
nvlist_add_uint8(nvlist_t * nvl,const char * name,uint8_t value)1361b713c91eSToomas Soome nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value)
1362b713c91eSToomas Soome {
1363b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value));
1364b713c91eSToomas Soome }
1365b713c91eSToomas Soome 
1366b713c91eSToomas Soome int
nvlist_add_int16(nvlist_t * nvl,const char * name,int16_t value)1367b713c91eSToomas Soome nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value)
1368b713c91eSToomas Soome {
1369b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value));
1370b713c91eSToomas Soome }
1371b713c91eSToomas Soome 
1372b713c91eSToomas Soome int
nvlist_add_uint16(nvlist_t * nvl,const char * name,uint16_t value)1373b713c91eSToomas Soome nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value)
1374b713c91eSToomas Soome {
1375b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value));
1376b713c91eSToomas Soome }
1377b713c91eSToomas Soome 
1378b713c91eSToomas Soome int
nvlist_add_int32(nvlist_t * nvl,const char * name,int32_t value)1379b713c91eSToomas Soome nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value)
1380b713c91eSToomas Soome {
1381b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value));
1382b713c91eSToomas Soome }
1383b713c91eSToomas Soome 
1384b713c91eSToomas Soome int
nvlist_add_uint32(nvlist_t * nvl,const char * name,uint32_t value)1385b713c91eSToomas Soome nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value)
1386b713c91eSToomas Soome {
1387b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value));
1388b713c91eSToomas Soome }
1389b713c91eSToomas Soome 
1390b713c91eSToomas Soome int
nvlist_add_int64(nvlist_t * nvl,const char * name,int64_t value)1391b713c91eSToomas Soome nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value)
1392b713c91eSToomas Soome {
1393b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value));
1394b713c91eSToomas Soome }
1395b713c91eSToomas Soome 
1396b713c91eSToomas Soome int
nvlist_add_uint64(nvlist_t * nvl,const char * name,uint64_t value)1397b713c91eSToomas Soome nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value)
1398b713c91eSToomas Soome {
1399b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value));
1400b713c91eSToomas Soome }
1401b713c91eSToomas Soome 
1402b713c91eSToomas Soome int
nvlist_add_string(nvlist_t * nvl,const char * name,const char * value)1403b713c91eSToomas Soome nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1404b713c91eSToomas Soome {
1405b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value));
1406b713c91eSToomas Soome }
1407b713c91eSToomas Soome 
1408b713c91eSToomas Soome int
nvlist_add_boolean_array(nvlist_t * nvl,const char * name,boolean_t * a,uint32_t n)1409b713c91eSToomas Soome nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
1410b713c91eSToomas Soome     boolean_t *a, uint32_t n)
1411b713c91eSToomas Soome {
1412b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1413b713c91eSToomas Soome }
1414b713c91eSToomas Soome 
1415b713c91eSToomas Soome int
nvlist_add_byte_array(nvlist_t * nvl,const char * name,uint8_t * a,uint32_t n)1416b713c91eSToomas Soome nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1417b713c91eSToomas Soome {
1418b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1419b713c91eSToomas Soome }
1420b713c91eSToomas Soome 
1421b713c91eSToomas Soome int
nvlist_add_int8_array(nvlist_t * nvl,const char * name,int8_t * a,uint32_t n)1422b713c91eSToomas Soome nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n)
1423b713c91eSToomas Soome {
1424b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1425b713c91eSToomas Soome }
1426b713c91eSToomas Soome 
1427b713c91eSToomas Soome int
nvlist_add_uint8_array(nvlist_t * nvl,const char * name,uint8_t * a,uint32_t n)1428b713c91eSToomas Soome nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1429b713c91eSToomas Soome {
1430b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1431b713c91eSToomas Soome }
1432b713c91eSToomas Soome 
1433b713c91eSToomas Soome int
nvlist_add_int16_array(nvlist_t * nvl,const char * name,int16_t * a,uint32_t n)1434b713c91eSToomas Soome nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n)
1435b713c91eSToomas Soome {
1436b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1437b713c91eSToomas Soome }
1438b713c91eSToomas Soome 
1439b713c91eSToomas Soome int
nvlist_add_uint16_array(nvlist_t * nvl,const char * name,uint16_t * a,uint32_t n)1440b713c91eSToomas Soome nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a,
1441b713c91eSToomas Soome     uint32_t n)
1442b713c91eSToomas Soome {
1443b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1444b713c91eSToomas Soome }
1445b713c91eSToomas Soome 
1446b713c91eSToomas Soome int
nvlist_add_int32_array(nvlist_t * nvl,const char * name,int32_t * a,uint32_t n)1447b713c91eSToomas Soome nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n)
1448b713c91eSToomas Soome {
1449b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1450b713c91eSToomas Soome }
1451b713c91eSToomas Soome 
1452b713c91eSToomas Soome int
nvlist_add_uint32_array(nvlist_t * nvl,const char * name,uint32_t * a,uint32_t n)1453b713c91eSToomas Soome nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a,
1454b713c91eSToomas Soome     uint32_t n)
1455b713c91eSToomas Soome {
1456b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1457b713c91eSToomas Soome }
1458b713c91eSToomas Soome 
1459b713c91eSToomas Soome int
nvlist_add_int64_array(nvlist_t * nvl,const char * name,int64_t * a,uint32_t n)1460b713c91eSToomas Soome nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n)
1461b713c91eSToomas Soome {
1462b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1463b713c91eSToomas Soome }
1464b713c91eSToomas Soome 
1465b713c91eSToomas Soome int
nvlist_add_uint64_array(nvlist_t * nvl,const char * name,uint64_t * a,uint32_t n)1466b713c91eSToomas Soome nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a,
1467b713c91eSToomas Soome     uint32_t n)
1468b713c91eSToomas Soome {
1469b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1470b713c91eSToomas Soome }
1471b713c91eSToomas Soome 
1472b713c91eSToomas Soome int
nvlist_add_string_array(nvlist_t * nvl,const char * name,char * const * a,uint32_t n)1473b713c91eSToomas Soome nvlist_add_string_array(nvlist_t *nvl, const char *name,
1474b713c91eSToomas Soome     char * const *a, uint32_t n)
1475b713c91eSToomas Soome {
1476b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1477b713c91eSToomas Soome }
1478b713c91eSToomas Soome 
1479b713c91eSToomas Soome int
nvlist_add_nvlist(nvlist_t * nvl,const char * name,nvlist_t * val)1480b713c91eSToomas Soome nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
1481b713c91eSToomas Soome {
1482b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1483b713c91eSToomas Soome }
1484b713c91eSToomas Soome 
1485b713c91eSToomas Soome int
nvlist_add_nvlist_array(nvlist_t * nvl,const char * name,nvlist_t ** a,uint32_t n)1486b713c91eSToomas Soome nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a,
1487b713c91eSToomas Soome     uint32_t n)
1488b713c91eSToomas Soome {
1489b713c91eSToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1490b713c91eSToomas Soome }
1491b713c91eSToomas Soome 
1492b713c91eSToomas Soome static const char *typenames[] = {
1493b713c91eSToomas Soome 	"DATA_TYPE_UNKNOWN",
1494b713c91eSToomas Soome 	"DATA_TYPE_BOOLEAN",
1495b713c91eSToomas Soome 	"DATA_TYPE_BYTE",
1496b713c91eSToomas Soome 	"DATA_TYPE_INT16",
1497b713c91eSToomas Soome 	"DATA_TYPE_UINT16",
1498b713c91eSToomas Soome 	"DATA_TYPE_INT32",
1499b713c91eSToomas Soome 	"DATA_TYPE_UINT32",
1500b713c91eSToomas Soome 	"DATA_TYPE_INT64",
1501b713c91eSToomas Soome 	"DATA_TYPE_UINT64",
1502b713c91eSToomas Soome 	"DATA_TYPE_STRING",
1503b713c91eSToomas Soome 	"DATA_TYPE_BYTE_ARRAY",
1504b713c91eSToomas Soome 	"DATA_TYPE_INT16_ARRAY",
1505b713c91eSToomas Soome 	"DATA_TYPE_UINT16_ARRAY",
1506b713c91eSToomas Soome 	"DATA_TYPE_INT32_ARRAY",
1507b713c91eSToomas Soome 	"DATA_TYPE_UINT32_ARRAY",
1508b713c91eSToomas Soome 	"DATA_TYPE_INT64_ARRAY",
1509b713c91eSToomas Soome 	"DATA_TYPE_UINT64_ARRAY",
1510b713c91eSToomas Soome 	"DATA_TYPE_STRING_ARRAY",
1511b713c91eSToomas Soome 	"DATA_TYPE_HRTIME",
1512b713c91eSToomas Soome 	"DATA_TYPE_NVLIST",
1513b713c91eSToomas Soome 	"DATA_TYPE_NVLIST_ARRAY",
1514b713c91eSToomas Soome 	"DATA_TYPE_BOOLEAN_VALUE",
1515b713c91eSToomas Soome 	"DATA_TYPE_INT8",
1516b713c91eSToomas Soome 	"DATA_TYPE_UINT8",
1517b713c91eSToomas Soome 	"DATA_TYPE_BOOLEAN_ARRAY",
1518b713c91eSToomas Soome 	"DATA_TYPE_INT8_ARRAY",
1519b713c91eSToomas Soome 	"DATA_TYPE_UINT8_ARRAY"
1520b713c91eSToomas Soome };
1521b713c91eSToomas Soome 
1522b713c91eSToomas Soome int
nvpair_type_from_name(const char * name)1523b713c91eSToomas Soome nvpair_type_from_name(const char *name)
1524b713c91eSToomas Soome {
1525b713c91eSToomas Soome 	unsigned i;
1526b713c91eSToomas Soome 
1527b713c91eSToomas Soome 	for (i = 0; i < nitems(typenames); i++) {
1528b713c91eSToomas Soome 		if (strcmp(name, typenames[i]) == 0)
1529b713c91eSToomas Soome 			return (i);
1530b713c91eSToomas Soome 	}
1531b713c91eSToomas Soome 	return (0);
1532b713c91eSToomas Soome }
1533b713c91eSToomas Soome 
1534b713c91eSToomas Soome nvp_header_t *
nvpair_find(nvlist_t * nv,const char * name)1535b713c91eSToomas Soome nvpair_find(nvlist_t *nv, const char *name)
1536b713c91eSToomas Soome {
1537b713c91eSToomas Soome 	nvp_header_t *nvh;
1538b713c91eSToomas Soome 
1539b713c91eSToomas Soome 	nvh = NULL;
1540b713c91eSToomas Soome 	while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) {
1541b713c91eSToomas Soome 		nv_string_t *nvp_name;
1542b713c91eSToomas Soome 
1543b713c91eSToomas Soome 		nvp_name = (nv_string_t *)(nvh + 1);
1544b713c91eSToomas Soome 		if (nvp_name->nv_size == strlen(name) &&
1545b713c91eSToomas Soome 		    memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0)
1546b713c91eSToomas Soome 			break;
1547b713c91eSToomas Soome 	}
1548b713c91eSToomas Soome 	return (nvh);
1549b713c91eSToomas Soome }
1550b713c91eSToomas Soome 
1551b713c91eSToomas Soome void
nvpair_print(nvp_header_t * nvp,unsigned int indent)1552b713c91eSToomas Soome nvpair_print(nvp_header_t *nvp, unsigned int indent)
1553b713c91eSToomas Soome {
1554b713c91eSToomas Soome 	nv_string_t *nvp_name;
1555b713c91eSToomas Soome 	nv_pair_data_t *nvp_data;
1556b713c91eSToomas Soome 	nvlist_t nvlist;
15570b14c199SToomas Soome 	unsigned i, j;
15580b14c199SToomas Soome 	xdr_t xdr = {
15590b14c199SToomas Soome 		.xdr_op = XDR_OP_DECODE,
15600b14c199SToomas Soome 		.xdr_getint = _getint_mem,
15610b14c199SToomas Soome 		.xdr_getuint = _getuint_mem,
15620b14c199SToomas Soome 		.xdr_buf = (const uint8_t *)nvp,
15630b14c199SToomas Soome 		.xdr_idx = NULL,
15640b14c199SToomas Soome 		.xdr_buf_size = nvp->encoded_size
15650b14c199SToomas Soome 	};
1566b713c91eSToomas Soome 
1567b713c91eSToomas Soome 	nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof (*nvp));
1568b713c91eSToomas Soome 	nvp_data = (nv_pair_data_t *)
1569b713c91eSToomas Soome 	    NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size);
1570b713c91eSToomas Soome 
1571b713c91eSToomas Soome 	for (i = 0; i < indent; i++)
1572b713c91eSToomas Soome 		printf(" ");
1573b713c91eSToomas Soome 
1574b713c91eSToomas Soome 	printf("%s [%d] %.*s", typenames[nvp_data->nv_type],
1575b713c91eSToomas Soome 	    nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data);
1576b713c91eSToomas Soome 
15770b14c199SToomas Soome 	xdr.xdr_idx = nvp_data->nv_data;
1578b713c91eSToomas Soome 	switch (nvp_data->nv_type) {
1579b713c91eSToomas Soome 	case DATA_TYPE_BYTE:
1580b713c91eSToomas Soome 	case DATA_TYPE_INT8:
15810b14c199SToomas Soome 	case DATA_TYPE_UINT8: {
15820b14c199SToomas Soome 		char c;
15830b14c199SToomas Soome 
15840b14c199SToomas Soome 		if (xdr_char(&xdr, &c))
15850b14c199SToomas Soome 			printf(" = 0x%x\n", c);
1586b713c91eSToomas Soome 		break;
15870b14c199SToomas Soome 	}
1588b713c91eSToomas Soome 
1589b713c91eSToomas Soome 	case DATA_TYPE_INT16:
15900b14c199SToomas Soome 	case DATA_TYPE_UINT16: {
15910b14c199SToomas Soome 		unsigned short u;
15920b14c199SToomas Soome 
15930b14c199SToomas Soome 		if (xdr_u_short(&xdr, &u))
15940b14c199SToomas Soome 			printf(" = 0x%hx\n", u);
1595b713c91eSToomas Soome 		break;
15960b14c199SToomas Soome 	}
1597b713c91eSToomas Soome 
1598b713c91eSToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
1599b713c91eSToomas Soome 	case DATA_TYPE_INT32:
16000b14c199SToomas Soome 	case DATA_TYPE_UINT32: {
16010b14c199SToomas Soome 		unsigned u;
16020b14c199SToomas Soome 
16030b14c199SToomas Soome 		if (xdr_u_int(&xdr, &u))
16040b14c199SToomas Soome 			printf(" = 0x%x\n", u);
1605b713c91eSToomas Soome 		break;
16060b14c199SToomas Soome 	}
1607b713c91eSToomas Soome 
1608b713c91eSToomas Soome 	case DATA_TYPE_INT64:
16090b14c199SToomas Soome 	case DATA_TYPE_UINT64: {
16100b14c199SToomas Soome 		uint64_t u;
16110b14c199SToomas Soome 
16120b14c199SToomas Soome 		if (xdr_uint64(&xdr, &u))
16130b14c199SToomas Soome 			printf(" = 0x%jx\n", (uintmax_t)u);
1614b713c91eSToomas Soome 		break;
16150b14c199SToomas Soome 	}
16160b14c199SToomas Soome 
16170b14c199SToomas Soome 	case DATA_TYPE_INT64_ARRAY:
16180b14c199SToomas Soome 	case DATA_TYPE_UINT64_ARRAY: {
16190b14c199SToomas Soome 		uint64_t *u;
16209a2cc6e2SToomas Soome 
16210b14c199SToomas Soome 		if (xdr_array(&xdr, nvp_data->nv_nelem,
16220b14c199SToomas Soome 		    (xdrproc_t)xdr_uint64)) {
16230b14c199SToomas Soome 			u = (uint64_t *)(nvp_data->nv_data + sizeof (unsigned));
16240b14c199SToomas Soome 			for (i = 0; i < nvp_data->nv_nelem; i++)
16250b14c199SToomas Soome 				printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]);
16260b14c199SToomas Soome 			printf("\n");
16270b14c199SToomas Soome 		}
16280b14c199SToomas Soome 
16290b14c199SToomas Soome 		break;
16300b14c199SToomas Soome 	}
1631b713c91eSToomas Soome 
1632b713c91eSToomas Soome 	case DATA_TYPE_STRING:
1633b713c91eSToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1634b713c91eSToomas Soome 		nvp_name = (nv_string_t *)&nvp_data->nv_data[0];
1635b713c91eSToomas Soome 		for (i = 0; i < nvp_data->nv_nelem; i++) {
1636b713c91eSToomas Soome 			printf(" = \"%.*s\"\n", nvp_name->nv_size,
1637b713c91eSToomas Soome 			    nvp_name->nv_data);
1638b713c91eSToomas Soome 		}
1639b713c91eSToomas Soome 		break;
1640b713c91eSToomas Soome 
1641b713c91eSToomas Soome 	case DATA_TYPE_NVLIST:
1642b713c91eSToomas Soome 		printf("\n");
1643b713c91eSToomas Soome 		nvlist.nv_data = &nvp_data->nv_data[0];
1644b713c91eSToomas Soome 		nvlist_print(&nvlist, indent + 2);
1645b713c91eSToomas Soome 		break;
1646b713c91eSToomas Soome 
1647b713c91eSToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
1648b713c91eSToomas Soome 		nvlist.nv_data = &nvp_data->nv_data[0];
1649b713c91eSToomas Soome 		for (j = 0; j < nvp_data->nv_nelem; j++) {
1650b713c91eSToomas Soome 			size_t size;
1651b713c91eSToomas Soome 
1652b713c91eSToomas Soome 			printf("[%d]\n", j);
1653b713c91eSToomas Soome 			nvlist_print(&nvlist, indent + 2);
1654b713c91eSToomas Soome 			if (j != nvp_data->nv_nelem - 1) {
1655b713c91eSToomas Soome 				for (i = 0; i < indent; i++)
1656b713c91eSToomas Soome 					printf(" ");
1657b713c91eSToomas Soome 				printf("%s %.*s",
1658b713c91eSToomas Soome 				    typenames[nvp_data->nv_type],
1659b713c91eSToomas Soome 				    nvp_name->nv_size,
1660b713c91eSToomas Soome 				    nvp_name->nv_data);
1661b713c91eSToomas Soome 			}
1662b713c91eSToomas Soome 			xdr.xdr_idx = nvlist.nv_data;
1663b713c91eSToomas Soome 			xdr.xdr_buf = xdr.xdr_idx;
1664b713c91eSToomas Soome 			xdr.xdr_buf_size = nvp->encoded_size -
1665b713c91eSToomas Soome 			    (xdr.xdr_idx - (uint8_t *)nvp);
1666b713c91eSToomas Soome 
1667b713c91eSToomas Soome 			if (!nvlist_size_native(&xdr, &size))
1668b713c91eSToomas Soome 				return;
1669b713c91eSToomas Soome 
1670b713c91eSToomas Soome 			nvlist.nv_data += size;
1671b713c91eSToomas Soome 		}
1672b713c91eSToomas Soome 		break;
1673b713c91eSToomas Soome 
1674b713c91eSToomas Soome 	default:
1675b713c91eSToomas Soome 		printf("\n");
1676b713c91eSToomas Soome 	}
1677b713c91eSToomas Soome }
1678b713c91eSToomas Soome 
1679b713c91eSToomas Soome void
nvlist_print(const nvlist_t * nvl,unsigned int indent)1680b713c91eSToomas Soome nvlist_print(const nvlist_t *nvl, unsigned int indent)
1681b713c91eSToomas Soome {
1682b713c91eSToomas Soome 	nvs_data_t *data;
1683b713c91eSToomas Soome 	nvp_header_t *nvp;
1684b713c91eSToomas Soome 
1685b713c91eSToomas Soome 	data = (nvs_data_t *)nvl->nv_data;
1686b713c91eSToomas Soome 	nvp = &data->nvl_pair;  /* first pair in nvlist */
1687b713c91eSToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
1688b713c91eSToomas Soome 		nvpair_print(nvp, indent);
1689b713c91eSToomas Soome 		nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
1690b713c91eSToomas Soome 	}
1691b713c91eSToomas Soome 	printf("%*s\n", indent + 13, "End of nvlist");
1692b713c91eSToomas Soome }
1693