diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 1999-12-01 19:41:16 +0000 |
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 1999-12-01 19:41:16 +0000 |
| commit | 986314ee61771f7cdc651068ebe7af75c4322885 (patch) | |
| tree | b2f98b516ff544c1fa4b0c9a8ceed498018b9a79 /sys/netgraph | |
| parent | 3e6f44249fd9c37e76fcc8a0c44ccc3f129b12e9 (diff) | |
Notes
Diffstat (limited to 'sys/netgraph')
| -rw-r--r-- | sys/netgraph/ng_parse.c | 1604 | ||||
| -rw-r--r-- | sys/netgraph/ng_parse.h | 507 |
2 files changed, 2111 insertions, 0 deletions
diff --git a/sys/netgraph/ng_parse.c b/sys/netgraph/ng_parse.c new file mode 100644 index 000000000000..795d1c100028 --- /dev/null +++ b/sys/netgraph/ng_parse.c @@ -0,0 +1,1604 @@ + +/* + * ng_parse.c + * + * Copyright (c) 1999 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Archie Cobbs <archie@whistle.com> + * + * $Whistle: ng_parse.c,v 1.3 1999/11/29 01:43:48 archie Exp $ + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/ctype.h> + +#include <netinet/in.h> + +#include <netgraph/ng_message.h> +#include <netgraph/netgraph.h> +#include <netgraph/ng_parse.h> + +/* Compute alignment for primitive integral types */ +struct int16_temp { + char x; + int16_t y; +}; + +struct int32_temp { + char x; + int32_t y; +}; + +struct int64_temp { + char x; + int64_t y; +}; + +#define INT8_ALIGNMENT 1 +#define INT16_ALIGNMENT ((int)&((struct int16_temp *)0)->y) +#define INT32_ALIGNMENT ((int)&((struct int32_temp *)0)->y) +#define INT64_ALIGNMENT ((int)&((struct int64_temp *)0)->y) + +/* Type of composite object: struct, array, or fixedarray */ +enum comptype { + CT_STRUCT, + CT_ARRAY, + CT_FIXEDARRAY, +}; + +/* Composite types helper functions */ +static int ng_parse_composite(const struct ng_parse_type *type, + const char *s, int *off, const u_char *start, + u_char *const buf, int *buflen, enum comptype ctype); +static int ng_unparse_composite(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen, + enum comptype ctype); +static int ng_get_composite_elem_default(const struct ng_parse_type *type, + int index, const u_char *start, u_char *buf, + int *buflen, enum comptype ctype); +static int ng_get_composite_len(const struct ng_parse_type *type, + const u_char *start, const u_char *buf, + enum comptype ctype); +static const struct ng_parse_type *ng_get_composite_etype(const struct + ng_parse_type *type, int index, enum comptype ctype); +static int ng_parse_get_elem_pad(const struct ng_parse_type *type, + int index, enum comptype ctype, int posn); + +/* Parsing helper functions */ +static int ng_parse_skip_value(const char *s, int off, int *lenp); + +/* Poor man's virtual method calls */ +#define METHOD(t,m) (ng_get_ ## m ## _method(t)) +#define INVOKE(t,m) (*METHOD(t,m)) + +static ng_parse_t *ng_get_parse_method(const struct ng_parse_type *t); +static ng_unparse_t *ng_get_unparse_method(const struct ng_parse_type *t); +static ng_getDefault_t *ng_get_getDefault_method(const + struct ng_parse_type *t); +static ng_getAlign_t *ng_get_getAlign_method(const struct ng_parse_type *t); + +#define ALIGNMENT(t) (METHOD(t, getAlign) == NULL ? \ + 0 : INVOKE(t, getAlign)(t)) + +/* For converting binary to string */ +#define NG_PARSE_APPEND(fmt, args...) \ + do { \ + int len; \ + \ + len = snprintf((cbuf), (cbuflen), \ + fmt , ## args); \ + if (len >= (cbuflen)) \ + return (ERANGE); \ + (cbuf) += len; \ + (cbuflen) -= len; \ + } while (0) + +/************************************************************************ + PUBLIC FUNCTIONS + ************************************************************************/ + +/* + * Convert an ASCII string to binary according to the supplied type descriptor + */ +int +ng_parse(const struct ng_parse_type *type, + const char *string, int *off, u_char *buf, int *buflen) +{ + return INVOKE(type, parse)(type, string, off, buf, buf, buflen); +} + +/* + * Convert binary to an ASCII string according to the supplied type descriptor + */ +int +ng_unparse(const struct ng_parse_type *type, + const u_char *data, char *cbuf, int cbuflen) +{ + int off = 0; + + return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen); +} + +/* + * Fill in the default value according to the supplied type descriptor + */ +int +ng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen) +{ + ng_getDefault_t *const func = METHOD(type, getDefault); + + if (func == NULL) + return (EOPNOTSUPP); + return (*func)(type, buf, buf, buflen); +} + + +/************************************************************************ + STRUCTURE TYPE + ************************************************************************/ + +static int +ng_struct_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT); +} + +static int +ng_struct_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT); +} + +static int +ng_struct_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + int off = 0; + + return ng_parse_composite(type, + "{}", &off, start, buf, buflen, CT_STRUCT); +} + +static int +ng_struct_getAlign(const struct ng_parse_type *type) +{ + const struct ng_parse_struct_info *si = type->info; + const struct ng_parse_struct_field *field; + int align = 0; + + for (field = si->fields; field->name != NULL; field++) { + int falign = ALIGNMENT(field->type); + + if (falign > align) + align = falign; + } + return align; +} + +const struct ng_parse_type ng_parse_struct_type = { + NULL, + NULL, + NULL, + ng_struct_parse, + ng_struct_unparse, + ng_struct_getDefault, + ng_struct_getAlign +}; + +/************************************************************************ + FIXED LENGTH ARRAY TYPE + ************************************************************************/ + +static int +ng_fixedarray_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + return ng_parse_composite(type, + s, off, start, buf, buflen, CT_FIXEDARRAY); +} + +static int +ng_fixedarray_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + return ng_unparse_composite(type, + data, off, cbuf, cbuflen, CT_FIXEDARRAY); +} + +static int +ng_fixedarray_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + int off = 0; + + return ng_parse_composite(type, + "[]", &off, start, buf, buflen, CT_FIXEDARRAY); +} + +static int +ng_fixedarray_getAlign(const struct ng_parse_type *type) +{ + const struct ng_parse_fixedarray_info *fi = type->info; + + return ALIGNMENT(fi->elementType); +} + +const struct ng_parse_type ng_parse_fixedarray_type = { + NULL, + NULL, + NULL, + ng_fixedarray_parse, + ng_fixedarray_unparse, + ng_fixedarray_getDefault, + ng_fixedarray_getAlign +}; + +/************************************************************************ + VARIABLE LENGTH ARRAY TYPE + ************************************************************************/ + +static int +ng_array_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY); +} + +static int +ng_array_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY); +} + +static int +ng_array_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + int off = 0; + + return ng_parse_composite(type, + "[]", &off, start, buf, buflen, CT_ARRAY); +} + +static int +ng_array_getAlign(const struct ng_parse_type *type) +{ + const struct ng_parse_array_info *ai = type->info; + + return ALIGNMENT(ai->elementType); +} + +const struct ng_parse_type ng_parse_array_type = { + NULL, + NULL, + NULL, + ng_array_parse, + ng_array_unparse, + ng_array_getDefault, + ng_array_getAlign +}; + +/************************************************************************ + INT8 TYPE + ************************************************************************/ + +static int +ng_int8_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + long val; + int8_t val8; + char *eptr; + + val = strtol(s + *off, &eptr, 0); + if (val < -0x80 || val > 0xff || eptr == s + *off) + return (EINVAL); + *off = eptr - s; + val8 = (int8_t)val; + bcopy(&val8, buf, sizeof(int8_t)); + *buflen = sizeof(int8_t); + return (0); +} + +static int +ng_int8_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + int8_t val; + + bcopy(data + *off, &val, sizeof(int8_t)); + NG_PARSE_APPEND("%d", (int)val); + *off += sizeof(int8_t); + return (0); +} + +static int +ng_int8_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + int8_t val; + + if (*buflen < sizeof(int8_t)) + return (ERANGE); + val = 0; + bcopy(&val, buf, sizeof(int8_t)); + *buflen = sizeof(int8_t); + return (0); +} + +static int +ng_int8_getAlign(const struct ng_parse_type *type) +{ + return INT8_ALIGNMENT; +} + +const struct ng_parse_type ng_parse_int8_type = { + NULL, + NULL, + NULL, + ng_int8_parse, + ng_int8_unparse, + ng_int8_getDefault, + ng_int8_getAlign +}; + +/************************************************************************ + INT16 TYPE + ************************************************************************/ + +static int +ng_int16_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + long val; + int16_t val16; + char *eptr; + + val = strtol(s + *off, &eptr, 0); + if (val < -0x8000 || val > 0xffff || eptr == s + *off) + return (EINVAL); + *off = eptr - s; + val16 = (int16_t)val; + bcopy(&val16, buf, sizeof(int16_t)); + *buflen = sizeof(int16_t); + return (0); +} + +static int +ng_int16_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + int16_t val; + + bcopy(data + *off, &val, sizeof(int16_t)); + NG_PARSE_APPEND("%d", (int)val); + *off += sizeof(int16_t); + return (0); +} + +static int +ng_int16_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + int16_t val; + + if (*buflen < sizeof(int16_t)) + return (ERANGE); + val = 0; + bcopy(&val, buf, sizeof(int16_t)); + *buflen = sizeof(int16_t); + return (0); +} + +static int +ng_int16_getAlign(const struct ng_parse_type *type) +{ + return INT16_ALIGNMENT; +} + +const struct ng_parse_type ng_parse_int16_type = { + NULL, + NULL, + NULL, + ng_int16_parse, + ng_int16_unparse, + ng_int16_getDefault, + ng_int16_getAlign +}; + +/************************************************************************ + INT32 TYPE + ************************************************************************/ + +static int +ng_int32_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + long val; /* assumes long is at least 32 bits */ + int32_t val32; + char *eptr; + + val = strtol(s + *off, &eptr, 0); + if (val < -0x80000000 || val > 0xffffffff || eptr == s + *off) + return (EINVAL); + *off = eptr - s; + val32 = (int32_t)val; + bcopy(&val32, buf, sizeof(int32_t)); + *buflen = sizeof(int32_t); + return (0); +} + +static int +ng_int32_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + int32_t val; + + bcopy(data + *off, &val, sizeof(int32_t)); + NG_PARSE_APPEND("%ld", (long)val); + *off += sizeof(int32_t); + return (0); +} + +static int +ng_int32_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + int32_t val; + + if (*buflen < sizeof(int32_t)) + return (ERANGE); + val = 0; + bcopy(&val, buf, sizeof(int32_t)); + *buflen = sizeof(int32_t); + return (0); +} + +static int +ng_int32_getAlign(const struct ng_parse_type *type) +{ + return INT32_ALIGNMENT; +} + +const struct ng_parse_type ng_parse_int32_type = { + NULL, + NULL, + NULL, + ng_int32_parse, + ng_int32_unparse, + ng_int32_getDefault, + ng_int32_getAlign +}; + +/************************************************************************ + INT64 TYPE + ************************************************************************/ + +static int +ng_int64_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + quad_t val; + int64_t val64; + char *eptr; + + val = strtoq(s + *off, &eptr, 0); + if (eptr == s + *off) + return (EINVAL); + *off = eptr - s; + val64 = (int64_t)val; + bcopy(&val64, buf, sizeof(int64_t)); + *buflen = sizeof(int64_t); + return (0); +} + +static int +ng_int64_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + int64_t val; + + bcopy(data + *off, &val, sizeof(int64_t)); + NG_PARSE_APPEND("%lld", (long long)val); + *off += sizeof(int64_t); + return (0); +} + +static int +ng_int64_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + int64_t val; + + if (*buflen < sizeof(int64_t)) + return (ERANGE); + val = 0; + bcopy(&val, buf, sizeof(int64_t)); + *buflen = sizeof(int64_t); + return (0); +} + +static int +ng_int64_getAlign(const struct ng_parse_type *type) +{ + return INT64_ALIGNMENT; +} + +const struct ng_parse_type ng_parse_int64_type = { + NULL, + NULL, + NULL, + ng_int64_parse, + ng_int64_unparse, + ng_int64_getDefault, + ng_int64_getAlign +}; + +/************************************************************************ + STRING TYPE + ************************************************************************/ + +static int +ng_string_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + char *sval; + int len; + + if ((sval = ng_get_string_token(s, off, &len)) == NULL) + return (EINVAL); + *off += len; + len = strlen(sval) + 1; + bcopy(sval, buf, len); + FREE(sval, M_NETGRAPH); + *buflen = len; + return (0); +} + +static int +ng_string_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + const char *const raw = (const char *)data + *off; + char *const s = ng_encode_string(raw); + + if (s == NULL) + return (ENOMEM); + NG_PARSE_APPEND("%s", s); + *off += strlen(raw) + 1; + FREE(s, M_NETGRAPH); + return (0); +} + +static int +ng_string_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + + if (*buflen < 1) + return (ERANGE); + buf[0] = (u_char)'\0'; + *buflen = 1; + return (0); +} + +const struct ng_parse_type ng_parse_string_type = { + NULL, + NULL, + NULL, + ng_string_parse, + ng_string_unparse, + ng_string_getDefault, + NULL +}; + +/************************************************************************ + FIXED BUFFER STRING TYPE + ************************************************************************/ + +static int +ng_fixedstring_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + const struct ng_parse_fixedsstring_info *const fi = type->info; + char *sval; + int len; + + if ((sval = ng_get_string_token(s, off, &len)) == NULL) + return (EINVAL); + if (strlen(sval) + 1 > fi->bufSize) + return (E2BIG); + *off += len; + len = strlen(sval) + 1; + bcopy(sval, buf, len); + FREE(sval, M_NETGRAPH); + bzero(buf + len, fi->bufSize - len); + *buflen = fi->bufSize; + return (0); +} + +static int +ng_fixedstring_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + const struct ng_parse_fixedsstring_info *const fi = type->info; + int error, temp = *off; + + if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0) + return (error); + *off += fi->bufSize; + return (0); +} + +static int +ng_fixedstring_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + const struct ng_parse_fixedsstring_info *const fi = type->info; + + if (*buflen < fi->bufSize) + return (ERANGE); + bzero(buf, fi->bufSize); + *buflen = fi->bufSize; + return (0); +} + +const struct ng_parse_type ng_parse_fixedstring_type = { + NULL, + NULL, + NULL, + ng_fixedstring_parse, + ng_fixedstring_unparse, + ng_fixedstring_getDefault, + NULL +}; + +const struct ng_parse_fixedsstring_info ng_parse_nodebuf_info = { + NG_NODELEN + 1 +}; +const struct ng_parse_type ng_parse_nodebuf_type = { + &ng_parse_fixedstring_type, + &ng_parse_nodebuf_info +}; + +const struct ng_parse_fixedsstring_info ng_parse_hookbuf_info = { + NG_HOOKLEN + 1 +}; +const struct ng_parse_type ng_parse_hookbuf_type = { + &ng_parse_fixedstring_type, + &ng_parse_hookbuf_info +}; + +const struct ng_parse_fixedsstring_info ng_parse_pathbuf_info = { + NG_PATHLEN + 1 +}; +const struct ng_parse_type ng_parse_pathbuf_type = { + &ng_parse_fixedstring_type, + &ng_parse_pathbuf_info +}; + +const struct ng_parse_fixedsstring_info ng_parse_typebuf_info = { + NG_TYPELEN + 1 +}; +const struct ng_parse_type ng_parse_typebuf_type = { + &ng_parse_fixedstring_type, + &ng_parse_typebuf_info +}; + +const struct ng_parse_fixedsstring_info ng_parse_cmdbuf_info = { + NG_CMDSTRLEN + 1 +}; +const struct ng_parse_type ng_parse_cmdbuf_type = { + &ng_parse_fixedstring_type, + &ng_parse_cmdbuf_info +}; + +/************************************************************************ + IP ADDRESS TYPE + ************************************************************************/ + +static int +ng_ipaddr_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + int i, error; + + for (i = 0; i < 4; i++) { + if ((error = ng_int8_parse(&ng_parse_int8_type, + s, off, start, buf + i, buflen)) != 0) + return (error); + if (i < 3 && s[*off] != '.') + return (EINVAL); + (*off)++; + } + *buflen = 4; + return (0); +} + +static int +ng_ipaddr_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + struct in_addr ip; + + bcopy(data + *off, &ip, sizeof(ip)); + NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0], + ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]); + *off += sizeof(ip); + return (0); +} + +static int +ng_ipaddr_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + struct in_addr ip = { 0 }; + + if (*buflen < sizeof(ip)) + return (ERANGE); + bcopy(&ip, buf, sizeof(ip)); + *buflen = sizeof(ip); + return (0); +} + +const struct ng_parse_type ng_parse_ipaddr_type = { + NULL, + NULL, + NULL, + ng_ipaddr_parse, + ng_ipaddr_unparse, + ng_ipaddr_getDefault, + ng_int32_getAlign +}; + +/************************************************************************ + BYTE ARRAY TYPE + ************************************************************************/ + +/* Get the length of a byte array */ +static int +ng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type, + const u_char *start, const u_char *buf) +{ + ng_parse_array_getLength_t *const getLength = type->private; + + return (*getLength)(type, start, buf); +} + +static int +ng_bytearray_elem_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + int8_t val; + + bcopy(data + *off, &val, sizeof(int8_t)); + NG_PARSE_APPEND("0x%02x", (int)val & 0xff); /* always hex format */ + *off += sizeof(int8_t); + return (0); +} + +/* Byte array element type is int8, but always output in hex format */ +const struct ng_parse_type ng_parse_bytearray_elem_type = { + &ng_parse_int8_type, + NULL, + NULL, + NULL, + ng_bytearray_elem_unparse, + NULL, + NULL +}; + +static const struct ng_parse_array_info ng_parse_bytearray_subtype_info = { + &ng_parse_bytearray_elem_type, + &ng_parse_bytearray_subtype_getLength, + NULL +}; +static const struct ng_parse_type ng_parse_bytearray_subtype = { + &ng_parse_array_type, + &ng_parse_bytearray_subtype_info +}; + +static int +ng_bytearray_parse(const struct ng_parse_type *type, + const char *s, int *off, const u_char *const start, + u_char *const buf, int *buflen) +{ + char *str; + int toklen; + + /* We accept either an array of bytes or a string constant */ + if ((str = ng_get_string_token(s, off, &toklen)) != NULL) { + ng_parse_array_getLength_t *const getLength = type->info; + int arraylen, slen; + + arraylen = (*getLength)(type, start, buf); + if (arraylen > *buflen) { + FREE(str, M_NETGRAPH); + return (ERANGE); + } + slen = strlen(str) + 1; + if (slen > arraylen) { + FREE(str, M_NETGRAPH); + return (E2BIG); + } + bcopy(str, buf, slen); + bzero(buf + slen, arraylen - slen); + FREE(str, M_NETGRAPH); + *off += toklen; + *buflen = arraylen; + return (0); + } else { + struct ng_parse_type subtype; + + subtype = ng_parse_bytearray_subtype; + (const void *)subtype.private = type->info; + return ng_array_parse(&subtype, s, off, start, buf, buflen); + } +} + +static int +ng_bytearray_unparse(const struct ng_parse_type *type, + const u_char *data, int *off, char *cbuf, int cbuflen) +{ + struct ng_parse_type subtype; + + subtype = ng_parse_bytearray_subtype; + (const void *)subtype.private = type->info; + return ng_array_unparse(&subtype, data, off, cbuf, cbuflen); +} + +static int +ng_bytearray_getDefault(const struct ng_parse_type *type, + const u_char *const start, u_char *buf, int *buflen) +{ + struct ng_parse_type subtype; + + subtype = ng_parse_bytearray_subtype; + (const void *)subtype.private = type->info; + return ng_array_getDefault(&subtype, start, buf, buflen); +} + +const struct ng_parse_type ng_parse_bytearray_type = { + NULL, + NULL, + NULL, + ng_bytearray_parse, + ng_bytearray_unparse, + ng_bytearray_getDefault, + NULL +}; + +/************************************************************************ + STRUCT NG_MESG TYPE + ************************************************************************/ + +/* Get msg->header.arglen when "buf" is pointing to msg->data */ +static int +ng_parse_ng_mesg_getLength(const struct ng_parse_type *type, + const u_char *start, const u_char *buf) +{ + const struct ng_mesg *msg; + + msg = (const struct ng_mesg *)(buf - sizeof(*msg)); + return msg->header.arglen; +} + +/* Type for the variable length data portion of a struct ng_mesg */ +static const struct ng_parse_type ng_msg_data_type = { + &ng_parse_bytearray_type, + &ng_parse_ng_mesg_getLength +}; + +/* Type for the entire struct ng_mesg header with data section */ +static const struct ng_parse_struct_info + ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type); +const struct ng_parse_type ng_parse_ng_mesg_type = { + &ng_parse_struct_type, + &ng_parse_ng_mesg_type_info, +}; + +/************************************************************************ + COMPOSITE HELPER ROUTINES + ************************************************************************/ + +/* + * Convert a structure or array from ASCII to binary + */ +static int +ng_parse_composite(const struct ng_parse_type *type, const char *s, + int *off, const u_char *const start, u_char *const buf, int *buflen, + const enum comptype ctype) +{ + const int num = ng_get_composite_len(type, start, buf, ctype); + int nextIndex = 0; /* next implicit array index */ + u_int index; /* field or element index */ + int *foff; /* field value offsets in string */ + int align, len, blen, error = 0; + + /* Initialize */ + MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH, M_NOWAIT); + if (foff == NULL) { + error = ENOMEM; + goto done; + } + bzero(foff, num * sizeof(*foff)); + + /* Get opening brace/bracket */ + if (ng_parse_get_token(s, off, &len) + != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) { + error = EINVAL; + goto done; + } + *off += len; + + /* Get individual element value positions in the string */ + for (;;) { + enum ng_parse_token tok; + + /* Check for closing brace/bracket */ + tok = ng_parse_get_token(s, off, &len); + if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) { + *off += len; + break; + } + + /* For arrays, the 'name' (ie, index) is optional, so + distinguish name from values by seeing if the next + token is an equals sign */ + if (ctype != CT_STRUCT) { + int len2, off2; + char *eptr; + + /* If an opening brace/bracket, index is implied */ + if (tok == T_LBRACE || tok == T_LBRACKET) { + index = nextIndex++; + goto gotIndex; + } + + /* Might be an index, might be a value, either way... */ + if (tok != T_WORD) { + error = EINVAL; + goto done; + } + + /* If no equals sign follows, index is implied */ + off2 = *off + len; + if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) { + index = nextIndex++; + goto gotIndex; + } + + /* Index was specified explicitly; parse it */ + index = (u_int)strtoul(s + *off, &eptr, 0); + if (index < 0 || eptr - (s + *off) != len) { + error = EINVAL; + goto done; + } + nextIndex = index + 1; + *off += len + len2; +gotIndex: + } else { /* a structure field */ + const struct ng_parse_struct_field *field = NULL; + const struct ng_parse_struct_info *si = type->info; + + /* Find the field by name (required) in field list */ + if (tok != T_WORD) { + error = EINVAL; + goto done; + } + for (index = 0; index < num; index++) { + field = &si->fields[index]; + if (strncmp(&s[*off], field->name, len) == 0 + && field->name[len] == '\0') + break; + } + if (index == num) { + error = ENOENT; + goto done; + } + *off += len; + + /* Get equals sign */ + if (ng_parse_get_token(s, off, &len) != T_EQUALS) { + error = EINVAL; + goto done; + } + *off += len; + } + + /* Check array index */ + if (index >= num) { + error = E2BIG; + goto done; + } + + /* Save value's position and skip over it for now */ + if (foff[index] != 0) { + error = EALREADY; /* duplicate */ + goto done; + } + while (isspace(s[*off])) + (*off)++; + foff[index] = *off; + if ((error = ng_parse_skip_value(s, *off, &len)) != 0) + goto done; + *off += len; + } + + /* Now build binary structure from supplied values and defaults */ + for (blen = index = 0; index < num; index++) { + const struct ng_parse_type *const + etype = ng_get_composite_etype(type, index, ctype); + int k, pad, vlen; + + /* Zero-pad any alignment bytes */ + pad = ng_parse_get_elem_pad(type, index, ctype, blen); + for (k = 0; k < pad; k++) { + if (blen >= *buflen) { + error = ERANGE; + goto done; + } + buf[blen++] = 0; + } + + /* Get value */ + vlen = *buflen - blen; + if (foff[index] == 0) { /* use default value */ + error = ng_get_composite_elem_default(type, index, + start, buf + blen, &vlen, ctype); + } else { /* parse given value */ + *off = foff[index]; + error = INVOKE(etype, parse)(etype, + s, off, start, buf + blen, &vlen); + } + if (error != 0) + goto done; + blen += vlen; + } + + /* Make total composite structure size a multiple of its alignment */ + if ((align = ALIGNMENT(type)) != 0) { + while (blen % align != 0) { + if (blen >= *buflen) { + error = ERANGE; + goto done; + } + buf[blen++] = 0; + } + } + + /* Done */ + *buflen = blen; +done: + FREE(foff, M_NETGRAPH); + return (error); +} + +/* + * Convert an array or structure from binary to ASCII + */ +static int +ng_unparse_composite(const struct ng_parse_type *type, const u_char *data, + int *off, char *cbuf, int cbuflen, const enum comptype ctype) +{ + const int num = ng_get_composite_len(type, data, data + *off, ctype); + int nextIndex = 0, didOne = 0; + int error, index; + + /* Opening brace/bracket */ + NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '['); + + /* Do each item */ + for (index = 0; index < num; index++) { + const struct ng_parse_type *const + etype = ng_get_composite_etype(type, index, ctype); + u_char temp[1024]; + + /* Skip any alignment pad bytes */ + *off += ng_parse_get_elem_pad(type, index, ctype, *off); + + /* See if element is equal to its default value; skip if so */ + if (*off < sizeof(temp)) { + int tempsize = sizeof(temp) - *off; + + bcopy(data, temp, *off); + if (ng_get_composite_elem_default(type, index, temp, + temp + *off, &tempsize, ctype) == 0 + && bcmp(temp + *off, data + *off, tempsize) == 0) { + *off += tempsize; + continue; + } + } + + /* Print name= */ + NG_PARSE_APPEND(" "); + if (ctype != CT_STRUCT) { + if (index != nextIndex) { + nextIndex = index; + NG_PARSE_APPEND("%d=", index); + } + nextIndex++; + } else { + const struct ng_parse_struct_info *si = type->info; + + NG_PARSE_APPEND("%s=", si->fields[index].name); + } + + /* Print value */ + if ((error = INVOKE(etype, unparse) + (etype, data, off, cbuf, cbuflen)) != 0) + return (error); + cbuflen -= strlen(cbuf); + cbuf += strlen(cbuf); + didOne = 1; + } + + /* Closing brace/bracket */ + NG_PARSE_APPEND("%s%c", + didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']'); + return (0); +} + +/* + * Generate the default value for an element of an array or structure + * Returns EOPNOTSUPP if default value is unspecified. + */ +static int +ng_get_composite_elem_default(const struct ng_parse_type *type, + int index, const u_char *const start, u_char *buf, int *buflen, + const enum comptype ctype) +{ + const struct ng_parse_type *etype; + ng_getDefault_t *func; + + switch (ctype) { + case CT_STRUCT: + break; + case CT_ARRAY: + { + const struct ng_parse_array_info *const ai = type->info; + + if (ai->getDefault != NULL) { + return (*ai->getDefault)(type, + index, start, buf, buflen); + } + break; + } + case CT_FIXEDARRAY: + { + const struct ng_parse_fixedarray_info *const fi = type->info; + + if (*fi->getDefault != NULL) { + return (*fi->getDefault)(type, + index, start, buf, buflen); + } + break; + } + default: + panic("%s", __FUNCTION__); + } + + /* Default to element type default */ + etype = ng_get_composite_etype(type, index, ctype); + func = METHOD(etype, getDefault); + if (func == NULL) + return (EOPNOTSUPP); + return (*func)(etype, start, buf, buflen); +} + +/* + * Get the number of elements in a struct, variable or fixed array. + */ +static int +ng_get_composite_len(const struct ng_parse_type *type, + const u_char *const start, const u_char *buf, + const enum comptype ctype) +{ + switch (ctype) { + case CT_STRUCT: + { + const struct ng_parse_struct_info *const si = type->info; + int numFields = 0; + + for (numFields = 0; ; numFields++) { + const struct ng_parse_struct_field *const + fi = &si->fields[numFields]; + + if (fi->name == NULL) + break; + } + return (numFields); + } + case CT_ARRAY: + { + const struct ng_parse_array_info *const ai = type->info; + + return (*ai->getLength)(type, start, buf); + } + case CT_FIXEDARRAY: + { + const struct ng_parse_fixedarray_info *const fi = type->info; + + return fi->length; + } + default: + panic("%s", __FUNCTION__); + } + return (0); +} + +/* + * Return the type of the index'th element of a composite structure + */ +static const struct ng_parse_type * +ng_get_composite_etype(const struct ng_parse_type *type, + int index, const enum comptype ctype) +{ + const struct ng_parse_type *etype = NULL; + + switch (ctype) { + case CT_STRUCT: + { + const struct ng_parse_struct_info *const si = type->info; + + etype = si->fields[index].type; + break; + } + case CT_ARRAY: + { + const struct ng_parse_array_info *const ai = type->info; + + etype = ai->elementType; + break; + } + case CT_FIXEDARRAY: + { + const struct ng_parse_fixedarray_info *const fi = type->info; + + etype = fi->elementType; + break; + } + default: + panic("%s", __FUNCTION__); + } + return (etype); +} + +/* + * Get the number of bytes to skip to align for the next + * element in a composite structure. + */ +static int +ng_parse_get_elem_pad(const struct ng_parse_type *type, + int index, enum comptype ctype, int posn) +{ + const struct ng_parse_type *const + etype = ng_get_composite_etype(type, index, ctype); + int align; + + /* Get element's alignment, and possibly override */ + align = ALIGNMENT(etype); + if (ctype == CT_STRUCT) { + const struct ng_parse_struct_info *si = type->info; + + if (si->fields[index].alignment != 0) + align = si->fields[index].alignment; + } + + /* Return number of bytes to skip to align */ + return (align ? (align - (posn % align)) % align : 0); +} + +/************************************************************************ + PARSING HELPER ROUTINES + ************************************************************************/ + +/* + * Skip over a value + */ +static int +ng_parse_skip_value(const char *s, int off0, int *lenp) +{ + int len, nbracket, nbrace; + int off = off0; + + len = nbracket = nbrace = 0; + do { + switch (ng_parse_get_token(s, &off, &len)) { + case T_LBRACKET: + nbracket++; + break; + case T_LBRACE: + nbrace++; + break; + case T_RBRACKET: + if (nbracket-- == 0) + return (EINVAL); + break; + case T_RBRACE: + if (nbrace-- == 0) + return (EINVAL); + break; + case T_EOF: + return (EINVAL); + default: + break; + } + off += len; + } while (nbracket > 0 || nbrace > 0); + *lenp = off - off0; + return (0); +} + +/* + * Find the next token in the string, starting at offset *startp. + * Returns the token type, with *startp pointing to the first char + * and *lenp the length. + */ +enum ng_parse_token +ng_parse_get_token(const char *s, int *startp, int *lenp) +{ + char *t; + int i; + + while (isspace(s[*startp])) + (*startp)++; + switch (s[*startp]) { + case '\0': + *lenp = 0; + return T_EOF; + case '{': + *lenp = 1; + return T_LBRACE; + case '}': + *lenp = 1; + return T_RBRACE; + case '[': + *lenp = 1; + return T_LBRACKET; + case ']': + *lenp = 1; + return T_RBRACKET; + case '=': + *lenp = 1; + return T_EQUALS; + case '"': + if ((t = ng_get_string_token(s, startp, lenp)) == NULL) + return T_ERROR; + FREE(t, M_NETGRAPH); + return T_STRING; + default: + for (i = *startp + 1; s[i] != '\0' && !isspace(s[i]) + && s[i] != '{' && s[i] != '}' && s[i] != '[' + && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++) + ; + *lenp = i - *startp; + return T_WORD; + } +} + +/* + * Get a string token, which must be enclosed in double quotes. + * The normal C backslash escapes are recognized. + */ +char * +ng_get_string_token(const char *s, int *startp, int *lenp) +{ + char *cbuf, *p; + int start, off; + + while (isspace(s[*startp])) + (*startp)++; + start = *startp; + if (s[*startp] != '"') + return (NULL); + MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH, M_NOWAIT); + if (cbuf == NULL) + return (NULL); + strcpy(cbuf, s + start + 1); + for (off = 1, p = cbuf; *p != '\0'; off++, p++) { + if (*p == '"') { + *p = '\0'; + *lenp = off + 1; + return (cbuf); + } else if (p[0] == '\\' && p[1] != '\0') { + int x, k; + char *v; + + strcpy(p, p + 1); + v = p; + switch (*p) { + case 't': + *v = '\t'; + off++; + continue; + case 'n': + *v = '\n'; + off++; + continue; + case 'r': + *v = '\r'; + off++; + continue; + case 'v': + *v = '\v'; + off++; + continue; + case 'f': + *v = '\f'; + off++; + continue; + case '"': + *v = '"'; + off++; + continue; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + for (x = k = 0; + k < 3 && *v >= '0' && *v <= '7'; v++) { + x = (x << 3) + (*v - '0'); + off++; + } + *--v = (char)x; + break; + case 'x': + for (v++, x = k = 0; + k < 2 && isxdigit(*v); v++) { + x = (x << 4) + (isdigit(*v) ? + (*v - '0') : + (tolower(*v) - 'a' + 10)); + off++; + } + *--v = (char)x; + break; + default: + continue; + } + strcpy(p, v); + } + } + return (NULL); /* no closing quote */ +} + +/* + * Encode a string so it can be safely put in double quotes. + * Caller must free the result. + */ +char * +ng_encode_string(const char *raw) +{ + char *cbuf; + int off = 0; + + MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH, M_NOWAIT); + if (cbuf == NULL) + return (NULL); + cbuf[off++] = '"'; + for ( ; *raw != '\0'; raw++) { + switch (*raw) { + case '\t': + cbuf[off++] = '\\'; + cbuf[off++] = 't'; + break; + case '\f': + cbuf[off++] = '\\'; + cbuf[off++] = 'f'; + break; + case '\n': + cbuf[off++] = '\\'; + cbuf[off++] = 'n'; + break; + case '\r': + cbuf[off++] = '\\'; + cbuf[off++] = 'r'; + break; + case '\v': + cbuf[off++] = '\\'; + cbuf[off++] = 'v'; + break; + case '"': + case '\\': + cbuf[off++] = '\\'; + cbuf[off++] = *raw; + break; + default: + if (*raw < 0x20 || *raw > 0x7e) { + off += sprintf(cbuf + off, + "\\x%02x", (u_char)*raw); + break; + } + cbuf[off++] = *raw; + break; + } + } + cbuf[off++] = '"'; + cbuf[off] = '\0'; + return (cbuf); +} + +/************************************************************************ + VIRTUAL METHOD LOOKUP + ************************************************************************/ + +static ng_parse_t * +ng_get_parse_method(const struct ng_parse_type *t) +{ + while (t != NULL && t->parse == NULL) + t = t->supertype; + return (t ? t->parse : NULL); +} + +static ng_unparse_t * +ng_get_unparse_method(const struct ng_parse_type *t) +{ + while (t != NULL && t->unparse == NULL) + t = t->supertype; + return (t ? t->unparse : NULL); +} + +static ng_getDefault_t * +ng_get_getDefault_method(const struct ng_parse_type *t) +{ + while (t != NULL && t->getDefault == NULL) + t = t->supertype; + return (t ? t->getDefault : NULL); +} + +static ng_getAlign_t * +ng_get_getAlign_method(const struct ng_parse_type *t) +{ + while (t != NULL && t->getAlign == NULL) + t = t->supertype; + return (t ? t->getAlign : NULL); +} + diff --git a/sys/netgraph/ng_parse.h b/sys/netgraph/ng_parse.h new file mode 100644 index 000000000000..0dbf7691f0c4 --- /dev/null +++ b/sys/netgraph/ng_parse.h @@ -0,0 +1,507 @@ + +/* + * ng_parse.h + * + * Copyright (c) 1999 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Archie Cobbs <archie@whistle.com> + * + * $Whistle: ng_parse.h,v 1.2 1999/11/29 01:43:48 archie Exp $ + * $FreeBSD$ + */ + +#ifndef _NETGRAPH_PARSE_H_ +#define _NETGRAPH_PARSE_H_ + +/* + + This defines a library of routines for converting between various C + language types in binary form and ASCII strings. Types are user + definable. Several pre-defined types are supplied, for some common + C types: structures, variable and fixed length arrays, integer types, + variable and fixed length strings, IP addresses, etc. + + A netgraph node type may provide a list of types that correspond to + the structures it expects to send and receive in the arguments field + of a control message. This allows these messages to be converted + between their native binary form and the corresponding ASCII form. + + A future use of the ASCII form may be for inter-machine communication + of control messages, because the ASCII form is machine independent + whereas the native binary form is not. + + Syntax + ------ + + Structures: + + '{' [ <name>=<value> ... ] '}' + + Omitted fields have their default values by implication. + The order in which the fields are specified does not matter. + + Arrays: + + '[' [ [index=]<value> ... ] ']' + + Element value may be specified with or without the "<index>=" prefix; + If omitted, the index after the previous element is used. + Omitted fields have their default values by implication. + + Strings: + + "foo bar blah\r\n" + + That is, strings are specified just like C strings. The usual + backslash escapes are accepted. + + Other simple types (integers, IP addresses) have their obvious forms. + + Example + ------- + + Suppose we have a netgraph command that takes as an argument + a 'struct foo' shown below. Here is an example of a possible + value for the structure, and the corresponding ASCII encoding + of that value: + + Structure Binary value + --------- ------------ + + struct foo { + struct in_addr ip; 01 02 03 04 + int bar; 00 00 00 00 + char label[8]; 61 62 63 0a 00 00 00 00 + u_char alen; 03 00 + short ary[0]; 05 00 00 00 0a 00 + }; + + ASCII value + ----------- + + { ip=1.2.3.4 label="abc\n" alen=3 ary=[ 5 2=10 ] } + + Note that omitted fields and array elements get their default + values ("bar" and ary[2]), and that the alignment is handled + automatically (the extra 00 byte after "num"). Also, since byte + order and alignment are inherently machine dependent, so is this + conversion process. The above example shows an x86 (little + endian) encoding. Also the above example is tricky because the + structure is variable length, depending on 'alen', the number of + elements in the array 'ary'. + + Here is how one would define a parse type for the above structure, + subclassing the pre-defined types below. We construct the type in + a 'bottom up' fashion, defining each field's type first, then the + type for the whole structure ('//' comments used to avoid breakage). + + // Super-type info for 'label' field + struct ng_parse_fixedsstring_info foo_label_info = { 8 }; + + // Parse type for 'label' field + struct ng_parse_type foo_label_type = { + &ng_parse_fixedstring_type // super-type + &foo_label_info // super-type info + }; + + #define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) + + // Function to compute the length of the array 'ary', which + // is variable length, depending on the previous field 'alen'. + // Upon entry 'buf' will be pointing at &ary[0]. + int + foo_ary_getLength(const struct ng_parse_type *type, + const u_char *start, const u_char *buf) + { + const struct foo *f; + + f = (const struct foo *)(buf - OFFSETOF(struct foo, ary)); + return f->alen; + } + + // Super-type info for 'ary' field + struct ng_parse_array_info foo_ary_info = { + &ng_parse_int16_type, // element type + &foo_ary_getLength // func to get array length + } + + // Parse type for 'ary' field + struct ng_parse_type foo_ary_type = { + &ng_parse_array_type, // super-type + &foo_ary_info // super-type info + }; + + // Super-type info for struct foo + struct ng_parse_struct_info foo_fields = { + { "ip", &ng_parse_ipaddr_type }, + { "bar", &ng_parse_int32_type }, + { "label", &foo_label_type }, + { "alen", &ng_parse_int8_type }, + { "ary", &foo_ary_type }, + { NULL } + }; + + // Parse type for struct foo + struct ng_parse_type foo_type = { + &ng_parse_struct_type, // super-type + &foo_fields // super-type info + }; + + To define a type, you can define it as a sub-type of a predefined + type as shown above, possibly overriding some of the predefined + type's methods, or define an entirely new syntax, with the restriction + that the ASCII representation of your type's value must not contain + any whitespace or any of these characters: { } [ ] = " + + See ng_ksocket.c for an example of how to do this for 'struct sockaddr'. + See ng_parse.c to see implementations of the pre-defined types below. + +*/ + +/************************************************************************ + METHODS REQUIRED BY A TYPE + ************************************************************************/ + +/* + * Three methods are required for a type. These may be given explicitly + * or, if NULL, inherited from the super-type. The 'getDefault' method + * is always optional; the others are required if there is no super-type. + */ + +struct ng_parse_type; + +/* + * Convert ASCII to binary according to the supplied type. + * + * The ASCII characters begin at offset *off in 'string'. The binary + * representation is put into 'buf', which has at least *buflen bytes. + * 'start' points to the first byte output by ng_parse() (ie, start <= buf). + * + * Upon return, *buflen contains the length of the new binary data, and + * *off is updated to point just past the end of the parsed range of + * characters, or, in the case of an error, to the offending character(s). + * + * Return values: + * 0 Success; *buflen holds the length of the data + * and *off points just past the last char parsed. + * EALREADY Field specified twice + * ENOENT Unknown field + * E2BIG Array or character string overflow + * ERANGE Output was longer than *buflen bytes + * EINVAL Parse failure or other invalid content + * ENOMEM Out of memory + * EOPNOTSUPP Mandatory array/structure element missing + */ +typedef int ng_parse_t(const struct ng_parse_type *type, const char *string, + int *off, const u_char *start, + u_char *buf, int *buflen); + +/* + * Convert binary to ASCII according to the supplied type. + * + * The results are put into 'buf', which is at least buflen bytes long. + * *off points to the current byte in 'data' and should be updated + * before return to point just past the last byte unparsed. + * + * Returns: + * 0 Success + * ERANGE Output was longer than buflen bytes + */ +typedef int ng_unparse_t(const struct ng_parse_type *type, + const u_char *data, int *off, char *buf, int buflen); + +/* + * Compute the default value according to the supplied type. + * + * Store the result in 'buf', which is at least *buflen bytes long. + * Upon return *buflen contains the length of the output. + * + * Returns: + * 0 Success + * ERANGE Output was longer than *buflen bytes + * EOPNOTSUPP Default value is not specified for this type + */ +typedef int ng_getDefault_t(const struct ng_parse_type *type, + const u_char *start, u_char *buf, int *buflen); + +/* + * Return the alignment requirement of this type. Zero is same as one. + */ +typedef int ng_getAlign_t(const struct ng_parse_type *type); + +/************************************************************************ + TYPE DEFINITION + ************************************************************************/ + +/* + * This structure describes a type, which may be a sub-type of another + * type by pointing to it with 'supertype' and possibly omitting methods. + * Typically the super-type requires some type-specific info, which is + * supplied by the 'info' field. + * + * The 'private' field is ignored by all of the pre-defined types. + * Sub-types may use it as they see fit. + * + * The 'getDefault' method may always be omitted (even if there is no + * super-type), which means the value for any item of this type must + * always be explicitly given. + */ +struct ng_parse_type { + const struct ng_parse_type *supertype; /* super-type, if any */ + const void *info; /* type-specific info */ + void *private; /* client private info */ + ng_parse_t *parse; /* parse method */ + ng_unparse_t *unparse; /* unparse method */ + ng_getDefault_t *getDefault; /* get default value method */ + ng_getAlign_t *getAlign; /* get alignment */ +}; + +/************************************************************************ + PRE-DEFINED TYPES + ************************************************************************/ + +/* + * STRUCTURE TYPE + * + * This type supports arbitrary C structures. The normal field alignment + * rules for the local machine are applied. Fields are always parsed in + * field order, no matter what order they are listed in the ASCII string. + * + * Default value: Determined on a per-field basis + * Additional info: struct ng_parse_struct_info * + */ +extern const struct ng_parse_type ng_parse_struct_type; + +/* Each field has a name, type, and optional alignment override. If the + override is non-zero, the alignment is determined from the field type. + Note: add an extra struct ng_parse_struct_field with name == NULL + to indicate the end of the list. */ +struct ng_parse_struct_info { + struct ng_parse_struct_field { + const char *name; /* field name */ + const struct ng_parse_type + *type; /* field type */ + int alignment; /* override alignment */ + } fields[0]; +}; + +/* + * FIXED LENGTH ARRAY TYPE + * + * This type supports fixed length arrays, having any element type. + * + * Default value: As returned by getDefault for each index + * Additional info: struct ng_parse_fixedarray_info * + */ +extern const struct ng_parse_type ng_parse_fixedarray_type; + +/* + * Get the default value for the element at index 'index'. This method + * may be NULL, in which case the default value is computed from the + * element type. Otherwise, it should fill in the default value at *buf + * (having size *buflen) and update *buflen to the length of the filled-in + * value before return. If there is not enough routine return ERANGE. + */ +typedef int ng_parse_array_getDefault_t(const struct ng_parse_type *type, + int index, const u_char *start, + u_char *buf, int *buflen); + +struct ng_parse_fixedarray_info { + const struct ng_parse_type *elementType; + int length; + ng_parse_array_getDefault_t *getDefault; +}; + +/* + * VARIABLE LENGTH ARRAY TYPE + * + * Same as fixed length arrays, except that the length is determined + * by a function instead of a constant value. + * + * Default value: Same as with fixed length arrays + * Additional info: struct ng_parse_array_info * + */ +extern const struct ng_parse_type ng_parse_array_type; + +/* + * Return the length of the array. If the array is a field in a structure, + * all prior fields are guaranteed to be filled in already. Upon entry, + * 'start' is equal to the first byte parsed in this run, while 'buf' points + * to the first element of the array to be filled in. + */ +typedef int ng_parse_array_getLength_t(const struct ng_parse_type *type, + const u_char *start, const u_char *buf); + +struct ng_parse_array_info { + const struct ng_parse_type *elementType; + ng_parse_array_getLength_t *getLength; + ng_parse_array_getDefault_t *getDefault; +}; + +/* + * ARBITRARY LENGTH STRING TYPE + * + * For arbirary length, NUL-terminated strings. + * + * Default value: Empty string + * Additional info: None required + */ +extern const struct ng_parse_type ng_parse_string_type; + +/* + * BOUNDED LENGTH STRING TYPE + * + * These are strings that have a fixed-size buffer, and always include + * a terminating NUL character. + * + * Default value: Empty string + * Additional info: struct ng_parse_fixedsstring_info * + */ +extern const struct ng_parse_type ng_parse_fixedstring_type; + +struct ng_parse_fixedsstring_info { + int bufSize; /* size of buffer (including NUL) */ +}; + +/* + * COMMONLY USED BOUNDED LENGTH STRING TYPES + */ +extern const struct ng_parse_type ng_parse_nodebuf_type; /* NG_NODELEN + 1 */ +extern const struct ng_parse_type ng_parse_hookbuf_type; /* NG_HOOKLEN + 1 */ +extern const struct ng_parse_type ng_parse_pathbuf_type; /* NG_PATHLEN + 1 */ +extern const struct ng_parse_type ng_parse_typebuf_type; /* NG_TYPELEN + 1 */ +extern const struct ng_parse_type ng_parse_cmdbuf_type; /* NG_CMDSTRLEN + 1 */ + +/* + * INTEGER TYPES + * + * Default value: 0 + * Additional info: None required + */ +extern const struct ng_parse_type ng_parse_int8_type; +extern const struct ng_parse_type ng_parse_int16_type; +extern const struct ng_parse_type ng_parse_int32_type; +extern const struct ng_parse_type ng_parse_int64_type; + +/* + * IP ADDRESS TYPE + * + * Default value: 0.0.0.0 + * Additional info: None required + */ +extern const struct ng_parse_type ng_parse_ipaddr_type; + +/* + * VARIABLE LENGTH BYTE ARRAY TYPE + * + * The bytes are displayed in hex. The ASCII form may be either an + * array of bytes or a string constant, in which case the array is + * zero-filled after the string bytes. + * + * Default value: All bytes are zero + * Additional info: ng_parse_array_getLength_t * + */ +extern const struct ng_parse_type ng_parse_bytearray_type; + +/* + * NETGRAPH CONTROL MESSAGE TYPE + * + * This is the parse type for a struct ng_mesg. + * + * Default value: All fields zero + * Additional info: None required + */ +extern const struct ng_parse_type ng_parse_ng_mesg_type; + +/************************************************************************ + CONVERSTION AND PARSING ROUTINES + ************************************************************************/ + +/* Tokens for parsing structs and arrays */ +enum ng_parse_token { + T_LBRACE, /* '{' */ + T_RBRACE, /* '}' */ + T_LBRACKET, /* '[' */ + T_RBRACKET, /* ']' */ + T_EQUALS, /* '=' */ + T_STRING, /* string in double quotes */ + T_ERROR, /* error parsing string in double quotes */ + T_WORD, /* anything else containing no whitespace */ + T_EOF, /* end of string reached */ +}; + +/* + * See typedef ng_parse_t for definition + */ +extern int ng_parse(const struct ng_parse_type *type, const char *string, + int *off, u_char *buf, int *buflen); + +/* + * See typedef ng_unparse_t for definition (*off assumed to be zero). + */ +extern int ng_unparse(const struct ng_parse_type *type, + const u_char *data, char *buf, int buflen); + +/* + * See typedef ng_getDefault_t for definition + */ +extern int ng_parse_getDefault(const struct ng_parse_type *type, + u_char *buf, int *buflen); + +/* + * Parse a token: '*startp' is the offset to start looking. Upon + * successful return, '*startp' equals the beginning of the token + * and '*lenp' the length. If error, '*startp' points at the + * offending character(s). + */ +extern enum ng_parse_token ng_parse_get_token(const char *s, + int *startp, int *lenp); + +/* + * Like above, but specifically for getting a string token and returning + * the string value. The string token must be enclosed in double quotes + * and the normal C backslash escapes are recognized. The caller must + * eventually free() the returned result. Returns NULL if token is + * not a string token, or parse or other error. + */ +extern char *ng_get_string_token(const char *s, int *startp, int *lenp); + +/* + * Convert a raw string into a doubly-quoted string including any + * necessary backslash escapes. Caller must free the result. + * Returns NULL if ENOMEM. + */ +extern char *ng_encode_string(const char *s); + +#endif /* _NETGRAPH_PARSE_H_ */ + |
