25 RCSID(
"$Id: bddb466012355efd65b87ad783c546339d8d0943 $")
27 #define LOG_PREFIX mctx->mi->name
29 #include <freeradius-devel/server/base.h>
30 #include <freeradius-devel/server/module_rlm.h>
31 #include <freeradius-devel/server/modpriv.h>
32 #include <freeradius-devel/server/dl_module.h>
33 #include <freeradius-devel/server/rcode.h>
34 #include <freeradius-devel/server/tmpl.h>
35 #include <freeradius-devel/util/debug.h>
36 #include <freeradius-devel/util/types.h>
37 #include <freeradius-devel/util/value.h>
38 #include <freeradius-devel/unlang/xlat_func.h>
39 #include <freeradius-devel/unlang/call_env.h>
133 if (
unlikely((ret = func(ctx, &key_tmpl, t_rules, ci,
inst->driver_submodule->data, rule)) < 0))
return ret;
140 if (
inst->driver->key_parse)
return 0;
150 cf_log_err(ci,
"Driver only allows key type '%s', got '%s'",
156 cf_log_perr(ci,
"Can't convert key type '%s' to '%s'",
169 if (!
inst->driver->acquire) {
174 return inst->driver->acquire(
out, &
inst->config,
inst->driver_submodule->data, request);
182 if (!
inst->driver->release)
return;
183 if (!handle || !*handle)
return;
185 inst->driver->release(&
inst->config,
inst->driver_submodule->data, request, *handle);
196 return inst->driver->reconnect(handle, &
inst->config,
inst->driver_submodule->data, request);
209 if (
inst->driver->alloc)
return inst->driver->alloc(&
inst->config,
inst->driver_submodule->data, request);
230 if (!c || !*c || !
inst->driver->free)
return;
232 inst->driver->free(*c);
249 RDEBUG2(
"Merging cache entry into request");
251 while ((map = map_list_next(&c->
maps, map))) {
271 if (
inst->config.stats) {
300 ret =
inst->driver->find(&c, &
inst->config,
inst->driver_submodule->data, request, *handle, key);
311 RDEBUG2(
"No cache entry found for \"%pV\"", key);
327 RDEBUG2(
"Found entry for \"%pV\", but it expired %pV ago at %pV (packet received %pV). Removing it",
334 inst->driver->expire(&
inst->config,
inst->driver_submodule->data, request, handle, key);
340 RDEBUG2(
"Found entry for \"%pV\", but it was created before the current epoch. Removing it",
344 RDEBUG2(
"Found entry for \"%pV\"", key);
363 RDEBUG2(
"Expiring cache entry");
364 for (;;)
switch (
inst->driver->expire(&
inst->config,
inst->driver_submodule->data, request, *handle, key)) {
391 map_t const *map = NULL;
400 if ((
inst->config.max_entries > 0) &&
inst->driver->count &&
401 (
inst->driver->count(&
inst->config,
inst->driver_submodule->data, request, handle) >
inst->config.max_entries)) {
402 RWDEBUG(
"Cache is full: %d entries",
inst->config.max_entries);
410 map_list_init(&c->
maps);
412 RERROR(
"Failed copying key");
423 RDEBUG2(
"Creating new cache entry");
429 if (!maps)
goto skip_maps;
435 pool = talloc_pool(NULL, 2048);
436 while ((map = map_list_next(maps, map))) {
446 if (
map_to_vp(pool, &to_cache, request, map, NULL) < 0) {
460 case FR_CACHE_STATUS_ONLY:
461 case FR_CACHE_MERGE_NEW:
462 case FR_CACHE_ENTRY_HITS:
475 map_list_init(&c_map->
child);
480 switch (map->
lhs->type) {
509 REDEBUG(
"Failed copying attribute value");
521 map_list_insert_tail(&c->
maps, c_map);
523 talloc_free_children(pool);
533 if (
vp &&
vp->vp_bool) merge =
true;
540 ret =
inst->driver->insert(&
inst->config,
inst->driver_submodule->data, request, *handle, c);
571 if (!
inst->driver->set_ttl)
for (;;) {
574 ret =
inst->driver->insert(&
inst->config,
inst->driver_submodule->data, request, *handle, c);
596 ret =
inst->driver->set_ttl(&
inst->config,
inst->driver_submodule->data, request, *handle, c);
631 bool merge =
true, insert =
true, expire =
false, set_ttl =
false;
638 if (env->
key->vb_length == 0) {
639 REDEBUG(
"Zero length key string is invalid");
648 if (
vp &&
vp->vp_bool) {
670 if (
vp) merge =
vp->vp_bool;
673 if (
vp) insert =
vp->vp_bool;
677 if (
vp->vp_int32 == 0) {
679 }
else if (
vp->vp_int32 < 0) {
690 RDEBUG3(
"merge : %s", merge ?
"yes" :
"no");
691 RDEBUG3(
"insert : %s", insert ?
"yes" :
"no");
692 RDEBUG3(
"expire : %s", expire ?
"yes" :
"no");
732 if (expire && ((exists == -1) || (exists == 1))) {
766 if ((exists < 0) && (insert || set_ttl)) {
793 if (set_ttl && (exists == 1)) {
822 if (insert && (exists == 0)) {
860 switch (
vp->
da->attr) {
862 case FR_CACHE_STATUS_ONLY:
863 case FR_CACHE_ALLOW_MERGE:
864 case FR_CACHE_ALLOW_INSERT:
865 case FR_CACHE_MERGE_NEW:
911 .dict_def = request->dict,
912 .list_def = request_attr_request,
913 .prefix = TMPL_ATTR_REF_PREFIX_AUTO
937 while ((map = map_list_next(&c->maps, map))) {
1021 switch (
vp->
da->attr) {
1023 case FR_CACHE_STATUS_ONLY:
1024 case FR_CACHE_ALLOW_MERGE:
1025 case FR_CACHE_ALLOW_INSERT:
1026 case FR_CACHE_MERGE_NEW:
1052 if (env->
key->vb_length == 0) {
1053 REDEBUG(
"Zero length key string is invalid");
1090 if (env->
key->vb_length == 0) {
1091 REDEBUG(
"Zero length key string is invalid");
1104 RDEBUG2(
"Entry not found to load");
1130 bool expire =
false;
1135 if (env->
key->vb_length == 0) {
1136 REDEBUG(
"Zero length key string is invalid");
1146 ttl =
inst->config.ttl;
1149 if (
vp->vp_int32 == 0) {
1151 }
else if (
vp->vp_int32 < 0) {
1186 DEBUG3(
"Expiring cache entry");
1222 if (env->
key->vb_length == 0) {
1223 REDEBUG(
"Zero length key string is invalid");
1232 ttl =
inst->config.ttl;
1234 if (
vp && (
vp->vp_int32 > 0)) {
1289 if (env->
key->vb_length == 0) {
1290 REDEBUG(
"Zero length key string is invalid");
1303 REDEBUG2(
"Entry not found to delete");
1335 if (env->
key->vb_length == 0) {
1336 REDEBUG(
"Zero length key string is invalid");
1346 ttl =
inst->config.ttl;
1349 if (
vp->vp_int32 < 0) {
1399 talloc_free_children(
inst);
1412 cf_log_err(map->
ci,
"Destination must be an attribute ref or a list");
1430 MEM(maps = talloc(parsed, map_list_t));
1431 map_list_init(maps);
1440 if (map_list_empty(maps)) {
1441 cf_log_err(update,
"Update section must not be empty");
1471 if (
inst->config.epoch != 0) {
1472 cf_log_err(
conf,
"Must not set 'epoch' in the configuration files");
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
static int const char char buffer[256]
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
void call_env_parsed_free(call_env_parsed_head_t *parsed, call_env_parsed_t *ptr)
Remove a call_env_parsed_t from the list of parsed call envs.
call_env_parsed_t * call_env_parsed_add(TALLOC_CTX *ctx, call_env_parsed_head_t *head, call_env_parser_t const *rule)
Allocate a new call_env_parsed_t structure and add it to the list of parsed call envs.
int call_env_parse_pair(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, UNUSED call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
Standard function we use for parsing call env pairs.
void call_env_parsed_set_data(call_env_parsed_t *parsed, void const *data)
Assign data to a call_env_parsed_t.
#define CALL_ENV_TERMINATOR
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
module_instance_t const * mi
Module instance that the callenv is registered to.
#define FR_CALL_ENV_SUBSECTION_FUNC(_name, _name2, _flags, _func)
Specify a call_env_parser_t which parses a subsection using a callback function.
int(* call_env_parse_pair_t)(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, call_env_parser_t const *rule)
Callback for performing custom parsing of a CONF_PAIR.
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
#define FR_CALL_ENV_PARSE_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _parse_field)
Specify a call_env_parser_t which writes out the result of the parsing phase to the field specified.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Defines a CONF_PAIR to C data type mapping.
Common header for all CONF_* types.
A section grouping multiple CONF_PAIR.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_perr(_cf, _fmt,...)
static void * fr_dcursor_remove(fr_dcursor_t *cursor)
Remove the current item.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
fr_dcursor_eval_t void const * uctx
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
static bool fr_dict_attr_is_top_level(fr_dict_attr_t const *da)
Return true if this attribute is parented directly off the dictionary root.
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
static xlat_action_t cache_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Allow single attribute values to be retrieved from the cache.
#define REXDENT()
Exdent (unindent) R* messages by one level.
#define RPEDEBUG(fmt,...)
#define REDEBUG2(fmt,...)
#define RINDENT()
Indent R* messages by one level.
int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, UNUSED void *uctx)
Convert a map to a fr_pair_t.
int map_afrom_cs(TALLOC_CTX *ctx, map_list_t *out, CONF_SECTION *cs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules, map_validate_t validate, void *uctx, unsigned int max)
Convert a config section into an attribute map.
int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert map_t to fr_pair_t (s) and add them to a request_t.
ssize_t map_print(fr_sbuff_t *out, map_t const *map)
Print a map to a string.
void map_debug_log(request_t *request, map_t const *map, fr_pair_t const *vp)
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_BOOL
A truth value.
static bool is_printable(void const *value, size_t len)
Check whether the string is made up of printable UTF8 chars.
int unlang_fixup_update(map_t *map, void *ctx)
Validate and fixup a map that's part of an update section.
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Module instance to detach.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for detach calls.
Temporary structure to hold arguments for instantiation calls.
int module_rlm_submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic conf_parser_t func for loading drivers.
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
module_t common
Common fields presented by all modules.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
static const conf_parser_t config[]
#define pair_update_request(_attr, _da)
#define RDEBUG_ENABLED2()
#define RETURN_MODULE_RCODE(_rcode)
#define RETURN_MODULE_INVALID
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_FAIL
Module failed, don't reply.
@ RLM_MODULE_NOTFOUND
User not found.
@ RLM_MODULE_UPDATED
OK (pairs modified).
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
#define RETURN_MODULE_NOTFOUND
static int cache_acquire(rlm_cache_handle_t **out, rlm_cache_t const *inst, request_t *request)
Get exclusive use of a handle to access the cache.
static int mod_detach(module_detach_ctx_t const *mctx)
Free any memory allocated under the instance.
static unlang_action_t mod_method_update(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Create, or update a cache entry.
static fr_dict_attr_t const * attr_cache_allow_merge
static int cache_key_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, call_env_parser_t const *rule)
fr_value_box_t * key
To lookup the cache entry with.
static int cache_update_section_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, call_env_parser_t const *rule)
static unlang_action_t mod_method_ttl(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Change the TTL on an existing entry.
static fr_dict_attr_t const * attr_cache_ttl
static fr_dict_attr_t const * attr_cache_merge_new
static void cache_release(rlm_cache_t const *inst, request_t *request, rlm_cache_handle_t **handle)
Release a handle we previously acquired.
static fr_dict_t const * dict_freeradius
static int cache_verify(map_t *map, void *uctx)
Verify that a map in the cache section makes sense.
static rlm_cache_entry_t * cache_alloc(rlm_cache_t const *inst, request_t *request)
Allocate a cache entry.
map_list_t * maps
Attribute map applied to cache entries.
static unlang_action_t cache_set_ttl(rlm_rcode_t *p_result, rlm_cache_t const *inst, request_t *request, rlm_cache_handle_t **handle, rlm_cache_entry_t *c)
Update the TTL of an entry.
static unlang_action_t mod_cache_it(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Do caching checks.
static fr_dict_attr_t const * attr_cache_allow_insert
static unlang_action_t cache_insert(rlm_rcode_t *p_result, rlm_cache_t const *inst, request_t *request, rlm_cache_handle_t **handle, fr_value_box_t const *key, map_list_t const *maps, fr_time_delta_t ttl)
Create and insert a cache entry.
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Register module xlats.
static fr_dict_attr_t const * attr_cache_status_only
static void cache_free(rlm_cache_t const *inst, rlm_cache_entry_t **c)
Free memory associated with a cache entry.
static unlang_action_t mod_method_status(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Get the status by ${key} (without load)
static unlang_action_t mod_method_store(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Create, or update a cache entry.
static fr_dict_attr_t const * attr_cache_entry_hits
static unlang_action_t mod_method_load(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Load the avps by ${key}.
static xlat_arg_parser_t const cache_xlat_args[]
static int cache_reconnect(rlm_cache_handle_t **handle, rlm_cache_t const *inst, request_t *request)
Reconnect an suspected inviable handle.
static const call_env_method_t cache_method_env
fr_dict_attr_autoload_t rlm_cache_dict_attr[]
fr_dict_autoload_t rlm_cache_dict[]
static xlat_action_t cache_ttl_get_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
static rlm_rcode_t cache_merge(rlm_cache_t const *inst, request_t *request, rlm_cache_entry_t *c)
Merge a cached entry into a request_t.
static void cache_unref(request_t *request, rlm_cache_t const *inst, rlm_cache_entry_t *entry, rlm_cache_handle_t *handle)
Release the allocated resources and cleanup the avps.
int submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static const conf_parser_t module_config[]
static unlang_action_t cache_expire(rlm_rcode_t *p_result, rlm_cache_t const *inst, request_t *request, rlm_cache_handle_t **handle, fr_value_box_t const *key)
Expire a cache entry (removing it from the datastore)
static unlang_action_t mod_method_clear(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Delete the entries by ${key}.
static unlang_action_t cache_find(rlm_rcode_t *p_result, rlm_cache_entry_t **out, rlm_cache_t const *inst, request_t *request, rlm_cache_handle_t **handle, fr_value_box_t const *key)
Find a cached entry.
static int mod_instantiate(module_inst_ctx_t const *mctx)
Create a new rlm_cache_instance.
fr_value_box_t key
Key used to identify entry.
map_list_t maps
Head of the maps list.
fr_unix_time_t created
When the entry was created.
long long int hits
How many times the entry has been retrieved.
@ CACHE_RECONNECT
Handle needs to be reconnected.
@ CACHE_OK
Cache entry found/updated.
@ CACHE_MISS
Cache entry notfound.
fr_unix_time_t expires
When the entry expires.
Configuration for the rlm_cache module.
static int instantiate(module_inst_ctx_t const *mctx)
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
char const * name
Instance name e.g. user_database.
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
void * boot
Data allocated during the boostrap phase.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
module_t * exported
Public module structure.
Named methods exported by a module.
#define tmpl_value(_tmpl)
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
#define tmpl_is_attr(vpt)
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
@ TMPL_TYPE_DATA
Value in native boxed format.
int tmpl_attr_afrom_list(TALLOC_CTX *ctx, tmpl_t **out, tmpl_t const *list, fr_dict_attr_t const *da)
Create a new tmpl from a list tmpl and a da.
static bool tmpl_attr_tail_da_is_structural(tmpl_t const *vpt)
Return true if the the last attribute reference is a structural attribute.
static bool tmpl_is_list(tmpl_t const *vpt)
ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, fr_sbuff_t *name, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
static fr_type_t tmpl_cast_get(tmpl_t *vpt)
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
tmpl_t * tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len)
Create a new heap allocated tmpl_t.
int tmpl_cast_set(tmpl_t *vpt, fr_type_t type)
Set a cast for a tmpl.
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Optional arguments passed to vp_tmpl functions.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
fr_token_t op
The operator that controls insertion of the dst attribute.
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
map_list_t child
parent map, for nested ones
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
CONF_ITEM * ci
Config item that the map was created from.
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
#define talloc_get_type_abort_const
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
#define fr_time_delta_ispos(_a)
static fr_unix_time_t fr_unix_time_from_sec(int64_t sec)
#define fr_unix_time_sub(_a, _b)
Subtract one time from another.
static fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
Convert an fr_time_t (internal time) to our version of unix time (wallclock time)
#define fr_unix_time_lt(_a, _b)
#define fr_unix_time_add(_a, _b)
Add a time/time delta together.
A time delta, a difference in time measured in nanoseconds.
bool required
Argument must be present, and non-empty.
#define XLAT_ARG_PARSER_TERMINATOR
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition for a single argument consumend by an xlat function.
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
#define fr_box_time_delta(_val)
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
#define fr_box_time(_val)
static size_t char ** out
#define fr_box_date(_val)
void * env_data
Expanded call env data.
module_ctx_t const * mctx
Synthesised module calling ctx.
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
void xlat_func_call_env_set(xlat_t *x, call_env_method_t const *env_method)
Register call environment of an xlat.