xref: /freebsd/stand/libsa/zfs/nvlist.c (revision 9de6a13e)
13830659eSToomas Soome /*-
23830659eSToomas Soome  * Copyright 2020 Toomas Soome <tsoome@me.com>
33830659eSToomas Soome  *
43830659eSToomas Soome  * Redistribution and use in source and binary forms, with or without
53830659eSToomas Soome  * modification, are permitted provided that the following conditions
63830659eSToomas Soome  * are met:
73830659eSToomas Soome  * 1. Redistributions of source code must retain the above copyright
83830659eSToomas Soome  *    notice, this list of conditions and the following disclaimer.
93830659eSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
103830659eSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
113830659eSToomas Soome  *    documentation and/or other materials provided with the distribution.
123830659eSToomas Soome  *
133830659eSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
143830659eSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
153830659eSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
163830659eSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
173830659eSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
183830659eSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
193830659eSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
203830659eSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
213830659eSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
223830659eSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
233830659eSToomas Soome  * SUCH DAMAGE.
243830659eSToomas Soome  */
253830659eSToomas Soome 
263830659eSToomas Soome #include <sys/cdefs.h>
273830659eSToomas Soome __FBSDID("$FreeBSD$");
283830659eSToomas Soome 
293830659eSToomas Soome #include <stand.h>
30e307eb94SToomas Soome #include <stdbool.h>
313830659eSToomas Soome #include <sys/endian.h>
32e307eb94SToomas Soome #include <sys/stdint.h>
33e307eb94SToomas Soome #include <sys/param.h>
343830659eSToomas Soome #include <zfsimpl.h>
353830659eSToomas Soome #include "libzfs.h"
363830659eSToomas Soome 
37e307eb94SToomas Soome enum xdr_op {
38e307eb94SToomas Soome 	XDR_OP_ENCODE = 1,
39e307eb94SToomas Soome 	XDR_OP_DECODE = 2
40e307eb94SToomas Soome };
41e307eb94SToomas Soome 
423830659eSToomas Soome typedef struct xdr {
43e307eb94SToomas Soome 	enum xdr_op xdr_op;
44e307eb94SToomas Soome 	int (*xdr_getint)(struct xdr *, int *);
45e307eb94SToomas Soome 	int (*xdr_putint)(struct xdr *, int);
46e307eb94SToomas Soome 	int (*xdr_getuint)(struct xdr *, unsigned *);
47e307eb94SToomas Soome 	int (*xdr_putuint)(struct xdr *, unsigned);
48e307eb94SToomas Soome 	const uint8_t *xdr_buf;
49e307eb94SToomas Soome 	uint8_t *xdr_idx;
50e307eb94SToomas Soome 	size_t xdr_buf_size;
513830659eSToomas Soome } xdr_t;
523830659eSToomas Soome 
53e307eb94SToomas Soome static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *);
54e307eb94SToomas Soome static bool nvlist_size_xdr(xdr_t *, size_t *);
55e307eb94SToomas Soome static bool nvlist_size_native(xdr_t *, size_t *);
56e307eb94SToomas Soome static bool xdr_int(xdr_t *, int *);
57e307eb94SToomas Soome static bool xdr_u_int(xdr_t *, unsigned *);
583830659eSToomas Soome 
59e307eb94SToomas Soome typedef int (*xdrproc_t)(xdr_t *, void *);
603830659eSToomas Soome 
61e307eb94SToomas Soome /* Basic primitives for XDR translation operations, getint and putint. */
623830659eSToomas Soome static int
63e307eb94SToomas Soome _getint(struct xdr *xdr, int *ip)
643830659eSToomas Soome {
65e307eb94SToomas Soome 	*ip = be32dec(xdr->xdr_idx);
663830659eSToomas Soome 	return (sizeof(int));
673830659eSToomas Soome }
683830659eSToomas Soome 
693830659eSToomas Soome static int
70e307eb94SToomas Soome _putint(struct xdr *xdr, int i)
713830659eSToomas Soome {
72e307eb94SToomas Soome 	int *ip = (int *)xdr->xdr_idx;
73e307eb94SToomas Soome 
74e307eb94SToomas Soome 	*ip = htobe32(i);
75e307eb94SToomas Soome 	return (sizeof(int));
76e307eb94SToomas Soome }
77e307eb94SToomas Soome 
78e307eb94SToomas Soome static int
79e307eb94SToomas Soome _getuint(struct xdr *xdr, unsigned *ip)
80e307eb94SToomas Soome {
81e307eb94SToomas Soome 	*ip = be32dec(xdr->xdr_idx);
823830659eSToomas Soome 	return (sizeof(unsigned));
833830659eSToomas Soome }
843830659eSToomas Soome 
853830659eSToomas Soome static int
86e307eb94SToomas Soome _putuint(struct xdr *xdr, unsigned i)
873830659eSToomas Soome {
88e307eb94SToomas Soome 	unsigned *up = (unsigned *)xdr->xdr_idx;
893830659eSToomas Soome 
90e307eb94SToomas Soome 	*up = htobe32(i);
91e307eb94SToomas Soome 	return (sizeof(int));
923830659eSToomas Soome }
933830659eSToomas Soome 
949de6a13eSToomas Soome static int
959de6a13eSToomas Soome _getint_mem(struct xdr *xdr, int *ip)
969de6a13eSToomas Soome {
979de6a13eSToomas Soome 	*ip = *(int *)xdr->xdr_idx;
989de6a13eSToomas Soome 	return (sizeof(int));
999de6a13eSToomas Soome }
1009de6a13eSToomas Soome 
1019de6a13eSToomas Soome static int
1029de6a13eSToomas Soome _putint_mem(struct xdr *xdr, int i)
1039de6a13eSToomas Soome {
1049de6a13eSToomas Soome 	int *ip = (int *)xdr->xdr_idx;
1059de6a13eSToomas Soome 
1069de6a13eSToomas Soome 	*ip = i;
1079de6a13eSToomas Soome 	return (sizeof(int));
1089de6a13eSToomas Soome }
1099de6a13eSToomas Soome 
1109de6a13eSToomas Soome static int
1119de6a13eSToomas Soome _getuint_mem(struct xdr *xdr, unsigned *ip)
1129de6a13eSToomas Soome {
1139de6a13eSToomas Soome 	*ip = *(unsigned *)xdr->xdr_idx;
1149de6a13eSToomas Soome 	return (sizeof(unsigned));
1159de6a13eSToomas Soome }
1169de6a13eSToomas Soome 
1179de6a13eSToomas Soome static int
1189de6a13eSToomas Soome _putuint_mem(struct xdr *xdr, unsigned i)
1199de6a13eSToomas Soome {
1209de6a13eSToomas Soome 	unsigned *up = (unsigned *)xdr->xdr_idx;
1219de6a13eSToomas Soome 
1229de6a13eSToomas Soome 	*up = i;
1239de6a13eSToomas Soome 	return (sizeof(int));
1249de6a13eSToomas Soome }
1259de6a13eSToomas Soome 
126e307eb94SToomas Soome /*
127e307eb94SToomas Soome  * XDR data translations.
128e307eb94SToomas Soome  */
129e307eb94SToomas Soome static bool
130e307eb94SToomas Soome xdr_short(xdr_t *xdr, short *ip)
1313830659eSToomas Soome {
132e307eb94SToomas Soome 	int i;
133e307eb94SToomas Soome 	bool rv;
1343830659eSToomas Soome 
135e307eb94SToomas Soome 	i = *ip;
136e307eb94SToomas Soome 	if ((rv = xdr_int(xdr, &i))) {
137e307eb94SToomas Soome 		if (xdr->xdr_op == XDR_OP_DECODE)
138e307eb94SToomas Soome 			*ip = i;
139e307eb94SToomas Soome 	}
1403830659eSToomas Soome 	return (rv);
1413830659eSToomas Soome }
1423830659eSToomas Soome 
143e307eb94SToomas Soome static bool
144e307eb94SToomas Soome xdr_u_short(xdr_t *xdr, unsigned short *ip)
1453830659eSToomas Soome {
146e307eb94SToomas Soome 	unsigned u;
147e307eb94SToomas Soome 	bool rv;
1483830659eSToomas Soome 
149e307eb94SToomas Soome 	u = *ip;
150e307eb94SToomas Soome 	if ((rv = xdr_u_int(xdr, &u))) {
151e307eb94SToomas Soome 		if (xdr->xdr_op == XDR_OP_DECODE)
152e307eb94SToomas Soome 			*ip = u;
1533830659eSToomas Soome 	}
1543830659eSToomas Soome 	return (rv);
1553830659eSToomas Soome }
1563830659eSToomas Soome 
1573830659eSToomas Soome /*
158e307eb94SToomas Soome  * translate xdr->xdr_idx, increment it by size of int.
1593830659eSToomas Soome  */
160e307eb94SToomas Soome static bool
161e307eb94SToomas Soome xdr_int(xdr_t *xdr, int *ip)
1623830659eSToomas Soome {
163e307eb94SToomas Soome 	bool rv = false;
164e307eb94SToomas Soome 	int *i = (int *)xdr->xdr_idx;
165e307eb94SToomas Soome 
166e307eb94SToomas Soome 	if (xdr->xdr_idx + sizeof(int) > xdr->xdr_buf + xdr->xdr_buf_size)
167e307eb94SToomas Soome 		return (rv);
168e307eb94SToomas Soome 
169e307eb94SToomas Soome 	switch (xdr->xdr_op) {
170e307eb94SToomas Soome 	case XDR_OP_ENCODE:
171e307eb94SToomas Soome 		/* Encode value *ip, store to buf */
172e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_putint(xdr, *ip);
173e307eb94SToomas Soome 		rv = true;
174e307eb94SToomas Soome 		break;
175e307eb94SToomas Soome 
176e307eb94SToomas Soome 	case XDR_OP_DECODE:
177e307eb94SToomas Soome 		/* Decode buf, return value to *ip */
178e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_getint(xdr, i);
179e307eb94SToomas Soome 		*ip = *i;
180e307eb94SToomas Soome 		rv = true;
181e307eb94SToomas Soome 		break;
182e307eb94SToomas Soome 	}
183e307eb94SToomas Soome 	return (rv);
1843830659eSToomas Soome }
1853830659eSToomas Soome 
186e307eb94SToomas Soome /*
187e307eb94SToomas Soome  * translate xdr->xdr_idx, increment it by size of unsigned int.
188e307eb94SToomas Soome  */
189e307eb94SToomas Soome static bool
190e307eb94SToomas Soome xdr_u_int(xdr_t *xdr, unsigned *ip)
191e307eb94SToomas Soome {
192e307eb94SToomas Soome 	bool rv = false;
193e307eb94SToomas Soome 	unsigned *u = (unsigned *)xdr->xdr_idx;
194e307eb94SToomas Soome 
195e307eb94SToomas Soome 	if (xdr->xdr_idx + sizeof(unsigned) > xdr->xdr_buf + xdr->xdr_buf_size)
196e307eb94SToomas Soome 		return (rv);
197e307eb94SToomas Soome 
198e307eb94SToomas Soome 	switch (xdr->xdr_op) {
199e307eb94SToomas Soome 	case XDR_OP_ENCODE:
200e307eb94SToomas Soome 		/* Encode value *ip, store to buf */
201e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip);
202e307eb94SToomas Soome 		rv = true;
203e307eb94SToomas Soome 		break;
204e307eb94SToomas Soome 
205e307eb94SToomas Soome 	case XDR_OP_DECODE:
206e307eb94SToomas Soome 		/* Decode buf, return value to *ip */
207e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_getuint(xdr, u);
208e307eb94SToomas Soome 		*ip = *u;
209e307eb94SToomas Soome 		rv = true;
210e307eb94SToomas Soome 		break;
211e307eb94SToomas Soome 	}
212e307eb94SToomas Soome 	return (rv);
213e307eb94SToomas Soome }
214e307eb94SToomas Soome 
215e307eb94SToomas Soome static bool
216e307eb94SToomas Soome xdr_int64(xdr_t *xdr, int64_t *lp)
217e307eb94SToomas Soome {
218e307eb94SToomas Soome 	bool rv = false;
219e307eb94SToomas Soome 
220e307eb94SToomas Soome 	if (xdr->xdr_idx + sizeof(int64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
221e307eb94SToomas Soome 		return (rv);
222e307eb94SToomas Soome 
223e307eb94SToomas Soome 	switch (xdr->xdr_op) {
224e307eb94SToomas Soome 	case XDR_OP_ENCODE:
225e307eb94SToomas Soome 		/* Encode value *lp, store to buf */
2269de6a13eSToomas Soome 		if (xdr->xdr_putint == _putint)
2279de6a13eSToomas Soome 			*(int64_t *)xdr->xdr_idx = htobe64(*lp);
2289de6a13eSToomas Soome 		else
2299de6a13eSToomas Soome 			*(int64_t *)xdr->xdr_idx = *lp;
2309de6a13eSToomas Soome 		xdr->xdr_idx += sizeof(int64_t);
231e307eb94SToomas Soome 		rv = true;
232e307eb94SToomas Soome 		break;
233e307eb94SToomas Soome 
234e307eb94SToomas Soome 	case XDR_OP_DECODE:
235e307eb94SToomas Soome 		/* Decode buf, return value to *ip */
2369de6a13eSToomas Soome 		if (xdr->xdr_getint == _getint)
2379de6a13eSToomas Soome 			*lp = be64toh(*(int64_t *)xdr->xdr_idx);
2389de6a13eSToomas Soome 		else
2399de6a13eSToomas Soome 			*lp = *(int64_t *)xdr->xdr_idx;
2409de6a13eSToomas Soome 		xdr->xdr_idx += sizeof(int64_t);
241e307eb94SToomas Soome 		rv = true;
242e307eb94SToomas Soome 	}
243e307eb94SToomas Soome 	return (rv);
244e307eb94SToomas Soome }
245e307eb94SToomas Soome 
246e307eb94SToomas Soome static bool
247e307eb94SToomas Soome xdr_uint64(xdr_t *xdr, uint64_t *lp)
248e307eb94SToomas Soome {
249e307eb94SToomas Soome 	bool rv = false;
250e307eb94SToomas Soome 
251e307eb94SToomas Soome 	if (xdr->xdr_idx + sizeof(uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
252e307eb94SToomas Soome 		return (rv);
253e307eb94SToomas Soome 
254e307eb94SToomas Soome 	switch (xdr->xdr_op) {
255e307eb94SToomas Soome 	case XDR_OP_ENCODE:
256e307eb94SToomas Soome 		/* Encode value *ip, store to buf */
2579de6a13eSToomas Soome 		if (xdr->xdr_putint == _putint)
2589de6a13eSToomas Soome 			*(uint64_t *)xdr->xdr_idx = htobe64(*lp);
2599de6a13eSToomas Soome 		else
2609de6a13eSToomas Soome 			*(uint64_t *)xdr->xdr_idx = *lp;
2619de6a13eSToomas Soome 		xdr->xdr_idx += sizeof(uint64_t);
262e307eb94SToomas Soome 		rv = true;
263e307eb94SToomas Soome 		break;
264e307eb94SToomas Soome 
265e307eb94SToomas Soome 	case XDR_OP_DECODE:
266e307eb94SToomas Soome 		/* Decode buf, return value to *ip */
2679de6a13eSToomas Soome 		if (xdr->xdr_getuint == _getuint)
2689de6a13eSToomas Soome 			*lp = be64toh(*(uint64_t *)xdr->xdr_idx);
2699de6a13eSToomas Soome 		else
2709de6a13eSToomas Soome 			*lp = *(uint64_t *)xdr->xdr_idx;
2719de6a13eSToomas Soome 		xdr->xdr_idx += sizeof(uint64_t);
272e307eb94SToomas Soome 		rv = true;
273e307eb94SToomas Soome 	}
274e307eb94SToomas Soome 	return (rv);
275e307eb94SToomas Soome }
276e307eb94SToomas Soome 
277e307eb94SToomas Soome static bool
278e307eb94SToomas Soome xdr_char(xdr_t *xdr, char *cp)
279e307eb94SToomas Soome {
280e307eb94SToomas Soome 	int i;
281e307eb94SToomas Soome 	bool rv = false;
282e307eb94SToomas Soome 
283e307eb94SToomas Soome 	i = *cp;
284e307eb94SToomas Soome 	if ((rv = xdr_int(xdr, &i))) {
285e307eb94SToomas Soome 		if (xdr->xdr_op == XDR_OP_DECODE)
286e307eb94SToomas Soome 			*cp = i;
287e307eb94SToomas Soome 	}
288e307eb94SToomas Soome 	return (rv);
289e307eb94SToomas Soome }
290e307eb94SToomas Soome 
291e307eb94SToomas Soome static bool
292e307eb94SToomas Soome xdr_string(xdr_t *xdr, nv_string_t *s)
293e307eb94SToomas Soome {
294e307eb94SToomas Soome 	int size = 0;
295e307eb94SToomas Soome 	bool rv = false;
296e307eb94SToomas Soome 
297e307eb94SToomas Soome 	switch (xdr->xdr_op) {
298e307eb94SToomas Soome 	case XDR_OP_ENCODE:
299e307eb94SToomas Soome 		size = s->nv_size;
300e307eb94SToomas Soome 		if (xdr->xdr_idx + sizeof(unsigned) + NV_ALIGN4(size) >
301e307eb94SToomas Soome 		    xdr->xdr_buf + xdr->xdr_buf_size)
302e307eb94SToomas Soome 			break;
303e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size);
304e307eb94SToomas Soome 		xdr->xdr_idx += NV_ALIGN4(size);
305e307eb94SToomas Soome 		rv = true;
306e307eb94SToomas Soome 		break;
307e307eb94SToomas Soome 
308e307eb94SToomas Soome 	case XDR_OP_DECODE:
309e307eb94SToomas Soome 		if (xdr->xdr_idx + sizeof(unsigned) >
310e307eb94SToomas Soome 		    xdr->xdr_buf + xdr->xdr_buf_size)
311e307eb94SToomas Soome 			break;
312e307eb94SToomas Soome 		size = xdr->xdr_getuint(xdr, &s->nv_size);
313e307eb94SToomas Soome 		size = NV_ALIGN4(size + s->nv_size);
314e307eb94SToomas Soome 		if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size)
315e307eb94SToomas Soome 			break;
316e307eb94SToomas Soome 		xdr->xdr_idx += size;
317e307eb94SToomas Soome 		rv = true;
318e307eb94SToomas Soome 		break;
319e307eb94SToomas Soome 	}
320e307eb94SToomas Soome 	return (rv);
321e307eb94SToomas Soome }
322e307eb94SToomas Soome 
323e307eb94SToomas Soome static bool
324e307eb94SToomas Soome xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc)
325e307eb94SToomas Soome {
326e307eb94SToomas Soome 	bool rv = true;
3279de6a13eSToomas Soome 	unsigned c = nelem;
3289de6a13eSToomas Soome 
3299de6a13eSToomas Soome 	if (!xdr_u_int(xdr, &c))
3309de6a13eSToomas Soome 		return (false);
331e307eb94SToomas Soome 
332e307eb94SToomas Soome 	for (unsigned i = 0; i < nelem; i++) {
333e307eb94SToomas Soome 		if (!elproc(xdr, xdr->xdr_idx))
334e307eb94SToomas Soome 			return (false);
335e307eb94SToomas Soome 	}
336e307eb94SToomas Soome 	return (rv);
337e307eb94SToomas Soome }
338e307eb94SToomas Soome 
339e307eb94SToomas Soome /*
340e307eb94SToomas Soome  * nvlist management functions.
341e307eb94SToomas Soome  */
3423830659eSToomas Soome void
3433830659eSToomas Soome nvlist_destroy(nvlist_t *nvl)
3443830659eSToomas Soome {
3453830659eSToomas Soome 	if (nvl != NULL) {
3463830659eSToomas Soome 		/* Free data if it was allocated by us. */
3473830659eSToomas Soome 		if (nvl->nv_asize > 0)
3483830659eSToomas Soome 			free(nvl->nv_data);
3493830659eSToomas Soome 	}
3503830659eSToomas Soome 	free(nvl);
3513830659eSToomas Soome }
3523830659eSToomas Soome 
3533830659eSToomas Soome char *
3543830659eSToomas Soome nvstring_get(nv_string_t *nvs)
3553830659eSToomas Soome {
3563830659eSToomas Soome 	char *s;
3573830659eSToomas Soome 
3583830659eSToomas Soome 	s = malloc(nvs->nv_size + 1);
3593830659eSToomas Soome 	if (s != NULL) {
3603830659eSToomas Soome 		bcopy(nvs->nv_data, s, nvs->nv_size);
3613830659eSToomas Soome 		s[nvs->nv_size] = '\0';
3623830659eSToomas Soome 	}
3633830659eSToomas Soome 	return (s);
3643830659eSToomas Soome }
3653830659eSToomas Soome 
3663830659eSToomas Soome /*
3673830659eSToomas Soome  * Create empty nvlist.
3683830659eSToomas Soome  * The nvlist is terminated by 2x zeros (8 bytes).
3693830659eSToomas Soome  */
3703830659eSToomas Soome nvlist_t *
3713830659eSToomas Soome nvlist_create(int flag)
3723830659eSToomas Soome {
3733830659eSToomas Soome 	nvlist_t *nvl;
3743830659eSToomas Soome 	nvs_data_t *nvs;
3753830659eSToomas Soome 
3763830659eSToomas Soome 	nvl = calloc(1, sizeof(*nvl));
3773830659eSToomas Soome 	if (nvl == NULL)
3783830659eSToomas Soome 		return (nvl);
3793830659eSToomas Soome 
3803830659eSToomas Soome 	nvl->nv_header.nvh_encoding = NV_ENCODE_XDR;
3813830659eSToomas Soome 	nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN;
3823830659eSToomas Soome 
3833830659eSToomas Soome 	nvl->nv_asize = nvl->nv_size = sizeof(*nvs);
3843830659eSToomas Soome 	nvs = calloc(1, nvl->nv_asize);
3853830659eSToomas Soome 	if (nvs == NULL) {
3863830659eSToomas Soome 		free(nvl);
3873830659eSToomas Soome 		return (NULL);
3883830659eSToomas Soome 	}
3893830659eSToomas Soome 	/* data in nvlist is byte stream */
3903830659eSToomas Soome 	nvl->nv_data = (uint8_t *)nvs;
3913830659eSToomas Soome 
3923830659eSToomas Soome 	nvs->nvl_version = NV_VERSION;
3933830659eSToomas Soome 	nvs->nvl_nvflag = flag;
3943830659eSToomas Soome 	return (nvl);
3953830659eSToomas Soome }
3963830659eSToomas Soome 
397e307eb94SToomas Soome static bool
398e307eb94SToomas Soome nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl)
3993830659eSToomas Soome {
4003830659eSToomas Soome 	nv_string_t *nv_string;
4013830659eSToomas Soome 	nv_pair_data_t *nvp_data;
4023830659eSToomas Soome 	nvlist_t nvlist;
403e307eb94SToomas Soome 	unsigned type, nelem;
404e307eb94SToomas Soome 	xdr_t nv_xdr;
4053830659eSToomas Soome 
406e307eb94SToomas Soome 	nv_string = (nv_string_t *)xdr->xdr_idx;
407e307eb94SToomas Soome 	if (!xdr_string(xdr, nv_string)) {
408e307eb94SToomas Soome 		return (false);
409e307eb94SToomas Soome 	}
410e307eb94SToomas Soome 	nvp_data = (nv_pair_data_t *)xdr->xdr_idx;
4113830659eSToomas Soome 
412e307eb94SToomas Soome 	type = nvp_data->nv_type;
413e307eb94SToomas Soome 	nelem = nvp_data->nv_nelem;
414e307eb94SToomas Soome 	if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem))
415e307eb94SToomas Soome 		return (false);
4163830659eSToomas Soome 
417e307eb94SToomas Soome 	switch (type) {
4183830659eSToomas Soome 	case DATA_TYPE_NVLIST:
4193830659eSToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
4203830659eSToomas Soome 		bzero(&nvlist, sizeof(nvlist));
421e307eb94SToomas Soome 		nvlist.nv_data = xdr->xdr_idx;
4223830659eSToomas Soome 		nvlist.nv_idx = nvlist.nv_data;
423e307eb94SToomas Soome 
424e307eb94SToomas Soome 		/* Set up xdr for this nvlist. */
425e307eb94SToomas Soome 		nv_xdr = *xdr;
426e307eb94SToomas Soome 		nv_xdr.xdr_buf = nvlist.nv_data;
427e307eb94SToomas Soome 		nv_xdr.xdr_idx = nvlist.nv_data;
428e307eb94SToomas Soome 		nv_xdr.xdr_buf_size =
429e307eb94SToomas Soome 		    nvl->nv_data + nvl->nv_size - nvlist.nv_data;
430e307eb94SToomas Soome 
431e307eb94SToomas Soome 		for (unsigned i = 0; i < nelem; i++) {
432e307eb94SToomas Soome 			if (xdr->xdr_op == XDR_OP_ENCODE) {
433e307eb94SToomas Soome 				if (!nvlist_size_native(&nv_xdr,
434e307eb94SToomas Soome 				    &nvlist.nv_size))
435e307eb94SToomas Soome 					return (false);
436e307eb94SToomas Soome 			} else {
437e307eb94SToomas Soome 				if (!nvlist_size_xdr(&nv_xdr,
438e307eb94SToomas Soome 				    &nvlist.nv_size))
439e307eb94SToomas Soome 					return (false);
440e307eb94SToomas Soome 			}
441e307eb94SToomas Soome 			if (nvlist_xdr_nvlist(xdr, &nvlist) != 0)
442e307eb94SToomas Soome 				return (false);
443e307eb94SToomas Soome 
444e307eb94SToomas Soome 			nvlist.nv_data = nv_xdr.xdr_idx;
445e307eb94SToomas Soome 			nvlist.nv_idx = nv_xdr.xdr_idx;
446e307eb94SToomas Soome 
447e307eb94SToomas Soome 			nv_xdr.xdr_buf = nv_xdr.xdr_idx;
448e307eb94SToomas Soome 			nv_xdr.xdr_buf_size =
449e307eb94SToomas Soome 			    nvl->nv_data + nvl->nv_size - nvlist.nv_data;
4503830659eSToomas Soome 		}
4513830659eSToomas Soome 		break;
4523830659eSToomas Soome 
4533830659eSToomas Soome 	case DATA_TYPE_BOOLEAN:
4543830659eSToomas Soome 		/* BOOLEAN does not take value space */
4553830659eSToomas Soome 		break;
4563830659eSToomas Soome 	case DATA_TYPE_BYTE:
4573830659eSToomas Soome 	case DATA_TYPE_INT8:
4583830659eSToomas Soome 	case DATA_TYPE_UINT8:
459e307eb94SToomas Soome 		if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0]))
460e307eb94SToomas Soome 			return (false);
4613830659eSToomas Soome 		break;
4623830659eSToomas Soome 
4633830659eSToomas Soome 	case DATA_TYPE_INT16:
464e307eb94SToomas Soome 		if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0]))
465e307eb94SToomas Soome 			return (false);
4663830659eSToomas Soome 		break;
4673830659eSToomas Soome 
4683830659eSToomas Soome 	case DATA_TYPE_UINT16:
469e307eb94SToomas Soome 		if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0]))
470e307eb94SToomas Soome 			return (false);
4713830659eSToomas Soome 		break;
4723830659eSToomas Soome 
4733830659eSToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
4743830659eSToomas Soome 	case DATA_TYPE_INT32:
475e307eb94SToomas Soome 		if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0]))
476e307eb94SToomas Soome 			return (false);
4773830659eSToomas Soome 		break;
4783830659eSToomas Soome 
4793830659eSToomas Soome 	case DATA_TYPE_UINT32:
480e307eb94SToomas Soome 		if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0]))
481e307eb94SToomas Soome 			return (false);
4823830659eSToomas Soome 		break;
4833830659eSToomas Soome 
484e307eb94SToomas Soome 	case DATA_TYPE_HRTIME:
4853830659eSToomas Soome 	case DATA_TYPE_INT64:
486e307eb94SToomas Soome 		if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0]))
487e307eb94SToomas Soome 			return (false);
4883830659eSToomas Soome 		break;
4893830659eSToomas Soome 
4903830659eSToomas Soome 	case DATA_TYPE_UINT64:
491e307eb94SToomas Soome 		if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0]))
492e307eb94SToomas Soome 			return (false);
4933830659eSToomas Soome 		break;
4943830659eSToomas Soome 
495e307eb94SToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
4963830659eSToomas Soome 	case DATA_TYPE_STRING:
4973830659eSToomas Soome 		nv_string = (nv_string_t *)&nvp_data->nv_data[0];
498e307eb94SToomas Soome 		if (!xdr_string(xdr, nv_string))
499e307eb94SToomas Soome 			return (false);
500e307eb94SToomas Soome 		break;
5013830659eSToomas Soome 
502e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
503e307eb94SToomas Soome 		nv_string = (nv_string_t *)&nvp_data->nv_data[0];
504e307eb94SToomas Soome 		for (unsigned i = 0; i < nelem; i++) {
505e307eb94SToomas Soome 			if (!xdr_string(xdr, nv_string))
506e307eb94SToomas Soome 				return (false);
507e307eb94SToomas Soome 			nv_string = (nv_string_t *)xdr->xdr_idx;
508e307eb94SToomas Soome 		}
509e307eb94SToomas Soome 		break;
510e307eb94SToomas Soome 
511e307eb94SToomas Soome 	case DATA_TYPE_INT8_ARRAY:
512e307eb94SToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
513e307eb94SToomas Soome 	case DATA_TYPE_INT16_ARRAY:
514e307eb94SToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
515e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
516e307eb94SToomas Soome 	case DATA_TYPE_INT32_ARRAY:
517e307eb94SToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
518e307eb94SToomas Soome 		if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int))
519e307eb94SToomas Soome 			return (false);
520e307eb94SToomas Soome 		break;
521e307eb94SToomas Soome 
522e307eb94SToomas Soome 	case DATA_TYPE_INT64_ARRAY:
523e307eb94SToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
524e307eb94SToomas Soome 		if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64))
525e307eb94SToomas Soome 			return (false);
5263830659eSToomas Soome 		break;
5273830659eSToomas Soome 	}
528e307eb94SToomas Soome 	return (true);
5293830659eSToomas Soome }
5303830659eSToomas Soome 
5313830659eSToomas Soome static int
532e307eb94SToomas Soome nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl)
5333830659eSToomas Soome {
534e307eb94SToomas Soome 	nvp_header_t *nvph;
535e307eb94SToomas Soome 	nvs_data_t *nvs;
536e307eb94SToomas Soome 	unsigned encoded_size, decoded_size;
537e307eb94SToomas Soome 	int rv;
538e307eb94SToomas Soome 
539e307eb94SToomas Soome 	nvs = (nvs_data_t *)xdr->xdr_idx;
540e307eb94SToomas Soome 	nvph = &nvs->nvl_pair;
541e307eb94SToomas Soome 
542e307eb94SToomas Soome 	if (!xdr_u_int(xdr, &nvs->nvl_version))
543e307eb94SToomas Soome 		return (EINVAL);
544e307eb94SToomas Soome 	if (!xdr_u_int(xdr, &nvs->nvl_nvflag))
545e307eb94SToomas Soome 		return (EINVAL);
546e307eb94SToomas Soome 
547e307eb94SToomas Soome 	encoded_size = nvph->encoded_size;
548e307eb94SToomas Soome 	decoded_size = nvph->decoded_size;
549e307eb94SToomas Soome 
550e307eb94SToomas Soome 	if (xdr->xdr_op == XDR_OP_ENCODE) {
551e307eb94SToomas Soome 		if (!xdr_u_int(xdr, &nvph->encoded_size))
552e307eb94SToomas Soome 			return (EINVAL);
553e307eb94SToomas Soome 		if (!xdr_u_int(xdr, &nvph->decoded_size))
554e307eb94SToomas Soome 			return (EINVAL);
555e307eb94SToomas Soome 	} else {
556e307eb94SToomas Soome 		xdr->xdr_idx += 2 * sizeof(unsigned);
557e307eb94SToomas Soome 	}
558e307eb94SToomas Soome 
559e307eb94SToomas Soome 	rv = 0;
560e307eb94SToomas Soome 	while (encoded_size && decoded_size) {
561e307eb94SToomas Soome 		if (!nvlist_xdr_nvp(xdr, nvl))
562e307eb94SToomas Soome 			return (EINVAL);
563e307eb94SToomas Soome 
564e307eb94SToomas Soome 		nvph = (nvp_header_t *)(xdr->xdr_idx);
565e307eb94SToomas Soome 		encoded_size = nvph->encoded_size;
566e307eb94SToomas Soome 		decoded_size = nvph->decoded_size;
567e307eb94SToomas Soome 		if (xdr->xdr_op == XDR_OP_ENCODE) {
568e307eb94SToomas Soome 			if (!xdr_u_int(xdr, &nvph->encoded_size))
569e307eb94SToomas Soome 				return (EINVAL);
570e307eb94SToomas Soome 			if (!xdr_u_int(xdr, &nvph->decoded_size))
571e307eb94SToomas Soome 				return (EINVAL);
572e307eb94SToomas Soome 		} else {
573e307eb94SToomas Soome 			xdr->xdr_idx += 2 * sizeof(unsigned);
574e307eb94SToomas Soome 		}
575e307eb94SToomas Soome 	}
576e307eb94SToomas Soome 	return (rv);
577e307eb94SToomas Soome }
578e307eb94SToomas Soome 
579e307eb94SToomas Soome /*
580e307eb94SToomas Soome  * Calculate nvlist size, translating encoded_size and decoded_size.
581e307eb94SToomas Soome  */
582e307eb94SToomas Soome static bool
583e307eb94SToomas Soome nvlist_size_xdr(xdr_t *xdr, size_t *size)
584e307eb94SToomas Soome {
585e307eb94SToomas Soome 	uint8_t *pair;
5863830659eSToomas Soome 	unsigned encoded_size, decoded_size;
5873830659eSToomas Soome 
588e307eb94SToomas Soome 	xdr->xdr_idx += 2 * sizeof(unsigned);
5893830659eSToomas Soome 
590e307eb94SToomas Soome 	pair = xdr->xdr_idx;
591e307eb94SToomas Soome 	if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size))
592e307eb94SToomas Soome 		return (false);
593e307eb94SToomas Soome 
5943830659eSToomas Soome 	while (encoded_size && decoded_size) {
595e307eb94SToomas Soome 		xdr->xdr_idx = pair + encoded_size;
596e307eb94SToomas Soome 		pair = xdr->xdr_idx;
597e307eb94SToomas Soome 		if (!xdr_u_int(xdr, &encoded_size) ||
598e307eb94SToomas Soome 		    !xdr_u_int(xdr, &decoded_size))
599e307eb94SToomas Soome 			return (false);
6003830659eSToomas Soome 	}
601e307eb94SToomas Soome 	*size = xdr->xdr_idx - xdr->xdr_buf;
602e307eb94SToomas Soome 
603e307eb94SToomas Soome 	return (true);
604e307eb94SToomas Soome }
605e307eb94SToomas Soome 
606e307eb94SToomas Soome nvp_header_t *
607e307eb94SToomas Soome nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh)
608e307eb94SToomas Soome {
609e307eb94SToomas Soome 	uint8_t *pair;
610e307eb94SToomas Soome 	unsigned encoded_size, decoded_size;
611e307eb94SToomas Soome 	xdr_t xdr;
612e307eb94SToomas Soome 
613e307eb94SToomas Soome 	if (nvl == NULL)
614e307eb94SToomas Soome 		return (NULL);
615e307eb94SToomas Soome 
616e307eb94SToomas Soome 	xdr.xdr_buf = nvl->nv_data;
617e307eb94SToomas Soome 	xdr.xdr_idx = nvl->nv_data;
618e307eb94SToomas Soome 	xdr.xdr_buf_size = nvl->nv_size;
619e307eb94SToomas Soome 
620e307eb94SToomas Soome 	xdr.xdr_idx += 2 * sizeof(unsigned);
621e307eb94SToomas Soome 
622e307eb94SToomas Soome 	/* Skip tp current pair */
623e307eb94SToomas Soome 	if (nvh != NULL) {
624e307eb94SToomas Soome 		xdr.xdr_idx = (uint8_t *)nvh;
625e307eb94SToomas Soome 	}
626e307eb94SToomas Soome 
627e307eb94SToomas Soome 	pair = xdr.xdr_idx;
628e307eb94SToomas Soome 	if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
629e307eb94SToomas Soome 		return (NULL);
630e307eb94SToomas Soome 
631e307eb94SToomas Soome 	encoded_size = *(unsigned *)xdr.xdr_idx;
632e307eb94SToomas Soome 	xdr.xdr_idx += sizeof(unsigned);
633e307eb94SToomas Soome 	if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
634e307eb94SToomas Soome 		return (NULL);
635e307eb94SToomas Soome 
636e307eb94SToomas Soome 	decoded_size = *(unsigned *)xdr.xdr_idx;
637e307eb94SToomas Soome 	xdr.xdr_idx += sizeof(unsigned);
638e307eb94SToomas Soome 	if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
639e307eb94SToomas Soome 		return (NULL);
640e307eb94SToomas Soome 
641e307eb94SToomas Soome 	while (encoded_size && decoded_size) {
642e307eb94SToomas Soome 		if (nvh == NULL)
643e307eb94SToomas Soome 			return ((nvp_header_t *)pair);
644e307eb94SToomas Soome 
645e307eb94SToomas Soome 		xdr.xdr_idx = pair + encoded_size;
646e307eb94SToomas Soome 		nvh = (nvp_header_t *)xdr.xdr_idx;
647e307eb94SToomas Soome 
648e307eb94SToomas Soome 		if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
649e307eb94SToomas Soome 			return (NULL);
650e307eb94SToomas Soome 
651e307eb94SToomas Soome 		encoded_size = *(unsigned *)xdr.xdr_idx;
652e307eb94SToomas Soome 		xdr.xdr_idx += sizeof(unsigned);
653e307eb94SToomas Soome 		if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
654e307eb94SToomas Soome 			return (NULL);
655e307eb94SToomas Soome 		decoded_size = *(unsigned *)xdr.xdr_idx;
656e307eb94SToomas Soome 		xdr.xdr_idx += sizeof(unsigned);
657e307eb94SToomas Soome 		if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
658e307eb94SToomas Soome 			return (NULL);
659e307eb94SToomas Soome 
660e307eb94SToomas Soome 		if (encoded_size != 0 && decoded_size != 0) {
661e307eb94SToomas Soome 			return (nvh);
662e307eb94SToomas Soome 		}
663e307eb94SToomas Soome 	}
664e307eb94SToomas Soome 	return (NULL);
665e307eb94SToomas Soome }
666e307eb94SToomas Soome 
667e307eb94SToomas Soome /*
668e307eb94SToomas Soome  * Calculate nvlist size by walking in memory data.
669e307eb94SToomas Soome  */
670e307eb94SToomas Soome static bool
671e307eb94SToomas Soome nvlist_size_native(xdr_t *xdr, size_t *size)
672e307eb94SToomas Soome {
673e307eb94SToomas Soome 	uint8_t *pair;
674e307eb94SToomas Soome 	unsigned encoded_size, decoded_size;
675e307eb94SToomas Soome 
676e307eb94SToomas Soome 	xdr->xdr_idx += 2 * sizeof(unsigned);
677e307eb94SToomas Soome 
678e307eb94SToomas Soome 	pair = xdr->xdr_idx;
679e307eb94SToomas Soome 	if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
680e307eb94SToomas Soome 		return (false);
681e307eb94SToomas Soome 
682e307eb94SToomas Soome 	encoded_size = *(unsigned *)xdr->xdr_idx;
683e307eb94SToomas Soome 	xdr->xdr_idx += sizeof(unsigned);
684e307eb94SToomas Soome 	if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
685e307eb94SToomas Soome 		return (false);
686e307eb94SToomas Soome 	decoded_size = *(unsigned *)xdr->xdr_idx;
687e307eb94SToomas Soome 	xdr->xdr_idx += sizeof(unsigned);
688e307eb94SToomas Soome 	while (encoded_size && decoded_size) {
689e307eb94SToomas Soome 		xdr->xdr_idx = pair + encoded_size;
690e307eb94SToomas Soome 		pair = xdr->xdr_idx;
691e307eb94SToomas Soome 		if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
692e307eb94SToomas Soome 			return (false);
693e307eb94SToomas Soome 		encoded_size = *(unsigned *)xdr->xdr_idx;
694e307eb94SToomas Soome 		xdr->xdr_idx += sizeof(unsigned);
695e307eb94SToomas Soome 		if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
696e307eb94SToomas Soome 			return (false);
697e307eb94SToomas Soome 		decoded_size = *(unsigned *)xdr->xdr_idx;
698e307eb94SToomas Soome 		xdr->xdr_idx += sizeof(unsigned);
699e307eb94SToomas Soome 	}
700e307eb94SToomas Soome 	*size = xdr->xdr_idx - xdr->xdr_buf;
701e307eb94SToomas Soome 
702e307eb94SToomas Soome 	return (true);
703e307eb94SToomas Soome }
704e307eb94SToomas Soome 
705e307eb94SToomas Soome /*
706e307eb94SToomas Soome  * Export nvlist to byte stream format.
707e307eb94SToomas Soome  */
708e307eb94SToomas Soome int
709e307eb94SToomas Soome nvlist_export(nvlist_t *nvl)
710e307eb94SToomas Soome {
711e307eb94SToomas Soome 	int rv;
712e307eb94SToomas Soome 	xdr_t xdr = {
713e307eb94SToomas Soome 		.xdr_op = XDR_OP_ENCODE,
714e307eb94SToomas Soome 		.xdr_putint = _putint,
715e307eb94SToomas Soome 		.xdr_putuint = _putuint,
716e307eb94SToomas Soome 		.xdr_buf = nvl->nv_data,
717e307eb94SToomas Soome 		.xdr_idx = nvl->nv_data,
718e307eb94SToomas Soome 		.xdr_buf_size = nvl->nv_size
719e307eb94SToomas Soome 	};
720e307eb94SToomas Soome 
721e307eb94SToomas Soome 	if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR)
722e307eb94SToomas Soome 		return (ENOTSUP);
723e307eb94SToomas Soome 
724e307eb94SToomas Soome 	nvl->nv_idx = nvl->nv_data;
725e307eb94SToomas Soome 	rv = nvlist_xdr_nvlist(&xdr, nvl);
726e307eb94SToomas Soome 
727e307eb94SToomas Soome 	return (rv);
7283830659eSToomas Soome }
7293830659eSToomas Soome 
7303830659eSToomas Soome /*
7313830659eSToomas Soome  * Import nvlist from byte stream.
7323830659eSToomas Soome  * Determine the stream size and allocate private copy.
7333830659eSToomas Soome  * Then translate the data.
7343830659eSToomas Soome  */
7353830659eSToomas Soome nvlist_t *
736e307eb94SToomas Soome nvlist_import(const char *stream, size_t size)
7373830659eSToomas Soome {
7383830659eSToomas Soome 	nvlist_t *nvl;
739e307eb94SToomas Soome 	xdr_t xdr = {
740e307eb94SToomas Soome 		.xdr_op = XDR_OP_DECODE,
741e307eb94SToomas Soome 		.xdr_getint = _getint,
742e307eb94SToomas Soome 		.xdr_getuint = _getuint
743e307eb94SToomas Soome 	};
7443830659eSToomas Soome 
745e307eb94SToomas Soome 	/* Check the nvlist head. */
746e307eb94SToomas Soome 	if (stream[0] != NV_ENCODE_XDR ||
747e307eb94SToomas Soome 	    (stream[1] != '\0' && stream[1] != '\1') ||
748e307eb94SToomas Soome 	    stream[2] != '\0' || stream[3] != '\0' ||
749e307eb94SToomas Soome 	    be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION ||
750e307eb94SToomas Soome 	    be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME)
7513830659eSToomas Soome 		return (NULL);
7523830659eSToomas Soome 
7533830659eSToomas Soome 	nvl = malloc(sizeof(*nvl));
7543830659eSToomas Soome 	if (nvl == NULL)
7553830659eSToomas Soome 		return (nvl);
7563830659eSToomas Soome 
757e307eb94SToomas Soome 	nvl->nv_header.nvh_encoding = stream[0];
758e307eb94SToomas Soome 	nvl->nv_header.nvh_endian = stream[1];
759e307eb94SToomas Soome 	nvl->nv_header.nvh_reserved1 = stream[2];
760e307eb94SToomas Soome 	nvl->nv_header.nvh_reserved2 = stream[3];
761e307eb94SToomas Soome 
762e307eb94SToomas Soome 	xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4;
763e307eb94SToomas Soome 	xdr.xdr_buf_size = size - 4;
764e307eb94SToomas Soome 
765e307eb94SToomas Soome 	if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) {
766e307eb94SToomas Soome 		free(nvl);
767e307eb94SToomas Soome 		return (NULL);
768e307eb94SToomas Soome 	}
769e307eb94SToomas Soome 	nvl->nv_size = nvl->nv_asize;
7703830659eSToomas Soome 	nvl->nv_data = malloc(nvl->nv_asize);
7713830659eSToomas Soome 	if (nvl->nv_data == NULL) {
7723830659eSToomas Soome 		free(nvl);
7733830659eSToomas Soome 		return (NULL);
7743830659eSToomas Soome 	}
7753830659eSToomas Soome 	nvl->nv_idx = nvl->nv_data;
776e307eb94SToomas Soome 	bcopy(stream + 4, nvl->nv_data, nvl->nv_asize);
7773830659eSToomas Soome 
778e307eb94SToomas Soome 	xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data;
779e307eb94SToomas Soome 	xdr.xdr_buf_size = nvl->nv_asize;
780e307eb94SToomas Soome 
781e307eb94SToomas Soome 	if (nvlist_xdr_nvlist(&xdr, nvl) != 0) {
782e307eb94SToomas Soome 		free(nvl->nv_data);
783e307eb94SToomas Soome 		free(nvl);
784e307eb94SToomas Soome 		nvl = NULL;
785e307eb94SToomas Soome 	}
786e307eb94SToomas Soome 
7873830659eSToomas Soome 	return (nvl);
7883830659eSToomas Soome }
7893830659eSToomas Soome 
7903830659eSToomas Soome /*
7913830659eSToomas Soome  * remove pair from this nvlist.
7923830659eSToomas Soome  */
7933830659eSToomas Soome int
7943830659eSToomas Soome nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
7953830659eSToomas Soome {
7963830659eSToomas Soome 	uint8_t *head, *tail;
7973830659eSToomas Soome 	nvs_data_t *data;
7983830659eSToomas Soome 	nvp_header_t *nvp;
7993830659eSToomas Soome 	nv_string_t *nvp_name;
8003830659eSToomas Soome 	nv_pair_data_t *nvp_data;
8013830659eSToomas Soome 	size_t size;
802e307eb94SToomas Soome 	xdr_t xdr;
8033830659eSToomas Soome 
8043830659eSToomas Soome 	if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
8053830659eSToomas Soome 		return (EINVAL);
8063830659eSToomas Soome 
807e307eb94SToomas Soome 	/* Make sure the nvlist size is set correct */
808e307eb94SToomas Soome 	xdr.xdr_idx = nvl->nv_data;
809e307eb94SToomas Soome 	xdr.xdr_buf = xdr.xdr_idx;
810e307eb94SToomas Soome 	xdr.xdr_buf_size = nvl->nv_size;
811e307eb94SToomas Soome 	if (!nvlist_size_native(&xdr, &nvl->nv_size))
812e307eb94SToomas Soome 		return (EINVAL);
813e307eb94SToomas Soome 
814e307eb94SToomas Soome 	data = (nvs_data_t *)nvl->nv_data;
8153830659eSToomas Soome 	nvp = &data->nvl_pair;	/* first pair in nvlist */
8163830659eSToomas Soome 	head = (uint8_t *)nvp;
8173830659eSToomas Soome 
8183830659eSToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
819e307eb94SToomas Soome 		nvp_name = (nv_string_t *)(nvp + 1);
8203830659eSToomas Soome 
821e307eb94SToomas Soome 		nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] +
822e307eb94SToomas Soome 		    NV_ALIGN4(nvp_name->nv_size));
8233830659eSToomas Soome 
824e307eb94SToomas Soome 		if (strlen(name) == nvp_name->nv_size &&
825e307eb94SToomas Soome 		    memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
826e307eb94SToomas Soome 		    (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
8273830659eSToomas Soome 			/*
8283830659eSToomas Soome 			 * set tail to point to next nvpair and size
8293830659eSToomas Soome 			 * is the length of the tail.
8303830659eSToomas Soome 			 */
8313830659eSToomas Soome 			tail = head + nvp->encoded_size;
832e307eb94SToomas Soome 			size = nvl->nv_size - (tail - nvl->nv_data);
8333830659eSToomas Soome 
8343830659eSToomas Soome 			/* adjust the size of the nvlist. */
8353830659eSToomas Soome 			nvl->nv_size -= nvp->encoded_size;
8363830659eSToomas Soome 			bcopy(tail, head, size);
8373830659eSToomas Soome 			return (0);
8383830659eSToomas Soome 		}
8393830659eSToomas Soome 		/* Not our pair, skip to next. */
8403830659eSToomas Soome 		head = head + nvp->encoded_size;
8413830659eSToomas Soome 		nvp = (nvp_header_t *)head;
8423830659eSToomas Soome 	}
8433830659eSToomas Soome 	return (ENOENT);
8443830659eSToomas Soome }
8453830659eSToomas Soome 
846e307eb94SToomas Soome static int
847e307eb94SToomas Soome clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size,
848e307eb94SToomas Soome     nvlist_t **nvlist)
849e307eb94SToomas Soome {
850e307eb94SToomas Soome 	nvlist_t *nv;
851e307eb94SToomas Soome 
852e307eb94SToomas Soome 	nv = calloc(1, sizeof(*nv));
853e307eb94SToomas Soome 	if (nv == NULL)
854e307eb94SToomas Soome 		return (ENOMEM);
855e307eb94SToomas Soome 
856e307eb94SToomas Soome 	nv->nv_header = nvl->nv_header;
857e307eb94SToomas Soome 	nv->nv_asize = size;
858e307eb94SToomas Soome 	nv->nv_size = size;
859e307eb94SToomas Soome 	nv->nv_data = malloc(nv->nv_asize);
860e307eb94SToomas Soome 	if (nv->nv_data == NULL) {
861e307eb94SToomas Soome 		free(nv);
862e307eb94SToomas Soome 		return (ENOMEM);
863e307eb94SToomas Soome 	}
864e307eb94SToomas Soome 
865e307eb94SToomas Soome 	bcopy(ptr, nv->nv_data, nv->nv_asize);
866e307eb94SToomas Soome 	*nvlist = nv;
867e307eb94SToomas Soome 	return (0);
868e307eb94SToomas Soome }
869e307eb94SToomas Soome 
870e307eb94SToomas Soome /*
871e307eb94SToomas Soome  * Return the next nvlist in an nvlist array.
872e307eb94SToomas Soome  */
873e307eb94SToomas Soome static uint8_t *
874e307eb94SToomas Soome nvlist_next(const uint8_t *ptr)
875e307eb94SToomas Soome {
876e307eb94SToomas Soome 	nvs_data_t *data;
877e307eb94SToomas Soome 	nvp_header_t *nvp;
878e307eb94SToomas Soome 
879e307eb94SToomas Soome 	data = (nvs_data_t *)ptr;
880e307eb94SToomas Soome 	nvp = &data->nvl_pair;	/* first pair in nvlist */
881e307eb94SToomas Soome 
882e307eb94SToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
883e307eb94SToomas Soome 		nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
884e307eb94SToomas Soome 	}
885e307eb94SToomas Soome 	return ((uint8_t *)nvp + sizeof(*nvp));
886e307eb94SToomas Soome }
887e307eb94SToomas Soome 
888e307eb94SToomas Soome /*
889e307eb94SToomas Soome  * Note: nvlist and nvlist array must be freed by caller.
890e307eb94SToomas Soome  */
8913830659eSToomas Soome int
8923830659eSToomas Soome nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type,
8933830659eSToomas Soome     int *elementsp, void *valuep, int *sizep)
8943830659eSToomas Soome {
8953830659eSToomas Soome 	nvs_data_t *data;
8963830659eSToomas Soome 	nvp_header_t *nvp;
8973830659eSToomas Soome 	nv_string_t *nvp_name;
8983830659eSToomas Soome 	nv_pair_data_t *nvp_data;
899e307eb94SToomas Soome 	nvlist_t **nvlist, *nv;
900e307eb94SToomas Soome 	uint8_t *ptr;
901e307eb94SToomas Soome 	int rv;
9023830659eSToomas Soome 
9033830659eSToomas Soome 	if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
9043830659eSToomas Soome 		return (EINVAL);
9053830659eSToomas Soome 
9063830659eSToomas Soome 	data = (nvs_data_t *)nvl->nv_data;
9073830659eSToomas Soome 	nvp = &data->nvl_pair;	/* first pair in nvlist */
9083830659eSToomas Soome 
9093830659eSToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
9103830659eSToomas Soome 		nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp));
911e307eb94SToomas Soome 		if (nvl->nv_data + nvl->nv_size <
912e307eb94SToomas Soome 		    nvp_name->nv_data + nvp_name->nv_size)
913e307eb94SToomas Soome 			return (EIO);
9143830659eSToomas Soome 
9153830659eSToomas Soome 		nvp_data = (nv_pair_data_t *)
9163830659eSToomas Soome 		    NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
9173830659eSToomas Soome 		    nvp_name->nv_size);
9183830659eSToomas Soome 
919e307eb94SToomas Soome 		if (strlen(name) == nvp_name->nv_size &&
920e307eb94SToomas Soome 		    memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
921e307eb94SToomas Soome 		    (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
9223830659eSToomas Soome 			if (elementsp != NULL)
9233830659eSToomas Soome 				*elementsp = nvp_data->nv_nelem;
9243830659eSToomas Soome 			switch (nvp_data->nv_type) {
9253830659eSToomas Soome 			case DATA_TYPE_UINT64:
926e307eb94SToomas Soome 				bcopy(nvp_data->nv_data, valuep,
927e307eb94SToomas Soome 				    sizeof(uint64_t));
9283830659eSToomas Soome 				return (0);
9293830659eSToomas Soome 			case DATA_TYPE_STRING:
9303830659eSToomas Soome 				nvp_name = (nv_string_t *)nvp_data->nv_data;
9313830659eSToomas Soome 				if (sizep != NULL) {
9323830659eSToomas Soome 					*sizep = nvp_name->nv_size;
9333830659eSToomas Soome 				}
9343830659eSToomas Soome 				*(const uint8_t **)valuep =
9353830659eSToomas Soome 				    &nvp_name->nv_data[0];
9363830659eSToomas Soome 				return (0);
9373830659eSToomas Soome 			case DATA_TYPE_NVLIST:
938e307eb94SToomas Soome 				ptr = &nvp_data->nv_data[0];
939e307eb94SToomas Soome 				rv = clone_nvlist(nvl, ptr,
940e307eb94SToomas Soome 				    nvlist_next(ptr) - ptr, &nv);
941e307eb94SToomas Soome 				if (rv == 0) {
942e307eb94SToomas Soome 					*(nvlist_t **)valuep = nv;
9433830659eSToomas Soome 				}
944e307eb94SToomas Soome 				return (rv);
945e307eb94SToomas Soome 
946e307eb94SToomas Soome 			case DATA_TYPE_NVLIST_ARRAY:
947e307eb94SToomas Soome 				nvlist = calloc(nvp_data->nv_nelem,
948e307eb94SToomas Soome 				    sizeof(nvlist_t *));
949e307eb94SToomas Soome 				if (nvlist == NULL)
9503830659eSToomas Soome 					return (ENOMEM);
951e307eb94SToomas Soome 				ptr = &nvp_data->nv_data[0];
952e307eb94SToomas Soome 				rv = 0;
953e307eb94SToomas Soome 				for (unsigned i = 0; i < nvp_data->nv_nelem;
954e307eb94SToomas Soome 				    i++) {
955e307eb94SToomas Soome 					rv = clone_nvlist(nvl, ptr,
956e307eb94SToomas Soome 					    nvlist_next(ptr) - ptr, &nvlist[i]);
957e307eb94SToomas Soome 					if (rv != 0)
958e307eb94SToomas Soome 						goto error;
959e307eb94SToomas Soome 					ptr = nvlist_next(ptr);
960e307eb94SToomas Soome 				}
961e307eb94SToomas Soome 				*(nvlist_t ***)valuep = nvlist;
962e307eb94SToomas Soome 				return (rv);
9633830659eSToomas Soome 			}
9643830659eSToomas Soome 			return (EIO);
9653830659eSToomas Soome 		}
9663830659eSToomas Soome 		/* Not our pair, skip to next. */
9673830659eSToomas Soome 		nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
968e307eb94SToomas Soome 		if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp)
969e307eb94SToomas Soome 			return (EIO);
9703830659eSToomas Soome 	}
9713830659eSToomas Soome 	return (ENOENT);
972e307eb94SToomas Soome error:
973e307eb94SToomas Soome 	for (unsigned i = 0; i < nvp_data->nv_nelem; i++) {
974e307eb94SToomas Soome 		free(nvlist[i]->nv_data);
975e307eb94SToomas Soome 		free(nvlist[i]);
976e307eb94SToomas Soome 	}
977e307eb94SToomas Soome 	free(nvlist);
978e307eb94SToomas Soome 	return (rv);
9793830659eSToomas Soome }
9803830659eSToomas Soome 
981e307eb94SToomas Soome static int
982e307eb94SToomas Soome get_value_size(data_type_t type, const void *data, uint32_t nelem)
9833830659eSToomas Soome {
984e307eb94SToomas Soome 	uint64_t value_sz = 0;
9853830659eSToomas Soome 
986e307eb94SToomas Soome 	switch (type) {
987e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN:
988e307eb94SToomas Soome 		value_sz = 0;
989e307eb94SToomas Soome 		break;
990e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
991e307eb94SToomas Soome 	case DATA_TYPE_BYTE:
992e307eb94SToomas Soome 	case DATA_TYPE_INT8:
993e307eb94SToomas Soome 	case DATA_TYPE_UINT8:
994e307eb94SToomas Soome 	case DATA_TYPE_INT16:
995e307eb94SToomas Soome 	case DATA_TYPE_UINT16:
996e307eb94SToomas Soome 	case DATA_TYPE_INT32:
997e307eb94SToomas Soome 	case DATA_TYPE_UINT32:
998e307eb94SToomas Soome 		/* Our smallest data unit is 32-bit */
999e307eb94SToomas Soome 		value_sz = sizeof(uint32_t);
1000e307eb94SToomas Soome 		break;
1001e307eb94SToomas Soome 	case DATA_TYPE_HRTIME:
1002e307eb94SToomas Soome 	case DATA_TYPE_INT64:
1003e307eb94SToomas Soome 		value_sz = sizeof(int64_t);
1004e307eb94SToomas Soome 		break;
1005e307eb94SToomas Soome 	case DATA_TYPE_UINT64:
1006e307eb94SToomas Soome 		value_sz = sizeof(uint64_t);
1007e307eb94SToomas Soome 		break;
1008e307eb94SToomas Soome 	case DATA_TYPE_STRING:
1009e307eb94SToomas Soome 		if (data == NULL)
1010e307eb94SToomas Soome 			value_sz = 0;
1011e307eb94SToomas Soome 		else
1012e307eb94SToomas Soome 			value_sz = strlen(data) + 1;
1013e307eb94SToomas Soome 		break;
1014e307eb94SToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
1015e307eb94SToomas Soome 		value_sz = nelem * sizeof(uint8_t);
1016e307eb94SToomas Soome 		break;
1017e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
1018e307eb94SToomas Soome 	case DATA_TYPE_INT8_ARRAY:
1019e307eb94SToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
1020e307eb94SToomas Soome 	case DATA_TYPE_INT16_ARRAY:
1021e307eb94SToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
1022e307eb94SToomas Soome 	case DATA_TYPE_INT32_ARRAY:
1023e307eb94SToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
1024e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(uint32_t);
1025e307eb94SToomas Soome 		break;
1026e307eb94SToomas Soome 	case DATA_TYPE_INT64_ARRAY:
1027e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(int64_t);
1028e307eb94SToomas Soome 		break;
1029e307eb94SToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
1030e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(uint64_t);
1031e307eb94SToomas Soome 		break;
1032e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1033e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(uint64_t);
1034e307eb94SToomas Soome 
1035e307eb94SToomas Soome 		if (data != NULL) {
1036e307eb94SToomas Soome 			char *const *strs = data;
1037e307eb94SToomas Soome 			uint32_t i;
1038e307eb94SToomas Soome 
1039e307eb94SToomas Soome 			for (i = 0; i < nelem; i++) {
1040e307eb94SToomas Soome 				if (strs[i] == NULL)
1041e307eb94SToomas Soome 					return (-1);
1042e307eb94SToomas Soome 				value_sz += strlen(strs[i]) + 1;
1043e307eb94SToomas Soome 			}
1044e307eb94SToomas Soome 		}
1045e307eb94SToomas Soome 		break;
1046e307eb94SToomas Soome 	case DATA_TYPE_NVLIST:
1047e307eb94SToomas Soome 		/*
1048e307eb94SToomas Soome 		 * The decoded size of nvlist is constant.
1049e307eb94SToomas Soome 		 */
1050e307eb94SToomas Soome 		value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1051e307eb94SToomas Soome 		break;
1052e307eb94SToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
1053e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(uint64_t) +
1054e307eb94SToomas Soome 		    (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1055e307eb94SToomas Soome 		break;
1056e307eb94SToomas Soome 	default:
1057e307eb94SToomas Soome 		return (-1);
1058e307eb94SToomas Soome 	}
1059e307eb94SToomas Soome 
1060e307eb94SToomas Soome 	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1061e307eb94SToomas Soome }
1062e307eb94SToomas Soome 
1063e307eb94SToomas Soome static int
1064e307eb94SToomas Soome get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem)
1065e307eb94SToomas Soome {
1066e307eb94SToomas Soome 	uint64_t value_sz = 0;
1067e307eb94SToomas Soome 	xdr_t xdr;
1068e307eb94SToomas Soome 	size_t size;
1069e307eb94SToomas Soome 
1070e307eb94SToomas Soome 	switch (type) {
1071e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN:
1072e307eb94SToomas Soome 		value_sz = 0;
1073e307eb94SToomas Soome 		break;
1074e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
1075e307eb94SToomas Soome 	case DATA_TYPE_BYTE:
1076e307eb94SToomas Soome 	case DATA_TYPE_INT8:
1077e307eb94SToomas Soome 	case DATA_TYPE_UINT8:
1078e307eb94SToomas Soome 	case DATA_TYPE_INT16:
1079e307eb94SToomas Soome 	case DATA_TYPE_UINT16:
1080e307eb94SToomas Soome 	case DATA_TYPE_INT32:
1081e307eb94SToomas Soome 	case DATA_TYPE_UINT32:
1082e307eb94SToomas Soome 		/* Our smallest data unit is 32-bit */
1083e307eb94SToomas Soome 		value_sz = sizeof(uint32_t);
1084e307eb94SToomas Soome 		break;
1085e307eb94SToomas Soome 	case DATA_TYPE_HRTIME:
1086e307eb94SToomas Soome 	case DATA_TYPE_INT64:
1087e307eb94SToomas Soome 	case DATA_TYPE_UINT64:
1088e307eb94SToomas Soome 		value_sz = sizeof(uint64_t);
1089e307eb94SToomas Soome 		break;
1090e307eb94SToomas Soome 	case DATA_TYPE_STRING:
1091e307eb94SToomas Soome 		value_sz = 4 + NV_ALIGN4(strlen(data));
1092e307eb94SToomas Soome 		break;
1093e307eb94SToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
1094e307eb94SToomas Soome 		value_sz = NV_ALIGN4(nelem);
1095e307eb94SToomas Soome 		break;
1096e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
1097e307eb94SToomas Soome 	case DATA_TYPE_INT8_ARRAY:
1098e307eb94SToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
1099e307eb94SToomas Soome 	case DATA_TYPE_INT16_ARRAY:
1100e307eb94SToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
1101e307eb94SToomas Soome 	case DATA_TYPE_INT32_ARRAY:
1102e307eb94SToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
1103e307eb94SToomas Soome 		value_sz = 4 + (uint64_t)nelem * sizeof(uint32_t);
1104e307eb94SToomas Soome 		break;
1105e307eb94SToomas Soome 	case DATA_TYPE_INT64_ARRAY:
1106e307eb94SToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
1107e307eb94SToomas Soome 		value_sz = 4 + (uint64_t)nelem * sizeof(uint64_t);
1108e307eb94SToomas Soome 		break;
1109e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1110e307eb94SToomas Soome 		if (data != NULL) {
1111e307eb94SToomas Soome 			char *const *strs = data;
1112e307eb94SToomas Soome 			uint32_t i;
1113e307eb94SToomas Soome 
1114e307eb94SToomas Soome 			for (i = 0; i < nelem; i++) {
1115e307eb94SToomas Soome 				value_sz += 4 + NV_ALIGN4(strlen(strs[i]));
1116e307eb94SToomas Soome 			}
1117e307eb94SToomas Soome 		}
1118e307eb94SToomas Soome 		break;
1119e307eb94SToomas Soome 	case DATA_TYPE_NVLIST:
1120e307eb94SToomas Soome 		xdr.xdr_idx = ((nvlist_t *)data)->nv_data;
1121e307eb94SToomas Soome 		xdr.xdr_buf = xdr.xdr_idx;
1122e307eb94SToomas Soome 		xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size;
1123e307eb94SToomas Soome 
1124e307eb94SToomas Soome 		if (!nvlist_size_native(&xdr, &size))
1125e307eb94SToomas Soome 			return (-1);
1126e307eb94SToomas Soome 
1127e307eb94SToomas Soome 		value_sz = size;
1128e307eb94SToomas Soome 		break;
1129e307eb94SToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
1130e307eb94SToomas Soome 		value_sz = 0;
1131e307eb94SToomas Soome 		for (uint32_t i = 0; i < nelem; i++) {
1132e307eb94SToomas Soome 			xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1133e307eb94SToomas Soome 			xdr.xdr_buf = xdr.xdr_idx;
1134e307eb94SToomas Soome 			xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1135e307eb94SToomas Soome 
1136e307eb94SToomas Soome 			if (!nvlist_size_native(&xdr, &size))
1137e307eb94SToomas Soome 				return (-1);
1138e307eb94SToomas Soome 			value_sz += size;
1139e307eb94SToomas Soome 		}
1140e307eb94SToomas Soome 		break;
1141e307eb94SToomas Soome 	default:
1142e307eb94SToomas Soome 		return (-1);
1143e307eb94SToomas Soome 	}
1144e307eb94SToomas Soome 
1145e307eb94SToomas Soome 	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1146e307eb94SToomas Soome }
1147e307eb94SToomas Soome 
1148e307eb94SToomas Soome #define	NVPE_SIZE(name_len, data_len) \
1149e307eb94SToomas Soome 	(4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len)
1150e307eb94SToomas Soome #define	NVP_SIZE(name_len, data_len) \
1151e307eb94SToomas Soome 	(NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len))
1152e307eb94SToomas Soome 
1153e307eb94SToomas Soome static int
1154e307eb94SToomas Soome nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1155e307eb94SToomas Soome     uint32_t nelem, const void *data)
1156e307eb94SToomas Soome {
1157e307eb94SToomas Soome 	nvs_data_t *nvs;
1158e307eb94SToomas Soome 	nvp_header_t head, *hp;
1159e307eb94SToomas Soome 	uint8_t *ptr;
1160e307eb94SToomas Soome 	size_t namelen;
1161e307eb94SToomas Soome 	int decoded_size, encoded_size;
11629de6a13eSToomas Soome 	xdr_t xdr = {
11639de6a13eSToomas Soome 		.xdr_op = XDR_OP_ENCODE,
11649de6a13eSToomas Soome 		.xdr_putint = _putint_mem,
11659de6a13eSToomas Soome 		.xdr_putuint = _putuint_mem,
11669de6a13eSToomas Soome 		.xdr_buf = nvl->nv_data,
11679de6a13eSToomas Soome 		.xdr_idx = nvl->nv_data,
11689de6a13eSToomas Soome 		.xdr_buf_size = nvl->nv_size
11699de6a13eSToomas Soome 	};
1170e307eb94SToomas Soome 
1171e307eb94SToomas Soome 	nvs = (nvs_data_t *)nvl->nv_data;
1172e307eb94SToomas Soome 	if (nvs->nvl_nvflag & NV_UNIQUE_NAME)
1173e307eb94SToomas Soome 		(void) nvlist_remove(nvl, name, type);
1174e307eb94SToomas Soome 
1175e307eb94SToomas Soome 	xdr.xdr_buf = nvl->nv_data;
1176e307eb94SToomas Soome 	xdr.xdr_idx = nvl->nv_data;
1177e307eb94SToomas Soome 	xdr.xdr_buf_size = nvl->nv_size;
1178e307eb94SToomas Soome 	if (!nvlist_size_native(&xdr, &nvl->nv_size))
11793830659eSToomas Soome 		return (EINVAL);
11803830659eSToomas Soome 
1181e307eb94SToomas Soome 	namelen = strlen(name);
1182e307eb94SToomas Soome 	if ((decoded_size = get_value_size(type, data, nelem)) < 0)
1183e307eb94SToomas Soome 		return (EINVAL);
1184e307eb94SToomas Soome 	if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0)
1185e307eb94SToomas Soome 		return (EINVAL);
11863830659eSToomas Soome 
1187e307eb94SToomas Soome 	/*
1188e307eb94SToomas Soome 	 * The encoded size is calculated as:
1189e307eb94SToomas Soome 	 * encode_size (4) + decode_size (4) +
1190e307eb94SToomas Soome 	 * name string size  (4 + NV_ALIGN4(namelen) +
1191e307eb94SToomas Soome 	 * data type (4) + nelem size (4) + datalen
1192e307eb94SToomas Soome 	 *
1193e307eb94SToomas Soome 	 * The decoded size is calculated as:
1194e307eb94SToomas Soome 	 * Note: namelen is with terminating 0.
1195e307eb94SToomas Soome 	 * NV_ALIGN(sizeof(nvpair_t) (4 * 4) + namelen + 1) +
1196e307eb94SToomas Soome 	 * NV_ALIGN(data_len)
1197e307eb94SToomas Soome 	 */
1198e307eb94SToomas Soome 
1199e307eb94SToomas Soome 	head.encoded_size = NVPE_SIZE(namelen, encoded_size);
1200e307eb94SToomas Soome 	head.decoded_size = NVP_SIZE(namelen + 1, decoded_size);
1201e307eb94SToomas Soome 
1202e307eb94SToomas Soome 	if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) {
1203e307eb94SToomas Soome 		ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size);
1204e307eb94SToomas Soome 		if (ptr == NULL)
1205e307eb94SToomas Soome 			return (ENOMEM);
1206e307eb94SToomas Soome 		nvl->nv_data = ptr;
1207e307eb94SToomas Soome 		nvl->nv_asize += head.encoded_size;
12083830659eSToomas Soome 	}
1209e307eb94SToomas Soome 	nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof(*hp);
1210e307eb94SToomas Soome 	bzero(nvl->nv_idx, head.encoded_size + 8);
1211e307eb94SToomas Soome 	hp = (nvp_header_t *)nvl->nv_idx;
1212e307eb94SToomas Soome 	*hp = head;
1213e307eb94SToomas Soome 	nvl->nv_idx += sizeof(*hp);
12149de6a13eSToomas Soome 
12159de6a13eSToomas Soome 	xdr.xdr_buf = nvl->nv_data;
12169de6a13eSToomas Soome 	xdr.xdr_idx = nvl->nv_idx;
12179de6a13eSToomas Soome 
12189de6a13eSToomas Soome 	xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen);
12199de6a13eSToomas Soome 	strlcpy((char *)xdr.xdr_idx, name, namelen + 1);
12209de6a13eSToomas Soome 	xdr.xdr_idx += NV_ALIGN4(namelen);
12219de6a13eSToomas Soome 	xdr.xdr_idx += xdr.xdr_putuint(&xdr, type);
12229de6a13eSToomas Soome 	xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem);
1223e307eb94SToomas Soome 
1224e307eb94SToomas Soome 	switch (type) {
1225e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN:
1226e307eb94SToomas Soome 		break;
12279de6a13eSToomas Soome 
1228e307eb94SToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
12299de6a13eSToomas Soome 		xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12309de6a13eSToomas Soome 		bcopy(data, xdr.xdr_idx, nelem);
12319de6a13eSToomas Soome 		xdr.xdr_idx += NV_ALIGN4(encoded_size);
1232e307eb94SToomas Soome 		break;
12339de6a13eSToomas Soome 
1234e307eb94SToomas Soome 	case DATA_TYPE_STRING:
1235e307eb94SToomas Soome 		encoded_size = strlen(data);
12369de6a13eSToomas Soome 		xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12379de6a13eSToomas Soome 		strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1);
12389de6a13eSToomas Soome 		xdr.xdr_idx += NV_ALIGN4(encoded_size);
1239e307eb94SToomas Soome 		break;
12409de6a13eSToomas Soome 
1241e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1242e307eb94SToomas Soome 		for (uint32_t i = 0; i < nelem; i++) {
1243e307eb94SToomas Soome 			encoded_size = strlen(((char **)data)[i]);
12449de6a13eSToomas Soome 			xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12459de6a13eSToomas Soome 			strlcpy((char *)xdr.xdr_idx, ((char **)data)[i],
1246e307eb94SToomas Soome 			    encoded_size + 1);
12479de6a13eSToomas Soome 			xdr.xdr_idx += NV_ALIGN4(encoded_size);
1248e307eb94SToomas Soome 		}
1249e307eb94SToomas Soome 		break;
12509de6a13eSToomas Soome 
1251e307eb94SToomas Soome 	case DATA_TYPE_BYTE:
1252e307eb94SToomas Soome 	case DATA_TYPE_INT8:
1253e307eb94SToomas Soome 	case DATA_TYPE_UINT8:
12549de6a13eSToomas Soome 		xdr_char(&xdr, (char *)data);
12559de6a13eSToomas Soome 		break;
12569de6a13eSToomas Soome 
1257e307eb94SToomas Soome 	case DATA_TYPE_INT8_ARRAY:
1258e307eb94SToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
12599de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_char);
1260e307eb94SToomas Soome 		break;
12619de6a13eSToomas Soome 
1262e307eb94SToomas Soome 	case DATA_TYPE_INT16:
12639de6a13eSToomas Soome 		xdr_short(&xdr, (short *)data);
12649de6a13eSToomas Soome 		break;
12659de6a13eSToomas Soome 
1266e307eb94SToomas Soome 	case DATA_TYPE_UINT16:
12679de6a13eSToomas Soome 		xdr_u_short(&xdr, (unsigned short *)data);
12689de6a13eSToomas Soome 		break;
12699de6a13eSToomas Soome 
1270e307eb94SToomas Soome 	case DATA_TYPE_INT16_ARRAY:
12719de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_short);
12729de6a13eSToomas Soome 		break;
12739de6a13eSToomas Soome 
1274e307eb94SToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
12759de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short);
1276e307eb94SToomas Soome 		break;
12779de6a13eSToomas Soome 
12789de6a13eSToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
12799de6a13eSToomas Soome 	case DATA_TYPE_INT32:
12809de6a13eSToomas Soome 		xdr_int(&xdr, (int *)data);
12819de6a13eSToomas Soome 		break;
12829de6a13eSToomas Soome 
12839de6a13eSToomas Soome 	case DATA_TYPE_UINT32:
12849de6a13eSToomas Soome 		xdr_u_int(&xdr, (unsigned int *)data);
12859de6a13eSToomas Soome 		break;
12869de6a13eSToomas Soome 
12879de6a13eSToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
12889de6a13eSToomas Soome 	case DATA_TYPE_INT32_ARRAY:
12899de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_int);
12909de6a13eSToomas Soome 		break;
12919de6a13eSToomas Soome 
12929de6a13eSToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
12939de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int);
12949de6a13eSToomas Soome 		break;
12959de6a13eSToomas Soome 
12969de6a13eSToomas Soome 	case DATA_TYPE_INT64:
12979de6a13eSToomas Soome 		xdr_int64(&xdr, (int64_t *)data);
12989de6a13eSToomas Soome 		break;
12999de6a13eSToomas Soome 
13009de6a13eSToomas Soome 	case DATA_TYPE_UINT64:
13019de6a13eSToomas Soome 		xdr_uint64(&xdr, (uint64_t *)data);
13029de6a13eSToomas Soome 		break;
13039de6a13eSToomas Soome 
13049de6a13eSToomas Soome 	case DATA_TYPE_INT64_ARRAY:
13059de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64);
13069de6a13eSToomas Soome 		break;
13079de6a13eSToomas Soome 
13089de6a13eSToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
13099de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64);
13109de6a13eSToomas Soome 		break;
13119de6a13eSToomas Soome 
1312e307eb94SToomas Soome 	case DATA_TYPE_NVLIST:
13139de6a13eSToomas Soome 		bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size);
1314e307eb94SToomas Soome 		break;
13159de6a13eSToomas Soome 
1316e307eb94SToomas Soome 	case DATA_TYPE_NVLIST_ARRAY: {
1317e307eb94SToomas Soome 		size_t size;
13189de6a13eSToomas Soome 		xdr_t xdr_nv;
1319e307eb94SToomas Soome 
1320e307eb94SToomas Soome 		for (uint32_t i = 0; i < nelem; i++) {
13219de6a13eSToomas Soome 			xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
13229de6a13eSToomas Soome 			xdr_nv.xdr_buf = xdr_nv.xdr_idx;
13239de6a13eSToomas Soome 			xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1324e307eb94SToomas Soome 
13259de6a13eSToomas Soome 			if (!nvlist_size_native(&xdr_nv, &size))
1326e307eb94SToomas Soome 				return (EINVAL);
1327e307eb94SToomas Soome 
13289de6a13eSToomas Soome 			bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx,
13299de6a13eSToomas Soome 			    size);
13309de6a13eSToomas Soome 			xdr.xdr_idx += size;
1331e307eb94SToomas Soome 		}
1332e307eb94SToomas Soome 		break;
1333e307eb94SToomas Soome 	}
1334e307eb94SToomas Soome 	default:
13359de6a13eSToomas Soome 		bcopy(data, xdr.xdr_idx, encoded_size);
1336e307eb94SToomas Soome 	}
1337e307eb94SToomas Soome 
1338e307eb94SToomas Soome 	nvl->nv_size += head.encoded_size;
1339e307eb94SToomas Soome 
13403830659eSToomas Soome 	return (0);
13413830659eSToomas Soome }
13423830659eSToomas Soome 
1343e307eb94SToomas Soome int
1344e307eb94SToomas Soome nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t value)
13453830659eSToomas Soome {
1346e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1,
1347e307eb94SToomas Soome 	    &value));
1348e307eb94SToomas Soome }
1349e307eb94SToomas Soome 
1350e307eb94SToomas Soome int
1351e307eb94SToomas Soome nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value)
1352e307eb94SToomas Soome {
1353e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value));
1354e307eb94SToomas Soome }
1355e307eb94SToomas Soome 
1356e307eb94SToomas Soome int
1357e307eb94SToomas Soome nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value)
1358e307eb94SToomas Soome {
1359e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value));
1360e307eb94SToomas Soome }
1361e307eb94SToomas Soome 
1362e307eb94SToomas Soome int
1363e307eb94SToomas Soome nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value)
1364e307eb94SToomas Soome {
1365e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value));
1366e307eb94SToomas Soome }
1367e307eb94SToomas Soome 
1368e307eb94SToomas Soome int
1369e307eb94SToomas Soome nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value)
1370e307eb94SToomas Soome {
1371e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value));
1372e307eb94SToomas Soome }
1373e307eb94SToomas Soome 
1374e307eb94SToomas Soome int
1375e307eb94SToomas Soome nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value)
1376e307eb94SToomas Soome {
1377e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value));
1378e307eb94SToomas Soome }
1379e307eb94SToomas Soome 
1380e307eb94SToomas Soome int
1381e307eb94SToomas Soome nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value)
1382e307eb94SToomas Soome {
1383e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value));
1384e307eb94SToomas Soome }
1385e307eb94SToomas Soome 
1386e307eb94SToomas Soome int
1387e307eb94SToomas Soome nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value)
1388e307eb94SToomas Soome {
1389e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value));
1390e307eb94SToomas Soome }
1391e307eb94SToomas Soome 
1392e307eb94SToomas Soome int
1393e307eb94SToomas Soome nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value)
1394e307eb94SToomas Soome {
1395e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value));
1396e307eb94SToomas Soome }
1397e307eb94SToomas Soome 
1398e307eb94SToomas Soome int
1399e307eb94SToomas Soome nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value)
1400e307eb94SToomas Soome {
1401e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value));
1402e307eb94SToomas Soome }
1403e307eb94SToomas Soome 
1404e307eb94SToomas Soome int
1405e307eb94SToomas Soome nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1406e307eb94SToomas Soome {
1407e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value));
1408e307eb94SToomas Soome }
1409e307eb94SToomas Soome 
1410e307eb94SToomas Soome int
1411e307eb94SToomas Soome nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
1412e307eb94SToomas Soome     boolean_t *a, uint32_t n)
1413e307eb94SToomas Soome {
1414e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1415e307eb94SToomas Soome }
1416e307eb94SToomas Soome 
1417e307eb94SToomas Soome int
1418e307eb94SToomas Soome nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1419e307eb94SToomas Soome {
1420e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1421e307eb94SToomas Soome }
1422e307eb94SToomas Soome 
1423e307eb94SToomas Soome int
1424e307eb94SToomas Soome nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n)
1425e307eb94SToomas Soome {
1426e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1427e307eb94SToomas Soome }
1428e307eb94SToomas Soome 
1429e307eb94SToomas Soome int
1430e307eb94SToomas Soome nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1431e307eb94SToomas Soome {
1432e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1433e307eb94SToomas Soome }
1434e307eb94SToomas Soome 
1435e307eb94SToomas Soome int
1436e307eb94SToomas Soome nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n)
1437e307eb94SToomas Soome {
1438e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1439e307eb94SToomas Soome }
1440e307eb94SToomas Soome 
1441e307eb94SToomas Soome int
1442e307eb94SToomas Soome nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a,
1443e307eb94SToomas Soome     uint32_t n)
1444e307eb94SToomas Soome {
1445e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1446e307eb94SToomas Soome }
1447e307eb94SToomas Soome 
1448e307eb94SToomas Soome int
1449e307eb94SToomas Soome nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n)
1450e307eb94SToomas Soome {
1451e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1452e307eb94SToomas Soome }
1453e307eb94SToomas Soome 
1454e307eb94SToomas Soome int
1455e307eb94SToomas Soome nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a,
1456e307eb94SToomas Soome     uint32_t n)
1457e307eb94SToomas Soome {
1458e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1459e307eb94SToomas Soome }
1460e307eb94SToomas Soome 
1461e307eb94SToomas Soome int
1462e307eb94SToomas Soome nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n)
1463e307eb94SToomas Soome {
1464e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1465e307eb94SToomas Soome }
1466e307eb94SToomas Soome 
1467e307eb94SToomas Soome int
1468e307eb94SToomas Soome nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a,
1469e307eb94SToomas Soome     uint32_t n)
1470e307eb94SToomas Soome {
1471e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1472e307eb94SToomas Soome }
1473e307eb94SToomas Soome 
1474e307eb94SToomas Soome int
1475e307eb94SToomas Soome nvlist_add_string_array(nvlist_t *nvl, const char *name,
1476e307eb94SToomas Soome     char * const *a, uint32_t n)
1477e307eb94SToomas Soome {
1478e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1479e307eb94SToomas Soome }
1480e307eb94SToomas Soome 
1481e307eb94SToomas Soome int
1482e307eb94SToomas Soome nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
1483e307eb94SToomas Soome {
1484e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1485e307eb94SToomas Soome }
1486e307eb94SToomas Soome 
1487e307eb94SToomas Soome int
1488e307eb94SToomas Soome nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a,
1489e307eb94SToomas Soome     uint32_t n)
1490e307eb94SToomas Soome {
1491e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1492e307eb94SToomas Soome }
1493e307eb94SToomas Soome 
14943830659eSToomas Soome static const char *typenames[] = {
14953830659eSToomas Soome 	"DATA_TYPE_UNKNOWN",
14963830659eSToomas Soome 	"DATA_TYPE_BOOLEAN",
14973830659eSToomas Soome 	"DATA_TYPE_BYTE",
14983830659eSToomas Soome 	"DATA_TYPE_INT16",
14993830659eSToomas Soome 	"DATA_TYPE_UINT16",
15003830659eSToomas Soome 	"DATA_TYPE_INT32",
15013830659eSToomas Soome 	"DATA_TYPE_UINT32",
15023830659eSToomas Soome 	"DATA_TYPE_INT64",
15033830659eSToomas Soome 	"DATA_TYPE_UINT64",
15043830659eSToomas Soome 	"DATA_TYPE_STRING",
15053830659eSToomas Soome 	"DATA_TYPE_BYTE_ARRAY",
15063830659eSToomas Soome 	"DATA_TYPE_INT16_ARRAY",
15073830659eSToomas Soome 	"DATA_TYPE_UINT16_ARRAY",
15083830659eSToomas Soome 	"DATA_TYPE_INT32_ARRAY",
15093830659eSToomas Soome 	"DATA_TYPE_UINT32_ARRAY",
15103830659eSToomas Soome 	"DATA_TYPE_INT64_ARRAY",
15113830659eSToomas Soome 	"DATA_TYPE_UINT64_ARRAY",
15123830659eSToomas Soome 	"DATA_TYPE_STRING_ARRAY",
15133830659eSToomas Soome 	"DATA_TYPE_HRTIME",
15143830659eSToomas Soome 	"DATA_TYPE_NVLIST",
15153830659eSToomas Soome 	"DATA_TYPE_NVLIST_ARRAY",
15163830659eSToomas Soome 	"DATA_TYPE_BOOLEAN_VALUE",
15173830659eSToomas Soome 	"DATA_TYPE_INT8",
15183830659eSToomas Soome 	"DATA_TYPE_UINT8",
15193830659eSToomas Soome 	"DATA_TYPE_BOOLEAN_ARRAY",
15203830659eSToomas Soome 	"DATA_TYPE_INT8_ARRAY",
15213830659eSToomas Soome 	"DATA_TYPE_UINT8_ARRAY"
15223830659eSToomas Soome };
1523e307eb94SToomas Soome 
1524e307eb94SToomas Soome int
1525e307eb94SToomas Soome nvpair_type_from_name(const char *name)
1526e307eb94SToomas Soome {
1527e307eb94SToomas Soome 	unsigned i;
1528e307eb94SToomas Soome 
1529e307eb94SToomas Soome 	for (i = 0; i < nitems(typenames); i++) {
1530e307eb94SToomas Soome 		if (strcmp(name, typenames[i]) == 0)
1531e307eb94SToomas Soome 			return (i);
1532e307eb94SToomas Soome 	}
1533e307eb94SToomas Soome 	return (0);
1534e307eb94SToomas Soome }
1535e307eb94SToomas Soome 
1536e307eb94SToomas Soome nvp_header_t *
1537e307eb94SToomas Soome nvpair_find(nvlist_t *nv, const char *name)
1538e307eb94SToomas Soome {
1539e307eb94SToomas Soome 	nvp_header_t *nvh;
1540e307eb94SToomas Soome 
1541e307eb94SToomas Soome 	nvh = NULL;
1542e307eb94SToomas Soome 	while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) {
1543e307eb94SToomas Soome 		nv_string_t *nvp_name;
1544e307eb94SToomas Soome 
1545e307eb94SToomas Soome 		nvp_name = (nv_string_t *)(nvh + 1);
1546e307eb94SToomas Soome 		if (nvp_name->nv_size == strlen(name) &&
1547e307eb94SToomas Soome 		    memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0)
1548e307eb94SToomas Soome 			break;
1549e307eb94SToomas Soome 	}
1550e307eb94SToomas Soome 	return (nvh);
1551e307eb94SToomas Soome }
1552e307eb94SToomas Soome 
1553e307eb94SToomas Soome void
1554e307eb94SToomas Soome nvpair_print(nvp_header_t *nvp, unsigned int indent)
1555e307eb94SToomas Soome {
15563830659eSToomas Soome 	nv_string_t *nvp_name;
15573830659eSToomas Soome 	nv_pair_data_t *nvp_data;
15583830659eSToomas Soome 	nvlist_t nvlist;
15599de6a13eSToomas Soome 	unsigned i, j;
15609de6a13eSToomas Soome 	xdr_t xdr = {
15619de6a13eSToomas Soome 		.xdr_op = XDR_OP_DECODE,
15629de6a13eSToomas Soome 		.xdr_getint = _getint_mem,
15639de6a13eSToomas Soome 		.xdr_getuint = _getuint_mem,
15649de6a13eSToomas Soome 		.xdr_buf = (const uint8_t *)nvp,
15659de6a13eSToomas Soome 		.xdr_idx = NULL,
15669de6a13eSToomas Soome 		.xdr_buf_size = nvp->encoded_size
15679de6a13eSToomas Soome 	};
15683830659eSToomas Soome 
15693830659eSToomas Soome 	nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp));
15703830659eSToomas Soome 	nvp_data = (nv_pair_data_t *)
1571e307eb94SToomas Soome 	    NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size);
15723830659eSToomas Soome 
1573e307eb94SToomas Soome 	for (i = 0; i < indent; i++)
15743830659eSToomas Soome 		printf(" ");
15753830659eSToomas Soome 
15763830659eSToomas Soome 	printf("%s [%d] %.*s", typenames[nvp_data->nv_type],
15773830659eSToomas Soome 	    nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data);
15783830659eSToomas Soome 
15799de6a13eSToomas Soome 	xdr.xdr_idx = nvp_data->nv_data;
15803830659eSToomas Soome 	switch (nvp_data->nv_type) {
1581e307eb94SToomas Soome 	case DATA_TYPE_BYTE:
1582e307eb94SToomas Soome 	case DATA_TYPE_INT8:
15839de6a13eSToomas Soome 	case DATA_TYPE_UINT8: {
15849de6a13eSToomas Soome 		char c;
15859de6a13eSToomas Soome 
15869de6a13eSToomas Soome 		if (xdr_char(&xdr, &c))
15879de6a13eSToomas Soome 			printf(" = 0x%x\n", c);
15883830659eSToomas Soome 		break;
15899de6a13eSToomas Soome 	}
15903830659eSToomas Soome 
1591e307eb94SToomas Soome 	case DATA_TYPE_INT16:
15929de6a13eSToomas Soome 	case DATA_TYPE_UINT16: {
15939de6a13eSToomas Soome 		unsigned short u;
15949de6a13eSToomas Soome 
15959de6a13eSToomas Soome 		if (xdr_u_short(&xdr, &u))
15969de6a13eSToomas Soome 			printf(" = 0x%hx\n", u);
1597e307eb94SToomas Soome 		break;
15989de6a13eSToomas Soome 	}
1599e307eb94SToomas Soome 
1600e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
1601e307eb94SToomas Soome 	case DATA_TYPE_INT32:
16029de6a13eSToomas Soome 	case DATA_TYPE_UINT32: {
16039de6a13eSToomas Soome 		unsigned u;
16049de6a13eSToomas Soome 
16059de6a13eSToomas Soome 		if (xdr_u_int(&xdr, &u))
1606e307eb94SToomas Soome 			printf(" = 0x%x\n", u);
1607e307eb94SToomas Soome 		break;
16089de6a13eSToomas Soome 	}
1609e307eb94SToomas Soome 
1610e307eb94SToomas Soome 	case DATA_TYPE_INT64:
16119de6a13eSToomas Soome 	case DATA_TYPE_UINT64: {
16129de6a13eSToomas Soome 		uint64_t u;
16139de6a13eSToomas Soome 
16149de6a13eSToomas Soome 		if (xdr_uint64(&xdr, &u))
16159de6a13eSToomas Soome 			printf(" = 0x%jx\n", (uintmax_t)u);
1616e307eb94SToomas Soome 		break;
16179de6a13eSToomas Soome 	}
16189de6a13eSToomas Soome 
16199de6a13eSToomas Soome 	case DATA_TYPE_INT64_ARRAY:
16209de6a13eSToomas Soome 	case DATA_TYPE_UINT64_ARRAY: {
16219de6a13eSToomas Soome 		uint64_t *u;
16229de6a13eSToomas Soome 
16239de6a13eSToomas Soome 		if (xdr_array(&xdr, nvp_data->nv_nelem,
16249de6a13eSToomas Soome 		    (xdrproc_t)xdr_uint64)) {
16259de6a13eSToomas Soome 			u = (uint64_t *)(nvp_data->nv_data + sizeof(unsigned));
16269de6a13eSToomas Soome 			for (i = 0; i < nvp_data->nv_nelem; i++)
16279de6a13eSToomas Soome 				printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]);
16289de6a13eSToomas Soome 			printf("\n");
16299de6a13eSToomas Soome 		}
16309de6a13eSToomas Soome 
16319de6a13eSToomas Soome 		break;
16329de6a13eSToomas Soome 	}
1633e307eb94SToomas Soome 
1634e307eb94SToomas Soome 	case DATA_TYPE_STRING:
1635e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
16363830659eSToomas Soome 		nvp_name = (nv_string_t *)&nvp_data->nv_data[0];
1637e307eb94SToomas Soome 		for (i = 0; i < nvp_data->nv_nelem; i++) {
16383830659eSToomas Soome 			printf(" = \"%.*s\"\n", nvp_name->nv_size,
16393830659eSToomas Soome 			    nvp_name->nv_data);
16403830659eSToomas Soome 		}
1641e307eb94SToomas Soome 		break;
16423830659eSToomas Soome 
16433830659eSToomas Soome 	case DATA_TYPE_NVLIST:
16443830659eSToomas Soome 		printf("\n");
16453830659eSToomas Soome 		nvlist.nv_data = &nvp_data->nv_data[0];
16463830659eSToomas Soome 		nvlist_print(&nvlist, indent + 2);
16473830659eSToomas Soome 		break;
16483830659eSToomas Soome 
16493830659eSToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
16503830659eSToomas Soome 		nvlist.nv_data = &nvp_data->nv_data[0];
16513830659eSToomas Soome 		for (j = 0; j < nvp_data->nv_nelem; j++) {
1652e307eb94SToomas Soome 			size_t size;
1653e307eb94SToomas Soome 
16543830659eSToomas Soome 			printf("[%d]\n", j);
16553830659eSToomas Soome 			nvlist_print(&nvlist, indent + 2);
16563830659eSToomas Soome 			if (j != nvp_data->nv_nelem - 1) {
16573830659eSToomas Soome 				for (i = 0; i < indent; i++)
16583830659eSToomas Soome 					printf(" ");
16593830659eSToomas Soome 				printf("%s %.*s",
16603830659eSToomas Soome 				    typenames[nvp_data->nv_type],
16613830659eSToomas Soome 				    nvp_name->nv_size,
16623830659eSToomas Soome 				    nvp_name->nv_data);
16633830659eSToomas Soome 			}
1664e307eb94SToomas Soome 			xdr.xdr_idx = nvlist.nv_data;
1665e307eb94SToomas Soome 			xdr.xdr_buf = xdr.xdr_idx;
1666e307eb94SToomas Soome 			xdr.xdr_buf_size = nvp->encoded_size -
1667e307eb94SToomas Soome 			    (xdr.xdr_idx - (uint8_t *)nvp);
1668e307eb94SToomas Soome 
1669e307eb94SToomas Soome 			if (!nvlist_size_native(&xdr, &size))
1670e307eb94SToomas Soome 				return;
1671e307eb94SToomas Soome 
1672e307eb94SToomas Soome 			nvlist.nv_data += size;
16733830659eSToomas Soome 		}
16743830659eSToomas Soome 		break;
16753830659eSToomas Soome 
16763830659eSToomas Soome 	default:
16773830659eSToomas Soome 		printf("\n");
16783830659eSToomas Soome 	}
1679e307eb94SToomas Soome }
1680e307eb94SToomas Soome 
1681e307eb94SToomas Soome void
1682e307eb94SToomas Soome nvlist_print(const nvlist_t *nvl, unsigned int indent)
1683e307eb94SToomas Soome {
1684e307eb94SToomas Soome 	nvs_data_t *data;
1685e307eb94SToomas Soome 	nvp_header_t *nvp;
1686e307eb94SToomas Soome 
1687e307eb94SToomas Soome 	data = (nvs_data_t *)nvl->nv_data;
1688e307eb94SToomas Soome 	nvp = &data->nvl_pair;  /* first pair in nvlist */
1689e307eb94SToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
1690e307eb94SToomas Soome 		nvpair_print(nvp, indent);
16913830659eSToomas Soome 		nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
16923830659eSToomas Soome 	}
16933830659eSToomas Soome 	printf("%*s\n", indent + 13, "End of nvlist");
16943830659eSToomas Soome }
1695