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