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