]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add mechanism for adding type specific dictionary extensions
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 13 Oct 2020 22:25:23 +0000 (17:25 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 13 Oct 2020 22:32:11 +0000 (17:32 -0500)
13 files changed:
src/lib/server/tmpl_tokenize.c
src/lib/unlang/xlat_builtin.c
src/lib/util/dbuff.c
src/lib/util/dict.h
src/lib/util/dict_ext.c [new file with mode: 0644]
src/lib/util/dict_priv.h
src/lib/util/dict_tokenize.c
src/lib/util/dict_unknown.c
src/lib/util/dict_util.c
src/lib/util/libfreeradius-util.mk
src/lib/util/pair.c
src/lib/util/proto.c
src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c

index 915f6d2270030392b67585514cebf18ee92e1446..9d40f577349cb90de401f568a30e88e22cab9fdf 100644 (file)
@@ -1570,7 +1570,7 @@ do_suffix:
                 *      group ref.
                 */
                case FR_TYPE_GROUP:
-                       parent = da->ref;
+                       parent = fr_dict_attr_ref(da);
                        break;
 
                case FR_TYPE_STRUCT:
index 4627b40cc1efe33ae829d2ae1b9cfe0ce64b2083..0c94835e95f83b8ffb68d1c94dd37d4ee1ff2e32 100644 (file)
@@ -259,6 +259,11 @@ static void _xlat_func_tree_free(void *xlat)
 
 
 /** Register an old style xlat function
+ *
+ * @note No new legacy xlat functions should be added to the server.
+ *       Each one added creates additional work later for a member
+ *      of the development team to fix the function to conform to
+ *      the new API.
  *
  * @param[in] mod_inst         Instance of module that's registering the xlat function.
  * @param[in] name             xlat name.
index fcc29a2deb14c96abe2c648efeaf228d7913e46e..516b37da871a28d5aaaea52dd6852f86760d792a 100644 (file)
@@ -23,7 +23,7 @@
  * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
  */
 
-RCSID("$Id:")
+RCSID("$Id$")
 
 #include <freeradius-devel/util/dbuff.h>
 
index f320a080a09ddb889d232ea433a8f5e7ec6a1bf9..267a2f5e6187c9d78579eff9522a577a2450ca34 100644 (file)
@@ -111,26 +111,85 @@ enum {
 
 extern const size_t dict_attr_sizes[FR_TYPE_MAX + 1][2];
 
+/** Extension identifier
+ *
+ */
+typedef enum {
+       FR_DICT_ATTR_EXT_CHILDREN = 0,                          //!< Attribute has children.
+       FR_DICT_ATTR_EXT_REF,                                   //!< Attribute references another
+                                                               ///< attribute and/or dictionary
+       FR_DICT_ATTR_EXT_VENDOR,                                //!< Cached vendor pointer.
+       FR_DICT_ATTR_EXT_DA_STACK,                              //!< Cached da stack.
+       FR_DICT_ATTR_EXT_PROTOCOL_SPECIFIC,                     //!< Protocol specific extensions
+       FR_DICT_ATTR_EXT_MAX
+} fr_dict_attr_ext_t;
+
+/** The alignment of object extension structures
+ *
+ */
+#define FR_DICT_ATTR_EXT_ALIGNMENT     sizeof(uintptr_t)
+
+/** 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_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 - Protocol-specific
+ *
+ */
+typedef struct {
+       void                    *uctx;                          //!< Protocol specific extensions
+} fr_dict_attr_ext_protocol_specific_t;
+
 /** Dictionary attribute
  */
 struct dict_attr_s {
+       fr_dict_t _CONST* _CONST dict;                          //!< Dict attribute belongs to.
+
+       char const              *name;                          //!< Attribute name.
+
        unsigned int            attr;                           //!< Attribute number.
        unsigned int            depth;                          //!< Depth of nesting for this attribute.
 
        fr_type_t               type;                           //!< Value type.
-       char const              *name;                          //!< Attribute name.
 
-       fr_dict_t _CONST* _CONST dict;                          //!< Dict attribute belongs to.
        fr_dict_attr_t const    *parent;                        //!< Immediate parent of this attribute.
        fr_dict_attr_t const    *next;                          //!< Next child in bin.
 
        fr_dict_attr_flags_t    flags;                          //!< Flags.
 
-       /*
-        *      The remaining fields vary depending on the attribute
-        *      properties.
-        */
-       fr_dict_attr_t const    *vendor;                        //!< ancestor which has type #FR_TYPE_VENDOR
        union {
                /*
                 *      Children are possible for:
@@ -146,9 +205,9 @@ struct dict_attr_s {
                fr_dict_attr_t const    **children;             //!< Children of this attribute.
                fr_dict_attr_t const    *ref;                   //!< reference, only for #FR_TYPE_GROUP
        };
+       uint8_t                 ext[FR_DICT_ATTR_EXT_MAX];      //!< Extensions to the dictionary attribute.
 
-       fr_dict_attr_t const    *da_stack[0];                   //!< load-time TLV stacks
-};
+} CC_HINT(aligned(FR_DICT_ATTR_EXT_ALIGNMENT));
 
 /** Value of an enumerated attribute
  *
@@ -248,6 +307,10 @@ typedef struct fr_dict_gctx_s fr_dict_gctx_t;
  */
 #define FR_DICT_TLV_NEST_MAX           (24)
 
+/** Maximum level of da stack caching
+ */
+#define FR_DICT_DA_STACK_CACHE_MAX     (5)
+
 /** Maximum TLV stack size
  *
  * The additional attributes are to account for
@@ -270,6 +333,82 @@ typedef struct fr_dict_gctx_s fr_dict_gctx_t;
 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
+ *
+ * @{
+ */
+
+/** 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))))
+
+/** Minimum extension lengths
+ */
+extern size_t const fr_dict_ext_length_min[];
+
+/* 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;
+}
+/** @} */
+
 /** @name Programatically create dictionary attributes and values
  *
  * @{
@@ -407,11 +546,34 @@ static inline bool fr_dict_attr_is_top_level(fr_dict_attr_t const *da)
  */
 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;
 
-       if (!da->vendor) return 0;
+       ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_VENDOR);
+       if (!ext) return 0;
 
-       return da->vendor->attr;
+       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);
@@ -420,9 +582,7 @@ fr_dict_vendor_t const      *fr_dict_vendor_by_name(fr_dict_t const *dict, char const
 
 fr_dict_vendor_t const *fr_dict_vendor_by_num(fr_dict_t const *dict, uint32_t vendor_pen);
 
-fr_dict_attr_t const   *fr_dict_vendor_attr_by_da(fr_dict_attr_t const *da);
-
-fr_dict_attr_t const   *fr_dict_vendor_attr_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen);
+fr_dict_attr_t const   *fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen);
 
 ssize_t                        fr_dict_attr_by_name_substr(fr_dict_attr_err_t *err, fr_dict_attr_t const **out,
                                                    fr_dict_t const *dict, fr_sbuff_t *name) CC_HINT(nonnull(2,4));
diff --git a/src/lib/util/dict_ext.c b/src/lib/util/dict_ext.c
new file mode 100644 (file)
index 0000000..8c93a95
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ *   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 dictionary structures
+ *
+ * @file src/lib/util/dict_attr_ext.c
+ *
+ * @copyright 2020 The FreeRADIUS server project
+ * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/util/dict_priv.h>
+
+/** Holds the minimum lengths of the extension structures
+ *
+ */
+size_t const fr_dict_ext_length_min[FR_DICT_ATTR_EXT_MAX] = {
+       [FR_DICT_ATTR_EXT_CHILDREN]     = sizeof(fr_dict_attr_ext_children_t),
+       [FR_DICT_ATTR_EXT_REF]          = sizeof(fr_dict_attr_ext_ref_t),
+       [FR_DICT_ATTR_EXT_VENDOR]       = sizeof(fr_dict_attr_ext_vendor_t),
+       [FR_DICT_ATTR_EXT_DA_STACK]     = sizeof(fr_dict_attr_ext_da_stack_t),
+};
+
+/** 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          len;
+       size_t          aligned = ROUND_UP(ext_len, FR_DICT_ATTR_EXT_ALIGNMENT);
+       size_t          offset;
+
+       fr_dict_attr_t  *n_da, *da = *da_p;
+
+       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;
+       }
+
+       if (da->ext[ext]) return fr_dict_attr_ext(da, ext);
+
+       len = talloc_array_length((uint8_t *)da);
+
+       offset = len / FR_DICT_ATTR_EXT_ALIGNMENT;
+       if (offset > UINT8_MAX) {
+               fr_strerror_printf("Insufficient space remaining for extensions");
+               return NULL;
+       }
+
+       n_da = talloc_realloc_size(ctx, da, len + aligned);
+       if (!n_da) return NULL;
+       talloc_set_type(n_da, fr_dict_attr_t);
+
+       *da_p = n_da;
+       da->ext[ext] = (uint8_t)offset;
+
+       return (void *)(((uintptr_t)n_da) + len);
+}
+
+/** 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_length_min[ext]);
+}
+
+/** 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 end = 0, start, i;
+       size_t  len;
+
+       start = da->ext[ext];
+       if (!start) return 0;
+
+       len = talloc_array_length((uint8_t const *)da);
+       end = len / FR_DICT_ATTR_EXT_ALIGNMENT;
+
+       /*
+        *      Figure out where the extension ends
+        */
+       for (i = 0; i < NUM_ELEMENTS(da->ext); i++) {
+               if ((da->ext[i] > start) && (da->ext[i] < end)) end = da->ext[i];
+       }
+
+       return (end - start) * FR_DICT_ATTR_EXT_ALIGNMENT;
+}
+
+/** Copy extension data from one attribute to another
+ *
+ * @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 start 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)
+{
+       uint8_t start;
+       size_t  ext_len;
+       void    *ptr;
+
+       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;
+       }
+
+       start = da_in->ext[ext];
+       if (!start) return NULL;
+
+       ext_len = dict_attr_ext_len(da_in, ext);
+       ptr = dict_attr_ext_alloc_size(ctx, da_out_p, ext, ext_len);
+       if (!ptr) return NULL;
+
+       /*
+        *      Copy extension data over
+        */
+       memcpy(ptr, (void *)((uintptr_t)(da_in) + (start * FR_DICT_ATTR_EXT_ALIGNMENT)), ext_len);
+
+       return ptr;
+}
index 4d451cdec5c4b8bc1afe9ee68fa41fbae2b21ff3..886495d2b348c8ffc50b7cc312baabfc55db5a84 100644 (file)
@@ -126,57 +126,81 @@ struct fr_dict_gctx_s {
 
 extern fr_dict_gctx_t *dict_gctx;
 
-extern fr_table_num_ordered_t const date_precision_table[];
-extern size_t date_precision_table_len;
+extern fr_table_num_ordered_t const    date_precision_table[];
+extern size_t                          date_precision_table_len;
 
 fr_dict_t              *dict_alloc(TALLOC_CTX *ctx);
 
 int                    dict_dlopen(fr_dict_t *dict, char const *name);
 
-/** Initialise fields in a dictionary attribute structure
+fr_dict_attr_t                 *dict_attr_alloc_null(TALLOC_CTX *ctx);
+
+int                    dict_attr_init(TALLOC_CTX *ctx, 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_alloc(TALLOC_CTX *ctx,
+                                        fr_dict_attr_t const *parent,
+                                        char const *name, int attr,
+                                        fr_type_t type, fr_dict_attr_flags_t const *flags);
+
+/** @name Add extension structures to attributes
  *
- * @param[in] da               to initialise.
- * @param[in] parent           of the attribute, if none, should be
- *                             the dictionary root.
- * @param[in] attr             number.
- * @param[in] type             of the attribute.
- * @param[in] flags            to assign.
+ * @{
  */
-static inline void dict_attr_init(fr_dict_attr_t *da,
-                                 fr_dict_attr_t const *parent, int attr,
-                                 fr_type_t type, fr_dict_attr_flags_t const *flags)
+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);
+
+static inline int dict_attr_ref_set(fr_dict_attr_t const *da, fr_dict_attr_t const *ref)
 {
-       da->attr = attr;
-       da->type = type;
-       da->flags = *flags;
-       da->parent = parent;
-
-       if (parent) {
-               da->dict = parent->dict;
-               da->depth = parent->depth + 1;
-       } else {
-               da->depth = 0;
+       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 contains no ref extension", da->name);
+               return -1;
        }
+       ext->ref = ref;
 
-       /*
-        *      Point to the vendor definition.  Since ~90% of
-        *      attributes are VSAs, caching this pointer will help.
-        */
-       if (parent) {
-               if (parent->type == FR_TYPE_VENDOR) {
-                       da->vendor = parent;
-               } else if (parent->vendor) {
-                       da->vendor = parent->vendor;
-               }
+       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 contains no children extension", da->name);
+               return -1;
        }
+       ext->children = children;
+
+       return 0;
 }
 
