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/10.4/sys/netgraph/ng_parse.c 278140 2015-02-03 07:59:33Z dim $
   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                 subtype.private = __DECONST(void *, 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         subtype.private = __DECONST(void *, 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         subtype.private = __DECONST(void *, 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                         u_long ul;
 1240                         int len2, off2;
 1241                         char *eptr;
 1242 
 1243                         /* If an opening brace/bracket, index is implied */
 1244                         if (tok == T_LBRACE || tok == T_LBRACKET) {
 1245                                 index = nextIndex++;
 1246                                 goto gotIndex;
 1247                         }
 1248 
 1249                         /* Might be an index, might be a value, either way... */
 1250                         if (tok != T_WORD) {
 1251                                 error = EINVAL;
 1252                                 goto done;
 1253                         }
 1254 
 1255                         /* If no equals sign follows, index is implied */
 1256                         off2 = *off + len;
 1257                         if (ng_parse_get_token(s, &off2, &len2) != T_EQUALS) {
 1258                                 index = nextIndex++;
 1259                                 goto gotIndex;
 1260                         }
 1261 
 1262                         /* Index was specified explicitly; parse it */
 1263                         ul = strtoul(s + *off, &eptr, 0);
 1264                         if (ul == ULONG_MAX || eptr - (s + *off) != len) {
 1265                                 error = EINVAL;
 1266                                 goto done;
 1267                         }
 1268                         index = (u_int)ul;
 1269                         nextIndex = index + 1;
 1270                         *off += len + len2;
 1271                 } else {                        /* a structure field */
 1272                         const struct ng_parse_struct_field *const
 1273                             fields = type->info;
 1274 
 1275                         /* Find the field by name (required) in field list */
 1276                         if (tok != T_WORD) {
 1277                                 error = EINVAL;
 1278                                 goto done;
 1279                         }
 1280                         for (index = 0; index < num; index++) {
 1281                                 const struct ng_parse_struct_field *const
 1282                                     field = &fields[index];
 1283 
 1284                                 if (strncmp(&s[*off], field->name, len) == 0
 1285                                     && field->name[len] == '\0')
 1286                                         break;
 1287                         }
 1288                         if (index == num) {
 1289                                 error = ENOENT;
 1290                                 goto done;
 1291                         }
 1292                         *off += len;
 1293 
 1294                         /* Get equals sign */
 1295                         if (ng_parse_get_token(s, off, &len) != T_EQUALS) {
 1296                                 error = EINVAL;
 1297                                 goto done;
 1298                         }
 1299                         *off += len;
 1300                 }
 1301 gotIndex:
 1302 
 1303                 /* Check array index */
 1304                 if (index >= num) {
 1305                         error = E2BIG;
 1306                         goto done;
 1307                 }
 1308 
 1309                 /* Save value's position and skip over it for now */
 1310                 if (foff[index] != 0) {
 1311                         error = EALREADY;               /* duplicate */
 1312                         goto done;
 1313                 }
 1314                 while (isspace(s[*off]))
 1315                         (*off)++;
 1316                 foff[index] = *off;
 1317                 if ((error = ng_parse_skip_value(s, *off, &len)) != 0)
 1318                         goto done;
 1319                 *off += len;
 1320         }
 1321 
 1322         /* Now build binary structure from supplied values and defaults */
 1323         for (blen = index = 0; index < num; index++) {
 1324                 const struct ng_parse_type *const
 1325                     etype = ng_get_composite_etype(type, index, ctype);
 1326                 int k, pad, vlen;
 1327 
 1328                 /* Zero-pad any alignment bytes */
 1329                 pad = ng_parse_get_elem_pad(type, index, ctype, blen);
 1330                 for (k = 0; k < pad; k++) {
 1331                         if (blen >= *buflen) {
 1332                                 error = ERANGE;
 1333                                 goto done;
 1334                         }
 1335                         buf[blen++] = 0;
 1336                 }
 1337 
 1338                 /* Get value */
 1339                 vlen = *buflen - blen;
 1340                 if (foff[index] == 0) {         /* use default value */
 1341                         error = ng_get_composite_elem_default(type, index,
 1342                             start, buf + blen, &vlen, ctype);
 1343                 } else {                        /* parse given value */
 1344                         *off = foff[index];
 1345                         error = INVOKE(etype, parse)(etype,
 1346                             s, off, start, buf + blen, &vlen);
 1347                 }
 1348                 if (error != 0)
 1349                         goto done;
 1350                 blen += vlen;
 1351         }
 1352 
 1353         /* Make total composite structure size a multiple of its alignment */
 1354         if ((align = ALIGNMENT(type)) != 0) {
 1355                 while (blen % align != 0) {
 1356                         if (blen >= *buflen) {
 1357                                 error = ERANGE;
 1358                                 goto done;
 1359                         }
 1360                         buf[blen++] = 0;
 1361                 }
 1362         }
 1363 
 1364         /* Done */
 1365         *buflen = blen;
 1366 done:
 1367         if (foff != NULL)
 1368                 free(foff, M_NETGRAPH_PARSE);
 1369         return (error);
 1370 }
 1371 
 1372 /*
 1373  * Convert an array or structure from binary to ASCII
 1374  */
 1375 static int
 1376 ng_unparse_composite(const struct ng_parse_type *type, const u_char *data,
 1377         int *off, char *cbuf, int cbuflen, const enum comptype ctype)
 1378 {
 1379         const struct ng_mesg *const hdr
 1380             = (const struct ng_mesg *)(data - sizeof(*hdr));
 1381         const int num = ng_get_composite_len(type, data, data + *off, ctype);
 1382         const int workSize = 20 * 1024;         /* XXX hard coded constant */
 1383         int nextIndex = 0, didOne = 0;
 1384         int error, index;
 1385         u_char *workBuf;
 1386 
 1387         /* Get workspace for checking default values */
 1388         workBuf = malloc(workSize, M_NETGRAPH_PARSE, M_NOWAIT);
 1389         if (workBuf == NULL)
 1390                 return (ENOMEM);
 1391 
 1392         /* Opening brace/bracket */
 1393         if ((error = ng_parse_append(&cbuf, &cbuflen, "%c",
 1394             (ctype == CT_STRUCT) ? '{' : '[')) != 0)
 1395                 goto fail;
 1396 
 1397         /* Do each item */
 1398         for (index = 0; index < num; index++) {
 1399                 const struct ng_parse_type *const
 1400                     etype = ng_get_composite_etype(type, index, ctype);
 1401 
 1402                 /* Skip any alignment pad bytes */
 1403                 *off += ng_parse_get_elem_pad(type, index, ctype, *off);
 1404 
 1405                 /*
 1406                  * See if element is equal to its default value; skip if so.
 1407                  * Copy struct ng_mesg header for types that peek into it.
 1408                  */
 1409                 if (sizeof(*hdr) + *off < workSize) {
 1410                         int tempsize = workSize - sizeof(*hdr) - *off;
 1411 
 1412                         bcopy(hdr, workBuf, sizeof(*hdr) + *off);
 1413                         if (ng_get_composite_elem_default(type, index, workBuf
 1414                               + sizeof(*hdr), workBuf + sizeof(*hdr) + *off,
 1415                               &tempsize, ctype) == 0
 1416                             && bcmp(workBuf + sizeof(*hdr) + *off,
 1417                               data + *off, tempsize) == 0) {
 1418                                 *off += tempsize;
 1419                                 continue;
 1420                         }
 1421                 }
 1422 
 1423                 /* Print name= */
 1424                 if ((error = ng_parse_append(&cbuf, &cbuflen, " ")) != 0)
 1425                         goto fail;
 1426                 if (ctype != CT_STRUCT) {
 1427                         if (index != nextIndex) {
 1428                                 nextIndex = index;
 1429                                 if ((error = ng_parse_append(&cbuf,
 1430                                     &cbuflen, "%d=", index)) != 0)
 1431                                         goto fail;
 1432                         }
 1433                         nextIndex++;
 1434                 } else {
 1435                         const struct ng_parse_struct_field *const
 1436                             fields = type->info;
 1437 
 1438                         if ((error = ng_parse_append(&cbuf,
 1439                             &cbuflen, "%s=", fields[index].name)) != 0)
 1440                                 goto fail;
 1441                 }
 1442 
 1443                 /* Print value */
 1444                 if ((error = INVOKE(etype, unparse)
 1445                     (etype, data, off, cbuf, cbuflen)) != 0) {
 1446                         free(workBuf, M_NETGRAPH_PARSE);
 1447                         return (error);
 1448                 }
 1449                 cbuflen -= strlen(cbuf);
 1450                 cbuf += strlen(cbuf);
 1451                 didOne = 1;
 1452         }
 1453 
 1454         /* Closing brace/bracket */
 1455         error = ng_parse_append(&cbuf, &cbuflen, "%s%c",
 1456             didOne ? " " : "", (ctype == CT_STRUCT) ? '}' : ']');
 1457 
 1458 fail:
 1459         /* Clean up after failure */
 1460         free(workBuf, M_NETGRAPH_PARSE);
 1461         return (error);
 1462 }
 1463 
 1464 /*
 1465  * Generate the default value for an element of an array or structure
 1466  * Returns EOPNOTSUPP if default value is unspecified.
 1467  */
 1468 static int
 1469 ng_get_composite_elem_default(const struct ng_parse_type *type,
 1470         int index, const u_char *const start, u_char *buf, int *buflen,
 1471         const enum comptype ctype)
 1472 {
 1473         const struct ng_parse_type *etype;
 1474         ng_getDefault_t *func;
 1475 
 1476         switch (ctype) {
 1477         case CT_STRUCT:
 1478                 break;
 1479         case CT_ARRAY:
 1480             {
 1481                 const struct ng_parse_array_info *const ai = type->info;
 1482 
 1483                 if (ai->getDefault != NULL) {
 1484                         return (*ai->getDefault)(type,
 1485                             index, start, buf, buflen);
 1486                 }
 1487                 break;
 1488             }
 1489         case CT_FIXEDARRAY:
 1490             {
 1491                 const struct ng_parse_fixedarray_info *const fi = type->info;
 1492 
 1493                 if (*fi->getDefault != NULL) {
 1494                         return (*fi->getDefault)(type,
 1495                             index, start, buf, buflen);
 1496                 }
 1497                 break;
 1498             }
 1499         default:
 1500             panic("%s", __func__);
 1501         }
 1502 
 1503         /* Default to element type default */
 1504         etype = ng_get_composite_etype(type, index, ctype);
 1505         func = METHOD(etype, getDefault);
 1506         if (func == NULL)
 1507                 return (EOPNOTSUPP);
 1508         return (*func)(etype, start, buf, buflen);
 1509 }
 1510 
 1511 /*
 1512  * Get the number of elements in a struct, variable or fixed array.
 1513  */
 1514 static int
 1515 ng_get_composite_len(const struct ng_parse_type *type,
 1516         const u_char *const start, const u_char *buf,
 1517         const enum comptype ctype)
 1518 {
 1519         switch (ctype) {
 1520         case CT_STRUCT:
 1521             {
 1522                 const struct ng_parse_struct_field *const fields = type->info;
 1523                 int numFields = 0;
 1524 
 1525                 for (numFields = 0; ; numFields++) {
 1526                         const struct ng_parse_struct_field *const
 1527                                 fi = &fields[numFields];
 1528 
 1529                         if (fi->name == NULL)
 1530                                 break;
 1531                 }
 1532                 return (numFields);
 1533             }
 1534         case CT_ARRAY:
 1535             {
 1536                 const struct ng_parse_array_info *const ai = type->info;
 1537 
 1538                 return (*ai->getLength)(type, start, buf);
 1539             }
 1540         case CT_FIXEDARRAY:
 1541             {
 1542                 const struct ng_parse_fixedarray_info *const fi = type->info;
 1543 
 1544                 return fi->length;
 1545             }
 1546         default:
 1547             panic("%s", __func__);
 1548         }
 1549         return (0);
 1550 }
 1551 
 1552 /*
 1553  * Return the type of the index'th element of a composite structure
 1554  */
 1555 static const struct ng_parse_type *
 1556 ng_get_composite_etype(const struct ng_parse_type *type,
 1557         int index, const enum comptype ctype)
 1558 {
 1559         const struct ng_parse_type *etype = NULL;
 1560 
 1561         switch (ctype) {
 1562         case CT_STRUCT:
 1563             {
 1564                 const struct ng_parse_struct_field *const fields = type->info;
 1565 
 1566                 etype = fields[index].type;
 1567                 break;
 1568             }
 1569         case CT_ARRAY:
 1570             {
 1571                 const struct ng_parse_array_info *const ai = type->info;
 1572 
 1573                 etype = ai->elementType;
 1574                 break;
 1575             }
 1576         case CT_FIXEDARRAY:
 1577             {
 1578                 const struct ng_parse_fixedarray_info *const fi = type->info;
 1579 
 1580                 etype = fi->elementType;
 1581                 break;
 1582             }
 1583         default:
 1584             panic("%s", __func__);
 1585         }
 1586         return (etype);
 1587 }
 1588 
 1589 /*
 1590  * Get the number of bytes to skip to align for the next
 1591  * element in a composite structure.
 1592  */
 1593 static int
 1594 ng_parse_get_elem_pad(const struct ng_parse_type *type,
 1595         int index, enum comptype ctype, int posn)
 1596 {
 1597         const struct ng_parse_type *const
 1598             etype = ng_get_composite_etype(type, index, ctype);
 1599         int align;
 1600 
 1601         /* Get element's alignment, and possibly override */
 1602         align = ALIGNMENT(etype);
 1603         if (ctype == CT_STRUCT) {
 1604                 const struct ng_parse_struct_field *const fields = type->info;
 1605 
 1606                 if (fields[index].alignment != 0)
 1607                         align = fields[index].alignment;
 1608         }
 1609 
 1610         /* Return number of bytes to skip to align */
 1611         return (align ? (align - (posn % align)) % align : 0);
 1612 }
 1613 
 1614 /************************************************************************
 1615                         PARSING HELPER ROUTINES
 1616  ************************************************************************/
 1617 
 1618 /*
 1619  * Append to a fixed length string buffer.
 1620  */
 1621 static int
 1622 ng_parse_append(char **cbufp, int *cbuflenp, const char *fmt, ...)
 1623 {
 1624         va_list args;
 1625         int len;
 1626 
 1627         va_start(args, fmt);
 1628         len = vsnprintf(*cbufp, *cbuflenp, fmt, args);
 1629         va_end(args);
 1630         if (len >= *cbuflenp)
 1631                 return ERANGE;
 1632         *cbufp += len;
 1633         *cbuflenp -= len;
 1634 
 1635         return (0);
 1636 }
 1637 
 1638 /*
 1639  * Skip over a value
 1640  */
 1641 static int
 1642 ng_parse_skip_value(const char *s, int off0, int *lenp)
 1643 {
 1644         int len, nbracket, nbrace;
 1645         int off = off0;
 1646 
 1647         len = nbracket = nbrace = 0;
 1648         do {
 1649                 switch (ng_parse_get_token(s, &off, &len)) {
 1650                 case T_LBRACKET:
 1651                         nbracket++;
 1652                         break;
 1653                 case T_LBRACE:
 1654                         nbrace++;
 1655                         break;
 1656                 case T_RBRACKET:
 1657                         if (nbracket-- == 0)
 1658                                 return (EINVAL);
 1659                         break;
 1660                 case T_RBRACE:
 1661                         if (nbrace-- == 0)
 1662                                 return (EINVAL);
 1663                         break;
 1664                 case T_EOF:
 1665                         return (EINVAL);
 1666                 default:
 1667                         break;
 1668                 }
 1669                 off += len;
 1670         } while (nbracket > 0 || nbrace > 0);
 1671         *lenp = off - off0;
 1672         return (0);
 1673 }
 1674 
 1675 /*
 1676  * Find the next token in the string, starting at offset *startp.
 1677  * Returns the token type, with *startp pointing to the first char
 1678  * and *lenp the length.
 1679  */
 1680 enum ng_parse_token
 1681 ng_parse_get_token(const char *s, int *startp, int *lenp)
 1682 {
 1683         char *t;
 1684         int i;
 1685 
 1686         while (isspace(s[*startp]))
 1687                 (*startp)++;
 1688         switch (s[*startp]) {
 1689         case '\0':
 1690                 *lenp = 0;
 1691                 return T_EOF;
 1692         case '{':
 1693                 *lenp = 1;
 1694                 return T_LBRACE;
 1695         case '}':
 1696                 *lenp = 1;
 1697                 return T_RBRACE;
 1698         case '[':
 1699                 *lenp = 1;
 1700                 return T_LBRACKET;
 1701         case ']':
 1702                 *lenp = 1;
 1703                 return T_RBRACKET;
 1704         case '=':
 1705                 *lenp = 1;
 1706                 return T_EQUALS;
 1707         case '"':
 1708                 if ((t = ng_get_string_token(s, startp, lenp, NULL)) == NULL)
 1709                         return T_ERROR;
 1710                 free(t, M_NETGRAPH_PARSE);
 1711                 return T_STRING;
 1712         default:
 1713                 for (i = *startp + 1; s[i] != '\0' && !isspace(s[i])
 1714                     && s[i] != '{' && s[i] != '}' && s[i] != '['
 1715                     && s[i] != ']' && s[i] != '=' && s[i] != '"'; i++)
 1716                         ;
 1717                 *lenp = i - *startp;
 1718                 return T_WORD;
 1719         }
 1720 }
 1721 
 1722 /*
 1723  * Get a string token, which must be enclosed in double quotes.
 1724  * The normal C backslash escapes are recognized.
 1725  */
 1726 char *
 1727 ng_get_string_token(const char *s, int *startp, int *lenp, int *slenp)
 1728 {
 1729         char *cbuf, *p;
 1730         int start, off;
 1731         int slen;
 1732 
 1733         while (isspace(s[*startp]))
 1734                 (*startp)++;
 1735         start = *startp;
 1736         if (s[*startp] != '"')
 1737                 return (NULL);
 1738         cbuf = malloc(strlen(s + start), M_NETGRAPH_PARSE, M_NOWAIT);
 1739         if (cbuf == NULL)
 1740                 return (NULL);
 1741         strcpy(cbuf, s + start + 1);
 1742         for (slen = 0, off = 1, p = cbuf; *p != '\0'; slen++, off++, p++) {
 1743                 if (*p == '"') {
 1744                         *p = '\0';
 1745                         *lenp = off + 1;
 1746                         if (slenp != NULL)
 1747                                 *slenp = slen;
 1748                         return (cbuf);
 1749                 } else if (p[0] == '\\' && p[1] != '\0') {
 1750                         int x, k;
 1751                         char *v;
 1752 
 1753                         strcpy(p, p + 1);
 1754                         v = p;
 1755                         switch (*p) {
 1756                         case 't':
 1757                                 *v = '\t';
 1758                                 off++;
 1759                                 continue;
 1760                         case 'n':
 1761                                 *v = '\n';
 1762                                 off++;
 1763                                 continue;
 1764                         case 'r':
 1765                                 *v = '\r';
 1766                                 off++;
 1767                                 continue;
 1768                         case 'v':
 1769                                 *v =  '\v';
 1770                                 off++;
 1771                                 continue;
 1772                         case 'f':
 1773                                 *v =  '\f';
 1774                                 off++;
 1775                                 continue;
 1776                         case '"':
 1777                                 *v =  '"';
 1778                                 off++;
 1779                                 continue;
 1780                         case '': case '1': case '2': case '3':
 1781                         case '4': case '5': case '6': case '7':
 1782                                 for (x = k = 0;
 1783                                     k < 3 && *v >= '' && *v <= '7'; v++) {
 1784                                         x = (x << 3) + (*v - '');
 1785                                         off++;
 1786                                 }
 1787                                 *--v = (char)x;
 1788                                 break;
 1789                         case 'x':
 1790                                 for (v++, x = k = 0;
 1791                                     k < 2 && isxdigit(*v); v++) {
 1792                                         x = (x << 4) + (isdigit(*v) ?
 1793                                               (*v - '') :
 1794                                               (tolower(*v) - 'a' + 10));
 1795                                         off++;
 1796                                 }
 1797                                 *--v = (char)x;
 1798                                 break;
 1799                         default:
 1800                                 continue;
 1801                         }
 1802                         strcpy(p, v);
 1803                 }
 1804         }
 1805         free(cbuf, M_NETGRAPH_PARSE);
 1806         return (NULL);          /* no closing quote */
 1807 }
 1808 
 1809 /*
 1810  * Encode a string so it can be safely put in double quotes.
 1811  * Caller must free the result. Exactly "slen" characters
 1812  * are encoded.
 1813  */
 1814 char *
 1815 ng_encode_string(const char *raw, int slen)
 1816 {
 1817         char *cbuf;
 1818         int off = 0;
 1819         int i;
 1820 
 1821         cbuf = malloc(strlen(raw) * 4 + 3, M_NETGRAPH_PARSE, M_NOWAIT);
 1822         if (cbuf == NULL)
 1823                 return (NULL);
 1824         cbuf[off++] = '"';
 1825         for (i = 0; i < slen; i++, raw++) {
 1826                 switch (*raw) {
 1827                 case '\t':
 1828                         cbuf[off++] = '\\';
 1829                         cbuf[off++] = 't';
 1830                         break;
 1831                 case '\f':
 1832                         cbuf[off++] = '\\';
 1833                         cbuf[off++] = 'f';
 1834                         break;
 1835                 case '\n':
 1836                         cbuf[off++] = '\\';
 1837                         cbuf[off++] = 'n';
 1838                         break;
 1839                 case '\r':
 1840                         cbuf[off++] = '\\';
 1841                         cbuf[off++] = 'r';
 1842                         break;
 1843                 case '\v':
 1844                         cbuf[off++] = '\\';
 1845                         cbuf[off++] = 'v';
 1846                         break;
 1847                 case '"':
 1848                 case '\\':
 1849                         cbuf[off++] = '\\';
 1850                         cbuf[off++] = *raw;
 1851                         break;
 1852                 default:
 1853                         if (*raw < 0x20 || *raw > 0x7e) {
 1854                                 off += sprintf(cbuf + off,
 1855                                     "\\x%02x", (u_char)*raw);
 1856                                 break;
 1857                         }
 1858                         cbuf[off++] = *raw;
 1859                         break;
 1860                 }
 1861         }
 1862         cbuf[off++] = '"';
 1863         cbuf[off] = '\0';
 1864         return (cbuf);
 1865 }
 1866 
 1867 /************************************************************************
 1868                         VIRTUAL METHOD LOOKUP
 1869  ************************************************************************/
 1870 
 1871 static ng_parse_t *
 1872 ng_get_parse_method(const struct ng_parse_type *t)
 1873 {
 1874         while (t != NULL && t->parse == NULL)
 1875                 t = t->supertype;
 1876         return (t ? t->parse : NULL);
 1877 }
 1878 
 1879 static ng_unparse_t *
 1880 ng_get_unparse_method(const struct ng_parse_type *t)
 1881 {
 1882         while (t != NULL && t->unparse == NULL)
 1883                 t = t->supertype;
 1884         return (t ? t->unparse : NULL);
 1885 }
 1886 
 1887 static ng_getDefault_t *
 1888 ng_get_getDefault_method(const struct ng_parse_type *t)
 1889 {
 1890         while (t != NULL && t->getDefault == NULL)
 1891                 t = t->supertype;
 1892         return (t ? t->getDefault : NULL);
 1893 }
 1894 
 1895 static ng_getAlign_t *
 1896 ng_get_getAlign_method(const struct ng_parse_type *t)
 1897 {
 1898         while (t != NULL && t->getAlign == NULL)
 1899                 t = t->supertype;
 1900         return (t ? t->getAlign : NULL);
 1901 }
 1902 

Cache object: a2fd2c3a66195dc5aba7de20e7f8da2d


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