ng_parse.c revision 90047
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 90047 2002-02-01 02:21:41Z archie $
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", __func__);
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", __func__);
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", __func__);
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", __func__);
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 struct ng_mesg *const hdr
1311	    = (const struct ng_mesg *)(data - sizeof(*hdr));
1312	const int num = ng_get_composite_len(type, data, data + *off, ctype);
1313	const int workSize = 20 * 1024;		/* XXX hard coded constant */
1314	int nextIndex = 0, didOne = 0;
1315	int error, index;
1316	u_char *workBuf;
1317
1318	/* Get workspace for checking default values */
1319	MALLOC(workBuf, u_char *, workSize, M_NETGRAPH_PARSE, M_NOWAIT);
1320	if (workBuf == NULL)
1321		return (ENOMEM);
1322
1323	/* Opening brace/bracket */
1324	NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
1325
1326	/* Do each item */
1327	for (index = 0; index < num; index++) {
1328		const struct ng_parse_type *const
1329		    etype = ng_get_composite_etype(type, index, ctype);
1330
1331		/* Skip any alignment pad bytes */
1332		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
1333
1334		/*
1335		 * See if element is equal to its default value; skip if so.
1336		 * Copy struct ng_mesg header for types that peek into it.
1337		 */
1338		if (sizeof(*hdr) + *off < workSize) {
1339			int tempsize = workSize - sizeof(*hdr) - *off;
1340
1341			bcopy(hdr, workBuf, sizeof(*hdr));
1342			bcopy(data + sizeof(*hdr), workBuf, *off);
1343			if (ng_get_composite_elem_default(type, index, workBuf
1344			      + sizeof(*hdr), workBuf + sizeof(*hdr) + *off,
1345			      &tempsize, ctype) == 0
1346			    && bcmp(workBuf + sizeof(*hdr) + *off,
1347			      data + *off, tempsize) == 0) {
1348				*off += tempsize;
1349				continue;
1350			}
1351		}
1352
1353		/* Print name= */
1354		NG_PARSE_APPEND(" ");
1355		if (ctype != CT_STRUCT) {
1356			if (index != nextIndex) {
1357				nextIndex = index;
1358				NG_PARSE_APPEND("%d=", index);
1359			}
1360			nextIndex++;
1361		} else {
1362			const struct ng_parse_struct_info *si = type->info;
1363
1364			NG_PARSE_APPEND("%s=", si->fields[index].name);
1365		}
1366
1367		/* Print value */
1368		if ((error = INVOKE(etype, unparse)
1369		    (etype, data, off, cbuf, cbuflen)) != 0) {
1370			FREE(workBuf, M_NETGRAPH_PARSE);
1371			return (error);
1372		}
1373		cbuflen -= strlen(cbuf);
1374		cbuf += strlen(cbuf);
1375		didOne = 1;
1376	}
1377	FREE(workBuf, M_NETGRAPH_PARSE);
1378
1379	/* Closing brace/bracket */
1380	NG_PARSE_APPEND("%s%c",
1381	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
1382	return (0);
1383}
1384
1385/*
1386 * Generate the default value for an element of an array or structure
1387 * Returns EOPNOTSUPP if default value is unspecified.
1388 */
1389static int
1390ng_get_composite_elem_default(const struct ng_parse_type *type,
1391	int index, const u_char *const start, u_char *buf, int *buflen,
1392	const enum comptype ctype)
1393{
1394	const struct ng_parse_type *etype;
1395	ng_getDefault_t *func;
1396
1397	switch (ctype) {
1398	case CT_STRUCT:
1399		break;
1400	case CT_ARRAY:
1401	    {
1402		const struct ng_parse_array_info *const ai = type->info;
1403
1404		if (ai->getDefault != NULL) {
1405			return (*ai->getDefault)(type,
1406			    index, start, buf, buflen);
1407		}
1408		break;
1409	    }
1410	case CT_FIXEDARRAY:
1411	    {
1412		const struct ng_parse_fixedarray_info *const fi = type->info;
1413
1414		if (*fi->getDefault != NULL) {
1415			return (*fi->getDefault)(type,
1416			    index, start, buf, buflen);
1417		}
1418		break;
1419	    }
1420	default:
1421	    panic("%s", __func__);
1422	}
1423
1424	/* Default to element type default */
1425	etype = ng_get_composite_etype(type, index, ctype);
1426	func = METHOD(etype, getDefault);
1427	if (func == NULL)
1428		return (EOPNOTSUPP);
1429	return (*func)(etype, start, buf, buflen);
1430}
1431
1432/*
1433 * Get the number of elements in a struct, variable or fixed array.
1434 */
1435static int
1436ng_get_composite_len(const struct ng_parse_type *type,
1437	const u_char *const start, const u_char *buf,
1438	const enum comptype ctype)
1439{
1440	switch (ctype) {
1441	case CT_STRUCT:
1442	    {
1443		const struct ng_parse_struct_info *const si = type->info;
1444		int numFields = 0;
1445
1446		for (numFields = 0; ; numFields++) {
1447			const struct ng_parse_struct_field *const
1448				fi = &si->fields[numFields];
1449
1450			if (fi->name == NULL)
1451				break;
1452		}
1453		return (numFields);
1454	    }
1455	case CT_ARRAY:
1456	    {
1457		const struct ng_parse_array_info *const ai = type->info;
1458
1459		return (*ai->getLength)(type, start, buf);
1460	    }
1461	case CT_FIXEDARRAY:
1462	    {
1463		const struct ng_parse_fixedarray_info *const fi = type->info;
1464
1465		return fi->length;
1466	    }
1467	default:
1468	    panic("%s", __func__);
1469	}
1470	return (0);
1471}
1472
1473/*
1474 * Return the type of the index'th element of a composite structure
1475 */
1476static const struct ng_parse_type *
1477ng_get_composite_etype(const struct ng_parse_type *type,
1478	int index, const enum comptype ctype)
1479{
1480	const struct ng_parse_type *etype = NULL;
1481
1482	switch (ctype) {
1483	case CT_STRUCT:
1484	    {
1485		const struct ng_parse_struct_info *const si = type->info;
1486
1487		etype = si->fields[index].type;
1488		break;
1489	    }
1490	case CT_ARRAY:
1491	    {
1492		const struct ng_parse_array_info *const ai = type->info;
1493
1494		etype = ai->elementType;
1495		break;
1496	    }
1497	case CT_FIXEDARRAY:
1498	    {
1499		const struct ng_parse_fixedarray_info *const fi = type->info;
1500
1501		etype = fi->elementType;
1502		break;
1503	    }
1504	default:
1505	    panic("%s", __func__);
1506	}
1507	return (etype);
1508}
1509
1510/*
1511 * Get the number of bytes to skip to align for the next
1512 * element in a composite structure.
1513 */
1514static int
1515ng_parse_get_elem_pad(const struct ng_parse_type *type,
1516	int index, enum comptype ctype, int posn)
1517{
1518	const struct ng_parse_type *const
1519	    etype = ng_get_composite_etype(type, index, ctype);
1520	int align;
1521
1522	/* Get element's alignment, and possibly override */
1523	align = ALIGNMENT(etype);
1524	if (ctype == CT_STRUCT) {
1525		const struct ng_parse_struct_info *si = type->info;
1526
1527		if (si->fields[index].alignment != 0)
1528			align = si->fields[index].alignment;
1529	}
1530
1531	/* Return number of bytes to skip to align */
1532	return (align ? (align - (posn % align)) % align : 0);
1533}
1534
1535/************************************************************************
1536			PARSING HELPER ROUTINES
1537 ************************************************************************/
1538
1539/*
1540 * Skip over a value
1541 */
1542static int
1543ng_parse_skip_value(const char *s, int off0, int *lenp)
1544{
1545	int len, nbracket, nbrace;
1546	int off = off0;
1547
1548	len = nbracket = nbrace = 0;
1549	do {
1550		switch (ng_parse_get_token(s, &off, &len)) {
1551		case T_LBRACKET:
1552			nbracket++;
1553			break;
1554		case T_LBRACE:
1555			nbrace++;
1556			break;
1557		case T_RBRACKET:
1558			if (nbracket-- == 0)
1559				return (EINVAL);
1560			break;
1561		case T_RBRACE:
1562			if (nbrace-- == 0)
1563				return (EINVAL);
1564			break;
1565		case T_EOF:
1566			return (EINVAL);
1567		default:
1568			break;
1569		}
1570		off += len;
1571	} while (nbracket > 0 || nbrace > 0);
1572	*lenp = off - off0;
1573	return (0);
1574}
1575
1576/*
1577 * Find the next token in the string, starting at offset *startp.
1578 * Returns the token type, with *startp pointing to the first char
1579 * and *lenp the length.
1580 */
1581enum ng_parse_token
1582ng_parse_get_token(const char *s, int *startp, int *lenp)
1583{
1584	char *t;
1585	int i;
1586
1587	while (isspace(s[*startp]))
1588		(*startp)++;
1589	switch (s[*startp]) {
1590	case '\0':
1591		*lenp = 0;
1592		return T_EOF;
1593	case '{':
1594		*lenp = 1;
1595		return T_LBRACE;
1596	case '}':
1597		*lenp = 1;
1598		return T_RBRACE;
1599	case '[':
1600		*lenp = 1;
1601		return T_LBRACKET;
1602	case ']':
1603		*lenp = 1;
1604		return T_RBRACKET;
1605	case '=':
1606		*lenp = 1;
1607		return T_EQUALS;
1608	case '"':
1609		if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
1610			return T_ERROR;
1611		FREE(t, M_NETGRAPH_PARSE);
1612		return T_STRING;
1613	default:
1614		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
1615		    && s[i] != '{' && s[i] != '}' && s[i] != '['
1616		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
1617			;
1618		*lenp = i - *startp;
1619		return T_WORD;
1620	}
1621}
1622
1623/*
1624 * Get a string token, which must be enclosed in double quotes.
1625 * The normal C backslash escapes are recognized.
1626 */
1627char *
1628ng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
1629{
1630	char *cbuf, *p;
1631	int start, off;
1632	int slen;
1633
1634	while (isspace(s[*startp]))
1635		(*startp)++;
1636	start = *startp;
1637	if (s[*startp] != '"')
1638		return (NULL);
1639	MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
1640	if (cbuf == NULL)
1641		return (NULL);
1642	strcpy(cbuf, s + start + 1);
1643	for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
1644		if (*p == '"') {
1645			*p = '\0';
1646			*lenp = off + 1;
1647			if (slenp != NULL)
1648				*slenp = slen;
1649			return (cbuf);
1650		} else if (p[0] == '\\' && p[1] != '\0') {
1651			int x, k;
1652			char *v;
1653
1654			strcpy(p, p + 1);
1655			v = p;
1656			switch (*p) {
1657			case 't':
1658				*v = '\t';
1659				off++;
1660				continue;
1661			case 'n':
1662				*v = '\n';
1663				off++;
1664				continue;
1665			case 'r':
1666				*v = '\r';
1667				off++;
1668				continue;
1669			case 'v':
1670				*v =  '\v';
1671				off++;
1672				continue;
1673			case 'f':
1674				*v =  '\f';
1675				off++;
1676				continue;
1677			case '"':
1678				*v =  '"';
1679				off++;
1680				continue;
1681			case '0': case '1': case '2': case '3':
1682			case '4': case '5': case '6': case '7':
1683				for (x = k = 0;
1684				    k < 3 && *v >= '0' && *v <= '7'; v++) {
1685					x = (x << 3) + (*v - '0');
1686					off++;
1687				}
1688				*--v = (char)x;
1689				break;
1690			case 'x':
1691				for (v++, x = k = 0;
1692				    k < 2 && isxdigit(*v); v++) {
1693					x = (x << 4) + (isdigit(*v) ?
1694					      (*v - '0') :
1695					      (tolower(*v) - 'a' + 10));
1696					off++;
1697				}
1698				*--v = (char)x;
1699				break;
1700			default:
1701				continue;
1702			}
1703			strcpy(p, v);
1704		}
1705	}
1706	return (NULL);		/* no closing quote */
1707}
1708
1709/*
1710 * Encode a string so it can be safely put in double quotes.
1711 * Caller must free the result. Exactly "slen" characters
1712 * are encoded.
1713 */
1714char *
1715ng_encode_string(const char *raw, int slen)
1716{
1717	char *cbuf;
1718	int off = 0;
1719	int i;
1720
1721	MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
1722	if (cbuf == NULL)
1723		return (NULL);
1724	cbuf[off++] = '"';
1725	for (i = 0; i < slen; i++, raw++) {
1726		switch (*raw) {
1727		case '\t':
1728			cbuf[off++] = '\\';
1729			cbuf[off++] = 't';
1730			break;
1731		case '\f':
1732			cbuf[off++] = '\\';
1733			cbuf[off++] = 'f';
1734			break;
1735		case '\n':
1736			cbuf[off++] = '\\';
1737			cbuf[off++] = 'n';
1738			break;
1739		case '\r':
1740			cbuf[off++] = '\\';
1741			cbuf[off++] = 'r';
1742			break;
1743		case '\v':
1744			cbuf[off++] = '\\';
1745			cbuf[off++] = 'v';
1746			break;
1747		case '"':
1748		case '\\':
1749			cbuf[off++] = '\\';
1750			cbuf[off++] = *raw;
1751			break;
1752		default:
1753			if (*raw < 0x20 || *raw > 0x7e) {
1754				off += sprintf(cbuf + off,
1755				    "\\x%02x", (u_char)*raw);
1756				break;
1757			}
1758			cbuf[off++] = *raw;
1759			break;
1760		}
1761	}
1762	cbuf[off++] = '"';
1763	cbuf[off] = '\0';
1764	return (cbuf);
1765}
1766
1767/************************************************************************
1768			VIRTUAL METHOD LOOKUP
1769 ************************************************************************/
1770
1771static ng_parse_t *
1772ng_get_parse_method(const struct ng_parse_type *t)
1773{
1774	while (t != NULL && t->parse == NULL)
1775		t = t->supertype;
1776	return (t ? t->parse : NULL);
1777}
1778
1779static ng_unparse_t *
1780ng_get_unparse_method(const struct ng_parse_type *t)
1781{
1782	while (t != NULL && t->unparse == NULL)
1783		t = t->supertype;
1784	return (t ? t->unparse : NULL);
1785}
1786
1787static ng_getDefault_t *
1788ng_get_getDefault_method(const struct ng_parse_type *t)
1789{
1790	while (t != NULL && t->getDefault == NULL)
1791		t = t->supertype;
1792	return (t ? t->getDefault : NULL);
1793}
1794
1795static ng_getAlign_t *
1796ng_get_getAlign_method(const struct ng_parse_type *t)
1797{
1798	while (t != NULL && t->getAlign == NULL)
1799		t = t->supertype;
1800	return (t ? t->getAlign : NULL);
1801}
1802
1803