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