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: releng/9.2/sys/netgraph/ng_parse.c 249132 2013-04-05 08:22:11Z mav $
   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 && s[*off] != '.')
  965                         return (EINVAL);
  966                 (*off)++;
  967         }
  968         *buflen = 4;
  969         return (0);
  970 }
  971 
  972 static int
  973 ng_ipaddr_unparse(const struct ng_parse_type *type,
  974         const u_char *data, int *off, char *cbuf, int cbuflen)
  975 {
  976         struct in_addr ip;
  977         int error;
  978 
  979         bcopy(data + *off, &ip, sizeof(ip));
  980         if ((error = ng_parse_append(&cbuf, &cbuflen, "%d.%d.%d.%d",
  981             ((u_char *)&ip)[0], ((u_char *)&ip)[1],
  982             ((u_char *)&ip)[2], ((u_char *)&ip)[3])) != 0)
  983                 return (error);
  984         *off += sizeof(ip);
  985         return (0);
  986 }
  987 
  988 static int
  989 ng_ipaddr_getDefault(const struct ng_parse_type *type,
  990         const u_char *const start, u_char *buf, int *buflen)
  991 {
  992         struct in_addr ip = { 0 };
  993 
  994         if (*buflen < sizeof(ip))
  995                 return (ERANGE);
  996         bcopy(&ip, buf, sizeof(ip));
  997         *buflen = sizeof(ip);
  998         return (0);
  999 }
 1000 
 1001 const struct ng_parse_type ng_parse_ipaddr_type = {
 1002         NULL,
 1003         NULL,
 1004         NULL,
 1005         ng_ipaddr_parse,
 1006         ng_ipaddr_unparse,
 1007         ng_ipaddr_getDefault,
 1008         ng_int32_getAlign
 1009 };
 1010 
 1011 /************************************************************************
 1012                         ETHERNET ADDRESS TYPE
 1013  ************************************************************************/
 1014 
 1015 static int
 1016 ng_enaddr_parse(const struct ng_parse_type *type,
 1017         const char *s, int *const off, const u_char *const start,
 1018         u_char *const buf, int *const buflen)
 1019 {
 1020         char *eptr;
 1021         u_long val;
 1022         int i;
 1023 
 1024         if (*buflen < ETHER_ADDR_LEN)
 1025                 return (ERANGE);
 1026         for (i = 0; i < ETHER_ADDR_LEN; i++) {
 1027                 val = strtoul(s + *off, &eptr, 16);
 1028                 if (val > 0xff || eptr == s + *off)
 1029                         return (EINVAL);
 1030                 buf[i] = (u_char)val;
 1031                 *off = (eptr - s);
 1032                 if (i < ETHER_ADDR_LEN - 1) {
 1033                         if (*eptr != ':')
 1034                                 return (EINVAL);
 1035                         (*off)++;
 1036                 }
 1037         }
 1038         *buflen = ETHER_ADDR_LEN;
 1039         return (0);
 1040 }
 1041 
 1042 static int
 1043 ng_enaddr_unparse(const struct ng_parse_type *type,
 1044         const u_char *data, int *off, char *cbuf, int cbuflen)
 1045 {
 1046         int len;
 1047 
 1048         len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x",
 1049             data[*off], data[*off + 1], data[*off + 2],
 1050             data[*off + 3], data[*off + 4], data[*off + 5]);
 1051         if (len >= cbuflen)
 1052                 return (ERANGE);
 1053         *off += ETHER_ADDR_LEN;
 1054         return (0);
 1055 }
 1056 
 1057 const struct ng_parse_type ng_parse_enaddr_type = {
 1058         NULL,
 1059         NULL,
 1060         NULL,
 1061         ng_enaddr_parse,
 1062         ng_enaddr_unparse,
 1063         NULL,
 1064         0
 1065 };
 1066 
 1067 /************************************************************************
 1068                         BYTE ARRAY TYPE
 1069  ************************************************************************/
 1070 
 1071 /* Get the length of a byte array */
 1072 static int
 1073 ng_parse_bytearray_subtype_getLength(const struct ng_parse_type *type,
 1074         const u_char *start, const u_char *buf)
 1075 {
 1076         ng_parse_array_getLength_t *const getLength = type->private;
 1077 
 1078         return (*getLength)(type, start, buf);
 1079 }
 1080 
 1081 /* Byte array element type is hex int8 */
 1082 static const struct ng_parse_array_info ng_parse_bytearray_subtype_info = {
 1083         &ng_parse_hint8_type,
 1084         &ng_parse_bytearray_subtype_getLength,
 1085         NULL
 1086 };
 1087 static const struct ng_parse_type ng_parse_bytearray_subtype = {
 1088         &ng_parse_array_type,
 1089         &ng_parse_bytearray_subtype_info
 1090 };
 1091 
 1092 static int
 1093 ng_bytearray_parse(const struct ng_parse_type *type,
 1094         const char *s, int *off, const u_char *const start,
 1095         u_char *const buf, int *buflen)
 1096 {
 1097         char *str;
 1098         int toklen;
 1099         int slen;
 1100 
 1101         /* We accept either an array of bytes or a string constant */
 1102         if ((str = ng_get_string_token(s, off, &toklen, &slen)) != NULL) {
 1103                 ng_parse_array_getLength_t *const getLength = type->info;
 1104                 int arraylen;
 1105 
 1106                 arraylen = (*getLength)(type, start, buf);
 1107                 if (arraylen > *buflen) {
 1108                         free(str, M_NETGRAPH_PARSE);
 1109                         return (ERANGE);
 1110                 }
 1111                 if (slen > arraylen) {
 1112                         free(str, M_NETGRAPH_PARSE);
 1113                         return (E2BIG);
 1114                 }
 1115                 bcopy(str, buf, slen);
 1116                 bzero(buf + slen, arraylen - slen);
 1117                 free(str, M_NETGRAPH_PARSE);
 1118                 *off += toklen;
 1119                 *buflen = arraylen;
 1120                 return (0);
 1121         } else {
 1122                 struct ng_parse_type subtype;
 1123 
 1124                 subtype = ng_parse_bytearray_subtype;
 1125                 *(const void **)&subtype.private = type->info;
 1126                 return ng_array_parse(&subtype, s, off, start, buf, buflen);
 1127         }
 1128 }
 1129 
 1130 static int
 1131 ng_bytearray_unparse(const struct ng_parse_type *type,
 1132         const u_char *data, int *off, char *cbuf, int cbuflen)
 1133 {
 1134         struct ng_parse_type subtype;
 1135 
 1136         subtype = ng_parse_bytearray_subtype;
 1137         *(const void **)&subtype.private = type->info;
 1138         return ng_array_unparse(&subtype, data, off, cbuf, cbuflen);
 1139 }
 1140 
 1141 static int
 1142 ng_bytearray_getDefault(const struct ng_parse_type *type,
 1143         const u_char *const start, u_char *buf, int *buflen)
 1144 {
 1145         struct ng_parse_type subtype;
 1146 
 1147         subtype = ng_parse_bytearray_subtype;
 1148         *(const void **)&subtype.private = type->info;
 1149         return ng_array_getDefault(&subtype, start, buf, buflen);
 1150 }
 1151 
 1152 const struct ng_parse_type ng_parse_bytearray_type = {
 1153         NULL,
 1154         NULL,
 1155         NULL,
 1156         ng_bytearray_parse,
 1157         ng_bytearray_unparse,
 1158         ng_bytearray_getDefault,
 1159         NULL
 1160 };
 1161 
 1162 /************************************************************************
 1163                         STRUCT NG_MESG TYPE
 1164  ************************************************************************/
 1165 
 1166 /* Get msg->header.arglen when "buf" is pointing to msg->data */
 1167 static int
 1168 ng_parse_ng_mesg_getLength(const struct ng_parse_type *type,
 1169         const u_char *start, const u_char *buf)
 1170 {
 1171         const struct ng_mesg *msg;
 1172 
 1173         msg = (const struct ng_mesg *)(buf - sizeof(*msg));
 1174         return msg->header.arglen;
 1175 }
 1176 
 1177 /* Type for the variable length data portion of a struct ng_mesg */
 1178 static const struct ng_parse_type ng_msg_data_type = {
 1179         &ng_parse_bytearray_type,
 1180         &ng_parse_ng_mesg_getLength
 1181 };
 1182 
 1183 /* Type for the entire struct ng_mesg header with data section */
 1184 static const struct ng_parse_struct_field ng_parse_ng_mesg_type_fields[]
 1185         = NG_GENERIC_NG_MESG_INFO(&ng_msg_data_type);
 1186 const struct ng_parse_type ng_parse_ng_mesg_type = {
 1187         &ng_parse_struct_type,
 1188         &ng_parse_ng_mesg_type_fields,
 1189 };
 1190 
 1191 /************************************************************************
 1192                         COMPOSITE HELPER ROUTINES
 1193  ************************************************************************/
 1194 
 1195 /*
 1196  * Convert a structure or array from ASCII to binary
 1197  */
 1198 static int
 1199 ng_parse_composite(const struct ng_parse_type *type, const char *s,
 1200         int *off, const u_char *const start, u_char *const buf, int *buflen,
 1201         const enum comptype ctype)
 1202 {
 1203         const int num = ng_get_composite_len(type, start, buf, ctype);
 1204         int nextIndex = 0;              /* next implicit array index */
 1205         u_int index;                    /* field or element index */
 1206         int *foff;                      /* field value offsets in string */
 1207         int align, len, blen, error = 0;
 1208 
 1209         /* Initialize */
 1210         foff = malloc(num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO);
 1211         if (foff == NULL) {
 1212                 error = ENOMEM;
 1213                 goto done;
 1214         }
 1215 
 1216         /* Get opening brace/bracket */
 1217         if (ng_parse_get_token(s, off, &len)
 1218             != (ctype == CT_STRUCT ? T_LBRACE : T_LBRACKET)) {
 1219                 error = EINVAL;
 1220                 goto done;
 1221         }
 1222         *off += len;
 1223 
 1224         /* Get individual element value positions in the string */
 1225         for (;;) {
 1226                 enum ng_parse_token tok;
 1227 
 1228                 /* Check for closing brace/bracket */
 1229                 tok = ng_parse_get_token(s, off, &len);
 1230                 if (tok == (ctype == CT_STRUCT ? T_RBRACE : T_RBRACKET)) {
 1231                         *off += len;
 1232                         break;
 1233                 }
 1234 
 1235                 /* For arrays, the 'name' (ie, index) is optional, so
 1236                    distinguish name from values by seeing if the next
 1237                    token is an equals sign */
 1238                 if (ctype != CT_STRUCT) {
 1239                         int len2, off2;
 1240                         char *eptr;
 1241 
 1242                         /* If an opening brace/bracket, index is implied */
 1243                         if (tok == T_LBRACE || tok == T_LBRACKET) {
 1244                                 index = nextIndex++;
 1245                                 goto gotIndex;
 1246                         }
 1247 
 1248                         /* Might be an index, might be a value, either way... */
 1249                         if (tok != T_WORD) {
 1250                                 error = EINVAL;
 1251                                 goto done;
 1252                         }
 1253 
 1254                         /* If no equals sign follows, index is implied */
 1255                         off2 = *off + len;
 1256                         if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
 1257                                 index = nextIndex++;
 1258                                 goto gotIndex;
 1259                         }
 1260 
 1261                         /* Index was specified explicitly; parse it */
 1262                         index = (u_int)strtoul(s + *off, &eptr, 0);
 1263                         if (index < 0 || eptr - (s + *off) != len) {
 1264                                 error = EINVAL;
 1265                                 goto done;
 1266                         }
 1267                         nextIndex = index + 1;
 1268                         *off += len + len2;
 1269                 } else {                        /* a structure field */
 1270                         const struct ng_parse_struct_field *const
 1271                             fields = type->info;
 1272 
 1273                         /* Find the field by name (required) in field list */
 1274                         if (tok != T_WORD) {
 1275                                 error = EINVAL;
 1276                                 goto done;
 1277                         }
 1278                         for (index = 0; index < num; index++) {
 1279                                 const struct ng_parse_struct_field *const
 1280                                     field = &fields[index];
 1281 
 1282                                 if (strncmp(&s[*off], field->name, len) == 0
 1283                                     && field->name[len] == '\0')
 1284                                         break;
 1285                         }
 1286                         if (index == num) {
 1287                                 error = ENOENT;
 1288                                 goto done;
 1289                         }
 1290                         *off += len;
 1291 
 1292                         /* Get equals sign */
 1293                         if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
 1294                                 error = EINVAL;
 1295                                 goto done;
 1296                         }
 1297                         *off += len;
 1298                 }
 1299 gotIndex:
 1300 
 1301                 /* Check array index */
 1302                 if (index >= num) {
 1303                         error = E2BIG;
 1304                         goto done;
 1305                 }
 1306 
 1307                 /* Save value's position and skip over it for now */
 1308                 if (foff[index] != 0) {
 1309                         error = EALREADY;               /* duplicate */
 1310                         goto done;
 1311                 }
 1312                 while (isspace(s[*off]))
 1313                         (*off)++;
 1314                 foff[index] = *off;
 1315                 if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
 1316                         goto done;
 1317                 *off += len;
 1318         }
 1319 
 1320         /* Now build binary structure from supplied values and defaults */
 1321         for (blen = index = 0; index < num; index++) {
 1322                 const struct ng_parse_type *const
 1323                     etype = ng_get_composite_etype(type, index, ctype);
 1324                 int k, pad, vlen;
 1325 
 1326                 /* Zero-pad any alignment bytes */
 1327                 pad = ng_parse_get_elem_pad(type, index, ctype, blen);
 1328                 for (k = 0; k < pad; k++) {
 1329                         if (blen >= *buflen) {
 1330                                 error = ERANGE;
 1331                                 goto done;
 1332                         }
 1333                         buf[blen++] = 0;
 1334                 }
 1335 
 1336                 /* Get value */
 1337                 vlen = *buflen - blen;
 1338                 if (foff[index] == 0) {         /* use default value */
 1339                         error = ng_get_composite_elem_default(type, index,
 1340                             start, buf + blen, &vlen, ctype);
 1341                 } else {                        /* parse given value */
 1342                         *off = foff[index];
 1343                         error = INVOKE(etype, parse)(etype,
 1344                             s, off, start, buf + blen, &vlen);
 1345                 }
 1346                 if (error != 0)
 1347                         goto done;
 1348                 blen += vlen;
 1349         }
 1350 
 1351         /* Make total composite structure size a multiple of its alignment */
 1352         if ((align = ALIGNMENT(type)) != 0) {
 1353                 while (blen % align != 0) {
 1354                         if (blen >= *buflen) {
 1355                                 error = ERANGE;
 1356                                 goto done;
 1357                         }
 1358                         buf[blen++] = 0;
 1359                 }
 1360         }
 1361 
 1362         /* Done */
 1363         *buflen = blen;
 1364 done:
 1365         if (foff != NULL)
 1366                 free(foff, M_NETGRAPH_PARSE);
 1367         return (error);
 1368 }
 1369 
 1370 /*
 1371  * Convert an array or structure from binary to ASCII
 1372  */
 1373 static int
 1374 ng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
 1375         int *off, char *cbuf, int cbuflen, const enum comptype ctype)
 1376 {
 1377         const struct ng_mesg *const hdr
 1378             = (const struct ng_mesg *)(data - sizeof(*hdr));
 1379         const int num = ng_get_composite_len(type, data, data + *off, ctype);
 1380         const int workSize = 20 * 1024;         /* XXX hard coded constant */
 1381         int nextIndex = 0, didOne = 0;
 1382         int error, index;
 1383         u_char *workBuf;
 1384 
 1385         /* Get workspace for checking default values */
 1386         workBuf = malloc(workSize, M_NETGRAPH_PARSE, M_NOWAIT);
 1387         if (workBuf == NULL)
 1388                 return (ENOMEM);
 1389 
 1390         /* Opening brace/bracket */
 1391         if ((error = ng_parse_append(&cbuf, &cbuflen, "%c",
 1392             (ctype == CT_STRUCT) ? '{' : '[')) != 0)
 1393                 goto fail;
 1394 
 1395         /* Do each item */
 1396         for (index = 0; index < num; index++) {
 1397                 const struct ng_parse_type *const
 1398                     etype = ng_get_composite_etype(type, index, ctype);
 1399 
 1400                 /* Skip any alignment pad bytes */
 1401                 *off += ng_parse_get_elem_pad(type, index, ctype, *off);
 1402 
 1403                 /*
 1404                  * See if element is equal to its default value; skip if so.
 1405                  * Copy struct ng_mesg header for types that peek into it.
 1406                  */
 1407                 if (sizeof(*hdr) + *off < workSize) {
 1408                         int tempsize = workSize - sizeof(*hdr) - *off;
 1409 
 1410                         bcopy(hdr, workBuf, sizeof(*hdr) + *off);
 1411                         if (ng_get_composite_elem_default(type, index, workBuf
 1412                               + sizeof(*hdr), workBuf + sizeof(*hdr) + *off,
 1413                               &tempsize, ctype) == 0
 1414                             && bcmp(workBuf + sizeof(*hdr) + *off,
 1415                               data + *off, tempsize) == 0) {
 1416                                 *off += tempsize;
 1417                                 continue;
 1418                         }
 1419                 }
 1420 
 1421                 /* Print name= */
 1422                 if ((error = ng_parse_append(&cbuf, &cbuflen, " ")) != 0)
 1423                         goto fail;
 1424                 if (ctype != CT_STRUCT) {
 1425                         if (index != nextIndex) {
 1426                                 nextIndex = index;
 1427                                 if ((error = ng_parse_append(&cbuf,
 1428                                     &cbuflen, "%d=", index)) != 0)
 1429                                         goto fail;
 1430                         }
 1431                         nextIndex++;
 1432                 } else {
 1433                         const struct ng_parse_struct_field *const
 1434                             fields = type->info;
 1435 
 1436                         if ((error = ng_parse_append(&cbuf,
 1437                             &cbuflen, "%s=", fields[index].name)) != 0)
 1438                                 goto fail;
 1439                 }
 1440 
 1441                 /* Print value */
 1442                 if ((error = INVOKE(etype, unparse)
 1443                     (etype, data, off, cbuf, cbuflen)) != 0) {
 1444                         free(workBuf, M_NETGRAPH_PARSE);
 1445                         return (error);
 1446                 }
 1447                 cbuflen -= strlen(cbuf);
 1448                 cbuf += strlen(cbuf);
 1449                 didOne = 1;
 1450         }
 1451 
 1452         /* Closing brace/bracket */
 1453         error = ng_parse_append(&cbuf, &cbuflen, "%s%c",
 1454             didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
 1455 
 1456 fail:
 1457         /* Clean up after failure */
 1458         free(workBuf, M_NETGRAPH_PARSE);
 1459         return (error);
 1460 }
 1461 
 1462 /*
 1463  * Generate the default value for an element of an array or structure
 1464  * Returns EOPNOTSUPP if default value is unspecified.
 1465  */
 1466 static int
 1467 ng_get_composite_elem_default(const struct ng_parse_type *type,
 1468         int index, const u_char *const start, u_char *buf, int *buflen,
 1469         const enum comptype ctype)
 1470 {
 1471         const struct ng_parse_type *etype;
 1472         ng_getDefault_t *func;
 1473 
 1474         switch (ctype) {
 1475         case CT_STRUCT:
 1476                 break;
 1477         case CT_ARRAY:
 1478             {
 1479                 const struct ng_parse_array_info *const ai = type->info;
 1480 
 1481                 if (ai->getDefault != NULL) {
 1482                         return (*ai->getDefault)(type,
 1483                             index, start, buf, buflen);
 1484                 }
 1485                 break;
 1486             }
 1487         case CT_FIXEDARRAY:
 1488             {
 1489                 const struct ng_parse_fixedarray_info *const fi = type->info;
 1490 
 1491                 if (*fi->getDefault != NULL) {
 1492                         return (*fi->getDefault)(type,
 1493                             index, start, buf, buflen);
 1494                 }
 1495                 break;
 1496             }
 1497         default:
 1498             panic("%s", __func__);
 1499         }
 1500 
 1501         /* Default to element type default */
 1502         etype = ng_get_composite_etype(type, index, ctype);
 1503         func = METHOD(etype, getDefault);
 1504         if (func == NULL)
 1505                 return (EOPNOTSUPP);
 1506         return (*func)(etype, start, buf, buflen);
 1507 }
 1508 
 1509 /*
 1510  * Get the number of elements in a struct, variable or fixed array.
 1511  */
 1512 static int
 1513 ng_get_composite_len(const struct ng_parse_type *type,
 1514         const u_char *const start, const u_char *buf,
 1515         const enum comptype ctype)
 1516 {
 1517         switch (ctype) {
 1518         case CT_STRUCT:
 1519             {
 1520                 const struct ng_parse_struct_field *const fields = type->info;
 1521                 int numFields = 0;
 1522 
 1523                 for (numFields = 0; ; numFields++) {
 1524                         const struct ng_parse_struct_field *const
 1525                                 fi = &fields[numFields];
 1526 
 1527                         if (fi->name == NULL)
 1528                                 break;
 1529                 }
 1530                 return (numFields);
 1531             }
 1532         case CT_ARRAY:
 1533             {
 1534                 const struct ng_parse_array_info *const ai = type->info;
 1535 
 1536                 return (*ai->getLength)(type, start, buf);
 1537             }
 1538         case CT_FIXEDARRAY:
 1539             {
 1540                 const struct ng_parse_fixedarray_info *const fi = type->info;
 1541 
 1542                 return fi->length;
 1543             }
 1544         default:
 1545             panic("%s", __func__);
 1546         }
 1547         return (0);
 1548 }
 1549 
 1550 /*
 1551  * Return the type of the index'th element of a composite structure
 1552  */
 1553 static const struct ng_parse_type *
 1554 ng_get_composite_etype(const struct ng_parse_type *type,
 1555         int index, const enum comptype ctype)
 1556 {
 1557         const struct ng_parse_type *etype = NULL;
 1558 
 1559         switch (ctype) {
 1560         case CT_STRUCT:
 1561             {
 1562                 const struct ng_parse_struct_field *const fields = type->info;
 1563 
 1564                 etype = fields[index].type;
 1565                 break;
 1566             }
 1567         case CT_ARRAY:
 1568             {
 1569                 const struct ng_parse_array_info *const ai = type->info;
 1570 
 1571                 etype = ai->elementType;
 1572                 break;
 1573             }
 1574         case CT_FIXEDARRAY:
 1575             {
 1576                 const struct ng_parse_fixedarray_info *const fi = type->info;
 1577 
 1578                 etype = fi->elementType;
 1579                 break;
 1580             }
 1581         default:
 1582             panic("%s", __func__);
 1583         }
 1584         return (etype);
 1585 }
 1586 
 1587 /*
 1588  * Get the number of bytes to skip to align for the next
 1589  * element in a composite structure.
 1590  */
 1591 static int
 1592 ng_parse_get_elem_pad(const struct ng_parse_type *type,
 1593         int index, enum comptype ctype, int posn)
 1594 {
 1595         const struct ng_parse_type *const
 1596             etype = ng_get_composite_etype(type, index, ctype);
 1597         int align;
 1598 
 1599         /* Get element's alignment, and possibly override */
 1600         align = ALIGNMENT(etype);
 1601         if (ctype == CT_STRUCT) {
 1602                 const struct ng_parse_struct_field *const fields = type->info;
 1603 
 1604                 if (fields[index].alignment != 0)
 1605                         align = fields[index].alignment;
 1606         }
 1607 
 1608         /* Return number of bytes to skip to align */
 1609         return (align ? (align - (posn % align)) % align : 0);
 1610 }
 1611 
 1612 /************************************************************************
 1613                         PARSING HELPER ROUTINES
 1614  ************************************************************************/
 1615 
 1616 /*
 1617  * Append to a fixed length string buffer.
 1618  */
 1619 static int
 1620 ng_parse_append(char **cbufp, int *cbuflenp, const char *fmt, ...)
 1621 {
 1622         va_list args;
 1623         int len;
 1624 
 1625         va_start(args, fmt);
 1626         len = vsnprintf(*cbufp, *cbuflenp, fmt, args);
 1627         va_end(args);
 1628         if (len >= *cbuflenp)
 1629                 return ERANGE;
 1630         *cbufp += len;
 1631         *cbuflenp -= len;
 1632 
 1633         return (0);
 1634 }
 1635 
 1636 /*
 1637  * Skip over a value
 1638  */
 1639 static int
 1640 ng_parse_skip_value(const char *s, int off0, int *lenp)
 1641 {
 1642         int len, nbracket, nbrace;
 1643         int off = off0;
 1644 
 1645         len = nbracket = nbrace = 0;
 1646         do {
 1647                 switch (ng_parse_get_token(s, &off, &len)) {
 1648                 case T_LBRACKET:
 1649                         nbracket++;
 1650                         break;
 1651                 case T_LBRACE:
 1652                         nbrace++;
 1653                         break;
 1654                 case T_RBRACKET:
 1655                         if (nbracket-- == 0)
 1656                                 return (EINVAL);
 1657                         break;
 1658                 case T_RBRACE:
 1659                         if (nbrace-- == 0)
 1660                                 return (EINVAL);
 1661                         break;
 1662                 case T_EOF:
 1663                         return (EINVAL);
 1664                 default:
 1665                         break;
 1666                 }
 1667                 off += len;
 1668         } while (nbracket > 0 || nbrace > 0);
 1669         *lenp = off - off0;
 1670         return (0);
 1671 }
 1672 
 1673 /*
 1674  * Find the next token in the string, starting at offset *startp.
 1675  * Returns the token type, with *startp pointing to the first char
 1676  * and *lenp the length.
 1677  */
 1678 enum ng_parse_token
 1679 ng_parse_get_token(const char *s, int *startp, int *lenp)
 1680 {
 1681         char *t;
 1682         int i;
 1683 
 1684         while (isspace(s[*startp]))
 1685                 (*startp)++;
 1686         switch (s[*startp]) {
 1687         case '\0':
 1688                 *lenp = 0;
 1689                 return T_EOF;
 1690         case '{':
 1691                 *lenp = 1;
 1692                 return T_LBRACE;
 1693         case '}':
 1694                 *lenp = 1;
 1695                 return T_RBRACE;
 1696         case '[':
 1697                 *lenp = 1;
 1698                 return T_LBRACKET;
 1699         case ']':
 1700                 *lenp = 1;
 1701                 return T_RBRACKET;
 1702         case '=':
 1703                 *lenp = 1;
 1704                 return T_EQUALS;
 1705         case '"':
 1706                 if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
 1707                         return T_ERROR;
 1708                 free(t, M_NETGRAPH_PARSE);
 1709                 return T_STRING;
 1710         default:
 1711                 for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
 1712                     && s[i] != '{' && s[i] != '}' && s[i] != '['
 1713                     && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
 1714                         ;
 1715                 *lenp = i - *startp;
 1716                 return T_WORD;
 1717         }
 1718 }
 1719 
 1720 /*
 1721  * Get a string token, which must be enclosed in double quotes.
 1722  * The normal C backslash escapes are recognized.
 1723  */
 1724 char *
 1725 ng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
 1726 {
 1727         char *cbuf, *p;
 1728         int start, off;
 1729         int slen;
 1730 
 1731         while (isspace(s[*startp]))
 1732                 (*startp)++;
 1733         start = *startp;
 1734         if (s[*startp] != '"')
 1735                 return (NULL);
 1736         cbuf = malloc(strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
 1737         if (cbuf == NULL)
 1738                 return (NULL);
 1739         strcpy(cbuf, s + start + 1);
 1740         for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
 1741                 if (*p == '"') {
 1742                         *p = '\0';
 1743                         *lenp = off + 1;
 1744                         if (slenp != NULL)
 1745                                 *slenp = slen;
 1746                         return (cbuf);
 1747                 } else if (p[0] == '\\' && p[1] != '\0') {
 1748                         int x, k;
 1749                         char *v;
 1750 
 1751                         strcpy(p, p + 1);
 1752                         v = p;
 1753                         switch (*p) {
 1754                         case 't':
 1755                                 *v = '\t';
 1756                                 off++;
 1757                                 continue;
 1758                         case 'n':
 1759                                 *v = '\n';
 1760                                 off++;
 1761                                 continue;
 1762                         case 'r':
 1763                                 *v = '\r';
 1764                                 off++;
 1765                                 continue;
 1766                         case 'v':
 1767                                 *v =  '\v';
 1768                                 off++;
 1769                                 continue;
 1770                         case 'f':
 1771                                 *v =  '\f';
 1772                                 off++;
 1773                                 continue;
 1774                         case '"':
 1775                                 *v =  '"';
 1776                                 off++;
 1777                                 continue;
 1778                         case '': case '1': case '2': case '3':
 1779                         case '4': case '5': case '6': case '7':
 1780                                 for (x = k = 0;
 1781                                     k < 3 && *v >= '' && *v <= '7'; v++) {
 1782                                         x = (x << 3) + (*v - '');
 1783                                         off++;
 1784                                 }
 1785                                 *--v = (char)x;
 1786                                 break;
 1787                         case 'x':
 1788                                 for (v++, x = k = 0;
 1789                                     k < 2 && isxdigit(*v); v++) {
 1790                                         x = (x << 4) + (isdigit(*v) ?
 1791                                               (*v - '') :
 1792                                               (tolower(*v) - 'a' + 10));
 1793                                         off++;
 1794                                 }
 1795                                 *--v = (char)x;
 1796                                 break;
 1797                         default:
 1798                                 continue;
 1799                         }
 1800                         strcpy(p, v);
 1801                 }
 1802         }
 1803         free(cbuf, M_NETGRAPH_PARSE);
 1804         return (NULL);          /* no closing quote */
 1805 }
 1806 
 1807 /*
 1808  * Encode a string so it can be safely put in double quotes.
 1809  * Caller must free the result. Exactly "slen" characters
 1810  * are encoded.
 1811  */
 1812 char *
 1813 ng_encode_string(const char *raw, int slen)
 1814 {
 1815         char *cbuf;
 1816         int off = 0;
 1817         int i;
 1818 
 1819         cbuf = malloc(strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
 1820         if (cbuf == NULL)
 1821                 return (NULL);
 1822         cbuf[off++] = '"';
 1823         for (i = 0; i < slen; i++, raw++) {
 1824                 switch (*raw) {
 1825                 case '\t':
 1826                         cbuf[off++] = '\\';
 1827                         cbuf[off++] = 't';
 1828                         break;
 1829                 case '\f':
 1830                         cbuf[off++] = '\\';
 1831                         cbuf[off++] = 'f';
 1832                         break;
 1833                 case '\n':
 1834                         cbuf[off++] = '\\';
 1835                         cbuf[off++] = 'n';
 1836                         break;
 1837                 case '\r':
 1838                         cbuf[off++] = '\\';
 1839                         cbuf[off++] = 'r';
 1840                         break;
 1841                 case '\v':
 1842                         cbuf[off++] = '\\';
 1843                         cbuf[off++] = 'v';
 1844                         break;
 1845                 case '"':
 1846                 case '\\':
 1847                         cbuf[off++] = '\\';
 1848                         cbuf[off++] = *raw;
 1849                         break;
 1850                 default:
 1851                         if (*raw < 0x20 || *raw > 0x7e) {
 1852                                 off += sprintf(cbuf + off,
 1853                                     "\\x%02x", (u_char)*raw);
 1854                                 break;
 1855                         }
 1856                         cbuf[off++] = *raw;
 1857                         break;
 1858                 }
 1859         }
 1860         cbuf[off++] = '"';
 1861         cbuf[off] = '\0';
 1862         return (cbuf);
 1863 }
 1864 
 1865 /************************************************************************
 1866                         VIRTUAL METHOD LOOKUP
 1867  ************************************************************************/
 1868 
 1869 static ng_parse_t *
 1870 ng_get_parse_method(const struct ng_parse_type *t)
 1871 {
 1872         while (t != NULL && t->parse == NULL)
 1873                 t = t->supertype;
 1874         return (t ? t->parse : NULL);
 1875 }
 1876 
 1877 static ng_unparse_t *
 1878 ng_get_unparse_method(const struct ng_parse_type *t)
 1879 {
 1880         while (t != NULL && t->unparse == NULL)
 1881                 t = t->supertype;
 1882         return (t ? t->unparse : NULL);
 1883 }
 1884 
 1885 static ng_getDefault_t *
 1886 ng_get_getDefault_method(const struct ng_parse_type *t)
 1887 {
 1888         while (t != NULL && t->getDefault == NULL)
 1889                 t = t->supertype;
 1890         return (t ? t->getDefault : NULL);
 1891 }
 1892 
 1893 static ng_getAlign_t *
 1894 ng_get_getAlign_method(const struct ng_parse_type *t)
 1895 {
 1896         while (t != NULL && t->getAlign == NULL)
 1897                 t = t->supertype;
 1898         return (t ? t->getAlign : NULL);
 1899 }
 1900 

Cache object: bf6670185fc9acf87294af36c39a71e5


[ 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.