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