ng_parse.c revision 87599
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 87599 2001-12-10 08:09:49Z obrien $
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
5153913Sarchie#include <netinet/in.h>
5253913Sarchie
5353913Sarchie#include <netgraph/ng_message.h>
5453913Sarchie#include <netgraph/netgraph.h>
5553913Sarchie#include <netgraph/ng_parse.h>
5653913Sarchie
5770870Sjulian#ifdef NG_SEPARATE_MALLOC
5870870SjulianMALLOC_DEFINE(M_NETGRAPH_PARSE, "netgraph_parse", "netgraph parse info");
5970870Sjulian#else
6070870Sjulian#define M_NETGRAPH_PARSE M_NETGRAPH
6170870Sjulian#endif
6270870Sjulian
6353913Sarchie/* Compute alignment for primitive integral types */
6453913Sarchiestruct int16_temp {
6553913Sarchie	char	x;
6653913Sarchie	int16_t	y;
6753913Sarchie};
6853913Sarchie
6953913Sarchiestruct int32_temp {
7053913Sarchie	char	x;
7153913Sarchie	int32_t	y;
7253913Sarchie};
7353913Sarchie
7453913Sarchiestruct int64_temp {
7553913Sarchie	char	x;
7653913Sarchie	int64_t	y;
7753913Sarchie};
7853913Sarchie
7953913Sarchie#define INT8_ALIGNMENT		1
8053913Sarchie#define INT16_ALIGNMENT		((int)&((struct int16_temp *)0)->y)
8153913Sarchie#define INT32_ALIGNMENT		((int)&((struct int32_temp *)0)->y)
8253913Sarchie#define INT64_ALIGNMENT		((int)&((struct int64_temp *)0)->y)
8353913Sarchie
8464505Sarchie/* Output format for integral types */
8564505Sarchie#define INT_UNSIGNED		0
8664505Sarchie#define INT_SIGNED		1
8764505Sarchie#define INT_HEX			2
8864505Sarchie
8953913Sarchie/* Type of composite object: struct, array, or fixedarray */
9053913Sarchieenum comptype {
9153913Sarchie	CT_STRUCT,
9253913Sarchie	CT_ARRAY,
9353913Sarchie	CT_FIXEDARRAY,
9453913Sarchie};
9553913Sarchie
9653913Sarchie/* Composite types helper functions */
9753913Sarchiestatic int	ng_parse_composite(const struct ng_parse_type *type,
9853913Sarchie			const char *s, int *off, const u_char *start,
9953913Sarchie			u_char *const buf, int *buflen, enum comptype ctype);
10053913Sarchiestatic int	ng_unparse_composite(const struct ng_parse_type *type,
10153913Sarchie			const u_char *data, int *off, char *cbuf, int cbuflen,
10253913Sarchie			enum comptype ctype);
10353913Sarchiestatic int	ng_get_composite_elem_default(const struct ng_parse_type *type,
10453913Sarchie			int index, const u_char *start, u_char *buf,
10553913Sarchie			int *buflen, enum comptype ctype);
10653913Sarchiestatic int	ng_get_composite_len(const struct ng_parse_type *type,
10753913Sarchie			const u_char *start, const u_char *buf,
10853913Sarchie			enum comptype ctype);
10953913Sarchiestatic const	struct ng_parse_type *ng_get_composite_etype(const struct
11053913Sarchie			ng_parse_type *type, int index, enum comptype ctype);
11153913Sarchiestatic int	ng_parse_get_elem_pad(const struct ng_parse_type *type,
11253913Sarchie			int index, enum comptype ctype, int posn);
11353913Sarchie
11453913Sarchie/* Parsing helper functions */
11553913Sarchiestatic int	ng_parse_skip_value(const char *s, int off, int *lenp);
11653913Sarchie
11753913Sarchie/* Poor man's virtual method calls */
11853913Sarchie#define METHOD(t,m)	(ng_get_ ## m ## _method(t))
11953913Sarchie#define INVOKE(t,m)	(*METHOD(t,m))
12053913Sarchie
12153913Sarchiestatic ng_parse_t	*ng_get_parse_method(const struct ng_parse_type *t);
12253913Sarchiestatic ng_unparse_t	*ng_get_unparse_method(const struct ng_parse_type *t);
12353913Sarchiestatic ng_getDefault_t	*ng_get_getDefault_method(const
12453913Sarchie				struct ng_parse_type *t);
12553913Sarchiestatic ng_getAlign_t	*ng_get_getAlign_method(const struct ng_parse_type *t);
12653913Sarchie
12753913Sarchie#define ALIGNMENT(t)	(METHOD(t, getAlign) == NULL ? \
12853913Sarchie				0 : INVOKE(t, getAlign)(t))
12953913Sarchie
13053913Sarchie/* For converting binary to string */
13153913Sarchie#define NG_PARSE_APPEND(fmt, args...)				\
13253913Sarchie		do {						\
13353913Sarchie			int len;				\
13453913Sarchie								\
13553913Sarchie			len = snprintf((cbuf), (cbuflen),	\
13653913Sarchie				fmt , ## args);			\
13753913Sarchie			if (len >= (cbuflen))			\
13853913Sarchie				return (ERANGE);		\
13953913Sarchie			(cbuf) += len;				\
14053913Sarchie			(cbuflen) -= len;			\
14153913Sarchie		} while (0)
14253913Sarchie
14353913Sarchie/************************************************************************
14453913Sarchie			PUBLIC FUNCTIONS
14553913Sarchie ************************************************************************/
14653913Sarchie
14753913Sarchie/*
14853913Sarchie * Convert an ASCII string to binary according to the supplied type descriptor
14953913Sarchie */
15053913Sarchieint
15153913Sarchieng_parse(const struct ng_parse_type *type,
15253913Sarchie	const char *string, int *off, u_char *buf, int *buflen)
15353913Sarchie{
15453913Sarchie	return INVOKE(type, parse)(type, string, off, buf, buf, buflen);
15553913Sarchie}
15653913Sarchie
15753913Sarchie/*
15853913Sarchie * Convert binary to an ASCII string according to the supplied type descriptor
15953913Sarchie */
16053913Sarchieint
16153913Sarchieng_unparse(const struct ng_parse_type *type,
16253913Sarchie	const u_char *data, char *cbuf, int cbuflen)
16353913Sarchie{
16453913Sarchie	int off = 0;
16553913Sarchie
16653913Sarchie	return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen);
16753913Sarchie}
16853913Sarchie
16953913Sarchie/*
17053913Sarchie * Fill in the default value according to the supplied type descriptor
17153913Sarchie */
17253913Sarchieint
17353913Sarchieng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen)
17453913Sarchie{
17553913Sarchie	ng_getDefault_t *const func = METHOD(type, getDefault);
17653913Sarchie
17753913Sarchie	if (func == NULL)
17853913Sarchie		return (EOPNOTSUPP);
17953913Sarchie	return (*func)(type, buf, buf, buflen);
18053913Sarchie}
18153913Sarchie
18253913Sarchie
18353913Sarchie/************************************************************************
18453913Sarchie			STRUCTURE TYPE
18553913Sarchie ************************************************************************/
18653913Sarchie
18753913Sarchiestatic int
18853913Sarchieng_struct_parse(const struct ng_parse_type *type,
18953913Sarchie	const char *s, int *off, const u_char *const start,
19053913Sarchie	u_char *const buf, int *buflen)
19153913Sarchie{
19253913Sarchie	return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT);
19353913Sarchie}
19453913Sarchie
19553913Sarchiestatic int
19653913Sarchieng_struct_unparse(const struct ng_parse_type *type,
19753913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
19853913Sarchie{
19953913Sarchie	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT);
20053913Sarchie}
20153913Sarchie
20253913Sarchiestatic int
20353913Sarchieng_struct_getDefault(const struct ng_parse_type *type,
20453913Sarchie	const u_char *const start, u_char *buf, int *buflen)
20553913Sarchie{
20653913Sarchie	int off = 0;
20753913Sarchie
20853913Sarchie	return ng_parse_composite(type,
20953913Sarchie	    "{}", &off, start, buf, buflen, CT_STRUCT);
21053913Sarchie}
21153913Sarchie
21253913Sarchiestatic int
21353913Sarchieng_struct_getAlign(const struct ng_parse_type *type)
21453913Sarchie{
21553913Sarchie	const struct ng_parse_struct_info *si = type->info;
21653913Sarchie	const struct ng_parse_struct_field *field;
21753913Sarchie	int align = 0;
21853913Sarchie
21953913Sarchie	for (field = si->fields; field->name != NULL; field++) {
22053913Sarchie		int falign = ALIGNMENT(field->type);
22153913Sarchie
22253913Sarchie		if (falign > align)
22353913Sarchie			align = falign;
22453913Sarchie	}
22553913Sarchie	return align;
22653913Sarchie}
22753913Sarchie
22853913Sarchieconst struct ng_parse_type ng_parse_struct_type = {
22953913Sarchie	NULL,
23053913Sarchie	NULL,
23153913Sarchie	NULL,
23253913Sarchie	ng_struct_parse,
23353913Sarchie	ng_struct_unparse,
23453913Sarchie	ng_struct_getDefault,
23553913Sarchie	ng_struct_getAlign
23653913Sarchie};
23753913Sarchie
23853913Sarchie/************************************************************************
23953913Sarchie			FIXED LENGTH ARRAY TYPE
24053913Sarchie ************************************************************************/
24153913Sarchie
24253913Sarchiestatic int
24353913Sarchieng_fixedarray_parse(const struct ng_parse_type *type,
24453913Sarchie	const char *s, int *off, const u_char *const start,
24553913Sarchie	u_char *const buf, int *buflen)
24653913Sarchie{
24753913Sarchie	return ng_parse_composite(type,
24853913Sarchie	    s, off, start, buf, buflen, CT_FIXEDARRAY);
24953913Sarchie}
25053913Sarchie
25153913Sarchiestatic int
25253913Sarchieng_fixedarray_unparse(const struct ng_parse_type *type,
25353913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
25453913Sarchie{
25553913Sarchie	return ng_unparse_composite(type,
25653913Sarchie		data, off, cbuf, cbuflen, CT_FIXEDARRAY);
25753913Sarchie}
25853913Sarchie
25953913Sarchiestatic int
26053913Sarchieng_fixedarray_getDefault(const struct ng_parse_type *type,
26153913Sarchie	const u_char *const start, u_char *buf, int *buflen)
26253913Sarchie{
26353913Sarchie	int off = 0;
26453913Sarchie
26553913Sarchie	return ng_parse_composite(type,
26653913Sarchie	    "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
26753913Sarchie}
26853913Sarchie
26953913Sarchiestatic int
27053913Sarchieng_fixedarray_getAlign(const struct ng_parse_type *type)
27153913Sarchie{
27253913Sarchie	const struct ng_parse_fixedarray_info *fi = type->info;
27353913Sarchie
27453913Sarchie	return ALIGNMENT(fi->elementType);
27553913Sarchie}
27653913Sarchie
27753913Sarchieconst struct ng_parse_type ng_parse_fixedarray_type = {
27853913Sarchie	NULL,
27953913Sarchie	NULL,
28053913Sarchie	NULL,
28153913Sarchie	ng_fixedarray_parse,
28253913Sarchie	ng_fixedarray_unparse,
28353913Sarchie	ng_fixedarray_getDefault,
28453913Sarchie	ng_fixedarray_getAlign
28553913Sarchie};
28653913Sarchie
28753913Sarchie/************************************************************************
28853913Sarchie			VARIABLE LENGTH ARRAY TYPE
28953913Sarchie ************************************************************************/
29053913Sarchie
29153913Sarchiestatic int
29253913Sarchieng_array_parse(const struct ng_parse_type *type,
29353913Sarchie	const char *s, int *off, const u_char *const start,
29453913Sarchie	u_char *const buf, int *buflen)
29553913Sarchie{
29653913Sarchie	return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
29753913Sarchie}
29853913Sarchie
29953913Sarchiestatic int
30053913Sarchieng_array_unparse(const struct ng_parse_type *type,
30153913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
30253913Sarchie{
30353913Sarchie	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
30453913Sarchie}
30553913Sarchie
30653913Sarchiestatic int
30753913Sarchieng_array_getDefault(const struct ng_parse_type *type,
30853913Sarchie	const u_char *const start, u_char *buf, int *buflen)
30953913Sarchie{
31053913Sarchie	int off = 0;
31153913Sarchie
31253913Sarchie	return ng_parse_composite(type,
31353913Sarchie	    "[]", &off, start, buf, buflen, CT_ARRAY);
31453913Sarchie}
31553913Sarchie
31653913Sarchiestatic int
31753913Sarchieng_array_getAlign(const struct ng_parse_type *type)
31853913Sarchie{
31953913Sarchie	const struct ng_parse_array_info *ai = type->info;
32053913Sarchie
32153913Sarchie	return ALIGNMENT(ai->elementType);
32253913Sarchie}
32353913Sarchie
32453913Sarchieconst struct ng_parse_type ng_parse_array_type = {
32553913Sarchie	NULL,
32653913Sarchie	NULL,
32753913Sarchie	NULL,
32853913Sarchie	ng_array_parse,
32953913Sarchie	ng_array_unparse,
33053913Sarchie	ng_array_getDefault,
33153913Sarchie	ng_array_getAlign
33253913Sarchie};
33353913Sarchie
33453913Sarchie/************************************************************************
33553913Sarchie				INT8 TYPE
33653913Sarchie ************************************************************************/
33753913Sarchie
33853913Sarchiestatic int
33953913Sarchieng_int8_parse(const struct ng_parse_type *type,
34053913Sarchie	const char *s, int *off, const u_char *const start,
34153913Sarchie	u_char *const buf, int *buflen)
34253913Sarchie{
34353913Sarchie	long val;
34453913Sarchie	int8_t val8;
34553913Sarchie	char *eptr;
34653913Sarchie
34753913Sarchie	val = strtol(s + *off, &eptr, 0);
34876860Sjdp	if (val < (int8_t)0x80 || val > (u_int8_t)0xff || eptr == s + *off)
34953913Sarchie		return (EINVAL);
35053913Sarchie	*off = eptr - s;
35153913Sarchie	val8 = (int8_t)val;
35253913Sarchie	bcopy(&val8, buf, sizeof(int8_t));
35353913Sarchie	*buflen = sizeof(int8_t);
35453913Sarchie	return (0);
35553913Sarchie}
35653913Sarchie
35753913Sarchiestatic int
35853913Sarchieng_int8_unparse(const struct ng_parse_type *type,
35953913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
36053913Sarchie{
36164505Sarchie	const char *fmt;
36264505Sarchie	int fval;
36353913Sarchie	int8_t val;
36453913Sarchie
36553913Sarchie	bcopy(data + *off, &val, sizeof(int8_t));
36664505Sarchie	switch ((int)type->info) {
36764505Sarchie	case INT_SIGNED:
36864505Sarchie		fmt = "%d";
36964505Sarchie		fval = val;
37064505Sarchie		break;
37164505Sarchie	case INT_UNSIGNED:
37264505Sarchie		fmt = "%u";
37364505Sarchie		fval = (u_int8_t)val;
37464505Sarchie		break;
37564505Sarchie	case INT_HEX:
37664505Sarchie		fmt = "0x%x";
37764505Sarchie		fval = (u_int8_t)val;
37864505Sarchie		break;
37964505Sarchie	default:
38087599Sobrien		panic("%s: unknown type", __func__);
38183366Sjulian#ifdef	RESTARTABLE_PANICS
38283366Sjulian		return(0);
38383366Sjulian#endif
38464505Sarchie	}
38564505Sarchie	NG_PARSE_APPEND(fmt, fval);
38653913Sarchie	*off += sizeof(int8_t);
38753913Sarchie	return (0);
38853913Sarchie}
38953913Sarchie
39053913Sarchiestatic int
39153913Sarchieng_int8_getDefault(const struct ng_parse_type *type,
39253913Sarchie	const u_char *const start, u_char *buf, int *buflen)
39353913Sarchie{
39453913Sarchie	int8_t val;
39553913Sarchie
39653913Sarchie	if (*buflen < sizeof(int8_t))
39753913Sarchie		return (ERANGE);
39853913Sarchie	val = 0;
39953913Sarchie	bcopy(&val, buf, sizeof(int8_t));
40053913Sarchie	*buflen = sizeof(int8_t);
40153913Sarchie	return (0);
40253913Sarchie}
40353913Sarchie
40453913Sarchiestatic int
40553913Sarchieng_int8_getAlign(const struct ng_parse_type *type)
40653913Sarchie{
40753913Sarchie	return INT8_ALIGNMENT;
40853913Sarchie}
40953913Sarchie
41053913Sarchieconst struct ng_parse_type ng_parse_int8_type = {
41153913Sarchie	NULL,
41264505Sarchie	(void *)INT_SIGNED,
41353913Sarchie	NULL,
41453913Sarchie	ng_int8_parse,
41553913Sarchie	ng_int8_unparse,
41653913Sarchie	ng_int8_getDefault,
41753913Sarchie	ng_int8_getAlign
41853913Sarchie};
41953913Sarchie
42064505Sarchieconst struct ng_parse_type ng_parse_uint8_type = {
42164505Sarchie	&ng_parse_int8_type,
42264505Sarchie	(void *)INT_UNSIGNED
42364505Sarchie};
42464505Sarchie
42564505Sarchieconst struct ng_parse_type ng_parse_hint8_type = {
42664505Sarchie	&ng_parse_int8_type,
42764505Sarchie	(void *)INT_HEX
42864505Sarchie};
42964505Sarchie
43053913Sarchie/************************************************************************
43153913Sarchie				INT16 TYPE
43253913Sarchie ************************************************************************/
43353913Sarchie
43453913Sarchiestatic int
43553913Sarchieng_int16_parse(const struct ng_parse_type *type,
43653913Sarchie	const char *s, int *off, const u_char *const start,
43753913Sarchie	u_char *const buf, int *buflen)
43853913Sarchie{
43953913Sarchie	long val;
44053913Sarchie	int16_t val16;
44153913Sarchie	char *eptr;
44253913Sarchie
44353913Sarchie	val = strtol(s + *off, &eptr, 0);
44476860Sjdp	if (val < (int16_t)0x8000
44576860Sjdp	    || val > (u_int16_t)0xffff || eptr == s + *off)
44653913Sarchie		return (EINVAL);
44753913Sarchie	*off = eptr - s;
44853913Sarchie	val16 = (int16_t)val;
44953913Sarchie	bcopy(&val16, buf, sizeof(int16_t));
45053913Sarchie	*buflen = sizeof(int16_t);
45153913Sarchie	return (0);
45253913Sarchie}
45353913Sarchie
45453913Sarchiestatic int
45553913Sarchieng_int16_unparse(const struct ng_parse_type *type,
45653913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
45753913Sarchie{
45864505Sarchie	const char *fmt;
45964505Sarchie	int fval;
46053913Sarchie	int16_t val;
46153913Sarchie
46253913Sarchie	bcopy(data + *off, &val, sizeof(int16_t));
46364505Sarchie	switch ((int)type->info) {
46464505Sarchie	case INT_SIGNED:
46564505Sarchie		fmt = "%d";
46664505Sarchie		fval = val;
46764505Sarchie		break;
46864505Sarchie	case INT_UNSIGNED:
46964505Sarchie		fmt = "%u";
47064505Sarchie		fval = (u_int16_t)val;
47164505Sarchie		break;
47264505Sarchie	case INT_HEX:
47364505Sarchie		fmt = "0x%x";
47464505Sarchie		fval = (u_int16_t)val;
47564505Sarchie		break;
47664505Sarchie	default:
47787599Sobrien		panic("%s: unknown type", __func__);
47883366Sjulian#ifdef	RESTARTABLE_PANICS
47983366Sjulian		return(0);
48083366Sjulian#endif
48164505Sarchie	}
48264505Sarchie	NG_PARSE_APPEND(fmt, fval);
48353913Sarchie	*off += sizeof(int16_t);
48453913Sarchie	return (0);
48553913Sarchie}
48653913Sarchie
48753913Sarchiestatic int
48853913Sarchieng_int16_getDefault(const struct ng_parse_type *type,
48953913Sarchie	const u_char *const start, u_char *buf, int *buflen)
49053913Sarchie{
49153913Sarchie	int16_t val;
49253913Sarchie
49353913Sarchie	if (*buflen < sizeof(int16_t))
49453913Sarchie		return (ERANGE);
49553913Sarchie	val = 0;
49653913Sarchie	bcopy(&val, buf, sizeof(int16_t));
49753913Sarchie	*buflen = sizeof(int16_t);
49853913Sarchie	return (0);
49953913Sarchie}
50053913Sarchie
50153913Sarchiestatic int
50253913Sarchieng_int16_getAlign(const struct ng_parse_type *type)
50353913Sarchie{
50453913Sarchie	return INT16_ALIGNMENT;
50553913Sarchie}
50653913Sarchie
50753913Sarchieconst struct ng_parse_type ng_parse_int16_type = {
50853913Sarchie	NULL,
50964505Sarchie	(void *)INT_SIGNED,
51053913Sarchie	NULL,
51153913Sarchie	ng_int16_parse,
51253913Sarchie	ng_int16_unparse,
51353913Sarchie	ng_int16_getDefault,
51453913Sarchie	ng_int16_getAlign
51553913Sarchie};
51653913Sarchie
51764505Sarchieconst struct ng_parse_type ng_parse_uint16_type = {
51864505Sarchie	&ng_parse_int16_type,
51964505Sarchie	(void *)INT_UNSIGNED
52064505Sarchie};
52164505Sarchie
52264505Sarchieconst struct ng_parse_type ng_parse_hint16_type = {
52364505Sarchie	&ng_parse_int16_type,
52464505Sarchie	(void *)INT_HEX
52564505Sarchie};
52664505Sarchie
52753913Sarchie/************************************************************************
52853913Sarchie				INT32 TYPE
52953913Sarchie ************************************************************************/
53053913Sarchie
53153913Sarchiestatic int
53253913Sarchieng_int32_parse(const struct ng_parse_type *type,
53353913Sarchie	const char *s, int *off, const u_char *const start,
53453913Sarchie	u_char *const buf, int *buflen)
53553913Sarchie{
53653913Sarchie	long val;			/* assumes long is at least 32 bits */
53753913Sarchie	int32_t val32;
53853913Sarchie	char *eptr;
53953913Sarchie
54053913Sarchie	val = strtol(s + *off, &eptr, 0);
54176860Sjdp	if (val < (int32_t)0x80000000
54276860Sjdp	    || val > (u_int32_t)0xffffffff || eptr == s + *off)
54353913Sarchie		return (EINVAL);
54453913Sarchie	*off = eptr - s;
54553913Sarchie	val32 = (int32_t)val;
54653913Sarchie	bcopy(&val32, buf, sizeof(int32_t));
54753913Sarchie	*buflen = sizeof(int32_t);
54853913Sarchie	return (0);
54953913Sarchie}
55053913Sarchie
55153913Sarchiestatic int
55253913Sarchieng_int32_unparse(const struct ng_parse_type *type,
55353913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
55453913Sarchie{
55564505Sarchie	const char *fmt;
55664505Sarchie	long fval;
55753913Sarchie	int32_t val;
55853913Sarchie
55953913Sarchie	bcopy(data + *off, &val, sizeof(int32_t));
56064505Sarchie	switch ((int)type->info) {
56164505Sarchie	case INT_SIGNED:
56264505Sarchie		fmt = "%ld";
56364505Sarchie		fval = val;
56464505Sarchie		break;
56564505Sarchie	case INT_UNSIGNED:
56664505Sarchie		fmt = "%lu";
56764505Sarchie		fval = (u_int32_t)val;
56864505Sarchie		break;
56964505Sarchie	case INT_HEX:
57064505Sarchie		fmt = "0x%lx";
57164505Sarchie		fval = (u_int32_t)val;
57264505Sarchie		break;
57364505Sarchie	default:
57487599Sobrien		panic("%s: unknown type", __func__);
57583366Sjulian#ifdef	RESTARTABLE_PANICS
57683366Sjulian		return(0);
57783366Sjulian#endif
57864505Sarchie	}
57964505Sarchie	NG_PARSE_APPEND(fmt, fval);
58053913Sarchie	*off += sizeof(int32_t);
58153913Sarchie	return (0);
58253913Sarchie}
58353913Sarchie
58453913Sarchiestatic int
58553913Sarchieng_int32_getDefault(const struct ng_parse_type *type,
58653913Sarchie	const u_char *const start, u_char *buf, int *buflen)
58753913Sarchie{
58853913Sarchie	int32_t val;
58953913Sarchie
59053913Sarchie	if (*buflen < sizeof(int32_t))
59153913Sarchie		return (ERANGE);
59253913Sarchie	val = 0;
59353913Sarchie	bcopy(&val, buf, sizeof(int32_t));
59453913Sarchie	*buflen = sizeof(int32_t);
59553913Sarchie	return (0);
59653913Sarchie}
59753913Sarchie
59853913Sarchiestatic int
59953913Sarchieng_int32_getAlign(const struct ng_parse_type *type)
60053913Sarchie{
60153913Sarchie	return INT32_ALIGNMENT;
60253913Sarchie}
60353913Sarchie
60453913Sarchieconst struct ng_parse_type ng_parse_int32_type = {
60553913Sarchie	NULL,
60664505Sarchie	(void *)INT_SIGNED,
60753913Sarchie	NULL,
60853913Sarchie	ng_int32_parse,
60953913Sarchie	ng_int32_unparse,
61053913Sarchie	ng_int32_getDefault,
61153913Sarchie	ng_int32_getAlign
61253913Sarchie};
61353913Sarchie
61464505Sarchieconst struct ng_parse_type ng_parse_uint32_type = {
61564505Sarchie	&ng_parse_int32_type,
61664505Sarchie	(void *)INT_UNSIGNED
61764505Sarchie};
61864505Sarchie
61964505Sarchieconst struct ng_parse_type ng_parse_hint32_type = {
62064505Sarchie	&ng_parse_int32_type,
62164505Sarchie	(void *)INT_HEX
62264505Sarchie};
62364505Sarchie
62453913Sarchie/************************************************************************
62553913Sarchie				INT64 TYPE
62653913Sarchie ************************************************************************/
62753913Sarchie
62853913Sarchiestatic int
62953913Sarchieng_int64_parse(const struct ng_parse_type *type,
63053913Sarchie	const char *s, int *off, const u_char *const start,
63153913Sarchie	u_char *const buf, int *buflen)
63253913Sarchie{
63353913Sarchie	quad_t val;
63453913Sarchie	int64_t val64;
63553913Sarchie	char *eptr;
63653913Sarchie
63753913Sarchie	val = strtoq(s + *off, &eptr, 0);
63853913Sarchie	if (eptr == s + *off)
63953913Sarchie		return (EINVAL);
64053913Sarchie	*off = eptr - s;
64153913Sarchie	val64 = (int64_t)val;
64253913Sarchie	bcopy(&val64, buf, sizeof(int64_t));
64353913Sarchie	*buflen = sizeof(int64_t);
64453913Sarchie	return (0);
64553913Sarchie}
64653913Sarchie
64753913Sarchiestatic int
64853913Sarchieng_int64_unparse(const struct ng_parse_type *type,
64953913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
65053913Sarchie{
65164505Sarchie	const char *fmt;
65264505Sarchie	long long fval;
65353913Sarchie	int64_t val;
65453913Sarchie
65553913Sarchie	bcopy(data + *off, &val, sizeof(int64_t));
65664505Sarchie	switch ((int)type->info) {
65764505Sarchie	case INT_SIGNED:
65864505Sarchie		fmt = "%lld";
65964505Sarchie		fval = val;
66064505Sarchie		break;
66164505Sarchie	case INT_UNSIGNED:
66264505Sarchie		fmt = "%llu";
66364505Sarchie		fval = (u_int64_t)val;
66464505Sarchie		break;
66564505Sarchie	case INT_HEX:
66664505Sarchie		fmt = "0x%llx";
66764505Sarchie		fval = (u_int64_t)val;
66864505Sarchie		break;
66964505Sarchie	default:
67087599Sobrien		panic("%s: unknown type", __func__);
67183366Sjulian#ifdef	RESTARTABLE_PANICS
67283366Sjulian		return(0);
67383366Sjulian#endif
67464505Sarchie	}
67564505Sarchie	NG_PARSE_APPEND(fmt, fval);
67653913Sarchie	*off += sizeof(int64_t);
67753913Sarchie	return (0);
67853913Sarchie}
67953913Sarchie
68053913Sarchiestatic int
68153913Sarchieng_int64_getDefault(const struct ng_parse_type *type,
68253913Sarchie	const u_char *const start, u_char *buf, int *buflen)
68353913Sarchie{
68453913Sarchie	int64_t val;
68553913Sarchie
68653913Sarchie	if (*buflen < sizeof(int64_t))
68753913Sarchie		return (ERANGE);
68853913Sarchie	val = 0;
68953913Sarchie	bcopy(&val, buf, sizeof(int64_t));
69053913Sarchie	*buflen = sizeof(int64_t);
69153913Sarchie	return (0);
69253913Sarchie}
69353913Sarchie
69453913Sarchiestatic int
69553913Sarchieng_int64_getAlign(const struct ng_parse_type *type)
69653913Sarchie{
69753913Sarchie	return INT64_ALIGNMENT;
69853913Sarchie}
69953913Sarchie
70053913Sarchieconst struct ng_parse_type ng_parse_int64_type = {
70153913Sarchie	NULL,
70264505Sarchie	(void *)INT_SIGNED,
70353913Sarchie	NULL,
70453913Sarchie	ng_int64_parse,
70553913Sarchie	ng_int64_unparse,
70653913Sarchie	ng_int64_getDefault,
70753913Sarchie	ng_int64_getAlign
70853913Sarchie};
70953913Sarchie
71064505Sarchieconst struct ng_parse_type ng_parse_uint64_type = {
71164505Sarchie	&ng_parse_int64_type,
71264505Sarchie	(void *)INT_UNSIGNED
71364505Sarchie};
71464505Sarchie
71564505Sarchieconst struct ng_parse_type ng_parse_hint64_type = {
71664505Sarchie	&ng_parse_int64_type,
71764505Sarchie	(void *)INT_HEX
71864505Sarchie};
71964505Sarchie
72053913Sarchie/************************************************************************
72153913Sarchie				STRING TYPE
72253913Sarchie ************************************************************************/
72353913Sarchie
72453913Sarchiestatic int
72553913Sarchieng_string_parse(const struct ng_parse_type *type,
72653913Sarchie	const char *s, int *off, const u_char *const start,
72753913Sarchie	u_char *const buf, int *buflen)
72853913Sarchie{
72953913Sarchie	char *sval;
73053913Sarchie	int len;
73168845Sbrian	int slen;
73253913Sarchie
73368845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
73453913Sarchie		return (EINVAL);
73553913Sarchie	*off += len;
73668845Sbrian	bcopy(sval, buf, slen + 1);
73770870Sjulian	FREE(sval, M_NETGRAPH_PARSE);
73868845Sbrian	*buflen = slen + 1;
73953913Sarchie	return (0);
74053913Sarchie}
74153913Sarchie
74253913Sarchiestatic int
74353913Sarchieng_string_unparse(const struct ng_parse_type *type,
74453913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
74553913Sarchie{
74653913Sarchie	const char *const raw = (const char *)data + *off;
74768845Sbrian	char *const s = ng_encode_string(raw, strlen(raw));
74853913Sarchie
74953913Sarchie	if (s == NULL)
75053913Sarchie		return (ENOMEM);
75153913Sarchie	NG_PARSE_APPEND("%s", s);
75253913Sarchie	*off += strlen(raw) + 1;
75370870Sjulian	FREE(s, M_NETGRAPH_PARSE);
75453913Sarchie	return (0);
75553913Sarchie}
75653913Sarchie
75753913Sarchiestatic int
75853913Sarchieng_string_getDefault(const struct ng_parse_type *type,
75953913Sarchie	const u_char *const start, u_char *buf, int *buflen)
76053913Sarchie{
76153913Sarchie
76253913Sarchie	if (*buflen < 1)
76353913Sarchie		return (ERANGE);
76453913Sarchie	buf[0] = (u_char)'\0';
76553913Sarchie	*buflen = 1;
76653913Sarchie	return (0);
76753913Sarchie}
76853913Sarchie
76953913Sarchieconst struct ng_parse_type ng_parse_string_type = {
77053913Sarchie	NULL,
77153913Sarchie	NULL,
77253913Sarchie	NULL,
77353913Sarchie	ng_string_parse,
77453913Sarchie	ng_string_unparse,
77553913Sarchie	ng_string_getDefault,
77653913Sarchie	NULL
77753913Sarchie};
77853913Sarchie
77953913Sarchie/************************************************************************
78053913Sarchie			FIXED BUFFER STRING TYPE
78153913Sarchie ************************************************************************/
78253913Sarchie
78353913Sarchiestatic int
78453913Sarchieng_fixedstring_parse(const struct ng_parse_type *type,
78553913Sarchie	const char *s, int *off, const u_char *const start,
78653913Sarchie	u_char *const buf, int *buflen)
78753913Sarchie{
78858011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
78953913Sarchie	char *sval;
79053913Sarchie	int len;
79168845Sbrian	int slen;
79253913Sarchie
79368845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
79453913Sarchie		return (EINVAL);
79568845Sbrian	if (slen + 1 > fi->bufSize)
79653913Sarchie		return (E2BIG);
79753913Sarchie	*off += len;
79868845Sbrian	bcopy(sval, buf, slen);
79970870Sjulian	FREE(sval, M_NETGRAPH_PARSE);
80068845Sbrian	bzero(buf + slen, fi->bufSize - slen);
80153913Sarchie	*buflen = fi->bufSize;
80253913Sarchie	return (0);
80353913Sarchie}
80453913Sarchie
80553913Sarchiestatic int
80653913Sarchieng_fixedstring_unparse(const struct ng_parse_type *type,
80753913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
80853913Sarchie{
80958011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
81053913Sarchie	int error, temp = *off;
81153913Sarchie
81253913Sarchie	if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
81353913Sarchie		return (error);
81453913Sarchie	*off += fi->bufSize;
81553913Sarchie	return (0);
81653913Sarchie}
81753913Sarchie
81853913Sarchiestatic int
81953913Sarchieng_fixedstring_getDefault(const struct ng_parse_type *type,
82053913Sarchie	const u_char *const start, u_char *buf, int *buflen)
82153913Sarchie{
82258011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
82353913Sarchie
82453913Sarchie	if (*buflen < fi->bufSize)
82553913Sarchie		return (ERANGE);
82653913Sarchie	bzero(buf, fi->bufSize);
82753913Sarchie	*buflen = fi->bufSize;
82853913Sarchie	return (0);
82953913Sarchie}
83053913Sarchie
83153913Sarchieconst struct ng_parse_type ng_parse_fixedstring_type = {
83253913Sarchie	NULL,
83353913Sarchie	NULL,
83453913Sarchie	NULL,
83553913Sarchie	ng_fixedstring_parse,
83653913Sarchie	ng_fixedstring_unparse,
83753913Sarchie	ng_fixedstring_getDefault,
83853913Sarchie	NULL
83953913Sarchie};
84053913Sarchie
84158011Sarchieconst struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
84253913Sarchie	NG_NODELEN + 1
84353913Sarchie};
84453913Sarchieconst struct ng_parse_type ng_parse_nodebuf_type = {
84553913Sarchie	&ng_parse_fixedstring_type,
84653913Sarchie	&ng_parse_nodebuf_info
84753913Sarchie};
84853913Sarchie
84958011Sarchieconst struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
85053913Sarchie	NG_HOOKLEN + 1
85153913Sarchie};
85253913Sarchieconst struct ng_parse_type ng_parse_hookbuf_type = {
85353913Sarchie	&ng_parse_fixedstring_type,
85453913Sarchie	&ng_parse_hookbuf_info
85553913Sarchie};
85653913Sarchie
85758011Sarchieconst struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
85853913Sarchie	NG_PATHLEN + 1
85953913Sarchie};
86053913Sarchieconst struct ng_parse_type ng_parse_pathbuf_type = {
86153913Sarchie	&ng_parse_fixedstring_type,
86253913Sarchie	&ng_parse_pathbuf_info
86353913Sarchie};
86453913Sarchie
86558011Sarchieconst struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
86653913Sarchie	NG_TYPELEN + 1
86753913Sarchie};
86853913Sarchieconst struct ng_parse_type ng_parse_typebuf_type = {
86953913Sarchie	&ng_parse_fixedstring_type,
87053913Sarchie	&ng_parse_typebuf_info
87153913Sarchie};
87253913Sarchie
87358011Sarchieconst struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
87453913Sarchie	NG_CMDSTRLEN + 1
87553913Sarchie};
87653913Sarchieconst struct ng_parse_type ng_parse_cmdbuf_type = {
87753913Sarchie	&ng_parse_fixedstring_type,
87853913Sarchie	&ng_parse_cmdbuf_info
87953913Sarchie};
88053913Sarchie
88153913Sarchie/************************************************************************
88268845Sbrian			EXPLICITLY SIZED STRING TYPE
88368845Sbrian ************************************************************************/
88468845Sbrian
88568845Sbrianstatic int
88668845Sbrianng_sizedstring_parse(const struct ng_parse_type *type,
88768845Sbrian	const char *s, int *off, const u_char *const start,
88868845Sbrian	u_char *const buf, int *buflen)
88968845Sbrian{
89068845Sbrian	char *sval;
89168845Sbrian	int len;
89268845Sbrian	int slen;
89368845Sbrian
89468845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
89568845Sbrian		return (EINVAL);
89668845Sbrian	if (slen > 0xffff)
89768845Sbrian		return (EINVAL);
89868845Sbrian	*off += len;
89968845Sbrian	*((u_int16_t *)buf) = (u_int16_t)slen;
90068845Sbrian	bcopy(sval, buf + 2, slen);
90170870Sjulian	FREE(sval, M_NETGRAPH_PARSE);
90268845Sbrian	*buflen = 2 + slen;
90368845Sbrian	return (0);
90468845Sbrian}
90568845Sbrian
90668845Sbrianstatic int
90768845Sbrianng_sizedstring_unparse(const struct ng_parse_type *type,
90868845Sbrian	const u_char *data, int *off, char *cbuf, int cbuflen)
90968845Sbrian{
91068845Sbrian	const char *const raw = (const char *)data + *off + 2;
91168845Sbrian	const int slen = *((const u_int16_t *)(data + *off));
91268845Sbrian	char *const s = ng_encode_string(raw, slen);
91368845Sbrian
91468845Sbrian	if (s == NULL)
91568845Sbrian		return (ENOMEM);
91668845Sbrian	NG_PARSE_APPEND("%s", s);
91770870Sjulian	FREE(s, M_NETGRAPH_PARSE);
91868845Sbrian	*off += slen + 2;
91968845Sbrian	return (0);
92068845Sbrian}
92168845Sbrian
92268845Sbrianstatic int
92368845Sbrianng_sizedstring_getDefault(const struct ng_parse_type *type,
92468845Sbrian	const u_char *const start, u_char *buf, int *buflen)
92568845Sbrian{
92668845Sbrian	if (*buflen < 2)
92768845Sbrian		return (ERANGE);
92868845Sbrian	bzero(buf, 2);
92968845Sbrian	*buflen = 2;
93068845Sbrian	return (0);
93168845Sbrian}
93268845Sbrian
93368845Sbrianconst struct ng_parse_type ng_parse_sizedstring_type = {
93468845Sbrian	NULL,
93568845Sbrian	NULL,
93668845Sbrian	NULL,
93768845Sbrian	ng_sizedstring_parse,
93868845Sbrian	ng_sizedstring_unparse,
93968845Sbrian	ng_sizedstring_getDefault,
94068845Sbrian	NULL
94168845Sbrian};
94268845Sbrian
94368845Sbrian/************************************************************************
94453913Sarchie			IP ADDRESS TYPE
94553913Sarchie ************************************************************************/
94653913Sarchie
94753913Sarchiestatic int
94853913Sarchieng_ipaddr_parse(const struct ng_parse_type *type,
94953913Sarchie	const char *s, int *off, const u_char *const start,
95053913Sarchie	u_char *const buf, int *buflen)
95153913Sarchie{
95253913Sarchie	int i, error;
95353913Sarchie
95453913Sarchie	for (i = 0; i < 4; i++) {
95553913Sarchie		if ((error = ng_int8_parse(&ng_parse_int8_type,
95653913Sarchie		    s, off, start, buf + i, buflen)) != 0)
95753913Sarchie			return (error);
95853913Sarchie		if (i < 3 && s[*off] != '.')
95953913Sarchie			return (EINVAL);
96053913Sarchie		(*off)++;
96153913Sarchie	}
96253913Sarchie	*buflen = 4;
96353913Sarchie	return (0);
96453913Sarchie}
96553913Sarchie
96653913Sarchiestatic int
96753913Sarchieng_ipaddr_unparse(const struct ng_parse_type *type,
96853913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
96953913Sarchie{
97053913Sarchie	struct in_addr ip;
97153913Sarchie
97253913Sarchie	bcopy(data + *off, &ip, sizeof(ip));
97353913Sarchie	NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0],
97453913Sarchie	    ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]);
97553913Sarchie	*off += sizeof(ip);
97653913Sarchie	return (0);
97753913Sarchie}
97853913Sarchie
97953913Sarchiestatic int
98053913Sarchieng_ipaddr_getDefault(const struct ng_parse_type *type,
98153913Sarchie	const u_char *const start, u_char *buf, int *buflen)
98253913Sarchie{
98353913Sarchie	struct in_addr ip = { 0 };
98453913Sarchie
98553913Sarchie	if (*buflen < sizeof(ip))
98653913Sarchie		return (ERANGE);
98753913Sarchie	bcopy(&ip, buf, sizeof(ip));
98853913Sarchie	*buflen = sizeof(ip);
98953913Sarchie	return (0);
99053913Sarchie}
99153913Sarchie
99253913Sarchieconst struct ng_parse_type ng_parse_ipaddr_type = {
99353913Sarchie	NULL,
99453913Sarchie	NULL,
99553913Sarchie	NULL,
99653913Sarchie	ng_ipaddr_parse,
99753913Sarchie	ng_ipaddr_unparse,
99853913Sarchie	ng_ipaddr_getDefault,
99953913Sarchie	ng_int32_getAlign
100053913Sarchie};
100153913Sarchie
100253913Sarchie/************************************************************************
100353913Sarchie			BYTE ARRAY TYPE
100453913Sarchie ************************************************************************/
100553913Sarchie
100653913Sarchie/* Get the length of a byte array */
100753913Sarchiestatic int
100853913Sarchieng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
100953913Sarchie	const u_char *start, const u_char *buf)
101053913Sarchie{
101153913Sarchie	ng_parse_array_getLength_t *const getLength = type->private;
101253913Sarchie
101353913Sarchie	return (*getLength)(type, start, buf);
101453913Sarchie}
101553913Sarchie
101664505Sarchie/* Byte array element type is hex int8 */
101753913Sarchiestatic const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
101864505Sarchie	&ng_parse_hint8_type,
101953913Sarchie	&ng_parse_bytearray_subtype_getLength,
102053913Sarchie	NULL
102153913Sarchie};
102253913Sarchiestatic const struct ng_parse_type ng_parse_bytearray_subtype = {
102353913Sarchie	&ng_parse_array_type,
102453913Sarchie	&ng_parse_bytearray_subtype_info
102553913Sarchie};
102653913Sarchie
102753913Sarchiestatic int
102853913Sarchieng_bytearray_parse(const struct ng_parse_type *type,
102953913Sarchie	const char *s, int *off, const u_char *const start,
103053913Sarchie	u_char *const buf, int *buflen)
103153913Sarchie{
103253913Sarchie	char *str;
103353913Sarchie	int toklen;
103468845Sbrian	int slen;
103553913Sarchie
103653913Sarchie	/* We accept either an array of bytes or a string constant */
103768845Sbrian	if ((str = ng_get_string_token(s, off, &toklen, &slen)) != NULL) {
103853913Sarchie		ng_parse_array_getLength_t *const getLength = type->info;
103968845Sbrian		int arraylen;
104053913Sarchie
104153913Sarchie		arraylen = (*getLength)(type, start, buf);
104253913Sarchie		if (arraylen > *buflen) {
104370870Sjulian			FREE(str, M_NETGRAPH_PARSE);
104453913Sarchie			return (ERANGE);
104553913Sarchie		}
104653913Sarchie		if (slen > arraylen) {
104770870Sjulian			FREE(str, M_NETGRAPH_PARSE);
104853913Sarchie			return (E2BIG);
104953913Sarchie		}
105053913Sarchie		bcopy(str, buf, slen);
105153913Sarchie		bzero(buf + slen, arraylen - slen);
105270870Sjulian		FREE(str, M_NETGRAPH_PARSE);
105353913Sarchie		*off += toklen;
105453913Sarchie		*buflen = arraylen;
105553913Sarchie		return (0);
105653913Sarchie	} else {
105753913Sarchie		struct ng_parse_type subtype;
105853913Sarchie
105953913Sarchie		subtype = ng_parse_bytearray_subtype;
106053913Sarchie		(const void *)subtype.private = type->info;
106153913Sarchie		return ng_array_parse(&subtype, s, off, start, buf, buflen);
106253913Sarchie	}
106353913Sarchie}
106453913Sarchie
106553913Sarchiestatic int
106653913Sarchieng_bytearray_unparse(const struct ng_parse_type *type,
106753913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
106853913Sarchie{
106953913Sarchie	struct ng_parse_type subtype;
107053913Sarchie
107153913Sarchie	subtype = ng_parse_bytearray_subtype;
107253913Sarchie	(const void *)subtype.private = type->info;
107353913Sarchie	return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
107453913Sarchie}
107553913Sarchie
107653913Sarchiestatic int
107753913Sarchieng_bytearray_getDefault(const struct ng_parse_type *type,
107853913Sarchie	const u_char *const start, u_char *buf, int *buflen)
107953913Sarchie{
108053913Sarchie	struct ng_parse_type subtype;
108153913Sarchie
108253913Sarchie	subtype = ng_parse_bytearray_subtype;
108353913Sarchie	(const void *)subtype.private = type->info;
108453913Sarchie	return ng_array_getDefault(&subtype, start, buf, buflen);
108553913Sarchie}
108653913Sarchie
108753913Sarchieconst struct ng_parse_type ng_parse_bytearray_type = {
108853913Sarchie	NULL,
108953913Sarchie	NULL,
109053913Sarchie	NULL,
109153913Sarchie	ng_bytearray_parse,
109253913Sarchie	ng_bytearray_unparse,
109353913Sarchie	ng_bytearray_getDefault,
109453913Sarchie	NULL
109553913Sarchie};
109653913Sarchie
109753913Sarchie/************************************************************************
109853913Sarchie			STRUCT NG_MESG TYPE
109953913Sarchie ************************************************************************/
110053913Sarchie
110153913Sarchie/* Get msg->header.arglen when "buf" is pointing to msg->data */
110253913Sarchiestatic int
110353913Sarchieng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
110453913Sarchie	const u_char *start, const u_char *buf)
110553913Sarchie{
110653913Sarchie	const struct ng_mesg *msg;
110753913Sarchie
110853913Sarchie	msg = (const struct ng_mesg *)(buf - sizeof(*msg));
110953913Sarchie	return msg->header.arglen;
111053913Sarchie}
111153913Sarchie
111253913Sarchie/* Type for the variable length data portion of a struct ng_mesg */
111353913Sarchiestatic const struct ng_parse_type ng_msg_data_type = {
111453913Sarchie	&ng_parse_bytearray_type,
111553913Sarchie	&ng_parse_ng_mesg_getLength
111653913Sarchie};
111753913Sarchie
111853913Sarchie/* Type for the entire struct ng_mesg header with data section */
111953913Sarchiestatic const struct ng_parse_struct_info
112053913Sarchie	ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
112153913Sarchieconst struct ng_parse_type ng_parse_ng_mesg_type = {
112253913Sarchie	&ng_parse_struct_type,
112353913Sarchie	&ng_parse_ng_mesg_type_info,
112453913Sarchie};
112553913Sarchie
112653913Sarchie/************************************************************************
112753913Sarchie			COMPOSITE HELPER ROUTINES
112853913Sarchie ************************************************************************/
112953913Sarchie
113053913Sarchie/*
113153913Sarchie * Convert a structure or array from ASCII to binary
113253913Sarchie */
113353913Sarchiestatic int
113453913Sarchieng_parse_composite(const struct ng_parse_type *type, const char *s,
113553913Sarchie	int *off, const u_char *const start, u_char *const buf, int *buflen,
113653913Sarchie	const enum comptype ctype)
113753913Sarchie{
113853913Sarchie	const int num = ng_get_composite_len(type, start, buf, ctype);
113953913Sarchie	int nextIndex = 0;		/* next implicit array index */
114053913Sarchie	u_int index;			/* field or element index */
114153913Sarchie	int *foff;			/* field value offsets in string */
114253913Sarchie	int align, len, blen, error = 0;
114353913Sarchie
114453913Sarchie	/* Initialize */
114570870Sjulian	MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO);
114653913Sarchie	if (foff == NULL) {
114753913Sarchie		error = ENOMEM;
114853913Sarchie		goto done;
114953913Sarchie	}
115053913Sarchie
115153913Sarchie	/* Get opening brace/bracket */
115253913Sarchie	if (ng_parse_get_token(s, off, &len)
115353913Sarchie	    != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
115453913Sarchie		error = EINVAL;
115553913Sarchie		goto done;
115653913Sarchie	}
115753913Sarchie	*off += len;
115853913Sarchie
115953913Sarchie	/* Get individual element value positions in the string */
116053913Sarchie	for (;;) {
116153913Sarchie		enum ng_parse_token tok;
116253913Sarchie
116353913Sarchie		/* Check for closing brace/bracket */
116453913Sarchie		tok = ng_parse_get_token(s, off, &len);
116553913Sarchie		if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
116653913Sarchie			*off += len;
116753913Sarchie			break;
116853913Sarchie		}
116953913Sarchie
117053913Sarchie		/* For arrays, the 'name' (ie, index) is optional, so
117153913Sarchie		   distinguish name from values by seeing if the next
117253913Sarchie		   token is an equals sign */
117353913Sarchie		if (ctype != CT_STRUCT) {
117453913Sarchie			int len2, off2;
117553913Sarchie			char *eptr;
117653913Sarchie
117753913Sarchie			/* If an opening brace/bracket, index is implied */
117853913Sarchie			if (tok == T_LBRACE || tok == T_LBRACKET) {
117953913Sarchie				index = nextIndex++;
118053913Sarchie				goto gotIndex;
118153913Sarchie			}
118253913Sarchie
118353913Sarchie			/* Might be an index, might be a value, either way... */
118453913Sarchie			if (tok != T_WORD) {
118553913Sarchie				error = EINVAL;
118653913Sarchie				goto done;
118753913Sarchie			}
118853913Sarchie
118953913Sarchie			/* If no equals sign follows, index is implied */
119053913Sarchie			off2 = *off + len;
119153913Sarchie			if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
119253913Sarchie				index = nextIndex++;
119353913Sarchie				goto gotIndex;
119453913Sarchie			}
119553913Sarchie
119653913Sarchie			/* Index was specified explicitly; parse it */
119753913Sarchie			index = (u_int)strtoul(s + *off, &eptr, 0);
119853913Sarchie			if (index < 0 || eptr - (s + *off) != len) {
119953913Sarchie				error = EINVAL;
120053913Sarchie				goto done;
120153913Sarchie			}
120253913Sarchie			nextIndex = index + 1;
120353913Sarchie			*off += len + len2;
120453913SarchiegotIndex:
120553913Sarchie		} else {			/* a structure field */
120653913Sarchie			const struct ng_parse_struct_field *field = NULL;
120753913Sarchie			const struct ng_parse_struct_info *si = type->info;
120853913Sarchie
120953913Sarchie			/* Find the field by name (required) in field list */
121053913Sarchie			if (tok != T_WORD) {
121153913Sarchie				error = EINVAL;
121253913Sarchie				goto done;
121353913Sarchie			}
121453913Sarchie			for (index = 0; index < num; index++) {
121553913Sarchie				field = &si->fields[index];
121653913Sarchie				if (strncmp(&s[*off], field->name, len) == 0
121753913Sarchie				    && field->name[len] == '\0')
121853913Sarchie					break;
121953913Sarchie			}
122053913Sarchie			if (index == num) {
122153913Sarchie				error = ENOENT;
122253913Sarchie				goto done;
122353913Sarchie			}
122453913Sarchie			*off += len;
122553913Sarchie
122653913Sarchie			/* Get equals sign */
122753913Sarchie			if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
122853913Sarchie				error = EINVAL;
122953913Sarchie				goto done;
123053913Sarchie			}
123153913Sarchie			*off += len;
123253913Sarchie		}
123353913Sarchie
123453913Sarchie		/* Check array index */
123553913Sarchie		if (index >= num) {
123653913Sarchie			error = E2BIG;
123753913Sarchie			goto done;
123853913Sarchie		}
123953913Sarchie
124053913Sarchie		/* Save value's position and skip over it for now */
124153913Sarchie		if (foff[index] != 0) {
124253913Sarchie			error = EALREADY;		/* duplicate */
124353913Sarchie			goto done;
124453913Sarchie		}
124553913Sarchie		while (isspace(s[*off]))
124653913Sarchie			(*off)++;
124753913Sarchie		foff[index] = *off;
124853913Sarchie		if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
124953913Sarchie			goto done;
125053913Sarchie		*off += len;
125153913Sarchie	}
125253913Sarchie
125353913Sarchie	/* Now build binary structure from supplied values and defaults */
125453913Sarchie	for (blen = index = 0; index < num; index++) {
125553913Sarchie		const struct ng_parse_type *const
125653913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
125753913Sarchie		int k, pad, vlen;
125853913Sarchie
125953913Sarchie		/* Zero-pad any alignment bytes */
126053913Sarchie		pad = ng_parse_get_elem_pad(type, index, ctype, blen);
126153913Sarchie		for (k = 0; k < pad; k++) {
126253913Sarchie			if (blen >= *buflen) {
126353913Sarchie				error = ERANGE;
126453913Sarchie				goto done;
126553913Sarchie			}
126653913Sarchie			buf[blen++] = 0;
126753913Sarchie		}
126853913Sarchie
126953913Sarchie		/* Get value */
127053913Sarchie		vlen = *buflen - blen;
127153913Sarchie		if (foff[index] == 0) {		/* use default value */
127253913Sarchie			error = ng_get_composite_elem_default(type, index,
127353913Sarchie			    start, buf + blen, &vlen, ctype);
127453913Sarchie		} else {			/* parse given value */
127553913Sarchie			*off = foff[index];
127653913Sarchie			error = INVOKE(etype, parse)(etype,
127753913Sarchie			    s, off, start, buf + blen, &vlen);
127853913Sarchie		}
127953913Sarchie		if (error != 0)
128053913Sarchie			goto done;
128153913Sarchie		blen += vlen;
128253913Sarchie	}
128353913Sarchie
128453913Sarchie	/* Make total composite structure size a multiple of its alignment */
128553913Sarchie	if ((align = ALIGNMENT(type)) != 0) {
128653913Sarchie		while (blen % align != 0) {
128753913Sarchie			if (blen >= *buflen) {
128853913Sarchie				error = ERANGE;
128953913Sarchie				goto done;
129053913Sarchie			}
129153913Sarchie			buf[blen++] = 0;
129253913Sarchie		}
129353913Sarchie	}
129453913Sarchie
129553913Sarchie	/* Done */
129653913Sarchie	*buflen = blen;
129753913Sarchiedone:
129865303Sarchie	if (foff != NULL)
129970870Sjulian		FREE(foff, M_NETGRAPH_PARSE);
130053913Sarchie	return (error);
130153913Sarchie}
130253913Sarchie
130353913Sarchie/*
130453913Sarchie * Convert an array or structure from binary to ASCII
130553913Sarchie */
130653913Sarchiestatic int
130753913Sarchieng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
130853913Sarchie	int *off, char *cbuf, int cbuflen, const enum comptype ctype)
130953913Sarchie{
131053913Sarchie	const int num = ng_get_composite_len(type, data, data + *off, ctype);
131164505Sarchie	const int workSize = 20 * 1024;		/* XXX hard coded constant */
131253913Sarchie	int nextIndex = 0, didOne = 0;
131353913Sarchie	int error, index;
131464505Sarchie	u_char *workBuf;
131553913Sarchie
131664505Sarchie	/* Get workspace for checking default values */
131770870Sjulian	MALLOC(workBuf, u_char *, workSize, M_NETGRAPH_PARSE, M_NOWAIT);
131864505Sarchie	if (workBuf == NULL)
131964505Sarchie		return (ENOMEM);
132064505Sarchie
132153913Sarchie	/* Opening brace/bracket */
132253913Sarchie	NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
132353913Sarchie
132453913Sarchie	/* Do each item */
132553913Sarchie	for (index = 0; index < num; index++) {
132653913Sarchie		const struct ng_parse_type *const
132753913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
132853913Sarchie
132953913Sarchie		/* Skip any alignment pad bytes */
133053913Sarchie		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
133153913Sarchie
133253913Sarchie		/* See if element is equal to its default value; skip if so */
133364505Sarchie		if (*off < workSize) {
133464505Sarchie			int tempsize = workSize - *off;
133553913Sarchie
133664505Sarchie			bcopy(data, workBuf, *off);
133764505Sarchie			if (ng_get_composite_elem_default(type, index, workBuf,
133864505Sarchie			      workBuf + *off, &tempsize, ctype) == 0
133964505Sarchie			    && bcmp(workBuf + *off,
134064505Sarchie			      data + *off, tempsize) == 0) {
134153913Sarchie				*off += tempsize;
134253913Sarchie				continue;
134353913Sarchie			}
134453913Sarchie		}
134553913Sarchie
134653913Sarchie		/* Print name= */
134753913Sarchie		NG_PARSE_APPEND(" ");
134853913Sarchie		if (ctype != CT_STRUCT) {
134953913Sarchie			if (index != nextIndex) {
135053913Sarchie				nextIndex = index;
135153913Sarchie				NG_PARSE_APPEND("%d=", index);
135253913Sarchie			}
135353913Sarchie			nextIndex++;
135453913Sarchie		} else {
135553913Sarchie			const struct ng_parse_struct_info *si = type->info;
135653913Sarchie
135753913Sarchie			NG_PARSE_APPEND("%s=", si->fields[index].name);
135853913Sarchie		}
135953913Sarchie
136053913Sarchie		/* Print value */
136153913Sarchie		if ((error = INVOKE(etype, unparse)
136264505Sarchie		    (etype, data, off, cbuf, cbuflen)) != 0) {
136370870Sjulian			FREE(workBuf, M_NETGRAPH_PARSE);
136453913Sarchie			return (error);
136564505Sarchie		}
136653913Sarchie		cbuflen -= strlen(cbuf);
136753913Sarchie		cbuf += strlen(cbuf);
136853913Sarchie		didOne = 1;
136953913Sarchie	}
137070870Sjulian	FREE(workBuf, M_NETGRAPH_PARSE);
137153913Sarchie
137253913Sarchie	/* Closing brace/bracket */
137353913Sarchie	NG_PARSE_APPEND("%s%c",
137453913Sarchie	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
137553913Sarchie	return (0);
137653913Sarchie}
137753913Sarchie
137853913Sarchie/*
137953913Sarchie * Generate the default value for an element of an array or structure
138053913Sarchie * Returns EOPNOTSUPP if default value is unspecified.
138153913Sarchie */
138253913Sarchiestatic int
138353913Sarchieng_get_composite_elem_default(const struct ng_parse_type *type,
138453913Sarchie	int index, const u_char *const start, u_char *buf, int *buflen,
138553913Sarchie	const enum comptype ctype)
138653913Sarchie{
138753913Sarchie	const struct ng_parse_type *etype;
138853913Sarchie	ng_getDefault_t *func;
138953913Sarchie
139053913Sarchie	switch (ctype) {
139153913Sarchie	case CT_STRUCT:
139253913Sarchie		break;
139353913Sarchie	case CT_ARRAY:
139453913Sarchie	    {
139553913Sarchie		const struct ng_parse_array_info *const ai = type->info;
139653913Sarchie
139753913Sarchie		if (ai->getDefault != NULL) {
139853913Sarchie			return (*ai->getDefault)(type,
139953913Sarchie			    index, start, buf, buflen);
140053913Sarchie		}
140153913Sarchie		break;
140253913Sarchie	    }
140353913Sarchie	case CT_FIXEDARRAY:
140453913Sarchie	    {
140553913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
140653913Sarchie
140753913Sarchie		if (*fi->getDefault != NULL) {
140853913Sarchie			return (*fi->getDefault)(type,
140953913Sarchie			    index, start, buf, buflen);
141053913Sarchie		}
141153913Sarchie		break;
141253913Sarchie	    }
141353913Sarchie	default:
141487599Sobrien	    panic("%s", __func__);
141553913Sarchie	}
141653913Sarchie
141753913Sarchie	/* Default to element type default */
141853913Sarchie	etype = ng_get_composite_etype(type, index, ctype);
141953913Sarchie	func = METHOD(etype, getDefault);
142053913Sarchie	if (func == NULL)
142153913Sarchie		return (EOPNOTSUPP);
142253913Sarchie	return (*func)(etype, start, buf, buflen);
142353913Sarchie}
142453913Sarchie
142553913Sarchie/*
142653913Sarchie * Get the number of elements in a struct, variable or fixed array.
142753913Sarchie */
142853913Sarchiestatic int
142953913Sarchieng_get_composite_len(const struct ng_parse_type *type,
143053913Sarchie	const u_char *const start, const u_char *buf,
143153913Sarchie	const enum comptype ctype)
143253913Sarchie{
143353913Sarchie	switch (ctype) {
143453913Sarchie	case CT_STRUCT:
143553913Sarchie	    {
143653913Sarchie		const struct ng_parse_struct_info *const si = type->info;
143753913Sarchie		int numFields = 0;
143853913Sarchie
143953913Sarchie		for (numFields = 0; ; numFields++) {
144053913Sarchie			const struct ng_parse_struct_field *const
144153913Sarchie				fi = &si->fields[numFields];
144253913Sarchie
144353913Sarchie			if (fi->name == NULL)
144453913Sarchie				break;
144553913Sarchie		}
144653913Sarchie		return (numFields);
144753913Sarchie	    }
144853913Sarchie	case CT_ARRAY:
144953913Sarchie	    {
145053913Sarchie		const struct ng_parse_array_info *const ai = type->info;
145153913Sarchie
145253913Sarchie		return (*ai->getLength)(type, start, buf);
145353913Sarchie	    }
145453913Sarchie	case CT_FIXEDARRAY:
145553913Sarchie	    {
145653913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
145753913Sarchie
145853913Sarchie		return fi->length;
145953913Sarchie	    }
146053913Sarchie	default:
146187599Sobrien	    panic("%s", __func__);
146253913Sarchie	}
146353913Sarchie	return (0);
146453913Sarchie}
146553913Sarchie
146653913Sarchie/*
146753913Sarchie * Return the type of the index'th element of a composite structure
146853913Sarchie */
146953913Sarchiestatic const struct ng_parse_type *
147053913Sarchieng_get_composite_etype(const struct ng_parse_type *type,
147153913Sarchie	int index, const enum comptype ctype)
147253913Sarchie{
147353913Sarchie	const struct ng_parse_type *etype = NULL;
147453913Sarchie
147553913Sarchie	switch (ctype) {
147653913Sarchie	case CT_STRUCT:
147753913Sarchie	    {
147853913Sarchie		const struct ng_parse_struct_info *const si = type->info;
147953913Sarchie
148053913Sarchie		etype = si->fields[index].type;
148153913Sarchie		break;
148253913Sarchie	    }
148353913Sarchie	case CT_ARRAY:
148453913Sarchie	    {
148553913Sarchie		const struct ng_parse_array_info *const ai = type->info;
148653913Sarchie
148753913Sarchie		etype = ai->elementType;
148853913Sarchie		break;
148953913Sarchie	    }
149053913Sarchie	case CT_FIXEDARRAY:
149153913Sarchie	    {
149253913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
149353913Sarchie
149453913Sarchie		etype = fi->elementType;
149553913Sarchie		break;
149653913Sarchie	    }
149753913Sarchie	default:
149887599Sobrien	    panic("%s", __func__);
149953913Sarchie	}
150053913Sarchie	return (etype);
150153913Sarchie}
150253913Sarchie
150353913Sarchie/*
150453913Sarchie * Get the number of bytes to skip to align for the next
150553913Sarchie * element in a composite structure.
150653913Sarchie */
150753913Sarchiestatic int
150853913Sarchieng_parse_get_elem_pad(const struct ng_parse_type *type,
150953913Sarchie	int index, enum comptype ctype, int posn)
151053913Sarchie{
151153913Sarchie	const struct ng_parse_type *const
151253913Sarchie	    etype = ng_get_composite_etype(type, index, ctype);
151353913Sarchie	int align;
151453913Sarchie
151553913Sarchie	/* Get element's alignment, and possibly override */
151653913Sarchie	align = ALIGNMENT(etype);
151753913Sarchie	if (ctype == CT_STRUCT) {
151853913Sarchie		const struct ng_parse_struct_info *si = type->info;
151953913Sarchie
152053913Sarchie		if (si->fields[index].alignment != 0)
152153913Sarchie			align = si->fields[index].alignment;
152253913Sarchie	}
152353913Sarchie
152453913Sarchie	/* Return number of bytes to skip to align */
152553913Sarchie	return (align ? (align - (posn % align)) % align : 0);
152653913Sarchie}
152753913Sarchie
152853913Sarchie/************************************************************************
152953913Sarchie			PARSING HELPER ROUTINES
153053913Sarchie ************************************************************************/
153153913Sarchie
153253913Sarchie/*
153353913Sarchie * Skip over a value
153453913Sarchie */
153553913Sarchiestatic int
153653913Sarchieng_parse_skip_value(const char *s, int off0, int *lenp)
153753913Sarchie{
153853913Sarchie	int len, nbracket, nbrace;
153953913Sarchie	int off = off0;
154053913Sarchie
154153913Sarchie	len = nbracket = nbrace = 0;
154253913Sarchie	do {
154353913Sarchie		switch (ng_parse_get_token(s, &off, &len)) {
154453913Sarchie		case T_LBRACKET:
154553913Sarchie			nbracket++;
154653913Sarchie			break;
154753913Sarchie		case T_LBRACE:
154853913Sarchie			nbrace++;
154953913Sarchie			break;
155053913Sarchie		case T_RBRACKET:
155153913Sarchie			if (nbracket-- == 0)
155253913Sarchie				return (EINVAL);
155353913Sarchie			break;
155453913Sarchie		case T_RBRACE:
155553913Sarchie			if (nbrace-- == 0)
155653913Sarchie				return (EINVAL);
155753913Sarchie			break;
155853913Sarchie		case T_EOF:
155953913Sarchie			return (EINVAL);
156053913Sarchie		default:
156153913Sarchie			break;
156253913Sarchie		}
156353913Sarchie		off += len;
156453913Sarchie	} while (nbracket > 0 || nbrace > 0);
156553913Sarchie	*lenp = off - off0;
156653913Sarchie	return (0);
156753913Sarchie}
156853913Sarchie
156953913Sarchie/*
157053913Sarchie * Find the next token in the string, starting at offset *startp.
157153913Sarchie * Returns the token type, with *startp pointing to the first char
157253913Sarchie * and *lenp the length.
157353913Sarchie */
157453913Sarchieenum ng_parse_token
157553913Sarchieng_parse_get_token(const char *s, int *startp, int *lenp)
157653913Sarchie{
157753913Sarchie	char *t;
157853913Sarchie	int i;
157953913Sarchie
158053913Sarchie	while (isspace(s[*startp]))
158153913Sarchie		(*startp)++;
158253913Sarchie	switch (s[*startp]) {
158353913Sarchie	case '\0':
158453913Sarchie		*lenp = 0;
158553913Sarchie		return T_EOF;
158653913Sarchie	case '{':
158753913Sarchie		*lenp = 1;
158853913Sarchie		return T_LBRACE;
158953913Sarchie	case '}':
159053913Sarchie		*lenp = 1;
159153913Sarchie		return T_RBRACE;
159253913Sarchie	case '[':
159353913Sarchie		*lenp = 1;
159453913Sarchie		return T_LBRACKET;
159553913Sarchie	case ']':
159653913Sarchie		*lenp = 1;
159753913Sarchie		return T_RBRACKET;
159853913Sarchie	case '=':
159953913Sarchie		*lenp = 1;
160053913Sarchie		return T_EQUALS;
160153913Sarchie	case '"':
160268845Sbrian		if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
160353913Sarchie			return T_ERROR;
160470870Sjulian		FREE(t, M_NETGRAPH_PARSE);
160553913Sarchie		return T_STRING;
160653913Sarchie	default:
160753913Sarchie		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
160853913Sarchie		    && s[i] != '{' && s[i] != '}' && s[i] != '['
160953913Sarchie		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
161053913Sarchie			;
161153913Sarchie		*lenp = i - *startp;
161253913Sarchie		return T_WORD;
161353913Sarchie	}
161453913Sarchie}
161553913Sarchie
161653913Sarchie/*
161753913Sarchie * Get a string token, which must be enclosed in double quotes.
161853913Sarchie * The normal C backslash escapes are recognized.
161953913Sarchie */
162053913Sarchiechar *
162168845Sbrianng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
162253913Sarchie{
162353913Sarchie	char *cbuf, *p;
162453913Sarchie	int start, off;
162568845Sbrian	int slen;
162653913Sarchie
162753913Sarchie	while (isspace(s[*startp]))
162853913Sarchie		(*startp)++;
162953913Sarchie	start = *startp;
163053913Sarchie	if (s[*startp] != '"')
163153913Sarchie		return (NULL);
163270870Sjulian	MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
163353913Sarchie	if (cbuf == NULL)
163453913Sarchie		return (NULL);
163553913Sarchie	strcpy(cbuf, s + start + 1);
163668845Sbrian	for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
163753913Sarchie		if (*p == '"') {
163853913Sarchie			*p = '\0';
163953913Sarchie			*lenp = off + 1;
164068845Sbrian			if (slenp != NULL)
164168845Sbrian				*slenp = slen;
164253913Sarchie			return (cbuf);
164353913Sarchie		} else if (p[0] == '\\' && p[1] != '\0') {
164453913Sarchie			int x, k;
164553913Sarchie			char *v;
164653913Sarchie
164753913Sarchie			strcpy(p, p + 1);
164853913Sarchie			v = p;
164953913Sarchie			switch (*p) {
165053913Sarchie			case 't':
165153913Sarchie				*v = '\t';
165253913Sarchie				off++;
165353913Sarchie				continue;
165453913Sarchie			case 'n':
165553913Sarchie				*v = '\n';
165653913Sarchie				off++;
165753913Sarchie				continue;
165853913Sarchie			case 'r':
165953913Sarchie				*v = '\r';
166053913Sarchie				off++;
166153913Sarchie				continue;
166253913Sarchie			case 'v':
166353913Sarchie				*v =  '\v';
166453913Sarchie				off++;
166553913Sarchie				continue;
166653913Sarchie			case 'f':
166753913Sarchie				*v =  '\f';
166853913Sarchie				off++;
166953913Sarchie				continue;
167053913Sarchie			case '"':
167153913Sarchie				*v =  '"';
167253913Sarchie				off++;
167353913Sarchie				continue;
167453913Sarchie			case '0': case '1': case '2': case '3':
167553913Sarchie			case '4': case '5': case '6': case '7':
167653913Sarchie				for (x = k = 0;
167753913Sarchie				    k < 3 && *v >= '0' && *v <= '7'; v++) {
167853913Sarchie					x = (x << 3) + (*v - '0');
167953913Sarchie					off++;
168053913Sarchie				}
168153913Sarchie				*--v = (char)x;
168253913Sarchie				break;
168353913Sarchie			case 'x':
168453913Sarchie				for (v++, x = k = 0;
168553913Sarchie				    k < 2 && isxdigit(*v); v++) {
168653913Sarchie					x = (x << 4) + (isdigit(*v) ?
168753913Sarchie					      (*v - '0') :
168853913Sarchie					      (tolower(*v) - 'a' + 10));
168953913Sarchie					off++;
169053913Sarchie				}
169153913Sarchie				*--v = (char)x;
169253913Sarchie				break;
169353913Sarchie			default:
169453913Sarchie				continue;
169553913Sarchie			}
169653913Sarchie			strcpy(p, v);
169753913Sarchie		}
169853913Sarchie	}
169953913Sarchie	return (NULL);		/* no closing quote */
170053913Sarchie}
170153913Sarchie
170253913Sarchie/*
170353913Sarchie * Encode a string so it can be safely put in double quotes.
170468845Sbrian * Caller must free the result. Exactly "slen" characters
170568845Sbrian * are encoded.
170653913Sarchie */
170753913Sarchiechar *
170868845Sbrianng_encode_string(const char *raw, int slen)
170953913Sarchie{
171053913Sarchie	char *cbuf;
171153913Sarchie	int off = 0;
171268845Sbrian	int i;
171353913Sarchie
171470870Sjulian	MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
171553913Sarchie	if (cbuf == NULL)
171653913Sarchie		return (NULL);
171753913Sarchie	cbuf[off++] = '"';
171868845Sbrian	for (i = 0; i < slen; i++, raw++) {
171953913Sarchie		switch (*raw) {
172053913Sarchie		case '\t':
172153913Sarchie			cbuf[off++] = '\\';
172253913Sarchie			cbuf[off++] = 't';
172353913Sarchie			break;
172453913Sarchie		case '\f':
172553913Sarchie			cbuf[off++] = '\\';
172653913Sarchie			cbuf[off++] = 'f';
172753913Sarchie			break;
172853913Sarchie		case '\n':
172953913Sarchie			cbuf[off++] = '\\';
173053913Sarchie			cbuf[off++] = 'n';
173153913Sarchie			break;
173253913Sarchie		case '\r':
173353913Sarchie			cbuf[off++] = '\\';
173453913Sarchie			cbuf[off++] = 'r';
173553913Sarchie			break;
173653913Sarchie		case '\v':
173753913Sarchie			cbuf[off++] = '\\';
173853913Sarchie			cbuf[off++] = 'v';
173953913Sarchie			break;
174053913Sarchie		case '"':
174153913Sarchie		case '\\':
174253913Sarchie			cbuf[off++] = '\\';
174353913Sarchie			cbuf[off++] = *raw;
174453913Sarchie			break;
174553913Sarchie		default:
174653913Sarchie			if (*raw < 0x20 || *raw > 0x7e) {
174753913Sarchie				off += sprintf(cbuf + off,
174853913Sarchie				    "\\x%02x", (u_char)*raw);
174953913Sarchie				break;
175053913Sarchie			}
175153913Sarchie			cbuf[off++] = *raw;
175253913Sarchie			break;
175353913Sarchie		}
175453913Sarchie	}
175553913Sarchie	cbuf[off++] = '"';
175653913Sarchie	cbuf[off] = '\0';
175753913Sarchie	return (cbuf);
175853913Sarchie}
175953913Sarchie
176053913Sarchie/************************************************************************
176153913Sarchie			VIRTUAL METHOD LOOKUP
176253913Sarchie ************************************************************************/
176353913Sarchie
176453913Sarchiestatic ng_parse_t *
176553913Sarchieng_get_parse_method(const struct ng_parse_type *t)
176653913Sarchie{
176753913Sarchie	while (t != NULL && t->parse == NULL)
176853913Sarchie		t = t->supertype;
176953913Sarchie	return (t ? t->parse : NULL);
177053913Sarchie}
177153913Sarchie
177253913Sarchiestatic ng_unparse_t *
177353913Sarchieng_get_unparse_method(const struct ng_parse_type *t)
177453913Sarchie{
177553913Sarchie	while (t != NULL && t->unparse == NULL)
177653913Sarchie		t = t->supertype;
177753913Sarchie	return (t ? t->unparse : NULL);
177853913Sarchie}
177953913Sarchie
178053913Sarchiestatic ng_getDefault_t *
178153913Sarchieng_get_getDefault_method(const struct ng_parse_type *t)
178253913Sarchie{
178353913Sarchie	while (t != NULL && t->getDefault == NULL)
178453913Sarchie		t = t->supertype;
178553913Sarchie	return (t ? t->getDefault : NULL);
178653913Sarchie}
178753913Sarchie
178853913Sarchiestatic ng_getAlign_t *
178953913Sarchieng_get_getAlign_method(const struct ng_parse_type *t)
179053913Sarchie{
179153913Sarchie	while (t != NULL && t->getAlign == NULL)
179253913Sarchie		t = t->supertype;
179353913Sarchie	return (t ? t->getAlign : NULL);
179453913Sarchie}
179553913Sarchie
1796