ng_parse.c revision 68845
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: head/sys/netgraph/ng_parse.c 68845 2000-11-16 23:14:53Z brian $ 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 */ 57struct int16_temp { 58 char x; 59 int16_t y; 60}; 61 62struct int32_temp { 63 char x; 64 int32_t y; 65}; 66 67struct 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 */ 83enum comptype { 84 CT_STRUCT, 85 CT_ARRAY, 86 CT_FIXEDARRAY, 87}; 88 89/* Composite types helper functions */ 90static 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); 93static 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); 96static 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); 99static int ng_get_composite_len(const struct ng_parse_type *type, 100 const u_char *start, const u_char *buf, 101 enum comptype ctype); 102static const struct ng_parse_type *ng_get_composite_etype(const struct 103 ng_parse_type *type, int index, enum comptype ctype); 104static 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 */ 108static 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 114static ng_parse_t *ng_get_parse_method(const struct ng_parse_type *t); 115static ng_unparse_t *ng_get_unparse_method(const struct ng_parse_type *t); 116static ng_getDefault_t *ng_get_getDefault_method(const 117 struct ng_parse_type *t); 118static 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 */ 143int 144ng_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 */ 153int 154ng_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 */ 165int 166ng_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 180static int 181ng_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 188static int 189ng_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 195static int 196ng_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 205static int 206ng_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 221const 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 235static int 236ng_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 244static int 245ng_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 252static int 253ng_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 262static int 263ng_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 270const 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 284static int 285ng_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 292static int 293ng_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 299static int 300ng_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 309static int 310ng_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 317const 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 331static int 332ng_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 350static int 351ng_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 380static int 381ng_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 394static int 395ng_int8_getAlign(const struct ng_parse_type *type) 396{ 397 return INT8_ALIGNMENT; 398} 399 400const 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 410const struct ng_parse_type ng_parse_uint8_type = { 411 &ng_parse_int8_type, 412 (void *)INT_UNSIGNED 413}; 414 415const 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 424static int 425ng_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 443static int 444ng_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 473static int 474ng_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 487static int 488ng_int16_getAlign(const struct ng_parse_type *type) 489{ 490 return INT16_ALIGNMENT; 491} 492 493const 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 503const struct ng_parse_type ng_parse_uint16_type = { 504 &ng_parse_int16_type, 505 (void *)INT_UNSIGNED 506}; 507 508const 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 517static int 518ng_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 537static int 538ng_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 567static int 568ng_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 581static int 582ng_int32_getAlign(const struct ng_parse_type *type) 583{ 584 return INT32_ALIGNMENT; 585} 586 587const 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 597const struct ng_parse_type ng_parse_uint32_type = { 598 &ng_parse_int32_type, 599 (void *)INT_UNSIGNED 600}; 601 602const 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 611static int 612ng_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 630static int 631ng_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 660static int 661ng_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 674static int 675ng_int64_getAlign(const struct ng_parse_type *type) 676{ 677 return INT64_ALIGNMENT; 678} 679 680const 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 690const struct ng_parse_type ng_parse_uint64_type = { 691 &ng_parse_int64_type, 692 (void *)INT_UNSIGNED 693}; 694 695const 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 704static int 705ng_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 722static int 723ng_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 737static int 738ng_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 749const 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 763static int 764ng_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 785static int 786ng_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 798static int 799ng_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 811const 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 821const struct ng_parse_fixedstring_info ng_parse_nodebuf_info = { 822 NG_NODELEN + 1 823}; 824const struct ng_parse_type ng_parse_nodebuf_type = { 825 &ng_parse_fixedstring_type, 826 &ng_parse_nodebuf_info 827}; 828 829const struct ng_parse_fixedstring_info ng_parse_hookbuf_info = { 830 NG_HOOKLEN + 1 831}; 832const struct ng_parse_type ng_parse_hookbuf_type = { 833 &ng_parse_fixedstring_type, 834 &ng_parse_hookbuf_info 835}; 836 837const struct ng_parse_fixedstring_info ng_parse_pathbuf_info = { 838 NG_PATHLEN + 1 839}; 840const struct ng_parse_type ng_parse_pathbuf_type = { 841 &ng_parse_fixedstring_type, 842 &ng_parse_pathbuf_info 843}; 844 845const struct ng_parse_fixedstring_info ng_parse_typebuf_info = { 846 NG_TYPELEN + 1 847}; 848const struct ng_parse_type ng_parse_typebuf_type = { 849 &ng_parse_fixedstring_type, 850 &ng_parse_typebuf_info 851}; 852 853const struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = { 854 NG_CMDSTRLEN + 1 855}; 856const 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 865static int 866ng_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 886static int 887ng_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 902static int 903ng_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 913const 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 927static int 928ng_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 946static int 947ng_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 959static int 960ng_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 972const 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 */ 987static int 988ng_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 */ 997static 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}; 1002static const struct ng_parse_type ng_parse_bytearray_subtype = { 1003 &ng_parse_array_type, 1004 &ng_parse_bytearray_subtype_info 1005}; 1006 1007static int 1008ng_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 1045static int 1046ng_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 1056static int 1057ng_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 1067const 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 */ 1082static int 1083ng_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 */ 1093static 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 */ 1099static const struct ng_parse_struct_info 1100 ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type); 1101const 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 */ 1113static int 1114ng_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); 1126 if (foff == NULL) { 1127 error = ENOMEM; 1128 goto done; 1129 } 1130 bzero(foff, num * sizeof(*foff)); 1131 1132 /* Get opening brace/bracket */ 1133 if (ng_parse_get_token(s, off, &len) 1134 != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) { 1135 error = EINVAL; 1136 goto done; 1137 } 1138 *off += len; 1139 1140 /* Get individual element value positions in the string */ 1141 for (;;) { 1142 enum ng_parse_token tok; 1143 1144 /* Check for closing brace/bracket */ 1145 tok = ng_parse_get_token(s, off, &len); 1146 if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) { 1147 *off += len; 1148 break; 1149 } 1150 1151 /* For arrays, the 'name' (ie, index) is optional, so 1152 distinguish name from values by seeing if the next 1153 token is an equals sign */ 1154 if (ctype != CT_STRUCT) { 1155 int len2, off2; 1156 char *eptr; 1157 1158 /* If an opening brace/bracket, index is implied */ 1159 if (tok == T_LBRACE || tok == T_LBRACKET) { 1160 index = nextIndex++; 1161 goto gotIndex; 1162 } 1163 1164 /* Might be an index, might be a value, either way... */ 1165 if (tok != T_WORD) { 1166 error = EINVAL; 1167 goto done; 1168 } 1169 1170 /* If no equals sign follows, index is implied */ 1171 off2 = *off + len; 1172 if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) { 1173 index = nextIndex++; 1174 goto gotIndex; 1175 } 1176 1177 /* Index was specified explicitly; parse it */ 1178 index = (u_int)strtoul(s + *off, &eptr, 0); 1179 if (index < 0 || eptr - (s + *off) != len) { 1180 error = EINVAL; 1181 goto done; 1182 } 1183 nextIndex = index + 1; 1184 *off += len + len2; 1185gotIndex: 1186 } else { /* a structure field */ 1187 const struct ng_parse_struct_field *field = NULL; 1188 const struct ng_parse_struct_info *si = type->info; 1189 1190 /* Find the field by name (required) in field list */ 1191 if (tok != T_WORD) { 1192 error = EINVAL; 1193 goto done; 1194 } 1195 for (index = 0; index < num; index++) { 1196 field = &si->fields[index]; 1197 if (strncmp(&s[*off], field->name, len) == 0 1198 && field->name[len] == '\0') 1199 break; 1200 } 1201 if (index == num) { 1202 error = ENOENT; 1203 goto done; 1204 } 1205 *off += len; 1206 1207 /* Get equals sign */ 1208 if (ng_parse_get_token(s, off, &len) != T_EQUALS) { 1209 error = EINVAL; 1210 goto done; 1211 } 1212 *off += len; 1213 } 1214 1215 /* Check array index */ 1216 if (index >= num) { 1217 error = E2BIG; 1218 goto done; 1219 } 1220 1221 /* Save value's position and skip over it for now */ 1222 if (foff[index] != 0) { 1223 error = EALREADY; /* duplicate */ 1224 goto done; 1225 } 1226 while (isspace(s[*off])) 1227 (*off)++; 1228 foff[index] = *off; 1229 if ((error = ng_parse_skip_value(s, *off, &len)) != 0) 1230 goto done; 1231 *off += len; 1232 } 1233 1234 /* Now build binary structure from supplied values and defaults */ 1235 for (blen = index = 0; index < num; index++) { 1236 const struct ng_parse_type *const 1237 etype = ng_get_composite_etype(type, index, ctype); 1238 int k, pad, vlen; 1239 1240 /* Zero-pad any alignment bytes */ 1241 pad = ng_parse_get_elem_pad(type, index, ctype, blen); 1242 for (k = 0; k < pad; k++) { 1243 if (blen >= *buflen) { 1244 error = ERANGE; 1245 goto done; 1246 } 1247 buf[blen++] = 0; 1248 } 1249 1250 /* Get value */ 1251 vlen = *buflen - blen; 1252 if (foff[index] == 0) { /* use default value */ 1253 error = ng_get_composite_elem_default(type, index, 1254 start, buf + blen, &vlen, ctype); 1255 } else { /* parse given value */ 1256 *off = foff[index]; 1257 error = INVOKE(etype, parse)(etype, 1258 s, off, start, buf + blen, &vlen); 1259 } 1260 if (error != 0) 1261 goto done; 1262 blen += vlen; 1263 } 1264 1265 /* Make total composite structure size a multiple of its alignment */ 1266 if ((align = ALIGNMENT(type)) != 0) { 1267 while (blen % align != 0) { 1268 if (blen >= *buflen) { 1269 error = ERANGE; 1270 goto done; 1271 } 1272 buf[blen++] = 0; 1273 } 1274 } 1275 1276 /* Done */ 1277 *buflen = blen; 1278done: 1279 if (foff != NULL) 1280 FREE(foff, M_NETGRAPH); 1281 return (error); 1282} 1283 1284/* 1285 * Convert an array or structure from binary to ASCII 1286 */ 1287static int 1288ng_unparse_composite(const struct ng_parse_type *type, const u_char *data, 1289 int *off, char *cbuf, int cbuflen, const enum comptype ctype) 1290{ 1291 const int num = ng_get_composite_len(type, data, data + *off, ctype); 1292 const int workSize = 20 * 1024; /* XXX hard coded constant */ 1293 int nextIndex = 0, didOne = 0; 1294 int error, index; 1295 u_char *workBuf; 1296 1297 /* Get workspace for checking default values */ 1298 MALLOC(workBuf, u_char *, workSize, M_NETGRAPH, M_NOWAIT); 1299 if (workBuf == NULL) 1300 return (ENOMEM); 1301 1302 /* Opening brace/bracket */ 1303 NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '['); 1304 1305 /* Do each item */ 1306 for (index = 0; index < num; index++) { 1307 const struct ng_parse_type *const 1308 etype = ng_get_composite_etype(type, index, ctype); 1309 1310 /* Skip any alignment pad bytes */ 1311 *off += ng_parse_get_elem_pad(type, index, ctype, *off); 1312 1313 /* See if element is equal to its default value; skip if so */ 1314 if (*off < workSize) { 1315 int tempsize = workSize - *off; 1316 1317 bcopy(data, workBuf, *off); 1318 if (ng_get_composite_elem_default(type, index, workBuf, 1319 workBuf + *off, &tempsize, ctype) == 0 1320 && bcmp(workBuf + *off, 1321 data + *off, tempsize) == 0) { 1322 *off += tempsize; 1323 continue; 1324 } 1325 } 1326 1327 /* Print name= */ 1328 NG_PARSE_APPEND(" "); 1329 if (ctype != CT_STRUCT) { 1330 if (index != nextIndex) { 1331 nextIndex = index; 1332 NG_PARSE_APPEND("%d=", index); 1333 } 1334 nextIndex++; 1335 } else { 1336 const struct ng_parse_struct_info *si = type->info; 1337 1338 NG_PARSE_APPEND("%s=", si->fields[index].name); 1339 } 1340 1341 /* Print value */ 1342 if ((error = INVOKE(etype, unparse) 1343 (etype, data, off, cbuf, cbuflen)) != 0) { 1344 FREE(workBuf, M_NETGRAPH); 1345 return (error); 1346 } 1347 cbuflen -= strlen(cbuf); 1348 cbuf += strlen(cbuf); 1349 didOne = 1; 1350 } 1351 FREE(workBuf, M_NETGRAPH); 1352 1353 /* Closing brace/bracket */ 1354 NG_PARSE_APPEND("%s%c", 1355 didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']'); 1356 return (0); 1357} 1358 1359/* 1360 * Generate the default value for an element of an array or structure 1361 * Returns EOPNOTSUPP if default value is unspecified. 1362 */ 1363static int 1364ng_get_composite_elem_default(const struct ng_parse_type *type, 1365 int index, const u_char *const start, u_char *buf, int *buflen, 1366 const enum comptype ctype) 1367{ 1368 const struct ng_parse_type *etype; 1369 ng_getDefault_t *func; 1370 1371 switch (ctype) { 1372 case CT_STRUCT: 1373 break; 1374 case CT_ARRAY: 1375 { 1376 const struct ng_parse_array_info *const ai = type->info; 1377 1378 if (ai->getDefault != NULL) { 1379 return (*ai->getDefault)(type, 1380 index, start, buf, buflen); 1381 } 1382 break; 1383 } 1384 case CT_FIXEDARRAY: 1385 { 1386 const struct ng_parse_fixedarray_info *const fi = type->info; 1387 1388 if (*fi->getDefault != NULL) { 1389 return (*fi->getDefault)(type, 1390 index, start, buf, buflen); 1391 } 1392 break; 1393 } 1394 default: 1395 panic("%s", __FUNCTION__); 1396 } 1397 1398 /* Default to element type default */ 1399 etype = ng_get_composite_etype(type, index, ctype); 1400 func = METHOD(etype, getDefault); 1401 if (func == NULL) 1402 return (EOPNOTSUPP); 1403 return (*func)(etype, start, buf, buflen); 1404} 1405 1406/* 1407 * Get the number of elements in a struct, variable or fixed array. 1408 */ 1409static int 1410ng_get_composite_len(const struct ng_parse_type *type, 1411 const u_char *const start, const u_char *buf, 1412 const enum comptype ctype) 1413{ 1414 switch (ctype) { 1415 case CT_STRUCT: 1416 { 1417 const struct ng_parse_struct_info *const si = type->info; 1418 int numFields = 0; 1419 1420 for (numFields = 0; ; numFields++) { 1421 const struct ng_parse_struct_field *const 1422 fi = &si->fields[numFields]; 1423 1424 if (fi->name == NULL) 1425 break; 1426 } 1427 return (numFields); 1428 } 1429 case CT_ARRAY: 1430 { 1431 const struct ng_parse_array_info *const ai = type->info; 1432 1433 return (*ai->getLength)(type, start, buf); 1434 } 1435 case CT_FIXEDARRAY: 1436 { 1437 const struct ng_parse_fixedarray_info *const fi = type->info; 1438 1439 return fi->length; 1440 } 1441 default: 1442 panic("%s", __FUNCTION__); 1443 } 1444 return (0); 1445} 1446 1447/* 1448 * Return the type of the index'th element of a composite structure 1449 */ 1450static const struct ng_parse_type * 1451ng_get_composite_etype(const struct ng_parse_type *type, 1452 int index, const enum comptype ctype) 1453{ 1454 const struct ng_parse_type *etype = NULL; 1455 1456 switch (ctype) { 1457 case CT_STRUCT: 1458 { 1459 const struct ng_parse_struct_info *const si = type->info; 1460 1461 etype = si->fields[index].type; 1462 break; 1463 } 1464 case CT_ARRAY: 1465 { 1466 const struct ng_parse_array_info *const ai = type->info; 1467 1468 etype = ai->elementType; 1469 break; 1470 } 1471 case CT_FIXEDARRAY: 1472 { 1473 const struct ng_parse_fixedarray_info *const fi = type->info; 1474 1475 etype = fi->elementType; 1476 break; 1477 } 1478 default: 1479 panic("%s", __FUNCTION__); 1480 } 1481 return (etype); 1482} 1483 1484/* 1485 * Get the number of bytes to skip to align for the next 1486 * element in a composite structure. 1487 */ 1488static int 1489ng_parse_get_elem_pad(const struct ng_parse_type *type, 1490 int index, enum comptype ctype, int posn) 1491{ 1492 const struct ng_parse_type *const 1493 etype = ng_get_composite_etype(type, index, ctype); 1494 int align; 1495 1496 /* Get element's alignment, and possibly override */ 1497 align = ALIGNMENT(etype); 1498 if (ctype == CT_STRUCT) { 1499 const struct ng_parse_struct_info *si = type->info; 1500 1501 if (si->fields[index].alignment != 0) 1502 align = si->fields[index].alignment; 1503 } 1504 1505 /* Return number of bytes to skip to align */ 1506 return (align ? (align - (posn % align)) % align : 0); 1507} 1508 1509/************************************************************************ 1510 PARSING HELPER ROUTINES 1511 ************************************************************************/ 1512 1513/* 1514 * Skip over a value 1515 */ 1516static int 1517ng_parse_skip_value(const char *s, int off0, int *lenp) 1518{ 1519 int len, nbracket, nbrace; 1520 int off = off0; 1521 1522 len = nbracket = nbrace = 0; 1523 do { 1524 switch (ng_parse_get_token(s, &off, &len)) { 1525 case T_LBRACKET: 1526 nbracket++; 1527 break; 1528 case T_LBRACE: 1529 nbrace++; 1530 break; 1531 case T_RBRACKET: 1532 if (nbracket-- == 0) 1533 return (EINVAL); 1534 break; 1535 case T_RBRACE: 1536 if (nbrace-- == 0) 1537 return (EINVAL); 1538 break; 1539 case T_EOF: 1540 return (EINVAL); 1541 default: 1542 break; 1543 } 1544 off += len; 1545 } while (nbracket > 0 || nbrace > 0); 1546 *lenp = off - off0; 1547 return (0); 1548} 1549 1550/* 1551 * Find the next token in the string, starting at offset *startp. 1552 * Returns the token type, with *startp pointing to the first char 1553 * and *lenp the length. 1554 */ 1555enum ng_parse_token 1556ng_parse_get_token(const char *s, int *startp, int *lenp) 1557{ 1558 char *t; 1559 int i; 1560 1561 while (isspace(s[*startp])) 1562 (*startp)++; 1563 switch (s[*startp]) { 1564 case '\0': 1565 *lenp = 0; 1566 return T_EOF; 1567 case '{': 1568 *lenp = 1; 1569 return T_LBRACE; 1570 case '}': 1571 *lenp = 1; 1572 return T_RBRACE; 1573 case '[': 1574 *lenp = 1; 1575 return T_LBRACKET; 1576 case ']': 1577 *lenp = 1; 1578 return T_RBRACKET; 1579 case '=': 1580 *lenp = 1; 1581 return T_EQUALS; 1582 case '"': 1583 if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL) 1584 return T_ERROR; 1585 FREE(t, M_NETGRAPH); 1586 return T_STRING; 1587 default: 1588 for (i = *startp + 1; s[i] != '\0' && !isspace(s[i]) 1589 && s[i] != '{' && s[i] != '}' && s[i] != '[' 1590 && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++) 1591 ; 1592 *lenp = i - *startp; 1593 return T_WORD; 1594 } 1595} 1596 1597/* 1598 * Get a string token, which must be enclosed in double quotes. 1599 * The normal C backslash escapes are recognized. 1600 */ 1601char * 1602ng_get_string_token(const char *s, int *startp, int *lenp, int *slenp) 1603{ 1604 char *cbuf, *p; 1605 int start, off; 1606 int slen; 1607 1608 while (isspace(s[*startp])) 1609 (*startp)++; 1610 start = *startp; 1611 if (s[*startp] != '"') 1612 return (NULL); 1613 MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH, M_NOWAIT); 1614 if (cbuf == NULL) 1615 return (NULL); 1616 strcpy(cbuf, s + start + 1); 1617 for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) { 1618 if (*p == '"') { 1619 *p = '\0'; 1620 *lenp = off + 1; 1621 if (slenp != NULL) 1622 *slenp = slen; 1623 return (cbuf); 1624 } else if (p[0] == '\\' && p[1] != '\0') { 1625 int x, k; 1626 char *v; 1627 1628 strcpy(p, p + 1); 1629 v = p; 1630 switch (*p) { 1631 case 't': 1632 *v = '\t'; 1633 off++; 1634 continue; 1635 case 'n': 1636 *v = '\n'; 1637 off++; 1638 continue; 1639 case 'r': 1640 *v = '\r'; 1641 off++; 1642 continue; 1643 case 'v': 1644 *v = '\v'; 1645 off++; 1646 continue; 1647 case 'f': 1648 *v = '\f'; 1649 off++; 1650 continue; 1651 case '"': 1652 *v = '"'; 1653 off++; 1654 continue; 1655 case '0': case '1': case '2': case '3': 1656 case '4': case '5': case '6': case '7': 1657 for (x = k = 0; 1658 k < 3 && *v >= '0' && *v <= '7'; v++) { 1659 x = (x << 3) + (*v - '0'); 1660 off++; 1661 } 1662 *--v = (char)x; 1663 break; 1664 case 'x': 1665 for (v++, x = k = 0; 1666 k < 2 && isxdigit(*v); v++) { 1667 x = (x << 4) + (isdigit(*v) ? 1668 (*v - '0') : 1669 (tolower(*v) - 'a' + 10)); 1670 off++; 1671 } 1672 *--v = (char)x; 1673 break; 1674 default: 1675 continue; 1676 } 1677 strcpy(p, v); 1678 } 1679 } 1680 return (NULL); /* no closing quote */ 1681} 1682 1683/* 1684 * Encode a string so it can be safely put in double quotes. 1685 * Caller must free the result. Exactly "slen" characters 1686 * are encoded. 1687 */ 1688char * 1689ng_encode_string(const char *raw, int slen) 1690{ 1691 char *cbuf; 1692 int off = 0; 1693 int i; 1694 1695 MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH, M_NOWAIT); 1696 if (cbuf == NULL) 1697 return (NULL); 1698 cbuf[off++] = '"'; 1699 for (i = 0; i < slen; i++, raw++) { 1700 switch (*raw) { 1701 case '\t': 1702 cbuf[off++] = '\\'; 1703 cbuf[off++] = 't'; 1704 break; 1705 case '\f': 1706 cbuf[off++] = '\\'; 1707 cbuf[off++] = 'f'; 1708 break; 1709 case '\n': 1710 cbuf[off++] = '\\'; 1711 cbuf[off++] = 'n'; 1712 break; 1713 case '\r': 1714 cbuf[off++] = '\\'; 1715 cbuf[off++] = 'r'; 1716 break; 1717 case '\v': 1718 cbuf[off++] = '\\'; 1719 cbuf[off++] = 'v'; 1720 break; 1721 case '"': 1722 case '\\': 1723 cbuf[off++] = '\\'; 1724 cbuf[off++] = *raw; 1725 break; 1726 default: 1727 if (*raw < 0x20 || *raw > 0x7e) { 1728 off += sprintf(cbuf + off, 1729 "\\x%02x", (u_char)*raw); 1730 break; 1731 } 1732 cbuf[off++] = *raw; 1733 break; 1734 } 1735 } 1736 cbuf[off++] = '"'; 1737 cbuf[off] = '\0'; 1738 return (cbuf); 1739} 1740 1741/************************************************************************ 1742 VIRTUAL METHOD LOOKUP 1743 ************************************************************************/ 1744 1745static ng_parse_t * 1746ng_get_parse_method(const struct ng_parse_type *t) 1747{ 1748 while (t != NULL && t->parse == NULL) 1749 t = t->supertype; 1750 return (t ? t->parse : NULL); 1751} 1752 1753static ng_unparse_t * 1754ng_get_unparse_method(const struct ng_parse_type *t) 1755{ 1756 while (t != NULL && t->unparse == NULL) 1757 t = t->supertype; 1758 return (t ? t->unparse : NULL); 1759} 1760 1761static ng_getDefault_t * 1762ng_get_getDefault_method(const struct ng_parse_type *t) 1763{ 1764 while (t != NULL && t->getDefault == NULL) 1765 t = t->supertype; 1766 return (t ? t->getDefault : NULL); 1767} 1768 1769static ng_getAlign_t * 1770ng_get_getAlign_method(const struct ng_parse_type *t) 1771{ 1772 while (t != NULL && t->getAlign == NULL) 1773 t = t->supertype; 1774 return (t ? t->getAlign : NULL); 1775} 1776 1777