ng_parse.c revision 123600
153913Sarchie
253913Sarchie/*
353913Sarchie * ng_parse.c
453913Sarchie *
553913Sarchie * Copyright (c) 1999 Whistle Communications, Inc.
653913Sarchie * All rights reserved.
753913Sarchie *
853913Sarchie * Subject to the following obligations and disclaimer of warranty, use and
953913Sarchie * redistribution of this software, in source or object code forms, with or
1053913Sarchie * without modifications are expressly permitted by Whistle Communications;
1153913Sarchie * provided, however, that:
1253913Sarchie * 1. Any and all reproductions of the source or object code must include the
1353913Sarchie *    copyright notice above and the following disclaimer of warranties; and
1453913Sarchie * 2. No rights are granted, in any manner or form, to use Whistle
1553913Sarchie *    Communications, Inc. trademarks, including the mark "WHISTLE
1653913Sarchie *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1753913Sarchie *    such appears in the above copyright notice or in the software.
1853913Sarchie *
1953913Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2053913Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2153913Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2253913Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2353913Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2453913Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2553913Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2653913Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2753913Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2853913Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
2953913Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3053913Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3153913Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3253913Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3353913Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3453913Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3553913Sarchie * OF SUCH DAMAGE.
3653913Sarchie *
3767506Sjulian * Author: Archie Cobbs <archie@freebsd.org>
3853913Sarchie *
3953913Sarchie * $Whistle: ng_parse.c,v 1.3 1999/11/29 01:43:48 archie Exp $
4053913Sarchie * $FreeBSD: head/sys/netgraph/ng_parse.c 123600 2003-12-17 12:40:34Z ru $
4153913Sarchie */
4253913Sarchie
4353913Sarchie#include <sys/types.h>
4453913Sarchie#include <sys/param.h>
4553913Sarchie#include <sys/systm.h>
4670870Sjulian#include <sys/kernel.h>
4753913Sarchie#include <sys/errno.h>
4853913Sarchie#include <sys/malloc.h>
4953913Sarchie#include <sys/ctype.h>
5053913Sarchie
51123600Sru#include <net/ethernet.h>
52123600Sru
5353913Sarchie#include <netinet/in.h>
5453913Sarchie
5553913Sarchie#include <netgraph/ng_message.h>
5653913Sarchie#include <netgraph/netgraph.h>
5753913Sarchie#include <netgraph/ng_parse.h>
5853913Sarchie
5970870Sjulian#ifdef NG_SEPARATE_MALLOC
6070870SjulianMALLOC_DEFINE(M_NETGRAPH_PARSE, "netgraph_parse", "netgraph parse info");
6170870Sjulian#else
6270870Sjulian#define M_NETGRAPH_PARSE M_NETGRAPH
6370870Sjulian#endif
6470870Sjulian
6553913Sarchie/* Compute alignment for primitive integral types */
6653913Sarchiestruct int16_temp {
6753913Sarchie	char	x;
6853913Sarchie	int16_t	y;
6953913Sarchie};
7053913Sarchie
7153913Sarchiestruct int32_temp {
7253913Sarchie	char	x;
7353913Sarchie	int32_t	y;
7453913Sarchie};
7553913Sarchie
7653913Sarchiestruct int64_temp {
7753913Sarchie	char	x;
7853913Sarchie	int64_t	y;
7953913Sarchie};
8053913Sarchie
8153913Sarchie#define INT8_ALIGNMENT		1
8253913Sarchie#define INT16_ALIGNMENT		((int)&((struct int16_temp *)0)->y)
8353913Sarchie#define INT32_ALIGNMENT		((int)&((struct int32_temp *)0)->y)
8453913Sarchie#define INT64_ALIGNMENT		((int)&((struct int64_temp *)0)->y)
8553913Sarchie
8664505Sarchie/* Output format for integral types */
8764505Sarchie#define INT_UNSIGNED		0
8864505Sarchie#define INT_SIGNED		1
8964505Sarchie#define INT_HEX			2
9064505Sarchie
9153913Sarchie/* Type of composite object: struct, array, or fixedarray */
9253913Sarchieenum comptype {
9353913Sarchie	CT_STRUCT,
9453913Sarchie	CT_ARRAY,
9553913Sarchie	CT_FIXEDARRAY,
9653913Sarchie};
9753913Sarchie
9853913Sarchie/* Composite types helper functions */
9953913Sarchiestatic int	ng_parse_composite(const struct ng_parse_type *type,
10053913Sarchie			const char *s, int *off, const u_char *start,
10153913Sarchie			u_char *const buf, int *buflen, enum comptype ctype);
10253913Sarchiestatic int	ng_unparse_composite(const struct ng_parse_type *type,
10353913Sarchie			const u_char *data, int *off, char *cbuf, int cbuflen,
10453913Sarchie			enum comptype ctype);
10553913Sarchiestatic int	ng_get_composite_elem_default(const struct ng_parse_type *type,
10653913Sarchie			int index, const u_char *start, u_char *buf,
10753913Sarchie			int *buflen, enum comptype ctype);
10853913Sarchiestatic int	ng_get_composite_len(const struct ng_parse_type *type,
10953913Sarchie			const u_char *start, const u_char *buf,
11053913Sarchie			enum comptype ctype);
11153913Sarchiestatic const	struct ng_parse_type *ng_get_composite_etype(const struct
11253913Sarchie			ng_parse_type *type, int index, enum comptype ctype);
11353913Sarchiestatic int	ng_parse_get_elem_pad(const struct ng_parse_type *type,
11453913Sarchie			int index, enum comptype ctype, int posn);
11553913Sarchie
11653913Sarchie/* Parsing helper functions */
11753913Sarchiestatic int	ng_parse_skip_value(const char *s, int off, int *lenp);
11853913Sarchie
11953913Sarchie/* Poor man's virtual method calls */
12053913Sarchie#define METHOD(t,m)	(ng_get_ ## m ## _method(t))
12153913Sarchie#define INVOKE(t,m)	(*METHOD(t,m))
12253913Sarchie
12353913Sarchiestatic ng_parse_t	*ng_get_parse_method(const struct ng_parse_type *t);
12453913Sarchiestatic ng_unparse_t	*ng_get_unparse_method(const struct ng_parse_type *t);
12553913Sarchiestatic ng_getDefault_t	*ng_get_getDefault_method(const
12653913Sarchie				struct ng_parse_type *t);
12753913Sarchiestatic ng_getAlign_t	*ng_get_getAlign_method(const struct ng_parse_type *t);
12853913Sarchie
12953913Sarchie#define ALIGNMENT(t)	(METHOD(t, getAlign) == NULL ? \
13053913Sarchie				0 : INVOKE(t, getAlign)(t))
13153913Sarchie
13253913Sarchie/* For converting binary to string */
13353913Sarchie#define NG_PARSE_APPEND(fmt, args...)				\
13453913Sarchie		do {						\
13553913Sarchie			int len;				\
13653913Sarchie								\
13753913Sarchie			len = snprintf((cbuf), (cbuflen),	\
13853913Sarchie				fmt , ## args);			\
13953913Sarchie			if (len >= (cbuflen))			\
14053913Sarchie				return (ERANGE);		\
14153913Sarchie			(cbuf) += len;				\
14253913Sarchie			(cbuflen) -= len;			\
14353913Sarchie		} while (0)
14453913Sarchie
14553913Sarchie/************************************************************************
14653913Sarchie			PUBLIC FUNCTIONS
14753913Sarchie ************************************************************************/
14853913Sarchie
14953913Sarchie/*
15053913Sarchie * Convert an ASCII string to binary according to the supplied type descriptor
15153913Sarchie */
15253913Sarchieint
15353913Sarchieng_parse(const struct ng_parse_type *type,
15453913Sarchie	const char *string, int *off, u_char *buf, int *buflen)
15553913Sarchie{
15653913Sarchie	return INVOKE(type, parse)(type, string, off, buf, buf, buflen);
15753913Sarchie}
15853913Sarchie
15953913Sarchie/*
16053913Sarchie * Convert binary to an ASCII string according to the supplied type descriptor
16153913Sarchie */
16253913Sarchieint
16353913Sarchieng_unparse(const struct ng_parse_type *type,
16453913Sarchie	const u_char *data, char *cbuf, int cbuflen)
16553913Sarchie{
16653913Sarchie	int off = 0;
16753913Sarchie
16853913Sarchie	return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen);
16953913Sarchie}
17053913Sarchie
17153913Sarchie/*
17253913Sarchie * Fill in the default value according to the supplied type descriptor
17353913Sarchie */
17453913Sarchieint
17553913Sarchieng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen)
17653913Sarchie{
17753913Sarchie	ng_getDefault_t *const func = METHOD(type, getDefault);
17853913Sarchie
17953913Sarchie	if (func == NULL)
18053913Sarchie		return (EOPNOTSUPP);
18153913Sarchie	return (*func)(type, buf, buf, buflen);
18253913Sarchie}
18353913Sarchie
18453913Sarchie
18553913Sarchie/************************************************************************
18653913Sarchie			STRUCTURE TYPE
18753913Sarchie ************************************************************************/
18853913Sarchie
18953913Sarchiestatic int
19053913Sarchieng_struct_parse(const struct ng_parse_type *type,
19153913Sarchie	const char *s, int *off, const u_char *const start,
19253913Sarchie	u_char *const buf, int *buflen)
19353913Sarchie{
19453913Sarchie	return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT);
19553913Sarchie}
19653913Sarchie
19753913Sarchiestatic int
19853913Sarchieng_struct_unparse(const struct ng_parse_type *type,
19953913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
20053913Sarchie{
20153913Sarchie	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT);
20253913Sarchie}
20353913Sarchie
20453913Sarchiestatic int
20553913Sarchieng_struct_getDefault(const struct ng_parse_type *type,
20653913Sarchie	const u_char *const start, u_char *buf, int *buflen)
20753913Sarchie{
20853913Sarchie	int off = 0;
20953913Sarchie
21053913Sarchie	return ng_parse_composite(type,
21153913Sarchie	    "{}", &off, start, buf, buflen, CT_STRUCT);
21253913Sarchie}
21353913Sarchie
21453913Sarchiestatic int
21553913Sarchieng_struct_getAlign(const struct ng_parse_type *type)
21653913Sarchie{
21753913Sarchie	const struct ng_parse_struct_field *field;
21853913Sarchie	int align = 0;
21953913Sarchie
22097685Sarchie	for (field = type->info; field->name != NULL; field++) {
22153913Sarchie		int falign = ALIGNMENT(field->type);
22253913Sarchie
22353913Sarchie		if (falign > align)
22453913Sarchie			align = falign;
22553913Sarchie	}
22653913Sarchie	return align;
22753913Sarchie}
22853913Sarchie
22953913Sarchieconst struct ng_parse_type ng_parse_struct_type = {
23053913Sarchie	NULL,
23153913Sarchie	NULL,
23253913Sarchie	NULL,
23353913Sarchie	ng_struct_parse,
23453913Sarchie	ng_struct_unparse,
23553913Sarchie	ng_struct_getDefault,
23653913Sarchie	ng_struct_getAlign
23753913Sarchie};
23853913Sarchie
23953913Sarchie/************************************************************************
24053913Sarchie			FIXED LENGTH ARRAY TYPE
24153913Sarchie ************************************************************************/
24253913Sarchie
24353913Sarchiestatic int
24453913Sarchieng_fixedarray_parse(const struct ng_parse_type *type,
24553913Sarchie	const char *s, int *off, const u_char *const start,
24653913Sarchie	u_char *const buf, int *buflen)
24753913Sarchie{
24853913Sarchie	return ng_parse_composite(type,
24953913Sarchie	    s, off, start, buf, buflen, CT_FIXEDARRAY);
25053913Sarchie}
25153913Sarchie
25253913Sarchiestatic int
25353913Sarchieng_fixedarray_unparse(const struct ng_parse_type *type,
25453913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
25553913Sarchie{
25653913Sarchie	return ng_unparse_composite(type,
25753913Sarchie		data, off, cbuf, cbuflen, CT_FIXEDARRAY);
25853913Sarchie}
25953913Sarchie
26053913Sarchiestatic int
26153913Sarchieng_fixedarray_getDefault(const struct ng_parse_type *type,
26253913Sarchie	const u_char *const start, u_char *buf, int *buflen)
26353913Sarchie{
26453913Sarchie	int off = 0;
26553913Sarchie
26653913Sarchie	return ng_parse_composite(type,
26753913Sarchie	    "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
26853913Sarchie}
26953913Sarchie
27053913Sarchiestatic int
27153913Sarchieng_fixedarray_getAlign(const struct ng_parse_type *type)
27253913Sarchie{
27353913Sarchie	const struct ng_parse_fixedarray_info *fi = type->info;
27453913Sarchie
27553913Sarchie	return ALIGNMENT(fi->elementType);
27653913Sarchie}
27753913Sarchie
27853913Sarchieconst struct ng_parse_type ng_parse_fixedarray_type = {
27953913Sarchie	NULL,
28053913Sarchie	NULL,
28153913Sarchie	NULL,
28253913Sarchie	ng_fixedarray_parse,
28353913Sarchie	ng_fixedarray_unparse,
28453913Sarchie	ng_fixedarray_getDefault,
28553913Sarchie	ng_fixedarray_getAlign
28653913Sarchie};
28753913Sarchie
28853913Sarchie/************************************************************************
28953913Sarchie			VARIABLE LENGTH ARRAY TYPE
29053913Sarchie ************************************************************************/
29153913Sarchie
29253913Sarchiestatic int
29353913Sarchieng_array_parse(const struct ng_parse_type *type,
29453913Sarchie	const char *s, int *off, const u_char *const start,
29553913Sarchie	u_char *const buf, int *buflen)
29653913Sarchie{
29753913Sarchie	return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
29853913Sarchie}
29953913Sarchie
30053913Sarchiestatic int
30153913Sarchieng_array_unparse(const struct ng_parse_type *type,
30253913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
30353913Sarchie{
30453913Sarchie	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
30553913Sarchie}
30653913Sarchie
30753913Sarchiestatic int
30853913Sarchieng_array_getDefault(const struct ng_parse_type *type,
30953913Sarchie	const u_char *const start, u_char *buf, int *buflen)
31053913Sarchie{
31153913Sarchie	int off = 0;
31253913Sarchie
31353913Sarchie	return ng_parse_composite(type,
31453913Sarchie	    "[]", &off, start, buf, buflen, CT_ARRAY);
31553913Sarchie}
31653913Sarchie
31753913Sarchiestatic int
31853913Sarchieng_array_getAlign(const struct ng_parse_type *type)
31953913Sarchie{
32053913Sarchie	const struct ng_parse_array_info *ai = type->info;
32153913Sarchie
32253913Sarchie	return ALIGNMENT(ai->elementType);
32353913Sarchie}
32453913Sarchie
32553913Sarchieconst struct ng_parse_type ng_parse_array_type = {
32653913Sarchie	NULL,
32753913Sarchie	NULL,
32853913Sarchie	NULL,
32953913Sarchie	ng_array_parse,
33053913Sarchie	ng_array_unparse,
33153913Sarchie	ng_array_getDefault,
33253913Sarchie	ng_array_getAlign
33353913Sarchie};
33453913Sarchie
33553913Sarchie/************************************************************************
33653913Sarchie				INT8 TYPE
33753913Sarchie ************************************************************************/
33853913Sarchie
33953913Sarchiestatic int
34053913Sarchieng_int8_parse(const struct ng_parse_type *type,
34153913Sarchie	const char *s, int *off, const u_char *const start,
34253913Sarchie	u_char *const buf, int *buflen)
34353913Sarchie{
34453913Sarchie	long val;
34553913Sarchie	int8_t val8;
34653913Sarchie	char *eptr;
34753913Sarchie
34853913Sarchie	val = strtol(s + *off, &eptr, 0);
34976860Sjdp	if (val < (int8_t)0x80 || val > (u_int8_t)0xff || eptr == s + *off)
35053913Sarchie		return (EINVAL);
35153913Sarchie	*off = eptr - s;
35253913Sarchie	val8 = (int8_t)val;
35353913Sarchie	bcopy(&val8, buf, sizeof(int8_t));
35453913Sarchie	*buflen = sizeof(int8_t);
35553913Sarchie	return (0);
35653913Sarchie}
35753913Sarchie
35853913Sarchiestatic int
35953913Sarchieng_int8_unparse(const struct ng_parse_type *type,
36053913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
36153913Sarchie{
36264505Sarchie	const char *fmt;
36364505Sarchie	int fval;
36453913Sarchie	int8_t val;
36553913Sarchie
36653913Sarchie	bcopy(data + *off, &val, sizeof(int8_t));
367106665Sjhb	switch ((intptr_t)type->info) {
36864505Sarchie	case INT_SIGNED:
36964505Sarchie		fmt = "%d";
37064505Sarchie		fval = val;
37164505Sarchie		break;
37264505Sarchie	case INT_UNSIGNED:
37364505Sarchie		fmt = "%u";
37464505Sarchie		fval = (u_int8_t)val;
37564505Sarchie		break;
37664505Sarchie	case INT_HEX:
37764505Sarchie		fmt = "0x%x";
37864505Sarchie		fval = (u_int8_t)val;
37964505Sarchie		break;
38064505Sarchie	default:
38187599Sobrien		panic("%s: unknown type", __func__);
38283366Sjulian#ifdef	RESTARTABLE_PANICS
38383366Sjulian		return(0);
38483366Sjulian#endif
38564505Sarchie	}
38664505Sarchie	NG_PARSE_APPEND(fmt, fval);
38753913Sarchie	*off += sizeof(int8_t);
38853913Sarchie	return (0);
38953913Sarchie}
39053913Sarchie
39153913Sarchiestatic int
39253913Sarchieng_int8_getDefault(const struct ng_parse_type *type,
39353913Sarchie	const u_char *const start, u_char *buf, int *buflen)
39453913Sarchie{
39553913Sarchie	int8_t val;
39653913Sarchie
39753913Sarchie	if (*buflen < sizeof(int8_t))
39853913Sarchie		return (ERANGE);
39953913Sarchie	val = 0;
40053913Sarchie	bcopy(&val, buf, sizeof(int8_t));
40153913Sarchie	*buflen = sizeof(int8_t);
40253913Sarchie	return (0);
40353913Sarchie}
40453913Sarchie
40553913Sarchiestatic int
40653913Sarchieng_int8_getAlign(const struct ng_parse_type *type)
40753913Sarchie{
40853913Sarchie	return INT8_ALIGNMENT;
40953913Sarchie}
41053913Sarchie
41153913Sarchieconst struct ng_parse_type ng_parse_int8_type = {
41253913Sarchie	NULL,
41364505Sarchie	(void *)INT_SIGNED,
41453913Sarchie	NULL,
41553913Sarchie	ng_int8_parse,
41653913Sarchie	ng_int8_unparse,
41753913Sarchie	ng_int8_getDefault,
41853913Sarchie	ng_int8_getAlign
41953913Sarchie};
42053913Sarchie
42164505Sarchieconst struct ng_parse_type ng_parse_uint8_type = {
42264505Sarchie	&ng_parse_int8_type,
42364505Sarchie	(void *)INT_UNSIGNED
42464505Sarchie};
42564505Sarchie
42664505Sarchieconst struct ng_parse_type ng_parse_hint8_type = {
42764505Sarchie	&ng_parse_int8_type,
42864505Sarchie	(void *)INT_HEX
42964505Sarchie};
43064505Sarchie
43153913Sarchie/************************************************************************
43253913Sarchie				INT16 TYPE
43353913Sarchie ************************************************************************/
43453913Sarchie
43553913Sarchiestatic int
43653913Sarchieng_int16_parse(const struct ng_parse_type *type,
43753913Sarchie	const char *s, int *off, const u_char *const start,
43853913Sarchie	u_char *const buf, int *buflen)
43953913Sarchie{
44053913Sarchie	long val;
44153913Sarchie	int16_t val16;
44253913Sarchie	char *eptr;
44353913Sarchie
44453913Sarchie	val = strtol(s + *off, &eptr, 0);
44576860Sjdp	if (val < (int16_t)0x8000
44676860Sjdp	    || val > (u_int16_t)0xffff || eptr == s + *off)
44753913Sarchie		return (EINVAL);
44853913Sarchie	*off = eptr - s;
44953913Sarchie	val16 = (int16_t)val;
45053913Sarchie	bcopy(&val16, buf, sizeof(int16_t));
45153913Sarchie	*buflen = sizeof(int16_t);
45253913Sarchie	return (0);
45353913Sarchie}
45453913Sarchie
45553913Sarchiestatic int
45653913Sarchieng_int16_unparse(const struct ng_parse_type *type,
45753913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
45853913Sarchie{
45964505Sarchie	const char *fmt;
46064505Sarchie	int fval;
46153913Sarchie	int16_t val;
46253913Sarchie
46353913Sarchie	bcopy(data + *off, &val, sizeof(int16_t));
464106665Sjhb	switch ((intptr_t)type->info) {
46564505Sarchie	case INT_SIGNED:
46664505Sarchie		fmt = "%d";
46764505Sarchie		fval = val;
46864505Sarchie		break;
46964505Sarchie	case INT_UNSIGNED:
47064505Sarchie		fmt = "%u";
47164505Sarchie		fval = (u_int16_t)val;
47264505Sarchie		break;
47364505Sarchie	case INT_HEX:
47464505Sarchie		fmt = "0x%x";
47564505Sarchie		fval = (u_int16_t)val;
47664505Sarchie		break;
47764505Sarchie	default:
47887599Sobrien		panic("%s: unknown type", __func__);
47983366Sjulian#ifdef	RESTARTABLE_PANICS
48083366Sjulian		return(0);
48183366Sjulian#endif
48264505Sarchie	}
48364505Sarchie	NG_PARSE_APPEND(fmt, fval);
48453913Sarchie	*off += sizeof(int16_t);
48553913Sarchie	return (0);
48653913Sarchie}
48753913Sarchie
48853913Sarchiestatic int
48953913Sarchieng_int16_getDefault(const struct ng_parse_type *type,
49053913Sarchie	const u_char *const start, u_char *buf, int *buflen)
49153913Sarchie{
49253913Sarchie	int16_t val;
49353913Sarchie
49453913Sarchie	if (*buflen < sizeof(int16_t))
49553913Sarchie		return (ERANGE);
49653913Sarchie	val = 0;
49753913Sarchie	bcopy(&val, buf, sizeof(int16_t));
49853913Sarchie	*buflen = sizeof(int16_t);
49953913Sarchie	return (0);
50053913Sarchie}
50153913Sarchie
50253913Sarchiestatic int
50353913Sarchieng_int16_getAlign(const struct ng_parse_type *type)
50453913Sarchie{
50553913Sarchie	return INT16_ALIGNMENT;
50653913Sarchie}
50753913Sarchie
50853913Sarchieconst struct ng_parse_type ng_parse_int16_type = {
50953913Sarchie	NULL,
51064505Sarchie	(void *)INT_SIGNED,
51153913Sarchie	NULL,
51253913Sarchie	ng_int16_parse,
51353913Sarchie	ng_int16_unparse,
51453913Sarchie	ng_int16_getDefault,
51553913Sarchie	ng_int16_getAlign
51653913Sarchie};
51753913Sarchie
51864505Sarchieconst struct ng_parse_type ng_parse_uint16_type = {
51964505Sarchie	&ng_parse_int16_type,
52064505Sarchie	(void *)INT_UNSIGNED
52164505Sarchie};
52264505Sarchie
52364505Sarchieconst struct ng_parse_type ng_parse_hint16_type = {
52464505Sarchie	&ng_parse_int16_type,
52564505Sarchie	(void *)INT_HEX
52664505Sarchie};
52764505Sarchie
52853913Sarchie/************************************************************************
52953913Sarchie				INT32 TYPE
53053913Sarchie ************************************************************************/
53153913Sarchie
53253913Sarchiestatic int
53353913Sarchieng_int32_parse(const struct ng_parse_type *type,
53453913Sarchie	const char *s, int *off, const u_char *const start,
53553913Sarchie	u_char *const buf, int *buflen)
53653913Sarchie{
53753913Sarchie	long val;			/* assumes long is at least 32 bits */
53853913Sarchie	int32_t val32;
53953913Sarchie	char *eptr;
54053913Sarchie
54153913Sarchie	val = strtol(s + *off, &eptr, 0);
54276860Sjdp	if (val < (int32_t)0x80000000
54376860Sjdp	    || val > (u_int32_t)0xffffffff || eptr == s + *off)
54453913Sarchie		return (EINVAL);
54553913Sarchie	*off = eptr - s;
54653913Sarchie	val32 = (int32_t)val;
54753913Sarchie	bcopy(&val32, buf, sizeof(int32_t));
54853913Sarchie	*buflen = sizeof(int32_t);
54953913Sarchie	return (0);
55053913Sarchie}
55153913Sarchie
55253913Sarchiestatic int
55353913Sarchieng_int32_unparse(const struct ng_parse_type *type,
55453913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
55553913Sarchie{
55664505Sarchie	const char *fmt;
55764505Sarchie	long fval;
55853913Sarchie	int32_t val;
55953913Sarchie
56053913Sarchie	bcopy(data + *off, &val, sizeof(int32_t));
561106665Sjhb	switch ((intptr_t)type->info) {
56264505Sarchie	case INT_SIGNED:
56364505Sarchie		fmt = "%ld";
56464505Sarchie		fval = val;
56564505Sarchie		break;
56664505Sarchie	case INT_UNSIGNED:
56764505Sarchie		fmt = "%lu";
56864505Sarchie		fval = (u_int32_t)val;
56964505Sarchie		break;
57064505Sarchie	case INT_HEX:
57164505Sarchie		fmt = "0x%lx";
57264505Sarchie		fval = (u_int32_t)val;
57364505Sarchie		break;
57464505Sarchie	default:
57587599Sobrien		panic("%s: unknown type", __func__);
57683366Sjulian#ifdef	RESTARTABLE_PANICS
57783366Sjulian		return(0);
57883366Sjulian#endif
57964505Sarchie	}
58064505Sarchie	NG_PARSE_APPEND(fmt, fval);
58153913Sarchie	*off += sizeof(int32_t);
58253913Sarchie	return (0);
58353913Sarchie}
58453913Sarchie
58553913Sarchiestatic int
58653913Sarchieng_int32_getDefault(const struct ng_parse_type *type,
58753913Sarchie	const u_char *const start, u_char *buf, int *buflen)
58853913Sarchie{
58953913Sarchie	int32_t val;
59053913Sarchie
59153913Sarchie	if (*buflen < sizeof(int32_t))
59253913Sarchie		return (ERANGE);
59353913Sarchie	val = 0;
59453913Sarchie	bcopy(&val, buf, sizeof(int32_t));
59553913Sarchie	*buflen = sizeof(int32_t);
59653913Sarchie	return (0);
59753913Sarchie}
59853913Sarchie
59953913Sarchiestatic int
60053913Sarchieng_int32_getAlign(const struct ng_parse_type *type)
60153913Sarchie{
60253913Sarchie	return INT32_ALIGNMENT;
60353913Sarchie}
60453913Sarchie
60553913Sarchieconst struct ng_parse_type ng_parse_int32_type = {
60653913Sarchie	NULL,
60764505Sarchie	(void *)INT_SIGNED,
60853913Sarchie	NULL,
60953913Sarchie	ng_int32_parse,
61053913Sarchie	ng_int32_unparse,
61153913Sarchie	ng_int32_getDefault,
61253913Sarchie	ng_int32_getAlign
61353913Sarchie};
61453913Sarchie
61564505Sarchieconst struct ng_parse_type ng_parse_uint32_type = {
61664505Sarchie	&ng_parse_int32_type,
61764505Sarchie	(void *)INT_UNSIGNED
61864505Sarchie};
61964505Sarchie
62064505Sarchieconst struct ng_parse_type ng_parse_hint32_type = {
62164505Sarchie	&ng_parse_int32_type,
62264505Sarchie	(void *)INT_HEX
62364505Sarchie};
62464505Sarchie
62553913Sarchie/************************************************************************
62653913Sarchie				INT64 TYPE
62753913Sarchie ************************************************************************/
62853913Sarchie
62953913Sarchiestatic int
63053913Sarchieng_int64_parse(const struct ng_parse_type *type,
63153913Sarchie	const char *s, int *off, const u_char *const start,
63253913Sarchie	u_char *const buf, int *buflen)
63353913Sarchie{
63453913Sarchie	quad_t val;
63553913Sarchie	int64_t val64;
63653913Sarchie	char *eptr;
63753913Sarchie
63853913Sarchie	val = strtoq(s + *off, &eptr, 0);
63953913Sarchie	if (eptr == s + *off)
64053913Sarchie		return (EINVAL);
64153913Sarchie	*off = eptr - s;
64253913Sarchie	val64 = (int64_t)val;
64353913Sarchie	bcopy(&val64, buf, sizeof(int64_t));
64453913Sarchie	*buflen = sizeof(int64_t);
64553913Sarchie	return (0);
64653913Sarchie}
64753913Sarchie
64853913Sarchiestatic int
64953913Sarchieng_int64_unparse(const struct ng_parse_type *type,
65053913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
65153913Sarchie{
65264505Sarchie	const char *fmt;
65364505Sarchie	long long fval;
65453913Sarchie	int64_t val;
65553913Sarchie
65653913Sarchie	bcopy(data + *off, &val, sizeof(int64_t));
657106665Sjhb	switch ((intptr_t)type->info) {
65864505Sarchie	case INT_SIGNED:
65964505Sarchie		fmt = "%lld";
66064505Sarchie		fval = val;
66164505Sarchie		break;
66264505Sarchie	case INT_UNSIGNED:
66364505Sarchie		fmt = "%llu";
66464505Sarchie		fval = (u_int64_t)val;
66564505Sarchie		break;
66664505Sarchie	case INT_HEX:
66764505Sarchie		fmt = "0x%llx";
66864505Sarchie		fval = (u_int64_t)val;
66964505Sarchie		break;
67064505Sarchie	default:
67187599Sobrien		panic("%s: unknown type", __func__);
67283366Sjulian#ifdef	RESTARTABLE_PANICS
67383366Sjulian		return(0);
67483366Sjulian#endif
67564505Sarchie	}
67664505Sarchie	NG_PARSE_APPEND(fmt, fval);
67753913Sarchie	*off += sizeof(int64_t);
67853913Sarchie	return (0);
67953913Sarchie}
68053913Sarchie
68153913Sarchiestatic int
68253913Sarchieng_int64_getDefault(const struct ng_parse_type *type,
68353913Sarchie	const u_char *const start, u_char *buf, int *buflen)
68453913Sarchie{
68553913Sarchie	int64_t val;
68653913Sarchie
68753913Sarchie	if (*buflen < sizeof(int64_t))
68853913Sarchie		return (ERANGE);
68953913Sarchie	val = 0;
69053913Sarchie	bcopy(&val, buf, sizeof(int64_t));
69153913Sarchie	*buflen = sizeof(int64_t);
69253913Sarchie	return (0);
69353913Sarchie}
69453913Sarchie
69553913Sarchiestatic int
69653913Sarchieng_int64_getAlign(const struct ng_parse_type *type)
69753913Sarchie{
69853913Sarchie	return INT64_ALIGNMENT;
69953913Sarchie}
70053913Sarchie
70153913Sarchieconst struct ng_parse_type ng_parse_int64_type = {
70253913Sarchie	NULL,
70364505Sarchie	(void *)INT_SIGNED,
70453913Sarchie	NULL,
70553913Sarchie	ng_int64_parse,
70653913Sarchie	ng_int64_unparse,
70753913Sarchie	ng_int64_getDefault,
70853913Sarchie	ng_int64_getAlign
70953913Sarchie};
71053913Sarchie
71164505Sarchieconst struct ng_parse_type ng_parse_uint64_type = {
71264505Sarchie	&ng_parse_int64_type,
71364505Sarchie	(void *)INT_UNSIGNED
71464505Sarchie};
71564505Sarchie
71664505Sarchieconst struct ng_parse_type ng_parse_hint64_type = {
71764505Sarchie	&ng_parse_int64_type,
71864505Sarchie	(void *)INT_HEX
71964505Sarchie};
72064505Sarchie
72153913Sarchie/************************************************************************
72253913Sarchie				STRING TYPE
72353913Sarchie ************************************************************************/
72453913Sarchie
72553913Sarchiestatic int
72653913Sarchieng_string_parse(const struct ng_parse_type *type,
72753913Sarchie	const char *s, int *off, const u_char *const start,
72853913Sarchie	u_char *const buf, int *buflen)
72953913Sarchie{
73053913Sarchie	char *sval;
73153913Sarchie	int len;
73268845Sbrian	int slen;
73353913Sarchie
73468845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
73553913Sarchie		return (EINVAL);
73653913Sarchie	*off += len;
73768845Sbrian	bcopy(sval, buf, slen + 1);
73870870Sjulian	FREE(sval, M_NETGRAPH_PARSE);
73968845Sbrian	*buflen = slen + 1;
74053913Sarchie	return (0);
74153913Sarchie}
74253913Sarchie
74353913Sarchiestatic int
74453913Sarchieng_string_unparse(const struct ng_parse_type *type,
74553913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
74653913Sarchie{
74753913Sarchie	const char *const raw = (const char *)data + *off;
74868845Sbrian	char *const s = ng_encode_string(raw, strlen(raw));
74953913Sarchie
75053913Sarchie	if (s == NULL)
75153913Sarchie		return (ENOMEM);
75253913Sarchie	NG_PARSE_APPEND("%s", s);
75353913Sarchie	*off += strlen(raw) + 1;
75470870Sjulian	FREE(s, M_NETGRAPH_PARSE);
75553913Sarchie	return (0);
75653913Sarchie}
75753913Sarchie
75853913Sarchiestatic int
75953913Sarchieng_string_getDefault(const struct ng_parse_type *type,
76053913Sarchie	const u_char *const start, u_char *buf, int *buflen)
76153913Sarchie{
76253913Sarchie
76353913Sarchie	if (*buflen < 1)
76453913Sarchie		return (ERANGE);
76553913Sarchie	buf[0] = (u_char)'\0';
76653913Sarchie	*buflen = 1;
76753913Sarchie	return (0);
76853913Sarchie}
76953913Sarchie
77053913Sarchieconst struct ng_parse_type ng_parse_string_type = {
77153913Sarchie	NULL,
77253913Sarchie	NULL,
77353913Sarchie	NULL,
77453913Sarchie	ng_string_parse,
77553913Sarchie	ng_string_unparse,
77653913Sarchie	ng_string_getDefault,
77753913Sarchie	NULL
77853913Sarchie};
77953913Sarchie
78053913Sarchie/************************************************************************
78153913Sarchie			FIXED BUFFER STRING TYPE
78253913Sarchie ************************************************************************/
78353913Sarchie
78453913Sarchiestatic int
78553913Sarchieng_fixedstring_parse(const struct ng_parse_type *type,
78653913Sarchie	const char *s, int *off, const u_char *const start,
78753913Sarchie	u_char *const buf, int *buflen)
78853913Sarchie{
78958011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
79053913Sarchie	char *sval;
79153913Sarchie	int len;
79268845Sbrian	int slen;
79353913Sarchie
79468845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
79553913Sarchie		return (EINVAL);
79668845Sbrian	if (slen + 1 > fi->bufSize)
79753913Sarchie		return (E2BIG);
79853913Sarchie	*off += len;
79968845Sbrian	bcopy(sval, buf, slen);
80070870Sjulian	FREE(sval, M_NETGRAPH_PARSE);
80168845Sbrian	bzero(buf + slen, fi->bufSize - slen);
80253913Sarchie	*buflen = fi->bufSize;
80353913Sarchie	return (0);
80453913Sarchie}
80553913Sarchie
80653913Sarchiestatic int
80753913Sarchieng_fixedstring_unparse(const struct ng_parse_type *type,
80853913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
80953913Sarchie{
81058011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
81153913Sarchie	int error, temp = *off;
81253913Sarchie
81353913Sarchie	if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
81453913Sarchie		return (error);
81553913Sarchie	*off += fi->bufSize;
81653913Sarchie	return (0);
81753913Sarchie}
81853913Sarchie
81953913Sarchiestatic int
82053913Sarchieng_fixedstring_getDefault(const struct ng_parse_type *type,
82153913Sarchie	const u_char *const start, u_char *buf, int *buflen)
82253913Sarchie{
82358011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
82453913Sarchie
82553913Sarchie	if (*buflen < fi->bufSize)
82653913Sarchie		return (ERANGE);
82753913Sarchie	bzero(buf, fi->bufSize);
82853913Sarchie	*buflen = fi->bufSize;
82953913Sarchie	return (0);
83053913Sarchie}
83153913Sarchie
83253913Sarchieconst struct ng_parse_type ng_parse_fixedstring_type = {
83353913Sarchie	NULL,
83453913Sarchie	NULL,
83553913Sarchie	NULL,
83653913Sarchie	ng_fixedstring_parse,
83753913Sarchie	ng_fixedstring_unparse,
83853913Sarchie	ng_fixedstring_getDefault,
83953913Sarchie	NULL
84053913Sarchie};
84153913Sarchie
84258011Sarchieconst struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
84353913Sarchie	NG_NODELEN + 1
84453913Sarchie};
84553913Sarchieconst struct ng_parse_type ng_parse_nodebuf_type = {
84653913Sarchie	&ng_parse_fixedstring_type,
84753913Sarchie	&ng_parse_nodebuf_info
84853913Sarchie};
84953913Sarchie
85058011Sarchieconst struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
85153913Sarchie	NG_HOOKLEN + 1
85253913Sarchie};
85353913Sarchieconst struct ng_parse_type ng_parse_hookbuf_type = {
85453913Sarchie	&ng_parse_fixedstring_type,
85553913Sarchie	&ng_parse_hookbuf_info
85653913Sarchie};
85753913Sarchie
85858011Sarchieconst struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
85953913Sarchie	NG_PATHLEN + 1
86053913Sarchie};
86153913Sarchieconst struct ng_parse_type ng_parse_pathbuf_type = {
86253913Sarchie	&ng_parse_fixedstring_type,
86353913Sarchie	&ng_parse_pathbuf_info
86453913Sarchie};
86553913Sarchie
86658011Sarchieconst struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
86753913Sarchie	NG_TYPELEN + 1
86853913Sarchie};
86953913Sarchieconst struct ng_parse_type ng_parse_typebuf_type = {
87053913Sarchie	&ng_parse_fixedstring_type,
87153913Sarchie	&ng_parse_typebuf_info
87253913Sarchie};
87353913Sarchie
87458011Sarchieconst struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
87553913Sarchie	NG_CMDSTRLEN + 1
87653913Sarchie};
87753913Sarchieconst struct ng_parse_type ng_parse_cmdbuf_type = {
87853913Sarchie	&ng_parse_fixedstring_type,
87953913Sarchie	&ng_parse_cmdbuf_info
88053913Sarchie};
88153913Sarchie
88253913Sarchie/************************************************************************
88368845Sbrian			EXPLICITLY SIZED STRING TYPE
88468845Sbrian ************************************************************************/
88568845Sbrian
88668845Sbrianstatic int
88768845Sbrianng_sizedstring_parse(const struct ng_parse_type *type,
88868845Sbrian	const char *s, int *off, const u_char *const start,
88968845Sbrian	u_char *const buf, int *buflen)
89068845Sbrian{
89168845Sbrian	char *sval;
89268845Sbrian	int len;
89368845Sbrian	int slen;
89468845Sbrian
89568845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
89668845Sbrian		return (EINVAL);
89768845Sbrian	if (slen > 0xffff)
89868845Sbrian		return (EINVAL);
89968845Sbrian	*off += len;
90068845Sbrian	*((u_int16_t *)buf) = (u_int16_t)slen;
90168845Sbrian	bcopy(sval, buf + 2, slen);
90270870Sjulian	FREE(sval, M_NETGRAPH_PARSE);
90368845Sbrian	*buflen = 2 + slen;
90468845Sbrian	return (0);
90568845Sbrian}
90668845Sbrian
90768845Sbrianstatic int
90868845Sbrianng_sizedstring_unparse(const struct ng_parse_type *type,
90968845Sbrian	const u_char *data, int *off, char *cbuf, int cbuflen)
91068845Sbrian{
91168845Sbrian	const char *const raw = (const char *)data + *off + 2;
91268845Sbrian	const int slen = *((const u_int16_t *)(data + *off));
91368845Sbrian	char *const s = ng_encode_string(raw, slen);
91468845Sbrian
91568845Sbrian	if (s == NULL)
91668845Sbrian		return (ENOMEM);
91768845Sbrian	NG_PARSE_APPEND("%s", s);
91870870Sjulian	FREE(s, M_NETGRAPH_PARSE);
91968845Sbrian	*off += slen + 2;
92068845Sbrian	return (0);
92168845Sbrian}
92268845Sbrian
92368845Sbrianstatic int
92468845Sbrianng_sizedstring_getDefault(const struct ng_parse_type *type,
92568845Sbrian	const u_char *const start, u_char *buf, int *buflen)
92668845Sbrian{
92768845Sbrian	if (*buflen < 2)
92868845Sbrian		return (ERANGE);
92968845Sbrian	bzero(buf, 2);
93068845Sbrian	*buflen = 2;
93168845Sbrian	return (0);
93268845Sbrian}
93368845Sbrian
93468845Sbrianconst struct ng_parse_type ng_parse_sizedstring_type = {
93568845Sbrian	NULL,
93668845Sbrian	NULL,
93768845Sbrian	NULL,
93868845Sbrian	ng_sizedstring_parse,
93968845Sbrian	ng_sizedstring_unparse,
94068845Sbrian	ng_sizedstring_getDefault,
94168845Sbrian	NULL
94268845Sbrian};
94368845Sbrian
94468845Sbrian/************************************************************************
94553913Sarchie			IP ADDRESS TYPE
94653913Sarchie ************************************************************************/
94753913Sarchie
94853913Sarchiestatic int
94953913Sarchieng_ipaddr_parse(const struct ng_parse_type *type,
95053913Sarchie	const char *s, int *off, const u_char *const start,
95153913Sarchie	u_char *const buf, int *buflen)
95253913Sarchie{
95353913Sarchie	int i, error;
95453913Sarchie
95553913Sarchie	for (i = 0; i < 4; i++) {
95653913Sarchie		if ((error = ng_int8_parse(&ng_parse_int8_type,
95753913Sarchie		    s, off, start, buf + i, buflen)) != 0)
95853913Sarchie			return (error);
95953913Sarchie		if (i < 3 && s[*off] != '.')
96053913Sarchie			return (EINVAL);
96153913Sarchie		(*off)++;
96253913Sarchie	}
96353913Sarchie	*buflen = 4;
96453913Sarchie	return (0);
96553913Sarchie}
96653913Sarchie
96753913Sarchiestatic int
96853913Sarchieng_ipaddr_unparse(const struct ng_parse_type *type,
96953913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
97053913Sarchie{
97153913Sarchie	struct in_addr ip;
97253913Sarchie
97353913Sarchie	bcopy(data + *off, &ip, sizeof(ip));
97453913Sarchie	NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0],
97553913Sarchie	    ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]);
97653913Sarchie	*off += sizeof(ip);
97753913Sarchie	return (0);
97853913Sarchie}
97953913Sarchie
98053913Sarchiestatic int
98153913Sarchieng_ipaddr_getDefault(const struct ng_parse_type *type,
98253913Sarchie	const u_char *const start, u_char *buf, int *buflen)
98353913Sarchie{
98453913Sarchie	struct in_addr ip = { 0 };
98553913Sarchie
98653913Sarchie	if (*buflen < sizeof(ip))
98753913Sarchie		return (ERANGE);
98853913Sarchie	bcopy(&ip, buf, sizeof(ip));
98953913Sarchie	*buflen = sizeof(ip);
99053913Sarchie	return (0);
99153913Sarchie}
99253913Sarchie
99353913Sarchieconst struct ng_parse_type ng_parse_ipaddr_type = {
99453913Sarchie	NULL,
99553913Sarchie	NULL,
99653913Sarchie	NULL,
99753913Sarchie	ng_ipaddr_parse,
99853913Sarchie	ng_ipaddr_unparse,
99953913Sarchie	ng_ipaddr_getDefault,
100053913Sarchie	ng_int32_getAlign
100153913Sarchie};
100253913Sarchie
100353913Sarchie/************************************************************************
1004123600Sru			ETHERNET ADDRESS TYPE
1005123600Sru ************************************************************************/
1006123600Sru
1007123600Srustatic int
1008123600Srung_enaddr_parse(const struct ng_parse_type *type,
1009123600Sru	const char *s, int *const off, const u_char *const start,
1010123600Sru	u_char *const buf, int *const buflen)
1011123600Sru{
1012123600Sru	char *eptr;
1013123600Sru	u_long val;
1014123600Sru	int i;
1015123600Sru
1016123600Sru	if (*buflen < ETHER_ADDR_LEN)
1017123600Sru		return (ERANGE);
1018123600Sru	for (i = 0; i < ETHER_ADDR_LEN; i++) {
1019123600Sru		val = strtoul(s + *off, &eptr, 16);
1020123600Sru		if (val > 0xff || eptr == s + *off)
1021123600Sru			return (EINVAL);
1022123600Sru		buf[i] = (u_char)val;
1023123600Sru		*off = (eptr - s);
1024123600Sru		if (i < ETHER_ADDR_LEN - 1) {
1025123600Sru			if (*eptr != ':')
1026123600Sru				return (EINVAL);
1027123600Sru			(*off)++;
1028123600Sru		}
1029123600Sru	}
1030123600Sru	*buflen = ETHER_ADDR_LEN;
1031123600Sru	return (0);
1032123600Sru}
1033123600Sru
1034123600Srustatic int
1035123600Srung_enaddr_unparse(const struct ng_parse_type *type,
1036123600Sru	const u_char *data, int *off, char *cbuf, int cbuflen)
1037123600Sru{
1038123600Sru	int len;
1039123600Sru
1040123600Sru	len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x",
1041123600Sru	    data[*off], data[*off + 1], data[*off + 2],
1042123600Sru	    data[*off + 3], data[*off + 4], data[*off + 5]);
1043123600Sru	if (len >= cbuflen)
1044123600Sru		return (ERANGE);
1045123600Sru	*off += ETHER_ADDR_LEN;
1046123600Sru	return (0);
1047123600Sru}
1048123600Sru
1049123600Sruconst struct ng_parse_type ng_parse_enaddr_type = {
1050123600Sru	NULL,
1051123600Sru	NULL,
1052123600Sru	NULL,
1053123600Sru	ng_enaddr_parse,
1054123600Sru	ng_enaddr_unparse,
1055123600Sru	NULL,
1056123600Sru	0
1057123600Sru};
1058123600Sru
1059123600Sru/************************************************************************
106053913Sarchie			BYTE ARRAY TYPE
106153913Sarchie ************************************************************************/
106253913Sarchie
106353913Sarchie/* Get the length of a byte array */
106453913Sarchiestatic int
106553913Sarchieng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
106653913Sarchie	const u_char *start, const u_char *buf)
106753913Sarchie{
106853913Sarchie	ng_parse_array_getLength_t *const getLength = type->private;
106953913Sarchie
107053913Sarchie	return (*getLength)(type, start, buf);
107153913Sarchie}
107253913Sarchie
107364505Sarchie/* Byte array element type is hex int8 */
107453913Sarchiestatic const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
107564505Sarchie	&ng_parse_hint8_type,
107653913Sarchie	&ng_parse_bytearray_subtype_getLength,
107753913Sarchie	NULL
107853913Sarchie};
107953913Sarchiestatic const struct ng_parse_type ng_parse_bytearray_subtype = {
108053913Sarchie	&ng_parse_array_type,
108153913Sarchie	&ng_parse_bytearray_subtype_info
108253913Sarchie};
108353913Sarchie
108453913Sarchiestatic int
108553913Sarchieng_bytearray_parse(const struct ng_parse_type *type,
108653913Sarchie	const char *s, int *off, const u_char *const start,
108753913Sarchie	u_char *const buf, int *buflen)
108853913Sarchie{
108953913Sarchie	char *str;
109053913Sarchie	int toklen;
109168845Sbrian	int slen;
109253913Sarchie
109353913Sarchie	/* We accept either an array of bytes or a string constant */
109468845Sbrian	if ((str = ng_get_string_token(s, off, &toklen, &slen)) != NULL) {
109553913Sarchie		ng_parse_array_getLength_t *const getLength = type->info;
109668845Sbrian		int arraylen;
109753913Sarchie
109853913Sarchie		arraylen = (*getLength)(type, start, buf);
109953913Sarchie		if (arraylen > *buflen) {
110070870Sjulian			FREE(str, M_NETGRAPH_PARSE);
110153913Sarchie			return (ERANGE);
110253913Sarchie		}
110353913Sarchie		if (slen > arraylen) {
110470870Sjulian			FREE(str, M_NETGRAPH_PARSE);
110553913Sarchie			return (E2BIG);
110653913Sarchie		}
110753913Sarchie		bcopy(str, buf, slen);
110853913Sarchie		bzero(buf + slen, arraylen - slen);
110970870Sjulian		FREE(str, M_NETGRAPH_PARSE);
111053913Sarchie		*off += toklen;
111153913Sarchie		*buflen = arraylen;
111253913Sarchie		return (0);
111353913Sarchie	} else {
111453913Sarchie		struct ng_parse_type subtype;
111553913Sarchie
111653913Sarchie		subtype = ng_parse_bytearray_subtype;
111753913Sarchie		(const void *)subtype.private = type->info;
111853913Sarchie		return ng_array_parse(&subtype, s, off, start, buf, buflen);
111953913Sarchie	}
112053913Sarchie}
112153913Sarchie
112253913Sarchiestatic int
112353913Sarchieng_bytearray_unparse(const struct ng_parse_type *type,
112453913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
112553913Sarchie{
112653913Sarchie	struct ng_parse_type subtype;
112753913Sarchie
112853913Sarchie	subtype = ng_parse_bytearray_subtype;
112953913Sarchie	(const void *)subtype.private = type->info;
113053913Sarchie	return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
113153913Sarchie}
113253913Sarchie
113353913Sarchiestatic int
113453913Sarchieng_bytearray_getDefault(const struct ng_parse_type *type,
113553913Sarchie	const u_char *const start, u_char *buf, int *buflen)
113653913Sarchie{
113753913Sarchie	struct ng_parse_type subtype;
113853913Sarchie
113953913Sarchie	subtype = ng_parse_bytearray_subtype;
114053913Sarchie	(const void *)subtype.private = type->info;
114153913Sarchie	return ng_array_getDefault(&subtype, start, buf, buflen);
114253913Sarchie}
114353913Sarchie
114453913Sarchieconst struct ng_parse_type ng_parse_bytearray_type = {
114553913Sarchie	NULL,
114653913Sarchie	NULL,
114753913Sarchie	NULL,
114853913Sarchie	ng_bytearray_parse,
114953913Sarchie	ng_bytearray_unparse,
115053913Sarchie	ng_bytearray_getDefault,
115153913Sarchie	NULL
115253913Sarchie};
115353913Sarchie
115453913Sarchie/************************************************************************
115553913Sarchie			STRUCT NG_MESG TYPE
115653913Sarchie ************************************************************************/
115753913Sarchie
115853913Sarchie/* Get msg->header.arglen when "buf" is pointing to msg->data */
115953913Sarchiestatic int
116053913Sarchieng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
116153913Sarchie	const u_char *start, const u_char *buf)
116253913Sarchie{
116353913Sarchie	const struct ng_mesg *msg;
116453913Sarchie
116553913Sarchie	msg = (const struct ng_mesg *)(buf - sizeof(*msg));
116653913Sarchie	return msg->header.arglen;
116753913Sarchie}
116853913Sarchie
116953913Sarchie/* Type for the variable length data portion of a struct ng_mesg */
117053913Sarchiestatic const struct ng_parse_type ng_msg_data_type = {
117153913Sarchie	&ng_parse_bytearray_type,
117253913Sarchie	&ng_parse_ng_mesg_getLength
117353913Sarchie};
117453913Sarchie
117553913Sarchie/* Type for the entire struct ng_mesg header with data section */
117697685Sarchiestatic const struct ng_parse_struct_field ng_parse_ng_mesg_type_fields[]
117797685Sarchie	= NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
117853913Sarchieconst struct ng_parse_type ng_parse_ng_mesg_type = {
117953913Sarchie	&ng_parse_struct_type,
118097685Sarchie	&ng_parse_ng_mesg_type_fields,
118153913Sarchie};
118253913Sarchie
118353913Sarchie/************************************************************************
118453913Sarchie			COMPOSITE HELPER ROUTINES
118553913Sarchie ************************************************************************/
118653913Sarchie
118753913Sarchie/*
118853913Sarchie * Convert a structure or array from ASCII to binary
118953913Sarchie */
119053913Sarchiestatic int
119153913Sarchieng_parse_composite(const struct ng_parse_type *type, const char *s,
119253913Sarchie	int *off, const u_char *const start, u_char *const buf, int *buflen,
119353913Sarchie	const enum comptype ctype)
119453913Sarchie{
119553913Sarchie	const int num = ng_get_composite_len(type, start, buf, ctype);
119653913Sarchie	int nextIndex = 0;		/* next implicit array index */
119753913Sarchie	u_int index;			/* field or element index */
119853913Sarchie	int *foff;			/* field value offsets in string */
119953913Sarchie	int align, len, blen, error = 0;
120053913Sarchie
120153913Sarchie	/* Initialize */
120270870Sjulian	MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO);
120353913Sarchie	if (foff == NULL) {
120453913Sarchie		error = ENOMEM;
120553913Sarchie		goto done;
120653913Sarchie	}
120753913Sarchie
120853913Sarchie	/* Get opening brace/bracket */
120953913Sarchie	if (ng_parse_get_token(s, off, &len)
121053913Sarchie	    != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
121153913Sarchie		error = EINVAL;
121253913Sarchie		goto done;
121353913Sarchie	}
121453913Sarchie	*off += len;
121553913Sarchie
121653913Sarchie	/* Get individual element value positions in the string */
121753913Sarchie	for (;;) {
121853913Sarchie		enum ng_parse_token tok;
121953913Sarchie
122053913Sarchie		/* Check for closing brace/bracket */
122153913Sarchie		tok = ng_parse_get_token(s, off, &len);
122253913Sarchie		if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
122353913Sarchie			*off += len;
122453913Sarchie			break;
122553913Sarchie		}
122653913Sarchie
122753913Sarchie		/* For arrays, the 'name' (ie, index) is optional, so
122853913Sarchie		   distinguish name from values by seeing if the next
122953913Sarchie		   token is an equals sign */
123053913Sarchie		if (ctype != CT_STRUCT) {
123153913Sarchie			int len2, off2;
123253913Sarchie			char *eptr;
123353913Sarchie
123453913Sarchie			/* If an opening brace/bracket, index is implied */
123553913Sarchie			if (tok == T_LBRACE || tok == T_LBRACKET) {
123653913Sarchie				index = nextIndex++;
123753913Sarchie				goto gotIndex;
123853913Sarchie			}
123953913Sarchie
124053913Sarchie			/* Might be an index, might be a value, either way... */
124153913Sarchie			if (tok != T_WORD) {
124253913Sarchie				error = EINVAL;
124353913Sarchie				goto done;
124453913Sarchie			}
124553913Sarchie
124653913Sarchie			/* If no equals sign follows, index is implied */
124753913Sarchie			off2 = *off + len;
124853913Sarchie			if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
124953913Sarchie				index = nextIndex++;
125053913Sarchie				goto gotIndex;
125153913Sarchie			}
125253913Sarchie
125353913Sarchie			/* Index was specified explicitly; parse it */
125453913Sarchie			index = (u_int)strtoul(s + *off, &eptr, 0);
125553913Sarchie			if (index < 0 || eptr - (s + *off) != len) {
125653913Sarchie				error = EINVAL;
125753913Sarchie				goto done;
125853913Sarchie			}
125953913Sarchie			nextIndex = index + 1;
126053913Sarchie			*off += len + len2;
126153913Sarchie		} else {			/* a structure field */
126297685Sarchie			const struct ng_parse_struct_field *const
126397685Sarchie			    fields = type->info;
126453913Sarchie
126553913Sarchie			/* Find the field by name (required) in field list */
126653913Sarchie			if (tok != T_WORD) {
126753913Sarchie				error = EINVAL;
126853913Sarchie				goto done;
126953913Sarchie			}
127053913Sarchie			for (index = 0; index < num; index++) {
127197685Sarchie				const struct ng_parse_struct_field *const
127297685Sarchie				    field = &fields[index];
127397685Sarchie
127453913Sarchie				if (strncmp(&s[*off], field->name, len) == 0
127553913Sarchie				    && field->name[len] == '\0')
127653913Sarchie					break;
127753913Sarchie			}
127853913Sarchie			if (index == num) {
127953913Sarchie				error = ENOENT;
128053913Sarchie				goto done;
128153913Sarchie			}
128253913Sarchie			*off += len;
128353913Sarchie
128453913Sarchie			/* Get equals sign */
128553913Sarchie			if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
128653913Sarchie				error = EINVAL;
128753913Sarchie				goto done;
128853913Sarchie			}
128953913Sarchie			*off += len;
129053913Sarchie		}
129197229SpetergotIndex:
129253913Sarchie
129353913Sarchie		/* Check array index */
129453913Sarchie		if (index >= num) {
129553913Sarchie			error = E2BIG;
129653913Sarchie			goto done;
129753913Sarchie		}
129853913Sarchie
129953913Sarchie		/* Save value's position and skip over it for now */
130053913Sarchie		if (foff[index] != 0) {
130153913Sarchie			error = EALREADY;		/* duplicate */
130253913Sarchie			goto done;
130353913Sarchie		}
130453913Sarchie		while (isspace(s[*off]))
130553913Sarchie			(*off)++;
130653913Sarchie		foff[index] = *off;
130753913Sarchie		if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
130853913Sarchie			goto done;
130953913Sarchie		*off += len;
131053913Sarchie	}
131153913Sarchie
131253913Sarchie	/* Now build binary structure from supplied values and defaults */
131353913Sarchie	for (blen = index = 0; index < num; index++) {
131453913Sarchie		const struct ng_parse_type *const
131553913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
131653913Sarchie		int k, pad, vlen;
131753913Sarchie
131853913Sarchie		/* Zero-pad any alignment bytes */
131953913Sarchie		pad = ng_parse_get_elem_pad(type, index, ctype, blen);
132053913Sarchie		for (k = 0; k < pad; k++) {
132153913Sarchie			if (blen >= *buflen) {
132253913Sarchie				error = ERANGE;
132353913Sarchie				goto done;
132453913Sarchie			}
132553913Sarchie			buf[blen++] = 0;
132653913Sarchie		}
132753913Sarchie
132853913Sarchie		/* Get value */
132953913Sarchie		vlen = *buflen - blen;
133053913Sarchie		if (foff[index] == 0) {		/* use default value */
133153913Sarchie			error = ng_get_composite_elem_default(type, index,
133253913Sarchie			    start, buf + blen, &vlen, ctype);
133353913Sarchie		} else {			/* parse given value */
133453913Sarchie			*off = foff[index];
133553913Sarchie			error = INVOKE(etype, parse)(etype,
133653913Sarchie			    s, off, start, buf + blen, &vlen);
133753913Sarchie		}
133853913Sarchie		if (error != 0)
133953913Sarchie			goto done;
134053913Sarchie		blen += vlen;
134153913Sarchie	}
134253913Sarchie
134353913Sarchie	/* Make total composite structure size a multiple of its alignment */
134453913Sarchie	if ((align = ALIGNMENT(type)) != 0) {
134553913Sarchie		while (blen % align != 0) {
134653913Sarchie			if (blen >= *buflen) {
134753913Sarchie				error = ERANGE;
134853913Sarchie				goto done;
134953913Sarchie			}
135053913Sarchie			buf[blen++] = 0;
135153913Sarchie		}
135253913Sarchie	}
135353913Sarchie
135453913Sarchie	/* Done */
135553913Sarchie	*buflen = blen;
135653913Sarchiedone:
135765303Sarchie	if (foff != NULL)
135870870Sjulian		FREE(foff, M_NETGRAPH_PARSE);
135953913Sarchie	return (error);
136053913Sarchie}
136153913Sarchie
136253913Sarchie/*
136353913Sarchie * Convert an array or structure from binary to ASCII
136453913Sarchie */
136553913Sarchiestatic int
136653913Sarchieng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
136753913Sarchie	int *off, char *cbuf, int cbuflen, const enum comptype ctype)
136853913Sarchie{
136990047Sarchie	const struct ng_mesg *const hdr
137090047Sarchie	    = (const struct ng_mesg *)(data - sizeof(*hdr));
137153913Sarchie	const int num = ng_get_composite_len(type, data, data + *off, ctype);
137264505Sarchie	const int workSize = 20 * 1024;		/* XXX hard coded constant */
137353913Sarchie	int nextIndex = 0, didOne = 0;
137453913Sarchie	int error, index;
137564505Sarchie	u_char *workBuf;
137653913Sarchie
137764505Sarchie	/* Get workspace for checking default values */
137870870Sjulian	MALLOC(workBuf, u_char *, workSize, M_NETGRAPH_PARSE, M_NOWAIT);
137964505Sarchie	if (workBuf == NULL)
138064505Sarchie		return (ENOMEM);
138164505Sarchie
138253913Sarchie	/* Opening brace/bracket */
138353913Sarchie	NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
138453913Sarchie
138553913Sarchie	/* Do each item */
138653913Sarchie	for (index = 0; index < num; index++) {
138753913Sarchie		const struct ng_parse_type *const
138853913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
138953913Sarchie
139053913Sarchie		/* Skip any alignment pad bytes */
139153913Sarchie		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
139253913Sarchie
139390047Sarchie		/*
139490047Sarchie		 * See if element is equal to its default value; skip if so.
139590047Sarchie		 * Copy struct ng_mesg header for types that peek into it.
139690047Sarchie		 */
139790047Sarchie		if (sizeof(*hdr) + *off < workSize) {
139890047Sarchie			int tempsize = workSize - sizeof(*hdr) - *off;
139953913Sarchie
140090584Sarchie			bcopy(hdr, workBuf, sizeof(*hdr) + *off);
140190047Sarchie			if (ng_get_composite_elem_default(type, index, workBuf
140290047Sarchie			      + sizeof(*hdr), workBuf + sizeof(*hdr) + *off,
140390047Sarchie			      &tempsize, ctype) == 0
140490047Sarchie			    && bcmp(workBuf + sizeof(*hdr) + *off,
140564505Sarchie			      data + *off, tempsize) == 0) {
140653913Sarchie				*off += tempsize;
140753913Sarchie				continue;
140853913Sarchie			}
140953913Sarchie		}
141053913Sarchie
141153913Sarchie		/* Print name= */
141253913Sarchie		NG_PARSE_APPEND(" ");
141353913Sarchie		if (ctype != CT_STRUCT) {
141453913Sarchie			if (index != nextIndex) {
141553913Sarchie				nextIndex = index;
141653913Sarchie				NG_PARSE_APPEND("%d=", index);
141753913Sarchie			}
141853913Sarchie			nextIndex++;
141953913Sarchie		} else {
142097685Sarchie			const struct ng_parse_struct_field *const
142197685Sarchie			    fields = type->info;
142253913Sarchie
142397685Sarchie			NG_PARSE_APPEND("%s=", fields[index].name);
142453913Sarchie		}
142553913Sarchie
142653913Sarchie		/* Print value */
142753913Sarchie		if ((error = INVOKE(etype, unparse)
142864505Sarchie		    (etype, data, off, cbuf, cbuflen)) != 0) {
142970870Sjulian			FREE(workBuf, M_NETGRAPH_PARSE);
143053913Sarchie			return (error);
143164505Sarchie		}
143253913Sarchie		cbuflen -= strlen(cbuf);
143353913Sarchie		cbuf += strlen(cbuf);
143453913Sarchie		didOne = 1;
143553913Sarchie	}
143670870Sjulian	FREE(workBuf, M_NETGRAPH_PARSE);
143753913Sarchie
143853913Sarchie	/* Closing brace/bracket */
143953913Sarchie	NG_PARSE_APPEND("%s%c",
144053913Sarchie	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
144153913Sarchie	return (0);
144253913Sarchie}
144353913Sarchie
144453913Sarchie/*
144553913Sarchie * Generate the default value for an element of an array or structure
144653913Sarchie * Returns EOPNOTSUPP if default value is unspecified.
144753913Sarchie */
144853913Sarchiestatic int
144953913Sarchieng_get_composite_elem_default(const struct ng_parse_type *type,
145053913Sarchie	int index, const u_char *const start, u_char *buf, int *buflen,
145153913Sarchie	const enum comptype ctype)
145253913Sarchie{
145353913Sarchie	const struct ng_parse_type *etype;
145453913Sarchie	ng_getDefault_t *func;
145553913Sarchie
145653913Sarchie	switch (ctype) {
145753913Sarchie	case CT_STRUCT:
145853913Sarchie		break;
145953913Sarchie	case CT_ARRAY:
146053913Sarchie	    {
146153913Sarchie		const struct ng_parse_array_info *const ai = type->info;
146253913Sarchie
146353913Sarchie		if (ai->getDefault != NULL) {
146453913Sarchie			return (*ai->getDefault)(type,
146553913Sarchie			    index, start, buf, buflen);
146653913Sarchie		}
146753913Sarchie		break;
146853913Sarchie	    }
146953913Sarchie	case CT_FIXEDARRAY:
147053913Sarchie	    {
147153913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
147253913Sarchie
147353913Sarchie		if (*fi->getDefault != NULL) {
147453913Sarchie			return (*fi->getDefault)(type,
147553913Sarchie			    index, start, buf, buflen);
147653913Sarchie		}
147753913Sarchie		break;
147853913Sarchie	    }
147953913Sarchie	default:
148087599Sobrien	    panic("%s", __func__);
148153913Sarchie	}
148253913Sarchie
148353913Sarchie	/* Default to element type default */
148453913Sarchie	etype = ng_get_composite_etype(type, index, ctype);
148553913Sarchie	func = METHOD(etype, getDefault);
148653913Sarchie	if (func == NULL)
148753913Sarchie		return (EOPNOTSUPP);
148853913Sarchie	return (*func)(etype, start, buf, buflen);
148953913Sarchie}
149053913Sarchie
149153913Sarchie/*
149253913Sarchie * Get the number of elements in a struct, variable or fixed array.
149353913Sarchie */
149453913Sarchiestatic int
149553913Sarchieng_get_composite_len(const struct ng_parse_type *type,
149653913Sarchie	const u_char *const start, const u_char *buf,
149753913Sarchie	const enum comptype ctype)
149853913Sarchie{
149953913Sarchie	switch (ctype) {
150053913Sarchie	case CT_STRUCT:
150153913Sarchie	    {
150297685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
150353913Sarchie		int numFields = 0;
150453913Sarchie
150553913Sarchie		for (numFields = 0; ; numFields++) {
150653913Sarchie			const struct ng_parse_struct_field *const
150797685Sarchie				fi = &fields[numFields];
150853913Sarchie
150953913Sarchie			if (fi->name == NULL)
151053913Sarchie				break;
151153913Sarchie		}
151253913Sarchie		return (numFields);
151353913Sarchie	    }
151453913Sarchie	case CT_ARRAY:
151553913Sarchie	    {
151653913Sarchie		const struct ng_parse_array_info *const ai = type->info;
151753913Sarchie
151853913Sarchie		return (*ai->getLength)(type, start, buf);
151953913Sarchie	    }
152053913Sarchie	case CT_FIXEDARRAY:
152153913Sarchie	    {
152253913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
152353913Sarchie
152453913Sarchie		return fi->length;
152553913Sarchie	    }
152653913Sarchie	default:
152787599Sobrien	    panic("%s", __func__);
152853913Sarchie	}
152953913Sarchie	return (0);
153053913Sarchie}
153153913Sarchie
153253913Sarchie/*
153353913Sarchie * Return the type of the index'th element of a composite structure
153453913Sarchie */
153553913Sarchiestatic const struct ng_parse_type *
153653913Sarchieng_get_composite_etype(const struct ng_parse_type *type,
153753913Sarchie	int index, const enum comptype ctype)
153853913Sarchie{
153953913Sarchie	const struct ng_parse_type *etype = NULL;
154053913Sarchie
154153913Sarchie	switch (ctype) {
154253913Sarchie	case CT_STRUCT:
154353913Sarchie	    {
154497685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
154553913Sarchie
154697685Sarchie		etype = fields[index].type;
154753913Sarchie		break;
154853913Sarchie	    }
154953913Sarchie	case CT_ARRAY:
155053913Sarchie	    {
155153913Sarchie		const struct ng_parse_array_info *const ai = type->info;
155253913Sarchie
155353913Sarchie		etype = ai->elementType;
155453913Sarchie		break;
155553913Sarchie	    }
155653913Sarchie	case CT_FIXEDARRAY:
155753913Sarchie	    {
155853913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
155953913Sarchie
156053913Sarchie		etype = fi->elementType;
156153913Sarchie		break;
156253913Sarchie	    }
156353913Sarchie	default:
156487599Sobrien	    panic("%s", __func__);
156553913Sarchie	}
156653913Sarchie	return (etype);
156753913Sarchie}
156853913Sarchie
156953913Sarchie/*
157053913Sarchie * Get the number of bytes to skip to align for the next
157153913Sarchie * element in a composite structure.
157253913Sarchie */
157353913Sarchiestatic int
157453913Sarchieng_parse_get_elem_pad(const struct ng_parse_type *type,
157553913Sarchie	int index, enum comptype ctype, int posn)
157653913Sarchie{
157753913Sarchie	const struct ng_parse_type *const
157853913Sarchie	    etype = ng_get_composite_etype(type, index, ctype);
157953913Sarchie	int align;
158053913Sarchie
158153913Sarchie	/* Get element's alignment, and possibly override */
158253913Sarchie	align = ALIGNMENT(etype);
158353913Sarchie	if (ctype == CT_STRUCT) {
158497685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
158553913Sarchie
158697685Sarchie		if (fields[index].alignment != 0)
158797685Sarchie			align = fields[index].alignment;
158853913Sarchie	}
158953913Sarchie
159053913Sarchie	/* Return number of bytes to skip to align */
159153913Sarchie	return (align ? (align - (posn % align)) % align : 0);
159253913Sarchie}
159353913Sarchie
159453913Sarchie/************************************************************************
159553913Sarchie			PARSING HELPER ROUTINES
159653913Sarchie ************************************************************************/
159753913Sarchie
159853913Sarchie/*
159953913Sarchie * Skip over a value
160053913Sarchie */
160153913Sarchiestatic int
160253913Sarchieng_parse_skip_value(const char *s, int off0, int *lenp)
160353913Sarchie{
160453913Sarchie	int len, nbracket, nbrace;
160553913Sarchie	int off = off0;
160653913Sarchie
160753913Sarchie	len = nbracket = nbrace = 0;
160853913Sarchie	do {
160953913Sarchie		switch (ng_parse_get_token(s, &off, &len)) {
161053913Sarchie		case T_LBRACKET:
161153913Sarchie			nbracket++;
161253913Sarchie			break;
161353913Sarchie		case T_LBRACE:
161453913Sarchie			nbrace++;
161553913Sarchie			break;
161653913Sarchie		case T_RBRACKET:
161753913Sarchie			if (nbracket-- == 0)
161853913Sarchie				return (EINVAL);
161953913Sarchie			break;
162053913Sarchie		case T_RBRACE:
162153913Sarchie			if (nbrace-- == 0)
162253913Sarchie				return (EINVAL);
162353913Sarchie			break;
162453913Sarchie		case T_EOF:
162553913Sarchie			return (EINVAL);
162653913Sarchie		default:
162753913Sarchie			break;
162853913Sarchie		}
162953913Sarchie		off += len;
163053913Sarchie	} while (nbracket > 0 || nbrace > 0);
163153913Sarchie	*lenp = off - off0;
163253913Sarchie	return (0);
163353913Sarchie}
163453913Sarchie
163553913Sarchie/*
163653913Sarchie * Find the next token in the string, starting at offset *startp.
163753913Sarchie * Returns the token type, with *startp pointing to the first char
163853913Sarchie * and *lenp the length.
163953913Sarchie */
164053913Sarchieenum ng_parse_token
164153913Sarchieng_parse_get_token(const char *s, int *startp, int *lenp)
164253913Sarchie{
164353913Sarchie	char *t;
164453913Sarchie	int i;
164553913Sarchie
164653913Sarchie	while (isspace(s[*startp]))
164753913Sarchie		(*startp)++;
164853913Sarchie	switch (s[*startp]) {
164953913Sarchie	case '\0':
165053913Sarchie		*lenp = 0;
165153913Sarchie		return T_EOF;
165253913Sarchie	case '{':
165353913Sarchie		*lenp = 1;
165453913Sarchie		return T_LBRACE;
165553913Sarchie	case '}':
165653913Sarchie		*lenp = 1;
165753913Sarchie		return T_RBRACE;
165853913Sarchie	case '[':
165953913Sarchie		*lenp = 1;
166053913Sarchie		return T_LBRACKET;
166153913Sarchie	case ']':
166253913Sarchie		*lenp = 1;
166353913Sarchie		return T_RBRACKET;
166453913Sarchie	case '=':
166553913Sarchie		*lenp = 1;
166653913Sarchie		return T_EQUALS;
166753913Sarchie	case '"':
166868845Sbrian		if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
166953913Sarchie			return T_ERROR;
167070870Sjulian		FREE(t, M_NETGRAPH_PARSE);
167153913Sarchie		return T_STRING;
167253913Sarchie	default:
167353913Sarchie		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
167453913Sarchie		    && s[i] != '{' && s[i] != '}' && s[i] != '['
167553913Sarchie		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
167653913Sarchie			;
167753913Sarchie		*lenp = i - *startp;
167853913Sarchie		return T_WORD;
167953913Sarchie	}
168053913Sarchie}
168153913Sarchie
168253913Sarchie/*
168353913Sarchie * Get a string token, which must be enclosed in double quotes.
168453913Sarchie * The normal C backslash escapes are recognized.
168553913Sarchie */
168653913Sarchiechar *
168768845Sbrianng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
168853913Sarchie{
168953913Sarchie	char *cbuf, *p;
169053913Sarchie	int start, off;
169168845Sbrian	int slen;
169253913Sarchie
169353913Sarchie	while (isspace(s[*startp]))
169453913Sarchie		(*startp)++;
169553913Sarchie	start = *startp;
169653913Sarchie	if (s[*startp] != '"')
169753913Sarchie		return (NULL);
169870870Sjulian	MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
169953913Sarchie	if (cbuf == NULL)
170053913Sarchie		return (NULL);
170153913Sarchie	strcpy(cbuf, s + start + 1);
170268845Sbrian	for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
170353913Sarchie		if (*p == '"') {
170453913Sarchie			*p = '\0';
170553913Sarchie			*lenp = off + 1;
170668845Sbrian			if (slenp != NULL)
170768845Sbrian				*slenp = slen;
170853913Sarchie			return (cbuf);
170953913Sarchie		} else if (p[0] == '\\' && p[1] != '\0') {
171053913Sarchie			int x, k;
171153913Sarchie			char *v;
171253913Sarchie
171353913Sarchie			strcpy(p, p + 1);
171453913Sarchie			v = p;
171553913Sarchie			switch (*p) {
171653913Sarchie			case 't':
171753913Sarchie				*v = '\t';
171853913Sarchie				off++;
171953913Sarchie				continue;
172053913Sarchie			case 'n':
172153913Sarchie				*v = '\n';
172253913Sarchie				off++;
172353913Sarchie				continue;
172453913Sarchie			case 'r':
172553913Sarchie				*v = '\r';
172653913Sarchie				off++;
172753913Sarchie				continue;
172853913Sarchie			case 'v':
172953913Sarchie				*v =  '\v';
173053913Sarchie				off++;
173153913Sarchie				continue;
173253913Sarchie			case 'f':
173353913Sarchie				*v =  '\f';
173453913Sarchie				off++;
173553913Sarchie				continue;
173653913Sarchie			case '"':
173753913Sarchie				*v =  '"';
173853913Sarchie				off++;
173953913Sarchie				continue;
174053913Sarchie			case '0': case '1': case '2': case '3':
174153913Sarchie			case '4': case '5': case '6': case '7':
174253913Sarchie				for (x = k = 0;
174353913Sarchie				    k < 3 && *v >= '0' && *v <= '7'; v++) {
174453913Sarchie					x = (x << 3) + (*v - '0');
174553913Sarchie					off++;
174653913Sarchie				}
174753913Sarchie				*--v = (char)x;
174853913Sarchie				break;
174953913Sarchie			case 'x':
175053913Sarchie				for (v++, x = k = 0;
175153913Sarchie				    k < 2 && isxdigit(*v); v++) {
175253913Sarchie					x = (x << 4) + (isdigit(*v) ?
175353913Sarchie					      (*v - '0') :
175453913Sarchie					      (tolower(*v) - 'a' + 10));
175553913Sarchie					off++;
175653913Sarchie				}
175753913Sarchie				*--v = (char)x;
175853913Sarchie				break;
175953913Sarchie			default:
176053913Sarchie				continue;
176153913Sarchie			}
176253913Sarchie			strcpy(p, v);
176353913Sarchie		}
176453913Sarchie	}
176553913Sarchie	return (NULL);		/* no closing quote */
176653913Sarchie}
176753913Sarchie
176853913Sarchie/*
176953913Sarchie * Encode a string so it can be safely put in double quotes.
177068845Sbrian * Caller must free the result. Exactly "slen" characters
177168845Sbrian * are encoded.
177253913Sarchie */
177353913Sarchiechar *
177468845Sbrianng_encode_string(const char *raw, int slen)
177553913Sarchie{
177653913Sarchie	char *cbuf;
177753913Sarchie	int off = 0;
177868845Sbrian	int i;
177953913Sarchie
178070870Sjulian	MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
178153913Sarchie	if (cbuf == NULL)
178253913Sarchie		return (NULL);
178353913Sarchie	cbuf[off++] = '"';
178468845Sbrian	for (i = 0; i < slen; i++, raw++) {
178553913Sarchie		switch (*raw) {
178653913Sarchie		case '\t':
178753913Sarchie			cbuf[off++] = '\\';
178853913Sarchie			cbuf[off++] = 't';
178953913Sarchie			break;
179053913Sarchie		case '\f':
179153913Sarchie			cbuf[off++] = '\\';
179253913Sarchie			cbuf[off++] = 'f';
179353913Sarchie			break;
179453913Sarchie		case '\n':
179553913Sarchie			cbuf[off++] = '\\';
179653913Sarchie			cbuf[off++] = 'n';
179753913Sarchie			break;
179853913Sarchie		case '\r':
179953913Sarchie			cbuf[off++] = '\\';
180053913Sarchie			cbuf[off++] = 'r';
180153913Sarchie			break;
180253913Sarchie		case '\v':
180353913Sarchie			cbuf[off++] = '\\';
180453913Sarchie			cbuf[off++] = 'v';
180553913Sarchie			break;
180653913Sarchie		case '"':
180753913Sarchie		case '\\':
180853913Sarchie			cbuf[off++] = '\\';
180953913Sarchie			cbuf[off++] = *raw;
181053913Sarchie			break;
181153913Sarchie		default:
181253913Sarchie			if (*raw < 0x20 || *raw > 0x7e) {
181353913Sarchie				off += sprintf(cbuf + off,
181453913Sarchie				    "\\x%02x", (u_char)*raw);
181553913Sarchie				break;
181653913Sarchie			}
181753913Sarchie			cbuf[off++] = *raw;
181853913Sarchie			break;
181953913Sarchie		}
182053913Sarchie	}
182153913Sarchie	cbuf[off++] = '"';
182253913Sarchie	cbuf[off] = '\0';
182353913Sarchie	return (cbuf);
182453913Sarchie}
182553913Sarchie
182653913Sarchie/************************************************************************
182753913Sarchie			VIRTUAL METHOD LOOKUP
182853913Sarchie ************************************************************************/
182953913Sarchie
183053913Sarchiestatic ng_parse_t *
183153913Sarchieng_get_parse_method(const struct ng_parse_type *t)
183253913Sarchie{
183353913Sarchie	while (t != NULL && t->parse == NULL)
183453913Sarchie		t = t->supertype;
183553913Sarchie	return (t ? t->parse : NULL);
183653913Sarchie}
183753913Sarchie
183853913Sarchiestatic ng_unparse_t *
183953913Sarchieng_get_unparse_method(const struct ng_parse_type *t)
184053913Sarchie{
184153913Sarchie	while (t != NULL && t->unparse == NULL)
184253913Sarchie		t = t->supertype;
184353913Sarchie	return (t ? t->unparse : NULL);
184453913Sarchie}
184553913Sarchie
184653913Sarchiestatic ng_getDefault_t *
184753913Sarchieng_get_getDefault_method(const struct ng_parse_type *t)
184853913Sarchie{
184953913Sarchie	while (t != NULL && t->getDefault == NULL)
185053913Sarchie		t = t->supertype;
185153913Sarchie	return (t ? t->getDefault : NULL);
185253913Sarchie}
185353913Sarchie
185453913Sarchiestatic ng_getAlign_t *
185553913Sarchieng_get_getAlign_method(const struct ng_parse_type *t)
185653913Sarchie{
185753913Sarchie	while (t != NULL && t->getAlign == NULL)
185853913Sarchie		t = t->supertype;
185953913Sarchie	return (t ? t->getAlign : NULL);
186053913Sarchie}
186153913Sarchie
1862