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$
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>
49154353Sglebius#include <sys/limits.h>
5053913Sarchie#include <sys/malloc.h>
51131108Sjulian#include <sys/mbuf.h>
5253913Sarchie#include <sys/ctype.h>
5353913Sarchie
54142902Sglebius#include <machine/stdarg.h>
55142902Sglebius
56123600Sru#include <net/ethernet.h>
57123600Sru
5853913Sarchie#include <netinet/in.h>
5953913Sarchie
6053913Sarchie#include <netgraph/ng_message.h>
6153913Sarchie#include <netgraph/netgraph.h>
6253913Sarchie#include <netgraph/ng_parse.h>
6353913Sarchie
6470870Sjulian#ifdef NG_SEPARATE_MALLOC
65249132Smavstatic MALLOC_DEFINE(M_NETGRAPH_PARSE, "netgraph_parse", "netgraph parse info");
6670870Sjulian#else
6770870Sjulian#define M_NETGRAPH_PARSE M_NETGRAPH
6870870Sjulian#endif
6970870Sjulian
7053913Sarchie/* Compute alignment for primitive integral types */
7153913Sarchiestruct int16_temp {
7253913Sarchie	char	x;
7353913Sarchie	int16_t	y;
7453913Sarchie};
7553913Sarchie
7653913Sarchiestruct int32_temp {
7753913Sarchie	char	x;
7853913Sarchie	int32_t	y;
7953913Sarchie};
8053913Sarchie
8153913Sarchiestruct int64_temp {
8253913Sarchie	char	x;
8353913Sarchie	int64_t	y;
8453913Sarchie};
8553913Sarchie
8653913Sarchie#define INT8_ALIGNMENT		1
87170996Smjacob#define INT16_ALIGNMENT		((size_t)&((struct int16_temp *)0)->y)
88170996Smjacob#define INT32_ALIGNMENT		((size_t)&((struct int32_temp *)0)->y)
89170996Smjacob#define INT64_ALIGNMENT		((size_t)&((struct int64_temp *)0)->y)
9053913Sarchie
9164505Sarchie/* Output format for integral types */
9264505Sarchie#define INT_UNSIGNED		0
9364505Sarchie#define INT_SIGNED		1
9464505Sarchie#define INT_HEX			2
9564505Sarchie
9653913Sarchie/* Type of composite object: struct, array, or fixedarray */
9753913Sarchieenum comptype {
9853913Sarchie	CT_STRUCT,
9953913Sarchie	CT_ARRAY,
10053913Sarchie	CT_FIXEDARRAY,
10153913Sarchie};
10253913Sarchie
10353913Sarchie/* Composite types helper functions */
10453913Sarchiestatic int	ng_parse_composite(const struct ng_parse_type *type,
10553913Sarchie			const char *s, int *off, const u_char *start,
10653913Sarchie			u_char *const buf, int *buflen, enum comptype ctype);
10753913Sarchiestatic int	ng_unparse_composite(const struct ng_parse_type *type,
10853913Sarchie			const u_char *data, int *off, char *cbuf, int cbuflen,
10953913Sarchie			enum comptype ctype);
11053913Sarchiestatic int	ng_get_composite_elem_default(const struct ng_parse_type *type,
11153913Sarchie			int index, const u_char *start, u_char *buf,
11253913Sarchie			int *buflen, enum comptype ctype);
11353913Sarchiestatic int	ng_get_composite_len(const struct ng_parse_type *type,
11453913Sarchie			const u_char *start, const u_char *buf,
11553913Sarchie			enum comptype ctype);
11653913Sarchiestatic const	struct ng_parse_type *ng_get_composite_etype(const struct
11753913Sarchie			ng_parse_type *type, int index, enum comptype ctype);
11853913Sarchiestatic int	ng_parse_get_elem_pad(const struct ng_parse_type *type,
11953913Sarchie			int index, enum comptype ctype, int posn);
12053913Sarchie
12153913Sarchie/* Parsing helper functions */
12253913Sarchiestatic int	ng_parse_skip_value(const char *s, int off, int *lenp);
123142902Sglebiusstatic int	ng_parse_append(char **cbufp, int *cbuflenp,
124142902Sglebius			const char *fmt, ...);
12553913Sarchie
12653913Sarchie/* Poor man's virtual method calls */
12753913Sarchie#define METHOD(t,m)	(ng_get_ ## m ## _method(t))
12853913Sarchie#define INVOKE(t,m)	(*METHOD(t,m))
12953913Sarchie
13053913Sarchiestatic ng_parse_t	*ng_get_parse_method(const struct ng_parse_type *t);
13153913Sarchiestatic ng_unparse_t	*ng_get_unparse_method(const struct ng_parse_type *t);
13253913Sarchiestatic ng_getDefault_t	*ng_get_getDefault_method(const
13353913Sarchie				struct ng_parse_type *t);
13453913Sarchiestatic ng_getAlign_t	*ng_get_getAlign_method(const struct ng_parse_type *t);
13553913Sarchie
13653913Sarchie#define ALIGNMENT(t)	(METHOD(t, getAlign) == NULL ? \
13753913Sarchie				0 : INVOKE(t, getAlign)(t))
13853913Sarchie
13953913Sarchie/************************************************************************
14053913Sarchie			PUBLIC FUNCTIONS
14153913Sarchie ************************************************************************/
14253913Sarchie
14353913Sarchie/*
14453913Sarchie * Convert an ASCII string to binary according to the supplied type descriptor
14553913Sarchie */
14653913Sarchieint
14753913Sarchieng_parse(const struct ng_parse_type *type,
14853913Sarchie	const char *string, int *off, u_char *buf, int *buflen)
14953913Sarchie{
15053913Sarchie	return INVOKE(type, parse)(type, string, off, buf, buf, buflen);
15153913Sarchie}
15253913Sarchie
15353913Sarchie/*
15453913Sarchie * Convert binary to an ASCII string according to the supplied type descriptor
15553913Sarchie */
15653913Sarchieint
15753913Sarchieng_unparse(const struct ng_parse_type *type,
15853913Sarchie	const u_char *data, char *cbuf, int cbuflen)
15953913Sarchie{
16053913Sarchie	int off = 0;
16153913Sarchie
16253913Sarchie	return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen);
16353913Sarchie}
16453913Sarchie
16553913Sarchie/*
16653913Sarchie * Fill in the default value according to the supplied type descriptor
16753913Sarchie */
16853913Sarchieint
16953913Sarchieng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen)
17053913Sarchie{
17153913Sarchie	ng_getDefault_t *const func = METHOD(type, getDefault);
17253913Sarchie
17353913Sarchie	if (func == NULL)
17453913Sarchie		return (EOPNOTSUPP);
17553913Sarchie	return (*func)(type, buf, buf, buflen);
17653913Sarchie}
17753913Sarchie
17853913Sarchie
17953913Sarchie/************************************************************************
18053913Sarchie			STRUCTURE TYPE
18153913Sarchie ************************************************************************/
18253913Sarchie
18353913Sarchiestatic int
18453913Sarchieng_struct_parse(const struct ng_parse_type *type,
18553913Sarchie	const char *s, int *off, const u_char *const start,
18653913Sarchie	u_char *const buf, int *buflen)
18753913Sarchie{
18853913Sarchie	return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT);
18953913Sarchie}
19053913Sarchie
19153913Sarchiestatic int
19253913Sarchieng_struct_unparse(const struct ng_parse_type *type,
19353913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
19453913Sarchie{
19553913Sarchie	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT);
19653913Sarchie}
19753913Sarchie
19853913Sarchiestatic int
19953913Sarchieng_struct_getDefault(const struct ng_parse_type *type,
20053913Sarchie	const u_char *const start, u_char *buf, int *buflen)
20153913Sarchie{
20253913Sarchie	int off = 0;
20353913Sarchie
20453913Sarchie	return ng_parse_composite(type,
20553913Sarchie	    "{}", &off, start, buf, buflen, CT_STRUCT);
20653913Sarchie}
20753913Sarchie
20853913Sarchiestatic int
20953913Sarchieng_struct_getAlign(const struct ng_parse_type *type)
21053913Sarchie{
21153913Sarchie	const struct ng_parse_struct_field *field;
21253913Sarchie	int align = 0;
21353913Sarchie
21497685Sarchie	for (field = type->info; field->name != NULL; field++) {
21553913Sarchie		int falign = ALIGNMENT(field->type);
21653913Sarchie
21753913Sarchie		if (falign > align)
21853913Sarchie			align = falign;
21953913Sarchie	}
22053913Sarchie	return align;
22153913Sarchie}
22253913Sarchie
22353913Sarchieconst struct ng_parse_type ng_parse_struct_type = {
22453913Sarchie	NULL,
22553913Sarchie	NULL,
22653913Sarchie	NULL,
22753913Sarchie	ng_struct_parse,
22853913Sarchie	ng_struct_unparse,
22953913Sarchie	ng_struct_getDefault,
23053913Sarchie	ng_struct_getAlign
23153913Sarchie};
23253913Sarchie
23353913Sarchie/************************************************************************
23453913Sarchie			FIXED LENGTH ARRAY TYPE
23553913Sarchie ************************************************************************/
23653913Sarchie
23753913Sarchiestatic int
23853913Sarchieng_fixedarray_parse(const struct ng_parse_type *type,
23953913Sarchie	const char *s, int *off, const u_char *const start,
24053913Sarchie	u_char *const buf, int *buflen)
24153913Sarchie{
24253913Sarchie	return ng_parse_composite(type,
24353913Sarchie	    s, off, start, buf, buflen, CT_FIXEDARRAY);
24453913Sarchie}
24553913Sarchie
24653913Sarchiestatic int
24753913Sarchieng_fixedarray_unparse(const struct ng_parse_type *type,
24853913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
24953913Sarchie{
25053913Sarchie	return ng_unparse_composite(type,
25153913Sarchie		data, off, cbuf, cbuflen, CT_FIXEDARRAY);
25253913Sarchie}
25353913Sarchie
25453913Sarchiestatic int
25553913Sarchieng_fixedarray_getDefault(const struct ng_parse_type *type,
25653913Sarchie	const u_char *const start, u_char *buf, int *buflen)
25753913Sarchie{
25853913Sarchie	int off = 0;
25953913Sarchie
26053913Sarchie	return ng_parse_composite(type,
26153913Sarchie	    "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
26253913Sarchie}
26353913Sarchie
26453913Sarchiestatic int
26553913Sarchieng_fixedarray_getAlign(const struct ng_parse_type *type)
26653913Sarchie{
26753913Sarchie	const struct ng_parse_fixedarray_info *fi = type->info;
26853913Sarchie
26953913Sarchie	return ALIGNMENT(fi->elementType);
27053913Sarchie}
27153913Sarchie
27253913Sarchieconst struct ng_parse_type ng_parse_fixedarray_type = {
27353913Sarchie	NULL,
27453913Sarchie	NULL,
27553913Sarchie	NULL,
27653913Sarchie	ng_fixedarray_parse,
27753913Sarchie	ng_fixedarray_unparse,
27853913Sarchie	ng_fixedarray_getDefault,
27953913Sarchie	ng_fixedarray_getAlign
28053913Sarchie};
28153913Sarchie
28253913Sarchie/************************************************************************
28353913Sarchie			VARIABLE LENGTH ARRAY TYPE
28453913Sarchie ************************************************************************/
28553913Sarchie
28653913Sarchiestatic int
28753913Sarchieng_array_parse(const struct ng_parse_type *type,
28853913Sarchie	const char *s, int *off, const u_char *const start,
28953913Sarchie	u_char *const buf, int *buflen)
29053913Sarchie{
29153913Sarchie	return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
29253913Sarchie}
29353913Sarchie
29453913Sarchiestatic int
29553913Sarchieng_array_unparse(const struct ng_parse_type *type,
29653913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
29753913Sarchie{
29853913Sarchie	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
29953913Sarchie}
30053913Sarchie
30153913Sarchiestatic int
30253913Sarchieng_array_getDefault(const struct ng_parse_type *type,
30353913Sarchie	const u_char *const start, u_char *buf, int *buflen)
30453913Sarchie{
30553913Sarchie	int off = 0;
30653913Sarchie
30753913Sarchie	return ng_parse_composite(type,
30853913Sarchie	    "[]", &off, start, buf, buflen, CT_ARRAY);
30953913Sarchie}
31053913Sarchie
31153913Sarchiestatic int
31253913Sarchieng_array_getAlign(const struct ng_parse_type *type)
31353913Sarchie{
31453913Sarchie	const struct ng_parse_array_info *ai = type->info;
31553913Sarchie
31653913Sarchie	return ALIGNMENT(ai->elementType);
31753913Sarchie}
31853913Sarchie
31953913Sarchieconst struct ng_parse_type ng_parse_array_type = {
32053913Sarchie	NULL,
32153913Sarchie	NULL,
32253913Sarchie	NULL,
32353913Sarchie	ng_array_parse,
32453913Sarchie	ng_array_unparse,
32553913Sarchie	ng_array_getDefault,
32653913Sarchie	ng_array_getAlign
32753913Sarchie};
32853913Sarchie
32953913Sarchie/************************************************************************
33053913Sarchie				INT8 TYPE
33153913Sarchie ************************************************************************/
33253913Sarchie
33353913Sarchiestatic int
33453913Sarchieng_int8_parse(const struct ng_parse_type *type,
33553913Sarchie	const char *s, int *off, const u_char *const start,
33653913Sarchie	u_char *const buf, int *buflen)
33753913Sarchie{
33853913Sarchie	long val;
33953913Sarchie	int8_t val8;
34053913Sarchie	char *eptr;
34153913Sarchie
34253913Sarchie	val = strtol(s + *off, &eptr, 0);
34376860Sjdp	if (val < (int8_t)0x80 || val > (u_int8_t)0xff || eptr == s + *off)
34453913Sarchie		return (EINVAL);
34553913Sarchie	*off = eptr - s;
34653913Sarchie	val8 = (int8_t)val;
34753913Sarchie	bcopy(&val8, buf, sizeof(int8_t));
34853913Sarchie	*buflen = sizeof(int8_t);
34953913Sarchie	return (0);
35053913Sarchie}
35153913Sarchie
35253913Sarchiestatic int
35353913Sarchieng_int8_unparse(const struct ng_parse_type *type,
35453913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
35553913Sarchie{
35664505Sarchie	const char *fmt;
35764505Sarchie	int fval;
358142902Sglebius	int error;
35953913Sarchie	int8_t val;
36053913Sarchie
36153913Sarchie	bcopy(data + *off, &val, sizeof(int8_t));
362106665Sjhb	switch ((intptr_t)type->info) {
36364505Sarchie	case INT_SIGNED:
36464505Sarchie		fmt = "%d";
36564505Sarchie		fval = val;
36664505Sarchie		break;
36764505Sarchie	case INT_UNSIGNED:
36864505Sarchie		fmt = "%u";
36964505Sarchie		fval = (u_int8_t)val;
37064505Sarchie		break;
37164505Sarchie	case INT_HEX:
37264505Sarchie		fmt = "0x%x";
37364505Sarchie		fval = (u_int8_t)val;
37464505Sarchie		break;
37564505Sarchie	default:
37687599Sobrien		panic("%s: unknown type", __func__);
37764505Sarchie	}
378142902Sglebius	if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0)
379142902Sglebius		return (error);
38053913Sarchie	*off += sizeof(int8_t);
38153913Sarchie	return (0);
38253913Sarchie}
38353913Sarchie
38453913Sarchiestatic int
38553913Sarchieng_int8_getDefault(const struct ng_parse_type *type,
38653913Sarchie	const u_char *const start, u_char *buf, int *buflen)
38753913Sarchie{
38853913Sarchie	int8_t val;
38953913Sarchie
39053913Sarchie	if (*buflen < sizeof(int8_t))
39153913Sarchie		return (ERANGE);
39253913Sarchie	val = 0;
39353913Sarchie	bcopy(&val, buf, sizeof(int8_t));
39453913Sarchie	*buflen = sizeof(int8_t);
39553913Sarchie	return (0);
39653913Sarchie}
39753913Sarchie
39853913Sarchiestatic int
39953913Sarchieng_int8_getAlign(const struct ng_parse_type *type)
40053913Sarchie{
40153913Sarchie	return INT8_ALIGNMENT;
40253913Sarchie}
40353913Sarchie
40453913Sarchieconst struct ng_parse_type ng_parse_int8_type = {
40553913Sarchie	NULL,
40664505Sarchie	(void *)INT_SIGNED,
40753913Sarchie	NULL,
40853913Sarchie	ng_int8_parse,
40953913Sarchie	ng_int8_unparse,
41053913Sarchie	ng_int8_getDefault,
41153913Sarchie	ng_int8_getAlign
41253913Sarchie};
41353913Sarchie
41464505Sarchieconst struct ng_parse_type ng_parse_uint8_type = {
41564505Sarchie	&ng_parse_int8_type,
41664505Sarchie	(void *)INT_UNSIGNED
41764505Sarchie};
41864505Sarchie
41964505Sarchieconst struct ng_parse_type ng_parse_hint8_type = {
42064505Sarchie	&ng_parse_int8_type,
42164505Sarchie	(void *)INT_HEX
42264505Sarchie};
42364505Sarchie
42453913Sarchie/************************************************************************
42553913Sarchie				INT16 TYPE
42653913Sarchie ************************************************************************/
42753913Sarchie
42853913Sarchiestatic int
42953913Sarchieng_int16_parse(const struct ng_parse_type *type,
43053913Sarchie	const char *s, int *off, const u_char *const start,
43153913Sarchie	u_char *const buf, int *buflen)
43253913Sarchie{
43353913Sarchie	long val;
43453913Sarchie	int16_t val16;
43553913Sarchie	char *eptr;
43653913Sarchie
43753913Sarchie	val = strtol(s + *off, &eptr, 0);
43876860Sjdp	if (val < (int16_t)0x8000
43976860Sjdp	    || val > (u_int16_t)0xffff || eptr == s + *off)
44053913Sarchie		return (EINVAL);
44153913Sarchie	*off = eptr - s;
44253913Sarchie	val16 = (int16_t)val;
44353913Sarchie	bcopy(&val16, buf, sizeof(int16_t));
44453913Sarchie	*buflen = sizeof(int16_t);
44553913Sarchie	return (0);
44653913Sarchie}
44753913Sarchie
44853913Sarchiestatic int
44953913Sarchieng_int16_unparse(const struct ng_parse_type *type,
45053913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
45153913Sarchie{
45264505Sarchie	const char *fmt;
45364505Sarchie	int fval;
454142902Sglebius	int error;
45553913Sarchie	int16_t val;
45653913Sarchie
45753913Sarchie	bcopy(data + *off, &val, sizeof(int16_t));
458106665Sjhb	switch ((intptr_t)type->info) {
45964505Sarchie	case INT_SIGNED:
46064505Sarchie		fmt = "%d";
46164505Sarchie		fval = val;
46264505Sarchie		break;
46364505Sarchie	case INT_UNSIGNED:
46464505Sarchie		fmt = "%u";
46564505Sarchie		fval = (u_int16_t)val;
46664505Sarchie		break;
46764505Sarchie	case INT_HEX:
46864505Sarchie		fmt = "0x%x";
46964505Sarchie		fval = (u_int16_t)val;
47064505Sarchie		break;
47164505Sarchie	default:
47287599Sobrien		panic("%s: unknown type", __func__);
47364505Sarchie	}
474142902Sglebius	if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0)
475142902Sglebius		return (error);
47653913Sarchie	*off += sizeof(int16_t);
47753913Sarchie	return (0);
47853913Sarchie}
47953913Sarchie
48053913Sarchiestatic int
48153913Sarchieng_int16_getDefault(const struct ng_parse_type *type,
48253913Sarchie	const u_char *const start, u_char *buf, int *buflen)
48353913Sarchie{
48453913Sarchie	int16_t val;
48553913Sarchie
48653913Sarchie	if (*buflen < sizeof(int16_t))
48753913Sarchie		return (ERANGE);
48853913Sarchie	val = 0;
48953913Sarchie	bcopy(&val, buf, sizeof(int16_t));
49053913Sarchie	*buflen = sizeof(int16_t);
49153913Sarchie	return (0);
49253913Sarchie}
49353913Sarchie
49453913Sarchiestatic int
49553913Sarchieng_int16_getAlign(const struct ng_parse_type *type)
49653913Sarchie{
49753913Sarchie	return INT16_ALIGNMENT;
49853913Sarchie}
49953913Sarchie
50053913Sarchieconst struct ng_parse_type ng_parse_int16_type = {
50153913Sarchie	NULL,
50264505Sarchie	(void *)INT_SIGNED,
50353913Sarchie	NULL,
50453913Sarchie	ng_int16_parse,
50553913Sarchie	ng_int16_unparse,
50653913Sarchie	ng_int16_getDefault,
50753913Sarchie	ng_int16_getAlign
50853913Sarchie};
50953913Sarchie
51064505Sarchieconst struct ng_parse_type ng_parse_uint16_type = {
51164505Sarchie	&ng_parse_int16_type,
51264505Sarchie	(void *)INT_UNSIGNED
51364505Sarchie};
51464505Sarchie
51564505Sarchieconst struct ng_parse_type ng_parse_hint16_type = {
51664505Sarchie	&ng_parse_int16_type,
51764505Sarchie	(void *)INT_HEX
51864505Sarchie};
51964505Sarchie
52053913Sarchie/************************************************************************
52153913Sarchie				INT32 TYPE
52253913Sarchie ************************************************************************/
52353913Sarchie
52453913Sarchiestatic int
52553913Sarchieng_int32_parse(const struct ng_parse_type *type,
52653913Sarchie	const char *s, int *off, const u_char *const start,
52753913Sarchie	u_char *const buf, int *buflen)
52853913Sarchie{
52953913Sarchie	long val;			/* assumes long is at least 32 bits */
53053913Sarchie	int32_t val32;
53153913Sarchie	char *eptr;
53253913Sarchie
533148645Sru	if ((intptr_t)type->info == INT_SIGNED)
534148645Sru		val = strtol(s + *off, &eptr, 0);
535148645Sru	else
536148645Sru		val = strtoul(s + *off, &eptr, 0);
53776860Sjdp	if (val < (int32_t)0x80000000
53876860Sjdp	    || val > (u_int32_t)0xffffffff || eptr == s + *off)
53953913Sarchie		return (EINVAL);
54053913Sarchie	*off = eptr - s;
54153913Sarchie	val32 = (int32_t)val;
54253913Sarchie	bcopy(&val32, buf, sizeof(int32_t));
54353913Sarchie	*buflen = sizeof(int32_t);
54453913Sarchie	return (0);
54553913Sarchie}
54653913Sarchie
54753913Sarchiestatic int
54853913Sarchieng_int32_unparse(const struct ng_parse_type *type,
54953913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
55053913Sarchie{
55164505Sarchie	const char *fmt;
55264505Sarchie	long fval;
553142902Sglebius	int error;
55453913Sarchie	int32_t val;
55553913Sarchie
55653913Sarchie	bcopy(data + *off, &val, sizeof(int32_t));
557106665Sjhb	switch ((intptr_t)type->info) {
55864505Sarchie	case INT_SIGNED:
55964505Sarchie		fmt = "%ld";
56064505Sarchie		fval = val;
56164505Sarchie		break;
56264505Sarchie	case INT_UNSIGNED:
56364505Sarchie		fmt = "%lu";
56464505Sarchie		fval = (u_int32_t)val;
56564505Sarchie		break;
56664505Sarchie	case INT_HEX:
56764505Sarchie		fmt = "0x%lx";
56864505Sarchie		fval = (u_int32_t)val;
56964505Sarchie		break;
57064505Sarchie	default:
57187599Sobrien		panic("%s: unknown type", __func__);
57264505Sarchie	}
573142902Sglebius	if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0)
574142902Sglebius		return (error);
57553913Sarchie	*off += sizeof(int32_t);
57653913Sarchie	return (0);
57753913Sarchie}
57853913Sarchie
57953913Sarchiestatic int
58053913Sarchieng_int32_getDefault(const struct ng_parse_type *type,
58153913Sarchie	const u_char *const start, u_char *buf, int *buflen)
58253913Sarchie{
58353913Sarchie	int32_t val;
58453913Sarchie
58553913Sarchie	if (*buflen < sizeof(int32_t))
58653913Sarchie		return (ERANGE);
58753913Sarchie	val = 0;
58853913Sarchie	bcopy(&val, buf, sizeof(int32_t));
58953913Sarchie	*buflen = sizeof(int32_t);
59053913Sarchie	return (0);
59153913Sarchie}
59253913Sarchie
59353913Sarchiestatic int
59453913Sarchieng_int32_getAlign(const struct ng_parse_type *type)
59553913Sarchie{
59653913Sarchie	return INT32_ALIGNMENT;
59753913Sarchie}
59853913Sarchie
59953913Sarchieconst struct ng_parse_type ng_parse_int32_type = {
60053913Sarchie	NULL,
60164505Sarchie	(void *)INT_SIGNED,
60253913Sarchie	NULL,
60353913Sarchie	ng_int32_parse,
60453913Sarchie	ng_int32_unparse,
60553913Sarchie	ng_int32_getDefault,
60653913Sarchie	ng_int32_getAlign
60753913Sarchie};
60853913Sarchie
60964505Sarchieconst struct ng_parse_type ng_parse_uint32_type = {
61064505Sarchie	&ng_parse_int32_type,
61164505Sarchie	(void *)INT_UNSIGNED
61264505Sarchie};
61364505Sarchie
61464505Sarchieconst struct ng_parse_type ng_parse_hint32_type = {
61564505Sarchie	&ng_parse_int32_type,
61664505Sarchie	(void *)INT_HEX
61764505Sarchie};
61864505Sarchie
61953913Sarchie/************************************************************************
62053913Sarchie				INT64 TYPE
62153913Sarchie ************************************************************************/
62253913Sarchie
62353913Sarchiestatic int
62453913Sarchieng_int64_parse(const struct ng_parse_type *type,
62553913Sarchie	const char *s, int *off, const u_char *const start,
62653913Sarchie	u_char *const buf, int *buflen)
62753913Sarchie{
62853913Sarchie	quad_t val;
62953913Sarchie	int64_t val64;
63053913Sarchie	char *eptr;
63153913Sarchie
63253913Sarchie	val = strtoq(s + *off, &eptr, 0);
63353913Sarchie	if (eptr == s + *off)
63453913Sarchie		return (EINVAL);
63553913Sarchie	*off = eptr - s;
63653913Sarchie	val64 = (int64_t)val;
63753913Sarchie	bcopy(&val64, buf, sizeof(int64_t));
63853913Sarchie	*buflen = sizeof(int64_t);
63953913Sarchie	return (0);
64053913Sarchie}
64153913Sarchie
64253913Sarchiestatic int
64353913Sarchieng_int64_unparse(const struct ng_parse_type *type,
64453913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
64553913Sarchie{
64664505Sarchie	const char *fmt;
64764505Sarchie	long long fval;
64853913Sarchie	int64_t val;
649142902Sglebius	int error;
65053913Sarchie
65153913Sarchie	bcopy(data + *off, &val, sizeof(int64_t));
652106665Sjhb	switch ((intptr_t)type->info) {
65364505Sarchie	case INT_SIGNED:
65464505Sarchie		fmt = "%lld";
65564505Sarchie		fval = val;
65664505Sarchie		break;
65764505Sarchie	case INT_UNSIGNED:
65864505Sarchie		fmt = "%llu";
65964505Sarchie		fval = (u_int64_t)val;
66064505Sarchie		break;
66164505Sarchie	case INT_HEX:
66264505Sarchie		fmt = "0x%llx";
66364505Sarchie		fval = (u_int64_t)val;
66464505Sarchie		break;
66564505Sarchie	default:
66687599Sobrien		panic("%s: unknown type", __func__);
66764505Sarchie	}
668142902Sglebius	if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0)
669142902Sglebius		return (error);
67053913Sarchie	*off += sizeof(int64_t);
67153913Sarchie	return (0);
67253913Sarchie}
67353913Sarchie
67453913Sarchiestatic int
67553913Sarchieng_int64_getDefault(const struct ng_parse_type *type,
67653913Sarchie	const u_char *const start, u_char *buf, int *buflen)
67753913Sarchie{
67853913Sarchie	int64_t val;
67953913Sarchie
68053913Sarchie	if (*buflen < sizeof(int64_t))
68153913Sarchie		return (ERANGE);
68253913Sarchie	val = 0;
68353913Sarchie	bcopy(&val, buf, sizeof(int64_t));
68453913Sarchie	*buflen = sizeof(int64_t);
68553913Sarchie	return (0);
68653913Sarchie}
68753913Sarchie
68853913Sarchiestatic int
68953913Sarchieng_int64_getAlign(const struct ng_parse_type *type)
69053913Sarchie{
69153913Sarchie	return INT64_ALIGNMENT;
69253913Sarchie}
69353913Sarchie
69453913Sarchieconst struct ng_parse_type ng_parse_int64_type = {
69553913Sarchie	NULL,
69664505Sarchie	(void *)INT_SIGNED,
69753913Sarchie	NULL,
69853913Sarchie	ng_int64_parse,
69953913Sarchie	ng_int64_unparse,
70053913Sarchie	ng_int64_getDefault,
70153913Sarchie	ng_int64_getAlign
70253913Sarchie};
70353913Sarchie
70464505Sarchieconst struct ng_parse_type ng_parse_uint64_type = {
70564505Sarchie	&ng_parse_int64_type,
70664505Sarchie	(void *)INT_UNSIGNED
70764505Sarchie};
70864505Sarchie
70964505Sarchieconst struct ng_parse_type ng_parse_hint64_type = {
71064505Sarchie	&ng_parse_int64_type,
71164505Sarchie	(void *)INT_HEX
71264505Sarchie};
71364505Sarchie
71453913Sarchie/************************************************************************
71553913Sarchie				STRING TYPE
71653913Sarchie ************************************************************************/
71753913Sarchie
71853913Sarchiestatic int
71953913Sarchieng_string_parse(const struct ng_parse_type *type,
72053913Sarchie	const char *s, int *off, const u_char *const start,
72153913Sarchie	u_char *const buf, int *buflen)
72253913Sarchie{
72353913Sarchie	char *sval;
72453913Sarchie	int len;
72568845Sbrian	int slen;
72653913Sarchie
72768845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
72853913Sarchie		return (EINVAL);
72953913Sarchie	*off += len;
73068845Sbrian	bcopy(sval, buf, slen + 1);
731184205Sdes	free(sval, M_NETGRAPH_PARSE);
73268845Sbrian	*buflen = slen + 1;
73353913Sarchie	return (0);
73453913Sarchie}
73553913Sarchie
73653913Sarchiestatic int
73753913Sarchieng_string_unparse(const struct ng_parse_type *type,
73853913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
73953913Sarchie{
74053913Sarchie	const char *const raw = (const char *)data + *off;
74168845Sbrian	char *const s = ng_encode_string(raw, strlen(raw));
742142902Sglebius	int error;
74353913Sarchie
74453913Sarchie	if (s == NULL)
74553913Sarchie		return (ENOMEM);
746142902Sglebius	if ((error = ng_parse_append(&cbuf, &cbuflen, "%s", s)) != 0) {
747184205Sdes		free(s, M_NETGRAPH_PARSE);
748142902Sglebius		return (error);
749142902Sglebius	}
75053913Sarchie	*off += strlen(raw) + 1;
751184205Sdes	free(s, M_NETGRAPH_PARSE);
75253913Sarchie	return (0);
75353913Sarchie}
75453913Sarchie
75553913Sarchiestatic int
75653913Sarchieng_string_getDefault(const struct ng_parse_type *type,
75753913Sarchie	const u_char *const start, u_char *buf, int *buflen)
75853913Sarchie{
75953913Sarchie
76053913Sarchie	if (*buflen < 1)
76153913Sarchie		return (ERANGE);
76253913Sarchie	buf[0] = (u_char)'\0';
76353913Sarchie	*buflen = 1;
76453913Sarchie	return (0);
76553913Sarchie}
76653913Sarchie
76753913Sarchieconst struct ng_parse_type ng_parse_string_type = {
76853913Sarchie	NULL,
76953913Sarchie	NULL,
77053913Sarchie	NULL,
77153913Sarchie	ng_string_parse,
77253913Sarchie	ng_string_unparse,
77353913Sarchie	ng_string_getDefault,
77453913Sarchie	NULL
77553913Sarchie};
77653913Sarchie
77753913Sarchie/************************************************************************
77853913Sarchie			FIXED BUFFER STRING TYPE
77953913Sarchie ************************************************************************/
78053913Sarchie
78153913Sarchiestatic int
78253913Sarchieng_fixedstring_parse(const struct ng_parse_type *type,
78353913Sarchie	const char *s, int *off, const u_char *const start,
78453913Sarchie	u_char *const buf, int *buflen)
78553913Sarchie{
78658011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
78753913Sarchie	char *sval;
78853913Sarchie	int len;
78968845Sbrian	int slen;
79053913Sarchie
79168845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
79253913Sarchie		return (EINVAL);
793154521Sru	if (slen + 1 > fi->bufSize) {
794184205Sdes		free(sval, M_NETGRAPH_PARSE);
795154521Sru		return (E2BIG);
796154521Sru	}
79753913Sarchie	*off += len;
79868845Sbrian	bcopy(sval, buf, slen);
799184205Sdes	free(sval, M_NETGRAPH_PARSE);
80068845Sbrian	bzero(buf + slen, fi->bufSize - slen);
80153913Sarchie	*buflen = fi->bufSize;
80253913Sarchie	return (0);
80353913Sarchie}
80453913Sarchie
80553913Sarchiestatic int
80653913Sarchieng_fixedstring_unparse(const struct ng_parse_type *type,
80753913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
80853913Sarchie{
80958011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
81053913Sarchie	int error, temp = *off;
81153913Sarchie
81253913Sarchie	if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
81353913Sarchie		return (error);
81453913Sarchie	*off += fi->bufSize;
81553913Sarchie	return (0);
81653913Sarchie}
81753913Sarchie
81853913Sarchiestatic int
81953913Sarchieng_fixedstring_getDefault(const struct ng_parse_type *type,
82053913Sarchie	const u_char *const start, u_char *buf, int *buflen)
82153913Sarchie{
82258011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
82353913Sarchie
82453913Sarchie	if (*buflen < fi->bufSize)
82553913Sarchie		return (ERANGE);
82653913Sarchie	bzero(buf, fi->bufSize);
82753913Sarchie	*buflen = fi->bufSize;
82853913Sarchie	return (0);
82953913Sarchie}
83053913Sarchie
83153913Sarchieconst struct ng_parse_type ng_parse_fixedstring_type = {
83253913Sarchie	NULL,
83353913Sarchie	NULL,
83453913Sarchie	NULL,
83553913Sarchie	ng_fixedstring_parse,
83653913Sarchie	ng_fixedstring_unparse,
83753913Sarchie	ng_fixedstring_getDefault,
83853913Sarchie	NULL
83953913Sarchie};
84053913Sarchie
84158011Sarchieconst struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
842125028Sharti	NG_NODESIZ
84353913Sarchie};
84453913Sarchieconst struct ng_parse_type ng_parse_nodebuf_type = {
84553913Sarchie	&ng_parse_fixedstring_type,
84653913Sarchie	&ng_parse_nodebuf_info
84753913Sarchie};
84853913Sarchie
84958011Sarchieconst struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
850125028Sharti	NG_HOOKSIZ
85153913Sarchie};
85253913Sarchieconst struct ng_parse_type ng_parse_hookbuf_type = {
85353913Sarchie	&ng_parse_fixedstring_type,
85453913Sarchie	&ng_parse_hookbuf_info
85553913Sarchie};
85653913Sarchie
85758011Sarchieconst struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
858125028Sharti	NG_PATHSIZ
85953913Sarchie};
86053913Sarchieconst struct ng_parse_type ng_parse_pathbuf_type = {
86153913Sarchie	&ng_parse_fixedstring_type,
86253913Sarchie	&ng_parse_pathbuf_info
86353913Sarchie};
86453913Sarchie
86558011Sarchieconst struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
866125028Sharti	NG_TYPESIZ
86753913Sarchie};
86853913Sarchieconst struct ng_parse_type ng_parse_typebuf_type = {
86953913Sarchie	&ng_parse_fixedstring_type,
87053913Sarchie	&ng_parse_typebuf_info
87153913Sarchie};
87253913Sarchie
87358011Sarchieconst struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
874125028Sharti	NG_CMDSTRSIZ
87553913Sarchie};
87653913Sarchieconst struct ng_parse_type ng_parse_cmdbuf_type = {
87753913Sarchie	&ng_parse_fixedstring_type,
87853913Sarchie	&ng_parse_cmdbuf_info
87953913Sarchie};
88053913Sarchie
88153913Sarchie/************************************************************************
88268845Sbrian			EXPLICITLY SIZED STRING TYPE
88368845Sbrian ************************************************************************/
88468845Sbrian
88568845Sbrianstatic int
88668845Sbrianng_sizedstring_parse(const struct ng_parse_type *type,
88768845Sbrian	const char *s, int *off, const u_char *const start,
88868845Sbrian	u_char *const buf, int *buflen)
88968845Sbrian{
89068845Sbrian	char *sval;
89168845Sbrian	int len;
89268845Sbrian	int slen;
89368845Sbrian
89468845Sbrian	if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
89568845Sbrian		return (EINVAL);
896154521Sru	if (slen > USHRT_MAX) {
897184205Sdes		free(sval, M_NETGRAPH_PARSE);
898154521Sru		return (EINVAL);
899154521Sru	}
90068845Sbrian	*off += len;
90168845Sbrian	*((u_int16_t *)buf) = (u_int16_t)slen;
90268845Sbrian	bcopy(sval, buf + 2, slen);
903184205Sdes	free(sval, M_NETGRAPH_PARSE);
90468845Sbrian	*buflen = 2 + slen;
90568845Sbrian	return (0);
90668845Sbrian}
90768845Sbrian
90868845Sbrianstatic int
90968845Sbrianng_sizedstring_unparse(const struct ng_parse_type *type,
91068845Sbrian	const u_char *data, int *off, char *cbuf, int cbuflen)
91168845Sbrian{
91268845Sbrian	const char *const raw = (const char *)data + *off + 2;
91368845Sbrian	const int slen = *((const u_int16_t *)(data + *off));
91468845Sbrian	char *const s = ng_encode_string(raw, slen);
915142902Sglebius	int error;
91668845Sbrian
91768845Sbrian	if (s == NULL)
91868845Sbrian		return (ENOMEM);
919142902Sglebius	if ((error = ng_parse_append(&cbuf, &cbuflen, "%s", s)) != 0) {
920184205Sdes		free(s, M_NETGRAPH_PARSE);
921142902Sglebius		return (error);
922142902Sglebius	}
923184205Sdes	free(s, M_NETGRAPH_PARSE);
92468845Sbrian	*off += slen + 2;
92568845Sbrian	return (0);
92668845Sbrian}
92768845Sbrian
92868845Sbrianstatic int
92968845Sbrianng_sizedstring_getDefault(const struct ng_parse_type *type,
93068845Sbrian	const u_char *const start, u_char *buf, int *buflen)
93168845Sbrian{
93268845Sbrian	if (*buflen < 2)
93368845Sbrian		return (ERANGE);
93468845Sbrian	bzero(buf, 2);
93568845Sbrian	*buflen = 2;
93668845Sbrian	return (0);
93768845Sbrian}
93868845Sbrian
93968845Sbrianconst struct ng_parse_type ng_parse_sizedstring_type = {
94068845Sbrian	NULL,
94168845Sbrian	NULL,
94268845Sbrian	NULL,
94368845Sbrian	ng_sizedstring_parse,
94468845Sbrian	ng_sizedstring_unparse,
94568845Sbrian	ng_sizedstring_getDefault,
94668845Sbrian	NULL
94768845Sbrian};
94868845Sbrian
94968845Sbrian/************************************************************************
95053913Sarchie			IP ADDRESS TYPE
95153913Sarchie ************************************************************************/
95253913Sarchie
95353913Sarchiestatic int
95453913Sarchieng_ipaddr_parse(const struct ng_parse_type *type,
95553913Sarchie	const char *s, int *off, const u_char *const start,
95653913Sarchie	u_char *const buf, int *buflen)
95753913Sarchie{
95853913Sarchie	int i, error;
95953913Sarchie
96053913Sarchie	for (i = 0; i < 4; i++) {
96153913Sarchie		if ((error = ng_int8_parse(&ng_parse_int8_type,
96253913Sarchie		    s, off, start, buf + i, buflen)) != 0)
96353913Sarchie			return (error);
96453913Sarchie		if (i < 3 && s[*off] != '.')
96553913Sarchie			return (EINVAL);
96653913Sarchie		(*off)++;
96753913Sarchie	}
96853913Sarchie	*buflen = 4;
96953913Sarchie	return (0);
97053913Sarchie}
97153913Sarchie
97253913Sarchiestatic int
97353913Sarchieng_ipaddr_unparse(const struct ng_parse_type *type,
97453913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
97553913Sarchie{
97653913Sarchie	struct in_addr ip;
977142902Sglebius	int error;
97853913Sarchie
97953913Sarchie	bcopy(data + *off, &ip, sizeof(ip));
980142902Sglebius	if ((error = ng_parse_append(&cbuf, &cbuflen, "%d.%d.%d.%d",
981142902Sglebius	    ((u_char *)&ip)[0], ((u_char *)&ip)[1],
982142902Sglebius	    ((u_char *)&ip)[2], ((u_char *)&ip)[3])) != 0)
983142902Sglebius		return (error);
98453913Sarchie	*off += sizeof(ip);
98553913Sarchie	return (0);
98653913Sarchie}
98753913Sarchie
98853913Sarchiestatic int
98953913Sarchieng_ipaddr_getDefault(const struct ng_parse_type *type,
99053913Sarchie	const u_char *const start, u_char *buf, int *buflen)
99153913Sarchie{
99253913Sarchie	struct in_addr ip = { 0 };
99353913Sarchie
99453913Sarchie	if (*buflen < sizeof(ip))
99553913Sarchie		return (ERANGE);
99653913Sarchie	bcopy(&ip, buf, sizeof(ip));
99753913Sarchie	*buflen = sizeof(ip);
99853913Sarchie	return (0);
99953913Sarchie}
100053913Sarchie
100153913Sarchieconst struct ng_parse_type ng_parse_ipaddr_type = {
100253913Sarchie	NULL,
100353913Sarchie	NULL,
100453913Sarchie	NULL,
100553913Sarchie	ng_ipaddr_parse,
100653913Sarchie	ng_ipaddr_unparse,
100753913Sarchie	ng_ipaddr_getDefault,
100853913Sarchie	ng_int32_getAlign
100953913Sarchie};
101053913Sarchie
101153913Sarchie/************************************************************************
1012123600Sru			ETHERNET ADDRESS TYPE
1013123600Sru ************************************************************************/
1014123600Sru
1015123600Srustatic int
1016123600Srung_enaddr_parse(const struct ng_parse_type *type,
1017123600Sru	const char *s, int *const off, const u_char *const start,
1018123600Sru	u_char *const buf, int *const buflen)
1019123600Sru{
1020123600Sru	char *eptr;
1021123600Sru	u_long val;
1022123600Sru	int i;
1023123600Sru
1024123600Sru	if (*buflen < ETHER_ADDR_LEN)
1025123600Sru		return (ERANGE);
1026123600Sru	for (i = 0; i < ETHER_ADDR_LEN; i++) {
1027123600Sru		val = strtoul(s + *off, &eptr, 16);
1028123600Sru		if (val > 0xff || eptr == s + *off)
1029123600Sru			return (EINVAL);
1030123600Sru		buf[i] = (u_char)val;
1031123600Sru		*off = (eptr - s);
1032123600Sru		if (i < ETHER_ADDR_LEN - 1) {
1033123600Sru			if (*eptr != ':')
1034123600Sru				return (EINVAL);
1035123600Sru			(*off)++;
1036123600Sru		}
1037123600Sru	}
1038123600Sru	*buflen = ETHER_ADDR_LEN;
1039123600Sru	return (0);
1040123600Sru}
1041123600Sru
1042123600Srustatic int
1043123600Srung_enaddr_unparse(const struct ng_parse_type *type,
1044123600Sru	const u_char *data, int *off, char *cbuf, int cbuflen)
1045123600Sru{
1046123600Sru	int len;
1047123600Sru
1048123600Sru	len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x",
1049123600Sru	    data[*off], data[*off + 1], data[*off + 2],
1050123600Sru	    data[*off + 3], data[*off + 4], data[*off + 5]);
1051123600Sru	if (len >= cbuflen)
1052123600Sru		return (ERANGE);
1053123600Sru	*off += ETHER_ADDR_LEN;
1054123600Sru	return (0);
1055123600Sru}
1056123600Sru
1057123600Sruconst struct ng_parse_type ng_parse_enaddr_type = {
1058123600Sru	NULL,
1059123600Sru	NULL,
1060123600Sru	NULL,
1061123600Sru	ng_enaddr_parse,
1062123600Sru	ng_enaddr_unparse,
1063123600Sru	NULL,
1064123600Sru	0
1065123600Sru};
1066123600Sru
1067123600Sru/************************************************************************
106853913Sarchie			BYTE ARRAY TYPE
106953913Sarchie ************************************************************************/
107053913Sarchie
107153913Sarchie/* Get the length of a byte array */
107253913Sarchiestatic int
107353913Sarchieng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
107453913Sarchie	const u_char *start, const u_char *buf)
107553913Sarchie{
107653913Sarchie	ng_parse_array_getLength_t *const getLength = type->private;
107753913Sarchie
107853913Sarchie	return (*getLength)(type, start, buf);
107953913Sarchie}
108053913Sarchie
108164505Sarchie/* Byte array element type is hex int8 */
108253913Sarchiestatic const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
108364505Sarchie	&ng_parse_hint8_type,
108453913Sarchie	&ng_parse_bytearray_subtype_getLength,
108553913Sarchie	NULL
108653913Sarchie};
108753913Sarchiestatic const struct ng_parse_type ng_parse_bytearray_subtype = {
108853913Sarchie	&ng_parse_array_type,
108953913Sarchie	&ng_parse_bytearray_subtype_info
109053913Sarchie};
109153913Sarchie
109253913Sarchiestatic int
109353913Sarchieng_bytearray_parse(const struct ng_parse_type *type,
109453913Sarchie	const char *s, int *off, const u_char *const start,
109553913Sarchie	u_char *const buf, int *buflen)
109653913Sarchie{
109753913Sarchie	char *str;
109853913Sarchie	int toklen;
109968845Sbrian	int slen;
110053913Sarchie
110153913Sarchie	/* We accept either an array of bytes or a string constant */
110268845Sbrian	if ((str = ng_get_string_token(s, off, &toklen, &slen)) != NULL) {
110353913Sarchie		ng_parse_array_getLength_t *const getLength = type->info;
110468845Sbrian		int arraylen;
110553913Sarchie
110653913Sarchie		arraylen = (*getLength)(type, start, buf);
110753913Sarchie		if (arraylen > *buflen) {
1108184205Sdes			free(str, M_NETGRAPH_PARSE);
110953913Sarchie			return (ERANGE);
111053913Sarchie		}
111153913Sarchie		if (slen > arraylen) {
1112184205Sdes			free(str, M_NETGRAPH_PARSE);
111353913Sarchie			return (E2BIG);
111453913Sarchie		}
111553913Sarchie		bcopy(str, buf, slen);
111653913Sarchie		bzero(buf + slen, arraylen - slen);
1117184205Sdes		free(str, M_NETGRAPH_PARSE);
111853913Sarchie		*off += toklen;
111953913Sarchie		*buflen = arraylen;
112053913Sarchie		return (0);
112153913Sarchie	} else {
112253913Sarchie		struct ng_parse_type subtype;
112353913Sarchie
112453913Sarchie		subtype = ng_parse_bytearray_subtype;
1125132780Skan		*(const void **)&subtype.private = type->info;
112653913Sarchie		return ng_array_parse(&subtype, s, off, start, buf, buflen);
112753913Sarchie	}
112853913Sarchie}
112953913Sarchie
113053913Sarchiestatic int
113153913Sarchieng_bytearray_unparse(const struct ng_parse_type *type,
113253913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
113353913Sarchie{
113453913Sarchie	struct ng_parse_type subtype;
113553913Sarchie
113653913Sarchie	subtype = ng_parse_bytearray_subtype;
1137132780Skan	*(const void **)&subtype.private = type->info;
113853913Sarchie	return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
113953913Sarchie}
114053913Sarchie
114153913Sarchiestatic int
114253913Sarchieng_bytearray_getDefault(const struct ng_parse_type *type,
114353913Sarchie	const u_char *const start, u_char *buf, int *buflen)
114453913Sarchie{
114553913Sarchie	struct ng_parse_type subtype;
114653913Sarchie
114753913Sarchie	subtype = ng_parse_bytearray_subtype;
1148132780Skan	*(const void **)&subtype.private = type->info;
114953913Sarchie	return ng_array_getDefault(&subtype, start, buf, buflen);
115053913Sarchie}
115153913Sarchie
115253913Sarchieconst struct ng_parse_type ng_parse_bytearray_type = {
115353913Sarchie	NULL,
115453913Sarchie	NULL,
115553913Sarchie	NULL,
115653913Sarchie	ng_bytearray_parse,
115753913Sarchie	ng_bytearray_unparse,
115853913Sarchie	ng_bytearray_getDefault,
115953913Sarchie	NULL
116053913Sarchie};
116153913Sarchie
116253913Sarchie/************************************************************************
116353913Sarchie			STRUCT NG_MESG TYPE
116453913Sarchie ************************************************************************/
116553913Sarchie
116653913Sarchie/* Get msg->header.arglen when "buf" is pointing to msg->data */
116753913Sarchiestatic int
116853913Sarchieng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
116953913Sarchie	const u_char *start, const u_char *buf)
117053913Sarchie{
117153913Sarchie	const struct ng_mesg *msg;
117253913Sarchie
117353913Sarchie	msg = (const struct ng_mesg *)(buf - sizeof(*msg));
117453913Sarchie	return msg->header.arglen;
117553913Sarchie}
117653913Sarchie
117753913Sarchie/* Type for the variable length data portion of a struct ng_mesg */
117853913Sarchiestatic const struct ng_parse_type ng_msg_data_type = {
117953913Sarchie	&ng_parse_bytearray_type,
118053913Sarchie	&ng_parse_ng_mesg_getLength
118153913Sarchie};
118253913Sarchie
118353913Sarchie/* Type for the entire struct ng_mesg header with data section */
118497685Sarchiestatic const struct ng_parse_struct_field ng_parse_ng_mesg_type_fields[]
118597685Sarchie	= NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
118653913Sarchieconst struct ng_parse_type ng_parse_ng_mesg_type = {
118753913Sarchie	&ng_parse_struct_type,
118897685Sarchie	&ng_parse_ng_mesg_type_fields,
118953913Sarchie};
119053913Sarchie
119153913Sarchie/************************************************************************
119253913Sarchie			COMPOSITE HELPER ROUTINES
119353913Sarchie ************************************************************************/
119453913Sarchie
119553913Sarchie/*
119653913Sarchie * Convert a structure or array from ASCII to binary
119753913Sarchie */
119853913Sarchiestatic int
119953913Sarchieng_parse_composite(const struct ng_parse_type *type, const char *s,
120053913Sarchie	int *off, const u_char *const start, u_char *const buf, int *buflen,
120153913Sarchie	const enum comptype ctype)
120253913Sarchie{
120353913Sarchie	const int num = ng_get_composite_len(type, start, buf, ctype);
120453913Sarchie	int nextIndex = 0;		/* next implicit array index */
120553913Sarchie	u_int index;			/* field or element index */
120653913Sarchie	int *foff;			/* field value offsets in string */
120753913Sarchie	int align, len, blen, error = 0;
120853913Sarchie
120953913Sarchie	/* Initialize */
1210184205Sdes	foff = malloc(num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO);
121153913Sarchie	if (foff == NULL) {
121253913Sarchie		error = ENOMEM;
121353913Sarchie		goto done;
121453913Sarchie	}
121553913Sarchie
121653913Sarchie	/* Get opening brace/bracket */
121753913Sarchie	if (ng_parse_get_token(s, off, &len)
121853913Sarchie	    != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
121953913Sarchie		error = EINVAL;
122053913Sarchie		goto done;
122153913Sarchie	}
122253913Sarchie	*off += len;
122353913Sarchie
122453913Sarchie	/* Get individual element value positions in the string */
122553913Sarchie	for (;;) {
122653913Sarchie		enum ng_parse_token tok;
122753913Sarchie
122853913Sarchie		/* Check for closing brace/bracket */
122953913Sarchie		tok = ng_parse_get_token(s, off, &len);
123053913Sarchie		if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
123153913Sarchie			*off += len;
123253913Sarchie			break;
123353913Sarchie		}
123453913Sarchie
123553913Sarchie		/* For arrays, the 'name' (ie, index) is optional, so
123653913Sarchie		   distinguish name from values by seeing if the next
123753913Sarchie		   token is an equals sign */
123853913Sarchie		if (ctype != CT_STRUCT) {
123953913Sarchie			int len2, off2;
124053913Sarchie			char *eptr;
124153913Sarchie
124253913Sarchie			/* If an opening brace/bracket, index is implied */
124353913Sarchie			if (tok == T_LBRACE || tok == T_LBRACKET) {
124453913Sarchie				index = nextIndex++;
124553913Sarchie				goto gotIndex;
124653913Sarchie			}
124753913Sarchie
124853913Sarchie			/* Might be an index, might be a value, either way... */
124953913Sarchie			if (tok != T_WORD) {
125053913Sarchie				error = EINVAL;
125153913Sarchie				goto done;
125253913Sarchie			}
125353913Sarchie
125453913Sarchie			/* If no equals sign follows, index is implied */
125553913Sarchie			off2 = *off + len;
125653913Sarchie			if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
125753913Sarchie				index = nextIndex++;
125853913Sarchie				goto gotIndex;
125953913Sarchie			}
126053913Sarchie
126153913Sarchie			/* Index was specified explicitly; parse it */
126253913Sarchie			index = (u_int)strtoul(s + *off, &eptr, 0);
126353913Sarchie			if (index < 0 || eptr - (s + *off) != len) {
126453913Sarchie				error = EINVAL;
126553913Sarchie				goto done;
126653913Sarchie			}
126753913Sarchie			nextIndex = index + 1;
126853913Sarchie			*off += len + len2;
126953913Sarchie		} else {			/* a structure field */
127097685Sarchie			const struct ng_parse_struct_field *const
127197685Sarchie			    fields = type->info;
127253913Sarchie
127353913Sarchie			/* Find the field by name (required) in field list */
127453913Sarchie			if (tok != T_WORD) {
127553913Sarchie				error = EINVAL;
127653913Sarchie				goto done;
127753913Sarchie			}
127853913Sarchie			for (index = 0; index < num; index++) {
127997685Sarchie				const struct ng_parse_struct_field *const
128097685Sarchie				    field = &fields[index];
128197685Sarchie
128253913Sarchie				if (strncmp(&s[*off], field->name, len) == 0
128353913Sarchie				    && field->name[len] == '\0')
128453913Sarchie					break;
128553913Sarchie			}
128653913Sarchie			if (index == num) {
128753913Sarchie				error = ENOENT;
128853913Sarchie				goto done;
128953913Sarchie			}
129053913Sarchie			*off += len;
129153913Sarchie
129253913Sarchie			/* Get equals sign */
129353913Sarchie			if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
129453913Sarchie				error = EINVAL;
129553913Sarchie				goto done;
129653913Sarchie			}
129753913Sarchie			*off += len;
129853913Sarchie		}
129997229SpetergotIndex:
130053913Sarchie
130153913Sarchie		/* Check array index */
130253913Sarchie		if (index >= num) {
130353913Sarchie			error = E2BIG;
130453913Sarchie			goto done;
130553913Sarchie		}
130653913Sarchie
130753913Sarchie		/* Save value's position and skip over it for now */
130853913Sarchie		if (foff[index] != 0) {
130953913Sarchie			error = EALREADY;		/* duplicate */
131053913Sarchie			goto done;
131153913Sarchie		}
131253913Sarchie		while (isspace(s[*off]))
131353913Sarchie			(*off)++;
131453913Sarchie		foff[index] = *off;
131553913Sarchie		if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
131653913Sarchie			goto done;
131753913Sarchie		*off += len;
131853913Sarchie	}
131953913Sarchie
132053913Sarchie	/* Now build binary structure from supplied values and defaults */
132153913Sarchie	for (blen = index = 0; index < num; index++) {
132253913Sarchie		const struct ng_parse_type *const
132353913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
132453913Sarchie		int k, pad, vlen;
132553913Sarchie
132653913Sarchie		/* Zero-pad any alignment bytes */
132753913Sarchie		pad = ng_parse_get_elem_pad(type, index, ctype, blen);
132853913Sarchie		for (k = 0; k < pad; k++) {
132953913Sarchie			if (blen >= *buflen) {
133053913Sarchie				error = ERANGE;
133153913Sarchie				goto done;
133253913Sarchie			}
133353913Sarchie			buf[blen++] = 0;
133453913Sarchie		}
133553913Sarchie
133653913Sarchie		/* Get value */
133753913Sarchie		vlen = *buflen - blen;
133853913Sarchie		if (foff[index] == 0) {		/* use default value */
133953913Sarchie			error = ng_get_composite_elem_default(type, index,
134053913Sarchie			    start, buf + blen, &vlen, ctype);
134153913Sarchie		} else {			/* parse given value */
134253913Sarchie			*off = foff[index];
134353913Sarchie			error = INVOKE(etype, parse)(etype,
134453913Sarchie			    s, off, start, buf + blen, &vlen);
134553913Sarchie		}
134653913Sarchie		if (error != 0)
134753913Sarchie			goto done;
134853913Sarchie		blen += vlen;
134953913Sarchie	}
135053913Sarchie
135153913Sarchie	/* Make total composite structure size a multiple of its alignment */
135253913Sarchie	if ((align = ALIGNMENT(type)) != 0) {
135353913Sarchie		while (blen % align != 0) {
135453913Sarchie			if (blen >= *buflen) {
135553913Sarchie				error = ERANGE;
135653913Sarchie				goto done;
135753913Sarchie			}
135853913Sarchie			buf[blen++] = 0;
135953913Sarchie		}
136053913Sarchie	}
136153913Sarchie
136253913Sarchie	/* Done */
136353913Sarchie	*buflen = blen;
136453913Sarchiedone:
136565303Sarchie	if (foff != NULL)
1366184205Sdes		free(foff, M_NETGRAPH_PARSE);
136753913Sarchie	return (error);
136853913Sarchie}
136953913Sarchie
137053913Sarchie/*
137153913Sarchie * Convert an array or structure from binary to ASCII
137253913Sarchie */
137353913Sarchiestatic int
137453913Sarchieng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
137553913Sarchie	int *off, char *cbuf, int cbuflen, const enum comptype ctype)
137653913Sarchie{
137790047Sarchie	const struct ng_mesg *const hdr
137890047Sarchie	    = (const struct ng_mesg *)(data - sizeof(*hdr));
137953913Sarchie	const int num = ng_get_composite_len(type, data, data + *off, ctype);
138064505Sarchie	const int workSize = 20 * 1024;		/* XXX hard coded constant */
138153913Sarchie	int nextIndex = 0, didOne = 0;
138253913Sarchie	int error, index;
138364505Sarchie	u_char *workBuf;
138453913Sarchie
138564505Sarchie	/* Get workspace for checking default values */
1386184205Sdes	workBuf = malloc(workSize, M_NETGRAPH_PARSE, M_NOWAIT);
138764505Sarchie	if (workBuf == NULL)
138864505Sarchie		return (ENOMEM);
138964505Sarchie
139053913Sarchie	/* Opening brace/bracket */
1391142902Sglebius	if ((error = ng_parse_append(&cbuf, &cbuflen, "%c",
1392142902Sglebius	    (ctype == CT_STRUCT) ? '{' : '[')) != 0)
1393142902Sglebius		goto fail;
139453913Sarchie
139553913Sarchie	/* Do each item */
139653913Sarchie	for (index = 0; index < num; index++) {
139753913Sarchie		const struct ng_parse_type *const
139853913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
139953913Sarchie
140053913Sarchie		/* Skip any alignment pad bytes */
140153913Sarchie		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
140253913Sarchie
140390047Sarchie		/*
140490047Sarchie		 * See if element is equal to its default value; skip if so.
140590047Sarchie		 * Copy struct ng_mesg header for types that peek into it.
140690047Sarchie		 */
140790047Sarchie		if (sizeof(*hdr) + *off < workSize) {
140890047Sarchie			int tempsize = workSize - sizeof(*hdr) - *off;
140953913Sarchie
141090584Sarchie			bcopy(hdr, workBuf, sizeof(*hdr) + *off);
141190047Sarchie			if (ng_get_composite_elem_default(type, index, workBuf
141290047Sarchie			      + sizeof(*hdr), workBuf + sizeof(*hdr) + *off,
141390047Sarchie			      &tempsize, ctype) == 0
141490047Sarchie			    && bcmp(workBuf + sizeof(*hdr) + *off,
141564505Sarchie			      data + *off, tempsize) == 0) {
141653913Sarchie				*off += tempsize;
141753913Sarchie				continue;
141853913Sarchie			}
141953913Sarchie		}
142053913Sarchie
142153913Sarchie		/* Print name= */
1422142902Sglebius		if ((error = ng_parse_append(&cbuf, &cbuflen, " ")) != 0)
1423142902Sglebius			goto fail;
142453913Sarchie		if (ctype != CT_STRUCT) {
142553913Sarchie			if (index != nextIndex) {
142653913Sarchie				nextIndex = index;
1427142902Sglebius				if ((error = ng_parse_append(&cbuf,
1428142902Sglebius				    &cbuflen, "%d=", index)) != 0)
1429142902Sglebius					goto fail;
143053913Sarchie			}
143153913Sarchie			nextIndex++;
143253913Sarchie		} else {
143397685Sarchie			const struct ng_parse_struct_field *const
143497685Sarchie			    fields = type->info;
143553913Sarchie
1436142902Sglebius			if ((error = ng_parse_append(&cbuf,
1437142902Sglebius			    &cbuflen, "%s=", fields[index].name)) != 0)
1438142902Sglebius				goto fail;
143953913Sarchie		}
144053913Sarchie
144153913Sarchie		/* Print value */
144253913Sarchie		if ((error = INVOKE(etype, unparse)
144364505Sarchie		    (etype, data, off, cbuf, cbuflen)) != 0) {
1444184205Sdes			free(workBuf, M_NETGRAPH_PARSE);
144553913Sarchie			return (error);
144664505Sarchie		}
144753913Sarchie		cbuflen -= strlen(cbuf);
144853913Sarchie		cbuf += strlen(cbuf);
144953913Sarchie		didOne = 1;
145053913Sarchie	}
145153913Sarchie
145253913Sarchie	/* Closing brace/bracket */
1453154375Sglebius	error = ng_parse_append(&cbuf, &cbuflen, "%s%c",
1454154375Sglebius	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
1455142902Sglebius
1456142902Sglebiusfail:
1457142902Sglebius	/* Clean up after failure */
1458184205Sdes	free(workBuf, M_NETGRAPH_PARSE);
1459142902Sglebius	return (error);
146053913Sarchie}
146153913Sarchie
146253913Sarchie/*
146353913Sarchie * Generate the default value for an element of an array or structure
146453913Sarchie * Returns EOPNOTSUPP if default value is unspecified.
146553913Sarchie */
146653913Sarchiestatic int
146753913Sarchieng_get_composite_elem_default(const struct ng_parse_type *type,
146853913Sarchie	int index, const u_char *const start, u_char *buf, int *buflen,
146953913Sarchie	const enum comptype ctype)
147053913Sarchie{
147153913Sarchie	const struct ng_parse_type *etype;
147253913Sarchie	ng_getDefault_t *func;
147353913Sarchie
147453913Sarchie	switch (ctype) {
147553913Sarchie	case CT_STRUCT:
147653913Sarchie		break;
147753913Sarchie	case CT_ARRAY:
147853913Sarchie	    {
147953913Sarchie		const struct ng_parse_array_info *const ai = type->info;
148053913Sarchie
148153913Sarchie		if (ai->getDefault != NULL) {
148253913Sarchie			return (*ai->getDefault)(type,
148353913Sarchie			    index, start, buf, buflen);
148453913Sarchie		}
148553913Sarchie		break;
148653913Sarchie	    }
148753913Sarchie	case CT_FIXEDARRAY:
148853913Sarchie	    {
148953913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
149053913Sarchie
149153913Sarchie		if (*fi->getDefault != NULL) {
149253913Sarchie			return (*fi->getDefault)(type,
149353913Sarchie			    index, start, buf, buflen);
149453913Sarchie		}
149553913Sarchie		break;
149653913Sarchie	    }
149753913Sarchie	default:
149887599Sobrien	    panic("%s", __func__);
149953913Sarchie	}
150053913Sarchie
150153913Sarchie	/* Default to element type default */
150253913Sarchie	etype = ng_get_composite_etype(type, index, ctype);
150353913Sarchie	func = METHOD(etype, getDefault);
150453913Sarchie	if (func == NULL)
150553913Sarchie		return (EOPNOTSUPP);
150653913Sarchie	return (*func)(etype, start, buf, buflen);
150753913Sarchie}
150853913Sarchie
150953913Sarchie/*
151053913Sarchie * Get the number of elements in a struct, variable or fixed array.
151153913Sarchie */
151253913Sarchiestatic int
151353913Sarchieng_get_composite_len(const struct ng_parse_type *type,
151453913Sarchie	const u_char *const start, const u_char *buf,
151553913Sarchie	const enum comptype ctype)
151653913Sarchie{
151753913Sarchie	switch (ctype) {
151853913Sarchie	case CT_STRUCT:
151953913Sarchie	    {
152097685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
152153913Sarchie		int numFields = 0;
152253913Sarchie
152353913Sarchie		for (numFields = 0; ; numFields++) {
152453913Sarchie			const struct ng_parse_struct_field *const
152597685Sarchie				fi = &fields[numFields];
152653913Sarchie
152753913Sarchie			if (fi->name == NULL)
152853913Sarchie				break;
152953913Sarchie		}
153053913Sarchie		return (numFields);
153153913Sarchie	    }
153253913Sarchie	case CT_ARRAY:
153353913Sarchie	    {
153453913Sarchie		const struct ng_parse_array_info *const ai = type->info;
153553913Sarchie
153653913Sarchie		return (*ai->getLength)(type, start, buf);
153753913Sarchie	    }
153853913Sarchie	case CT_FIXEDARRAY:
153953913Sarchie	    {
154053913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
154153913Sarchie
154253913Sarchie		return fi->length;
154353913Sarchie	    }
154453913Sarchie	default:
154587599Sobrien	    panic("%s", __func__);
154653913Sarchie	}
154753913Sarchie	return (0);
154853913Sarchie}
154953913Sarchie
155053913Sarchie/*
155153913Sarchie * Return the type of the index'th element of a composite structure
155253913Sarchie */
155353913Sarchiestatic const struct ng_parse_type *
155453913Sarchieng_get_composite_etype(const struct ng_parse_type *type,
155553913Sarchie	int index, const enum comptype ctype)
155653913Sarchie{
155753913Sarchie	const struct ng_parse_type *etype = NULL;
155853913Sarchie
155953913Sarchie	switch (ctype) {
156053913Sarchie	case CT_STRUCT:
156153913Sarchie	    {
156297685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
156353913Sarchie
156497685Sarchie		etype = fields[index].type;
156553913Sarchie		break;
156653913Sarchie	    }
156753913Sarchie	case CT_ARRAY:
156853913Sarchie	    {
156953913Sarchie		const struct ng_parse_array_info *const ai = type->info;
157053913Sarchie
157153913Sarchie		etype = ai->elementType;
157253913Sarchie		break;
157353913Sarchie	    }
157453913Sarchie	case CT_FIXEDARRAY:
157553913Sarchie	    {
157653913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
157753913Sarchie
157853913Sarchie		etype = fi->elementType;
157953913Sarchie		break;
158053913Sarchie	    }
158153913Sarchie	default:
158287599Sobrien	    panic("%s", __func__);
158353913Sarchie	}
158453913Sarchie	return (etype);
158553913Sarchie}
158653913Sarchie
158753913Sarchie/*
158853913Sarchie * Get the number of bytes to skip to align for the next
158953913Sarchie * element in a composite structure.
159053913Sarchie */
159153913Sarchiestatic int
159253913Sarchieng_parse_get_elem_pad(const struct ng_parse_type *type,
159353913Sarchie	int index, enum comptype ctype, int posn)
159453913Sarchie{
159553913Sarchie	const struct ng_parse_type *const
159653913Sarchie	    etype = ng_get_composite_etype(type, index, ctype);
159753913Sarchie	int align;
159853913Sarchie
159953913Sarchie	/* Get element's alignment, and possibly override */
160053913Sarchie	align = ALIGNMENT(etype);
160153913Sarchie	if (ctype == CT_STRUCT) {
160297685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
160353913Sarchie
160497685Sarchie		if (fields[index].alignment != 0)
160597685Sarchie			align = fields[index].alignment;
160653913Sarchie	}
160753913Sarchie
160853913Sarchie	/* Return number of bytes to skip to align */
160953913Sarchie	return (align ? (align - (posn % align)) % align : 0);
161053913Sarchie}
161153913Sarchie
161253913Sarchie/************************************************************************
161353913Sarchie			PARSING HELPER ROUTINES
161453913Sarchie ************************************************************************/
161553913Sarchie
161653913Sarchie/*
1617142902Sglebius * Append to a fixed length string buffer.
1618142902Sglebius */
1619142902Sglebiusstatic int
1620142902Sglebiusng_parse_append(char **cbufp, int *cbuflenp, const char *fmt, ...)
1621142902Sglebius{
1622142902Sglebius	va_list args;
1623142902Sglebius	int len;
1624142902Sglebius
1625142902Sglebius	va_start(args, fmt);
1626142902Sglebius	len = vsnprintf(*cbufp, *cbuflenp, fmt, args);
1627142902Sglebius	va_end(args);
1628142902Sglebius	if (len >= *cbuflenp)
1629142902Sglebius		return ERANGE;
1630142902Sglebius	*cbufp += len;
1631142902Sglebius	*cbuflenp -= len;
1632142902Sglebius
1633142902Sglebius	return (0);
1634142902Sglebius}
1635142902Sglebius
1636142902Sglebius/*
163753913Sarchie * Skip over a value
163853913Sarchie */
163953913Sarchiestatic int
164053913Sarchieng_parse_skip_value(const char *s, int off0, int *lenp)
164153913Sarchie{
164253913Sarchie	int len, nbracket, nbrace;
164353913Sarchie	int off = off0;
164453913Sarchie
164553913Sarchie	len = nbracket = nbrace = 0;
164653913Sarchie	do {
164753913Sarchie		switch (ng_parse_get_token(s, &off, &len)) {
164853913Sarchie		case T_LBRACKET:
164953913Sarchie			nbracket++;
165053913Sarchie			break;
165153913Sarchie		case T_LBRACE:
165253913Sarchie			nbrace++;
165353913Sarchie			break;
165453913Sarchie		case T_RBRACKET:
165553913Sarchie			if (nbracket-- == 0)
165653913Sarchie				return (EINVAL);
165753913Sarchie			break;
165853913Sarchie		case T_RBRACE:
165953913Sarchie			if (nbrace-- == 0)
166053913Sarchie				return (EINVAL);
166153913Sarchie			break;
166253913Sarchie		case T_EOF:
166353913Sarchie			return (EINVAL);
166453913Sarchie		default:
166553913Sarchie			break;
166653913Sarchie		}
166753913Sarchie		off += len;
166853913Sarchie	} while (nbracket > 0 || nbrace > 0);
166953913Sarchie	*lenp = off - off0;
167053913Sarchie	return (0);
167153913Sarchie}
167253913Sarchie
167353913Sarchie/*
167453913Sarchie * Find the next token in the string, starting at offset *startp.
167553913Sarchie * Returns the token type, with *startp pointing to the first char
167653913Sarchie * and *lenp the length.
167753913Sarchie */
167853913Sarchieenum ng_parse_token
167953913Sarchieng_parse_get_token(const char *s, int *startp, int *lenp)
168053913Sarchie{
168153913Sarchie	char *t;
168253913Sarchie	int i;
168353913Sarchie
168453913Sarchie	while (isspace(s[*startp]))
168553913Sarchie		(*startp)++;
168653913Sarchie	switch (s[*startp]) {
168753913Sarchie	case '\0':
168853913Sarchie		*lenp = 0;
168953913Sarchie		return T_EOF;
169053913Sarchie	case '{':
169153913Sarchie		*lenp = 1;
169253913Sarchie		return T_LBRACE;
169353913Sarchie	case '}':
169453913Sarchie		*lenp = 1;
169553913Sarchie		return T_RBRACE;
169653913Sarchie	case '[':
169753913Sarchie		*lenp = 1;
169853913Sarchie		return T_LBRACKET;
169953913Sarchie	case ']':
170053913Sarchie		*lenp = 1;
170153913Sarchie		return T_RBRACKET;
170253913Sarchie	case '=':
170353913Sarchie		*lenp = 1;
170453913Sarchie		return T_EQUALS;
170553913Sarchie	case '"':
170668845Sbrian		if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
170753913Sarchie			return T_ERROR;
1708184205Sdes		free(t, M_NETGRAPH_PARSE);
170953913Sarchie		return T_STRING;
171053913Sarchie	default:
171153913Sarchie		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
171253913Sarchie		    && s[i] != '{' && s[i] != '}' && s[i] != '['
171353913Sarchie		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
171453913Sarchie			;
171553913Sarchie		*lenp = i - *startp;
171653913Sarchie		return T_WORD;
171753913Sarchie	}
171853913Sarchie}
171953913Sarchie
172053913Sarchie/*
172153913Sarchie * Get a string token, which must be enclosed in double quotes.
172253913Sarchie * The normal C backslash escapes are recognized.
172353913Sarchie */
172453913Sarchiechar *
172568845Sbrianng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
172653913Sarchie{
172753913Sarchie	char *cbuf, *p;
172853913Sarchie	int start, off;
172968845Sbrian	int slen;
173053913Sarchie
173153913Sarchie	while (isspace(s[*startp]))
173253913Sarchie		(*startp)++;
173353913Sarchie	start = *startp;
173453913Sarchie	if (s[*startp] != '"')
173553913Sarchie		return (NULL);
1736184205Sdes	cbuf = malloc(strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
173753913Sarchie	if (cbuf == NULL)
173853913Sarchie		return (NULL);
173953913Sarchie	strcpy(cbuf, s + start + 1);
174068845Sbrian	for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
174153913Sarchie		if (*p == '"') {
174253913Sarchie			*p = '\0';
174353913Sarchie			*lenp = off + 1;
174468845Sbrian			if (slenp != NULL)
174568845Sbrian				*slenp = slen;
174653913Sarchie			return (cbuf);
174753913Sarchie		} else if (p[0] == '\\' && p[1] != '\0') {
174853913Sarchie			int x, k;
174953913Sarchie			char *v;
175053913Sarchie
175153913Sarchie			strcpy(p, p + 1);
175253913Sarchie			v = p;
175353913Sarchie			switch (*p) {
175453913Sarchie			case 't':
175553913Sarchie				*v = '\t';
175653913Sarchie				off++;
175753913Sarchie				continue;
175853913Sarchie			case 'n':
175953913Sarchie				*v = '\n';
176053913Sarchie				off++;
176153913Sarchie				continue;
176253913Sarchie			case 'r':
176353913Sarchie				*v = '\r';
176453913Sarchie				off++;
176553913Sarchie				continue;
176653913Sarchie			case 'v':
176753913Sarchie				*v =  '\v';
176853913Sarchie				off++;
176953913Sarchie				continue;
177053913Sarchie			case 'f':
177153913Sarchie				*v =  '\f';
177253913Sarchie				off++;
177353913Sarchie				continue;
177453913Sarchie			case '"':
177553913Sarchie				*v =  '"';
177653913Sarchie				off++;
177753913Sarchie				continue;
177853913Sarchie			case '0': case '1': case '2': case '3':
177953913Sarchie			case '4': case '5': case '6': case '7':
178053913Sarchie				for (x = k = 0;
178153913Sarchie				    k < 3 && *v >= '0' && *v <= '7'; v++) {
178253913Sarchie					x = (x << 3) + (*v - '0');
178353913Sarchie					off++;
178453913Sarchie				}
178553913Sarchie				*--v = (char)x;
178653913Sarchie				break;
178753913Sarchie			case 'x':
178853913Sarchie				for (v++, x = k = 0;
178953913Sarchie				    k < 2 && isxdigit(*v); v++) {
179053913Sarchie					x = (x << 4) + (isdigit(*v) ?
179153913Sarchie					      (*v - '0') :
179253913Sarchie					      (tolower(*v) - 'a' + 10));
179353913Sarchie					off++;
179453913Sarchie				}
179553913Sarchie				*--v = (char)x;
179653913Sarchie				break;
179753913Sarchie			default:
179853913Sarchie				continue;
179953913Sarchie			}
180053913Sarchie			strcpy(p, v);
180153913Sarchie		}
180253913Sarchie	}
1803184205Sdes	free(cbuf, M_NETGRAPH_PARSE);
180453913Sarchie	return (NULL);		/* no closing quote */
180553913Sarchie}
180653913Sarchie
180753913Sarchie/*
180853913Sarchie * Encode a string so it can be safely put in double quotes.
180968845Sbrian * Caller must free the result. Exactly "slen" characters
181068845Sbrian * are encoded.
181153913Sarchie */
181253913Sarchiechar *
181368845Sbrianng_encode_string(const char *raw, int slen)
181453913Sarchie{
181553913Sarchie	char *cbuf;
181653913Sarchie	int off = 0;
181768845Sbrian	int i;
181853913Sarchie
1819184205Sdes	cbuf = malloc(strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
182053913Sarchie	if (cbuf == NULL)
182153913Sarchie		return (NULL);
182253913Sarchie	cbuf[off++] = '"';
182368845Sbrian	for (i = 0; i < slen; i++, raw++) {
182453913Sarchie		switch (*raw) {
182553913Sarchie		case '\t':
182653913Sarchie			cbuf[off++] = '\\';
182753913Sarchie			cbuf[off++] = 't';
182853913Sarchie			break;
182953913Sarchie		case '\f':
183053913Sarchie			cbuf[off++] = '\\';
183153913Sarchie			cbuf[off++] = 'f';
183253913Sarchie			break;
183353913Sarchie		case '\n':
183453913Sarchie			cbuf[off++] = '\\';
183553913Sarchie			cbuf[off++] = 'n';
183653913Sarchie			break;
183753913Sarchie		case '\r':
183853913Sarchie			cbuf[off++] = '\\';
183953913Sarchie			cbuf[off++] = 'r';
184053913Sarchie			break;
184153913Sarchie		case '\v':
184253913Sarchie			cbuf[off++] = '\\';
184353913Sarchie			cbuf[off++] = 'v';
184453913Sarchie			break;
184553913Sarchie		case '"':
184653913Sarchie		case '\\':
184753913Sarchie			cbuf[off++] = '\\';
184853913Sarchie			cbuf[off++] = *raw;
184953913Sarchie			break;
185053913Sarchie		default:
185153913Sarchie			if (*raw < 0x20 || *raw > 0x7e) {
185253913Sarchie				off += sprintf(cbuf + off,
185353913Sarchie				    "\\x%02x", (u_char)*raw);
185453913Sarchie				break;
185553913Sarchie			}
185653913Sarchie			cbuf[off++] = *raw;
185753913Sarchie			break;
185853913Sarchie		}
185953913Sarchie	}
186053913Sarchie	cbuf[off++] = '"';
186153913Sarchie	cbuf[off] = '\0';
186253913Sarchie	return (cbuf);
186353913Sarchie}
186453913Sarchie
186553913Sarchie/************************************************************************
186653913Sarchie			VIRTUAL METHOD LOOKUP
186753913Sarchie ************************************************************************/
186853913Sarchie
186953913Sarchiestatic ng_parse_t *
187053913Sarchieng_get_parse_method(const struct ng_parse_type *t)
187153913Sarchie{
187253913Sarchie	while (t != NULL && t->parse == NULL)
187353913Sarchie		t = t->supertype;
187453913Sarchie	return (t ? t->parse : NULL);
187553913Sarchie}
187653913Sarchie
187753913Sarchiestatic ng_unparse_t *
187853913Sarchieng_get_unparse_method(const struct ng_parse_type *t)
187953913Sarchie{
188053913Sarchie	while (t != NULL && t->unparse == NULL)
188153913Sarchie		t = t->supertype;
188253913Sarchie	return (t ? t->unparse : NULL);
188353913Sarchie}
188453913Sarchie
188553913Sarchiestatic ng_getDefault_t *
188653913Sarchieng_get_getDefault_method(const struct ng_parse_type *t)
188753913Sarchie{
188853913Sarchie	while (t != NULL && t->getDefault == NULL)
188953913Sarchie		t = t->supertype;
189053913Sarchie	return (t ? t->getDefault : NULL);
189153913Sarchie}
189253913Sarchie
189353913Sarchiestatic ng_getAlign_t *
189453913Sarchieng_get_getAlign_method(const struct ng_parse_type *t)
189553913Sarchie{
189653913Sarchie	while (t != NULL && t->getAlign == NULL)
189753913Sarchie		t = t->supertype;
189853913Sarchie	return (t ? t->getAlign : NULL);
189953913Sarchie}
190053913Sarchie
1901