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