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