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

Cache object: e2939ee8a6ac0561568ebb7b8c5943f6


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