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_MAGIC 0xaea1e
62 #define NVH_DATA(nvh) ((unsigned char *)nvh + NVH_HSIZE(nvh))
63 #define NVH_HSIZE(nvh) \
64 (sizeof(struct nvhdr) + roundup2((nvh)->nvh_namesize, 8))
65 #define NVH_DSIZE(nvh) \
66 (((nvh)->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST ? \
68 le32toh((nvh)->nvh_dsize))
69 #define NVH_SIZE(nvh) (NVH_HSIZE(nvh) + roundup2(NVH_DSIZE(nvh), 8))
71 #define NV_CHECK(nv) do { \
72 assert((nv) != NULL); \
73 assert((nv)->nv_magic == NV_MAGIC); \
76 static void nv_add(struct nv *nv, const unsigned char *value, size_t vsize,
77 int type, const char *name);
78 static void nv_addv(struct nv *nv, const unsigned char *value, size_t vsize,
79 int type, const char *namefmt, va_list nameap);
80 static struct nvhdr *nv_find(struct nv *nv, int type, const char *namefmt,
82 static void nv_swap(struct nvhdr *nvh, bool tohost);
85 * Allocate and initialize new nv structure.
86 * Return NULL in case of malloc(3) failure.
93 nv = malloc(sizeof(*nv));
96 nv->nv_ebuf = ebuf_alloc(0);
97 if (nv->nv_ebuf == NULL) {
102 nv->nv_magic = NV_MAGIC;
107 * Free the given nv structure.
110 nv_free(struct nv *nv)
119 ebuf_free(nv->nv_ebuf);
124 * Return error for the given nv structure.
127 nv_error(const struct nv *nv)
135 return (nv->nv_error);
139 * Set error for the given nv structure and return previous error.
142 nv_set_error(struct nv *nv, int error)
151 preverr = nv->nv_error;
152 nv->nv_error = error;
157 * Validate correctness of the entire nv structure and all its elements.
158 * If extrap is not NULL, store number of extra bytes at the end of the buffer.
161 nv_validate(struct nv *nv, size_t *extrap)
164 unsigned char *data, *ptr;
165 size_t dsize, size, vsize;
174 assert(nv->nv_error == 0);
176 /* TODO: Check that names are unique? */
179 ptr = ebuf_data(nv->nv_ebuf, &size);
182 * Zeros at the end of the buffer are acceptable.
187 * Minimum size at this point is size of nvhdr structure, one
188 * character long name plus terminating '\0'.
190 if (size < sizeof(*nvh) + 2) {
194 nvh = (struct nvhdr *)ptr;
195 if (size < NVH_HSIZE(nvh)) {
199 if (nvh->nvh_name[nvh->nvh_namesize - 1] != '\0') {
203 if (strlen(nvh->nvh_name) !=
204 (size_t)(nvh->nvh_namesize - 1)) {
208 if ((nvh->nvh_type & NV_TYPE_MASK) < NV_TYPE_FIRST ||
209 (nvh->nvh_type & NV_TYPE_MASK) > NV_TYPE_LAST) {
213 dsize = NVH_DSIZE(nvh);
218 if (size < NVH_SIZE(nvh)) {
223 switch (nvh->nvh_type & NV_TYPE_MASK) {
243 if (dsize != vsize) {
248 case NV_TYPE_INT8_ARRAY:
249 case NV_TYPE_UINT8_ARRAY:
251 case NV_TYPE_INT16_ARRAY:
252 case NV_TYPE_UINT16_ARRAY:
256 case NV_TYPE_INT32_ARRAY:
257 case NV_TYPE_UINT32_ARRAY:
261 case NV_TYPE_INT64_ARRAY:
262 case NV_TYPE_UINT64_ARRAY:
265 if ((dsize % vsize) != 0) {
271 data = NVH_DATA(nvh);
272 if (data[dsize - 1] != '\0') {
276 if (strlen((char *)data) != dsize - 1) {
282 assert(!"invalid condition");
286 ptr += NVH_SIZE(nvh);
287 size -= NVH_SIZE(nvh);
291 if (nv->nv_error == 0)
292 nv->nv_error = error;
301 * Convert the given nv structure to network byte order and return ebuf
305 nv_hton(struct nv *nv)
312 assert(nv->nv_error == 0);
314 ptr = ebuf_data(nv->nv_ebuf, &size);
317 * Minimum size at this point is size of nvhdr structure,
318 * one character long name plus terminating '\0'.
320 assert(size >= sizeof(*nvh) + 2);
321 nvh = (struct nvhdr *)ptr;
322 assert(NVH_SIZE(nvh) <= size);
324 ptr += NVH_SIZE(nvh);
325 size -= NVH_SIZE(nvh);
328 return (nv->nv_ebuf);
332 * Create nv structure based on ebuf received from the network.
335 nv_ntoh(struct ebuf *eb)
343 nv = malloc(sizeof(*nv));
348 nv->nv_magic = NV_MAGIC;
350 if (nv_validate(nv, &extra) < 0) {
358 * Remove extra zeros at the end of the buffer.
360 ebuf_del_tail(eb, extra);
365 #define NV_DEFINE_ADD(type, TYPE) \
367 nv_add_##type(struct nv *nv, type##_t value, const char *namefmt, ...) \
371 va_start(nameap, namefmt); \
372 nv_addv(nv, (unsigned char *)&value, sizeof(value), \
373 NV_TYPE_##TYPE, namefmt, nameap); \
377 NV_DEFINE_ADD(int8, INT8)
378 NV_DEFINE_ADD(uint8, UINT8)
379 NV_DEFINE_ADD(int16, INT16)
380 NV_DEFINE_ADD(uint16, UINT16)
381 NV_DEFINE_ADD(int32, INT32)
382 NV_DEFINE_ADD(uint32, UINT32)
383 NV_DEFINE_ADD(int64, INT64)
384 NV_DEFINE_ADD(uint64, UINT64)
388 #define NV_DEFINE_ADD_ARRAY(type, TYPE) \
390 nv_add_##type##_array(struct nv *nv, const type##_t *value, \
391 size_t nsize, const char *namefmt, ...) \
395 va_start(nameap, namefmt); \
396 nv_addv(nv, (const unsigned char *)value, \
397 sizeof(value[0]) * nsize, NV_TYPE_##TYPE##_ARRAY, namefmt, \
402 NV_DEFINE_ADD_ARRAY(int8, INT8)
403 NV_DEFINE_ADD_ARRAY(uint8, UINT8)
404 NV_DEFINE_ADD_ARRAY(int16, INT16)
405 NV_DEFINE_ADD_ARRAY(uint16, UINT16)
406 NV_DEFINE_ADD_ARRAY(int32, INT32)
407 NV_DEFINE_ADD_ARRAY(uint32, UINT32)
408 NV_DEFINE_ADD_ARRAY(int64, INT64)
409 NV_DEFINE_ADD_ARRAY(uint64, UINT64)
411 #undef NV_DEFINE_ADD_ARRAY
414 nv_add_string(struct nv *nv, const char *value, const char *namefmt, ...)
419 size = strlen(value) + 1;
421 va_start(nameap, namefmt);
422 nv_addv(nv, (const unsigned char *)value, size, NV_TYPE_STRING,
428 nv_add_stringf(struct nv *nv, const char *name, const char *valuefmt, ...)
432 va_start(valueap, valuefmt);
433 nv_add_stringv(nv, name, valuefmt, valueap);
438 nv_add_stringv(struct nv *nv, const char *name, const char *valuefmt,
444 size = vasprintf(&value, valuefmt, valueap);
446 if (nv->nv_error == 0)
447 nv->nv_error = ENOMEM;
451 nv_add(nv, (const unsigned char *)value, size, NV_TYPE_STRING, name);
455 #define NV_DEFINE_GET(type, TYPE) \
457 nv_get_##type(struct nv *nv, const char *namefmt, ...) \
463 va_start(nameap, namefmt); \
464 nvh = nv_find(nv, NV_TYPE_##TYPE, namefmt, nameap); \
468 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); \
469 assert(sizeof(value) == nvh->nvh_dsize); \
470 bcopy(NVH_DATA(nvh), &value, sizeof(value)); \
475 NV_DEFINE_GET(int8, INT8)
476 NV_DEFINE_GET(uint8, UINT8)
477 NV_DEFINE_GET(int16, INT16)
478 NV_DEFINE_GET(uint16, UINT16)
479 NV_DEFINE_GET(int32, INT32)
480 NV_DEFINE_GET(uint32, UINT32)
481 NV_DEFINE_GET(int64, INT64)
482 NV_DEFINE_GET(uint64, UINT64)
486 #define NV_DEFINE_GET_ARRAY(type, TYPE) \
488 nv_get_##type##_array(struct nv *nv, size_t *sizep, \
489 const char *namefmt, ...) \
494 va_start(nameap, namefmt); \
495 nvh = nv_find(nv, NV_TYPE_##TYPE##_ARRAY, namefmt, nameap); \
499 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); \
500 assert((nvh->nvh_dsize % sizeof(type##_t)) == 0); \
502 *sizep = nvh->nvh_dsize / sizeof(type##_t); \
503 return ((type##_t *)(void *)NVH_DATA(nvh)); \
506 NV_DEFINE_GET_ARRAY(int8, INT8)
507 NV_DEFINE_GET_ARRAY(uint8, UINT8)
508 NV_DEFINE_GET_ARRAY(int16, INT16)
509 NV_DEFINE_GET_ARRAY(uint16, UINT16)
510 NV_DEFINE_GET_ARRAY(int32, INT32)
511 NV_DEFINE_GET_ARRAY(uint32, UINT32)
512 NV_DEFINE_GET_ARRAY(int64, INT64)
513 NV_DEFINE_GET_ARRAY(uint64, UINT64)
515 #undef NV_DEFINE_GET_ARRAY
518 nv_get_string(struct nv *nv, const char *namefmt, ...)
524 va_start(nameap, namefmt);
525 nvh = nv_find(nv, NV_TYPE_STRING, namefmt, nameap);
529 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);
530 assert(nvh->nvh_dsize >= 1);
532 assert(str[nvh->nvh_dsize - 1] == '\0');
533 assert(strlen(str) == nvh->nvh_dsize - 1);
538 * Dump content of the nv structure.
541 nv_dump(struct nv *nv)
544 unsigned char *data, *ptr;
549 if (nv_validate(nv, NULL) < 0) {
550 printf("error: %d\n", errno);
555 assert(nv->nv_error == 0);
557 ptr = ebuf_data(nv->nv_ebuf, &size);
559 assert(size >= sizeof(*nvh) + 2);
560 nvh = (struct nvhdr *)ptr;
561 assert(size >= NVH_SIZE(nvh));
562 swap = ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK);
563 dsize = NVH_DSIZE(nvh);
564 data = NVH_DATA(nvh);
565 printf(" %s", nvh->nvh_name);
566 switch (nvh->nvh_type & NV_TYPE_MASK) {
568 printf("(int8): %jd", (intmax_t)(*(int8_t *)data));
571 printf("(uint8): %ju", (uintmax_t)(*(uint8_t *)data));
574 printf("(int16): %jd", swap ?
575 (intmax_t)le16toh(*(int16_t *)(void *)data) :
576 (intmax_t)*(int16_t *)(void *)data);
579 printf("(uint16): %ju", swap ?
580 (uintmax_t)le16toh(*(uint16_t *)(void *)data) :
581 (uintmax_t)*(uint16_t *)(void *)data);
584 printf("(int32): %jd", swap ?
585 (intmax_t)le32toh(*(int32_t *)(void *)data) :
586 (intmax_t)*(int32_t *)(void *)data);
589 printf("(uint32): %ju", swap ?
590 (uintmax_t)le32toh(*(uint32_t *)(void *)data) :
591 (uintmax_t)*(uint32_t *)(void *)data);
594 printf("(int64): %jd", swap ?
595 (intmax_t)le64toh(*(int64_t *)(void *)data) :
596 (intmax_t)*(int64_t *)(void *)data);
599 printf("(uint64): %ju", swap ?
600 (uintmax_t)le64toh(*(uint64_t *)(void *)data) :
601 (uintmax_t)*(uint64_t *)(void *)data);
603 case NV_TYPE_INT8_ARRAY:
604 printf("(int8 array):");
605 for (ii = 0; ii < dsize; ii++)
606 printf(" %jd", (intmax_t)((int8_t *)data)[ii]);
608 case NV_TYPE_UINT8_ARRAY:
609 printf("(uint8 array):");
610 for (ii = 0; ii < dsize; ii++)
611 printf(" %ju", (uintmax_t)((uint8_t *)data)[ii]);
613 case NV_TYPE_INT16_ARRAY:
614 printf("(int16 array):");
615 for (ii = 0; ii < dsize / 2; ii++) {
616 printf(" %jd", swap ?
617 (intmax_t)le16toh(((int16_t *)(void *)data)[ii]) :
618 (intmax_t)((int16_t *)(void *)data)[ii]);
621 case NV_TYPE_UINT16_ARRAY:
622 printf("(uint16 array):");
623 for (ii = 0; ii < dsize / 2; ii++) {
624 printf(" %ju", swap ?
625 (uintmax_t)le16toh(((uint16_t *)(void *)data)[ii]) :
626 (uintmax_t)((uint16_t *)(void *)data)[ii]);
629 case NV_TYPE_INT32_ARRAY:
630 printf("(int32 array):");
631 for (ii = 0; ii < dsize / 4; ii++) {
632 printf(" %jd", swap ?
633 (intmax_t)le32toh(((int32_t *)(void *)data)[ii]) :
634 (intmax_t)((int32_t *)(void *)data)[ii]);
637 case NV_TYPE_UINT32_ARRAY:
638 printf("(uint32 array):");
639 for (ii = 0; ii < dsize / 4; ii++) {
640 printf(" %ju", swap ?
641 (uintmax_t)le32toh(((uint32_t *)(void *)data)[ii]) :
642 (uintmax_t)((uint32_t *)(void *)data)[ii]);
645 case NV_TYPE_INT64_ARRAY:
646 printf("(int64 array):");
647 for (ii = 0; ii < dsize / 8; ii++) {
648 printf(" %ju", swap ?
649 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
650 (uintmax_t)((uint64_t *)(void *)data)[ii]);
653 case NV_TYPE_UINT64_ARRAY:
654 printf("(uint64 array):");
655 for (ii = 0; ii < dsize / 8; ii++) {
656 printf(" %ju", swap ?
657 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
658 (uintmax_t)((uint64_t *)(void *)data)[ii]);
662 printf("(string): %s", (char *)data);
665 assert(!"invalid condition");
668 ptr += NVH_SIZE(nvh);
669 size -= NVH_SIZE(nvh);
674 * Local routines below.
678 nv_add(struct nv *nv, const unsigned char *value, size_t vsize, int type,
681 static unsigned char align[7];
692 namesize = strlen(name) + 1;
694 nvh = malloc(sizeof(*nvh) + roundup2(namesize, 8));
696 if (nv->nv_error == 0)
697 nv->nv_error = ENOMEM;
700 nvh->nvh_type = NV_ORDER_HOST | type;
701 nvh->nvh_namesize = (uint8_t)namesize;
702 nvh->nvh_dsize = (uint32_t)vsize;
703 bcopy(name, nvh->nvh_name, namesize);
705 /* Add header first. */
706 if (ebuf_add_tail(nv->nv_ebuf, nvh, NVH_HSIZE(nvh)) < 0) {
708 if (nv->nv_error == 0)
709 nv->nv_error = errno;
714 /* Add the actual data. */
715 if (ebuf_add_tail(nv->nv_ebuf, value, vsize) < 0) {
717 if (nv->nv_error == 0)
718 nv->nv_error = errno;
721 /* Align the data (if needed). */
722 vsize = roundup2(vsize, 8) - vsize;
725 assert(vsize > 0 && vsize <= sizeof(align));
726 if (ebuf_add_tail(nv->nv_ebuf, align, vsize) < 0) {
728 if (nv->nv_error == 0)
729 nv->nv_error = errno;
735 nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, int type,
736 const char *namefmt, va_list nameap)
741 namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
742 assert(namesize > 0 && namesize < sizeof(name));
744 nv_add(nv, value, vsize, type, name);
747 static struct nvhdr *
748 nv_find(struct nv *nv, int type, const char *namefmt, va_list nameap)
753 size_t size, namesize;
762 namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
763 assert(namesize > 0 && namesize < sizeof(name));
766 ptr = ebuf_data(nv->nv_ebuf, &size);
768 assert(size >= sizeof(*nvh) + 2);
769 nvh = (struct nvhdr *)ptr;
770 assert(size >= NVH_SIZE(nvh));
772 if (strcmp(nvh->nvh_name, name) == 0) {
773 if ((nvh->nvh_type & NV_TYPE_MASK) != type) {
775 if (nv->nv_error == 0)
776 nv->nv_error = EINVAL;
781 ptr += NVH_SIZE(nvh);
782 size -= NVH_SIZE(nvh);
785 if (nv->nv_error == 0)
786 nv->nv_error = ENOENT;
791 nv_swap(struct nvhdr *nvh, bool tohost)
793 unsigned char *data, *end, *p;
796 data = NVH_DATA(nvh);
798 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST)
800 nvh->nvh_dsize = le32toh(nvh->nvh_dsize);
801 end = data + nvh->nvh_dsize;
802 nvh->nvh_type &= ~NV_ORDER_MASK;
803 nvh->nvh_type |= NV_ORDER_HOST;
805 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK)
807 end = data + nvh->nvh_dsize;
808 nvh->nvh_dsize = htole32(nvh->nvh_dsize);
809 nvh->nvh_type &= ~NV_ORDER_MASK;
810 nvh->nvh_type |= NV_ORDER_NETWORK;
815 switch (nvh->nvh_type & NV_TYPE_MASK) {
818 case NV_TYPE_INT8_ARRAY:
819 case NV_TYPE_UINT8_ARRAY:
823 case NV_TYPE_INT16_ARRAY:
824 case NV_TYPE_UINT16_ARRAY:
830 case NV_TYPE_INT32_ARRAY:
831 case NV_TYPE_UINT32_ARRAY:
837 case NV_TYPE_INT64_ARRAY:
838 case NV_TYPE_UINT64_ARRAY:
841 for (p = data; p < end; p += vsize) {
845 *(uint16_t *)(void *)p =
846 le16toh(*(uint16_t *)(void *)p);
849 *(uint32_t *)(void *)p =
850 le32toh(*(uint32_t *)(void *)p);
853 *(uint64_t *)(void *)p =
854 le64toh(*(uint64_t *)(void *)p);
857 assert(!"invalid condition");
862 *(uint16_t *)(void *)p =
863 htole16(*(uint16_t *)(void *)p);
866 *(uint32_t *)(void *)p =
867 htole32(*(uint32_t *)(void *)p);
870 *(uint64_t *)(void *)p =
871 htole64(*(uint64_t *)(void *)p);
874 assert(!"invalid condition");
882 assert(!"unrecognized type");