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