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
41enum xdr_op {
42	XDR_OP_ENCODE = 1,
43	XDR_OP_DECODE = 2
44};
45
46typedef 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
57static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *);
58static bool nvlist_size_xdr(xdr_t *, size_t *);
59static bool nvlist_size_native(xdr_t *, size_t *);
60static bool xdr_int(xdr_t *, int *);
61static bool xdr_u_int(xdr_t *, unsigned *);
62
63typedef bool (*xdrproc_t)(xdr_t *, void *);
64
65/* Basic primitives for XDR translation operations, getint and putint. */
66static int
67_getint(struct xdr *xdr, int *ip)
68{
69	*ip = be32dec(xdr->xdr_idx);
70	return (sizeof(int));
71}
72
73static 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
82static int
83_getuint(struct xdr *xdr, unsigned *ip)
84{
85	*ip = be32dec(xdr->xdr_idx);
86	return (sizeof(unsigned));
87}
88
89static 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
98static int
99_getint_mem(struct xdr *xdr, int *ip)
100{
101	*ip = *(int *)xdr->xdr_idx;
102	return (sizeof(int));
103}
104
105static 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
114static int
115_getuint_mem(struct xdr *xdr, unsigned *ip)
116{
117	*ip = *(unsigned *)xdr->xdr_idx;
118	return (sizeof(unsigned));
119}
120
121static 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 */
133static bool
134xdr_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
147static bool
148xdr_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 */
164static bool
165xdr_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 */
193static bool
194xdr_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
219static bool
220xdr_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
250static bool
251xdr_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
281static bool
282xdr_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
295static bool
296xdr_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
327static bool
328xdr_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 */
346void
347nvlist_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
357char *
358nvstring_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 */
374nvlist_t *
375nvlist_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
401static bool
402nvlist_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
535static int
536nvlist_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 */
586static bool
587nvlist_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
610nvp_header_t *
611nvlist_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 */
674static bool
675nvlist_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 */
712int
713nvlist_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 */
739nvlist_t *
740nvlist_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 */
797int
798nvlist_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
850static int
851clone_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 */
877static uint8_t *
878nvlist_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 */
895int
896nvlist_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);
976error:
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
985static int
986get_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
1067static int
1068get_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
1157static int
1158nvlist_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
1348int
1349nvlist_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
1355int
1356nvlist_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
1361int
1362nvlist_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
1367int
1368nvlist_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
1373int
1374nvlist_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
1379int
1380nvlist_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
1385int
1386nvlist_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
1391int
1392nvlist_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
1397int
1398nvlist_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
1403int
1404nvlist_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
1409int
1410nvlist_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
1415int
1416nvlist_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
1421int
1422nvlist_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
1427int
1428nvlist_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
1433int
1434nvlist_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
1439int
1440nvlist_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
1445int
1446nvlist_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
1452int
1453nvlist_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
1458int
1459nvlist_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
1465int
1466nvlist_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
1471int
1472nvlist_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
1478int
1479nvlist_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
1485int
1486nvlist_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
1491int
1492nvlist_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
1498static 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
1528int
1529nvpair_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
1540nvp_header_t *
1541nvpair_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
1557void
1558nvpair_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
1685void
1686nvlist_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