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