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