ng_parse.c revision 87599
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 * 3767506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 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 87599 2001-12-10 08:09:49Z obrien $ 4153913Sarchie */ 4253913Sarchie 4353913Sarchie#include <sys/types.h> 4453913Sarchie#include <sys/param.h> 4553913Sarchie#include <sys/systm.h> 4670870Sjulian#include <sys/kernel.h> 4753913Sarchie#include <sys/errno.h> 4853913Sarchie#include <sys/malloc.h> 4953913Sarchie#include <sys/ctype.h> 5053913Sarchie 5153913Sarchie#include <netinet/in.h> 5253913Sarchie 5353913Sarchie#include <netgraph/ng_message.h> 5453913Sarchie#include <netgraph/netgraph.h> 5553913Sarchie#include <netgraph/ng_parse.h> 5653913Sarchie 5770870Sjulian#ifdef NG_SEPARATE_MALLOC 5870870SjulianMALLOC_DEFINE(M_NETGRAPH_PARSE, "netgraph_parse", "netgraph parse info"); 5970870Sjulian#else 6070870Sjulian#define M_NETGRAPH_PARSE M_NETGRAPH 6170870Sjulian#endif 6270870Sjulian 6353913Sarchie/* Compute alignment for primitive integral types */ 6453913Sarchiestruct int16_temp { 6553913Sarchie char x; 6653913Sarchie int16_t y; 6753913Sarchie}; 6853913Sarchie 6953913Sarchiestruct int32_temp { 7053913Sarchie char x; 7153913Sarchie int32_t y; 7253913Sarchie}; 7353913Sarchie 7453913Sarchiestruct int64_temp { 7553913Sarchie char x; 7653913Sarchie int64_t y; 7753913Sarchie}; 7853913Sarchie 7953913Sarchie#define INT8_ALIGNMENT 1 8053913Sarchie#define INT16_ALIGNMENT ((int)&((struct int16_temp *)0)->y) 8153913Sarchie#define INT32_ALIGNMENT ((int)&((struct int32_temp *)0)->y) 8253913Sarchie#define INT64_ALIGNMENT ((int)&((struct int64_temp *)0)->y) 8353913Sarchie 8464505Sarchie/* Output format for integral types */ 8564505Sarchie#define INT_UNSIGNED 0 8664505Sarchie#define INT_SIGNED 1 8764505Sarchie#define INT_HEX 2 8864505Sarchie 8953913Sarchie/* Type of composite object: struct, array, or fixedarray */ 9053913Sarchieenum comptype { 9153913Sarchie CT_STRUCT, 9253913Sarchie CT_ARRAY, 9353913Sarchie CT_FIXEDARRAY, 9453913Sarchie}; 9553913Sarchie 9653913Sarchie/* Composite types helper functions */ 9753913Sarchiestatic int ng_parse_composite(const struct ng_parse_type *type, 9853913Sarchie const char *s, int *off, const u_char *start, 9953913Sarchie u_char *const buf, int *buflen, enum comptype ctype); 10053913Sarchiestatic int ng_unparse_composite(const struct ng_parse_type *type, 10153913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen, 10253913Sarchie enum comptype ctype); 10353913Sarchiestatic int ng_get_composite_elem_default(const struct ng_parse_type *type, 10453913Sarchie int index, const u_char *start, u_char *buf, 10553913Sarchie int *buflen, enum comptype ctype); 10653913Sarchiestatic int ng_get_composite_len(const struct ng_parse_type *type, 10753913Sarchie const u_char *start, const u_char *buf, 10853913Sarchie enum comptype ctype); 10953913Sarchiestatic const struct ng_parse_type *ng_get_composite_etype(const struct 11053913Sarchie ng_parse_type *type, int index, enum comptype ctype); 11153913Sarchiestatic int ng_parse_get_elem_pad(const struct ng_parse_type *type, 11253913Sarchie int index, enum comptype ctype, int posn); 11353913Sarchie 11453913Sarchie/* Parsing helper functions */ 11553913Sarchiestatic int ng_parse_skip_value(const char *s, int off, int *lenp); 11653913Sarchie 11753913Sarchie/* Poor man's virtual method calls */ 11853913Sarchie#define METHOD(t,m) (ng_get_ ## m ## _method(t)) 11953913Sarchie#define INVOKE(t,m) (*METHOD(t,m)) 12053913Sarchie 12153913Sarchiestatic ng_parse_t *ng_get_parse_method(const struct ng_parse_type *t); 12253913Sarchiestatic ng_unparse_t *ng_get_unparse_method(const struct ng_parse_type *t); 12353913Sarchiestatic ng_getDefault_t *ng_get_getDefault_method(const 12453913Sarchie struct ng_parse_type *t); 12553913Sarchiestatic ng_getAlign_t *ng_get_getAlign_method(const struct ng_parse_type *t); 12653913Sarchie 12753913Sarchie#define ALIGNMENT(t) (METHOD(t, getAlign) == NULL ? \ 12853913Sarchie 0 : INVOKE(t, getAlign)(t)) 12953913Sarchie 13053913Sarchie/* For converting binary to string */ 13153913Sarchie#define NG_PARSE_APPEND(fmt, args...) \ 13253913Sarchie do { \ 13353913Sarchie int len; \ 13453913Sarchie \ 13553913Sarchie len = snprintf((cbuf), (cbuflen), \ 13653913Sarchie fmt , ## args); \ 13753913Sarchie if (len >= (cbuflen)) \ 13853913Sarchie return (ERANGE); \ 13953913Sarchie (cbuf) += len; \ 14053913Sarchie (cbuflen) -= len; \ 14153913Sarchie } while (0) 14253913Sarchie 14353913Sarchie/************************************************************************ 14453913Sarchie PUBLIC FUNCTIONS 14553913Sarchie ************************************************************************/ 14653913Sarchie 14753913Sarchie/* 14853913Sarchie * Convert an ASCII string to binary according to the supplied type descriptor 14953913Sarchie */ 15053913Sarchieint 15153913Sarchieng_parse(const struct ng_parse_type *type, 15253913Sarchie const char *string, int *off, u_char *buf, int *buflen) 15353913Sarchie{ 15453913Sarchie return INVOKE(type, parse)(type, string, off, buf, buf, buflen); 15553913Sarchie} 15653913Sarchie 15753913Sarchie/* 15853913Sarchie * Convert binary to an ASCII string according to the supplied type descriptor 15953913Sarchie */ 16053913Sarchieint 16153913Sarchieng_unparse(const struct ng_parse_type *type, 16253913Sarchie const u_char *data, char *cbuf, int cbuflen) 16353913Sarchie{ 16453913Sarchie int off = 0; 16553913Sarchie 16653913Sarchie return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen); 16753913Sarchie} 16853913Sarchie 16953913Sarchie/* 17053913Sarchie * Fill in the default value according to the supplied type descriptor 17153913Sarchie */ 17253913Sarchieint 17353913Sarchieng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen) 17453913Sarchie{ 17553913Sarchie ng_getDefault_t *const func = METHOD(type, getDefault); 17653913Sarchie 17753913Sarchie if (func == NULL) 17853913Sarchie return (EOPNOTSUPP); 17953913Sarchie return (*func)(type, buf, buf, buflen); 18053913Sarchie} 18153913Sarchie 18253913Sarchie 18353913Sarchie/************************************************************************ 18453913Sarchie STRUCTURE TYPE 18553913Sarchie ************************************************************************/ 18653913Sarchie 18753913Sarchiestatic int 18853913Sarchieng_struct_parse(const struct ng_parse_type *type, 18953913Sarchie const char *s, int *off, const u_char *const start, 19053913Sarchie u_char *const buf, int *buflen) 19153913Sarchie{ 19253913Sarchie return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT); 19353913Sarchie} 19453913Sarchie 19553913Sarchiestatic int 19653913Sarchieng_struct_unparse(const struct ng_parse_type *type, 19753913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 19853913Sarchie{ 19953913Sarchie return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT); 20053913Sarchie} 20153913Sarchie 20253913Sarchiestatic int 20353913Sarchieng_struct_getDefault(const struct ng_parse_type *type, 20453913Sarchie const u_char *const start, u_char *buf, int *buflen) 20553913Sarchie{ 20653913Sarchie int off = 0; 20753913Sarchie 20853913Sarchie return ng_parse_composite(type, 20953913Sarchie "{}", &off, start, buf, buflen, CT_STRUCT); 21053913Sarchie} 21153913Sarchie 21253913Sarchiestatic int 21353913Sarchieng_struct_getAlign(const struct ng_parse_type *type) 21453913Sarchie{ 21553913Sarchie const struct ng_parse_struct_info *si = type->info; 21653913Sarchie const struct ng_parse_struct_field *field; 21753913Sarchie int align = 0; 21853913Sarchie 21953913Sarchie for (field = si->fields; field->name != NULL; field++) { 22053913Sarchie int falign = ALIGNMENT(field->type); 22153913Sarchie 22253913Sarchie if (falign > align) 22353913Sarchie align = falign; 22453913Sarchie } 22553913Sarchie return align; 22653913Sarchie} 22753913Sarchie 22853913Sarchieconst struct ng_parse_type ng_parse_struct_type = { 22953913Sarchie NULL, 23053913Sarchie NULL, 23153913Sarchie NULL, 23253913Sarchie ng_struct_parse, 23353913Sarchie ng_struct_unparse, 23453913Sarchie ng_struct_getDefault, 23553913Sarchie ng_struct_getAlign 23653913Sarchie}; 23753913Sarchie 23853913Sarchie/************************************************************************ 23953913Sarchie FIXED LENGTH ARRAY TYPE 24053913Sarchie ************************************************************************/ 24153913Sarchie 24253913Sarchiestatic int 24353913Sarchieng_fixedarray_parse(const struct ng_parse_type *type, 24453913Sarchie const char *s, int *off, const u_char *const start, 24553913Sarchie u_char *const buf, int *buflen) 24653913Sarchie{ 24753913Sarchie return ng_parse_composite(type, 24853913Sarchie s, off, start, buf, buflen, CT_FIXEDARRAY); 24953913Sarchie} 25053913Sarchie 25153913Sarchiestatic int 25253913Sarchieng_fixedarray_unparse(const struct ng_parse_type *type, 25353913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 25453913Sarchie{ 25553913Sarchie return ng_unparse_composite(type, 25653913Sarchie data, off, cbuf, cbuflen, CT_FIXEDARRAY); 25753913Sarchie} 25853913Sarchie 25953913Sarchiestatic int 26053913Sarchieng_fixedarray_getDefault(const struct ng_parse_type *type, 26153913Sarchie const u_char *const start, u_char *buf, int *buflen) 26253913Sarchie{ 26353913Sarchie int off = 0; 26453913Sarchie 26553913Sarchie return ng_parse_composite(type, 26653913Sarchie "[]", &off, start, buf, buflen, CT_FIXEDARRAY); 26753913Sarchie} 26853913Sarchie 26953913Sarchiestatic int 27053913Sarchieng_fixedarray_getAlign(const struct ng_parse_type *type) 27153913Sarchie{ 27253913Sarchie const struct ng_parse_fixedarray_info *fi = type->info; 27353913Sarchie 27453913Sarchie return ALIGNMENT(fi->elementType); 27553913Sarchie} 27653913Sarchie 27753913Sarchieconst struct ng_parse_type ng_parse_fixedarray_type = { 27853913Sarchie NULL, 27953913Sarchie NULL, 28053913Sarchie NULL, 28153913Sarchie ng_fixedarray_parse, 28253913Sarchie ng_fixedarray_unparse, 28353913Sarchie ng_fixedarray_getDefault, 28453913Sarchie ng_fixedarray_getAlign 28553913Sarchie}; 28653913Sarchie 28753913Sarchie/************************************************************************ 28853913Sarchie VARIABLE LENGTH ARRAY TYPE 28953913Sarchie ************************************************************************/ 29053913Sarchie 29153913Sarchiestatic int 29253913Sarchieng_array_parse(const struct ng_parse_type *type, 29353913Sarchie const char *s, int *off, const u_char *const start, 29453913Sarchie u_char *const buf, int *buflen) 29553913Sarchie{ 29653913Sarchie return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY); 29753913Sarchie} 29853913Sarchie 29953913Sarchiestatic int 30053913Sarchieng_array_unparse(const struct ng_parse_type *type, 30153913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 30253913Sarchie{ 30353913Sarchie return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY); 30453913Sarchie} 30553913Sarchie 30653913Sarchiestatic int 30753913Sarchieng_array_getDefault(const struct ng_parse_type *type, 30853913Sarchie const u_char *const start, u_char *buf, int *buflen) 30953913Sarchie{ 31053913Sarchie int off = 0; 31153913Sarchie 31253913Sarchie return ng_parse_composite(type, 31353913Sarchie "[]", &off, start, buf, buflen, CT_ARRAY); 31453913Sarchie} 31553913Sarchie 31653913Sarchiestatic int 31753913Sarchieng_array_getAlign(const struct ng_parse_type *type) 31853913Sarchie{ 31953913Sarchie const struct ng_parse_array_info *ai = type->info; 32053913Sarchie 32153913Sarchie return ALIGNMENT(ai->elementType); 32253913Sarchie} 32353913Sarchie 32453913Sarchieconst struct ng_parse_type ng_parse_array_type = { 32553913Sarchie NULL, 32653913Sarchie NULL, 32753913Sarchie NULL, 32853913Sarchie ng_array_parse, 32953913Sarchie ng_array_unparse, 33053913Sarchie ng_array_getDefault, 33153913Sarchie ng_array_getAlign 33253913Sarchie}; 33353913Sarchie 33453913Sarchie/************************************************************************ 33553913Sarchie INT8 TYPE 33653913Sarchie ************************************************************************/ 33753913Sarchie 33853913Sarchiestatic int 33953913Sarchieng_int8_parse(const struct ng_parse_type *type, 34053913Sarchie const char *s, int *off, const u_char *const start, 34153913Sarchie u_char *const buf, int *buflen) 34253913Sarchie{ 34353913Sarchie long val; 34453913Sarchie int8_t val8; 34553913Sarchie char *eptr; 34653913Sarchie 34753913Sarchie val = strtol(s + *off, &eptr, 0); 34876860Sjdp if (val < (int8_t)0x80 || val > (u_int8_t)0xff || eptr == s + *off) 34953913Sarchie return (EINVAL); 35053913Sarchie *off = eptr - s; 35153913Sarchie val8 = (int8_t)val; 35253913Sarchie bcopy(&val8, buf, sizeof(int8_t)); 35353913Sarchie *buflen = sizeof(int8_t); 35453913Sarchie return (0); 35553913Sarchie} 35653913Sarchie 35753913Sarchiestatic int 35853913Sarchieng_int8_unparse(const struct ng_parse_type *type, 35953913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 36053913Sarchie{ 36164505Sarchie const char *fmt; 36264505Sarchie int fval; 36353913Sarchie int8_t val; 36453913Sarchie 36553913Sarchie bcopy(data + *off, &val, sizeof(int8_t)); 36664505Sarchie switch ((int)type->info) { 36764505Sarchie case INT_SIGNED: 36864505Sarchie fmt = "%d"; 36964505Sarchie fval = val; 37064505Sarchie break; 37164505Sarchie case INT_UNSIGNED: 37264505Sarchie fmt = "%u"; 37364505Sarchie fval = (u_int8_t)val; 37464505Sarchie break; 37564505Sarchie case INT_HEX: 37664505Sarchie fmt = "0x%x"; 37764505Sarchie fval = (u_int8_t)val; 37864505Sarchie break; 37964505Sarchie default: 38087599Sobrien panic("%s: unknown type", __func__); 38183366Sjulian#ifdef RESTARTABLE_PANICS 38283366Sjulian return(0); 38383366Sjulian#endif 38464505Sarchie } 38564505Sarchie NG_PARSE_APPEND(fmt, fval); 38653913Sarchie *off += sizeof(int8_t); 38753913Sarchie return (0); 38853913Sarchie} 38953913Sarchie 39053913Sarchiestatic int 39153913Sarchieng_int8_getDefault(const struct ng_parse_type *type, 39253913Sarchie const u_char *const start, u_char *buf, int *buflen) 39353913Sarchie{ 39453913Sarchie int8_t val; 39553913Sarchie 39653913Sarchie if (*buflen < sizeof(int8_t)) 39753913Sarchie return (ERANGE); 39853913Sarchie val = 0; 39953913Sarchie bcopy(&val, buf, sizeof(int8_t)); 40053913Sarchie *buflen = sizeof(int8_t); 40153913Sarchie return (0); 40253913Sarchie} 40353913Sarchie 40453913Sarchiestatic int 40553913Sarchieng_int8_getAlign(const struct ng_parse_type *type) 40653913Sarchie{ 40753913Sarchie return INT8_ALIGNMENT; 40853913Sarchie} 40953913Sarchie 41053913Sarchieconst struct ng_parse_type ng_parse_int8_type = { 41153913Sarchie NULL, 41264505Sarchie (void *)INT_SIGNED, 41353913Sarchie NULL, 41453913Sarchie ng_int8_parse, 41553913Sarchie ng_int8_unparse, 41653913Sarchie ng_int8_getDefault, 41753913Sarchie ng_int8_getAlign 41853913Sarchie}; 41953913Sarchie 42064505Sarchieconst struct ng_parse_type ng_parse_uint8_type = { 42164505Sarchie &ng_parse_int8_type, 42264505Sarchie (void *)INT_UNSIGNED 42364505Sarchie}; 42464505Sarchie 42564505Sarchieconst struct ng_parse_type ng_parse_hint8_type = { 42664505Sarchie &ng_parse_int8_type, 42764505Sarchie (void *)INT_HEX 42864505Sarchie}; 42964505Sarchie 43053913Sarchie/************************************************************************ 43153913Sarchie INT16 TYPE 43253913Sarchie ************************************************************************/ 43353913Sarchie 43453913Sarchiestatic int 43553913Sarchieng_int16_parse(const struct ng_parse_type *type, 43653913Sarchie const char *s, int *off, const u_char *const start, 43753913Sarchie u_char *const buf, int *buflen) 43853913Sarchie{ 43953913Sarchie long val; 44053913Sarchie int16_t val16; 44153913Sarchie char *eptr; 44253913Sarchie 44353913Sarchie val = strtol(s + *off, &eptr, 0); 44476860Sjdp if (val < (int16_t)0x8000 44576860Sjdp || val > (u_int16_t)0xffff || eptr == s + *off) 44653913Sarchie return (EINVAL); 44753913Sarchie *off = eptr - s; 44853913Sarchie val16 = (int16_t)val; 44953913Sarchie bcopy(&val16, buf, sizeof(int16_t)); 45053913Sarchie *buflen = sizeof(int16_t); 45153913Sarchie return (0); 45253913Sarchie} 45353913Sarchie 45453913Sarchiestatic int 45553913Sarchieng_int16_unparse(const struct ng_parse_type *type, 45653913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 45753913Sarchie{ 45864505Sarchie const char *fmt; 45964505Sarchie int fval; 46053913Sarchie int16_t val; 46153913Sarchie 46253913Sarchie bcopy(data + *off, &val, sizeof(int16_t)); 46364505Sarchie switch ((int)type->info) { 46464505Sarchie case INT_SIGNED: 46564505Sarchie fmt = "%d"; 46664505Sarchie fval = val; 46764505Sarchie break; 46864505Sarchie case INT_UNSIGNED: 46964505Sarchie fmt = "%u"; 47064505Sarchie fval = (u_int16_t)val; 47164505Sarchie break; 47264505Sarchie case INT_HEX: 47364505Sarchie fmt = "0x%x"; 47464505Sarchie fval = (u_int16_t)val; 47564505Sarchie break; 47664505Sarchie default: 47787599Sobrien panic("%s: unknown type", __func__); 47883366Sjulian#ifdef RESTARTABLE_PANICS 47983366Sjulian return(0); 48083366Sjulian#endif 48164505Sarchie } 48264505Sarchie NG_PARSE_APPEND(fmt, fval); 48353913Sarchie *off += sizeof(int16_t); 48453913Sarchie return (0); 48553913Sarchie} 48653913Sarchie 48753913Sarchiestatic int 48853913Sarchieng_int16_getDefault(const struct ng_parse_type *type, 48953913Sarchie const u_char *const start, u_char *buf, int *buflen) 49053913Sarchie{ 49153913Sarchie int16_t val; 49253913Sarchie 49353913Sarchie if (*buflen < sizeof(int16_t)) 49453913Sarchie return (ERANGE); 49553913Sarchie val = 0; 49653913Sarchie bcopy(&val, buf, sizeof(int16_t)); 49753913Sarchie *buflen = sizeof(int16_t); 49853913Sarchie return (0); 49953913Sarchie} 50053913Sarchie 50153913Sarchiestatic int 50253913Sarchieng_int16_getAlign(const struct ng_parse_type *type) 50353913Sarchie{ 50453913Sarchie return INT16_ALIGNMENT; 50553913Sarchie} 50653913Sarchie 50753913Sarchieconst struct ng_parse_type ng_parse_int16_type = { 50853913Sarchie NULL, 50964505Sarchie (void *)INT_SIGNED, 51053913Sarchie NULL, 51153913Sarchie ng_int16_parse, 51253913Sarchie ng_int16_unparse, 51353913Sarchie ng_int16_getDefault, 51453913Sarchie ng_int16_getAlign 51553913Sarchie}; 51653913Sarchie 51764505Sarchieconst struct ng_parse_type ng_parse_uint16_type = { 51864505Sarchie &ng_parse_int16_type, 51964505Sarchie (void *)INT_UNSIGNED 52064505Sarchie}; 52164505Sarchie 52264505Sarchieconst struct ng_parse_type ng_parse_hint16_type = { 52364505Sarchie &ng_parse_int16_type, 52464505Sarchie (void *)INT_HEX 52564505Sarchie}; 52664505Sarchie 52753913Sarchie/************************************************************************ 52853913Sarchie INT32 TYPE 52953913Sarchie ************************************************************************/ 53053913Sarchie 53153913Sarchiestatic int 53253913Sarchieng_int32_parse(const struct ng_parse_type *type, 53353913Sarchie const char *s, int *off, const u_char *const start, 53453913Sarchie u_char *const buf, int *buflen) 53553913Sarchie{ 53653913Sarchie long val; /* assumes long is at least 32 bits */ 53753913Sarchie int32_t val32; 53853913Sarchie char *eptr; 53953913Sarchie 54053913Sarchie val = strtol(s + *off, &eptr, 0); 54176860Sjdp if (val < (int32_t)0x80000000 54276860Sjdp || val > (u_int32_t)0xffffffff || eptr == s + *off) 54353913Sarchie return (EINVAL); 54453913Sarchie *off = eptr - s; 54553913Sarchie val32 = (int32_t)val; 54653913Sarchie bcopy(&val32, buf, sizeof(int32_t)); 54753913Sarchie *buflen = sizeof(int32_t); 54853913Sarchie return (0); 54953913Sarchie} 55053913Sarchie 55153913Sarchiestatic int 55253913Sarchieng_int32_unparse(const struct ng_parse_type *type, 55353913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 55453913Sarchie{ 55564505Sarchie const char *fmt; 55664505Sarchie long fval; 55753913Sarchie int32_t val; 55853913Sarchie 55953913Sarchie bcopy(data + *off, &val, sizeof(int32_t)); 56064505Sarchie switch ((int)type->info) { 56164505Sarchie case INT_SIGNED: 56264505Sarchie fmt = "%ld"; 56364505Sarchie fval = val; 56464505Sarchie break; 56564505Sarchie case INT_UNSIGNED: 56664505Sarchie fmt = "%lu"; 56764505Sarchie fval = (u_int32_t)val; 56864505Sarchie break; 56964505Sarchie case INT_HEX: 57064505Sarchie fmt = "0x%lx"; 57164505Sarchie fval = (u_int32_t)val; 57264505Sarchie break; 57364505Sarchie default: 57487599Sobrien panic("%s: unknown type", __func__); 57583366Sjulian#ifdef RESTARTABLE_PANICS 57683366Sjulian return(0); 57783366Sjulian#endif 57864505Sarchie } 57964505Sarchie NG_PARSE_APPEND(fmt, fval); 58053913Sarchie *off += sizeof(int32_t); 58153913Sarchie return (0); 58253913Sarchie} 58353913Sarchie 58453913Sarchiestatic int 58553913Sarchieng_int32_getDefault(const struct ng_parse_type *type, 58653913Sarchie const u_char *const start, u_char *buf, int *buflen) 58753913Sarchie{ 58853913Sarchie int32_t val; 58953913Sarchie 59053913Sarchie if (*buflen < sizeof(int32_t)) 59153913Sarchie return (ERANGE); 59253913Sarchie val = 0; 59353913Sarchie bcopy(&val, buf, sizeof(int32_t)); 59453913Sarchie *buflen = sizeof(int32_t); 59553913Sarchie return (0); 59653913Sarchie} 59753913Sarchie 59853913Sarchiestatic int 59953913Sarchieng_int32_getAlign(const struct ng_parse_type *type) 60053913Sarchie{ 60153913Sarchie return INT32_ALIGNMENT; 60253913Sarchie} 60353913Sarchie 60453913Sarchieconst struct ng_parse_type ng_parse_int32_type = { 60553913Sarchie NULL, 60664505Sarchie (void *)INT_SIGNED, 60753913Sarchie NULL, 60853913Sarchie ng_int32_parse, 60953913Sarchie ng_int32_unparse, 61053913Sarchie ng_int32_getDefault, 61153913Sarchie ng_int32_getAlign 61253913Sarchie}; 61353913Sarchie 61464505Sarchieconst struct ng_parse_type ng_parse_uint32_type = { 61564505Sarchie &ng_parse_int32_type, 61664505Sarchie (void *)INT_UNSIGNED 61764505Sarchie}; 61864505Sarchie 61964505Sarchieconst struct ng_parse_type ng_parse_hint32_type = { 62064505Sarchie &ng_parse_int32_type, 62164505Sarchie (void *)INT_HEX 62264505Sarchie}; 62364505Sarchie 62453913Sarchie/************************************************************************ 62553913Sarchie INT64 TYPE 62653913Sarchie ************************************************************************/ 62753913Sarchie 62853913Sarchiestatic int 62953913Sarchieng_int64_parse(const struct ng_parse_type *type, 63053913Sarchie const char *s, int *off, const u_char *const start, 63153913Sarchie u_char *const buf, int *buflen) 63253913Sarchie{ 63353913Sarchie quad_t val; 63453913Sarchie int64_t val64; 63553913Sarchie char *eptr; 63653913Sarchie 63753913Sarchie val = strtoq(s + *off, &eptr, 0); 63853913Sarchie if (eptr == s + *off) 63953913Sarchie return (EINVAL); 64053913Sarchie *off = eptr - s; 64153913Sarchie val64 = (int64_t)val; 64253913Sarchie bcopy(&val64, buf, sizeof(int64_t)); 64353913Sarchie *buflen = sizeof(int64_t); 64453913Sarchie return (0); 64553913Sarchie} 64653913Sarchie 64753913Sarchiestatic int 64853913Sarchieng_int64_unparse(const struct ng_parse_type *type, 64953913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 65053913Sarchie{ 65164505Sarchie const char *fmt; 65264505Sarchie long long fval; 65353913Sarchie int64_t val; 65453913Sarchie 65553913Sarchie bcopy(data + *off, &val, sizeof(int64_t)); 65664505Sarchie switch ((int)type->info) { 65764505Sarchie case INT_SIGNED: 65864505Sarchie fmt = "%lld"; 65964505Sarchie fval = val; 66064505Sarchie break; 66164505Sarchie case INT_UNSIGNED: 66264505Sarchie fmt = "%llu"; 66364505Sarchie fval = (u_int64_t)val; 66464505Sarchie break; 66564505Sarchie case INT_HEX: 66664505Sarchie fmt = "0x%llx"; 66764505Sarchie fval = (u_int64_t)val; 66864505Sarchie break; 66964505Sarchie default: 67087599Sobrien panic("%s: unknown type", __func__); 67183366Sjulian#ifdef RESTARTABLE_PANICS 67283366Sjulian return(0); 67383366Sjulian#endif 67464505Sarchie } 67564505Sarchie NG_PARSE_APPEND(fmt, fval); 67653913Sarchie *off += sizeof(int64_t); 67753913Sarchie return (0); 67853913Sarchie} 67953913Sarchie 68053913Sarchiestatic int 68153913Sarchieng_int64_getDefault(const struct ng_parse_type *type, 68253913Sarchie const u_char *const start, u_char *buf, int *buflen) 68353913Sarchie{ 68453913Sarchie int64_t val; 68553913Sarchie 68653913Sarchie if (*buflen < sizeof(int64_t)) 68753913Sarchie return (ERANGE); 68853913Sarchie val = 0; 68953913Sarchie bcopy(&val, buf, sizeof(int64_t)); 69053913Sarchie *buflen = sizeof(int64_t); 69153913Sarchie return (0); 69253913Sarchie} 69353913Sarchie 69453913Sarchiestatic int 69553913Sarchieng_int64_getAlign(const struct ng_parse_type *type) 69653913Sarchie{ 69753913Sarchie return INT64_ALIGNMENT; 69853913Sarchie} 69953913Sarchie 70053913Sarchieconst struct ng_parse_type ng_parse_int64_type = { 70153913Sarchie NULL, 70264505Sarchie (void *)INT_SIGNED, 70353913Sarchie NULL, 70453913Sarchie ng_int64_parse, 70553913Sarchie ng_int64_unparse, 70653913Sarchie ng_int64_getDefault, 70753913Sarchie ng_int64_getAlign 70853913Sarchie}; 70953913Sarchie 71064505Sarchieconst struct ng_parse_type ng_parse_uint64_type = { 71164505Sarchie &ng_parse_int64_type, 71264505Sarchie (void *)INT_UNSIGNED 71364505Sarchie}; 71464505Sarchie 71564505Sarchieconst struct ng_parse_type ng_parse_hint64_type = { 71664505Sarchie &ng_parse_int64_type, 71764505Sarchie (void *)INT_HEX 71864505Sarchie}; 71964505Sarchie 72053913Sarchie/************************************************************************ 72153913Sarchie STRING TYPE 72253913Sarchie ************************************************************************/ 72353913Sarchie 72453913Sarchiestatic int 72553913Sarchieng_string_parse(const struct ng_parse_type *type, 72653913Sarchie const char *s, int *off, const u_char *const start, 72753913Sarchie u_char *const buf, int *buflen) 72853913Sarchie{ 72953913Sarchie char *sval; 73053913Sarchie int len; 73168845Sbrian int slen; 73253913Sarchie 73368845Sbrian if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL) 73453913Sarchie return (EINVAL); 73553913Sarchie *off += len; 73668845Sbrian bcopy(sval, buf, slen + 1); 73770870Sjulian FREE(sval, M_NETGRAPH_PARSE); 73868845Sbrian *buflen = slen + 1; 73953913Sarchie return (0); 74053913Sarchie} 74153913Sarchie 74253913Sarchiestatic int 74353913Sarchieng_string_unparse(const struct ng_parse_type *type, 74453913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 74553913Sarchie{ 74653913Sarchie const char *const raw = (const char *)data + *off; 74768845Sbrian char *const s = ng_encode_string(raw, strlen(raw)); 74853913Sarchie 74953913Sarchie if (s == NULL) 75053913Sarchie return (ENOMEM); 75153913Sarchie NG_PARSE_APPEND("%s", s); 75253913Sarchie *off += strlen(raw) + 1; 75370870Sjulian FREE(s, M_NETGRAPH_PARSE); 75453913Sarchie return (0); 75553913Sarchie} 75653913Sarchie 75753913Sarchiestatic int 75853913Sarchieng_string_getDefault(const struct ng_parse_type *type, 75953913Sarchie const u_char *const start, u_char *buf, int *buflen) 76053913Sarchie{ 76153913Sarchie 76253913Sarchie if (*buflen < 1) 76353913Sarchie return (ERANGE); 76453913Sarchie buf[0] = (u_char)'\0'; 76553913Sarchie *buflen = 1; 76653913Sarchie return (0); 76753913Sarchie} 76853913Sarchie 76953913Sarchieconst struct ng_parse_type ng_parse_string_type = { 77053913Sarchie NULL, 77153913Sarchie NULL, 77253913Sarchie NULL, 77353913Sarchie ng_string_parse, 77453913Sarchie ng_string_unparse, 77553913Sarchie ng_string_getDefault, 77653913Sarchie NULL 77753913Sarchie}; 77853913Sarchie 77953913Sarchie/************************************************************************ 78053913Sarchie FIXED BUFFER STRING TYPE 78153913Sarchie ************************************************************************/ 78253913Sarchie 78353913Sarchiestatic int 78453913Sarchieng_fixedstring_parse(const struct ng_parse_type *type, 78553913Sarchie const char *s, int *off, const u_char *const start, 78653913Sarchie u_char *const buf, int *buflen) 78753913Sarchie{ 78858011Sarchie const struct ng_parse_fixedstring_info *const fi = type->info; 78953913Sarchie char *sval; 79053913Sarchie int len; 79168845Sbrian int slen; 79253913Sarchie 79368845Sbrian if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL) 79453913Sarchie return (EINVAL); 79568845Sbrian if (slen + 1 > fi->bufSize) 79653913Sarchie return (E2BIG); 79753913Sarchie *off += len; 79868845Sbrian bcopy(sval, buf, slen); 79970870Sjulian FREE(sval, M_NETGRAPH_PARSE); 80068845Sbrian bzero(buf + slen, fi->bufSize - slen); 80153913Sarchie *buflen = fi->bufSize; 80253913Sarchie return (0); 80353913Sarchie} 80453913Sarchie 80553913Sarchiestatic int 80653913Sarchieng_fixedstring_unparse(const struct ng_parse_type *type, 80753913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 80853913Sarchie{ 80958011Sarchie const struct ng_parse_fixedstring_info *const fi = type->info; 81053913Sarchie int error, temp = *off; 81153913Sarchie 81253913Sarchie if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0) 81353913Sarchie return (error); 81453913Sarchie *off += fi->bufSize; 81553913Sarchie return (0); 81653913Sarchie} 81753913Sarchie 81853913Sarchiestatic int 81953913Sarchieng_fixedstring_getDefault(const struct ng_parse_type *type, 82053913Sarchie const u_char *const start, u_char *buf, int *buflen) 82153913Sarchie{ 82258011Sarchie const struct ng_parse_fixedstring_info *const fi = type->info; 82353913Sarchie 82453913Sarchie if (*buflen < fi->bufSize) 82553913Sarchie return (ERANGE); 82653913Sarchie bzero(buf, fi->bufSize); 82753913Sarchie *buflen = fi->bufSize; 82853913Sarchie return (0); 82953913Sarchie} 83053913Sarchie 83153913Sarchieconst struct ng_parse_type ng_parse_fixedstring_type = { 83253913Sarchie NULL, 83353913Sarchie NULL, 83453913Sarchie NULL, 83553913Sarchie ng_fixedstring_parse, 83653913Sarchie ng_fixedstring_unparse, 83753913Sarchie ng_fixedstring_getDefault, 83853913Sarchie NULL 83953913Sarchie}; 84053913Sarchie 84158011Sarchieconst struct ng_parse_fixedstring_info ng_parse_nodebuf_info = { 84253913Sarchie NG_NODELEN + 1 84353913Sarchie}; 84453913Sarchieconst struct ng_parse_type ng_parse_nodebuf_type = { 84553913Sarchie &ng_parse_fixedstring_type, 84653913Sarchie &ng_parse_nodebuf_info 84753913Sarchie}; 84853913Sarchie 84958011Sarchieconst struct ng_parse_fixedstring_info ng_parse_hookbuf_info = { 85053913Sarchie NG_HOOKLEN + 1 85153913Sarchie}; 85253913Sarchieconst struct ng_parse_type ng_parse_hookbuf_type = { 85353913Sarchie &ng_parse_fixedstring_type, 85453913Sarchie &ng_parse_hookbuf_info 85553913Sarchie}; 85653913Sarchie 85758011Sarchieconst struct ng_parse_fixedstring_info ng_parse_pathbuf_info = { 85853913Sarchie NG_PATHLEN + 1 85953913Sarchie}; 86053913Sarchieconst struct ng_parse_type ng_parse_pathbuf_type = { 86153913Sarchie &ng_parse_fixedstring_type, 86253913Sarchie &ng_parse_pathbuf_info 86353913Sarchie}; 86453913Sarchie 86558011Sarchieconst struct ng_parse_fixedstring_info ng_parse_typebuf_info = { 86653913Sarchie NG_TYPELEN + 1 86753913Sarchie}; 86853913Sarchieconst struct ng_parse_type ng_parse_typebuf_type = { 86953913Sarchie &ng_parse_fixedstring_type, 87053913Sarchie &ng_parse_typebuf_info 87153913Sarchie}; 87253913Sarchie 87358011Sarchieconst struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = { 87453913Sarchie NG_CMDSTRLEN + 1 87553913Sarchie}; 87653913Sarchieconst struct ng_parse_type ng_parse_cmdbuf_type = { 87753913Sarchie &ng_parse_fixedstring_type, 87853913Sarchie &ng_parse_cmdbuf_info 87953913Sarchie}; 88053913Sarchie 88153913Sarchie/************************************************************************ 88268845Sbrian EXPLICITLY SIZED STRING TYPE 88368845Sbrian ************************************************************************/ 88468845Sbrian 88568845Sbrianstatic int 88668845Sbrianng_sizedstring_parse(const struct ng_parse_type *type, 88768845Sbrian const char *s, int *off, const u_char *const start, 88868845Sbrian u_char *const buf, int *buflen) 88968845Sbrian{ 89068845Sbrian char *sval; 89168845Sbrian int len; 89268845Sbrian int slen; 89368845Sbrian 89468845Sbrian if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL) 89568845Sbrian return (EINVAL); 89668845Sbrian if (slen > 0xffff) 89768845Sbrian return (EINVAL); 89868845Sbrian *off += len; 89968845Sbrian *((u_int16_t *)buf) = (u_int16_t)slen; 90068845Sbrian bcopy(sval, buf + 2, slen); 90170870Sjulian FREE(sval, M_NETGRAPH_PARSE); 90268845Sbrian *buflen = 2 + slen; 90368845Sbrian return (0); 90468845Sbrian} 90568845Sbrian 90668845Sbrianstatic int 90768845Sbrianng_sizedstring_unparse(const struct ng_parse_type *type, 90868845Sbrian const u_char *data, int *off, char *cbuf, int cbuflen) 90968845Sbrian{ 91068845Sbrian const char *const raw = (const char *)data + *off + 2; 91168845Sbrian const int slen = *((const u_int16_t *)(data + *off)); 91268845Sbrian char *const s = ng_encode_string(raw, slen); 91368845Sbrian 91468845Sbrian if (s == NULL) 91568845Sbrian return (ENOMEM); 91668845Sbrian NG_PARSE_APPEND("%s", s); 91770870Sjulian FREE(s, M_NETGRAPH_PARSE); 91868845Sbrian *off += slen + 2; 91968845Sbrian return (0); 92068845Sbrian} 92168845Sbrian 92268845Sbrianstatic int 92368845Sbrianng_sizedstring_getDefault(const struct ng_parse_type *type, 92468845Sbrian const u_char *const start, u_char *buf, int *buflen) 92568845Sbrian{ 92668845Sbrian if (*buflen < 2) 92768845Sbrian return (ERANGE); 92868845Sbrian bzero(buf, 2); 92968845Sbrian *buflen = 2; 93068845Sbrian return (0); 93168845Sbrian} 93268845Sbrian 93368845Sbrianconst struct ng_parse_type ng_parse_sizedstring_type = { 93468845Sbrian NULL, 93568845Sbrian NULL, 93668845Sbrian NULL, 93768845Sbrian ng_sizedstring_parse, 93868845Sbrian ng_sizedstring_unparse, 93968845Sbrian ng_sizedstring_getDefault, 94068845Sbrian NULL 94168845Sbrian}; 94268845Sbrian 94368845Sbrian/************************************************************************ 94453913Sarchie IP ADDRESS TYPE 94553913Sarchie ************************************************************************/ 94653913Sarchie 94753913Sarchiestatic int 94853913Sarchieng_ipaddr_parse(const struct ng_parse_type *type, 94953913Sarchie const char *s, int *off, const u_char *const start, 95053913Sarchie u_char *const buf, int *buflen) 95153913Sarchie{ 95253913Sarchie int i, error; 95353913Sarchie 95453913Sarchie for (i = 0; i < 4; i++) { 95553913Sarchie if ((error = ng_int8_parse(&ng_parse_int8_type, 95653913Sarchie s, off, start, buf + i, buflen)) != 0) 95753913Sarchie return (error); 95853913Sarchie if (i < 3 && s[*off] != '.') 95953913Sarchie return (EINVAL); 96053913Sarchie (*off)++; 96153913Sarchie } 96253913Sarchie *buflen = 4; 96353913Sarchie return (0); 96453913Sarchie} 96553913Sarchie 96653913Sarchiestatic int 96753913Sarchieng_ipaddr_unparse(const struct ng_parse_type *type, 96853913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 96953913Sarchie{ 97053913Sarchie struct in_addr ip; 97153913Sarchie 97253913Sarchie bcopy(data + *off, &ip, sizeof(ip)); 97353913Sarchie NG_PARSE_APPEND("%d.%d.%d.%d", ((u_char *)&ip)[0], 97453913Sarchie ((u_char *)&ip)[1], ((u_char *)&ip)[2], ((u_char *)&ip)[3]); 97553913Sarchie *off += sizeof(ip); 97653913Sarchie return (0); 97753913Sarchie} 97853913Sarchie 97953913Sarchiestatic int 98053913Sarchieng_ipaddr_getDefault(const struct ng_parse_type *type, 98153913Sarchie const u_char *const start, u_char *buf, int *buflen) 98253913Sarchie{ 98353913Sarchie struct in_addr ip = { 0 }; 98453913Sarchie 98553913Sarchie if (*buflen < sizeof(ip)) 98653913Sarchie return (ERANGE); 98753913Sarchie bcopy(&ip, buf, sizeof(ip)); 98853913Sarchie *buflen = sizeof(ip); 98953913Sarchie return (0); 99053913Sarchie} 99153913Sarchie 99253913Sarchieconst struct ng_parse_type ng_parse_ipaddr_type = { 99353913Sarchie NULL, 99453913Sarchie NULL, 99553913Sarchie NULL, 99653913Sarchie ng_ipaddr_parse, 99753913Sarchie ng_ipaddr_unparse, 99853913Sarchie ng_ipaddr_getDefault, 99953913Sarchie ng_int32_getAlign 100053913Sarchie}; 100153913Sarchie 100253913Sarchie/************************************************************************ 100353913Sarchie BYTE ARRAY TYPE 100453913Sarchie ************************************************************************/ 100553913Sarchie 100653913Sarchie/* Get the length of a byte array */ 100753913Sarchiestatic int 100853913Sarchieng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type, 100953913Sarchie const u_char *start, const u_char *buf) 101053913Sarchie{ 101153913Sarchie ng_parse_array_getLength_t *const getLength = type->private; 101253913Sarchie 101353913Sarchie return (*getLength)(type, start, buf); 101453913Sarchie} 101553913Sarchie 101664505Sarchie/* Byte array element type is hex int8 */ 101753913Sarchiestatic const struct ng_parse_array_info ng_parse_bytearray_subtype_info = { 101864505Sarchie &ng_parse_hint8_type, 101953913Sarchie &ng_parse_bytearray_subtype_getLength, 102053913Sarchie NULL 102153913Sarchie}; 102253913Sarchiestatic const struct ng_parse_type ng_parse_bytearray_subtype = { 102353913Sarchie &ng_parse_array_type, 102453913Sarchie &ng_parse_bytearray_subtype_info 102553913Sarchie}; 102653913Sarchie 102753913Sarchiestatic int 102853913Sarchieng_bytearray_parse(const struct ng_parse_type *type, 102953913Sarchie const char *s, int *off, const u_char *const start, 103053913Sarchie u_char *const buf, int *buflen) 103153913Sarchie{ 103253913Sarchie char *str; 103353913Sarchie int toklen; 103468845Sbrian int slen; 103553913Sarchie 103653913Sarchie /* We accept either an array of bytes or a string constant */ 103768845Sbrian if ((str = ng_get_string_token(s, off, &toklen, &slen)) != NULL) { 103853913Sarchie ng_parse_array_getLength_t *const getLength = type->info; 103968845Sbrian int arraylen; 104053913Sarchie 104153913Sarchie arraylen = (*getLength)(type, start, buf); 104253913Sarchie if (arraylen > *buflen) { 104370870Sjulian FREE(str, M_NETGRAPH_PARSE); 104453913Sarchie return (ERANGE); 104553913Sarchie } 104653913Sarchie if (slen > arraylen) { 104770870Sjulian FREE(str, M_NETGRAPH_PARSE); 104853913Sarchie return (E2BIG); 104953913Sarchie } 105053913Sarchie bcopy(str, buf, slen); 105153913Sarchie bzero(buf + slen, arraylen - slen); 105270870Sjulian FREE(str, M_NETGRAPH_PARSE); 105353913Sarchie *off += toklen; 105453913Sarchie *buflen = arraylen; 105553913Sarchie return (0); 105653913Sarchie } else { 105753913Sarchie struct ng_parse_type subtype; 105853913Sarchie 105953913Sarchie subtype = ng_parse_bytearray_subtype; 106053913Sarchie (const void *)subtype.private = type->info; 106153913Sarchie return ng_array_parse(&subtype, s, off, start, buf, buflen); 106253913Sarchie } 106353913Sarchie} 106453913Sarchie 106553913Sarchiestatic int 106653913Sarchieng_bytearray_unparse(const struct ng_parse_type *type, 106753913Sarchie const u_char *data, int *off, char *cbuf, int cbuflen) 106853913Sarchie{ 106953913Sarchie struct ng_parse_type subtype; 107053913Sarchie 107153913Sarchie subtype = ng_parse_bytearray_subtype; 107253913Sarchie (const void *)subtype.private = type->info; 107353913Sarchie return ng_array_unparse(&subtype, data, off, cbuf, cbuflen); 107453913Sarchie} 107553913Sarchie 107653913Sarchiestatic int 107753913Sarchieng_bytearray_getDefault(const struct ng_parse_type *type, 107853913Sarchie const u_char *const start, u_char *buf, int *buflen) 107953913Sarchie{ 108053913Sarchie struct ng_parse_type subtype; 108153913Sarchie 108253913Sarchie subtype = ng_parse_bytearray_subtype; 108353913Sarchie (const void *)subtype.private = type->info; 108453913Sarchie return ng_array_getDefault(&subtype, start, buf, buflen); 108553913Sarchie} 108653913Sarchie 108753913Sarchieconst struct ng_parse_type ng_parse_bytearray_type = { 108853913Sarchie NULL, 108953913Sarchie NULL, 109053913Sarchie NULL, 109153913Sarchie ng_bytearray_parse, 109253913Sarchie ng_bytearray_unparse, 109353913Sarchie ng_bytearray_getDefault, 109453913Sarchie NULL 109553913Sarchie}; 109653913Sarchie 109753913Sarchie/************************************************************************ 109853913Sarchie STRUCT NG_MESG TYPE 109953913Sarchie ************************************************************************/ 110053913Sarchie 110153913Sarchie/* Get msg->header.arglen when "buf" is pointing to msg->data */ 110253913Sarchiestatic int 110353913Sarchieng_parse_ng_mesg_getLength(const struct ng_parse_type *type, 110453913Sarchie const u_char *start, const u_char *buf) 110553913Sarchie{ 110653913Sarchie const struct ng_mesg *msg; 110753913Sarchie 110853913Sarchie msg = (const struct ng_mesg *)(buf - sizeof(*msg)); 110953913Sarchie return msg->header.arglen; 111053913Sarchie} 111153913Sarchie 111253913Sarchie/* Type for the variable length data portion of a struct ng_mesg */ 111353913Sarchiestatic const struct ng_parse_type ng_msg_data_type = { 111453913Sarchie &ng_parse_bytearray_type, 111553913Sarchie &ng_parse_ng_mesg_getLength 111653913Sarchie}; 111753913Sarchie 111853913Sarchie/* Type for the entire struct ng_mesg header with data section */ 111953913Sarchiestatic const struct ng_parse_struct_info 112053913Sarchie ng_parse_ng_mesg_type_info = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type); 112153913Sarchieconst struct ng_parse_type ng_parse_ng_mesg_type = { 112253913Sarchie &ng_parse_struct_type, 112353913Sarchie &ng_parse_ng_mesg_type_info, 112453913Sarchie}; 112553913Sarchie 112653913Sarchie/************************************************************************ 112753913Sarchie COMPOSITE HELPER ROUTINES 112853913Sarchie ************************************************************************/ 112953913Sarchie 113053913Sarchie/* 113153913Sarchie * Convert a structure or array from ASCII to binary 113253913Sarchie */ 113353913Sarchiestatic int 113453913Sarchieng_parse_composite(const struct ng_parse_type *type, const char *s, 113553913Sarchie int *off, const u_char *const start, u_char *const buf, int *buflen, 113653913Sarchie const enum comptype ctype) 113753913Sarchie{ 113853913Sarchie const int num = ng_get_composite_len(type, start, buf, ctype); 113953913Sarchie int nextIndex = 0; /* next implicit array index */ 114053913Sarchie u_int index; /* field or element index */ 114153913Sarchie int *foff; /* field value offsets in string */ 114253913Sarchie int align, len, blen, error = 0; 114353913Sarchie 114453913Sarchie /* Initialize */ 114570870Sjulian MALLOC(foff, int *, num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO); 114653913Sarchie if (foff == NULL) { 114753913Sarchie error = ENOMEM; 114853913Sarchie goto done; 114953913Sarchie } 115053913Sarchie 115153913Sarchie /* Get opening brace/bracket */ 115253913Sarchie if (ng_parse_get_token(s, off, &len) 115353913Sarchie != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) { 115453913Sarchie error = EINVAL; 115553913Sarchie goto done; 115653913Sarchie } 115753913Sarchie *off += len; 115853913Sarchie 115953913Sarchie /* Get individual element value positions in the string */ 116053913Sarchie for (;;) { 116153913Sarchie enum ng_parse_token tok; 116253913Sarchie 116353913Sarchie /* Check for closing brace/bracket */ 116453913Sarchie tok = ng_parse_get_token(s, off, &len); 116553913Sarchie if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) { 116653913Sarchie *off += len; 116753913Sarchie break; 116853913Sarchie } 116953913Sarchie 117053913Sarchie /* For arrays, the 'name' (ie, index) is optional, so 117153913Sarchie distinguish name from values by seeing if the next 117253913Sarchie token is an equals sign */ 117353913Sarchie if (ctype != CT_STRUCT) { 117453913Sarchie int len2, off2; 117553913Sarchie char *eptr; 117653913Sarchie 117753913Sarchie /* If an opening brace/bracket, index is implied */ 117853913Sarchie if (tok == T_LBRACE || tok == T_LBRACKET) { 117953913Sarchie index = nextIndex++; 118053913Sarchie goto gotIndex; 118153913Sarchie } 118253913Sarchie 118353913Sarchie /* Might be an index, might be a value, either way... */ 118453913Sarchie if (tok != T_WORD) { 118553913Sarchie error = EINVAL; 118653913Sarchie goto done; 118753913Sarchie } 118853913Sarchie 118953913Sarchie /* If no equals sign follows, index is implied */ 119053913Sarchie off2 = *off + len; 119153913Sarchie if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) { 119253913Sarchie index = nextIndex++; 119353913Sarchie goto gotIndex; 119453913Sarchie } 119553913Sarchie 119653913Sarchie /* Index was specified explicitly; parse it */ 119753913Sarchie index = (u_int)strtoul(s + *off, &eptr, 0); 119853913Sarchie if (index < 0 || eptr - (s + *off) != len) { 119953913Sarchie error = EINVAL; 120053913Sarchie goto done; 120153913Sarchie } 120253913Sarchie nextIndex = index + 1; 120353913Sarchie *off += len + len2; 120453913SarchiegotIndex: 120553913Sarchie } else { /* a structure field */ 120653913Sarchie const struct ng_parse_struct_field *field = NULL; 120753913Sarchie const struct ng_parse_struct_info *si = type->info; 120853913Sarchie 120953913Sarchie /* Find the field by name (required) in field list */ 121053913Sarchie if (tok != T_WORD) { 121153913Sarchie error = EINVAL; 121253913Sarchie goto done; 121353913Sarchie } 121453913Sarchie for (index = 0; index < num; index++) { 121553913Sarchie field = &si->fields[index]; 121653913Sarchie if (strncmp(&s[*off], field->name, len) == 0 121753913Sarchie && field->name[len] == '\0') 121853913Sarchie break; 121953913Sarchie } 122053913Sarchie if (index == num) { 122153913Sarchie error = ENOENT; 122253913Sarchie goto done; 122353913Sarchie } 122453913Sarchie *off += len; 122553913Sarchie 122653913Sarchie /* Get equals sign */ 122753913Sarchie if (ng_parse_get_token(s, off, &len) != T_EQUALS) { 122853913Sarchie error = EINVAL; 122953913Sarchie goto done; 123053913Sarchie } 123153913Sarchie *off += len; 123253913Sarchie } 123353913Sarchie 123453913Sarchie /* Check array index */ 123553913Sarchie if (index >= num) { 123653913Sarchie error = E2BIG; 123753913Sarchie goto done; 123853913Sarchie } 123953913Sarchie 124053913Sarchie /* Save value's position and skip over it for now */ 124153913Sarchie if (foff[index] != 0) { 124253913Sarchie error = EALREADY; /* duplicate */ 124353913Sarchie goto done; 124453913Sarchie } 124553913Sarchie while (isspace(s[*off])) 124653913Sarchie (*off)++; 124753913Sarchie foff[index] = *off; 124853913Sarchie if ((error = ng_parse_skip_value(s, *off, &len)) != 0) 124953913Sarchie goto done; 125053913Sarchie *off += len; 125153913Sarchie } 125253913Sarchie 125353913Sarchie /* Now build binary structure from supplied values and defaults */ 125453913Sarchie for (blen = index = 0; index < num; index++) { 125553913Sarchie const struct ng_parse_type *const 125653913Sarchie etype = ng_get_composite_etype(type, index, ctype); 125753913Sarchie int k, pad, vlen; 125853913Sarchie 125953913Sarchie /* Zero-pad any alignment bytes */ 126053913Sarchie pad = ng_parse_get_elem_pad(type, index, ctype, blen); 126153913Sarchie for (k = 0; k < pad; k++) { 126253913Sarchie if (blen >= *buflen) { 126353913Sarchie error = ERANGE; 126453913Sarchie goto done; 126553913Sarchie } 126653913Sarchie buf[blen++] = 0; 126753913Sarchie } 126853913Sarchie 126953913Sarchie /* Get value */ 127053913Sarchie vlen = *buflen - blen; 127153913Sarchie if (foff[index] == 0) { /* use default value */ 127253913Sarchie error = ng_get_composite_elem_default(type, index, 127353913Sarchie start, buf + blen, &vlen, ctype); 127453913Sarchie } else { /* parse given value */ 127553913Sarchie *off = foff[index]; 127653913Sarchie error = INVOKE(etype, parse)(etype, 127753913Sarchie s, off, start, buf + blen, &vlen); 127853913Sarchie } 127953913Sarchie if (error != 0) 128053913Sarchie goto done; 128153913Sarchie blen += vlen; 128253913Sarchie } 128353913Sarchie 128453913Sarchie /* Make total composite structure size a multiple of its alignment */ 128553913Sarchie if ((align = ALIGNMENT(type)) != 0) { 128653913Sarchie while (blen % align != 0) { 128753913Sarchie if (blen >= *buflen) { 128853913Sarchie error = ERANGE; 128953913Sarchie goto done; 129053913Sarchie } 129153913Sarchie buf[blen++] = 0; 129253913Sarchie } 129353913Sarchie } 129453913Sarchie 129553913Sarchie /* Done */ 129653913Sarchie *buflen = blen; 129753913Sarchiedone: 129865303Sarchie if (foff != NULL) 129970870Sjulian FREE(foff, M_NETGRAPH_PARSE); 130053913Sarchie return (error); 130153913Sarchie} 130253913Sarchie 130353913Sarchie/* 130453913Sarchie * Convert an array or structure from binary to ASCII 130553913Sarchie */ 130653913Sarchiestatic int 130753913Sarchieng_unparse_composite(const struct ng_parse_type *type, const u_char *data, 130853913Sarchie int *off, char *cbuf, int cbuflen, const enum comptype ctype) 130953913Sarchie{ 131053913Sarchie const int num = ng_get_composite_len(type, data, data + *off, ctype); 131164505Sarchie const int workSize = 20 * 1024; /* XXX hard coded constant */ 131253913Sarchie int nextIndex = 0, didOne = 0; 131353913Sarchie int error, index; 131464505Sarchie u_char *workBuf; 131553913Sarchie 131664505Sarchie /* Get workspace for checking default values */ 131770870Sjulian MALLOC(workBuf, u_char *, workSize, M_NETGRAPH_PARSE, M_NOWAIT); 131864505Sarchie if (workBuf == NULL) 131964505Sarchie return (ENOMEM); 132064505Sarchie 132153913Sarchie /* Opening brace/bracket */ 132253913Sarchie NG_PARSE_APPEND("%c", (ctype == CT_STRUCT) ? '{' : '['); 132353913Sarchie 132453913Sarchie /* Do each item */ 132553913Sarchie for (index = 0; index < num; index++) { 132653913Sarchie const struct ng_parse_type *const 132753913Sarchie etype = ng_get_composite_etype(type, index, ctype); 132853913Sarchie 132953913Sarchie /* Skip any alignment pad bytes */ 133053913Sarchie *off += ng_parse_get_elem_pad(type, index, ctype, *off); 133153913Sarchie 133253913Sarchie /* See if element is equal to its default value; skip if so */ 133364505Sarchie if (*off < workSize) { 133464505Sarchie int tempsize = workSize - *off; 133553913Sarchie 133664505Sarchie bcopy(data, workBuf, *off); 133764505Sarchie if (ng_get_composite_elem_default(type, index, workBuf, 133864505Sarchie workBuf + *off, &tempsize, ctype) == 0 133964505Sarchie && bcmp(workBuf + *off, 134064505Sarchie data + *off, tempsize) == 0) { 134153913Sarchie *off += tempsize; 134253913Sarchie continue; 134353913Sarchie } 134453913Sarchie } 134553913Sarchie 134653913Sarchie /* Print name= */ 134753913Sarchie NG_PARSE_APPEND(" "); 134853913Sarchie if (ctype != CT_STRUCT) { 134953913Sarchie if (index != nextIndex) { 135053913Sarchie nextIndex = index; 135153913Sarchie NG_PARSE_APPEND("%d=", index); 135253913Sarchie } 135353913Sarchie nextIndex++; 135453913Sarchie } else { 135553913Sarchie const struct ng_parse_struct_info *si = type->info; 135653913Sarchie 135753913Sarchie NG_PARSE_APPEND("%s=", si->fields[index].name); 135853913Sarchie } 135953913Sarchie 136053913Sarchie /* Print value */ 136153913Sarchie if ((error = INVOKE(etype, unparse) 136264505Sarchie (etype, data, off, cbuf, cbuflen)) != 0) { 136370870Sjulian FREE(workBuf, M_NETGRAPH_PARSE); 136453913Sarchie return (error); 136564505Sarchie } 136653913Sarchie cbuflen -= strlen(cbuf); 136753913Sarchie cbuf += strlen(cbuf); 136853913Sarchie didOne = 1; 136953913Sarchie } 137070870Sjulian FREE(workBuf, M_NETGRAPH_PARSE); 137153913Sarchie 137253913Sarchie /* Closing brace/bracket */ 137353913Sarchie NG_PARSE_APPEND("%s%c", 137453913Sarchie didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']'); 137553913Sarchie return (0); 137653913Sarchie} 137753913Sarchie 137853913Sarchie/* 137953913Sarchie * Generate the default value for an element of an array or structure 138053913Sarchie * Returns EOPNOTSUPP if default value is unspecified. 138153913Sarchie */ 138253913Sarchiestatic int 138353913Sarchieng_get_composite_elem_default(const struct ng_parse_type *type, 138453913Sarchie int index, const u_char *const start, u_char *buf, int *buflen, 138553913Sarchie const enum comptype ctype) 138653913Sarchie{ 138753913Sarchie const struct ng_parse_type *etype; 138853913Sarchie ng_getDefault_t *func; 138953913Sarchie 139053913Sarchie switch (ctype) { 139153913Sarchie case CT_STRUCT: 139253913Sarchie break; 139353913Sarchie case CT_ARRAY: 139453913Sarchie { 139553913Sarchie const struct ng_parse_array_info *const ai = type->info; 139653913Sarchie 139753913Sarchie if (ai->getDefault != NULL) { 139853913Sarchie return (*ai->getDefault)(type, 139953913Sarchie index, start, buf, buflen); 140053913Sarchie } 140153913Sarchie break; 140253913Sarchie } 140353913Sarchie case CT_FIXEDARRAY: 140453913Sarchie { 140553913Sarchie const struct ng_parse_fixedarray_info *const fi = type->info; 140653913Sarchie 140753913Sarchie if (*fi->getDefault != NULL) { 140853913Sarchie return (*fi->getDefault)(type, 140953913Sarchie index, start, buf, buflen); 141053913Sarchie } 141153913Sarchie break; 141253913Sarchie } 141353913Sarchie default: 141487599Sobrien panic("%s", __func__); 141553913Sarchie } 141653913Sarchie 141753913Sarchie /* Default to element type default */ 141853913Sarchie etype = ng_get_composite_etype(type, index, ctype); 141953913Sarchie func = METHOD(etype, getDefault); 142053913Sarchie if (func == NULL) 142153913Sarchie return (EOPNOTSUPP); 142253913Sarchie return (*func)(etype, start, buf, buflen); 142353913Sarchie} 142453913Sarchie 142553913Sarchie/* 142653913Sarchie * Get the number of elements in a struct, variable or fixed array. 142753913Sarchie */ 142853913Sarchiestatic int 142953913Sarchieng_get_composite_len(const struct ng_parse_type *type, 143053913Sarchie const u_char *const start, const u_char *buf, 143153913Sarchie const enum comptype ctype) 143253913Sarchie{ 143353913Sarchie switch (ctype) { 143453913Sarchie case CT_STRUCT: 143553913Sarchie { 143653913Sarchie const struct ng_parse_struct_info *const si = type->info; 143753913Sarchie int numFields = 0; 143853913Sarchie 143953913Sarchie for (numFields = 0; ; numFields++) { 144053913Sarchie const struct ng_parse_struct_field *const 144153913Sarchie fi = &si->fields[numFields]; 144253913Sarchie 144353913Sarchie if (fi->name == NULL) 144453913Sarchie break; 144553913Sarchie } 144653913Sarchie return (numFields); 144753913Sarchie } 144853913Sarchie case CT_ARRAY: 144953913Sarchie { 145053913Sarchie const struct ng_parse_array_info *const ai = type->info; 145153913Sarchie 145253913Sarchie return (*ai->getLength)(type, start, buf); 145353913Sarchie } 145453913Sarchie case CT_FIXEDARRAY: 145553913Sarchie { 145653913Sarchie const struct ng_parse_fixedarray_info *const fi = type->info; 145753913Sarchie 145853913Sarchie return fi->length; 145953913Sarchie } 146053913Sarchie default: 146187599Sobrien panic("%s", __func__); 146253913Sarchie } 146353913Sarchie return (0); 146453913Sarchie} 146553913Sarchie 146653913Sarchie/* 146753913Sarchie * Return the type of the index'th element of a composite structure 146853913Sarchie */ 146953913Sarchiestatic const struct ng_parse_type * 147053913Sarchieng_get_composite_etype(const struct ng_parse_type *type, 147153913Sarchie int index, const enum comptype ctype) 147253913Sarchie{ 147353913Sarchie const struct ng_parse_type *etype = NULL; 147453913Sarchie 147553913Sarchie switch (ctype) { 147653913Sarchie case CT_STRUCT: 147753913Sarchie { 147853913Sarchie const struct ng_parse_struct_info *const si = type->info; 147953913Sarchie 148053913Sarchie etype = si->fields[index].type; 148153913Sarchie break; 148253913Sarchie } 148353913Sarchie case CT_ARRAY: 148453913Sarchie { 148553913Sarchie const struct ng_parse_array_info *const ai = type->info; 148653913Sarchie 148753913Sarchie etype = ai->elementType; 148853913Sarchie break; 148953913Sarchie } 149053913Sarchie case CT_FIXEDARRAY: 149153913Sarchie { 149253913Sarchie const struct ng_parse_fixedarray_info *const fi = type->info; 149353913Sarchie 149453913Sarchie etype = fi->elementType; 149553913Sarchie break; 149653913Sarchie } 149753913Sarchie default: 149887599Sobrien panic("%s", __func__); 149953913Sarchie } 150053913Sarchie return (etype); 150153913Sarchie} 150253913Sarchie 150353913Sarchie/* 150453913Sarchie * Get the number of bytes to skip to align for the next 150553913Sarchie * element in a composite structure. 150653913Sarchie */ 150753913Sarchiestatic int 150853913Sarchieng_parse_get_elem_pad(const struct ng_parse_type *type, 150953913Sarchie int index, enum comptype ctype, int posn) 151053913Sarchie{ 151153913Sarchie const struct ng_parse_type *const 151253913Sarchie etype = ng_get_composite_etype(type, index, ctype); 151353913Sarchie int align; 151453913Sarchie 151553913Sarchie /* Get element's alignment, and possibly override */ 151653913Sarchie align = ALIGNMENT(etype); 151753913Sarchie if (ctype == CT_STRUCT) { 151853913Sarchie const struct ng_parse_struct_info *si = type->info; 151953913Sarchie 152053913Sarchie if (si->fields[index].alignment != 0) 152153913Sarchie align = si->fields[index].alignment; 152253913Sarchie } 152353913Sarchie 152453913Sarchie /* Return number of bytes to skip to align */ 152553913Sarchie return (align ? (align - (posn % align)) % align : 0); 152653913Sarchie} 152753913Sarchie 152853913Sarchie/************************************************************************ 152953913Sarchie PARSING HELPER ROUTINES 153053913Sarchie ************************************************************************/ 153153913Sarchie 153253913Sarchie/* 153353913Sarchie * Skip over a value 153453913Sarchie */ 153553913Sarchiestatic int 153653913Sarchieng_parse_skip_value(const char *s, int off0, int *lenp) 153753913Sarchie{ 153853913Sarchie int len, nbracket, nbrace; 153953913Sarchie int off = off0; 154053913Sarchie 154153913Sarchie len = nbracket = nbrace = 0; 154253913Sarchie do { 154353913Sarchie switch (ng_parse_get_token(s, &off, &len)) { 154453913Sarchie case T_LBRACKET: 154553913Sarchie nbracket++; 154653913Sarchie break; 154753913Sarchie case T_LBRACE: 154853913Sarchie nbrace++; 154953913Sarchie break; 155053913Sarchie case T_RBRACKET: 155153913Sarchie if (nbracket-- == 0) 155253913Sarchie return (EINVAL); 155353913Sarchie break; 155453913Sarchie case T_RBRACE: 155553913Sarchie if (nbrace-- == 0) 155653913Sarchie return (EINVAL); 155753913Sarchie break; 155853913Sarchie case T_EOF: 155953913Sarchie return (EINVAL); 156053913Sarchie default: 156153913Sarchie break; 156253913Sarchie } 156353913Sarchie off += len; 156453913Sarchie } while (nbracket > 0 || nbrace > 0); 156553913Sarchie *lenp = off - off0; 156653913Sarchie return (0); 156753913Sarchie} 156853913Sarchie 156953913Sarchie/* 157053913Sarchie * Find the next token in the string, starting at offset *startp. 157153913Sarchie * Returns the token type, with *startp pointing to the first char 157253913Sarchie * and *lenp the length. 157353913Sarchie */ 157453913Sarchieenum ng_parse_token 157553913Sarchieng_parse_get_token(const char *s, int *startp, int *lenp) 157653913Sarchie{ 157753913Sarchie char *t; 157853913Sarchie int i; 157953913Sarchie 158053913Sarchie while (isspace(s[*startp])) 158153913Sarchie (*startp)++; 158253913Sarchie switch (s[*startp]) { 158353913Sarchie case '\0': 158453913Sarchie *lenp = 0; 158553913Sarchie return T_EOF; 158653913Sarchie case '{': 158753913Sarchie *lenp = 1; 158853913Sarchie return T_LBRACE; 158953913Sarchie case '}': 159053913Sarchie *lenp = 1; 159153913Sarchie return T_RBRACE; 159253913Sarchie case '[': 159353913Sarchie *lenp = 1; 159453913Sarchie return T_LBRACKET; 159553913Sarchie case ']': 159653913Sarchie *lenp = 1; 159753913Sarchie return T_RBRACKET; 159853913Sarchie case '=': 159953913Sarchie *lenp = 1; 160053913Sarchie return T_EQUALS; 160153913Sarchie case '"': 160268845Sbrian if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL) 160353913Sarchie return T_ERROR; 160470870Sjulian FREE(t, M_NETGRAPH_PARSE); 160553913Sarchie return T_STRING; 160653913Sarchie default: 160753913Sarchie for (i = *startp + 1; s[i] != '\0' && !isspace(s[i]) 160853913Sarchie && s[i] != '{' && s[i] != '}' && s[i] != '[' 160953913Sarchie && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++) 161053913Sarchie ; 161153913Sarchie *lenp = i - *startp; 161253913Sarchie return T_WORD; 161353913Sarchie } 161453913Sarchie} 161553913Sarchie 161653913Sarchie/* 161753913Sarchie * Get a string token, which must be enclosed in double quotes. 161853913Sarchie * The normal C backslash escapes are recognized. 161953913Sarchie */ 162053913Sarchiechar * 162168845Sbrianng_get_string_token(const char *s, int *startp, int *lenp, int *slenp) 162253913Sarchie{ 162353913Sarchie char *cbuf, *p; 162453913Sarchie int start, off; 162568845Sbrian int slen; 162653913Sarchie 162753913Sarchie while (isspace(s[*startp])) 162853913Sarchie (*startp)++; 162953913Sarchie start = *startp; 163053913Sarchie if (s[*startp] != '"') 163153913Sarchie return (NULL); 163270870Sjulian MALLOC(cbuf, char *, strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT); 163353913Sarchie if (cbuf == NULL) 163453913Sarchie return (NULL); 163553913Sarchie strcpy(cbuf, s + start + 1); 163668845Sbrian for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) { 163753913Sarchie if (*p == '"') { 163853913Sarchie *p = '\0'; 163953913Sarchie *lenp = off + 1; 164068845Sbrian if (slenp != NULL) 164168845Sbrian *slenp = slen; 164253913Sarchie return (cbuf); 164353913Sarchie } else if (p[0] == '\\' && p[1] != '\0') { 164453913Sarchie int x, k; 164553913Sarchie char *v; 164653913Sarchie 164753913Sarchie strcpy(p, p + 1); 164853913Sarchie v = p; 164953913Sarchie switch (*p) { 165053913Sarchie case 't': 165153913Sarchie *v = '\t'; 165253913Sarchie off++; 165353913Sarchie continue; 165453913Sarchie case 'n': 165553913Sarchie *v = '\n'; 165653913Sarchie off++; 165753913Sarchie continue; 165853913Sarchie case 'r': 165953913Sarchie *v = '\r'; 166053913Sarchie off++; 166153913Sarchie continue; 166253913Sarchie case 'v': 166353913Sarchie *v = '\v'; 166453913Sarchie off++; 166553913Sarchie continue; 166653913Sarchie case 'f': 166753913Sarchie *v = '\f'; 166853913Sarchie off++; 166953913Sarchie continue; 167053913Sarchie case '"': 167153913Sarchie *v = '"'; 167253913Sarchie off++; 167353913Sarchie continue; 167453913Sarchie case '0': case '1': case '2': case '3': 167553913Sarchie case '4': case '5': case '6': case '7': 167653913Sarchie for (x = k = 0; 167753913Sarchie k < 3 && *v >= '0' && *v <= '7'; v++) { 167853913Sarchie x = (x << 3) + (*v - '0'); 167953913Sarchie off++; 168053913Sarchie } 168153913Sarchie *--v = (char)x; 168253913Sarchie break; 168353913Sarchie case 'x': 168453913Sarchie for (v++, x = k = 0; 168553913Sarchie k < 2 && isxdigit(*v); v++) { 168653913Sarchie x = (x << 4) + (isdigit(*v) ? 168753913Sarchie (*v - '0') : 168853913Sarchie (tolower(*v) - 'a' + 10)); 168953913Sarchie off++; 169053913Sarchie } 169153913Sarchie *--v = (char)x; 169253913Sarchie break; 169353913Sarchie default: 169453913Sarchie continue; 169553913Sarchie } 169653913Sarchie strcpy(p, v); 169753913Sarchie } 169853913Sarchie } 169953913Sarchie return (NULL); /* no closing quote */ 170053913Sarchie} 170153913Sarchie 170253913Sarchie/* 170353913Sarchie * Encode a string so it can be safely put in double quotes. 170468845Sbrian * Caller must free the result. Exactly "slen" characters 170568845Sbrian * are encoded. 170653913Sarchie */ 170753913Sarchiechar * 170868845Sbrianng_encode_string(const char *raw, int slen) 170953913Sarchie{ 171053913Sarchie char *cbuf; 171153913Sarchie int off = 0; 171268845Sbrian int i; 171353913Sarchie 171470870Sjulian MALLOC(cbuf, char *, strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT); 171553913Sarchie if (cbuf == NULL) 171653913Sarchie return (NULL); 171753913Sarchie cbuf[off++] = '"'; 171868845Sbrian for (i = 0; i < slen; i++, raw++) { 171953913Sarchie switch (*raw) { 172053913Sarchie case '\t': 172153913Sarchie cbuf[off++] = '\\'; 172253913Sarchie cbuf[off++] = 't'; 172353913Sarchie break; 172453913Sarchie case '\f': 172553913Sarchie cbuf[off++] = '\\'; 172653913Sarchie cbuf[off++] = 'f'; 172753913Sarchie break; 172853913Sarchie case '\n': 172953913Sarchie cbuf[off++] = '\\'; 173053913Sarchie cbuf[off++] = 'n'; 173153913Sarchie break; 173253913Sarchie case '\r': 173353913Sarchie cbuf[off++] = '\\'; 173453913Sarchie cbuf[off++] = 'r'; 173553913Sarchie break; 173653913Sarchie case '\v': 173753913Sarchie cbuf[off++] = '\\'; 173853913Sarchie cbuf[off++] = 'v'; 173953913Sarchie break; 174053913Sarchie case '"': 174153913Sarchie case '\\': 174253913Sarchie cbuf[off++] = '\\'; 174353913Sarchie cbuf[off++] = *raw; 174453913Sarchie break; 174553913Sarchie default: 174653913Sarchie if (*raw < 0x20 || *raw > 0x7e) { 174753913Sarchie off += sprintf(cbuf + off, 174853913Sarchie "\\x%02x", (u_char)*raw); 174953913Sarchie break; 175053913Sarchie } 175153913Sarchie cbuf[off++] = *raw; 175253913Sarchie break; 175353913Sarchie } 175453913Sarchie } 175553913Sarchie cbuf[off++] = '"'; 175653913Sarchie cbuf[off] = '\0'; 175753913Sarchie return (cbuf); 175853913Sarchie} 175953913Sarchie 176053913Sarchie/************************************************************************ 176153913Sarchie VIRTUAL METHOD LOOKUP 176253913Sarchie ************************************************************************/ 176353913Sarchie 176453913Sarchiestatic ng_parse_t * 176553913Sarchieng_get_parse_method(const struct ng_parse_type *t) 176653913Sarchie{ 176753913Sarchie while (t != NULL && t->parse == NULL) 176853913Sarchie t = t->supertype; 176953913Sarchie return (t ? t->parse : NULL); 177053913Sarchie} 177153913Sarchie 177253913Sarchiestatic ng_unparse_t * 177353913Sarchieng_get_unparse_method(const struct ng_parse_type *t) 177453913Sarchie{ 177553913Sarchie while (t != NULL && t->unparse == NULL) 177653913Sarchie t = t->supertype; 177753913Sarchie return (t ? t->unparse : NULL); 177853913Sarchie} 177953913Sarchie 178053913Sarchiestatic ng_getDefault_t * 178153913Sarchieng_get_getDefault_method(const struct ng_parse_type *t) 178253913Sarchie{ 178353913Sarchie while (t != NULL && t->getDefault == NULL) 178453913Sarchie t = t->supertype; 178553913Sarchie return (t ? t->getDefault : NULL); 178653913Sarchie} 178753913Sarchie 178853913Sarchiestatic ng_getAlign_t * 178953913Sarchieng_get_getAlign_method(const struct ng_parse_type *t) 179053913Sarchie{ 179153913Sarchie while (t != NULL && t->getAlign == NULL) 179253913Sarchie t = t->supertype; 179353913Sarchie return (t ? t->getAlign : NULL); 179453913Sarchie} 179553913Sarchie 1796