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