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