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