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