xref: /freebsd/sys/netgraph/ng_parse.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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", __FUNCTION__);
381 	}
382 	NG_PARSE_APPEND(fmt, fval);
383 	*off += sizeof(int8_t);
384 	return (0);
385 }
386 
387 static int
388 ng_int8_getDefault(const struct ng_parse_type *type,
389 	const u_char *const start, u_char *buf, int *buflen)
390 {
391 	int8_t val;
392 
393 	if (*buflen < sizeof(int8_t))
394 		return (ERANGE);
395 	val = 0;
396 	bcopy(&val, buf, sizeof(int8_t));
397 	*buflen = sizeof(int8_t);
398 	return (0);
399 }
400 
401 static int
402 ng_int8_getAlign(const struct ng_parse_type *type)
403 {
404 	return INT8_ALIGNMENT;
405 }
406 
407 const struct ng_parse_type ng_parse_int8_type = {
408 	NULL,
409 	(void *)INT_SIGNED,
410 	NULL,
411 	ng_int8_parse,
412 	ng_int8_unparse,
413 	ng_int8_getDefault,
414 	ng_int8_getAlign
415 };
416 
417 const struct ng_parse_type ng_parse_uint8_type = {
418 	&ng_parse_int8_type,
419 	(void *)INT_UNSIGNED
420 };
421 
422 const struct ng_parse_type ng_parse_hint8_type = {
423 	&ng_parse_int8_type,
424 	(void *)INT_HEX
425 };
426 
427 /************************************************************************
428 				INT16 TYPE
429  ************************************************************************/
430 
431 static int
432 ng_int16_parse(const struct ng_parse_type *type,
433 	const char *s, int *off, const u_char *const start,
434 	u_char *const buf, int *buflen)
435 {
436 	long val;
437 	int16_t val16;
438 	char *eptr;
439 
440 	val = strtol(s + *off, &eptr, 0);
441 	if (val < (int16_t)0x8000
442 	    || val > (u_int16_t)0xffff || eptr == s + *off)
443 		return (EINVAL);
444 	*off = eptr - s;
445 	val16 = (int16_t)val;
446 	bcopy(&val16, buf, sizeof(int16_t));
447 	*buflen = sizeof(int16_t);
448 	return (0);
449 }
450 
451 static int
452 ng_int16_unparse(const struct ng_parse_type *type,
453 	const u_char *data, int *off, char *cbuf, int cbuflen)
454 {
455 	const char *fmt;
456 	int fval;
457 	int16_t val;
458 
459 	bcopy(data + *off, &val, sizeof(int16_t));
460 	switch ((int)type->info) {
461 	case INT_SIGNED:
462 		fmt = "%d";
463 		fval = val;
464 		break;
465 	case INT_UNSIGNED:
466 		fmt = "%u";
467 		fval = (u_int16_t)val;
468 		break;
469 	case INT_HEX:
470 		fmt = "0x%x";
471 		fval = (u_int16_t)val;
472 		break;
473 	default:
474 		panic("%s: unknown type", __FUNCTION__);
475 	}
476 	NG_PARSE_APPEND(fmt, fval);
477 	*off += sizeof(int16_t);
478 	return (0);
479 }
480 
481 static int
482 ng_int16_getDefault(const struct ng_parse_type *type,
483 	const u_char *const start, u_char *buf, int *buflen)
484 {
485 	int16_t val;
486 
487 	if (*buflen < sizeof(int16_t))
488 		return (ERANGE);
489 	val = 0;
490 	bcopy(&val, buf, sizeof(int16_t));
491 	*buflen = sizeof(int16_t);
492 	return (0);
493 }
494 
495 static int
496 ng_int16_getAlign(const struct ng_parse_type *type)
497 {
498 	return INT16_ALIGNMENT;
499 }
500 
501 const struct ng_parse_type ng_parse_int16_type = {
502 	NULL,
503 	(void *)INT_SIGNED,
504 	NULL,
505 	ng_int16_parse,
506 	ng_int16_unparse,
507 	ng_int16_getDefault,
508 	ng_int16_getAlign
509 };
510 
511 const struct ng_parse_type ng_parse_uint16_type = {
512 	&ng_parse_int16_type,
513 	(void *)INT_UNSIGNED
514 };
515 
516 const struct ng_parse_type ng_parse_hint16_type = {
517 	&ng_parse_int16_type,
518 	(void *)INT_HEX
519 };
520 
521 /************************************************************************
522 				INT32 TYPE
523  ************************************************************************/
524 
525 static int
526 ng_int32_parse(const struct ng_parse_type *type,
527 	const char *s, int *off, const u_char *const start,
528 	u_char *const buf, int *buflen)
529 {
530 	long val;			/* assumes long is at least 32 bits */
531 	int32_t val32;
532 	char *eptr;
533 
534 	val = strtol(s + *off, &eptr, 0);
535 	if (val < (int32_t)0x80000000
536 	    || val > (u_int32_t)0xffffffff || eptr == s + *off)
537 		return (EINVAL);
538 	*off = eptr - s;
539 	val32 = (int32_t)val;
540 	bcopy(&val32, buf, sizeof(int32_t));
541 	*buflen = sizeof(int32_t);
542 	return (0);
543 }
544 
545 static int
546 ng_int32_unparse(const struct ng_parse_type *type,
547 	const u_char *data, int *off, char *cbuf, int cbuflen)
548 {
549 	const char *fmt;
550 	long fval;
551 	int32_t val;
552 
553 	bcopy(data + *off, &val, sizeof(int32_t));
554 	switch ((int)type->info) {
555 	case INT_SIGNED:
556 		fmt = "%ld";
557 		fval = val;
558 		break;
559 	case INT_UNSIGNED:
560 		fmt = "%lu";
561 		fval = (u_int32_t)val;
562 		break;
563 	case INT_HEX:
564 		fmt = "0x%lx";
565 		fval = (u_int32_t)val;
566 		break;
567 	default:
568 		panic("%s: unknown type", __FUNCTION__);
569 	}
570 	NG_PARSE_APPEND(fmt, fval);
571 	*off += sizeof(int32_t);
572 	return (0);
573 }
574 
575 static int
576 ng_int32_getDefault(const struct ng_parse_type *type,
577 	const u_char *const start, u_char *buf, int *buflen)
578 {
579 	int32_t val;
580 
581 	if (*buflen < sizeof(int32_t))
582 		return (ERANGE);
583 	val = 0;
584 	bcopy(&val, buf, sizeof(int32_t));
585 	*buflen = sizeof(int32_t);
586 	return (0);
587 }
588 
589 static int
590 ng_int32_getAlign(const struct ng_parse_type *type)
591 {
592 	return INT32_ALIGNMENT;
593 }
594 
595 const struct ng_parse_type ng_parse_int32_type = {
596 	NULL,
597 	(void *)INT_SIGNED,
598 	NULL,
599 	ng_int32_parse,
600 	ng_int32_unparse,
601 	ng_int32_getDefault,
602 	ng_int32_getAlign
603 };
604 
605 const struct ng_parse_type ng_parse_uint32_type = {
606 	&ng_parse_int32_type,
607 	(void *)INT_UNSIGNED
608 };
609 
610 const struct ng_parse_type ng_parse_hint32_type = {
611 	&ng_parse_int32_type,
612 	(void *)INT_HEX
613 };
614 
615 /************************************************************************
616 				INT64 TYPE
617  ************************************************************************/
618 
619 static int
620 ng_int64_parse(const struct ng_parse_type *type,
621 	const char *s, int *off, const u_char *const start,
622 	u_char *const buf, int *buflen)
623 {
624 	quad_t val;
625 	int64_t val64;
626 	char *eptr;
627 
628 	val = strtoq(s + *off, &eptr, 0);
629 	if (eptr == s + *off)
630 		return (EINVAL);
631 	*off = eptr - s;
632 	val64 = (int64_t)val;
633 	bcopy(&val64, buf, sizeof(int64_t));
634 	*buflen = sizeof(int64_t);
635 	return (0);
636 }
637 
638 static int
639 ng_int64_unparse(const struct ng_parse_type *type,
640 	const u_char *data, int *off, char *cbuf, int cbuflen)
641 {
642 	const char *fmt;
643 	long long fval;
644 	int64_t val;
645 
646 	bcopy(data + *off, &val, sizeof(int64_t));
647 	switch ((int)type->info) {
648 	case INT_SIGNED:
649 		fmt = "%lld";
650 		fval = val;
651 		break;
652 	case INT_UNSIGNED:
653 		fmt = "%llu";
654 		fval = (u_int64_t)val;
655 		break;
656 	case INT_HEX:
657 		fmt = "0x%llx";
658 		fval = (u_int64_t)val;
659 		break;
660 	default:
661 		panic("%s: unknown type", __FUNCTION__);
662 	}
663 	NG_PARSE_APPEND(fmt, fval);
664 	*off += sizeof(int64_t);
665 	return (0);
666 }
667 
668 static int
669 ng_int64_getDefault(const struct ng_parse_type *type,
670 	const u_char *const start, u_char *buf, int *buflen)
671 {
672 	int64_t val;
673 
674 	if (*buflen < sizeof(int64_t))
675 		return (ERANGE);
676 	val = 0;
677 	bcopy(&val, buf, sizeof(int64_t));
678 	*buflen = sizeof(int64_t);
679 	return (0);
680 }
681 
682 static int
683 ng_int64_getAlign(const struct ng_parse_type *type)
684 {
685 	return INT64_ALIGNMENT;
686 }
687 
688 const struct ng_parse_type ng_parse_int64_type = {
689 	NULL,
690 	(void *)INT_SIGNED,
691 	NULL,
692 	ng_int64_parse,
693 	ng_int64_unparse,
694 	ng_int64_getDefault,
695 	ng_int64_getAlign
696 };
697 
698 const struct ng_parse_type ng_parse_uint64_type = {
699 	&ng_parse_int64_type,
700 	(void *)INT_UNSIGNED
701 };
702 
703 const struct ng_parse_type ng_parse_hint64_type = {
704 	&ng_parse_int64_type,
705 	(void *)INT_HEX
706 };
707 
708 /************************************************************************
709 				STRING TYPE
710  ************************************************************************/
711 
712 static int
713 ng_string_parse(const struct ng_parse_type *type,
714 	const char *s, int *off, const u_char *const start,
715 	u_char *const buf, int *buflen)
716 {
717 	char *sval;
718 	int len;
719 	int slen;
720 
721 	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
722 		return (EINVAL);
723 	*off += len;
724 	bcopy(sval, buf, slen + 1);
725 	FREE(sval, M_NETGRAPH_PARSE);
726 	*buflen = slen + 1;
727 	return (0);
728 }
729 
730 static int
731 ng_string_unparse(const struct ng_parse_type *type,
732 	const u_char *data, int *off, char *cbuf, int cbuflen)
733 {
734 	const char *const raw = (const char *)data + *off;
735 	char *const s = ng_encode_string(raw, strlen(raw));
736 
737 	if (s == NULL)
738 		return (ENOMEM);
739 	NG_PARSE_APPEND("%s", s);
740 	*off += strlen(raw) + 1;
741 	FREE(s, M_NETGRAPH_PARSE);
742 	return (0);
743 }
744 
745 static int
746 ng_string_getDefault(const struct ng_parse_type *type,
747 	const u_char *const start, u_char *buf, int *buflen)
748 {
749 
750 	if (*buflen < 1)
751 		return (ERANGE);
752 	buf[0] = (u_char)'\0';
753 	*buflen = 1;
754 	return (0);
755 }
756 
757 const struct ng_parse_type ng_parse_string_type = {
758 	NULL,
759 	NULL,
760 	NULL,
761 	ng_string_parse,
762 	ng_string_unparse,
763 	ng_string_getDefault,
764 	NULL
765 };
766 
767 /************************************************************************
768 			FIXED BUFFER STRING TYPE
769  ************************************************************************/
770 
771 static int
772 ng_fixedstring_parse(const struct ng_parse_type *type,
773 	const char *s, int *off, const u_char *const start,
774 	u_char *const buf, int *buflen)
775 {
776 	const struct ng_parse_fixedstring_info *const fi = type->info;
777 	char *sval;
778 	int len;
779 	int slen;
780 
781 	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
782 		return (EINVAL);
783 	if (slen + 1 > fi->bufSize)
784 		return (E2BIG);
785 	*off += len;
786 	bcopy(sval, buf, slen);
787 	FREE(sval, M_NETGRAPH_PARSE);
788 	bzero(buf + slen, fi->bufSize - slen);
789 	*buflen = fi->bufSize;
790 	return (0);
791 }
792 
793 static int
794 ng_fixedstring_unparse(const struct ng_parse_type *type,
795 	const u_char *data, int *off, char *cbuf, int cbuflen)
796 {
797 	const struct ng_parse_fixedstring_info *const fi = type->info;
798 	int error, temp = *off;
799 
800 	if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
801 		return (error);
802 	*off += fi->bufSize;
803 	return (0);
804 }
805 
806 static int
807 ng_fixedstring_getDefault(const struct ng_parse_type *type,
808 	const u_char *const start, u_char *buf, int *buflen)
809 {
810 	const struct ng_parse_fixedstring_info *const fi = type->info;
811 
812 	if (*buflen < fi->bufSize)
813 		return (ERANGE);
814 	bzero(buf, fi->bufSize);
815 	*buflen = fi->bufSize;
816 	return (0);
817 }
818 
819 const struct ng_parse_type ng_parse_fixedstring_type = {
820 	NULL,
821 	NULL,
822 	NULL,
823 	ng_fixedstring_parse,
824 	ng_fixedstring_unparse,
825 	ng_fixedstring_getDefault,
826 	NULL
827 };
828 
829 const struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
830 	NG_NODELEN + 1
831 };
832 const struct ng_parse_type ng_parse_nodebuf_type = {
833 	&ng_parse_fixedstring_type,
834 	&ng_parse_nodebuf_info
835 };
836 
837 const struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
838 	NG_HOOKLEN + 1
839 };
840 const struct ng_parse_type ng_parse_hookbuf_type = {
841 	&ng_parse_fixedstring_type,
842 	&ng_parse_hookbuf_info
843 };
844 
845 const struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
846 	NG_PATHLEN + 1
847 };
848 const struct ng_parse_type ng_parse_pathbuf_type = {
849 	&ng_parse_fixedstring_type,
850 	&ng_parse_pathbuf_info
851 };
852 
853 const struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
854 	NG_TYPELEN + 1
855 };
856 const struct ng_parse_type ng_parse_typebuf_type = {
857 	&ng_parse_fixedstring_type,
858 	&ng_parse_typebuf_info
859 };
860 
861 const struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
862 	NG_CMDSTRLEN + 1
863 };
864 const struct ng_parse_type ng_parse_cmdbuf_type = {
865 	&ng_parse_fixedstring_type,
866 	&ng_parse_cmdbuf_info
867 };
868 
869 /************************************************************************
870 			EXPLICITLY SIZED STRING TYPE
871  ************************************************************************/
872 
873 static int
874 ng_sizedstring_parse(const struct ng_parse_type *type,
875 	const char *s, int *off, const u_char *const start,
876 	u_char *const buf, int *buflen)
877 {
878 	char *sval;
879 	int len;
880 	int slen;
881 
882 	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
883 		return (EINVAL);
884 	if (slen > 0xffff)
885 		return (EINVAL);
886 	*off += len;
887 	*((u_int16_t *)buf) = (u_int16_t)slen;
888 	bcopy(sval, buf + 2, slen);
889 	FREE(sval, M_NETGRAPH_PARSE);
890 	*buflen = 2 + slen;
891 	return (0);
892 }
893 
894 static int
895 ng_sizedstring_unparse(const struct ng_parse_type *type,
896 	const u_char *data, int *off, char *cbuf, int cbuflen)
897 {
898 	const char *const raw = (const char *)data + *off + 2;
899 	const int slen = *((const u_int16_t *)(data + *off));
900 	char *const s = ng_encode_string(raw, slen);
901 
902 	if (s == NULL)
903 		return (ENOMEM);
904 	NG_PARSE_APPEND("%s", s);
905 	FREE(s, M_NETGRAPH_PARSE);
906 	*off += slen + 2;
907 	return (0);
908 }
909 
910 static int
911 ng_sizedstring_getDefault(const struct ng_parse_type *type,
912 	const u_char *const start, u_char *buf, int *buflen)
913 {
914 	if (*buflen < 2)
915 		return (ERANGE);
916 	bzero(buf, 2);
917 	*buflen = 2;
918 	return (0);
919 }
920 
921 const struct ng_parse_type ng_parse_sizedstring_type = {
922 	NULL,
923 	NULL,
924 	NULL,
925 	ng_sizedstring_parse,
926 	ng_sizedstring_unparse,
927 	ng_sizedstring_getDefault,
928 	NULL
929 };
930 
931 /************************************************************************
932 			IP ADDRESS TYPE
933  ************************************************************************/
934 
935 static int
936 ng_ipaddr_parse(const struct ng_parse_type *type,
937 	const char *s, int *off, const u_char *const start,
938 	u_char *const buf, int *buflen)
939 {
940 	int i, error;
941 
942 	for (i = 0; i < 4; i++) {
943 		if ((error = ng_int8_parse(&ng_parse_int8_type,
944 		    s, off, start, buf + i, buflen)) != 0)
945 			return (error);
946 		if (i < 3 && s[*off] != '.')
947 			return (EINVAL);
948 		(*off)++;
949 	}
950 	*buflen = 4;
951 	return (0);
952 }
953 
954 static int
955 ng_ipaddr_unparse(const struct ng_parse_type *type,
956 	const u_char *data, int *off, char *cbuf, int cbuflen)
957 {
958 	struct in_addr ip;
959 
960 	bcopy(data + *off, &ip, sizeof(ip));
961 	NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0],
962 	    ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]);
963 	*off += sizeof(ip);
964 	return (0);
965 }
966 
967 static int
968 ng_ipaddr_getDefault(const struct ng_parse_type *type,
969 	const u_char *const start, u_char *buf, int *buflen)
970 {
971 	struct in_addr ip = { 0 };
972 
973 	if (*buflen < sizeof(ip))
974 		return (ERANGE);
975 	bcopy(&ip, buf, sizeof(ip));
976 	*buflen = sizeof(ip);
977 	return (0);
978 }
979 
980 const struct ng_parse_type ng_parse_ipaddr_type = {
981 	NULL,
982 	NULL,
983 	NULL,
984 	ng_ipaddr_parse,
985 	ng_ipaddr_unparse,
986 	ng_ipaddr_getDefault,
987 	ng_int32_getAlign
988 };
989 
990 /************************************************************************
991 			BYTE ARRAY TYPE
992  ************************************************************************/
993 
994 /* Get the length of a byte array */
995 static int
996 ng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
997 	const u_char *start, const u_char *buf)
998 {
999 	ng_parse_array_getLength_t *const getLength = type->private;
1000 
1001 	return (*getLength)(type, start, buf);
1002 }
1003 
1004 /* Byte array element type is hex int8 */
1005 static const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
1006 	&ng_parse_hint8_type,
1007 	&ng_parse_bytearray_subtype_getLength,
1008 	NULL
1009 };
1010 static const struct ng_parse_type ng_parse_bytearray_subtype = {
1011 	&ng_parse_array_type,
1012 	&ng_parse_bytearray_subtype_info
1013 };
1014 
1015 static int
1016 ng_bytearray_parse(const struct ng_parse_type *type,
1017 	const char *s, int *off, const u_char *const start,
1018 	u_char *const buf, int *buflen)
1019 {
1020 	char *str;
1021 	int toklen;
1022 	int slen;
1023 
1024 	/* We accept either an array of bytes or a string constant */
1025 	if ((str = ng_get_string_token(s, off, &toklen, &slen)) != NULL) {
1026 		ng_parse_array_getLength_t *const getLength = type->info;
1027 		int arraylen;
1028 
1029 		arraylen = (*getLength)(type, start, buf);
1030 		if (arraylen > *buflen) {
1031 			FREE(str, M_NETGRAPH_PARSE);
1032 			return (ERANGE);
1033 		}
1034 		if (slen > arraylen) {
1035 			FREE(str, M_NETGRAPH_PARSE);
1036 			return (E2BIG);
1037 		}
1038 		bcopy(str, buf, slen);
1039 		bzero(buf + slen, arraylen - slen);
1040 		FREE(str, M_NETGRAPH_PARSE);
1041 		*off += toklen;
1042 		*buflen = arraylen;
1043 		return (0);
1044 	} else {
1045 		struct ng_parse_type subtype;
1046 
1047 		subtype = ng_parse_bytearray_subtype;
1048 		(const void *)subtype.private = type->info;
1049 		return ng_array_parse(&subtype, s, off, start, buf, buflen);
1050 	}
1051 }
1052 
1053 static int
1054 ng_bytearray_unparse(const struct ng_parse_type *type,
1055 	const u_char *data, int *off, char *cbuf, int cbuflen)
1056 {
1057 	struct ng_parse_type subtype;
1058 
1059 	subtype = ng_parse_bytearray_subtype;
1060 	(const void *)subtype.private = type->info;
1061 	return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
1062 }
1063 
1064 static int
1065 ng_bytearray_getDefault(const struct ng_parse_type *type,
1066 	const u_char *const start, u_char *buf, int *buflen)
1067 {
1068 	struct ng_parse_type subtype;
1069 
1070 	subtype = ng_parse_bytearray_subtype;
1071 	(const void *)subtype.private = type->info;
1072 	return ng_array_getDefault(&subtype, start, buf, buflen);
1073 }
1074 
1075 const struct ng_parse_type ng_parse_bytearray_type = {
1076 	NULL,
1077 	NULL,
1078 	NULL,
1079 	ng_bytearray_parse,
1080 	ng_bytearray_unparse,
1081 	ng_bytearray_getDefault,
1082 	NULL
1083 };
1084 
1085 /************************************************************************
1086 			STRUCT NG_MESG TYPE
1087  ************************************************************************/
1088 
1089 /* Get msg->header.arglen when "buf" is pointing to msg->data */
1090 static int
1091 ng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
1092 	const u_char *start, const u_char *buf)
1093 {
1094 	const struct ng_mesg *msg;
1095 
1096 	msg = (const struct ng_mesg *)(buf - sizeof(*msg));
1097 	return msg->header.arglen;
1098 }
1099 
1100 /* Type for the variable length data portion of a struct ng_mesg */
1101 static const struct ng_parse_type ng_msg_data_type = {
1102 	&ng_parse_bytearray_type,
1103 	&ng_parse_ng_mesg_getLength
1104 };
1105 
1106 /* Type for the entire struct ng_mesg header with data section */
1107 static const struct ng_parse_struct_info
1108 	ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
1109 const struct ng_parse_type ng_parse_ng_mesg_type = {
1110 	&ng_parse_struct_type,
1111 	&ng_parse_ng_mesg_type_info,
1112 };
1113 
1114 /************************************************************************
1115 			COMPOSITE HELPER ROUTINES
1116  ************************************************************************/
1117 
1118 /*
1119  * Convert a structure or array from ASCII to binary
1120  */
1121 static int
1122 ng_parse_composite(const struct ng_parse_type *type, const char *s,
1123 	int *off, const u_char *const start, u_char *const buf, int *buflen,
1124 	const enum comptype ctype)
1125 {
1126 	const int num = ng_get_composite_len(type, start, buf, ctype);
1127 	int nextIndex = 0;		/* next implicit array index */
1128 	u_int index;			/* field or element index */
1129 	int *foff;			/* field value offsets in string */
1130 	int align, len, blen, error = 0;
1131 
1132 	/* Initialize */
1133 	MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO);
1134 	if (foff == NULL) {
1135 		error = ENOMEM;
1136 		goto done;
1137 	}
1138 
1139 	/* Get opening brace/bracket */
1140 	if (ng_parse_get_token(s, off, &len)
1141 	    != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
1142 		error = EINVAL;
1143 		goto done;
1144 	}
1145 	*off += len;
1146 
1147 	/* Get individual element value positions in the string */
1148 	for (;;) {
1149 		enum ng_parse_token tok;
1150 
1151 		/* Check for closing brace/bracket */
1152 		tok = ng_parse_get_token(s, off, &len);
1153 		if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
1154 			*off += len;
1155 			break;
1156 		}
1157 
1158 		/* For arrays, the 'name' (ie, index) is optional, so
1159 		   distinguish name from values by seeing if the next
1160 		   token is an equals sign */
1161 		if (ctype != CT_STRUCT) {
1162 			int len2, off2;
1163 			char *eptr;
1164 
1165 			/* If an opening brace/bracket, index is implied */
1166 			if (tok == T_LBRACE || tok == T_LBRACKET) {
1167 				index = nextIndex++;
1168 				goto gotIndex;
1169 			}
1170 
1171 			/* Might be an index, might be a value, either way... */
1172 			if (tok != T_WORD) {
1173 				error = EINVAL;
1174 				goto done;
1175 			}
1176 
1177 			/* If no equals sign follows, index is implied */
1178 			off2 = *off + len;
1179 			if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
1180 				index = nextIndex++;
1181 				goto gotIndex;
1182 			}
1183 
1184 			/* Index was specified explicitly; parse it */
1185 			index = (u_int)strtoul(s + *off, &eptr, 0);
1186 			if (index < 0 || eptr - (s + *off) != len) {
1187 				error = EINVAL;
1188 				goto done;
1189 			}
1190 			nextIndex = index + 1;
1191 			*off += len + len2;
1192 gotIndex:
1193 		} else {			/* a structure field */
1194 			const struct ng_parse_struct_field *field = NULL;
1195 			const struct ng_parse_struct_info *si = type->info;
1196 
1197 			/* Find the field by name (required) in field list */
1198 			if (tok != T_WORD) {
1199 				error = EINVAL;
1200 				goto done;
1201 			}
1202 			for (index = 0; index < num; index++) {
1203 				field = &si->fields[index];
1204 				if (strncmp(&s[*off], field->name, len) == 0
1205 				    && field->name[len] == '\0')
1206 					break;
1207 			}
1208 			if (index == num) {
1209 				error = ENOENT;
1210 				goto done;
1211 			}
1212 			*off += len;
1213 
1214 			/* Get equals sign */
1215 			if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
1216 				error = EINVAL;
1217 				goto done;
1218 			}
1219 			*off += len;
1220 		}
1221 
1222 		/* Check array index */
1223 		if (index >= num) {
1224 			error = E2BIG;
1225 			goto done;
1226 		}
1227 
1228 		/* Save value's position and skip over it for now */
1229 		if (foff[index] != 0) {
1230 			error = EALREADY;		/* duplicate */
1231 			goto done;
1232 		}
1233 		while (isspace(s[*off]))
1234 			(*off)++;
1235 		foff[index] = *off;
1236 		if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
1237 			goto done;
1238 		*off += len;
1239 	}
1240 
1241 	/* Now build binary structure from supplied values and defaults */
1242 	for (blen = index = 0; index < num; index++) {
1243 		const struct ng_parse_type *const
1244 		    etype = ng_get_composite_etype(type, index, ctype);
1245 		int k, pad, vlen;
1246 
1247 		/* Zero-pad any alignment bytes */
1248 		pad = ng_parse_get_elem_pad(type, index, ctype, blen);
1249 		for (k = 0; k < pad; k++) {
1250 			if (blen >= *buflen) {
1251 				error = ERANGE;
1252 				goto done;
1253 			}
1254 			buf[blen++] = 0;
1255 		}
1256 
1257 		/* Get value */
1258 		vlen = *buflen - blen;
1259 		if (foff[index] == 0) {		/* use default value */
1260 			error = ng_get_composite_elem_default(type, index,
1261 			    start, buf + blen, &vlen, ctype);
1262 		} else {			/* parse given value */
1263 			*off = foff[index];
1264 			error = INVOKE(etype, parse)(etype,
1265 			    s, off, start, buf + blen, &vlen);
1266 		}
1267 		if (error != 0)
1268 			goto done;
1269 		blen += vlen;
1270 	}
1271 
1272 	/* Make total composite structure size a multiple of its alignment */
1273 	if ((align = ALIGNMENT(type)) != 0) {
1274 		while (blen % align != 0) {
1275 			if (blen >= *buflen) {
1276 				error = ERANGE;
1277 				goto done;
1278 			}
1279 			buf[blen++] = 0;
1280 		}
1281 	}
1282 
1283 	/* Done */
1284 	*buflen = blen;
1285 done:
1286 	if (foff != NULL)
1287 		FREE(foff, M_NETGRAPH_PARSE);
1288 	return (error);
1289 }
1290 
1291 /*
1292  * Convert an array or structure from binary to ASCII
1293  */
1294 static int
1295 ng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
1296 	int *off, char *cbuf, int cbuflen, const enum comptype ctype)
1297 {
1298 	const int num = ng_get_composite_len(type, data, data + *off, ctype);
1299 	const int workSize = 20 * 1024;		/* XXX hard coded constant */
1300 	int nextIndex = 0, didOne = 0;
1301 	int error, index;
1302 	u_char *workBuf;
1303 
1304 	/* Get workspace for checking default values */
1305 	MALLOC(workBuf, u_char *, workSize, M_NETGRAPH_PARSE, M_NOWAIT);
1306 	if (workBuf == NULL)
1307 		return (ENOMEM);
1308 
1309 	/* Opening brace/bracket */
1310 	NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
1311 
1312 	/* Do each item */
1313 	for (index = 0; index < num; index++) {
1314 		const struct ng_parse_type *const
1315 		    etype = ng_get_composite_etype(type, index, ctype);
1316 
1317 		/* Skip any alignment pad bytes */
1318 		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
1319 
1320 		/* See if element is equal to its default value; skip if so */
1321 		if (*off < workSize) {
1322 			int tempsize = workSize - *off;
1323 
1324 			bcopy(data, workBuf, *off);
1325 			if (ng_get_composite_elem_default(type, index, workBuf,
1326 			      workBuf + *off, &tempsize, ctype) == 0
1327 			    && bcmp(workBuf + *off,
1328 			      data + *off, tempsize) == 0) {
1329 				*off += tempsize;
1330 				continue;
1331 			}
1332 		}
1333 
1334 		/* Print name= */
1335 		NG_PARSE_APPEND(" ");
1336 		if (ctype != CT_STRUCT) {
1337 			if (index != nextIndex) {
1338 				nextIndex = index;
1339 				NG_PARSE_APPEND("%d=", index);
1340 			}
1341 			nextIndex++;
1342 		} else {
1343 			const struct ng_parse_struct_info *si = type->info;
1344 
1345 			NG_PARSE_APPEND("%s=", si->fields[index].name);
1346 		}
1347 
1348 		/* Print value */
1349 		if ((error = INVOKE(etype, unparse)
1350 		    (etype, data, off, cbuf, cbuflen)) != 0) {
1351 			FREE(workBuf, M_NETGRAPH_PARSE);
1352 			return (error);
1353 		}
1354 		cbuflen -= strlen(cbuf);
1355 		cbuf += strlen(cbuf);
1356 		didOne = 1;
1357 	}
1358 	FREE(workBuf, M_NETGRAPH_PARSE);
1359 
1360 	/* Closing brace/bracket */
1361 	NG_PARSE_APPEND("%s%c",
1362 	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
1363 	return (0);
1364 }
1365 
1366 /*
1367  * Generate the default value for an element of an array or structure
1368  * Returns EOPNOTSUPP if default value is unspecified.
1369  */
1370 static int
1371 ng_get_composite_elem_default(const struct ng_parse_type *type,
1372 	int index, const u_char *const start, u_char *buf, int *buflen,
1373 	const enum comptype ctype)
1374 {
1375 	const struct ng_parse_type *etype;
1376 	ng_getDefault_t *func;
1377 
1378 	switch (ctype) {
1379 	case CT_STRUCT:
1380 		break;
1381 	case CT_ARRAY:
1382 	    {
1383 		const struct ng_parse_array_info *const ai = type->info;
1384 
1385 		if (ai->getDefault != NULL) {
1386 			return (*ai->getDefault)(type,
1387 			    index, start, buf, buflen);
1388 		}
1389 		break;
1390 	    }
1391 	case CT_FIXEDARRAY:
1392 	    {
1393 		const struct ng_parse_fixedarray_info *const fi = type->info;
1394 
1395 		if (*fi->getDefault != NULL) {
1396 			return (*fi->getDefault)(type,
1397 			    index, start, buf, buflen);
1398 		}
1399 		break;
1400 	    }
1401 	default:
1402 	    panic("%s", __FUNCTION__);
1403 	}
1404 
1405 	/* Default to element type default */
1406 	etype = ng_get_composite_etype(type, index, ctype);
1407 	func = METHOD(etype, getDefault);
1408 	if (func == NULL)
1409 		return (EOPNOTSUPP);
1410 	return (*func)(etype, start, buf, buflen);
1411 }
1412 
1413 /*
1414  * Get the number of elements in a struct, variable or fixed array.
1415  */
1416 static int
1417 ng_get_composite_len(const struct ng_parse_type *type,
1418 	const u_char *const start, const u_char *buf,
1419 	const enum comptype ctype)
1420 {
1421 	switch (ctype) {
1422 	case CT_STRUCT:
1423 	    {
1424 		const struct ng_parse_struct_info *const si = type->info;
1425 		int numFields = 0;
1426 
1427 		for (numFields = 0; ; numFields++) {
1428 			const struct ng_parse_struct_field *const
1429 				fi = &si->fields[numFields];
1430 
1431 			if (fi->name == NULL)
1432 				break;
1433 		}
1434 		return (numFields);
1435 	    }
1436 	case CT_ARRAY:
1437 	    {
1438 		const struct ng_parse_array_info *const ai = type->info;
1439 
1440 		return (*ai->getLength)(type, start, buf);
1441 	    }
1442 	case CT_FIXEDARRAY:
1443 	    {
1444 		const struct ng_parse_fixedarray_info *const fi = type->info;
1445 
1446 		return fi->length;
1447 	    }
1448 	default:
1449 	    panic("%s", __FUNCTION__);
1450 	}
1451 	return (0);
1452 }
1453 
1454 /*
1455  * Return the type of the index'th element of a composite structure
1456  */
1457 static const struct ng_parse_type *
1458 ng_get_composite_etype(const struct ng_parse_type *type,
1459 	int index, const enum comptype ctype)
1460 {
1461 	const struct ng_parse_type *etype = NULL;
1462 
1463 	switch (ctype) {
1464 	case CT_STRUCT:
1465 	    {
1466 		const struct ng_parse_struct_info *const si = type->info;
1467 
1468 		etype = si->fields[index].type;
1469 		break;
1470 	    }
1471 	case CT_ARRAY:
1472 	    {
1473 		const struct ng_parse_array_info *const ai = type->info;
1474 
1475 		etype = ai->elementType;
1476 		break;
1477 	    }
1478 	case CT_FIXEDARRAY:
1479 	    {
1480 		const struct ng_parse_fixedarray_info *const fi = type->info;
1481 
1482 		etype = fi->elementType;
1483 		break;
1484 	    }
1485 	default:
1486 	    panic("%s", __FUNCTION__);
1487 	}
1488 	return (etype);
1489 }
1490 
1491 /*
1492  * Get the number of bytes to skip to align for the next
1493  * element in a composite structure.
1494  */
1495 static int
1496 ng_parse_get_elem_pad(const struct ng_parse_type *type,
1497 	int index, enum comptype ctype, int posn)
1498 {
1499 	const struct ng_parse_type *const
1500 	    etype = ng_get_composite_etype(type, index, ctype);
1501 	int align;
1502 
1503 	/* Get element's alignment, and possibly override */
1504 	align = ALIGNMENT(etype);
1505 	if (ctype == CT_STRUCT) {
1506 		const struct ng_parse_struct_info *si = type->info;
1507 
1508 		if (si->fields[index].alignment != 0)
1509 			align = si->fields[index].alignment;
1510 	}
1511 
1512 	/* Return number of bytes to skip to align */
1513 	return (align ? (align - (posn % align)) % align : 0);
1514 }
1515 
1516 /************************************************************************
1517 			PARSING HELPER ROUTINES
1518  ************************************************************************/
1519 
1520 /*
1521  * Skip over a value
1522  */
1523 static int
1524 ng_parse_skip_value(const char *s, int off0, int *lenp)
1525 {
1526 	int len, nbracket, nbrace;
1527 	int off = off0;
1528 
1529 	len = nbracket = nbrace = 0;
1530 	do {
1531 		switch (ng_parse_get_token(s, &off, &len)) {
1532 		case T_LBRACKET:
1533 			nbracket++;
1534 			break;
1535 		case T_LBRACE:
1536 			nbrace++;
1537 			break;
1538 		case T_RBRACKET:
1539 			if (nbracket-- == 0)
1540 				return (EINVAL);
1541 			break;
1542 		case T_RBRACE:
1543 			if (nbrace-- == 0)
1544 				return (EINVAL);
1545 			break;
1546 		case T_EOF:
1547 			return (EINVAL);
1548 		default:
1549 			break;
1550 		}
1551 		off += len;
1552 	} while (nbracket > 0 || nbrace > 0);
1553 	*lenp = off - off0;
1554 	return (0);
1555 }
1556 
1557 /*
1558  * Find the next token in the string, starting at offset *startp.
1559  * Returns the token type, with *startp pointing to the first char
1560  * and *lenp the length.
1561  */
1562 enum ng_parse_token
1563 ng_parse_get_token(const char *s, int *startp, int *lenp)
1564 {
1565 	char *t;
1566 	int i;
1567 
1568 	while (isspace(s[*startp]))
1569 		(*startp)++;
1570 	switch (s[*startp]) {
1571 	case '\0':
1572 		*lenp = 0;
1573 		return T_EOF;
1574 	case '{':
1575 		*lenp = 1;
1576 		return T_LBRACE;
1577 	case '}':
1578 		*lenp = 1;
1579 		return T_RBRACE;
1580 	case '[':
1581 		*lenp = 1;
1582 		return T_LBRACKET;
1583 	case ']':
1584 		*lenp = 1;
1585 		return T_RBRACKET;
1586 	case '=':
1587 		*lenp = 1;
1588 		return T_EQUALS;
1589 	case '"':
1590 		if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
1591 			return T_ERROR;
1592 		FREE(t, M_NETGRAPH_PARSE);
1593 		return T_STRING;
1594 	default:
1595 		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
1596 		    && s[i] != '{' && s[i] != '}' && s[i] != '['
1597 		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
1598 			;
1599 		*lenp = i - *startp;
1600 		return T_WORD;
1601 	}
1602 }
1603 
1604 /*
1605  * Get a string token, which must be enclosed in double quotes.
1606  * The normal C backslash escapes are recognized.
1607  */
1608 char *
1609 ng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
1610 {
1611 	char *cbuf, *p;
1612 	int start, off;
1613 	int slen;
1614 
1615 	while (isspace(s[*startp]))
1616 		(*startp)++;
1617 	start = *startp;
1618 	if (s[*startp] != '"')
1619 		return (NULL);
1620 	MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
1621 	if (cbuf == NULL)
1622 		return (NULL);
1623 	strcpy(cbuf, s + start + 1);
1624 	for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
1625 		if (*p == '"') {
1626 			*p = '\0';
1627 			*lenp = off + 1;
1628 			if (slenp != NULL)
1629 				*slenp = slen;
1630 			return (cbuf);
1631 		} else if (p[0] == '\\' && p[1] != '\0') {
1632 			int x, k;
1633 			char *v;
1634 
1635 			strcpy(p, p + 1);
1636 			v = p;
1637 			switch (*p) {
1638 			case 't':
1639 				*v = '\t';
1640 				off++;
1641 				continue;
1642 			case 'n':
1643 				*v = '\n';
1644 				off++;
1645 				continue;
1646 			case 'r':
1647 				*v = '\r';
1648 				off++;
1649 				continue;
1650 			case 'v':
1651 				*v =  '\v';
1652 				off++;
1653 				continue;
1654 			case 'f':
1655 				*v =  '\f';
1656 				off++;
1657 				continue;
1658 			case '"':
1659 				*v =  '"';
1660 				off++;
1661 				continue;
1662 			case '0': case '1': case '2': case '3':
1663 			case '4': case '5': case '6': case '7':
1664 				for (x = k = 0;
1665 				    k < 3 && *v >= '0' && *v <= '7'; v++) {
1666 					x = (x << 3) + (*v - '0');
1667 					off++;
1668 				}
1669 				*--v = (char)x;
1670 				break;
1671 			case 'x':
1672 				for (v++, x = k = 0;
1673 				    k < 2 && isxdigit(*v); v++) {
1674 					x = (x << 4) + (isdigit(*v) ?
1675 					      (*v - '0') :
1676 					      (tolower(*v) - 'a' + 10));
1677 					off++;
1678 				}
1679 				*--v = (char)x;
1680 				break;
1681 			default:
1682 				continue;
1683 			}
1684 			strcpy(p, v);
1685 		}
1686 	}
1687 	return (NULL);		/* no closing quote */
1688 }
1689 
1690 /*
1691  * Encode a string so it can be safely put in double quotes.
1692  * Caller must free the result. Exactly "slen" characters
1693  * are encoded.
1694  */
1695 char *
1696 ng_encode_string(const char *raw, int slen)
1697 {
1698 	char *cbuf;
1699 	int off = 0;
1700 	int i;
1701 
1702 	MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
1703 	if (cbuf == NULL)
1704 		return (NULL);
1705 	cbuf[off++] = '"';
1706 	for (i = 0; i < slen; i++, raw++) {
1707 		switch (*raw) {
1708 		case '\t':
1709 			cbuf[off++] = '\\';
1710 			cbuf[off++] = 't';
1711 			break;
1712 		case '\f':
1713 			cbuf[off++] = '\\';
1714 			cbuf[off++] = 'f';
1715 			break;
1716 		case '\n':
1717 			cbuf[off++] = '\\';
1718 			cbuf[off++] = 'n';
1719 			break;
1720 		case '\r':
1721 			cbuf[off++] = '\\';
1722 			cbuf[off++] = 'r';
1723 			break;
1724 		case '\v':
1725 			cbuf[off++] = '\\';
1726 			cbuf[off++] = 'v';
1727 			break;
1728 		case '"':
1729 		case '\\':
1730 			cbuf[off++] = '\\';
1731 			cbuf[off++] = *raw;
1732 			break;
1733 		default:
1734 			if (*raw < 0x20 || *raw > 0x7e) {
1735 				off += sprintf(cbuf + off,
1736 				    "\\x%02x", (u_char)*raw);
1737 				break;
1738 			}
1739 			cbuf[off++] = *raw;
1740 			break;
1741 		}
1742 	}
1743 	cbuf[off++] = '"';
1744 	cbuf[off] = '\0';
1745 	return (cbuf);
1746 }
1747 
1748 /************************************************************************
1749 			VIRTUAL METHOD LOOKUP
1750  ************************************************************************/
1751 
1752 static ng_parse_t *
1753 ng_get_parse_method(const struct ng_parse_type *t)
1754 {
1755 	while (t != NULL && t->parse == NULL)
1756 		t = t->supertype;
1757 	return (t ? t->parse : NULL);
1758 }
1759 
1760 static ng_unparse_t *
1761 ng_get_unparse_method(const struct ng_parse_type *t)
1762 {
1763 	while (t != NULL && t->unparse == NULL)
1764 		t = t->supertype;
1765 	return (t ? t->unparse : NULL);
1766 }
1767 
1768 static ng_getDefault_t *
1769 ng_get_getDefault_method(const struct ng_parse_type *t)
1770 {
1771 	while (t != NULL && t->getDefault == NULL)
1772 		t = t->supertype;
1773 	return (t ? t->getDefault : NULL);
1774 }
1775 
1776 static ng_getAlign_t *
1777 ng_get_getAlign_method(const struct ng_parse_type *t)
1778 {
1779 	while (t != NULL && t->getAlign == NULL)
1780 		t = t->supertype;
1781 	return (t ? t->getAlign : NULL);
1782 }
1783 
1784