return NULL;
}
+/** Find a pair with a matching da walking the nested da tree
+ *
+ * The list should be the one containing the top level attributes.
+ *
+ * @param[in] list to search in.
+ * @param[in] prev pair to start searching from.
+ * @param[in] da the next da to find.
+ * @return
+ * - first matching fr_pair_t.
+ * - NULL if no fr_pair_ts match.
+ */
+fr_pair_t *fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
+{
+ fr_pair_t *vp;
+ fr_dict_attr_t const **find; /* DA currently being looked for */
+ fr_pair_list_t const *cur_list; /* Current list being searched */
+ fr_da_stack_t da_stack;
+
+ if (fr_pair_list_empty(list)) return NULL;
+
+ /*
+ * In the common case, we're looking for attributes in
+ * the root (at level 1), so we just skip to a special
+ * function for that
+ */
+ if (da->depth <= 1) return fr_pair_find_by_da(list, prev, da);
+
+ fr_proto_da_stack_build(&da_stack, da);
+
+ /*
+ * Find the relevant starting point for `prev`
+ */
+ if (prev) {
+ cur_list = fr_pair_parent_list(prev);
+ find = &da_stack.da[prev->da->depth - 1];
+ vp = UNCONST(fr_pair_t *, prev);
+ } else {
+ cur_list = list;
+ find = &da_stack.da[0];
+ vp = NULL;
+ }
+
+ /*
+ * Loop over the list at each level until we find a matching da.
+ */
+ while (true) {
+ fr_pair_t *next;
+
+ fr_assert((*find)->depth <= da->depth);
+
+ /*
+ * Find a vp which matches a given da. If found,
+ * recurse into the child list to find the child
+ * attribute.
+ *
+ */
+ next = fr_pair_find_by_da(cur_list, vp, *find);
+ if (next) {
+ /*
+ * We've found a match for the requested
+ * da - return it.
+ */
+ if ((*find) == da) return next;
+
+ /*
+ * Prepare to search the next level.
+ */
+ cur_list = &next->vp_group;
+ find++;
+ vp = NULL;
+ continue;
+ }
+
+ /*
+ * We hit the end of the top-level list. Therefore we found nothing.
+ */
+ if (cur_list == list) break;
+
+ /*
+ * We hit the end of *A* list. Go to the parent
+ * VP, and then find its list.
+ *
+ * We still then have to go to the next attribute
+ * in the parent list, as we've checked all of the
+ * children of this VP.
+ */
+ find--;
+ vp = fr_pair_list_parent(cur_list);
+ cur_list = fr_pair_parent_list(vp);
+ }
+
+ /*
+ * Compatiblitity with flat atttrbutes
+ */
+ if (fr_pair_parent_list(prev) != list) prev = NULL;
+ return fr_pair_find_by_da(list, prev, da);
+}
+
/** Find a pair which has the specified ancestor
*
* @param[in] list to search in.
fr_pair_t *fr_pair_find_by_da_idx(fr_pair_list_t const *list,
fr_dict_attr_t const *da, unsigned int idx) CC_HINT(nonnull);
+fr_pair_t *fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev,
+ fr_dict_attr_t const *da) CC_HINT(nonnull(1,3));
+
fr_pair_t *fr_pair_find_by_ancestor(fr_pair_list_t const *list, fr_pair_t const *prev,
fr_dict_attr_t const *ancestor) CC_HINT(nonnull(1,3));