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