ng_parse.c revision 97685
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 97685 2002-05-31 23:48:03Z archie $
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_field *field;
21653913Sarchie	int align = 0;
21753913Sarchie
21897685Sarchie	for (field = type->info; field->name != NULL; field++) {
21953913Sarchie		int falign = ALIGNMENT(field->type);
22053913Sarchie
22153913Sarchie		if (falign > align)
22253913Sarchie			align = falign;
22353913Sarchie	}
22453913Sarchie	return align;
22553913Sarchie}
22653913Sarchie
22753913Sarchieconst struct ng_parse_type ng_parse_struct_type = {
22853913Sarchie	NULL,
22953913Sarchie	NULL,
23053913Sarchie	NULL,
23153913Sarchie	ng_struct_parse,
23253913Sarchie	ng_struct_unparse,
23353913Sarchie	ng_struct_getDefault,
23453913Sarchie	ng_struct_getAlign
23553913Sarchie};
23653913Sarchie
23753913Sarchie/************************************************************************
23853913Sarchie			FIXED LENGTH ARRAY TYPE
23953913Sarchie ************************************************************************/
24053913Sarchie
24153913Sarchiestatic int
24253913Sarchieng_fixedarray_parse(const struct ng_parse_type *type,
24353913Sarchie	const char *s, int *off, const u_char *const start,
24453913Sarchie	u_char *const buf, int *buflen)
24553913Sarchie{
24653913Sarchie	return ng_parse_composite(type,
24753913Sarchie	    s, off, start, buf, buflen, CT_FIXEDARRAY);
24853913Sarchie}
24953913Sarchie
25053913Sarchiestatic int
25153913Sarchieng_fixedarray_unparse(const struct ng_parse_type *type,
25253913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
25353913Sarchie{
25453913Sarchie	return ng_unparse_composite(type,
25553913Sarchie		data, off, cbuf, cbuflen, CT_FIXEDARRAY);
25653913Sarchie}
25753913Sarchie
25853913Sarchiestatic int
25953913Sarchieng_fixedarray_getDefault(const struct ng_parse_type *type,
26053913Sarchie	const u_char *const start, u_char *buf, int *buflen)
26153913Sarchie{
26253913Sarchie	int off = 0;
26353913Sarchie
26453913Sarchie	return ng_parse_composite(type,
26553913Sarchie	    "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
26653913Sarchie}
26753913Sarchie
26853913Sarchiestatic int
26953913Sarchieng_fixedarray_getAlign(const struct ng_parse_type *type)
27053913Sarchie{
27153913Sarchie	const struct ng_parse_fixedarray_info *fi = type->info;
27253913Sarchie
27353913Sarchie	return ALIGNMENT(fi->elementType);
27453913Sarchie}
27553913Sarchie
27653913Sarchieconst struct ng_parse_type ng_parse_fixedarray_type = {
27753913Sarchie	NULL,
27853913Sarchie	NULL,
27953913Sarchie	NULL,
28053913Sarchie	ng_fixedarray_parse,
28153913Sarchie	ng_fixedarray_unparse,
28253913Sarchie	ng_fixedarray_getDefault,
28353913Sarchie	ng_fixedarray_getAlign
28453913Sarchie};
28553913Sarchie
28653913Sarchie/************************************************************************
28753913Sarchie			VARIABLE LENGTH ARRAY TYPE
28853913Sarchie ************************************************************************/
28953913Sarchie
29053913Sarchiestatic int
29153913Sarchieng_array_parse(const struct ng_parse_type *type,
29253913Sarchie	const char *s, int *off, const u_char *const start,
29353913Sarchie	u_char *const buf, int *buflen)
29453913Sarchie{
29553913Sarchie	return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
29653913Sarchie}
29753913Sarchie
29853913Sarchiestatic int
29953913Sarchieng_array_unparse(const struct ng_parse_type *type,
30053913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
30153913Sarchie{
30253913Sarchie	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
30353913Sarchie}
30453913Sarchie
30553913Sarchiestatic int
30653913Sarchieng_array_getDefault(const struct ng_parse_type *type,
30753913Sarchie	const u_char *const start, u_char *buf, int *buflen)
30853913Sarchie{
30953913Sarchie	int off = 0;
31053913Sarchie
31153913Sarchie	return ng_parse_composite(type,
31253913Sarchie	    "[]", &off, start, buf, buflen, CT_ARRAY);
31353913Sarchie}
31453913Sarchie
31553913Sarchiestatic int
31653913Sarchieng_array_getAlign(const struct ng_parse_type *type)
31753913Sarchie{
31853913Sarchie	const struct ng_parse_array_info *ai = type->info;
31953913Sarchie
32053913Sarchie	return ALIGNMENT(ai->elementType);
32153913Sarchie}
32253913Sarchie
32353913Sarchieconst struct ng_parse_type ng_parse_array_type = {
32453913Sarchie	NULL,
32553913Sarchie	NULL,
32653913Sarchie	NULL,
32753913Sarchie	ng_array_parse,
32853913Sarchie	ng_array_unparse,
32953913Sarchie	ng_array_getDefault,
33053913Sarchie	ng_array_getAlign
33153913Sarchie};
33253913Sarchie
33353913Sarchie/************************************************************************
33453913Sarchie				INT8 TYPE
33553913Sarchie ************************************************************************/
33653913Sarchie
33753913Sarchiestatic int
33853913Sarchieng_int8_parse(const struct ng_parse_type *type,
33953913Sarchie	const char *s, int *off, const u_char *const start,
34053913Sarchie	u_char *const buf, int *buflen)
34153913Sarchie{
34253913Sarchie	long val;
34353913Sarchie	int8_t val8;
34453913Sarchie	char *eptr;
34553913Sarchie
34653913Sarchie	val = strtol(s + *off, &eptr, 0);
34776860Sjdp	if (val < (int8_t)0x80 || val > (u_int8_t)0xff || eptr == s + *off)
34853913Sarchie		return (EINVAL);
34953913Sarchie	*off = eptr - s;
35053913Sarchie	val8 = (int8_t)val;
35153913Sarchie	bcopy(&val8, buf, sizeof(int8_t));
35253913Sarchie	*buflen = sizeof(int8_t);
35353913Sarchie	return (0);
35453913Sarchie}
35553913Sarchie
35653913Sarchiestatic int
35753913Sarchieng_int8_unparse(const struct ng_parse_type *type,
35853913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
35953913Sarchie{
36064505Sarchie	const char *fmt;
36164505Sarchie	int fval;
36253913Sarchie	int8_t val;
36353913Sarchie
36453913Sarchie	bcopy(data + *off, &val, sizeof(int8_t));
36564505Sarchie	switch ((int)type->info) {
36664505Sarchie	case INT_SIGNED:
36764505Sarchie		fmt = "%d";
36864505Sarchie		fval = val;
36964505Sarchie		break;
37064505Sarchie	case INT_UNSIGNED:
37164505Sarchie		fmt = "%u";
37264505Sarchie		fval = (u_int8_t)val;
37364505Sarchie		break;
37464505Sarchie	case INT_HEX:
37564505Sarchie		fmt = "0x%x";
37664505Sarchie		fval = (u_int8_t)val;
37764505Sarchie		break;
37864505Sarchie	default:
37987599Sobrien		panic("%s: unknown type", __func__);
38083366Sjulian#ifdef	RESTARTABLE_PANICS
38183366Sjulian		return(0);
38283366Sjulian#endif
38364505Sarchie	}
38464505Sarchie	NG_PARSE_APPEND(fmt, fval);
38553913Sarchie	*off += sizeof(int8_t);
38653913Sarchie	return (0);
38753913Sarchie}
38853913Sarchie
38953913Sarchiestatic int
39053913Sarchieng_int8_getDefault(const struct ng_parse_type *type,
39153913Sarchie	const u_char *const start, u_char *buf, int *buflen)
39253913Sarchie{
39353913Sarchie	int8_t val;
39453913Sarchie
39553913Sarchie	if (*buflen < sizeof(int8_t))
39653913Sarchie		return (ERANGE);
39753913Sarchie	val = 0;
39853913Sarchie	bcopy(&val, buf, sizeof(int8_t));
39953913Sarchie	*buflen = sizeof(int8_t);
40053913Sarchie	return (0);
40153913Sarchie}
40253913Sarchie
40353913Sarchiestatic int
40453913Sarchieng_int8_getAlign(const struct ng_parse_type *type)
40553913Sarchie{
40653913Sarchie	return INT8_ALIGNMENT;
40753913Sarchie}
40853913Sarchie
40953913Sarchieconst struct ng_parse_type ng_parse_int8_type = {
41053913Sarchie	NULL,
41164505Sarchie	(void *)INT_SIGNED,
41253913Sarchie	NULL,
41353913Sarchie	ng_int8_parse,
41453913Sarchie	ng_int8_unparse,
41553913Sarchie	ng_int8_getDefault,
41653913Sarchie	ng_int8_getAlign
41753913Sarchie};
41853913Sarchie
41964505Sarchieconst struct ng_parse_type ng_parse_uint8_type = {
42064505Sarchie	&ng_parse_int8_type,
42164505Sarchie	(void *)INT_UNSIGNED
42264505Sarchie};
42364505Sarchie
42464505Sarchieconst struct ng_parse_type ng_parse_hint8_type = {
42564505Sarchie	&ng_parse_int8_type,
42664505Sarchie	(void *)INT_HEX
42764505Sarchie};
42864505Sarchie
42953913Sarchie/************************************************************************
43053913Sarchie				INT16 TYPE
43153913Sarchie ************************************************************************/
43253913Sarchie
43353913Sarchiestatic int
43453913Sarchieng_int16_parse(const struct ng_parse_type *type,
43553913Sarchie	const char *s, int *off, const u_char *const start,
43653913Sarchie	u_char *const buf, int *buflen)
43753913Sarchie{
43853913Sarchie	long val;
43953913Sarchie	int16_t val16;
44053913Sarchie	char *eptr;
44153913Sarchie
44253913Sarchie	val = strtol(s + *off, &eptr, 0);
44376860Sjdp	if (val < (int16_t)0x8000
44476860Sjdp	    || val > (u_int16_t)0xffff || eptr == s + *off)
44553913Sarchie		return (EINVAL);
44653913Sarchie	*off = eptr - s;
44753913Sarchie	val16 = (int16_t)val;
44853913Sarchie	bcopy(&val16, buf, sizeof(int16_t));
44953913Sarchie	*buflen = sizeof(int16_t);
45053913Sarchie	return (0);
45153913Sarchie}
45253913Sarchie
45353913Sarchiestatic int
45453913Sarchieng_int16_unparse(const struct ng_parse_type *type,
45553913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
45653913Sarchie{
45764505Sarchie	const char *fmt;
45864505Sarchie	int fval;
45953913Sarchie	int16_t val;
46053913Sarchie
46153913Sarchie	bcopy(data + *off, &val, sizeof(int16_t));
46264505Sarchie	switch ((int)type->info) {
46364505Sarchie	case INT_SIGNED:
46464505Sarchie		fmt = "%d";
46564505Sarchie		fval = val;
46664505Sarchie		break;
46764505Sarchie	case INT_UNSIGNED:
46864505Sarchie		fmt = "%u";
46964505Sarchie		fval = (u_int16_t)val;
47064505Sarchie		break;
47164505Sarchie	case INT_HEX:
47264505Sarchie		fmt = "0x%x";
47364505Sarchie		fval = (u_int16_t)val;
47464505Sarchie		break;
47564505Sarchie	default:
47687599Sobrien		panic("%s: unknown type", __func__);
47783366Sjulian#ifdef	RESTARTABLE_PANICS
47883366Sjulian		return(0);
47983366Sjulian#endif
48064505Sarchie	}
48164505Sarchie	NG_PARSE_APPEND(fmt, fval);
48253913Sarchie	*off += sizeof(int16_t);
48353913Sarchie	return (0);
48453913Sarchie}
48553913Sarchie
48653913Sarchiestatic int
48753913Sarchieng_int16_getDefault(const struct ng_parse_type *type,
48853913Sarchie	const u_char *const start, u_char *buf, int *buflen)
48953913Sarchie{
49053913Sarchie	int16_t val;
49153913Sarchie
49253913Sarchie	if (*buflen < sizeof(int16_t))
49353913Sarchie		return (ERANGE);
49453913Sarchie	val = 0;
49553913Sarchie	bcopy(&val, buf, sizeof(int16_t));
49653913Sarchie	*buflen = sizeof(int16_t);
49753913Sarchie	return (0);
49853913Sarchie}
49953913Sarchie
50053913Sarchiestatic int
50153913Sarchieng_int16_getAlign(const struct ng_parse_type *type)
50253913Sarchie{
50353913Sarchie	return INT16_ALIGNMENT;
50453913Sarchie}
50553913Sarchie
50653913Sarchieconst struct ng_parse_type ng_parse_int16_type = {
50753913Sarchie	NULL,
50864505Sarchie	(void *)INT_SIGNED,
50953913Sarchie	NULL,
51053913Sarchie	ng_int16_parse,
51153913Sarchie	ng_int16_unparse,
51253913Sarchie	ng_int16_getDefault,
51353913Sarchie	ng_int16_getAlign
51453913Sarchie};
51553913Sarchie
51664505Sarchieconst struct ng_parse_type ng_parse_uint16_type = {
51764505Sarchie	&ng_parse_int16_type,
51864505Sarchie	(void *)INT_UNSIGNED
51964505Sarchie};
52064505Sarchie
52164505Sarchieconst struct ng_parse_type ng_parse_hint16_type = {
52264505Sarchie	&ng_parse_int16_type,
52364505Sarchie	(void *)INT_HEX
52464505Sarchie};
52564505Sarchie
52653913Sarchie/************************************************************************
52753913Sarchie				INT32 TYPE
52853913Sarchie ************************************************************************/
52953913Sarchie
53053913Sarchiestatic int
53153913Sarchieng_int32_parse(const struct ng_parse_type *type,
53253913Sarchie	const char *s, int *off, const u_char *const start,
53353913Sarchie	u_char *const buf, int *buflen)
53453913Sarchie{
53553913Sarchie	long val;			/* assumes long is at least 32 bits */
53653913Sarchie	int32_t val32;
53753913Sarchie	char *eptr;
53853913Sarchie
53953913Sarchie	val = strtol(s + *off, &eptr, 0);
54076860Sjdp	if (val < (int32_t)0x80000000
54176860Sjdp	    || val > (u_int32_t)0xffffffff || eptr == s + *off)
54253913Sarchie		return (EINVAL);
54353913Sarchie	*off = eptr - s;
54453913Sarchie	val32 = (int32_t)val;
54553913Sarchie	bcopy(&val32, buf, sizeof(int32_t));
54653913Sarchie	*buflen = sizeof(int32_t);
54753913Sarchie	return (0);
54853913Sarchie}
54953913Sarchie
55053913Sarchiestatic int
55153913Sarchieng_int32_unparse(const struct ng_parse_type *type,
55253913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
55353913Sarchie{
55464505Sarchie	const char *fmt;
55564505Sarchie	long fval;
55653913Sarchie	int32_t val;
55753913Sarchie
55853913Sarchie	bcopy(data + *off, &val, sizeof(int32_t));
55964505Sarchie	switch ((int)type->info) {
56064505Sarchie	case INT_SIGNED:
56164505Sarchie		fmt = "%ld";
56264505Sarchie		fval = val;
56364505Sarchie		break;
56464505Sarchie	case INT_UNSIGNED:
56564505Sarchie		fmt = "%lu";
56664505Sarchie		fval = (u_int32_t)val;
56764505Sarchie		break;
56864505Sarchie	case INT_HEX:
56964505Sarchie		fmt = "0x%lx";
57064505Sarchie		fval = (u_int32_t)val;
57164505Sarchie		break;
57264505Sarchie	default:
57387599Sobrien		panic("%s: unknown type", __func__);
57483366Sjulian#ifdef	RESTARTABLE_PANICS
57583366Sjulian		return(0);
57683366Sjulian#endif
57764505Sarchie	}
57864505Sarchie	NG_PARSE_APPEND(fmt, fval);
57953913Sarchie	*off += sizeof(int32_t);
58053913Sarchie	return (0);
58153913Sarchie}
58253913Sarchie
58353913Sarchiestatic int
58453913Sarchieng_int32_getDefault(const struct ng_parse_type *type,
58553913Sarchie	const u_char *const start, u_char *buf, int *buflen)
58653913Sarchie{
58753913Sarchie	int32_t val;
58853913Sarchie
58953913Sarchie	if (*buflen < sizeof(int32_t))
59053913Sarchie		return (ERANGE);
59153913Sarchie	val = 0;
59253913Sarchie	bcopy(&val, buf, sizeof(int32_t));
59353913Sarchie	*buflen = sizeof(int32_t);
59453913Sarchie	return (0);
59553913Sarchie}
59653913Sarchie
59753913Sarchiestatic int
59853913Sarchieng_int32_getAlign(const struct ng_parse_type *type)
59953913Sarchie{
60053913Sarchie	return INT32_ALIGNMENT;
60153913Sarchie}
60253913Sarchie
60353913Sarchieconst struct ng_parse_type ng_parse_int32_type = {
60453913Sarchie	NULL,
60564505Sarchie	(void *)INT_SIGNED,
60653913Sarchie	NULL,
60753913Sarchie	ng_int32_parse,
60853913Sarchie	ng_int32_unparse,
60953913Sarchie	ng_int32_getDefault,
61053913Sarchie	ng_int32_getAlign
61153913Sarchie};
61253913Sarchie
61364505Sarchieconst struct ng_parse_type ng_parse_uint32_type = {
61464505Sarchie	&ng_parse_int32_type,
61564505Sarchie	(void *)INT_UNSIGNED
61664505Sarchie};
61764505Sarchie
61864505Sarchieconst struct ng_parse_type ng_parse_hint32_type = {
61964505Sarchie	&ng_parse_int32_type,
62064505Sarchie	(void *)INT_HEX
62164505Sarchie};
62264505Sarchie
62353913Sarchie/************************************************************************
62453913Sarchie				INT64 TYPE
62553913Sarchie ************************************************************************/
62653913Sarchie
62753913Sarchiestatic int
62853913Sarchieng_int64_parse(const struct ng_parse_type *type,
62953913Sarchie	const char *s, int *off, const u_char *const start,
63053913Sarchie	u_char *const buf, int *buflen)
63153913Sarchie{
63253913Sarchie	quad_t val;
63353913Sarchie	int64_t val64;
63453913Sarchie	char *eptr;
63553913Sarchie
63653913Sarchie	val = strtoq(s + *off, &eptr, 0);
63753913Sarchie	if (eptr == s + *off)
63853913Sarchie		return (EINVAL);
63953913Sarchie	*off = eptr - s;
64053913Sarchie	val64 = (int64_t)val;
64153913Sarchie	bcopy(&val64, buf, sizeof(int64_t));
64253913Sarchie	*buflen = sizeof(int64_t);
64353913Sarchie	return (0);
64453913Sarchie}
64553913Sarchie
64653913Sarchiestatic int
64753913Sarchieng_int64_unparse(const struct ng_parse_type *type,
64853913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
64953913Sarchie{
65064505Sarchie	const char *fmt;
65164505Sarchie	long long fval;
65253913Sarchie	int64_t val;
65353913Sarchie
65453913Sarchie	bcopy(data + *off, &val, sizeof(int64_t));
65564505Sarchie	switch ((int)type->info) {
65664505Sarchie	case INT_SIGNED:
65764505Sarchie		fmt = "%lld";
65864505Sarchie		fval = val;
65964505Sarchie		break;
66064505Sarchie	case INT_UNSIGNED:
66164505Sarchie		fmt = "%llu";
66264505Sarchie		fval = (u_int64_t)val;
66364505Sarchie		break;
66464505Sarchie	case INT_HEX:
66564505Sarchie		fmt = "0x%llx";
66664505Sarchie		fval = (u_int64_t)val;
66764505Sarchie		break;
66864505Sarchie	default:
66987599Sobrien		panic("%s: unknown type", __func__);
67083366Sjulian#ifdef	RESTARTABLE_PANICS
67183366Sjulian		return(0);
67283366Sjulian#endif
67364505Sarchie	}
67464505Sarchie	NG_PARSE_APPEND(fmt, fval);
67553913Sarchie	*off += sizeof(int64_t);
67653913Sarchie	return (0);
67753913Sarchie}
67853913Sarchie
67953913Sarchiestatic int
68053913Sarchieng_int64_getDefault(const struct ng_parse_type *type,
68153913Sarchie	const u_char *const start, u_char *buf, int *buflen)
68253913Sarchie{
68353913Sarchie	int64_t val;
68453913Sarchie
68553913Sarchie	if (*buflen < sizeof(int64_t))
68653913Sarchie		return (ERANGE);
68753913Sarchie	val = 0;
68853913Sarchie	bcopy(&val, buf, sizeof(int64_t));
68953913Sarchie	*buflen = sizeof(int64_t);
69053913Sarchie	return (0);
69153913Sarchie}
69253913Sarchie
69353913Sarchiestatic int
69453913Sarchieng_int64_getAlign(const struct ng_parse_type *type)
69553913Sarchie{
69653913Sarchie	return INT64_ALIGNMENT;
69753913Sarchie}
69853913Sarchie
69953913Sarchieconst struct ng_parse_type ng_parse_int64_type = {
70053913Sarchie	NULL,
70164505Sarchie	(void *)INT_SIGNED,
70253913Sarchie	NULL,
70353913Sarchie	ng_int64_parse,
70453913Sarchie	ng_int64_unparse,
70553913Sarchie	ng_int64_getDefault,
70653913Sarchie	ng_int64_getAlign
70753913Sarchie};
70853913Sarchie
70964505Sarchieconst struct ng_parse_type ng_parse_uint64_type = {
71064505Sarchie	&ng_parse_int64_type,
71164505Sarchie	(void *)INT_UNSIGNED
71264505Sarchie};
71364505Sarchie
71464505Sarchieconst struct ng_parse_type ng_parse_hint64_type = {
71564505Sarchie	&ng_parse_int64_type,
71664505Sarchie	(void *)INT_HEX
71764505Sarchie};
71864505Sarchie
71953913Sarchie/************************************************************************
72053913Sarchie				STRING TYPE
72153913Sarchie ************************************************************************/
72253913Sarchie
72353913Sarchiestatic int
72453913Sarchieng_string_parse(const struct ng_parse_type *type,
72553913Sarchie	const char *s, int *off, const u_char *const start,
72653913Sarchie	u_char *const buf, int *buflen)
72753913Sarchie{
72853913Sarchie	char *sval;
72953913Sarchie	int len;
73068845Sbrian	int slen;
73153913Sarchie
73268845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
73353913Sarchie		return (EINVAL);
73453913Sarchie	*off += len;
73568845Sbrian	bcopy(sval, buf, slen + 1);
73670870Sjulian	FREE(sval, M_NETGRAPH_PARSE);
73768845Sbrian	*buflen = slen + 1;
73853913Sarchie	return (0);
73953913Sarchie}
74053913Sarchie
74153913Sarchiestatic int
74253913Sarchieng_string_unparse(const struct ng_parse_type *type,
74353913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
74453913Sarchie{
74553913Sarchie	const char *const raw = (const char *)data + *off;
74668845Sbrian	char *const s = ng_encode_string(raw, strlen(raw));
74753913Sarchie
74853913Sarchie	if (s == NULL)
74953913Sarchie		return (ENOMEM);
75053913Sarchie	NG_PARSE_APPEND("%s", s);
75153913Sarchie	*off += strlen(raw) + 1;
75270870Sjulian	FREE(s, M_NETGRAPH_PARSE);
75353913Sarchie	return (0);
75453913Sarchie}
75553913Sarchie
75653913Sarchiestatic int
75753913Sarchieng_string_getDefault(const struct ng_parse_type *type,
75853913Sarchie	const u_char *const start, u_char *buf, int *buflen)
75953913Sarchie{
76053913Sarchie
76153913Sarchie	if (*buflen < 1)
76253913Sarchie		return (ERANGE);
76353913Sarchie	buf[0] = (u_char)'\0';
76453913Sarchie	*buflen = 1;
76553913Sarchie	return (0);
76653913Sarchie}
76753913Sarchie
76853913Sarchieconst struct ng_parse_type ng_parse_string_type = {
76953913Sarchie	NULL,
77053913Sarchie	NULL,
77153913Sarchie	NULL,
77253913Sarchie	ng_string_parse,
77353913Sarchie	ng_string_unparse,
77453913Sarchie	ng_string_getDefault,
77553913Sarchie	NULL
77653913Sarchie};
77753913Sarchie
77853913Sarchie/************************************************************************
77953913Sarchie			FIXED BUFFER STRING TYPE
78053913Sarchie ************************************************************************/
78153913Sarchie
78253913Sarchiestatic int
78353913Sarchieng_fixedstring_parse(const struct ng_parse_type *type,
78453913Sarchie	const char *s, int *off, const u_char *const start,
78553913Sarchie	u_char *const buf, int *buflen)
78653913Sarchie{
78758011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
78853913Sarchie	char *sval;
78953913Sarchie	int len;
79068845Sbrian	int slen;
79153913Sarchie
79268845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
79353913Sarchie		return (EINVAL);
79468845Sbrian	if (slen + 1 > fi->bufSize)
79553913Sarchie		return (E2BIG);
79653913Sarchie	*off += len;
79768845Sbrian	bcopy(sval, buf, slen);
79870870Sjulian	FREE(sval, M_NETGRAPH_PARSE);
79968845Sbrian	bzero(buf + slen, fi->bufSize - slen);
80053913Sarchie	*buflen = fi->bufSize;
80153913Sarchie	return (0);
80253913Sarchie}
80353913Sarchie
80453913Sarchiestatic int
80553913Sarchieng_fixedstring_unparse(const struct ng_parse_type *type,
80653913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
80753913Sarchie{
80858011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
80953913Sarchie	int error, temp = *off;
81053913Sarchie
81153913Sarchie	if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
81253913Sarchie		return (error);
81353913Sarchie	*off += fi->bufSize;
81453913Sarchie	return (0);
81553913Sarchie}
81653913Sarchie
81753913Sarchiestatic int
81853913Sarchieng_fixedstring_getDefault(const struct ng_parse_type *type,
81953913Sarchie	const u_char *const start, u_char *buf, int *buflen)
82053913Sarchie{
82158011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
82253913Sarchie
82353913Sarchie	if (*buflen < fi->bufSize)
82453913Sarchie		return (ERANGE);
82553913Sarchie	bzero(buf, fi->bufSize);
82653913Sarchie	*buflen = fi->bufSize;
82753913Sarchie	return (0);
82853913Sarchie}
82953913Sarchie
83053913Sarchieconst struct ng_parse_type ng_parse_fixedstring_type = {
83153913Sarchie	NULL,
83253913Sarchie	NULL,
83353913Sarchie	NULL,
83453913Sarchie	ng_fixedstring_parse,
83553913Sarchie	ng_fixedstring_unparse,
83653913Sarchie	ng_fixedstring_getDefault,
83753913Sarchie	NULL
83853913Sarchie};
83953913Sarchie
84058011Sarchieconst struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
84153913Sarchie	NG_NODELEN + 1
84253913Sarchie};
84353913Sarchieconst struct ng_parse_type ng_parse_nodebuf_type = {
84453913Sarchie	&ng_parse_fixedstring_type,
84553913Sarchie	&ng_parse_nodebuf_info
84653913Sarchie};
84753913Sarchie
84858011Sarchieconst struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
84953913Sarchie	NG_HOOKLEN + 1
85053913Sarchie};
85153913Sarchieconst struct ng_parse_type ng_parse_hookbuf_type = {
85253913Sarchie	&ng_parse_fixedstring_type,
85353913Sarchie	&ng_parse_hookbuf_info
85453913Sarchie};
85553913Sarchie
85658011Sarchieconst struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
85753913Sarchie	NG_PATHLEN + 1
85853913Sarchie};
85953913Sarchieconst struct ng_parse_type ng_parse_pathbuf_type = {
86053913Sarchie	&ng_parse_fixedstring_type,
86153913Sarchie	&ng_parse_pathbuf_info
86253913Sarchie};
86353913Sarchie
86458011Sarchieconst struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
86553913Sarchie	NG_TYPELEN + 1
86653913Sarchie};
86753913Sarchieconst struct ng_parse_type ng_parse_typebuf_type = {
86853913Sarchie	&ng_parse_fixedstring_type,
86953913Sarchie	&ng_parse_typebuf_info
87053913Sarchie};
87153913Sarchie
87258011Sarchieconst struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
87353913Sarchie	NG_CMDSTRLEN + 1
87453913Sarchie};
87553913Sarchieconst struct ng_parse_type ng_parse_cmdbuf_type = {
87653913Sarchie	&ng_parse_fixedstring_type,
87753913Sarchie	&ng_parse_cmdbuf_info
87853913Sarchie};
87953913Sarchie
88053913Sarchie/************************************************************************
88168845Sbrian			EXPLICITLY SIZED STRING TYPE
88268845Sbrian ************************************************************************/
88368845Sbrian
88468845Sbrianstatic int
88568845Sbrianng_sizedstring_parse(const struct ng_parse_type *type,
88668845Sbrian	const char *s, int *off, const u_char *const start,
88768845Sbrian	u_char *const buf, int *buflen)
88868845Sbrian{
88968845Sbrian	char *sval;
89068845Sbrian	int len;
89168845Sbrian	int slen;
89268845Sbrian
89368845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
89468845Sbrian		return (EINVAL);
89568845Sbrian	if (slen > 0xffff)
89668845Sbrian		return (EINVAL);
89768845Sbrian	*off += len;
89868845Sbrian	*((u_int16_t *)buf) = (u_int16_t)slen;
89968845Sbrian	bcopy(sval, buf + 2, slen);
90070870Sjulian	FREE(sval, M_NETGRAPH_PARSE);
90168845Sbrian	*buflen = 2 + slen;
90268845Sbrian	return (0);
90368845Sbrian}
90468845Sbrian
90568845Sbrianstatic int
90668845Sbrianng_sizedstring_unparse(const struct ng_parse_type *type,
90768845Sbrian	const u_char *data, int *off, char *cbuf, int cbuflen)
90868845Sbrian{
90968845Sbrian	const char *const raw = (const char *)data + *off + 2;
91068845Sbrian	const int slen = *((const u_int16_t *)(data + *off));
91168845Sbrian	char *const s = ng_encode_string(raw, slen);
91268845Sbrian
91368845Sbrian	if (s == NULL)
91468845Sbrian		return (ENOMEM);
91568845Sbrian	NG_PARSE_APPEND("%s", s);
91670870Sjulian	FREE(s, M_NETGRAPH_PARSE);
91768845Sbrian	*off += slen + 2;
91868845Sbrian	return (0);
91968845Sbrian}
92068845Sbrian
92168845Sbrianstatic int
92268845Sbrianng_sizedstring_getDefault(const struct ng_parse_type *type,
92368845Sbrian	const u_char *const start, u_char *buf, int *buflen)
92468845Sbrian{
92568845Sbrian	if (*buflen < 2)
92668845Sbrian		return (ERANGE);
92768845Sbrian	bzero(buf, 2);
92868845Sbrian	*buflen = 2;
92968845Sbrian	return (0);
93068845Sbrian}
93168845Sbrian
93268845Sbrianconst struct ng_parse_type ng_parse_sizedstring_type = {
93368845Sbrian	NULL,
93468845Sbrian	NULL,
93568845Sbrian	NULL,
93668845Sbrian	ng_sizedstring_parse,
93768845Sbrian	ng_sizedstring_unparse,
93868845Sbrian	ng_sizedstring_getDefault,
93968845Sbrian	NULL
94068845Sbrian};
94168845Sbrian
94268845Sbrian/************************************************************************
94353913Sarchie			IP ADDRESS TYPE
94453913Sarchie ************************************************************************/
94553913Sarchie
94653913Sarchiestatic int
94753913Sarchieng_ipaddr_parse(const struct ng_parse_type *type,
94853913Sarchie	const char *s, int *off, const u_char *const start,
94953913Sarchie	u_char *const buf, int *buflen)
95053913Sarchie{
95153913Sarchie	int i, error;
95253913Sarchie
95353913Sarchie	for (i = 0; i < 4; i++) {
95453913Sarchie		if ((error = ng_int8_parse(&ng_parse_int8_type,
95553913Sarchie		    s, off, start, buf + i, buflen)) != 0)
95653913Sarchie			return (error);
95753913Sarchie		if (i < 3 && s[*off] != '.')
95853913Sarchie			return (EINVAL);
95953913Sarchie		(*off)++;
96053913Sarchie	}
96153913Sarchie	*buflen = 4;
96253913Sarchie	return (0);
96353913Sarchie}
96453913Sarchie
96553913Sarchiestatic int
96653913Sarchieng_ipaddr_unparse(const struct ng_parse_type *type,
96753913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
96853913Sarchie{
96953913Sarchie	struct in_addr ip;
97053913Sarchie
97153913Sarchie	bcopy(data + *off, &ip, sizeof(ip));
97253913Sarchie	NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0],
97353913Sarchie	    ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]);
97453913Sarchie	*off += sizeof(ip);
97553913Sarchie	return (0);
97653913Sarchie}
97753913Sarchie
97853913Sarchiestatic int
97953913Sarchieng_ipaddr_getDefault(const struct ng_parse_type *type,
98053913Sarchie	const u_char *const start, u_char *buf, int *buflen)
98153913Sarchie{
98253913Sarchie	struct in_addr ip = { 0 };
98353913Sarchie
98453913Sarchie	if (*buflen < sizeof(ip))
98553913Sarchie		return (ERANGE);
98653913Sarchie	bcopy(&ip, buf, sizeof(ip));
98753913Sarchie	*buflen = sizeof(ip);
98853913Sarchie	return (0);
98953913Sarchie}
99053913Sarchie
99153913Sarchieconst struct ng_parse_type ng_parse_ipaddr_type = {
99253913Sarchie	NULL,
99353913Sarchie	NULL,
99453913Sarchie	NULL,
99553913Sarchie	ng_ipaddr_parse,
99653913Sarchie	ng_ipaddr_unparse,
99753913Sarchie	ng_ipaddr_getDefault,
99853913Sarchie	ng_int32_getAlign
99953913Sarchie};
100053913Sarchie
100153913Sarchie/************************************************************************
100253913Sarchie			BYTE ARRAY TYPE
100353913Sarchie ************************************************************************/
100453913Sarchie
100553913Sarchie/* Get the length of a byte array */
100653913Sarchiestatic int
100753913Sarchieng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
100853913Sarchie	const u_char *start, const u_char *buf)
100953913Sarchie{
101053913Sarchie	ng_parse_array_getLength_t *const getLength = type->private;
101153913Sarchie
101253913Sarchie	return (*getLength)(type, start, buf);
101353913Sarchie}
101453913Sarchie
101564505Sarchie/* Byte array element type is hex int8 */
101653913Sarchiestatic const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
101764505Sarchie	&ng_parse_hint8_type,
101853913Sarchie	&ng_parse_bytearray_subtype_getLength,
101953913Sarchie	NULL
102053913Sarchie};
102153913Sarchiestatic const struct ng_parse_type ng_parse_bytearray_subtype = {
102253913Sarchie	&ng_parse_array_type,
102353913Sarchie	&ng_parse_bytearray_subtype_info
102453913Sarchie};
102553913Sarchie
102653913Sarchiestatic int
102753913Sarchieng_bytearray_parse(const struct ng_parse_type *type,
102853913Sarchie	const char *s, int *off, const u_char *const start,
102953913Sarchie	u_char *const buf, int *buflen)
103053913Sarchie{
103153913Sarchie	char *str;
103253913Sarchie	int toklen;
103368845Sbrian	int slen;
103453913Sarchie
103553913Sarchie	/* We accept either an array of bytes or a string constant */
103668845Sbrian	if ((str = ng_get_string_token(s, off, &toklen, &slen)) != NULL) {
103753913Sarchie		ng_parse_array_getLength_t *const getLength = type->info;
103868845Sbrian		int arraylen;
103953913Sarchie
104053913Sarchie		arraylen = (*getLength)(type, start, buf);
104153913Sarchie		if (arraylen > *buflen) {
104270870Sjulian			FREE(str, M_NETGRAPH_PARSE);
104353913Sarchie			return (ERANGE);
104453913Sarchie		}
104553913Sarchie		if (slen > arraylen) {
104670870Sjulian			FREE(str, M_NETGRAPH_PARSE);
104753913Sarchie			return (E2BIG);
104853913Sarchie		}
104953913Sarchie		bcopy(str, buf, slen);
105053913Sarchie		bzero(buf + slen, arraylen - slen);
105170870Sjulian		FREE(str, M_NETGRAPH_PARSE);
105253913Sarchie		*off += toklen;
105353913Sarchie		*buflen = arraylen;
105453913Sarchie		return (0);
105553913Sarchie	} else {
105653913Sarchie		struct ng_parse_type subtype;
105753913Sarchie
105853913Sarchie		subtype = ng_parse_bytearray_subtype;
105953913Sarchie		(const void *)subtype.private = type->info;
106053913Sarchie		return ng_array_parse(&subtype, s, off, start, buf, buflen);
106153913Sarchie	}
106253913Sarchie}
106353913Sarchie
106453913Sarchiestatic int
106553913Sarchieng_bytearray_unparse(const struct ng_parse_type *type,
106653913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
106753913Sarchie{
106853913Sarchie	struct ng_parse_type subtype;
106953913Sarchie
107053913Sarchie	subtype = ng_parse_bytearray_subtype;
107153913Sarchie	(const void *)subtype.private = type->info;
107253913Sarchie	return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
107353913Sarchie}
107453913Sarchie
107553913Sarchiestatic int
107653913Sarchieng_bytearray_getDefault(const struct ng_parse_type *type,
107753913Sarchie	const u_char *const start, u_char *buf, int *buflen)
107853913Sarchie{
107953913Sarchie	struct ng_parse_type subtype;
108053913Sarchie
108153913Sarchie	subtype = ng_parse_bytearray_subtype;
108253913Sarchie	(const void *)subtype.private = type->info;
108353913Sarchie	return ng_array_getDefault(&subtype, start, buf, buflen);
108453913Sarchie}
108553913Sarchie
108653913Sarchieconst struct ng_parse_type ng_parse_bytearray_type = {
108753913Sarchie	NULL,
108853913Sarchie	NULL,
108953913Sarchie	NULL,
109053913Sarchie	ng_bytearray_parse,
109153913Sarchie	ng_bytearray_unparse,
109253913Sarchie	ng_bytearray_getDefault,
109353913Sarchie	NULL
109453913Sarchie};
109553913Sarchie
109653913Sarchie/************************************************************************
109753913Sarchie			STRUCT NG_MESG TYPE
109853913Sarchie ************************************************************************/
109953913Sarchie
110053913Sarchie/* Get msg->header.arglen when "buf" is pointing to msg->data */
110153913Sarchiestatic int
110253913Sarchieng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
110353913Sarchie	const u_char *start, const u_char *buf)
110453913Sarchie{
110553913Sarchie	const struct ng_mesg *msg;
110653913Sarchie
110753913Sarchie	msg = (const struct ng_mesg *)(buf - sizeof(*msg));
110853913Sarchie	return msg->header.arglen;
110953913Sarchie}
111053913Sarchie
111153913Sarchie/* Type for the variable length data portion of a struct ng_mesg */
111253913Sarchiestatic const struct ng_parse_type ng_msg_data_type = {
111353913Sarchie	&ng_parse_bytearray_type,
111453913Sarchie	&ng_parse_ng_mesg_getLength
111553913Sarchie};
111653913Sarchie
111753913Sarchie/* Type for the entire struct ng_mesg header with data section */
111897685Sarchiestatic const struct ng_parse_struct_field ng_parse_ng_mesg_type_fields[]
111997685Sarchie	= NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
112053913Sarchieconst struct ng_parse_type ng_parse_ng_mesg_type = {
112153913Sarchie	&ng_parse_struct_type,
112297685Sarchie	&ng_parse_ng_mesg_type_fields,
112353913Sarchie};
112453913Sarchie
112553913Sarchie/************************************************************************
112653913Sarchie			COMPOSITE HELPER ROUTINES
112753913Sarchie ************************************************************************/
112853913Sarchie
112953913Sarchie/*
113053913Sarchie * Convert a structure or array from ASCII to binary
113153913Sarchie */
113253913Sarchiestatic int
113353913Sarchieng_parse_composite(const struct ng_parse_type *type, const char *s,
113453913Sarchie	int *off, const u_char *const start, u_char *const buf, int *buflen,
113553913Sarchie	const enum comptype ctype)
113653913Sarchie{
113753913Sarchie	const int num = ng_get_composite_len(type, start, buf, ctype);
113853913Sarchie	int nextIndex = 0;		/* next implicit array index */
113953913Sarchie	u_int index;			/* field or element index */
114053913Sarchie	int *foff;			/* field value offsets in string */
114153913Sarchie	int align, len, blen, error = 0;
114253913Sarchie
114353913Sarchie	/* Initialize */
114470870Sjulian	MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO);
114553913Sarchie	if (foff == NULL) {
114653913Sarchie		error = ENOMEM;
114753913Sarchie		goto done;
114853913Sarchie	}
114953913Sarchie
115053913Sarchie	/* Get opening brace/bracket */
115153913Sarchie	if (ng_parse_get_token(s, off, &len)
115253913Sarchie	    != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
115353913Sarchie		error = EINVAL;
115453913Sarchie		goto done;
115553913Sarchie	}
115653913Sarchie	*off += len;
115753913Sarchie
115853913Sarchie	/* Get individual element value positions in the string */
115953913Sarchie	for (;;) {
116053913Sarchie		enum ng_parse_token tok;
116153913Sarchie
116253913Sarchie		/* Check for closing brace/bracket */
116353913Sarchie		tok = ng_parse_get_token(s, off, &len);
116453913Sarchie		if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
116553913Sarchie			*off += len;
116653913Sarchie			break;
116753913Sarchie		}
116853913Sarchie
116953913Sarchie		/* For arrays, the 'name' (ie, index) is optional, so
117053913Sarchie		   distinguish name from values by seeing if the next
117153913Sarchie		   token is an equals sign */
117253913Sarchie		if (ctype != CT_STRUCT) {
117353913Sarchie			int len2, off2;
117453913Sarchie			char *eptr;
117553913Sarchie
117653913Sarchie			/* If an opening brace/bracket, index is implied */
117753913Sarchie			if (tok == T_LBRACE || tok == T_LBRACKET) {
117853913Sarchie				index = nextIndex++;
117953913Sarchie				goto gotIndex;
118053913Sarchie			}
118153913Sarchie
118253913Sarchie			/* Might be an index, might be a value, either way... */
118353913Sarchie			if (tok != T_WORD) {
118453913Sarchie				error = EINVAL;
118553913Sarchie				goto done;
118653913Sarchie			}
118753913Sarchie
118853913Sarchie			/* If no equals sign follows, index is implied */
118953913Sarchie			off2 = *off + len;
119053913Sarchie			if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
119153913Sarchie				index = nextIndex++;
119253913Sarchie				goto gotIndex;
119353913Sarchie			}
119453913Sarchie
119553913Sarchie			/* Index was specified explicitly; parse it */
119653913Sarchie			index = (u_int)strtoul(s + *off, &eptr, 0);
119753913Sarchie			if (index < 0 || eptr - (s + *off) != len) {
119853913Sarchie				error = EINVAL;
119953913Sarchie				goto done;
120053913Sarchie			}
120153913Sarchie			nextIndex = index + 1;
120253913Sarchie			*off += len + len2;
120353913Sarchie		} else {			/* a structure field */
120497685Sarchie			const struct ng_parse_struct_field *const
120597685Sarchie			    fields = type->info;
120653913Sarchie
120753913Sarchie			/* Find the field by name (required) in field list */
120853913Sarchie			if (tok != T_WORD) {
120953913Sarchie				error = EINVAL;
121053913Sarchie				goto done;
121153913Sarchie			}
121253913Sarchie			for (index = 0; index < num; index++) {
121397685Sarchie				const struct ng_parse_struct_field *const
121497685Sarchie				    field = &fields[index];
121597685Sarchie
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		}
123397229SpetergotIndex:
123453913Sarchie
123553913Sarchie		/* Check array index */
123653913Sarchie		if (index >= num) {
123753913Sarchie			error = E2BIG;
123853913Sarchie			goto done;
123953913Sarchie		}
124053913Sarchie
124153913Sarchie		/* Save value's position and skip over it for now */
124253913Sarchie		if (foff[index] != 0) {
124353913Sarchie			error = EALREADY;		/* duplicate */
124453913Sarchie			goto done;
124553913Sarchie		}
124653913Sarchie		while (isspace(s[*off]))
124753913Sarchie			(*off)++;
124853913Sarchie		foff[index] = *off;
124953913Sarchie		if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
125053913Sarchie			goto done;
125153913Sarchie		*off += len;
125253913Sarchie	}
125353913Sarchie
125453913Sarchie	/* Now build binary structure from supplied values and defaults */
125553913Sarchie	for (blen = index = 0; index < num; index++) {
125653913Sarchie		const struct ng_parse_type *const
125753913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
125853913Sarchie		int k, pad, vlen;
125953913Sarchie
126053913Sarchie		/* Zero-pad any alignment bytes */
126153913Sarchie		pad = ng_parse_get_elem_pad(type, index, ctype, blen);
126253913Sarchie		for (k = 0; k < pad; k++) {
126353913Sarchie			if (blen >= *buflen) {
126453913Sarchie				error = ERANGE;
126553913Sarchie				goto done;
126653913Sarchie			}
126753913Sarchie			buf[blen++] = 0;
126853913Sarchie		}
126953913Sarchie
127053913Sarchie		/* Get value */
127153913Sarchie		vlen = *buflen - blen;
127253913Sarchie		if (foff[index] == 0) {		/* use default value */
127353913Sarchie			error = ng_get_composite_elem_default(type, index,
127453913Sarchie			    start, buf + blen, &vlen, ctype);
127553913Sarchie		} else {			/* parse given value */
127653913Sarchie			*off = foff[index];
127753913Sarchie			error = INVOKE(etype, parse)(etype,
127853913Sarchie			    s, off, start, buf + blen, &vlen);
127953913Sarchie		}
128053913Sarchie		if (error != 0)
128153913Sarchie			goto done;
128253913Sarchie		blen += vlen;
128353913Sarchie	}
128453913Sarchie
128553913Sarchie	/* Make total composite structure size a multiple of its alignment */
128653913Sarchie	if ((align = ALIGNMENT(type)) != 0) {
128753913Sarchie		while (blen % align != 0) {
128853913Sarchie			if (blen >= *buflen) {
128953913Sarchie				error = ERANGE;
129053913Sarchie				goto done;
129153913Sarchie			}
129253913Sarchie			buf[blen++] = 0;
129353913Sarchie		}
129453913Sarchie	}
129553913Sarchie
129653913Sarchie	/* Done */
129753913Sarchie	*buflen = blen;
129853913Sarchiedone:
129965303Sarchie	if (foff != NULL)
130070870Sjulian		FREE(foff, M_NETGRAPH_PARSE);
130153913Sarchie	return (error);
130253913Sarchie}
130353913Sarchie
130453913Sarchie/*
130553913Sarchie * Convert an array or structure from binary to ASCII
130653913Sarchie */
130753913Sarchiestatic int
130853913Sarchieng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
130953913Sarchie	int *off, char *cbuf, int cbuflen, const enum comptype ctype)
131053913Sarchie{
131190047Sarchie	const struct ng_mesg *const hdr
131290047Sarchie	    = (const struct ng_mesg *)(data - sizeof(*hdr));
131353913Sarchie	const int num = ng_get_composite_len(type, data, data + *off, ctype);
131464505Sarchie	const int workSize = 20 * 1024;		/* XXX hard coded constant */
131553913Sarchie	int nextIndex = 0, didOne = 0;
131653913Sarchie	int error, index;
131764505Sarchie	u_char *workBuf;
131853913Sarchie
131964505Sarchie	/* Get workspace for checking default values */
132070870Sjulian	MALLOC(workBuf, u_char *, workSize, M_NETGRAPH_PARSE, M_NOWAIT);
132164505Sarchie	if (workBuf == NULL)
132264505Sarchie		return (ENOMEM);
132364505Sarchie
132453913Sarchie	/* Opening brace/bracket */
132553913Sarchie	NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
132653913Sarchie
132753913Sarchie	/* Do each item */
132853913Sarchie	for (index = 0; index < num; index++) {
132953913Sarchie		const struct ng_parse_type *const
133053913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
133153913Sarchie
133253913Sarchie		/* Skip any alignment pad bytes */
133353913Sarchie		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
133453913Sarchie
133590047Sarchie		/*
133690047Sarchie		 * See if element is equal to its default value; skip if so.
133790047Sarchie		 * Copy struct ng_mesg header for types that peek into it.
133890047Sarchie		 */
133990047Sarchie		if (sizeof(*hdr) + *off < workSize) {
134090047Sarchie			int tempsize = workSize - sizeof(*hdr) - *off;
134153913Sarchie
134290584Sarchie			bcopy(hdr, workBuf, sizeof(*hdr) + *off);
134390047Sarchie			if (ng_get_composite_elem_default(type, index, workBuf
134490047Sarchie			      + sizeof(*hdr), workBuf + sizeof(*hdr) + *off,
134590047Sarchie			      &tempsize, ctype) == 0
134690047Sarchie			    && bcmp(workBuf + sizeof(*hdr) + *off,
134764505Sarchie			      data + *off, tempsize) == 0) {
134853913Sarchie				*off += tempsize;
134953913Sarchie				continue;
135053913Sarchie			}
135153913Sarchie		}
135253913Sarchie
135353913Sarchie		/* Print name= */
135453913Sarchie		NG_PARSE_APPEND(" ");
135553913Sarchie		if (ctype != CT_STRUCT) {
135653913Sarchie			if (index != nextIndex) {
135753913Sarchie				nextIndex = index;
135853913Sarchie				NG_PARSE_APPEND("%d=", index);
135953913Sarchie			}
136053913Sarchie			nextIndex++;
136153913Sarchie		} else {
136297685Sarchie			const struct ng_parse_struct_field *const
136397685Sarchie			    fields = type->info;
136453913Sarchie
136597685Sarchie			NG_PARSE_APPEND("%s=", fields[index].name);
136653913Sarchie		}
136753913Sarchie
136853913Sarchie		/* Print value */
136953913Sarchie		if ((error = INVOKE(etype, unparse)
137064505Sarchie		    (etype, data, off, cbuf, cbuflen)) != 0) {
137170870Sjulian			FREE(workBuf, M_NETGRAPH_PARSE);
137253913Sarchie			return (error);
137364505Sarchie		}
137453913Sarchie		cbuflen -= strlen(cbuf);
137553913Sarchie		cbuf += strlen(cbuf);
137653913Sarchie		didOne = 1;
137753913Sarchie	}
137870870Sjulian	FREE(workBuf, M_NETGRAPH_PARSE);
137953913Sarchie
138053913Sarchie	/* Closing brace/bracket */
138153913Sarchie	NG_PARSE_APPEND("%s%c",
138253913Sarchie	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
138353913Sarchie	return (0);
138453913Sarchie}
138553913Sarchie
138653913Sarchie/*
138753913Sarchie * Generate the default value for an element of an array or structure
138853913Sarchie * Returns EOPNOTSUPP if default value is unspecified.
138953913Sarchie */
139053913Sarchiestatic int
139153913Sarchieng_get_composite_elem_default(const struct ng_parse_type *type,
139253913Sarchie	int index, const u_char *const start, u_char *buf, int *buflen,
139353913Sarchie	const enum comptype ctype)
139453913Sarchie{
139553913Sarchie	const struct ng_parse_type *etype;
139653913Sarchie	ng_getDefault_t *func;
139753913Sarchie
139853913Sarchie	switch (ctype) {
139953913Sarchie	case CT_STRUCT:
140053913Sarchie		break;
140153913Sarchie	case CT_ARRAY:
140253913Sarchie	    {
140353913Sarchie		const struct ng_parse_array_info *const ai = type->info;
140453913Sarchie
140553913Sarchie		if (ai->getDefault != NULL) {
140653913Sarchie			return (*ai->getDefault)(type,
140753913Sarchie			    index, start, buf, buflen);
140853913Sarchie		}
140953913Sarchie		break;
141053913Sarchie	    }
141153913Sarchie	case CT_FIXEDARRAY:
141253913Sarchie	    {
141353913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
141453913Sarchie
141553913Sarchie		if (*fi->getDefault != NULL) {
141653913Sarchie			return (*fi->getDefault)(type,
141753913Sarchie			    index, start, buf, buflen);
141853913Sarchie		}
141953913Sarchie		break;
142053913Sarchie	    }
142153913Sarchie	default:
142287599Sobrien	    panic("%s", __func__);
142353913Sarchie	}
142453913Sarchie
142553913Sarchie	/* Default to element type default */
142653913Sarchie	etype = ng_get_composite_etype(type, index, ctype);
142753913Sarchie	func = METHOD(etype, getDefault);
142853913Sarchie	if (func == NULL)
142953913Sarchie		return (EOPNOTSUPP);
143053913Sarchie	return (*func)(etype, start, buf, buflen);
143153913Sarchie}
143253913Sarchie
143353913Sarchie/*
143453913Sarchie * Get the number of elements in a struct, variable or fixed array.
143553913Sarchie */
143653913Sarchiestatic int
143753913Sarchieng_get_composite_len(const struct ng_parse_type *type,
143853913Sarchie	const u_char *const start, const u_char *buf,
143953913Sarchie	const enum comptype ctype)
144053913Sarchie{
144153913Sarchie	switch (ctype) {
144253913Sarchie	case CT_STRUCT:
144353913Sarchie	    {
144497685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
144553913Sarchie		int numFields = 0;
144653913Sarchie
144753913Sarchie		for (numFields = 0; ; numFields++) {
144853913Sarchie			const struct ng_parse_struct_field *const
144997685Sarchie				fi = &fields[numFields];
145053913Sarchie
145153913Sarchie			if (fi->name == NULL)
145253913Sarchie				break;
145353913Sarchie		}
145453913Sarchie		return (numFields);
145553913Sarchie	    }
145653913Sarchie	case CT_ARRAY:
145753913Sarchie	    {
145853913Sarchie		const struct ng_parse_array_info *const ai = type->info;
145953913Sarchie
146053913Sarchie		return (*ai->getLength)(type, start, buf);
146153913Sarchie	    }
146253913Sarchie	case CT_FIXEDARRAY:
146353913Sarchie	    {
146453913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
146553913Sarchie
146653913Sarchie		return fi->length;
146753913Sarchie	    }
146853913Sarchie	default:
146987599Sobrien	    panic("%s", __func__);
147053913Sarchie	}
147153913Sarchie	return (0);
147253913Sarchie}
147353913Sarchie
147453913Sarchie/*
147553913Sarchie * Return the type of the index'th element of a composite structure
147653913Sarchie */
147753913Sarchiestatic const struct ng_parse_type *
147853913Sarchieng_get_composite_etype(const struct ng_parse_type *type,
147953913Sarchie	int index, const enum comptype ctype)
148053913Sarchie{
148153913Sarchie	const struct ng_parse_type *etype = NULL;
148253913Sarchie
148353913Sarchie	switch (ctype) {
148453913Sarchie	case CT_STRUCT:
148553913Sarchie	    {
148697685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
148753913Sarchie
148897685Sarchie		etype = fields[index].type;
148953913Sarchie		break;
149053913Sarchie	    }
149153913Sarchie	case CT_ARRAY:
149253913Sarchie	    {
149353913Sarchie		const struct ng_parse_array_info *const ai = type->info;
149453913Sarchie
149553913Sarchie		etype = ai->elementType;
149653913Sarchie		break;
149753913Sarchie	    }
149853913Sarchie	case CT_FIXEDARRAY:
149953913Sarchie	    {
150053913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
150153913Sarchie
150253913Sarchie		etype = fi->elementType;
150353913Sarchie		break;
150453913Sarchie	    }
150553913Sarchie	default:
150687599Sobrien	    panic("%s", __func__);
150753913Sarchie	}
150853913Sarchie	return (etype);
150953913Sarchie}
151053913Sarchie
151153913Sarchie/*
151253913Sarchie * Get the number of bytes to skip to align for the next
151353913Sarchie * element in a composite structure.
151453913Sarchie */
151553913Sarchiestatic int
151653913Sarchieng_parse_get_elem_pad(const struct ng_parse_type *type,
151753913Sarchie	int index, enum comptype ctype, int posn)
151853913Sarchie{
151953913Sarchie	const struct ng_parse_type *const
152053913Sarchie	    etype = ng_get_composite_etype(type, index, ctype);
152153913Sarchie	int align;
152253913Sarchie
152353913Sarchie	/* Get element's alignment, and possibly override */
152453913Sarchie	align = ALIGNMENT(etype);
152553913Sarchie	if (ctype == CT_STRUCT) {
152697685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
152753913Sarchie
152897685Sarchie		if (fields[index].alignment != 0)
152997685Sarchie			align = fields[index].alignment;
153053913Sarchie	}
153153913Sarchie
153253913Sarchie	/* Return number of bytes to skip to align */
153353913Sarchie	return (align ? (align - (posn % align)) % align : 0);
153453913Sarchie}
153553913Sarchie
153653913Sarchie/************************************************************************
153753913Sarchie			PARSING HELPER ROUTINES
153853913Sarchie ************************************************************************/
153953913Sarchie
154053913Sarchie/*
154153913Sarchie * Skip over a value
154253913Sarchie */
154353913Sarchiestatic int
154453913Sarchieng_parse_skip_value(const char *s, int off0, int *lenp)
154553913Sarchie{
154653913Sarchie	int len, nbracket, nbrace;
154753913Sarchie	int off = off0;
154853913Sarchie
154953913Sarchie	len = nbracket = nbrace = 0;
155053913Sarchie	do {
155153913Sarchie		switch (ng_parse_get_token(s, &off, &len)) {
155253913Sarchie		case T_LBRACKET:
155353913Sarchie			nbracket++;
155453913Sarchie			break;
155553913Sarchie		case T_LBRACE:
155653913Sarchie			nbrace++;
155753913Sarchie			break;
155853913Sarchie		case T_RBRACKET:
155953913Sarchie			if (nbracket-- == 0)
156053913Sarchie				return (EINVAL);
156153913Sarchie			break;
156253913Sarchie		case T_RBRACE:
156353913Sarchie			if (nbrace-- == 0)
156453913Sarchie				return (EINVAL);
156553913Sarchie			break;
156653913Sarchie		case T_EOF:
156753913Sarchie			return (EINVAL);
156853913Sarchie		default:
156953913Sarchie			break;
157053913Sarchie		}
157153913Sarchie		off += len;
157253913Sarchie	} while (nbracket > 0 || nbrace > 0);
157353913Sarchie	*lenp = off - off0;
157453913Sarchie	return (0);
157553913Sarchie}
157653913Sarchie
157753913Sarchie/*
157853913Sarchie * Find the next token in the string, starting at offset *startp.
157953913Sarchie * Returns the token type, with *startp pointing to the first char
158053913Sarchie * and *lenp the length.
158153913Sarchie */
158253913Sarchieenum ng_parse_token
158353913Sarchieng_parse_get_token(const char *s, int *startp, int *lenp)
158453913Sarchie{
158553913Sarchie	char *t;
158653913Sarchie	int i;
158753913Sarchie
158853913Sarchie	while (isspace(s[*startp]))
158953913Sarchie		(*startp)++;
159053913Sarchie	switch (s[*startp]) {
159153913Sarchie	case '\0':
159253913Sarchie		*lenp = 0;
159353913Sarchie		return T_EOF;
159453913Sarchie	case '{':
159553913Sarchie		*lenp = 1;
159653913Sarchie		return T_LBRACE;
159753913Sarchie	case '}':
159853913Sarchie		*lenp = 1;
159953913Sarchie		return T_RBRACE;
160053913Sarchie	case '[':
160153913Sarchie		*lenp = 1;
160253913Sarchie		return T_LBRACKET;
160353913Sarchie	case ']':
160453913Sarchie		*lenp = 1;
160553913Sarchie		return T_RBRACKET;
160653913Sarchie	case '=':
160753913Sarchie		*lenp = 1;
160853913Sarchie		return T_EQUALS;
160953913Sarchie	case '"':
161068845Sbrian		if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
161153913Sarchie			return T_ERROR;
161270870Sjulian		FREE(t, M_NETGRAPH_PARSE);
161353913Sarchie		return T_STRING;
161453913Sarchie	default:
161553913Sarchie		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
161653913Sarchie		    && s[i] != '{' && s[i] != '}' && s[i] != '['
161753913Sarchie		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
161853913Sarchie			;
161953913Sarchie		*lenp = i - *startp;
162053913Sarchie		return T_WORD;
162153913Sarchie	}
162253913Sarchie}
162353913Sarchie
162453913Sarchie/*
162553913Sarchie * Get a string token, which must be enclosed in double quotes.
162653913Sarchie * The normal C backslash escapes are recognized.
162753913Sarchie */
162853913Sarchiechar *
162968845Sbrianng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
163053913Sarchie{
163153913Sarchie	char *cbuf, *p;
163253913Sarchie	int start, off;
163368845Sbrian	int slen;
163453913Sarchie
163553913Sarchie	while (isspace(s[*startp]))
163653913Sarchie		(*startp)++;
163753913Sarchie	start = *startp;
163853913Sarchie	if (s[*startp] != '"')
163953913Sarchie		return (NULL);
164070870Sjulian	MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
164153913Sarchie	if (cbuf == NULL)
164253913Sarchie		return (NULL);
164353913Sarchie	strcpy(cbuf, s + start + 1);
164468845Sbrian	for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
164553913Sarchie		if (*p == '"') {
164653913Sarchie			*p = '\0';
164753913Sarchie			*lenp = off + 1;
164868845Sbrian			if (slenp != NULL)
164968845Sbrian				*slenp = slen;
165053913Sarchie			return (cbuf);
165153913Sarchie		} else if (p[0] == '\\' && p[1] != '\0') {
165253913Sarchie			int x, k;
165353913Sarchie			char *v;
165453913Sarchie
165553913Sarchie			strcpy(p, p + 1);
165653913Sarchie			v = p;
165753913Sarchie			switch (*p) {
165853913Sarchie			case 't':
165953913Sarchie				*v = '\t';
166053913Sarchie				off++;
166153913Sarchie				continue;
166253913Sarchie			case 'n':
166353913Sarchie				*v = '\n';
166453913Sarchie				off++;
166553913Sarchie				continue;
166653913Sarchie			case 'r':
166753913Sarchie				*v = '\r';
166853913Sarchie				off++;
166953913Sarchie				continue;
167053913Sarchie			case 'v':
167153913Sarchie				*v =  '\v';
167253913Sarchie				off++;
167353913Sarchie				continue;
167453913Sarchie			case 'f':
167553913Sarchie				*v =  '\f';
167653913Sarchie				off++;
167753913Sarchie				continue;
167853913Sarchie			case '"':
167953913Sarchie				*v =  '"';
168053913Sarchie				off++;
168153913Sarchie				continue;
168253913Sarchie			case '0': case '1': case '2': case '3':
168353913Sarchie			case '4': case '5': case '6': case '7':
168453913Sarchie				for (x = k = 0;
168553913Sarchie				    k < 3 && *v >= '0' && *v <= '7'; v++) {
168653913Sarchie					x = (x << 3) + (*v - '0');
168753913Sarchie					off++;
168853913Sarchie				}
168953913Sarchie				*--v = (char)x;
169053913Sarchie				break;
169153913Sarchie			case 'x':
169253913Sarchie				for (v++, x = k = 0;
169353913Sarchie				    k < 2 && isxdigit(*v); v++) {
169453913Sarchie					x = (x << 4) + (isdigit(*v) ?
169553913Sarchie					      (*v - '0') :
169653913Sarchie					      (tolower(*v) - 'a' + 10));
169753913Sarchie					off++;
169853913Sarchie				}
169953913Sarchie				*--v = (char)x;
170053913Sarchie				break;
170153913Sarchie			default:
170253913Sarchie				continue;
170353913Sarchie			}
170453913Sarchie			strcpy(p, v);
170553913Sarchie		}
170653913Sarchie	}
170753913Sarchie	return (NULL);		/* no closing quote */
170853913Sarchie}
170953913Sarchie
171053913Sarchie/*
171153913Sarchie * Encode a string so it can be safely put in double quotes.
171268845Sbrian * Caller must free the result. Exactly "slen" characters
171368845Sbrian * are encoded.
171453913Sarchie */
171553913Sarchiechar *
171668845Sbrianng_encode_string(const char *raw, int slen)
171753913Sarchie{
171853913Sarchie	char *cbuf;
171953913Sarchie	int off = 0;
172068845Sbrian	int i;
172153913Sarchie
172270870Sjulian	MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
172353913Sarchie	if (cbuf == NULL)
172453913Sarchie		return (NULL);
172553913Sarchie	cbuf[off++] = '"';
172668845Sbrian	for (i = 0; i < slen; i++, raw++) {
172753913Sarchie		switch (*raw) {
172853913Sarchie		case '\t':
172953913Sarchie			cbuf[off++] = '\\';
173053913Sarchie			cbuf[off++] = 't';
173153913Sarchie			break;
173253913Sarchie		case '\f':
173353913Sarchie			cbuf[off++] = '\\';
173453913Sarchie			cbuf[off++] = 'f';
173553913Sarchie			break;
173653913Sarchie		case '\n':
173753913Sarchie			cbuf[off++] = '\\';
173853913Sarchie			cbuf[off++] = 'n';
173953913Sarchie			break;
174053913Sarchie		case '\r':
174153913Sarchie			cbuf[off++] = '\\';
174253913Sarchie			cbuf[off++] = 'r';
174353913Sarchie			break;
174453913Sarchie		case '\v':
174553913Sarchie			cbuf[off++] = '\\';
174653913Sarchie			cbuf[off++] = 'v';
174753913Sarchie			break;
174853913Sarchie		case '"':
174953913Sarchie		case '\\':
175053913Sarchie			cbuf[off++] = '\\';
175153913Sarchie			cbuf[off++] = *raw;
175253913Sarchie			break;
175353913Sarchie		default:
175453913Sarchie			if (*raw < 0x20 || *raw > 0x7e) {
175553913Sarchie				off += sprintf(cbuf + off,
175653913Sarchie				    "\\x%02x", (u_char)*raw);
175753913Sarchie				break;
175853913Sarchie			}
175953913Sarchie			cbuf[off++] = *raw;
176053913Sarchie			break;
176153913Sarchie		}
176253913Sarchie	}
176353913Sarchie	cbuf[off++] = '"';
176453913Sarchie	cbuf[off] = '\0';
176553913Sarchie	return (cbuf);
176653913Sarchie}
176753913Sarchie
176853913Sarchie/************************************************************************
176953913Sarchie			VIRTUAL METHOD LOOKUP
177053913Sarchie ************************************************************************/
177153913Sarchie
177253913Sarchiestatic ng_parse_t *
177353913Sarchieng_get_parse_method(const struct ng_parse_type *t)
177453913Sarchie{
177553913Sarchie	while (t != NULL && t->parse == NULL)
177653913Sarchie		t = t->supertype;
177753913Sarchie	return (t ? t->parse : NULL);
177853913Sarchie}
177953913Sarchie
178053913Sarchiestatic ng_unparse_t *
178153913Sarchieng_get_unparse_method(const struct ng_parse_type *t)
178253913Sarchie{
178353913Sarchie	while (t != NULL && t->unparse == NULL)
178453913Sarchie		t = t->supertype;
178553913Sarchie	return (t ? t->unparse : NULL);
178653913Sarchie}
178753913Sarchie
178853913Sarchiestatic ng_getDefault_t *
178953913Sarchieng_get_getDefault_method(const struct ng_parse_type *t)
179053913Sarchie{
179153913Sarchie	while (t != NULL && t->getDefault == NULL)
179253913Sarchie		t = t->supertype;
179353913Sarchie	return (t ? t->getDefault : NULL);
179453913Sarchie}
179553913Sarchie
179653913Sarchiestatic ng_getAlign_t *
179753913Sarchieng_get_getAlign_method(const struct ng_parse_type *t)
179853913Sarchie{
179953913Sarchie	while (t != NULL && t->getAlign == NULL)
180053913Sarchie		t = t->supertype;
180153913Sarchie	return (t ? t->getAlign : NULL);
180253913Sarchie}
180353913Sarchie
1804