/** * Iterate over all strings in the @p inp string array. * * @param inp The string array to be iterated. This must be a buffer * of one or more NUL-terminated strings -- * @see BHND_NVRAM_TYPE_STRING_ARRAY. * @param ilen The size, in bytes, of @p inp, including any * terminating NUL character(s). * @param prev The value previously returned by * bhnd_nvram_string_array_next(), or NULL to begin * iteration. * * @retval non-NULL A reference to the next NUL-terminated string * @retval NULL If the end of the string array is reached. */ const char * bhnd_nvram_string_array_next(const char *inp, size_t ilen, const char *prev) { size_t nremain, plen; if (ilen == 0) return (NULL); if (prev == NULL) return (inp); /* Advance to next value */ BHND_NV_ASSERT(prev >= inp, ("invalid prev pointer")); BHND_NV_ASSERT(prev < (inp+ilen), ("invalid prev pointer")); nremain = ilen - (size_t)(prev - inp); plen = strnlen(prev, nremain); nremain -= plen; /* Only a trailing NUL remains? */ if (nremain <= 1) return (NULL); return (prev + plen + 1); }
/** * Return true if @p type is a signed integer type, false otherwise. * * Will return false for all array types. * * @param type The type to query. */ bool bhnd_nvram_is_signed_type(bhnd_nvram_type type) { switch (type) { case BHND_NVRAM_TYPE_INT8: case BHND_NVRAM_TYPE_INT16: case BHND_NVRAM_TYPE_INT32: case BHND_NVRAM_TYPE_INT64: BHND_NV_ASSERT(bhnd_nvram_is_int_type(type), ("non-int type?")); return (true); case BHND_NVRAM_TYPE_CHAR: case BHND_NVRAM_TYPE_UINT8: case BHND_NVRAM_TYPE_UINT16: case BHND_NVRAM_TYPE_UINT32: case BHND_NVRAM_TYPE_UINT64: case BHND_NVRAM_TYPE_STRING: case BHND_NVRAM_TYPE_UINT8_ARRAY: case BHND_NVRAM_TYPE_UINT16_ARRAY: case BHND_NVRAM_TYPE_UINT32_ARRAY: case BHND_NVRAM_TYPE_UINT64_ARRAY: case BHND_NVRAM_TYPE_INT8_ARRAY: case BHND_NVRAM_TYPE_INT16_ARRAY: case BHND_NVRAM_TYPE_INT32_ARRAY: case BHND_NVRAM_TYPE_INT64_ARRAY: case BHND_NVRAM_TYPE_CHAR_ARRAY: case BHND_NVRAM_TYPE_STRING_ARRAY: return (false); } /* Quiesce gcc4.2 */ BHND_NV_PANIC("bhnd nvram type %u unknown", type); }
/** * A generic implementation of bhnd_nvram_data_getvar(). * * This implementation will call bhnd_nvram_data_getvar_ptr() to fetch * a pointer to the variable data and perform data coercion on behalf * of the caller. * * If a variable definition for the requested variable is available via * bhnd_nvram_find_vardefn(), the definition will be used to provide a * formatting instance to bhnd_nvram_val_init(). */ int bhnd_nvram_data_generic_rp_getvar(struct bhnd_nvram_data *nv, void *cookiep, void *outp, size_t *olen, bhnd_nvram_type otype) { bhnd_nvram_val val; const bhnd_nvram_val_fmt *fmt; const void *vptr; bhnd_nvram_type vtype; size_t vlen; int error; BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR, ("instance does not advertise READ_PTR support")); /* Fetch variable data and value format*/ vptr = bhnd_nvram_data_getvar_ptr_info(nv, cookiep, &vlen, &vtype, &fmt); if (vptr == NULL) return (EINVAL); /* Attempt value coercion */ error = bhnd_nvram_val_init(&val, fmt, vptr, vlen, vtype, BHND_NVRAM_VAL_BORROW_DATA); if (error) return (error); error = bhnd_nvram_val_encode(&val, outp, olen, otype); /* Clean up */ bhnd_nvram_val_release(&val); return (error); }
/** * Allocate and initialize a new instance of data class @p cls, copying and * parsing NVRAM data from @p io. * * The caller is responsible for releasing the returned parser instance * reference via bhnd_nvram_data_release(). * * @param cls If non-NULL, the data class to be allocated. If NULL, * bhnd_nvram_data_probe_classes() will be used to determine the data format. * @param[out] nv On success, a pointer to the newly allocated NVRAM data instance. * @param io An I/O context mapping the NVRAM data to be copied and parsed. * * @retval 0 success * @retval non-zero if an error occurs during allocation or initialization, a * regular unix error code will be returned. */ int bhnd_nvram_data_new(bhnd_nvram_data_class *cls, struct bhnd_nvram_data **nv, struct bhnd_nvram_io *io) { struct bhnd_nvram_data *data; int error; /* If NULL, try to identify the appropriate class */ if (cls == NULL) return (bhnd_nvram_data_probe_classes(nv, io, NULL, 0)); /* Allocate new instance */ BHND_NV_ASSERT(sizeof(struct bhnd_nvram_data) <= cls->size, ("instance size %zu less than minimum %zu", cls->size, sizeof(struct bhnd_nvram_data))); data = bhnd_nv_calloc(1, cls->size); data->cls = cls; refcount_init(&data->refs, 1); /* Let the class handle initialization */ if ((error = cls->op_new(data, io))) { bhnd_nv_free(data); return (error); } *nv = data; return (0); }
/* * Common bhnd_nvram_data_getvar_ptr() wrapper used by * bhnd_nvram_data_generic_rp_getvar() and * bhnd_nvram_data_generic_rp_copy_val(). * * If a variable definition for the requested variable is found via * bhnd_nvram_find_vardefn(), the definition will be used to populate fmt. */ static const void * bhnd_nvram_data_getvar_ptr_info(struct bhnd_nvram_data *nv, void *cookiep, size_t *len, bhnd_nvram_type *type, const bhnd_nvram_val_fmt **fmt) { const struct bhnd_nvram_vardefn *vdefn; const char *name; const void *vptr; BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR, ("instance does not advertise READ_PTR support")); /* Fetch pointer to variable data */ vptr = bhnd_nvram_data_getvar_ptr(nv, cookiep, len, type); if (vptr == NULL) return (NULL); /* Select a default value format implementation */ /* Fetch the reference variable name */ name = bhnd_nvram_data_getvar_name(nv, cookiep); /* Trim path prefix, if any; the Broadcom NVRAM format assumes a global * namespace for all variable definitions */ if (bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_DEVPATHS) name = bhnd_nvram_trim_path_name(name); /* Check the variable definition table for a matching entry; if * it exists, use it to populate the value format. */ vdefn = bhnd_nvram_find_vardefn(name); if (vdefn != NULL) { BHND_NV_ASSERT(vdefn->fmt != NULL, ("NULL format for %s", name)); *fmt = vdefn->fmt; } else if (*type == BHND_NVRAM_TYPE_STRING) { /* Default to Broadcom-specific string interpretation */ *fmt = &bhnd_nvram_val_bcm_string_fmt; } else { /* Fall back on native formatting */ *fmt = bhnd_nvram_val_default_fmt(*type); } return (vptr); }
/** * Return the variable ID for a variable definition. * * @param defn Variable definition previously returned by * bhnd_nvram_find_vardefn() or bhnd_nvram_get_vardefn(). */ size_t bhnd_nvram_get_vardefn_id(const struct bhnd_nvram_vardefn *defn) { BHND_NV_ASSERT( defn >= bhnd_nvram_vardefns && defn <= &bhnd_nvram_vardefns[bhnd_nvram_num_vardefns-1], ("invalid variable definition pointer %p", defn)); return (defn - bhnd_nvram_vardefns); }
/** * A generic implementation of bhnd_nvram_data_copy_val(). * * This implementation will call bhnd_nvram_data_getvar_ptr() to fetch * a pointer to the variable data and perform data coercion on behalf * of the caller. * * If a variable definition for the requested variable is available via * bhnd_nvram_find_vardefn(), the definition will be used to provide a * formatting instance to bhnd_nvram_val_init(). */ int bhnd_nvram_data_generic_rp_copy_val(struct bhnd_nvram_data *nv, void *cookiep, bhnd_nvram_val **value) { const bhnd_nvram_val_fmt *fmt; const void *vptr; bhnd_nvram_type vtype; size_t vlen; BHND_NV_ASSERT(bhnd_nvram_data_caps(nv) & BHND_NVRAM_DATA_CAP_READ_PTR, ("instance does not advertise READ_PTR support")); /* Fetch variable data and value format*/ vptr = bhnd_nvram_data_getvar_ptr_info(nv, cookiep, &vlen, &vtype, &fmt); if (vptr == NULL) return (EINVAL); /* Allocate and return the new value instance */ return (bhnd_nvram_val_new(value, fmt, vptr, vlen, vtype, BHND_NVRAM_VAL_DYNAMIC)); }
/** * Calculate the number of elements represented by a value of @p len bytes * with @p type. * * @param type The value type. * @param data The actual data to be queried, or NULL if unknown. * @param len The length in bytes of @p data, or if @p data is NULL, * the expected length in bytes. * @param[out] nelem On success, the number of elements. If @p type is not * a fixed width type (e.g. BHND_NVRAM_TYPE_STRING_ARRAY), * and @p data is NULL, an @p nelem value of 0 will be * returned. * * @retval 0 success * @retval EFTYPE if @p type is not an array type, and @p len is not * equal to the size of a single element of @p type. * @retval EFAULT if @p len is not correctly aligned for elements of * @p type. */ int bhnd_nvram_value_nelem(bhnd_nvram_type type, const void *data, size_t len, size_t *nelem) { bhnd_nvram_type base_type; size_t base_size; /* Length must be aligned to the element size */ base_type = bhnd_nvram_base_type(type); base_size = bhnd_nvram_value_size(base_type, NULL, 0, 1); if (base_size != 0 && len % base_size != 0) return (EFAULT); switch (type) { case BHND_NVRAM_TYPE_STRING: case BHND_NVRAM_TYPE_STRING_ARRAY: { const char *p; size_t nleft; /* Cannot determine the element count without parsing * the actual data */ if (data == NULL) { *nelem = 0; return (0); } /* Iterate over the NUL-terminated strings to calculate * total element count */ p = data; nleft = len; *nelem = 0; while (nleft > 0) { size_t slen; /* Increment element count */ (*nelem)++; /* If not a string array, data must not contain more * than one entry. */ if (!bhnd_nvram_is_array_type(type) && *nelem > 1) return (EFTYPE); /* Determine string length */ slen = strnlen(p, nleft); nleft -= slen; /* Advance input */ p += slen; /* Account for trailing NUL, if we haven't hit the end * of the input */ if (nleft > 0) { nleft--; p++; } } return (0); } case BHND_NVRAM_TYPE_INT8: case BHND_NVRAM_TYPE_UINT8: case BHND_NVRAM_TYPE_CHAR: case BHND_NVRAM_TYPE_INT16: case BHND_NVRAM_TYPE_UINT16: case BHND_NVRAM_TYPE_INT32: case BHND_NVRAM_TYPE_UINT32: case BHND_NVRAM_TYPE_INT64: case BHND_NVRAM_TYPE_UINT64: /* Length must be equal to the size of exactly one * element (arrays can represent zero elements -- non-array * types cannot) */ if (len != base_size) return (EFTYPE); *nelem = 1; return (0); case BHND_NVRAM_TYPE_UINT8_ARRAY: case BHND_NVRAM_TYPE_UINT16_ARRAY: case BHND_NVRAM_TYPE_UINT32_ARRAY: case BHND_NVRAM_TYPE_UINT64_ARRAY: case BHND_NVRAM_TYPE_INT8_ARRAY: case BHND_NVRAM_TYPE_INT16_ARRAY: case BHND_NVRAM_TYPE_INT32_ARRAY: case BHND_NVRAM_TYPE_INT64_ARRAY: case BHND_NVRAM_TYPE_CHAR_ARRAY: BHND_NV_ASSERT(base_size != 0, ("invalid base size")); *nelem = len / base_size; return (0); } /* Quiesce gcc4.2 */ BHND_NV_PANIC("bhnd nvram type %u unknown", type); }