*
* @copyright 2015 The FreeRADIUS server project
*/
+RCSIDH(dict_h, "$Id$")
#ifdef __cplusplus
extern "C" {
#include <freeradius-devel/build.h>
#include <freeradius-devel/missing.h>
#include <freeradius-devel/util/dl.h>
+#include <freeradius-devel/util/ext.h>
#include <freeradius-devel/util/rbtree.h>
#include <freeradius-devel/util/sbuff.h>
#include <freeradius-devel/util/table.h>
#include <stdbool.h>
#include <stdint.h>
#include <talloc.h>
-#include <limits.h>
/*
* Avoid circular type references.
/** Extension identifier
*
- * @note New extension structures should also be added to the #fr_dict_ext_length_min table in dict_ext.c
+ * @note New extension structures should also be added to the #fr_dict_attr_ext_info table in dict_ext.c
*/
typedef enum {
FR_DICT_ATTR_EXT_NAME = 0, //!< Name of the attribute.
FR_DICT_ATTR_EXT_MAX
} fr_dict_attr_ext_t;
-/** The alignment of object extension structures
- *
- */
-#ifdef __WORD_SIZE
-# if __WORD_SIZE < 4
-# define FR_DICT_ATTR_EXT_ALIGNMENT sizeof(uint32_t)
-# else
-# define FR_DICT_ATTR_EXT_ALIGNMENT __WORD_SIZE /* From limits.h */
-# endif
-#else
-# define FR_DICT_ATTR_EXT_ALIGNMENT sizeof(uint64_t)
-#endif
-
-/** Attribute extension - Holds children for an attribute
- *
- * Children are possible for:
- *
- * #FR_TYPE_TLV, #FR_TYPE_VENDOR, #FR_TYPE_VSA, #FR_TYPE_STRUCT
- *
- * *or* where the parent->parent->type is
- * #FR_TYPE_STRUCT, and "parent" is a "key"
- * field. Note that these attributes therefore
- * cannot have VALUEs, as the child defines their
- * VALUE. See dict_attr_can_have_children() for details.
- */
-typedef struct {
- fr_hash_table_t *child_by_name; //!< Namespace at this level in the hierarchy.
- fr_dict_attr_t const **children; //!< Children of this attribute.
-} fr_dict_attr_ext_children_t;
-
-/** Attribute extension - Holds a reference to an attribute in another dictionary
- *
- */
-typedef struct {
- fr_dict_attr_t const *ref; //!< reference, only for #FR_TYPE_GROUP
-} fr_dict_attr_ext_ref_t;
-
-/** Attribute extension - Cached vendor pointer
- *
- */
-typedef struct {
- fr_dict_attr_t const *vendor; //!< ancestor which has type #FR_TYPE_VENDOR
-} fr_dict_attr_ext_vendor_t;
-
-/** Attribute extension - Stack of dictionary attributes that describe the path back to the root of the dictionary
- *
- */
-typedef struct {
- fr_dict_attr_t const *da_stack[0]; //!< Stack of dictionary attributes
-} fr_dict_attr_ext_da_stack_t;
-
-/** Attribute extension - Holds enumeration values
- *
- */
-typedef struct {
- fr_hash_table_t *value_by_name; //!< Lookup an enumeration value by name
- fr_hash_table_t *name_by_value; //!< Lookup a name by value
-} fr_dict_attr_ext_enumv_t;
-
-/** Attribute extension - Protocol-specific
- *
- */
-typedef struct {
- void *uctx; //!< Protocol specific extensions
-} fr_dict_attr_ext_protocol_specific_t;
-
/** Dictionary attribute
*/
struct dict_attr_s {
fr_dict_attr_flags_t flags; //!< Flags.
uint8_t ext[FR_DICT_ATTR_EXT_MAX]; //!< Extensions to the dictionary attribute.
-} CC_HINT(aligned(FR_DICT_ATTR_EXT_ALIGNMENT));
+} CC_HINT(aligned(FR_EXT_ALIGNMENT));
+
+/** Extension identifier
+ *
+ * @note New extension structures should also be added to the #fr_dict_ext_length_min table in dict_ext.c
+ */
+typedef enum {
+ FR_DICT_ENUM_EXT_UNION_REF = 0, //!< Reference to a union/subs-struct.
+ FR_DICT_ENUM_EXT_MAX
+} fr_dict_enum_ext_t;
/** Value of an enumerated attribute
*
///< on partial buffers.
fr_value_box_t const *value; //!< Enum value (what name maps to).
+ uint8_t ext[FR_DICT_ENUM_EXT_MAX]; //!< Extensions to the dictionary attribute.
+
fr_dict_attr_t const *child_struct[0]; //!< for key fields
-} fr_dict_enum_t;
+} fr_dict_enum_t CC_HINT(aligned(FR_EXT_ALIGNMENT));
/** Private enterprise
*
extern bool const fr_dict_attr_allowed_chars[UINT8_MAX + 1];
extern bool const fr_dict_non_data_types[FR_TYPE_MAX + 1];
-/** @name Add extension structures to attributes
+/** @name Dictionary structure extensions
*
* @{
*/
-
-/** Return a pointer to the specified extension structure
- */
-#define DICT_EXT_OFFSET(_ptr, _ext) ((void *)(((_ptr)->ext[_ext] * FR_DICT_ATTR_EXT_ALIGNMENT) + ((uintptr_t)(_ptr))))
-
-/* Retrieve an extension structure for a dictionary attribute
- *
- * @param[in] da to retrieve structure from.
- * @param[in] ext to retrieve.
- * @return
- * - NULL if the extension wasn't found.
- * - A pointer to the start of the extension.
- */
-static inline void *fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
-{
- if (!da->ext[ext]) return NULL;
-
- return DICT_EXT_OFFSET(da, ext);
-}
-
-/** Return whether a da has a given extension or not
- *
- * @param[in] da to check for extensions.
- * @param[in] ext to check.
- * @return
- * - true if the da has the specified extension.
- * - false if the da does not have the specified extension
- */
-static inline bool fr_dict_attr_has_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
-{
- return (da->ext[ext] > 0);
-}
-
-/** Return the cached da stack (if any) associated with an attribute
- *
- * @param[in] da to return cached da stack for.
- * @return
- * - NULL if no da stack available.
- * - The cached da stack on success.
- */
-static inline fr_dict_attr_t const **fr_dict_attr_da_stack(fr_dict_attr_t const *da)
-{
- fr_dict_attr_ext_da_stack_t *ext;
-
- ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_DA_STACK);
- if (!ext) return NULL;
-
- return ext->da_stack;
-}
-
-/** Return the reference associated with a group type attribute
- *
- * @param[in] da to return the reference for.
- * @return
- * - NULL if no reference available.
- * - A pointer to the attribute being referenced.
- */
-static inline fr_dict_attr_t const *fr_dict_attr_ref(fr_dict_attr_t const *da)
-{
- fr_dict_attr_ext_ref_t *ext;
-
- ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_REF);
- if (!ext) return NULL;
-
- return ext->ref;
-}
+#include <freeradius-devel/util/dict_ext.h>
/** @} */
/** @name Programatically create dictionary attributes and values
int fr_dict_str_to_argv(char *str, char **argv, int max_argc);
/** @} */
+
/** @name Unknown ephemeral attributes
*
* @{
*/
fr_dict_attr_t const *fr_dict_root(fr_dict_t const *dict);
+bool fr_dict_is_read_only(fr_dict_t const *dict);
+
ssize_t fr_dict_by_protocol_substr(fr_dict_attr_err_t *err,
fr_dict_t const **out, fr_sbuff_t *name, fr_dict_t const *dict_def);
return true;
}
-/** Return the vendor number for an attribute
- *
- * @param[in] da The dictionary attribute to find the
- * vendor for.
- * @return
- * - 0 this isn't a vendor specific attribute.
- * - The vendor PEN.
- */
-static inline uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
-{
- fr_dict_attr_ext_vendor_t *ext;
-
- if (da->type == FR_TYPE_VENDOR) return da->attr;
-
- ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_VENDOR);
- if (!ext || !ext->vendor) return 0;
-
- return ext->vendor->attr;
-}
-
-/** Return the vendor da for an attribute
- *
- * @param[in] da The dictionary attribute to find the
- * vendor for.
- * @return
- * - 0 this isn't a vendor specific attribute.
- * - The vendor PEN.
- */
-static inline fr_dict_attr_t const *fr_dict_vendor_da_by_da(fr_dict_attr_t const *da)
-{
- fr_dict_attr_ext_vendor_t *ext;
-
- if (da->type == FR_TYPE_VENDOR) return da;
-
- ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_VENDOR);
- if (!ext) return NULL;
-
- return ext->vendor;
-}
-
fr_dict_vendor_t const *fr_dict_vendor_by_da(fr_dict_attr_t const *da);
fr_dict_vendor_t const *fr_dict_vendor_by_name(fr_dict_t const *dict, char const *name);
RCSID("$Id$")
#include <freeradius-devel/util/dict_priv.h>
+#include <freeradius-devel/util/dict_ext_priv.h>
#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/util/table.h>
#include <freeradius-devel/util/talloc.h>
-/** Copy function for fixing up extensions after they're copy
- *
- */
-typedef void *(* fr_dict_attr_ext_copy_t)(TALLOC_CTX *ctx, fr_dict_attr_t **da_out_p,
- fr_dict_attr_ext_t ext, void *ext_ptr, size_t ext_len);
-
-/** Additional information for a given extension
- */
-typedef struct {
- size_t min; //!< Minimum size of extension.
- bool has_hdr; //!< Has additional metadata allocated before
- ///< the extension data.
- bool can_copy; //!< Copying this extension between attributes is allowed.
- fr_dict_attr_ext_copy_t copy; //!< Override the normal copy operation with a callback.
-} fr_dict_attr_ext_info_t;
-
-static void *fr_dict_attr_ext_enumv_copy(TALLOC_CTX *ctx, fr_dict_attr_t **da_p,
- fr_dict_attr_ext_t ext, void *ext_ptr, size_t ext_len);
-
-
-static void *fr_dict_attr_ext_vendor_copy(TALLOC_CTX *ctx, fr_dict_attr_t **da_p,
- fr_dict_attr_ext_t ext, void *ext_ptr, UNUSED size_t ext_len);
-
static fr_table_num_ordered_t const dict_attr_ext_table[] = {
{ L("name"), FR_DICT_ATTR_EXT_NAME },
{ L("children"), FR_DICT_ATTR_EXT_CHILDREN },
};
static size_t dict_attr_ext_table_len = NUM_ELEMENTS(dict_attr_ext_table);
-/** Holds additional information about extension structures
- *
- */
-static fr_dict_attr_ext_info_t const fr_dict_ext_info[] = {
- [FR_DICT_ATTR_EXT_NAME] = {
- .min = sizeof(char),
- .has_hdr = true,
- .can_copy = false, /* Name may change, and we can only set it once */
- },
- [FR_DICT_ATTR_EXT_CHILDREN] = {
- .min = sizeof(fr_dict_attr_ext_children_t),
- .can_copy = false, /* Limitation in hashing scheme we use */
- },
- [FR_DICT_ATTR_EXT_REF] = {
- .min = sizeof(fr_dict_attr_ext_ref_t),
- .can_copy = true,
- },
- [FR_DICT_ATTR_EXT_VENDOR] = {
- .min = sizeof(fr_dict_attr_ext_vendor_t),
- .can_copy = true,
- .copy = fr_dict_attr_ext_vendor_copy
- },
- [FR_DICT_ATTR_EXT_ENUMV] = {
- .min = sizeof(fr_dict_attr_ext_enumv_t),
- .can_copy = true,
- .copy = fr_dict_attr_ext_enumv_copy
- },
- [FR_DICT_ATTR_EXT_DA_STACK] = {
- .min = sizeof(fr_dict_attr_ext_da_stack_t),
- .has_hdr = true,
- .can_copy = false /* Reinitialised for each new attribute */
- },
- [FR_DICT_ATTR_EXT_MAX] = {}
-};
-
-/** Optional extension header struct
- *
- */
-typedef struct {
- size_t len; //!< Length of extension data.
- uint8_t data[]; //!< Extension data
-} CC_HINT(aligned(FR_DICT_ATTR_EXT_ALIGNMENT)) dict_attr_ext_hdr_t;
-
/** Copy all enumeration values from one attribute to another
*
*/
-static void *fr_dict_attr_ext_enumv_copy(TALLOC_CTX *ctx, fr_dict_attr_t **da_p,
- fr_dict_attr_ext_t ext, void *ext_ptr, UNUSED size_t ext_len)
+static void *fr_dict_attr_ext_enumv_copy(void **chunk_p, int ext, void *ext_ptr, UNUSED size_t ext_len)
{
+ fr_dict_attr_t **da_p = (fr_dict_attr_t **)chunk_p;
fr_dict_attr_ext_enumv_t *new_ext, *old_ext;
fr_hash_iter_t iter;
fr_dict_enum_t *enumv;
bool has_child = da_is_key_field(*da_p);
- new_ext = dict_attr_ext_alloc(ctx, da_p, ext);
+ new_ext = dict_attr_ext_alloc(da_p, ext);
if (!new_ext) return NULL;
old_ext = ext_ptr;
/** Rediscover the parent of this attribute, and cache it
*
*/
-static void *fr_dict_attr_ext_vendor_copy(TALLOC_CTX *ctx, fr_dict_attr_t **da_p,
- fr_dict_attr_ext_t ext, void *ext_ptr, UNUSED size_t ext_len)
+static void *fr_dict_attr_ext_vendor_copy(void **chunk_p, int ext, void *ext_ptr, UNUSED size_t ext_len)
{
+ fr_dict_attr_t **da_p = (fr_dict_attr_t **)chunk_p;
fr_dict_attr_ext_vendor_t *new_ext, *old_ext = ext_ptr;
fr_dict_attr_t const **da_stack;
fr_dict_attr_t const *old_vendor = old_ext->vendor;
if (da_stack) {
new_vendor = da_stack[old_vendor->depth];
if ((new_vendor->type == old_vendor->type) && (new_vendor->attr == old_vendor->attr)) {
- new_ext = dict_attr_ext_alloc(ctx, da_p, ext);
+ new_ext = dict_attr_ext_alloc(da_p, ext);
if (!new_ext) return NULL;
new_ext->vendor = new_vendor;
*/
for (da = (*da_p)->parent; da; da = da->parent) {
if ((da->type == old_vendor->type) && (da->attr == old_vendor->attr)) {
- new_ext = dict_attr_ext_alloc(ctx, da_p, ext);
+ new_ext = dict_attr_ext_alloc(da_p, ext);
if (!new_ext) return NULL;
new_ext->vendor = da;
return NULL;
}
-/** Add a variable length extension to a dictionary attribute
- *
- * Extensions are appended to the existing #fr_dict_attr_t memory chunk
- * using realloc.
- *
- * When a new extension is allocated it will not be initialised.
- *
- * @param[in] ctx the dict attr was originally allocated in.
- * @param[in,out] da_p The dictionary attribute to add an extension for.
- * Under certain circumstances the value of *da_p will
- * be changed to point to a new memory block.
- * All cached copied of the previous pointer should be
- * updated. This means that attributes that have
- * already been added to a dictionary should not have
- * extensions allocated unless care is taken to update
- * all references.
- * @param[in] ext to alloc.
- * @param[in] ext_len The length of the extension.
- * @return
- * - NULL if we failed allocating an extension.
- * - A pointer to the extension we allocated.
- */
-void *dict_attr_ext_alloc_size(TALLOC_CTX *ctx, fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext, size_t ext_len)
-{
- size_t aligned_len = ROUND_UP_POW2(ext_len, FR_DICT_ATTR_EXT_ALIGNMENT);
- size_t da_len;
- size_t hdr_len = 0;
-
- size_t offset;
-
- fr_dict_attr_ext_info_t const *info;
- fr_dict_attr_t *n_da, *da = *da_p;
- uint8_t *ext_ptr;
-
- (void)talloc_get_type_abort(da, fr_dict_attr_t);
-
- if (da->ext[ext]) return fr_dict_attr_ext(da, ext);
-
- if (unlikely(da->dict && da->dict->read_only)) {
- fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root(da->dict)->name);
- return NULL;
- }
-
- info = &fr_dict_ext_info[ext];
- if (info->has_hdr) hdr_len = sizeof(dict_attr_ext_hdr_t); /* Add space for a length prefix */
-
- /*
- * Packing the offsets into a uint8_t means
- * the offset address of the final extension
- * must be less than or equal to
- * UINT8_MAX * FR_DICT_ATTR_EXT_ALIGNMENT
- */
- da_len = talloc_length(da);
- offset = (da_len + hdr_len) / FR_DICT_ATTR_EXT_ALIGNMENT;
- if (unlikely(offset > UINT8_MAX)) {
- fr_strerror_printf("Insufficient space remaining for extensions");
- return NULL;
- }
-
- n_da = talloc_realloc_size(ctx, da, da_len + hdr_len + aligned_len);
- if (!n_da) {
- fr_strerror_printf("Failed in realloc for dictionary extension '%s'. "
- "Tried to realloc %zu bytes -> %zu bytes",
- fr_table_str_by_value(dict_attr_ext_table, ext, "<INVALID>"),
- da_len, da_len + aligned_len);
- return NULL;
- }
- talloc_set_type(n_da, fr_dict_attr_t);
- *da_p = n_da;
-
- n_da->ext[ext] = (uint8_t)offset;
- ext_ptr = ((uint8_t *)n_da) + da_len;
-
- if (info->has_hdr) {
- dict_attr_ext_hdr_t *ext_hdr = (dict_attr_ext_hdr_t *)ext_ptr;
-
- ext_hdr->len = ext_len; /* Record the real size */
- return &ext_hdr->data; /* Pointer to the data portion */
- }
-
- return ext_ptr;
-}
-
-/** Add a fixed length extension to a dictionary attribute
- *
- * Extensions are appended to the existing #fr_dict_attr_t memory chunk
- * using realloc.
- *
- * When a new extension is allocated it will not be initialised.
- * In the majority of instances this is OK as its value will be set
- * immediately, but care should be taken to ensure it is initialised
- * as some point.
- *
- * @param[in] ctx the dict attr was originally allocated in.
- * @param[in,out] da_p The dictionary attribute to add an extension for.
- * Under certain circumstances the value of *da_p will
- * be changed to point to a new memory block.
- * All cached copied of the previous pointer should be
- * updated. This means that attributes that have
- * already been added to a dictionary should not have
- * extensions allocated unless care is taken to update
- * all references.
- * @param[in] ext to alloc.
- * @return
- * - NULL if we failed allocating an extension.
- * - A pointer to the extension we allocated.
- */
-void *dict_attr_ext_alloc(TALLOC_CTX *ctx, fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext)
-{
- return dict_attr_ext_alloc_size(ctx, da_p, ext, fr_dict_ext_info[ext].min);
-}
-
-/** Return the length of an extension
- *
- * @param[in] da to return extension length for.
- * @param[in] ext to return length for.
- * @return
- * - 0 if no extension exists.
- * - >0 the length of the extension.
- */
-size_t dict_attr_ext_len(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
-{
- uint8_t offset;
- fr_dict_attr_ext_info_t const *info;
- dict_attr_ext_hdr_t *ext_hdr;
-
- offset = da->ext[ext];
- if (!offset) return 0;
-
- info = &fr_dict_ext_info[ext];
- if (!info->has_hdr) return info->min; /* Fixed size */
-
- ext_hdr = (dict_attr_ext_hdr_t *)((uintptr_t)da) + ((offset * FR_DICT_ATTR_EXT_ALIGNMENT) - sizeof(dict_attr_ext_hdr_t));
- return ext_hdr->len;
-}
-
-/** Copy extension data from one attribute to another
+/** Holds additional information about extension structures
*
- * @param[in] ctx to realloc da_out in.
- * @param[in] da_in to copy extension from.
- * @param[in] ext to copy.
- * @return
- * - NULL if we failed to allocate an extension structure.
- * - A pointer to the offset of the extension in da_out.
*/
-void *dict_attr_ext_copy(TALLOC_CTX *ctx,
- fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in, fr_dict_attr_ext_t ext)
-{
- void *ext_ptr, *new_ext_ptr;
- size_t ext_len;
-
- fr_dict_attr_ext_info_t const *info;
-
- if (unlikely((*da_out_p)->dict && (*da_out_p)->dict->read_only)) {
- fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root((*da_out_p)->dict)->name);
- return NULL;
+fr_ext_t const fr_dict_attr_ext_def = {
+ .offset_of_exts = __offsetof(fr_dict_attr_t, ext),
+ .name_table = dict_attr_ext_table,
+ .name_table_len = &dict_attr_ext_table_len,
+ .max = FR_DICT_ATTR_EXT_MAX,
+ .info = {
+ [FR_DICT_ATTR_EXT_NAME] = {
+ .min = sizeof(char),
+ .has_hdr = true,
+ .can_copy = false, /* Name may change, and we can only set it once */
+ },
+ [FR_DICT_ATTR_EXT_CHILDREN] = {
+ .min = sizeof(fr_dict_attr_ext_children_t),
+ .can_copy = false, /* Limitation in hashing scheme we use */
+ },
+ [FR_DICT_ATTR_EXT_REF] = {
+ .min = sizeof(fr_dict_attr_ext_ref_t),
+ .can_copy = true,
+ },
+ [FR_DICT_ATTR_EXT_VENDOR] = {
+ .min = sizeof(fr_dict_attr_ext_vendor_t),
+ .can_copy = true,
+ .copy = fr_dict_attr_ext_vendor_copy
+ },
+ [FR_DICT_ATTR_EXT_ENUMV] = {
+ .min = sizeof(fr_dict_attr_ext_enumv_t),
+ .can_copy = true,
+ .copy = fr_dict_attr_ext_enumv_copy
+ },
+ [FR_DICT_ATTR_EXT_DA_STACK] = {
+ .min = sizeof(fr_dict_attr_ext_da_stack_t),
+ .has_hdr = true,
+ .can_copy = false /* Reinitialised for each new attribute */
+ },
+ [FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC] = {
+ .min = sizeof(fr_dict_ext_protocol_specific_t),
+ .can_copy = true
+ },
+ [FR_DICT_ATTR_EXT_MAX] = {}
}
+};
- info = &fr_dict_ext_info[ext];
- if (!info->can_copy) {
- fr_strerror_printf("Extension cannot be copied");
- return NULL;
- }
-
- ext_len = dict_attr_ext_len(da_in, ext);
- ext_ptr = fr_dict_attr_ext(da_in, ext);
- if (!ext_ptr) return NULL;
-
- /*
- * Use the special copy function.
- * Its responsible for allocating the extension in the
- * destination attribute.
- */
- if (info->copy) return info->copy(ctx, da_out_p, ext, ext_ptr, ext_len);
-
- /*
- * If there's no special function
- * just memcpy the data over.
- */
- new_ext_ptr = dict_attr_ext_alloc_size(ctx, da_out_p, ext, ext_len);
- if (!new_ext_ptr) return NULL;
- memcpy(new_ext_ptr, ext_ptr, ext_len);
-
- return new_ext_ptr;
-}
+static fr_table_num_ordered_t const dict_enum_ext_table[] = {
+ { L("union_ref"), FR_DICT_ENUM_EXT_UNION_REF }
+};
+static size_t dict_enum_ext_table_len = NUM_ELEMENTS(dict_enum_ext_table);
-/** Copy all the extensions from one attribute to another
+/** Holds additional information about extension structures
*
*/
-int dict_attr_ext_copy_all(TALLOC_CTX *ctx,
- fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in)
-{
- fr_dict_attr_ext_t i;
-
- for (i = 0; i < NUM_ELEMENTS(da_in->ext); i++) {
- if (!da_in->ext[i] || !fr_dict_ext_info[i].can_copy) continue;
- if (!dict_attr_ext_copy(ctx, da_out_p, da_in, i)) return -1;
+fr_ext_t const fr_dict_enum_ext_def = {
+ .offset_of_exts = __offsetof(fr_dict_enum_t, ext),
+ .name_table = dict_enum_ext_table,
+ .name_table_len = &dict_enum_ext_table_len,
+ .max = FR_DICT_ENUM_EXT_MAX,
+ .info = {
+ [FR_DICT_ENUM_EXT_UNION_REF] = {
+ .min = sizeof(fr_dict_enum_ext_union_ref_t),
+ .can_copy = true
+ },
+ [FR_DICT_ENUM_EXT_MAX] = {}
}
+};
- return 0;
-}
-
-void dict_attr_ext_debug(fr_dict_attr_t const *da)
-{
- fr_dict_attr_ext_t i;
-
- FR_FAULT_LOG("ext: %s - total len = %zu, ext len = %zu",
- da->name, talloc_length(da), talloc_length(da) - sizeof(fr_dict_attr_t));
-
- for (i = 0; i < NUM_ELEMENTS(da->ext); i++) {
- if (fr_dict_attr_has_ext(da, i)) {
- void *ext = fr_dict_attr_ext(da, i);
- size_t ext_len = dict_attr_ext_len(da, i);
-
- if (ext_len > 1024) {
- FR_FAULT_LOG("ext: %s - bad length %zu - limiting to 1024",
- fr_table_str_by_value(dict_attr_ext_table, i, "<INVALID>"),
- ext_len);
- ext_len = 1024;
- }
-
- FR_FAULT_LOG("ext: %s - start=%p end=%p len=%zu",
- fr_table_str_by_value(dict_attr_ext_table, i, "<INVALID>"),
- ext, ((uint8_t *)ext) + ext_len, ext_len);
- FR_FAULT_LOG_HEX(ext, ext_len);
- }
- }
-}
--- /dev/null
+#pragma once
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Multi-protocol AVP dictionary API
+ *
+ * @file src/lib/util/dict_ext.h
+ *
+ * @copyright 2020 The FreeRADIUS server project
+ * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSIDH(dict_ext_h, "$Id$")
+
+#include <freeradius-devel/util/dict.h>
+#include <freeradius-devel/util/ext.h>
+
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Attribute extension - Holds children for an attribute
+ *
+ * Children are possible for:
+ *
+ * #FR_TYPE_TLV, #FR_TYPE_VENDOR, #FR_TYPE_VSA, #FR_TYPE_STRUCT
+ *
+ * *or* where the parent->parent->type is
+ * #FR_TYPE_STRUCT, and "parent" is a "key"
+ * field. Note that these attributes therefore
+ * cannot have VALUEs, as the child defines their
+ * VALUE. See dict_attr_can_have_children() for details.
+ */
+typedef struct {
+ fr_hash_table_t *child_by_name; //!< Namespace at this level in the hierarchy.
+ fr_dict_attr_t const **children; //!< Children of this attribute.
+} fr_dict_attr_ext_children_t;
+
+/** Attribute extension - Holds a reference to an attribute in another dictionary
+ *
+ */
+typedef struct {
+ fr_dict_attr_t const *ref; //!< reference, only for #FR_TYPE_GROUP
+} fr_dict_attr_ext_ref_t;
+
+/** Attribute extension - Cached vendor pointer
+ *
+ */
+typedef struct {
+ fr_dict_attr_t const *vendor; //!< ancestor which has type #FR_TYPE_VENDOR
+} fr_dict_attr_ext_vendor_t;
+
+/** Attribute extension - Stack of dictionary attributes that describe the path back to the root of the dictionary
+ *
+ */
+typedef struct {
+ fr_dict_attr_t const *da_stack[0]; //!< Stack of dictionary attributes
+} fr_dict_attr_ext_da_stack_t;
+
+/** Attribute extension - Holds enumeration values
+ *
+ */
+typedef struct {
+ fr_hash_table_t *value_by_name; //!< Lookup an enumeration value by name
+ fr_hash_table_t *name_by_value; //!< Lookup a name by value
+} fr_dict_attr_ext_enumv_t;
+
+/** Enum extension - Sub-struct or union pointer
+ *
+ */
+typedef struct {
+ fr_dict_attr_t const *union_ref; //!< The union da this value points into.
+} fr_dict_enum_ext_union_ref_t;
+
+/** Attribute extension - Protocol-specific
+ *
+ */
+typedef struct {
+ void *uctx; //!< Protocol specific extensions
+} fr_dict_ext_protocol_specific_t;
+
+/** @name Add extension structures to attributes
+ *
+ * @{
+ */
+
+/* Retrieve an extension structure for a dictionary attribute
+ *
+ * @param[in] da to retrieve structure from.
+ * @param[in] ext to retrieve.
+ * @return
+ * - NULL if the extension wasn't found.
+ * - A pointer to the start of the extension.
+ */
+static inline void *fr_dict_attr_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
+{
+ if (!da->ext[ext]) return NULL;
+
+ return FR_EXT_PTR(da, ext, ext);
+}
+
+/** Return whether a da has a given extension or not
+ *
+ * @param[in] da to check for extensions.
+ * @param[in] ext to check.
+ * @return
+ * - true if the da has the specified extension.
+ * - false if the da does not have the specified extension
+ */
+static inline bool fr_dict_attr_has_ext(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
+{
+ return (da->ext[ext] > 0);
+}
+
+/** Return the cached da stack (if any) associated with an attribute
+ *
+ * @param[in] da to return cached da stack for.
+ * @return
+ * - NULL if no da stack available.
+ * - The cached da stack on success.
+ */
+static inline fr_dict_attr_t const **fr_dict_attr_da_stack(fr_dict_attr_t const *da)
+{
+ fr_dict_attr_ext_da_stack_t *ext;
+
+ ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_DA_STACK);
+ if (!ext) return NULL;
+
+ return ext->da_stack;
+}
+
+/** Return the reference associated with a group type attribute
+ *
+ * @param[in] da to return the reference for.
+ * @return
+ * - NULL if no reference available.
+ * - A pointer to the attribute being referenced.
+ */
+static inline fr_dict_attr_t const *fr_dict_attr_ref(fr_dict_attr_t const *da)
+{
+ fr_dict_attr_ext_ref_t *ext;
+
+ ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_REF);
+ if (!ext) return NULL;
+
+ return ext->ref;
+}
+
+/** Return the vendor number for an attribute
+ *
+ * @param[in] da The dictionary attribute to find the
+ * vendor for.
+ * @return
+ * - 0 this isn't a vendor specific attribute.
+ * - The vendor PEN.
+ */
+static inline uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
+{
+ fr_dict_attr_ext_vendor_t *ext;
+
+ if (da->type == FR_TYPE_VENDOR) return da->attr;
+
+ ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_VENDOR);
+ if (!ext || !ext->vendor) return 0;
+
+ return ext->vendor->attr;
+}
+
+/** Return the vendor da for an attribute
+ *
+ * @param[in] da The dictionary attribute to find the
+ * vendor for.
+ * @return
+ * - 0 this isn't a vendor specific attribute.
+ * - The vendor PEN.
+ */
+static inline fr_dict_attr_t const *fr_dict_vendor_da_by_da(fr_dict_attr_t const *da)
+{
+ fr_dict_attr_ext_vendor_t *ext;
+
+ if (da->type == FR_TYPE_VENDOR) return da;
+
+ ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_VENDOR);
+ if (!ext) return NULL;
+
+ return ext->vendor;
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+#pragma once
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Extensions for dictionary definitions
+ *
+ * @file src/lib/util/dict_ext_priv.h
+ *
+ * @copyright 2020 The FreeRADIUS server project
+ * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSIDH(dict_ext_priv_h, "$Id$")
+
+#include <freeradius-devel/util/dict.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern fr_ext_t const fr_dict_attr_ext_def;
+extern fr_ext_t const fr_dict_enum_ext_def;
+
+/** @name Add extension structures to attributes
+ *
+ * @{
+ */
+
+/** Allocate an attribute extension of a particular size
+ *
+ */
+static inline void *dict_attr_ext_alloc_size(fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext, size_t ext_len)
+{
+ if (unlikely((*da_p)->dict && fr_dict_is_read_only((*da_p)->dict))) {
+ fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root((*da_p)->dict)->name);
+ return NULL;
+ }
+
+ return fr_ext_alloc_size(&fr_dict_attr_ext_def, (void **)da_p, ext, ext_len);
+}
+
+/** Allocate an attribute extension
+ *
+ */
+static inline void *dict_attr_ext_alloc(fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext)
+{
+ if (unlikely((*da_p)->dict && fr_dict_is_read_only((*da_p)->dict))) {
+ fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root((*da_p)->dict)->name);
+ return NULL;
+ }
+
+ return fr_ext_alloc_size(&fr_dict_attr_ext_def, (void **)da_p, ext, fr_dict_attr_ext_def.info[ext].min);
+}
+
+/** Return the length of an attribute extension
+ *
+ */
+static inline size_t dict_attr_ext_len(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext)
+{
+ return fr_ext_len(&fr_dict_attr_ext_def, (void const *)da, ext);
+}
+
+/** Copy a single attribute extension from one attribute to another
+ *
+ */
+static inline void *dict_attr_ext_copy(fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in, fr_dict_attr_ext_t ext)
+{
+ if (unlikely((*da_out_p)->dict && fr_dict_is_read_only((*da_out_p)->dict))) {
+ fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root((*da_out_p)->dict)->name);
+ return NULL;
+ }
+
+ return fr_ext_copy(&fr_dict_attr_ext_def, (void **)da_out_p, (void const *)da_in, ext);
+}
+
+/** Copy all attribute extensions from one attribute to another
+ *
+ */
+static inline int dict_attr_ext_copy_all(fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in)
+{
+ if (unlikely((*da_out_p)->dict && fr_dict_is_read_only((*da_out_p)->dict))) {
+ fr_strerror_printf("%s dictionary has been marked as read only", fr_dict_root((*da_out_p)->dict)->name);
+ return -1;
+ }
+
+ return fr_ext_copy_all(&fr_dict_attr_ext_def, (void **)da_out_p, (void const *)da_in);
+}
+
+/** Print extension debug information for attributes
+ *
+ */
+static inline void dict_attr_ext_debug(fr_dict_attr_t const *da)
+{
+ fr_ext_debug(&fr_dict_attr_ext_def, da->name, da);
+}
+/** @} */
+
+/** @name Convenience functions for populating attribute extensions
+ *
+ * @{
+ */
+static inline int dict_attr_ref_set(fr_dict_attr_t const *da, fr_dict_attr_t const *ref)
+{
+ fr_dict_attr_ext_ref_t *ext;
+
+ ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_REF);
+ if (unlikely(!ext)) {
+ fr_strerror_printf("%s (%s) contains no 'ref' extension", da->name,
+ fr_table_str_by_value(fr_value_box_type_table, da->type, "<UNKNOWN>"));
+ return -1;
+ }
+ ext->ref = ref;
+
+ return 0;
+}
+
+static inline int dict_attr_children_set(fr_dict_attr_t const *da, fr_dict_attr_t const **children)
+{
+ fr_dict_attr_ext_children_t *ext;
+
+ ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_CHILDREN);
+ if (unlikely(!ext)) {
+ fr_strerror_printf("%s (%s) contains no 'children' extension", da->name,
+ fr_table_str_by_value(fr_value_box_type_table, da->type, "<UNKNOWN>"));
+ return -1;
+ }
+ ext->children = children;
+
+ return 0;
+}
+
+static inline fr_dict_attr_t const **dict_attr_children(fr_dict_attr_t const *da)
+{
+ fr_dict_attr_ext_children_t *ext;
+
+ ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_CHILDREN);
+ if (unlikely(!ext)) {
+ fr_strerror_printf("%s (%s) contains no 'children' extension", da->name,
+ fr_table_str_by_value(fr_value_box_type_table, da->type, "<UNKNOWN>"));
+ return NULL;
+ }
+ return ext->children;
+}
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
#define _DICT_PRIVATE 1
+#include <freeradius-devel/protocol/base.h>
#include <freeradius-devel/util/dict.h>
-#include <freeradius-devel/util/hash.h>
+#include <freeradius-devel/util/dict_ext_priv.h>
#include <freeradius-devel/util/dl.h>
-#include <freeradius-devel/protocol/base.h>
+#include <freeradius-devel/util/hash.h>
#define DICT_POOL_SIZE (1024 * 1024 * 2)
#define DICT_FIXUP_POOL_SIZE (1024)
fr_dict_attr_t *dict_attr_alloc_null(TALLOC_CTX *ctx);
-int dict_attr_init(TALLOC_CTX *ctx, fr_dict_attr_t **da_p,
+int dict_attr_init(fr_dict_attr_t **da_p,
fr_dict_attr_t const *parent,
char const *name, int attr,
fr_type_t type, fr_dict_attr_flags_t const *flags);
fr_dict_attr_t *dict_attr_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *in, char const *new_name);
-/** @name Add extension structures to attributes
- *
- * @{
- */
-void *dict_attr_ext_alloc_size(TALLOC_CTX *ctx, fr_dict_attr_t **da_p,
- fr_dict_attr_ext_t ext, size_t ext_len);
-
-void *dict_attr_ext_alloc(TALLOC_CTX *ctx, fr_dict_attr_t **da_p, fr_dict_attr_ext_t ext);
-
-size_t dict_attr_ext_len(fr_dict_attr_t const *da, fr_dict_attr_ext_t ext);
-
-void *dict_attr_ext_copy(TALLOC_CTX *ctx,
- fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in,
- fr_dict_attr_ext_t ext);
-
-int dict_attr_ext_copy_all(TALLOC_CTX *ctx,
- fr_dict_attr_t **da_out_p, fr_dict_attr_t const *da_in);
-
-void dict_attr_ext_debug(fr_dict_attr_t const *da);
-
-static inline int dict_attr_ref_set(fr_dict_attr_t const *da, fr_dict_attr_t const *ref)
-{
- fr_dict_attr_ext_ref_t *ext;
-
- ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_REF);
- if (unlikely(!ext)) {
- fr_strerror_printf("%s (%s) contains no 'ref' extension", da->name,
- fr_table_str_by_value(fr_value_box_type_table, da->type, "<UNKNOWN>"));
- return -1;
- }
- ext->ref = ref;
-
- return 0;
-}
-
-static inline int dict_attr_children_set(fr_dict_attr_t const *da, fr_dict_attr_t const **children)
-{
- fr_dict_attr_ext_children_t *ext;
-
- ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_CHILDREN);
- if (unlikely(!ext)) {
- fr_strerror_printf("%s (%s) contains no 'children' extension", da->name,
- fr_table_str_by_value(fr_value_box_type_table, da->type, "<UNKNOWN>"));
- return -1;
- }
- ext->children = children;
-
- return 0;
-}
-
-static inline fr_dict_attr_t const **dict_attr_children(fr_dict_attr_t const *da)
-{
- fr_dict_attr_ext_children_t *ext;
-
- ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_CHILDREN);
- if (unlikely(!ext)) {
- fr_strerror_printf("%s (%s) contains no 'children' extension", da->name,
- fr_table_str_by_value(fr_value_box_type_table, da->type, "<UNKNOWN>"));
- return NULL;
- }
- return ext->children;
-}
-/** @} */
-
int dict_attr_child_add(fr_dict_attr_t *parent, fr_dict_attr_t *child);
int dict_protocol_add(fr_dict_t *dict);
/*
* Initialize the rest of the fields.
*/
- dict_attr_init(ctx, &n, parent, new_name ? new_name : da->name, da->attr, type, &flags);
- dict_attr_ext_copy_all(ctx, &n, da);
+ dict_attr_init(&n, parent, new_name ? new_name : da->name, da->attr, type, &flags);
+ dict_attr_ext_copy_all(&n, da);
DA_VERIFY(n);
return n;
* Leaf attribute
*/
case '\0':
- dict_attr_init(ctx, &n, our_parent, oid_str, num, FR_TYPE_OCTETS, &flags);
+ dict_attr_init(&n, our_parent, oid_str, num, FR_TYPE_OCTETS, &flags);
break;
}
p++;
*
* @note This function can only be used _before_ the attribute is inserted into the dictionary.
*
- * @param[in] ctx to realloc attribute in.
* @param[in] da_p to set name for.
* @param[in] name to set. If NULL a name will be automatically generated.
*/
-static inline CC_HINT(always_inline) int dict_attr_name_set(TALLOC_CTX *ctx, fr_dict_attr_t **da_p, char const *name)
+static inline CC_HINT(always_inline) int dict_attr_name_set(fr_dict_attr_t **da_p, char const *name)
{
char buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1];
size_t name_len;
* We do still need to fixup the da->name pointer
* though.
*/
- name_start = dict_attr_ext_alloc_size(ctx, da_p, FR_DICT_ATTR_EXT_NAME, name_len + 1);
+ name_start = dict_attr_ext_alloc_size(da_p, FR_DICT_ATTR_EXT_NAME, name_len + 1);
if (!name_start) return -1;
name_end = name_start + name_len;
*
* @note This function can only be used _before_ the attribute is inserted into the dictionary.
*
- * @param[in] ctx to realloc attribute in.
* @param[in] da_p to set a group reference for.
*/
-static inline CC_HINT(always_inline) int dict_attr_children_init(TALLOC_CTX *ctx, fr_dict_attr_t **da_p)
+static inline CC_HINT(always_inline) int dict_attr_children_init(fr_dict_attr_t **da_p)
{
fr_dict_attr_ext_children_t *ext;
- ext = dict_attr_ext_alloc(ctx, da_p, FR_DICT_ATTR_EXT_CHILDREN);
+ ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_CHILDREN);
if (unlikely(!ext)) return -1;
memset(ext, 0, sizeof(*ext));
*
* @note This function can only be used _before_ the attribute is inserted into the dictionary.
*
- * @param[in] ctx to realloc attribute in.
* @param[in] da_p to set a group reference for.
*/
-static inline CC_HINT(always_inline) int dict_attr_ref_init(TALLOC_CTX *ctx, fr_dict_attr_t **da_p)
+static inline CC_HINT(always_inline) int dict_attr_ref_init(fr_dict_attr_t **da_p)
{
fr_dict_attr_ext_ref_t *ext;
- ext = dict_attr_ext_alloc(ctx, da_p, FR_DICT_ATTR_EXT_REF);
+ ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_REF);
if (unlikely(!ext)) return -1;
memset(ext, 0, sizeof(*ext));
*
* @note This function can only be used _before_ the attribute is inserted into the dictionary.
*
- * @param[in] ctx to realloc attribute in.
* @param[in] da_p to set a group reference for.
* @param[in] vendor to set.
*/
-static inline CC_HINT(always_inline) int dict_attr_vendor_set(TALLOC_CTX *ctx,
- fr_dict_attr_t **da_p, fr_dict_attr_t const *vendor)
+static inline CC_HINT(always_inline) int dict_attr_vendor_set(fr_dict_attr_t **da_p, fr_dict_attr_t const *vendor)
{
fr_dict_attr_ext_vendor_t *ext;
- ext = dict_attr_ext_alloc(ctx, da_p, FR_DICT_ATTR_EXT_VENDOR);
+ ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_VENDOR);
if (unlikely(!ext)) return -1;
ext->vendor = vendor;
*
* @note This function can only be used _before_ the attribute is inserted into the dictionary.
*
- * @param[in] ctx to realloc attribute in.
* @param[in] da_p to populate the da_stack for.
*/
-static inline CC_HINT(always_inline) int dict_attr_da_stack_set(TALLOC_CTX *ctx, fr_dict_attr_t **da_p)
+static inline CC_HINT(always_inline) int dict_attr_da_stack_set(fr_dict_attr_t **da_p)
{
fr_dict_attr_ext_da_stack_t *ext, *p_ext;
fr_dict_attr_t *da = *da_p;
p_ext = fr_dict_attr_ext(parent, FR_DICT_ATTR_EXT_DA_STACK);
if (!p_ext) return 1;
- ext = dict_attr_ext_alloc_size(ctx, da_p, FR_DICT_ATTR_EXT_DA_STACK, sizeof(ext->da_stack[0]) * (da->depth + 1));
+ ext = dict_attr_ext_alloc_size(da_p, FR_DICT_ATTR_EXT_DA_STACK, sizeof(ext->da_stack[0]) * (da->depth + 1));
if (unlikely(!ext)) return -1;
memcpy(ext->da_stack, p_ext->da_stack, sizeof(ext->da_stack[0]) * parent->depth);
*
* @note This function can only be used _before_ the attribute is inserted into the dictionary.
*
- * @param[in] ctx to realloc attribute in.
* @param[in] da_p to set a group reference for.
*/
-static inline CC_HINT(always_inline) int dict_attr_enumv_init(TALLOC_CTX *ctx, fr_dict_attr_t **da_p)
+static inline CC_HINT(always_inline) int dict_attr_enumv_init(fr_dict_attr_t **da_p)
{
fr_dict_attr_ext_enumv_t *ext;
- ext = dict_attr_ext_alloc(ctx, da_p, FR_DICT_ATTR_EXT_ENUMV);
+ ext = dict_attr_ext_alloc(da_p, FR_DICT_ATTR_EXT_ENUMV);
if (unlikely(!ext)) return -1;
memset(ext, 0, sizeof(*ext));
*
* @note This function can only be used _before_ the attribute is inserted into the dictionary.
*
- * @param[in] ctx To use if we need to re-alloc the da
* @param[in] da_p to initialise.
* @param[in] parent of the attribute, if none, should be
* the dictionary root.
* @param[in] type of the attribute.
* @param[in] flags to assign.
*/
-int dict_attr_init(TALLOC_CTX *ctx, fr_dict_attr_t **da_p,
+int dict_attr_init(fr_dict_attr_t **da_p,
fr_dict_attr_t const *parent,
char const *name, int attr,
fr_type_t type, fr_dict_attr_flags_t const *flags)
* attributes are VSAs, caching this pointer will help.
*/
if (parent->type == FR_TYPE_VENDOR) {
- if (dict_attr_vendor_set(ctx, da_p, parent) < 0) return -1;
+ if (dict_attr_vendor_set(da_p, parent) < 0) return -1;
} else {
- dict_attr_ext_copy(ctx, da_p, parent, FR_DICT_ATTR_EXT_VENDOR); /* Noop if no vendor extension */
+ dict_attr_ext_copy(da_p, parent, FR_DICT_ATTR_EXT_VENDOR); /* Noop if no vendor extension */
}
} else {
(*da_p)->depth = 0;
* Cache the da_stack so we don't need
* to generate it at runtime.
*/
- dict_attr_da_stack_set(ctx, da_p);
+ dict_attr_da_stack_set(da_p);
/*
* Structural types can have children
case FR_TYPE_STRUCTURAL:
structural:
if (type == FR_TYPE_GROUP) {
- if (dict_attr_ref_init(ctx, da_p) < 0) return -1;
+ if (dict_attr_ref_init(da_p) < 0) return -1;
break;
}
if (type == FR_TYPE_TLV) {
- if (dict_attr_ref_init(ctx, da_p) < 0) return -1;
+ if (dict_attr_ref_init(da_p) < 0) return -1;
}
- if (dict_attr_children_init(ctx, da_p) < 0) return -1;
+ if (dict_attr_children_init(da_p) < 0) return -1;
break;
/*
*/
case FR_TYPE_UINT8: /* Hopefully temporary until unions are done properly */
case FR_TYPE_UINT16: /* Same here */
- if (dict_attr_enumv_init(ctx, da_p) < 0) return -1;
+ if (dict_attr_enumv_init(da_p) < 0) return -1;
goto structural;
/*
* Leaf types
*/
default:
- if (dict_attr_enumv_init(ctx, da_p) < 0) return -1;
+ if (dict_attr_enumv_init(da_p) < 0) return -1;
break;
}
* Name is a separate talloc chunk. We allocate
* it last because we cache the pointer value.
*/
- if (dict_attr_name_set(ctx, da_p, name) < 0) return -1;
+ if (dict_attr_name_set(da_p, name) < 0) return -1;
DA_VERIFY(*da_p);
n = dict_attr_alloc_null(ctx);
if (unlikely(!n)) return NULL;
- if (dict_attr_init(ctx, &n, parent, name, attr, type, flags) < 0) {
+ if (dict_attr_init(&n, parent, name, attr, type, flags) < 0) {
talloc_free(n);
return NULL;
}
n = dict_attr_alloc(ctx, in->parent, new_name ? new_name : in->name, in->attr, in->type, &in->flags);
if (unlikely(!n)) return NULL;
- if (dict_attr_ext_copy_all(ctx, &n, in) < 0) {
+ if (dict_attr_ext_copy_all(&n, in) < 0) {
talloc_free(n);
return NULL;
}
return dict->root;
}
+bool fr_dict_is_read_only(fr_dict_t const *dict)
+{
+ return dict->read_only;
+}
+
ssize_t dict_by_protocol_substr(fr_dict_attr_err_t *err,
fr_dict_t **out, fr_sbuff_t *name, fr_dict_t const *dict_def)
{
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Extensions to talloced structures
+ *
+ * @file src/lib/util/ext.c
+ *
+ * @copyright 2020 The FreeRADIUS server project
+ * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/ext.h>
+#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/table.h>
+#include <freeradius-devel/util/talloc.h>
+
+#define CHUNK_EXT_PTR(_chunk, _chunk_ext, _ext) ((void *)((chunk_ext[_ext] * FR_EXT_ALIGNMENT) + ((uintptr_t)(_chunk))))
+#define CHUNK_EXT(_chunk, _offset) ((uint8_t *)(((uintptr_t)_chunk) + (_offset)))
+
+/** Add a variable length extension to a dictionary attribute
+ *
+ * Extensions are appended to the existing #fr_dict_attr_t memory chunk
+ * using realloc.
+ *
+ * When a new extension is allocated it will not be initialised.
+ *
+ * @param[in] def Extension definitions.
+ * @param[in,out] chunk_p The chunk to add an extension for.
+ * Under certain circumstances the value of *chunk_p will
+ * be changed to point to a new memory block.
+ * All cached copied of the previous pointer should be
+ * updated. This means that attributes that have
+ * already been added to a dictionary should not have
+ * extensions allocated unless care is taken to update
+ * all references.
+ * @param[in] ext to alloc.
+ * @param[in] ext_len The length of the extension.
+ * @return
+ * - NULL if we failed allocating an extension.
+ * - A pointer to the extension we allocated.
+ */
+void *fr_ext_alloc_size(fr_ext_t const *def, void **chunk_p, int ext, size_t ext_len)
+{
+ size_t aligned_len = ROUND_UP_POW2(ext_len, FR_EXT_ALIGNMENT);
+ size_t chunk_len;
+ size_t hdr_len = 0;
+
+ size_t offset;
+
+ fr_ext_info_t const *info;
+ void *n_chunk, *chunk = *chunk_p;
+ uint8_t *chunk_ext;
+ uint8_t *ext_ptr;
+ char const *type;
+
+ chunk_ext = CHUNK_EXT(*chunk_p, def->offset_of_exts);
+ if (chunk_ext[ext]) return CHUNK_EXT_PTR(*chunk_p, chunk_ext, ext);
+
+ info = &def->info[ext];
+ if (info->has_hdr) hdr_len = sizeof(dict_ext_hdr_t); /* Add space for a length prefix */
+
+ /*
+ * Packing the offsets into a uint8_t means
+ * the offset address of the final extension
+ * must be less than or equal to
+ * UINT8_MAX * FR_EXT_ALIGNMENT
+ */
+ chunk_len = talloc_get_size(chunk);
+ offset = (chunk_len + hdr_len) / FR_EXT_ALIGNMENT;
+ if (unlikely(offset > UINT8_MAX)) {
+ fr_strerror_printf("Insufficient space remaining for extensions");
+ return NULL;
+ }
+
+ type = talloc_get_name(chunk);
+ n_chunk = talloc_realloc_size(NULL, chunk, chunk_len + hdr_len + aligned_len);
+ if (!n_chunk) {
+ fr_strerror_printf("Failed reallocing %s. Tried to realloc %zu bytes -> %zu bytes",
+ type, chunk_len, chunk_len + aligned_len);
+ return NULL;
+ }
+ talloc_set_name_const(n_chunk, type);
+ *chunk_p = n_chunk;
+
+ chunk_ext = CHUNK_EXT(*chunk_p, def->offset_of_exts);
+ chunk_ext[ext] = (uint8_t)offset;
+
+ ext_ptr = ((uint8_t *)n_chunk) + chunk_len;
+
+ if (info->has_hdr) {
+ dict_ext_hdr_t *ext_hdr = (dict_ext_hdr_t *)ext_ptr;
+
+ ext_hdr->len = ext_len; /* Record the real size */
+ return &ext_hdr->data; /* Pointer to the data portion */
+ }
+
+ return ext_ptr;
+}
+
+/** Return the length of an extension
+ *
+ * @param[in] def Extension definitions.
+ * @param[in] chunk to return extension length for.
+ * @param[in] ext to return length for.
+ * @return
+ * - 0 if no extension exists.
+ * - >0 the length of the extension.
+ */
+size_t fr_ext_len(fr_ext_t const *def, void const *chunk, int ext)
+{
+ uint8_t offset;
+ fr_ext_info_t const *info;
+ dict_ext_hdr_t *ext_hdr;
+ uint8_t *chunk_ext;
+
+ chunk_ext = CHUNK_EXT(chunk, def->offset_of_exts);
+ offset = chunk_ext[ext];
+ if (!offset) return 0;
+
+ info = &def->info[ext];
+ if (!info->has_hdr) return info->min; /* Fixed size */
+
+ ext_hdr = (dict_ext_hdr_t *)((uintptr_t)chunk) + ((offset * FR_EXT_ALIGNMENT) - sizeof(dict_ext_hdr_t));
+ return ext_hdr->len;
+}
+
+/** Copy extension data from one attribute to another
+ *
+ * @param[in] def Extension definitions.
+ * @param[in,out] chunk_out to copy extension to.
+ * @param[in] chunk_in to copy extension from.
+ * @param[in] ext to copy.
+ * @return
+ * - NULL if we failed to allocate an extension structure.
+ * - A pointer to the offset of the extension in da_out.
+ */
+void *fr_ext_copy(fr_ext_t const *def, void **chunk_out, void const *chunk_in, int ext)
+{
+ void *ext_ptr, *new_ext_ptr;
+ uint8_t *chunk_ext;
+ size_t ext_len;
+
+ fr_ext_info_t const *info;
+
+ info = &def->info[ext];
+ if (!info->can_copy) {
+ fr_strerror_printf("Extension cannot be copied");
+ return NULL;
+ }
+
+ chunk_ext = CHUNK_EXT(chunk_in, def->offset_of_exts);
+ ext_ptr = CHUNK_EXT_PTR(chunk_in, chunk_ext, ext);
+ if (!ext_ptr) return NULL;
+
+ ext_len = fr_ext_len(def, chunk_in, ext);
+
+ /*
+ * Use the special copy function.
+ * Its responsible for allocating the extension in the
+ * destination attribute.
+ */
+ if (info->copy) return info->copy(chunk_out, ext, ext_ptr, ext_len);
+
+ /*
+ * If there's no special function
+ * just memcpy the data over.
+ */
+ new_ext_ptr = fr_ext_alloc_size(def, chunk_out, ext, ext_len);
+ if (!new_ext_ptr) return NULL;
+ memcpy(new_ext_ptr, ext_ptr, ext_len);
+
+ return new_ext_ptr;
+}
+
+/** Copy all the extensions from one attribute to another
+ *
+ */
+int fr_ext_copy_all(fr_ext_t const *def, void **chunk_out, void const *chunk_in)
+{
+ int i;
+ uint8_t *ext_in = CHUNK_EXT(chunk_in, def->offset_of_exts);
+
+ for (i = 0; i < def->max; i++) {
+ if (!ext_in[i] || !def->info[i].can_copy) continue;
+ if (!fr_ext_copy(def, chunk_out, chunk_in, i)) return -1;
+ }
+
+ return 0;
+}
+
+void fr_ext_debug(fr_ext_t const *def, char const *name, void const *chunk)
+{
+ int i;
+
+ FR_FAULT_LOG("ext: %s - total len = %zu", name, talloc_get_size(chunk));
+ for (i = 0; i < (int)def->max; i++) {
+ uint8_t *chunk_ext = CHUNK_EXT(def->info, def->offset_of_exts);
+ if (chunk_ext[i]) {
+ void *ext = CHUNK_EXT_PTR(chunk, chunk_ext, i);
+ size_t ext_len = fr_ext_len(def, chunk, i);
+
+ char const *ext_name = fr_table_ordered_str_by_num(def->name_table,
+ *def->name_table_len,
+ i, "<INVALID>");
+
+ if (ext_len > 1024) {
+ FR_FAULT_LOG("ext: %s - possibly bad length %zu - limiting dump to 1024",
+ ext_name, ext_len);
+ ext_len = 1024;
+ }
+
+ FR_FAULT_LOG("ext: %s - start=%p end=%p len=%zu",
+ ext_name, ext, ((uint8_t *)ext) + ext_len, ext_len);
+ FR_FAULT_LOG_HEX(ext, ext_len);
+ }
+ }
+}
--- /dev/null
+#pragma once
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Extensions to talloced structures
+ *
+ * These allow multiple variable length chunks to be appended to talloced
+ * structures. Extensions can either contain a header in which case the
+ * exact length is recorded, or they can be of a fixed size.
+ *
+ * The structure being extended must be padded to a multiple of FR_EXT_ALIGNMENT.
+ *
+ * It is strongly recommended that extended structures are allocated in a
+ * talloc_pool() to avoid the overhead of multiple reallocs.
+ *
+ * @file src/lib/util/ext.h
+ *
+ * @copyright 2020 The FreeRADIUS server project
+ * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSIDH(ext_h, "$Id$")
+
+#include <freeradius-devel/util/table.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** The alignment of object extension structures
+ *
+ */
+#ifdef __WORD_SIZE
+# if __WORD_SIZE < 4
+# define FR_EXT_ALIGNMENT sizeof(uint32_t)
+# else
+# define FR_EXT_ALIGNMENT __WORD_SIZE /* From limits.h */
+# endif
+#else
+# define FR_EXT_ALIGNMENT sizeof(uint64_t)
+#endif
+
+/** Function for fixing up extensions after they're copied
+ *
+ */
+typedef void *(* fr_ext_copy_t)(void **chunk_p, int ext, void *ext_ptr, size_t ext_len);
+
+/** Additional information for a given extension
+ */
+typedef struct {
+ size_t min; //!< Minimum size of extension.
+ bool has_hdr; //!< Has additional metadata allocated before
+ ///< the extension data.
+ bool can_copy; //!< Copying this extension between attributes is allowed.
+ fr_ext_copy_t copy; //!< Override the normal copy operation with a callback.
+} fr_ext_info_t;
+
+/** Structure to define a set of extensions
+ *
+ */
+typedef struct {
+ size_t offset_of_exts; //!< Where in the extended struct the extensions array starts.
+ fr_table_num_ordered_t const *name_table; //!< String identifiers for the extensions.
+ size_t *name_table_len; //!< How many extensions there are in the table.
+ int max; //!< The highest extension value.
+ fr_ext_info_t const info[]; //!< Additional information about each extension.
+} fr_ext_t;
+
+/** Optional extension header struct
+ *
+ */
+typedef struct {
+ size_t len; //!< Length of extension data.
+ uint8_t data[]; //!< Extension data
+} CC_HINT(aligned(FR_EXT_ALIGNMENT)) dict_ext_hdr_t;
+
+/** @name Generic extension manipulation functions that can be used with any talloced chunk
+ *
+ * @{
+ */
+
+/** Return a pointer to the specified extension structure
+ *
+ * @param[in] _ptr to fetch extension for.
+ * @param[in] _field Array of extensions.
+ * @param[in] _ext to retrieve.
+ */
+#define FR_EXT_PTR(_ptr, _field, _ext) ((void *)(((_ptr)->_field[_ext] * FR_EXT_ALIGNMENT) + ((uintptr_t)(_ptr))))
+
+void *fr_ext_alloc_size(fr_ext_t const *def, void **chunk_p, int ext, size_t ext_len);
+
+size_t fr_ext_len(fr_ext_t const *def, void const *chunk_in, int ext);
+
+void *fr_ext_copy(fr_ext_t const *def, void **chunk_out, void const *chunk_in, int ext);
+
+int fr_ext_copy_all(fr_ext_t const *def, void **chunk_out, void const *chunk_in);
+
+void fr_ext_debug(fr_ext_t const *def, char const *name, void const *chunk);
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
dl.c \
dns.c \
event.c \
+ ext.c \
fifo.c \
file.c \
fopencookie.c \
(_p < _end) && (_iter = *((void **)(_p))); \
_p = (__typeof__(_p))((__typeof__(_array))_p) + 1)
-/** Get the number of bytes in a given talloc chunk
- *
- */
-#define talloc_length(_ptr) talloc_array_length((uint8_t const *)(_ptr))
-
typedef int(* fr_talloc_free_func_t)(void *fire_ctx, void *uctx);
typedef struct fr_talloc_destructor_s fr_talloc_destructor_t;