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/dev/bhnd/nvram/bhnd_nvram_value_fmts.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  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer,
   10  *    without modification.
   11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   13  *    redistribution must be conditioned upon including a substantially
   14  *    similar Disclaimer requirement for further binary redistribution.
   15  *
   16  * NO WARRANTY
   17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   27  * THE POSSIBILITY OF SUCH DAMAGES.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 
   35 #include <net/ethernet.h>
   36 
   37 #ifdef _KERNEL
   38 
   39 #include <sys/ctype.h>
   40 #include <sys/kernel.h>
   41 #include <sys/malloc.h>
   42 #include <sys/systm.h>
   43 
   44 #include <machine/_inttypes.h>
   45 
   46 #else /* !_KERNEL */
   47 
   48 #include <ctype.h>
   49 #include <errno.h>
   50 #include <inttypes.h>
   51 #include <stdlib.h>
   52 #include <string.h>
   53 
   54 #endif /* _KERNEL */
   55 
   56 #include "bhnd_nvram_private.h"
   57 
   58 #include "bhnd_nvram_valuevar.h"
   59 
   60 static bool              bhnd_nvram_ident_octet_string(const char *inp,
   61                              size_t ilen, char *delim, size_t *nelem);
   62 static bool              bhnd_nvram_ident_num_string(const char *inp,
   63                              size_t ilen, u_int base, u_int *obase);
   64 
   65 static int               bhnd_nvram_val_bcm_macaddr_filter(
   66                              const bhnd_nvram_val_fmt **fmt, const void *inp,
   67                              size_t ilen, bhnd_nvram_type itype);
   68 static int               bhnd_nvram_val_bcm_macaddr_encode(
   69                              bhnd_nvram_val *value, void *outp, size_t *olen,
   70                              bhnd_nvram_type otype);
   71 
   72 static int               bhnd_nvram_val_bcm_macaddr_string_filter(
   73                              const bhnd_nvram_val_fmt **fmt, const void *inp,
   74                              size_t ilen, bhnd_nvram_type itype);
   75 static int               bhnd_nvram_val_bcm_macaddr_string_encode_elem(
   76                              bhnd_nvram_val *value, const void *inp,
   77                              size_t ilen, void *outp, size_t *olen, 
   78                              bhnd_nvram_type otype);
   79 static const void       *bhnd_nvram_val_bcm_macaddr_string_next(
   80                              bhnd_nvram_val *value, const void *prev,
   81                              size_t *len);
   82 
   83 static int               bhnd_nvram_val_bcm_int_filter(
   84                              const bhnd_nvram_val_fmt **fmt, const void *inp,
   85                              size_t ilen, bhnd_nvram_type itype);
   86 static int               bhnd_nvram_val_bcm_int_encode(bhnd_nvram_val *value,
   87                              void *outp, size_t *olen, bhnd_nvram_type otype);
   88 
   89 static int               bhnd_nvram_val_bcm_decimal_encode_elem(
   90                              bhnd_nvram_val *value, const void *inp,
   91                              size_t ilen, void *outp, size_t *olen,
   92                              bhnd_nvram_type otype);
   93 static int               bhnd_nvram_val_bcm_hex_encode_elem(
   94                              bhnd_nvram_val *value, const void *inp,
   95                              size_t ilen, void *outp, size_t *olen,
   96                              bhnd_nvram_type otype);
   97 
   98 static int               bhnd_nvram_val_bcm_leddc_filter(
   99                              const bhnd_nvram_val_fmt **fmt, const void *inp,
  100                              size_t ilen, bhnd_nvram_type itype);
  101 static int               bhnd_nvram_val_bcm_leddc_encode_elem(
  102                              bhnd_nvram_val *value, const void *inp,
  103                              size_t ilen, void *outp, size_t *olen,
  104                              bhnd_nvram_type otype);
  105 
  106 static int               bhnd_nvram_val_bcmstr_encode(bhnd_nvram_val *value,
  107                              void *outp, size_t *olen, bhnd_nvram_type otype);
  108 
  109 static int               bhnd_nvram_val_bcmstr_csv_filter(
  110                              const bhnd_nvram_val_fmt **fmt, const void *inp,
  111                              size_t ilen, bhnd_nvram_type itype);
  112 static const void       *bhnd_nvram_val_bcmstr_csv_next(bhnd_nvram_val *value,
  113                              const void *prev, size_t *len);
  114 
  115 /**
  116  * Broadcom NVRAM MAC address format.
  117  */
  118 const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_macaddr_fmt = {
  119         .name           = "bcm-macaddr",
  120         .native_type    = BHND_NVRAM_TYPE_UINT8_ARRAY,
  121         .op_filter      = bhnd_nvram_val_bcm_macaddr_filter,
  122         .op_encode      = bhnd_nvram_val_bcm_macaddr_encode,
  123 };
  124 
  125 /** Broadcom NVRAM MAC address string format. */
  126 static const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_macaddr_string_fmt = {
  127         .name           = "bcm-macaddr-string",
  128         .native_type    = BHND_NVRAM_TYPE_STRING,
  129         .op_filter      = bhnd_nvram_val_bcm_macaddr_string_filter,
  130         .op_encode_elem = bhnd_nvram_val_bcm_macaddr_string_encode_elem,
  131         .op_next        = bhnd_nvram_val_bcm_macaddr_string_next,
  132 };
  133 
  134 /**
  135  * Broadcom NVRAM LED duty-cycle format.
  136  */
  137 const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_leddc_fmt = {
  138         .name           = "bcm-leddc",
  139         .native_type    = BHND_NVRAM_TYPE_UINT32,
  140         .op_filter      = bhnd_nvram_val_bcm_leddc_filter,
  141         .op_encode_elem = bhnd_nvram_val_bcm_leddc_encode_elem,
  142 };
  143 
  144 /**
  145  * Broadcom NVRAM decimal integer format.
  146  *
  147  * Extends standard integer handling, encoding the string representation of
  148  * the integer value as a decimal string:
  149  * - Positive values will be string-encoded without a prefix.
  150  * - Negative values will be string-encoded with a leading '-' sign.
  151  */
  152 const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_decimal_fmt = {
  153         .name           = "bcm-decimal",
  154         .native_type    = BHND_NVRAM_TYPE_UINT64,
  155         .op_filter      = bhnd_nvram_val_bcm_int_filter,
  156         .op_encode      = bhnd_nvram_val_bcm_int_encode,
  157         .op_encode_elem = bhnd_nvram_val_bcm_decimal_encode_elem,
  158 };
  159 
  160 /**
  161  * Broadcom NVRAM decimal integer format.
  162  *
  163  * Extends standard integer handling, encoding the string representation of
  164  * unsigned and positive signed integer values as an 0x-prefixed hexadecimal
  165  * string.
  166  * 
  167  * For compatibility with standard Broadcom NVRAM parsing, if the integer is
  168  * both signed and negative, it will be string encoded as a negative decimal
  169  * value, not as a twos-complement hexadecimal value.
  170  */
  171 const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_hex_fmt = {
  172         .name           = "bcm-hex",
  173         .native_type    = BHND_NVRAM_TYPE_UINT64,
  174         .op_filter      = bhnd_nvram_val_bcm_int_filter,
  175         .op_encode      = bhnd_nvram_val_bcm_int_encode,
  176         .op_encode_elem = bhnd_nvram_val_bcm_hex_encode_elem,
  177 };
  178 
  179 /**
  180  * Broadcom NVRAM string format.
  181  * 
  182  * Handles standard, comma-delimited, and octet-string values as used in
  183  * Broadcom NVRAM data.
  184  */
  185 const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_string_fmt = {
  186         .name           = "bcm-string",
  187         .native_type    = BHND_NVRAM_TYPE_STRING,
  188         .op_encode      = bhnd_nvram_val_bcmstr_encode,
  189 };
  190 
  191 /** Broadcom comma-delimited string. */
  192 static const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_string_csv_fmt = {
  193         .name           = "bcm-string[]",
  194         .native_type    = BHND_NVRAM_TYPE_STRING,
  195         .op_filter      = bhnd_nvram_val_bcmstr_csv_filter,
  196         .op_next        = bhnd_nvram_val_bcmstr_csv_next,
  197 };
  198 
  199 /* Built-in format definitions */
  200 #define BHND_NVRAM_VAL_FMT_NATIVE(_n, _type)                            \
  201         const bhnd_nvram_val_fmt bhnd_nvram_val_ ## _n ## _fmt = {      \
  202                 .name           = __STRING(_n),                         \
  203                 .native_type    = BHND_NVRAM_TYPE_ ## _type,            \
  204         }
  205 
  206 BHND_NVRAM_VAL_FMT_NATIVE(uint8,        UINT8);
  207 BHND_NVRAM_VAL_FMT_NATIVE(uint16,       UINT16);
  208 BHND_NVRAM_VAL_FMT_NATIVE(uint32,       UINT32);
  209 BHND_NVRAM_VAL_FMT_NATIVE(uint64,       UINT64);
  210 BHND_NVRAM_VAL_FMT_NATIVE(int8,         INT8);
  211 BHND_NVRAM_VAL_FMT_NATIVE(int16,        INT16);
  212 BHND_NVRAM_VAL_FMT_NATIVE(int32,        INT32);
  213 BHND_NVRAM_VAL_FMT_NATIVE(int64,        INT64);
  214 BHND_NVRAM_VAL_FMT_NATIVE(char,         CHAR);
  215 BHND_NVRAM_VAL_FMT_NATIVE(bool,         BOOL);
  216 BHND_NVRAM_VAL_FMT_NATIVE(string,       STRING);
  217 BHND_NVRAM_VAL_FMT_NATIVE(data,         DATA);
  218 BHND_NVRAM_VAL_FMT_NATIVE(null,         NULL);
  219 
  220 BHND_NVRAM_VAL_FMT_NATIVE(uint8_array,  UINT8_ARRAY);
  221 BHND_NVRAM_VAL_FMT_NATIVE(uint16_array, UINT16_ARRAY);
  222 BHND_NVRAM_VAL_FMT_NATIVE(uint32_array, UINT32_ARRAY);
  223 BHND_NVRAM_VAL_FMT_NATIVE(uint64_array, UINT64_ARRAY);
  224 BHND_NVRAM_VAL_FMT_NATIVE(int8_array,   INT8_ARRAY);
  225 BHND_NVRAM_VAL_FMT_NATIVE(int16_array,  INT16_ARRAY);
  226 BHND_NVRAM_VAL_FMT_NATIVE(int32_array,  INT32_ARRAY);
  227 BHND_NVRAM_VAL_FMT_NATIVE(int64_array,  INT64_ARRAY);
  228 BHND_NVRAM_VAL_FMT_NATIVE(char_array,   CHAR_ARRAY);
  229 BHND_NVRAM_VAL_FMT_NATIVE(bool_array,   BOOL_ARRAY);
  230 BHND_NVRAM_VAL_FMT_NATIVE(string_array, STRING_ARRAY);
  231 
  232 /**
  233  * Common hex/decimal integer filter implementation.
  234  */
  235 static int
  236 bhnd_nvram_val_bcm_int_filter(const bhnd_nvram_val_fmt **fmt, const void *inp,
  237     size_t ilen, bhnd_nvram_type itype)
  238 {
  239         bhnd_nvram_type itype_base;
  240 
  241         itype_base = bhnd_nvram_base_type(itype);
  242 
  243         switch (itype_base) {
  244         case BHND_NVRAM_TYPE_STRING:
  245                 /*
  246                  * If the input is a string, delegate to the Broadcom
  247                  * string format -- preserving the original string value
  248                  * takes priority over enforcing hexadecimal/integer string
  249                  * formatting.
  250                  */
  251                 *fmt = &bhnd_nvram_val_bcm_string_fmt;
  252                 return (0);
  253 
  254         default:
  255                 if (bhnd_nvram_is_int_type(itype_base))
  256                         return (0);
  257 
  258                 return (EFTYPE);
  259         }
  260 }
  261 
  262 /**
  263  * Broadcom hex/decimal integer encode implementation.
  264  */
  265 static int
  266 bhnd_nvram_val_bcm_int_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
  267     bhnd_nvram_type otype)
  268 {
  269         /* If encoding to a string, format multiple elements (if any) with a
  270          * comma delimiter. */
  271         if (otype == BHND_NVRAM_TYPE_STRING)
  272                 return (bhnd_nvram_val_printf(value, "%[]s", outp, olen, ","));
  273 
  274         return (bhnd_nvram_val_generic_encode(value, outp, olen, otype));
  275 }
  276 
  277 /**
  278  * Broadcom hex integer encode_elem implementation.
  279  */
  280 static int
  281 bhnd_nvram_val_bcm_hex_encode_elem(bhnd_nvram_val *value, const void *inp,
  282     size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
  283 {
  284         bhnd_nvram_type itype;
  285         ssize_t         width;
  286         int             error;
  287 
  288         itype = bhnd_nvram_val_elem_type(value);
  289         BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("invalid type"));
  290 
  291         /* If not encoding as a string, perform generic value encoding */
  292         if (otype != BHND_NVRAM_TYPE_STRING)
  293                 return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen,
  294                     outp, olen, otype));
  295 
  296         /* If the value is a signed, negative value, encode as a decimal
  297          * string */
  298         if (bhnd_nvram_is_signed_type(itype)) {
  299                 int64_t         sval;
  300                 size_t          slen;
  301                 bhnd_nvram_type stype;
  302 
  303                 stype = BHND_NVRAM_TYPE_INT64;
  304                 slen = sizeof(sval);
  305 
  306                 /* Fetch 64-bit signed representation */
  307                 error = bhnd_nvram_value_coerce(inp, ilen, itype, &sval, &slen,
  308                     stype);
  309                 if (error)
  310                         return (error);
  311 
  312                 /* Decimal encoding required? */
  313                 if (sval < 0)
  314                         return (bhnd_nvram_value_printf("%I64d", &sval, slen,
  315                             stype, outp, olen, otype));
  316         }
  317 
  318         /*
  319          * Encode the value as a hex string.
  320          * 
  321          * Most producers of Broadcom NVRAM values zero-pad hex values out to
  322          * their native width (width * two hex characters), and we do the same
  323          * for compatibility
  324          */
  325         width = bhnd_nvram_type_width(itype) * 2;
  326         return (bhnd_nvram_value_printf("0x%0*I64X", inp, ilen, itype,
  327             outp, olen, width));
  328 }
  329 
  330 /**
  331  * Broadcom decimal integer encode_elem implementation.
  332  */
  333 static int
  334 bhnd_nvram_val_bcm_decimal_encode_elem(bhnd_nvram_val *value, const void *inp,
  335     size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
  336 {
  337         const char      *sfmt;
  338         bhnd_nvram_type  itype;
  339 
  340         itype = bhnd_nvram_val_elem_type(value);
  341         BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("invalid type"));
  342 
  343         /* If not encoding as a string, perform generic value encoding */
  344         if (otype != BHND_NVRAM_TYPE_STRING)
  345                 return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen,
  346                     outp, olen, otype));
  347 
  348         sfmt = bhnd_nvram_is_signed_type(itype) ? "%I64d" : "%I64u";
  349         return (bhnd_nvram_value_printf(sfmt, inp, ilen, itype, outp, olen));
  350 }
  351 
  352 /**
  353  * Broadcom LED duty-cycle filter.
  354  */
  355 static int
  356 bhnd_nvram_val_bcm_leddc_filter(const bhnd_nvram_val_fmt **fmt,
  357     const void *inp, size_t ilen, bhnd_nvram_type itype)
  358 {
  359         const char      *p;
  360         size_t           plen;
  361 
  362         switch (itype) {
  363         case BHND_NVRAM_TYPE_UINT16:
  364         case BHND_NVRAM_TYPE_UINT32:
  365                 return (0);
  366 
  367         case BHND_NVRAM_TYPE_STRING:
  368                 /* Trim any whitespace */
  369                 p = inp;
  370                 plen = bhnd_nvram_trim_field(&p, ilen, '\0');
  371 
  372                 /* If the value is not a valid integer string, delegate to the
  373                  * Broadcom string format */
  374                 if (!bhnd_nvram_ident_num_string(p, plen, 0, NULL))
  375                         *fmt = &bhnd_nvram_val_bcm_string_fmt;
  376 
  377                 return (0);
  378         default:
  379                 return (EFTYPE);
  380         }
  381 }
  382 
  383 /**
  384  * Broadcom LED duty-cycle encode.
  385  */
  386 static int
  387 bhnd_nvram_val_bcm_leddc_encode_elem(bhnd_nvram_val *value, const void *inp,
  388     size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
  389 {
  390         bhnd_nvram_type         itype;
  391         size_t                  limit, nbytes;
  392         int                     error;
  393         uint16_t                led16;
  394         uint32_t                led32;
  395         bool                    led16_lossy;
  396         union {
  397                 uint16_t        u16;
  398                 uint32_t        u32;
  399         } strval;
  400 
  401         /*
  402          * LED duty-cycle values represent the on/off periods as a 32-bit
  403          * integer, with the top 16 bits representing on cycles, and the
  404          * bottom 16 representing off cycles.
  405          * 
  406          * LED duty cycle values have three different formats:
  407          * 
  408          * - SPROM:     A 16-bit unsigned integer, with on/off cycles encoded
  409          *              as 8-bit values.
  410          * - NVRAM:     A 16-bit decimal or hexadecimal string, with on/off
  411          *              cycles encoded as 8-bit values as per the SPROM format.
  412          * - NVRAM:     A 32-bit decimal or hexadecimal string, with on/off
  413          *              cycles encoded as 16-bit values.
  414          *
  415          * To convert from a 16-bit representation to a 32-bit representation:
  416          *     ((value & 0xFF00) << 16) | ((value & 0x00FF) << 8)
  417          * 
  418          * To convert from a 32-bit representation to a 16-bit representation,
  419          * perform the same operation in reverse, discarding the lower 8-bits
  420          * of each half of the 32-bit representation:
  421          *     ((value >> 16) & 0xFF00) | ((value >> 8) & 0x00FF)
  422          */
  423 
  424         itype = bhnd_nvram_val_elem_type(value);
  425         nbytes = 0;
  426         led16_lossy = false;
  427 
  428         /* Determine output byte limit */
  429         if (outp != NULL)
  430                 limit = *olen;
  431         else
  432                 limit = 0;
  433 
  434         /* If the input/output types match, just delegate to standard value
  435          * encoding support */
  436         if (otype == itype) {
  437                 return (bhnd_nvram_value_coerce(inp, ilen, itype, outp, olen,
  438                     otype));
  439         }
  440 
  441         /* If our value is a string, it may either be a 16-bit or a 32-bit
  442          * representation of the duty cycle */
  443         if (itype == BHND_NVRAM_TYPE_STRING) {
  444                 const char      *p;
  445                 uint32_t         ival;
  446                 size_t           nlen, parsed;
  447 
  448                 /* Parse integer value */
  449                 p = inp;
  450                 nlen = sizeof(ival);
  451                 error = bhnd_nvram_parse_int(p, ilen, 0, &parsed, &ival, &nlen,
  452                     BHND_NVRAM_TYPE_UINT32);
  453                 if (error)
  454                         return (error);
  455 
  456                 /* Trailing garbage? */
  457                 if (parsed < ilen && *(p+parsed) != '\0')
  458                         return (EFTYPE);
  459 
  460                 /* Point inp and itype to either our parsed 32-bit or 16-bit
  461                  * value */
  462                 inp = &strval;
  463                 if (ival & 0xFFFF0000) {
  464                         strval.u32 = ival;
  465                         itype = BHND_NVRAM_TYPE_UINT32;
  466                 } else {
  467                         strval.u16 = ival;
  468                         itype = BHND_NVRAM_TYPE_UINT16;
  469                 }
  470         }
  471 
  472         /* Populate both u32 and (possibly lossy) u16 LEDDC representations */
  473         switch (itype) {
  474         case BHND_NVRAM_TYPE_UINT16: {
  475                 led16 = *(const uint16_t *)inp;
  476                 led32 = ((led16 & 0xFF00) << 16) | ((led16 & 0x00FF) << 8);
  477 
  478                 /* If all bits are set in the 16-bit value (indicating that
  479                  * the value is 'unset' in SPROM), we must update the 32-bit
  480                  * representation to match. */
  481                 if (led16 == UINT16_MAX)
  482                         led32 = UINT32_MAX;
  483 
  484                 break;
  485         }
  486 
  487         case BHND_NVRAM_TYPE_UINT32:
  488                 led32 = *(const uint32_t *)inp;
  489                 led16 = ((led32 >> 16) & 0xFF00) | ((led32 >> 8) & 0x00FF);
  490 
  491                 /*
  492                  * Determine whether the led16 conversion is lossy:
  493                  * 
  494                  * - If the lower 8 bits of each half of the 32-bit value
  495                  *   aren't set, we can safely use the 16-bit representation
  496                  *   without losing data.
  497                  * - If all bits in the 32-bit value are set, the variable is
  498                  *   treated as unset in  SPROM. We can safely use the 16-bit
  499                  *   representation without losing data.
  500                  */
  501                 if ((led32 & 0x00FF00FF) != 0 && led32 != UINT32_MAX)
  502                         led16_lossy = true;
  503 
  504                 break;
  505         default:
  506                 BHND_NV_PANIC("unsupported backing data type: %s",
  507                     bhnd_nvram_type_name(itype));
  508         }
  509 
  510         /*
  511          * Encode as requested output type.
  512          */
  513         switch (otype) {
  514         case BHND_NVRAM_TYPE_STRING:
  515                 /*
  516                  * Prefer 16-bit format.
  517                  */
  518                 if (!led16_lossy) {
  519                         return (bhnd_nvram_value_printf("0x%04hX", &led16,
  520                             sizeof(led16), BHND_NVRAM_TYPE_UINT16, outp, olen));
  521                 } else {
  522                         return (bhnd_nvram_value_printf("0x%04X", &led32,
  523                             sizeof(led32), BHND_NVRAM_TYPE_UINT32, outp, olen));
  524                 }
  525 
  526                 break;
  527 
  528         case BHND_NVRAM_TYPE_UINT16: {
  529                 /* Can we encode as uint16 without losing data? */
  530                 if (led16_lossy)
  531                         return (ERANGE);
  532 
  533                 /* Write led16 format */
  534                 nbytes += sizeof(uint16_t);
  535                 if (limit >= nbytes)
  536                         *(uint16_t *)outp = led16;
  537 
  538                 break;
  539         }
  540 
  541         case BHND_NVRAM_TYPE_UINT32:
  542                 /* Write led32 format */
  543                 nbytes += sizeof(uint32_t);
  544                 if (limit >= nbytes)
  545                         *(uint32_t *)outp = led32;
  546                 break;
  547 
  548         default:
  549                 /* No other output formats are supported */
  550                 return (EFTYPE);
  551         }
  552 
  553         /* Provide the actual length */
  554         *olen = nbytes;
  555 
  556         /* Report insufficient space (if output was requested) */
  557         if (limit < nbytes && outp != NULL)
  558                 return (ENOMEM);
  559 
  560         return (0);
  561 }
  562 
  563 /**
  564  * Broadcom NVRAM string encoding.
  565  */
  566 static int
  567 bhnd_nvram_val_bcmstr_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
  568     bhnd_nvram_type otype)
  569 {
  570         bhnd_nvram_val                   array;
  571         const bhnd_nvram_val_fmt        *array_fmt;
  572         const void                      *inp;
  573         bhnd_nvram_type                 itype;
  574         size_t                          ilen;
  575         int                             error;
  576 
  577         inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
  578 
  579         /* If the output is not an array type (or if it's a character array),
  580          * we can fall back on standard string encoding */
  581         if (!bhnd_nvram_is_array_type(otype) ||
  582             otype == BHND_NVRAM_TYPE_CHAR_ARRAY)
  583         {
  584                 return (bhnd_nvram_value_coerce(inp, ilen, itype, outp, olen,
  585                     otype));
  586         }
  587 
  588         /* Otherwise, we need to interpret our value as either a macaddr
  589          * string, or a comma-delimited string. */
  590         inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
  591         if (bhnd_nvram_ident_octet_string(inp, ilen, NULL, NULL))
  592                 array_fmt = &bhnd_nvram_val_bcm_macaddr_string_fmt;
  593         else
  594                 array_fmt = &bhnd_nvram_val_bcm_string_csv_fmt;
  595 
  596         /* Wrap in array-typed representation */
  597         error = bhnd_nvram_val_init(&array, array_fmt, inp, ilen, itype,
  598             BHND_NVRAM_VAL_BORROW_DATA);
  599         if (error) {
  600                 BHND_NV_LOG("error initializing array representation: %d\n",
  601                     error);
  602                 return (error);
  603         }
  604 
  605         /* Ask the array-typed value to perform the encode */
  606         error = bhnd_nvram_val_encode(&array, outp, olen, otype);
  607         if (error)
  608                 BHND_NV_LOG("error encoding array representation: %d\n", error);
  609 
  610         bhnd_nvram_val_release(&array);
  611 
  612         return (error);
  613 }
  614 
  615 /**
  616  * Broadcom NVRAM comma-delimited string filter.
  617  */
  618 static int
  619 bhnd_nvram_val_bcmstr_csv_filter(const bhnd_nvram_val_fmt **fmt,
  620     const void *inp, size_t ilen, bhnd_nvram_type itype)
  621 {
  622         switch (itype) {
  623         case BHND_NVRAM_TYPE_STRING:
  624         case BHND_NVRAM_TYPE_STRING_ARRAY:
  625                 return (0);
  626         default:
  627                 return (EFTYPE);
  628         }
  629 }
  630 
  631 /**
  632  * Broadcom NVRAM comma-delimited string iteration.
  633  */
  634 static const void *
  635 bhnd_nvram_val_bcmstr_csv_next(bhnd_nvram_val *value, const void *prev,
  636     size_t *len)
  637 {
  638         const char      *next;
  639         const char      *inp;
  640         bhnd_nvram_type  itype;
  641         size_t           ilen, remain;
  642         char             delim;
  643 
  644         /* Fetch backing representation */
  645         inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
  646 
  647         /* Fetch next value */
  648         switch (itype) {
  649         case BHND_NVRAM_TYPE_STRING:
  650                 /* Zero-length array? */
  651                 if (ilen == 0)
  652                         return (NULL);
  653 
  654                 if (prev == NULL) {
  655                         /* First element */
  656                         next = inp;
  657                         remain = ilen;
  658                         delim = ',';
  659                 } else {
  660                         /* Advance to the previous element's delimiter */
  661                         next = (const char *)prev + *len;
  662 
  663                         /* Did we hit the end of the string? */
  664                         if ((size_t)(next - inp) >= ilen)
  665                                 return (NULL);
  666 
  667                         /* Fetch (and skip past) the delimiter */
  668                         delim = *next;
  669                         next++;
  670                         remain = ilen - (size_t)(next - inp);
  671 
  672                         /* Was the delimiter the final character? */
  673                         if (remain == 0)
  674                                 return (NULL);
  675                 }
  676 
  677                 /* Parse the field value, up to the next delimiter */
  678                 *len = bhnd_nvram_parse_field(&next, remain, delim);
  679 
  680                 return (next);
  681 
  682         case BHND_NVRAM_TYPE_STRING_ARRAY:
  683                 /* Delegate to default array iteration */
  684                 return (bhnd_nvram_value_array_next(inp, ilen, itype, prev,
  685                     len));
  686         default:
  687                 BHND_NV_PANIC("unsupported type: %d", itype);
  688         }
  689 }
  690 
  691 /**
  692  * MAC address filter.
  693  */
  694 static int
  695 bhnd_nvram_val_bcm_macaddr_filter(const bhnd_nvram_val_fmt **fmt,
  696     const void *inp, size_t ilen, bhnd_nvram_type itype)
  697 {
  698         switch (itype) {
  699         case BHND_NVRAM_TYPE_UINT8_ARRAY:
  700                 return (0);
  701         case BHND_NVRAM_TYPE_STRING:
  702                 /* Let bcm_macaddr_string format handle it */
  703                 *fmt = &bhnd_nvram_val_bcm_macaddr_string_fmt;
  704                 return (0);
  705         default:
  706                 return (EFTYPE);
  707         }
  708 }
  709 
  710 /**
  711  * MAC address encoding.
  712  */
  713 static int
  714 bhnd_nvram_val_bcm_macaddr_encode(bhnd_nvram_val *value, void *outp,
  715     size_t *olen, bhnd_nvram_type otype)
  716 {
  717         const void      *inp;
  718         bhnd_nvram_type  itype;
  719         size_t           ilen;
  720 
  721         /*
  722          * If converting to a string (or a single-element string array),
  723          * produce an octet string (00:00:...).
  724          */
  725         if (bhnd_nvram_base_type(otype) == BHND_NVRAM_TYPE_STRING) {
  726                 return (bhnd_nvram_val_printf(value, "%[]02hhX", outp, olen,
  727                     ":"));
  728         }
  729 
  730         /* Otherwise, use standard encoding support */
  731         inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
  732         return (bhnd_nvram_value_coerce(inp, ilen, itype, outp, olen, otype));}
  733 
  734 /**
  735  * MAC address string filter.
  736  */
  737 static int
  738 bhnd_nvram_val_bcm_macaddr_string_filter(const bhnd_nvram_val_fmt **fmt,
  739     const void *inp, size_t ilen, bhnd_nvram_type itype)
  740 {
  741         switch (itype) {
  742         case BHND_NVRAM_TYPE_STRING:
  743                 /* Use the standard Broadcom string format implementation if
  744                  * the input is not an octet string. */
  745                 if (!bhnd_nvram_ident_octet_string(inp, ilen, NULL, NULL))
  746                         *fmt = &bhnd_nvram_val_bcm_string_fmt;
  747 
  748                 return (0);
  749         default:
  750                 return (EFTYPE);
  751         }
  752 }
  753 
  754 /**
  755  * MAC address string octet encoding.
  756  */
  757 static int
  758 bhnd_nvram_val_bcm_macaddr_string_encode_elem(bhnd_nvram_val *value,
  759     const void *inp, size_t ilen, void *outp, size_t *olen,
  760     bhnd_nvram_type otype)
  761 {
  762         size_t  nparsed;
  763         int     error;
  764 
  765         /* If integer encoding is requested, explicitly parse our
  766          * non-0x-prefixed as a base 16 integer value */
  767         if (bhnd_nvram_is_int_type(otype)) {
  768                 error = bhnd_nvram_parse_int(inp, ilen, 16, &nparsed, outp,
  769                     olen, otype);
  770                 if (error)
  771                         return (error);
  772 
  773                 if (nparsed != ilen)
  774                         return (EFTYPE);
  775 
  776                 return (0);
  777         }
  778 
  779         /* Otherwise, use standard encoding support */
  780         return (bhnd_nvram_value_coerce(inp, ilen,
  781             bhnd_nvram_val_elem_type(value), outp, olen, otype));
  782 }
  783 
  784 /**
  785  * MAC address string octet iteration.
  786  */
  787 static const void *
  788 bhnd_nvram_val_bcm_macaddr_string_next(bhnd_nvram_val *value, const void *prev,
  789     size_t *len)
  790 {
  791         const char      *next;
  792         const char      *str;
  793         bhnd_nvram_type  stype;
  794         size_t           slen, remain;
  795         char             delim;
  796 
  797         /* Fetch backing string */
  798         str = bhnd_nvram_val_bytes(value, &slen, &stype);
  799         BHND_NV_ASSERT(stype == BHND_NVRAM_TYPE_STRING,
  800             ("unsupported type: %d", stype));
  801 
  802         /* Zero-length array? */
  803         if (slen == 0)
  804                 return (NULL);
  805 
  806         if (prev == NULL) {
  807                 /* First element */
  808 
  809                 /* Determine delimiter */
  810                 if (!bhnd_nvram_ident_octet_string(str, slen, &delim, NULL)) {
  811                         /* Default to comma-delimited parsing */
  812                         delim = ',';
  813                 }
  814 
  815                 /* Parsing will start at the base string pointer */
  816                 next = str;
  817                 remain = slen;
  818         } else {
  819                 /* Advance to the previous element's delimiter */
  820                 next = (const char *)prev + *len;
  821 
  822                 /* Did we hit the end of the string? */
  823                 if ((size_t)(next - str) >= slen)
  824                         return (NULL);
  825 
  826                 /* Fetch (and skip past) the delimiter */
  827                 delim = *next;
  828                 next++;
  829                 remain = slen - (size_t)(next - str);
  830 
  831                 /* Was the delimiter the final character? */
  832                 if (remain == 0)
  833                         return (NULL);
  834         }
  835 
  836         /* Parse the field value, up to the next delimiter */
  837         *len = bhnd_nvram_parse_field(&next, remain, delim);
  838 
  839         return (next);
  840 }
  841 
  842 /**
  843  * Determine whether @p inp is in octet string format, consisting of a
  844  * fields of two hex characters, separated with ':' or '-' delimiters.
  845  * 
  846  * This may be used to identify MAC address octet strings
  847  * (BHND_NVRAM_SFMT_MACADDR).
  848  *
  849  * @param               inp     The string to be parsed.
  850  * @param               ilen    The length of @p inp, in bytes.
  851  * @param[out]          delim   On success, the delimiter used by this octet
  852  *                              string. May be set to NULL if the field
  853  *                              delimiter is not desired.
  854  * @param[out]          nelem   On success, the number of fields in this
  855  *                              octet string. May be set to NULL if the field
  856  *                              count is not desired.
  857  *
  858  * 
  859  * @retval true         if @p inp is a valid octet string
  860  * @retval false        if @p inp is not a valid octet string.
  861  */
  862 static bool
  863 bhnd_nvram_ident_octet_string(const char *inp, size_t ilen, char *delim,
  864     size_t *nelem)
  865 {
  866         size_t  elem_count;
  867         size_t  max_elem_count, min_elem_count;
  868         size_t  field_count;
  869         char    idelim;
  870 
  871         field_count = 0;
  872 
  873         /* Require exactly two digits. If we relax this, there is room
  874          * for ambiguity with signed integers and the '-' delimiter */
  875         min_elem_count = 2;
  876         max_elem_count = 2;
  877 
  878         /* Identify the delimiter used. The standard delimiter for MAC
  879          * addresses is ':', but some earlier NVRAM formats may use '-' */
  880         for (const char *d = ":-";; d++) {
  881                 const char *loc;
  882 
  883                 /* No delimiter found, not an octet string */
  884                 if (*d == '\0')
  885                         return (false);
  886 
  887                 /* Look for the delimiter */
  888                 if ((loc = memchr(inp, *d, ilen)) == NULL)
  889                         continue;
  890 
  891                 /* Delimiter found */
  892                 idelim = *loc;
  893                 break;
  894         }
  895 
  896         /* To disambiguate from signed integers, if the delimiter is "-",
  897          * the octets must be exactly 2 chars each */
  898         if (idelim == '-')
  899                 min_elem_count = 2;
  900 
  901         /* String must be composed of individual octets (zero or more hex
  902          * digits) separated by our delimiter. */
  903         elem_count = 0;
  904         for (const char *p = inp; (size_t)(p - inp) < ilen; p++) {
  905                 switch (*p) {
  906                 case ':':
  907                 case '-':
  908                 case '\0':
  909                         /* Hit a delim character; all delims must match
  910                          * the first delimiter used */
  911                         if (*p != '\0' && *p != idelim)
  912                                 return (false);
  913 
  914                         /* Must have parsed at least min_elem_count digits */
  915                         if (elem_count < min_elem_count)
  916                                 return (false);
  917 
  918                         /* Reset element count */
  919                         elem_count = 0;
  920 
  921                         /* Bump field count */
  922                         field_count++;
  923                         break;
  924                 default:
  925                         /* More than maximum number of hex digits? */
  926                         if (elem_count >= max_elem_count)
  927                                 return (false);
  928 
  929                         /* Octet values must be hex digits */
  930                         if (!bhnd_nv_isxdigit(*p))
  931                                 return (false);
  932 
  933                         elem_count++;
  934                         break;
  935                 }
  936         }
  937 
  938         if (delim != NULL)
  939                 *delim = idelim;
  940 
  941         if (nelem != NULL)
  942                 *nelem = field_count;
  943 
  944         return (true);
  945 }
  946 
  947 /**
  948  * Determine whether @p inp is in hexadecimal, octal, or decimal string
  949  * format.
  950  *
  951  * - A @p str may be prefixed with a single optional '+' or '-' sign denoting
  952  *   signedness.
  953  * - A hexadecimal @p str may include an '0x' or '0X' prefix, denoting that a
  954  *   base 16 integer follows.
  955  * - An octal @p str may include a '' prefix, denoting that an octal integer
  956  *   follows.
  957  * 
  958  * @param       inp     The string to be parsed.
  959  * @param       ilen    The length of @p inp, in bytes.
  960  * @param       base    The input string's base (2-36), or 0.
  961  * @param[out]  obase   On success, will be set to the base of the parsed
  962  *                      integer. May be set to NULL if the base is not
  963  *                      desired.
  964  *
  965  * @retval true         if @p inp is a valid number string
  966  * @retval false        if @p inp is not a valid number string.
  967  * @retval false        if @p base is invalid.
  968  */
  969 static bool
  970 bhnd_nvram_ident_num_string(const char *inp, size_t ilen, u_int base,
  971     u_int *obase)
  972 {
  973         size_t  nbytes, ndigits;
  974 
  975         nbytes = 0;
  976         ndigits = 0;
  977 
  978         /* Parse and skip sign */
  979         if (nbytes >= ilen)
  980                 return (false);
  981 
  982         if (inp[nbytes] == '-' || inp[nbytes] == '+')
  983                 nbytes++;
  984 
  985         /* Truncated after sign character? */
  986         if (nbytes == ilen)
  987                 return (false);
  988 
  989         /* Identify (or validate) hex base, skipping 0x/0X prefix */
  990         if (base == 16 || base == 0) {
  991                 /* Check for (and skip) 0x/0X prefix */
  992                 if (ilen - nbytes >= 2 && inp[nbytes] == '' &&
  993                     (inp[nbytes+1] == 'x' || inp[nbytes+1] == 'X'))
  994                 {
  995                         base = 16;
  996                         nbytes += 2;
  997                 }
  998         }
  999 
 1000         /* Truncated after hex prefix? */
 1001         if (nbytes == ilen)
 1002                 return (false);
 1003 
 1004         /* Differentiate decimal/octal by looking for a leading 0 */
 1005         if (base == 0) {
 1006                 if (inp[nbytes] == '') {
 1007                         base = 8;
 1008                 } else {
 1009                         base = 10;
 1010                 }
 1011         }
 1012 
 1013         /* Consume and validate all remaining digit characters */
 1014         for (; nbytes < ilen; nbytes++) {
 1015                 u_int   carry;
 1016                 char    c;
 1017 
 1018                 /* Parse carry value */
 1019                 c = inp[nbytes];
 1020                 if (bhnd_nv_isdigit(c)) {
 1021                         carry = c - '';
 1022                 } else if (bhnd_nv_isxdigit(c)) {
 1023                         if (bhnd_nv_isupper(c))
 1024                                 carry = (c - 'A') + 10;
 1025                         else
 1026                                 carry = (c - 'a') + 10;
 1027                 } else {
 1028                         /* Hit a non-digit character */
 1029                         return (false);
 1030                 }
 1031 
 1032                 /* If carry is outside the base, it's not a valid digit
 1033                  * in the current parse context; consider it a non-digit
 1034                  * character */
 1035                 if (carry >= base)
 1036                         return (false);
 1037 
 1038                 /* Increment parsed digit count */
 1039                 ndigits++;
 1040         }
 1041 
 1042         /* Empty integer string? */
 1043         if (ndigits == 0)
 1044                 return (false);
 1045 
 1046         /* Valid integer -- provide the base and return */
 1047         if (obase != NULL)
 1048                 *obase = base;
 1049         return (true);
 1050 }

Cache object: facf5eb1420c8def185b468d5e4bf76b


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