ng_parse.c revision 67506
119370Spst
2130803Smarcel/*
398944Sobrien * ng_parse.c
419370Spst *
598944Sobrien * Copyright (c) 1999 Whistle Communications, Inc.
619370Spst * All rights reserved.
798944Sobrien *
898944Sobrien * Subject to the following obligations and disclaimer of warranty, use and
998944Sobrien * redistribution of this software, in source or object code forms, with or
1098944Sobrien * without modifications are expressly permitted by Whistle Communications;
1119370Spst * provided, however, that:
1298944Sobrien * 1. Any and all reproductions of the source or object code must include the
1398944Sobrien *    copyright notice above and the following disclaimer of warranties; and
1498944Sobrien * 2. No rights are granted, in any manner or form, to use Whistle
1598944Sobrien *    Communications, Inc. trademarks, including the mark "WHISTLE
1619370Spst *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1798944Sobrien *    such appears in the above copyright notice or in the software.
1898944Sobrien *
1998944Sobrien * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2098944Sobrien * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2119370Spst * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2219370Spst * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2319370Spst * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2419370Spst * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2519370Spst * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2619370Spst * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2719370Spst * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2819370Spst * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
2919370Spst * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3098944Sobrien * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3119370Spst * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3298944Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3398944Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3498944Sobrien * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3598944Sobrien * OF SUCH DAMAGE.
3698944Sobrien *
3798944Sobrien * Author: Archie Cobbs <archie@freebsd.org>
3898944Sobrien *
3946283Sdfr * $Whistle: ng_parse.c,v 1.3 1999/11/29 01:43:48 archie Exp $
4019370Spst * $FreeBSD: head/sys/netgraph/ng_parse.c 67506 2000-10-24 17:32:45Z julian $
4119370Spst */
4219370Spst
4319370Spst#include <sys/types.h>
4419370Spst#include <sys/param.h>
4519370Spst#include <sys/systm.h>
4619370Spst#include <sys/errno.h>
4719370Spst#include <sys/malloc.h>
48130803Smarcel#include <sys/ctype.h>
4919370Spst
5019370Spst#include <netinet/in.h>
5119370Spst
5219370Spst#include <netgraph/ng_message.h>
5319370Spst#include <netgraph/netgraph.h>
5419370Spst#include <netgraph/ng_parse.h>
5519370Spst
5619370Spst/* Compute alignment for primitive integral types */
5719370Spststruct int16_temp {
5819370Spst	char	x;
5919370Spst	int16_t	y;
6019370Spst};
6119370Spst
6219370Spststruct int32_temp {
6319370Spst	char	x;
6419370Spst	int32_t	y;
6519370Spst};
6619370Spst
6719370Spststruct int64_temp {
6819370Spst	char	x;
6919370Spst	int64_t	y;
7019370Spst};
7119370Spst
7219370Spst#define INT8_ALIGNMENT		1
7319370Spst#define INT16_ALIGNMENT		((int)&((struct int16_temp *)0)->y)
7419370Spst#define INT32_ALIGNMENT		((int)&((struct int32_temp *)0)->y)
7519370Spst#define INT64_ALIGNMENT		((int)&((struct int64_temp *)0)->y)
7619370Spst
7719370Spst/* Output format for integral types */
7819370Spst#define INT_UNSIGNED		0
7919370Spst#define INT_SIGNED		1
8019370Spst#define INT_HEX			2
8119370Spst
8219370Spst/* Type of composite object: struct, array, or fixedarray */
8319370Spstenum comptype {
8419370Spst	CT_STRUCT,
8519370Spst	CT_ARRAY,
8619370Spst	CT_FIXEDARRAY,
8719370Spst};
8819370Spst
8919370Spst/* Composite types helper functions */
9019370Spststatic int	ng_parse_composite(const struct ng_parse_type *type,
9119370Spst			const char *s, int *off, const u_char *start,
9219370Spst			u_char *const buf, int *buflen, enum comptype ctype);
9319370Spststatic int	ng_unparse_composite(const struct ng_parse_type *type,
9419370Spst			const u_char *data, int *off, char *cbuf, int cbuflen,
9519370Spst			enum comptype ctype);
9619370Spststatic int	ng_get_composite_elem_default(const struct ng_parse_type *type,
9798944Sobrien			int index, const u_char *start, u_char *buf,
9819370Spst			int *buflen, enum comptype ctype);
9919370Spststatic int	ng_get_composite_len(const struct ng_parse_type *type,
10046283Sdfr			const u_char *start, const u_char *buf,
10119370Spst			enum comptype ctype);
10219370Spststatic const	struct ng_parse_type *ng_get_composite_etype(const struct
10319370Spst			ng_parse_type *type, int index, enum comptype ctype);
10419370Spststatic int	ng_parse_get_elem_pad(const struct ng_parse_type *type,
10519370Spst			int index, enum comptype ctype, int posn);
10619370Spst
10719370Spst/* Parsing helper functions */
10819370Spststatic int	ng_parse_skip_value(const char *s, int off, int *lenp);
10919370Spst
11019370Spst/* Poor man's virtual method calls */
11119370Spst#define METHOD(t,m)	(ng_get_ ## m ## _method(t))
11298944Sobrien#define INVOKE(t,m)	(*METHOD(t,m))
11398944Sobrien
11419370Spststatic ng_parse_t	*ng_get_parse_method(const struct ng_parse_type *t);
115130803Smarcelstatic ng_unparse_t	*ng_get_unparse_method(const struct ng_parse_type *t);
11619370Spststatic ng_getDefault_t	*ng_get_getDefault_method(const
11719370Spst				struct ng_parse_type *t);
11819370Spststatic ng_getAlign_t	*ng_get_getAlign_method(const struct ng_parse_type *t);
11919370Spst
12019370Spst#define ALIGNMENT(t)	(METHOD(t, getAlign) == NULL ? \
12119370Spst				0 : INVOKE(t, getAlign)(t))
12219370Spst
12319370Spst/* For converting binary to string */
12419370Spst#define NG_PARSE_APPEND(fmt, args...)				\
12519370Spst		do {						\
12619370Spst			int len;				\
12719370Spst								\
12819370Spst			len = snprintf((cbuf), (cbuflen),	\
12998944Sobrien				fmt , ## args);			\
13019370Spst			if (len >= (cbuflen))			\
13119370Spst				return (ERANGE);		\
13219370Spst			(cbuf) += len;				\
13319370Spst			(cbuflen) -= len;			\
13419370Spst		} while (0)
13519370Spst
13619370Spst/************************************************************************
13719370Spst			PUBLIC FUNCTIONS
13819370Spst ************************************************************************/
13919370Spst
14019370Spst/*
14119370Spst * Convert an ASCII string to binary according to the supplied type descriptor
14219370Spst */
14319370Spstint
14419370Spstng_parse(const struct ng_parse_type *type,
14519370Spst	const char *string, int *off, u_char *buf, int *buflen)
14619370Spst{
14719370Spst	return INVOKE(type, parse)(type, string, off, buf, buf, buflen);
14819370Spst}
14919370Spst
15019370Spst/*
15119370Spst * Convert binary to an ASCII string according to the supplied type descriptor
15219370Spst */
15319370Spstint
15419370Spstng_unparse(const struct ng_parse_type *type,
15519370Spst	const u_char *data, char *cbuf, int cbuflen)
15619370Spst{
15719370Spst	int off = 0;
15819370Spst
15919370Spst	return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen);
16019370Spst}
16119370Spst
16219370Spst/*
16319370Spst * Fill in the default value according to the supplied type descriptor
16419370Spst */
16519370Spstint
16619370Spstng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen)
16719370Spst{
16819370Spst	ng_getDefault_t *const func = METHOD(type, getDefault);
16919370Spst
17019370Spst	if (func == NULL)
17119370Spst		return (EOPNOTSUPP);
17219370Spst	return (*func)(type, buf, buf, buflen);
17319370Spst}
17419370Spst
17519370Spst
17646283Sdfr/************************************************************************
17719370Spst			STRUCTURE TYPE
17819370Spst ************************************************************************/
17919370Spst
18019370Spststatic int
18119370Spstng_struct_parse(const struct ng_parse_type *type,
18219370Spst	const char *s, int *off, const u_char *const start,
18319370Spst	u_char *const buf, int *buflen)
18419370Spst{
18519370Spst	return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT);
18619370Spst}
18719370Spst
18819370Spststatic int
18919370Spstng_struct_unparse(const struct ng_parse_type *type,
19019370Spst	const u_char *data, int *off, char *cbuf, int cbuflen)
19119370Spst{
19219370Spst	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT);
19319370Spst}
19419370Spst
19519370Spststatic int
19619370Spstng_struct_getDefault(const struct ng_parse_type *type,
19719370Spst	const u_char *const start, u_char *buf, int *buflen)
19819370Spst{
19998944Sobrien	int off = 0;
20019370Spst
201130803Smarcel	return ng_parse_composite(type,
20219370Spst	    "{}", &off, start, buf, buflen, CT_STRUCT);
20319370Spst}
20419370Spst
20598944Sobrienstatic int
20698944Sobrienng_struct_getAlign(const struct ng_parse_type *type)
20798944Sobrien{
20898944Sobrien	const struct ng_parse_struct_info *si = type->info;
20998944Sobrien	const struct ng_parse_struct_field *field;
21098944Sobrien	int align = 0;
21198944Sobrien
21298944Sobrien	for (field = si->fields; field->name != NULL; field++) {
21398944Sobrien		int falign = ALIGNMENT(field->type);
21498944Sobrien
21598944Sobrien		if (falign > align)
21698944Sobrien			align = falign;
21798944Sobrien	}
21898944Sobrien	return align;
21998944Sobrien}
22098944Sobrien
22198944Sobrienconst struct ng_parse_type ng_parse_struct_type = {
22298944Sobrien	NULL,
22398944Sobrien	NULL,
22498944Sobrien	NULL,
22598944Sobrien	ng_struct_parse,
22698944Sobrien	ng_struct_unparse,
22798944Sobrien	ng_struct_getDefault,
22898944Sobrien	ng_struct_getAlign
22998944Sobrien};
23098944Sobrien
23198944Sobrien/************************************************************************
23298944Sobrien			FIXED LENGTH ARRAY TYPE
23398944Sobrien ************************************************************************/
23498944Sobrien
23598944Sobrienstatic int
23698944Sobrienng_fixedarray_parse(const struct ng_parse_type *type,
23798944Sobrien	const char *s, int *off, const u_char *const start,
23898944Sobrien	u_char *const buf, int *buflen)
23998944Sobrien{
24098944Sobrien	return ng_parse_composite(type,
24198944Sobrien	    s, off, start, buf, buflen, CT_FIXEDARRAY);
24298944Sobrien}
24398944Sobrien
24498944Sobrienstatic int
24598944Sobrienng_fixedarray_unparse(const struct ng_parse_type *type,
24698944Sobrien	const u_char *data, int *off, char *cbuf, int cbuflen)
24798944Sobrien{
24898944Sobrien	return ng_unparse_composite(type,
24998944Sobrien		data, off, cbuf, cbuflen, CT_FIXEDARRAY);
25098944Sobrien}
25198944Sobrien
25298944Sobrienstatic int
25398944Sobrienng_fixedarray_getDefault(const struct ng_parse_type *type,
25498944Sobrien	const u_char *const start, u_char *buf, int *buflen)
25598944Sobrien{
25698944Sobrien	int off = 0;
25798944Sobrien
25898944Sobrien	return ng_parse_composite(type,
25998944Sobrien	    "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
26098944Sobrien}
26198944Sobrien
26298944Sobrienstatic int
26398944Sobrienng_fixedarray_getAlign(const struct ng_parse_type *type)
26498944Sobrien{
26598944Sobrien	const struct ng_parse_fixedarray_info *fi = type->info;
26698944Sobrien
26798944Sobrien	return ALIGNMENT(fi->elementType);
26898944Sobrien}
26998944Sobrien
27098944Sobrienconst struct ng_parse_type ng_parse_fixedarray_type = {
27198944Sobrien	NULL,
27298944Sobrien	NULL,
27398944Sobrien	NULL,
27498944Sobrien	ng_fixedarray_parse,
27598944Sobrien	ng_fixedarray_unparse,
27698944Sobrien	ng_fixedarray_getDefault,
27798944Sobrien	ng_fixedarray_getAlign
27898944Sobrien};
27998944Sobrien
28098944Sobrien/************************************************************************
28198944Sobrien			VARIABLE LENGTH ARRAY TYPE
28298944Sobrien ************************************************************************/
28398944Sobrien
28498944Sobrienstatic int
28598944Sobrienng_array_parse(const struct ng_parse_type *type,
28698944Sobrien	const char *s, int *off, const u_char *const start,
28798944Sobrien	u_char *const buf, int *buflen)
28898944Sobrien{
28998944Sobrien	return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
29098944Sobrien}
29198944Sobrien
29298944Sobrienstatic int
29398944Sobrienng_array_unparse(const struct ng_parse_type *type,
29498944Sobrien	const u_char *data, int *off, char *cbuf, int cbuflen)
29598944Sobrien{
29698944Sobrien	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
29798944Sobrien}
29898944Sobrien
29998944Sobrienstatic int
30098944Sobrienng_array_getDefault(const struct ng_parse_type *type,
30198944Sobrien	const u_char *const start, u_char *buf, int *buflen)
30298944Sobrien{
30398944Sobrien	int off = 0;
30498944Sobrien
30598944Sobrien	return ng_parse_composite(type,
30698944Sobrien	    "[]", &off, start, buf, buflen, CT_ARRAY);
30798944Sobrien}
30898944Sobrien
30998944Sobrienstatic int
31098944Sobrienng_array_getAlign(const struct ng_parse_type *type)
31198944Sobrien{
31298944Sobrien	const struct ng_parse_array_info *ai = type->info;
31398944Sobrien
31498944Sobrien	return ALIGNMENT(ai->elementType);
31598944Sobrien}
31698944Sobrien
31798944Sobrienconst struct ng_parse_type ng_parse_array_type = {
31898944Sobrien	NULL,
31998944Sobrien	NULL,
32098944Sobrien	NULL,
32198944Sobrien	ng_array_parse,
32298944Sobrien	ng_array_unparse,
32398944Sobrien	ng_array_getDefault,
32498944Sobrien	ng_array_getAlign
32598944Sobrien};
32698944Sobrien
32798944Sobrien/************************************************************************
32898944Sobrien				INT8 TYPE
32998944Sobrien ************************************************************************/
33098944Sobrien
33198944Sobrienstatic int
33298944Sobrienng_int8_parse(const struct ng_parse_type *type,
33398944Sobrien	const char *s, int *off, const u_char *const start,
33498944Sobrien	u_char *const buf, int *buflen)
33598944Sobrien{
33698944Sobrien	long val;
33798944Sobrien	int8_t val8;
33898944Sobrien	char *eptr;
33998944Sobrien
34098944Sobrien	val = strtol(s + *off, &eptr, 0);
34198944Sobrien	if (val < -0x80 || val > 0xff || eptr == s + *off)
34298944Sobrien		return (EINVAL);
34398944Sobrien	*off = eptr - s;
34498944Sobrien	val8 = (int8_t)val;
34598944Sobrien	bcopy(&val8, buf, sizeof(int8_t));
34698944Sobrien	*buflen = sizeof(int8_t);
34798944Sobrien	return (0);
34898944Sobrien}
34998944Sobrien
35098944Sobrienstatic int
35198944Sobrienng_int8_unparse(const struct ng_parse_type *type,
35219370Spst	const u_char *data, int *off, char *cbuf, int cbuflen)
35319370Spst{
35498944Sobrien	const char *fmt;
35519370Spst	int fval;
35619370Spst	int8_t val;
35719370Spst
35898944Sobrien	bcopy(data + *off, &val, sizeof(int8_t));
35998944Sobrien	switch ((int)type->info) {
36098944Sobrien	case INT_SIGNED:
36198944Sobrien		fmt = "%d";
36298944Sobrien		fval = val;
36398944Sobrien		break;
36498944Sobrien	case INT_UNSIGNED:
36598944Sobrien		fmt = "%u";
36698944Sobrien		fval = (u_int8_t)val;
36798944Sobrien		break;
36898944Sobrien	case INT_HEX:
36998944Sobrien		fmt = "0x%x";
37098944Sobrien		fval = (u_int8_t)val;
37198944Sobrien		break;
37298944Sobrien	default:
37398944Sobrien		panic("%s: unknown type", __FUNCTION__);
37498944Sobrien	}
37598944Sobrien	NG_PARSE_APPEND(fmt, fval);
37698944Sobrien	*off += sizeof(int8_t);
37798944Sobrien	return (0);
37898944Sobrien}
37998944Sobrien
38098944Sobrienstatic int
38198944Sobrienng_int8_getDefault(const struct ng_parse_type *type,
38298944Sobrien	const u_char *const start, u_char *buf, int *buflen)
38398944Sobrien{
38498944Sobrien	int8_t val;
38598944Sobrien
38698944Sobrien	if (*buflen < sizeof(int8_t))
38798944Sobrien		return (ERANGE);
38898944Sobrien	val = 0;
38998944Sobrien	bcopy(&val, buf, sizeof(int8_t));
39019370Spst	*buflen = sizeof(int8_t);
39119370Spst	return (0);
39219370Spst}
39319370Spst
39419370Spststatic int
39519370Spstng_int8_getAlign(const struct ng_parse_type *type)
39619370Spst{
39719370Spst	return INT8_ALIGNMENT;
39819370Spst}
39919370Spst
40098944Sobrienconst struct ng_parse_type ng_parse_int8_type = {
40119370Spst	NULL,
40219370Spst	(void *)INT_SIGNED,
40398944Sobrien	NULL,
40498944Sobrien	ng_int8_parse,
40598944Sobrien	ng_int8_unparse,
40698944Sobrien	ng_int8_getDefault,
40798944Sobrien	ng_int8_getAlign
40819370Spst};
40919370Spst
41098944Sobrienconst struct ng_parse_type ng_parse_uint8_type = {
41198944Sobrien	&ng_parse_int8_type,
41219370Spst	(void *)INT_UNSIGNED
41319370Spst};
41419370Spst
41519370Spstconst struct ng_parse_type ng_parse_hint8_type = {
41619370Spst	&ng_parse_int8_type,
41798944Sobrien	(void *)INT_HEX
418130803Smarcel};
41919370Spst
42019370Spst/************************************************************************
42119370Spst				INT16 TYPE
42219370Spst ************************************************************************/
42346283Sdfr
42419370Spststatic int
42519370Spstng_int16_parse(const struct ng_parse_type *type,
42619370Spst	const char *s, int *off, const u_char *const start,
42719370Spst	u_char *const buf, int *buflen)
428130803Smarcel{
429130803Smarcel	long val;
430130803Smarcel	int16_t val16;
431130803Smarcel	char *eptr;
432130803Smarcel
43398944Sobrien	val = strtol(s + *off, &eptr, 0);
43498944Sobrien	if (val < -0x8000 || val > 0xffff || eptr == s + *off)
43598944Sobrien		return (EINVAL);
43698944Sobrien	*off = eptr - s;
43719370Spst	val16 = (int16_t)val;
43819370Spst	bcopy(&val16, buf, sizeof(int16_t));
43919370Spst	*buflen = sizeof(int16_t);
44098944Sobrien	return (0);
441130803Smarcel}
44219370Spst
44319370Spststatic int
44419370Spstng_int16_unparse(const struct ng_parse_type *type,
44519370Spst	const u_char *data, int *off, char *cbuf, int cbuflen)
44619370Spst{
44719370Spst	const char *fmt;
44898944Sobrien	int fval;
44919370Spst	int16_t val;
45019370Spst
45119370Spst	bcopy(data + *off, &val, sizeof(int16_t));
45219370Spst	switch ((int)type->info) {
45319370Spst	case INT_SIGNED:
45419370Spst		fmt = "%d";
45519370Spst		fval = val;
45619370Spst		break;
45719370Spst	case INT_UNSIGNED:
45819370Spst		fmt = "%u";
45919370Spst		fval = (u_int16_t)val;
46019370Spst		break;
46119370Spst	case INT_HEX:
46219370Spst		fmt = "0x%x";
46319370Spst		fval = (u_int16_t)val;
46419370Spst		break;
46519370Spst	default:
46619370Spst		panic("%s: unknown type", __FUNCTION__);
46719370Spst	}
46819370Spst	NG_PARSE_APPEND(fmt, fval);
46919370Spst	*off += sizeof(int16_t);
47019370Spst	return (0);
47119370Spst}
47219370Spst
47319370Spststatic int
474ng_int16_getDefault(const struct ng_parse_type *type,
475	const u_char *const start, u_char *buf, int *buflen)
476{
477	int16_t val;
478
479	if (*buflen < sizeof(int16_t))
480		return (ERANGE);
481	val = 0;
482	bcopy(&val, buf, sizeof(int16_t));
483	*buflen = sizeof(int16_t);
484	return (0);
485}
486
487static int
488ng_int16_getAlign(const struct ng_parse_type *type)
489{
490	return INT16_ALIGNMENT;
491}
492
493const struct ng_parse_type ng_parse_int16_type = {
494	NULL,
495	(void *)INT_SIGNED,
496	NULL,
497	ng_int16_parse,
498	ng_int16_unparse,
499	ng_int16_getDefault,
500	ng_int16_getAlign
501};
502
503const struct ng_parse_type ng_parse_uint16_type = {
504	&ng_parse_int16_type,
505	(void *)INT_UNSIGNED
506};
507
508const struct ng_parse_type ng_parse_hint16_type = {
509	&ng_parse_int16_type,
510	(void *)INT_HEX
511};
512
513/************************************************************************
514				INT32 TYPE
515 ************************************************************************/
516
517static int
518ng_int32_parse(const struct ng_parse_type *type,
519	const char *s, int *off, const u_char *const start,
520	u_char *const buf, int *buflen)
521{
522	long val;			/* assumes long is at least 32 bits */
523	int32_t val32;
524	char *eptr;
525
526	val = strtol(s + *off, &eptr, 0);
527	if (val < (long)-0x80000000
528	    || val > (u_long)0xffffffff || eptr == s + *off)
529		return (EINVAL);
530	*off = eptr - s;
531	val32 = (int32_t)val;
532	bcopy(&val32, buf, sizeof(int32_t));
533	*buflen = sizeof(int32_t);
534	return (0);
535}
536
537static int
538ng_int32_unparse(const struct ng_parse_type *type,
539	const u_char *data, int *off, char *cbuf, int cbuflen)
540{
541	const char *fmt;
542	long fval;
543	int32_t val;
544
545	bcopy(data + *off, &val, sizeof(int32_t));
546	switch ((int)type->info) {
547	case INT_SIGNED:
548		fmt = "%ld";
549		fval = val;
550		break;
551	case INT_UNSIGNED:
552		fmt = "%lu";
553		fval = (u_int32_t)val;
554		break;
555	case INT_HEX:
556		fmt = "0x%lx";
557		fval = (u_int32_t)val;
558		break;
559	default:
560		panic("%s: unknown type", __FUNCTION__);
561	}
562	NG_PARSE_APPEND(fmt, fval);
563	*off += sizeof(int32_t);
564	return (0);
565}
566
567static int
568ng_int32_getDefault(const struct ng_parse_type *type,
569	const u_char *const start, u_char *buf, int *buflen)
570{
571	int32_t val;
572
573	if (*buflen < sizeof(int32_t))
574		return (ERANGE);
575	val = 0;
576	bcopy(&val, buf, sizeof(int32_t));
577	*buflen = sizeof(int32_t);
578	return (0);
579}
580
581static int
582ng_int32_getAlign(const struct ng_parse_type *type)
583{
584	return INT32_ALIGNMENT;
585}
586
587const struct ng_parse_type ng_parse_int32_type = {
588	NULL,
589	(void *)INT_SIGNED,
590	NULL,
591	ng_int32_parse,
592	ng_int32_unparse,
593	ng_int32_getDefault,
594	ng_int32_getAlign
595};
596
597const struct ng_parse_type ng_parse_uint32_type = {
598	&ng_parse_int32_type,
599	(void *)INT_UNSIGNED
600};
601
602const struct ng_parse_type ng_parse_hint32_type = {
603	&ng_parse_int32_type,
604	(void *)INT_HEX
605};
606
607/************************************************************************
608				INT64 TYPE
609 ************************************************************************/
610
611static int
612ng_int64_parse(const struct ng_parse_type *type,
613	const char *s, int *off, const u_char *const start,
614	u_char *const buf, int *buflen)
615{
616	quad_t val;
617	int64_t val64;
618	char *eptr;
619
620	val = strtoq(s + *off, &eptr, 0);
621	if (eptr == s + *off)
622		return (EINVAL);
623	*off = eptr - s;
624	val64 = (int64_t)val;
625	bcopy(&val64, buf, sizeof(int64_t));
626	*buflen = sizeof(int64_t);
627	return (0);
628}
629
630static int
631ng_int64_unparse(const struct ng_parse_type *type,
632	const u_char *data, int *off, char *cbuf, int cbuflen)
633{
634	const char *fmt;
635	long long fval;
636	int64_t val;
637
638	bcopy(data + *off, &val, sizeof(int64_t));
639	switch ((int)type->info) {
640	case INT_SIGNED:
641		fmt = "%lld";
642		fval = val;
643		break;
644	case INT_UNSIGNED:
645		fmt = "%llu";
646		fval = (u_int64_t)val;
647		break;
648	case INT_HEX:
649		fmt = "0x%llx";
650		fval = (u_int64_t)val;
651		break;
652	default:
653		panic("%s: unknown type", __FUNCTION__);
654	}
655	NG_PARSE_APPEND(fmt, fval);
656	*off += sizeof(int64_t);
657	return (0);
658}
659
660static int
661ng_int64_getDefault(const struct ng_parse_type *type,
662	const u_char *const start, u_char *buf, int *buflen)
663{
664	int64_t val;
665
666	if (*buflen < sizeof(int64_t))
667		return (ERANGE);
668	val = 0;
669	bcopy(&val, buf, sizeof(int64_t));
670	*buflen = sizeof(int64_t);
671	return (0);
672}
673
674static int
675ng_int64_getAlign(const struct ng_parse_type *type)
676{
677	return INT64_ALIGNMENT;
678}
679
680const struct ng_parse_type ng_parse_int64_type = {
681	NULL,
682	(void *)INT_SIGNED,
683	NULL,
684	ng_int64_parse,
685	ng_int64_unparse,
686	ng_int64_getDefault,
687	ng_int64_getAlign
688};
689
690const struct ng_parse_type ng_parse_uint64_type = {
691	&ng_parse_int64_type,
692	(void *)INT_UNSIGNED
693};
694
695const struct ng_parse_type ng_parse_hint64_type = {
696	&ng_parse_int64_type,
697	(void *)INT_HEX
698};
699
700/************************************************************************
701				STRING TYPE
702 ************************************************************************/
703
704static int
705ng_string_parse(const struct ng_parse_type *type,
706	const char *s, int *off, const u_char *const start,
707	u_char *const buf, int *buflen)
708{
709	char *sval;
710	int len;
711
712	if ((sval = ng_get_string_token(s, off, &len)) == NULL)
713		return (EINVAL);
714	*off += len;
715	len = strlen(sval) + 1;
716	bcopy(sval, buf, len);
717	FREE(sval, M_NETGRAPH);
718	*buflen = len;
719	return (0);
720}
721
722static int
723ng_string_unparse(const struct ng_parse_type *type,
724	const u_char *data, int *off, char *cbuf, int cbuflen)
725{
726	const char *const raw = (const char *)data + *off;
727	char *const s = ng_encode_string(raw);
728
729	if (s == NULL)
730		return (ENOMEM);
731	NG_PARSE_APPEND("%s", s);
732	*off += strlen(raw) + 1;
733	FREE(s, M_NETGRAPH);
734	return (0);
735}
736
737static int
738ng_string_getDefault(const struct ng_parse_type *type,
739	const u_char *const start, u_char *buf, int *buflen)
740{
741
742	if (*buflen < 1)
743		return (ERANGE);
744	buf[0] = (u_char)'\0';
745	*buflen = 1;
746	return (0);
747}
748
749const struct ng_parse_type ng_parse_string_type = {
750	NULL,
751	NULL,
752	NULL,
753	ng_string_parse,
754	ng_string_unparse,
755	ng_string_getDefault,
756	NULL
757};
758
759/************************************************************************
760			FIXED BUFFER STRING TYPE
761 ************************************************************************/
762
763static int
764ng_fixedstring_parse(const struct ng_parse_type *type,
765	const char *s, int *off, const u_char *const start,
766	u_char *const buf, int *buflen)
767{
768	const struct ng_parse_fixedstring_info *const fi = type->info;
769	char *sval;
770	int len;
771
772	if ((sval = ng_get_string_token(s, off, &len)) == NULL)
773		return (EINVAL);
774	if (strlen(sval) + 1 > fi->bufSize)
775		return (E2BIG);
776	*off += len;
777	len = strlen(sval) + 1;
778	bcopy(sval, buf, len);
779	FREE(sval, M_NETGRAPH);
780	bzero(buf + len, fi->bufSize - len);
781	*buflen = fi->bufSize;
782	return (0);
783}
784
785static int
786ng_fixedstring_unparse(const struct ng_parse_type *type,
787	const u_char *data, int *off, char *cbuf, int cbuflen)
788{
789	const struct ng_parse_fixedstring_info *const fi = type->info;
790	int error, temp = *off;
791
792	if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
793		return (error);
794	*off += fi->bufSize;
795	return (0);
796}
797
798static int
799ng_fixedstring_getDefault(const struct ng_parse_type *type,
800	const u_char *const start, u_char *buf, int *buflen)
801{
802	const struct ng_parse_fixedstring_info *const fi = type->info;
803
804	if (*buflen < fi->bufSize)
805		return (ERANGE);
806	bzero(buf, fi->bufSize);
807	*buflen = fi->bufSize;
808	return (0);
809}
810
811const struct ng_parse_type ng_parse_fixedstring_type = {
812	NULL,
813	NULL,
814	NULL,
815	ng_fixedstring_parse,
816	ng_fixedstring_unparse,
817	ng_fixedstring_getDefault,
818	NULL
819};
820
821const struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
822	NG_NODELEN + 1
823};
824const struct ng_parse_type ng_parse_nodebuf_type = {
825	&ng_parse_fixedstring_type,
826	&ng_parse_nodebuf_info
827};
828
829const struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
830	NG_HOOKLEN + 1
831};
832const struct ng_parse_type ng_parse_hookbuf_type = {
833	&ng_parse_fixedstring_type,
834	&ng_parse_hookbuf_info
835};
836
837const struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
838	NG_PATHLEN + 1
839};
840const struct ng_parse_type ng_parse_pathbuf_type = {
841	&ng_parse_fixedstring_type,
842	&ng_parse_pathbuf_info
843};
844
845const struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
846	NG_TYPELEN + 1
847};
848const struct ng_parse_type ng_parse_typebuf_type = {
849	&ng_parse_fixedstring_type,
850	&ng_parse_typebuf_info
851};
852
853const struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
854	NG_CMDSTRLEN + 1
855};
856const struct ng_parse_type ng_parse_cmdbuf_type = {
857	&ng_parse_fixedstring_type,
858	&ng_parse_cmdbuf_info
859};
860
861/************************************************************************
862			IP ADDRESS TYPE
863 ************************************************************************/
864
865static int
866ng_ipaddr_parse(const struct ng_parse_type *type,
867	const char *s, int *off, const u_char *const start,
868	u_char *const buf, int *buflen)
869{
870	int i, error;
871
872	for (i = 0; i < 4; i++) {
873		if ((error = ng_int8_parse(&ng_parse_int8_type,
874		    s, off, start, buf + i, buflen)) != 0)
875			return (error);
876		if (i < 3 && s[*off] != '.')
877			return (EINVAL);
878		(*off)++;
879	}
880	*buflen = 4;
881	return (0);
882}
883
884static int
885ng_ipaddr_unparse(const struct ng_parse_type *type,
886	const u_char *data, int *off, char *cbuf, int cbuflen)
887{
888	struct in_addr ip;
889
890	bcopy(data + *off, &ip, sizeof(ip));
891	NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0],
892	    ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]);
893	*off += sizeof(ip);
894	return (0);
895}
896
897static int
898ng_ipaddr_getDefault(const struct ng_parse_type *type,
899	const u_char *const start, u_char *buf, int *buflen)
900{
901	struct in_addr ip = { 0 };
902
903	if (*buflen < sizeof(ip))
904		return (ERANGE);
905	bcopy(&ip, buf, sizeof(ip));
906	*buflen = sizeof(ip);
907	return (0);
908}
909
910const struct ng_parse_type ng_parse_ipaddr_type = {
911	NULL,
912	NULL,
913	NULL,
914	ng_ipaddr_parse,
915	ng_ipaddr_unparse,
916	ng_ipaddr_getDefault,
917	ng_int32_getAlign
918};
919
920/************************************************************************
921			BYTE ARRAY TYPE
922 ************************************************************************/
923
924/* Get the length of a byte array */
925static int
926ng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
927	const u_char *start, const u_char *buf)
928{
929	ng_parse_array_getLength_t *const getLength = type->private;
930
931	return (*getLength)(type, start, buf);
932}
933
934/* Byte array element type is hex int8 */
935static const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
936	&ng_parse_hint8_type,
937	&ng_parse_bytearray_subtype_getLength,
938	NULL
939};
940static const struct ng_parse_type ng_parse_bytearray_subtype = {
941	&ng_parse_array_type,
942	&ng_parse_bytearray_subtype_info
943};
944
945static int
946ng_bytearray_parse(const struct ng_parse_type *type,
947	const char *s, int *off, const u_char *const start,
948	u_char *const buf, int *buflen)
949{
950	char *str;
951	int toklen;
952
953	/* We accept either an array of bytes or a string constant */
954	if ((str = ng_get_string_token(s, off, &toklen)) != NULL) {
955		ng_parse_array_getLength_t *const getLength = type->info;
956		int arraylen, slen;
957
958		arraylen = (*getLength)(type, start, buf);
959		if (arraylen > *buflen) {
960			FREE(str, M_NETGRAPH);
961			return (ERANGE);
962		}
963		slen = strlen(str) + 1;
964		if (slen > arraylen) {
965			FREE(str, M_NETGRAPH);
966			return (E2BIG);
967		}
968		bcopy(str, buf, slen);
969		bzero(buf + slen, arraylen - slen);
970		FREE(str, M_NETGRAPH);
971		*off += toklen;
972		*buflen = arraylen;
973		return (0);
974	} else {
975		struct ng_parse_type subtype;
976
977		subtype = ng_parse_bytearray_subtype;
978		(const void *)subtype.private = type->info;
979		return ng_array_parse(&subtype, s, off, start, buf, buflen);
980	}
981}
982
983static int
984ng_bytearray_unparse(const struct ng_parse_type *type,
985	const u_char *data, int *off, char *cbuf, int cbuflen)
986{
987	struct ng_parse_type subtype;
988
989	subtype = ng_parse_bytearray_subtype;
990	(const void *)subtype.private = type->info;
991	return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
992}
993
994static int
995ng_bytearray_getDefault(const struct ng_parse_type *type,
996	const u_char *const start, u_char *buf, int *buflen)
997{
998	struct ng_parse_type subtype;
999
1000	subtype = ng_parse_bytearray_subtype;
1001	(const void *)subtype.private = type->info;
1002	return ng_array_getDefault(&subtype, start, buf, buflen);
1003}
1004
1005const struct ng_parse_type ng_parse_bytearray_type = {
1006	NULL,
1007	NULL,
1008	NULL,
1009	ng_bytearray_parse,
1010	ng_bytearray_unparse,
1011	ng_bytearray_getDefault,
1012	NULL
1013};
1014
1015/************************************************************************
1016			STRUCT NG_MESG TYPE
1017 ************************************************************************/
1018
1019/* Get msg->header.arglen when "buf" is pointing to msg->data */
1020static int
1021ng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
1022	const u_char *start, const u_char *buf)
1023{
1024	const struct ng_mesg *msg;
1025
1026	msg = (const struct ng_mesg *)(buf - sizeof(*msg));
1027	return msg->header.arglen;
1028}
1029
1030/* Type for the variable length data portion of a struct ng_mesg */
1031static const struct ng_parse_type ng_msg_data_type = {
1032	&ng_parse_bytearray_type,
1033	&ng_parse_ng_mesg_getLength
1034};
1035
1036/* Type for the entire struct ng_mesg header with data section */
1037static const struct ng_parse_struct_info
1038	ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
1039const struct ng_parse_type ng_parse_ng_mesg_type = {
1040	&ng_parse_struct_type,
1041	&ng_parse_ng_mesg_type_info,
1042};
1043
1044/************************************************************************
1045			COMPOSITE HELPER ROUTINES
1046 ************************************************************************/
1047
1048/*
1049 * Convert a structure or array from ASCII to binary
1050 */
1051static int
1052ng_parse_composite(const struct ng_parse_type *type, const char *s,
1053	int *off, const u_char *const start, u_char *const buf, int *buflen,
1054	const enum comptype ctype)
1055{
1056	const int num = ng_get_composite_len(type, start, buf, ctype);
1057	int nextIndex = 0;		/* next implicit array index */
1058	u_int index;			/* field or element index */
1059	int *foff;			/* field value offsets in string */
1060	int align, len, blen, error = 0;
1061
1062	/* Initialize */
1063	MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH, M_NOWAIT);
1064	if (foff == NULL) {
1065		error = ENOMEM;
1066		goto done;
1067	}
1068	bzero(foff, num * sizeof(*foff));
1069
1070	/* Get opening brace/bracket */
1071	if (ng_parse_get_token(s, off, &len)
1072	    != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
1073		error = EINVAL;
1074		goto done;
1075	}
1076	*off += len;
1077
1078	/* Get individual element value positions in the string */
1079	for (;;) {
1080		enum ng_parse_token tok;
1081
1082		/* Check for closing brace/bracket */
1083		tok = ng_parse_get_token(s, off, &len);
1084		if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
1085			*off += len;
1086			break;
1087		}
1088
1089		/* For arrays, the 'name' (ie, index) is optional, so
1090		   distinguish name from values by seeing if the next
1091		   token is an equals sign */
1092		if (ctype != CT_STRUCT) {
1093			int len2, off2;
1094			char *eptr;
1095
1096			/* If an opening brace/bracket, index is implied */
1097			if (tok == T_LBRACE || tok == T_LBRACKET) {
1098				index = nextIndex++;
1099				goto gotIndex;
1100			}
1101
1102			/* Might be an index, might be a value, either way... */
1103			if (tok != T_WORD) {
1104				error = EINVAL;
1105				goto done;
1106			}
1107
1108			/* If no equals sign follows, index is implied */
1109			off2 = *off + len;
1110			if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
1111				index = nextIndex++;
1112				goto gotIndex;
1113			}
1114
1115			/* Index was specified explicitly; parse it */
1116			index = (u_int)strtoul(s + *off, &eptr, 0);
1117			if (index < 0 || eptr - (s + *off) != len) {
1118				error = EINVAL;
1119				goto done;
1120			}
1121			nextIndex = index + 1;
1122			*off += len + len2;
1123gotIndex:
1124		} else {			/* a structure field */
1125			const struct ng_parse_struct_field *field = NULL;
1126			const struct ng_parse_struct_info *si = type->info;
1127
1128			/* Find the field by name (required) in field list */
1129			if (tok != T_WORD) {
1130				error = EINVAL;
1131				goto done;
1132			}
1133			for (index = 0; index < num; index++) {
1134				field = &si->fields[index];
1135				if (strncmp(&s[*off], field->name, len) == 0
1136				    && field->name[len] == '\0')
1137					break;
1138			}
1139			if (index == num) {
1140				error = ENOENT;
1141				goto done;
1142			}
1143			*off += len;
1144
1145			/* Get equals sign */
1146			if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
1147				error = EINVAL;
1148				goto done;
1149			}
1150			*off += len;
1151		}
1152
1153		/* Check array index */
1154		if (index >= num) {
1155			error = E2BIG;
1156			goto done;
1157		}
1158
1159		/* Save value's position and skip over it for now */
1160		if (foff[index] != 0) {
1161			error = EALREADY;		/* duplicate */
1162			goto done;
1163		}
1164		while (isspace(s[*off]))
1165			(*off)++;
1166		foff[index] = *off;
1167		if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
1168			goto done;
1169		*off += len;
1170	}
1171
1172	/* Now build binary structure from supplied values and defaults */
1173	for (blen = index = 0; index < num; index++) {
1174		const struct ng_parse_type *const
1175		    etype = ng_get_composite_etype(type, index, ctype);
1176		int k, pad, vlen;
1177
1178		/* Zero-pad any alignment bytes */
1179		pad = ng_parse_get_elem_pad(type, index, ctype, blen);
1180		for (k = 0; k < pad; k++) {
1181			if (blen >= *buflen) {
1182				error = ERANGE;
1183				goto done;
1184			}
1185			buf[blen++] = 0;
1186		}
1187
1188		/* Get value */
1189		vlen = *buflen - blen;
1190		if (foff[index] == 0) {		/* use default value */
1191			error = ng_get_composite_elem_default(type, index,
1192			    start, buf + blen, &vlen, ctype);
1193		} else {			/* parse given value */
1194			*off = foff[index];
1195			error = INVOKE(etype, parse)(etype,
1196			    s, off, start, buf + blen, &vlen);
1197		}
1198		if (error != 0)
1199			goto done;
1200		blen += vlen;
1201	}
1202
1203	/* Make total composite structure size a multiple of its alignment */
1204	if ((align = ALIGNMENT(type)) != 0) {
1205		while (blen % align != 0) {
1206			if (blen >= *buflen) {
1207				error = ERANGE;
1208				goto done;
1209			}
1210			buf[blen++] = 0;
1211		}
1212	}
1213
1214	/* Done */
1215	*buflen = blen;
1216done:
1217	if (foff != NULL)
1218		FREE(foff, M_NETGRAPH);
1219	return (error);
1220}
1221
1222/*
1223 * Convert an array or structure from binary to ASCII
1224 */
1225static int
1226ng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
1227	int *off, char *cbuf, int cbuflen, const enum comptype ctype)
1228{
1229	const int num = ng_get_composite_len(type, data, data + *off, ctype);
1230	const int workSize = 20 * 1024;		/* XXX hard coded constant */
1231	int nextIndex = 0, didOne = 0;
1232	int error, index;
1233	u_char *workBuf;
1234
1235	/* Get workspace for checking default values */
1236	MALLOC(workBuf, u_char *, workSize, M_NETGRAPH, M_NOWAIT);
1237	if (workBuf == NULL)
1238		return (ENOMEM);
1239
1240	/* Opening brace/bracket */
1241	NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
1242
1243	/* Do each item */
1244	for (index = 0; index < num; index++) {
1245		const struct ng_parse_type *const
1246		    etype = ng_get_composite_etype(type, index, ctype);
1247
1248		/* Skip any alignment pad bytes */
1249		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
1250
1251		/* See if element is equal to its default value; skip if so */
1252		if (*off < workSize) {
1253			int tempsize = workSize - *off;
1254
1255			bcopy(data, workBuf, *off);
1256			if (ng_get_composite_elem_default(type, index, workBuf,
1257			      workBuf + *off, &tempsize, ctype) == 0
1258			    && bcmp(workBuf + *off,
1259			      data + *off, tempsize) == 0) {
1260				*off += tempsize;
1261				continue;
1262			}
1263		}
1264
1265		/* Print name= */
1266		NG_PARSE_APPEND(" ");
1267		if (ctype != CT_STRUCT) {
1268			if (index != nextIndex) {
1269				nextIndex = index;
1270				NG_PARSE_APPEND("%d=", index);
1271			}
1272			nextIndex++;
1273		} else {
1274			const struct ng_parse_struct_info *si = type->info;
1275
1276			NG_PARSE_APPEND("%s=", si->fields[index].name);
1277		}
1278
1279		/* Print value */
1280		if ((error = INVOKE(etype, unparse)
1281		    (etype, data, off, cbuf, cbuflen)) != 0) {
1282			FREE(workBuf, M_NETGRAPH);
1283			return (error);
1284		}
1285		cbuflen -= strlen(cbuf);
1286		cbuf += strlen(cbuf);
1287		didOne = 1;
1288	}
1289	FREE(workBuf, M_NETGRAPH);
1290
1291	/* Closing brace/bracket */
1292	NG_PARSE_APPEND("%s%c",
1293	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
1294	return (0);
1295}
1296
1297/*
1298 * Generate the default value for an element of an array or structure
1299 * Returns EOPNOTSUPP if default value is unspecified.
1300 */
1301static int
1302ng_get_composite_elem_default(const struct ng_parse_type *type,
1303	int index, const u_char *const start, u_char *buf, int *buflen,
1304	const enum comptype ctype)
1305{
1306	const struct ng_parse_type *etype;
1307	ng_getDefault_t *func;
1308
1309	switch (ctype) {
1310	case CT_STRUCT:
1311		break;
1312	case CT_ARRAY:
1313	    {
1314		const struct ng_parse_array_info *const ai = type->info;
1315
1316		if (ai->getDefault != NULL) {
1317			return (*ai->getDefault)(type,
1318			    index, start, buf, buflen);
1319		}
1320		break;
1321	    }
1322	case CT_FIXEDARRAY:
1323	    {
1324		const struct ng_parse_fixedarray_info *const fi = type->info;
1325
1326		if (*fi->getDefault != NULL) {
1327			return (*fi->getDefault)(type,
1328			    index, start, buf, buflen);
1329		}
1330		break;
1331	    }
1332	default:
1333	    panic("%s", __FUNCTION__);
1334	}
1335
1336	/* Default to element type default */
1337	etype = ng_get_composite_etype(type, index, ctype);
1338	func = METHOD(etype, getDefault);
1339	if (func == NULL)
1340		return (EOPNOTSUPP);
1341	return (*func)(etype, start, buf, buflen);
1342}
1343
1344/*
1345 * Get the number of elements in a struct, variable or fixed array.
1346 */
1347static int
1348ng_get_composite_len(const struct ng_parse_type *type,
1349	const u_char *const start, const u_char *buf,
1350	const enum comptype ctype)
1351{
1352	switch (ctype) {
1353	case CT_STRUCT:
1354	    {
1355		const struct ng_parse_struct_info *const si = type->info;
1356		int numFields = 0;
1357
1358		for (numFields = 0; ; numFields++) {
1359			const struct ng_parse_struct_field *const
1360				fi = &si->fields[numFields];
1361
1362			if (fi->name == NULL)
1363				break;
1364		}
1365		return (numFields);
1366	    }
1367	case CT_ARRAY:
1368	    {
1369		const struct ng_parse_array_info *const ai = type->info;
1370
1371		return (*ai->getLength)(type, start, buf);
1372	    }
1373	case CT_FIXEDARRAY:
1374	    {
1375		const struct ng_parse_fixedarray_info *const fi = type->info;
1376
1377		return fi->length;
1378	    }
1379	default:
1380	    panic("%s", __FUNCTION__);
1381	}
1382	return (0);
1383}
1384
1385/*
1386 * Return the type of the index'th element of a composite structure
1387 */
1388static const struct ng_parse_type *
1389ng_get_composite_etype(const struct ng_parse_type *type,
1390	int index, const enum comptype ctype)
1391{
1392	const struct ng_parse_type *etype = NULL;
1393
1394	switch (ctype) {
1395	case CT_STRUCT:
1396	    {
1397		const struct ng_parse_struct_info *const si = type->info;
1398
1399		etype = si->fields[index].type;
1400		break;
1401	    }
1402	case CT_ARRAY:
1403	    {
1404		const struct ng_parse_array_info *const ai = type->info;
1405
1406		etype = ai->elementType;
1407		break;
1408	    }
1409	case CT_FIXEDARRAY:
1410	    {
1411		const struct ng_parse_fixedarray_info *const fi = type->info;
1412
1413		etype = fi->elementType;
1414		break;
1415	    }
1416	default:
1417	    panic("%s", __FUNCTION__);
1418	}
1419	return (etype);
1420}
1421
1422/*
1423 * Get the number of bytes to skip to align for the next
1424 * element in a composite structure.
1425 */
1426static int
1427ng_parse_get_elem_pad(const struct ng_parse_type *type,
1428	int index, enum comptype ctype, int posn)
1429{
1430	const struct ng_parse_type *const
1431	    etype = ng_get_composite_etype(type, index, ctype);
1432	int align;
1433
1434	/* Get element's alignment, and possibly override */
1435	align = ALIGNMENT(etype);
1436	if (ctype == CT_STRUCT) {
1437		const struct ng_parse_struct_info *si = type->info;
1438
1439		if (si->fields[index].alignment != 0)
1440			align = si->fields[index].alignment;
1441	}
1442
1443	/* Return number of bytes to skip to align */
1444	return (align ? (align - (posn % align)) % align : 0);
1445}
1446
1447/************************************************************************
1448			PARSING HELPER ROUTINES
1449 ************************************************************************/
1450
1451/*
1452 * Skip over a value
1453 */
1454static int
1455ng_parse_skip_value(const char *s, int off0, int *lenp)
1456{
1457	int len, nbracket, nbrace;
1458	int off = off0;
1459
1460	len = nbracket = nbrace = 0;
1461	do {
1462		switch (ng_parse_get_token(s, &off, &len)) {
1463		case T_LBRACKET:
1464			nbracket++;
1465			break;
1466		case T_LBRACE:
1467			nbrace++;
1468			break;
1469		case T_RBRACKET:
1470			if (nbracket-- == 0)
1471				return (EINVAL);
1472			break;
1473		case T_RBRACE:
1474			if (nbrace-- == 0)
1475				return (EINVAL);
1476			break;
1477		case T_EOF:
1478			return (EINVAL);
1479		default:
1480			break;
1481		}
1482		off += len;
1483	} while (nbracket > 0 || nbrace > 0);
1484	*lenp = off - off0;
1485	return (0);
1486}
1487
1488/*
1489 * Find the next token in the string, starting at offset *startp.
1490 * Returns the token type, with *startp pointing to the first char
1491 * and *lenp the length.
1492 */
1493enum ng_parse_token
1494ng_parse_get_token(const char *s, int *startp, int *lenp)
1495{
1496	char *t;
1497	int i;
1498
1499	while (isspace(s[*startp]))
1500		(*startp)++;
1501	switch (s[*startp]) {
1502	case '\0':
1503		*lenp = 0;
1504		return T_EOF;
1505	case '{':
1506		*lenp = 1;
1507		return T_LBRACE;
1508	case '}':
1509		*lenp = 1;
1510		return T_RBRACE;
1511	case '[':
1512		*lenp = 1;
1513		return T_LBRACKET;
1514	case ']':
1515		*lenp = 1;
1516		return T_RBRACKET;
1517	case '=':
1518		*lenp = 1;
1519		return T_EQUALS;
1520	case '"':
1521		if ((t = ng_get_string_token(s, startp, lenp)) == NULL)
1522			return T_ERROR;
1523		FREE(t, M_NETGRAPH);
1524		return T_STRING;
1525	default:
1526		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
1527		    && s[i] != '{' && s[i] != '}' && s[i] != '['
1528		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
1529			;
1530		*lenp = i - *startp;
1531		return T_WORD;
1532	}
1533}
1534
1535/*
1536 * Get a string token, which must be enclosed in double quotes.
1537 * The normal C backslash escapes are recognized.
1538 */
1539char *
1540ng_get_string_token(const char *s, int *startp, int *lenp)
1541{
1542	char *cbuf, *p;
1543	int start, off;
1544
1545	while (isspace(s[*startp]))
1546		(*startp)++;
1547	start = *startp;
1548	if (s[*startp] != '"')
1549		return (NULL);
1550	MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH, M_NOWAIT);
1551	if (cbuf == NULL)
1552		return (NULL);
1553	strcpy(cbuf, s + start + 1);
1554	for (off = 1, p = cbuf; *p != '\0'; off++, p++) {
1555		if (*p == '"') {
1556			*p = '\0';
1557			*lenp = off + 1;
1558			return (cbuf);
1559		} else if (p[0] == '\\' && p[1] != '\0') {
1560			int x, k;
1561			char *v;
1562
1563			strcpy(p, p + 1);
1564			v = p;
1565			switch (*p) {
1566			case 't':
1567				*v = '\t';
1568				off++;
1569				continue;
1570			case 'n':
1571				*v = '\n';
1572				off++;
1573				continue;
1574			case 'r':
1575				*v = '\r';
1576				off++;
1577				continue;
1578			case 'v':
1579				*v =  '\v';
1580				off++;
1581				continue;
1582			case 'f':
1583				*v =  '\f';
1584				off++;
1585				continue;
1586			case '"':
1587				*v =  '"';
1588				off++;
1589				continue;
1590			case '0': case '1': case '2': case '3':
1591			case '4': case '5': case '6': case '7':
1592				for (x = k = 0;
1593				    k < 3 && *v >= '0' && *v <= '7'; v++) {
1594					x = (x << 3) + (*v - '0');
1595					off++;
1596				}
1597				*--v = (char)x;
1598				break;
1599			case 'x':
1600				for (v++, x = k = 0;
1601				    k < 2 && isxdigit(*v); v++) {
1602					x = (x << 4) + (isdigit(*v) ?
1603					      (*v - '0') :
1604					      (tolower(*v) - 'a' + 10));
1605					off++;
1606				}
1607				*--v = (char)x;
1608				break;
1609			default:
1610				continue;
1611			}
1612			strcpy(p, v);
1613		}
1614	}
1615	return (NULL);		/* no closing quote */
1616}
1617
1618/*
1619 * Encode a string so it can be safely put in double quotes.
1620 * Caller must free the result.
1621 */
1622char *
1623ng_encode_string(const char *raw)
1624{
1625	char *cbuf;
1626	int off = 0;
1627
1628	MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH, M_NOWAIT);
1629	if (cbuf == NULL)
1630		return (NULL);
1631	cbuf[off++] = '"';
1632	for ( ; *raw != '\0'; raw++) {
1633		switch (*raw) {
1634		case '\t':
1635			cbuf[off++] = '\\';
1636			cbuf[off++] = 't';
1637			break;
1638		case '\f':
1639			cbuf[off++] = '\\';
1640			cbuf[off++] = 'f';
1641			break;
1642		case '\n':
1643			cbuf[off++] = '\\';
1644			cbuf[off++] = 'n';
1645			break;
1646		case '\r':
1647			cbuf[off++] = '\\';
1648			cbuf[off++] = 'r';
1649			break;
1650		case '\v':
1651			cbuf[off++] = '\\';
1652			cbuf[off++] = 'v';
1653			break;
1654		case '"':
1655		case '\\':
1656			cbuf[off++] = '\\';
1657			cbuf[off++] = *raw;
1658			break;
1659		default:
1660			if (*raw < 0x20 || *raw > 0x7e) {
1661				off += sprintf(cbuf + off,
1662				    "\\x%02x", (u_char)*raw);
1663				break;
1664			}
1665			cbuf[off++] = *raw;
1666			break;
1667		}
1668	}
1669	cbuf[off++] = '"';
1670	cbuf[off] = '\0';
1671	return (cbuf);
1672}
1673
1674/************************************************************************
1675			VIRTUAL METHOD LOOKUP
1676 ************************************************************************/
1677
1678static ng_parse_t *
1679ng_get_parse_method(const struct ng_parse_type *t)
1680{
1681	while (t != NULL && t->parse == NULL)
1682		t = t->supertype;
1683	return (t ? t->parse : NULL);
1684}
1685
1686static ng_unparse_t *
1687ng_get_unparse_method(const struct ng_parse_type *t)
1688{
1689	while (t != NULL && t->unparse == NULL)
1690		t = t->supertype;
1691	return (t ? t->unparse : NULL);
1692}
1693
1694static ng_getDefault_t *
1695ng_get_getDefault_method(const struct ng_parse_type *t)
1696{
1697	while (t != NULL && t->getDefault == NULL)
1698		t = t->supertype;
1699	return (t ? t->getDefault : NULL);
1700}
1701
1702static ng_getAlign_t *
1703ng_get_getAlign_method(const struct ng_parse_type *t)
1704{
1705	while (t != NULL && t->getAlign == NULL)
1706		t = t->supertype;
1707	return (t ? t->getAlign : NULL);
1708}
1709
1710