xref: /freebsd/stand/libsa/zfs/nvlist.c (revision 7c43148a)
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 
26e097436cSMark Johnston #include <sys/param.h>
273830659eSToomas Soome #include <sys/endian.h>
28e307eb94SToomas Soome #include <sys/stdint.h>
29e097436cSMark Johnston #ifdef _STANDALONE
30e097436cSMark Johnston #include <stand.h>
31e097436cSMark Johnston #else
32e097436cSMark Johnston #include <errno.h>
33e097436cSMark Johnston #include <stdbool.h>
34e097436cSMark Johnston #include <stdio.h>
35e097436cSMark Johnston #include <stdlib.h>
36e097436cSMark Johnston #include <string.h>
37e097436cSMark Johnston #endif
38e097436cSMark Johnston 
39e097436cSMark Johnston #include "nvlist.h"
403830659eSToomas Soome 
41e307eb94SToomas Soome enum xdr_op {
42e307eb94SToomas Soome 	XDR_OP_ENCODE = 1,
43e307eb94SToomas Soome 	XDR_OP_DECODE = 2
44e307eb94SToomas Soome };
45e307eb94SToomas Soome 
463830659eSToomas Soome typedef struct xdr {
47e307eb94SToomas Soome 	enum xdr_op xdr_op;
48e307eb94SToomas Soome 	int (*xdr_getint)(struct xdr *, int *);
49e307eb94SToomas Soome 	int (*xdr_putint)(struct xdr *, int);
50e307eb94SToomas Soome 	int (*xdr_getuint)(struct xdr *, unsigned *);
51e307eb94SToomas Soome 	int (*xdr_putuint)(struct xdr *, unsigned);
52e307eb94SToomas Soome 	const uint8_t *xdr_buf;
53e307eb94SToomas Soome 	uint8_t *xdr_idx;
54e307eb94SToomas Soome 	size_t xdr_buf_size;
553830659eSToomas Soome } xdr_t;
563830659eSToomas Soome 
57e307eb94SToomas Soome static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *);
58e307eb94SToomas Soome static bool nvlist_size_xdr(xdr_t *, size_t *);
59e307eb94SToomas Soome static bool nvlist_size_native(xdr_t *, size_t *);
60e307eb94SToomas Soome static bool xdr_int(xdr_t *, int *);
61e307eb94SToomas Soome static bool xdr_u_int(xdr_t *, unsigned *);
623830659eSToomas Soome 
632ae58414SToomas Soome typedef bool (*xdrproc_t)(xdr_t *, void *);
643830659eSToomas Soome 
65e307eb94SToomas Soome /* Basic primitives for XDR translation operations, getint and putint. */
663830659eSToomas Soome static int
_getint(struct xdr * xdr,int * ip)67e307eb94SToomas Soome _getint(struct xdr *xdr, int *ip)
683830659eSToomas Soome {
69e307eb94SToomas Soome 	*ip = be32dec(xdr->xdr_idx);
703830659eSToomas Soome 	return (sizeof(int));
713830659eSToomas Soome }
723830659eSToomas Soome 
733830659eSToomas Soome static int
_putint(struct xdr * xdr,int i)74e307eb94SToomas Soome _putint(struct xdr *xdr, int i)
753830659eSToomas Soome {
76e307eb94SToomas Soome 	int *ip = (int *)xdr->xdr_idx;
77e307eb94SToomas Soome 
78e307eb94SToomas Soome 	*ip = htobe32(i);
79e307eb94SToomas Soome 	return (sizeof(int));
80e307eb94SToomas Soome }
81e307eb94SToomas Soome 
82e307eb94SToomas Soome static int
_getuint(struct xdr * xdr,unsigned * ip)83e307eb94SToomas Soome _getuint(struct xdr *xdr, unsigned *ip)
84e307eb94SToomas Soome {
85e307eb94SToomas Soome 	*ip = be32dec(xdr->xdr_idx);
863830659eSToomas Soome 	return (sizeof(unsigned));
873830659eSToomas Soome }
883830659eSToomas Soome 
893830659eSToomas Soome static int
_putuint(struct xdr * xdr,unsigned i)90e307eb94SToomas Soome _putuint(struct xdr *xdr, unsigned i)
913830659eSToomas Soome {
92e307eb94SToomas Soome 	unsigned *up = (unsigned *)xdr->xdr_idx;
933830659eSToomas Soome 
94e307eb94SToomas Soome 	*up = htobe32(i);
95e307eb94SToomas Soome 	return (sizeof(int));
963830659eSToomas Soome }
973830659eSToomas Soome 
989de6a13eSToomas Soome static int
_getint_mem(struct xdr * xdr,int * ip)999de6a13eSToomas Soome _getint_mem(struct xdr *xdr, int *ip)
1009de6a13eSToomas Soome {
1019de6a13eSToomas Soome 	*ip = *(int *)xdr->xdr_idx;
1029de6a13eSToomas Soome 	return (sizeof(int));
1039de6a13eSToomas Soome }
1049de6a13eSToomas Soome 
1059de6a13eSToomas Soome static int
_putint_mem(struct xdr * xdr,int i)1069de6a13eSToomas Soome _putint_mem(struct xdr *xdr, int i)
1079de6a13eSToomas Soome {
1089de6a13eSToomas Soome 	int *ip = (int *)xdr->xdr_idx;
1099de6a13eSToomas Soome 
1109de6a13eSToomas Soome 	*ip = i;
1119de6a13eSToomas Soome 	return (sizeof(int));
1129de6a13eSToomas Soome }
1139de6a13eSToomas Soome 
1149de6a13eSToomas Soome static int
_getuint_mem(struct xdr * xdr,unsigned * ip)1159de6a13eSToomas Soome _getuint_mem(struct xdr *xdr, unsigned *ip)
1169de6a13eSToomas Soome {
1179de6a13eSToomas Soome 	*ip = *(unsigned *)xdr->xdr_idx;
1189de6a13eSToomas Soome 	return (sizeof(unsigned));
1199de6a13eSToomas Soome }
1209de6a13eSToomas Soome 
1219de6a13eSToomas Soome static int
_putuint_mem(struct xdr * xdr,unsigned i)1229de6a13eSToomas Soome _putuint_mem(struct xdr *xdr, unsigned i)
1239de6a13eSToomas Soome {
1249de6a13eSToomas Soome 	unsigned *up = (unsigned *)xdr->xdr_idx;
1259de6a13eSToomas Soome 
1269de6a13eSToomas Soome 	*up = i;
1279de6a13eSToomas Soome 	return (sizeof(int));
1289de6a13eSToomas Soome }
1299de6a13eSToomas Soome 
130e307eb94SToomas Soome /*
131e307eb94SToomas Soome  * XDR data translations.
132e307eb94SToomas Soome  */
133e307eb94SToomas Soome static bool
xdr_short(xdr_t * xdr,short * ip)134e307eb94SToomas Soome xdr_short(xdr_t *xdr, short *ip)
1353830659eSToomas Soome {
136e307eb94SToomas Soome 	int i;
137e307eb94SToomas Soome 	bool rv;
1383830659eSToomas Soome 
139e307eb94SToomas Soome 	i = *ip;
140e307eb94SToomas Soome 	if ((rv = xdr_int(xdr, &i))) {
141e307eb94SToomas Soome 		if (xdr->xdr_op == XDR_OP_DECODE)
142e307eb94SToomas Soome 			*ip = i;
143e307eb94SToomas Soome 	}
1443830659eSToomas Soome 	return (rv);
1453830659eSToomas Soome }
1463830659eSToomas Soome 
147e307eb94SToomas Soome static bool
xdr_u_short(xdr_t * xdr,unsigned short * ip)148e307eb94SToomas Soome xdr_u_short(xdr_t *xdr, unsigned short *ip)
1493830659eSToomas Soome {
150e307eb94SToomas Soome 	unsigned u;
151e307eb94SToomas Soome 	bool rv;
1523830659eSToomas Soome 
153e307eb94SToomas Soome 	u = *ip;
154e307eb94SToomas Soome 	if ((rv = xdr_u_int(xdr, &u))) {
155e307eb94SToomas Soome 		if (xdr->xdr_op == XDR_OP_DECODE)
156e307eb94SToomas Soome 			*ip = u;
1573830659eSToomas Soome 	}
1583830659eSToomas Soome 	return (rv);
1593830659eSToomas Soome }
1603830659eSToomas Soome 
1613830659eSToomas Soome /*
162e307eb94SToomas Soome  * translate xdr->xdr_idx, increment it by size of int.
1633830659eSToomas Soome  */
164e307eb94SToomas Soome static bool
xdr_int(xdr_t * xdr,int * ip)165e307eb94SToomas Soome xdr_int(xdr_t *xdr, int *ip)
1663830659eSToomas Soome {
167e307eb94SToomas Soome 	bool rv = false;
168e307eb94SToomas Soome 	int *i = (int *)xdr->xdr_idx;
169e307eb94SToomas Soome 
170e307eb94SToomas Soome 	if (xdr->xdr_idx + sizeof(int) > xdr->xdr_buf + xdr->xdr_buf_size)
171e307eb94SToomas Soome 		return (rv);
172e307eb94SToomas Soome 
173e307eb94SToomas Soome 	switch (xdr->xdr_op) {
174e307eb94SToomas Soome 	case XDR_OP_ENCODE:
175e307eb94SToomas Soome 		/* Encode value *ip, store to buf */
176e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_putint(xdr, *ip);
177e307eb94SToomas Soome 		rv = true;
178e307eb94SToomas Soome 		break;
179e307eb94SToomas Soome 
180e307eb94SToomas Soome 	case XDR_OP_DECODE:
181e307eb94SToomas Soome 		/* Decode buf, return value to *ip */
182e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_getint(xdr, i);
183e307eb94SToomas Soome 		*ip = *i;
184e307eb94SToomas Soome 		rv = true;
185e307eb94SToomas Soome 		break;
186e307eb94SToomas Soome 	}
187e307eb94SToomas Soome 	return (rv);
1883830659eSToomas Soome }
1893830659eSToomas Soome 
190e307eb94SToomas Soome /*
191e307eb94SToomas Soome  * translate xdr->xdr_idx, increment it by size of unsigned int.
192e307eb94SToomas Soome  */
193e307eb94SToomas Soome static bool
xdr_u_int(xdr_t * xdr,unsigned * ip)194e307eb94SToomas Soome xdr_u_int(xdr_t *xdr, unsigned *ip)
195e307eb94SToomas Soome {
196e307eb94SToomas Soome 	bool rv = false;
197e307eb94SToomas Soome 	unsigned *u = (unsigned *)xdr->xdr_idx;
198e307eb94SToomas Soome 
199e307eb94SToomas Soome 	if (xdr->xdr_idx + sizeof(unsigned) > xdr->xdr_buf + xdr->xdr_buf_size)
200e307eb94SToomas Soome 		return (rv);
201e307eb94SToomas Soome 
202e307eb94SToomas Soome 	switch (xdr->xdr_op) {
203e307eb94SToomas Soome 	case XDR_OP_ENCODE:
204e307eb94SToomas Soome 		/* Encode value *ip, store to buf */
205e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip);
206e307eb94SToomas Soome 		rv = true;
207e307eb94SToomas Soome 		break;
208e307eb94SToomas Soome 
209e307eb94SToomas Soome 	case XDR_OP_DECODE:
210e307eb94SToomas Soome 		/* Decode buf, return value to *ip */
211e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_getuint(xdr, u);
212e307eb94SToomas Soome 		*ip = *u;
213e307eb94SToomas Soome 		rv = true;
214e307eb94SToomas Soome 		break;
215e307eb94SToomas Soome 	}
216e307eb94SToomas Soome 	return (rv);
217e307eb94SToomas Soome }
218e307eb94SToomas Soome 
219e307eb94SToomas Soome static bool
xdr_int64(xdr_t * xdr,int64_t * lp)220e307eb94SToomas Soome xdr_int64(xdr_t *xdr, int64_t *lp)
221e307eb94SToomas Soome {
222e307eb94SToomas Soome 	bool rv = false;
223e307eb94SToomas Soome 
224e307eb94SToomas Soome 	if (xdr->xdr_idx + sizeof(int64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
225e307eb94SToomas Soome 		return (rv);
226e307eb94SToomas Soome 
227e307eb94SToomas Soome 	switch (xdr->xdr_op) {
228e307eb94SToomas Soome 	case XDR_OP_ENCODE:
229e307eb94SToomas Soome 		/* Encode value *lp, store to buf */
2309de6a13eSToomas Soome 		if (xdr->xdr_putint == _putint)
2319de6a13eSToomas Soome 			*(int64_t *)xdr->xdr_idx = htobe64(*lp);
2329de6a13eSToomas Soome 		else
2339de6a13eSToomas Soome 			*(int64_t *)xdr->xdr_idx = *lp;
2349de6a13eSToomas Soome 		xdr->xdr_idx += sizeof(int64_t);
235e307eb94SToomas Soome 		rv = true;
236e307eb94SToomas Soome 		break;
237e307eb94SToomas Soome 
238e307eb94SToomas Soome 	case XDR_OP_DECODE:
239e307eb94SToomas Soome 		/* Decode buf, return value to *ip */
2409de6a13eSToomas Soome 		if (xdr->xdr_getint == _getint)
2419de6a13eSToomas Soome 			*lp = be64toh(*(int64_t *)xdr->xdr_idx);
2429de6a13eSToomas Soome 		else
2439de6a13eSToomas Soome 			*lp = *(int64_t *)xdr->xdr_idx;
2449de6a13eSToomas Soome 		xdr->xdr_idx += sizeof(int64_t);
245e307eb94SToomas Soome 		rv = true;
246e307eb94SToomas Soome 	}
247e307eb94SToomas Soome 	return (rv);
248e307eb94SToomas Soome }
249e307eb94SToomas Soome 
250e307eb94SToomas Soome static bool
xdr_uint64(xdr_t * xdr,uint64_t * lp)251e307eb94SToomas Soome xdr_uint64(xdr_t *xdr, uint64_t *lp)
252e307eb94SToomas Soome {
253e307eb94SToomas Soome 	bool rv = false;
254e307eb94SToomas Soome 
255e307eb94SToomas Soome 	if (xdr->xdr_idx + sizeof(uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
256e307eb94SToomas Soome 		return (rv);
257e307eb94SToomas Soome 
258e307eb94SToomas Soome 	switch (xdr->xdr_op) {
259e307eb94SToomas Soome 	case XDR_OP_ENCODE:
260e307eb94SToomas Soome 		/* Encode value *ip, store to buf */
2619de6a13eSToomas Soome 		if (xdr->xdr_putint == _putint)
2629de6a13eSToomas Soome 			*(uint64_t *)xdr->xdr_idx = htobe64(*lp);
2639de6a13eSToomas Soome 		else
2649de6a13eSToomas Soome 			*(uint64_t *)xdr->xdr_idx = *lp;
2659de6a13eSToomas Soome 		xdr->xdr_idx += sizeof(uint64_t);
266e307eb94SToomas Soome 		rv = true;
267e307eb94SToomas Soome 		break;
268e307eb94SToomas Soome 
269e307eb94SToomas Soome 	case XDR_OP_DECODE:
270e307eb94SToomas Soome 		/* Decode buf, return value to *ip */
2719de6a13eSToomas Soome 		if (xdr->xdr_getuint == _getuint)
2729de6a13eSToomas Soome 			*lp = be64toh(*(uint64_t *)xdr->xdr_idx);
2739de6a13eSToomas Soome 		else
2749de6a13eSToomas Soome 			*lp = *(uint64_t *)xdr->xdr_idx;
2759de6a13eSToomas Soome 		xdr->xdr_idx += sizeof(uint64_t);
276e307eb94SToomas Soome 		rv = true;
277e307eb94SToomas Soome 	}
278e307eb94SToomas Soome 	return (rv);
279e307eb94SToomas Soome }
280e307eb94SToomas Soome 
281e307eb94SToomas Soome static bool
xdr_char(xdr_t * xdr,char * cp)282e307eb94SToomas Soome xdr_char(xdr_t *xdr, char *cp)
283e307eb94SToomas Soome {
284e307eb94SToomas Soome 	int i;
285e307eb94SToomas Soome 	bool rv = false;
286e307eb94SToomas Soome 
287e307eb94SToomas Soome 	i = *cp;
288e307eb94SToomas Soome 	if ((rv = xdr_int(xdr, &i))) {
289e307eb94SToomas Soome 		if (xdr->xdr_op == XDR_OP_DECODE)
290e307eb94SToomas Soome 			*cp = i;
291e307eb94SToomas Soome 	}
292e307eb94SToomas Soome 	return (rv);
293e307eb94SToomas Soome }
294e307eb94SToomas Soome 
295e307eb94SToomas Soome static bool
xdr_string(xdr_t * xdr,nv_string_t * s)296e307eb94SToomas Soome xdr_string(xdr_t *xdr, nv_string_t *s)
297e307eb94SToomas Soome {
298e307eb94SToomas Soome 	int size = 0;
299e307eb94SToomas Soome 	bool rv = false;
300e307eb94SToomas Soome 
301e307eb94SToomas Soome 	switch (xdr->xdr_op) {
302e307eb94SToomas Soome 	case XDR_OP_ENCODE:
303e307eb94SToomas Soome 		size = s->nv_size;
304e307eb94SToomas Soome 		if (xdr->xdr_idx + sizeof(unsigned) + NV_ALIGN4(size) >
305e307eb94SToomas Soome 		    xdr->xdr_buf + xdr->xdr_buf_size)
306e307eb94SToomas Soome 			break;
307e307eb94SToomas Soome 		xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size);
308e307eb94SToomas Soome 		xdr->xdr_idx += NV_ALIGN4(size);
309e307eb94SToomas Soome 		rv = true;
310e307eb94SToomas Soome 		break;
311e307eb94SToomas Soome 
312e307eb94SToomas Soome 	case XDR_OP_DECODE:
313e307eb94SToomas Soome 		if (xdr->xdr_idx + sizeof(unsigned) >
314e307eb94SToomas Soome 		    xdr->xdr_buf + xdr->xdr_buf_size)
315e307eb94SToomas Soome 			break;
316e307eb94SToomas Soome 		size = xdr->xdr_getuint(xdr, &s->nv_size);
317e307eb94SToomas Soome 		size = NV_ALIGN4(size + s->nv_size);
318e307eb94SToomas Soome 		if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size)
319e307eb94SToomas Soome 			break;
320e307eb94SToomas Soome 		xdr->xdr_idx += size;
321e307eb94SToomas Soome 		rv = true;
322e307eb94SToomas Soome 		break;
323e307eb94SToomas Soome 	}
324e307eb94SToomas Soome 	return (rv);
325e307eb94SToomas Soome }
326e307eb94SToomas Soome 
327e307eb94SToomas Soome static bool
xdr_array(xdr_t * xdr,const unsigned nelem,const xdrproc_t elproc)328e307eb94SToomas Soome xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc)
329e307eb94SToomas Soome {
330e307eb94SToomas Soome 	bool rv = true;
3319de6a13eSToomas Soome 	unsigned c = nelem;
3329de6a13eSToomas Soome 
3339de6a13eSToomas Soome 	if (!xdr_u_int(xdr, &c))
3349de6a13eSToomas Soome 		return (false);
335e307eb94SToomas Soome 
336e307eb94SToomas Soome 	for (unsigned i = 0; i < nelem; i++) {
337e307eb94SToomas Soome 		if (!elproc(xdr, xdr->xdr_idx))
338e307eb94SToomas Soome 			return (false);
339e307eb94SToomas Soome 	}
340e307eb94SToomas Soome 	return (rv);
341e307eb94SToomas Soome }
342e307eb94SToomas Soome 
343e307eb94SToomas Soome /*
344e307eb94SToomas Soome  * nvlist management functions.
345e307eb94SToomas Soome  */
3463830659eSToomas Soome void
nvlist_destroy(nvlist_t * nvl)3473830659eSToomas Soome nvlist_destroy(nvlist_t *nvl)
3483830659eSToomas Soome {
3493830659eSToomas Soome 	if (nvl != NULL) {
3503830659eSToomas Soome 		/* Free data if it was allocated by us. */
3513830659eSToomas Soome 		if (nvl->nv_asize > 0)
3523830659eSToomas Soome 			free(nvl->nv_data);
3533830659eSToomas Soome 	}
3543830659eSToomas Soome 	free(nvl);
3553830659eSToomas Soome }
3563830659eSToomas Soome 
3573830659eSToomas Soome char *
nvstring_get(nv_string_t * nvs)3583830659eSToomas Soome nvstring_get(nv_string_t *nvs)
3593830659eSToomas Soome {
3603830659eSToomas Soome 	char *s;
3613830659eSToomas Soome 
3623830659eSToomas Soome 	s = malloc(nvs->nv_size + 1);
3633830659eSToomas Soome 	if (s != NULL) {
3643830659eSToomas Soome 		bcopy(nvs->nv_data, s, nvs->nv_size);
3653830659eSToomas Soome 		s[nvs->nv_size] = '\0';
3663830659eSToomas Soome 	}
3673830659eSToomas Soome 	return (s);
3683830659eSToomas Soome }
3693830659eSToomas Soome 
3703830659eSToomas Soome /*
3713830659eSToomas Soome  * Create empty nvlist.
3723830659eSToomas Soome  * The nvlist is terminated by 2x zeros (8 bytes).
3733830659eSToomas Soome  */
3743830659eSToomas Soome nvlist_t *
nvlist_create(int flag)3753830659eSToomas Soome nvlist_create(int flag)
3763830659eSToomas Soome {
3773830659eSToomas Soome 	nvlist_t *nvl;
3783830659eSToomas Soome 	nvs_data_t *nvs;
3793830659eSToomas Soome 
3803830659eSToomas Soome 	nvl = calloc(1, sizeof(*nvl));
3813830659eSToomas Soome 	if (nvl == NULL)
3823830659eSToomas Soome 		return (nvl);
3833830659eSToomas Soome 
3843830659eSToomas Soome 	nvl->nv_header.nvh_encoding = NV_ENCODE_XDR;
3853830659eSToomas Soome 	nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN;
3863830659eSToomas Soome 
3873830659eSToomas Soome 	nvl->nv_asize = nvl->nv_size = sizeof(*nvs);
3883830659eSToomas Soome 	nvs = calloc(1, nvl->nv_asize);
3893830659eSToomas Soome 	if (nvs == NULL) {
3903830659eSToomas Soome 		free(nvl);
3913830659eSToomas Soome 		return (NULL);
3923830659eSToomas Soome 	}
3933830659eSToomas Soome 	/* data in nvlist is byte stream */
3943830659eSToomas Soome 	nvl->nv_data = (uint8_t *)nvs;
3953830659eSToomas Soome 
3963830659eSToomas Soome 	nvs->nvl_version = NV_VERSION;
3973830659eSToomas Soome 	nvs->nvl_nvflag = flag;
3983830659eSToomas Soome 	return (nvl);
3993830659eSToomas Soome }
4003830659eSToomas Soome 
401e307eb94SToomas Soome static bool
nvlist_xdr_nvp(xdr_t * xdr,nvlist_t * nvl)402e307eb94SToomas Soome nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl)
4033830659eSToomas Soome {
4043830659eSToomas Soome 	nv_string_t *nv_string;
4053830659eSToomas Soome 	nv_pair_data_t *nvp_data;
4063830659eSToomas Soome 	nvlist_t nvlist;
407e307eb94SToomas Soome 	unsigned type, nelem;
408e307eb94SToomas Soome 	xdr_t nv_xdr;
4093830659eSToomas Soome 
410e307eb94SToomas Soome 	nv_string = (nv_string_t *)xdr->xdr_idx;
411e307eb94SToomas Soome 	if (!xdr_string(xdr, nv_string)) {
412e307eb94SToomas Soome 		return (false);
413e307eb94SToomas Soome 	}
414e307eb94SToomas Soome 	nvp_data = (nv_pair_data_t *)xdr->xdr_idx;
4153830659eSToomas Soome 
416e307eb94SToomas Soome 	type = nvp_data->nv_type;
417e307eb94SToomas Soome 	nelem = nvp_data->nv_nelem;
418e307eb94SToomas Soome 	if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem))
419e307eb94SToomas Soome 		return (false);
4203830659eSToomas Soome 
421e307eb94SToomas Soome 	switch (type) {
4223830659eSToomas Soome 	case DATA_TYPE_NVLIST:
4233830659eSToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
4243830659eSToomas Soome 		bzero(&nvlist, sizeof(nvlist));
425e307eb94SToomas Soome 		nvlist.nv_data = xdr->xdr_idx;
4263830659eSToomas Soome 		nvlist.nv_idx = nvlist.nv_data;
427e307eb94SToomas Soome 
428e307eb94SToomas Soome 		/* Set up xdr for this nvlist. */
429e307eb94SToomas Soome 		nv_xdr = *xdr;
430e307eb94SToomas Soome 		nv_xdr.xdr_buf = nvlist.nv_data;
431e307eb94SToomas Soome 		nv_xdr.xdr_idx = nvlist.nv_data;
432e307eb94SToomas Soome 		nv_xdr.xdr_buf_size =
433e307eb94SToomas Soome 		    nvl->nv_data + nvl->nv_size - nvlist.nv_data;
434e307eb94SToomas Soome 
435e307eb94SToomas Soome 		for (unsigned i = 0; i < nelem; i++) {
436e307eb94SToomas Soome 			if (xdr->xdr_op == XDR_OP_ENCODE) {
437e307eb94SToomas Soome 				if (!nvlist_size_native(&nv_xdr,
438e307eb94SToomas Soome 				    &nvlist.nv_size))
439e307eb94SToomas Soome 					return (false);
440e307eb94SToomas Soome 			} else {
441e307eb94SToomas Soome 				if (!nvlist_size_xdr(&nv_xdr,
442e307eb94SToomas Soome 				    &nvlist.nv_size))
443e307eb94SToomas Soome 					return (false);
444e307eb94SToomas Soome 			}
445e307eb94SToomas Soome 			if (nvlist_xdr_nvlist(xdr, &nvlist) != 0)
446e307eb94SToomas Soome 				return (false);
447e307eb94SToomas Soome 
448e307eb94SToomas Soome 			nvlist.nv_data = nv_xdr.xdr_idx;
449e307eb94SToomas Soome 			nvlist.nv_idx = nv_xdr.xdr_idx;
450e307eb94SToomas Soome 
451e307eb94SToomas Soome 			nv_xdr.xdr_buf = nv_xdr.xdr_idx;
452e307eb94SToomas Soome 			nv_xdr.xdr_buf_size =
453e307eb94SToomas Soome 			    nvl->nv_data + nvl->nv_size - nvlist.nv_data;
4543830659eSToomas Soome 		}
4553830659eSToomas Soome 		break;
4563830659eSToomas Soome 
4573830659eSToomas Soome 	case DATA_TYPE_BOOLEAN:
4583830659eSToomas Soome 		/* BOOLEAN does not take value space */
4593830659eSToomas Soome 		break;
4603830659eSToomas Soome 	case DATA_TYPE_BYTE:
4613830659eSToomas Soome 	case DATA_TYPE_INT8:
4623830659eSToomas Soome 	case DATA_TYPE_UINT8:
463e307eb94SToomas Soome 		if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0]))
464e307eb94SToomas Soome 			return (false);
4653830659eSToomas Soome 		break;
4663830659eSToomas Soome 
4673830659eSToomas Soome 	case DATA_TYPE_INT16:
468e307eb94SToomas Soome 		if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0]))
469e307eb94SToomas Soome 			return (false);
4703830659eSToomas Soome 		break;
4713830659eSToomas Soome 
4723830659eSToomas Soome 	case DATA_TYPE_UINT16:
473e307eb94SToomas Soome 		if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0]))
474e307eb94SToomas Soome 			return (false);
4753830659eSToomas Soome 		break;
4763830659eSToomas Soome 
4773830659eSToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
4783830659eSToomas Soome 	case DATA_TYPE_INT32:
479e307eb94SToomas Soome 		if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0]))
480e307eb94SToomas Soome 			return (false);
4813830659eSToomas Soome 		break;
4823830659eSToomas Soome 
4833830659eSToomas Soome 	case DATA_TYPE_UINT32:
484e307eb94SToomas Soome 		if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0]))
485e307eb94SToomas Soome 			return (false);
4863830659eSToomas Soome 		break;
4873830659eSToomas Soome 
488e307eb94SToomas Soome 	case DATA_TYPE_HRTIME:
4893830659eSToomas Soome 	case DATA_TYPE_INT64:
490e307eb94SToomas Soome 		if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0]))
491e307eb94SToomas Soome 			return (false);
4923830659eSToomas Soome 		break;
4933830659eSToomas Soome 
4943830659eSToomas Soome 	case DATA_TYPE_UINT64:
495e307eb94SToomas Soome 		if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0]))
496e307eb94SToomas Soome 			return (false);
4973830659eSToomas Soome 		break;
4983830659eSToomas Soome 
499e307eb94SToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
5003830659eSToomas Soome 	case DATA_TYPE_STRING:
5013830659eSToomas Soome 		nv_string = (nv_string_t *)&nvp_data->nv_data[0];
502e307eb94SToomas Soome 		if (!xdr_string(xdr, nv_string))
503e307eb94SToomas Soome 			return (false);
504e307eb94SToomas Soome 		break;
5053830659eSToomas Soome 
506e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
507e307eb94SToomas Soome 		nv_string = (nv_string_t *)&nvp_data->nv_data[0];
508e307eb94SToomas Soome 		for (unsigned i = 0; i < nelem; i++) {
509e307eb94SToomas Soome 			if (!xdr_string(xdr, nv_string))
510e307eb94SToomas Soome 				return (false);
511e307eb94SToomas Soome 			nv_string = (nv_string_t *)xdr->xdr_idx;
512e307eb94SToomas Soome 		}
513e307eb94SToomas Soome 		break;
514e307eb94SToomas Soome 
515e307eb94SToomas Soome 	case DATA_TYPE_INT8_ARRAY:
516e307eb94SToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
517e307eb94SToomas Soome 	case DATA_TYPE_INT16_ARRAY:
518e307eb94SToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
519e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
520e307eb94SToomas Soome 	case DATA_TYPE_INT32_ARRAY:
521e307eb94SToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
522e307eb94SToomas Soome 		if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int))
523e307eb94SToomas Soome 			return (false);
524e307eb94SToomas Soome 		break;
525e307eb94SToomas Soome 
526e307eb94SToomas Soome 	case DATA_TYPE_INT64_ARRAY:
527e307eb94SToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
528e307eb94SToomas Soome 		if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64))
529e307eb94SToomas Soome 			return (false);
5303830659eSToomas Soome 		break;
5313830659eSToomas Soome 	}
532e307eb94SToomas Soome 	return (true);
5333830659eSToomas Soome }
5343830659eSToomas Soome 
5353830659eSToomas Soome static int
nvlist_xdr_nvlist(xdr_t * xdr,nvlist_t * nvl)536e307eb94SToomas Soome nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl)
5373830659eSToomas Soome {
538e307eb94SToomas Soome 	nvp_header_t *nvph;
539e307eb94SToomas Soome 	nvs_data_t *nvs;
540e307eb94SToomas Soome 	unsigned encoded_size, decoded_size;
541e307eb94SToomas Soome 	int rv;
542e307eb94SToomas Soome 
543e307eb94SToomas Soome 	nvs = (nvs_data_t *)xdr->xdr_idx;
544e307eb94SToomas Soome 	nvph = &nvs->nvl_pair;
545e307eb94SToomas Soome 
546e307eb94SToomas Soome 	if (!xdr_u_int(xdr, &nvs->nvl_version))
547e307eb94SToomas Soome 		return (EINVAL);
548e307eb94SToomas Soome 	if (!xdr_u_int(xdr, &nvs->nvl_nvflag))
549e307eb94SToomas Soome 		return (EINVAL);
550e307eb94SToomas Soome 
551e307eb94SToomas Soome 	encoded_size = nvph->encoded_size;
552e307eb94SToomas Soome 	decoded_size = nvph->decoded_size;
553e307eb94SToomas Soome 
554e307eb94SToomas Soome 	if (xdr->xdr_op == XDR_OP_ENCODE) {
555e307eb94SToomas Soome 		if (!xdr_u_int(xdr, &nvph->encoded_size))
556e307eb94SToomas Soome 			return (EINVAL);
557e307eb94SToomas Soome 		if (!xdr_u_int(xdr, &nvph->decoded_size))
558e307eb94SToomas Soome 			return (EINVAL);
559e307eb94SToomas Soome 	} else {
560e307eb94SToomas Soome 		xdr->xdr_idx += 2 * sizeof(unsigned);
561e307eb94SToomas Soome 	}
562e307eb94SToomas Soome 
563e307eb94SToomas Soome 	rv = 0;
564e307eb94SToomas Soome 	while (encoded_size && decoded_size) {
565e307eb94SToomas Soome 		if (!nvlist_xdr_nvp(xdr, nvl))
566e307eb94SToomas Soome 			return (EINVAL);
567e307eb94SToomas Soome 
568e307eb94SToomas Soome 		nvph = (nvp_header_t *)(xdr->xdr_idx);
569e307eb94SToomas Soome 		encoded_size = nvph->encoded_size;
570e307eb94SToomas Soome 		decoded_size = nvph->decoded_size;
571e307eb94SToomas Soome 		if (xdr->xdr_op == XDR_OP_ENCODE) {
572e307eb94SToomas Soome 			if (!xdr_u_int(xdr, &nvph->encoded_size))
573e307eb94SToomas Soome 				return (EINVAL);
574e307eb94SToomas Soome 			if (!xdr_u_int(xdr, &nvph->decoded_size))
575e307eb94SToomas Soome 				return (EINVAL);
576e307eb94SToomas Soome 		} else {
577e307eb94SToomas Soome 			xdr->xdr_idx += 2 * sizeof(unsigned);
578e307eb94SToomas Soome 		}
579e307eb94SToomas Soome 	}
580e307eb94SToomas Soome 	return (rv);
581e307eb94SToomas Soome }
582e307eb94SToomas Soome 
583e307eb94SToomas Soome /*
584e307eb94SToomas Soome  * Calculate nvlist size, translating encoded_size and decoded_size.
585e307eb94SToomas Soome  */
586e307eb94SToomas Soome static bool
nvlist_size_xdr(xdr_t * xdr,size_t * size)587e307eb94SToomas Soome nvlist_size_xdr(xdr_t *xdr, size_t *size)
588e307eb94SToomas Soome {
589e307eb94SToomas Soome 	uint8_t *pair;
5903830659eSToomas Soome 	unsigned encoded_size, decoded_size;
5913830659eSToomas Soome 
592e307eb94SToomas Soome 	xdr->xdr_idx += 2 * sizeof(unsigned);
5933830659eSToomas Soome 
594e307eb94SToomas Soome 	pair = xdr->xdr_idx;
595e307eb94SToomas Soome 	if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size))
596e307eb94SToomas Soome 		return (false);
597e307eb94SToomas Soome 
5983830659eSToomas Soome 	while (encoded_size && decoded_size) {
599e307eb94SToomas Soome 		xdr->xdr_idx = pair + encoded_size;
600e307eb94SToomas Soome 		pair = xdr->xdr_idx;
601e307eb94SToomas Soome 		if (!xdr_u_int(xdr, &encoded_size) ||
602e307eb94SToomas Soome 		    !xdr_u_int(xdr, &decoded_size))
603e307eb94SToomas Soome 			return (false);
6043830659eSToomas Soome 	}
605e307eb94SToomas Soome 	*size = xdr->xdr_idx - xdr->xdr_buf;
606e307eb94SToomas Soome 
607e307eb94SToomas Soome 	return (true);
608e307eb94SToomas Soome }
609e307eb94SToomas Soome 
610e307eb94SToomas Soome nvp_header_t *
nvlist_next_nvpair(nvlist_t * nvl,nvp_header_t * nvh)611e307eb94SToomas Soome nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh)
612e307eb94SToomas Soome {
613e307eb94SToomas Soome 	uint8_t *pair;
614e307eb94SToomas Soome 	unsigned encoded_size, decoded_size;
615e307eb94SToomas Soome 	xdr_t xdr;
616e307eb94SToomas Soome 
617e307eb94SToomas Soome 	if (nvl == NULL)
618e307eb94SToomas Soome 		return (NULL);
619e307eb94SToomas Soome 
620e307eb94SToomas Soome 	xdr.xdr_buf = nvl->nv_data;
621e307eb94SToomas Soome 	xdr.xdr_idx = nvl->nv_data;
622e307eb94SToomas Soome 	xdr.xdr_buf_size = nvl->nv_size;
623e307eb94SToomas Soome 
624e307eb94SToomas Soome 	xdr.xdr_idx += 2 * sizeof(unsigned);
625e307eb94SToomas Soome 
626e307eb94SToomas Soome 	/* Skip tp current pair */
627e307eb94SToomas Soome 	if (nvh != NULL) {
628e307eb94SToomas Soome 		xdr.xdr_idx = (uint8_t *)nvh;
629e307eb94SToomas Soome 	}
630e307eb94SToomas Soome 
631e307eb94SToomas Soome 	pair = xdr.xdr_idx;
632e307eb94SToomas Soome 	if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
633e307eb94SToomas Soome 		return (NULL);
634e307eb94SToomas Soome 
635e307eb94SToomas Soome 	encoded_size = *(unsigned *)xdr.xdr_idx;
636e307eb94SToomas Soome 	xdr.xdr_idx += sizeof(unsigned);
637e307eb94SToomas Soome 	if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
638e307eb94SToomas Soome 		return (NULL);
639e307eb94SToomas Soome 
640e307eb94SToomas Soome 	decoded_size = *(unsigned *)xdr.xdr_idx;
641e307eb94SToomas Soome 	xdr.xdr_idx += sizeof(unsigned);
642e307eb94SToomas Soome 	if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
643e307eb94SToomas Soome 		return (NULL);
644e307eb94SToomas Soome 
645e307eb94SToomas Soome 	while (encoded_size && decoded_size) {
646e307eb94SToomas Soome 		if (nvh == NULL)
647e307eb94SToomas Soome 			return ((nvp_header_t *)pair);
648e307eb94SToomas Soome 
649e307eb94SToomas Soome 		xdr.xdr_idx = pair + encoded_size;
650e307eb94SToomas Soome 		nvh = (nvp_header_t *)xdr.xdr_idx;
651e307eb94SToomas Soome 
652e307eb94SToomas Soome 		if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
653e307eb94SToomas Soome 			return (NULL);
654e307eb94SToomas Soome 
655e307eb94SToomas Soome 		encoded_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 		decoded_size = *(unsigned *)xdr.xdr_idx;
660e307eb94SToomas Soome 		xdr.xdr_idx += sizeof(unsigned);
661e307eb94SToomas Soome 		if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
662e307eb94SToomas Soome 			return (NULL);
663e307eb94SToomas Soome 
664e307eb94SToomas Soome 		if (encoded_size != 0 && decoded_size != 0) {
665e307eb94SToomas Soome 			return (nvh);
666e307eb94SToomas Soome 		}
667e307eb94SToomas Soome 	}
668e307eb94SToomas Soome 	return (NULL);
669e307eb94SToomas Soome }
670e307eb94SToomas Soome 
671e307eb94SToomas Soome /*
672e307eb94SToomas Soome  * Calculate nvlist size by walking in memory data.
673e307eb94SToomas Soome  */
674e307eb94SToomas Soome static bool
nvlist_size_native(xdr_t * xdr,size_t * size)675e307eb94SToomas Soome nvlist_size_native(xdr_t *xdr, size_t *size)
676e307eb94SToomas Soome {
677e307eb94SToomas Soome 	uint8_t *pair;
678e307eb94SToomas Soome 	unsigned encoded_size, decoded_size;
679e307eb94SToomas Soome 
680e307eb94SToomas Soome 	xdr->xdr_idx += 2 * sizeof(unsigned);
681e307eb94SToomas Soome 
682e307eb94SToomas Soome 	pair = xdr->xdr_idx;
683e307eb94SToomas Soome 	if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
684e307eb94SToomas Soome 		return (false);
685e307eb94SToomas Soome 
686e307eb94SToomas Soome 	encoded_size = *(unsigned *)xdr->xdr_idx;
687e307eb94SToomas Soome 	xdr->xdr_idx += sizeof(unsigned);
688e307eb94SToomas Soome 	if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
689e307eb94SToomas Soome 		return (false);
690e307eb94SToomas Soome 	decoded_size = *(unsigned *)xdr->xdr_idx;
691e307eb94SToomas Soome 	xdr->xdr_idx += sizeof(unsigned);
692e307eb94SToomas Soome 	while (encoded_size && decoded_size) {
693e307eb94SToomas Soome 		xdr->xdr_idx = pair + encoded_size;
694e307eb94SToomas Soome 		pair = xdr->xdr_idx;
695e307eb94SToomas Soome 		if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
696e307eb94SToomas Soome 			return (false);
697e307eb94SToomas Soome 		encoded_size = *(unsigned *)xdr->xdr_idx;
698e307eb94SToomas Soome 		xdr->xdr_idx += sizeof(unsigned);
699e307eb94SToomas Soome 		if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
700e307eb94SToomas Soome 			return (false);
701e307eb94SToomas Soome 		decoded_size = *(unsigned *)xdr->xdr_idx;
702e307eb94SToomas Soome 		xdr->xdr_idx += sizeof(unsigned);
703e307eb94SToomas Soome 	}
704e307eb94SToomas Soome 	*size = xdr->xdr_idx - xdr->xdr_buf;
705e307eb94SToomas Soome 
706e307eb94SToomas Soome 	return (true);
707e307eb94SToomas Soome }
708e307eb94SToomas Soome 
709e307eb94SToomas Soome /*
710e307eb94SToomas Soome  * Export nvlist to byte stream format.
711e307eb94SToomas Soome  */
712e307eb94SToomas Soome int
nvlist_export(nvlist_t * nvl)713e307eb94SToomas Soome nvlist_export(nvlist_t *nvl)
714e307eb94SToomas Soome {
715e307eb94SToomas Soome 	int rv;
716e307eb94SToomas Soome 	xdr_t xdr = {
717e307eb94SToomas Soome 		.xdr_op = XDR_OP_ENCODE,
718e307eb94SToomas Soome 		.xdr_putint = _putint,
719e307eb94SToomas Soome 		.xdr_putuint = _putuint,
720e307eb94SToomas Soome 		.xdr_buf = nvl->nv_data,
721e307eb94SToomas Soome 		.xdr_idx = nvl->nv_data,
722e307eb94SToomas Soome 		.xdr_buf_size = nvl->nv_size
723e307eb94SToomas Soome 	};
724e307eb94SToomas Soome 
725e307eb94SToomas Soome 	if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR)
726e307eb94SToomas Soome 		return (ENOTSUP);
727e307eb94SToomas Soome 
728e307eb94SToomas Soome 	nvl->nv_idx = nvl->nv_data;
729e307eb94SToomas Soome 	rv = nvlist_xdr_nvlist(&xdr, nvl);
730e307eb94SToomas Soome 
731e307eb94SToomas Soome 	return (rv);
7323830659eSToomas Soome }
7333830659eSToomas Soome 
7343830659eSToomas Soome /*
7353830659eSToomas Soome  * Import nvlist from byte stream.
7363830659eSToomas Soome  * Determine the stream size and allocate private copy.
7373830659eSToomas Soome  * Then translate the data.
7383830659eSToomas Soome  */
7393830659eSToomas Soome nvlist_t *
nvlist_import(const char * stream,size_t size)740e307eb94SToomas Soome nvlist_import(const char *stream, size_t size)
7413830659eSToomas Soome {
7423830659eSToomas Soome 	nvlist_t *nvl;
743e307eb94SToomas Soome 	xdr_t xdr = {
744e307eb94SToomas Soome 		.xdr_op = XDR_OP_DECODE,
745e307eb94SToomas Soome 		.xdr_getint = _getint,
746e307eb94SToomas Soome 		.xdr_getuint = _getuint
747e307eb94SToomas Soome 	};
7483830659eSToomas Soome 
749e307eb94SToomas Soome 	/* Check the nvlist head. */
750e307eb94SToomas Soome 	if (stream[0] != NV_ENCODE_XDR ||
751e307eb94SToomas Soome 	    (stream[1] != '\0' && stream[1] != '\1') ||
752e307eb94SToomas Soome 	    stream[2] != '\0' || stream[3] != '\0' ||
753e307eb94SToomas Soome 	    be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION ||
754e307eb94SToomas Soome 	    be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME)
7553830659eSToomas Soome 		return (NULL);
7563830659eSToomas Soome 
7573830659eSToomas Soome 	nvl = malloc(sizeof(*nvl));
7583830659eSToomas Soome 	if (nvl == NULL)
7593830659eSToomas Soome 		return (nvl);
7603830659eSToomas Soome 
761e307eb94SToomas Soome 	nvl->nv_header.nvh_encoding = stream[0];
762e307eb94SToomas Soome 	nvl->nv_header.nvh_endian = stream[1];
763e307eb94SToomas Soome 	nvl->nv_header.nvh_reserved1 = stream[2];
764e307eb94SToomas Soome 	nvl->nv_header.nvh_reserved2 = stream[3];
765e307eb94SToomas Soome 
766e307eb94SToomas Soome 	xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4;
767e307eb94SToomas Soome 	xdr.xdr_buf_size = size - 4;
768e307eb94SToomas Soome 
769e307eb94SToomas Soome 	if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) {
770e307eb94SToomas Soome 		free(nvl);
771e307eb94SToomas Soome 		return (NULL);
772e307eb94SToomas Soome 	}
773e307eb94SToomas Soome 	nvl->nv_size = nvl->nv_asize;
7743830659eSToomas Soome 	nvl->nv_data = malloc(nvl->nv_asize);
7753830659eSToomas Soome 	if (nvl->nv_data == NULL) {
7763830659eSToomas Soome 		free(nvl);
7773830659eSToomas Soome 		return (NULL);
7783830659eSToomas Soome 	}
7793830659eSToomas Soome 	nvl->nv_idx = nvl->nv_data;
780e307eb94SToomas Soome 	bcopy(stream + 4, nvl->nv_data, nvl->nv_asize);
7813830659eSToomas Soome 
782e307eb94SToomas Soome 	xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data;
783e307eb94SToomas Soome 	xdr.xdr_buf_size = nvl->nv_asize;
784e307eb94SToomas Soome 
785e307eb94SToomas Soome 	if (nvlist_xdr_nvlist(&xdr, nvl) != 0) {
786e307eb94SToomas Soome 		free(nvl->nv_data);
787e307eb94SToomas Soome 		free(nvl);
788e307eb94SToomas Soome 		nvl = NULL;
789e307eb94SToomas Soome 	}
790e307eb94SToomas Soome 
7913830659eSToomas Soome 	return (nvl);
7923830659eSToomas Soome }
7933830659eSToomas Soome 
7943830659eSToomas Soome /*
7953830659eSToomas Soome  * remove pair from this nvlist.
7963830659eSToomas Soome  */
7973830659eSToomas Soome int
nvlist_remove(nvlist_t * nvl,const char * name,data_type_t type)7983830659eSToomas Soome nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
7993830659eSToomas Soome {
8003830659eSToomas Soome 	uint8_t *head, *tail;
8013830659eSToomas Soome 	nvs_data_t *data;
8023830659eSToomas Soome 	nvp_header_t *nvp;
8033830659eSToomas Soome 	nv_string_t *nvp_name;
8043830659eSToomas Soome 	nv_pair_data_t *nvp_data;
8053830659eSToomas Soome 	size_t size;
806e307eb94SToomas Soome 	xdr_t xdr;
8073830659eSToomas Soome 
8083830659eSToomas Soome 	if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
8093830659eSToomas Soome 		return (EINVAL);
8103830659eSToomas Soome 
811e307eb94SToomas Soome 	/* Make sure the nvlist size is set correct */
812e307eb94SToomas Soome 	xdr.xdr_idx = nvl->nv_data;
813e307eb94SToomas Soome 	xdr.xdr_buf = xdr.xdr_idx;
814e307eb94SToomas Soome 	xdr.xdr_buf_size = nvl->nv_size;
815e307eb94SToomas Soome 	if (!nvlist_size_native(&xdr, &nvl->nv_size))
816e307eb94SToomas Soome 		return (EINVAL);
817e307eb94SToomas Soome 
818e307eb94SToomas Soome 	data = (nvs_data_t *)nvl->nv_data;
8193830659eSToomas Soome 	nvp = &data->nvl_pair;	/* first pair in nvlist */
8203830659eSToomas Soome 	head = (uint8_t *)nvp;
8213830659eSToomas Soome 
8223830659eSToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
823e307eb94SToomas Soome 		nvp_name = (nv_string_t *)(nvp + 1);
8243830659eSToomas Soome 
825e307eb94SToomas Soome 		nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] +
826e307eb94SToomas Soome 		    NV_ALIGN4(nvp_name->nv_size));
8273830659eSToomas Soome 
828e307eb94SToomas Soome 		if (strlen(name) == nvp_name->nv_size &&
829e307eb94SToomas Soome 		    memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
830e307eb94SToomas Soome 		    (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
8313830659eSToomas Soome 			/*
8323830659eSToomas Soome 			 * set tail to point to next nvpair and size
8333830659eSToomas Soome 			 * is the length of the tail.
8343830659eSToomas Soome 			 */
8353830659eSToomas Soome 			tail = head + nvp->encoded_size;
836e307eb94SToomas Soome 			size = nvl->nv_size - (tail - nvl->nv_data);
8373830659eSToomas Soome 
8383830659eSToomas Soome 			/* adjust the size of the nvlist. */
8393830659eSToomas Soome 			nvl->nv_size -= nvp->encoded_size;
8403830659eSToomas Soome 			bcopy(tail, head, size);
8413830659eSToomas Soome 			return (0);
8423830659eSToomas Soome 		}
8433830659eSToomas Soome 		/* Not our pair, skip to next. */
8443830659eSToomas Soome 		head = head + nvp->encoded_size;
8453830659eSToomas Soome 		nvp = (nvp_header_t *)head;
8463830659eSToomas Soome 	}
8473830659eSToomas Soome 	return (ENOENT);
8483830659eSToomas Soome }
8493830659eSToomas Soome 
850e307eb94SToomas Soome static int
clone_nvlist(const nvlist_t * nvl,const uint8_t * ptr,unsigned size,nvlist_t ** nvlist)851e307eb94SToomas Soome clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size,
852e307eb94SToomas Soome     nvlist_t **nvlist)
853e307eb94SToomas Soome {
854e307eb94SToomas Soome 	nvlist_t *nv;
855e307eb94SToomas Soome 
856e307eb94SToomas Soome 	nv = calloc(1, sizeof(*nv));
857e307eb94SToomas Soome 	if (nv == NULL)
858e307eb94SToomas Soome 		return (ENOMEM);
859e307eb94SToomas Soome 
860e307eb94SToomas Soome 	nv->nv_header = nvl->nv_header;
861e307eb94SToomas Soome 	nv->nv_asize = size;
862e307eb94SToomas Soome 	nv->nv_size = size;
863e307eb94SToomas Soome 	nv->nv_data = malloc(nv->nv_asize);
864e307eb94SToomas Soome 	if (nv->nv_data == NULL) {
865e307eb94SToomas Soome 		free(nv);
866e307eb94SToomas Soome 		return (ENOMEM);
867e307eb94SToomas Soome 	}
868e307eb94SToomas Soome 
869e307eb94SToomas Soome 	bcopy(ptr, nv->nv_data, nv->nv_asize);
870e307eb94SToomas Soome 	*nvlist = nv;
871e307eb94SToomas Soome 	return (0);
872e307eb94SToomas Soome }
873e307eb94SToomas Soome 
874e307eb94SToomas Soome /*
875e307eb94SToomas Soome  * Return the next nvlist in an nvlist array.
876e307eb94SToomas Soome  */
877e307eb94SToomas Soome static uint8_t *
nvlist_next(const uint8_t * ptr)878e307eb94SToomas Soome nvlist_next(const uint8_t *ptr)
879e307eb94SToomas Soome {
880e307eb94SToomas Soome 	nvs_data_t *data;
881e307eb94SToomas Soome 	nvp_header_t *nvp;
882e307eb94SToomas Soome 
883e307eb94SToomas Soome 	data = (nvs_data_t *)ptr;
884e307eb94SToomas Soome 	nvp = &data->nvl_pair;	/* first pair in nvlist */
885e307eb94SToomas Soome 
886e307eb94SToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
887e307eb94SToomas Soome 		nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
888e307eb94SToomas Soome 	}
889e307eb94SToomas Soome 	return ((uint8_t *)nvp + sizeof(*nvp));
890e307eb94SToomas Soome }
891e307eb94SToomas Soome 
892e307eb94SToomas Soome /*
893e307eb94SToomas Soome  * Note: nvlist and nvlist array must be freed by caller.
894e307eb94SToomas Soome  */
8953830659eSToomas Soome int
nvlist_find(const nvlist_t * nvl,const char * name,data_type_t type,int * elementsp,void * valuep,int * sizep)8963830659eSToomas Soome nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type,
8973830659eSToomas Soome     int *elementsp, void *valuep, int *sizep)
8983830659eSToomas Soome {
8993830659eSToomas Soome 	nvs_data_t *data;
9003830659eSToomas Soome 	nvp_header_t *nvp;
9013830659eSToomas Soome 	nv_string_t *nvp_name;
9023830659eSToomas Soome 	nv_pair_data_t *nvp_data;
903e307eb94SToomas Soome 	nvlist_t **nvlist, *nv;
904e307eb94SToomas Soome 	uint8_t *ptr;
905e307eb94SToomas Soome 	int rv;
9063830659eSToomas Soome 
9073830659eSToomas Soome 	if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
9083830659eSToomas Soome 		return (EINVAL);
9093830659eSToomas Soome 
9103830659eSToomas Soome 	data = (nvs_data_t *)nvl->nv_data;
9113830659eSToomas Soome 	nvp = &data->nvl_pair;	/* first pair in nvlist */
9123830659eSToomas Soome 
9133830659eSToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
9143830659eSToomas Soome 		nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp));
915e307eb94SToomas Soome 		if (nvl->nv_data + nvl->nv_size <
916e307eb94SToomas Soome 		    nvp_name->nv_data + nvp_name->nv_size)
917e307eb94SToomas Soome 			return (EIO);
9183830659eSToomas Soome 
9193830659eSToomas Soome 		nvp_data = (nv_pair_data_t *)
9203830659eSToomas Soome 		    NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
9213830659eSToomas Soome 		    nvp_name->nv_size);
9223830659eSToomas Soome 
923e307eb94SToomas Soome 		if (strlen(name) == nvp_name->nv_size &&
924e307eb94SToomas Soome 		    memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
925e307eb94SToomas Soome 		    (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
9263830659eSToomas Soome 			if (elementsp != NULL)
9273830659eSToomas Soome 				*elementsp = nvp_data->nv_nelem;
9283830659eSToomas Soome 			switch (nvp_data->nv_type) {
9293830659eSToomas Soome 			case DATA_TYPE_UINT64:
930e307eb94SToomas Soome 				bcopy(nvp_data->nv_data, valuep,
931e307eb94SToomas Soome 				    sizeof(uint64_t));
9323830659eSToomas Soome 				return (0);
9333830659eSToomas Soome 			case DATA_TYPE_STRING:
9343830659eSToomas Soome 				nvp_name = (nv_string_t *)nvp_data->nv_data;
9353830659eSToomas Soome 				if (sizep != NULL) {
9363830659eSToomas Soome 					*sizep = nvp_name->nv_size;
9373830659eSToomas Soome 				}
9383830659eSToomas Soome 				*(const uint8_t **)valuep =
9393830659eSToomas Soome 				    &nvp_name->nv_data[0];
9403830659eSToomas Soome 				return (0);
9413830659eSToomas Soome 			case DATA_TYPE_NVLIST:
942e307eb94SToomas Soome 				ptr = &nvp_data->nv_data[0];
943e307eb94SToomas Soome 				rv = clone_nvlist(nvl, ptr,
944e307eb94SToomas Soome 				    nvlist_next(ptr) - ptr, &nv);
945e307eb94SToomas Soome 				if (rv == 0) {
946e307eb94SToomas Soome 					*(nvlist_t **)valuep = nv;
9473830659eSToomas Soome 				}
948e307eb94SToomas Soome 				return (rv);
949e307eb94SToomas Soome 
950e307eb94SToomas Soome 			case DATA_TYPE_NVLIST_ARRAY:
951e307eb94SToomas Soome 				nvlist = calloc(nvp_data->nv_nelem,
952e307eb94SToomas Soome 				    sizeof(nvlist_t *));
953e307eb94SToomas Soome 				if (nvlist == NULL)
9543830659eSToomas Soome 					return (ENOMEM);
955e307eb94SToomas Soome 				ptr = &nvp_data->nv_data[0];
956e307eb94SToomas Soome 				rv = 0;
957e307eb94SToomas Soome 				for (unsigned i = 0; i < nvp_data->nv_nelem;
958e307eb94SToomas Soome 				    i++) {
959e307eb94SToomas Soome 					rv = clone_nvlist(nvl, ptr,
960e307eb94SToomas Soome 					    nvlist_next(ptr) - ptr, &nvlist[i]);
961e307eb94SToomas Soome 					if (rv != 0)
962e307eb94SToomas Soome 						goto error;
963e307eb94SToomas Soome 					ptr = nvlist_next(ptr);
964e307eb94SToomas Soome 				}
965e307eb94SToomas Soome 				*(nvlist_t ***)valuep = nvlist;
966e307eb94SToomas Soome 				return (rv);
9673830659eSToomas Soome 			}
9683830659eSToomas Soome 			return (EIO);
9693830659eSToomas Soome 		}
9703830659eSToomas Soome 		/* Not our pair, skip to next. */
9713830659eSToomas Soome 		nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
972e307eb94SToomas Soome 		if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp)
973e307eb94SToomas Soome 			return (EIO);
9743830659eSToomas Soome 	}
9753830659eSToomas Soome 	return (ENOENT);
976e307eb94SToomas Soome error:
977e307eb94SToomas Soome 	for (unsigned i = 0; i < nvp_data->nv_nelem; i++) {
978e307eb94SToomas Soome 		free(nvlist[i]->nv_data);
979e307eb94SToomas Soome 		free(nvlist[i]);
980e307eb94SToomas Soome 	}
981e307eb94SToomas Soome 	free(nvlist);
982e307eb94SToomas Soome 	return (rv);
9833830659eSToomas Soome }
9843830659eSToomas Soome 
985e307eb94SToomas Soome static int
get_value_size(data_type_t type,const void * data,uint32_t nelem)986e307eb94SToomas Soome get_value_size(data_type_t type, const void *data, uint32_t nelem)
9873830659eSToomas Soome {
988e307eb94SToomas Soome 	uint64_t value_sz = 0;
9893830659eSToomas Soome 
990e307eb94SToomas Soome 	switch (type) {
991e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN:
992e307eb94SToomas Soome 		value_sz = 0;
993e307eb94SToomas Soome 		break;
994e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
995e307eb94SToomas Soome 	case DATA_TYPE_BYTE:
996e307eb94SToomas Soome 	case DATA_TYPE_INT8:
997e307eb94SToomas Soome 	case DATA_TYPE_UINT8:
998e307eb94SToomas Soome 	case DATA_TYPE_INT16:
999e307eb94SToomas Soome 	case DATA_TYPE_UINT16:
1000e307eb94SToomas Soome 	case DATA_TYPE_INT32:
1001e307eb94SToomas Soome 	case DATA_TYPE_UINT32:
1002e307eb94SToomas Soome 		/* Our smallest data unit is 32-bit */
1003e307eb94SToomas Soome 		value_sz = sizeof(uint32_t);
1004e307eb94SToomas Soome 		break;
1005e307eb94SToomas Soome 	case DATA_TYPE_HRTIME:
1006e307eb94SToomas Soome 	case DATA_TYPE_INT64:
1007e307eb94SToomas Soome 		value_sz = sizeof(int64_t);
1008e307eb94SToomas Soome 		break;
1009e307eb94SToomas Soome 	case DATA_TYPE_UINT64:
1010e307eb94SToomas Soome 		value_sz = sizeof(uint64_t);
1011e307eb94SToomas Soome 		break;
1012e307eb94SToomas Soome 	case DATA_TYPE_STRING:
1013e307eb94SToomas Soome 		if (data == NULL)
1014e307eb94SToomas Soome 			value_sz = 0;
1015e307eb94SToomas Soome 		else
1016e307eb94SToomas Soome 			value_sz = strlen(data) + 1;
1017e307eb94SToomas Soome 		break;
1018e307eb94SToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
1019e307eb94SToomas Soome 		value_sz = nelem * sizeof(uint8_t);
1020e307eb94SToomas Soome 		break;
1021e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
1022e307eb94SToomas Soome 	case DATA_TYPE_INT8_ARRAY:
1023e307eb94SToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
1024e307eb94SToomas Soome 	case DATA_TYPE_INT16_ARRAY:
1025e307eb94SToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
1026e307eb94SToomas Soome 	case DATA_TYPE_INT32_ARRAY:
1027e307eb94SToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
1028e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(uint32_t);
1029e307eb94SToomas Soome 		break;
1030e307eb94SToomas Soome 	case DATA_TYPE_INT64_ARRAY:
1031e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(int64_t);
1032e307eb94SToomas Soome 		break;
1033e307eb94SToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
1034e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(uint64_t);
1035e307eb94SToomas Soome 		break;
1036e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1037e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(uint64_t);
1038e307eb94SToomas Soome 
1039e307eb94SToomas Soome 		if (data != NULL) {
1040e307eb94SToomas Soome 			char *const *strs = data;
1041e307eb94SToomas Soome 			uint32_t i;
1042e307eb94SToomas Soome 
1043e307eb94SToomas Soome 			for (i = 0; i < nelem; i++) {
1044e307eb94SToomas Soome 				if (strs[i] == NULL)
1045e307eb94SToomas Soome 					return (-1);
1046e307eb94SToomas Soome 				value_sz += strlen(strs[i]) + 1;
1047e307eb94SToomas Soome 			}
1048e307eb94SToomas Soome 		}
1049e307eb94SToomas Soome 		break;
1050e307eb94SToomas Soome 	case DATA_TYPE_NVLIST:
1051e307eb94SToomas Soome 		/*
1052e307eb94SToomas Soome 		 * The decoded size of nvlist is constant.
1053e307eb94SToomas Soome 		 */
1054e307eb94SToomas Soome 		value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1055e307eb94SToomas Soome 		break;
1056e307eb94SToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
1057e307eb94SToomas Soome 		value_sz = (uint64_t)nelem * sizeof(uint64_t) +
1058e307eb94SToomas Soome 		    (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1059e307eb94SToomas Soome 		break;
1060e307eb94SToomas Soome 	default:
1061e307eb94SToomas Soome 		return (-1);
1062e307eb94SToomas Soome 	}
1063e307eb94SToomas Soome 
1064e307eb94SToomas Soome 	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1065e307eb94SToomas Soome }
1066e307eb94SToomas Soome 
1067e307eb94SToomas Soome static int
get_nvp_data_size(data_type_t type,const void * data,uint32_t nelem)1068e307eb94SToomas Soome get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem)
1069e307eb94SToomas Soome {
1070e307eb94SToomas Soome 	uint64_t value_sz = 0;
1071e307eb94SToomas Soome 	xdr_t xdr;
1072e307eb94SToomas Soome 	size_t size;
1073e307eb94SToomas Soome 
1074e307eb94SToomas Soome 	switch (type) {
1075e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN:
1076e307eb94SToomas Soome 		value_sz = 0;
1077e307eb94SToomas Soome 		break;
1078e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
1079e307eb94SToomas Soome 	case DATA_TYPE_BYTE:
1080e307eb94SToomas Soome 	case DATA_TYPE_INT8:
1081e307eb94SToomas Soome 	case DATA_TYPE_UINT8:
1082e307eb94SToomas Soome 	case DATA_TYPE_INT16:
1083e307eb94SToomas Soome 	case DATA_TYPE_UINT16:
1084e307eb94SToomas Soome 	case DATA_TYPE_INT32:
1085e307eb94SToomas Soome 	case DATA_TYPE_UINT32:
1086e307eb94SToomas Soome 		/* Our smallest data unit is 32-bit */
1087e307eb94SToomas Soome 		value_sz = sizeof(uint32_t);
1088e307eb94SToomas Soome 		break;
1089e307eb94SToomas Soome 	case DATA_TYPE_HRTIME:
1090e307eb94SToomas Soome 	case DATA_TYPE_INT64:
1091e307eb94SToomas Soome 	case DATA_TYPE_UINT64:
1092e307eb94SToomas Soome 		value_sz = sizeof(uint64_t);
1093e307eb94SToomas Soome 		break;
1094e307eb94SToomas Soome 	case DATA_TYPE_STRING:
1095e307eb94SToomas Soome 		value_sz = 4 + NV_ALIGN4(strlen(data));
1096e307eb94SToomas Soome 		break;
1097e307eb94SToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
1098e307eb94SToomas Soome 		value_sz = NV_ALIGN4(nelem);
1099e307eb94SToomas Soome 		break;
1100e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
1101e307eb94SToomas Soome 	case DATA_TYPE_INT8_ARRAY:
1102e307eb94SToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
1103e307eb94SToomas Soome 	case DATA_TYPE_INT16_ARRAY:
1104e307eb94SToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
1105e307eb94SToomas Soome 	case DATA_TYPE_INT32_ARRAY:
1106e307eb94SToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
1107e307eb94SToomas Soome 		value_sz = 4 + (uint64_t)nelem * sizeof(uint32_t);
1108e307eb94SToomas Soome 		break;
1109e307eb94SToomas Soome 	case DATA_TYPE_INT64_ARRAY:
1110e307eb94SToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
1111e307eb94SToomas Soome 		value_sz = 4 + (uint64_t)nelem * sizeof(uint64_t);
1112e307eb94SToomas Soome 		break;
1113e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1114e307eb94SToomas Soome 		if (data != NULL) {
1115e307eb94SToomas Soome 			char *const *strs = data;
1116e307eb94SToomas Soome 			uint32_t i;
1117e307eb94SToomas Soome 
1118e307eb94SToomas Soome 			for (i = 0; i < nelem; i++) {
1119e307eb94SToomas Soome 				value_sz += 4 + NV_ALIGN4(strlen(strs[i]));
1120e307eb94SToomas Soome 			}
1121e307eb94SToomas Soome 		}
1122e307eb94SToomas Soome 		break;
1123e307eb94SToomas Soome 	case DATA_TYPE_NVLIST:
1124e307eb94SToomas Soome 		xdr.xdr_idx = ((nvlist_t *)data)->nv_data;
1125e307eb94SToomas Soome 		xdr.xdr_buf = xdr.xdr_idx;
1126e307eb94SToomas Soome 		xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size;
1127e307eb94SToomas Soome 
1128e307eb94SToomas Soome 		if (!nvlist_size_native(&xdr, &size))
1129e307eb94SToomas Soome 			return (-1);
1130e307eb94SToomas Soome 
1131e307eb94SToomas Soome 		value_sz = size;
1132e307eb94SToomas Soome 		break;
1133e307eb94SToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
1134e307eb94SToomas Soome 		value_sz = 0;
1135e307eb94SToomas Soome 		for (uint32_t i = 0; i < nelem; i++) {
1136e307eb94SToomas Soome 			xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1137e307eb94SToomas Soome 			xdr.xdr_buf = xdr.xdr_idx;
1138e307eb94SToomas Soome 			xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1139e307eb94SToomas Soome 
1140e307eb94SToomas Soome 			if (!nvlist_size_native(&xdr, &size))
1141e307eb94SToomas Soome 				return (-1);
1142e307eb94SToomas Soome 			value_sz += size;
1143e307eb94SToomas Soome 		}
1144e307eb94SToomas Soome 		break;
1145e307eb94SToomas Soome 	default:
1146e307eb94SToomas Soome 		return (-1);
1147e307eb94SToomas Soome 	}
1148e307eb94SToomas Soome 
1149e307eb94SToomas Soome 	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1150e307eb94SToomas Soome }
1151e307eb94SToomas Soome 
1152e307eb94SToomas Soome #define	NVPE_SIZE(name_len, data_len) \
1153e307eb94SToomas Soome 	(4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len)
1154e307eb94SToomas Soome #define	NVP_SIZE(name_len, data_len) \
1155e307eb94SToomas Soome 	(NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len))
1156e307eb94SToomas Soome 
1157e307eb94SToomas Soome static int
nvlist_add_common(nvlist_t * nvl,const char * name,data_type_t type,uint32_t nelem,const void * data)1158e307eb94SToomas Soome nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1159e307eb94SToomas Soome     uint32_t nelem, const void *data)
1160e307eb94SToomas Soome {
1161e307eb94SToomas Soome 	nvs_data_t *nvs;
1162e307eb94SToomas Soome 	nvp_header_t head, *hp;
1163e307eb94SToomas Soome 	uint8_t *ptr;
1164e307eb94SToomas Soome 	size_t namelen;
1165e307eb94SToomas Soome 	int decoded_size, encoded_size;
11669de6a13eSToomas Soome 	xdr_t xdr = {
11679de6a13eSToomas Soome 		.xdr_op = XDR_OP_ENCODE,
11689de6a13eSToomas Soome 		.xdr_putint = _putint_mem,
11699de6a13eSToomas Soome 		.xdr_putuint = _putuint_mem,
11709de6a13eSToomas Soome 		.xdr_buf = nvl->nv_data,
11719de6a13eSToomas Soome 		.xdr_idx = nvl->nv_data,
11729de6a13eSToomas Soome 		.xdr_buf_size = nvl->nv_size
11739de6a13eSToomas Soome 	};
1174e307eb94SToomas Soome 
1175e307eb94SToomas Soome 	nvs = (nvs_data_t *)nvl->nv_data;
1176e307eb94SToomas Soome 	if (nvs->nvl_nvflag & NV_UNIQUE_NAME)
1177e307eb94SToomas Soome 		(void) nvlist_remove(nvl, name, type);
1178e307eb94SToomas Soome 
1179e307eb94SToomas Soome 	xdr.xdr_buf = nvl->nv_data;
1180e307eb94SToomas Soome 	xdr.xdr_idx = nvl->nv_data;
1181e307eb94SToomas Soome 	xdr.xdr_buf_size = nvl->nv_size;
1182e307eb94SToomas Soome 	if (!nvlist_size_native(&xdr, &nvl->nv_size))
11833830659eSToomas Soome 		return (EINVAL);
11843830659eSToomas Soome 
1185e307eb94SToomas Soome 	namelen = strlen(name);
1186e307eb94SToomas Soome 	if ((decoded_size = get_value_size(type, data, nelem)) < 0)
1187e307eb94SToomas Soome 		return (EINVAL);
1188e307eb94SToomas Soome 	if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0)
1189e307eb94SToomas Soome 		return (EINVAL);
11903830659eSToomas Soome 
1191e307eb94SToomas Soome 	/*
1192e307eb94SToomas Soome 	 * The encoded size is calculated as:
1193e307eb94SToomas Soome 	 * encode_size (4) + decode_size (4) +
1194e307eb94SToomas Soome 	 * name string size  (4 + NV_ALIGN4(namelen) +
1195e307eb94SToomas Soome 	 * data type (4) + nelem size (4) + datalen
1196e307eb94SToomas Soome 	 *
1197e307eb94SToomas Soome 	 * The decoded size is calculated as:
1198e307eb94SToomas Soome 	 * Note: namelen is with terminating 0.
1199e307eb94SToomas Soome 	 * NV_ALIGN(sizeof(nvpair_t) (4 * 4) + namelen + 1) +
1200e307eb94SToomas Soome 	 * NV_ALIGN(data_len)
1201e307eb94SToomas Soome 	 */
1202e307eb94SToomas Soome 
1203e307eb94SToomas Soome 	head.encoded_size = NVPE_SIZE(namelen, encoded_size);
1204e307eb94SToomas Soome 	head.decoded_size = NVP_SIZE(namelen + 1, decoded_size);
1205e307eb94SToomas Soome 
1206e307eb94SToomas Soome 	if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) {
1207e307eb94SToomas Soome 		ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size);
1208e307eb94SToomas Soome 		if (ptr == NULL)
1209e307eb94SToomas Soome 			return (ENOMEM);
1210e307eb94SToomas Soome 		nvl->nv_data = ptr;
1211e307eb94SToomas Soome 		nvl->nv_asize += head.encoded_size;
12123830659eSToomas Soome 	}
1213e307eb94SToomas Soome 	nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof(*hp);
1214e307eb94SToomas Soome 	bzero(nvl->nv_idx, head.encoded_size + 8);
1215e307eb94SToomas Soome 	hp = (nvp_header_t *)nvl->nv_idx;
1216e307eb94SToomas Soome 	*hp = head;
1217e307eb94SToomas Soome 	nvl->nv_idx += sizeof(*hp);
12189de6a13eSToomas Soome 
12199de6a13eSToomas Soome 	xdr.xdr_buf = nvl->nv_data;
1220bcc3148cSMark Johnston 	xdr.xdr_buf_size = nvl->nv_asize;
12219de6a13eSToomas Soome 	xdr.xdr_idx = nvl->nv_idx;
12229de6a13eSToomas Soome 
12239de6a13eSToomas Soome 	xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen);
12249de6a13eSToomas Soome 	strlcpy((char *)xdr.xdr_idx, name, namelen + 1);
12259de6a13eSToomas Soome 	xdr.xdr_idx += NV_ALIGN4(namelen);
12269de6a13eSToomas Soome 	xdr.xdr_idx += xdr.xdr_putuint(&xdr, type);
12279de6a13eSToomas Soome 	xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem);
1228e307eb94SToomas Soome 
1229e307eb94SToomas Soome 	switch (type) {
1230e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN:
1231e307eb94SToomas Soome 		break;
12329de6a13eSToomas Soome 
1233e307eb94SToomas Soome 	case DATA_TYPE_BYTE_ARRAY:
12349de6a13eSToomas Soome 		xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12359de6a13eSToomas Soome 		bcopy(data, xdr.xdr_idx, nelem);
12369de6a13eSToomas Soome 		xdr.xdr_idx += NV_ALIGN4(encoded_size);
1237e307eb94SToomas Soome 		break;
12389de6a13eSToomas Soome 
1239e307eb94SToomas Soome 	case DATA_TYPE_STRING:
1240e307eb94SToomas Soome 		encoded_size = strlen(data);
12419de6a13eSToomas Soome 		xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12429de6a13eSToomas Soome 		strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1);
12439de6a13eSToomas Soome 		xdr.xdr_idx += NV_ALIGN4(encoded_size);
1244e307eb94SToomas Soome 		break;
12459de6a13eSToomas Soome 
1246e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
1247e307eb94SToomas Soome 		for (uint32_t i = 0; i < nelem; i++) {
1248e307eb94SToomas Soome 			encoded_size = strlen(((char **)data)[i]);
12499de6a13eSToomas Soome 			xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
12509de6a13eSToomas Soome 			strlcpy((char *)xdr.xdr_idx, ((char **)data)[i],
1251e307eb94SToomas Soome 			    encoded_size + 1);
12529de6a13eSToomas Soome 			xdr.xdr_idx += NV_ALIGN4(encoded_size);
1253e307eb94SToomas Soome 		}
1254e307eb94SToomas Soome 		break;
12559de6a13eSToomas Soome 
1256e307eb94SToomas Soome 	case DATA_TYPE_BYTE:
1257e307eb94SToomas Soome 	case DATA_TYPE_INT8:
1258e307eb94SToomas Soome 	case DATA_TYPE_UINT8:
12599de6a13eSToomas Soome 		xdr_char(&xdr, (char *)data);
12609de6a13eSToomas Soome 		break;
12619de6a13eSToomas Soome 
1262e307eb94SToomas Soome 	case DATA_TYPE_INT8_ARRAY:
1263e307eb94SToomas Soome 	case DATA_TYPE_UINT8_ARRAY:
12649de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_char);
1265e307eb94SToomas Soome 		break;
12669de6a13eSToomas Soome 
1267e307eb94SToomas Soome 	case DATA_TYPE_INT16:
12689de6a13eSToomas Soome 		xdr_short(&xdr, (short *)data);
12699de6a13eSToomas Soome 		break;
12709de6a13eSToomas Soome 
1271e307eb94SToomas Soome 	case DATA_TYPE_UINT16:
12729de6a13eSToomas Soome 		xdr_u_short(&xdr, (unsigned short *)data);
12739de6a13eSToomas Soome 		break;
12749de6a13eSToomas Soome 
1275e307eb94SToomas Soome 	case DATA_TYPE_INT16_ARRAY:
12769de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_short);
12779de6a13eSToomas Soome 		break;
12789de6a13eSToomas Soome 
1279e307eb94SToomas Soome 	case DATA_TYPE_UINT16_ARRAY:
12809de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short);
1281e307eb94SToomas Soome 		break;
12829de6a13eSToomas Soome 
12839de6a13eSToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
12849de6a13eSToomas Soome 	case DATA_TYPE_INT32:
12859de6a13eSToomas Soome 		xdr_int(&xdr, (int *)data);
12869de6a13eSToomas Soome 		break;
12879de6a13eSToomas Soome 
12889de6a13eSToomas Soome 	case DATA_TYPE_UINT32:
12899de6a13eSToomas Soome 		xdr_u_int(&xdr, (unsigned int *)data);
12909de6a13eSToomas Soome 		break;
12919de6a13eSToomas Soome 
12929de6a13eSToomas Soome 	case DATA_TYPE_BOOLEAN_ARRAY:
12939de6a13eSToomas Soome 	case DATA_TYPE_INT32_ARRAY:
12949de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_int);
12959de6a13eSToomas Soome 		break;
12969de6a13eSToomas Soome 
12979de6a13eSToomas Soome 	case DATA_TYPE_UINT32_ARRAY:
12989de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int);
12999de6a13eSToomas Soome 		break;
13009de6a13eSToomas Soome 
13019de6a13eSToomas Soome 	case DATA_TYPE_INT64:
13029de6a13eSToomas Soome 		xdr_int64(&xdr, (int64_t *)data);
13039de6a13eSToomas Soome 		break;
13049de6a13eSToomas Soome 
13059de6a13eSToomas Soome 	case DATA_TYPE_UINT64:
13069de6a13eSToomas Soome 		xdr_uint64(&xdr, (uint64_t *)data);
13079de6a13eSToomas Soome 		break;
13089de6a13eSToomas Soome 
13099de6a13eSToomas Soome 	case DATA_TYPE_INT64_ARRAY:
13109de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64);
13119de6a13eSToomas Soome 		break;
13129de6a13eSToomas Soome 
13139de6a13eSToomas Soome 	case DATA_TYPE_UINT64_ARRAY:
13149de6a13eSToomas Soome 		xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64);
13159de6a13eSToomas Soome 		break;
13169de6a13eSToomas Soome 
1317e307eb94SToomas Soome 	case DATA_TYPE_NVLIST:
13189de6a13eSToomas Soome 		bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size);
1319e307eb94SToomas Soome 		break;
13209de6a13eSToomas Soome 
1321e307eb94SToomas Soome 	case DATA_TYPE_NVLIST_ARRAY: {
1322e307eb94SToomas Soome 		size_t size;
13239de6a13eSToomas Soome 		xdr_t xdr_nv;
1324e307eb94SToomas Soome 
1325e307eb94SToomas Soome 		for (uint32_t i = 0; i < nelem; i++) {
13269de6a13eSToomas Soome 			xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
13279de6a13eSToomas Soome 			xdr_nv.xdr_buf = xdr_nv.xdr_idx;
13289de6a13eSToomas Soome 			xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1329e307eb94SToomas Soome 
13309de6a13eSToomas Soome 			if (!nvlist_size_native(&xdr_nv, &size))
1331e307eb94SToomas Soome 				return (EINVAL);
1332e307eb94SToomas Soome 
13339de6a13eSToomas Soome 			bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx,
13349de6a13eSToomas Soome 			    size);
13359de6a13eSToomas Soome 			xdr.xdr_idx += size;
1336e307eb94SToomas Soome 		}
1337e307eb94SToomas Soome 		break;
1338e307eb94SToomas Soome 	}
1339e307eb94SToomas Soome 	default:
13409de6a13eSToomas Soome 		bcopy(data, xdr.xdr_idx, encoded_size);
1341e307eb94SToomas Soome 	}
1342e307eb94SToomas Soome 
1343e307eb94SToomas Soome 	nvl->nv_size += head.encoded_size;
1344e307eb94SToomas Soome 
13453830659eSToomas Soome 	return (0);
13463830659eSToomas Soome }
13473830659eSToomas Soome 
1348e307eb94SToomas Soome int
nvlist_add_boolean_value(nvlist_t * nvl,const char * name,int value)1349e097436cSMark Johnston nvlist_add_boolean_value(nvlist_t *nvl, const char *name, int value)
13503830659eSToomas Soome {
1351e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1,
1352e307eb94SToomas Soome 	    &value));
1353e307eb94SToomas Soome }
1354e307eb94SToomas Soome 
1355e307eb94SToomas Soome int
nvlist_add_byte(nvlist_t * nvl,const char * name,uint8_t value)1356e307eb94SToomas Soome nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value)
1357e307eb94SToomas Soome {
1358e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value));
1359e307eb94SToomas Soome }
1360e307eb94SToomas Soome 
1361e307eb94SToomas Soome int
nvlist_add_int8(nvlist_t * nvl,const char * name,int8_t value)1362e307eb94SToomas Soome nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value)
1363e307eb94SToomas Soome {
1364e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value));
1365e307eb94SToomas Soome }
1366e307eb94SToomas Soome 
1367e307eb94SToomas Soome int
nvlist_add_uint8(nvlist_t * nvl,const char * name,uint8_t value)1368e307eb94SToomas Soome nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value)
1369e307eb94SToomas Soome {
1370e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value));
1371e307eb94SToomas Soome }
1372e307eb94SToomas Soome 
1373e307eb94SToomas Soome int
nvlist_add_int16(nvlist_t * nvl,const char * name,int16_t value)1374e307eb94SToomas Soome nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value)
1375e307eb94SToomas Soome {
1376e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value));
1377e307eb94SToomas Soome }
1378e307eb94SToomas Soome 
1379e307eb94SToomas Soome int
nvlist_add_uint16(nvlist_t * nvl,const char * name,uint16_t value)1380e307eb94SToomas Soome nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value)
1381e307eb94SToomas Soome {
1382e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value));
1383e307eb94SToomas Soome }
1384e307eb94SToomas Soome 
1385e307eb94SToomas Soome int
nvlist_add_int32(nvlist_t * nvl,const char * name,int32_t value)1386e307eb94SToomas Soome nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value)
1387e307eb94SToomas Soome {
1388e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value));
1389e307eb94SToomas Soome }
1390e307eb94SToomas Soome 
1391e307eb94SToomas Soome int
nvlist_add_uint32(nvlist_t * nvl,const char * name,uint32_t value)1392e307eb94SToomas Soome nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value)
1393e307eb94SToomas Soome {
1394e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value));
1395e307eb94SToomas Soome }
1396e307eb94SToomas Soome 
1397e307eb94SToomas Soome int
nvlist_add_int64(nvlist_t * nvl,const char * name,int64_t value)1398e307eb94SToomas Soome nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value)
1399e307eb94SToomas Soome {
1400e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value));
1401e307eb94SToomas Soome }
1402e307eb94SToomas Soome 
1403e307eb94SToomas Soome int
nvlist_add_uint64(nvlist_t * nvl,const char * name,uint64_t value)1404e307eb94SToomas Soome nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value)
1405e307eb94SToomas Soome {
1406e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value));
1407e307eb94SToomas Soome }
1408e307eb94SToomas Soome 
1409e307eb94SToomas Soome int
nvlist_add_string(nvlist_t * nvl,const char * name,const char * value)1410e307eb94SToomas Soome nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1411e307eb94SToomas Soome {
1412e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value));
1413e307eb94SToomas Soome }
1414e307eb94SToomas Soome 
1415e307eb94SToomas Soome int
nvlist_add_boolean_array(nvlist_t * nvl,const char * name,int * a,uint32_t n)1416e097436cSMark Johnston nvlist_add_boolean_array(nvlist_t *nvl, const char *name, int *a, uint32_t n)
1417e307eb94SToomas Soome {
1418e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1419e307eb94SToomas Soome }
1420e307eb94SToomas Soome 
1421e307eb94SToomas Soome int
nvlist_add_byte_array(nvlist_t * nvl,const char * name,uint8_t * a,uint32_t n)1422e307eb94SToomas Soome nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1423e307eb94SToomas Soome {
1424e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1425e307eb94SToomas Soome }
1426e307eb94SToomas Soome 
1427e307eb94SToomas Soome int
nvlist_add_int8_array(nvlist_t * nvl,const char * name,int8_t * a,uint32_t n)1428e307eb94SToomas Soome nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n)
1429e307eb94SToomas Soome {
1430e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1431e307eb94SToomas Soome }
1432e307eb94SToomas Soome 
1433e307eb94SToomas Soome int
nvlist_add_uint8_array(nvlist_t * nvl,const char * name,uint8_t * a,uint32_t n)1434e307eb94SToomas Soome nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1435e307eb94SToomas Soome {
1436e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1437e307eb94SToomas Soome }
1438e307eb94SToomas Soome 
1439e307eb94SToomas Soome int
nvlist_add_int16_array(nvlist_t * nvl,const char * name,int16_t * a,uint32_t n)1440e307eb94SToomas Soome nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n)
1441e307eb94SToomas Soome {
1442e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1443e307eb94SToomas Soome }
1444e307eb94SToomas Soome 
1445e307eb94SToomas Soome int
nvlist_add_uint16_array(nvlist_t * nvl,const char * name,uint16_t * a,uint32_t n)1446e307eb94SToomas Soome nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a,
1447e307eb94SToomas Soome     uint32_t n)
1448e307eb94SToomas Soome {
1449e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1450e307eb94SToomas Soome }
1451e307eb94SToomas Soome 
1452e307eb94SToomas Soome int
nvlist_add_int32_array(nvlist_t * nvl,const char * name,int32_t * a,uint32_t n)1453e307eb94SToomas Soome nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n)
1454e307eb94SToomas Soome {
1455e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1456e307eb94SToomas Soome }
1457e307eb94SToomas Soome 
1458e307eb94SToomas Soome int
nvlist_add_uint32_array(nvlist_t * nvl,const char * name,uint32_t * a,uint32_t n)1459e307eb94SToomas Soome nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a,
1460e307eb94SToomas Soome     uint32_t n)
1461e307eb94SToomas Soome {
1462e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1463e307eb94SToomas Soome }
1464e307eb94SToomas Soome 
1465e307eb94SToomas Soome int
nvlist_add_int64_array(nvlist_t * nvl,const char * name,int64_t * a,uint32_t n)1466e307eb94SToomas Soome nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n)
1467e307eb94SToomas Soome {
1468e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1469e307eb94SToomas Soome }
1470e307eb94SToomas Soome 
1471e307eb94SToomas Soome int
nvlist_add_uint64_array(nvlist_t * nvl,const char * name,uint64_t * a,uint32_t n)1472e307eb94SToomas Soome nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a,
1473e307eb94SToomas Soome     uint32_t n)
1474e307eb94SToomas Soome {
1475e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1476e307eb94SToomas Soome }
1477e307eb94SToomas Soome 
1478e307eb94SToomas Soome int
nvlist_add_string_array(nvlist_t * nvl,const char * name,char * const * a,uint32_t n)1479e307eb94SToomas Soome nvlist_add_string_array(nvlist_t *nvl, const char *name,
1480e307eb94SToomas Soome     char * const *a, uint32_t n)
1481e307eb94SToomas Soome {
1482e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1483e307eb94SToomas Soome }
1484e307eb94SToomas Soome 
1485e307eb94SToomas Soome int
nvlist_add_nvlist(nvlist_t * nvl,const char * name,nvlist_t * val)1486e307eb94SToomas Soome nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
1487e307eb94SToomas Soome {
1488e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1489e307eb94SToomas Soome }
1490e307eb94SToomas Soome 
1491e307eb94SToomas Soome int
nvlist_add_nvlist_array(nvlist_t * nvl,const char * name,nvlist_t ** a,uint32_t n)1492e307eb94SToomas Soome nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a,
1493e307eb94SToomas Soome     uint32_t n)
1494e307eb94SToomas Soome {
1495e307eb94SToomas Soome 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1496e307eb94SToomas Soome }
1497e307eb94SToomas Soome 
14983830659eSToomas Soome static const char *typenames[] = {
14993830659eSToomas Soome 	"DATA_TYPE_UNKNOWN",
15003830659eSToomas Soome 	"DATA_TYPE_BOOLEAN",
15013830659eSToomas Soome 	"DATA_TYPE_BYTE",
15023830659eSToomas Soome 	"DATA_TYPE_INT16",
15033830659eSToomas Soome 	"DATA_TYPE_UINT16",
15043830659eSToomas Soome 	"DATA_TYPE_INT32",
15053830659eSToomas Soome 	"DATA_TYPE_UINT32",
15063830659eSToomas Soome 	"DATA_TYPE_INT64",
15073830659eSToomas Soome 	"DATA_TYPE_UINT64",
15083830659eSToomas Soome 	"DATA_TYPE_STRING",
15093830659eSToomas Soome 	"DATA_TYPE_BYTE_ARRAY",
15103830659eSToomas Soome 	"DATA_TYPE_INT16_ARRAY",
15113830659eSToomas Soome 	"DATA_TYPE_UINT16_ARRAY",
15123830659eSToomas Soome 	"DATA_TYPE_INT32_ARRAY",
15133830659eSToomas Soome 	"DATA_TYPE_UINT32_ARRAY",
15143830659eSToomas Soome 	"DATA_TYPE_INT64_ARRAY",
15153830659eSToomas Soome 	"DATA_TYPE_UINT64_ARRAY",
15163830659eSToomas Soome 	"DATA_TYPE_STRING_ARRAY",
15173830659eSToomas Soome 	"DATA_TYPE_HRTIME",
15183830659eSToomas Soome 	"DATA_TYPE_NVLIST",
15193830659eSToomas Soome 	"DATA_TYPE_NVLIST_ARRAY",
15203830659eSToomas Soome 	"DATA_TYPE_BOOLEAN_VALUE",
15213830659eSToomas Soome 	"DATA_TYPE_INT8",
15223830659eSToomas Soome 	"DATA_TYPE_UINT8",
15233830659eSToomas Soome 	"DATA_TYPE_BOOLEAN_ARRAY",
15243830659eSToomas Soome 	"DATA_TYPE_INT8_ARRAY",
15253830659eSToomas Soome 	"DATA_TYPE_UINT8_ARRAY"
15263830659eSToomas Soome };
1527e307eb94SToomas Soome 
1528e307eb94SToomas Soome int
nvpair_type_from_name(const char * name)1529e307eb94SToomas Soome nvpair_type_from_name(const char *name)
1530e307eb94SToomas Soome {
1531e307eb94SToomas Soome 	unsigned i;
1532e307eb94SToomas Soome 
1533e307eb94SToomas Soome 	for (i = 0; i < nitems(typenames); i++) {
1534e307eb94SToomas Soome 		if (strcmp(name, typenames[i]) == 0)
1535e307eb94SToomas Soome 			return (i);
1536e307eb94SToomas Soome 	}
1537e307eb94SToomas Soome 	return (0);
1538e307eb94SToomas Soome }
1539e307eb94SToomas Soome 
1540e307eb94SToomas Soome nvp_header_t *
nvpair_find(nvlist_t * nv,const char * name)1541e307eb94SToomas Soome nvpair_find(nvlist_t *nv, const char *name)
1542e307eb94SToomas Soome {
1543e307eb94SToomas Soome 	nvp_header_t *nvh;
1544e307eb94SToomas Soome 
1545e307eb94SToomas Soome 	nvh = NULL;
1546e307eb94SToomas Soome 	while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) {
1547e307eb94SToomas Soome 		nv_string_t *nvp_name;
1548e307eb94SToomas Soome 
1549e307eb94SToomas Soome 		nvp_name = (nv_string_t *)(nvh + 1);
1550e307eb94SToomas Soome 		if (nvp_name->nv_size == strlen(name) &&
1551e307eb94SToomas Soome 		    memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0)
1552e307eb94SToomas Soome 			break;
1553e307eb94SToomas Soome 	}
1554e307eb94SToomas Soome 	return (nvh);
1555e307eb94SToomas Soome }
1556e307eb94SToomas Soome 
1557e307eb94SToomas Soome void
nvpair_print(nvp_header_t * nvp,unsigned int indent)1558e307eb94SToomas Soome nvpair_print(nvp_header_t *nvp, unsigned int indent)
1559e307eb94SToomas Soome {
15603830659eSToomas Soome 	nv_string_t *nvp_name;
15613830659eSToomas Soome 	nv_pair_data_t *nvp_data;
15623830659eSToomas Soome 	nvlist_t nvlist;
15639de6a13eSToomas Soome 	unsigned i, j;
15649de6a13eSToomas Soome 	xdr_t xdr = {
15659de6a13eSToomas Soome 		.xdr_op = XDR_OP_DECODE,
15669de6a13eSToomas Soome 		.xdr_getint = _getint_mem,
15679de6a13eSToomas Soome 		.xdr_getuint = _getuint_mem,
15689de6a13eSToomas Soome 		.xdr_buf = (const uint8_t *)nvp,
15699de6a13eSToomas Soome 		.xdr_idx = NULL,
15709de6a13eSToomas Soome 		.xdr_buf_size = nvp->encoded_size
15719de6a13eSToomas Soome 	};
15723830659eSToomas Soome 
15733830659eSToomas Soome 	nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp));
15743830659eSToomas Soome 	nvp_data = (nv_pair_data_t *)
1575e307eb94SToomas Soome 	    NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size);
15763830659eSToomas Soome 
1577e307eb94SToomas Soome 	for (i = 0; i < indent; i++)
15783830659eSToomas Soome 		printf(" ");
15793830659eSToomas Soome 
15803830659eSToomas Soome 	printf("%s [%d] %.*s", typenames[nvp_data->nv_type],
15813830659eSToomas Soome 	    nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data);
15823830659eSToomas Soome 
15839de6a13eSToomas Soome 	xdr.xdr_idx = nvp_data->nv_data;
15843830659eSToomas Soome 	switch (nvp_data->nv_type) {
1585e307eb94SToomas Soome 	case DATA_TYPE_BYTE:
1586e307eb94SToomas Soome 	case DATA_TYPE_INT8:
15879de6a13eSToomas Soome 	case DATA_TYPE_UINT8: {
15889de6a13eSToomas Soome 		char c;
15899de6a13eSToomas Soome 
15909de6a13eSToomas Soome 		if (xdr_char(&xdr, &c))
15919de6a13eSToomas Soome 			printf(" = 0x%x\n", c);
15923830659eSToomas Soome 		break;
15939de6a13eSToomas Soome 	}
15943830659eSToomas Soome 
1595e307eb94SToomas Soome 	case DATA_TYPE_INT16:
15969de6a13eSToomas Soome 	case DATA_TYPE_UINT16: {
15979de6a13eSToomas Soome 		unsigned short u;
15989de6a13eSToomas Soome 
15999de6a13eSToomas Soome 		if (xdr_u_short(&xdr, &u))
16009de6a13eSToomas Soome 			printf(" = 0x%hx\n", u);
1601e307eb94SToomas Soome 		break;
16029de6a13eSToomas Soome 	}
1603e307eb94SToomas Soome 
1604e307eb94SToomas Soome 	case DATA_TYPE_BOOLEAN_VALUE:
1605e307eb94SToomas Soome 	case DATA_TYPE_INT32:
16069de6a13eSToomas Soome 	case DATA_TYPE_UINT32: {
16079de6a13eSToomas Soome 		unsigned u;
16089de6a13eSToomas Soome 
16099de6a13eSToomas Soome 		if (xdr_u_int(&xdr, &u))
1610e307eb94SToomas Soome 			printf(" = 0x%x\n", u);
1611e307eb94SToomas Soome 		break;
16129de6a13eSToomas Soome 	}
1613e307eb94SToomas Soome 
1614e307eb94SToomas Soome 	case DATA_TYPE_INT64:
16159de6a13eSToomas Soome 	case DATA_TYPE_UINT64: {
16169de6a13eSToomas Soome 		uint64_t u;
16179de6a13eSToomas Soome 
16189de6a13eSToomas Soome 		if (xdr_uint64(&xdr, &u))
16199de6a13eSToomas Soome 			printf(" = 0x%jx\n", (uintmax_t)u);
1620e307eb94SToomas Soome 		break;
16219de6a13eSToomas Soome 	}
16229de6a13eSToomas Soome 
16239de6a13eSToomas Soome 	case DATA_TYPE_INT64_ARRAY:
16249de6a13eSToomas Soome 	case DATA_TYPE_UINT64_ARRAY: {
16259de6a13eSToomas Soome 		uint64_t *u;
16269de6a13eSToomas Soome 
16279de6a13eSToomas Soome 		if (xdr_array(&xdr, nvp_data->nv_nelem,
16289de6a13eSToomas Soome 		    (xdrproc_t)xdr_uint64)) {
16299de6a13eSToomas Soome 			u = (uint64_t *)(nvp_data->nv_data + sizeof(unsigned));
16309de6a13eSToomas Soome 			for (i = 0; i < nvp_data->nv_nelem; i++)
16319de6a13eSToomas Soome 				printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]);
16329de6a13eSToomas Soome 			printf("\n");
16339de6a13eSToomas Soome 		}
16349de6a13eSToomas Soome 
16359de6a13eSToomas Soome 		break;
16369de6a13eSToomas Soome 	}
1637e307eb94SToomas Soome 
1638e307eb94SToomas Soome 	case DATA_TYPE_STRING:
1639e307eb94SToomas Soome 	case DATA_TYPE_STRING_ARRAY:
16403830659eSToomas Soome 		nvp_name = (nv_string_t *)&nvp_data->nv_data[0];
1641e307eb94SToomas Soome 		for (i = 0; i < nvp_data->nv_nelem; i++) {
16423830659eSToomas Soome 			printf(" = \"%.*s\"\n", nvp_name->nv_size,
16433830659eSToomas Soome 			    nvp_name->nv_data);
16443830659eSToomas Soome 		}
1645e307eb94SToomas Soome 		break;
16463830659eSToomas Soome 
16473830659eSToomas Soome 	case DATA_TYPE_NVLIST:
16483830659eSToomas Soome 		printf("\n");
16493830659eSToomas Soome 		nvlist.nv_data = &nvp_data->nv_data[0];
16503830659eSToomas Soome 		nvlist_print(&nvlist, indent + 2);
16513830659eSToomas Soome 		break;
16523830659eSToomas Soome 
16533830659eSToomas Soome 	case DATA_TYPE_NVLIST_ARRAY:
16543830659eSToomas Soome 		nvlist.nv_data = &nvp_data->nv_data[0];
16553830659eSToomas Soome 		for (j = 0; j < nvp_data->nv_nelem; j++) {
1656e307eb94SToomas Soome 			size_t size;
1657e307eb94SToomas Soome 
16583830659eSToomas Soome 			printf("[%d]\n", j);
16593830659eSToomas Soome 			nvlist_print(&nvlist, indent + 2);
16603830659eSToomas Soome 			if (j != nvp_data->nv_nelem - 1) {
16613830659eSToomas Soome 				for (i = 0; i < indent; i++)
16623830659eSToomas Soome 					printf(" ");
16633830659eSToomas Soome 				printf("%s %.*s",
16643830659eSToomas Soome 				    typenames[nvp_data->nv_type],
16653830659eSToomas Soome 				    nvp_name->nv_size,
16663830659eSToomas Soome 				    nvp_name->nv_data);
16673830659eSToomas Soome 			}
1668e307eb94SToomas Soome 			xdr.xdr_idx = nvlist.nv_data;
1669e307eb94SToomas Soome 			xdr.xdr_buf = xdr.xdr_idx;
1670e307eb94SToomas Soome 			xdr.xdr_buf_size = nvp->encoded_size -
1671e307eb94SToomas Soome 			    (xdr.xdr_idx - (uint8_t *)nvp);
1672e307eb94SToomas Soome 
1673e307eb94SToomas Soome 			if (!nvlist_size_native(&xdr, &size))
1674e307eb94SToomas Soome 				return;
1675e307eb94SToomas Soome 
1676e307eb94SToomas Soome 			nvlist.nv_data += size;
16773830659eSToomas Soome 		}
16783830659eSToomas Soome 		break;
16793830659eSToomas Soome 
16803830659eSToomas Soome 	default:
16813830659eSToomas Soome 		printf("\n");
16823830659eSToomas Soome 	}
1683e307eb94SToomas Soome }
1684e307eb94SToomas Soome 
1685e307eb94SToomas Soome void
nvlist_print(const nvlist_t * nvl,unsigned int indent)1686e307eb94SToomas Soome nvlist_print(const nvlist_t *nvl, unsigned int indent)
1687e307eb94SToomas Soome {
1688e307eb94SToomas Soome 	nvs_data_t *data;
1689e307eb94SToomas Soome 	nvp_header_t *nvp;
1690e307eb94SToomas Soome 
1691e307eb94SToomas Soome 	data = (nvs_data_t *)nvl->nv_data;
1692e307eb94SToomas Soome 	nvp = &data->nvl_pair;  /* first pair in nvlist */
1693e307eb94SToomas Soome 	while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
1694e307eb94SToomas Soome 		nvpair_print(nvp, indent);
16953830659eSToomas Soome 		nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
16963830659eSToomas Soome 	}
16973830659eSToomas Soome 	printf("%*s\n", indent + 13, "End of nvlist");
16983830659eSToomas Soome }
1699