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