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_NONE 0 50 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 68 69 #define NV_TYPE_MASK 0x7f 70 #define NV_TYPE_FIRST NV_TYPE_INT8 71 #define NV_TYPE_LAST NV_TYPE_STRING 72 73 #define NV_ORDER_NETWORK 0x00 74 #define NV_ORDER_HOST 0x80 75 76 #define NV_ORDER_MASK 0x80 77 78 #define NV_MAGIC 0xaea1e 79 struct nv { 80 int nv_magic; 81 int nv_error; 82 struct ebuf *nv_ebuf; 83 }; 84 85 struct nvhdr { 86 uint8_t nvh_type; 87 uint8_t nvh_namesize; 88 uint32_t nvh_dsize; 89 char nvh_name[0]; 90 } __packed; 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 ? \ 96 (nvh)->nvh_dsize : \ 97 le32toh((nvh)->nvh_dsize)) 98 #define NVH_SIZE(nvh) (NVH_HSIZE(nvh) + roundup2(NVH_DSIZE(nvh), 8)) 99 100 #define NV_CHECK(nv) do { \ 101 assert((nv) != NULL); \ 102 assert((nv)->nv_magic == NV_MAGIC); \ 103 } while (0) 104 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, 110 va_list nameap); 111 static void nv_swap(struct nvhdr *nvh, bool tohost); 112 113 /* 114 * Allocate and initialize new nv structure. 115 * Return NULL in case of malloc(3) failure. 116 */ 117 struct nv * 118 nv_alloc(void) 119 { 120 struct nv *nv; 121 122 nv = malloc(sizeof(*nv)); 123 if (nv == NULL) 124 return (NULL); 125 nv->nv_ebuf = ebuf_alloc(0); 126 if (nv->nv_ebuf == NULL) { 127 free(nv); 128 return (NULL); 129 } 130 nv->nv_error = 0; 131 nv->nv_magic = NV_MAGIC; 132 return (nv); 133 } 134 135 /* 136 * Free the given nv structure. 137 */ 138 void 139 nv_free(struct nv *nv) 140 { 141 142 if (nv == NULL) 143 return; 144 145 NV_CHECK(nv); 146 147 nv->nv_magic = 0; 148 ebuf_free(nv->nv_ebuf); 149 free(nv); 150 } 151 152 /* 153 * Return error for the given nv structure. 154 */ 155 int 156 nv_error(const struct nv *nv) 157 { 158 159 if (nv == NULL) 160 return (ENOMEM); 161 162 NV_CHECK(nv); 163 164 return (nv->nv_error); 165 } 166 167 /* 168 * Set error for the given nv structure and return previous error. 169 */ 170 int 171 nv_set_error(struct nv *nv, int error) 172 { 173 int preverr; 174 175 if (nv == NULL) 176 return (ENOMEM); 177 178 NV_CHECK(nv); 179 180 preverr = nv->nv_error; 181 nv->nv_error = error; 182 return (preverr); 183 } 184 185 /* 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. 188 */ 189 int 190 nv_validate(struct nv *nv, size_t *extrap) 191 { 192 struct nvhdr *nvh; 193 unsigned char *data, *ptr; 194 size_t dsize, size, vsize; 195 int error; 196 197 if (nv == NULL) { 198 errno = ENOMEM; 199 return (-1); 200 } 201 202 NV_CHECK(nv); 203 assert(nv->nv_error == 0); 204 205 /* TODO: Check that names are unique? */ 206 207 error = 0; 208 ptr = ebuf_data(nv->nv_ebuf, &size); 209 while (size > 0) { 210 /* 211 * Zeros at the end of the buffer are acceptable. 212 */ 213 if (ptr[0] == '\0') 214 break; 215 /* 216 * Minimum size at this point is size of nvhdr structure, one 217 * character long name plus terminating '\0'. 218 */ 219 if (size < sizeof(*nvh) + 2) { 220 error = EINVAL; 221 break; 222 } 223 nvh = (struct nvhdr *)ptr; 224 if (size < NVH_HSIZE(nvh)) { 225 error = EINVAL; 226 break; 227 } 228 if (nvh->nvh_name[nvh->nvh_namesize - 1] != '\0') { 229 error = EINVAL; 230 break; 231 } 232 if (strlen(nvh->nvh_name) != 233 (size_t)(nvh->nvh_namesize - 1)) { 234 error = EINVAL; 235 break; 236 } 237 if ((nvh->nvh_type & NV_TYPE_MASK) < NV_TYPE_FIRST || 238 (nvh->nvh_type & NV_TYPE_MASK) > NV_TYPE_LAST) { 239 error = EINVAL; 240 break; 241 } 242 dsize = NVH_DSIZE(nvh); 243 if (dsize == 0) { 244 error = EINVAL; 245 break; 246 } 247 if (size < NVH_SIZE(nvh)) { 248 error = EINVAL; 249 break; 250 } 251 vsize = 0; 252 switch (nvh->nvh_type & NV_TYPE_MASK) { 253 case NV_TYPE_INT8: 254 case NV_TYPE_UINT8: 255 if (vsize == 0) 256 vsize = 1; 257 /* FALLTHOUGH */ 258 case NV_TYPE_INT16: 259 case NV_TYPE_UINT16: 260 if (vsize == 0) 261 vsize = 2; 262 /* FALLTHOUGH */ 263 case NV_TYPE_INT32: 264 case NV_TYPE_UINT32: 265 if (vsize == 0) 266 vsize = 4; 267 /* FALLTHOUGH */ 268 case NV_TYPE_INT64: 269 case NV_TYPE_UINT64: 270 if (vsize == 0) 271 vsize = 8; 272 if (dsize != vsize) { 273 error = EINVAL; 274 break; 275 } 276 break; 277 case NV_TYPE_INT8_ARRAY: 278 case NV_TYPE_UINT8_ARRAY: 279 break; 280 case NV_TYPE_INT16_ARRAY: 281 case NV_TYPE_UINT16_ARRAY: 282 if (vsize == 0) 283 vsize = 2; 284 /* FALLTHOUGH */ 285 case NV_TYPE_INT32_ARRAY: 286 case NV_TYPE_UINT32_ARRAY: 287 if (vsize == 0) 288 vsize = 4; 289 /* FALLTHOUGH */ 290 case NV_TYPE_INT64_ARRAY: 291 case NV_TYPE_UINT64_ARRAY: 292 if (vsize == 0) 293 vsize = 8; 294 if ((dsize % vsize) != 0) { 295 error = EINVAL; 296 break; 297 } 298 break; 299 case NV_TYPE_STRING: 300 data = NVH_DATA(nvh); 301 if (data[dsize - 1] != '\0') { 302 error = EINVAL; 303 break; 304 } 305 if (strlen((char *)data) != dsize - 1) { 306 error = EINVAL; 307 break; 308 } 309 break; 310 default: 311 assert(!"invalid condition"); 312 } 313 if (error != 0) 314 break; 315 ptr += NVH_SIZE(nvh); 316 size -= NVH_SIZE(nvh); 317 } 318 if (error != 0) { 319 errno = error; 320 if (nv->nv_error == 0) 321 nv->nv_error = error; 322 return (-1); 323 } 324 if (extrap != NULL) 325 *extrap = size; 326 return (0); 327 } 328 329 /* 330 * Convert the given nv structure to network byte order and return ebuf 331 * structure. 332 */ 333 struct ebuf * 334 nv_hton(struct nv *nv) 335 { 336 struct nvhdr *nvh; 337 unsigned char *ptr; 338 size_t size; 339 340 NV_CHECK(nv); 341 assert(nv->nv_error == 0); 342 343 ptr = ebuf_data(nv->nv_ebuf, &size); 344 while (size > 0) { 345 /* 346 * Minimum size at this point is size of nvhdr structure, 347 * one character long name plus terminating '\0'. 348 */ 349 assert(size >= sizeof(*nvh) + 2); 350 nvh = (struct nvhdr *)ptr; 351 assert(NVH_SIZE(nvh) <= size); 352 nv_swap(nvh, false); 353 ptr += NVH_SIZE(nvh); 354 size -= NVH_SIZE(nvh); 355 } 356 357 return (nv->nv_ebuf); 358 } 359 360 /* 361 * Create nv structure based on ebuf received from the network. 362 */ 363 struct nv * 364 nv_ntoh(struct ebuf *eb) 365 { 366 struct nv *nv; 367 size_t extra; 368 int rerrno; 369 370 assert(eb != NULL); 371 372 nv = malloc(sizeof(*nv)); 373 if (nv == NULL) 374 return (NULL); 375 nv->nv_error = 0; 376 nv->nv_ebuf = eb; 377 nv->nv_magic = NV_MAGIC; 378 379 if (nv_validate(nv, &extra) < 0) { 380 rerrno = errno; 381 nv->nv_magic = 0; 382 free(nv); 383 errno = rerrno; 384 return (NULL); 385 } 386 /* 387 * Remove extra zeros at the end of the buffer. 388 */ 389 ebuf_del_tail(eb, extra); 390 391 return (nv); 392 } 393 394 #define NV_DEFINE_ADD(type, TYPE) \ 395 void \ 396 nv_add_##type(struct nv *nv, type##_t value, const char *namefmt, ...) \ 397 { \ 398 va_list nameap; \ 399 \ 400 va_start(nameap, namefmt); \ 401 nv_addv(nv, (unsigned char *)&value, sizeof(value), \ 402 NV_TYPE_##TYPE, namefmt, nameap); \ 403 va_end(nameap); \ 404 } 405 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) 414 415 #undef NV_DEFINE_ADD 416 417 #define NV_DEFINE_ADD_ARRAY(type, TYPE) \ 418 void \ 419 nv_add_##type##_array(struct nv *nv, const type##_t *value, \ 420 size_t nsize, const char *namefmt, ...) \ 421 { \ 422 va_list nameap; \ 423 \ 424 va_start(nameap, namefmt); \ 425 nv_addv(nv, (const unsigned char *)value, \ 426 sizeof(value[0]) * nsize, NV_TYPE_##TYPE##_ARRAY, namefmt, \ 427 nameap); \ 428 va_end(nameap); \ 429 } 430 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) 439 440 #undef NV_DEFINE_ADD_ARRAY 441 442 void 443 nv_add_string(struct nv *nv, const char *value, const char *namefmt, ...) 444 { 445 va_list nameap; 446 size_t size; 447 448 size = strlen(value) + 1; 449 450 va_start(nameap, namefmt); 451 nv_addv(nv, (const unsigned char *)value, size, NV_TYPE_STRING, 452 namefmt, nameap); 453 va_end(nameap); 454 } 455 456 void 457 nv_add_stringf(struct nv *nv, const char *name, const char *valuefmt, ...) 458 { 459 va_list valueap; 460 461 va_start(valueap, valuefmt); 462 nv_add_stringv(nv, name, valuefmt, valueap); 463 va_end(valueap); 464 } 465 466 void 467 nv_add_stringv(struct nv *nv, const char *name, const char *valuefmt, 468 va_list valueap) 469 { 470 char *value; 471 ssize_t size; 472 473 size = vasprintf(&value, valuefmt, valueap); 474 if (size < 0) { 475 if (nv->nv_error == 0) 476 nv->nv_error = ENOMEM; 477 return; 478 } 479 size++; 480 nv_add(nv, (const unsigned char *)value, size, NV_TYPE_STRING, name); 481 free(value); 482 } 483 484 #define NV_DEFINE_GET(type, TYPE) \ 485 type##_t \ 486 nv_get_##type(struct nv *nv, const char *namefmt, ...) \ 487 { \ 488 struct nvhdr *nvh; \ 489 va_list nameap; \ 490 type##_t value; \ 491 \ 492 va_start(nameap, namefmt); \ 493 nvh = nv_find(nv, NV_TYPE_##TYPE, namefmt, nameap); \ 494 va_end(nameap); \ 495 if (nvh == NULL) \ 496 return (0); \ 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)); \ 500 \ 501 return (value); \ 502 } 503 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) 512 513 #undef NV_DEFINE_GET 514 515 #define NV_DEFINE_GET_ARRAY(type, TYPE) \ 516 const type##_t * \ 517 nv_get_##type##_array(struct nv *nv, size_t *sizep, \ 518 const char *namefmt, ...) \ 519 { \ 520 struct nvhdr *nvh; \ 521 va_list nameap; \ 522 \ 523 va_start(nameap, namefmt); \ 524 nvh = nv_find(nv, NV_TYPE_##TYPE##_ARRAY, namefmt, nameap); \ 525 va_end(nameap); \ 526 if (nvh == NULL) \ 527 return (NULL); \ 528 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); \ 529 assert((nvh->nvh_dsize % sizeof(type##_t)) == 0); \ 530 if (sizep != NULL) \ 531 *sizep = nvh->nvh_dsize / sizeof(type##_t); \ 532 return ((type##_t *)(void *)NVH_DATA(nvh)); \ 533 } 534 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) 543 544 #undef NV_DEFINE_GET_ARRAY 545 546 const char * 547 nv_get_string(struct nv *nv, const char *namefmt, ...) 548 { 549 struct nvhdr *nvh; 550 va_list nameap; 551 char *str; 552 553 va_start(nameap, namefmt); 554 nvh = nv_find(nv, NV_TYPE_STRING, namefmt, nameap); 555 va_end(nameap); 556 if (nvh == NULL) 557 return (NULL); 558 assert((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); 559 assert(nvh->nvh_dsize >= 1); 560 str = NVH_DATA(nvh); 561 assert(str[nvh->nvh_dsize - 1] == '\0'); 562 assert(strlen(str) == nvh->nvh_dsize - 1); 563 return (str); 564 } 565 566 static bool 567 nv_vexists(struct nv *nv, const char *namefmt, va_list nameap) 568 { 569 struct nvhdr *nvh; 570 int snverror, serrno; 571 572 if (nv == NULL) 573 return (false); 574 575 serrno = errno; 576 snverror = nv->nv_error; 577 578 nvh = nv_find(nv, NV_TYPE_NONE, namefmt, nameap); 579 580 errno = serrno; 581 nv->nv_error = snverror; 582 583 return (nvh != NULL); 584 } 585 586 bool 587 nv_exists(struct nv *nv, const char *namefmt, ...) 588 { 589 va_list nameap; 590 bool ret; 591 592 va_start(nameap, namefmt); 593 ret = nv_vexists(nv, namefmt, nameap); 594 va_end(nameap); 595 596 return (ret); 597 } 598 599 void 600 nv_assert(struct nv *nv, const char *namefmt, ...) 601 { 602 va_list nameap; 603 604 va_start(nameap, namefmt); 605 assert(nv_vexists(nv, namefmt, nameap)); 606 va_end(nameap); 607 } 608 609 /* 610 * Dump content of the nv structure. 611 */ 612 void 613 nv_dump(struct nv *nv) 614 { 615 struct nvhdr *nvh; 616 unsigned char *data, *ptr; 617 size_t dsize, size; 618 unsigned int ii; 619 bool swap; 620 621 if (nv_validate(nv, NULL) < 0) { 622 printf("error: %d\n", errno); 623 return; 624 } 625 626 NV_CHECK(nv); 627 assert(nv->nv_error == 0); 628 629 ptr = ebuf_data(nv->nv_ebuf, &size); 630 while (size > 0) { 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) { 639 case NV_TYPE_INT8: 640 printf("(int8): %jd", (intmax_t)(*(int8_t *)data)); 641 break; 642 case NV_TYPE_UINT8: 643 printf("(uint8): %ju", (uintmax_t)(*(uint8_t *)data)); 644 break; 645 case NV_TYPE_INT16: 646 printf("(int16): %jd", swap ? 647 (intmax_t)le16toh(*(int16_t *)(void *)data) : 648 (intmax_t)*(int16_t *)(void *)data); 649 break; 650 case NV_TYPE_UINT16: 651 printf("(uint16): %ju", swap ? 652 (uintmax_t)le16toh(*(uint16_t *)(void *)data) : 653 (uintmax_t)*(uint16_t *)(void *)data); 654 break; 655 case NV_TYPE_INT32: 656 printf("(int32): %jd", swap ? 657 (intmax_t)le32toh(*(int32_t *)(void *)data) : 658 (intmax_t)*(int32_t *)(void *)data); 659 break; 660 case NV_TYPE_UINT32: 661 printf("(uint32): %ju", swap ? 662 (uintmax_t)le32toh(*(uint32_t *)(void *)data) : 663 (uintmax_t)*(uint32_t *)(void *)data); 664 break; 665 case NV_TYPE_INT64: 666 printf("(int64): %jd", swap ? 667 (intmax_t)le64toh(*(int64_t *)(void *)data) : 668 (intmax_t)*(int64_t *)(void *)data); 669 break; 670 case NV_TYPE_UINT64: 671 printf("(uint64): %ju", swap ? 672 (uintmax_t)le64toh(*(uint64_t *)(void *)data) : 673 (uintmax_t)*(uint64_t *)(void *)data); 674 break; 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]); 679 break; 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]); 684 break; 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]); 691 } 692 break; 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]); 699 } 700 break; 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]); 707 } 708 break; 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]); 715 } 716 break; 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]); 723 } 724 break; 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]); 731 } 732 break; 733 case NV_TYPE_STRING: 734 printf("(string): %s", (char *)data); 735 break; 736 default: 737 assert(!"invalid condition"); 738 } 739 printf("\n"); 740 ptr += NVH_SIZE(nvh); 741 size -= NVH_SIZE(nvh); 742 } 743 } 744 745 /* 746 * Local routines below. 747 */ 748 749 static void 750 nv_add(struct nv *nv, const unsigned char *value, size_t vsize, int type, 751 const char *name) 752 { 753 static unsigned char align[7]; 754 struct nvhdr *nvh; 755 size_t namesize; 756 757 if (nv == NULL) { 758 errno = ENOMEM; 759 return; 760 } 761 762 NV_CHECK(nv); 763 764 namesize = strlen(name) + 1; 765 766 nvh = malloc(sizeof(*nvh) + roundup2(namesize, 8)); 767 if (nvh == NULL) { 768 if (nv->nv_error == 0) 769 nv->nv_error = ENOMEM; 770 return; 771 } 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); 776 777 /* Add header first. */ 778 if (ebuf_add_tail(nv->nv_ebuf, nvh, NVH_HSIZE(nvh)) < 0) { 779 assert(errno != 0); 780 if (nv->nv_error == 0) 781 nv->nv_error = errno; 782 free(nvh); 783 return; 784 } 785 free(nvh); 786 /* Add the actual data. */ 787 if (ebuf_add_tail(nv->nv_ebuf, value, vsize) < 0) { 788 assert(errno != 0); 789 if (nv->nv_error == 0) 790 nv->nv_error = errno; 791 return; 792 } 793 /* Align the data (if needed). */ 794 vsize = roundup2(vsize, 8) - vsize; 795 if (vsize == 0) 796 return; 797 assert(vsize > 0 && vsize <= sizeof(align)); 798 if (ebuf_add_tail(nv->nv_ebuf, align, vsize) < 0) { 799 assert(errno != 0); 800 if (nv->nv_error == 0) 801 nv->nv_error = errno; 802 return; 803 } 804 } 805 806 static void 807 nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, int type, 808 const char *namefmt, va_list nameap) 809 { 810 char name[255]; 811 size_t namesize; 812 813 namesize = vsnprintf(name, sizeof(name), namefmt, nameap); 814 assert(namesize > 0 && namesize < sizeof(name)); 815 816 nv_add(nv, value, vsize, type, name); 817 } 818 819 static struct nvhdr * 820 nv_find(struct nv *nv, int type, const char *namefmt, va_list nameap) 821 { 822 char name[255]; 823 struct nvhdr *nvh; 824 unsigned char *ptr; 825 size_t size, namesize; 826 827 if (nv == NULL) { 828 errno = ENOMEM; 829 return (NULL); 830 } 831 832 NV_CHECK(nv); 833 834 namesize = vsnprintf(name, sizeof(name), namefmt, nameap); 835 assert(namesize > 0 && namesize < sizeof(name)); 836 namesize++; 837 838 ptr = ebuf_data(nv->nv_ebuf, &size); 839 while (size > 0) { 840 assert(size >= sizeof(*nvh) + 2); 841 nvh = (struct nvhdr *)ptr; 842 assert(size >= NVH_SIZE(nvh)); 843 nv_swap(nvh, true); 844 if (strcmp(nvh->nvh_name, name) == 0) { 845 if (type != NV_TYPE_NONE && 846 (nvh->nvh_type & NV_TYPE_MASK) != type) { 847 errno = EINVAL; 848 if (nv->nv_error == 0) 849 nv->nv_error = EINVAL; 850 return (NULL); 851 } 852 return (nvh); 853 } 854 ptr += NVH_SIZE(nvh); 855 size -= NVH_SIZE(nvh); 856 } 857 errno = ENOENT; 858 if (nv->nv_error == 0) 859 nv->nv_error = ENOENT; 860 return (NULL); 861 } 862 863 static void 864 nv_swap(struct nvhdr *nvh, bool tohost) 865 { 866 unsigned char *data, *end, *p; 867 size_t vsize; 868 869 data = NVH_DATA(nvh); 870 if (tohost) { 871 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST) 872 return; 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; 877 } else { 878 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK) 879 return; 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; 884 } 885 886 vsize = 0; 887 888 switch (nvh->nvh_type & NV_TYPE_MASK) { 889 case NV_TYPE_INT8: 890 case NV_TYPE_UINT8: 891 case NV_TYPE_INT8_ARRAY: 892 case NV_TYPE_UINT8_ARRAY: 893 break; 894 case NV_TYPE_INT16: 895 case NV_TYPE_UINT16: 896 case NV_TYPE_INT16_ARRAY: 897 case NV_TYPE_UINT16_ARRAY: 898 if (vsize == 0) 899 vsize = 2; 900 /* FALLTHOUGH */ 901 case NV_TYPE_INT32: 902 case NV_TYPE_UINT32: 903 case NV_TYPE_INT32_ARRAY: 904 case NV_TYPE_UINT32_ARRAY: 905 if (vsize == 0) 906 vsize = 4; 907 /* FALLTHOUGH */ 908 case NV_TYPE_INT64: 909 case NV_TYPE_UINT64: 910 case NV_TYPE_INT64_ARRAY: 911 case NV_TYPE_UINT64_ARRAY: 912 if (vsize == 0) 913 vsize = 8; 914 for (p = data; p < end; p += vsize) { 915 if (tohost) { 916 switch (vsize) { 917 case 2: 918 *(uint16_t *)(void *)p = 919 le16toh(*(uint16_t *)(void *)p); 920 break; 921 case 4: 922 *(uint32_t *)(void *)p = 923 le32toh(*(uint32_t *)(void *)p); 924 break; 925 case 8: 926 *(uint64_t *)(void *)p = 927 le64toh(*(uint64_t *)(void *)p); 928 break; 929 default: 930 assert(!"invalid condition"); 931 } 932 } else { 933 switch (vsize) { 934 case 2: 935 *(uint16_t *)(void *)p = 936 htole16(*(uint16_t *)(void *)p); 937 break; 938 case 4: 939 *(uint32_t *)(void *)p = 940 htole32(*(uint32_t *)(void *)p); 941 break; 942 case 8: 943 *(uint64_t *)(void *)p = 944 htole64(*(uint64_t *)(void *)p); 945 break; 946 default: 947 assert(!"invalid condition"); 948 } 949 } 950 } 951 break; 952 case NV_TYPE_STRING: 953 break; 954 default: 955 assert(!"unrecognized type"); 956 } 957 } 958