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

Cache object: 363e551f3959bbdb14b33aeb3cd2817c


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