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