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