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