177cb4d3eSLandon J. Fuller /*-
277cb4d3eSLandon J. Fuller * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
377cb4d3eSLandon J. Fuller * All rights reserved.
477cb4d3eSLandon J. Fuller *
577cb4d3eSLandon J. Fuller * Redistribution and use in source and binary forms, with or without
677cb4d3eSLandon J. Fuller * modification, are permitted provided that the following conditions
777cb4d3eSLandon J. Fuller * are met:
877cb4d3eSLandon J. Fuller * 1. Redistributions of source code must retain the above copyright
977cb4d3eSLandon J. Fuller * notice, this list of conditions and the following disclaimer,
1077cb4d3eSLandon J. Fuller * without modification.
1177cb4d3eSLandon J. Fuller * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1277cb4d3eSLandon J. Fuller * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1377cb4d3eSLandon J. Fuller * redistribution must be conditioned upon including a substantially
1477cb4d3eSLandon J. Fuller * similar Disclaimer requirement for further binary redistribution.
1577cb4d3eSLandon J. Fuller *
1677cb4d3eSLandon J. Fuller * NO WARRANTY
1777cb4d3eSLandon J. Fuller * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1877cb4d3eSLandon J. Fuller * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1977cb4d3eSLandon J. Fuller * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2077cb4d3eSLandon J. Fuller * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2177cb4d3eSLandon J. Fuller * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2277cb4d3eSLandon J. Fuller * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2377cb4d3eSLandon J. Fuller * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2477cb4d3eSLandon J. Fuller * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2577cb4d3eSLandon J. Fuller * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2677cb4d3eSLandon J. Fuller * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2777cb4d3eSLandon J. Fuller * THE POSSIBILITY OF SUCH DAMAGES.
2877cb4d3eSLandon J. Fuller */
2977cb4d3eSLandon J. Fuller
3077cb4d3eSLandon J. Fuller #include <sys/param.h>
3177cb4d3eSLandon J. Fuller
3277cb4d3eSLandon J. Fuller #include <net/ethernet.h>
3377cb4d3eSLandon J. Fuller
3477cb4d3eSLandon J. Fuller #ifdef _KERNEL
3577cb4d3eSLandon J. Fuller
3677cb4d3eSLandon J. Fuller #include <sys/ctype.h>
3777cb4d3eSLandon J. Fuller #include <sys/kernel.h>
3877cb4d3eSLandon J. Fuller #include <sys/malloc.h>
3977cb4d3eSLandon J. Fuller #include <sys/systm.h>
4077cb4d3eSLandon J. Fuller
4177cb4d3eSLandon J. Fuller #include <machine/_inttypes.h>
4277cb4d3eSLandon J. Fuller
4377cb4d3eSLandon J. Fuller #else /* !_KERNEL */
4477cb4d3eSLandon J. Fuller
4577cb4d3eSLandon J. Fuller #include <ctype.h>
4677cb4d3eSLandon J. Fuller #include <errno.h>
4777cb4d3eSLandon J. Fuller #include <inttypes.h>
4877cb4d3eSLandon J. Fuller #include <stdlib.h>
4977cb4d3eSLandon J. Fuller #include <string.h>
5077cb4d3eSLandon J. Fuller
5177cb4d3eSLandon J. Fuller #endif /* _KERNEL */
5277cb4d3eSLandon J. Fuller
5377cb4d3eSLandon J. Fuller #include "bhnd_nvram_private.h"
5477cb4d3eSLandon J. Fuller
5577cb4d3eSLandon J. Fuller #include "bhnd_nvram_valuevar.h"
5677cb4d3eSLandon J. Fuller
5777cb4d3eSLandon J. Fuller static bool bhnd_nvram_ident_octet_string(const char *inp,
5877cb4d3eSLandon J. Fuller size_t ilen, char *delim, size_t *nelem);
5977cb4d3eSLandon J. Fuller static bool bhnd_nvram_ident_num_string(const char *inp,
6077cb4d3eSLandon J. Fuller size_t ilen, u_int base, u_int *obase);
6177cb4d3eSLandon J. Fuller
6277cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcm_macaddr_filter(
6358efe686SLandon J. Fuller const bhnd_nvram_val_fmt **fmt, const void *inp,
6477cb4d3eSLandon J. Fuller size_t ilen, bhnd_nvram_type itype);
6577cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcm_macaddr_encode(
6658efe686SLandon J. Fuller bhnd_nvram_val *value, void *outp, size_t *olen,
6777cb4d3eSLandon J. Fuller bhnd_nvram_type otype);
6877cb4d3eSLandon J. Fuller
6977cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcm_macaddr_string_filter(
7058efe686SLandon J. Fuller const bhnd_nvram_val_fmt **fmt, const void *inp,
7177cb4d3eSLandon J. Fuller size_t ilen, bhnd_nvram_type itype);
7277cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcm_macaddr_string_encode_elem(
7358efe686SLandon J. Fuller bhnd_nvram_val *value, const void *inp,
7477cb4d3eSLandon J. Fuller size_t ilen, void *outp, size_t *olen,
7577cb4d3eSLandon J. Fuller bhnd_nvram_type otype);
7677cb4d3eSLandon J. Fuller static const void *bhnd_nvram_val_bcm_macaddr_string_next(
7758efe686SLandon J. Fuller bhnd_nvram_val *value, const void *prev,
7877cb4d3eSLandon J. Fuller size_t *len);
7977cb4d3eSLandon J. Fuller
8077cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcm_int_filter(
8158efe686SLandon J. Fuller const bhnd_nvram_val_fmt **fmt, const void *inp,
8277cb4d3eSLandon J. Fuller size_t ilen, bhnd_nvram_type itype);
8358efe686SLandon J. Fuller static int bhnd_nvram_val_bcm_int_encode(bhnd_nvram_val *value,
8477cb4d3eSLandon J. Fuller void *outp, size_t *olen, bhnd_nvram_type otype);
8577cb4d3eSLandon J. Fuller
8677cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcm_decimal_encode_elem(
8758efe686SLandon J. Fuller bhnd_nvram_val *value, const void *inp,
8877cb4d3eSLandon J. Fuller size_t ilen, void *outp, size_t *olen,
8977cb4d3eSLandon J. Fuller bhnd_nvram_type otype);
9077cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcm_hex_encode_elem(
9158efe686SLandon J. Fuller bhnd_nvram_val *value, const void *inp,
9277cb4d3eSLandon J. Fuller size_t ilen, void *outp, size_t *olen,
9377cb4d3eSLandon J. Fuller bhnd_nvram_type otype);
9477cb4d3eSLandon J. Fuller
9577cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcm_leddc_filter(
9658efe686SLandon J. Fuller const bhnd_nvram_val_fmt **fmt, const void *inp,
9777cb4d3eSLandon J. Fuller size_t ilen, bhnd_nvram_type itype);
9877cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcm_leddc_encode_elem(
9958efe686SLandon J. Fuller bhnd_nvram_val *value, const void *inp,
10077cb4d3eSLandon J. Fuller size_t ilen, void *outp, size_t *olen,
10177cb4d3eSLandon J. Fuller bhnd_nvram_type otype);
10277cb4d3eSLandon J. Fuller
10358efe686SLandon J. Fuller static int bhnd_nvram_val_bcmstr_encode(bhnd_nvram_val *value,
10477cb4d3eSLandon J. Fuller void *outp, size_t *olen, bhnd_nvram_type otype);
10577cb4d3eSLandon J. Fuller
10677cb4d3eSLandon J. Fuller static int bhnd_nvram_val_bcmstr_csv_filter(
10758efe686SLandon J. Fuller const bhnd_nvram_val_fmt **fmt, const void *inp,
10877cb4d3eSLandon J. Fuller size_t ilen, bhnd_nvram_type itype);
10958efe686SLandon J. Fuller static const void *bhnd_nvram_val_bcmstr_csv_next(bhnd_nvram_val *value,
11077cb4d3eSLandon J. Fuller const void *prev, size_t *len);
11177cb4d3eSLandon J. Fuller
11277cb4d3eSLandon J. Fuller /**
11377cb4d3eSLandon J. Fuller * Broadcom NVRAM MAC address format.
11477cb4d3eSLandon J. Fuller */
11558efe686SLandon J. Fuller const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_macaddr_fmt = {
11677cb4d3eSLandon J. Fuller .name = "bcm-macaddr",
11777cb4d3eSLandon J. Fuller .native_type = BHND_NVRAM_TYPE_UINT8_ARRAY,
11877cb4d3eSLandon J. Fuller .op_filter = bhnd_nvram_val_bcm_macaddr_filter,
11977cb4d3eSLandon J. Fuller .op_encode = bhnd_nvram_val_bcm_macaddr_encode,
12077cb4d3eSLandon J. Fuller };
12177cb4d3eSLandon J. Fuller
12277cb4d3eSLandon J. Fuller /** Broadcom NVRAM MAC address string format. */
12358efe686SLandon J. Fuller static const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_macaddr_string_fmt = {
12477cb4d3eSLandon J. Fuller .name = "bcm-macaddr-string",
12577cb4d3eSLandon J. Fuller .native_type = BHND_NVRAM_TYPE_STRING,
12677cb4d3eSLandon J. Fuller .op_filter = bhnd_nvram_val_bcm_macaddr_string_filter,
12777cb4d3eSLandon J. Fuller .op_encode_elem = bhnd_nvram_val_bcm_macaddr_string_encode_elem,
12877cb4d3eSLandon J. Fuller .op_next = bhnd_nvram_val_bcm_macaddr_string_next,
12977cb4d3eSLandon J. Fuller };
13077cb4d3eSLandon J. Fuller
13177cb4d3eSLandon J. Fuller /**
13277cb4d3eSLandon J. Fuller * Broadcom NVRAM LED duty-cycle format.
13377cb4d3eSLandon J. Fuller */
13458efe686SLandon J. Fuller const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_leddc_fmt = {
13577cb4d3eSLandon J. Fuller .name = "bcm-leddc",
13677cb4d3eSLandon J. Fuller .native_type = BHND_NVRAM_TYPE_UINT32,
13777cb4d3eSLandon J. Fuller .op_filter = bhnd_nvram_val_bcm_leddc_filter,
13877cb4d3eSLandon J. Fuller .op_encode_elem = bhnd_nvram_val_bcm_leddc_encode_elem,
13977cb4d3eSLandon J. Fuller };
14077cb4d3eSLandon J. Fuller
14177cb4d3eSLandon J. Fuller /**
14277cb4d3eSLandon J. Fuller * Broadcom NVRAM decimal integer format.
14377cb4d3eSLandon J. Fuller *
14477cb4d3eSLandon J. Fuller * Extends standard integer handling, encoding the string representation of
14577cb4d3eSLandon J. Fuller * the integer value as a decimal string:
14677cb4d3eSLandon J. Fuller * - Positive values will be string-encoded without a prefix.
14777cb4d3eSLandon J. Fuller * - Negative values will be string-encoded with a leading '-' sign.
14877cb4d3eSLandon J. Fuller */
14958efe686SLandon J. Fuller const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_decimal_fmt = {
15077cb4d3eSLandon J. Fuller .name = "bcm-decimal",
15177cb4d3eSLandon J. Fuller .native_type = BHND_NVRAM_TYPE_UINT64,
15277cb4d3eSLandon J. Fuller .op_filter = bhnd_nvram_val_bcm_int_filter,
15377cb4d3eSLandon J. Fuller .op_encode = bhnd_nvram_val_bcm_int_encode,
15477cb4d3eSLandon J. Fuller .op_encode_elem = bhnd_nvram_val_bcm_decimal_encode_elem,
15577cb4d3eSLandon J. Fuller };
15677cb4d3eSLandon J. Fuller
15777cb4d3eSLandon J. Fuller /**
15877cb4d3eSLandon J. Fuller * Broadcom NVRAM decimal integer format.
15977cb4d3eSLandon J. Fuller *
16077cb4d3eSLandon J. Fuller * Extends standard integer handling, encoding the string representation of
16177cb4d3eSLandon J. Fuller * unsigned and positive signed integer values as an 0x-prefixed hexadecimal
16277cb4d3eSLandon J. Fuller * string.
16377cb4d3eSLandon J. Fuller *
16477cb4d3eSLandon J. Fuller * For compatibility with standard Broadcom NVRAM parsing, if the integer is
16577cb4d3eSLandon J. Fuller * both signed and negative, it will be string encoded as a negative decimal
16677cb4d3eSLandon J. Fuller * value, not as a twos-complement hexadecimal value.
16777cb4d3eSLandon J. Fuller */
16858efe686SLandon J. Fuller const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_hex_fmt = {
16977cb4d3eSLandon J. Fuller .name = "bcm-hex",
17077cb4d3eSLandon J. Fuller .native_type = BHND_NVRAM_TYPE_UINT64,
17177cb4d3eSLandon J. Fuller .op_filter = bhnd_nvram_val_bcm_int_filter,
17277cb4d3eSLandon J. Fuller .op_encode = bhnd_nvram_val_bcm_int_encode,
17377cb4d3eSLandon J. Fuller .op_encode_elem = bhnd_nvram_val_bcm_hex_encode_elem,
17477cb4d3eSLandon J. Fuller };
17577cb4d3eSLandon J. Fuller
17677cb4d3eSLandon J. Fuller /**
17777cb4d3eSLandon J. Fuller * Broadcom NVRAM string format.
17877cb4d3eSLandon J. Fuller *
17977cb4d3eSLandon J. Fuller * Handles standard, comma-delimited, and octet-string values as used in
18077cb4d3eSLandon J. Fuller * Broadcom NVRAM data.
18177cb4d3eSLandon J. Fuller */
18258efe686SLandon J. Fuller const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_string_fmt = {
18377cb4d3eSLandon J. Fuller .name = "bcm-string",
18477cb4d3eSLandon J. Fuller .native_type = BHND_NVRAM_TYPE_STRING,
18577cb4d3eSLandon J. Fuller .op_encode = bhnd_nvram_val_bcmstr_encode,
18677cb4d3eSLandon J. Fuller };
18777cb4d3eSLandon J. Fuller
18877cb4d3eSLandon J. Fuller /** Broadcom comma-delimited string. */
18958efe686SLandon J. Fuller static const bhnd_nvram_val_fmt bhnd_nvram_val_bcm_string_csv_fmt = {
19077cb4d3eSLandon J. Fuller .name = "bcm-string[]",
19177cb4d3eSLandon J. Fuller .native_type = BHND_NVRAM_TYPE_STRING,
19277cb4d3eSLandon J. Fuller .op_filter = bhnd_nvram_val_bcmstr_csv_filter,
19377cb4d3eSLandon J. Fuller .op_next = bhnd_nvram_val_bcmstr_csv_next,
19477cb4d3eSLandon J. Fuller };
19577cb4d3eSLandon J. Fuller
1969be0790dSLandon J. Fuller /* Built-in format definitions */
1979be0790dSLandon J. Fuller #define BHND_NVRAM_VAL_FMT_NATIVE(_n, _type) \
1989be0790dSLandon J. Fuller const bhnd_nvram_val_fmt bhnd_nvram_val_ ## _n ## _fmt = { \
1999be0790dSLandon J. Fuller .name = __STRING(_n), \
2009be0790dSLandon J. Fuller .native_type = BHND_NVRAM_TYPE_ ## _type, \
2019be0790dSLandon J. Fuller }
2029be0790dSLandon J. Fuller
2039be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(uint8, UINT8);
2049be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(uint16, UINT16);
2059be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(uint32, UINT32);
2069be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(uint64, UINT64);
2079be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(int8, INT8);
2089be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(int16, INT16);
2099be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(int32, INT32);
2109be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(int64, INT64);
2119be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(char, CHAR);
212*6cffadf0SLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(bool, BOOL);
2139be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(string, STRING);
214*6cffadf0SLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(data, DATA);
215*6cffadf0SLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(null, NULL);
2169be0790dSLandon J. Fuller
2179be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(uint8_array, UINT8_ARRAY);
2189be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(uint16_array, UINT16_ARRAY);
2199be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(uint32_array, UINT32_ARRAY);
2209be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(uint64_array, UINT64_ARRAY);
2219be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(int8_array, INT8_ARRAY);
2229be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(int16_array, INT16_ARRAY);
2239be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(int32_array, INT32_ARRAY);
2249be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(int64_array, INT64_ARRAY);
2259be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(char_array, CHAR_ARRAY);
226*6cffadf0SLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(bool_array, BOOL_ARRAY);
2279be0790dSLandon J. Fuller BHND_NVRAM_VAL_FMT_NATIVE(string_array, STRING_ARRAY);
2289be0790dSLandon J. Fuller
22977cb4d3eSLandon J. Fuller /**
23077cb4d3eSLandon J. Fuller * Common hex/decimal integer filter implementation.
23177cb4d3eSLandon J. Fuller */
23277cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_int_filter(const bhnd_nvram_val_fmt ** fmt,const void * inp,size_t ilen,bhnd_nvram_type itype)23358efe686SLandon J. Fuller bhnd_nvram_val_bcm_int_filter(const bhnd_nvram_val_fmt **fmt, const void *inp,
23477cb4d3eSLandon J. Fuller size_t ilen, bhnd_nvram_type itype)
23577cb4d3eSLandon J. Fuller {
23677cb4d3eSLandon J. Fuller bhnd_nvram_type itype_base;
23777cb4d3eSLandon J. Fuller
23877cb4d3eSLandon J. Fuller itype_base = bhnd_nvram_base_type(itype);
23977cb4d3eSLandon J. Fuller
24077cb4d3eSLandon J. Fuller switch (itype_base) {
24177cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_STRING:
24277cb4d3eSLandon J. Fuller /*
24377cb4d3eSLandon J. Fuller * If the input is a string, delegate to the Broadcom
24477cb4d3eSLandon J. Fuller * string format -- preserving the original string value
24577cb4d3eSLandon J. Fuller * takes priority over enforcing hexadecimal/integer string
24677cb4d3eSLandon J. Fuller * formatting.
24777cb4d3eSLandon J. Fuller */
24877cb4d3eSLandon J. Fuller *fmt = &bhnd_nvram_val_bcm_string_fmt;
24977cb4d3eSLandon J. Fuller return (0);
25077cb4d3eSLandon J. Fuller
25177cb4d3eSLandon J. Fuller default:
25277cb4d3eSLandon J. Fuller if (bhnd_nvram_is_int_type(itype_base))
25377cb4d3eSLandon J. Fuller return (0);
25477cb4d3eSLandon J. Fuller
25577cb4d3eSLandon J. Fuller return (EFTYPE);
25677cb4d3eSLandon J. Fuller }
25777cb4d3eSLandon J. Fuller }
25877cb4d3eSLandon J. Fuller
25977cb4d3eSLandon J. Fuller /**
26077cb4d3eSLandon J. Fuller * Broadcom hex/decimal integer encode implementation.
26177cb4d3eSLandon J. Fuller */
26277cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_int_encode(bhnd_nvram_val * value,void * outp,size_t * olen,bhnd_nvram_type otype)26358efe686SLandon J. Fuller bhnd_nvram_val_bcm_int_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
26477cb4d3eSLandon J. Fuller bhnd_nvram_type otype)
26577cb4d3eSLandon J. Fuller {
26677cb4d3eSLandon J. Fuller /* If encoding to a string, format multiple elements (if any) with a
26777cb4d3eSLandon J. Fuller * comma delimiter. */
26877cb4d3eSLandon J. Fuller if (otype == BHND_NVRAM_TYPE_STRING)
26977cb4d3eSLandon J. Fuller return (bhnd_nvram_val_printf(value, "%[]s", outp, olen, ","));
27077cb4d3eSLandon J. Fuller
27177cb4d3eSLandon J. Fuller return (bhnd_nvram_val_generic_encode(value, outp, olen, otype));
27277cb4d3eSLandon J. Fuller }
27377cb4d3eSLandon J. Fuller
27477cb4d3eSLandon J. Fuller /**
27577cb4d3eSLandon J. Fuller * Broadcom hex integer encode_elem implementation.
27677cb4d3eSLandon J. Fuller */
27777cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_hex_encode_elem(bhnd_nvram_val * value,const void * inp,size_t ilen,void * outp,size_t * olen,bhnd_nvram_type otype)27858efe686SLandon J. Fuller bhnd_nvram_val_bcm_hex_encode_elem(bhnd_nvram_val *value, const void *inp,
27977cb4d3eSLandon J. Fuller size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
28077cb4d3eSLandon J. Fuller {
28177cb4d3eSLandon J. Fuller bhnd_nvram_type itype;
28277cb4d3eSLandon J. Fuller ssize_t width;
28377cb4d3eSLandon J. Fuller int error;
28477cb4d3eSLandon J. Fuller
28577cb4d3eSLandon J. Fuller itype = bhnd_nvram_val_elem_type(value);
28677cb4d3eSLandon J. Fuller BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("invalid type"));
28777cb4d3eSLandon J. Fuller
28877cb4d3eSLandon J. Fuller /* If not encoding as a string, perform generic value encoding */
28977cb4d3eSLandon J. Fuller if (otype != BHND_NVRAM_TYPE_STRING)
29077cb4d3eSLandon J. Fuller return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen,
29177cb4d3eSLandon J. Fuller outp, olen, otype));
29277cb4d3eSLandon J. Fuller
29377cb4d3eSLandon J. Fuller /* If the value is a signed, negative value, encode as a decimal
29477cb4d3eSLandon J. Fuller * string */
29577cb4d3eSLandon J. Fuller if (bhnd_nvram_is_signed_type(itype)) {
29677cb4d3eSLandon J. Fuller int64_t sval;
29777cb4d3eSLandon J. Fuller size_t slen;
29877cb4d3eSLandon J. Fuller bhnd_nvram_type stype;
29977cb4d3eSLandon J. Fuller
30077cb4d3eSLandon J. Fuller stype = BHND_NVRAM_TYPE_INT64;
30177cb4d3eSLandon J. Fuller slen = sizeof(sval);
30277cb4d3eSLandon J. Fuller
30377cb4d3eSLandon J. Fuller /* Fetch 64-bit signed representation */
30477cb4d3eSLandon J. Fuller error = bhnd_nvram_value_coerce(inp, ilen, itype, &sval, &slen,
30577cb4d3eSLandon J. Fuller stype);
30677cb4d3eSLandon J. Fuller if (error)
30777cb4d3eSLandon J. Fuller return (error);
30877cb4d3eSLandon J. Fuller
30977cb4d3eSLandon J. Fuller /* Decimal encoding required? */
31077cb4d3eSLandon J. Fuller if (sval < 0)
31177cb4d3eSLandon J. Fuller return (bhnd_nvram_value_printf("%I64d", &sval, slen,
31277cb4d3eSLandon J. Fuller stype, outp, olen, otype));
31377cb4d3eSLandon J. Fuller }
31477cb4d3eSLandon J. Fuller
31577cb4d3eSLandon J. Fuller /*
31677cb4d3eSLandon J. Fuller * Encode the value as a hex string.
31777cb4d3eSLandon J. Fuller *
31877cb4d3eSLandon J. Fuller * Most producers of Broadcom NVRAM values zero-pad hex values out to
31977cb4d3eSLandon J. Fuller * their native width (width * two hex characters), and we do the same
32077cb4d3eSLandon J. Fuller * for compatibility
32177cb4d3eSLandon J. Fuller */
3229be0790dSLandon J. Fuller width = bhnd_nvram_type_width(itype) * 2;
32377cb4d3eSLandon J. Fuller return (bhnd_nvram_value_printf("0x%0*I64X", inp, ilen, itype,
32477cb4d3eSLandon J. Fuller outp, olen, width));
32577cb4d3eSLandon J. Fuller }
32677cb4d3eSLandon J. Fuller
32777cb4d3eSLandon J. Fuller /**
32877cb4d3eSLandon J. Fuller * Broadcom decimal integer encode_elem implementation.
32977cb4d3eSLandon J. Fuller */
33077cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_decimal_encode_elem(bhnd_nvram_val * value,const void * inp,size_t ilen,void * outp,size_t * olen,bhnd_nvram_type otype)33158efe686SLandon J. Fuller bhnd_nvram_val_bcm_decimal_encode_elem(bhnd_nvram_val *value, const void *inp,
33277cb4d3eSLandon J. Fuller size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
33377cb4d3eSLandon J. Fuller {
33477cb4d3eSLandon J. Fuller const char *sfmt;
33577cb4d3eSLandon J. Fuller bhnd_nvram_type itype;
33677cb4d3eSLandon J. Fuller
33777cb4d3eSLandon J. Fuller itype = bhnd_nvram_val_elem_type(value);
33877cb4d3eSLandon J. Fuller BHND_NV_ASSERT(bhnd_nvram_is_int_type(itype), ("invalid type"));
33977cb4d3eSLandon J. Fuller
34077cb4d3eSLandon J. Fuller /* If not encoding as a string, perform generic value encoding */
34177cb4d3eSLandon J. Fuller if (otype != BHND_NVRAM_TYPE_STRING)
34277cb4d3eSLandon J. Fuller return (bhnd_nvram_val_generic_encode_elem(value, inp, ilen,
34377cb4d3eSLandon J. Fuller outp, olen, otype));
34477cb4d3eSLandon J. Fuller
34577cb4d3eSLandon J. Fuller sfmt = bhnd_nvram_is_signed_type(itype) ? "%I64d" : "%I64u";
34677cb4d3eSLandon J. Fuller return (bhnd_nvram_value_printf(sfmt, inp, ilen, itype, outp, olen));
34777cb4d3eSLandon J. Fuller }
34877cb4d3eSLandon J. Fuller
34977cb4d3eSLandon J. Fuller /**
35077cb4d3eSLandon J. Fuller * Broadcom LED duty-cycle filter.
35177cb4d3eSLandon J. Fuller */
35277cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_leddc_filter(const bhnd_nvram_val_fmt ** fmt,const void * inp,size_t ilen,bhnd_nvram_type itype)35358efe686SLandon J. Fuller bhnd_nvram_val_bcm_leddc_filter(const bhnd_nvram_val_fmt **fmt,
35477cb4d3eSLandon J. Fuller const void *inp, size_t ilen, bhnd_nvram_type itype)
35577cb4d3eSLandon J. Fuller {
35677cb4d3eSLandon J. Fuller const char *p;
35777cb4d3eSLandon J. Fuller size_t plen;
35877cb4d3eSLandon J. Fuller
35977cb4d3eSLandon J. Fuller switch (itype) {
36077cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_UINT16:
36177cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_UINT32:
36277cb4d3eSLandon J. Fuller return (0);
36377cb4d3eSLandon J. Fuller
36477cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_STRING:
36577cb4d3eSLandon J. Fuller /* Trim any whitespace */
36677cb4d3eSLandon J. Fuller p = inp;
36777cb4d3eSLandon J. Fuller plen = bhnd_nvram_trim_field(&p, ilen, '\0');
36877cb4d3eSLandon J. Fuller
36977cb4d3eSLandon J. Fuller /* If the value is not a valid integer string, delegate to the
37077cb4d3eSLandon J. Fuller * Broadcom string format */
37177cb4d3eSLandon J. Fuller if (!bhnd_nvram_ident_num_string(p, plen, 0, NULL))
37277cb4d3eSLandon J. Fuller *fmt = &bhnd_nvram_val_bcm_string_fmt;
37377cb4d3eSLandon J. Fuller
37477cb4d3eSLandon J. Fuller return (0);
37577cb4d3eSLandon J. Fuller default:
37677cb4d3eSLandon J. Fuller return (EFTYPE);
37777cb4d3eSLandon J. Fuller }
37877cb4d3eSLandon J. Fuller }
37977cb4d3eSLandon J. Fuller
38077cb4d3eSLandon J. Fuller /**
38177cb4d3eSLandon J. Fuller * Broadcom LED duty-cycle encode.
38277cb4d3eSLandon J. Fuller */
38377cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_leddc_encode_elem(bhnd_nvram_val * value,const void * inp,size_t ilen,void * outp,size_t * olen,bhnd_nvram_type otype)38458efe686SLandon J. Fuller bhnd_nvram_val_bcm_leddc_encode_elem(bhnd_nvram_val *value, const void *inp,
38577cb4d3eSLandon J. Fuller size_t ilen, void *outp, size_t *olen, bhnd_nvram_type otype)
38677cb4d3eSLandon J. Fuller {
38777cb4d3eSLandon J. Fuller bhnd_nvram_type itype;
38877cb4d3eSLandon J. Fuller size_t limit, nbytes;
38977cb4d3eSLandon J. Fuller int error;
39077cb4d3eSLandon J. Fuller uint16_t led16;
39177cb4d3eSLandon J. Fuller uint32_t led32;
39277cb4d3eSLandon J. Fuller bool led16_lossy;
39377cb4d3eSLandon J. Fuller union {
39477cb4d3eSLandon J. Fuller uint16_t u16;
39577cb4d3eSLandon J. Fuller uint32_t u32;
39677cb4d3eSLandon J. Fuller } strval;
39777cb4d3eSLandon J. Fuller
39877cb4d3eSLandon J. Fuller /*
39977cb4d3eSLandon J. Fuller * LED duty-cycle values represent the on/off periods as a 32-bit
40077cb4d3eSLandon J. Fuller * integer, with the top 16 bits representing on cycles, and the
40177cb4d3eSLandon J. Fuller * bottom 16 representing off cycles.
40277cb4d3eSLandon J. Fuller *
40377cb4d3eSLandon J. Fuller * LED duty cycle values have three different formats:
40477cb4d3eSLandon J. Fuller *
40577cb4d3eSLandon J. Fuller * - SPROM: A 16-bit unsigned integer, with on/off cycles encoded
40677cb4d3eSLandon J. Fuller * as 8-bit values.
40777cb4d3eSLandon J. Fuller * - NVRAM: A 16-bit decimal or hexadecimal string, with on/off
40877cb4d3eSLandon J. Fuller * cycles encoded as 8-bit values as per the SPROM format.
40977cb4d3eSLandon J. Fuller * - NVRAM: A 32-bit decimal or hexadecimal string, with on/off
41077cb4d3eSLandon J. Fuller * cycles encoded as 16-bit values.
41177cb4d3eSLandon J. Fuller *
41277cb4d3eSLandon J. Fuller * To convert from a 16-bit representation to a 32-bit representation:
41377cb4d3eSLandon J. Fuller * ((value & 0xFF00) << 16) | ((value & 0x00FF) << 8)
41477cb4d3eSLandon J. Fuller *
41577cb4d3eSLandon J. Fuller * To convert from a 32-bit representation to a 16-bit representation,
41677cb4d3eSLandon J. Fuller * perform the same operation in reverse, discarding the lower 8-bits
41777cb4d3eSLandon J. Fuller * of each half of the 32-bit representation:
41877cb4d3eSLandon J. Fuller * ((value >> 16) & 0xFF00) | ((value >> 8) & 0x00FF)
41977cb4d3eSLandon J. Fuller */
42077cb4d3eSLandon J. Fuller
42177cb4d3eSLandon J. Fuller itype = bhnd_nvram_val_elem_type(value);
42277cb4d3eSLandon J. Fuller nbytes = 0;
42377cb4d3eSLandon J. Fuller led16_lossy = false;
42477cb4d3eSLandon J. Fuller
42577cb4d3eSLandon J. Fuller /* Determine output byte limit */
42677cb4d3eSLandon J. Fuller if (outp != NULL)
42777cb4d3eSLandon J. Fuller limit = *olen;
42877cb4d3eSLandon J. Fuller else
42977cb4d3eSLandon J. Fuller limit = 0;
43077cb4d3eSLandon J. Fuller
43177cb4d3eSLandon J. Fuller /* If the input/output types match, just delegate to standard value
43277cb4d3eSLandon J. Fuller * encoding support */
43377cb4d3eSLandon J. Fuller if (otype == itype) {
43477cb4d3eSLandon J. Fuller return (bhnd_nvram_value_coerce(inp, ilen, itype, outp, olen,
43577cb4d3eSLandon J. Fuller otype));
43677cb4d3eSLandon J. Fuller }
43777cb4d3eSLandon J. Fuller
43877cb4d3eSLandon J. Fuller /* If our value is a string, it may either be a 16-bit or a 32-bit
43977cb4d3eSLandon J. Fuller * representation of the duty cycle */
44077cb4d3eSLandon J. Fuller if (itype == BHND_NVRAM_TYPE_STRING) {
44177cb4d3eSLandon J. Fuller const char *p;
44277cb4d3eSLandon J. Fuller uint32_t ival;
44377cb4d3eSLandon J. Fuller size_t nlen, parsed;
44477cb4d3eSLandon J. Fuller
44577cb4d3eSLandon J. Fuller /* Parse integer value */
44677cb4d3eSLandon J. Fuller p = inp;
44777cb4d3eSLandon J. Fuller nlen = sizeof(ival);
44877cb4d3eSLandon J. Fuller error = bhnd_nvram_parse_int(p, ilen, 0, &parsed, &ival, &nlen,
44977cb4d3eSLandon J. Fuller BHND_NVRAM_TYPE_UINT32);
45077cb4d3eSLandon J. Fuller if (error)
45177cb4d3eSLandon J. Fuller return (error);
45277cb4d3eSLandon J. Fuller
45377cb4d3eSLandon J. Fuller /* Trailing garbage? */
45477cb4d3eSLandon J. Fuller if (parsed < ilen && *(p+parsed) != '\0')
45577cb4d3eSLandon J. Fuller return (EFTYPE);
45677cb4d3eSLandon J. Fuller
45777cb4d3eSLandon J. Fuller /* Point inp and itype to either our parsed 32-bit or 16-bit
45877cb4d3eSLandon J. Fuller * value */
45977cb4d3eSLandon J. Fuller inp = &strval;
46077cb4d3eSLandon J. Fuller if (ival & 0xFFFF0000) {
46177cb4d3eSLandon J. Fuller strval.u32 = ival;
46277cb4d3eSLandon J. Fuller itype = BHND_NVRAM_TYPE_UINT32;
46377cb4d3eSLandon J. Fuller } else {
46477cb4d3eSLandon J. Fuller strval.u16 = ival;
46577cb4d3eSLandon J. Fuller itype = BHND_NVRAM_TYPE_UINT16;
46677cb4d3eSLandon J. Fuller }
46777cb4d3eSLandon J. Fuller }
46877cb4d3eSLandon J. Fuller
46977cb4d3eSLandon J. Fuller /* Populate both u32 and (possibly lossy) u16 LEDDC representations */
47077cb4d3eSLandon J. Fuller switch (itype) {
47177cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_UINT16: {
47277cb4d3eSLandon J. Fuller led16 = *(const uint16_t *)inp;
47377cb4d3eSLandon J. Fuller led32 = ((led16 & 0xFF00) << 16) | ((led16 & 0x00FF) << 8);
47477cb4d3eSLandon J. Fuller
47577cb4d3eSLandon J. Fuller /* If all bits are set in the 16-bit value (indicating that
47677cb4d3eSLandon J. Fuller * the value is 'unset' in SPROM), we must update the 32-bit
47777cb4d3eSLandon J. Fuller * representation to match. */
47877cb4d3eSLandon J. Fuller if (led16 == UINT16_MAX)
47977cb4d3eSLandon J. Fuller led32 = UINT32_MAX;
48077cb4d3eSLandon J. Fuller
48177cb4d3eSLandon J. Fuller break;
48277cb4d3eSLandon J. Fuller }
48377cb4d3eSLandon J. Fuller
48477cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_UINT32:
48577cb4d3eSLandon J. Fuller led32 = *(const uint32_t *)inp;
48677cb4d3eSLandon J. Fuller led16 = ((led32 >> 16) & 0xFF00) | ((led32 >> 8) & 0x00FF);
48777cb4d3eSLandon J. Fuller
48877cb4d3eSLandon J. Fuller /*
48977cb4d3eSLandon J. Fuller * Determine whether the led16 conversion is lossy:
49077cb4d3eSLandon J. Fuller *
49177cb4d3eSLandon J. Fuller * - If the lower 8 bits of each half of the 32-bit value
49277cb4d3eSLandon J. Fuller * aren't set, we can safely use the 16-bit representation
49377cb4d3eSLandon J. Fuller * without losing data.
49477cb4d3eSLandon J. Fuller * - If all bits in the 32-bit value are set, the variable is
49577cb4d3eSLandon J. Fuller * treated as unset in SPROM. We can safely use the 16-bit
49677cb4d3eSLandon J. Fuller * representation without losing data.
49777cb4d3eSLandon J. Fuller */
49877cb4d3eSLandon J. Fuller if ((led32 & 0x00FF00FF) != 0 && led32 != UINT32_MAX)
49977cb4d3eSLandon J. Fuller led16_lossy = true;
50077cb4d3eSLandon J. Fuller
50177cb4d3eSLandon J. Fuller break;
50277cb4d3eSLandon J. Fuller default:
50377cb4d3eSLandon J. Fuller BHND_NV_PANIC("unsupported backing data type: %s",
50477cb4d3eSLandon J. Fuller bhnd_nvram_type_name(itype));
50577cb4d3eSLandon J. Fuller }
50677cb4d3eSLandon J. Fuller
50777cb4d3eSLandon J. Fuller /*
50877cb4d3eSLandon J. Fuller * Encode as requested output type.
50977cb4d3eSLandon J. Fuller */
51077cb4d3eSLandon J. Fuller switch (otype) {
51177cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_STRING:
51277cb4d3eSLandon J. Fuller /*
51377cb4d3eSLandon J. Fuller * Prefer 16-bit format.
51477cb4d3eSLandon J. Fuller */
51577cb4d3eSLandon J. Fuller if (!led16_lossy) {
51677cb4d3eSLandon J. Fuller return (bhnd_nvram_value_printf("0x%04hX", &led16,
51777cb4d3eSLandon J. Fuller sizeof(led16), BHND_NVRAM_TYPE_UINT16, outp, olen));
51877cb4d3eSLandon J. Fuller } else {
51977cb4d3eSLandon J. Fuller return (bhnd_nvram_value_printf("0x%04X", &led32,
52077cb4d3eSLandon J. Fuller sizeof(led32), BHND_NVRAM_TYPE_UINT32, outp, olen));
52177cb4d3eSLandon J. Fuller }
52277cb4d3eSLandon J. Fuller
52377cb4d3eSLandon J. Fuller break;
52477cb4d3eSLandon J. Fuller
52577cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_UINT16: {
52677cb4d3eSLandon J. Fuller /* Can we encode as uint16 without losing data? */
52777cb4d3eSLandon J. Fuller if (led16_lossy)
52877cb4d3eSLandon J. Fuller return (ERANGE);
52977cb4d3eSLandon J. Fuller
53077cb4d3eSLandon J. Fuller /* Write led16 format */
53177cb4d3eSLandon J. Fuller nbytes += sizeof(uint16_t);
53277cb4d3eSLandon J. Fuller if (limit >= nbytes)
53377cb4d3eSLandon J. Fuller *(uint16_t *)outp = led16;
53477cb4d3eSLandon J. Fuller
53577cb4d3eSLandon J. Fuller break;
53677cb4d3eSLandon J. Fuller }
53777cb4d3eSLandon J. Fuller
53877cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_UINT32:
53977cb4d3eSLandon J. Fuller /* Write led32 format */
54077cb4d3eSLandon J. Fuller nbytes += sizeof(uint32_t);
54177cb4d3eSLandon J. Fuller if (limit >= nbytes)
54277cb4d3eSLandon J. Fuller *(uint32_t *)outp = led32;
54377cb4d3eSLandon J. Fuller break;
54477cb4d3eSLandon J. Fuller
54577cb4d3eSLandon J. Fuller default:
54677cb4d3eSLandon J. Fuller /* No other output formats are supported */
54777cb4d3eSLandon J. Fuller return (EFTYPE);
54877cb4d3eSLandon J. Fuller }
54977cb4d3eSLandon J. Fuller
55077cb4d3eSLandon J. Fuller /* Provide the actual length */
55177cb4d3eSLandon J. Fuller *olen = nbytes;
55277cb4d3eSLandon J. Fuller
55377cb4d3eSLandon J. Fuller /* Report insufficient space (if output was requested) */
55477cb4d3eSLandon J. Fuller if (limit < nbytes && outp != NULL)
55577cb4d3eSLandon J. Fuller return (ENOMEM);
55677cb4d3eSLandon J. Fuller
55777cb4d3eSLandon J. Fuller return (0);
55877cb4d3eSLandon J. Fuller }
55977cb4d3eSLandon J. Fuller
56077cb4d3eSLandon J. Fuller /**
56177cb4d3eSLandon J. Fuller * Broadcom NVRAM string encoding.
56277cb4d3eSLandon J. Fuller */
56377cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcmstr_encode(bhnd_nvram_val * value,void * outp,size_t * olen,bhnd_nvram_type otype)56458efe686SLandon J. Fuller bhnd_nvram_val_bcmstr_encode(bhnd_nvram_val *value, void *outp, size_t *olen,
56558efe686SLandon J. Fuller bhnd_nvram_type otype)
56677cb4d3eSLandon J. Fuller {
56758efe686SLandon J. Fuller bhnd_nvram_val array;
56858efe686SLandon J. Fuller const bhnd_nvram_val_fmt *array_fmt;
56977cb4d3eSLandon J. Fuller const void *inp;
57077cb4d3eSLandon J. Fuller bhnd_nvram_type itype;
57177cb4d3eSLandon J. Fuller size_t ilen;
57277cb4d3eSLandon J. Fuller int error;
57377cb4d3eSLandon J. Fuller
57477cb4d3eSLandon J. Fuller inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
57577cb4d3eSLandon J. Fuller
57677cb4d3eSLandon J. Fuller /* If the output is not an array type (or if it's a character array),
57777cb4d3eSLandon J. Fuller * we can fall back on standard string encoding */
57877cb4d3eSLandon J. Fuller if (!bhnd_nvram_is_array_type(otype) ||
57977cb4d3eSLandon J. Fuller otype == BHND_NVRAM_TYPE_CHAR_ARRAY)
58077cb4d3eSLandon J. Fuller {
58177cb4d3eSLandon J. Fuller return (bhnd_nvram_value_coerce(inp, ilen, itype, outp, olen,
58277cb4d3eSLandon J. Fuller otype));
58377cb4d3eSLandon J. Fuller }
58477cb4d3eSLandon J. Fuller
58577cb4d3eSLandon J. Fuller /* Otherwise, we need to interpret our value as either a macaddr
58677cb4d3eSLandon J. Fuller * string, or a comma-delimited string. */
58777cb4d3eSLandon J. Fuller inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
58877cb4d3eSLandon J. Fuller if (bhnd_nvram_ident_octet_string(inp, ilen, NULL, NULL))
58977cb4d3eSLandon J. Fuller array_fmt = &bhnd_nvram_val_bcm_macaddr_string_fmt;
59077cb4d3eSLandon J. Fuller else
59177cb4d3eSLandon J. Fuller array_fmt = &bhnd_nvram_val_bcm_string_csv_fmt;
59277cb4d3eSLandon J. Fuller
59377cb4d3eSLandon J. Fuller /* Wrap in array-typed representation */
59477cb4d3eSLandon J. Fuller error = bhnd_nvram_val_init(&array, array_fmt, inp, ilen, itype,
59577cb4d3eSLandon J. Fuller BHND_NVRAM_VAL_BORROW_DATA);
59677cb4d3eSLandon J. Fuller if (error) {
59777cb4d3eSLandon J. Fuller BHND_NV_LOG("error initializing array representation: %d\n",
59877cb4d3eSLandon J. Fuller error);
59977cb4d3eSLandon J. Fuller return (error);
60077cb4d3eSLandon J. Fuller }
60177cb4d3eSLandon J. Fuller
60277cb4d3eSLandon J. Fuller /* Ask the array-typed value to perform the encode */
60377cb4d3eSLandon J. Fuller error = bhnd_nvram_val_encode(&array, outp, olen, otype);
60477cb4d3eSLandon J. Fuller if (error)
60577cb4d3eSLandon J. Fuller BHND_NV_LOG("error encoding array representation: %d\n", error);
60677cb4d3eSLandon J. Fuller
60777cb4d3eSLandon J. Fuller bhnd_nvram_val_release(&array);
60877cb4d3eSLandon J. Fuller
60977cb4d3eSLandon J. Fuller return (error);
61077cb4d3eSLandon J. Fuller }
61177cb4d3eSLandon J. Fuller
61277cb4d3eSLandon J. Fuller /**
61377cb4d3eSLandon J. Fuller * Broadcom NVRAM comma-delimited string filter.
61477cb4d3eSLandon J. Fuller */
61577cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcmstr_csv_filter(const bhnd_nvram_val_fmt ** fmt,const void * inp,size_t ilen,bhnd_nvram_type itype)61658efe686SLandon J. Fuller bhnd_nvram_val_bcmstr_csv_filter(const bhnd_nvram_val_fmt **fmt,
61777cb4d3eSLandon J. Fuller const void *inp, size_t ilen, bhnd_nvram_type itype)
61877cb4d3eSLandon J. Fuller {
61977cb4d3eSLandon J. Fuller switch (itype) {
62077cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_STRING:
62177cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_STRING_ARRAY:
62277cb4d3eSLandon J. Fuller return (0);
62377cb4d3eSLandon J. Fuller default:
62477cb4d3eSLandon J. Fuller return (EFTYPE);
62577cb4d3eSLandon J. Fuller }
62677cb4d3eSLandon J. Fuller }
62777cb4d3eSLandon J. Fuller
62877cb4d3eSLandon J. Fuller /**
62977cb4d3eSLandon J. Fuller * Broadcom NVRAM comma-delimited string iteration.
63077cb4d3eSLandon J. Fuller */
63177cb4d3eSLandon J. Fuller static const void *
bhnd_nvram_val_bcmstr_csv_next(bhnd_nvram_val * value,const void * prev,size_t * len)63258efe686SLandon J. Fuller bhnd_nvram_val_bcmstr_csv_next(bhnd_nvram_val *value, const void *prev,
63377cb4d3eSLandon J. Fuller size_t *len)
63477cb4d3eSLandon J. Fuller {
63577cb4d3eSLandon J. Fuller const char *next;
63677cb4d3eSLandon J. Fuller const char *inp;
63777cb4d3eSLandon J. Fuller bhnd_nvram_type itype;
63877cb4d3eSLandon J. Fuller size_t ilen, remain;
63977cb4d3eSLandon J. Fuller char delim;
64077cb4d3eSLandon J. Fuller
64177cb4d3eSLandon J. Fuller /* Fetch backing representation */
64277cb4d3eSLandon J. Fuller inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
64377cb4d3eSLandon J. Fuller
64477cb4d3eSLandon J. Fuller /* Fetch next value */
64577cb4d3eSLandon J. Fuller switch (itype) {
64677cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_STRING:
64777cb4d3eSLandon J. Fuller /* Zero-length array? */
64877cb4d3eSLandon J. Fuller if (ilen == 0)
64977cb4d3eSLandon J. Fuller return (NULL);
65077cb4d3eSLandon J. Fuller
65177cb4d3eSLandon J. Fuller if (prev == NULL) {
65277cb4d3eSLandon J. Fuller /* First element */
65377cb4d3eSLandon J. Fuller next = inp;
65477cb4d3eSLandon J. Fuller remain = ilen;
65577cb4d3eSLandon J. Fuller delim = ',';
65677cb4d3eSLandon J. Fuller } else {
65777cb4d3eSLandon J. Fuller /* Advance to the previous element's delimiter */
65877cb4d3eSLandon J. Fuller next = (const char *)prev + *len;
65977cb4d3eSLandon J. Fuller
66077cb4d3eSLandon J. Fuller /* Did we hit the end of the string? */
66177cb4d3eSLandon J. Fuller if ((size_t)(next - inp) >= ilen)
66277cb4d3eSLandon J. Fuller return (NULL);
66377cb4d3eSLandon J. Fuller
66477cb4d3eSLandon J. Fuller /* Fetch (and skip past) the delimiter */
66577cb4d3eSLandon J. Fuller delim = *next;
66677cb4d3eSLandon J. Fuller next++;
66777cb4d3eSLandon J. Fuller remain = ilen - (size_t)(next - inp);
66877cb4d3eSLandon J. Fuller
66977cb4d3eSLandon J. Fuller /* Was the delimiter the final character? */
67077cb4d3eSLandon J. Fuller if (remain == 0)
67177cb4d3eSLandon J. Fuller return (NULL);
67277cb4d3eSLandon J. Fuller }
67377cb4d3eSLandon J. Fuller
67477cb4d3eSLandon J. Fuller /* Parse the field value, up to the next delimiter */
67577cb4d3eSLandon J. Fuller *len = bhnd_nvram_parse_field(&next, remain, delim);
67677cb4d3eSLandon J. Fuller
67777cb4d3eSLandon J. Fuller return (next);
67877cb4d3eSLandon J. Fuller
67977cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_STRING_ARRAY:
6809be0790dSLandon J. Fuller /* Delegate to default array iteration */
6819be0790dSLandon J. Fuller return (bhnd_nvram_value_array_next(inp, ilen, itype, prev,
6829be0790dSLandon J. Fuller len));
68377cb4d3eSLandon J. Fuller default:
68477cb4d3eSLandon J. Fuller BHND_NV_PANIC("unsupported type: %d", itype);
68577cb4d3eSLandon J. Fuller }
68677cb4d3eSLandon J. Fuller }
68777cb4d3eSLandon J. Fuller
68877cb4d3eSLandon J. Fuller /**
68977cb4d3eSLandon J. Fuller * MAC address filter.
69077cb4d3eSLandon J. Fuller */
69177cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_macaddr_filter(const bhnd_nvram_val_fmt ** fmt,const void * inp,size_t ilen,bhnd_nvram_type itype)69258efe686SLandon J. Fuller bhnd_nvram_val_bcm_macaddr_filter(const bhnd_nvram_val_fmt **fmt,
69377cb4d3eSLandon J. Fuller const void *inp, size_t ilen, bhnd_nvram_type itype)
69477cb4d3eSLandon J. Fuller {
69577cb4d3eSLandon J. Fuller switch (itype) {
69677cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_UINT8_ARRAY:
69777cb4d3eSLandon J. Fuller return (0);
69877cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_STRING:
69977cb4d3eSLandon J. Fuller /* Let bcm_macaddr_string format handle it */
70077cb4d3eSLandon J. Fuller *fmt = &bhnd_nvram_val_bcm_macaddr_string_fmt;
70177cb4d3eSLandon J. Fuller return (0);
70277cb4d3eSLandon J. Fuller default:
70377cb4d3eSLandon J. Fuller return (EFTYPE);
70477cb4d3eSLandon J. Fuller }
70577cb4d3eSLandon J. Fuller }
70677cb4d3eSLandon J. Fuller
70777cb4d3eSLandon J. Fuller /**
70877cb4d3eSLandon J. Fuller * MAC address encoding.
70977cb4d3eSLandon J. Fuller */
71077cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_macaddr_encode(bhnd_nvram_val * value,void * outp,size_t * olen,bhnd_nvram_type otype)71158efe686SLandon J. Fuller bhnd_nvram_val_bcm_macaddr_encode(bhnd_nvram_val *value, void *outp,
71277cb4d3eSLandon J. Fuller size_t *olen, bhnd_nvram_type otype)
71377cb4d3eSLandon J. Fuller {
71477cb4d3eSLandon J. Fuller const void *inp;
71577cb4d3eSLandon J. Fuller bhnd_nvram_type itype;
71677cb4d3eSLandon J. Fuller size_t ilen;
71777cb4d3eSLandon J. Fuller
71877cb4d3eSLandon J. Fuller /*
71977cb4d3eSLandon J. Fuller * If converting to a string (or a single-element string array),
72077cb4d3eSLandon J. Fuller * produce an octet string (00:00:...).
72177cb4d3eSLandon J. Fuller */
72277cb4d3eSLandon J. Fuller if (bhnd_nvram_base_type(otype) == BHND_NVRAM_TYPE_STRING) {
72377cb4d3eSLandon J. Fuller return (bhnd_nvram_val_printf(value, "%[]02hhX", outp, olen,
72477cb4d3eSLandon J. Fuller ":"));
72577cb4d3eSLandon J. Fuller }
72677cb4d3eSLandon J. Fuller
72777cb4d3eSLandon J. Fuller /* Otherwise, use standard encoding support */
72877cb4d3eSLandon J. Fuller inp = bhnd_nvram_val_bytes(value, &ilen, &itype);
72977cb4d3eSLandon J. Fuller return (bhnd_nvram_value_coerce(inp, ilen, itype, outp, olen, otype));}
73077cb4d3eSLandon J. Fuller
73177cb4d3eSLandon J. Fuller /**
73277cb4d3eSLandon J. Fuller * MAC address string filter.
73377cb4d3eSLandon J. Fuller */
73477cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_macaddr_string_filter(const bhnd_nvram_val_fmt ** fmt,const void * inp,size_t ilen,bhnd_nvram_type itype)73558efe686SLandon J. Fuller bhnd_nvram_val_bcm_macaddr_string_filter(const bhnd_nvram_val_fmt **fmt,
73677cb4d3eSLandon J. Fuller const void *inp, size_t ilen, bhnd_nvram_type itype)
73777cb4d3eSLandon J. Fuller {
73877cb4d3eSLandon J. Fuller switch (itype) {
73977cb4d3eSLandon J. Fuller case BHND_NVRAM_TYPE_STRING:
74077cb4d3eSLandon J. Fuller /* Use the standard Broadcom string format implementation if
74177cb4d3eSLandon J. Fuller * the input is not an octet string. */
74277cb4d3eSLandon J. Fuller if (!bhnd_nvram_ident_octet_string(inp, ilen, NULL, NULL))
74377cb4d3eSLandon J. Fuller *fmt = &bhnd_nvram_val_bcm_string_fmt;
74477cb4d3eSLandon J. Fuller
74577cb4d3eSLandon J. Fuller return (0);
74677cb4d3eSLandon J. Fuller default:
74777cb4d3eSLandon J. Fuller return (EFTYPE);
74877cb4d3eSLandon J. Fuller }
74977cb4d3eSLandon J. Fuller }
75077cb4d3eSLandon J. Fuller
75177cb4d3eSLandon J. Fuller /**
75277cb4d3eSLandon J. Fuller * MAC address string octet encoding.
75377cb4d3eSLandon J. Fuller */
75477cb4d3eSLandon J. Fuller static int
bhnd_nvram_val_bcm_macaddr_string_encode_elem(bhnd_nvram_val * value,const void * inp,size_t ilen,void * outp,size_t * olen,bhnd_nvram_type otype)75558efe686SLandon J. Fuller bhnd_nvram_val_bcm_macaddr_string_encode_elem(bhnd_nvram_val *value,
75677cb4d3eSLandon J. Fuller const void *inp, size_t ilen, void *outp, size_t *olen,
75777cb4d3eSLandon J. Fuller bhnd_nvram_type otype)
75877cb4d3eSLandon J. Fuller {
75977cb4d3eSLandon J. Fuller size_t nparsed;
76077cb4d3eSLandon J. Fuller int error;
76177cb4d3eSLandon J. Fuller
76277cb4d3eSLandon J. Fuller /* If integer encoding is requested, explicitly parse our
76377cb4d3eSLandon J. Fuller * non-0x-prefixed as a base 16 integer value */
76477cb4d3eSLandon J. Fuller if (bhnd_nvram_is_int_type(otype)) {
76577cb4d3eSLandon J. Fuller error = bhnd_nvram_parse_int(inp, ilen, 16, &nparsed, outp,
76677cb4d3eSLandon J. Fuller olen, otype);
76777cb4d3eSLandon J. Fuller if (error)
76877cb4d3eSLandon J. Fuller return (error);
76977cb4d3eSLandon J. Fuller
77077cb4d3eSLandon J. Fuller if (nparsed != ilen)
77177cb4d3eSLandon J. Fuller return (EFTYPE);
77277cb4d3eSLandon J. Fuller
77377cb4d3eSLandon J. Fuller return (0);
77477cb4d3eSLandon J. Fuller }
77577cb4d3eSLandon J. Fuller
77677cb4d3eSLandon J. Fuller /* Otherwise, use standard encoding support */
77777cb4d3eSLandon J. Fuller return (bhnd_nvram_value_coerce(inp, ilen,
77877cb4d3eSLandon J. Fuller bhnd_nvram_val_elem_type(value), outp, olen, otype));
77977cb4d3eSLandon J. Fuller }
78077cb4d3eSLandon J. Fuller
78177cb4d3eSLandon J. Fuller /**
78277cb4d3eSLandon J. Fuller * MAC address string octet iteration.
78377cb4d3eSLandon J. Fuller */
78477cb4d3eSLandon J. Fuller static const void *
bhnd_nvram_val_bcm_macaddr_string_next(bhnd_nvram_val * value,const void * prev,size_t * len)78558efe686SLandon J. Fuller bhnd_nvram_val_bcm_macaddr_string_next(bhnd_nvram_val *value, const void *prev,
78677cb4d3eSLandon J. Fuller size_t *len)
78777cb4d3eSLandon J. Fuller {
78877cb4d3eSLandon J. Fuller const char *next;
78977cb4d3eSLandon J. Fuller const char *str;
79077cb4d3eSLandon J. Fuller bhnd_nvram_type stype;
79177cb4d3eSLandon J. Fuller size_t slen, remain;
79277cb4d3eSLandon J. Fuller char delim;
79377cb4d3eSLandon J. Fuller
79477cb4d3eSLandon J. Fuller /* Fetch backing string */
79577cb4d3eSLandon J. Fuller str = bhnd_nvram_val_bytes(value, &slen, &stype);
79677cb4d3eSLandon J. Fuller BHND_NV_ASSERT(stype == BHND_NVRAM_TYPE_STRING,
79777cb4d3eSLandon J. Fuller ("unsupported type: %d", stype));
79877cb4d3eSLandon J. Fuller
79977cb4d3eSLandon J. Fuller /* Zero-length array? */
80077cb4d3eSLandon J. Fuller if (slen == 0)
80177cb4d3eSLandon J. Fuller return (NULL);
80277cb4d3eSLandon J. Fuller
80377cb4d3eSLandon J. Fuller if (prev == NULL) {
80477cb4d3eSLandon J. Fuller /* First element */
80577cb4d3eSLandon J. Fuller
80677cb4d3eSLandon J. Fuller /* Determine delimiter */
80777cb4d3eSLandon J. Fuller if (!bhnd_nvram_ident_octet_string(str, slen, &delim, NULL)) {
80877cb4d3eSLandon J. Fuller /* Default to comma-delimited parsing */
80977cb4d3eSLandon J. Fuller delim = ',';
81077cb4d3eSLandon J. Fuller }
81177cb4d3eSLandon J. Fuller
81277cb4d3eSLandon J. Fuller /* Parsing will start at the base string pointer */
81377cb4d3eSLandon J. Fuller next = str;
81477cb4d3eSLandon J. Fuller remain = slen;
81577cb4d3eSLandon J. Fuller } else {
81677cb4d3eSLandon J. Fuller /* Advance to the previous element's delimiter */
81777cb4d3eSLandon J. Fuller next = (const char *)prev + *len;
81877cb4d3eSLandon J. Fuller
81977cb4d3eSLandon J. Fuller /* Did we hit the end of the string? */
82077cb4d3eSLandon J. Fuller if ((size_t)(next - str) >= slen)
82177cb4d3eSLandon J. Fuller return (NULL);
82277cb4d3eSLandon J. Fuller
82377cb4d3eSLandon J. Fuller /* Fetch (and skip past) the delimiter */
82477cb4d3eSLandon J. Fuller delim = *next;
82577cb4d3eSLandon J. Fuller next++;
82677cb4d3eSLandon J. Fuller remain = slen - (size_t)(next - str);
82777cb4d3eSLandon J. Fuller
82877cb4d3eSLandon J. Fuller /* Was the delimiter the final character? */
82977cb4d3eSLandon J. Fuller if (remain == 0)
83077cb4d3eSLandon J. Fuller return (NULL);
83177cb4d3eSLandon J. Fuller }
83277cb4d3eSLandon J. Fuller
83377cb4d3eSLandon J. Fuller /* Parse the field value, up to the next delimiter */
83477cb4d3eSLandon J. Fuller *len = bhnd_nvram_parse_field(&next, remain, delim);
83577cb4d3eSLandon J. Fuller
83677cb4d3eSLandon J. Fuller return (next);
83777cb4d3eSLandon J. Fuller }
83877cb4d3eSLandon J. Fuller
83977cb4d3eSLandon J. Fuller /**
84077cb4d3eSLandon J. Fuller * Determine whether @p inp is in octet string format, consisting of a
84177cb4d3eSLandon J. Fuller * fields of two hex characters, separated with ':' or '-' delimiters.
84277cb4d3eSLandon J. Fuller *
84377cb4d3eSLandon J. Fuller * This may be used to identify MAC address octet strings
84477cb4d3eSLandon J. Fuller * (BHND_NVRAM_SFMT_MACADDR).
84577cb4d3eSLandon J. Fuller *
84677cb4d3eSLandon J. Fuller * @param inp The string to be parsed.
84777cb4d3eSLandon J. Fuller * @param ilen The length of @p inp, in bytes.
84877cb4d3eSLandon J. Fuller * @param[out] delim On success, the delimiter used by this octet
84977cb4d3eSLandon J. Fuller * string. May be set to NULL if the field
85077cb4d3eSLandon J. Fuller * delimiter is not desired.
85177cb4d3eSLandon J. Fuller * @param[out] nelem On success, the number of fields in this
85277cb4d3eSLandon J. Fuller * octet string. May be set to NULL if the field
85377cb4d3eSLandon J. Fuller * count is not desired.
85477cb4d3eSLandon J. Fuller *
85577cb4d3eSLandon J. Fuller *
85677cb4d3eSLandon J. Fuller * @retval true if @p inp is a valid octet string
85777cb4d3eSLandon J. Fuller * @retval false if @p inp is not a valid octet string.
85877cb4d3eSLandon J. Fuller */
85977cb4d3eSLandon J. Fuller static bool
bhnd_nvram_ident_octet_string(const char * inp,size_t ilen,char * delim,size_t * nelem)86077cb4d3eSLandon J. Fuller bhnd_nvram_ident_octet_string(const char *inp, size_t ilen, char *delim,
86177cb4d3eSLandon J. Fuller size_t *nelem)
86277cb4d3eSLandon J. Fuller {
86377cb4d3eSLandon J. Fuller size_t elem_count;
86477cb4d3eSLandon J. Fuller size_t max_elem_count, min_elem_count;
86577cb4d3eSLandon J. Fuller size_t field_count;
86677cb4d3eSLandon J. Fuller char idelim;
86777cb4d3eSLandon J. Fuller
86877cb4d3eSLandon J. Fuller field_count = 0;
86977cb4d3eSLandon J. Fuller
87077cb4d3eSLandon J. Fuller /* Require exactly two digits. If we relax this, there is room
87177cb4d3eSLandon J. Fuller * for ambiguity with signed integers and the '-' delimiter */
87277cb4d3eSLandon J. Fuller min_elem_count = 2;
87377cb4d3eSLandon J. Fuller max_elem_count = 2;
87477cb4d3eSLandon J. Fuller
87577cb4d3eSLandon J. Fuller /* Identify the delimiter used. The standard delimiter for MAC
87677cb4d3eSLandon J. Fuller * addresses is ':', but some earlier NVRAM formats may use '-' */
87777cb4d3eSLandon J. Fuller for (const char *d = ":-";; d++) {
87877cb4d3eSLandon J. Fuller const char *loc;
87977cb4d3eSLandon J. Fuller
88077cb4d3eSLandon J. Fuller /* No delimiter found, not an octet string */
88177cb4d3eSLandon J. Fuller if (*d == '\0')
88277cb4d3eSLandon J. Fuller return (false);
88377cb4d3eSLandon J. Fuller
88477cb4d3eSLandon J. Fuller /* Look for the delimiter */
88577cb4d3eSLandon J. Fuller if ((loc = memchr(inp, *d, ilen)) == NULL)
88677cb4d3eSLandon J. Fuller continue;
88777cb4d3eSLandon J. Fuller
88877cb4d3eSLandon J. Fuller /* Delimiter found */
88977cb4d3eSLandon J. Fuller idelim = *loc;
89077cb4d3eSLandon J. Fuller break;
89177cb4d3eSLandon J. Fuller }
89277cb4d3eSLandon J. Fuller
89377cb4d3eSLandon J. Fuller /* To disambiguate from signed integers, if the delimiter is "-",
89477cb4d3eSLandon J. Fuller * the octets must be exactly 2 chars each */
89577cb4d3eSLandon J. Fuller if (idelim == '-')
89677cb4d3eSLandon J. Fuller min_elem_count = 2;
89777cb4d3eSLandon J. Fuller
89877cb4d3eSLandon J. Fuller /* String must be composed of individual octets (zero or more hex
89977cb4d3eSLandon J. Fuller * digits) separated by our delimiter. */
90077cb4d3eSLandon J. Fuller elem_count = 0;
90177cb4d3eSLandon J. Fuller for (const char *p = inp; (size_t)(p - inp) < ilen; p++) {
90277cb4d3eSLandon J. Fuller switch (*p) {
90377cb4d3eSLandon J. Fuller case ':':
90477cb4d3eSLandon J. Fuller case '-':
90577cb4d3eSLandon J. Fuller case '\0':
90677cb4d3eSLandon J. Fuller /* Hit a delim character; all delims must match
90777cb4d3eSLandon J. Fuller * the first delimiter used */
90877cb4d3eSLandon J. Fuller if (*p != '\0' && *p != idelim)
90977cb4d3eSLandon J. Fuller return (false);
91077cb4d3eSLandon J. Fuller
91177cb4d3eSLandon J. Fuller /* Must have parsed at least min_elem_count digits */
91277cb4d3eSLandon J. Fuller if (elem_count < min_elem_count)
91377cb4d3eSLandon J. Fuller return (false);
91477cb4d3eSLandon J. Fuller
91577cb4d3eSLandon J. Fuller /* Reset element count */
91677cb4d3eSLandon J. Fuller elem_count = 0;
91777cb4d3eSLandon J. Fuller
91877cb4d3eSLandon J. Fuller /* Bump field count */
91977cb4d3eSLandon J. Fuller field_count++;
92077cb4d3eSLandon J. Fuller break;
92177cb4d3eSLandon J. Fuller default:
92277cb4d3eSLandon J. Fuller /* More than maximum number of hex digits? */
92377cb4d3eSLandon J. Fuller if (elem_count >= max_elem_count)
92477cb4d3eSLandon J. Fuller return (false);
92577cb4d3eSLandon J. Fuller
92677cb4d3eSLandon J. Fuller /* Octet values must be hex digits */
92777cb4d3eSLandon J. Fuller if (!bhnd_nv_isxdigit(*p))
92877cb4d3eSLandon J. Fuller return (false);
92977cb4d3eSLandon J. Fuller
93077cb4d3eSLandon J. Fuller elem_count++;
93177cb4d3eSLandon J. Fuller break;
93277cb4d3eSLandon J. Fuller }
93377cb4d3eSLandon J. Fuller }
93477cb4d3eSLandon J. Fuller
93577cb4d3eSLandon J. Fuller if (delim != NULL)
93677cb4d3eSLandon J. Fuller *delim = idelim;
93777cb4d3eSLandon J. Fuller
93877cb4d3eSLandon J. Fuller if (nelem != NULL)
93977cb4d3eSLandon J. Fuller *nelem = field_count;
94077cb4d3eSLandon J. Fuller
94177cb4d3eSLandon J. Fuller return (true);
94277cb4d3eSLandon J. Fuller }
94377cb4d3eSLandon J. Fuller
94477cb4d3eSLandon J. Fuller /**
94577cb4d3eSLandon J. Fuller * Determine whether @p inp is in hexadecimal, octal, or decimal string
94677cb4d3eSLandon J. Fuller * format.
94777cb4d3eSLandon J. Fuller *
94877cb4d3eSLandon J. Fuller * - A @p str may be prefixed with a single optional '+' or '-' sign denoting
94977cb4d3eSLandon J. Fuller * signedness.
95077cb4d3eSLandon J. Fuller * - A hexadecimal @p str may include an '0x' or '0X' prefix, denoting that a
95177cb4d3eSLandon J. Fuller * base 16 integer follows.
95277cb4d3eSLandon J. Fuller * - An octal @p str may include a '0' prefix, denoting that an octal integer
95377cb4d3eSLandon J. Fuller * follows.
95477cb4d3eSLandon J. Fuller *
95577cb4d3eSLandon J. Fuller * @param inp The string to be parsed.
95677cb4d3eSLandon J. Fuller * @param ilen The length of @p inp, in bytes.
95777cb4d3eSLandon J. Fuller * @param base The input string's base (2-36), or 0.
95877cb4d3eSLandon J. Fuller * @param[out] obase On success, will be set to the base of the parsed
95977cb4d3eSLandon J. Fuller * integer. May be set to NULL if the base is not
96077cb4d3eSLandon J. Fuller * desired.
96177cb4d3eSLandon J. Fuller *
96277cb4d3eSLandon J. Fuller * @retval true if @p inp is a valid number string
96377cb4d3eSLandon J. Fuller * @retval false if @p inp is not a valid number string.
96477cb4d3eSLandon J. Fuller * @retval false if @p base is invalid.
96577cb4d3eSLandon J. Fuller */
96677cb4d3eSLandon J. Fuller static bool
bhnd_nvram_ident_num_string(const char * inp,size_t ilen,u_int base,u_int * obase)96777cb4d3eSLandon J. Fuller bhnd_nvram_ident_num_string(const char *inp, size_t ilen, u_int base,
96877cb4d3eSLandon J. Fuller u_int *obase)
96977cb4d3eSLandon J. Fuller {
97077cb4d3eSLandon J. Fuller size_t nbytes, ndigits;
97177cb4d3eSLandon J. Fuller
97277cb4d3eSLandon J. Fuller nbytes = 0;
97377cb4d3eSLandon J. Fuller ndigits = 0;
97477cb4d3eSLandon J. Fuller
97577cb4d3eSLandon J. Fuller /* Parse and skip sign */
97677cb4d3eSLandon J. Fuller if (nbytes >= ilen)
97777cb4d3eSLandon J. Fuller return (false);
97877cb4d3eSLandon J. Fuller
97977cb4d3eSLandon J. Fuller if (inp[nbytes] == '-' || inp[nbytes] == '+')
98077cb4d3eSLandon J. Fuller nbytes++;
98177cb4d3eSLandon J. Fuller
98277cb4d3eSLandon J. Fuller /* Truncated after sign character? */
98377cb4d3eSLandon J. Fuller if (nbytes == ilen)
98477cb4d3eSLandon J. Fuller return (false);
98577cb4d3eSLandon J. Fuller
98677cb4d3eSLandon J. Fuller /* Identify (or validate) hex base, skipping 0x/0X prefix */
98777cb4d3eSLandon J. Fuller if (base == 16 || base == 0) {
98877cb4d3eSLandon J. Fuller /* Check for (and skip) 0x/0X prefix */
98977cb4d3eSLandon J. Fuller if (ilen - nbytes >= 2 && inp[nbytes] == '0' &&
99077cb4d3eSLandon J. Fuller (inp[nbytes+1] == 'x' || inp[nbytes+1] == 'X'))
99177cb4d3eSLandon J. Fuller {
99277cb4d3eSLandon J. Fuller base = 16;
99377cb4d3eSLandon J. Fuller nbytes += 2;
99477cb4d3eSLandon J. Fuller }
99577cb4d3eSLandon J. Fuller }
99677cb4d3eSLandon J. Fuller
99777cb4d3eSLandon J. Fuller /* Truncated after hex prefix? */
99877cb4d3eSLandon J. Fuller if (nbytes == ilen)
99977cb4d3eSLandon J. Fuller return (false);
100077cb4d3eSLandon J. Fuller
100177cb4d3eSLandon J. Fuller /* Differentiate decimal/octal by looking for a leading 0 */
100277cb4d3eSLandon J. Fuller if (base == 0) {
100377cb4d3eSLandon J. Fuller if (inp[nbytes] == '0') {
100477cb4d3eSLandon J. Fuller base = 8;
100577cb4d3eSLandon J. Fuller } else {
100677cb4d3eSLandon J. Fuller base = 10;
100777cb4d3eSLandon J. Fuller }
100877cb4d3eSLandon J. Fuller }
100977cb4d3eSLandon J. Fuller
101077cb4d3eSLandon J. Fuller /* Consume and validate all remaining digit characters */
101177cb4d3eSLandon J. Fuller for (; nbytes < ilen; nbytes++) {
101277cb4d3eSLandon J. Fuller u_int carry;
101377cb4d3eSLandon J. Fuller char c;
101477cb4d3eSLandon J. Fuller
101577cb4d3eSLandon J. Fuller /* Parse carry value */
101677cb4d3eSLandon J. Fuller c = inp[nbytes];
101777cb4d3eSLandon J. Fuller if (bhnd_nv_isdigit(c)) {
101877cb4d3eSLandon J. Fuller carry = c - '0';
101977cb4d3eSLandon J. Fuller } else if (bhnd_nv_isxdigit(c)) {
102077cb4d3eSLandon J. Fuller if (bhnd_nv_isupper(c))
102177cb4d3eSLandon J. Fuller carry = (c - 'A') + 10;
102277cb4d3eSLandon J. Fuller else
102377cb4d3eSLandon J. Fuller carry = (c - 'a') + 10;
102477cb4d3eSLandon J. Fuller } else {
102577cb4d3eSLandon J. Fuller /* Hit a non-digit character */
102677cb4d3eSLandon J. Fuller return (false);
102777cb4d3eSLandon J. Fuller }
102877cb4d3eSLandon J. Fuller
102977cb4d3eSLandon J. Fuller /* If carry is outside the base, it's not a valid digit
103077cb4d3eSLandon J. Fuller * in the current parse context; consider it a non-digit
103177cb4d3eSLandon J. Fuller * character */
103277cb4d3eSLandon J. Fuller if (carry >= base)
103377cb4d3eSLandon J. Fuller return (false);
103477cb4d3eSLandon J. Fuller
103577cb4d3eSLandon J. Fuller /* Increment parsed digit count */
103677cb4d3eSLandon J. Fuller ndigits++;
103777cb4d3eSLandon J. Fuller }
103877cb4d3eSLandon J. Fuller
103977cb4d3eSLandon J. Fuller /* Empty integer string? */
104077cb4d3eSLandon J. Fuller if (ndigits == 0)
104177cb4d3eSLandon J. Fuller return (false);
104277cb4d3eSLandon J. Fuller
104377cb4d3eSLandon J. Fuller /* Valid integer -- provide the base and return */
104477cb4d3eSLandon J. Fuller if (obase != NULL)
104577cb4d3eSLandon J. Fuller *obase = base;
104677cb4d3eSLandon J. Fuller return (true);
104777cb4d3eSLandon J. Fuller }
1048