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