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