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