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