1 2 /* 3 * ng_parse.c 4 * 5 * Copyright (c) 1999 Whistle Communications, Inc. 6 * All rights reserved. 7 * 8 * Subject to the following obligations and disclaimer of warranty, use and 9 * redistribution of this software, in source or object code forms, with or 10 * without modifications are expressly permitted by Whistle Communications; 11 * provided, however, that: 12 * 1. Any and all reproductions of the source or object code must include the 13 * copyright notice above and the following disclaimer of warranties; and 14 * 2. No rights are granted, in any manner or form, to use Whistle 15 * Communications, Inc. trademarks, including the mark "WHISTLE 16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 * such appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 * OF SUCH DAMAGE. 36 * 37 * Author: Archie Cobbs <archie@freebsd.org> 38 * 39 * $Whistle: ng_parse.c,v 1.3 1999/11/29 01:43:48 archie Exp $ 40 * $FreeBSD$ 41 */ 42 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/errno.h> 48 #include <sys/malloc.h> 49 #include <sys/ctype.h> 50 51 #include <net/ethernet.h> 52 53 #include <netinet/in.h> 54 55 #include <netgraph/ng_message.h> 56 #include <netgraph/netgraph.h> 57 #include <netgraph/ng_parse.h> 58 59 #ifdef NG_SEPARATE_MALLOC 60 MALLOC_DEFINE(M_NETGRAPH_PARSE, "netgraph_parse", "netgraph parse info"); 61 #else 62 #define M_NETGRAPH_PARSE M_NETGRAPH 63 #endif 64 65 /* Compute alignment for primitive integral types */ 66 struct int16_temp { 67 char x; 68 int16_t y; 69 }; 70 71 struct int32_temp { 72 char x; 73 int32_t y; 74 }; 75 76 struct int64_temp { 77 char x; 78 int64_t y; 79 }; 80 81 #define INT8_ALIGNMENT 1 82 #define INT16_ALIGNMENT ((int)&((struct int16_temp *)0)->y) 83 #define INT32_ALIGNMENT ((int)&((struct int32_temp *)0)->y) 84 #define INT64_ALIGNMENT ((int)&((struct int64_temp *)0)->y) 85 86 /* Output format for integral types */ 87 #define INT_UNSIGNED 0 88 #define INT_SIGNED 1 89 #define INT_HEX 2 90 91 /* Type of composite object: struct, array, or fixedarray */ 92 enum comptype { 93 CT_STRUCT, 94 CT_ARRAY, 95 CT_FIXEDARRAY, 96 }; 97 98 /* Composite types helper functions */ 99 static int ng_parse_composite(const struct ng_parse_type *type, 100 const char *s, int *off, const u_char *start, 101 u_char *const buf, int *buflen, enum comptype ctype); 102 static int ng_unparse_composite(const struct ng_parse_type *type, 103 const u_char *data, int *off, char *cbuf, int cbuflen, 104 enum comptype ctype); 105 static int ng_get_composite_elem_default(const struct ng_parse_type *type, 106 int index, const u_char *start, u_char *buf, 107 int *buflen, enum comptype ctype); 108 static int ng_get_composite_len(const struct ng_parse_type *type, 109 const u_char *start, const u_char *buf, 110 enum comptype ctype); 111 static const struct ng_parse_type *ng_get_composite_etype(const struct 112 ng_parse_type *type, int index, enum comptype ctype); 113 static int ng_parse_get_elem_pad(const struct ng_parse_type *type, 114 int index, enum comptype ctype, int posn); 115 116 /* Parsing helper functions */ 117 static int ng_parse_skip_value(const char *s, int off, int *lenp); 118 119 /* Poor man's virtual method calls */ 120 #define METHOD(t,m) (ng_get_ ## m ## _method(t)) 121 #define INVOKE(t,m) (*METHOD(t,m)) 122 123 static ng_parse_t *ng_get_parse_method(const struct ng_parse_type *t); 124 static ng_unparse_t *ng_get_unparse_method(const struct ng_parse_type *t); 125 static ng_getDefault_t *ng_get_getDefault_method(const 126 struct ng_parse_type *t); 127 static ng_getAlign_t *ng_get_getAlign_method(const struct ng_parse_type *t); 128 129 #define ALIGNMENT(t) (METHOD(t, getAlign) == NULL ? \ 130 0 : INVOKE(t, getAlign)(t)) 131 132 /* For converting binary to string */ 133 #define NG_PARSE_APPEND(fmt, args...) \ 134 do { \ 135 int len; \ 136 \ 137 len = snprintf((cbuf), (cbuflen), \ 138 fmt , ## args); \ 139 if (len >= (cbuflen)) \ 140 return (ERANGE); \ 141 (cbuf) += len; \ 142 (cbuflen) -= len; \ 143 } while (0) 144 145 /************************************************************************ 146 PUBLIC FUNCTIONS 147 ************************************************************************/ 148 149 /* 150 * Convert an ASCII string to binary according to the supplied type descriptor 151 */ 152 int 153 ng_parse(const struct ng_parse_type *type, 154 const char *string, int *off, u_char *buf, int *buflen) 155 { 156 return INVOKE(type, parse)(type, string, off, buf, buf, buflen); 157 } 158 159 /* 160 * Convert binary to an ASCII string according to the supplied type descriptor 161 */ 162 int 163 ng_unparse(const struct ng_parse_type *type, 164 const u_char *data, char *cbuf, int cbuflen) 165 { 166 int off = 0; 167 168 return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen); 169 } 170 171 /* 172 * Fill in the default value according to the supplied type descriptor 173 */ 174 int 175 ng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen) 176 { 177 ng_getDefault_t *const func = METHOD(type, getDefault); 178 179 if (func == NULL) 180 return (EOPNOTSUPP); 181 return (*func)(type, buf, buf, buflen); 182 } 183 184 185 /************************************************************************ 186 STRUCTURE TYPE 187 ************************************************************************/ 188 189 static int 190 ng_struct_parse(const struct ng_parse_type *type, 191 const char *s, int *off, const u_char *const start, 192 u_char *const buf, int *buflen) 193 { 194 return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT); 195 } 196 197 static int 198 ng_struct_unparse(const struct ng_parse_type *type, 199 const u_char *data, int *off, char *cbuf, int cbuflen) 200 { 201 return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT); 202 } 203 204 static int 205 ng_struct_getDefault(const struct ng_parse_type *type, 206 const u_char *const start, u_char *buf, int *buflen) 207 { 208 int off = 0; 209 210 return ng_parse_composite(type, 211 "{}", &off, start, buf, buflen, CT_STRUCT); 212 } 213 214 static int 215 ng_struct_getAlign(const struct ng_parse_type *type) 216 { 217 const struct ng_parse_struct_field *field; 218 int align = 0; 219 220 for (field = type->info; field->name != NULL; field++) { 221 int falign = ALIGNMENT(field->type); 222 223 if (falign > align) 224 align = falign; 225 } 226 return align; 227 } 228 229 const struct ng_parse_type ng_parse_struct_type = { 230 NULL, 231 NULL, 232 NULL, 233 ng_struct_parse, 234 ng_struct_unparse, 235 ng_struct_getDefault, 236 ng_struct_getAlign 237 }; 238 239 /************************************************************************ 240 FIXED LENGTH ARRAY TYPE 241 ************************************************************************/ 242 243 static int 244 ng_fixedarray_parse(const struct ng_parse_type *type, 245 const char *s, int *off, const u_char *const start, 246 u_char *const buf, int *buflen) 247 { 248 return ng_parse_composite(type, 249 s, off, start, buf, buflen, CT_FIXEDARRAY); 250 } 251 252 static int 253 ng_fixedarray_unparse(const struct ng_parse_type *type, 254 const u_char *data, int *off, char *cbuf, int cbuflen) 255 { 256 return ng_unparse_composite(type, 257 data, off, cbuf, cbuflen, CT_FIXEDARRAY); 258 } 259 260 static int 261 ng_fixedarray_getDefault(const struct ng_parse_type *type, 262 const u_char *const start, u_char *buf, int *buflen) 263 { 264 int off = 0; 265 266 return ng_parse_composite(type, 267 "[]", &off, start, buf, buflen, CT_FIXEDARRAY); 268 } 269 270 static int 271 ng_fixedarray_getAlign(const struct ng_parse_type *type) 272 { 273 const struct ng_parse_fixedarray_info *fi = type->info; 274 275 return ALIGNMENT(fi->elementType); 276 } 277 278 const struct ng_parse_type ng_parse_fixedarray_type = { 279 NULL, 280 NULL, 281 NULL, 282 ng_fixedarray_parse, 283 ng_fixedarray_unparse, 284 ng_fixedarray_getDefault, 285 ng_fixedarray_getAlign 286 }; 287 288 /************************************************************************ 289 VARIABLE LENGTH ARRAY TYPE 290 ************************************************************************/ 291 292 static int 293 ng_array_parse(const struct ng_parse_type *type, 294 const char *s, int *off, const u_char *const start, 295 u_char *const buf, int *buflen) 296 { 297 return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY); 298 } 299 300 static int 301 ng_array_unparse(const struct ng_parse_type *type, 302 const u_char *data, int *off, char *cbuf, int cbuflen) 303 { 304 return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY); 305 } 306 307 static int 308 ng_array_getDefault(const struct ng_parse_type *type, 309 const u_char *const start, u_char *buf, int *buflen) 310 { 311 int off = 0; 312 313 return ng_parse_composite(type, 314 "[]", &off, start, buf, buflen, CT_ARRAY); 315 } 316 317 static int 318 ng_array_getAlign(const struct ng_parse_type *type) 319 { 320 const struct ng_parse_array_info *ai = type->info; 321 322 return ALIGNMENT(ai->elementType); 323 } 324 325 const struct ng_parse_type ng_parse_array_type = { 326 NULL, 327 NULL, 328 NULL, 329 ng_array_parse, 330 ng_array_unparse, 331 ng_array_getDefault, 332 ng_array_getAlign 333 }; 334 335 /************************************************************************ 336 INT8 TYPE 337 ************************************************************************/ 338 339 static int 340 ng_int8_parse(const struct ng_parse_type *type, 341 const char *s, int *off, const u_char *const start, 342 u_char *const buf, int *buflen) 343 { 344 long val; 345 int8_t val8; 346 char *eptr; 347 348 val = strtol(s + *off, &eptr, 0); 349 if (val < (int8_t)0x80 || val > (u_int8_t)0xff || eptr == s + *off) 350 return (EINVAL); 351 *off = eptr - s; 352 val8 = (int8_t)val; 353 bcopy(&val8, buf, sizeof(int8_t)); 354 *buflen = sizeof(int8_t); 355 return (0); 356 } 357 358 static int 359 ng_int8_unparse(const struct ng_parse_type *type, 360 const u_char *data, int *off, char *cbuf, int cbuflen) 361 { 362 const char *fmt; 363 int fval; 364 int8_t val; 365 366 bcopy(data + *off, &val, sizeof(int8_t)); 367 switch ((intptr_t)type->info) { 368 case INT_SIGNED: 369 fmt = "%d"; 370 fval = val; 371 break; 372 case INT_UNSIGNED: 373 fmt = "%u"; 374 fval = (u_int8_t)val; 375 break; 376 case INT_HEX: 377 fmt = "0x%x"; 378 fval = (u_int8_t)val; 379 break; 380 default: 381 panic("%s: unknown type", __func__); 382 #ifdef RESTARTABLE_PANICS 383 return(0); 384 #endif 385 } 386 NG_PARSE_APPEND(fmt, fval); 387 *off += sizeof(int8_t); 388 return (0); 389 } 390 391 static int 392 ng_int8_getDefault(const struct ng_parse_type *type, 393 const u_char *const start, u_char *buf, int *buflen) 394 { 395 int8_t val; 396 397 if (*buflen < sizeof(int8_t)) 398 return (ERANGE); 399 val = 0; 400 bcopy(&val, buf, sizeof(int8_t)); 401 *buflen = sizeof(int8_t); 402 return (0); 403 } 404 405 static int 406 ng_int8_getAlign(const struct ng_parse_type *type) 407 { 408 return INT8_ALIGNMENT; 409 } 410 411 const struct ng_parse_type ng_parse_int8_type = { 412 NULL, 413 (void *)INT_SIGNED, 414 NULL, 415 ng_int8_parse, 416 ng_int8_unparse, 417 ng_int8_getDefault, 418 ng_int8_getAlign 419 }; 420 421 const struct ng_parse_type ng_parse_uint8_type = { 422 &ng_parse_int8_type, 423 (void *)INT_UNSIGNED 424 }; 425 426 const struct ng_parse_type ng_parse_hint8_type = { 427 &ng_parse_int8_type, 428 (void *)INT_HEX 429 }; 430 431 /************************************************************************ 432 INT16 TYPE 433 ************************************************************************/ 434 435 static int 436 ng_int16_parse(const struct ng_parse_type *type, 437 const char *s, int *off, const u_char *const start, 438 u_char *const buf, int *buflen) 439 { 440 long val; 441 int16_t val16; 442 char *eptr; 443 444 val = strtol(s + *off, &eptr, 0); 445 if (val < (int16_t)0x8000 446 || val > (u_int16_t)0xffff || eptr == s + *off) 447 return (EINVAL); 448 *off = eptr - s; 449 val16 = (int16_t)val; 450 bcopy(&val16, buf, sizeof(int16_t)); 451 *buflen = sizeof(int16_t); 452 return (0); 453 } 454 455 static int 456 ng_int16_unparse(const struct ng_parse_type *type, 457 const u_char *data, int *off, char *cbuf, int cbuflen) 458 { 459 const char *fmt; 460 int fval; 461 int16_t val; 462 463 bcopy(data + *off, &val, sizeof(int16_t)); 464 switch ((intptr_t)type->info) { 465 case INT_SIGNED: 466 fmt = "%d"; 467 fval = val; 468 break; 469 case INT_UNSIGNED: 470 fmt = "%u"; 471 fval = (u_int16_t)val; 472 break; 473 case INT_HEX: 474 fmt = "0x%x"; 475 fval = (u_int16_t)val; 476 break; 477 default: 478 panic("%s: unknown type", __func__); 479 #ifdef RESTARTABLE_PANICS 480 return(0); 481 #endif 482 } 483 NG_PARSE_APPEND(fmt, fval); 484 *off += sizeof(int16_t); 485 return (0); 486 } 487 488 static int 489 ng_int16_getDefault(const struct ng_parse_type *type, 490 const u_char *const start, u_char *buf, int *buflen) 491 { 492 int16_t val; 493 494 if (*buflen < sizeof(int16_t)) 495 return (ERANGE); 496 val = 0; 497 bcopy(&val, buf, sizeof(int16_t)); 498 *buflen = sizeof(int16_t); 499 return (0); 500 } 501 502 static int 503 ng_int16_getAlign(const struct ng_parse_type *type) 504 { 505 return INT16_ALIGNMENT; 506 } 507 508 const struct ng_parse_type ng_parse_int16_type = { 509 NULL, 510 (void *)INT_SIGNED, 511 NULL, 512 ng_int16_parse, 513 ng_int16_unparse, 514 ng_int16_getDefault, 515 ng_int16_getAlign 516 }; 517 518 const struct ng_parse_type ng_parse_uint16_type = { 519 &ng_parse_int16_type, 520 (void *)INT_UNSIGNED 521 }; 522 523 const struct ng_parse_type ng_parse_hint16_type = { 524 &ng_parse_int16_type, 525 (void *)INT_HEX 526 }; 527 528 /************************************************************************ 529 INT32 TYPE 530 ************************************************************************/ 531 532 static int 533 ng_int32_parse(const struct ng_parse_type *type, 534 const char *s, int *off, const u_char *const start, 535 u_char *const buf, int *buflen) 536 { 537 long val; /* assumes long is at least 32 bits */ 538 int32_t val32; 539 char *eptr; 540 541 val = strtol(s + *off, &eptr, 0); 542 if (val < (int32_t)0x80000000 543 || val > (u_int32_t)0xffffffff || eptr == s + *off) 544 return (EINVAL); 545 *off = eptr - s; 546 val32 = (int32_t)val; 547 bcopy(&val32, buf, sizeof(int32_t)); 548 *buflen = sizeof(int32_t); 549 return (0); 550 } 551 552 static int 553 ng_int32_unparse(const struct ng_parse_type *type, 554 const u_char *data, int *off, char *cbuf, int cbuflen) 555 { 556 const char *fmt; 557 long fval; 558 int32_t val; 559 560 bcopy(data + *off, &val, sizeof(int32_t)); 561 switch ((intptr_t)type->info) { 562 case INT_SIGNED: 563 fmt = "%ld"; 564 fval = val; 565 break; 566 case INT_UNSIGNED: 567 fmt = "%lu"; 568 fval = (u_int32_t)val; 569 break; 570 case INT_HEX: 571 fmt = "0x%lx"; 572 fval = (u_int32_t)val; 573 break; 574 default: 575 panic("%s: unknown type", __func__); 576 #ifdef RESTARTABLE_PANICS 577 return(0); 578 #endif 579 } 580 NG_PARSE_APPEND(fmt, fval); 581 *off += sizeof(int32_t); 582 return (0); 583 } 584 585 static int 586 ng_int32_getDefault(const struct ng_parse_type *type, 587 const u_char *const start, u_char *buf, int *buflen) 588 { 589 int32_t val; 590 591 if (*buflen < sizeof(int32_t)) 592 return (ERANGE); 593 val = 0; 594 bcopy(&val, buf, sizeof(int32_t)); 595 *buflen = sizeof(int32_t); 596 return (0); 597 } 598 599 static int 600 ng_int32_getAlign(const struct ng_parse_type *type) 601 { 602 return INT32_ALIGNMENT; 603 } 604 605 const struct ng_parse_type ng_parse_int32_type = { 606 NULL, 607 (void *)INT_SIGNED, 608 NULL, 609 ng_int32_parse, 610 ng_int32_unparse, 611 ng_int32_getDefault, 612 ng_int32_getAlign 613 }; 614 615 const struct ng_parse_type ng_parse_uint32_type = { 616 &ng_parse_int32_type, 617 (void *)INT_UNSIGNED 618 }; 619 620 const struct ng_parse_type ng_parse_hint32_type = { 621 &ng_parse_int32_type, 622 (void *)INT_HEX 623 }; 624 625 /************************************************************************ 626 INT64 TYPE 627 ************************************************************************/ 628 629 static int 630 ng_int64_parse(const struct ng_parse_type *type, 631 const char *s, int *off, const u_char *const start, 632 u_char *const buf, int *buflen) 633 { 634 quad_t val; 635 int64_t val64; 636 char *eptr; 637 638 val = strtoq(s + *off, &eptr, 0); 639 if (eptr == s + *off) 640 return (EINVAL); 641 *off = eptr - s; 642 val64 = (int64_t)val; 643 bcopy(&val64, buf, sizeof(int64_t)); 644 *buflen = sizeof(int64_t); 645 return (0); 646 } 647 648 static int 649 ng_int64_unparse(const struct ng_parse_type *type, 650 const u_char *data, int *off, char *cbuf, int cbuflen) 651 { 652 const char *fmt; 653 long long fval; 654 int64_t val; 655 656 bcopy(data + *off, &val, sizeof(int64_t)); 657 switch ((intptr_t)type->info) { 658 case INT_SIGNED: 659 fmt = "%lld"; 660 fval = val; 661 break; 662 case INT_UNSIGNED: 663 fmt = "%llu"; 664 fval = (u_int64_t)val; 665 break; 666 case INT_HEX: 667 fmt = "0x%llx"; 668 fval = (u_int64_t)val; 669 break; 670 default: 671 panic("%s: unknown type", __func__); 672 #ifdef RESTARTABLE_PANICS 673 return(0); 674 #endif 675 } 676 NG_PARSE_APPEND(fmt, fval); 677 *off += sizeof(int64_t); 678 return (0); 679 } 680 681 static int 682 ng_int64_getDefault(const struct ng_parse_type *type, 683 const u_char *const start, u_char *buf, int *buflen) 684 { 685 int64_t val; 686 687 if (*buflen < sizeof(int64_t)) 688 return (ERANGE); 689 val = 0; 690 bcopy(&val, buf, sizeof(int64_t)); 691 *buflen = sizeof(int64_t); 692 return (0); 693 } 694 695 static int 696 ng_int64_getAlign(const struct ng_parse_type *type) 697 { 698 return INT64_ALIGNMENT; 699 } 700 701 const struct ng_parse_type ng_parse_int64_type = { 702 NULL, 703 (void *)INT_SIGNED, 704 NULL, 705 ng_int64_parse, 706 ng_int64_unparse, 707 ng_int64_getDefault, 708 ng_int64_getAlign 709 }; 710 711 const struct ng_parse_type ng_parse_uint64_type = { 712 &ng_parse_int64_type, 713 (void *)INT_UNSIGNED 714 }; 715 716 const struct ng_parse_type ng_parse_hint64_type = { 717 &ng_parse_int64_type, 718 (void *)INT_HEX 719 }; 720 721 /************************************************************************ 722 STRING TYPE 723 ************************************************************************/ 724 725 static int 726 ng_string_parse(const struct ng_parse_type *type, 727 const char *s, int *off, const u_char *const start, 728 u_char *const buf, int *buflen) 729 { 730 char *sval; 731 int len; 732 int slen; 733 734 if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL) 735 return (EINVAL); 736 *off += len; 737 bcopy(sval, buf, slen + 1); 738 FREE(sval, M_NETGRAPH_PARSE); 739 *buflen = slen + 1; 740 return (0); 741 } 742 743 static int 744 ng_string_unparse(const struct ng_parse_type *type, 745 const u_char *data, int *off, char *cbuf, int cbuflen) 746 { 747 const char *const raw = (const char *)data + *off; 748 char *const s = ng_encode_string(raw, strlen(raw)); 749 750 if (s == NULL) 751 return (ENOMEM); 752 NG_PARSE_APPEND("%s", s); 753 *off += strlen(raw) + 1; 754 FREE(s, M_NETGRAPH_PARSE); 755 return (0); 756 } 757 758 static int 759 ng_string_getDefault(const struct ng_parse_type *type, 760 const u_char *const start, u_char *buf, int *buflen) 761 { 762 763 if (*buflen < 1) 764 return (ERANGE); 765 buf[0] = (u_char)'\0'; 766 *buflen = 1; 767 return (0); 768 } 769 770 const struct ng_parse_type ng_parse_string_type = { 771 NULL, 772 NULL, 773 NULL, 774 ng_string_parse, 775 ng_string_unparse, 776 ng_string_getDefault, 777 NULL 778 }; 779 780 /************************************************************************ 781 FIXED BUFFER STRING TYPE 782 ************************************************************************/ 783 784 static int 785 ng_fixedstring_parse(const struct ng_parse_type *type, 786 const char *s, int *off, const u_char *const start, 787 u_char *const buf, int *buflen) 788 { 789 const struct ng_parse_fixedstring_info *const fi = type->info; 790 char *sval; 791 int len; 792 int slen; 793 794 if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL) 795 return (EINVAL); 796 if (slen + 1 > fi->bufSize) 797 return (E2BIG); 798 *off += len; 799 bcopy(sval, buf, slen); 800 FREE(sval, M_NETGRAPH_PARSE); 801 bzero(buf + slen, fi->bufSize - slen); 802 *buflen = fi->bufSize; 803 return (0); 804 } 805 806 static int 807 ng_fixedstring_unparse(const struct ng_parse_type *type, 808 const u_char *data, int *off, char *cbuf, int cbuflen) 809 { 810 const struct ng_parse_fixedstring_info *const fi = type->info; 811 int error, temp = *off; 812 813 if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0) 814 return (error); 815 *off += fi->bufSize; 816 return (0); 817 } 818 819 static int 820 ng_fixedstring_getDefault(const struct ng_parse_type *type, 821 const u_char *const start, u_char *buf, int *buflen) 822 { 823 const struct ng_parse_fixedstring_info *const fi = type->info; 824 825 if (*buflen < fi->bufSize) 826 return (ERANGE); 827 bzero(buf, fi->bufSize); 828 *buflen = fi->bufSize; 829 return (0); 830 } 831 832 const struct ng_parse_type ng_parse_fixedstring_type = { 833 NULL, 834 NULL, 835 NULL, 836 ng_fixedstring_parse, 837 ng_fixedstring_unparse, 838 ng_fixedstring_getDefault, 839 NULL 840 }; 841 842 const struct ng_parse_fixedstring_info ng_parse_nodebuf_info = { 843 NG_NODESIZ 844 }; 845 const struct ng_parse_type ng_parse_nodebuf_type = { 846 &ng_parse_fixedstring_type, 847 &ng_parse_nodebuf_info 848 }; 849 850 const struct ng_parse_fixedstring_info ng_parse_hookbuf_info = { 851 NG_HOOKSIZ 852 }; 853 const struct ng_parse_type ng_parse_hookbuf_type = { 854 &ng_parse_fixedstring_type, 855 &ng_parse_hookbuf_info 856 }; 857 858 const struct ng_parse_fixedstring_info ng_parse_pathbuf_info = { 859 NG_PATHSIZ 860 }; 861 const struct ng_parse_type ng_parse_pathbuf_type = { 862 &ng_parse_fixedstring_type, 863 &ng_parse_pathbuf_info 864 }; 865 866 const struct ng_parse_fixedstring_info ng_parse_typebuf_info = { 867 NG_TYPESIZ 868 }; 869 const struct ng_parse_type ng_parse_typebuf_type = { 870 &ng_parse_fixedstring_type, 871 &ng_parse_typebuf_info 872 }; 873 874 const struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = { 875 NG_CMDSTRSIZ 876 }; 877 const struct ng_parse_type ng_parse_cmdbuf_type = { 878 &ng_parse_fixedstring_type, 879 &ng_parse_cmdbuf_info 880 }; 881 882 /************************************************************************ 883 EXPLICITLY SIZED STRING TYPE 884 ************************************************************************/ 885 886 static int 887 ng_sizedstring_parse(const struct ng_parse_type *type, 888 const char *s, int *off, const u_char *const start, 889 u_char *const buf, int *buflen) 890 { 891 char *sval; 892 int len; 893 int slen; 894 895 if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL) 896 return (EINVAL); 897 if (slen > 0xffff) 898 return (EINVAL); 899 *off += len; 900 *((u_int16_t *)buf) = (u_int16_t)slen; 901 bcopy(sval, buf + 2, slen); 902 FREE(sval, M_NETGRAPH_PARSE); 903 *buflen = 2 + slen; 904 return (0); 905 } 906 907 static int 908 ng_sizedstring_unparse(const struct ng_parse_type *type, 909 const u_char *data, int *off, char *cbuf, int cbuflen) 910 { 911 const char *const raw = (const char *)data + *off + 2; 912 const int slen = *((const u_int16_t *)(data + *off)); 913 char *const s = ng_encode_string(raw, slen); 914 915 if (s == NULL) 916 return (ENOMEM); 917 NG_PARSE_APPEND("%s", s); 918 FREE(s, M_NETGRAPH_PARSE); 919 *off += slen + 2; 920 return (0); 921 } 922 923 static int 924 ng_sizedstring_getDefault(const struct ng_parse_type *type, 925 const u_char *const start, u_char *buf, int *buflen) 926 { 927 if (*buflen < 2) 928 return (ERANGE); 929 bzero(buf, 2); 930 *buflen = 2; 931 return (0); 932 } 933 934 const struct ng_parse_type ng_parse_sizedstring_type = { 935 NULL, 936 NULL, 937 NULL, 938 ng_sizedstring_parse, 939 ng_sizedstring_unparse, 940 ng_sizedstring_getDefault, 941 NULL 942 }; 943 944 /************************************************************************ 945 IP ADDRESS TYPE 946 ************************************************************************/ 947 948 static int 949 ng_ipaddr_parse(const struct ng_parse_type *type, 950 const char *s, int *off, const u_char *const start, 951 u_char *const buf, int *buflen) 952 { 953 int i, error; 954 955 for (i = 0; i < 4; i++) { 956 if ((error = ng_int8_parse(&ng_parse_int8_type, 957 s, off, start, buf + i, buflen)) != 0) 958 return (error); 959 if (i < 3 && s[*off] != '.') 960 return (EINVAL); 961 (*off)++; 962 } 963 *buflen = 4; 964 return (0); 965 } 966 967 static int 968 ng_ipaddr_unparse(const struct ng_parse_type *type, 969 const u_char *data, int *off, char *cbuf, int cbuflen) 970 { 971 struct in_addr ip; 972 973 bcopy(data + *off, &ip, sizeof(ip)); 974 NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0], 975 ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]); 976 *off += sizeof(ip); 977 return (0); 978 } 979 980 static int 981 ng_ipaddr_getDefault(const struct ng_parse_type *type, 982 const u_char *const start, u_char *buf, int *buflen) 983 { 984 struct in_addr ip = { 0 }; 985 986 if (*buflen < sizeof(ip)) 987 return (ERANGE); 988 bcopy(&ip, buf, sizeof(ip)); 989 *buflen = sizeof(ip); 990 return (0); 991 } 992 993 const struct ng_parse_type ng_parse_ipaddr_type = { 994 NULL, 995 NULL, 996 NULL, 997 ng_ipaddr_parse, 998 ng_ipaddr_unparse, 999 ng_ipaddr_getDefault, 1000 ng_int32_getAlign 1001 }; 1002 1003 /************************************************************************ 1004 ETHERNET ADDRESS TYPE 1005 ************************************************************************/ 1006 1007 static int 1008 ng_enaddr_parse(const struct ng_parse_type *type, 1009 const char *s, int *const off, const u_char *const start, 1010 u_char *const buf, int *const buflen) 1011 { 1012 char *eptr; 1013 u_long val; 1014 int i; 1015 1016 if (*buflen < ETHER_ADDR_LEN) 1017 return (ERANGE); 1018 for (i = 0; i < ETHER_ADDR_LEN; i++) { 1019 val = strtoul(s + *off, &eptr, 16); 1020 if (val > 0xff || eptr == s + *off) 1021 return (EINVAL); 1022 buf[i] = (u_char)val; 1023 *off = (eptr - s); 1024 if (i < ETHER_ADDR_LEN - 1) { 1025 if (*eptr != ':') 1026 return (EINVAL); 1027 (*off)++; 1028 } 1029 } 1030 *buflen = ETHER_ADDR_LEN; 1031 return (0); 1032 } 1033 1034 static int 1035 ng_enaddr_unparse(const struct ng_parse_type *type, 1036 const u_char *data, int *off, char *cbuf, int cbuflen) 1037 { 1038 int len; 1039 1040 len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x", 1041 data[*off], data[*off + 1], data[*off + 2], 1042 data[*off + 3], data[*off + 4], data[*off + 5]); 1043 if (len >= cbuflen) 1044 return (ERANGE); 1045 *off += ETHER_ADDR_LEN; 1046 return (0); 1047 } 1048 1049 const struct ng_parse_type ng_parse_enaddr_type = { 1050 NULL, 1051 NULL, 1052 NULL, 1053 ng_enaddr_parse, 1054 ng_enaddr_unparse, 1055 NULL, 1056 0 1057 }; 1058 1059 /************************************************************************ 1060 BYTE ARRAY TYPE 1061 ************************************************************************/ 1062 1063 /* Get the length of a byte array */ 1064 static int 1065 ng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type, 1066 const u_char *start, const u_char *buf) 1067 { 1068 ng_parse_array_getLength_t *const getLength = type->private; 1069 1070 return (*getLength)(type, start, buf); 1071 } 1072 1073 /* Byte array element type is hex int8 */ 1074 static const struct ng_parse_array_info ng_parse_bytearray_subtype_info = { 1075 &ng_parse_hint8_type, 1076 &ng_parse_bytearray_subtype_getLength, 1077 NULL 1078 }; 1079 static const struct ng_parse_type ng_parse_bytearray_subtype = { 1080 &ng_parse_array_type, 1081 &ng_parse_bytearray_subtype_info 1082 }; 1083 1084 static int 1085 ng_bytearray_parse(const struct ng_parse_type *type, 1086 const char *s, int *off, const u_char *const start, 1087 u_char *const buf, int *buflen) 1088 { 1089 char *str; 1090 int toklen; 1091 int slen; 1092 1093 /* We accept either an array of bytes or a string constant */ 1094 if ((str = ng_get_string_token(s, off, &toklen, &slen)) != NULL) { 1095 ng_parse_array_getLength_t *const getLength = type->info; 1096 int arraylen; 1097 1098 arraylen = (*getLength)(type, start, buf); 1099 if (arraylen > *buflen) { 1100 FREE(str, M_NETGRAPH_PARSE); 1101 return (ERANGE); 1102 } 1103 if (slen > arraylen) { 1104 FREE(str, M_NETGRAPH_PARSE); 1105 return (E2BIG); 1106 } 1107 bcopy(str, buf, slen); 1108 bzero(buf + slen, arraylen - slen); 1109 FREE(str, M_NETGRAPH_PARSE); 1110 *off += toklen; 1111 *buflen = arraylen; 1112 return (0); 1113 } else { 1114 struct ng_parse_type subtype; 1115 1116 subtype = ng_parse_bytearray_subtype; 1117 (const void *)subtype.private = type->info; 1118 return ng_array_parse(&subtype, s, off, start, buf, buflen); 1119 } 1120 } 1121 1122 static int 1123 ng_bytearray_unparse(const struct ng_parse_type *type, 1124 const u_char *data, int *off, char *cbuf, int cbuflen) 1125 { 1126 struct ng_parse_type subtype; 1127 1128 subtype = ng_parse_bytearray_subtype; 1129 (const void *)subtype.private = type->info; 1130 return ng_array_unparse(&subtype, data, off, cbuf, cbuflen); 1131 } 1132 1133 static int 1134 ng_bytearray_getDefault(const struct ng_parse_type *type, 1135 const u_char *const start, u_char *buf, int *buflen) 1136 { 1137 struct ng_parse_type subtype; 1138 1139 subtype = ng_parse_bytearray_subtype; 1140 (const void *)subtype.private = type->info; 1141 return ng_array_getDefault(&subtype, start, buf, buflen); 1142 } 1143 1144 const struct ng_parse_type ng_parse_bytearray_type = { 1145 NULL, 1146 NULL, 1147 NULL, 1148 ng_bytearray_parse, 1149 ng_bytearray_unparse, 1150 ng_bytearray_getDefault, 1151 NULL 1152 }; 1153 1154 /************************************************************************ 1155 STRUCT NG_MESG TYPE 1156 ************************************************************************/ 1157 1158 /* Get msg->header.arglen when "buf" is pointing to msg->data */ 1159 static int 1160 ng_parse_ng_mesg_getLength(const struct ng_parse_type *type, 1161 const u_char *start, const u_char *buf) 1162 { 1163 const struct ng_mesg *msg; 1164 1165 msg = (const struct ng_mesg *)(buf - sizeof(*msg)); 1166 return msg->header.arglen; 1167 } 1168 1169 /* Type for the variable length data portion of a struct ng_mesg */ 1170 static const struct ng_parse_type ng_msg_data_type = { 1171 &ng_parse_bytearray_type, 1172 &ng_parse_ng_mesg_getLength 1173 }; 1174 1175 /* Type for the entire struct ng_mesg header with data section */ 1176 static const struct ng_parse_struct_field ng_parse_ng_mesg_type_fields[] 1177 = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type); 1178 const struct ng_parse_type ng_parse_ng_mesg_type = { 1179 &ng_parse_struct_type, 1180 &ng_parse_ng_mesg_type_fields, 1181 }; 1182 1183 /************************************************************************ 1184 COMPOSITE HELPER ROUTINES 1185 ************************************************************************/ 1186 1187 /* 1188 * Convert a structure or array from ASCII to binary 1189 */ 1190 static int 1191 ng_parse_composite(const struct ng_parse_type *type, const char *s, 1192 int *off, const u_char *const start, u_char *const buf, int *buflen, 1193 const enum comptype ctype) 1194 { 1195 const int num = ng_get_composite_len(type, start, buf, ctype); 1196 int nextIndex = 0; /* next implicit array index */ 1197 u_int index; /* field or element index */ 1198 int *foff; /* field value offsets in string */ 1199 int align, len, blen, error = 0; 1200 1201 /* Initialize */ 1202 MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO); 1203 if (foff == NULL) { 1204 error = ENOMEM; 1205 goto done; 1206 } 1207 1208 /* Get opening brace/bracket */ 1209 if (ng_parse_get_token(s, off, &len) 1210 != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) { 1211 error = EINVAL; 1212 goto done; 1213 } 1214 *off += len; 1215 1216 /* Get individual element value positions in the string */ 1217 for (;;) { 1218 enum ng_parse_token tok; 1219 1220 /* Check for closing brace/bracket */ 1221 tok = ng_parse_get_token(s, off, &len); 1222 if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) { 1223 *off += len; 1224 break; 1225 } 1226 1227 /* For arrays, the 'name' (ie, index) is optional, so 1228 distinguish name from values by seeing if the next 1229 token is an equals sign */ 1230 if (ctype != CT_STRUCT) { 1231 int len2, off2; 1232 char *eptr; 1233 1234 /* If an opening brace/bracket, index is implied */ 1235 if (tok == T_LBRACE || tok == T_LBRACKET) { 1236 index = nextIndex++; 1237 goto gotIndex; 1238 } 1239 1240 /* Might be an index, might be a value, either way... */ 1241 if (tok != T_WORD) { 1242 error = EINVAL; 1243 goto done; 1244 } 1245 1246 /* If no equals sign follows, index is implied */ 1247 off2 = *off + len; 1248 if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) { 1249 index = nextIndex++; 1250 goto gotIndex; 1251 } 1252 1253 /* Index was specified explicitly; parse it */ 1254 index = (u_int)strtoul(s + *off, &eptr, 0); 1255 if (index < 0 || eptr - (s + *off) != len) { 1256 error = EINVAL; 1257 goto done; 1258 } 1259 nextIndex = index + 1; 1260 *off += len + len2; 1261 } else { /* a structure field */ 1262 const struct ng_parse_struct_field *const 1263 fields = type->info; 1264 1265 /* Find the field by name (required) in field list */ 1266 if (tok != T_WORD) { 1267 error = EINVAL; 1268 goto done; 1269 } 1270 for (index = 0; index < num; index++) { 1271 const struct ng_parse_struct_field *const 1272 field = &fields[index]; 1273 1274 if (strncmp(&s[*off], field->name, len) == 0 1275 && field->name[len] == '\0') 1276 break; 1277 } 1278 if (index == num) { 1279 error = ENOENT; 1280 goto done; 1281 } 1282 *off += len; 1283 1284 /* Get equals sign */ 1285 if (ng_parse_get_token(s, off, &len) != T_EQUALS) { 1286 error = EINVAL; 1287 goto done; 1288 } 1289 *off += len; 1290 } 1291 gotIndex: 1292 1293 /* Check array index */ 1294 if (index >= num) { 1295 error = E2BIG; 1296 goto done; 1297 } 1298 1299 /* Save value's position and skip over it for now */ 1300 if (foff[index] != 0) { 1301 error = EALREADY; /* duplicate */ 1302 goto done; 1303 } 1304 while (isspace(s[*off])) 1305 (*off)++; 1306 foff[index] = *off; 1307 if ((error = ng_parse_skip_value(s, *off, &len)) != 0) 1308 goto done; 1309 *off += len; 1310 } 1311 1312 /* Now build binary structure from supplied values and defaults */ 1313 for (blen = index = 0; index < num; index++) { 1314 const struct ng_parse_type *const 1315 etype = ng_get_composite_etype(type, index, ctype); 1316 int k, pad, vlen; 1317 1318 /* Zero-pad any alignment bytes */ 1319 pad = ng_parse_get_elem_pad(type, index, ctype, blen); 1320 for (k = 0; k < pad; k++) { 1321 if (blen >= *buflen) { 1322 error = ERANGE; 1323 goto done; 1324 } 1325 buf[blen++] = 0; 1326 } 1327 1328 /* Get value */ 1329 vlen = *buflen - blen; 1330 if (foff[index] == 0) { /* use default value */ 1331 error = ng_get_composite_elem_default(type, index, 1332 start, buf + blen, &vlen, ctype); 1333 } else { /* parse given value */ 1334 *off = foff[index]; 1335 error = INVOKE(etype, parse)(etype, 1336 s, off, start, buf + blen, &vlen); 1337 } 1338 if (error != 0) 1339 goto done; 1340 blen += vlen; 1341 } 1342 1343 /* Make total composite structure size a multiple of its alignment */ 1344 if ((align = ALIGNMENT(type)) != 0) { 1345 while (blen % align != 0) { 1346 if (blen >= *buflen) { 1347 error = ERANGE; 1348 goto done; 1349 } 1350 buf[blen++] = 0; 1351 } 1352 } 1353 1354 /* Done */ 1355 *buflen = blen; 1356 done: 1357 if (foff != NULL) 1358 FREE(foff, M_NETGRAPH_PARSE); 1359 return (error); 1360 } 1361 1362 /* 1363 * Convert an array or structure from binary to ASCII 1364 */ 1365 static int 1366 ng_unparse_composite(const struct ng_parse_type *type, const u_char *data, 1367 int *off, char *cbuf, int cbuflen, const enum comptype ctype) 1368 { 1369 const struct ng_mesg *const hdr 1370 = (const struct ng_mesg *)(data - sizeof(*hdr)); 1371 const int num = ng_get_composite_len(type, data, data + *off, ctype); 1372 const int workSize = 20 * 1024; /* XXX hard coded constant */ 1373 int nextIndex = 0, didOne = 0; 1374 int error, index; 1375 u_char *workBuf; 1376 1377 /* Get workspace for checking default values */ 1378 MALLOC(workBuf, u_char *, workSize, M_NETGRAPH_PARSE, M_NOWAIT); 1379 if (workBuf == NULL) 1380 return (ENOMEM); 1381 1382 /* Opening brace/bracket */ 1383 NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '['); 1384 1385 /* Do each item */ 1386 for (index = 0; index < num; index++) { 1387 const struct ng_parse_type *const 1388 etype = ng_get_composite_etype(type, index, ctype); 1389 1390 /* Skip any alignment pad bytes */ 1391 *off += ng_parse_get_elem_pad(type, index, ctype, *off); 1392 1393 /* 1394 * See if element is equal to its default value; skip if so. 1395 * Copy struct ng_mesg header for types that peek into it. 1396 */ 1397 if (sizeof(*hdr) + *off < workSize) { 1398 int tempsize = workSize - sizeof(*hdr) - *off; 1399 1400 bcopy(hdr, workBuf, sizeof(*hdr) + *off); 1401 if (ng_get_composite_elem_default(type, index, workBuf 1402 + sizeof(*hdr), workBuf + sizeof(*hdr) + *off, 1403 &tempsize, ctype) == 0 1404 && bcmp(workBuf + sizeof(*hdr) + *off, 1405 data + *off, tempsize) == 0) { 1406 *off += tempsize; 1407 continue; 1408 } 1409 } 1410 1411 /* Print name= */ 1412 NG_PARSE_APPEND(" "); 1413 if (ctype != CT_STRUCT) { 1414 if (index != nextIndex) { 1415 nextIndex = index; 1416 NG_PARSE_APPEND("%d=", index); 1417 } 1418 nextIndex++; 1419 } else { 1420 const struct ng_parse_struct_field *const 1421 fields = type->info; 1422 1423 NG_PARSE_APPEND("%s=", fields[index].name); 1424 } 1425 1426 /* Print value */ 1427 if ((error = INVOKE(etype, unparse) 1428 (etype, data, off, cbuf, cbuflen)) != 0) { 1429 FREE(workBuf, M_NETGRAPH_PARSE); 1430 return (error); 1431 } 1432 cbuflen -= strlen(cbuf); 1433 cbuf += strlen(cbuf); 1434 didOne = 1; 1435 } 1436 FREE(workBuf, M_NETGRAPH_PARSE); 1437 1438 /* Closing brace/bracket */ 1439 NG_PARSE_APPEND("%s%c", 1440 didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']'); 1441 return (0); 1442 } 1443 1444 /* 1445 * Generate the default value for an element of an array or structure 1446 * Returns EOPNOTSUPP if default value is unspecified. 1447 */ 1448 static int 1449 ng_get_composite_elem_default(const struct ng_parse_type *type, 1450 int index, const u_char *const start, u_char *buf, int *buflen, 1451 const enum comptype ctype) 1452 { 1453 const struct ng_parse_type *etype; 1454 ng_getDefault_t *func; 1455 1456 switch (ctype) { 1457 case CT_STRUCT: 1458 break; 1459 case CT_ARRAY: 1460 { 1461 const struct ng_parse_array_info *const ai = type->info; 1462 1463 if (ai->getDefault != NULL) { 1464 return (*ai->getDefault)(type, 1465 index, start, buf, buflen); 1466 } 1467 break; 1468 } 1469 case CT_FIXEDARRAY: 1470 { 1471 const struct ng_parse_fixedarray_info *const fi = type->info; 1472 1473 if (*fi->getDefault != NULL) { 1474 return (*fi->getDefault)(type, 1475 index, start, buf, buflen); 1476 } 1477 break; 1478 } 1479 default: 1480 panic("%s", __func__); 1481 } 1482 1483 /* Default to element type default */ 1484 etype = ng_get_composite_etype(type, index, ctype); 1485 func = METHOD(etype, getDefault); 1486 if (func == NULL) 1487 return (EOPNOTSUPP); 1488 return (*func)(etype, start, buf, buflen); 1489 } 1490 1491 /* 1492 * Get the number of elements in a struct, variable or fixed array. 1493 */ 1494 static int 1495 ng_get_composite_len(const struct ng_parse_type *type, 1496 const u_char *const start, const u_char *buf, 1497 const enum comptype ctype) 1498 { 1499 switch (ctype) { 1500 case CT_STRUCT: 1501 { 1502 const struct ng_parse_struct_field *const fields = type->info; 1503 int numFields = 0; 1504 1505 for (numFields = 0; ; numFields++) { 1506 const struct ng_parse_struct_field *const 1507 fi = &fields[numFields]; 1508 1509 if (fi->name == NULL) 1510 break; 1511 } 1512 return (numFields); 1513 } 1514 case CT_ARRAY: 1515 { 1516 const struct ng_parse_array_info *const ai = type->info; 1517 1518 return (*ai->getLength)(type, start, buf); 1519 } 1520 case CT_FIXEDARRAY: 1521 { 1522 const struct ng_parse_fixedarray_info *const fi = type->info; 1523 1524 return fi->length; 1525 } 1526 default: 1527 panic("%s", __func__); 1528 } 1529 return (0); 1530 } 1531 1532 /* 1533 * Return the type of the index'th element of a composite structure 1534 */ 1535 static const struct ng_parse_type * 1536 ng_get_composite_etype(const struct ng_parse_type *type, 1537 int index, const enum comptype ctype) 1538 { 1539 const struct ng_parse_type *etype = NULL; 1540 1541 switch (ctype) { 1542 case CT_STRUCT: 1543 { 1544 const struct ng_parse_struct_field *const fields = type->info; 1545 1546 etype = fields[index].type; 1547 break; 1548 } 1549 case CT_ARRAY: 1550 { 1551 const struct ng_parse_array_info *const ai = type->info; 1552 1553 etype = ai->elementType; 1554 break; 1555 } 1556 case CT_FIXEDARRAY: 1557 { 1558 const struct ng_parse_fixedarray_info *const fi = type->info; 1559 1560 etype = fi->elementType; 1561 break; 1562 } 1563 default: 1564 panic("%s", __func__); 1565 } 1566 return (etype); 1567 } 1568 1569 /* 1570 * Get the number of bytes to skip to align for the next 1571 * element in a composite structure. 1572 */ 1573 static int 1574 ng_parse_get_elem_pad(const struct ng_parse_type *type, 1575 int index, enum comptype ctype, int posn) 1576 { 1577 const struct ng_parse_type *const 1578 etype = ng_get_composite_etype(type, index, ctype); 1579 int align; 1580 1581 /* Get element's alignment, and possibly override */ 1582 align = ALIGNMENT(etype); 1583 if (ctype == CT_STRUCT) { 1584 const struct ng_parse_struct_field *const fields = type->info; 1585 1586 if (fields[index].alignment != 0) 1587 align = fields[index].alignment; 1588 } 1589 1590 /* Return number of bytes to skip to align */ 1591 return (align ? (align - (posn % align)) % align : 0); 1592 } 1593 1594 /************************************************************************ 1595 PARSING HELPER ROUTINES 1596 ************************************************************************/ 1597 1598 /* 1599 * Skip over a value 1600 */ 1601 static int 1602 ng_parse_skip_value(const char *s, int off0, int *lenp) 1603 { 1604 int len, nbracket, nbrace; 1605 int off = off0; 1606 1607 len = nbracket = nbrace = 0; 1608 do { 1609 switch (ng_parse_get_token(s, &off, &len)) { 1610 case T_LBRACKET: 1611 nbracket++; 1612 break; 1613 case T_LBRACE: 1614 nbrace++; 1615 break; 1616 case T_RBRACKET: 1617 if (nbracket-- == 0) 1618 return (EINVAL); 1619 break; 1620 case T_RBRACE: 1621 if (nbrace-- == 0) 1622 return (EINVAL); 1623 break; 1624 case T_EOF: 1625 return (EINVAL); 1626 default: 1627 break; 1628 } 1629 off += len; 1630 } while (nbracket > 0 || nbrace > 0); 1631 *lenp = off - off0; 1632 return (0); 1633 } 1634 1635 /* 1636 * Find the next token in the string, starting at offset *startp. 1637 * Returns the token type, with *startp pointing to the first char 1638 * and *lenp the length. 1639 */ 1640 enum ng_parse_token 1641 ng_parse_get_token(const char *s, int *startp, int *lenp) 1642 { 1643 char *t; 1644 int i; 1645 1646 while (isspace(s[*startp])) 1647 (*startp)++; 1648 switch (s[*startp]) { 1649 case '\0': 1650 *lenp = 0; 1651 return T_EOF; 1652 case '{': 1653 *lenp = 1; 1654 return T_LBRACE; 1655 case '}': 1656 *lenp = 1; 1657 return T_RBRACE; 1658 case '[': 1659 *lenp = 1; 1660 return T_LBRACKET; 1661 case ']': 1662 *lenp = 1; 1663 return T_RBRACKET; 1664 case '=': 1665 *lenp = 1; 1666 return T_EQUALS; 1667 case '"': 1668 if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL) 1669 return T_ERROR; 1670 FREE(t, M_NETGRAPH_PARSE); 1671 return T_STRING; 1672 default: 1673 for (i = *startp + 1; s[i] != '\0' && !isspace(s[i]) 1674 && s[i] != '{' && s[i] != '}' && s[i] != '[' 1675 && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++) 1676 ; 1677 *lenp = i - *startp; 1678 return T_WORD; 1679 } 1680 } 1681 1682 /* 1683 * Get a string token, which must be enclosed in double quotes. 1684 * The normal C backslash escapes are recognized. 1685 */ 1686 char * 1687 ng_get_string_token(const char *s, int *startp, int *lenp, int *slenp) 1688 { 1689 char *cbuf, *p; 1690 int start, off; 1691 int slen; 1692 1693 while (isspace(s[*startp])) 1694 (*startp)++; 1695 start = *startp; 1696 if (s[*startp] != '"') 1697 return (NULL); 1698 MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT); 1699 if (cbuf == NULL) 1700 return (NULL); 1701 strcpy(cbuf, s + start + 1); 1702 for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) { 1703 if (*p == '"') { 1704 *p = '\0'; 1705 *lenp = off + 1; 1706 if (slenp != NULL) 1707 *slenp = slen; 1708 return (cbuf); 1709 } else if (p[0] == '\\' && p[1] != '\0') { 1710 int x, k; 1711 char *v; 1712 1713 strcpy(p, p + 1); 1714 v = p; 1715 switch (*p) { 1716 case 't': 1717 *v = '\t'; 1718 off++; 1719 continue; 1720 case 'n': 1721 *v = '\n'; 1722 off++; 1723 continue; 1724 case 'r': 1725 *v = '\r'; 1726 off++; 1727 continue; 1728 case 'v': 1729 *v = '\v'; 1730 off++; 1731 continue; 1732 case 'f': 1733 *v = '\f'; 1734 off++; 1735 continue; 1736 case '"': 1737 *v = '"'; 1738 off++; 1739 continue; 1740 case '0': case '1': case '2': case '3': 1741 case '4': case '5': case '6': case '7': 1742 for (x = k = 0; 1743 k < 3 && *v >= '0' && *v <= '7'; v++) { 1744 x = (x << 3) + (*v - '0'); 1745 off++; 1746 } 1747 *--v = (char)x; 1748 break; 1749 case 'x': 1750 for (v++, x = k = 0; 1751 k < 2 && isxdigit(*v); v++) { 1752 x = (x << 4) + (isdigit(*v) ? 1753 (*v - '0') : 1754 (tolower(*v) - 'a' + 10)); 1755 off++; 1756 } 1757 *--v = (char)x; 1758 break; 1759 default: 1760 continue; 1761 } 1762 strcpy(p, v); 1763 } 1764 } 1765 FREE(cbuf, M_NETGRAPH_PARSE); 1766 return (NULL); /* no closing quote */ 1767 } 1768 1769 /* 1770 * Encode a string so it can be safely put in double quotes. 1771 * Caller must free the result. Exactly "slen" characters 1772 * are encoded. 1773 */ 1774 char * 1775 ng_encode_string(const char *raw, int slen) 1776 { 1777 char *cbuf; 1778 int off = 0; 1779 int i; 1780 1781 MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT); 1782 if (cbuf == NULL) 1783 return (NULL); 1784 cbuf[off++] = '"'; 1785 for (i = 0; i < slen; i++, raw++) { 1786 switch (*raw) { 1787 case '\t': 1788 cbuf[off++] = '\\'; 1789 cbuf[off++] = 't'; 1790 break; 1791 case '\f': 1792 cbuf[off++] = '\\'; 1793 cbuf[off++] = 'f'; 1794 break; 1795 case '\n': 1796 cbuf[off++] = '\\'; 1797 cbuf[off++] = 'n'; 1798 break; 1799 case '\r': 1800 cbuf[off++] = '\\'; 1801 cbuf[off++] = 'r'; 1802 break; 1803 case '\v': 1804 cbuf[off++] = '\\'; 1805 cbuf[off++] = 'v'; 1806 break; 1807 case '"': 1808 case '\\': 1809 cbuf[off++] = '\\'; 1810 cbuf[off++] = *raw; 1811 break; 1812 default: 1813 if (*raw < 0x20 || *raw > 0x7e) { 1814 off += sprintf(cbuf + off, 1815 "\\x%02x", (u_char)*raw); 1816 break; 1817 } 1818 cbuf[off++] = *raw; 1819 break; 1820 } 1821 } 1822 cbuf[off++] = '"'; 1823 cbuf[off] = '\0'; 1824 return (cbuf); 1825 } 1826 1827 /************************************************************************ 1828 VIRTUAL METHOD LOOKUP 1829 ************************************************************************/ 1830 1831 static ng_parse_t * 1832 ng_get_parse_method(const struct ng_parse_type *t) 1833 { 1834 while (t != NULL && t->parse == NULL) 1835 t = t->supertype; 1836 return (t ? t->parse : NULL); 1837 } 1838 1839 static ng_unparse_t * 1840 ng_get_unparse_method(const struct ng_parse_type *t) 1841 { 1842 while (t != NULL && t->unparse == NULL) 1843 t = t->supertype; 1844 return (t ? t->unparse : NULL); 1845 } 1846 1847 static ng_getDefault_t * 1848 ng_get_getDefault_method(const struct ng_parse_type *t) 1849 { 1850 while (t != NULL && t->getDefault == NULL) 1851 t = t->supertype; 1852 return (t ? t->getDefault : NULL); 1853 } 1854 1855 static ng_getAlign_t * 1856 ng_get_getAlign_method(const struct ng_parse_type *t) 1857 { 1858 while (t != NULL && t->getAlign == NULL) 1859 t = t->supertype; 1860 return (t ? t->getAlign : NULL); 1861 } 1862 1863