#include <freeradius-devel/util/dict.h>
#include <freeradius-devel/util/hash.h>
+#include <freeradius-devel/util/dl.h>
#include <freeradius-devel/protocol/base.h>
#define DICT_POOL_SIZE (1024 * 1024 * 2)
unsigned int vsa_parent; //!< varies with different protocols
int default_type_size; //!< for TLVs and VSAs
int default_type_length; //!< for TLVs and VSAs
+
+ dl_t *dl; //!< for validation
+ fr_dict_protocol_t const *proto; //!< protocol-specific validation functions
};
extern bool dict_initialised;
extern fr_table_num_ordered_t const date_precision_table[];
extern size_t date_precision_table_len;
-fr_dict_t *dict_alloc(TALLOC_CTX *ctx);
+fr_dict_t *dict_alloc(TALLOC_CTX *ctx, char const *name);
/** Initialise fields in a dictionary attribute structure
*
return 0;
}
- dict = dict_alloc(NULL);
+ dict = dict_alloc(NULL, argv[0]);
/*
* Set the root attribute with the protocol name
memcpy(&tmp, &dict_dir_default, sizeof(tmp));
dict_path = dict_subdir ? talloc_asprintf(NULL, "%s%c%s", dict_dir_default, FR_DIR_SEP, dict_subdir) : tmp;
- dict = dict_alloc(dict_ctx);
+ dict = dict_alloc(dict_ctx, NULL);
if (!dict) {
error:
if (!fr_dict_internal) talloc_free(dict);
#include <freeradius-devel/util/conf.h>
#include <freeradius-devel/util/dict_priv.h>
-#include <freeradius-devel/util/dl.h>
#include <freeradius-devel/util/hash.h>
#include <freeradius-devel/util/misc.h>
#include <freeradius-devel/util/proto.h>
///< wasn't provided.
TALLOC_CTX *dict_ctx;
+static dl_loader_t *dict_loader; //!< for protocol validation
+
static fr_hash_table_t *protocol_by_name = NULL; //!< Hash containing names of all the registered protocols.
static fr_hash_table_t *protocol_by_num = NULL; //!< Hash containing numbers of all the registered protocols.
return fr_hash_table_finddata(dict->values_by_alias, &find);
}
+static int dict_dlopen(fr_dict_t *dict, char const *name)
+{
+ char *module_name;
+
+ if (!name) return 0;
+
+ module_name = talloc_typed_asprintf(NULL, "libfreeradius-%s", name);
+
+ /*
+ * Pass in dict as the uctx so that we can get at it in
+ * any callbacks.
+ *
+ * Not all dictionaries have validation functions. It's
+ * a soft error if they don't exist.
+ */
+ dict->dl = dl_by_name(dict_loader, module_name, dict, false);
+
+ talloc_free(module_name);
+ return 0;
+}
+
static int _dict_free_autoref(UNUSED void *ctx, void *data)
{
fr_dict_t *dict = data;
/** Allocate a new dictionary
*
* @param[in] ctx to allocate dictionary in.
+ * @param[in] name the name of the protocol
* @return
* - NULL on memory allocation error.
*/
-fr_dict_t *dict_alloc(TALLOC_CTX *ctx)
+fr_dict_t *dict_alloc(TALLOC_CTX *ctx, char const *name)
{
fr_dict_t *dict;
dict->values_by_da = fr_hash_table_create(dict, dict_enum_value_hash, dict_enum_value_cmp, hash_pool_free);
if (!dict->values_by_da) goto error;
+ if (dict_dlopen(dict, name) < 0) goto error;
+
+ /*
+ * Try to load libfreeradius-NAME
+ */
+
return dict;
}
_fr_dict_dump(dict, dict->root, 0);
}
+/** Callback to automatically load validation routines for dictionaries.
+ *
+ * @param[in] dl the library we just loaded
+ * @param[in] symbol pointer to a fr_dict_protocol_t table
+ * @param[in] user_ctx the global context which we don't need
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+static int dict_onload_func(dl_t const *dl, void *symbol, UNUSED void *user_ctx)
+{
+ fr_dict_t *dict = talloc_get_type_abort(dl->uctx, fr_dict_t);
+ fr_dict_protocol_t const *proto = symbol;
+
+ /*
+ * Set the protocol-specific callbacks.
+ */
+ dict->proto = proto;
+
+ return 0;
+}
+
/** Initialise the global protocol hashes
*
* @note Must be called before any other dictionary functions.
talloc_free(dict_dir_default); /* Free previous value */
dict_dir_default = talloc_strdup(ctx, dict_dir);
+ dict_loader = dl_loader_init(ctx, NULL, NULL, false, false);
+ if (!dict_loader) return -1;
+
+ if (dl_symbol_init_cb_register(dict_loader, 0, "dict_protocol", dict_onload_func, NULL) < 0) {
+ return -1;
+ }
+
dict_initialised = true;
return 0;