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

Cache object: 7dc0d35cc90ad160e46f5690cf102cb6


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