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: releng/10.3/sys/netgraph/ng_parse.c 278140 2015-02-03 07:59:33Z dim $
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
65227293Sedstatic 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;
1125278140Sdim		subtype.private = __DECONST(void *, 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;
1137278140Sdim	subtype.private = __DECONST(void *, 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;
1148278140Sdim	subtype.private = __DECONST(void *, 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) {
1239246821Sglebius			u_long ul;
124053913Sarchie			int len2, off2;
124153913Sarchie			char *eptr;
124253913Sarchie
124353913Sarchie			/* If an opening brace/bracket, index is implied */
124453913Sarchie			if (tok == T_LBRACE || tok == T_LBRACKET) {
124553913Sarchie				index = nextIndex++;
124653913Sarchie				goto gotIndex;
124753913Sarchie			}
124853913Sarchie
124953913Sarchie			/* Might be an index, might be a value, either way... */
125053913Sarchie			if (tok != T_WORD) {
125153913Sarchie				error = EINVAL;
125253913Sarchie				goto done;
125353913Sarchie			}
125453913Sarchie
125553913Sarchie			/* If no equals sign follows, index is implied */
125653913Sarchie			off2 = *off + len;
125753913Sarchie			if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
125853913Sarchie				index = nextIndex++;
125953913Sarchie				goto gotIndex;
126053913Sarchie			}
126153913Sarchie
126253913Sarchie			/* Index was specified explicitly; parse it */
1263246821Sglebius			ul = strtoul(s + *off, &eptr, 0);
1264246821Sglebius			if (ul == ULONG_MAX || eptr - (s + *off) != len) {
126553913Sarchie				error = EINVAL;
126653913Sarchie				goto done;
126753913Sarchie			}
1268246821Sglebius			index = (u_int)ul;
126953913Sarchie			nextIndex = index + 1;
127053913Sarchie			*off += len + len2;
127153913Sarchie		} else {			/* a structure field */
127297685Sarchie			const struct ng_parse_struct_field *const
127397685Sarchie			    fields = type->info;
127453913Sarchie
127553913Sarchie			/* Find the field by name (required) in field list */
127653913Sarchie			if (tok != T_WORD) {
127753913Sarchie				error = EINVAL;
127853913Sarchie				goto done;
127953913Sarchie			}
128053913Sarchie			for (index = 0; index < num; index++) {
128197685Sarchie				const struct ng_parse_struct_field *const
128297685Sarchie				    field = &fields[index];
128397685Sarchie
128453913Sarchie				if (strncmp(&s[*off], field->name, len) == 0
128553913Sarchie				    && field->name[len] == '\0')
128653913Sarchie					break;
128753913Sarchie			}
128853913Sarchie			if (index == num) {
128953913Sarchie				error = ENOENT;
129053913Sarchie				goto done;
129153913Sarchie			}
129253913Sarchie			*off += len;
129353913Sarchie
129453913Sarchie			/* Get equals sign */
129553913Sarchie			if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
129653913Sarchie				error = EINVAL;
129753913Sarchie				goto done;
129853913Sarchie			}
129953913Sarchie			*off += len;
130053913Sarchie		}
130197229SpetergotIndex:
130253913Sarchie
130353913Sarchie		/* Check array index */
130453913Sarchie		if (index >= num) {
130553913Sarchie			error = E2BIG;
130653913Sarchie			goto done;
130753913Sarchie		}
130853913Sarchie
130953913Sarchie		/* Save value's position and skip over it for now */
131053913Sarchie		if (foff[index] != 0) {
131153913Sarchie			error = EALREADY;		/* duplicate */
131253913Sarchie			goto done;
131353913Sarchie		}
131453913Sarchie		while (isspace(s[*off]))
131553913Sarchie			(*off)++;
131653913Sarchie		foff[index] = *off;
131753913Sarchie		if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
131853913Sarchie			goto done;
131953913Sarchie		*off += len;
132053913Sarchie	}
132153913Sarchie
132253913Sarchie	/* Now build binary structure from supplied values and defaults */
132353913Sarchie	for (blen = index = 0; index < num; index++) {
132453913Sarchie		const struct ng_parse_type *const
132553913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
132653913Sarchie		int k, pad, vlen;
132753913Sarchie
132853913Sarchie		/* Zero-pad any alignment bytes */
132953913Sarchie		pad = ng_parse_get_elem_pad(type, index, ctype, blen);
133053913Sarchie		for (k = 0; k < pad; k++) {
133153913Sarchie			if (blen >= *buflen) {
133253913Sarchie				error = ERANGE;
133353913Sarchie				goto done;
133453913Sarchie			}
133553913Sarchie			buf[blen++] = 0;
133653913Sarchie		}
133753913Sarchie
133853913Sarchie		/* Get value */
133953913Sarchie		vlen = *buflen - blen;
134053913Sarchie		if (foff[index] == 0) {		/* use default value */
134153913Sarchie			error = ng_get_composite_elem_default(type, index,
134253913Sarchie			    start, buf + blen, &vlen, ctype);
134353913Sarchie		} else {			/* parse given value */
134453913Sarchie			*off = foff[index];
134553913Sarchie			error = INVOKE(etype, parse)(etype,
134653913Sarchie			    s, off, start, buf + blen, &vlen);
134753913Sarchie		}
134853913Sarchie		if (error != 0)
134953913Sarchie			goto done;
135053913Sarchie		blen += vlen;
135153913Sarchie	}
135253913Sarchie
135353913Sarchie	/* Make total composite structure size a multiple of its alignment */
135453913Sarchie	if ((align = ALIGNMENT(type)) != 0) {
135553913Sarchie		while (blen % align != 0) {
135653913Sarchie			if (blen >= *buflen) {
135753913Sarchie				error = ERANGE;
135853913Sarchie				goto done;
135953913Sarchie			}
136053913Sarchie			buf[blen++] = 0;
136153913Sarchie		}
136253913Sarchie	}
136353913Sarchie
136453913Sarchie	/* Done */
136553913Sarchie	*buflen = blen;
136653913Sarchiedone:
136765303Sarchie	if (foff != NULL)
1368184205Sdes		free(foff, M_NETGRAPH_PARSE);
136953913Sarchie	return (error);
137053913Sarchie}
137153913Sarchie
137253913Sarchie/*
137353913Sarchie * Convert an array or structure from binary to ASCII
137453913Sarchie */
137553913Sarchiestatic int
137653913Sarchieng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
137753913Sarchie	int *off, char *cbuf, int cbuflen, const enum comptype ctype)
137853913Sarchie{
137990047Sarchie	const struct ng_mesg *const hdr
138090047Sarchie	    = (const struct ng_mesg *)(data - sizeof(*hdr));
138153913Sarchie	const int num = ng_get_composite_len(type, data, data + *off, ctype);
138264505Sarchie	const int workSize = 20 * 1024;		/* XXX hard coded constant */
138353913Sarchie	int nextIndex = 0, didOne = 0;
138453913Sarchie	int error, index;
138564505Sarchie	u_char *workBuf;
138653913Sarchie
138764505Sarchie	/* Get workspace for checking default values */
1388184205Sdes	workBuf = malloc(workSize, M_NETGRAPH_PARSE, M_NOWAIT);
138964505Sarchie	if (workBuf == NULL)
139064505Sarchie		return (ENOMEM);
139164505Sarchie
139253913Sarchie	/* Opening brace/bracket */
1393142902Sglebius	if ((error = ng_parse_append(&cbuf, &cbuflen, "%c",
1394142902Sglebius	    (ctype == CT_STRUCT) ? '{' : '[')) != 0)
1395142902Sglebius		goto fail;
139653913Sarchie
139753913Sarchie	/* Do each item */
139853913Sarchie	for (index = 0; index < num; index++) {
139953913Sarchie		const struct ng_parse_type *const
140053913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
140153913Sarchie
140253913Sarchie		/* Skip any alignment pad bytes */
140353913Sarchie		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
140453913Sarchie
140590047Sarchie		/*
140690047Sarchie		 * See if element is equal to its default value; skip if so.
140790047Sarchie		 * Copy struct ng_mesg header for types that peek into it.
140890047Sarchie		 */
140990047Sarchie		if (sizeof(*hdr) + *off < workSize) {
141090047Sarchie			int tempsize = workSize - sizeof(*hdr) - *off;
141153913Sarchie
141290584Sarchie			bcopy(hdr, workBuf, sizeof(*hdr) + *off);
141390047Sarchie			if (ng_get_composite_elem_default(type, index, workBuf
141490047Sarchie			      + sizeof(*hdr), workBuf + sizeof(*hdr) + *off,
141590047Sarchie			      &tempsize, ctype) == 0
141690047Sarchie			    && bcmp(workBuf + sizeof(*hdr) + *off,
141764505Sarchie			      data + *off, tempsize) == 0) {
141853913Sarchie				*off += tempsize;
141953913Sarchie				continue;
142053913Sarchie			}
142153913Sarchie		}
142253913Sarchie
142353913Sarchie		/* Print name= */
1424142902Sglebius		if ((error = ng_parse_append(&cbuf, &cbuflen, " ")) != 0)
1425142902Sglebius			goto fail;
142653913Sarchie		if (ctype != CT_STRUCT) {
142753913Sarchie			if (index != nextIndex) {
142853913Sarchie				nextIndex = index;
1429142902Sglebius				if ((error = ng_parse_append(&cbuf,
1430142902Sglebius				    &cbuflen, "%d=", index)) != 0)
1431142902Sglebius					goto fail;
143253913Sarchie			}
143353913Sarchie			nextIndex++;
143453913Sarchie		} else {
143597685Sarchie			const struct ng_parse_struct_field *const
143697685Sarchie			    fields = type->info;
143753913Sarchie
1438142902Sglebius			if ((error = ng_parse_append(&cbuf,
1439142902Sglebius			    &cbuflen, "%s=", fields[index].name)) != 0)
1440142902Sglebius				goto fail;
144153913Sarchie		}
144253913Sarchie
144353913Sarchie		/* Print value */
144453913Sarchie		if ((error = INVOKE(etype, unparse)
144564505Sarchie		    (etype, data, off, cbuf, cbuflen)) != 0) {
1446184205Sdes			free(workBuf, M_NETGRAPH_PARSE);
144753913Sarchie			return (error);
144864505Sarchie		}
144953913Sarchie		cbuflen -= strlen(cbuf);
145053913Sarchie		cbuf += strlen(cbuf);
145153913Sarchie		didOne = 1;
145253913Sarchie	}
145353913Sarchie
145453913Sarchie	/* Closing brace/bracket */
1455154375Sglebius	error = ng_parse_append(&cbuf, &cbuflen, "%s%c",
1456154375Sglebius	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
1457142902Sglebius
1458142902Sglebiusfail:
1459142902Sglebius	/* Clean up after failure */
1460184205Sdes	free(workBuf, M_NETGRAPH_PARSE);
1461142902Sglebius	return (error);
146253913Sarchie}
146353913Sarchie
146453913Sarchie/*
146553913Sarchie * Generate the default value for an element of an array or structure
146653913Sarchie * Returns EOPNOTSUPP if default value is unspecified.
146753913Sarchie */
146853913Sarchiestatic int
146953913Sarchieng_get_composite_elem_default(const struct ng_parse_type *type,
147053913Sarchie	int index, const u_char *const start, u_char *buf, int *buflen,
147153913Sarchie	const enum comptype ctype)
147253913Sarchie{
147353913Sarchie	const struct ng_parse_type *etype;
147453913Sarchie	ng_getDefault_t *func;
147553913Sarchie
147653913Sarchie	switch (ctype) {
147753913Sarchie	case CT_STRUCT:
147853913Sarchie		break;
147953913Sarchie	case CT_ARRAY:
148053913Sarchie	    {
148153913Sarchie		const struct ng_parse_array_info *const ai = type->info;
148253913Sarchie
148353913Sarchie		if (ai->getDefault != NULL) {
148453913Sarchie			return (*ai->getDefault)(type,
148553913Sarchie			    index, start, buf, buflen);
148653913Sarchie		}
148753913Sarchie		break;
148853913Sarchie	    }
148953913Sarchie	case CT_FIXEDARRAY:
149053913Sarchie	    {
149153913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
149253913Sarchie
149353913Sarchie		if (*fi->getDefault != NULL) {
149453913Sarchie			return (*fi->getDefault)(type,
149553913Sarchie			    index, start, buf, buflen);
149653913Sarchie		}
149753913Sarchie		break;
149853913Sarchie	    }
149953913Sarchie	default:
150087599Sobrien	    panic("%s", __func__);
150153913Sarchie	}
150253913Sarchie
150353913Sarchie	/* Default to element type default */
150453913Sarchie	etype = ng_get_composite_etype(type, index, ctype);
150553913Sarchie	func = METHOD(etype, getDefault);
150653913Sarchie	if (func == NULL)
150753913Sarchie		return (EOPNOTSUPP);
150853913Sarchie	return (*func)(etype, start, buf, buflen);
150953913Sarchie}
151053913Sarchie
151153913Sarchie/*
151253913Sarchie * Get the number of elements in a struct, variable or fixed array.
151353913Sarchie */
151453913Sarchiestatic int
151553913Sarchieng_get_composite_len(const struct ng_parse_type *type,
151653913Sarchie	const u_char *const start, const u_char *buf,
151753913Sarchie	const enum comptype ctype)
151853913Sarchie{
151953913Sarchie	switch (ctype) {
152053913Sarchie	case CT_STRUCT:
152153913Sarchie	    {
152297685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
152353913Sarchie		int numFields = 0;
152453913Sarchie
152553913Sarchie		for (numFields = 0; ; numFields++) {
152653913Sarchie			const struct ng_parse_struct_field *const
152797685Sarchie				fi = &fields[numFields];
152853913Sarchie
152953913Sarchie			if (fi->name == NULL)
153053913Sarchie				break;
153153913Sarchie		}
153253913Sarchie		return (numFields);
153353913Sarchie	    }
153453913Sarchie	case CT_ARRAY:
153553913Sarchie	    {
153653913Sarchie		const struct ng_parse_array_info *const ai = type->info;
153753913Sarchie
153853913Sarchie		return (*ai->getLength)(type, start, buf);
153953913Sarchie	    }
154053913Sarchie	case CT_FIXEDARRAY:
154153913Sarchie	    {
154253913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
154353913Sarchie
154453913Sarchie		return fi->length;
154553913Sarchie	    }
154653913Sarchie	default:
154787599Sobrien	    panic("%s", __func__);
154853913Sarchie	}
154953913Sarchie	return (0);
155053913Sarchie}
155153913Sarchie
155253913Sarchie/*
155353913Sarchie * Return the type of the index'th element of a composite structure
155453913Sarchie */
155553913Sarchiestatic const struct ng_parse_type *
155653913Sarchieng_get_composite_etype(const struct ng_parse_type *type,
155753913Sarchie	int index, const enum comptype ctype)
155853913Sarchie{
155953913Sarchie	const struct ng_parse_type *etype = NULL;
156053913Sarchie
156153913Sarchie	switch (ctype) {
156253913Sarchie	case CT_STRUCT:
156353913Sarchie	    {
156497685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
156553913Sarchie
156697685Sarchie		etype = fields[index].type;
156753913Sarchie		break;
156853913Sarchie	    }
156953913Sarchie	case CT_ARRAY:
157053913Sarchie	    {
157153913Sarchie		const struct ng_parse_array_info *const ai = type->info;
157253913Sarchie
157353913Sarchie		etype = ai->elementType;
157453913Sarchie		break;
157553913Sarchie	    }
157653913Sarchie	case CT_FIXEDARRAY:
157753913Sarchie	    {
157853913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
157953913Sarchie
158053913Sarchie		etype = fi->elementType;
158153913Sarchie		break;
158253913Sarchie	    }
158353913Sarchie	default:
158487599Sobrien	    panic("%s", __func__);
158553913Sarchie	}
158653913Sarchie	return (etype);
158753913Sarchie}
158853913Sarchie
158953913Sarchie/*
159053913Sarchie * Get the number of bytes to skip to align for the next
159153913Sarchie * element in a composite structure.
159253913Sarchie */
159353913Sarchiestatic int
159453913Sarchieng_parse_get_elem_pad(const struct ng_parse_type *type,
159553913Sarchie	int index, enum comptype ctype, int posn)
159653913Sarchie{
159753913Sarchie	const struct ng_parse_type *const
159853913Sarchie	    etype = ng_get_composite_etype(type, index, ctype);
159953913Sarchie	int align;
160053913Sarchie
160153913Sarchie	/* Get element's alignment, and possibly override */
160253913Sarchie	align = ALIGNMENT(etype);
160353913Sarchie	if (ctype == CT_STRUCT) {
160497685Sarchie		const struct ng_parse_struct_field *const fields = type->info;
160553913Sarchie
160697685Sarchie		if (fields[index].alignment != 0)
160797685Sarchie			align = fields[index].alignment;
160853913Sarchie	}
160953913Sarchie
161053913Sarchie	/* Return number of bytes to skip to align */
161153913Sarchie	return (align ? (align - (posn % align)) % align : 0);
161253913Sarchie}
161353913Sarchie
161453913Sarchie/************************************************************************
161553913Sarchie			PARSING HELPER ROUTINES
161653913Sarchie ************************************************************************/
161753913Sarchie
161853913Sarchie/*
1619142902Sglebius * Append to a fixed length string buffer.
1620142902Sglebius */
1621142902Sglebiusstatic int
1622142902Sglebiusng_parse_append(char **cbufp, int *cbuflenp, const char *fmt, ...)
1623142902Sglebius{
1624142902Sglebius	va_list args;
1625142902Sglebius	int len;
1626142902Sglebius
1627142902Sglebius	va_start(args, fmt);
1628142902Sglebius	len = vsnprintf(*cbufp, *cbuflenp, fmt, args);
1629142902Sglebius	va_end(args);
1630142902Sglebius	if (len >= *cbuflenp)
1631142902Sglebius		return ERANGE;
1632142902Sglebius	*cbufp += len;
1633142902Sglebius	*cbuflenp -= len;
1634142902Sglebius
1635142902Sglebius	return (0);
1636142902Sglebius}
1637142902Sglebius
1638142902Sglebius/*
163953913Sarchie * Skip over a value
164053913Sarchie */
164153913Sarchiestatic int
164253913Sarchieng_parse_skip_value(const char *s, int off0, int *lenp)
164353913Sarchie{
164453913Sarchie	int len, nbracket, nbrace;
164553913Sarchie	int off = off0;
164653913Sarchie
164753913Sarchie	len = nbracket = nbrace = 0;
164853913Sarchie	do {
164953913Sarchie		switch (ng_parse_get_token(s, &off, &len)) {
165053913Sarchie		case T_LBRACKET:
165153913Sarchie			nbracket++;
165253913Sarchie			break;
165353913Sarchie		case T_LBRACE:
165453913Sarchie			nbrace++;
165553913Sarchie			break;
165653913Sarchie		case T_RBRACKET:
165753913Sarchie			if (nbracket-- == 0)
165853913Sarchie				return (EINVAL);
165953913Sarchie			break;
166053913Sarchie		case T_RBRACE:
166153913Sarchie			if (nbrace-- == 0)
166253913Sarchie				return (EINVAL);
166353913Sarchie			break;
166453913Sarchie		case T_EOF:
166553913Sarchie			return (EINVAL);
166653913Sarchie		default:
166753913Sarchie			break;
166853913Sarchie		}
166953913Sarchie		off += len;
167053913Sarchie	} while (nbracket > 0 || nbrace > 0);
167153913Sarchie	*lenp = off - off0;
167253913Sarchie	return (0);
167353913Sarchie}
167453913Sarchie
167553913Sarchie/*
167653913Sarchie * Find the next token in the string, starting at offset *startp.
167753913Sarchie * Returns the token type, with *startp pointing to the first char
167853913Sarchie * and *lenp the length.
167953913Sarchie */
168053913Sarchieenum ng_parse_token
168153913Sarchieng_parse_get_token(const char *s, int *startp, int *lenp)
168253913Sarchie{
168353913Sarchie	char *t;
168453913Sarchie	int i;
168553913Sarchie
168653913Sarchie	while (isspace(s[*startp]))
168753913Sarchie		(*startp)++;
168853913Sarchie	switch (s[*startp]) {
168953913Sarchie	case '\0':
169053913Sarchie		*lenp = 0;
169153913Sarchie		return T_EOF;
169253913Sarchie	case '{':
169353913Sarchie		*lenp = 1;
169453913Sarchie		return T_LBRACE;
169553913Sarchie	case '}':
169653913Sarchie		*lenp = 1;
169753913Sarchie		return T_RBRACE;
169853913Sarchie	case '[':
169953913Sarchie		*lenp = 1;
170053913Sarchie		return T_LBRACKET;
170153913Sarchie	case ']':
170253913Sarchie		*lenp = 1;
170353913Sarchie		return T_RBRACKET;
170453913Sarchie	case '=':
170553913Sarchie		*lenp = 1;
170653913Sarchie		return T_EQUALS;
170753913Sarchie	case '"':
170868845Sbrian		if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
170953913Sarchie			return T_ERROR;
1710184205Sdes		free(t, M_NETGRAPH_PARSE);
171153913Sarchie		return T_STRING;
171253913Sarchie	default:
171353913Sarchie		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
171453913Sarchie		    && s[i] != '{' && s[i] != '}' && s[i] != '['
171553913Sarchie		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
171653913Sarchie			;
171753913Sarchie		*lenp = i - *startp;
171853913Sarchie		return T_WORD;
171953913Sarchie	}
172053913Sarchie}
172153913Sarchie
172253913Sarchie/*
172353913Sarchie * Get a string token, which must be enclosed in double quotes.
172453913Sarchie * The normal C backslash escapes are recognized.
172553913Sarchie */
172653913Sarchiechar *
172768845Sbrianng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
172853913Sarchie{
172953913Sarchie	char *cbuf, *p;
173053913Sarchie	int start, off;
173168845Sbrian	int slen;
173253913Sarchie
173353913Sarchie	while (isspace(s[*startp]))
173453913Sarchie		(*startp)++;
173553913Sarchie	start = *startp;
173653913Sarchie	if (s[*startp] != '"')
173753913Sarchie		return (NULL);
1738184205Sdes	cbuf = malloc(strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
173953913Sarchie	if (cbuf == NULL)
174053913Sarchie		return (NULL);
174153913Sarchie	strcpy(cbuf, s + start + 1);
174268845Sbrian	for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
174353913Sarchie		if (*p == '"') {
174453913Sarchie			*p = '\0';
174553913Sarchie			*lenp = off + 1;
174668845Sbrian			if (slenp != NULL)
174768845Sbrian				*slenp = slen;
174853913Sarchie			return (cbuf);
174953913Sarchie		} else if (p[0] == '\\' && p[1] != '\0') {
175053913Sarchie			int x, k;
175153913Sarchie			char *v;
175253913Sarchie
175353913Sarchie			strcpy(p, p + 1);
175453913Sarchie			v = p;
175553913Sarchie			switch (*p) {
175653913Sarchie			case 't':
175753913Sarchie				*v = '\t';
175853913Sarchie				off++;
175953913Sarchie				continue;
176053913Sarchie			case 'n':
176153913Sarchie				*v = '\n';
176253913Sarchie				off++;
176353913Sarchie				continue;
176453913Sarchie			case 'r':
176553913Sarchie				*v = '\r';
176653913Sarchie				off++;
176753913Sarchie				continue;
176853913Sarchie			case 'v':
176953913Sarchie				*v =  '\v';
177053913Sarchie				off++;
177153913Sarchie				continue;
177253913Sarchie			case 'f':
177353913Sarchie				*v =  '\f';
177453913Sarchie				off++;
177553913Sarchie				continue;
177653913Sarchie			case '"':
177753913Sarchie				*v =  '"';
177853913Sarchie				off++;
177953913Sarchie				continue;
178053913Sarchie			case '0': case '1': case '2': case '3':
178153913Sarchie			case '4': case '5': case '6': case '7':
178253913Sarchie				for (x = k = 0;
178353913Sarchie				    k < 3 && *v >= '0' && *v <= '7'; v++) {
178453913Sarchie					x = (x << 3) + (*v - '0');
178553913Sarchie					off++;
178653913Sarchie				}
178753913Sarchie				*--v = (char)x;
178853913Sarchie				break;
178953913Sarchie			case 'x':
179053913Sarchie				for (v++, x = k = 0;
179153913Sarchie				    k < 2 && isxdigit(*v); v++) {
179253913Sarchie					x = (x << 4) + (isdigit(*v) ?
179353913Sarchie					      (*v - '0') :
179453913Sarchie					      (tolower(*v) - 'a' + 10));
179553913Sarchie					off++;
179653913Sarchie				}
179753913Sarchie				*--v = (char)x;
179853913Sarchie				break;
179953913Sarchie			default:
180053913Sarchie				continue;
180153913Sarchie			}
180253913Sarchie			strcpy(p, v);
180353913Sarchie		}
180453913Sarchie	}
1805184205Sdes	free(cbuf, M_NETGRAPH_PARSE);
180653913Sarchie	return (NULL);		/* no closing quote */
180753913Sarchie}
180853913Sarchie
180953913Sarchie/*
181053913Sarchie * Encode a string so it can be safely put in double quotes.
181168845Sbrian * Caller must free the result. Exactly "slen" characters
181268845Sbrian * are encoded.
181353913Sarchie */
181453913Sarchiechar *
181568845Sbrianng_encode_string(const char *raw, int slen)
181653913Sarchie{
181753913Sarchie	char *cbuf;
181853913Sarchie	int off = 0;
181968845Sbrian	int i;
182053913Sarchie
1821184205Sdes	cbuf = malloc(strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
182253913Sarchie	if (cbuf == NULL)
182353913Sarchie		return (NULL);
182453913Sarchie	cbuf[off++] = '"';
182568845Sbrian	for (i = 0; i < slen; i++, raw++) {
182653913Sarchie		switch (*raw) {
182753913Sarchie		case '\t':
182853913Sarchie			cbuf[off++] = '\\';
182953913Sarchie			cbuf[off++] = 't';
183053913Sarchie			break;
183153913Sarchie		case '\f':
183253913Sarchie			cbuf[off++] = '\\';
183353913Sarchie			cbuf[off++] = 'f';
183453913Sarchie			break;
183553913Sarchie		case '\n':
183653913Sarchie			cbuf[off++] = '\\';
183753913Sarchie			cbuf[off++] = 'n';
183853913Sarchie			break;
183953913Sarchie		case '\r':
184053913Sarchie			cbuf[off++] = '\\';
184153913Sarchie			cbuf[off++] = 'r';
184253913Sarchie			break;
184353913Sarchie		case '\v':
184453913Sarchie			cbuf[off++] = '\\';
184553913Sarchie			cbuf[off++] = 'v';
184653913Sarchie			break;
184753913Sarchie		case '"':
184853913Sarchie		case '\\':
184953913Sarchie			cbuf[off++] = '\\';
185053913Sarchie			cbuf[off++] = *raw;
185153913Sarchie			break;
185253913Sarchie		default:
185353913Sarchie			if (*raw < 0x20 || *raw > 0x7e) {
185453913Sarchie				off += sprintf(cbuf + off,
185553913Sarchie				    "\\x%02x", (u_char)*raw);
185653913Sarchie				break;
185753913Sarchie			}
185853913Sarchie			cbuf[off++] = *raw;
185953913Sarchie			break;
186053913Sarchie		}
186153913Sarchie	}
186253913Sarchie	cbuf[off++] = '"';
186353913Sarchie	cbuf[off] = '\0';
186453913Sarchie	return (cbuf);
186553913Sarchie}
186653913Sarchie
186753913Sarchie/************************************************************************
186853913Sarchie			VIRTUAL METHOD LOOKUP
186953913Sarchie ************************************************************************/
187053913Sarchie
187153913Sarchiestatic ng_parse_t *
187253913Sarchieng_get_parse_method(const struct ng_parse_type *t)
187353913Sarchie{
187453913Sarchie	while (t != NULL && t->parse == NULL)
187553913Sarchie		t = t->supertype;
187653913Sarchie	return (t ? t->parse : NULL);
187753913Sarchie}
187853913Sarchie
187953913Sarchiestatic ng_unparse_t *
188053913Sarchieng_get_unparse_method(const struct ng_parse_type *t)
188153913Sarchie{
188253913Sarchie	while (t != NULL && t->unparse == NULL)
188353913Sarchie		t = t->supertype;
188453913Sarchie	return (t ? t->unparse : NULL);
188553913Sarchie}
188653913Sarchie
188753913Sarchiestatic ng_getDefault_t *
188853913Sarchieng_get_getDefault_method(const struct ng_parse_type *t)
188953913Sarchie{
189053913Sarchie	while (t != NULL && t->getDefault == NULL)
189153913Sarchie		t = t->supertype;
189253913Sarchie	return (t ? t->getDefault : NULL);
189353913Sarchie}
189453913Sarchie
189553913Sarchiestatic ng_getAlign_t *
189653913Sarchieng_get_getAlign_method(const struct ng_parse_type *t)
189753913Sarchie{
189853913Sarchie	while (t != NULL && t->getAlign == NULL)
189953913Sarchie		t = t->supertype;
190053913Sarchie	return (t ? t->getAlign : NULL);
190153913Sarchie}
190253913Sarchie
1903