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