]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add fr_pair_find_by_da_nested() to find pairs by their da structure
authorNick Porter <nick@portercomputing.co.uk>
Thu, 11 Aug 2022 11:11:15 +0000 (12:11 +0100)
committerNick Porter <nick@portercomputing.co.uk>
Tue, 16 Aug 2022 15:58:44 +0000 (16:58 +0100)
src/lib/util/pair.c
src/lib/util/pair.h

index 09c45e8553f56fbf53479f7351ce5777b1bc23e1..51d69d764cadb1f3e1a8143792204495df85ab85 100644 (file)
@@ -696,6 +696,104 @@ fr_pair_t *fr_pair_find_by_da_idx(fr_pair_list_t const *list, fr_dict_attr_t con
        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.
index ae295d4bd0488ecda67a3dc2ae2061e783670a8d..112099b4b52a87a8a4d59a72afb46b12e621e9cf 100644 (file)
@@ -408,6 +408,9 @@ fr_pair_t   *fr_pair_find_by_da(fr_pair_list_t const *list,
 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));