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