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