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