2 * Copyright 2020 Toomas Soome <tsoome@me.com>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/endian.h>
31 #include <sys/stdint.h>
51 int (*xdr_getint)(struct xdr *, int *);
52 int (*xdr_putint)(struct xdr *, int);
53 int (*xdr_getuint)(struct xdr *, unsigned *);
54 int (*xdr_putuint)(struct xdr *, unsigned);
55 const uint8_t *xdr_buf;
60 static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *);
61 static bool nvlist_size_xdr(xdr_t *, size_t *);
62 static bool nvlist_size_native(xdr_t *, size_t *);
63 static bool xdr_int(xdr_t *, int *);
64 static bool xdr_u_int(xdr_t *, unsigned *);
66 typedef bool (*xdrproc_t)(xdr_t *, void *);
68 /* Basic primitives for XDR translation operations, getint and putint. */
70 _getint(struct xdr *xdr, int *ip)
72 *ip = be32dec(xdr->xdr_idx);
77 _putint(struct xdr *xdr, int i)
79 int *ip = (int *)xdr->xdr_idx;
86 _getuint(struct xdr *xdr, unsigned *ip)
88 *ip = be32dec(xdr->xdr_idx);
89 return (sizeof(unsigned));
93 _putuint(struct xdr *xdr, unsigned i)
95 unsigned *up = (unsigned *)xdr->xdr_idx;
102 _getint_mem(struct xdr *xdr, int *ip)
104 *ip = *(int *)xdr->xdr_idx;
105 return (sizeof(int));
109 _putint_mem(struct xdr *xdr, int i)
111 int *ip = (int *)xdr->xdr_idx;
114 return (sizeof(int));
118 _getuint_mem(struct xdr *xdr, unsigned *ip)
120 *ip = *(unsigned *)xdr->xdr_idx;
121 return (sizeof(unsigned));
125 _putuint_mem(struct xdr *xdr, unsigned i)
127 unsigned *up = (unsigned *)xdr->xdr_idx;
130 return (sizeof(int));
134 * XDR data translations.
137 xdr_short(xdr_t *xdr, short *ip)
143 if ((rv = xdr_int(xdr, &i))) {
144 if (xdr->xdr_op == XDR_OP_DECODE)
151 xdr_u_short(xdr_t *xdr, unsigned short *ip)
157 if ((rv = xdr_u_int(xdr, &u))) {
158 if (xdr->xdr_op == XDR_OP_DECODE)
165 * translate xdr->xdr_idx, increment it by size of int.
168 xdr_int(xdr_t *xdr, int *ip)
171 int *i = (int *)xdr->xdr_idx;
173 if (xdr->xdr_idx + sizeof(int) > xdr->xdr_buf + xdr->xdr_buf_size)
176 switch (xdr->xdr_op) {
178 /* Encode value *ip, store to buf */
179 xdr->xdr_idx += xdr->xdr_putint(xdr, *ip);
184 /* Decode buf, return value to *ip */
185 xdr->xdr_idx += xdr->xdr_getint(xdr, i);
194 * translate xdr->xdr_idx, increment it by size of unsigned int.
197 xdr_u_int(xdr_t *xdr, unsigned *ip)
200 unsigned *u = (unsigned *)xdr->xdr_idx;
202 if (xdr->xdr_idx + sizeof(unsigned) > xdr->xdr_buf + xdr->xdr_buf_size)
205 switch (xdr->xdr_op) {
207 /* Encode value *ip, store to buf */
208 xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip);
213 /* Decode buf, return value to *ip */
214 xdr->xdr_idx += xdr->xdr_getuint(xdr, u);
223 xdr_int64(xdr_t *xdr, int64_t *lp)
227 if (xdr->xdr_idx + sizeof(int64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
230 switch (xdr->xdr_op) {
232 /* Encode value *lp, store to buf */
233 if (xdr->xdr_putint == _putint)
234 *(int64_t *)xdr->xdr_idx = htobe64(*lp);
236 *(int64_t *)xdr->xdr_idx = *lp;
237 xdr->xdr_idx += sizeof(int64_t);
242 /* Decode buf, return value to *ip */
243 if (xdr->xdr_getint == _getint)
244 *lp = be64toh(*(int64_t *)xdr->xdr_idx);
246 *lp = *(int64_t *)xdr->xdr_idx;
247 xdr->xdr_idx += sizeof(int64_t);
254 xdr_uint64(xdr_t *xdr, uint64_t *lp)
258 if (xdr->xdr_idx + sizeof(uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
261 switch (xdr->xdr_op) {
263 /* Encode value *ip, store to buf */
264 if (xdr->xdr_putint == _putint)
265 *(uint64_t *)xdr->xdr_idx = htobe64(*lp);
267 *(uint64_t *)xdr->xdr_idx = *lp;
268 xdr->xdr_idx += sizeof(uint64_t);
273 /* Decode buf, return value to *ip */
274 if (xdr->xdr_getuint == _getuint)
275 *lp = be64toh(*(uint64_t *)xdr->xdr_idx);
277 *lp = *(uint64_t *)xdr->xdr_idx;
278 xdr->xdr_idx += sizeof(uint64_t);
285 xdr_char(xdr_t *xdr, char *cp)
291 if ((rv = xdr_int(xdr, &i))) {
292 if (xdr->xdr_op == XDR_OP_DECODE)
299 xdr_string(xdr_t *xdr, nv_string_t *s)
304 switch (xdr->xdr_op) {
307 if (xdr->xdr_idx + sizeof(unsigned) + NV_ALIGN4(size) >
308 xdr->xdr_buf + xdr->xdr_buf_size)
310 xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size);
311 xdr->xdr_idx += NV_ALIGN4(size);
316 if (xdr->xdr_idx + sizeof(unsigned) >
317 xdr->xdr_buf + xdr->xdr_buf_size)
319 size = xdr->xdr_getuint(xdr, &s->nv_size);
320 size = NV_ALIGN4(size + s->nv_size);
321 if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size)
323 xdr->xdr_idx += size;
331 xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc)
336 if (!xdr_u_int(xdr, &c))
339 for (unsigned i = 0; i < nelem; i++) {
340 if (!elproc(xdr, xdr->xdr_idx))
347 * nvlist management functions.
350 nvlist_destroy(nvlist_t *nvl)
353 /* Free data if it was allocated by us. */
354 if (nvl->nv_asize > 0)
361 nvstring_get(nv_string_t *nvs)
365 s = malloc(nvs->nv_size + 1);
367 bcopy(nvs->nv_data, s, nvs->nv_size);
368 s[nvs->nv_size] = '\0';
374 * Create empty nvlist.
375 * The nvlist is terminated by 2x zeros (8 bytes).
378 nvlist_create(int flag)
383 nvl = calloc(1, sizeof(*nvl));
387 nvl->nv_header.nvh_encoding = NV_ENCODE_XDR;
388 nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN;
390 nvl->nv_asize = nvl->nv_size = sizeof(*nvs);
391 nvs = calloc(1, nvl->nv_asize);
396 /* data in nvlist is byte stream */
397 nvl->nv_data = (uint8_t *)nvs;
399 nvs->nvl_version = NV_VERSION;
400 nvs->nvl_nvflag = flag;
405 nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl)
407 nv_string_t *nv_string;
408 nv_pair_data_t *nvp_data;
410 unsigned type, nelem;
413 nv_string = (nv_string_t *)xdr->xdr_idx;
414 if (!xdr_string(xdr, nv_string)) {
417 nvp_data = (nv_pair_data_t *)xdr->xdr_idx;
419 type = nvp_data->nv_type;
420 nelem = nvp_data->nv_nelem;
421 if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem))
425 case DATA_TYPE_NVLIST:
426 case DATA_TYPE_NVLIST_ARRAY:
427 bzero(&nvlist, sizeof(nvlist));
428 nvlist.nv_data = xdr->xdr_idx;
429 nvlist.nv_idx = nvlist.nv_data;
431 /* Set up xdr for this nvlist. */
433 nv_xdr.xdr_buf = nvlist.nv_data;
434 nv_xdr.xdr_idx = nvlist.nv_data;
435 nv_xdr.xdr_buf_size =
436 nvl->nv_data + nvl->nv_size - nvlist.nv_data;
438 for (unsigned i = 0; i < nelem; i++) {
439 if (xdr->xdr_op == XDR_OP_ENCODE) {
440 if (!nvlist_size_native(&nv_xdr,
444 if (!nvlist_size_xdr(&nv_xdr,
448 if (nvlist_xdr_nvlist(xdr, &nvlist) != 0)
451 nvlist.nv_data = nv_xdr.xdr_idx;
452 nvlist.nv_idx = nv_xdr.xdr_idx;
454 nv_xdr.xdr_buf = nv_xdr.xdr_idx;
455 nv_xdr.xdr_buf_size =
456 nvl->nv_data + nvl->nv_size - nvlist.nv_data;
460 case DATA_TYPE_BOOLEAN:
461 /* BOOLEAN does not take value space */
465 case DATA_TYPE_UINT8:
466 if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0]))
470 case DATA_TYPE_INT16:
471 if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0]))
475 case DATA_TYPE_UINT16:
476 if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0]))
480 case DATA_TYPE_BOOLEAN_VALUE:
481 case DATA_TYPE_INT32:
482 if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0]))
486 case DATA_TYPE_UINT32:
487 if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0]))
491 case DATA_TYPE_HRTIME:
492 case DATA_TYPE_INT64:
493 if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0]))
497 case DATA_TYPE_UINT64:
498 if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0]))
502 case DATA_TYPE_BYTE_ARRAY:
503 case DATA_TYPE_STRING:
504 nv_string = (nv_string_t *)&nvp_data->nv_data[0];
505 if (!xdr_string(xdr, nv_string))
509 case DATA_TYPE_STRING_ARRAY:
510 nv_string = (nv_string_t *)&nvp_data->nv_data[0];
511 for (unsigned i = 0; i < nelem; i++) {
512 if (!xdr_string(xdr, nv_string))
514 nv_string = (nv_string_t *)xdr->xdr_idx;
518 case DATA_TYPE_INT8_ARRAY:
519 case DATA_TYPE_UINT8_ARRAY:
520 case DATA_TYPE_INT16_ARRAY:
521 case DATA_TYPE_UINT16_ARRAY:
522 case DATA_TYPE_BOOLEAN_ARRAY:
523 case DATA_TYPE_INT32_ARRAY:
524 case DATA_TYPE_UINT32_ARRAY:
525 if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int))
529 case DATA_TYPE_INT64_ARRAY:
530 case DATA_TYPE_UINT64_ARRAY:
531 if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64))
539 nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl)
543 unsigned encoded_size, decoded_size;
546 nvs = (nvs_data_t *)xdr->xdr_idx;
547 nvph = &nvs->nvl_pair;
549 if (!xdr_u_int(xdr, &nvs->nvl_version))
551 if (!xdr_u_int(xdr, &nvs->nvl_nvflag))
554 encoded_size = nvph->encoded_size;
555 decoded_size = nvph->decoded_size;
557 if (xdr->xdr_op == XDR_OP_ENCODE) {
558 if (!xdr_u_int(xdr, &nvph->encoded_size))
560 if (!xdr_u_int(xdr, &nvph->decoded_size))
563 xdr->xdr_idx += 2 * sizeof(unsigned);
567 while (encoded_size && decoded_size) {
568 if (!nvlist_xdr_nvp(xdr, nvl))
571 nvph = (nvp_header_t *)(xdr->xdr_idx);
572 encoded_size = nvph->encoded_size;
573 decoded_size = nvph->decoded_size;
574 if (xdr->xdr_op == XDR_OP_ENCODE) {
575 if (!xdr_u_int(xdr, &nvph->encoded_size))
577 if (!xdr_u_int(xdr, &nvph->decoded_size))
580 xdr->xdr_idx += 2 * sizeof(unsigned);
587 * Calculate nvlist size, translating encoded_size and decoded_size.
590 nvlist_size_xdr(xdr_t *xdr, size_t *size)
593 unsigned encoded_size, decoded_size;
595 xdr->xdr_idx += 2 * sizeof(unsigned);
598 if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size))
601 while (encoded_size && decoded_size) {
602 xdr->xdr_idx = pair + encoded_size;
604 if (!xdr_u_int(xdr, &encoded_size) ||
605 !xdr_u_int(xdr, &decoded_size))
608 *size = xdr->xdr_idx - xdr->xdr_buf;
614 nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh)
617 unsigned encoded_size, decoded_size;
623 xdr.xdr_buf = nvl->nv_data;
624 xdr.xdr_idx = nvl->nv_data;
625 xdr.xdr_buf_size = nvl->nv_size;
627 xdr.xdr_idx += 2 * sizeof(unsigned);
629 /* Skip tp current pair */
631 xdr.xdr_idx = (uint8_t *)nvh;
635 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
638 encoded_size = *(unsigned *)xdr.xdr_idx;
639 xdr.xdr_idx += sizeof(unsigned);
640 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
643 decoded_size = *(unsigned *)xdr.xdr_idx;
644 xdr.xdr_idx += sizeof(unsigned);
645 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
648 while (encoded_size && decoded_size) {
650 return ((nvp_header_t *)pair);
652 xdr.xdr_idx = pair + encoded_size;
653 nvh = (nvp_header_t *)xdr.xdr_idx;
655 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
658 encoded_size = *(unsigned *)xdr.xdr_idx;
659 xdr.xdr_idx += sizeof(unsigned);
660 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
662 decoded_size = *(unsigned *)xdr.xdr_idx;
663 xdr.xdr_idx += sizeof(unsigned);
664 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
667 if (encoded_size != 0 && decoded_size != 0) {
675 * Calculate nvlist size by walking in memory data.
678 nvlist_size_native(xdr_t *xdr, size_t *size)
681 unsigned encoded_size, decoded_size;
683 xdr->xdr_idx += 2 * sizeof(unsigned);
686 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
689 encoded_size = *(unsigned *)xdr->xdr_idx;
690 xdr->xdr_idx += sizeof(unsigned);
691 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
693 decoded_size = *(unsigned *)xdr->xdr_idx;
694 xdr->xdr_idx += sizeof(unsigned);
695 while (encoded_size && decoded_size) {
696 xdr->xdr_idx = pair + encoded_size;
698 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
700 encoded_size = *(unsigned *)xdr->xdr_idx;
701 xdr->xdr_idx += sizeof(unsigned);
702 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
704 decoded_size = *(unsigned *)xdr->xdr_idx;
705 xdr->xdr_idx += sizeof(unsigned);
707 *size = xdr->xdr_idx - xdr->xdr_buf;
713 * Export nvlist to byte stream format.
716 nvlist_export(nvlist_t *nvl)
720 .xdr_op = XDR_OP_ENCODE,
721 .xdr_putint = _putint,
722 .xdr_putuint = _putuint,
723 .xdr_buf = nvl->nv_data,
724 .xdr_idx = nvl->nv_data,
725 .xdr_buf_size = nvl->nv_size
728 if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR)
731 nvl->nv_idx = nvl->nv_data;
732 rv = nvlist_xdr_nvlist(&xdr, nvl);
738 * Import nvlist from byte stream.
739 * Determine the stream size and allocate private copy.
740 * Then translate the data.
743 nvlist_import(const char *stream, size_t size)
747 .xdr_op = XDR_OP_DECODE,
748 .xdr_getint = _getint,
749 .xdr_getuint = _getuint
752 /* Check the nvlist head. */
753 if (stream[0] != NV_ENCODE_XDR ||
754 (stream[1] != '\0' && stream[1] != '\1') ||
755 stream[2] != '\0' || stream[3] != '\0' ||
756 be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION ||
757 be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME)
760 nvl = malloc(sizeof(*nvl));
764 nvl->nv_header.nvh_encoding = stream[0];
765 nvl->nv_header.nvh_endian = stream[1];
766 nvl->nv_header.nvh_reserved1 = stream[2];
767 nvl->nv_header.nvh_reserved2 = stream[3];
769 xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4;
770 xdr.xdr_buf_size = size - 4;
772 if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) {
776 nvl->nv_size = nvl->nv_asize;
777 nvl->nv_data = malloc(nvl->nv_asize);
778 if (nvl->nv_data == NULL) {
782 nvl->nv_idx = nvl->nv_data;
783 bcopy(stream + 4, nvl->nv_data, nvl->nv_asize);
785 xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data;
786 xdr.xdr_buf_size = nvl->nv_asize;
788 if (nvlist_xdr_nvlist(&xdr, nvl) != 0) {
798 * remove pair from this nvlist.
801 nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
803 uint8_t *head, *tail;
806 nv_string_t *nvp_name;
807 nv_pair_data_t *nvp_data;
811 if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
814 /* Make sure the nvlist size is set correct */
815 xdr.xdr_idx = nvl->nv_data;
816 xdr.xdr_buf = xdr.xdr_idx;
817 xdr.xdr_buf_size = nvl->nv_size;
818 if (!nvlist_size_native(&xdr, &nvl->nv_size))
821 data = (nvs_data_t *)nvl->nv_data;
822 nvp = &data->nvl_pair; /* first pair in nvlist */
823 head = (uint8_t *)nvp;
825 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
826 nvp_name = (nv_string_t *)(nvp + 1);
828 nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] +
829 NV_ALIGN4(nvp_name->nv_size));
831 if (strlen(name) == nvp_name->nv_size &&
832 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
833 (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
835 * set tail to point to next nvpair and size
836 * is the length of the tail.
838 tail = head + nvp->encoded_size;
839 size = nvl->nv_size - (tail - nvl->nv_data);
841 /* adjust the size of the nvlist. */
842 nvl->nv_size -= nvp->encoded_size;
843 bcopy(tail, head, size);
846 /* Not our pair, skip to next. */
847 head = head + nvp->encoded_size;
848 nvp = (nvp_header_t *)head;
854 clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size,
859 nv = calloc(1, sizeof(*nv));
863 nv->nv_header = nvl->nv_header;
866 nv->nv_data = malloc(nv->nv_asize);
867 if (nv->nv_data == NULL) {
872 bcopy(ptr, nv->nv_data, nv->nv_asize);
878 * Return the next nvlist in an nvlist array.
881 nvlist_next(const uint8_t *ptr)
886 data = (nvs_data_t *)ptr;
887 nvp = &data->nvl_pair; /* first pair in nvlist */
889 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
890 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
892 return ((uint8_t *)nvp + sizeof(*nvp));
896 * Note: nvlist and nvlist array must be freed by caller.
899 nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type,
900 int *elementsp, void *valuep, int *sizep)
904 nv_string_t *nvp_name;
905 nv_pair_data_t *nvp_data;
906 nvlist_t **nvlist, *nv;
910 if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
913 data = (nvs_data_t *)nvl->nv_data;
914 nvp = &data->nvl_pair; /* first pair in nvlist */
916 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
917 nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp));
918 if (nvl->nv_data + nvl->nv_size <
919 nvp_name->nv_data + nvp_name->nv_size)
922 nvp_data = (nv_pair_data_t *)
923 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
926 if (strlen(name) == nvp_name->nv_size &&
927 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
928 (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
929 if (elementsp != NULL)
930 *elementsp = nvp_data->nv_nelem;
931 switch (nvp_data->nv_type) {
932 case DATA_TYPE_UINT64:
933 bcopy(nvp_data->nv_data, valuep,
936 case DATA_TYPE_STRING:
937 nvp_name = (nv_string_t *)nvp_data->nv_data;
939 *sizep = nvp_name->nv_size;
941 *(const uint8_t **)valuep =
942 &nvp_name->nv_data[0];
944 case DATA_TYPE_NVLIST:
945 ptr = &nvp_data->nv_data[0];
946 rv = clone_nvlist(nvl, ptr,
947 nvlist_next(ptr) - ptr, &nv);
949 *(nvlist_t **)valuep = nv;
953 case DATA_TYPE_NVLIST_ARRAY:
954 nvlist = calloc(nvp_data->nv_nelem,
958 ptr = &nvp_data->nv_data[0];
960 for (unsigned i = 0; i < nvp_data->nv_nelem;
962 rv = clone_nvlist(nvl, ptr,
963 nvlist_next(ptr) - ptr, &nvlist[i]);
966 ptr = nvlist_next(ptr);
968 *(nvlist_t ***)valuep = nvlist;
973 /* Not our pair, skip to next. */
974 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
975 if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp)
980 for (unsigned i = 0; i < nvp_data->nv_nelem; i++) {
981 free(nvlist[i]->nv_data);
989 get_value_size(data_type_t type, const void *data, uint32_t nelem)
991 uint64_t value_sz = 0;
994 case DATA_TYPE_BOOLEAN:
997 case DATA_TYPE_BOOLEAN_VALUE:
1000 case DATA_TYPE_UINT8:
1001 case DATA_TYPE_INT16:
1002 case DATA_TYPE_UINT16:
1003 case DATA_TYPE_INT32:
1004 case DATA_TYPE_UINT32:
1005 /* Our smallest data unit is 32-bit */
1006 value_sz = sizeof(uint32_t);
1008 case DATA_TYPE_HRTIME:
1009 case DATA_TYPE_INT64:
1010 value_sz = sizeof(int64_t);
1012 case DATA_TYPE_UINT64:
1013 value_sz = sizeof(uint64_t);
1015 case DATA_TYPE_STRING:
1019 value_sz = strlen(data) + 1;
1021 case DATA_TYPE_BYTE_ARRAY:
1022 value_sz = nelem * sizeof(uint8_t);
1024 case DATA_TYPE_BOOLEAN_ARRAY:
1025 case DATA_TYPE_INT8_ARRAY:
1026 case DATA_TYPE_UINT8_ARRAY:
1027 case DATA_TYPE_INT16_ARRAY:
1028 case DATA_TYPE_UINT16_ARRAY:
1029 case DATA_TYPE_INT32_ARRAY:
1030 case DATA_TYPE_UINT32_ARRAY:
1031 value_sz = (uint64_t)nelem * sizeof(uint32_t);
1033 case DATA_TYPE_INT64_ARRAY:
1034 value_sz = (uint64_t)nelem * sizeof(int64_t);
1036 case DATA_TYPE_UINT64_ARRAY:
1037 value_sz = (uint64_t)nelem * sizeof(uint64_t);
1039 case DATA_TYPE_STRING_ARRAY:
1040 value_sz = (uint64_t)nelem * sizeof(uint64_t);
1043 char *const *strs = data;
1046 for (i = 0; i < nelem; i++) {
1047 if (strs[i] == NULL)
1049 value_sz += strlen(strs[i]) + 1;
1053 case DATA_TYPE_NVLIST:
1055 * The decoded size of nvlist is constant.
1057 value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1059 case DATA_TYPE_NVLIST_ARRAY:
1060 value_sz = (uint64_t)nelem * sizeof(uint64_t) +
1061 (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1067 return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1071 get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem)
1073 uint64_t value_sz = 0;
1078 case DATA_TYPE_BOOLEAN:
1081 case DATA_TYPE_BOOLEAN_VALUE:
1082 case DATA_TYPE_BYTE:
1083 case DATA_TYPE_INT8:
1084 case DATA_TYPE_UINT8:
1085 case DATA_TYPE_INT16:
1086 case DATA_TYPE_UINT16:
1087 case DATA_TYPE_INT32:
1088 case DATA_TYPE_UINT32:
1089 /* Our smallest data unit is 32-bit */
1090 value_sz = sizeof(uint32_t);
1092 case DATA_TYPE_HRTIME:
1093 case DATA_TYPE_INT64:
1094 case DATA_TYPE_UINT64:
1095 value_sz = sizeof(uint64_t);
1097 case DATA_TYPE_STRING:
1098 value_sz = 4 + NV_ALIGN4(strlen(data));
1100 case DATA_TYPE_BYTE_ARRAY:
1101 value_sz = NV_ALIGN4(nelem);
1103 case DATA_TYPE_BOOLEAN_ARRAY:
1104 case DATA_TYPE_INT8_ARRAY:
1105 case DATA_TYPE_UINT8_ARRAY:
1106 case DATA_TYPE_INT16_ARRAY:
1107 case DATA_TYPE_UINT16_ARRAY:
1108 case DATA_TYPE_INT32_ARRAY:
1109 case DATA_TYPE_UINT32_ARRAY:
1110 value_sz = 4 + (uint64_t)nelem * sizeof(uint32_t);
1112 case DATA_TYPE_INT64_ARRAY:
1113 case DATA_TYPE_UINT64_ARRAY:
1114 value_sz = 4 + (uint64_t)nelem * sizeof(uint64_t);
1116 case DATA_TYPE_STRING_ARRAY:
1118 char *const *strs = data;
1121 for (i = 0; i < nelem; i++) {
1122 value_sz += 4 + NV_ALIGN4(strlen(strs[i]));
1126 case DATA_TYPE_NVLIST:
1127 xdr.xdr_idx = ((nvlist_t *)data)->nv_data;
1128 xdr.xdr_buf = xdr.xdr_idx;
1129 xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size;
1131 if (!nvlist_size_native(&xdr, &size))
1136 case DATA_TYPE_NVLIST_ARRAY:
1138 for (uint32_t i = 0; i < nelem; i++) {
1139 xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1140 xdr.xdr_buf = xdr.xdr_idx;
1141 xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1143 if (!nvlist_size_native(&xdr, &size))
1152 return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1155 #define NVPE_SIZE(name_len, data_len) \
1156 (4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len)
1157 #define NVP_SIZE(name_len, data_len) \
1158 (NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len))
1161 nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1162 uint32_t nelem, const void *data)
1165 nvp_header_t head, *hp;
1168 int decoded_size, encoded_size;
1170 .xdr_op = XDR_OP_ENCODE,
1171 .xdr_putint = _putint_mem,
1172 .xdr_putuint = _putuint_mem,
1173 .xdr_buf = nvl->nv_data,
1174 .xdr_idx = nvl->nv_data,
1175 .xdr_buf_size = nvl->nv_size
1178 nvs = (nvs_data_t *)nvl->nv_data;
1179 if (nvs->nvl_nvflag & NV_UNIQUE_NAME)
1180 (void) nvlist_remove(nvl, name, type);
1182 xdr.xdr_buf = nvl->nv_data;
1183 xdr.xdr_idx = nvl->nv_data;
1184 xdr.xdr_buf_size = nvl->nv_size;
1185 if (!nvlist_size_native(&xdr, &nvl->nv_size))
1188 namelen = strlen(name);
1189 if ((decoded_size = get_value_size(type, data, nelem)) < 0)
1191 if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0)
1195 * The encoded size is calculated as:
1196 * encode_size (4) + decode_size (4) +
1197 * name string size (4 + NV_ALIGN4(namelen) +
1198 * data type (4) + nelem size (4) + datalen
1200 * The decoded size is calculated as:
1201 * Note: namelen is with terminating 0.
1202 * NV_ALIGN(sizeof(nvpair_t) (4 * 4) + namelen + 1) +
1203 * NV_ALIGN(data_len)
1206 head.encoded_size = NVPE_SIZE(namelen, encoded_size);
1207 head.decoded_size = NVP_SIZE(namelen + 1, decoded_size);
1209 if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) {
1210 ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size);
1214 nvl->nv_asize += head.encoded_size;
1216 nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof(*hp);
1217 bzero(nvl->nv_idx, head.encoded_size + 8);
1218 hp = (nvp_header_t *)nvl->nv_idx;
1220 nvl->nv_idx += sizeof(*hp);
1222 xdr.xdr_buf = nvl->nv_data;
1223 xdr.xdr_buf_size = nvl->nv_asize;
1224 xdr.xdr_idx = nvl->nv_idx;
1226 xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen);
1227 strlcpy((char *)xdr.xdr_idx, name, namelen + 1);
1228 xdr.xdr_idx += NV_ALIGN4(namelen);
1229 xdr.xdr_idx += xdr.xdr_putuint(&xdr, type);
1230 xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem);
1233 case DATA_TYPE_BOOLEAN:
1236 case DATA_TYPE_BYTE_ARRAY:
1237 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
1238 bcopy(data, xdr.xdr_idx, nelem);
1239 xdr.xdr_idx += NV_ALIGN4(encoded_size);
1242 case DATA_TYPE_STRING:
1243 encoded_size = strlen(data);
1244 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
1245 strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1);
1246 xdr.xdr_idx += NV_ALIGN4(encoded_size);
1249 case DATA_TYPE_STRING_ARRAY:
1250 for (uint32_t i = 0; i < nelem; i++) {
1251 encoded_size = strlen(((char **)data)[i]);
1252 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
1253 strlcpy((char *)xdr.xdr_idx, ((char **)data)[i],
1255 xdr.xdr_idx += NV_ALIGN4(encoded_size);
1259 case DATA_TYPE_BYTE:
1260 case DATA_TYPE_INT8:
1261 case DATA_TYPE_UINT8:
1262 xdr_char(&xdr, (char *)data);
1265 case DATA_TYPE_INT8_ARRAY:
1266 case DATA_TYPE_UINT8_ARRAY:
1267 xdr_array(&xdr, nelem, (xdrproc_t)xdr_char);
1270 case DATA_TYPE_INT16:
1271 xdr_short(&xdr, (short *)data);
1274 case DATA_TYPE_UINT16:
1275 xdr_u_short(&xdr, (unsigned short *)data);
1278 case DATA_TYPE_INT16_ARRAY:
1279 xdr_array(&xdr, nelem, (xdrproc_t)xdr_short);
1282 case DATA_TYPE_UINT16_ARRAY:
1283 xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short);
1286 case DATA_TYPE_BOOLEAN_VALUE:
1287 case DATA_TYPE_INT32:
1288 xdr_int(&xdr, (int *)data);
1291 case DATA_TYPE_UINT32:
1292 xdr_u_int(&xdr, (unsigned int *)data);
1295 case DATA_TYPE_BOOLEAN_ARRAY:
1296 case DATA_TYPE_INT32_ARRAY:
1297 xdr_array(&xdr, nelem, (xdrproc_t)xdr_int);
1300 case DATA_TYPE_UINT32_ARRAY:
1301 xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int);
1304 case DATA_TYPE_INT64:
1305 xdr_int64(&xdr, (int64_t *)data);
1308 case DATA_TYPE_UINT64:
1309 xdr_uint64(&xdr, (uint64_t *)data);
1312 case DATA_TYPE_INT64_ARRAY:
1313 xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64);
1316 case DATA_TYPE_UINT64_ARRAY:
1317 xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64);
1320 case DATA_TYPE_NVLIST:
1321 bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size);
1324 case DATA_TYPE_NVLIST_ARRAY: {
1328 for (uint32_t i = 0; i < nelem; i++) {
1329 xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1330 xdr_nv.xdr_buf = xdr_nv.xdr_idx;
1331 xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1333 if (!nvlist_size_native(&xdr_nv, &size))
1336 bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx,
1338 xdr.xdr_idx += size;
1343 bcopy(data, xdr.xdr_idx, encoded_size);
1346 nvl->nv_size += head.encoded_size;
1352 nvlist_add_boolean_value(nvlist_t *nvl, const char *name, int value)
1354 return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1,
1359 nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value)
1361 return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value));
1365 nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value)
1367 return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value));
1371 nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value)
1373 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value));
1377 nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value)
1379 return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value));
1383 nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value)
1385 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value));
1389 nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value)
1391 return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value));
1395 nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value)
1397 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value));
1401 nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value)
1403 return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value));
1407 nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value)
1409 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value));
1413 nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1415 return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value));
1419 nvlist_add_boolean_array(nvlist_t *nvl, const char *name, int *a, uint32_t n)
1421 return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1425 nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1427 return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1431 nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n)
1433 return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1437 nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1439 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1443 nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n)
1445 return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1449 nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a,
1452 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1456 nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n)
1458 return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1462 nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a,
1465 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1469 nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n)
1471 return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1475 nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a,
1478 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1482 nvlist_add_string_array(nvlist_t *nvl, const char *name,
1483 char * const *a, uint32_t n)
1485 return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1489 nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
1491 return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1495 nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a,
1498 return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1501 static const char *typenames[] = {
1502 "DATA_TYPE_UNKNOWN",
1503 "DATA_TYPE_BOOLEAN",
1512 "DATA_TYPE_BYTE_ARRAY",
1513 "DATA_TYPE_INT16_ARRAY",
1514 "DATA_TYPE_UINT16_ARRAY",
1515 "DATA_TYPE_INT32_ARRAY",
1516 "DATA_TYPE_UINT32_ARRAY",
1517 "DATA_TYPE_INT64_ARRAY",
1518 "DATA_TYPE_UINT64_ARRAY",
1519 "DATA_TYPE_STRING_ARRAY",
1522 "DATA_TYPE_NVLIST_ARRAY",
1523 "DATA_TYPE_BOOLEAN_VALUE",
1526 "DATA_TYPE_BOOLEAN_ARRAY",
1527 "DATA_TYPE_INT8_ARRAY",
1528 "DATA_TYPE_UINT8_ARRAY"
1532 nvpair_type_from_name(const char *name)
1536 for (i = 0; i < nitems(typenames); i++) {
1537 if (strcmp(name, typenames[i]) == 0)
1544 nvpair_find(nvlist_t *nv, const char *name)
1549 while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) {
1550 nv_string_t *nvp_name;
1552 nvp_name = (nv_string_t *)(nvh + 1);
1553 if (nvp_name->nv_size == strlen(name) &&
1554 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0)
1561 nvpair_print(nvp_header_t *nvp, unsigned int indent)
1563 nv_string_t *nvp_name;
1564 nv_pair_data_t *nvp_data;
1568 .xdr_op = XDR_OP_DECODE,
1569 .xdr_getint = _getint_mem,
1570 .xdr_getuint = _getuint_mem,
1571 .xdr_buf = (const uint8_t *)nvp,
1573 .xdr_buf_size = nvp->encoded_size
1576 nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp));
1577 nvp_data = (nv_pair_data_t *)
1578 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size);
1580 for (i = 0; i < indent; i++)
1583 printf("%s [%d] %.*s", typenames[nvp_data->nv_type],
1584 nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data);
1586 xdr.xdr_idx = nvp_data->nv_data;
1587 switch (nvp_data->nv_type) {
1588 case DATA_TYPE_BYTE:
1589 case DATA_TYPE_INT8:
1590 case DATA_TYPE_UINT8: {
1593 if (xdr_char(&xdr, &c))
1594 printf(" = 0x%x\n", c);
1598 case DATA_TYPE_INT16:
1599 case DATA_TYPE_UINT16: {
1602 if (xdr_u_short(&xdr, &u))
1603 printf(" = 0x%hx\n", u);
1607 case DATA_TYPE_BOOLEAN_VALUE:
1608 case DATA_TYPE_INT32:
1609 case DATA_TYPE_UINT32: {
1612 if (xdr_u_int(&xdr, &u))
1613 printf(" = 0x%x\n", u);
1617 case DATA_TYPE_INT64:
1618 case DATA_TYPE_UINT64: {
1621 if (xdr_uint64(&xdr, &u))
1622 printf(" = 0x%jx\n", (uintmax_t)u);
1626 case DATA_TYPE_INT64_ARRAY:
1627 case DATA_TYPE_UINT64_ARRAY: {
1630 if (xdr_array(&xdr, nvp_data->nv_nelem,
1631 (xdrproc_t)xdr_uint64)) {
1632 u = (uint64_t *)(nvp_data->nv_data + sizeof(unsigned));
1633 for (i = 0; i < nvp_data->nv_nelem; i++)
1634 printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]);
1641 case DATA_TYPE_STRING:
1642 case DATA_TYPE_STRING_ARRAY:
1643 nvp_name = (nv_string_t *)&nvp_data->nv_data[0];
1644 for (i = 0; i < nvp_data->nv_nelem; i++) {
1645 printf(" = \"%.*s\"\n", nvp_name->nv_size,
1650 case DATA_TYPE_NVLIST:
1652 nvlist.nv_data = &nvp_data->nv_data[0];
1653 nvlist_print(&nvlist, indent + 2);
1656 case DATA_TYPE_NVLIST_ARRAY:
1657 nvlist.nv_data = &nvp_data->nv_data[0];
1658 for (j = 0; j < nvp_data->nv_nelem; j++) {
1661 printf("[%d]\n", j);
1662 nvlist_print(&nvlist, indent + 2);
1663 if (j != nvp_data->nv_nelem - 1) {
1664 for (i = 0; i < indent; i++)
1667 typenames[nvp_data->nv_type],
1671 xdr.xdr_idx = nvlist.nv_data;
1672 xdr.xdr_buf = xdr.xdr_idx;
1673 xdr.xdr_buf_size = nvp->encoded_size -
1674 (xdr.xdr_idx - (uint8_t *)nvp);
1676 if (!nvlist_size_native(&xdr, &size))
1679 nvlist.nv_data += size;
1689 nvlist_print(const nvlist_t *nvl, unsigned int indent)
1694 data = (nvs_data_t *)nvl->nv_data;
1695 nvp = &data->nvl_pair; /* first pair in nvlist */
1696 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
1697 nvpair_print(nvp, indent);
1698 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
1700 printf("%*s\n", indent + 13, "End of nvlist");