Deleted Added
full compact
ng_parse.c (54249) ng_parse.c (58011)
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