]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add pair_afrom_da_nested()
authorAlan T. DeKok <aland@freeradius.org>
Sat, 8 Jul 2023 19:44:50 +0000 (15:44 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 10 Jul 2023 19:55:07 +0000 (15:55 -0400)
which is similar to fr_pair_update_by_da_parent(), except that
function takes a parent pair.  In some cases, we need to use
separate TALLOC_CTX and fr_pair_list_t.

src/lib/util/pair.c
src/lib/util/pair.h
src/lib/util/pair_tests.c

index 632a53a65afb6d7496f0ba373f818ed913fd4083..1b1dcedbee10292772e983155a46ab0c15890f35 100644 (file)
@@ -447,6 +447,59 @@ fr_pair_t *fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent
        return vp;
 }
 
+/** Create a pair (and all intermediate parents), and append it to the list
+ *
+ *  If the relevant leaf pair already exists, then a new one is created.
+ *
+ *  This function is similar to fr_pair_update_by_da_parent(), except that function requires
+ *  a parent pair, and this one takes a separate talloc ctx and pair list.
+ *
+ * @param[in] ctx      for allocated memory, usually a pointer to a #fr_radius_packet_t.
+ * @param[out] list    where the created pair is supposed to go.
+ * @param[in] da       the da for the pair to create
+ * @return
+ *     - A new #fr_pair_t.
+ *     - NULL on error.
+ */
+fr_pair_t *fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
+{
+       fr_pair_t *vp;
+       unsigned int            i;
+       TALLOC_CTX              *cur_ctx;
+       fr_dict_attr_t const    *find;          /* DA currently being looked for */
+       fr_pair_list_t          *cur_list;      /* Current list being searched */
+       fr_da_stack_t           da_stack;
+
+       if (da->depth <= 1) {
+               if  (fr_pair_append_by_da(ctx, &vp, list, da) < 0) return NULL;
+               return vp;
+       }
+
+       fr_proto_da_stack_build(&da_stack, da);
+       cur_list = list;
+       cur_ctx = ctx;
+
+       for (i = 0; i <= da->depth; i++) {
+               find = da_stack.da[i];
+
+               vp = fr_pair_find_by_da(cur_list, NULL, find);
+               if (!vp || (vp->da == da)) {
+                       if  (fr_pair_append_by_da(cur_ctx, &vp, cur_list, find) < 0) return NULL;
+               }
+
+               if (find == da) return vp;
+
+               fr_assert(fr_type_is_structural(vp->da->type));
+
+               cur_ctx = vp;
+               cur_list = &vp->vp_group;
+       }
+
+       fr_assert(0);
+
+       return NULL;
+}
+
 /** Copy a single valuepair
  *
  * Allocate a new valuepair and copy the da from the old vp.
index 67665efbffdf26d04956313e3f725d68c63eca69..62976c0c0509fe31fe4c2014480ffd99e4c0e002 100644 (file)
@@ -438,6 +438,8 @@ int         fr_pair_reinit_from_da(fr_pair_list_t *list, fr_pair_t *vp, fr_dict_attr_t
 
 fr_pair_t      *fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr) CC_HINT(warn_unused_result);
 
+fr_pair_t      *fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da) CC_HINT(warn_unused_result) CC_HINT(nonnull(2,3));
+
 fr_pair_t      *fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp) CC_HINT(nonnull(2)) CC_HINT(warn_unused_result);
 
 int            fr_pair_steal(TALLOC_CTX *ctx, fr_pair_t *vp) CC_HINT(nonnull);
index 447cc54f64e5c3b7b86a7395aab38077e407ba6a..6a1d58533b4b530d2285b50525c1d25b572c77dc 100644 (file)
@@ -127,6 +127,35 @@ static void test_fr_pair_afrom_child_num(void)
        talloc_free(vp);
 }
 
+static void test_fr_pair_afrom_da_nested(void)
+{
+       fr_pair_t    *vp, *parent = NULL;
+       fr_pair_list_t  local_pairs;
+
+       fr_pair_list_init(&local_pairs);
+
+       TEST_CASE("Allocation using fr_pair_afrom_da_nested");
+       TEST_CHECK((vp = fr_pair_afrom_da_nested(autofree, &local_pairs, fr_dict_attr_test_tlv_string)) != NULL);
+
+       TEST_CHECK(vp && vp->da == fr_dict_attr_test_tlv_string);
+       TEST_MSG("Expected attr(%s) == vp->da->attr(%s)", fr_dict_attr_test_tlv_string->name, vp->da->name);
+
+       TEST_CASE("Validating PAIR_VERIFY()");
+       PAIR_VERIFY(vp);
+
+       TEST_CASE("Top list does not have the tlv child attribute");
+       TEST_CHECK(fr_pair_find_by_da(&local_pairs, NULL, fr_dict_attr_test_tlv_string) == NULL);
+
+       TEST_CASE("Top list does have the tlv attribute");
+       parent = fr_pair_find_by_da(&local_pairs, NULL, fr_dict_attr_test_tlv);
+       TEST_CHECK(parent != NULL);
+
+       TEST_CASE("Parent list does have the tlv child attribute");
+       TEST_CHECK(fr_pair_find_by_da(&parent->vp_group, NULL, fr_dict_attr_test_tlv_string) == vp);
+
+       talloc_free(parent);    /* not vp! */
+}
+
 static void test_fr_pair_copy(void)
 {
        fr_pair_t *vp, *copy;
@@ -1354,6 +1383,7 @@ TEST_LIST = {
         */
        { "fr_pair_afrom_da",                     test_fr_pair_afrom_da },
        { "fr_pair_afrom_child_num",              test_fr_pair_afrom_child_num },
+       { "fr_pair_afrom_da_nested",              test_fr_pair_afrom_da_nested },
        { "fr_pair_copy",                         test_fr_pair_copy },
        { "fr_pair_steal",                        test_fr_pair_steal },