-fr_dict_attr_t                 *dict_attr_alloc_name(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, char const *name);
+static inline fr_dict_attr_t const **dict_attr_children(fr_dict_attr_t const *da)
+{
+       fr_dict_attr_ext_children_t *ext;
 
-fr_dict_attr_t         *dict_attr_alloc(TALLOC_CTX *ctx,
-                                        fr_dict_attr_t const *parent,
-                                        char const *name, int attr,
-                                        fr_type_t type, fr_dict_attr_flags_t const *flags);
+       ext = fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_CHILDREN);
+       if (unlikely(!ext)) {
+               fr_strerror_printf("%s contains no children extension", da->name);
+               return NULL;
+       }
+       return ext->children;
+}
+/** @} */
 
 int                    dict_attr_child_add(fr_dict_attr_t *parent, fr_dict_attr_t *child);
 
index 88de9dda1c468d49addb866bab2e5b67143102dc..ee9fc13bbfb88e3066dffb1b7734d5a0e8c8303b 100644 (file)
@@ -180,6 +180,8 @@ static int dict_read_sscanf_i(unsigned int *pvalue, char const *str)
  */
 static int dict_root_set(fr_dict_t *dict, char const *name, unsigned int proto_number)
 {
+       fr_dict_attr_t *da;
+
        fr_dict_attr_flags_t flags = {
                .is_root = 1,
                .type_size = 1,
@@ -191,10 +193,10 @@ static int dict_root_set(fr_dict_t *dict, char const *name, unsigned int proto_n
                return -1;
        }
 
-       dict->root = dict_attr_alloc_name(dict, NULL, name);
-       if (!dict->root) return -1;
+       da = dict_attr_alloc(dict, NULL, name, proto_number, FR_TYPE_TLV, &flags);
+       if (unlikely(!da)) return -1;
 
-       dict_attr_init(dict->root, NULL, proto_number, FR_TYPE_TLV, &flags);
+       dict->root = da;
        dict->root->dict = dict;
        DA_VERIFY(dict->root);
 
@@ -535,6 +537,7 @@ static fr_dict_attr_t const *dict_gctx_unwind(dict_tokenize_ctx_t *ctx)
 static int dict_read_process_alias(dict_tokenize_ctx_t *ctx, char **argv, int argc)
 {
        fr_dict_attr_t const *da;
+       fr_dict_attr_t *new;
 
        if (argc != 2) {
                fr_strerror_printf("Invalid ALIAS syntax");
@@ -571,10 +574,10 @@ static int dict_read_process_alias(dict_tokenize_ctx_t *ctx, char **argv, int ar
         *      second one is prioritized for printing.  For ALIASes,
         *      we want the first one to be prioritized.
         */
-       da = dict_attr_alloc(ctx->dict->pool, da->parent, argv[0], da->attr, da->type, &da->flags);
-       if (!da) return -1;
+       new = dict_attr_alloc(ctx->dict->pool, da->parent, argv[0], da->attr, da->type, &da->flags);
+       if (unlikely(!new)) return -1;
 
-       if (!fr_hash_table_insert(ctx->dict->attributes_by_name, da)) {
+       if (!fr_hash_table_insert(ctx->dict->attributes_by_name, new)) {
                fr_strerror_printf("Internal error storing attribute");
                talloc_const_free(da);
                return -1;
@@ -836,7 +839,8 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *ctx, char **argv, in
 
                        talloc_free(ref);
                        self->dict = dict;
-                       self->ref = da;
+
+                       dict_attr_ref_set(self, da);
                }
        }
 
@@ -1677,7 +1681,7 @@ static int fr_dict_finalise(dict_tokenize_ctx_t *ctx)
                        }
 
                        talloc_free(this->ref);
-                       this->da->ref = da;
+                       dict_attr_ref_set(this->da, da);
 
                        next = this->next;
                }
@@ -2337,9 +2341,11 @@ static int _dict_from_file(dict_tokenize_ctx_t *ctx,
                                        }
                                }
 
+                               new = dict_attr_alloc(ctx->dict->pool,
+                                                     vsa_da, argv[1], vendor->pen, FR_TYPE_VENDOR, &flags);
+                               if (unlikely(!new)) goto error;
+
                                memcpy(&mutable, &vsa_da, sizeof(mutable));
-                               new = dict_attr_alloc(mutable, vsa_da, argv[1],
-                                                     vendor->pen, FR_TYPE_VENDOR, &flags);
                                if (dict_attr_child_add(mutable, new) < 0) {
                                        talloc_free(new);
                                        goto error;
index e3653cde6f4dbef88d5fcd14851e197f037b558a..a4d974a241cef1a35d6488faf354ea48f47ff483 100644 (file)
@@ -46,7 +46,7 @@ fr_dict_attr_t *fr_dict_unknown_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
        /*
         *      Allocate an attribute.
         */
-       n = dict_attr_alloc_name(ctx, da->parent, da->name);
+       n = dict_attr_alloc_null(ctx);
        if (!n) return NULL;
 
        /*
@@ -85,7 +85,7 @@ fr_dict_attr_t *fr_dict_unknown_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
        /*
         *      Initialize the rest of the fields.
         */
-       dict_attr_init(n, parent, da->attr, type, &flags);
+       dict_attr_init(ctx, &n, parent, da->name, da->attr, type, &flags);
 
        DA_VERIFY(n);
 
@@ -148,6 +148,7 @@ fr_dict_attr_t const *fr_dict_unknown_add(fr_dict_t *dict, fr_dict_attr_t const
                if (dict_vendor_add(dict, old->name, old->attr) < 0) return NULL;
 
                n = dict_attr_alloc(dict->pool, parent, old->name, old->attr, old->type, &flags);
+               if (unlikely(!n)) return NULL;
 
                /*
                 *      Setup parenting for the attribute
@@ -342,7 +343,7 @@ fr_dict_attr_t const *fr_dict_unknown_afrom_fields(TALLOC_CTX *ctx, fr_dict_attr
        /*
         *      The config files may reference the unknown by name.
         *      If so, use the pre-defined name instead of an unknown
-        *      one.!
+        *      one!
         */
        da = fr_dict_attr_by_name(dict_by_da(parent), n->name);
        if (da) {
@@ -464,10 +465,10 @@ ssize_t fr_dict_unknown_afrom_oid_str(TALLOC_CTX *ctx, fr_dict_attr_t **out,
         *      or more of the leading components may, in fact, be
         *      known.
         */
-       n = dict_attr_alloc_name(ctx, parent, oid_str);
+       n = dict_attr_alloc_null(ctx);
 
        /*
-        *      While the name of this attribu
+        *      Parse the name of this attribute
         */
        do {
                unsigned int            num;
@@ -530,7 +531,7 @@ ssize_t fr_dict_unknown_afrom_oid_str(TALLOC_CTX *ctx, fr_dict_attr_t **out,
                 *      Leaf attribute
                 */
                case '\0':
-                       dict_attr_init(n, our_parent, num, FR_TYPE_OCTETS, &flags);
+                       dict_attr_init(ctx, &n, our_parent, oid_str, num, FR_TYPE_OCTETS, &flags);
                        break;
                }
                p++;
index c015d43e3ad02625d97cee40a22a95ff321b45d2..eefdc378829440862739140c882fc3871e1b7864 100644 (file)
@@ -359,55 +359,238 @@ static int dict_enum_value_cmp(void const *one, void const *two)
        return fr_value_box_cmp(a->value, b->value);
 }
 
-/** Allocate a dictionary attribute and assign a name
+/** Set a dictionary attribute's name
  *
- * @param[in] ctx              to allocate attribute in.
- * @param[in] parent           of this da
- * @param[in] name             to set.
- * @return
- *     - 0 on success.
- *     - -1 on failure (memory allocation error).
+ * @note This function can only be used _before_ the attribute is inserted into the dictionary.
+ *
+ * @param[in] da       to set name for.
+ * @param[in] name     to set.  If NULL a name will be automatically generated.
  */
-fr_dict_attr_t *dict_attr_alloc_name(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, char const *name)
+static inline CC_HINT(always_inline) int dict_attr_name_set(fr_dict_attr_t *da, char const *name)
 {
-       int             depth = 0;
-       fr_dict_attr_t  *da;
+       char            buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1];
+       size_t          name_len;
 
+       /*
+        *      Generate a name if non is specified
+        */
        if (!name) {
-               fr_strerror_printf("No attribute name provided");
-               return NULL;
+               fr_sbuff_t      unknown_name = FR_SBUFF_OUT(buffer, sizeof(buffer));
+
+               fr_sbuff_in_strcpy_literal(&unknown_name, "Attr-");
+               if (da->parent) {
+                       if (fr_dict_print_attr_oid(&unknown_name, NULL, da->parent) > 0) {
+                               fr_sbuff_in_char(&unknown_name, '.');
+                       }
+               }
+               fr_sbuff_in_sprintf(&unknown_name, "%u", da->attr);
+
+               name = buffer;
+               name_len = fr_sbuff_used(&unknown_name);
+       } else {
+               name_len = strlen(name);
        }
 
-       if (parent) depth = parent->depth + 1;
+       da->name = talloc_bstrndup(da, name, name_len);
+       if (unlikely(!da->name)) {
+               fr_strerror_printf("Failed allocating space for attribute name");
+               return -1;
+       }
 
-       da = talloc_zero_size(ctx, sizeof(fr_dict_attr_t) + sizeof(da->da_stack[0]) * (depth + 1));
-       if (!da) return NULL;
+       return 0;
+}
 
-       talloc_set_type(da, fr_dict_attr_t);
+/** Initialise an attribute's da stack from its parent
+ *
+ * @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)
+{
+       fr_dict_attr_ext_da_stack_t     *ext, *p_ext;
+       fr_dict_attr_t                  *da = *da_p;
+       fr_dict_attr_t const            *parent = da->parent;
 
-       da->name = talloc_typed_strdup(da, name);
-       if (!da->name) {
-               talloc_free(da);
-               fr_strerror_printf("Out of memory");
-               return NULL;
-       }
+       if (!parent) return 1;
+       if (da->depth > FR_DICT_DA_STACK_CACHE_MAX) return 1;
+       if (fr_dict_attr_ext(da, FR_DICT_ATTR_EXT_DA_STACK)) return 1;
+
+       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));
+       if (unlikely(!ext)) return -1;
+
+       memcpy(ext->da_stack, p_ext->da_stack, sizeof(ext->da_stack[0]) * parent->depth);
 
        /*
-        *      Set up parent / child relationship, and copy the
-        *      da_stack from the parent.
+        *      Always set the last stack entry to ourselves.
+        */
+       ext->da_stack[da->depth] = da;
+
+       return 0;
+}
+
+/** Cache the vendor pointer for an attribute
+ *
+ * @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)
+{
+       fr_dict_attr_ext_vendor_t       *ext;
+
+       ext = dict_attr_ext_alloc(ctx, da_p, FR_DICT_ATTR_EXT_VENDOR);
+       if (unlikely(!ext)) return -1;
+
+       ext->vendor = vendor;
+
+       return 0;
+}
+
+/** Set a reference for a grouping attribute
+ *
+ * @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)
+{
+       fr_dict_attr_ext_ref_t          *ext;
+
+       ext = dict_attr_ext_alloc(ctx, da_p, FR_DICT_ATTR_EXT_REF);
+       if (unlikely(!ext)) return -1;
+       memset(ext, 0, sizeof(*ext));
+
+       return 0;
+}
+
+/** Add a child/nesting extension to an attribute
+ *
+ * @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)
+{
+       fr_dict_attr_ext_ref_t          *ext;
+
+       ext = dict_attr_ext_alloc(ctx, da_p, FR_DICT_ATTR_EXT_CHILDREN);
+       if (unlikely(!ext)) return -1;
+       memset(ext, 0, sizeof(*ext));
+
+       return 0;
+}
+
+/** Initialise fields in a dictionary attribute structure
+ *
+ * @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] name             of attribute.  Pass NULL for auto-generated name.
+ * @param[in] attr             number.
+ * @param[in] type             of the attribute.
+ * @param[in] flags            to assign.
+ */
+int dict_attr_init(TALLOC_CTX *ctx, 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  *da = *da_p;
+
+       *da = (fr_dict_attr_t) {
+               .attr = attr,
+               .type = type,
+               .flags = *flags,
+               .parent = parent,
+       };
+       *da_p = da;
+
+       /*
+        *      Record the parent
         */
        if (parent) {
-               da->parent = parent;
-               da->depth = depth;
+               da->dict = parent->dict;
+               da->depth = parent->depth + 1;
 
-               memcpy(&da->da_stack[0], &parent->da_stack[0],
-                      sizeof(da->da_stack[0]) * depth);
+               /*
+                *      Point to the vendor definition.  Since ~90% of
+                *      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;
+               } else {
+                       dict_attr_ext_copy(ctx, da_p, parent, FR_DICT_ATTR_EXT_VENDOR); /* Noop if no vendor extension */
+               }
+       } else {
+               da->depth = 0;
        }
 
        /*
-        *      Always set the last stack entry to ourselves.
+        *      Cache the da_stack so we don't need
+        *      to generate it at runtime.
         */
-       da->da_stack[depth] = da;
+       dict_attr_da_stack_set(ctx, da_p);
+
+       /*
+        *      Structural types can have children
+        *      so add the extension for them.
+        */
+       switch (type) {
+       case FR_TYPE_STRUCTURAL:
+               if (dict_attr_children_init(ctx, da_p) < 0) return -1;
+               if ((type == FR_TYPE_TLV) || (type == FR_TYPE_GROUP)) {
+                       if (dict_attr_ref_init(ctx, da_p) < 0) return -1;
+               }
+               break;
+
+       default:
+               break;
+       }
+       da = *da_p;
+
+       /*
+        *      Name is a separate talloc chunk, so allocate it last
+        *      so re-allocing for the extensions doesn't eat up
+        *      pool space.
+        */
+       if (dict_attr_name_set(da, name) < 0) return -1;
+       DA_VERIFY(*da_p);
+
+       return 0;
+}
+
+/** Allocate a partially completed attribute
+ *
+ * This is useful in some instances where we need to pre-allocate the attribute
+ * for talloc hierarchy reasons, but want to finish initialising it
+ * with #fr_dict_init later.
+ *
+ * @param[in] ctx              to allocate attribute in.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure (memory allocation error).
+ */
+fr_dict_attr_t *dict_attr_alloc_null(TALLOC_CTX *ctx)
+{
+       fr_dict_attr_t *da;
+
+       da = talloc(ctx, fr_dict_attr_t);
+       if (unlikely(!da)) return NULL;
+
+       talloc_set_type(da, fr_dict_attr_t);
 
        return da;
 }
@@ -433,30 +616,10 @@ fr_dict_attr_t *dict_attr_alloc(TALLOC_CTX *ctx,
 {
        fr_dict_attr_t  *n;
 
-       if (!fr_cond_assert(parent) || !fr_cond_assert(parent->dict)) return NULL;
+       n = dict_attr_alloc_null(ctx);
+       if (unlikely(!n)) return NULL;
 
-       /*
-        *      Allocate a new attribute
-        */
-       if (!name) {
-               char            buffer[FR_DICT_ATTR_MAX_NAME_LEN + 1];
-               fr_sbuff_t      unknown_name = FR_SBUFF_OUT(buffer, sizeof(buffer));
-
-               fr_sbuff_in_strcpy_literal(&unknown_name, "Attr-");
-               if (parent) {
-                       if (fr_dict_print_attr_oid(&unknown_name, NULL, parent) > 0) {
-                               fr_sbuff_in_char(&unknown_name, '.');
-                       }
-               }
-               fr_sbuff_in_sprintf(&unknown_name, "%u", attr);
-
-               n = dict_attr_alloc_name(ctx, parent, buffer);
-       } else {
-               n = dict_attr_alloc_name(ctx, parent, name);
-       }
-
-       dict_attr_init(n, parent, attr, type, flags);
-       DA_VERIFY(n);
+       dict_attr_init(ctx, &n, parent, name, attr, type, flags);
 
        return n;
 }
@@ -471,12 +634,16 @@ fr_dict_attr_t *dict_attr_alloc(TALLOC_CTX *ctx,
  */
 static fr_dict_attr_t *dict_attr_acopy(TALLOC_CTX *ctx, fr_dict_attr_t const *in)
 {
-       fr_dict_attr_t *n;
-
-       n = dict_attr_alloc_name(ctx, in->parent, in->name);
-       if (!n) return NULL;
+       fr_dict_attr_t  *n;
+       uint8_t         i;
 
-       dict_attr_init(n, in->parent, in->attr, in->type, &in->flags);
+       n = dict_attr_alloc(ctx, in->parent, in->name, in->attr, in->type, &in->flags);
+       for (i = 0; i < NUM_ELEMENTS(in->ext); i++) if (in->ext[i]) {
+               if (unlikely(!dict_attr_ext_copy(ctx, &n, in, i))) {
+                       talloc_free(n);
+                       return NULL;
+               }
+       }
        DA_VERIFY(n);
 
        return n;
@@ -551,11 +718,16 @@ int dict_vendor_add(fr_dict_t *dict, char const *name, unsigned int num)
        }
 
        vendor = talloc_zero(dict, fr_dict_vendor_t);
+       if (!vendor) {
+       oom:
+               fr_strerror_printf("Out of memory");
+               return -1;
+       }
+
        vendor->name = talloc_typed_strdup(vendor, name);
        if (!vendor->name) {
                talloc_free(vendor);
-               fr_strerror_printf("Out of memory");
-               return -1;
+               goto oom;
        }
        vendor->pen = num;
        vendor->type = vendor->length = 1; /* defaults */
@@ -663,7 +835,7 @@ int dict_attr_child_add(fr_dict_attr_t *parent, fr_dict_attr_t *child)
 
        if (da_has_ref(parent)) {
                fr_strerror_printf("Cannot add children to attribute '%s' which has 'ref=%s'",
-                                  parent->name, parent->ref->name);
+                                  parent->name, fr_dict_attr_ref(parent)->name);
                return false;
        }
 
@@ -1705,26 +1877,6 @@ fr_dict_vendor_t const *fr_dict_vendor_by_num(fr_dict_t const *dict, uint32_t ve
        return fr_hash_table_finddata(dict->vendors_by_num, &(fr_dict_vendor_t) { .pen = vendor_pen });
 }
 
-/** Return the vendor that parents this attribute
- *
- * @note Uses the dictionary hierachy to determine the parent
- *
- * @param[in] da               The dictionary attribute to find parent for.
- * @return
- *     - NULL if the attribute has no vendor.
- *     - A fr_dict_attr_t representing this attribute's associated vendor.
- */
-fr_dict_attr_t const *fr_dict_vendor_attr_by_da(fr_dict_attr_t const *da)
-{
-       DA_VERIFY(da);
-
-       if (da->type == FR_TYPE_VENDOR) return da;
-
-       if (!da->vendor) return NULL;
-
-       return da->vendor;
-}
-
 /** Return vendor attribute for the specified dictionary and pen
  *
  * @param[in] vendor_root      of the vendor root attribute.  Could be 26 (for example) in RADIUS.
@@ -1733,7 +1885,7 @@ fr_dict_attr_t const *fr_dict_vendor_attr_by_da(fr_dict_attr_t const *da)
  *     - NULL if vendor does not exist.
  *     - A fr_dict_attr_t representing the vendor in the dictionary hierarchy.
  */
-fr_dict_attr_t const *fr_dict_vendor_attr_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
+fr_dict_attr_t const *fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
 {
        fr_dict_attr_t const *vendor;
 
@@ -2057,7 +2209,7 @@ fr_dict_attr_t const *fr_dict_attr_child_by_da(fr_dict_attr_t const *parent, fr_
        DA_VERIFY(parent);
 #endif
 
-       if (da_has_ref(parent)) parent = parent->ref;
+       if (da_has_ref(parent)) parent = fr_dict_attr_ref(parent);
 
        if (!dict_attr_can_have_children(parent) || !parent->children) return NULL;
 
@@ -2100,7 +2252,7 @@ inline fr_dict_attr_t *dict_attr_child_by_num(fr_dict_attr_t const *parent, unsi
        /*
         *      Do any necessary dereferencing
         */
-       if (da_has_ref(parent)) parent = parent->ref;
+       if (da_has_ref(parent)) parent = fr_dict_attr_ref(parent);
 
        if (!dict_attr_can_have_children(parent) || !parent->children) {
                return NULL;
@@ -2156,7 +2308,7 @@ ssize_t fr_dict_attr_child_by_name_substr(fr_dict_attr_err_t *err,
        /*
         *      Do any necessary dereferencing
         */
-       if (da_has_ref(parent)) parent = parent->ref;
+       if (da_has_ref(parent)) parent = fr_dict_attr_ref(parent);
 
        if (!dict_attr_can_have_children(parent)) {
                fr_strerror_printf("Parent (%s) is a %s, it cannot contain nested attributes",
index f471aa95b5367d29187ca79330b411c6849f4b82..0febfb05aed39f49ef0d83ea515844e25513acba 100644 (file)
@@ -12,6 +12,7 @@ SOURCES               := \
                   cursor.c \
                   dbuff.c \
                   debug.c \
+                  dict_ext.c \
                   dict_print.c \
                   dict_tokenize.c \
                   dict_unknown.c \
index 71dc37cb75c79eeec82cfed7278d00ee73727585..f376d1a8234b07b4557c022ff438a22df9fe7ca6 100644 (file)
@@ -165,7 +165,7 @@ VALUE_PAIR *fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *paren
                 *      is a TLV attribute parented by a vendor, that's
                 *      also fine...
                 */
-               vendor = fr_dict_vendor_attr_by_da(parent);
+               vendor = fr_dict_vendor_da_by_da(parent);
                if (vendor) vendor_id = vendor->attr;
 
                da = fr_dict_unknown_afrom_fields(ctx, parent,
index e8c0e0bb8a147b96128fa973a9177c983b5fdfd4..91e5454aa458f8d2b3a7f95763c582dd3b6b6aa0 100644 (file)
@@ -123,13 +123,19 @@ void *fr_proto_next_encodable(void **prev, void *to_eval, void *uctx)
  */
 void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
 {
+       fr_dict_attr_t const **cached;
+
        if (!da) return;
 
-       if (!da->flags.is_unknown) {
+       /*
+        *      See if we have a cached da stack available
+        */
+       cached = fr_dict_attr_da_stack(da);
+       if (cached) {
                /*
                 *      da->da_stack[0] is dict->root
                 */
-               memcpy(&stack->da[0], &da->da_stack[1], sizeof(stack->da[0]) * da->depth);
+               memcpy(&stack->da[0], &cached[1], sizeof(stack->da[0]) * da->depth);
 
        } else {
                fr_dict_attr_t const    *da_p, **da_o;
index 41fc2c0d546eaecdde3d4c07a3fd4ff2c4e02638..da5de1c9039383f3419896e606a143be09befb2f 100644 (file)
@@ -201,7 +201,7 @@ static ssize_t eap_ttls_decode_pair(TALLOC_CTX *ctx, fr_cursor_t *cursor, fr_dic
                        p += 4;
                        value_len -= 4; /* -= 4 for the vendor ID field */
 
-                       our_parent = fr_dict_vendor_attr_by_num(attr_vendor_specific, vendor);
+                       our_parent = fr_dict_vendor_da_by_num(attr_vendor_specific, vendor);
                        if (!our_parent) {
                                if (flags & FR_DIAMETER_AVP_FLAG_MANDATORY) {
                                        fr_strerror_printf("Mandatory bit set and no vendor %u found", vendor);