int line; //!< ditto.
} dict_fixup_common_t;
+/** Add an enumeration value to an attribute that wasn't defined at the time the value was parsed
+ *
+ */
+typedef struct {
+ dict_fixup_common_t common; //!< Common fields.
+
+ char *alias; //!< we need to create.
+ fr_dict_attr_t *alias_parent; //!< Where to add the alias.
+
+ char *ref; //!< what the alias references.
+ fr_dict_attr_t *ref_parent; //!< Parent attribute to resolve the 'attribute' string in.
+} dict_fixup_alias_t;
+
/** Add an enumeration value to an attribute that wasn't defined at the time the value was parsed
*
*/
}
+/** Resolve a group reference
+ *
+ * This is required as the reference may point to another dictionary which
+ * hasn't been loaded yet.
+ *
+ * @param[in] fctx Holds current dictionary parsing information.
+ * @param[in] filename this fixup relates to.
+ * @param[in] line this fixup relates to.
+ * @param[in] alias_parent where to add the alias.
+ * @param[in] alias alias to add.
+ * @param[in] ref_parent attribute that should contain the reference.
+ * @param[in] ref OID string representing what the group references.
+ * @return
+ * - 0 on success.
+ * - -1 on out of memory.
+ */
+int dict_fixup_alias(dict_fixup_ctx_t *fctx, char const *filename, int line,
+ fr_dict_attr_t *alias_parent, char const *alias,
+ fr_dict_attr_t *ref_parent, char const *ref)
+{
+ dict_fixup_alias_t *fixup;
+
+ fixup = talloc(fctx->pool, dict_fixup_alias_t);
+ if (!fixup) {
+ fr_strerror_const("Out of memory");
+ return -1;
+ }
+ *fixup = (dict_fixup_alias_t) {
+ .alias = talloc_typed_strdup(fixup, alias),
+ .alias_parent = alias_parent,
+ .ref = talloc_typed_strdup(fixup, ref),
+ .ref_parent = ref_parent
+ };
+
+ return dict_fixup_common(filename, line, &fctx->alias, &fixup->common);
+}
+
+static inline CC_HINT(always_inline) int dict_fixup_alias_apply(UNUSED dict_fixup_ctx_t *fctx, dict_fixup_alias_t *fixup)
+{
+ fr_dict_attr_t const *da;
+
+ /*
+ * The <ref> can be a name.
+ */
+ da = fr_dict_attr_by_oid(NULL, fixup->ref_parent, fixup->ref);
+ if (!da) {
+ fr_strerror_printf("Attribute '%s' aliased by '%s' doesn't exist in namespace '%s'",
+ fixup->ref, fixup->alias, fixup->ref_parent->name);
+ return -1;
+ }
+
+ return dict_attr_alias_add(fixup->alias_parent, fixup->alias, da);
+}
/** Initialise a fixup ctx
*
fr_dlist_talloc_init(&fctx->group, dict_fixup_group_t, common.entry);
fr_dlist_talloc_init(&fctx->clone, dict_fixup_clone_t, common.entry);
fr_dlist_talloc_init(&fctx->vsa, dict_fixup_vsa_t, common.entry);
+ fr_dlist_talloc_init(&fctx->alias, dict_fixup_alias_t, common.entry);
fctx->pool = talloc_pool(ctx, DICT_FIXUP_POOL_SIZE);
if (!fctx->pool) return -1;
/*
* Apply all the fctx in order
*
+
* - Enumerations first as they have no dependencies
* - Group references next, as group attributes may be cloned.
* - Clones last as all other references and additions should
* be applied before cloning.
- * - Hash table fctx last.
+ * - VSAs
+ * - Aliases last as all attributes need to be defined.
*/
APPLY_FIXUP(fctx, enumv, dict_fixup_enumv_apply, dict_fixup_enumv_t);
APPLY_FIXUP(fctx, group, dict_fixup_group_apply, dict_fixup_group_t);
APPLY_FIXUP(fctx, clone, dict_fixup_clone_apply, dict_fixup_clone_t);
APPLY_FIXUP(fctx, vsa, dict_fixup_vsa_apply, dict_fixup_vsa_t);
+ APPLY_FIXUP(fctx, alias, dict_fixup_alias_apply, dict_fixup_alias_t);
TALLOC_FREE(fctx->pool);
fr_dlist_head_t group; //!< Group references to resolve.
fr_dlist_head_t clone; //!< Clone operation to apply.
fr_dlist_head_t vsa; //!< VSAs to add vendors for
+ fr_dlist_head_t alias; //!< Aliases that can't be resolved immediately.
} dict_fixup_ctx_t;
int dict_fixup_enumv(dict_fixup_ctx_t *fctx, char const *filename, int line,
int dict_fixup_vsa(dict_fixup_ctx_t *fctx, char const *filename, int line,
fr_dict_attr_t *da);
+int dict_fixup_alias(dict_fixup_ctx_t *fctx, char const *filename, int line,
+ fr_dict_attr_t *alias_parent, char const *alias,
+ fr_dict_attr_t *ref_parent, char const *ref);
+
int dict_fixup_init(TALLOC_CTX *ctx, dict_fixup_ctx_t *fctx);
int dict_fixup_apply(dict_fixup_ctx_t *fctx);
return copied;
}
+/** Add an alias to an existing attribute
+ *
+ */
+int dict_attr_alias_add(fr_dict_attr_t const *parent, char const *alias, fr_dict_attr_t const *ref)
+{
+ fr_dict_attr_t const *da;
+ fr_dict_attr_t *self;
+ fr_hash_table_t *namespace;
+
+ da = dict_attr_by_name(NULL, parent, alias);
+ if (da) {
+ fr_strerror_printf("ALIAS '%s' conflicts with another attribute in namespace %s",
+ alias, parent->name);
+ return -1;
+ }
+
+ /*
+ * Note that we do NOT call fr_dict_attr_add() here.
+ *
+ * When that function adds two equivalent attributes, the
+ * second one is prioritized for printing. For ALIASes,
+ * we want the pre-existing one to be prioritized.
+ *
+ * i.e. you can lookup the ALIAS by "name", but you
+ * actually get returned "ref".
+ */
+ {
+ fr_dict_attr_flags_t flags = ref->flags;
+
+ flags.is_alias = 1; /* These get followed automatically by public functions */
+
+ self = dict_attr_alloc(parent->dict->pool, parent, alias, ref->attr, ref->type, (&(dict_attr_args_t){ .flags = &flags, .ref = ref }));
+ if (unlikely(!self)) return -1;
+ }
+
+ self->dict = parent->dict;
+
+ fr_assert(fr_dict_attr_ref(self) == ref);
+
+ namespace = dict_attr_namespace(parent);
+ if (!namespace) {
+ fr_strerror_printf("Attribute '%s' does not contain a namespace", parent->name);
+ error:
+ talloc_free(self);
+ return -1;
+ }
+
+ if (!fr_hash_table_insert(namespace, self)) {
+ fr_strerror_const("Internal error storing attribute");
+ goto error;
+ }
+
+ return 0;
+}
+
/** Add a protocol to the global protocol table
*
* Inserts a protocol into the global protocol table. Uses the root attributes