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