1 /*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Pawel Jakub Dawidek under sponsorship from 6 * the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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. 16 * 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 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/endian.h> 35 36 #include <assert.h> 37 #include <bitstring.h> 38 #include <errno.h> 39 #include <stdarg.h> 40 #include <stdbool.h> 41 #include <stdint.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include <ebuf.h> 47 #include <nv.h> 48 49 #define NV_TYPE_INT8 1 50 #define NV_TYPE_UINT8 2 51 #define NV_TYPE_INT16 3 52 #define NV_TYPE_UINT16 4 53 #define NV_TYPE_INT32 5 54 #define NV_TYPE_UINT32 6 55 #define NV_TYPE_INT64 7 56 #define NV_TYPE_UINT64 8 57 #define NV_TYPE_INT8_ARRAY 9 58 #define NV_TYPE_UINT8_ARRAY 10 59 #define NV_TYPE_INT16_ARRAY 11 60 #define NV_TYPE_UINT16_ARRAY 12 61 #define NV_TYPE_INT32_ARRAY 13 62 #define NV_TYPE_UINT32_ARRAY 14 63 #define NV_TYPE_INT64_ARRAY 15 64 #define NV_TYPE_UINT64_ARRAY 16 65 #define NV_TYPE_STRING 17 66 67 #define NV_TYPE_MASK 0x7f 68 #define NV_TYPE_FIRST NV_TYPE_INT8 69 #define NV_TYPE_LAST NV_TYPE_STRING 70 71 #define NV_ORDER_NETWORK 0x00 72 #define NV_ORDER_HOST 0x80 73 74 #define NV_ORDER_MASK 0x80 75 76 #define NV_MAGIC 0xaea1e 77 struct nv { 78 int nv_magic; 79 int nv_error; 80 struct ebuf *nv_ebuf; 81 }; 82 83 struct nvhdr { 84 uint8_t nvh_type; 85 uint8_t nvh_namesize; 86 uint32_t nvh_dsize; 87 char nvh_name[0]; 88 } __packed; 89 #define NVH_DATA(nvh) ((unsigned char *)nvh + NVH_HSIZE(nvh)) 90 #define NVH_HSIZE(nvh) \ 91 (sizeof(struct nvhdr) + roundup2((nvh)->nvh_namesize, 8)) 92 #define NVH_DSIZE(nvh) \ 93 (((nvh)->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST ? \ 94 (nvh)->nvh_dsize : \ 95 le32toh((nvh)->nvh_dsize)) 96 #define NVH_SIZE(nvh) (NVH_HSIZE(nvh) + roundup2(NVH_DSIZE(nvh), 8)) 97 98 #define NV_CHECK(nv) do { \ 99 assert((nv) != NULL); \ 100 assert((nv)->nv_magic == NV_MAGIC); \ 101 } while (0) 102 103 static void nv_add(struct nv *nv, const unsigned char *value, size_t vsize, 104 int type, const char *name); 105 static void nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, 106 int type, const char *namefmt, va_list nameap); 107 static struct nvhdr *nv_find(struct nv *nv, int type, const char *namefmt, 108 va_list nameap); 109 static void nv_swap(struct nvhdr *nvh, bool tohost); 110 111 /* 112 * Allocate and initialize new nv structure. 113 * Return NULL in case of malloc(3) failure. 114 */ 115 struct nv * 116 nv_alloc(void) 117 { 118 struct nv *nv; 119 120 nv = malloc(sizeof(*nv)); 121 if (nv == NULL) 122 return (NULL); 123 nv->nv_ebuf = ebuf_alloc(0); 124 if (nv->nv_ebuf == NULL) { 125 free(nv); 126 return (NULL); 127 } 128 nv->nv_error = 0; 129 nv->nv_magic = NV_MAGIC; 130 return (nv); 131 } 132 133 /* 134 * Free the given nv structure. 135 */ 136 void 137 nv_free(struct nv *nv) 138 { 139 140 if (nv == NULL) 141 return; 142 143 NV_CHECK(nv); 144 145 nv->nv_magic = 0; 146 ebuf_free(nv->nv_ebuf); 147 free(nv); 148 } 149 150 /* 151 * Return error for the given nv structure. 152 */ 153 int 154 nv_error(const struct nv *nv) 155 { 156 157 if (nv == NULL) 158 return (ENOMEM); 159 160 NV_CHECK(nv); 161 162 return (nv->nv_error); 163 } 164 165 /* 166 * Set error for the given nv structure and return previous error. 167 */ 168 int 169 nv_set_error(struct nv *nv, int error) 170 { 171 int preverr; 172 173 if (nv == NULL) 174 return (ENOMEM); 175 176 NV_CHECK(nv); 177 178 preverr = nv->nv_error; 179 nv->nv_error = error; 180 return (preverr); 181 } 182 183 /* 184 * Validate correctness of the entire nv structure and all its elements. 185 * If extrap is not NULL, store number of extra bytes at the end of the buffer. 186 */ 187 int 188 nv_validate(struct nv *nv, size_t *extrap) 189 { 190 struct nvhdr *nvh; 191 unsigned char *data, *ptr; 192 size_t dsize, size, vsize; 193 int error; 194 195 if (nv == NULL) { 196 errno = ENOMEM; 197 return (-1); 198 } 199 200 NV_CHECK(nv); 201 assert(nv->nv_error == 0); 202 203 /* TODO: Check that names are unique? */ 204 205 error = 0; 206 ptr = ebuf_data(nv->nv_ebuf, &size); 207 while (size > 0) { 208 /* 209 * Zeros at the end of the buffer are acceptable. 210 */ 211 if (ptr[0] == '\0') 212 break; 213 /* 214 * Minimum size at this point is size of nvhdr structure, one 215 * character long name plus terminating '\0'. 216 */ 217 if (size < sizeof(*nvh) + 2) { 218 error = EINVAL; 219 break; 220 } 221 nvh = (struct nvhdr *)ptr; 222 if (size < NVH_HSIZE(nvh)) { 223 error = EINVAL; 224 break; 225 } 226 if (nvh->nvh_name[nvh->nvh_namesize - 1] != '\0') { 227 error = EINVAL; 228 break; 229 } 230 if (strlen(nvh->nvh_name) != 231 (size_t)(nvh->nvh_namesize - 1)) { 232 error = EINVAL; 233 break; 234 } 235 if ((nvh->nvh_type & NV_TYPE_MASK) < NV_TYPE_FIRST || 236 (nvh->nvh_type & NV_TYPE_MASK) > NV_TYPE_LAST) { 237 error = EINVAL; 238 break; 239 } 240 dsize = NVH_DSIZE(nvh); 241 if (dsize == 0) { 242 error = EINVAL; 243 break; 244 } 245 if (size < NVH_SIZE(nvh)) { 246 error = EINVAL; 247 break; 248 } 249 vsize = 0; 250 switch (nvh->nvh_type & NV_TYPE_MASK) { 251 case NV_TYPE_INT8: 252 case NV_TYPE_UINT8: 253 if (vsize == 0) 254 vsize = 1; 255 /* FALLTHOUGH */ 256 case NV_TYPE_INT16: 257 case NV_TYPE_UINT16: 258 if (vsize == 0) 259 vsize = 2; 260 /* FALLTHOUGH */ 261 case NV_TYPE_INT32: 262 case NV_TYPE_UINT32: 263 if (vsize == 0) 264 vsize = 4; 265 /* FALLTHOUGH */ 266 case NV_TYPE_INT64: 267 case NV_TYPE_UINT64: 268 if (vsize == 0) 269 vsize = 8; 270 if (dsize != vsize) { 271 error = EINVAL; 272 break; 273 } 274 break; 275 case NV_TYPE_INT8_ARRAY: 276 case NV_TYPE_UINT8_ARRAY: 277 break; 278 case NV_TYPE_INT16_ARRAY: 279 case NV_TYPE_UINT16_ARRAY: 280 if (vsize == 0) 281 vsize = 2; 282 /* FALLTHOUGH */ 283 case NV_TYPE_INT32_ARRAY: 284 case NV_TYPE_UINT32_ARRAY: 285 if (vsize == 0) 286 vsize = 4; 287 /* FALLTHOUGH */ 288 case NV_TYPE_INT64_ARRAY: 289 case NV_TYPE_UINT64_ARRAY: 290 if (vsize == 0) 291 vsize = 8; 292 if ((dsize % vsize) != 0) { 293 error = EINVAL; 294 break; 295 } 296 break; 297 case NV_TYPE_STRING: 298 data = NVH_DATA(nvh); 299 if (data[dsize - 1] != '\0') { 300 error = EINVAL; 301 break; 302 } 303 if (strlen((char *)data) != dsize - 1) { 304 error = EINVAL; 305 break; 306 } 307 break; 308 default: 309 assert(!"invalid condition"); 310 } 311 if (error != 0) 312 break; 313 ptr += NVH_SIZE(nvh); 314 size -= NVH_SIZE(nvh); 315 } 316 if (error != 0) { 317 errno = error; 318 if (nv->nv_error == 0) 319 nv->nv_error = error; 320 return (-1); 321 } 322 if (extrap != NULL) 323 *extrap = size; 324 return (0); 325 } 326 327 /* 328 * Convert the given nv structure to network byte order and return ebuf 329 * structure. 330 */ 331 struct ebuf * 332 nv_hton(struct nv *nv) 333 { 334 struct nvhdr *nvh; 335 unsigned char *ptr; 336 size_t size; 337 338 NV_CHECK(nv); 339 assert(nv->nv_error == 0); 340 341 ptr = ebuf_data(nv->nv_ebuf, &size); 342 while (size > 0) { 343 /* 344 * Minimum size at this point is size of nvhdr structure, 345 * one character long name plus terminating '\0'. 346 */ 347 assert(size >= sizeof(*nvh) + 2); 348 nvh = (struct nvhdr *)ptr; 349 assert(NVH_SIZE(nvh) <= size); 350 nv_swap(nvh, false); 351 ptr += NVH_SIZE(nvh); 352 size -= NVH_SIZE(nvh); 353 } 354 355 return (nv->nv_ebuf); 356 } 357 358 /* 359 * Create nv structure based on ebuf received from the network. 360 */ 361 struct nv * 362 nv_ntoh(struct ebuf *eb) 363 { 364 struct nv *nv; 365 size_t extra; 366 int rerrno; 367 368 assert(eb != NULL); 369 370 nv = malloc(sizeof(*nv)); 371 if (nv == NULL) 372 return (NULL); 373 nv->nv_error = 0; 374 nv->nv_ebuf = eb; 375 nv->nv_magic = NV_MAGIC; 376 377 if (nv_validate(nv, &extra) < 0) { 378 rerrno = errno; 379 nv->nv_magic = 0; 380 free(nv); 381 errno = rerrno; 382 return (NULL); 383 } 384 /* 385 * Remove extra zeros at the end of the buffer. 386 */ 387 ebuf_del_tail(eb, extra); 388 389 return (nv); 390 } 391 392 #define NV_DEFINE_ADD(type, TYPE) \ 393 void \ 394 nv_add_##type(struct nv *nv, type##_t value, const char *namefmt, ...) \ 395 { \ 396 va_list nameap; \ 397 \ 398 va_start(nameap, namefmt); \ 399 nv_addv(nv, (unsigned char *)&value, sizeof(value), \ 400 NV_TYPE_##TYPE, namefmt, nameap); \ 401 va_end(nameap); \ 402 } 403 404 NV_DEFINE_ADD(int8, INT8) 405 NV_DEFINE_ADD(uint8, UINT8) 406 NV_DEFINE_ADD(int16, INT16) 407 NV_DEFINE_ADD(uint16, UINT16) 408 NV_DEFINE_ADD(int32, INT32) 409 NV_DEFINE_ADD(uint32, UINT32) 410 NV_DEFINE_ADD(int64, INT64) 411 NV_DEFINE_ADD(uint64, UINT64) 412 413 #undef NV_DEFINE_ADD 414 415 #define NV_DEFINE_ADD_ARRAY(type, TYPE) \ 416 void \ 417 nv_add_##type##_array(struct nv *nv, const type##_t *value, \ 418 size_t nsize, const char *namefmt, ...) \ 419 { \ 420 va_list nameap; \ 421 \ 422 va_start(nameap, namefmt); \ 423 nv_addv(nv, (const unsigned char *)value, \ 424 sizeof(value[0]) * nsize, NV_TYPE_##TYPE##_ARRAY, namefmt, \ 425 nameap); \ 426 va_end(nameap); \ 427 } 428 429 NV_DEFINE_ADD_ARRAY(int8, INT8) 430 NV_DEFINE_ADD_ARRAY(uint8, UINT8) 431 NV_DEFINE_ADD_ARRAY(int16, INT16) 432 NV_DEFINE_ADD_ARRAY(uint16, UINT16) 433 NV_DEFINE_ADD_ARRAY(int32, INT32) 434 NV_DEFINE_ADD_ARRAY(uint32, UINT32) 435 NV_DEFINE_ADD_ARRAY(int64, INT64) 436 NV_DEFINE_ADD_ARRAY(uint64, UINT64) 437 438 #undef NV_DEFINE_ADD_ARRAY 439 440 void 441 nv_add_string(struct nv *nv, const char *value, const char *namefmt, ...) 442 { 443 va_list nameap; 444 size_t size; 445 446 size = strlen(value) + 1; 447 448 va_start(nameap, namefmt); 449 nv_addv(nv, (const unsigned char *)value, size, NV_TYPE_STRING, 450 namefmt, nameap); 451 va_end(nameap); 452 } 453 454 void 455 nv_add_stringf(struct nv *nv, const char *name, const char *valuefmt, ...) 456 { 457 va_list valueap; 458 459 va_start(valueap, valuefmt); 460 nv_add_stringv(nv, name, valuefmt, valueap); 461 va_end(valueap); 462 } 463 464 void 465 nv_add_stringv(struct nv *nv, const char *name, const char *valuefmt, 466 va_list valueap) 467 { 468 char *value; 469 ssize_t size; 470 471 size = vasprintf(&value, valuefmt, valueap); 472 if (size < 0) { 473 if (nv->nv_error == 0) 474 nv->nv_error = ENOMEM; 475 return; 476 } 477 size++; 478 nv_add(nv, (const unsigned char *)value, size, NV_TYPE_STRING, name); 479 free(value); 480 } 481 482 #define NV_DEFINE_GET(type, TYPE) \ 483 type##_t \ 484 nv_get_##type(struct nv *nv, const char *namefmt, ...) \ 485 { \ 486 struct nvhdr *nvh; \ 487 va_list nameap; \ 488 type##_t value; \ 489 \ 490 va_start(nameap, namefmt); \ 491 nvh = nv_find(nv, NV_TYPE_##TYPE, namefmt, nameap); \ 492 va_end(nameap); \ 493 if (nvh == NULL) \ 494 return (0); \ 495 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); \ 496 assert(sizeof(value) == nvh->nvh_dsize); \ 497 bcopy(NVH_DATA(nvh), &value, sizeof(value)); \ 498 \ 499 return (value); \ 500 } 501 502 NV_DEFINE_GET(int8, INT8) 503 NV_DEFINE_GET(uint8, UINT8) 504 NV_DEFINE_GET(int16, INT16) 505 NV_DEFINE_GET(uint16, UINT16) 506 NV_DEFINE_GET(int32, INT32) 507 NV_DEFINE_GET(uint32, UINT32) 508 NV_DEFINE_GET(int64, INT64) 509 NV_DEFINE_GET(uint64, UINT64) 510 511 #undef NV_DEFINE_GET 512 513 #define NV_DEFINE_GET_ARRAY(type, TYPE) \ 514 const type##_t * \ 515 nv_get_##type##_array(struct nv *nv, size_t *sizep, \ 516 const char *namefmt, ...) \ 517 { \ 518 struct nvhdr *nvh; \ 519 va_list nameap; \ 520 \ 521 va_start(nameap, namefmt); \ 522 nvh = nv_find(nv, NV_TYPE_##TYPE##_ARRAY, namefmt, nameap); \ 523 va_end(nameap); \ 524 if (nvh == NULL) \ 525 return (NULL); \ 526 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); \ 527 assert((nvh->nvh_dsize % sizeof(type##_t)) == 0); \ 528 if (sizep != NULL) \ 529 *sizep = nvh->nvh_dsize / sizeof(type##_t); \ 530 return ((type##_t *)(void *)NVH_DATA(nvh)); \ 531 } 532 533 NV_DEFINE_GET_ARRAY(int8, INT8) 534 NV_DEFINE_GET_ARRAY(uint8, UINT8) 535 NV_DEFINE_GET_ARRAY(int16, INT16) 536 NV_DEFINE_GET_ARRAY(uint16, UINT16) 537 NV_DEFINE_GET_ARRAY(int32, INT32) 538 NV_DEFINE_GET_ARRAY(uint32, UINT32) 539 NV_DEFINE_GET_ARRAY(int64, INT64) 540 NV_DEFINE_GET_ARRAY(uint64, UINT64) 541 542 #undef NV_DEFINE_GET_ARRAY 543 544 const char * 545 nv_get_string(struct nv *nv, const char *namefmt, ...) 546 { 547 struct nvhdr *nvh; 548 va_list nameap; 549 char *str; 550 551 va_start(nameap, namefmt); 552 nvh = nv_find(nv, NV_TYPE_STRING, namefmt, nameap); 553 va_end(nameap); 554 if (nvh == NULL) 555 return (NULL); 556 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); 557 assert(nvh->nvh_dsize >= 1); 558 str = NVH_DATA(nvh); 559 assert(str[nvh->nvh_dsize - 1] == '\0'); 560 assert(strlen(str) == nvh->nvh_dsize - 1); 561 return (str); 562 } 563 564 /* 565 * Dump content of the nv structure. 566 */ 567 void 568 nv_dump(struct nv *nv) 569 { 570 struct nvhdr *nvh; 571 unsigned char *data, *ptr; 572 size_t dsize, size; 573 unsigned int ii; 574 bool swap; 575 576 if (nv_validate(nv, NULL) < 0) { 577 printf("error: %d\n", errno); 578 return; 579 } 580 581 NV_CHECK(nv); 582 assert(nv->nv_error == 0); 583 584 ptr = ebuf_data(nv->nv_ebuf, &size); 585 while (size > 0) { 586 assert(size >= sizeof(*nvh) + 2); 587 nvh = (struct nvhdr *)ptr; 588 assert(size >= NVH_SIZE(nvh)); 589 swap = ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK); 590 dsize = NVH_DSIZE(nvh); 591 data = NVH_DATA(nvh); 592 printf(" %s", nvh->nvh_name); 593 switch (nvh->nvh_type & NV_TYPE_MASK) { 594 case NV_TYPE_INT8: 595 printf("(int8): %jd", (intmax_t)(*(int8_t *)data)); 596 break; 597 case NV_TYPE_UINT8: 598 printf("(uint8): %ju", (uintmax_t)(*(uint8_t *)data)); 599 break; 600 case NV_TYPE_INT16: 601 printf("(int16): %jd", swap ? 602 (intmax_t)le16toh(*(int16_t *)(void *)data) : 603 (intmax_t)*(int16_t *)(void *)data); 604 break; 605 case NV_TYPE_UINT16: 606 printf("(uint16): %ju", swap ? 607 (uintmax_t)le16toh(*(uint16_t *)(void *)data) : 608 (uintmax_t)*(uint16_t *)(void *)data); 609 break; 610 case NV_TYPE_INT32: 611 printf("(int32): %jd", swap ? 612 (intmax_t)le32toh(*(int32_t *)(void *)data) : 613 (intmax_t)*(int32_t *)(void *)data); 614 break; 615 case NV_TYPE_UINT32: 616 printf("(uint32): %ju", swap ? 617 (uintmax_t)le32toh(*(uint32_t *)(void *)data) : 618 (uintmax_t)*(uint32_t *)(void *)data); 619 break; 620 case NV_TYPE_INT64: 621 printf("(int64): %jd", swap ? 622 (intmax_t)le64toh(*(int64_t *)(void *)data) : 623 (intmax_t)*(int64_t *)(void *)data); 624 break; 625 case NV_TYPE_UINT64: 626 printf("(uint64): %ju", swap ? 627 (uintmax_t)le64toh(*(uint64_t *)(void *)data) : 628 (uintmax_t)*(uint64_t *)(void *)data); 629 break; 630 case NV_TYPE_INT8_ARRAY: 631 printf("(int8 array):"); 632 for (ii = 0; ii < dsize; ii++) 633 printf(" %jd", (intmax_t)((int8_t *)data)[ii]); 634 break; 635 case NV_TYPE_UINT8_ARRAY: 636 printf("(uint8 array):"); 637 for (ii = 0; ii < dsize; ii++) 638 printf(" %ju", (uintmax_t)((uint8_t *)data)[ii]); 639 break; 640 case NV_TYPE_INT16_ARRAY: 641 printf("(int16 array):"); 642 for (ii = 0; ii < dsize / 2; ii++) { 643 printf(" %jd", swap ? 644 (intmax_t)le16toh(((int16_t *)(void *)data)[ii]) : 645 (intmax_t)((int16_t *)(void *)data)[ii]); 646 } 647 break; 648 case NV_TYPE_UINT16_ARRAY: 649 printf("(uint16 array):"); 650 for (ii = 0; ii < dsize / 2; ii++) { 651 printf(" %ju", swap ? 652 (uintmax_t)le16toh(((uint16_t *)(void *)data)[ii]) : 653 (uintmax_t)((uint16_t *)(void *)data)[ii]); 654 } 655 break; 656 case NV_TYPE_INT32_ARRAY: 657 printf("(int32 array):"); 658 for (ii = 0; ii < dsize / 4; ii++) { 659 printf(" %jd", swap ? 660 (intmax_t)le32toh(((int32_t *)(void *)data)[ii]) : 661 (intmax_t)((int32_t *)(void *)data)[ii]); 662 } 663 break; 664 case NV_TYPE_UINT32_ARRAY: 665 printf("(uint32 array):"); 666 for (ii = 0; ii < dsize / 4; ii++) { 667 printf(" %ju", swap ? 668 (uintmax_t)le32toh(((uint32_t *)(void *)data)[ii]) : 669 (uintmax_t)((uint32_t *)(void *)data)[ii]); 670 } 671 break; 672 case NV_TYPE_INT64_ARRAY: 673 printf("(int64 array):"); 674 for (ii = 0; ii < dsize / 8; ii++) { 675 printf(" %ju", swap ? 676 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) : 677 (uintmax_t)((uint64_t *)(void *)data)[ii]); 678 } 679 break; 680 case NV_TYPE_UINT64_ARRAY: 681 printf("(uint64 array):"); 682 for (ii = 0; ii < dsize / 8; ii++) { 683 printf(" %ju", swap ? 684 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) : 685 (uintmax_t)((uint64_t *)(void *)data)[ii]); 686 } 687 break; 688 case NV_TYPE_STRING: 689 printf("(string): %s", (char *)data); 690 break; 691 default: 692 assert(!"invalid condition"); 693 } 694 printf("\n"); 695 ptr += NVH_SIZE(nvh); 696 size -= NVH_SIZE(nvh); 697 } 698 } 699 700 /* 701 * Local routines below. 702 */ 703 704 static void 705 nv_add(struct nv *nv, const unsigned char *value, size_t vsize, int type, 706 const char *name) 707 { 708 static unsigned char align[7]; 709 struct nvhdr *nvh; 710 size_t namesize; 711 712 if (nv == NULL) { 713 errno = ENOMEM; 714 return; 715 } 716 717 NV_CHECK(nv); 718 719 namesize = strlen(name) + 1; 720 721 nvh = malloc(sizeof(*nvh) + roundup2(namesize, 8)); 722 if (nvh == NULL) { 723 if (nv->nv_error == 0) 724 nv->nv_error = ENOMEM; 725 return; 726 } 727 nvh->nvh_type = NV_ORDER_HOST | type; 728 nvh->nvh_namesize = (uint8_t)namesize; 729 nvh->nvh_dsize = (uint32_t)vsize; 730 bcopy(name, nvh->nvh_name, namesize); 731 732 /* Add header first. */ 733 if (ebuf_add_tail(nv->nv_ebuf, nvh, NVH_HSIZE(nvh)) < 0) { 734 assert(errno != 0); 735 if (nv->nv_error == 0) 736 nv->nv_error = errno; 737 free(nvh); 738 return; 739 } 740 free(nvh); 741 /* Add the actual data. */ 742 if (ebuf_add_tail(nv->nv_ebuf, value, vsize) < 0) { 743 assert(errno != 0); 744 if (nv->nv_error == 0) 745 nv->nv_error = errno; 746 return; 747 } 748 /* Align the data (if needed). */ 749 vsize = roundup2(vsize, 8) - vsize; 750 if (vsize == 0) 751 return; 752 assert(vsize > 0 && vsize <= sizeof(align)); 753 if (ebuf_add_tail(nv->nv_ebuf, align, vsize) < 0) { 754 assert(errno != 0); 755 if (nv->nv_error == 0) 756 nv->nv_error = errno; 757 return; 758 } 759 } 760 761 static void 762 nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, int type, 763 const char *namefmt, va_list nameap) 764 { 765 char name[255]; 766 size_t namesize; 767 768 namesize = vsnprintf(name, sizeof(name), namefmt, nameap); 769 assert(namesize > 0 && namesize < sizeof(name)); 770 771 nv_add(nv, value, vsize, type, name); 772 } 773 774 static struct nvhdr * 775 nv_find(struct nv *nv, int type, const char *namefmt, va_list nameap) 776 { 777 char name[255]; 778 struct nvhdr *nvh; 779 unsigned char *ptr; 780 size_t size, namesize; 781 782 if (nv == NULL) { 783 errno = ENOMEM; 784 return (NULL); 785 } 786 787 NV_CHECK(nv); 788 789 namesize = vsnprintf(name, sizeof(name), namefmt, nameap); 790 assert(namesize > 0 && namesize < sizeof(name)); 791 namesize++; 792 793 ptr = ebuf_data(nv->nv_ebuf, &size); 794 while (size > 0) { 795 assert(size >= sizeof(*nvh) + 2); 796 nvh = (struct nvhdr *)ptr; 797 assert(size >= NVH_SIZE(nvh)); 798 nv_swap(nvh, true); 799 if (strcmp(nvh->nvh_name, name) == 0) { 800 if ((nvh->nvh_type & NV_TYPE_MASK) != type) { 801 errno = EINVAL; 802 if (nv->nv_error == 0) 803 nv->nv_error = EINVAL; 804 return (NULL); 805 } 806 return (nvh); 807 } 808 ptr += NVH_SIZE(nvh); 809 size -= NVH_SIZE(nvh); 810 } 811 errno = ENOENT; 812 if (nv->nv_error == 0) 813 nv->nv_error = ENOENT; 814 return (NULL); 815 } 816 817 static void 818 nv_swap(struct nvhdr *nvh, bool tohost) 819 { 820 unsigned char *data, *end, *p; 821 size_t vsize; 822 823 data = NVH_DATA(nvh); 824 if (tohost) { 825 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST) 826 return; 827 nvh->nvh_dsize = le32toh(nvh->nvh_dsize); 828 end = data + nvh->nvh_dsize; 829 nvh->nvh_type &= ~NV_ORDER_MASK; 830 nvh->nvh_type |= NV_ORDER_HOST; 831 } else { 832 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK) 833 return; 834 end = data + nvh->nvh_dsize; 835 nvh->nvh_dsize = htole32(nvh->nvh_dsize); 836 nvh->nvh_type &= ~NV_ORDER_MASK; 837 nvh->nvh_type |= NV_ORDER_NETWORK; 838 } 839 840 vsize = 0; 841 842 switch (nvh->nvh_type & NV_TYPE_MASK) { 843 case NV_TYPE_INT8: 844 case NV_TYPE_UINT8: 845 case NV_TYPE_INT8_ARRAY: 846 case NV_TYPE_UINT8_ARRAY: 847 break; 848 case NV_TYPE_INT16: 849 case NV_TYPE_UINT16: 850 case NV_TYPE_INT16_ARRAY: 851 case NV_TYPE_UINT16_ARRAY: 852 if (vsize == 0) 853 vsize = 2; 854 /* FALLTHOUGH */ 855 case NV_TYPE_INT32: 856 case NV_TYPE_UINT32: 857 case NV_TYPE_INT32_ARRAY: 858 case NV_TYPE_UINT32_ARRAY: 859 if (vsize == 0) 860 vsize = 4; 861 /* FALLTHOUGH */ 862 case NV_TYPE_INT64: 863 case NV_TYPE_UINT64: 864 case NV_TYPE_INT64_ARRAY: 865 case NV_TYPE_UINT64_ARRAY: 866 if (vsize == 0) 867 vsize = 8; 868 for (p = data; p < end; p += vsize) { 869 if (tohost) { 870 switch (vsize) { 871 case 2: 872 *(uint16_t *)(void *)p = 873 le16toh(*(uint16_t *)(void *)p); 874 break; 875 case 4: 876 *(uint32_t *)(void *)p = 877 le32toh(*(uint32_t *)(void *)p); 878 break; 879 case 8: 880 *(uint64_t *)(void *)p = 881 le64toh(*(uint64_t *)(void *)p); 882 break; 883 default: 884 assert(!"invalid condition"); 885 } 886 } else { 887 switch (vsize) { 888 case 2: 889 *(uint16_t *)(void *)p = 890 htole16(*(uint16_t *)(void *)p); 891 break; 892 case 4: 893 *(uint32_t *)(void *)p = 894 htole32(*(uint32_t *)(void *)p); 895 break; 896 case 8: 897 *(uint64_t *)(void *)p = 898 htole64(*(uint64_t *)(void *)p); 899 break; 900 default: 901 assert(!"invalid condition"); 902 } 903 } 904 } 905 break; 906 case NV_TYPE_STRING: 907 break; 908 default: 909 assert(!"unrecognized type"); 910 } 911 } 912