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 $
| 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 54249 1999-12-07 05:50:48Z julian $
| 40 * $FreeBSD: head/sys/netgraph/ng_parse.c 58011 2000-03-13 18:50:38Z 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/ctype.h> 49 50#include <netinet/in.h> 51 52#include <netgraph/ng_message.h> 53#include <netgraph/netgraph.h> 54#include <netgraph/ng_parse.h> 55 56/* Compute alignment for primitive integral types */ 57struct int16_temp { 58 char x; 59 int16_t y; 60}; 61 62struct int32_temp { 63 char x; 64 int32_t y; 65}; 66 67struct int64_temp { 68 char x; 69 int64_t y; 70}; 71 72#define INT8_ALIGNMENT 1 73#define INT16_ALIGNMENT ((int)&((struct int16_temp *)0)->y) 74#define INT32_ALIGNMENT ((int)&((struct int32_temp *)0)->y) 75#define INT64_ALIGNMENT ((int)&((struct int64_temp *)0)->y) 76 77/* Type of composite object: struct, array, or fixedarray */ 78enum comptype { 79 CT_STRUCT, 80 CT_ARRAY, 81 CT_FIXEDARRAY, 82}; 83 84/* Composite types helper functions */ 85static 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); 88static 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); 91static 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); 94static int ng_get_composite_len(const struct ng_parse_type *type, 95 const u_char *start, const u_char *buf, 96 enum comptype ctype); 97static const struct ng_parse_type *ng_get_composite_etype(const struct 98 ng_parse_type *type, int index, enum comptype ctype); 99static 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 */ 103static 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 109static ng_parse_t *ng_get_parse_method(const struct ng_parse_type *t); 110static ng_unparse_t *ng_get_unparse_method(const struct ng_parse_type *t); 111static ng_getDefault_t *ng_get_getDefault_method(const 112 struct ng_parse_type *t); 113static 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 */ 138int 139ng_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 */ 148int 149ng_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 */ 160int 161ng_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 175static int 176ng_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 183static int 184ng_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 190static int 191ng_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 200static int 201ng_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 216const 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 230static int 231ng_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 239static int 240ng_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 247static int 248ng_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 257static int 258ng_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 265const 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 279static int 280ng_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 287static int 288ng_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 294static int 295ng_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 304static int 305ng_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 312const 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 326static int 327ng_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 345static int 346ng_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 357static int 358ng_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 371static int 372ng_int8_getAlign(const struct ng_parse_type *type) 373{ 374 return INT8_ALIGNMENT; 375} 376 377const 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 391static int 392ng_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 410static int 411ng_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 422static int 423ng_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 436static int 437ng_int16_getAlign(const struct ng_parse_type *type) 438{ 439 return INT16_ALIGNMENT; 440} 441 442const 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 456static int 457ng_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 476static int 477ng_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 488static int 489ng_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 502static int 503ng_int32_getAlign(const struct ng_parse_type *type) 504{ 505 return INT32_ALIGNMENT; 506} 507 508const 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 522static int 523ng_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 541static int 542ng_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 553static int 554ng_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 567static int 568ng_int64_getAlign(const struct ng_parse_type *type) 569{ 570 return INT64_ALIGNMENT; 571} 572 573const 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 587static int 588ng_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 605static int 606ng_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 620static int 621ng_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 632const 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 646static int 647ng_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{
| 41 */ 42 43#include <sys/types.h> 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/errno.h> 47#include <sys/malloc.h> 48#include <sys/ctype.h> 49 50#include <netinet/in.h> 51 52#include <netgraph/ng_message.h> 53#include <netgraph/netgraph.h> 54#include <netgraph/ng_parse.h> 55 56/* Compute alignment for primitive integral types */ 57struct int16_temp { 58 char x; 59 int16_t y; 60}; 61 62struct int32_temp { 63 char x; 64 int32_t y; 65}; 66 67struct int64_temp { 68 char x; 69 int64_t y; 70}; 71 72#define INT8_ALIGNMENT 1 73#define INT16_ALIGNMENT ((int)&((struct int16_temp *)0)->y) 74#define INT32_ALIGNMENT ((int)&((struct int32_temp *)0)->y) 75#define INT64_ALIGNMENT ((int)&((struct int64_temp *)0)->y) 76 77/* Type of composite object: struct, array, or fixedarray */ 78enum comptype { 79 CT_STRUCT, 80 CT_ARRAY, 81 CT_FIXEDARRAY, 82}; 83 84/* Composite types helper functions */ 85static 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); 88static 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); 91static 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); 94static int ng_get_composite_len(const struct ng_parse_type *type, 95 const u_char *start, const u_char *buf, 96 enum comptype ctype); 97static const struct ng_parse_type *ng_get_composite_etype(const struct 98 ng_parse_type *type, int index, enum comptype ctype); 99static 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 */ 103static 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 109static ng_parse_t *ng_get_parse_method(const struct ng_parse_type *t); 110static ng_unparse_t *ng_get_unparse_method(const struct ng_parse_type *t); 111static ng_getDefault_t *ng_get_getDefault_method(const 112 struct ng_parse_type *t); 113static 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 */ 138int 139ng_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 */ 148int 149ng_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 */ 160int 161ng_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 175static int 176ng_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 183static int 184ng_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 190static int 191ng_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 200static int 201ng_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 216const 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 230static int 231ng_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 239static int 240ng_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 247static int 248ng_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 257static int 258ng_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 265const 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 279static int 280ng_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 287static int 288ng_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 294static int 295ng_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 304static int 305ng_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 312const 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 326static int 327ng_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 345static int 346ng_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 357static int 358ng_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 371static int 372ng_int8_getAlign(const struct ng_parse_type *type) 373{ 374 return INT8_ALIGNMENT; 375} 376 377const 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 391static int 392ng_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 410static int 411ng_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 422static int 423ng_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 436static int 437ng_int16_getAlign(const struct ng_parse_type *type) 438{ 439 return INT16_ALIGNMENT; 440} 441 442const 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 456static int 457ng_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 476static int 477ng_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 488static int 489ng_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 502static int 503ng_int32_getAlign(const struct ng_parse_type *type) 504{ 505 return INT32_ALIGNMENT; 506} 507 508const 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 522static int 523ng_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 541static int 542ng_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 553static int 554ng_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 567static int 568ng_int64_getAlign(const struct ng_parse_type *type) 569{ 570 return INT64_ALIGNMENT; 571} 572 573const 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 587static int 588ng_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 605static int 606ng_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 620static int 621ng_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 632const 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 646static int 647ng_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;
| 651 const struct ng_parse_fixedstring_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 668static int 669ng_fixedstring_unparse(const struct ng_parse_type *type, 670 const u_char *data, int *off, char *cbuf, int cbuflen) 671{
| 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 668static int 669ng_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;
| 672 const struct ng_parse_fixedstring_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 681static int 682ng_fixedstring_getDefault(const struct ng_parse_type *type, 683 const u_char *const start, u_char *buf, int *buflen) 684{
| 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 681static int 682ng_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;
| 685 const struct ng_parse_fixedstring_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 694const 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
| 686 687 if (*buflen < fi->bufSize) 688 return (ERANGE); 689 bzero(buf, fi->bufSize); 690 *buflen = fi->bufSize; 691 return (0); 692} 693 694const 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
|
704const struct ng_parse_fixedsstring_info ng_parse_nodebuf_info = {
| 704const struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
|
705 NG_NODELEN + 1 706}; 707const struct ng_parse_type ng_parse_nodebuf_type = { 708 &ng_parse_fixedstring_type, 709 &ng_parse_nodebuf_info 710}; 711
| 705 NG_NODELEN + 1 706}; 707const struct ng_parse_type ng_parse_nodebuf_type = { 708 &ng_parse_fixedstring_type, 709 &ng_parse_nodebuf_info 710}; 711
|
712const struct ng_parse_fixedsstring_info ng_parse_hookbuf_info = {
| 712const struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
|
713 NG_HOOKLEN + 1 714}; 715const struct ng_parse_type ng_parse_hookbuf_type = { 716 &ng_parse_fixedstring_type, 717 &ng_parse_hookbuf_info 718}; 719
| 713 NG_HOOKLEN + 1 714}; 715const struct ng_parse_type ng_parse_hookbuf_type = { 716 &ng_parse_fixedstring_type, 717 &ng_parse_hookbuf_info 718}; 719
|
720const struct ng_parse_fixedsstring_info ng_parse_pathbuf_info = {
| 720const struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
|
721 NG_PATHLEN + 1 722}; 723const struct ng_parse_type ng_parse_pathbuf_type = { 724 &ng_parse_fixedstring_type, 725 &ng_parse_pathbuf_info 726}; 727
| 721 NG_PATHLEN + 1 722}; 723const struct ng_parse_type ng_parse_pathbuf_type = { 724 &ng_parse_fixedstring_type, 725 &ng_parse_pathbuf_info 726}; 727
|
728const struct ng_parse_fixedsstring_info ng_parse_typebuf_info = {
| 728const struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
|
729 NG_TYPELEN + 1 730}; 731const struct ng_parse_type ng_parse_typebuf_type = { 732 &ng_parse_fixedstring_type, 733 &ng_parse_typebuf_info 734}; 735
| 729 NG_TYPELEN + 1 730}; 731const struct ng_parse_type ng_parse_typebuf_type = { 732 &ng_parse_fixedstring_type, 733 &ng_parse_typebuf_info 734}; 735
|
736const struct ng_parse_fixedsstring_info ng_parse_cmdbuf_info = {
| 736const struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
|
737 NG_CMDSTRLEN + 1 738}; 739const 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 748static int 749ng_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 767static int 768ng_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 780static int 781ng_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 793const 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 */ 808static int 809ng_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 817static int 818ng_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 */ 830const 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 840static 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}; 845static const struct ng_parse_type ng_parse_bytearray_subtype = { 846 &ng_parse_array_type, 847 &ng_parse_bytearray_subtype_info 848}; 849 850static int 851ng_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 888static int 889ng_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 899static int 900ng_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 910const 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 */ 925static int 926ng_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 */ 936static 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 */ 942static const struct ng_parse_struct_info 943 ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type); 944const 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 */ 956static int 957ng_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; 1028gotIndex: 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; 1121done: 1122 FREE(foff, M_NETGRAPH); 1123 return (error); 1124} 1125 1126/* 1127 * Convert an array or structure from binary to ASCII 1128 */ 1129static int 1130ng_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 */ 1195static int 1196ng_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 */ 1241static int 1242ng_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 */ 1282static const struct ng_parse_type * 1283ng_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 */ 1320static int 1321ng_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 */ 1348static int 1349ng_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 */ 1387enum ng_parse_token 1388ng_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 */ 1433char * 1434ng_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 */ 1516char * 1517ng_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 1572static ng_parse_t * 1573ng_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 1580static ng_unparse_t * 1581ng_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 1588static ng_getDefault_t * 1589ng_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 1596static ng_getAlign_t * 1597ng_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
| 737 NG_CMDSTRLEN + 1 738}; 739const 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 748static int 749ng_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 767static int 768ng_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 780static int 781ng_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 793const 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 */ 808static int 809ng_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 817static int 818ng_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 */ 830const 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 840static 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}; 845static const struct ng_parse_type ng_parse_bytearray_subtype = { 846 &ng_parse_array_type, 847 &ng_parse_bytearray_subtype_info 848}; 849 850static int 851ng_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 888static int 889ng_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 899static int 900ng_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 910const 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 */ 925static int 926ng_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 */ 936static 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 */ 942static const struct ng_parse_struct_info 943 ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type); 944const 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 */ 956static int 957ng_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; 1028gotIndex: 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; 1121done: 1122 FREE(foff, M_NETGRAPH); 1123 return (error); 1124} 1125 1126/* 1127 * Convert an array or structure from binary to ASCII 1128 */ 1129static int 1130ng_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 */ 1195static int 1196ng_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 */ 1241static int 1242ng_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 */ 1282static const struct ng_parse_type * 1283ng_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 */ 1320static int 1321ng_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 */ 1348static int 1349ng_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 */ 1387enum ng_parse_token 1388ng_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 */ 1433char * 1434ng_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 */ 1516char * 1517ng_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 1572static ng_parse_t * 1573ng_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 1580static ng_unparse_t * 1581ng_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 1588static ng_getDefault_t * 1589ng_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 1596static ng_getAlign_t * 1597ng_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
|