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