1*a1fd9364Slogwang /*
2*a1fd9364Slogwang * ng_parse.c
3*a1fd9364Slogwang */
4*a1fd9364Slogwang
5*a1fd9364Slogwang /*-
6*a1fd9364Slogwang * Copyright (c) 1999 Whistle Communications, Inc.
7*a1fd9364Slogwang * All rights reserved.
8*a1fd9364Slogwang *
9*a1fd9364Slogwang * Subject to the following obligations and disclaimer of warranty, use and
10*a1fd9364Slogwang * redistribution of this software, in source or object code forms, with or
11*a1fd9364Slogwang * without modifications are expressly permitted by Whistle Communications;
12*a1fd9364Slogwang * provided, however, that:
13*a1fd9364Slogwang * 1. Any and all reproductions of the source or object code must include the
14*a1fd9364Slogwang * copyright notice above and the following disclaimer of warranties; and
15*a1fd9364Slogwang * 2. No rights are granted, in any manner or form, to use Whistle
16*a1fd9364Slogwang * Communications, Inc. trademarks, including the mark "WHISTLE
17*a1fd9364Slogwang * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18*a1fd9364Slogwang * such appears in the above copyright notice or in the software.
19*a1fd9364Slogwang *
20*a1fd9364Slogwang * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21*a1fd9364Slogwang * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22*a1fd9364Slogwang * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23*a1fd9364Slogwang * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24*a1fd9364Slogwang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25*a1fd9364Slogwang * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26*a1fd9364Slogwang * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27*a1fd9364Slogwang * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28*a1fd9364Slogwang * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29*a1fd9364Slogwang * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30*a1fd9364Slogwang * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31*a1fd9364Slogwang * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32*a1fd9364Slogwang * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33*a1fd9364Slogwang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34*a1fd9364Slogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35*a1fd9364Slogwang * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36*a1fd9364Slogwang * OF SUCH DAMAGE.
37*a1fd9364Slogwang *
38*a1fd9364Slogwang * Author: Archie Cobbs <[email protected]>
39*a1fd9364Slogwang *
40*a1fd9364Slogwang * $Whistle: ng_parse.c,v 1.3 1999/11/29 01:43:48 archie Exp $
41*a1fd9364Slogwang * $FreeBSD$
42*a1fd9364Slogwang */
43*a1fd9364Slogwang
44*a1fd9364Slogwang #include <sys/types.h>
45*a1fd9364Slogwang #include <sys/param.h>
46*a1fd9364Slogwang #include <sys/systm.h>
47*a1fd9364Slogwang #include <sys/kernel.h>
48*a1fd9364Slogwang #include <sys/errno.h>
49*a1fd9364Slogwang #include <sys/limits.h>
50*a1fd9364Slogwang #include <sys/malloc.h>
51*a1fd9364Slogwang #include <sys/mbuf.h>
52*a1fd9364Slogwang #include <sys/ctype.h>
53*a1fd9364Slogwang
54*a1fd9364Slogwang #include <machine/stdarg.h>
55*a1fd9364Slogwang
56*a1fd9364Slogwang #include <net/ethernet.h>
57*a1fd9364Slogwang
58*a1fd9364Slogwang #include <netinet/in.h>
59*a1fd9364Slogwang
60*a1fd9364Slogwang #include <netgraph/ng_message.h>
61*a1fd9364Slogwang #include <netgraph/netgraph.h>
62*a1fd9364Slogwang #include <netgraph/ng_parse.h>
63*a1fd9364Slogwang
64*a1fd9364Slogwang #ifdef NG_SEPARATE_MALLOC
65*a1fd9364Slogwang static MALLOC_DEFINE(M_NETGRAPH_PARSE, "netgraph_parse", "netgraph parse info");
66*a1fd9364Slogwang #else
67*a1fd9364Slogwang #define M_NETGRAPH_PARSE M_NETGRAPH
68*a1fd9364Slogwang #endif
69*a1fd9364Slogwang
70*a1fd9364Slogwang /* Compute alignment for primitive integral types */
71*a1fd9364Slogwang struct int16_temp {
72*a1fd9364Slogwang char x;
73*a1fd9364Slogwang int16_t y;
74*a1fd9364Slogwang };
75*a1fd9364Slogwang
76*a1fd9364Slogwang struct int32_temp {
77*a1fd9364Slogwang char x;
78*a1fd9364Slogwang int32_t y;
79*a1fd9364Slogwang };
80*a1fd9364Slogwang
81*a1fd9364Slogwang struct int64_temp {
82*a1fd9364Slogwang char x;
83*a1fd9364Slogwang int64_t y;
84*a1fd9364Slogwang };
85*a1fd9364Slogwang
86*a1fd9364Slogwang #define INT8_ALIGNMENT 1
87*a1fd9364Slogwang #define INT16_ALIGNMENT ((size_t)&((struct int16_temp *)0)->y)
88*a1fd9364Slogwang #define INT32_ALIGNMENT ((size_t)&((struct int32_temp *)0)->y)
89*a1fd9364Slogwang #define INT64_ALIGNMENT ((size_t)&((struct int64_temp *)0)->y)
90*a1fd9364Slogwang
91*a1fd9364Slogwang /* Output format for integral types */
92*a1fd9364Slogwang #define INT_UNSIGNED 0
93*a1fd9364Slogwang #define INT_SIGNED 1
94*a1fd9364Slogwang #define INT_HEX 2
95*a1fd9364Slogwang
96*a1fd9364Slogwang /* Type of composite object: struct, array, or fixedarray */
97*a1fd9364Slogwang enum comptype {
98*a1fd9364Slogwang CT_STRUCT,
99*a1fd9364Slogwang CT_ARRAY,
100*a1fd9364Slogwang CT_FIXEDARRAY,
101*a1fd9364Slogwang };
102*a1fd9364Slogwang
103*a1fd9364Slogwang /* Composite types helper functions */
104*a1fd9364Slogwang static int ng_parse_composite(const struct ng_parse_type *type,
105*a1fd9364Slogwang const char *s, int *off, const u_char *start,
106*a1fd9364Slogwang u_char *const buf, int *buflen, enum comptype ctype);
107*a1fd9364Slogwang static int ng_unparse_composite(const struct ng_parse_type *type,
108*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen,
109*a1fd9364Slogwang enum comptype ctype);
110*a1fd9364Slogwang static int ng_get_composite_elem_default(const struct ng_parse_type *type,
111*a1fd9364Slogwang int index, const u_char *start, u_char *buf,
112*a1fd9364Slogwang int *buflen, enum comptype ctype);
113*a1fd9364Slogwang static int ng_get_composite_len(const struct ng_parse_type *type,
114*a1fd9364Slogwang const u_char *start, const u_char *buf,
115*a1fd9364Slogwang enum comptype ctype);
116*a1fd9364Slogwang static const struct ng_parse_type *ng_get_composite_etype(const struct
117*a1fd9364Slogwang ng_parse_type *type, int index, enum comptype ctype);
118*a1fd9364Slogwang static int ng_parse_get_elem_pad(const struct ng_parse_type *type,
119*a1fd9364Slogwang int index, enum comptype ctype, int posn);
120*a1fd9364Slogwang
121*a1fd9364Slogwang /* Parsing helper functions */
122*a1fd9364Slogwang static int ng_parse_skip_value(const char *s, int off, int *lenp);
123*a1fd9364Slogwang static int ng_parse_append(char **cbufp, int *cbuflenp,
124*a1fd9364Slogwang const char *fmt, ...);
125*a1fd9364Slogwang
126*a1fd9364Slogwang /* Poor man's virtual method calls */
127*a1fd9364Slogwang #define METHOD(t,m) (ng_get_ ## m ## _method(t))
128*a1fd9364Slogwang #define INVOKE(t,m) (*METHOD(t,m))
129*a1fd9364Slogwang
130*a1fd9364Slogwang static ng_parse_t *ng_get_parse_method(const struct ng_parse_type *t);
131*a1fd9364Slogwang static ng_unparse_t *ng_get_unparse_method(const struct ng_parse_type *t);
132*a1fd9364Slogwang static ng_getDefault_t *ng_get_getDefault_method(const
133*a1fd9364Slogwang struct ng_parse_type *t);
134*a1fd9364Slogwang static ng_getAlign_t *ng_get_getAlign_method(const struct ng_parse_type *t);
135*a1fd9364Slogwang
136*a1fd9364Slogwang #define ALIGNMENT(t) (METHOD(t, getAlign) == NULL ? \
137*a1fd9364Slogwang 0 : INVOKE(t, getAlign)(t))
138*a1fd9364Slogwang
139*a1fd9364Slogwang /************************************************************************
140*a1fd9364Slogwang PUBLIC FUNCTIONS
141*a1fd9364Slogwang ************************************************************************/
142*a1fd9364Slogwang
143*a1fd9364Slogwang /*
144*a1fd9364Slogwang * Convert an ASCII string to binary according to the supplied type descriptor
145*a1fd9364Slogwang */
146*a1fd9364Slogwang int
ng_parse(const struct ng_parse_type * type,const char * string,int * off,u_char * buf,int * buflen)147*a1fd9364Slogwang ng_parse(const struct ng_parse_type *type,
148*a1fd9364Slogwang const char *string, int *off, u_char *buf, int *buflen)
149*a1fd9364Slogwang {
150*a1fd9364Slogwang return INVOKE(type, parse)(type, string, off, buf, buf, buflen);
151*a1fd9364Slogwang }
152*a1fd9364Slogwang
153*a1fd9364Slogwang /*
154*a1fd9364Slogwang * Convert binary to an ASCII string according to the supplied type descriptor
155*a1fd9364Slogwang */
156*a1fd9364Slogwang int
ng_unparse(const struct ng_parse_type * type,const u_char * data,char * cbuf,int cbuflen)157*a1fd9364Slogwang ng_unparse(const struct ng_parse_type *type,
158*a1fd9364Slogwang const u_char *data, char *cbuf, int cbuflen)
159*a1fd9364Slogwang {
160*a1fd9364Slogwang int off = 0;
161*a1fd9364Slogwang
162*a1fd9364Slogwang return INVOKE(type, unparse)(type, data, &off, cbuf, cbuflen);
163*a1fd9364Slogwang }
164*a1fd9364Slogwang
165*a1fd9364Slogwang /*
166*a1fd9364Slogwang * Fill in the default value according to the supplied type descriptor
167*a1fd9364Slogwang */
168*a1fd9364Slogwang int
ng_parse_getDefault(const struct ng_parse_type * type,u_char * buf,int * buflen)169*a1fd9364Slogwang ng_parse_getDefault(const struct ng_parse_type *type, u_char *buf, int *buflen)
170*a1fd9364Slogwang {
171*a1fd9364Slogwang ng_getDefault_t *const func = METHOD(type, getDefault);
172*a1fd9364Slogwang
173*a1fd9364Slogwang if (func == NULL)
174*a1fd9364Slogwang return (EOPNOTSUPP);
175*a1fd9364Slogwang return (*func)(type, buf, buf, buflen);
176*a1fd9364Slogwang }
177*a1fd9364Slogwang
178*a1fd9364Slogwang /************************************************************************
179*a1fd9364Slogwang STRUCTURE TYPE
180*a1fd9364Slogwang ************************************************************************/
181*a1fd9364Slogwang
182*a1fd9364Slogwang static int
ng_struct_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)183*a1fd9364Slogwang ng_struct_parse(const struct ng_parse_type *type,
184*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
185*a1fd9364Slogwang u_char *const buf, int *buflen)
186*a1fd9364Slogwang {
187*a1fd9364Slogwang return ng_parse_composite(type, s, off, start, buf, buflen, CT_STRUCT);
188*a1fd9364Slogwang }
189*a1fd9364Slogwang
190*a1fd9364Slogwang static int
ng_struct_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)191*a1fd9364Slogwang ng_struct_unparse(const struct ng_parse_type *type,
192*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
193*a1fd9364Slogwang {
194*a1fd9364Slogwang return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_STRUCT);
195*a1fd9364Slogwang }
196*a1fd9364Slogwang
197*a1fd9364Slogwang static int
ng_struct_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)198*a1fd9364Slogwang ng_struct_getDefault(const struct ng_parse_type *type,
199*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
200*a1fd9364Slogwang {
201*a1fd9364Slogwang int off = 0;
202*a1fd9364Slogwang
203*a1fd9364Slogwang return ng_parse_composite(type,
204*a1fd9364Slogwang "{}", &off, start, buf, buflen, CT_STRUCT);
205*a1fd9364Slogwang }
206*a1fd9364Slogwang
207*a1fd9364Slogwang static int
ng_struct_getAlign(const struct ng_parse_type * type)208*a1fd9364Slogwang ng_struct_getAlign(const struct ng_parse_type *type)
209*a1fd9364Slogwang {
210*a1fd9364Slogwang const struct ng_parse_struct_field *field;
211*a1fd9364Slogwang int align = 0;
212*a1fd9364Slogwang
213*a1fd9364Slogwang for (field = type->info; field->name != NULL; field++) {
214*a1fd9364Slogwang int falign = ALIGNMENT(field->type);
215*a1fd9364Slogwang
216*a1fd9364Slogwang if (falign > align)
217*a1fd9364Slogwang align = falign;
218*a1fd9364Slogwang }
219*a1fd9364Slogwang return align;
220*a1fd9364Slogwang }
221*a1fd9364Slogwang
222*a1fd9364Slogwang const struct ng_parse_type ng_parse_struct_type = {
223*a1fd9364Slogwang NULL,
224*a1fd9364Slogwang NULL,
225*a1fd9364Slogwang NULL,
226*a1fd9364Slogwang ng_struct_parse,
227*a1fd9364Slogwang ng_struct_unparse,
228*a1fd9364Slogwang ng_struct_getDefault,
229*a1fd9364Slogwang ng_struct_getAlign
230*a1fd9364Slogwang };
231*a1fd9364Slogwang
232*a1fd9364Slogwang /************************************************************************
233*a1fd9364Slogwang FIXED LENGTH ARRAY TYPE
234*a1fd9364Slogwang ************************************************************************/
235*a1fd9364Slogwang
236*a1fd9364Slogwang static int
ng_fixedarray_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)237*a1fd9364Slogwang ng_fixedarray_parse(const struct ng_parse_type *type,
238*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
239*a1fd9364Slogwang u_char *const buf, int *buflen)
240*a1fd9364Slogwang {
241*a1fd9364Slogwang return ng_parse_composite(type,
242*a1fd9364Slogwang s, off, start, buf, buflen, CT_FIXEDARRAY);
243*a1fd9364Slogwang }
244*a1fd9364Slogwang
245*a1fd9364Slogwang static int
ng_fixedarray_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)246*a1fd9364Slogwang ng_fixedarray_unparse(const struct ng_parse_type *type,
247*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
248*a1fd9364Slogwang {
249*a1fd9364Slogwang return ng_unparse_composite(type,
250*a1fd9364Slogwang data, off, cbuf, cbuflen, CT_FIXEDARRAY);
251*a1fd9364Slogwang }
252*a1fd9364Slogwang
253*a1fd9364Slogwang static int
ng_fixedarray_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)254*a1fd9364Slogwang ng_fixedarray_getDefault(const struct ng_parse_type *type,
255*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
256*a1fd9364Slogwang {
257*a1fd9364Slogwang int off = 0;
258*a1fd9364Slogwang
259*a1fd9364Slogwang return ng_parse_composite(type,
260*a1fd9364Slogwang "[]", &off, start, buf, buflen, CT_FIXEDARRAY);
261*a1fd9364Slogwang }
262*a1fd9364Slogwang
263*a1fd9364Slogwang static int
ng_fixedarray_getAlign(const struct ng_parse_type * type)264*a1fd9364Slogwang ng_fixedarray_getAlign(const struct ng_parse_type *type)
265*a1fd9364Slogwang {
266*a1fd9364Slogwang const struct ng_parse_fixedarray_info *fi = type->info;
267*a1fd9364Slogwang
268*a1fd9364Slogwang return ALIGNMENT(fi->elementType);
269*a1fd9364Slogwang }
270*a1fd9364Slogwang
271*a1fd9364Slogwang const struct ng_parse_type ng_parse_fixedarray_type = {
272*a1fd9364Slogwang NULL,
273*a1fd9364Slogwang NULL,
274*a1fd9364Slogwang NULL,
275*a1fd9364Slogwang ng_fixedarray_parse,
276*a1fd9364Slogwang ng_fixedarray_unparse,
277*a1fd9364Slogwang ng_fixedarray_getDefault,
278*a1fd9364Slogwang ng_fixedarray_getAlign
279*a1fd9364Slogwang };
280*a1fd9364Slogwang
281*a1fd9364Slogwang /************************************************************************
282*a1fd9364Slogwang VARIABLE LENGTH ARRAY TYPE
283*a1fd9364Slogwang ************************************************************************/
284*a1fd9364Slogwang
285*a1fd9364Slogwang static int
ng_array_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)286*a1fd9364Slogwang ng_array_parse(const struct ng_parse_type *type,
287*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
288*a1fd9364Slogwang u_char *const buf, int *buflen)
289*a1fd9364Slogwang {
290*a1fd9364Slogwang return ng_parse_composite(type, s, off, start, buf, buflen, CT_ARRAY);
291*a1fd9364Slogwang }
292*a1fd9364Slogwang
293*a1fd9364Slogwang static int
ng_array_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)294*a1fd9364Slogwang ng_array_unparse(const struct ng_parse_type *type,
295*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
296*a1fd9364Slogwang {
297*a1fd9364Slogwang return ng_unparse_composite(type, data, off, cbuf, cbuflen, CT_ARRAY);
298*a1fd9364Slogwang }
299*a1fd9364Slogwang
300*a1fd9364Slogwang static int
ng_array_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)301*a1fd9364Slogwang ng_array_getDefault(const struct ng_parse_type *type,
302*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
303*a1fd9364Slogwang {
304*a1fd9364Slogwang int off = 0;
305*a1fd9364Slogwang
306*a1fd9364Slogwang return ng_parse_composite(type,
307*a1fd9364Slogwang "[]", &off, start, buf, buflen, CT_ARRAY);
308*a1fd9364Slogwang }
309*a1fd9364Slogwang
310*a1fd9364Slogwang static int
ng_array_getAlign(const struct ng_parse_type * type)311*a1fd9364Slogwang ng_array_getAlign(const struct ng_parse_type *type)
312*a1fd9364Slogwang {
313*a1fd9364Slogwang const struct ng_parse_array_info *ai = type->info;
314*a1fd9364Slogwang
315*a1fd9364Slogwang return ALIGNMENT(ai->elementType);
316*a1fd9364Slogwang }
317*a1fd9364Slogwang
318*a1fd9364Slogwang const struct ng_parse_type ng_parse_array_type = {
319*a1fd9364Slogwang NULL,
320*a1fd9364Slogwang NULL,
321*a1fd9364Slogwang NULL,
322*a1fd9364Slogwang ng_array_parse,
323*a1fd9364Slogwang ng_array_unparse,
324*a1fd9364Slogwang ng_array_getDefault,
325*a1fd9364Slogwang ng_array_getAlign
326*a1fd9364Slogwang };
327*a1fd9364Slogwang
328*a1fd9364Slogwang /************************************************************************
329*a1fd9364Slogwang INT8 TYPE
330*a1fd9364Slogwang ************************************************************************/
331*a1fd9364Slogwang
332*a1fd9364Slogwang static int
ng_int8_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)333*a1fd9364Slogwang ng_int8_parse(const struct ng_parse_type *type,
334*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
335*a1fd9364Slogwang u_char *const buf, int *buflen)
336*a1fd9364Slogwang {
337*a1fd9364Slogwang long val;
338*a1fd9364Slogwang int8_t val8;
339*a1fd9364Slogwang char *eptr;
340*a1fd9364Slogwang
341*a1fd9364Slogwang val = strtol(s + *off, &eptr, 0);
342*a1fd9364Slogwang if (val < (int8_t)0x80 || val > (u_int8_t)0xff || eptr == s + *off)
343*a1fd9364Slogwang return (EINVAL);
344*a1fd9364Slogwang *off = eptr - s;
345*a1fd9364Slogwang val8 = (int8_t)val;
346*a1fd9364Slogwang bcopy(&val8, buf, sizeof(int8_t));
347*a1fd9364Slogwang *buflen = sizeof(int8_t);
348*a1fd9364Slogwang return (0);
349*a1fd9364Slogwang }
350*a1fd9364Slogwang
351*a1fd9364Slogwang static int
ng_int8_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)352*a1fd9364Slogwang ng_int8_unparse(const struct ng_parse_type *type,
353*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
354*a1fd9364Slogwang {
355*a1fd9364Slogwang const char *fmt;
356*a1fd9364Slogwang int fval;
357*a1fd9364Slogwang int error;
358*a1fd9364Slogwang int8_t val;
359*a1fd9364Slogwang
360*a1fd9364Slogwang bcopy(data + *off, &val, sizeof(int8_t));
361*a1fd9364Slogwang switch ((intptr_t)type->info) {
362*a1fd9364Slogwang case INT_SIGNED:
363*a1fd9364Slogwang fmt = "%d";
364*a1fd9364Slogwang fval = val;
365*a1fd9364Slogwang break;
366*a1fd9364Slogwang case INT_UNSIGNED:
367*a1fd9364Slogwang fmt = "%u";
368*a1fd9364Slogwang fval = (u_int8_t)val;
369*a1fd9364Slogwang break;
370*a1fd9364Slogwang case INT_HEX:
371*a1fd9364Slogwang fmt = "0x%x";
372*a1fd9364Slogwang fval = (u_int8_t)val;
373*a1fd9364Slogwang break;
374*a1fd9364Slogwang default:
375*a1fd9364Slogwang panic("%s: unknown type", __func__);
376*a1fd9364Slogwang }
377*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0)
378*a1fd9364Slogwang return (error);
379*a1fd9364Slogwang *off += sizeof(int8_t);
380*a1fd9364Slogwang return (0);
381*a1fd9364Slogwang }
382*a1fd9364Slogwang
383*a1fd9364Slogwang static int
ng_int8_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)384*a1fd9364Slogwang ng_int8_getDefault(const struct ng_parse_type *type,
385*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
386*a1fd9364Slogwang {
387*a1fd9364Slogwang int8_t val;
388*a1fd9364Slogwang
389*a1fd9364Slogwang if (*buflen < sizeof(int8_t))
390*a1fd9364Slogwang return (ERANGE);
391*a1fd9364Slogwang val = 0;
392*a1fd9364Slogwang bcopy(&val, buf, sizeof(int8_t));
393*a1fd9364Slogwang *buflen = sizeof(int8_t);
394*a1fd9364Slogwang return (0);
395*a1fd9364Slogwang }
396*a1fd9364Slogwang
397*a1fd9364Slogwang static int
ng_int8_getAlign(const struct ng_parse_type * type)398*a1fd9364Slogwang ng_int8_getAlign(const struct ng_parse_type *type)
399*a1fd9364Slogwang {
400*a1fd9364Slogwang return INT8_ALIGNMENT;
401*a1fd9364Slogwang }
402*a1fd9364Slogwang
403*a1fd9364Slogwang const struct ng_parse_type ng_parse_int8_type = {
404*a1fd9364Slogwang NULL,
405*a1fd9364Slogwang (void *)INT_SIGNED,
406*a1fd9364Slogwang NULL,
407*a1fd9364Slogwang ng_int8_parse,
408*a1fd9364Slogwang ng_int8_unparse,
409*a1fd9364Slogwang ng_int8_getDefault,
410*a1fd9364Slogwang ng_int8_getAlign
411*a1fd9364Slogwang };
412*a1fd9364Slogwang
413*a1fd9364Slogwang const struct ng_parse_type ng_parse_uint8_type = {
414*a1fd9364Slogwang &ng_parse_int8_type,
415*a1fd9364Slogwang (void *)INT_UNSIGNED
416*a1fd9364Slogwang };
417*a1fd9364Slogwang
418*a1fd9364Slogwang const struct ng_parse_type ng_parse_hint8_type = {
419*a1fd9364Slogwang &ng_parse_int8_type,
420*a1fd9364Slogwang (void *)INT_HEX
421*a1fd9364Slogwang };
422*a1fd9364Slogwang
423*a1fd9364Slogwang /************************************************************************
424*a1fd9364Slogwang INT16 TYPE
425*a1fd9364Slogwang ************************************************************************/
426*a1fd9364Slogwang
427*a1fd9364Slogwang static int
ng_int16_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)428*a1fd9364Slogwang ng_int16_parse(const struct ng_parse_type *type,
429*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
430*a1fd9364Slogwang u_char *const buf, int *buflen)
431*a1fd9364Slogwang {
432*a1fd9364Slogwang long val;
433*a1fd9364Slogwang int16_t val16;
434*a1fd9364Slogwang char *eptr;
435*a1fd9364Slogwang
436*a1fd9364Slogwang val = strtol(s + *off, &eptr, 0);
437*a1fd9364Slogwang if (val < (int16_t)0x8000
438*a1fd9364Slogwang || val > (u_int16_t)0xffff || eptr == s + *off)
439*a1fd9364Slogwang return (EINVAL);
440*a1fd9364Slogwang *off = eptr - s;
441*a1fd9364Slogwang val16 = (int16_t)val;
442*a1fd9364Slogwang bcopy(&val16, buf, sizeof(int16_t));
443*a1fd9364Slogwang *buflen = sizeof(int16_t);
444*a1fd9364Slogwang return (0);
445*a1fd9364Slogwang }
446*a1fd9364Slogwang
447*a1fd9364Slogwang static int
ng_int16_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)448*a1fd9364Slogwang ng_int16_unparse(const struct ng_parse_type *type,
449*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
450*a1fd9364Slogwang {
451*a1fd9364Slogwang const char *fmt;
452*a1fd9364Slogwang int fval;
453*a1fd9364Slogwang int error;
454*a1fd9364Slogwang int16_t val;
455*a1fd9364Slogwang
456*a1fd9364Slogwang bcopy(data + *off, &val, sizeof(int16_t));
457*a1fd9364Slogwang switch ((intptr_t)type->info) {
458*a1fd9364Slogwang case INT_SIGNED:
459*a1fd9364Slogwang fmt = "%d";
460*a1fd9364Slogwang fval = val;
461*a1fd9364Slogwang break;
462*a1fd9364Slogwang case INT_UNSIGNED:
463*a1fd9364Slogwang fmt = "%u";
464*a1fd9364Slogwang fval = (u_int16_t)val;
465*a1fd9364Slogwang break;
466*a1fd9364Slogwang case INT_HEX:
467*a1fd9364Slogwang fmt = "0x%x";
468*a1fd9364Slogwang fval = (u_int16_t)val;
469*a1fd9364Slogwang break;
470*a1fd9364Slogwang default:
471*a1fd9364Slogwang panic("%s: unknown type", __func__);
472*a1fd9364Slogwang }
473*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0)
474*a1fd9364Slogwang return (error);
475*a1fd9364Slogwang *off += sizeof(int16_t);
476*a1fd9364Slogwang return (0);
477*a1fd9364Slogwang }
478*a1fd9364Slogwang
479*a1fd9364Slogwang static int
ng_int16_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)480*a1fd9364Slogwang ng_int16_getDefault(const struct ng_parse_type *type,
481*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
482*a1fd9364Slogwang {
483*a1fd9364Slogwang int16_t val;
484*a1fd9364Slogwang
485*a1fd9364Slogwang if (*buflen < sizeof(int16_t))
486*a1fd9364Slogwang return (ERANGE);
487*a1fd9364Slogwang val = 0;
488*a1fd9364Slogwang bcopy(&val, buf, sizeof(int16_t));
489*a1fd9364Slogwang *buflen = sizeof(int16_t);
490*a1fd9364Slogwang return (0);
491*a1fd9364Slogwang }
492*a1fd9364Slogwang
493*a1fd9364Slogwang static int
ng_int16_getAlign(const struct ng_parse_type * type)494*a1fd9364Slogwang ng_int16_getAlign(const struct ng_parse_type *type)
495*a1fd9364Slogwang {
496*a1fd9364Slogwang return INT16_ALIGNMENT;
497*a1fd9364Slogwang }
498*a1fd9364Slogwang
499*a1fd9364Slogwang const struct ng_parse_type ng_parse_int16_type = {
500*a1fd9364Slogwang NULL,
501*a1fd9364Slogwang (void *)INT_SIGNED,
502*a1fd9364Slogwang NULL,
503*a1fd9364Slogwang ng_int16_parse,
504*a1fd9364Slogwang ng_int16_unparse,
505*a1fd9364Slogwang ng_int16_getDefault,
506*a1fd9364Slogwang ng_int16_getAlign
507*a1fd9364Slogwang };
508*a1fd9364Slogwang
509*a1fd9364Slogwang const struct ng_parse_type ng_parse_uint16_type = {
510*a1fd9364Slogwang &ng_parse_int16_type,
511*a1fd9364Slogwang (void *)INT_UNSIGNED
512*a1fd9364Slogwang };
513*a1fd9364Slogwang
514*a1fd9364Slogwang const struct ng_parse_type ng_parse_hint16_type = {
515*a1fd9364Slogwang &ng_parse_int16_type,
516*a1fd9364Slogwang (void *)INT_HEX
517*a1fd9364Slogwang };
518*a1fd9364Slogwang
519*a1fd9364Slogwang /************************************************************************
520*a1fd9364Slogwang INT32 TYPE
521*a1fd9364Slogwang ************************************************************************/
522*a1fd9364Slogwang
523*a1fd9364Slogwang static int
ng_int32_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)524*a1fd9364Slogwang ng_int32_parse(const struct ng_parse_type *type,
525*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
526*a1fd9364Slogwang u_char *const buf, int *buflen)
527*a1fd9364Slogwang {
528*a1fd9364Slogwang long val; /* assumes long is at least 32 bits */
529*a1fd9364Slogwang int32_t val32;
530*a1fd9364Slogwang char *eptr;
531*a1fd9364Slogwang
532*a1fd9364Slogwang if ((intptr_t)type->info == INT_SIGNED)
533*a1fd9364Slogwang val = strtol(s + *off, &eptr, 0);
534*a1fd9364Slogwang else
535*a1fd9364Slogwang val = strtoul(s + *off, &eptr, 0);
536*a1fd9364Slogwang if (val < (int32_t)0x80000000
537*a1fd9364Slogwang || val > (u_int32_t)0xffffffff || eptr == s + *off)
538*a1fd9364Slogwang return (EINVAL);
539*a1fd9364Slogwang *off = eptr - s;
540*a1fd9364Slogwang val32 = (int32_t)val;
541*a1fd9364Slogwang bcopy(&val32, buf, sizeof(int32_t));
542*a1fd9364Slogwang *buflen = sizeof(int32_t);
543*a1fd9364Slogwang return (0);
544*a1fd9364Slogwang }
545*a1fd9364Slogwang
546*a1fd9364Slogwang static int
ng_int32_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)547*a1fd9364Slogwang ng_int32_unparse(const struct ng_parse_type *type,
548*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
549*a1fd9364Slogwang {
550*a1fd9364Slogwang const char *fmt;
551*a1fd9364Slogwang long fval;
552*a1fd9364Slogwang int error;
553*a1fd9364Slogwang int32_t val;
554*a1fd9364Slogwang
555*a1fd9364Slogwang bcopy(data + *off, &val, sizeof(int32_t));
556*a1fd9364Slogwang switch ((intptr_t)type->info) {
557*a1fd9364Slogwang case INT_SIGNED:
558*a1fd9364Slogwang fmt = "%ld";
559*a1fd9364Slogwang fval = val;
560*a1fd9364Slogwang break;
561*a1fd9364Slogwang case INT_UNSIGNED:
562*a1fd9364Slogwang fmt = "%lu";
563*a1fd9364Slogwang fval = (u_int32_t)val;
564*a1fd9364Slogwang break;
565*a1fd9364Slogwang case INT_HEX:
566*a1fd9364Slogwang fmt = "0x%lx";
567*a1fd9364Slogwang fval = (u_int32_t)val;
568*a1fd9364Slogwang break;
569*a1fd9364Slogwang default:
570*a1fd9364Slogwang panic("%s: unknown type", __func__);
571*a1fd9364Slogwang }
572*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0)
573*a1fd9364Slogwang return (error);
574*a1fd9364Slogwang *off += sizeof(int32_t);
575*a1fd9364Slogwang return (0);
576*a1fd9364Slogwang }
577*a1fd9364Slogwang
578*a1fd9364Slogwang static int
ng_int32_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)579*a1fd9364Slogwang ng_int32_getDefault(const struct ng_parse_type *type,
580*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
581*a1fd9364Slogwang {
582*a1fd9364Slogwang int32_t val;
583*a1fd9364Slogwang
584*a1fd9364Slogwang if (*buflen < sizeof(int32_t))
585*a1fd9364Slogwang return (ERANGE);
586*a1fd9364Slogwang val = 0;
587*a1fd9364Slogwang bcopy(&val, buf, sizeof(int32_t));
588*a1fd9364Slogwang *buflen = sizeof(int32_t);
589*a1fd9364Slogwang return (0);
590*a1fd9364Slogwang }
591*a1fd9364Slogwang
592*a1fd9364Slogwang static int
ng_int32_getAlign(const struct ng_parse_type * type)593*a1fd9364Slogwang ng_int32_getAlign(const struct ng_parse_type *type)
594*a1fd9364Slogwang {
595*a1fd9364Slogwang return INT32_ALIGNMENT;
596*a1fd9364Slogwang }
597*a1fd9364Slogwang
598*a1fd9364Slogwang const struct ng_parse_type ng_parse_int32_type = {
599*a1fd9364Slogwang NULL,
600*a1fd9364Slogwang (void *)INT_SIGNED,
601*a1fd9364Slogwang NULL,
602*a1fd9364Slogwang ng_int32_parse,
603*a1fd9364Slogwang ng_int32_unparse,
604*a1fd9364Slogwang ng_int32_getDefault,
605*a1fd9364Slogwang ng_int32_getAlign
606*a1fd9364Slogwang };
607*a1fd9364Slogwang
608*a1fd9364Slogwang const struct ng_parse_type ng_parse_uint32_type = {
609*a1fd9364Slogwang &ng_parse_int32_type,
610*a1fd9364Slogwang (void *)INT_UNSIGNED
611*a1fd9364Slogwang };
612*a1fd9364Slogwang
613*a1fd9364Slogwang const struct ng_parse_type ng_parse_hint32_type = {
614*a1fd9364Slogwang &ng_parse_int32_type,
615*a1fd9364Slogwang (void *)INT_HEX
616*a1fd9364Slogwang };
617*a1fd9364Slogwang
618*a1fd9364Slogwang /************************************************************************
619*a1fd9364Slogwang INT64 TYPE
620*a1fd9364Slogwang ************************************************************************/
621*a1fd9364Slogwang
622*a1fd9364Slogwang static int
ng_int64_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)623*a1fd9364Slogwang ng_int64_parse(const struct ng_parse_type *type,
624*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
625*a1fd9364Slogwang u_char *const buf, int *buflen)
626*a1fd9364Slogwang {
627*a1fd9364Slogwang quad_t val;
628*a1fd9364Slogwang int64_t val64;
629*a1fd9364Slogwang char *eptr;
630*a1fd9364Slogwang
631*a1fd9364Slogwang val = strtoq(s + *off, &eptr, 0);
632*a1fd9364Slogwang if (eptr == s + *off)
633*a1fd9364Slogwang return (EINVAL);
634*a1fd9364Slogwang *off = eptr - s;
635*a1fd9364Slogwang val64 = (int64_t)val;
636*a1fd9364Slogwang bcopy(&val64, buf, sizeof(int64_t));
637*a1fd9364Slogwang *buflen = sizeof(int64_t);
638*a1fd9364Slogwang return (0);
639*a1fd9364Slogwang }
640*a1fd9364Slogwang
641*a1fd9364Slogwang static int
ng_int64_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)642*a1fd9364Slogwang ng_int64_unparse(const struct ng_parse_type *type,
643*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
644*a1fd9364Slogwang {
645*a1fd9364Slogwang const char *fmt;
646*a1fd9364Slogwang long long fval;
647*a1fd9364Slogwang int64_t val;
648*a1fd9364Slogwang int error;
649*a1fd9364Slogwang
650*a1fd9364Slogwang bcopy(data + *off, &val, sizeof(int64_t));
651*a1fd9364Slogwang switch ((intptr_t)type->info) {
652*a1fd9364Slogwang case INT_SIGNED:
653*a1fd9364Slogwang fmt = "%lld";
654*a1fd9364Slogwang fval = val;
655*a1fd9364Slogwang break;
656*a1fd9364Slogwang case INT_UNSIGNED:
657*a1fd9364Slogwang fmt = "%llu";
658*a1fd9364Slogwang fval = (u_int64_t)val;
659*a1fd9364Slogwang break;
660*a1fd9364Slogwang case INT_HEX:
661*a1fd9364Slogwang fmt = "0x%llx";
662*a1fd9364Slogwang fval = (u_int64_t)val;
663*a1fd9364Slogwang break;
664*a1fd9364Slogwang default:
665*a1fd9364Slogwang panic("%s: unknown type", __func__);
666*a1fd9364Slogwang }
667*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf, &cbuflen, fmt, fval)) != 0)
668*a1fd9364Slogwang return (error);
669*a1fd9364Slogwang *off += sizeof(int64_t);
670*a1fd9364Slogwang return (0);
671*a1fd9364Slogwang }
672*a1fd9364Slogwang
673*a1fd9364Slogwang static int
ng_int64_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)674*a1fd9364Slogwang ng_int64_getDefault(const struct ng_parse_type *type,
675*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
676*a1fd9364Slogwang {
677*a1fd9364Slogwang int64_t val;
678*a1fd9364Slogwang
679*a1fd9364Slogwang if (*buflen < sizeof(int64_t))
680*a1fd9364Slogwang return (ERANGE);
681*a1fd9364Slogwang val = 0;
682*a1fd9364Slogwang bcopy(&val, buf, sizeof(int64_t));
683*a1fd9364Slogwang *buflen = sizeof(int64_t);
684*a1fd9364Slogwang return (0);
685*a1fd9364Slogwang }
686*a1fd9364Slogwang
687*a1fd9364Slogwang static int
ng_int64_getAlign(const struct ng_parse_type * type)688*a1fd9364Slogwang ng_int64_getAlign(const struct ng_parse_type *type)
689*a1fd9364Slogwang {
690*a1fd9364Slogwang return INT64_ALIGNMENT;
691*a1fd9364Slogwang }
692*a1fd9364Slogwang
693*a1fd9364Slogwang const struct ng_parse_type ng_parse_int64_type = {
694*a1fd9364Slogwang NULL,
695*a1fd9364Slogwang (void *)INT_SIGNED,
696*a1fd9364Slogwang NULL,
697*a1fd9364Slogwang ng_int64_parse,
698*a1fd9364Slogwang ng_int64_unparse,
699*a1fd9364Slogwang ng_int64_getDefault,
700*a1fd9364Slogwang ng_int64_getAlign
701*a1fd9364Slogwang };
702*a1fd9364Slogwang
703*a1fd9364Slogwang const struct ng_parse_type ng_parse_uint64_type = {
704*a1fd9364Slogwang &ng_parse_int64_type,
705*a1fd9364Slogwang (void *)INT_UNSIGNED
706*a1fd9364Slogwang };
707*a1fd9364Slogwang
708*a1fd9364Slogwang const struct ng_parse_type ng_parse_hint64_type = {
709*a1fd9364Slogwang &ng_parse_int64_type,
710*a1fd9364Slogwang (void *)INT_HEX
711*a1fd9364Slogwang };
712*a1fd9364Slogwang
713*a1fd9364Slogwang /************************************************************************
714*a1fd9364Slogwang STRING TYPE
715*a1fd9364Slogwang ************************************************************************/
716*a1fd9364Slogwang
717*a1fd9364Slogwang static int
ng_string_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)718*a1fd9364Slogwang ng_string_parse(const struct ng_parse_type *type,
719*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
720*a1fd9364Slogwang u_char *const buf, int *buflen)
721*a1fd9364Slogwang {
722*a1fd9364Slogwang char *sval;
723*a1fd9364Slogwang int len;
724*a1fd9364Slogwang int slen;
725*a1fd9364Slogwang
726*a1fd9364Slogwang if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
727*a1fd9364Slogwang return (EINVAL);
728*a1fd9364Slogwang *off += len;
729*a1fd9364Slogwang bcopy(sval, buf, slen + 1);
730*a1fd9364Slogwang free(sval, M_NETGRAPH_PARSE);
731*a1fd9364Slogwang *buflen = slen + 1;
732*a1fd9364Slogwang return (0);
733*a1fd9364Slogwang }
734*a1fd9364Slogwang
735*a1fd9364Slogwang static int
ng_string_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)736*a1fd9364Slogwang ng_string_unparse(const struct ng_parse_type *type,
737*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
738*a1fd9364Slogwang {
739*a1fd9364Slogwang const char *const raw = (const char *)data + *off;
740*a1fd9364Slogwang char *const s = ng_encode_string(raw, strlen(raw));
741*a1fd9364Slogwang int error;
742*a1fd9364Slogwang
743*a1fd9364Slogwang if (s == NULL)
744*a1fd9364Slogwang return (ENOMEM);
745*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf, &cbuflen, "%s", s)) != 0) {
746*a1fd9364Slogwang free(s, M_NETGRAPH_PARSE);
747*a1fd9364Slogwang return (error);
748*a1fd9364Slogwang }
749*a1fd9364Slogwang *off += strlen(raw) + 1;
750*a1fd9364Slogwang free(s, M_NETGRAPH_PARSE);
751*a1fd9364Slogwang return (0);
752*a1fd9364Slogwang }
753*a1fd9364Slogwang
754*a1fd9364Slogwang static int
ng_string_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)755*a1fd9364Slogwang ng_string_getDefault(const struct ng_parse_type *type,
756*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
757*a1fd9364Slogwang {
758*a1fd9364Slogwang
759*a1fd9364Slogwang if (*buflen < 1)
760*a1fd9364Slogwang return (ERANGE);
761*a1fd9364Slogwang buf[0] = (u_char)'\0';
762*a1fd9364Slogwang *buflen = 1;
763*a1fd9364Slogwang return (0);
764*a1fd9364Slogwang }
765*a1fd9364Slogwang
766*a1fd9364Slogwang const struct ng_parse_type ng_parse_string_type = {
767*a1fd9364Slogwang NULL,
768*a1fd9364Slogwang NULL,
769*a1fd9364Slogwang NULL,
770*a1fd9364Slogwang ng_string_parse,
771*a1fd9364Slogwang ng_string_unparse,
772*a1fd9364Slogwang ng_string_getDefault,
773*a1fd9364Slogwang NULL
774*a1fd9364Slogwang };
775*a1fd9364Slogwang
776*a1fd9364Slogwang /************************************************************************
777*a1fd9364Slogwang FIXED BUFFER STRING TYPE
778*a1fd9364Slogwang ************************************************************************/
779*a1fd9364Slogwang
780*a1fd9364Slogwang static int
ng_fixedstring_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)781*a1fd9364Slogwang ng_fixedstring_parse(const struct ng_parse_type *type,
782*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
783*a1fd9364Slogwang u_char *const buf, int *buflen)
784*a1fd9364Slogwang {
785*a1fd9364Slogwang const struct ng_parse_fixedstring_info *const fi = type->info;
786*a1fd9364Slogwang char *sval;
787*a1fd9364Slogwang int len;
788*a1fd9364Slogwang int slen;
789*a1fd9364Slogwang
790*a1fd9364Slogwang if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
791*a1fd9364Slogwang return (EINVAL);
792*a1fd9364Slogwang if (slen + 1 > fi->bufSize) {
793*a1fd9364Slogwang free(sval, M_NETGRAPH_PARSE);
794*a1fd9364Slogwang return (E2BIG);
795*a1fd9364Slogwang }
796*a1fd9364Slogwang *off += len;
797*a1fd9364Slogwang bcopy(sval, buf, slen);
798*a1fd9364Slogwang free(sval, M_NETGRAPH_PARSE);
799*a1fd9364Slogwang bzero(buf + slen, fi->bufSize - slen);
800*a1fd9364Slogwang *buflen = fi->bufSize;
801*a1fd9364Slogwang return (0);
802*a1fd9364Slogwang }
803*a1fd9364Slogwang
804*a1fd9364Slogwang static int
ng_fixedstring_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)805*a1fd9364Slogwang ng_fixedstring_unparse(const struct ng_parse_type *type,
806*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
807*a1fd9364Slogwang {
808*a1fd9364Slogwang const struct ng_parse_fixedstring_info *const fi = type->info;
809*a1fd9364Slogwang int error, temp = *off;
810*a1fd9364Slogwang
811*a1fd9364Slogwang if ((error = ng_string_unparse(type, data, &temp, cbuf, cbuflen)) != 0)
812*a1fd9364Slogwang return (error);
813*a1fd9364Slogwang *off += fi->bufSize;
814*a1fd9364Slogwang return (0);
815*a1fd9364Slogwang }
816*a1fd9364Slogwang
817*a1fd9364Slogwang static int
ng_fixedstring_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)818*a1fd9364Slogwang ng_fixedstring_getDefault(const struct ng_parse_type *type,
819*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
820*a1fd9364Slogwang {
821*a1fd9364Slogwang const struct ng_parse_fixedstring_info *const fi = type->info;
822*a1fd9364Slogwang
823*a1fd9364Slogwang if (*buflen < fi->bufSize)
824*a1fd9364Slogwang return (ERANGE);
825*a1fd9364Slogwang bzero(buf, fi->bufSize);
826*a1fd9364Slogwang *buflen = fi->bufSize;
827*a1fd9364Slogwang return (0);
828*a1fd9364Slogwang }
829*a1fd9364Slogwang
830*a1fd9364Slogwang const struct ng_parse_type ng_parse_fixedstring_type = {
831*a1fd9364Slogwang NULL,
832*a1fd9364Slogwang NULL,
833*a1fd9364Slogwang NULL,
834*a1fd9364Slogwang ng_fixedstring_parse,
835*a1fd9364Slogwang ng_fixedstring_unparse,
836*a1fd9364Slogwang ng_fixedstring_getDefault,
837*a1fd9364Slogwang NULL
838*a1fd9364Slogwang };
839*a1fd9364Slogwang
840*a1fd9364Slogwang const struct ng_parse_fixedstring_info ng_parse_nodebuf_info = {
841*a1fd9364Slogwang NG_NODESIZ
842*a1fd9364Slogwang };
843*a1fd9364Slogwang const struct ng_parse_type ng_parse_nodebuf_type = {
844*a1fd9364Slogwang &ng_parse_fixedstring_type,
845*a1fd9364Slogwang &ng_parse_nodebuf_info
846*a1fd9364Slogwang };
847*a1fd9364Slogwang
848*a1fd9364Slogwang const struct ng_parse_fixedstring_info ng_parse_hookbuf_info = {
849*a1fd9364Slogwang NG_HOOKSIZ
850*a1fd9364Slogwang };
851*a1fd9364Slogwang const struct ng_parse_type ng_parse_hookbuf_type = {
852*a1fd9364Slogwang &ng_parse_fixedstring_type,
853*a1fd9364Slogwang &ng_parse_hookbuf_info
854*a1fd9364Slogwang };
855*a1fd9364Slogwang
856*a1fd9364Slogwang const struct ng_parse_fixedstring_info ng_parse_pathbuf_info = {
857*a1fd9364Slogwang NG_PATHSIZ
858*a1fd9364Slogwang };
859*a1fd9364Slogwang const struct ng_parse_type ng_parse_pathbuf_type = {
860*a1fd9364Slogwang &ng_parse_fixedstring_type,
861*a1fd9364Slogwang &ng_parse_pathbuf_info
862*a1fd9364Slogwang };
863*a1fd9364Slogwang
864*a1fd9364Slogwang const struct ng_parse_fixedstring_info ng_parse_typebuf_info = {
865*a1fd9364Slogwang NG_TYPESIZ
866*a1fd9364Slogwang };
867*a1fd9364Slogwang const struct ng_parse_type ng_parse_typebuf_type = {
868*a1fd9364Slogwang &ng_parse_fixedstring_type,
869*a1fd9364Slogwang &ng_parse_typebuf_info
870*a1fd9364Slogwang };
871*a1fd9364Slogwang
872*a1fd9364Slogwang const struct ng_parse_fixedstring_info ng_parse_cmdbuf_info = {
873*a1fd9364Slogwang NG_CMDSTRSIZ
874*a1fd9364Slogwang };
875*a1fd9364Slogwang const struct ng_parse_type ng_parse_cmdbuf_type = {
876*a1fd9364Slogwang &ng_parse_fixedstring_type,
877*a1fd9364Slogwang &ng_parse_cmdbuf_info
878*a1fd9364Slogwang };
879*a1fd9364Slogwang
880*a1fd9364Slogwang /************************************************************************
881*a1fd9364Slogwang EXPLICITLY SIZED STRING TYPE
882*a1fd9364Slogwang ************************************************************************/
883*a1fd9364Slogwang
884*a1fd9364Slogwang static int
ng_sizedstring_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)885*a1fd9364Slogwang ng_sizedstring_parse(const struct ng_parse_type *type,
886*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
887*a1fd9364Slogwang u_char *const buf, int *buflen)
888*a1fd9364Slogwang {
889*a1fd9364Slogwang char *sval;
890*a1fd9364Slogwang int len;
891*a1fd9364Slogwang int slen;
892*a1fd9364Slogwang
893*a1fd9364Slogwang if ((sval = ng_get_string_token(s, off, &len, &slen)) == NULL)
894*a1fd9364Slogwang return (EINVAL);
895*a1fd9364Slogwang if (slen > USHRT_MAX) {
896*a1fd9364Slogwang free(sval, M_NETGRAPH_PARSE);
897*a1fd9364Slogwang return (EINVAL);
898*a1fd9364Slogwang }
899*a1fd9364Slogwang *off += len;
900*a1fd9364Slogwang *((u_int16_t *)buf) = (u_int16_t)slen;
901*a1fd9364Slogwang bcopy(sval, buf + 2, slen);
902*a1fd9364Slogwang free(sval, M_NETGRAPH_PARSE);
903*a1fd9364Slogwang *buflen = 2 + slen;
904*a1fd9364Slogwang return (0);
905*a1fd9364Slogwang }
906*a1fd9364Slogwang
907*a1fd9364Slogwang static int
ng_sizedstring_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)908*a1fd9364Slogwang ng_sizedstring_unparse(const struct ng_parse_type *type,
909*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
910*a1fd9364Slogwang {
911*a1fd9364Slogwang const char *const raw = (const char *)data + *off + 2;
912*a1fd9364Slogwang const int slen = *((const u_int16_t *)(data + *off));
913*a1fd9364Slogwang char *const s = ng_encode_string(raw, slen);
914*a1fd9364Slogwang int error;
915*a1fd9364Slogwang
916*a1fd9364Slogwang if (s == NULL)
917*a1fd9364Slogwang return (ENOMEM);
918*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf, &cbuflen, "%s", s)) != 0) {
919*a1fd9364Slogwang free(s, M_NETGRAPH_PARSE);
920*a1fd9364Slogwang return (error);
921*a1fd9364Slogwang }
922*a1fd9364Slogwang free(s, M_NETGRAPH_PARSE);
923*a1fd9364Slogwang *off += slen + 2;
924*a1fd9364Slogwang return (0);
925*a1fd9364Slogwang }
926*a1fd9364Slogwang
927*a1fd9364Slogwang static int
ng_sizedstring_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)928*a1fd9364Slogwang ng_sizedstring_getDefault(const struct ng_parse_type *type,
929*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
930*a1fd9364Slogwang {
931*a1fd9364Slogwang if (*buflen < 2)
932*a1fd9364Slogwang return (ERANGE);
933*a1fd9364Slogwang bzero(buf, 2);
934*a1fd9364Slogwang *buflen = 2;
935*a1fd9364Slogwang return (0);
936*a1fd9364Slogwang }
937*a1fd9364Slogwang
938*a1fd9364Slogwang const struct ng_parse_type ng_parse_sizedstring_type = {
939*a1fd9364Slogwang NULL,
940*a1fd9364Slogwang NULL,
941*a1fd9364Slogwang NULL,
942*a1fd9364Slogwang ng_sizedstring_parse,
943*a1fd9364Slogwang ng_sizedstring_unparse,
944*a1fd9364Slogwang ng_sizedstring_getDefault,
945*a1fd9364Slogwang NULL
946*a1fd9364Slogwang };
947*a1fd9364Slogwang
948*a1fd9364Slogwang /************************************************************************
949*a1fd9364Slogwang IP ADDRESS TYPE
950*a1fd9364Slogwang ************************************************************************/
951*a1fd9364Slogwang
952*a1fd9364Slogwang static int
ng_ipaddr_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)953*a1fd9364Slogwang ng_ipaddr_parse(const struct ng_parse_type *type,
954*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
955*a1fd9364Slogwang u_char *const buf, int *buflen)
956*a1fd9364Slogwang {
957*a1fd9364Slogwang int i, error;
958*a1fd9364Slogwang
959*a1fd9364Slogwang for (i = 0; i < 4; i++) {
960*a1fd9364Slogwang if ((error = ng_int8_parse(&ng_parse_int8_type,
961*a1fd9364Slogwang s, off, start, buf + i, buflen)) != 0)
962*a1fd9364Slogwang return (error);
963*a1fd9364Slogwang if (i < 3 && s[*off] != '.')
964*a1fd9364Slogwang return (EINVAL);
965*a1fd9364Slogwang (*off)++;
966*a1fd9364Slogwang }
967*a1fd9364Slogwang *buflen = 4;
968*a1fd9364Slogwang return (0);
969*a1fd9364Slogwang }
970*a1fd9364Slogwang
971*a1fd9364Slogwang static int
ng_ipaddr_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)972*a1fd9364Slogwang ng_ipaddr_unparse(const struct ng_parse_type *type,
973*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
974*a1fd9364Slogwang {
975*a1fd9364Slogwang struct in_addr ip;
976*a1fd9364Slogwang int error;
977*a1fd9364Slogwang
978*a1fd9364Slogwang bcopy(data + *off, &ip, sizeof(ip));
979*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf, &cbuflen, "%d.%d.%d.%d",
980*a1fd9364Slogwang ((u_char *)&ip)[0], ((u_char *)&ip)[1],
981*a1fd9364Slogwang ((u_char *)&ip)[2], ((u_char *)&ip)[3])) != 0)
982*a1fd9364Slogwang return (error);
983*a1fd9364Slogwang *off += sizeof(ip);
984*a1fd9364Slogwang return (0);
985*a1fd9364Slogwang }
986*a1fd9364Slogwang
987*a1fd9364Slogwang static int
ng_ipaddr_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)988*a1fd9364Slogwang ng_ipaddr_getDefault(const struct ng_parse_type *type,
989*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
990*a1fd9364Slogwang {
991*a1fd9364Slogwang struct in_addr ip = { 0 };
992*a1fd9364Slogwang
993*a1fd9364Slogwang if (*buflen < sizeof(ip))
994*a1fd9364Slogwang return (ERANGE);
995*a1fd9364Slogwang bcopy(&ip, buf, sizeof(ip));
996*a1fd9364Slogwang *buflen = sizeof(ip);
997*a1fd9364Slogwang return (0);
998*a1fd9364Slogwang }
999*a1fd9364Slogwang
1000*a1fd9364Slogwang const struct ng_parse_type ng_parse_ipaddr_type = {
1001*a1fd9364Slogwang NULL,
1002*a1fd9364Slogwang NULL,
1003*a1fd9364Slogwang NULL,
1004*a1fd9364Slogwang ng_ipaddr_parse,
1005*a1fd9364Slogwang ng_ipaddr_unparse,
1006*a1fd9364Slogwang ng_ipaddr_getDefault,
1007*a1fd9364Slogwang ng_int32_getAlign
1008*a1fd9364Slogwang };
1009*a1fd9364Slogwang
1010*a1fd9364Slogwang /************************************************************************
1011*a1fd9364Slogwang ETHERNET ADDRESS TYPE
1012*a1fd9364Slogwang ************************************************************************/
1013*a1fd9364Slogwang
1014*a1fd9364Slogwang static int
ng_enaddr_parse(const struct ng_parse_type * type,const char * s,int * const off,const u_char * const start,u_char * const buf,int * const buflen)1015*a1fd9364Slogwang ng_enaddr_parse(const struct ng_parse_type *type,
1016*a1fd9364Slogwang const char *s, int *const off, const u_char *const start,
1017*a1fd9364Slogwang u_char *const buf, int *const buflen)
1018*a1fd9364Slogwang {
1019*a1fd9364Slogwang char *eptr;
1020*a1fd9364Slogwang u_long val;
1021*a1fd9364Slogwang int i;
1022*a1fd9364Slogwang
1023*a1fd9364Slogwang if (*buflen < ETHER_ADDR_LEN)
1024*a1fd9364Slogwang return (ERANGE);
1025*a1fd9364Slogwang for (i = 0; i < ETHER_ADDR_LEN; i++) {
1026*a1fd9364Slogwang val = strtoul(s + *off, &eptr, 16);
1027*a1fd9364Slogwang if (val > 0xff || eptr == s + *off)
1028*a1fd9364Slogwang return (EINVAL);
1029*a1fd9364Slogwang buf[i] = (u_char)val;
1030*a1fd9364Slogwang *off = (eptr - s);
1031*a1fd9364Slogwang if (i < ETHER_ADDR_LEN - 1) {
1032*a1fd9364Slogwang if (*eptr != ':')
1033*a1fd9364Slogwang return (EINVAL);
1034*a1fd9364Slogwang (*off)++;
1035*a1fd9364Slogwang }
1036*a1fd9364Slogwang }
1037*a1fd9364Slogwang *buflen = ETHER_ADDR_LEN;
1038*a1fd9364Slogwang return (0);
1039*a1fd9364Slogwang }
1040*a1fd9364Slogwang
1041*a1fd9364Slogwang static int
ng_enaddr_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)1042*a1fd9364Slogwang ng_enaddr_unparse(const struct ng_parse_type *type,
1043*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
1044*a1fd9364Slogwang {
1045*a1fd9364Slogwang int len;
1046*a1fd9364Slogwang
1047*a1fd9364Slogwang len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x",
1048*a1fd9364Slogwang data[*off], data[*off + 1], data[*off + 2],
1049*a1fd9364Slogwang data[*off + 3], data[*off + 4], data[*off + 5]);
1050*a1fd9364Slogwang if (len >= cbuflen)
1051*a1fd9364Slogwang return (ERANGE);
1052*a1fd9364Slogwang *off += ETHER_ADDR_LEN;
1053*a1fd9364Slogwang return (0);
1054*a1fd9364Slogwang }
1055*a1fd9364Slogwang
1056*a1fd9364Slogwang const struct ng_parse_type ng_parse_enaddr_type = {
1057*a1fd9364Slogwang NULL,
1058*a1fd9364Slogwang NULL,
1059*a1fd9364Slogwang NULL,
1060*a1fd9364Slogwang ng_enaddr_parse,
1061*a1fd9364Slogwang ng_enaddr_unparse,
1062*a1fd9364Slogwang NULL,
1063*a1fd9364Slogwang 0
1064*a1fd9364Slogwang };
1065*a1fd9364Slogwang
1066*a1fd9364Slogwang /************************************************************************
1067*a1fd9364Slogwang BYTE ARRAY TYPE
1068*a1fd9364Slogwang ************************************************************************/
1069*a1fd9364Slogwang
1070*a1fd9364Slogwang /* Get the length of a byte array */
1071*a1fd9364Slogwang static int
ng_parse_bytearray_subtype_getLength(const struct ng_parse_type * type,const u_char * start,const u_char * buf)1072*a1fd9364Slogwang ng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
1073*a1fd9364Slogwang const u_char *start, const u_char *buf)
1074*a1fd9364Slogwang {
1075*a1fd9364Slogwang ng_parse_array_getLength_t *const getLength = type->private;
1076*a1fd9364Slogwang
1077*a1fd9364Slogwang return (*getLength)(type, start, buf);
1078*a1fd9364Slogwang }
1079*a1fd9364Slogwang
1080*a1fd9364Slogwang /* Byte array element type is hex int8 */
1081*a1fd9364Slogwang static const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
1082*a1fd9364Slogwang &ng_parse_hint8_type,
1083*a1fd9364Slogwang &ng_parse_bytearray_subtype_getLength,
1084*a1fd9364Slogwang NULL
1085*a1fd9364Slogwang };
1086*a1fd9364Slogwang static const struct ng_parse_type ng_parse_bytearray_subtype = {
1087*a1fd9364Slogwang &ng_parse_array_type,
1088*a1fd9364Slogwang &ng_parse_bytearray_subtype_info
1089*a1fd9364Slogwang };
1090*a1fd9364Slogwang
1091*a1fd9364Slogwang static int
ng_bytearray_parse(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen)1092*a1fd9364Slogwang ng_bytearray_parse(const struct ng_parse_type *type,
1093*a1fd9364Slogwang const char *s, int *off, const u_char *const start,
1094*a1fd9364Slogwang u_char *const buf, int *buflen)
1095*a1fd9364Slogwang {
1096*a1fd9364Slogwang char *str;
1097*a1fd9364Slogwang int toklen;
1098*a1fd9364Slogwang int slen;
1099*a1fd9364Slogwang
1100*a1fd9364Slogwang /* We accept either an array of bytes or a string constant */
1101*a1fd9364Slogwang if ((str = ng_get_string_token(s, off, &toklen, &slen)) != NULL) {
1102*a1fd9364Slogwang ng_parse_array_getLength_t *const getLength = type->info;
1103*a1fd9364Slogwang int arraylen;
1104*a1fd9364Slogwang
1105*a1fd9364Slogwang arraylen = (*getLength)(type, start, buf);
1106*a1fd9364Slogwang if (arraylen > *buflen) {
1107*a1fd9364Slogwang free(str, M_NETGRAPH_PARSE);
1108*a1fd9364Slogwang return (ERANGE);
1109*a1fd9364Slogwang }
1110*a1fd9364Slogwang if (slen > arraylen) {
1111*a1fd9364Slogwang free(str, M_NETGRAPH_PARSE);
1112*a1fd9364Slogwang return (E2BIG);
1113*a1fd9364Slogwang }
1114*a1fd9364Slogwang bcopy(str, buf, slen);
1115*a1fd9364Slogwang bzero(buf + slen, arraylen - slen);
1116*a1fd9364Slogwang free(str, M_NETGRAPH_PARSE);
1117*a1fd9364Slogwang *off += toklen;
1118*a1fd9364Slogwang *buflen = arraylen;
1119*a1fd9364Slogwang return (0);
1120*a1fd9364Slogwang } else {
1121*a1fd9364Slogwang struct ng_parse_type subtype;
1122*a1fd9364Slogwang
1123*a1fd9364Slogwang subtype = ng_parse_bytearray_subtype;
1124*a1fd9364Slogwang subtype.private = __DECONST(void *, type->info);
1125*a1fd9364Slogwang return ng_array_parse(&subtype, s, off, start, buf, buflen);
1126*a1fd9364Slogwang }
1127*a1fd9364Slogwang }
1128*a1fd9364Slogwang
1129*a1fd9364Slogwang static int
ng_bytearray_unparse(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen)1130*a1fd9364Slogwang ng_bytearray_unparse(const struct ng_parse_type *type,
1131*a1fd9364Slogwang const u_char *data, int *off, char *cbuf, int cbuflen)
1132*a1fd9364Slogwang {
1133*a1fd9364Slogwang struct ng_parse_type subtype;
1134*a1fd9364Slogwang
1135*a1fd9364Slogwang subtype = ng_parse_bytearray_subtype;
1136*a1fd9364Slogwang subtype.private = __DECONST(void *, type->info);
1137*a1fd9364Slogwang return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
1138*a1fd9364Slogwang }
1139*a1fd9364Slogwang
1140*a1fd9364Slogwang static int
ng_bytearray_getDefault(const struct ng_parse_type * type,const u_char * const start,u_char * buf,int * buflen)1141*a1fd9364Slogwang ng_bytearray_getDefault(const struct ng_parse_type *type,
1142*a1fd9364Slogwang const u_char *const start, u_char *buf, int *buflen)
1143*a1fd9364Slogwang {
1144*a1fd9364Slogwang struct ng_parse_type subtype;
1145*a1fd9364Slogwang
1146*a1fd9364Slogwang subtype = ng_parse_bytearray_subtype;
1147*a1fd9364Slogwang subtype.private = __DECONST(void *, type->info);
1148*a1fd9364Slogwang return ng_array_getDefault(&subtype, start, buf, buflen);
1149*a1fd9364Slogwang }
1150*a1fd9364Slogwang
1151*a1fd9364Slogwang const struct ng_parse_type ng_parse_bytearray_type = {
1152*a1fd9364Slogwang NULL,
1153*a1fd9364Slogwang NULL,
1154*a1fd9364Slogwang NULL,
1155*a1fd9364Slogwang ng_bytearray_parse,
1156*a1fd9364Slogwang ng_bytearray_unparse,
1157*a1fd9364Slogwang ng_bytearray_getDefault,
1158*a1fd9364Slogwang NULL
1159*a1fd9364Slogwang };
1160*a1fd9364Slogwang
1161*a1fd9364Slogwang /************************************************************************
1162*a1fd9364Slogwang STRUCT NG_MESG TYPE
1163*a1fd9364Slogwang ************************************************************************/
1164*a1fd9364Slogwang
1165*a1fd9364Slogwang /* Get msg->header.arglen when "buf" is pointing to msg->data */
1166*a1fd9364Slogwang static int
ng_parse_ng_mesg_getLength(const struct ng_parse_type * type,const u_char * start,const u_char * buf)1167*a1fd9364Slogwang ng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
1168*a1fd9364Slogwang const u_char *start, const u_char *buf)
1169*a1fd9364Slogwang {
1170*a1fd9364Slogwang const struct ng_mesg *msg;
1171*a1fd9364Slogwang
1172*a1fd9364Slogwang msg = (const struct ng_mesg *)(buf - sizeof(*msg));
1173*a1fd9364Slogwang return msg->header.arglen;
1174*a1fd9364Slogwang }
1175*a1fd9364Slogwang
1176*a1fd9364Slogwang /* Type for the variable length data portion of a struct ng_mesg */
1177*a1fd9364Slogwang static const struct ng_parse_type ng_msg_data_type = {
1178*a1fd9364Slogwang &ng_parse_bytearray_type,
1179*a1fd9364Slogwang &ng_parse_ng_mesg_getLength
1180*a1fd9364Slogwang };
1181*a1fd9364Slogwang
1182*a1fd9364Slogwang /* Type for the entire struct ng_mesg header with data section */
1183*a1fd9364Slogwang static const struct ng_parse_struct_field ng_parse_ng_mesg_type_fields[]
1184*a1fd9364Slogwang = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
1185*a1fd9364Slogwang const struct ng_parse_type ng_parse_ng_mesg_type = {
1186*a1fd9364Slogwang &ng_parse_struct_type,
1187*a1fd9364Slogwang &ng_parse_ng_mesg_type_fields,
1188*a1fd9364Slogwang };
1189*a1fd9364Slogwang
1190*a1fd9364Slogwang /************************************************************************
1191*a1fd9364Slogwang COMPOSITE HELPER ROUTINES
1192*a1fd9364Slogwang ************************************************************************/
1193*a1fd9364Slogwang
1194*a1fd9364Slogwang /*
1195*a1fd9364Slogwang * Convert a structure or array from ASCII to binary
1196*a1fd9364Slogwang */
1197*a1fd9364Slogwang static int
ng_parse_composite(const struct ng_parse_type * type,const char * s,int * off,const u_char * const start,u_char * const buf,int * buflen,const enum comptype ctype)1198*a1fd9364Slogwang ng_parse_composite(const struct ng_parse_type *type, const char *s,
1199*a1fd9364Slogwang int *off, const u_char *const start, u_char *const buf, int *buflen,
1200*a1fd9364Slogwang const enum comptype ctype)
1201*a1fd9364Slogwang {
1202*a1fd9364Slogwang const int num = ng_get_composite_len(type, start, buf, ctype);
1203*a1fd9364Slogwang int nextIndex = 0; /* next implicit array index */
1204*a1fd9364Slogwang u_int index; /* field or element index */
1205*a1fd9364Slogwang int *foff; /* field value offsets in string */
1206*a1fd9364Slogwang int align, len, blen, error = 0;
1207*a1fd9364Slogwang
1208*a1fd9364Slogwang /* Initialize */
1209*a1fd9364Slogwang foff = malloc(num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO);
1210*a1fd9364Slogwang if (foff == NULL) {
1211*a1fd9364Slogwang error = ENOMEM;
1212*a1fd9364Slogwang goto done;
1213*a1fd9364Slogwang }
1214*a1fd9364Slogwang
1215*a1fd9364Slogwang /* Get opening brace/bracket */
1216*a1fd9364Slogwang if (ng_parse_get_token(s, off, &len)
1217*a1fd9364Slogwang != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
1218*a1fd9364Slogwang error = EINVAL;
1219*a1fd9364Slogwang goto done;
1220*a1fd9364Slogwang }
1221*a1fd9364Slogwang *off += len;
1222*a1fd9364Slogwang
1223*a1fd9364Slogwang /* Get individual element value positions in the string */
1224*a1fd9364Slogwang for (;;) {
1225*a1fd9364Slogwang enum ng_parse_token tok;
1226*a1fd9364Slogwang
1227*a1fd9364Slogwang /* Check for closing brace/bracket */
1228*a1fd9364Slogwang tok = ng_parse_get_token(s, off, &len);
1229*a1fd9364Slogwang if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
1230*a1fd9364Slogwang *off += len;
1231*a1fd9364Slogwang break;
1232*a1fd9364Slogwang }
1233*a1fd9364Slogwang
1234*a1fd9364Slogwang /* For arrays, the 'name' (ie, index) is optional, so
1235*a1fd9364Slogwang distinguish name from values by seeing if the next
1236*a1fd9364Slogwang token is an equals sign */
1237*a1fd9364Slogwang if (ctype != CT_STRUCT) {
1238*a1fd9364Slogwang u_long ul;
1239*a1fd9364Slogwang int len2, off2;
1240*a1fd9364Slogwang char *eptr;
1241*a1fd9364Slogwang
1242*a1fd9364Slogwang /* If an opening brace/bracket, index is implied */
1243*a1fd9364Slogwang if (tok == T_LBRACE || tok == T_LBRACKET) {
1244*a1fd9364Slogwang index = nextIndex++;
1245*a1fd9364Slogwang goto gotIndex;
1246*a1fd9364Slogwang }
1247*a1fd9364Slogwang
1248*a1fd9364Slogwang /* Might be an index, might be a value, either way... */
1249*a1fd9364Slogwang if (tok != T_WORD) {
1250*a1fd9364Slogwang error = EINVAL;
1251*a1fd9364Slogwang goto done;
1252*a1fd9364Slogwang }
1253*a1fd9364Slogwang
1254*a1fd9364Slogwang /* If no equals sign follows, index is implied */
1255*a1fd9364Slogwang off2 = *off + len;
1256*a1fd9364Slogwang if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
1257*a1fd9364Slogwang index = nextIndex++;
1258*a1fd9364Slogwang goto gotIndex;
1259*a1fd9364Slogwang }
1260*a1fd9364Slogwang
1261*a1fd9364Slogwang /* Index was specified explicitly; parse it */
1262*a1fd9364Slogwang ul = strtoul(s + *off, &eptr, 0);
1263*a1fd9364Slogwang if (ul == ULONG_MAX || eptr - (s + *off) != len) {
1264*a1fd9364Slogwang error = EINVAL;
1265*a1fd9364Slogwang goto done;
1266*a1fd9364Slogwang }
1267*a1fd9364Slogwang index = (u_int)ul;
1268*a1fd9364Slogwang nextIndex = index + 1;
1269*a1fd9364Slogwang *off += len + len2;
1270*a1fd9364Slogwang } else { /* a structure field */
1271*a1fd9364Slogwang const struct ng_parse_struct_field *const
1272*a1fd9364Slogwang fields = type->info;
1273*a1fd9364Slogwang
1274*a1fd9364Slogwang /* Find the field by name (required) in field list */
1275*a1fd9364Slogwang if (tok != T_WORD) {
1276*a1fd9364Slogwang error = EINVAL;
1277*a1fd9364Slogwang goto done;
1278*a1fd9364Slogwang }
1279*a1fd9364Slogwang for (index = 0; index < num; index++) {
1280*a1fd9364Slogwang const struct ng_parse_struct_field *const
1281*a1fd9364Slogwang field = &fields[index];
1282*a1fd9364Slogwang
1283*a1fd9364Slogwang if (strncmp(&s[*off], field->name, len) == 0
1284*a1fd9364Slogwang && field->name[len] == '\0')
1285*a1fd9364Slogwang break;
1286*a1fd9364Slogwang }
1287*a1fd9364Slogwang if (index == num) {
1288*a1fd9364Slogwang error = ENOENT;
1289*a1fd9364Slogwang goto done;
1290*a1fd9364Slogwang }
1291*a1fd9364Slogwang *off += len;
1292*a1fd9364Slogwang
1293*a1fd9364Slogwang /* Get equals sign */
1294*a1fd9364Slogwang if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
1295*a1fd9364Slogwang error = EINVAL;
1296*a1fd9364Slogwang goto done;
1297*a1fd9364Slogwang }
1298*a1fd9364Slogwang *off += len;
1299*a1fd9364Slogwang }
1300*a1fd9364Slogwang gotIndex:
1301*a1fd9364Slogwang
1302*a1fd9364Slogwang /* Check array index */
1303*a1fd9364Slogwang if (index >= num) {
1304*a1fd9364Slogwang error = E2BIG;
1305*a1fd9364Slogwang goto done;
1306*a1fd9364Slogwang }
1307*a1fd9364Slogwang
1308*a1fd9364Slogwang /* Save value's position and skip over it for now */
1309*a1fd9364Slogwang if (foff[index] != 0) {
1310*a1fd9364Slogwang error = EALREADY; /* duplicate */
1311*a1fd9364Slogwang goto done;
1312*a1fd9364Slogwang }
1313*a1fd9364Slogwang while (isspace(s[*off]))
1314*a1fd9364Slogwang (*off)++;
1315*a1fd9364Slogwang foff[index] = *off;
1316*a1fd9364Slogwang if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
1317*a1fd9364Slogwang goto done;
1318*a1fd9364Slogwang *off += len;
1319*a1fd9364Slogwang }
1320*a1fd9364Slogwang
1321*a1fd9364Slogwang /* Now build binary structure from supplied values and defaults */
1322*a1fd9364Slogwang for (blen = index = 0; index < num; index++) {
1323*a1fd9364Slogwang const struct ng_parse_type *const
1324*a1fd9364Slogwang etype = ng_get_composite_etype(type, index, ctype);
1325*a1fd9364Slogwang int k, pad, vlen;
1326*a1fd9364Slogwang
1327*a1fd9364Slogwang /* Zero-pad any alignment bytes */
1328*a1fd9364Slogwang pad = ng_parse_get_elem_pad(type, index, ctype, blen);
1329*a1fd9364Slogwang for (k = 0; k < pad; k++) {
1330*a1fd9364Slogwang if (blen >= *buflen) {
1331*a1fd9364Slogwang error = ERANGE;
1332*a1fd9364Slogwang goto done;
1333*a1fd9364Slogwang }
1334*a1fd9364Slogwang buf[blen++] = 0;
1335*a1fd9364Slogwang }
1336*a1fd9364Slogwang
1337*a1fd9364Slogwang /* Get value */
1338*a1fd9364Slogwang vlen = *buflen - blen;
1339*a1fd9364Slogwang if (foff[index] == 0) { /* use default value */
1340*a1fd9364Slogwang error = ng_get_composite_elem_default(type, index,
1341*a1fd9364Slogwang start, buf + blen, &vlen, ctype);
1342*a1fd9364Slogwang } else { /* parse given value */
1343*a1fd9364Slogwang *off = foff[index];
1344*a1fd9364Slogwang error = INVOKE(etype, parse)(etype,
1345*a1fd9364Slogwang s, off, start, buf + blen, &vlen);
1346*a1fd9364Slogwang }
1347*a1fd9364Slogwang if (error != 0)
1348*a1fd9364Slogwang goto done;
1349*a1fd9364Slogwang blen += vlen;
1350*a1fd9364Slogwang }
1351*a1fd9364Slogwang
1352*a1fd9364Slogwang /* Make total composite structure size a multiple of its alignment */
1353*a1fd9364Slogwang if ((align = ALIGNMENT(type)) != 0) {
1354*a1fd9364Slogwang while (blen % align != 0) {
1355*a1fd9364Slogwang if (blen >= *buflen) {
1356*a1fd9364Slogwang error = ERANGE;
1357*a1fd9364Slogwang goto done;
1358*a1fd9364Slogwang }
1359*a1fd9364Slogwang buf[blen++] = 0;
1360*a1fd9364Slogwang }
1361*a1fd9364Slogwang }
1362*a1fd9364Slogwang
1363*a1fd9364Slogwang /* Done */
1364*a1fd9364Slogwang *buflen = blen;
1365*a1fd9364Slogwang done:
1366*a1fd9364Slogwang if (foff != NULL)
1367*a1fd9364Slogwang free(foff, M_NETGRAPH_PARSE);
1368*a1fd9364Slogwang return (error);
1369*a1fd9364Slogwang }
1370*a1fd9364Slogwang
1371*a1fd9364Slogwang /*
1372*a1fd9364Slogwang * Convert an array or structure from binary to ASCII
1373*a1fd9364Slogwang */
1374*a1fd9364Slogwang static int
ng_unparse_composite(const struct ng_parse_type * type,const u_char * data,int * off,char * cbuf,int cbuflen,const enum comptype ctype)1375*a1fd9364Slogwang ng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
1376*a1fd9364Slogwang int *off, char *cbuf, int cbuflen, const enum comptype ctype)
1377*a1fd9364Slogwang {
1378*a1fd9364Slogwang const struct ng_mesg *const hdr
1379*a1fd9364Slogwang = (const struct ng_mesg *)(data - sizeof(*hdr));
1380*a1fd9364Slogwang const int num = ng_get_composite_len(type, data, data + *off, ctype);
1381*a1fd9364Slogwang const int workSize = 20 * 1024; /* XXX hard coded constant */
1382*a1fd9364Slogwang int nextIndex = 0, didOne = 0;
1383*a1fd9364Slogwang int error, index;
1384*a1fd9364Slogwang u_char *workBuf;
1385*a1fd9364Slogwang
1386*a1fd9364Slogwang /* Get workspace for checking default values */
1387*a1fd9364Slogwang workBuf = malloc(workSize, M_NETGRAPH_PARSE, M_NOWAIT);
1388*a1fd9364Slogwang if (workBuf == NULL)
1389*a1fd9364Slogwang return (ENOMEM);
1390*a1fd9364Slogwang
1391*a1fd9364Slogwang /* Opening brace/bracket */
1392*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf, &cbuflen, "%c",
1393*a1fd9364Slogwang (ctype == CT_STRUCT) ? '{' : '[')) != 0)
1394*a1fd9364Slogwang goto fail;
1395*a1fd9364Slogwang
1396*a1fd9364Slogwang /* Do each item */
1397*a1fd9364Slogwang for (index = 0; index < num; index++) {
1398*a1fd9364Slogwang const struct ng_parse_type *const
1399*a1fd9364Slogwang etype = ng_get_composite_etype(type, index, ctype);
1400*a1fd9364Slogwang
1401*a1fd9364Slogwang /* Skip any alignment pad bytes */
1402*a1fd9364Slogwang *off += ng_parse_get_elem_pad(type, index, ctype, *off);
1403*a1fd9364Slogwang
1404*a1fd9364Slogwang /*
1405*a1fd9364Slogwang * See if element is equal to its default value; skip if so.
1406*a1fd9364Slogwang * Copy struct ng_mesg header for types that peek into it.
1407*a1fd9364Slogwang */
1408*a1fd9364Slogwang if (sizeof(*hdr) + *off < workSize) {
1409*a1fd9364Slogwang int tempsize = workSize - sizeof(*hdr) - *off;
1410*a1fd9364Slogwang
1411*a1fd9364Slogwang bcopy(hdr, workBuf, sizeof(*hdr) + *off);
1412*a1fd9364Slogwang if (ng_get_composite_elem_default(type, index, workBuf
1413*a1fd9364Slogwang + sizeof(*hdr), workBuf + sizeof(*hdr) + *off,
1414*a1fd9364Slogwang &tempsize, ctype) == 0
1415*a1fd9364Slogwang && bcmp(workBuf + sizeof(*hdr) + *off,
1416*a1fd9364Slogwang data + *off, tempsize) == 0) {
1417*a1fd9364Slogwang *off += tempsize;
1418*a1fd9364Slogwang continue;
1419*a1fd9364Slogwang }
1420*a1fd9364Slogwang }
1421*a1fd9364Slogwang
1422*a1fd9364Slogwang /* Print name= */
1423*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf, &cbuflen, " ")) != 0)
1424*a1fd9364Slogwang goto fail;
1425*a1fd9364Slogwang if (ctype != CT_STRUCT) {
1426*a1fd9364Slogwang if (index != nextIndex) {
1427*a1fd9364Slogwang nextIndex = index;
1428*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf,
1429*a1fd9364Slogwang &cbuflen, "%d=", index)) != 0)
1430*a1fd9364Slogwang goto fail;
1431*a1fd9364Slogwang }
1432*a1fd9364Slogwang nextIndex++;
1433*a1fd9364Slogwang } else {
1434*a1fd9364Slogwang const struct ng_parse_struct_field *const
1435*a1fd9364Slogwang fields = type->info;
1436*a1fd9364Slogwang
1437*a1fd9364Slogwang if ((error = ng_parse_append(&cbuf,
1438*a1fd9364Slogwang &cbuflen, "%s=", fields[index].name)) != 0)
1439*a1fd9364Slogwang goto fail;
1440*a1fd9364Slogwang }
1441*a1fd9364Slogwang
1442*a1fd9364Slogwang /* Print value */
1443*a1fd9364Slogwang if ((error = INVOKE(etype, unparse)
1444*a1fd9364Slogwang (etype, data, off, cbuf, cbuflen)) != 0) {
1445*a1fd9364Slogwang free(workBuf, M_NETGRAPH_PARSE);
1446*a1fd9364Slogwang return (error);
1447*a1fd9364Slogwang }
1448*a1fd9364Slogwang cbuflen -= strlen(cbuf);
1449*a1fd9364Slogwang cbuf += strlen(cbuf);
1450*a1fd9364Slogwang didOne = 1;
1451*a1fd9364Slogwang }
1452*a1fd9364Slogwang
1453*a1fd9364Slogwang /* Closing brace/bracket */
1454*a1fd9364Slogwang error = ng_parse_append(&cbuf, &cbuflen, "%s%c",
1455*a1fd9364Slogwang didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
1456*a1fd9364Slogwang
1457*a1fd9364Slogwang fail:
1458*a1fd9364Slogwang /* Clean up after failure */
1459*a1fd9364Slogwang free(workBuf, M_NETGRAPH_PARSE);
1460*a1fd9364Slogwang return (error);
1461*a1fd9364Slogwang }
1462*a1fd9364Slogwang
1463*a1fd9364Slogwang /*
1464*a1fd9364Slogwang * Generate the default value for an element of an array or structure
1465*a1fd9364Slogwang * Returns EOPNOTSUPP if default value is unspecified.
1466*a1fd9364Slogwang */
1467*a1fd9364Slogwang static int
ng_get_composite_elem_default(const struct ng_parse_type * type,int index,const u_char * const start,u_char * buf,int * buflen,const enum comptype ctype)1468*a1fd9364Slogwang ng_get_composite_elem_default(const struct ng_parse_type *type,
1469*a1fd9364Slogwang int index, const u_char *const start, u_char *buf, int *buflen,
1470*a1fd9364Slogwang const enum comptype ctype)
1471*a1fd9364Slogwang {
1472*a1fd9364Slogwang const struct ng_parse_type *etype;
1473*a1fd9364Slogwang ng_getDefault_t *func;
1474*a1fd9364Slogwang
1475*a1fd9364Slogwang switch (ctype) {
1476*a1fd9364Slogwang case CT_STRUCT:
1477*a1fd9364Slogwang break;
1478*a1fd9364Slogwang case CT_ARRAY:
1479*a1fd9364Slogwang {
1480*a1fd9364Slogwang const struct ng_parse_array_info *const ai = type->info;
1481*a1fd9364Slogwang
1482*a1fd9364Slogwang if (ai->getDefault != NULL) {
1483*a1fd9364Slogwang return (*ai->getDefault)(type,
1484*a1fd9364Slogwang index, start, buf, buflen);
1485*a1fd9364Slogwang }
1486*a1fd9364Slogwang break;
1487*a1fd9364Slogwang }
1488*a1fd9364Slogwang case CT_FIXEDARRAY:
1489*a1fd9364Slogwang {
1490*a1fd9364Slogwang const struct ng_parse_fixedarray_info *const fi = type->info;
1491*a1fd9364Slogwang
1492*a1fd9364Slogwang if (*fi->getDefault != NULL) {
1493*a1fd9364Slogwang return (*fi->getDefault)(type,
1494*a1fd9364Slogwang index, start, buf, buflen);
1495*a1fd9364Slogwang }
1496*a1fd9364Slogwang break;
1497*a1fd9364Slogwang }
1498*a1fd9364Slogwang default:
1499*a1fd9364Slogwang panic("%s", __func__);
1500*a1fd9364Slogwang }
1501*a1fd9364Slogwang
1502*a1fd9364Slogwang /* Default to element type default */
1503*a1fd9364Slogwang etype = ng_get_composite_etype(type, index, ctype);
1504*a1fd9364Slogwang func = METHOD(etype, getDefault);
1505*a1fd9364Slogwang if (func == NULL)
1506*a1fd9364Slogwang return (EOPNOTSUPP);
1507*a1fd9364Slogwang return (*func)(etype, start, buf, buflen);
1508*a1fd9364Slogwang }
1509*a1fd9364Slogwang
1510*a1fd9364Slogwang /*
1511*a1fd9364Slogwang * Get the number of elements in a struct, variable or fixed array.
1512*a1fd9364Slogwang */
1513*a1fd9364Slogwang static int
ng_get_composite_len(const struct ng_parse_type * type,const u_char * const start,const u_char * buf,const enum comptype ctype)1514*a1fd9364Slogwang ng_get_composite_len(const struct ng_parse_type *type,
1515*a1fd9364Slogwang const u_char *const start, const u_char *buf,
1516*a1fd9364Slogwang const enum comptype ctype)
1517*a1fd9364Slogwang {
1518*a1fd9364Slogwang switch (ctype) {
1519*a1fd9364Slogwang case CT_STRUCT:
1520*a1fd9364Slogwang {
1521*a1fd9364Slogwang const struct ng_parse_struct_field *const fields = type->info;
1522*a1fd9364Slogwang int numFields = 0;
1523*a1fd9364Slogwang
1524*a1fd9364Slogwang for (numFields = 0; ; numFields++) {
1525*a1fd9364Slogwang const struct ng_parse_struct_field *const
1526*a1fd9364Slogwang fi = &fields[numFields];
1527*a1fd9364Slogwang
1528*a1fd9364Slogwang if (fi->name == NULL)
1529*a1fd9364Slogwang break;
1530*a1fd9364Slogwang }
1531*a1fd9364Slogwang return (numFields);
1532*a1fd9364Slogwang }
1533*a1fd9364Slogwang case CT_ARRAY:
1534*a1fd9364Slogwang {
1535*a1fd9364Slogwang const struct ng_parse_array_info *const ai = type->info;
1536*a1fd9364Slogwang
1537*a1fd9364Slogwang return (*ai->getLength)(type, start, buf);
1538*a1fd9364Slogwang }
1539*a1fd9364Slogwang case CT_FIXEDARRAY:
1540*a1fd9364Slogwang {
1541*a1fd9364Slogwang const struct ng_parse_fixedarray_info *const fi = type->info;
1542*a1fd9364Slogwang
1543*a1fd9364Slogwang return fi->length;
1544*a1fd9364Slogwang }
1545*a1fd9364Slogwang default:
1546*a1fd9364Slogwang panic("%s", __func__);
1547*a1fd9364Slogwang }
1548*a1fd9364Slogwang return (0);
1549*a1fd9364Slogwang }
1550*a1fd9364Slogwang
1551*a1fd9364Slogwang /*
1552*a1fd9364Slogwang * Return the type of the index'th element of a composite structure
1553*a1fd9364Slogwang */
1554*a1fd9364Slogwang static const struct ng_parse_type *
ng_get_composite_etype(const struct ng_parse_type * type,int index,const enum comptype ctype)1555*a1fd9364Slogwang ng_get_composite_etype(const struct ng_parse_type *type,
1556*a1fd9364Slogwang int index, const enum comptype ctype)
1557*a1fd9364Slogwang {
1558*a1fd9364Slogwang const struct ng_parse_type *etype = NULL;
1559*a1fd9364Slogwang
1560*a1fd9364Slogwang switch (ctype) {
1561*a1fd9364Slogwang case CT_STRUCT:
1562*a1fd9364Slogwang {
1563*a1fd9364Slogwang const struct ng_parse_struct_field *const fields = type->info;
1564*a1fd9364Slogwang
1565*a1fd9364Slogwang etype = fields[index].type;
1566*a1fd9364Slogwang break;
1567*a1fd9364Slogwang }
1568*a1fd9364Slogwang case CT_ARRAY:
1569*a1fd9364Slogwang {
1570*a1fd9364Slogwang const struct ng_parse_array_info *const ai = type->info;
1571*a1fd9364Slogwang
1572*a1fd9364Slogwang etype = ai->elementType;
1573*a1fd9364Slogwang break;
1574*a1fd9364Slogwang }
1575*a1fd9364Slogwang case CT_FIXEDARRAY:
1576*a1fd9364Slogwang {
1577*a1fd9364Slogwang const struct ng_parse_fixedarray_info *const fi = type->info;
1578*a1fd9364Slogwang
1579*a1fd9364Slogwang etype = fi->elementType;
1580*a1fd9364Slogwang break;
1581*a1fd9364Slogwang }
1582*a1fd9364Slogwang default:
1583*a1fd9364Slogwang panic("%s", __func__);
1584*a1fd9364Slogwang }
1585*a1fd9364Slogwang return (etype);
1586*a1fd9364Slogwang }
1587*a1fd9364Slogwang
1588*a1fd9364Slogwang /*
1589*a1fd9364Slogwang * Get the number of bytes to skip to align for the next
1590*a1fd9364Slogwang * element in a composite structure.
1591*a1fd9364Slogwang */
1592*a1fd9364Slogwang static int
ng_parse_get_elem_pad(const struct ng_parse_type * type,int index,enum comptype ctype,int posn)1593*a1fd9364Slogwang ng_parse_get_elem_pad(const struct ng_parse_type *type,
1594*a1fd9364Slogwang int index, enum comptype ctype, int posn)
1595*a1fd9364Slogwang {
1596*a1fd9364Slogwang const struct ng_parse_type *const
1597*a1fd9364Slogwang etype = ng_get_composite_etype(type, index, ctype);
1598*a1fd9364Slogwang int align;
1599*a1fd9364Slogwang
1600*a1fd9364Slogwang /* Get element's alignment, and possibly override */
1601*a1fd9364Slogwang align = ALIGNMENT(etype);
1602*a1fd9364Slogwang if (ctype == CT_STRUCT) {
1603*a1fd9364Slogwang const struct ng_parse_struct_field *const fields = type->info;
1604*a1fd9364Slogwang
1605*a1fd9364Slogwang if (fields[index].alignment != 0)
1606*a1fd9364Slogwang align = fields[index].alignment;
1607*a1fd9364Slogwang }
1608*a1fd9364Slogwang
1609*a1fd9364Slogwang /* Return number of bytes to skip to align */
1610*a1fd9364Slogwang return (align ? (align - (posn % align)) % align : 0);
1611*a1fd9364Slogwang }
1612*a1fd9364Slogwang
1613*a1fd9364Slogwang /************************************************************************
1614*a1fd9364Slogwang PARSING HELPER ROUTINES
1615*a1fd9364Slogwang ************************************************************************/
1616*a1fd9364Slogwang
1617*a1fd9364Slogwang /*
1618*a1fd9364Slogwang * Append to a fixed length string buffer.
1619*a1fd9364Slogwang */
1620*a1fd9364Slogwang static int
ng_parse_append(char ** cbufp,int * cbuflenp,const char * fmt,...)1621*a1fd9364Slogwang ng_parse_append(char **cbufp, int *cbuflenp, const char *fmt, ...)
1622*a1fd9364Slogwang {
1623*a1fd9364Slogwang va_list args;
1624*a1fd9364Slogwang int len;
1625*a1fd9364Slogwang
1626*a1fd9364Slogwang va_start(args, fmt);
1627*a1fd9364Slogwang len = vsnprintf(*cbufp, *cbuflenp, fmt, args);
1628*a1fd9364Slogwang va_end(args);
1629*a1fd9364Slogwang if (len >= *cbuflenp)
1630*a1fd9364Slogwang return ERANGE;
1631*a1fd9364Slogwang *cbufp += len;
1632*a1fd9364Slogwang *cbuflenp -= len;
1633*a1fd9364Slogwang
1634*a1fd9364Slogwang return (0);
1635*a1fd9364Slogwang }
1636*a1fd9364Slogwang
1637*a1fd9364Slogwang /*
1638*a1fd9364Slogwang * Skip over a value
1639*a1fd9364Slogwang */
1640*a1fd9364Slogwang static int
ng_parse_skip_value(const char * s,int off0,int * lenp)1641*a1fd9364Slogwang ng_parse_skip_value(const char *s, int off0, int *lenp)
1642*a1fd9364Slogwang {
1643*a1fd9364Slogwang int len, nbracket, nbrace;
1644*a1fd9364Slogwang int off = off0;
1645*a1fd9364Slogwang
1646*a1fd9364Slogwang len = nbracket = nbrace = 0;
1647*a1fd9364Slogwang do {
1648*a1fd9364Slogwang switch (ng_parse_get_token(s, &off, &len)) {
1649*a1fd9364Slogwang case T_LBRACKET:
1650*a1fd9364Slogwang nbracket++;
1651*a1fd9364Slogwang break;
1652*a1fd9364Slogwang case T_LBRACE:
1653*a1fd9364Slogwang nbrace++;
1654*a1fd9364Slogwang break;
1655*a1fd9364Slogwang case T_RBRACKET:
1656*a1fd9364Slogwang if (nbracket-- == 0)
1657*a1fd9364Slogwang return (EINVAL);
1658*a1fd9364Slogwang break;
1659*a1fd9364Slogwang case T_RBRACE:
1660*a1fd9364Slogwang if (nbrace-- == 0)
1661*a1fd9364Slogwang return (EINVAL);
1662*a1fd9364Slogwang break;
1663*a1fd9364Slogwang case T_EOF:
1664*a1fd9364Slogwang return (EINVAL);
1665*a1fd9364Slogwang default:
1666*a1fd9364Slogwang break;
1667*a1fd9364Slogwang }
1668*a1fd9364Slogwang off += len;
1669*a1fd9364Slogwang } while (nbracket > 0 || nbrace > 0);
1670*a1fd9364Slogwang *lenp = off - off0;
1671*a1fd9364Slogwang return (0);
1672*a1fd9364Slogwang }
1673*a1fd9364Slogwang
1674*a1fd9364Slogwang /*
1675*a1fd9364Slogwang * Find the next token in the string, starting at offset *startp.
1676*a1fd9364Slogwang * Returns the token type, with *startp pointing to the first char
1677*a1fd9364Slogwang * and *lenp the length.
1678*a1fd9364Slogwang */
1679*a1fd9364Slogwang enum ng_parse_token
ng_parse_get_token(const char * s,int * startp,int * lenp)1680*a1fd9364Slogwang ng_parse_get_token(const char *s, int *startp, int *lenp)
1681*a1fd9364Slogwang {
1682*a1fd9364Slogwang char *t;
1683*a1fd9364Slogwang int i;
1684*a1fd9364Slogwang
1685*a1fd9364Slogwang while (isspace(s[*startp]))
1686*a1fd9364Slogwang (*startp)++;
1687*a1fd9364Slogwang switch (s[*startp]) {
1688*a1fd9364Slogwang case '\0':
1689*a1fd9364Slogwang *lenp = 0;
1690*a1fd9364Slogwang return T_EOF;
1691*a1fd9364Slogwang case '{':
1692*a1fd9364Slogwang *lenp = 1;
1693*a1fd9364Slogwang return T_LBRACE;
1694*a1fd9364Slogwang case '}':
1695*a1fd9364Slogwang *lenp = 1;
1696*a1fd9364Slogwang return T_RBRACE;
1697*a1fd9364Slogwang case '[':
1698*a1fd9364Slogwang *lenp = 1;
1699*a1fd9364Slogwang return T_LBRACKET;
1700*a1fd9364Slogwang case ']':
1701*a1fd9364Slogwang *lenp = 1;
1702*a1fd9364Slogwang return T_RBRACKET;
1703*a1fd9364Slogwang case '=':
1704*a1fd9364Slogwang *lenp = 1;
1705*a1fd9364Slogwang return T_EQUALS;
1706*a1fd9364Slogwang case '"':
1707*a1fd9364Slogwang if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
1708*a1fd9364Slogwang return T_ERROR;
1709*a1fd9364Slogwang free(t, M_NETGRAPH_PARSE);
1710*a1fd9364Slogwang return T_STRING;
1711*a1fd9364Slogwang default:
1712*a1fd9364Slogwang for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
1713*a1fd9364Slogwang && s[i] != '{' && s[i] != '}' && s[i] != '['
1714*a1fd9364Slogwang && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
1715*a1fd9364Slogwang ;
1716*a1fd9364Slogwang *lenp = i - *startp;
1717*a1fd9364Slogwang return T_WORD;
1718*a1fd9364Slogwang }
1719*a1fd9364Slogwang }
1720*a1fd9364Slogwang
1721*a1fd9364Slogwang /*
1722*a1fd9364Slogwang * Get a string token, which must be enclosed in double quotes.
1723*a1fd9364Slogwang * The normal C backslash escapes are recognized.
1724*a1fd9364Slogwang */
1725*a1fd9364Slogwang char *
ng_get_string_token(const char * s,int * startp,int * lenp,int * slenp)1726*a1fd9364Slogwang ng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
1727*a1fd9364Slogwang {
1728*a1fd9364Slogwang char *cbuf, *p;
1729*a1fd9364Slogwang int start, off;
1730*a1fd9364Slogwang int slen;
1731*a1fd9364Slogwang
1732*a1fd9364Slogwang while (isspace(s[*startp]))
1733*a1fd9364Slogwang (*startp)++;
1734*a1fd9364Slogwang start = *startp;
1735*a1fd9364Slogwang if (s[*startp] != '"')
1736*a1fd9364Slogwang return (NULL);
1737*a1fd9364Slogwang cbuf = malloc(strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
1738*a1fd9364Slogwang if (cbuf == NULL)
1739*a1fd9364Slogwang return (NULL);
1740*a1fd9364Slogwang strcpy(cbuf, s + start + 1);
1741*a1fd9364Slogwang for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
1742*a1fd9364Slogwang if (*p == '"') {
1743*a1fd9364Slogwang *p = '\0';
1744*a1fd9364Slogwang *lenp = off + 1;
1745*a1fd9364Slogwang if (slenp != NULL)
1746*a1fd9364Slogwang *slenp = slen;
1747*a1fd9364Slogwang return (cbuf);
1748*a1fd9364Slogwang } else if (p[0] == '\\' && p[1] != '\0') {
1749*a1fd9364Slogwang int x, k;
1750*a1fd9364Slogwang char *v;
1751*a1fd9364Slogwang
1752*a1fd9364Slogwang strcpy(p, p + 1);
1753*a1fd9364Slogwang v = p;
1754*a1fd9364Slogwang switch (*p) {
1755*a1fd9364Slogwang case 't':
1756*a1fd9364Slogwang *v = '\t';
1757*a1fd9364Slogwang off++;
1758*a1fd9364Slogwang continue;
1759*a1fd9364Slogwang case 'n':
1760*a1fd9364Slogwang *v = '\n';
1761*a1fd9364Slogwang off++;
1762*a1fd9364Slogwang continue;
1763*a1fd9364Slogwang case 'r':
1764*a1fd9364Slogwang *v = '\r';
1765*a1fd9364Slogwang off++;
1766*a1fd9364Slogwang continue;
1767*a1fd9364Slogwang case 'v':
1768*a1fd9364Slogwang *v = '\v';
1769*a1fd9364Slogwang off++;
1770*a1fd9364Slogwang continue;
1771*a1fd9364Slogwang case 'f':
1772*a1fd9364Slogwang *v = '\f';
1773*a1fd9364Slogwang off++;
1774*a1fd9364Slogwang continue;
1775*a1fd9364Slogwang case '"':
1776*a1fd9364Slogwang *v = '"';
1777*a1fd9364Slogwang off++;
1778*a1fd9364Slogwang continue;
1779*a1fd9364Slogwang case '0': case '1': case '2': case '3':
1780*a1fd9364Slogwang case '4': case '5': case '6': case '7':
1781*a1fd9364Slogwang for (x = k = 0;
1782*a1fd9364Slogwang k < 3 && *v >= '0' && *v <= '7'; v++) {
1783*a1fd9364Slogwang x = (x << 3) + (*v - '0');
1784*a1fd9364Slogwang off++;
1785*a1fd9364Slogwang }
1786*a1fd9364Slogwang *--v = (char)x;
1787*a1fd9364Slogwang break;
1788*a1fd9364Slogwang case 'x':
1789*a1fd9364Slogwang for (v++, x = k = 0;
1790*a1fd9364Slogwang k < 2 && isxdigit(*v); v++) {
1791*a1fd9364Slogwang x = (x << 4) + (isdigit(*v) ?
1792*a1fd9364Slogwang (*v - '0') :
1793*a1fd9364Slogwang (tolower(*v) - 'a' + 10));
1794*a1fd9364Slogwang off++;
1795*a1fd9364Slogwang }
1796*a1fd9364Slogwang *--v = (char)x;
1797*a1fd9364Slogwang break;
1798*a1fd9364Slogwang default:
1799*a1fd9364Slogwang continue;
1800*a1fd9364Slogwang }
1801*a1fd9364Slogwang strcpy(p, v);
1802*a1fd9364Slogwang }
1803*a1fd9364Slogwang }
1804*a1fd9364Slogwang free(cbuf, M_NETGRAPH_PARSE);
1805*a1fd9364Slogwang return (NULL); /* no closing quote */
1806*a1fd9364Slogwang }
1807*a1fd9364Slogwang
1808*a1fd9364Slogwang /*
1809*a1fd9364Slogwang * Encode a string so it can be safely put in double quotes.
1810*a1fd9364Slogwang * Caller must free the result. Exactly "slen" characters
1811*a1fd9364Slogwang * are encoded.
1812*a1fd9364Slogwang */
1813*a1fd9364Slogwang char *
ng_encode_string(const char * raw,int slen)1814*a1fd9364Slogwang ng_encode_string(const char *raw, int slen)
1815*a1fd9364Slogwang {
1816*a1fd9364Slogwang char *cbuf;
1817*a1fd9364Slogwang int off = 0;
1818*a1fd9364Slogwang int i;
1819*a1fd9364Slogwang
1820*a1fd9364Slogwang cbuf = malloc(strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
1821*a1fd9364Slogwang if (cbuf == NULL)
1822*a1fd9364Slogwang return (NULL);
1823*a1fd9364Slogwang cbuf[off++] = '"';
1824*a1fd9364Slogwang for (i = 0; i < slen; i++, raw++) {
1825*a1fd9364Slogwang switch (*raw) {
1826*a1fd9364Slogwang case '\t':
1827*a1fd9364Slogwang cbuf[off++] = '\\';
1828*a1fd9364Slogwang cbuf[off++] = 't';
1829*a1fd9364Slogwang break;
1830*a1fd9364Slogwang case '\f':
1831*a1fd9364Slogwang cbuf[off++] = '\\';
1832*a1fd9364Slogwang cbuf[off++] = 'f';
1833*a1fd9364Slogwang break;
1834*a1fd9364Slogwang case '\n':
1835*a1fd9364Slogwang cbuf[off++] = '\\';
1836*a1fd9364Slogwang cbuf[off++] = 'n';
1837*a1fd9364Slogwang break;
1838*a1fd9364Slogwang case '\r':
1839*a1fd9364Slogwang cbuf[off++] = '\\';
1840*a1fd9364Slogwang cbuf[off++] = 'r';
1841*a1fd9364Slogwang break;
1842*a1fd9364Slogwang case '\v':
1843*a1fd9364Slogwang cbuf[off++] = '\\';
1844*a1fd9364Slogwang cbuf[off++] = 'v';
1845*a1fd9364Slogwang break;
1846*a1fd9364Slogwang case '"':
1847*a1fd9364Slogwang case '\\':
1848*a1fd9364Slogwang cbuf[off++] = '\\';
1849*a1fd9364Slogwang cbuf[off++] = *raw;
1850*a1fd9364Slogwang break;
1851*a1fd9364Slogwang default:
1852*a1fd9364Slogwang if (*raw < 0x20 || *raw > 0x7e) {
1853*a1fd9364Slogwang off += sprintf(cbuf + off,
1854*a1fd9364Slogwang "\\x%02x", (u_char)*raw);
1855*a1fd9364Slogwang break;
1856*a1fd9364Slogwang }
1857*a1fd9364Slogwang cbuf[off++] = *raw;
1858*a1fd9364Slogwang break;
1859*a1fd9364Slogwang }
1860*a1fd9364Slogwang }
1861*a1fd9364Slogwang cbuf[off++] = '"';
1862*a1fd9364Slogwang cbuf[off] = '\0';
1863*a1fd9364Slogwang return (cbuf);
1864*a1fd9364Slogwang }
1865*a1fd9364Slogwang
1866*a1fd9364Slogwang /************************************************************************
1867*a1fd9364Slogwang VIRTUAL METHOD LOOKUP
1868*a1fd9364Slogwang ************************************************************************/
1869*a1fd9364Slogwang
1870*a1fd9364Slogwang static ng_parse_t *
ng_get_parse_method(const struct ng_parse_type * t)1871*a1fd9364Slogwang ng_get_parse_method(const struct ng_parse_type *t)
1872*a1fd9364Slogwang {
1873*a1fd9364Slogwang while (t != NULL && t->parse == NULL)
1874*a1fd9364Slogwang t = t->supertype;
1875*a1fd9364Slogwang return (t ? t->parse : NULL);
1876*a1fd9364Slogwang }
1877*a1fd9364Slogwang
1878*a1fd9364Slogwang static ng_unparse_t *
ng_get_unparse_method(const struct ng_parse_type * t)1879*a1fd9364Slogwang ng_get_unparse_method(const struct ng_parse_type *t)
1880*a1fd9364Slogwang {
1881*a1fd9364Slogwang while (t != NULL && t->unparse == NULL)
1882*a1fd9364Slogwang t = t->supertype;
1883*a1fd9364Slogwang return (t ? t->unparse : NULL);
1884*a1fd9364Slogwang }
1885*a1fd9364Slogwang
1886*a1fd9364Slogwang static ng_getDefault_t *
ng_get_getDefault_method(const struct ng_parse_type * t)1887*a1fd9364Slogwang ng_get_getDefault_method(const struct ng_parse_type *t)
1888*a1fd9364Slogwang {
1889*a1fd9364Slogwang while (t != NULL && t->getDefault == NULL)
1890*a1fd9364Slogwang t = t->supertype;
1891*a1fd9364Slogwang return (t ? t->getDefault : NULL);
1892*a1fd9364Slogwang }
1893*a1fd9364Slogwang
1894*a1fd9364Slogwang static ng_getAlign_t *
ng_get_getAlign_method(const struct ng_parse_type * t)1895*a1fd9364Slogwang ng_get_getAlign_method(const struct ng_parse_type *t)
1896*a1fd9364Slogwang {
1897*a1fd9364Slogwang while (t != NULL && t->getAlign == NULL)
1898*a1fd9364Slogwang t = t->supertype;
1899*a1fd9364Slogwang return (t ? t->getAlign : NULL);
1900*a1fd9364Slogwang }
1901