2 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/endian.h>
37 #include <bitstring.h>
49 #define NV_TYPE_NONE 0
51 #define NV_TYPE_INT8 1
52 #define NV_TYPE_UINT8 2
53 #define NV_TYPE_INT16 3
54 #define NV_TYPE_UINT16 4
55 #define NV_TYPE_INT32 5
56 #define NV_TYPE_UINT32 6
57 #define NV_TYPE_INT64 7
58 #define NV_TYPE_UINT64 8
59 #define NV_TYPE_INT8_ARRAY 9
60 #define NV_TYPE_UINT8_ARRAY 10
61 #define NV_TYPE_INT16_ARRAY 11
62 #define NV_TYPE_UINT16_ARRAY 12
63 #define NV_TYPE_INT32_ARRAY 13
64 #define NV_TYPE_UINT32_ARRAY 14
65 #define NV_TYPE_INT64_ARRAY 15
66 #define NV_TYPE_UINT64_ARRAY 16
67 #define NV_TYPE_STRING 17
69 #define NV_TYPE_MASK 0x7f
70 #define NV_TYPE_FIRST NV_TYPE_INT8
71 #define NV_TYPE_LAST NV_TYPE_STRING
73 #define NV_ORDER_NETWORK 0x00
74 #define NV_ORDER_HOST 0x80
76 #define NV_ORDER_MASK 0x80
78 #define NV_MAGIC 0xaea1e
91 #define NVH_DATA(nvh) ((unsigned char *)nvh + NVH_HSIZE(nvh))
92 #define NVH_HSIZE(nvh) \
93 (sizeof(struct nvhdr) + roundup2((nvh)->nvh_namesize, 8))
94 #define NVH_DSIZE(nvh) \
95 (((nvh)->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST ? \
97 le32toh((nvh)->nvh_dsize))
98 #define NVH_SIZE(nvh) (NVH_HSIZE(nvh) + roundup2(NVH_DSIZE(nvh), 8))
100 #define NV_CHECK(nv) do { \
101 assert((nv) != NULL); \
102 assert((nv)->nv_magic == NV_MAGIC); \
105 static void nv_add(struct nv *nv, const unsigned char *value, size_t vsize,
106 int type, const char *name);
107 static void nv_addv(struct nv *nv, const unsigned char *value, size_t vsize,
108 int type, const char *namefmt, va_list nameap);
109 static struct nvhdr *nv_find(struct nv *nv, int type, const char *namefmt,
111 static void nv_swap(struct nvhdr *nvh, bool tohost);
114 * Allocate and initialize new nv structure.
115 * Return NULL in case of malloc(3) failure.
122 nv = malloc(sizeof(*nv));
125 nv->nv_ebuf = ebuf_alloc(0);
126 if (nv->nv_ebuf == NULL) {
131 nv->nv_magic = NV_MAGIC;
136 * Free the given nv structure.
139 nv_free(struct nv *nv)
148 ebuf_free(nv->nv_ebuf);
153 * Return error for the given nv structure.
156 nv_error(const struct nv *nv)
164 return (nv->nv_error);
168 * Set error for the given nv structure and return previous error.
171 nv_set_error(struct nv *nv, int error)
180 preverr = nv->nv_error;
181 nv->nv_error = error;
186 * Validate correctness of the entire nv structure and all its elements.
187 * If extrap is not NULL, store number of extra bytes at the end of the buffer.
190 nv_validate(struct nv *nv, size_t *extrap)
193 unsigned char *data, *ptr;
194 size_t dsize, size, vsize;
203 assert(nv->nv_error == 0);
205 /* TODO: Check that names are unique? */
208 ptr = ebuf_data(nv->nv_ebuf, &size);
211 * Zeros at the end of the buffer are acceptable.
216 * Minimum size at this point is size of nvhdr structure, one
217 * character long name plus terminating '\0'.
219 if (size < sizeof(*nvh) + 2) {
223 nvh = (struct nvhdr *)ptr;
224 if (size < NVH_HSIZE(nvh)) {
228 if (nvh->nvh_name[nvh->nvh_namesize - 1] != '\0') {
232 if (strlen(nvh->nvh_name) !=
233 (size_t)(nvh->nvh_namesize - 1)) {
237 if ((nvh->nvh_type & NV_TYPE_MASK) < NV_TYPE_FIRST ||
238 (nvh->nvh_type & NV_TYPE_MASK) > NV_TYPE_LAST) {
242 dsize = NVH_DSIZE(nvh);
247 if (size < NVH_SIZE(nvh)) {
252 switch (nvh->nvh_type & NV_TYPE_MASK) {
272 if (dsize != vsize) {
277 case NV_TYPE_INT8_ARRAY:
278 case NV_TYPE_UINT8_ARRAY:
280 case NV_TYPE_INT16_ARRAY:
281 case NV_TYPE_UINT16_ARRAY:
285 case NV_TYPE_INT32_ARRAY:
286 case NV_TYPE_UINT32_ARRAY:
290 case NV_TYPE_INT64_ARRAY:
291 case NV_TYPE_UINT64_ARRAY:
294 if ((dsize % vsize) != 0) {
300 data = NVH_DATA(nvh);
301 if (data[dsize - 1] != '\0') {
305 if (strlen((char *)data) != dsize - 1) {
311 assert(!"invalid condition");
315 ptr += NVH_SIZE(nvh);
316 size -= NVH_SIZE(nvh);
320 if (nv->nv_error == 0)
321 nv->nv_error = error;
330 * Convert the given nv structure to network byte order and return ebuf
334 nv_hton(struct nv *nv)
341 assert(nv->nv_error == 0);
343 ptr = ebuf_data(nv->nv_ebuf, &size);
346 * Minimum size at this point is size of nvhdr structure,
347 * one character long name plus terminating '\0'.
349 assert(size >= sizeof(*nvh) + 2);
350 nvh = (struct nvhdr *)ptr;
351 assert(NVH_SIZE(nvh) <= size);
353 ptr += NVH_SIZE(nvh);
354 size -= NVH_SIZE(nvh);
357 return (nv->nv_ebuf);
361 * Create nv structure based on ebuf received from the network.
364 nv_ntoh(struct ebuf *eb)
372 nv = malloc(sizeof(*nv));
377 nv->nv_magic = NV_MAGIC;
379 if (nv_validate(nv, &extra) < 0) {
387 * Remove extra zeros at the end of the buffer.
389 ebuf_del_tail(eb, extra);
394 #define NV_DEFINE_ADD(type, TYPE) \
396 nv_add_##type(struct nv *nv, type##_t value, const char *namefmt, ...) \
400 va_start(nameap, namefmt); \
401 nv_addv(nv, (unsigned char *)&value, sizeof(value), \
402 NV_TYPE_##TYPE, namefmt, nameap); \
406 NV_DEFINE_ADD(int8, INT8)
407 NV_DEFINE_ADD(uint8, UINT8)
408 NV_DEFINE_ADD(int16, INT16)
409 NV_DEFINE_ADD(uint16, UINT16)
410 NV_DEFINE_ADD(int32, INT32)
411 NV_DEFINE_ADD(uint32, UINT32)
412 NV_DEFINE_ADD(int64, INT64)
413 NV_DEFINE_ADD(uint64, UINT64)
417 #define NV_DEFINE_ADD_ARRAY(type, TYPE) \
419 nv_add_##type##_array(struct nv *nv, const type##_t *value, \
420 size_t nsize, const char *namefmt, ...) \
424 va_start(nameap, namefmt); \
425 nv_addv(nv, (const unsigned char *)value, \
426 sizeof(value[0]) * nsize, NV_TYPE_##TYPE##_ARRAY, namefmt, \
431 NV_DEFINE_ADD_ARRAY(int8, INT8)
432 NV_DEFINE_ADD_ARRAY(uint8, UINT8)
433 NV_DEFINE_ADD_ARRAY(int16, INT16)
434 NV_DEFINE_ADD_ARRAY(uint16, UINT16)
435 NV_DEFINE_ADD_ARRAY(int32, INT32)
436 NV_DEFINE_ADD_ARRAY(uint32, UINT32)
437 NV_DEFINE_ADD_ARRAY(int64, INT64)
438 NV_DEFINE_ADD_ARRAY(uint64, UINT64)
440 #undef NV_DEFINE_ADD_ARRAY
443 nv_add_string(struct nv *nv, const char *value, const char *namefmt, ...)
448 size = strlen(value) + 1;
450 va_start(nameap, namefmt);
451 nv_addv(nv, (const unsigned char *)value, size, NV_TYPE_STRING,
457 nv_add_stringf(struct nv *nv, const char *name, const char *valuefmt, ...)
461 va_start(valueap, valuefmt);
462 nv_add_stringv(nv, name, valuefmt, valueap);
467 nv_add_stringv(struct nv *nv, const char *name, const char *valuefmt,
473 size = vasprintf(&value, valuefmt, valueap);
475 if (nv->nv_error == 0)
476 nv->nv_error = ENOMEM;
480 nv_add(nv, (const unsigned char *)value, size, NV_TYPE_STRING, name);
484 #define NV_DEFINE_GET(type, TYPE) \
486 nv_get_##type(struct nv *nv, const char *namefmt, ...) \
492 va_start(nameap, namefmt); \
493 nvh = nv_find(nv, NV_TYPE_##TYPE, namefmt, nameap); \
497 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); \
498 assert(sizeof(value) == nvh->nvh_dsize); \
499 bcopy(NVH_DATA(nvh), &value, sizeof(value)); \
504 NV_DEFINE_GET(int8, INT8)
505 NV_DEFINE_GET(uint8, UINT8)
506 NV_DEFINE_GET(int16, INT16)
507 NV_DEFINE_GET(uint16, UINT16)
508 NV_DEFINE_GET(int32, INT32)
509 NV_DEFINE_GET(uint32, UINT32)
510 NV_DEFINE_GET(int64, INT64)
511 NV_DEFINE_GET(uint64, UINT64)
515 #define NV_DEFINE_GET_ARRAY(type, TYPE) \
517 nv_get_##type##_array(struct nv *nv, size_t *sizep, \
518 const char *namefmt, ...) \
523 va_start(nameap, namefmt); \
524 nvh = nv_find(nv, NV_TYPE_##TYPE##_ARRAY, namefmt, nameap); \
528 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); \
529 assert((nvh->nvh_dsize % sizeof(type##_t)) == 0); \
531 *sizep = nvh->nvh_dsize / sizeof(type##_t); \
532 return ((type##_t *)(void *)NVH_DATA(nvh)); \
535 NV_DEFINE_GET_ARRAY(int8, INT8)
536 NV_DEFINE_GET_ARRAY(uint8, UINT8)
537 NV_DEFINE_GET_ARRAY(int16, INT16)
538 NV_DEFINE_GET_ARRAY(uint16, UINT16)
539 NV_DEFINE_GET_ARRAY(int32, INT32)
540 NV_DEFINE_GET_ARRAY(uint32, UINT32)
541 NV_DEFINE_GET_ARRAY(int64, INT64)
542 NV_DEFINE_GET_ARRAY(uint64, UINT64)
544 #undef NV_DEFINE_GET_ARRAY
547 nv_get_string(struct nv *nv, const char *namefmt, ...)
553 va_start(nameap, namefmt);
554 nvh = nv_find(nv, NV_TYPE_STRING, namefmt, nameap);
558 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);
559 assert(nvh->nvh_dsize >= 1);
561 assert(str[nvh->nvh_dsize - 1] == '\0');
562 assert(strlen(str) == nvh->nvh_dsize - 1);
567 nv_vexists(struct nv *nv, const char *namefmt, va_list nameap)
570 int snverror, serrno;
576 snverror = nv->nv_error;
578 nvh = nv_find(nv, NV_TYPE_NONE, namefmt, nameap);
581 nv->nv_error = snverror;
583 return (nvh != NULL);
587 nv_exists(struct nv *nv, const char *namefmt, ...)
592 va_start(nameap, namefmt);
593 ret = nv_vexists(nv, namefmt, nameap);
600 nv_assert(struct nv *nv, const char *namefmt, ...)
604 va_start(nameap, namefmt);
605 assert(nv_vexists(nv, namefmt, nameap));
610 * Dump content of the nv structure.
613 nv_dump(struct nv *nv)
616 unsigned char *data, *ptr;
621 if (nv_validate(nv, NULL) < 0) {
622 printf("error: %d\n", errno);
627 assert(nv->nv_error == 0);
629 ptr = ebuf_data(nv->nv_ebuf, &size);
631 assert(size >= sizeof(*nvh) + 2);
632 nvh = (struct nvhdr *)ptr;
633 assert(size >= NVH_SIZE(nvh));
634 swap = ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK);
635 dsize = NVH_DSIZE(nvh);
636 data = NVH_DATA(nvh);
637 printf(" %s", nvh->nvh_name);
638 switch (nvh->nvh_type & NV_TYPE_MASK) {
640 printf("(int8): %jd", (intmax_t)(*(int8_t *)data));
643 printf("(uint8): %ju", (uintmax_t)(*(uint8_t *)data));
646 printf("(int16): %jd", swap ?
647 (intmax_t)le16toh(*(int16_t *)(void *)data) :
648 (intmax_t)*(int16_t *)(void *)data);
651 printf("(uint16): %ju", swap ?
652 (uintmax_t)le16toh(*(uint16_t *)(void *)data) :
653 (uintmax_t)*(uint16_t *)(void *)data);
656 printf("(int32): %jd", swap ?
657 (intmax_t)le32toh(*(int32_t *)(void *)data) :
658 (intmax_t)*(int32_t *)(void *)data);
661 printf("(uint32): %ju", swap ?
662 (uintmax_t)le32toh(*(uint32_t *)(void *)data) :
663 (uintmax_t)*(uint32_t *)(void *)data);
666 printf("(int64): %jd", swap ?
667 (intmax_t)le64toh(*(int64_t *)(void *)data) :
668 (intmax_t)*(int64_t *)(void *)data);
671 printf("(uint64): %ju", swap ?
672 (uintmax_t)le64toh(*(uint64_t *)(void *)data) :
673 (uintmax_t)*(uint64_t *)(void *)data);
675 case NV_TYPE_INT8_ARRAY:
676 printf("(int8 array):");
677 for (ii = 0; ii < dsize; ii++)
678 printf(" %jd", (intmax_t)((int8_t *)data)[ii]);
680 case NV_TYPE_UINT8_ARRAY:
681 printf("(uint8 array):");
682 for (ii = 0; ii < dsize; ii++)
683 printf(" %ju", (uintmax_t)((uint8_t *)data)[ii]);
685 case NV_TYPE_INT16_ARRAY:
686 printf("(int16 array):");
687 for (ii = 0; ii < dsize / 2; ii++) {
688 printf(" %jd", swap ?
689 (intmax_t)le16toh(((int16_t *)(void *)data)[ii]) :
690 (intmax_t)((int16_t *)(void *)data)[ii]);
693 case NV_TYPE_UINT16_ARRAY:
694 printf("(uint16 array):");
695 for (ii = 0; ii < dsize / 2; ii++) {
696 printf(" %ju", swap ?
697 (uintmax_t)le16toh(((uint16_t *)(void *)data)[ii]) :
698 (uintmax_t)((uint16_t *)(void *)data)[ii]);
701 case NV_TYPE_INT32_ARRAY:
702 printf("(int32 array):");
703 for (ii = 0; ii < dsize / 4; ii++) {
704 printf(" %jd", swap ?
705 (intmax_t)le32toh(((int32_t *)(void *)data)[ii]) :
706 (intmax_t)((int32_t *)(void *)data)[ii]);
709 case NV_TYPE_UINT32_ARRAY:
710 printf("(uint32 array):");
711 for (ii = 0; ii < dsize / 4; ii++) {
712 printf(" %ju", swap ?
713 (uintmax_t)le32toh(((uint32_t *)(void *)data)[ii]) :
714 (uintmax_t)((uint32_t *)(void *)data)[ii]);
717 case NV_TYPE_INT64_ARRAY:
718 printf("(int64 array):");
719 for (ii = 0; ii < dsize / 8; ii++) {
720 printf(" %ju", swap ?
721 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
722 (uintmax_t)((uint64_t *)(void *)data)[ii]);
725 case NV_TYPE_UINT64_ARRAY:
726 printf("(uint64 array):");
727 for (ii = 0; ii < dsize / 8; ii++) {
728 printf(" %ju", swap ?
729 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
730 (uintmax_t)((uint64_t *)(void *)data)[ii]);
734 printf("(string): %s", (char *)data);
737 assert(!"invalid condition");
740 ptr += NVH_SIZE(nvh);
741 size -= NVH_SIZE(nvh);
746 * Local routines below.
750 nv_add(struct nv *nv, const unsigned char *value, size_t vsize, int type,
753 static unsigned char align[7];
764 namesize = strlen(name) + 1;
766 nvh = malloc(sizeof(*nvh) + roundup2(namesize, 8));
768 if (nv->nv_error == 0)
769 nv->nv_error = ENOMEM;
772 nvh->nvh_type = NV_ORDER_HOST | type;
773 nvh->nvh_namesize = (uint8_t)namesize;
774 nvh->nvh_dsize = (uint32_t)vsize;
775 bcopy(name, nvh->nvh_name, namesize);
777 /* Add header first. */
778 if (ebuf_add_tail(nv->nv_ebuf, nvh, NVH_HSIZE(nvh)) < 0) {
780 if (nv->nv_error == 0)
781 nv->nv_error = errno;
786 /* Add the actual data. */
787 if (ebuf_add_tail(nv->nv_ebuf, value, vsize) < 0) {
789 if (nv->nv_error == 0)
790 nv->nv_error = errno;
793 /* Align the data (if needed). */
794 vsize = roundup2(vsize, 8) - vsize;
797 assert(vsize > 0 && vsize <= sizeof(align));
798 if (ebuf_add_tail(nv->nv_ebuf, align, vsize) < 0) {
800 if (nv->nv_error == 0)
801 nv->nv_error = errno;
807 nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, int type,
808 const char *namefmt, va_list nameap)
813 namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
814 assert(namesize > 0 && namesize < sizeof(name));
816 nv_add(nv, value, vsize, type, name);
819 static struct nvhdr *
820 nv_find(struct nv *nv, int type, const char *namefmt, va_list nameap)
825 size_t size, namesize;
834 namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
835 assert(namesize > 0 && namesize < sizeof(name));
838 ptr = ebuf_data(nv->nv_ebuf, &size);
840 assert(size >= sizeof(*nvh) + 2);
841 nvh = (struct nvhdr *)ptr;
842 assert(size >= NVH_SIZE(nvh));
844 if (strcmp(nvh->nvh_name, name) == 0) {
845 if (type != NV_TYPE_NONE &&
846 (nvh->nvh_type & NV_TYPE_MASK) != type) {
848 if (nv->nv_error == 0)
849 nv->nv_error = EINVAL;
854 ptr += NVH_SIZE(nvh);
855 size -= NVH_SIZE(nvh);
858 if (nv->nv_error == 0)
859 nv->nv_error = ENOENT;
864 nv_swap(struct nvhdr *nvh, bool tohost)
866 unsigned char *data, *end, *p;
869 data = NVH_DATA(nvh);
871 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST)
873 nvh->nvh_dsize = le32toh(nvh->nvh_dsize);
874 end = data + nvh->nvh_dsize;
875 nvh->nvh_type &= ~NV_ORDER_MASK;
876 nvh->nvh_type |= NV_ORDER_HOST;
878 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK)
880 end = data + nvh->nvh_dsize;
881 nvh->nvh_dsize = htole32(nvh->nvh_dsize);
882 nvh->nvh_type &= ~NV_ORDER_MASK;
883 nvh->nvh_type |= NV_ORDER_NETWORK;
888 switch (nvh->nvh_type & NV_TYPE_MASK) {
891 case NV_TYPE_INT8_ARRAY:
892 case NV_TYPE_UINT8_ARRAY:
896 case NV_TYPE_INT16_ARRAY:
897 case NV_TYPE_UINT16_ARRAY:
903 case NV_TYPE_INT32_ARRAY:
904 case NV_TYPE_UINT32_ARRAY:
910 case NV_TYPE_INT64_ARRAY:
911 case NV_TYPE_UINT64_ARRAY:
914 for (p = data; p < end; p += vsize) {
918 *(uint16_t *)(void *)p =
919 le16toh(*(uint16_t *)(void *)p);
922 *(uint32_t *)(void *)p =
923 le32toh(*(uint32_t *)(void *)p);
926 *(uint64_t *)(void *)p =
927 le64toh(*(uint64_t *)(void *)p);
930 assert(!"invalid condition");
935 *(uint16_t *)(void *)p =
936 htole16(*(uint16_t *)(void *)p);
939 *(uint32_t *)(void *)p =
940 htole32(*(uint32_t *)(void *)p);
943 *(uint64_t *)(void *)p =
944 htole64(*(uint64_t *)(void *)p);
947 assert(!"invalid condition");
955 assert(!"unrecognized type");