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