ng_parse.c revision 58011
153913Sarchie
253913Sarchie/*
353913Sarchie * ng_parse.c
453913Sarchie *
553913Sarchie * Copyright (c) 1999 Whistle Communications, Inc.
653913Sarchie * All rights reserved.
753913Sarchie *
853913Sarchie * Subject to the following obligations and disclaimer of warranty, use and
953913Sarchie * redistribution of this software, in source or object code forms, with or
1053913Sarchie * without modifications are expressly permitted by Whistle Communications;
1153913Sarchie * provided, however, that:
1253913Sarchie * 1. Any and all reproductions of the source or object code must include the
1353913Sarchie *    copyright notice above and the following disclaimer of warranties; and
1453913Sarchie * 2. No rights are granted, in any manner or form, to use Whistle
1553913Sarchie *    Communications, Inc. trademarks, including the mark "WHISTLE
1653913Sarchie *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1753913Sarchie *    such appears in the above copyright notice or in the software.
1853913Sarchie *
1953913Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2053913Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2153913Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2253913Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2353913Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2453913Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2553913Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2653913Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2753913Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2853913Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
2953913Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3053913Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3153913Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3253913Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3353913Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3453913Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3553913Sarchie * OF SUCH DAMAGE.
3653913Sarchie *
3753913Sarchie * Author: Archie Cobbs <archie@whistle.com>
3853913Sarchie *
3953913Sarchie * $Whistle: ng_parse.c,v 1.3 1999/11/29 01:43:48 archie Exp $
4053913Sarchie * $FreeBSD: head/sys/netgraph/ng_parse.c 58011 2000-03-13 18:50:38Z archie $
4153913Sarchie */
4253913Sarchie
4353913Sarchie#include <sys/types.h>
4453913Sarchie#include <sys/param.h>
4553913Sarchie#include <sys/systm.h>
4653913Sarchie#include <sys/errno.h>
4753913Sarchie#include <sys/malloc.h>
4853913Sarchie#include <sys/ctype.h>
4953913Sarchie
5053913Sarchie#include <netinet/in.h>
5153913Sarchie
5253913Sarchie#include <netgraph/ng_message.h>
5353913Sarchie#include <netgraph/netgraph.h>
5453913Sarchie#include <netgraph/ng_parse.h>
5553913Sarchie
5653913Sarchie/* Compute alignment for primitive integral types */
5753913Sarchiestruct int16_temp {
5853913Sarchie	char	x;
5953913Sarchie	int16_t	y;
6053913Sarchie};
6153913Sarchie
6253913Sarchiestruct int32_temp {
6353913Sarchie	char	x;
6453913Sarchie	int32_t	y;
6553913Sarchie};
6653913Sarchie
6753913Sarchiestruct int64_temp {
6853913Sarchie	char	x;
6953913Sarchie	int64_t	y;
7053913Sarchie};
7153913Sarchie
7253913Sarchie#define INT8_ALIGNMENT		1
7353913Sarchie#define INT16_ALIGNMENT		((int)&((struct int16_temp *)0)->y)
7453913Sarchie#define INT32_ALIGNMENT		((int)&((struct int32_temp *)0)->y)
7553913Sarchie#define INT64_ALIGNMENT		((int)&((struct int64_temp *)0)->y)
7653913Sarchie
7753913Sarchie/* Type of composite object: struct, array, or fixedarray */
7853913Sarchieenum comptype {
7953913Sarchie	CT_STRUCT,
8053913Sarchie	CT_ARRAY,
8153913Sarchie	CT_FIXEDARRAY,
8253913Sarchie};
8353913Sarchie
8453913Sarchie/* Composite types helper functions */
8553913Sarchiestatic int	ng_parse_composite(const struct ng_parse_type *type,
8653913Sarchie			const char *s, int *off, const u_char *start,
8753913Sarchie			u_char *const buf, int *buflen, enum comptype ctype);
8853913Sarchiestatic int	ng_unparse_composite(const struct ng_parse_type *type,
8953913Sarchie			const u_char *data, int *off, char *cbuf, int cbuflen,
9053913Sarchie			enum comptype ctype);
9153913Sarchiestatic int	ng_get_composite_elem_default(const struct ng_parse_type *type,
9253913Sarchie			int index, const u_char *start, u_char *buf,
9353913Sarchie			int *buflen, enum comptype ctype);
9453913Sarchiestatic int	ng_get_composite_len(const struct ng_parse_type *type,
9553913Sarchie			const u_char *start, const u_char *buf,
9653913Sarchie			enum comptype ctype);
9753913Sarchiestatic const	struct ng_parse_type *ng_get_composite_etype(const struct
9853913Sarchie			ng_parse_type *type, int index, enum comptype ctype);
9953913Sarchiestatic int	ng_parse_get_elem_pad(const struct ng_parse_type *type,
10053913Sarchie			int index, enum comptype ctype, int posn);
10153913Sarchie
10253913Sarchie/* Parsing helper functions */
10353913Sarchiestatic int	ng_parse_skip_value(const char *s, int off, int *lenp);
10453913Sarchie
10553913Sarchie/* Poor man's virtual method calls */
10653913Sarchie#define METHOD(t,m)	(ng_get_ ## m ## _method(t))
10753913Sarchie#define INVOKE(t,m)	(*METHOD(t,m))
10853913Sarchie
10953913Sarchiestatic ng_parse_t	*ng_get_parse_method(const struct ng_parse_type *t);
11053913Sarchiestatic ng_unparse_t	*ng_get_unparse_method(const struct ng_parse_type *t);
11153913Sarchiestatic ng_getDefault_t	*ng_get_getDefault_method(const
11253913Sarchie				struct ng_parse_type *t);
11353913Sarchiestatic ng_getAlign_t	*ng_get_getAlign_method(const struct ng_parse_type *t);
11453913Sarchie
11553913Sarchie#define ALIGNMENT(t)	(METHOD(t, getAlign) == NULL ? \
11653913Sarchie				0 : INVOKE(t, getAlign)(t))
11753913Sarchie
11853913Sarchie/* For converting binary to string */
11953913Sarchie#define NG_PARSE_APPEND(fmt, args...)				\
12053913Sarchie		do {						\
12153913Sarchie			int len;				\
12253913Sarchie								\
12353913Sarchie			len = snprintf((cbuf), (cbuflen),	\
12453913Sarchie				fmt , ## args);			\
12553913Sarchie			if (len >= (cbuflen))			\
12653913Sarchie				return (ERANGE);		\
12753913Sarchie			(cbuf) += len;				\
12853913Sarchie			(cbuflen) -= len;			\
12953913Sarchie		} while (0)
13053913Sarchie
13153913Sarchie/************************************************************************
13253913Sarchie			PUBLIC FUNCTIONS
13353913Sarchie ************************************************************************/
13453913Sarchie
13553913Sarchie/*
13653913Sarchie * Convert an ASCII string to binary according to the supplied type descriptor
13753913Sarchie */
13853913Sarchieint
13953913Sarchieng_parse(const struct ng_parse_type *type,
14053913Sarchie	const char *string, int *off, u_char *buf, int *buflen)
14153913Sarchie{
14253913Sarchie	return INVOKE(type, parse)(type, string, off, buf, buf, buflen);
14353913Sarchie}
14453913Sarchie
14553913Sarchie/*
14653913Sarchie * Convert binary to an ASCII string according to the supplied type descriptor
14753913Sarchie */
14853913Sarchieint
14953913Sarchieng_unparse(const struct ng_parse_type *type,
15053913Sarchie	const u_char *data, char *cbuf, int cbuflen)
15153913Sarchie{
15253913Sarchie	int off = 0;
15353913Sarchie
15453913Sarchie	return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen);
15553913Sarchie}
15653913Sarchie
15753913Sarchie/*
15853913Sarchie * Fill in the default value according to the supplied type descriptor
15953913Sarchie */
16053913Sarchieint
16153913Sarchieng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen)
16253913Sarchie{
16353913Sarchie	ng_getDefault_t *const func = METHOD(type, getDefault);
16453913Sarchie
16553913Sarchie	if (func == NULL)
16653913Sarchie		return (EOPNOTSUPP);
16753913Sarchie	return (*func)(type, buf, buf, buflen);
16853913Sarchie}
16953913Sarchie
17053913Sarchie
17153913Sarchie/************************************************************************
17253913Sarchie			STRUCTURE TYPE
17353913Sarchie ************************************************************************/
17453913Sarchie
17553913Sarchiestatic int
17653913Sarchieng_struct_parse(const struct ng_parse_type *type,
17753913Sarchie	const char *s, int *off, const u_char *const start,
17853913Sarchie	u_char *const buf, int *buflen)
17953913Sarchie{
18053913Sarchie	return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT);
18153913Sarchie}
18253913Sarchie
18353913Sarchiestatic int
18453913Sarchieng_struct_unparse(const struct ng_parse_type *type,
18553913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
18653913Sarchie{
18753913Sarchie	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT);
18853913Sarchie}
18953913Sarchie
19053913Sarchiestatic int
19153913Sarchieng_struct_getDefault(const struct ng_parse_type *type,
19253913Sarchie	const u_char *const start, u_char *buf, int *buflen)
19353913Sarchie{
19453913Sarchie	int off = 0;
19553913Sarchie
19653913Sarchie	return ng_parse_composite(type,
19753913Sarchie	    "{}", &off, start, buf, buflen, CT_STRUCT);
19853913Sarchie}
19953913Sarchie
20053913Sarchiestatic int
20153913Sarchieng_struct_getAlign(const struct ng_parse_type *type)
20253913Sarchie{
20353913Sarchie	const struct ng_parse_struct_info *si = type->info;
20453913Sarchie	const struct ng_parse_struct_field *field;
20553913Sarchie	int align = 0;
20653913Sarchie
20753913Sarchie	for (field = si->fields; field->name != NULL; field++) {
20853913Sarchie		int falign = ALIGNMENT(field->type);
20953913Sarchie
21053913Sarchie		if (falign > align)
21153913Sarchie			align = falign;
21253913Sarchie	}
21353913Sarchie	return align;
21453913Sarchie}
21553913Sarchie
21653913Sarchieconst struct ng_parse_type ng_parse_struct_type = {
21753913Sarchie	NULL,
21853913Sarchie	NULL,
21953913Sarchie	NULL,
22053913Sarchie	ng_struct_parse,
22153913Sarchie	ng_struct_unparse,
22253913Sarchie	ng_struct_getDefault,
22353913Sarchie	ng_struct_getAlign
22453913Sarchie};
22553913Sarchie
22653913Sarchie/************************************************************************
22753913Sarchie			FIXED LENGTH ARRAY TYPE
22853913Sarchie ************************************************************************/
22953913Sarchie
23053913Sarchiestatic int
23153913Sarchieng_fixedarray_parse(const struct ng_parse_type *type,
23253913Sarchie	const char *s, int *off, const u_char *const start,
23353913Sarchie	u_char *const buf, int *buflen)
23453913Sarchie{
23553913Sarchie	return ng_parse_composite(type,
23653913Sarchie	    s, off, start, buf, buflen, CT_FIXEDARRAY);
23753913Sarchie}
23853913Sarchie
23953913Sarchiestatic int
24053913Sarchieng_fixedarray_unparse(const struct ng_parse_type *type,
24153913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
24253913Sarchie{
24353913Sarchie	return ng_unparse_composite(type,
24453913Sarchie		data, off, cbuf, cbuflen, CT_FIXEDARRAY);
24553913Sarchie}
24653913Sarchie
24753913Sarchiestatic int
24853913Sarchieng_fixedarray_getDefault(const struct ng_parse_type *type,
24953913Sarchie	const u_char *const start, u_char *buf, int *buflen)
25053913Sarchie{
25153913Sarchie	int off = 0;
25253913Sarchie
25353913Sarchie	return ng_parse_composite(type,
25453913Sarchie	    "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
25553913Sarchie}
25653913Sarchie
25753913Sarchiestatic int
25853913Sarchieng_fixedarray_getAlign(const struct ng_parse_type *type)
25953913Sarchie{
26053913Sarchie	const struct ng_parse_fixedarray_info *fi = type->info;
26153913Sarchie
26253913Sarchie	return ALIGNMENT(fi->elementType);
26353913Sarchie}
26453913Sarchie
26553913Sarchieconst struct ng_parse_type ng_parse_fixedarray_type = {
26653913Sarchie	NULL,
26753913Sarchie	NULL,
26853913Sarchie	NULL,
26953913Sarchie	ng_fixedarray_parse,
27053913Sarchie	ng_fixedarray_unparse,
27153913Sarchie	ng_fixedarray_getDefault,
27253913Sarchie	ng_fixedarray_getAlign
27353913Sarchie};
27453913Sarchie
27553913Sarchie/************************************************************************
27653913Sarchie			VARIABLE LENGTH ARRAY TYPE
27753913Sarchie ************************************************************************/
27853913Sarchie
27953913Sarchiestatic int
28053913Sarchieng_array_parse(const struct ng_parse_type *type,
28153913Sarchie	const char *s, int *off, const u_char *const start,
28253913Sarchie	u_char *const buf, int *buflen)
28353913Sarchie{
28453913Sarchie	return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
28553913Sarchie}
28653913Sarchie
28753913Sarchiestatic int
28853913Sarchieng_array_unparse(const struct ng_parse_type *type,
28953913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
29053913Sarchie{
29153913Sarchie	return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
29253913Sarchie}
29353913Sarchie
29453913Sarchiestatic int
29553913Sarchieng_array_getDefault(const struct ng_parse_type *type,
29653913Sarchie	const u_char *const start, u_char *buf, int *buflen)
29753913Sarchie{
29853913Sarchie	int off = 0;
29953913Sarchie
30053913Sarchie	return ng_parse_composite(type,
30153913Sarchie	    "[]", &off, start, buf, buflen, CT_ARRAY);
30253913Sarchie}
30353913Sarchie
30453913Sarchiestatic int
30553913Sarchieng_array_getAlign(const struct ng_parse_type *type)
30653913Sarchie{
30753913Sarchie	const struct ng_parse_array_info *ai = type->info;
30853913Sarchie
30953913Sarchie	return ALIGNMENT(ai->elementType);
31053913Sarchie}
31153913Sarchie
31253913Sarchieconst struct ng_parse_type ng_parse_array_type = {
31353913Sarchie	NULL,
31453913Sarchie	NULL,
31553913Sarchie	NULL,
31653913Sarchie	ng_array_parse,
31753913Sarchie	ng_array_unparse,
31853913Sarchie	ng_array_getDefault,
31953913Sarchie	ng_array_getAlign
32053913Sarchie};
32153913Sarchie
32253913Sarchie/************************************************************************
32353913Sarchie				INT8 TYPE
32453913Sarchie ************************************************************************/
32553913Sarchie
32653913Sarchiestatic int
32753913Sarchieng_int8_parse(const struct ng_parse_type *type,
32853913Sarchie	const char *s, int *off, const u_char *const start,
32953913Sarchie	u_char *const buf, int *buflen)
33053913Sarchie{
33153913Sarchie	long val;
33253913Sarchie	int8_t val8;
33353913Sarchie	char *eptr;
33453913Sarchie
33553913Sarchie	val = strtol(s + *off, &eptr, 0);
33653913Sarchie	if (val < -0x80 || val > 0xff || eptr == s + *off)
33753913Sarchie		return (EINVAL);
33853913Sarchie	*off = eptr - s;
33953913Sarchie	val8 = (int8_t)val;
34053913Sarchie	bcopy(&val8, buf, sizeof(int8_t));
34153913Sarchie	*buflen = sizeof(int8_t);
34253913Sarchie	return (0);
34353913Sarchie}
34453913Sarchie
34553913Sarchiestatic int
34653913Sarchieng_int8_unparse(const struct ng_parse_type *type,
34753913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
34853913Sarchie{
34953913Sarchie	int8_t val;
35053913Sarchie
35153913Sarchie	bcopy(data + *off, &val, sizeof(int8_t));
35253913Sarchie	NG_PARSE_APPEND("%d", (int)val);
35353913Sarchie	*off += sizeof(int8_t);
35453913Sarchie	return (0);
35553913Sarchie}
35653913Sarchie
35753913Sarchiestatic int
35853913Sarchieng_int8_getDefault(const struct ng_parse_type *type,
35953913Sarchie	const u_char *const start, u_char *buf, int *buflen)
36053913Sarchie{
36153913Sarchie	int8_t val;
36253913Sarchie
36353913Sarchie	if (*buflen < sizeof(int8_t))
36453913Sarchie		return (ERANGE);
36553913Sarchie	val = 0;
36653913Sarchie	bcopy(&val, buf, sizeof(int8_t));
36753913Sarchie	*buflen = sizeof(int8_t);
36853913Sarchie	return (0);
36953913Sarchie}
37053913Sarchie
37153913Sarchiestatic int
37253913Sarchieng_int8_getAlign(const struct ng_parse_type *type)
37353913Sarchie{
37453913Sarchie	return INT8_ALIGNMENT;
37553913Sarchie}
37653913Sarchie
37753913Sarchieconst struct ng_parse_type ng_parse_int8_type = {
37853913Sarchie	NULL,
37953913Sarchie	NULL,
38053913Sarchie	NULL,
38153913Sarchie	ng_int8_parse,
38253913Sarchie	ng_int8_unparse,
38353913Sarchie	ng_int8_getDefault,
38453913Sarchie	ng_int8_getAlign
38553913Sarchie};
38653913Sarchie
38753913Sarchie/************************************************************************
38853913Sarchie				INT16 TYPE
38953913Sarchie ************************************************************************/
39053913Sarchie
39153913Sarchiestatic int
39253913Sarchieng_int16_parse(const struct ng_parse_type *type,
39353913Sarchie	const char *s, int *off, const u_char *const start,
39453913Sarchie	u_char *const buf, int *buflen)
39553913Sarchie{
39653913Sarchie	long val;
39753913Sarchie	int16_t val16;
39853913Sarchie	char *eptr;
39953913Sarchie
40053913Sarchie	val = strtol(s + *off, &eptr, 0);
40153913Sarchie	if (val < -0x8000 || val > 0xffff || eptr == s + *off)
40253913Sarchie		return (EINVAL);
40353913Sarchie	*off = eptr - s;
40453913Sarchie	val16 = (int16_t)val;
40553913Sarchie	bcopy(&val16, buf, sizeof(int16_t));
40653913Sarchie	*buflen = sizeof(int16_t);
40753913Sarchie	return (0);
40853913Sarchie}
40953913Sarchie
41053913Sarchiestatic int
41153913Sarchieng_int16_unparse(const struct ng_parse_type *type,
41253913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
41353913Sarchie{
41453913Sarchie	int16_t val;
41553913Sarchie
41653913Sarchie	bcopy(data + *off, &val, sizeof(int16_t));
41753913Sarchie	NG_PARSE_APPEND("%d", (int)val);
41853913Sarchie	*off += sizeof(int16_t);
41953913Sarchie	return (0);
42053913Sarchie}
42153913Sarchie
42253913Sarchiestatic int
42353913Sarchieng_int16_getDefault(const struct ng_parse_type *type,
42453913Sarchie	const u_char *const start, u_char *buf, int *buflen)
42553913Sarchie{
42653913Sarchie	int16_t val;
42753913Sarchie
42853913Sarchie	if (*buflen < sizeof(int16_t))
42953913Sarchie		return (ERANGE);
43053913Sarchie	val = 0;
43153913Sarchie	bcopy(&val, buf, sizeof(int16_t));
43253913Sarchie	*buflen = sizeof(int16_t);
43353913Sarchie	return (0);
43453913Sarchie}
43553913Sarchie
43653913Sarchiestatic int
43753913Sarchieng_int16_getAlign(const struct ng_parse_type *type)
43853913Sarchie{
43953913Sarchie	return INT16_ALIGNMENT;
44053913Sarchie}
44153913Sarchie
44253913Sarchieconst struct ng_parse_type ng_parse_int16_type = {
44353913Sarchie	NULL,
44453913Sarchie	NULL,
44553913Sarchie	NULL,
44653913Sarchie	ng_int16_parse,
44753913Sarchie	ng_int16_unparse,
44853913Sarchie	ng_int16_getDefault,
44953913Sarchie	ng_int16_getAlign
45053913Sarchie};
45153913Sarchie
45253913Sarchie/************************************************************************
45353913Sarchie				INT32 TYPE
45453913Sarchie ************************************************************************/
45553913Sarchie
45653913Sarchiestatic int
45753913Sarchieng_int32_parse(const struct ng_parse_type *type,
45853913Sarchie	const char *s, int *off, const u_char *const start,
45953913Sarchie	u_char *const buf, int *buflen)
46053913Sarchie{
46153913Sarchie	long val;			/* assumes long is at least 32 bits */
46253913Sarchie	int32_t val32;
46353913Sarchie	char *eptr;
46453913Sarchie
46553913Sarchie	val = strtol(s + *off, &eptr, 0);
46654094Sarchie	if (val < (long)-0x80000000
46754094Sarchie	    || val > (u_long)0xffffffff || eptr == s + *off)
46853913Sarchie		return (EINVAL);
46953913Sarchie	*off = eptr - s;
47053913Sarchie	val32 = (int32_t)val;
47153913Sarchie	bcopy(&val32, buf, sizeof(int32_t));
47253913Sarchie	*buflen = sizeof(int32_t);
47353913Sarchie	return (0);
47453913Sarchie}
47553913Sarchie
47653913Sarchiestatic int
47753913Sarchieng_int32_unparse(const struct ng_parse_type *type,
47853913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
47953913Sarchie{
48053913Sarchie	int32_t val;
48153913Sarchie
48253913Sarchie	bcopy(data + *off, &val, sizeof(int32_t));
48353913Sarchie	NG_PARSE_APPEND("%ld", (long)val);
48453913Sarchie	*off += sizeof(int32_t);
48553913Sarchie	return (0);
48653913Sarchie}
48753913Sarchie
48853913Sarchiestatic int
48953913Sarchieng_int32_getDefault(const struct ng_parse_type *type,
49053913Sarchie	const u_char *const start, u_char *buf, int *buflen)
49153913Sarchie{
49253913Sarchie	int32_t val;
49353913Sarchie
49453913Sarchie	if (*buflen < sizeof(int32_t))
49553913Sarchie		return (ERANGE);
49653913Sarchie	val = 0;
49753913Sarchie	bcopy(&val, buf, sizeof(int32_t));
49853913Sarchie	*buflen = sizeof(int32_t);
49953913Sarchie	return (0);
50053913Sarchie}
50153913Sarchie
50253913Sarchiestatic int
50353913Sarchieng_int32_getAlign(const struct ng_parse_type *type)
50453913Sarchie{
50553913Sarchie	return INT32_ALIGNMENT;
50653913Sarchie}
50753913Sarchie
50853913Sarchieconst struct ng_parse_type ng_parse_int32_type = {
50953913Sarchie	NULL,
51053913Sarchie	NULL,
51153913Sarchie	NULL,
51253913Sarchie	ng_int32_parse,
51353913Sarchie	ng_int32_unparse,
51453913Sarchie	ng_int32_getDefault,
51553913Sarchie	ng_int32_getAlign
51653913Sarchie};
51753913Sarchie
51853913Sarchie/************************************************************************
51953913Sarchie				INT64 TYPE
52053913Sarchie ************************************************************************/
52153913Sarchie
52253913Sarchiestatic int
52353913Sarchieng_int64_parse(const struct ng_parse_type *type,
52453913Sarchie	const char *s, int *off, const u_char *const start,
52553913Sarchie	u_char *const buf, int *buflen)
52653913Sarchie{
52753913Sarchie	quad_t val;
52853913Sarchie	int64_t val64;
52953913Sarchie	char *eptr;
53053913Sarchie
53153913Sarchie	val = strtoq(s + *off, &eptr, 0);
53253913Sarchie	if (eptr == s + *off)
53353913Sarchie		return (EINVAL);
53453913Sarchie	*off = eptr - s;
53553913Sarchie	val64 = (int64_t)val;
53653913Sarchie	bcopy(&val64, buf, sizeof(int64_t));
53753913Sarchie	*buflen = sizeof(int64_t);
53853913Sarchie	return (0);
53953913Sarchie}
54053913Sarchie
54153913Sarchiestatic int
54253913Sarchieng_int64_unparse(const struct ng_parse_type *type,
54353913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
54453913Sarchie{
54553913Sarchie	int64_t val;
54653913Sarchie
54753913Sarchie	bcopy(data + *off, &val, sizeof(int64_t));
54853913Sarchie	NG_PARSE_APPEND("%lld", (long long)val);
54953913Sarchie	*off += sizeof(int64_t);
55053913Sarchie	return (0);
55153913Sarchie}
55253913Sarchie
55353913Sarchiestatic int
55453913Sarchieng_int64_getDefault(const struct ng_parse_type *type,
55553913Sarchie	const u_char *const start, u_char *buf, int *buflen)
55653913Sarchie{
55753913Sarchie	int64_t val;
55853913Sarchie
55953913Sarchie	if (*buflen < sizeof(int64_t))
56053913Sarchie		return (ERANGE);
56153913Sarchie	val = 0;
56253913Sarchie	bcopy(&val, buf, sizeof(int64_t));
56353913Sarchie	*buflen = sizeof(int64_t);
56453913Sarchie	return (0);
56553913Sarchie}
56653913Sarchie
56753913Sarchiestatic int
56853913Sarchieng_int64_getAlign(const struct ng_parse_type *type)
56953913Sarchie{
57053913Sarchie	return INT64_ALIGNMENT;
57153913Sarchie}
57253913Sarchie
57353913Sarchieconst struct ng_parse_type ng_parse_int64_type = {
57453913Sarchie	NULL,
57553913Sarchie	NULL,
57653913Sarchie	NULL,
57753913Sarchie	ng_int64_parse,
57853913Sarchie	ng_int64_unparse,
57953913Sarchie	ng_int64_getDefault,
58053913Sarchie	ng_int64_getAlign
58153913Sarchie};
58253913Sarchie
58353913Sarchie/************************************************************************
58453913Sarchie				STRING TYPE
58553913Sarchie ************************************************************************/
58653913Sarchie
58753913Sarchiestatic int
58853913Sarchieng_string_parse(const struct ng_parse_type *type,
58953913Sarchie	const char *s, int *off, const u_char *const start,
59053913Sarchie	u_char *const buf, int *buflen)
59153913Sarchie{
59253913Sarchie	char *sval;
59353913Sarchie	int len;
59453913Sarchie
59553913Sarchie	if ((sval = ng_get_string_token(s, off, &len)) == NULL)
59653913Sarchie		return (EINVAL);
59753913Sarchie	*off += len;
59853913Sarchie	len = strlen(sval) + 1;
59953913Sarchie	bcopy(sval, buf, len);
60053913Sarchie	FREE(sval, M_NETGRAPH);
60153913Sarchie	*buflen = len;
60253913Sarchie	return (0);
60353913Sarchie}
60453913Sarchie
60553913Sarchiestatic int
60653913Sarchieng_string_unparse(const struct ng_parse_type *type,
60753913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
60853913Sarchie{
60953913Sarchie	const char *const raw = (const char *)data + *off;
61053913Sarchie	char *const s = ng_encode_string(raw);
61153913Sarchie
61253913Sarchie	if (s == NULL)
61353913Sarchie		return (ENOMEM);
61453913Sarchie	NG_PARSE_APPEND("%s", s);
61553913Sarchie	*off += strlen(raw) + 1;
61653913Sarchie	FREE(s, M_NETGRAPH);
61753913Sarchie	return (0);
61853913Sarchie}
61953913Sarchie
62053913Sarchiestatic int
62153913Sarchieng_string_getDefault(const struct ng_parse_type *type,
62253913Sarchie	const u_char *const start, u_char *buf, int *buflen)
62353913Sarchie{
62453913Sarchie
62553913Sarchie	if (*buflen < 1)
62653913Sarchie		return (ERANGE);
62753913Sarchie	buf[0] = (u_char)'\0';
62853913Sarchie	*buflen = 1;
62953913Sarchie	return (0);
63053913Sarchie}
63153913Sarchie
63253913Sarchieconst struct ng_parse_type ng_parse_string_type = {
63353913Sarchie	NULL,
63453913Sarchie	NULL,
63553913Sarchie	NULL,
63653913Sarchie	ng_string_parse,
63753913Sarchie	ng_string_unparse,
63853913Sarchie	ng_string_getDefault,
63953913Sarchie	NULL
64053913Sarchie};
64153913Sarchie
64253913Sarchie/************************************************************************
64353913Sarchie			FIXED BUFFER STRING TYPE
64453913Sarchie ************************************************************************/
64553913Sarchie
64653913Sarchiestatic int
64753913Sarchieng_fixedstring_parse(const struct ng_parse_type *type,
64853913Sarchie	const char *s, int *off, const u_char *const start,
64953913Sarchie	u_char *const buf, int *buflen)
65053913Sarchie{
65158011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
65253913Sarchie	char *sval;
65353913Sarchie	int len;
65453913Sarchie
65553913Sarchie	if ((sval = ng_get_string_token(s, off, &len)) == NULL)
65653913Sarchie		return (EINVAL);
65753913Sarchie	if (strlen(sval) + 1 > fi->bufSize)
65853913Sarchie		return (E2BIG);
65953913Sarchie	*off += len;
66053913Sarchie	len = strlen(sval) + 1;
66153913Sarchie	bcopy(sval, buf, len);
66253913Sarchie	FREE(sval, M_NETGRAPH);
66353913Sarchie	bzero(buf + len, fi->bufSize - len);
66453913Sarchie	*buflen = fi->bufSize;
66553913Sarchie	return (0);
66653913Sarchie}
66753913Sarchie
66853913Sarchiestatic int
66953913Sarchieng_fixedstring_unparse(const struct ng_parse_type *type,
67053913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
67153913Sarchie{
67258011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
67353913Sarchie	int error, temp = *off;
67453913Sarchie
67553913Sarchie	if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
67653913Sarchie		return (error);
67753913Sarchie	*off += fi->bufSize;
67853913Sarchie	return (0);
67953913Sarchie}
68053913Sarchie
68153913Sarchiestatic int
68253913Sarchieng_fixedstring_getDefault(const struct ng_parse_type *type,
68353913Sarchie	const u_char *const start, u_char *buf, int *buflen)
68453913Sarchie{
68558011Sarchie	const struct ng_parse_fixedstring_info *const fi = type->info;
68653913Sarchie
68753913Sarchie	if (*buflen < fi->bufSize)
68853913Sarchie		return (ERANGE);
68953913Sarchie	bzero(buf, fi->bufSize);
69053913Sarchie	*buflen = fi->bufSize;
69153913Sarchie	return (0);
69253913Sarchie}
69353913Sarchie
69453913Sarchieconst struct ng_parse_type ng_parse_fixedstring_type = {
69553913Sarchie	NULL,
69653913Sarchie	NULL,
69753913Sarchie	NULL,
69853913Sarchie	ng_fixedstring_parse,
69953913Sarchie	ng_fixedstring_unparse,
70053913Sarchie	ng_fixedstring_getDefault,
70153913Sarchie	NULL
70253913Sarchie};
70353913Sarchie
70458011Sarchieconst struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
70553913Sarchie	NG_NODELEN + 1
70653913Sarchie};
70753913Sarchieconst struct ng_parse_type ng_parse_nodebuf_type = {
70853913Sarchie	&ng_parse_fixedstring_type,
70953913Sarchie	&ng_parse_nodebuf_info
71053913Sarchie};
71153913Sarchie
71258011Sarchieconst struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
71353913Sarchie	NG_HOOKLEN + 1
71453913Sarchie};
71553913Sarchieconst struct ng_parse_type ng_parse_hookbuf_type = {
71653913Sarchie	&ng_parse_fixedstring_type,
71753913Sarchie	&ng_parse_hookbuf_info
71853913Sarchie};
71953913Sarchie
72058011Sarchieconst struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
72153913Sarchie	NG_PATHLEN + 1
72253913Sarchie};
72353913Sarchieconst struct ng_parse_type ng_parse_pathbuf_type = {
72453913Sarchie	&ng_parse_fixedstring_type,
72553913Sarchie	&ng_parse_pathbuf_info
72653913Sarchie};
72753913Sarchie
72858011Sarchieconst struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
72953913Sarchie	NG_TYPELEN + 1
73053913Sarchie};
73153913Sarchieconst struct ng_parse_type ng_parse_typebuf_type = {
73253913Sarchie	&ng_parse_fixedstring_type,
73353913Sarchie	&ng_parse_typebuf_info
73453913Sarchie};
73553913Sarchie
73658011Sarchieconst struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
73753913Sarchie	NG_CMDSTRLEN + 1
73853913Sarchie};
73953913Sarchieconst struct ng_parse_type ng_parse_cmdbuf_type = {
74053913Sarchie	&ng_parse_fixedstring_type,
74153913Sarchie	&ng_parse_cmdbuf_info
74253913Sarchie};
74353913Sarchie
74453913Sarchie/************************************************************************
74553913Sarchie			IP ADDRESS TYPE
74653913Sarchie ************************************************************************/
74753913Sarchie
74853913Sarchiestatic int
74953913Sarchieng_ipaddr_parse(const struct ng_parse_type *type,
75053913Sarchie	const char *s, int *off, const u_char *const start,
75153913Sarchie	u_char *const buf, int *buflen)
75253913Sarchie{
75353913Sarchie	int i, error;
75453913Sarchie
75553913Sarchie	for (i = 0; i < 4; i++) {
75653913Sarchie		if ((error = ng_int8_parse(&ng_parse_int8_type,
75753913Sarchie		    s, off, start, buf + i, buflen)) != 0)
75853913Sarchie			return (error);
75953913Sarchie		if (i < 3 && s[*off] != '.')
76053913Sarchie			return (EINVAL);
76153913Sarchie		(*off)++;
76253913Sarchie	}
76353913Sarchie	*buflen = 4;
76453913Sarchie	return (0);
76553913Sarchie}
76653913Sarchie
76753913Sarchiestatic int
76853913Sarchieng_ipaddr_unparse(const struct ng_parse_type *type,
76953913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
77053913Sarchie{
77153913Sarchie	struct in_addr ip;
77253913Sarchie
77353913Sarchie	bcopy(data + *off, &ip, sizeof(ip));
77453913Sarchie	NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0],
77553913Sarchie	    ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]);
77653913Sarchie	*off += sizeof(ip);
77753913Sarchie	return (0);
77853913Sarchie}
77953913Sarchie
78053913Sarchiestatic int
78153913Sarchieng_ipaddr_getDefault(const struct ng_parse_type *type,
78253913Sarchie	const u_char *const start, u_char *buf, int *buflen)
78353913Sarchie{
78453913Sarchie	struct in_addr ip = { 0 };
78553913Sarchie
78653913Sarchie	if (*buflen < sizeof(ip))
78753913Sarchie		return (ERANGE);
78853913Sarchie	bcopy(&ip, buf, sizeof(ip));
78953913Sarchie	*buflen = sizeof(ip);
79053913Sarchie	return (0);
79153913Sarchie}
79253913Sarchie
79353913Sarchieconst struct ng_parse_type ng_parse_ipaddr_type = {
79453913Sarchie	NULL,
79553913Sarchie	NULL,
79653913Sarchie	NULL,
79753913Sarchie	ng_ipaddr_parse,
79853913Sarchie	ng_ipaddr_unparse,
79953913Sarchie	ng_ipaddr_getDefault,
80053913Sarchie	ng_int32_getAlign
80153913Sarchie};
80253913Sarchie
80353913Sarchie/************************************************************************
80453913Sarchie			BYTE ARRAY TYPE
80553913Sarchie ************************************************************************/
80653913Sarchie
80753913Sarchie/* Get the length of a byte array */
80853913Sarchiestatic int
80953913Sarchieng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
81053913Sarchie	const u_char *start, const u_char *buf)
81153913Sarchie{
81253913Sarchie	ng_parse_array_getLength_t *const getLength = type->private;
81353913Sarchie
81453913Sarchie	return (*getLength)(type, start, buf);
81553913Sarchie}
81653913Sarchie
81753913Sarchiestatic int
81853913Sarchieng_bytearray_elem_unparse(const struct ng_parse_type *type,
81953913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
82053913Sarchie{
82153913Sarchie	int8_t val;
82253913Sarchie
82353913Sarchie	bcopy(data + *off, &val, sizeof(int8_t));
82453913Sarchie	NG_PARSE_APPEND("0x%02x", (int)val & 0xff);	/* always hex format */
82553913Sarchie	*off += sizeof(int8_t);
82653913Sarchie	return (0);
82753913Sarchie}
82853913Sarchie
82953913Sarchie/* Byte array element type is int8, but always output in hex format */
83053913Sarchieconst struct ng_parse_type ng_parse_bytearray_elem_type = {
83153913Sarchie	&ng_parse_int8_type,
83253913Sarchie	NULL,
83353913Sarchie	NULL,
83453913Sarchie	NULL,
83553913Sarchie	ng_bytearray_elem_unparse,
83653913Sarchie	NULL,
83753913Sarchie	NULL
83853913Sarchie};
83953913Sarchie
84053913Sarchiestatic const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
84153913Sarchie	&ng_parse_bytearray_elem_type,
84253913Sarchie	&ng_parse_bytearray_subtype_getLength,
84353913Sarchie	NULL
84453913Sarchie};
84553913Sarchiestatic const struct ng_parse_type ng_parse_bytearray_subtype = {
84653913Sarchie	&ng_parse_array_type,
84753913Sarchie	&ng_parse_bytearray_subtype_info
84853913Sarchie};
84953913Sarchie
85053913Sarchiestatic int
85153913Sarchieng_bytearray_parse(const struct ng_parse_type *type,
85253913Sarchie	const char *s, int *off, const u_char *const start,
85353913Sarchie	u_char *const buf, int *buflen)
85453913Sarchie{
85553913Sarchie	char *str;
85653913Sarchie	int toklen;
85753913Sarchie
85853913Sarchie	/* We accept either an array of bytes or a string constant */
85953913Sarchie	if ((str = ng_get_string_token(s, off, &toklen)) != NULL) {
86053913Sarchie		ng_parse_array_getLength_t *const getLength = type->info;
86153913Sarchie		int arraylen, slen;
86253913Sarchie
86353913Sarchie		arraylen = (*getLength)(type, start, buf);
86453913Sarchie		if (arraylen > *buflen) {
86553913Sarchie			FREE(str, M_NETGRAPH);
86653913Sarchie			return (ERANGE);
86753913Sarchie		}
86853913Sarchie		slen = strlen(str) + 1;
86953913Sarchie		if (slen > arraylen) {
87053913Sarchie			FREE(str, M_NETGRAPH);
87153913Sarchie			return (E2BIG);
87253913Sarchie		}
87353913Sarchie		bcopy(str, buf, slen);
87453913Sarchie		bzero(buf + slen, arraylen - slen);
87553913Sarchie		FREE(str, M_NETGRAPH);
87653913Sarchie		*off += toklen;
87753913Sarchie		*buflen = arraylen;
87853913Sarchie		return (0);
87953913Sarchie	} else {
88053913Sarchie		struct ng_parse_type subtype;
88153913Sarchie
88253913Sarchie		subtype = ng_parse_bytearray_subtype;
88353913Sarchie		(const void *)subtype.private = type->info;
88453913Sarchie		return ng_array_parse(&subtype, s, off, start, buf, buflen);
88553913Sarchie	}
88653913Sarchie}
88753913Sarchie
88853913Sarchiestatic int
88953913Sarchieng_bytearray_unparse(const struct ng_parse_type *type,
89053913Sarchie	const u_char *data, int *off, char *cbuf, int cbuflen)
89153913Sarchie{
89253913Sarchie	struct ng_parse_type subtype;
89353913Sarchie
89453913Sarchie	subtype = ng_parse_bytearray_subtype;
89553913Sarchie	(const void *)subtype.private = type->info;
89653913Sarchie	return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
89753913Sarchie}
89853913Sarchie
89953913Sarchiestatic int
90053913Sarchieng_bytearray_getDefault(const struct ng_parse_type *type,
90153913Sarchie	const u_char *const start, u_char *buf, int *buflen)
90253913Sarchie{
90353913Sarchie	struct ng_parse_type subtype;
90453913Sarchie
90553913Sarchie	subtype = ng_parse_bytearray_subtype;
90653913Sarchie	(const void *)subtype.private = type->info;
90753913Sarchie	return ng_array_getDefault(&subtype, start, buf, buflen);
90853913Sarchie}
90953913Sarchie
91053913Sarchieconst struct ng_parse_type ng_parse_bytearray_type = {
91153913Sarchie	NULL,
91253913Sarchie	NULL,
91353913Sarchie	NULL,
91453913Sarchie	ng_bytearray_parse,
91553913Sarchie	ng_bytearray_unparse,
91653913Sarchie	ng_bytearray_getDefault,
91753913Sarchie	NULL
91853913Sarchie};
91953913Sarchie
92053913Sarchie/************************************************************************
92153913Sarchie			STRUCT NG_MESG TYPE
92253913Sarchie ************************************************************************/
92353913Sarchie
92453913Sarchie/* Get msg->header.arglen when "buf" is pointing to msg->data */
92553913Sarchiestatic int
92653913Sarchieng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
92753913Sarchie	const u_char *start, const u_char *buf)
92853913Sarchie{
92953913Sarchie	const struct ng_mesg *msg;
93053913Sarchie
93153913Sarchie	msg = (const struct ng_mesg *)(buf - sizeof(*msg));
93253913Sarchie	return msg->header.arglen;
93353913Sarchie}
93453913Sarchie
93553913Sarchie/* Type for the variable length data portion of a struct ng_mesg */
93653913Sarchiestatic const struct ng_parse_type ng_msg_data_type = {
93753913Sarchie	&ng_parse_bytearray_type,
93853913Sarchie	&ng_parse_ng_mesg_getLength
93953913Sarchie};
94053913Sarchie
94153913Sarchie/* Type for the entire struct ng_mesg header with data section */
94253913Sarchiestatic const struct ng_parse_struct_info
94353913Sarchie	ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
94453913Sarchieconst struct ng_parse_type ng_parse_ng_mesg_type = {
94553913Sarchie	&ng_parse_struct_type,
94653913Sarchie	&ng_parse_ng_mesg_type_info,
94753913Sarchie};
94853913Sarchie
94953913Sarchie/************************************************************************
95053913Sarchie			COMPOSITE HELPER ROUTINES
95153913Sarchie ************************************************************************/
95253913Sarchie
95353913Sarchie/*
95453913Sarchie * Convert a structure or array from ASCII to binary
95553913Sarchie */
95653913Sarchiestatic int
95753913Sarchieng_parse_composite(const struct ng_parse_type *type, const char *s,
95853913Sarchie	int *off, const u_char *const start, u_char *const buf, int *buflen,
95953913Sarchie	const enum comptype ctype)
96053913Sarchie{
96153913Sarchie	const int num = ng_get_composite_len(type, start, buf, ctype);
96253913Sarchie	int nextIndex = 0;		/* next implicit array index */
96353913Sarchie	u_int index;			/* field or element index */
96453913Sarchie	int *foff;			/* field value offsets in string */
96553913Sarchie	int align, len, blen, error = 0;
96653913Sarchie
96753913Sarchie	/* Initialize */
96853913Sarchie	MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH, M_NOWAIT);
96953913Sarchie	if (foff == NULL) {
97053913Sarchie		error = ENOMEM;
97153913Sarchie		goto done;
97253913Sarchie	}
97353913Sarchie	bzero(foff, num * sizeof(*foff));
97453913Sarchie
97553913Sarchie	/* Get opening brace/bracket */
97653913Sarchie	if (ng_parse_get_token(s, off, &len)
97753913Sarchie	    != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
97853913Sarchie		error = EINVAL;
97953913Sarchie		goto done;
98053913Sarchie	}
98153913Sarchie	*off += len;
98253913Sarchie
98353913Sarchie	/* Get individual element value positions in the string */
98453913Sarchie	for (;;) {
98553913Sarchie		enum ng_parse_token tok;
98653913Sarchie
98753913Sarchie		/* Check for closing brace/bracket */
98853913Sarchie		tok = ng_parse_get_token(s, off, &len);
98953913Sarchie		if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
99053913Sarchie			*off += len;
99153913Sarchie			break;
99253913Sarchie		}
99353913Sarchie
99453913Sarchie		/* For arrays, the 'name' (ie, index) is optional, so
99553913Sarchie		   distinguish name from values by seeing if the next
99653913Sarchie		   token is an equals sign */
99753913Sarchie		if (ctype != CT_STRUCT) {
99853913Sarchie			int len2, off2;
99953913Sarchie			char *eptr;
100053913Sarchie
100153913Sarchie			/* If an opening brace/bracket, index is implied */
100253913Sarchie			if (tok == T_LBRACE || tok == T_LBRACKET) {
100353913Sarchie				index = nextIndex++;
100453913Sarchie				goto gotIndex;
100553913Sarchie			}
100653913Sarchie
100753913Sarchie			/* Might be an index, might be a value, either way... */
100853913Sarchie			if (tok != T_WORD) {
100953913Sarchie				error = EINVAL;
101053913Sarchie				goto done;
101153913Sarchie			}
101253913Sarchie
101353913Sarchie			/* If no equals sign follows, index is implied */
101453913Sarchie			off2 = *off + len;
101553913Sarchie			if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
101653913Sarchie				index = nextIndex++;
101753913Sarchie				goto gotIndex;
101853913Sarchie			}
101953913Sarchie
102053913Sarchie			/* Index was specified explicitly; parse it */
102153913Sarchie			index = (u_int)strtoul(s + *off, &eptr, 0);
102253913Sarchie			if (index < 0 || eptr - (s + *off) != len) {
102353913Sarchie				error = EINVAL;
102453913Sarchie				goto done;
102553913Sarchie			}
102653913Sarchie			nextIndex = index + 1;
102753913Sarchie			*off += len + len2;
102853913SarchiegotIndex:
102953913Sarchie		} else {			/* a structure field */
103053913Sarchie			const struct ng_parse_struct_field *field = NULL;
103153913Sarchie			const struct ng_parse_struct_info *si = type->info;
103253913Sarchie
103353913Sarchie			/* Find the field by name (required) in field list */
103453913Sarchie			if (tok != T_WORD) {
103553913Sarchie				error = EINVAL;
103653913Sarchie				goto done;
103753913Sarchie			}
103853913Sarchie			for (index = 0; index < num; index++) {
103953913Sarchie				field = &si->fields[index];
104053913Sarchie				if (strncmp(&s[*off], field->name, len) == 0
104153913Sarchie				    && field->name[len] == '\0')
104253913Sarchie					break;
104353913Sarchie			}
104453913Sarchie			if (index == num) {
104553913Sarchie				error = ENOENT;
104653913Sarchie				goto done;
104753913Sarchie			}
104853913Sarchie			*off += len;
104953913Sarchie
105053913Sarchie			/* Get equals sign */
105153913Sarchie			if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
105253913Sarchie				error = EINVAL;
105353913Sarchie				goto done;
105453913Sarchie			}
105553913Sarchie			*off += len;
105653913Sarchie		}
105753913Sarchie
105853913Sarchie		/* Check array index */
105953913Sarchie		if (index >= num) {
106053913Sarchie			error = E2BIG;
106153913Sarchie			goto done;
106253913Sarchie		}
106353913Sarchie
106453913Sarchie		/* Save value's position and skip over it for now */
106553913Sarchie		if (foff[index] != 0) {
106653913Sarchie			error = EALREADY;		/* duplicate */
106753913Sarchie			goto done;
106853913Sarchie		}
106953913Sarchie		while (isspace(s[*off]))
107053913Sarchie			(*off)++;
107153913Sarchie		foff[index] = *off;
107253913Sarchie		if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
107353913Sarchie			goto done;
107453913Sarchie		*off += len;
107553913Sarchie	}
107653913Sarchie
107753913Sarchie	/* Now build binary structure from supplied values and defaults */
107853913Sarchie	for (blen = index = 0; index < num; index++) {
107953913Sarchie		const struct ng_parse_type *const
108053913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
108153913Sarchie		int k, pad, vlen;
108253913Sarchie
108353913Sarchie		/* Zero-pad any alignment bytes */
108453913Sarchie		pad = ng_parse_get_elem_pad(type, index, ctype, blen);
108553913Sarchie		for (k = 0; k < pad; k++) {
108653913Sarchie			if (blen >= *buflen) {
108753913Sarchie				error = ERANGE;
108853913Sarchie				goto done;
108953913Sarchie			}
109053913Sarchie			buf[blen++] = 0;
109153913Sarchie		}
109253913Sarchie
109353913Sarchie		/* Get value */
109453913Sarchie		vlen = *buflen - blen;
109553913Sarchie		if (foff[index] == 0) {		/* use default value */
109653913Sarchie			error = ng_get_composite_elem_default(type, index,
109753913Sarchie			    start, buf + blen, &vlen, ctype);
109853913Sarchie		} else {			/* parse given value */
109953913Sarchie			*off = foff[index];
110053913Sarchie			error = INVOKE(etype, parse)(etype,
110153913Sarchie			    s, off, start, buf + blen, &vlen);
110253913Sarchie		}
110353913Sarchie		if (error != 0)
110453913Sarchie			goto done;
110553913Sarchie		blen += vlen;
110653913Sarchie	}
110753913Sarchie
110853913Sarchie	/* Make total composite structure size a multiple of its alignment */
110953913Sarchie	if ((align = ALIGNMENT(type)) != 0) {
111053913Sarchie		while (blen % align != 0) {
111153913Sarchie			if (blen >= *buflen) {
111253913Sarchie				error = ERANGE;
111353913Sarchie				goto done;
111453913Sarchie			}
111553913Sarchie			buf[blen++] = 0;
111653913Sarchie		}
111753913Sarchie	}
111853913Sarchie
111953913Sarchie	/* Done */
112053913Sarchie	*buflen = blen;
112153913Sarchiedone:
112253913Sarchie	FREE(foff, M_NETGRAPH);
112353913Sarchie	return (error);
112453913Sarchie}
112553913Sarchie
112653913Sarchie/*
112753913Sarchie * Convert an array or structure from binary to ASCII
112853913Sarchie */
112953913Sarchiestatic int
113053913Sarchieng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
113153913Sarchie	int *off, char *cbuf, int cbuflen, const enum comptype ctype)
113253913Sarchie{
113353913Sarchie	const int num = ng_get_composite_len(type, data, data + *off, ctype);
113453913Sarchie	int nextIndex = 0, didOne = 0;
113553913Sarchie	int error, index;
113653913Sarchie
113753913Sarchie	/* Opening brace/bracket */
113853913Sarchie	NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '[');
113953913Sarchie
114053913Sarchie	/* Do each item */
114153913Sarchie	for (index = 0; index < num; index++) {
114253913Sarchie		const struct ng_parse_type *const
114353913Sarchie		    etype = ng_get_composite_etype(type, index, ctype);
114453913Sarchie		u_char temp[1024];
114553913Sarchie
114653913Sarchie		/* Skip any alignment pad bytes */
114753913Sarchie		*off += ng_parse_get_elem_pad(type, index, ctype, *off);
114853913Sarchie
114953913Sarchie		/* See if element is equal to its default value; skip if so */
115053913Sarchie		if (*off < sizeof(temp)) {
115153913Sarchie			int tempsize = sizeof(temp) - *off;
115253913Sarchie
115353913Sarchie			bcopy(data, temp, *off);
115453913Sarchie			if (ng_get_composite_elem_default(type, index, temp,
115553913Sarchie			      temp + *off, &tempsize, ctype) == 0
115653913Sarchie			    && bcmp(temp + *off, data + *off, tempsize) == 0) {
115753913Sarchie				*off += tempsize;
115853913Sarchie				continue;
115953913Sarchie			}
116053913Sarchie		}
116153913Sarchie
116253913Sarchie		/* Print name= */
116353913Sarchie		NG_PARSE_APPEND(" ");
116453913Sarchie		if (ctype != CT_STRUCT) {
116553913Sarchie			if (index != nextIndex) {
116653913Sarchie				nextIndex = index;
116753913Sarchie				NG_PARSE_APPEND("%d=", index);
116853913Sarchie			}
116953913Sarchie			nextIndex++;
117053913Sarchie		} else {
117153913Sarchie			const struct ng_parse_struct_info *si = type->info;
117253913Sarchie
117353913Sarchie			NG_PARSE_APPEND("%s=", si->fields[index].name);
117453913Sarchie		}
117553913Sarchie
117653913Sarchie		/* Print value */
117753913Sarchie		if ((error = INVOKE(etype, unparse)
117853913Sarchie		    (etype, data, off, cbuf, cbuflen)) != 0)
117953913Sarchie			return (error);
118053913Sarchie		cbuflen -= strlen(cbuf);
118153913Sarchie		cbuf += strlen(cbuf);
118253913Sarchie		didOne = 1;
118353913Sarchie	}
118453913Sarchie
118553913Sarchie	/* Closing brace/bracket */
118653913Sarchie	NG_PARSE_APPEND("%s%c",
118753913Sarchie	    didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
118853913Sarchie	return (0);
118953913Sarchie}
119053913Sarchie
119153913Sarchie/*
119253913Sarchie * Generate the default value for an element of an array or structure
119353913Sarchie * Returns EOPNOTSUPP if default value is unspecified.
119453913Sarchie */
119553913Sarchiestatic int
119653913Sarchieng_get_composite_elem_default(const struct ng_parse_type *type,
119753913Sarchie	int index, const u_char *const start, u_char *buf, int *buflen,
119853913Sarchie	const enum comptype ctype)
119953913Sarchie{
120053913Sarchie	const struct ng_parse_type *etype;
120153913Sarchie	ng_getDefault_t *func;
120253913Sarchie
120353913Sarchie	switch (ctype) {
120453913Sarchie	case CT_STRUCT:
120553913Sarchie		break;
120653913Sarchie	case CT_ARRAY:
120753913Sarchie	    {
120853913Sarchie		const struct ng_parse_array_info *const ai = type->info;
120953913Sarchie
121053913Sarchie		if (ai->getDefault != NULL) {
121153913Sarchie			return (*ai->getDefault)(type,
121253913Sarchie			    index, start, buf, buflen);
121353913Sarchie		}
121453913Sarchie		break;
121553913Sarchie	    }
121653913Sarchie	case CT_FIXEDARRAY:
121753913Sarchie	    {
121853913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
121953913Sarchie
122053913Sarchie		if (*fi->getDefault != NULL) {
122153913Sarchie			return (*fi->getDefault)(type,
122253913Sarchie			    index, start, buf, buflen);
122353913Sarchie		}
122453913Sarchie		break;
122553913Sarchie	    }
122653913Sarchie	default:
122753913Sarchie	    panic("%s", __FUNCTION__);
122853913Sarchie	}
122953913Sarchie
123053913Sarchie	/* Default to element type default */
123153913Sarchie	etype = ng_get_composite_etype(type, index, ctype);
123253913Sarchie	func = METHOD(etype, getDefault);
123353913Sarchie	if (func == NULL)
123453913Sarchie		return (EOPNOTSUPP);
123553913Sarchie	return (*func)(etype, start, buf, buflen);
123653913Sarchie}
123753913Sarchie
123853913Sarchie/*
123953913Sarchie * Get the number of elements in a struct, variable or fixed array.
124053913Sarchie */
124153913Sarchiestatic int
124253913Sarchieng_get_composite_len(const struct ng_parse_type *type,
124353913Sarchie	const u_char *const start, const u_char *buf,
124453913Sarchie	const enum comptype ctype)
124553913Sarchie{
124653913Sarchie	switch (ctype) {
124753913Sarchie	case CT_STRUCT:
124853913Sarchie	    {
124953913Sarchie		const struct ng_parse_struct_info *const si = type->info;
125053913Sarchie		int numFields = 0;
125153913Sarchie
125253913Sarchie		for (numFields = 0; ; numFields++) {
125353913Sarchie			const struct ng_parse_struct_field *const
125453913Sarchie				fi = &si->fields[numFields];
125553913Sarchie
125653913Sarchie			if (fi->name == NULL)
125753913Sarchie				break;
125853913Sarchie		}
125953913Sarchie		return (numFields);
126053913Sarchie	    }
126153913Sarchie	case CT_ARRAY:
126253913Sarchie	    {
126353913Sarchie		const struct ng_parse_array_info *const ai = type->info;
126453913Sarchie
126553913Sarchie		return (*ai->getLength)(type, start, buf);
126653913Sarchie	    }
126753913Sarchie	case CT_FIXEDARRAY:
126853913Sarchie	    {
126953913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
127053913Sarchie
127153913Sarchie		return fi->length;
127253913Sarchie	    }
127353913Sarchie	default:
127453913Sarchie	    panic("%s", __FUNCTION__);
127553913Sarchie	}
127653913Sarchie	return (0);
127753913Sarchie}
127853913Sarchie
127953913Sarchie/*
128053913Sarchie * Return the type of the index'th element of a composite structure
128153913Sarchie */
128253913Sarchiestatic const struct ng_parse_type *
128353913Sarchieng_get_composite_etype(const struct ng_parse_type *type,
128453913Sarchie	int index, const enum comptype ctype)
128553913Sarchie{
128653913Sarchie	const struct ng_parse_type *etype = NULL;
128753913Sarchie
128853913Sarchie	switch (ctype) {
128953913Sarchie	case CT_STRUCT:
129053913Sarchie	    {
129153913Sarchie		const struct ng_parse_struct_info *const si = type->info;
129253913Sarchie
129353913Sarchie		etype = si->fields[index].type;
129453913Sarchie		break;
129553913Sarchie	    }
129653913Sarchie	case CT_ARRAY:
129753913Sarchie	    {
129853913Sarchie		const struct ng_parse_array_info *const ai = type->info;
129953913Sarchie
130053913Sarchie		etype = ai->elementType;
130153913Sarchie		break;
130253913Sarchie	    }
130353913Sarchie	case CT_FIXEDARRAY:
130453913Sarchie	    {
130553913Sarchie		const struct ng_parse_fixedarray_info *const fi = type->info;
130653913Sarchie
130753913Sarchie		etype = fi->elementType;
130853913Sarchie		break;
130953913Sarchie	    }
131053913Sarchie	default:
131153913Sarchie	    panic("%s", __FUNCTION__);
131253913Sarchie	}
131353913Sarchie	return (etype);
131453913Sarchie}
131553913Sarchie
131653913Sarchie/*
131753913Sarchie * Get the number of bytes to skip to align for the next
131853913Sarchie * element in a composite structure.
131953913Sarchie */
132053913Sarchiestatic int
132153913Sarchieng_parse_get_elem_pad(const struct ng_parse_type *type,
132253913Sarchie	int index, enum comptype ctype, int posn)
132353913Sarchie{
132453913Sarchie	const struct ng_parse_type *const
132553913Sarchie	    etype = ng_get_composite_etype(type, index, ctype);
132653913Sarchie	int align;
132753913Sarchie
132853913Sarchie	/* Get element's alignment, and possibly override */
132953913Sarchie	align = ALIGNMENT(etype);
133053913Sarchie	if (ctype == CT_STRUCT) {
133153913Sarchie		const struct ng_parse_struct_info *si = type->info;
133253913Sarchie
133353913Sarchie		if (si->fields[index].alignment != 0)
133453913Sarchie			align = si->fields[index].alignment;
133553913Sarchie	}
133653913Sarchie
133753913Sarchie	/* Return number of bytes to skip to align */
133853913Sarchie	return (align ? (align - (posn % align)) % align : 0);
133953913Sarchie}
134053913Sarchie
134153913Sarchie/************************************************************************
134253913Sarchie			PARSING HELPER ROUTINES
134353913Sarchie ************************************************************************/
134453913Sarchie
134553913Sarchie/*
134653913Sarchie * Skip over a value
134753913Sarchie */
134853913Sarchiestatic int
134953913Sarchieng_parse_skip_value(const char *s, int off0, int *lenp)
135053913Sarchie{
135153913Sarchie	int len, nbracket, nbrace;
135253913Sarchie	int off = off0;
135353913Sarchie
135453913Sarchie	len = nbracket = nbrace = 0;
135553913Sarchie	do {
135653913Sarchie		switch (ng_parse_get_token(s, &off, &len)) {
135753913Sarchie		case T_LBRACKET:
135853913Sarchie			nbracket++;
135953913Sarchie			break;
136053913Sarchie		case T_LBRACE:
136153913Sarchie			nbrace++;
136253913Sarchie			break;
136353913Sarchie		case T_RBRACKET:
136453913Sarchie			if (nbracket-- == 0)
136553913Sarchie				return (EINVAL);
136653913Sarchie			break;
136753913Sarchie		case T_RBRACE:
136853913Sarchie			if (nbrace-- == 0)
136953913Sarchie				return (EINVAL);
137053913Sarchie			break;
137153913Sarchie		case T_EOF:
137253913Sarchie			return (EINVAL);
137353913Sarchie		default:
137453913Sarchie			break;
137553913Sarchie		}
137653913Sarchie		off += len;
137753913Sarchie	} while (nbracket > 0 || nbrace > 0);
137853913Sarchie	*lenp = off - off0;
137953913Sarchie	return (0);
138053913Sarchie}
138153913Sarchie
138253913Sarchie/*
138353913Sarchie * Find the next token in the string, starting at offset *startp.
138453913Sarchie * Returns the token type, with *startp pointing to the first char
138553913Sarchie * and *lenp the length.
138653913Sarchie */
138753913Sarchieenum ng_parse_token
138853913Sarchieng_parse_get_token(const char *s, int *startp, int *lenp)
138953913Sarchie{
139053913Sarchie	char *t;
139153913Sarchie	int i;
139253913Sarchie
139353913Sarchie	while (isspace(s[*startp]))
139453913Sarchie		(*startp)++;
139553913Sarchie	switch (s[*startp]) {
139653913Sarchie	case '\0':
139753913Sarchie		*lenp = 0;
139853913Sarchie		return T_EOF;
139953913Sarchie	case '{':
140053913Sarchie		*lenp = 1;
140153913Sarchie		return T_LBRACE;
140253913Sarchie	case '}':
140353913Sarchie		*lenp = 1;
140453913Sarchie		return T_RBRACE;
140553913Sarchie	case '[':
140653913Sarchie		*lenp = 1;
140753913Sarchie		return T_LBRACKET;
140853913Sarchie	case ']':
140953913Sarchie		*lenp = 1;
141053913Sarchie		return T_RBRACKET;
141153913Sarchie	case '=':
141253913Sarchie		*lenp = 1;
141353913Sarchie		return T_EQUALS;
141453913Sarchie	case '"':
141553913Sarchie		if ((t = ng_get_string_token(s, startp, lenp)) == NULL)
141653913Sarchie			return T_ERROR;
141753913Sarchie		FREE(t, M_NETGRAPH);
141853913Sarchie		return T_STRING;
141953913Sarchie	default:
142053913Sarchie		for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
142153913Sarchie		    && s[i] != '{' && s[i] != '}' && s[i] != '['
142253913Sarchie		    && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
142353913Sarchie			;
142453913Sarchie		*lenp = i - *startp;
142553913Sarchie		return T_WORD;
142653913Sarchie	}
142753913Sarchie}
142853913Sarchie
142953913Sarchie/*
143053913Sarchie * Get a string token, which must be enclosed in double quotes.
143153913Sarchie * The normal C backslash escapes are recognized.
143253913Sarchie */
143353913Sarchiechar *
143453913Sarchieng_get_string_token(const char *s, int *startp, int *lenp)
143553913Sarchie{
143653913Sarchie	char *cbuf, *p;
143753913Sarchie	int start, off;
143853913Sarchie
143953913Sarchie	while (isspace(s[*startp]))
144053913Sarchie		(*startp)++;
144153913Sarchie	start = *startp;
144253913Sarchie	if (s[*startp] != '"')
144353913Sarchie		return (NULL);
144453913Sarchie	MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH, M_NOWAIT);
144553913Sarchie	if (cbuf == NULL)
144653913Sarchie		return (NULL);
144753913Sarchie	strcpy(cbuf, s + start + 1);
144853913Sarchie	for (off = 1, p = cbuf; *p != '\0'; off++, p++) {
144953913Sarchie		if (*p == '"') {
145053913Sarchie			*p = '\0';
145153913Sarchie			*lenp = off + 1;
145253913Sarchie			return (cbuf);
145353913Sarchie		} else if (p[0] == '\\' && p[1] != '\0') {
145453913Sarchie			int x, k;
145553913Sarchie			char *v;
145653913Sarchie
145753913Sarchie			strcpy(p, p + 1);
145853913Sarchie			v = p;
145953913Sarchie			switch (*p) {
146053913Sarchie			case 't':
146153913Sarchie				*v = '\t';
146253913Sarchie				off++;
146353913Sarchie				continue;
146453913Sarchie			case 'n':
146553913Sarchie				*v = '\n';
146653913Sarchie				off++;
146753913Sarchie				continue;
146853913Sarchie			case 'r':
146953913Sarchie				*v = '\r';
147053913Sarchie				off++;
147153913Sarchie				continue;
147253913Sarchie			case 'v':
147353913Sarchie				*v =  '\v';
147453913Sarchie				off++;
147553913Sarchie				continue;
147653913Sarchie			case 'f':
147753913Sarchie				*v =  '\f';
147853913Sarchie				off++;
147953913Sarchie				continue;
148053913Sarchie			case '"':
148153913Sarchie				*v =  '"';
148253913Sarchie				off++;
148353913Sarchie				continue;
148453913Sarchie			case '0': case '1': case '2': case '3':
148553913Sarchie			case '4': case '5': case '6': case '7':
148653913Sarchie				for (x = k = 0;
148753913Sarchie				    k < 3 && *v >= '0' && *v <= '7'; v++) {
148853913Sarchie					x = (x << 3) + (*v - '0');
148953913Sarchie					off++;
149053913Sarchie				}
149153913Sarchie				*--v = (char)x;
149253913Sarchie				break;
149353913Sarchie			case 'x':
149453913Sarchie				for (v++, x = k = 0;
149553913Sarchie				    k < 2 && isxdigit(*v); v++) {
149653913Sarchie					x = (x << 4) + (isdigit(*v) ?
149753913Sarchie					      (*v - '0') :
149853913Sarchie					      (tolower(*v) - 'a' + 10));
149953913Sarchie					off++;
150053913Sarchie				}
150153913Sarchie				*--v = (char)x;
150253913Sarchie				break;
150353913Sarchie			default:
150453913Sarchie				continue;
150553913Sarchie			}
150653913Sarchie			strcpy(p, v);
150753913Sarchie		}
150853913Sarchie	}
150953913Sarchie	return (NULL);		/* no closing quote */
151053913Sarchie}
151153913Sarchie
151253913Sarchie/*
151353913Sarchie * Encode a string so it can be safely put in double quotes.
151453913Sarchie * Caller must free the result.
151553913Sarchie */
151653913Sarchiechar *
151753913Sarchieng_encode_string(const char *raw)
151853913Sarchie{
151953913Sarchie	char *cbuf;
152053913Sarchie	int off = 0;
152153913Sarchie
152253913Sarchie	MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH, M_NOWAIT);
152353913Sarchie	if (cbuf == NULL)
152453913Sarchie		return (NULL);
152553913Sarchie	cbuf[off++] = '"';
152653913Sarchie	for ( ; *raw != '\0'; raw++) {
152753913Sarchie		switch (*raw) {
152853913Sarchie		case '\t':
152953913Sarchie			cbuf[off++] = '\\';
153053913Sarchie			cbuf[off++] = 't';
153153913Sarchie			break;
153253913Sarchie		case '\f':
153353913Sarchie			cbuf[off++] = '\\';
153453913Sarchie			cbuf[off++] = 'f';
153553913Sarchie			break;
153653913Sarchie		case '\n':
153753913Sarchie			cbuf[off++] = '\\';
153853913Sarchie			cbuf[off++] = 'n';
153953913Sarchie			break;
154053913Sarchie		case '\r':
154153913Sarchie			cbuf[off++] = '\\';
154253913Sarchie			cbuf[off++] = 'r';
154353913Sarchie			break;
154453913Sarchie		case '\v':
154553913Sarchie			cbuf[off++] = '\\';
154653913Sarchie			cbuf[off++] = 'v';
154753913Sarchie			break;
154853913Sarchie		case '"':
154953913Sarchie		case '\\':
155053913Sarchie			cbuf[off++] = '\\';
155153913Sarchie			cbuf[off++] = *raw;
155253913Sarchie			break;
155353913Sarchie		default:
155453913Sarchie			if (*raw < 0x20 || *raw > 0x7e) {
155553913Sarchie				off += sprintf(cbuf + off,
155653913Sarchie				    "\\x%02x", (u_char)*raw);
155753913Sarchie				break;
155853913Sarchie			}
155953913Sarchie			cbuf[off++] = *raw;
156053913Sarchie			break;
156153913Sarchie		}
156253913Sarchie	}
156353913Sarchie	cbuf[off++] = '"';
156453913Sarchie	cbuf[off] = '\0';
156553913Sarchie	return (cbuf);
156653913Sarchie}
156753913Sarchie
156853913Sarchie/************************************************************************
156953913Sarchie			VIRTUAL METHOD LOOKUP
157053913Sarchie ************************************************************************/
157153913Sarchie
157253913Sarchiestatic ng_parse_t *
157353913Sarchieng_get_parse_method(const struct ng_parse_type *t)
157453913Sarchie{
157553913Sarchie	while (t != NULL && t->parse == NULL)
157653913Sarchie		t = t->supertype;
157753913Sarchie	return (t ? t->parse : NULL);
157853913Sarchie}
157953913Sarchie
158053913Sarchiestatic ng_unparse_t *
158153913Sarchieng_get_unparse_method(const struct ng_parse_type *t)
158253913Sarchie{
158353913Sarchie	while (t != NULL && t->unparse == NULL)
158453913Sarchie		t = t->supertype;
158553913Sarchie	return (t ? t->unparse : NULL);
158653913Sarchie}
158753913Sarchie
158853913Sarchiestatic ng_getDefault_t *
158953913Sarchieng_get_getDefault_method(const struct ng_parse_type *t)
159053913Sarchie{
159153913Sarchie	while (t != NULL && t->getDefault == NULL)
159253913Sarchie		t = t->supertype;
159353913Sarchie	return (t ? t->getDefault : NULL);
159453913Sarchie}
159553913Sarchie
159653913Sarchiestatic ng_getAlign_t *
159753913Sarchieng_get_getAlign_method(const struct ng_parse_type *t)
159853913Sarchie{
159953913Sarchie	while (t != NULL && t->getAlign == NULL)
160053913Sarchie		t = t->supertype;
160153913Sarchie	return (t ? t->getAlign : NULL);
160253913Sarchie}
160353913Sarchie
1604