The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_parse.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d08ee23a29fa05017e3871508fd80919


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.