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