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.
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);
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;
*/
{ "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 },