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