The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_brotli.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: ed081cc16421614c3c0c448d78b336a4b9d42c77 $
19 * @file rlm_brotli.c
20 * @brief Add support for brotli compression
21 *
22 * @copyright 2024 The FreeRADIUS server project
23 * @copyright 2024 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
24 */
25RCSID("$Id: ed081cc16421614c3c0c448d78b336a4b9d42c77 $")
26
27#define LOG_PREFIX mctx->mi->name
28
29#include <brotli/encode.h>
30#include <brotli/decode.h>
31
32#include <freeradius-devel/util/atexit.h>
33#include <freeradius-devel/util/value.h>
34
35#include <freeradius-devel/server/module_rlm.h>
36
37#include <freeradius-devel/unlang/xlat.h>
38#include <freeradius-devel/unlang/xlat_func.h>
39
40static int quality_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
41static int window_bits_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
42static int block_bits_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
43
44typedef struct {
45 BrotliEncoderMode mode; //!< Default mode to use when compressing data.
46 int quality; //!< Default quality to use when compressing data.
47 int window_bits; //!< Default window bits to use when compressing data.
48 int block_bits; //!< Default block bits to use when compressing data.
49 bool block_bits_is_set; //!< Whether block_bits has been set.
51
52typedef struct {
53 size_t max_size; //!< Maximum amount we attempt to decode
55
56typedef struct {
57 rlm_brotli_compress_t compress; //!< Compression settings
58 rlm_brotli_decompress_t decompress; //!< Decompression settings
59 bool large_window; //!< non-standard "large", window size.
61
63 { L("font"), BROTLI_MODE_FONT }, //!< Probably not useful?
64 { L("generic"), BROTLI_MODE_GENERIC },
65 { L("text"), BROTLI_MODE_TEXT },
66};
68
70 { FR_CONF_OFFSET("mode", rlm_brotli_compress_t, mode), .dflt = "generic",
71 .func = cf_table_parse_int, .uctx = &(cf_table_parse_ctx_t){ .table = brotli_mode, .len = &brotli_mode_len } },
72 { FR_CONF_OFFSET("quality", rlm_brotli_compress_t, quality), .dflt = STRINGIFY(BROTLI_DEFAULT_QUALITY), .func = quality_parse },
73 { FR_CONF_OFFSET("window_bits", rlm_brotli_compress_t, window_bits), .dflt = STRINGIFY(BROTLI_DEFAULT_WINDOW), .func = window_bits_parse },
74 { FR_CONF_OFFSET_IS_SET("block_bits", FR_TYPE_INT32, 0, rlm_brotli_compress_t, block_bits), .dflt = STRINGIFY(BROTLI_MAX_INPUT_BLOCK_BITS), .func = block_bits_parse },
76};
77
79 { FR_CONF_OFFSET_TYPE_FLAGS("max_size", FR_TYPE_SIZE, 0, rlm_brotli_decompress_t, max_size), .dflt = "10M" }, /* 10MB */
81};
82
83static const conf_parser_t module_config[] = {
85 { FR_CONF_OFFSET_SUBSECTION("decompress", 0, rlm_brotli_t, decompress, module_decompress_config) },
86 { FR_CONF_OFFSET("large_window", rlm_brotli_t, large_window), .dflt = "no" }, /* For both compress and decompress */
87
89};
90
91static _Thread_local TALLOC_CTX *brotli_pool; //!< Thread-local pool for brotli state
92
93static inline CC_HINT(always_inline)
94TALLOC_CTX *brotli_pool_get(void)
95{
96 if (unlikely(brotli_pool == NULL)) {
97 TALLOC_CTX *pool;
98
99 MEM(pool = talloc_pool(NULL, 4096));
100 fr_atexit_thread_local(brotli_pool, fr_atexit_talloc_free, pool);
101
102 }
103 return brotli_pool;
104}
105
106static void *brotli_talloc_alloc(void *uctx, size_t size)
107{
108 void *ptr = talloc_size(uctx, size);
109 return ptr;
110}
111
112static void brotli_talloc_free(UNUSED void *uctx, void *to_free)
113{
114 talloc_free(to_free);
115}
116
117static int quality_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
118{
119 int ret;
120 int value;
121
122 ret = cf_pair_parse_value(ctx, out, parent, ci, rule);
123 if (ret < 0) return ret;
124
125 value = *(int *) out;
126 if ((value > BROTLI_MAX_QUALITY) || (value < BROTLI_MIN_QUALITY)) {
127 cf_log_err(ci, "Allowed values are between %d-%d, got %d", BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY, value);
128 return -1;
129 }
130
131 return 0;
132}
133
134static int window_bits_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
135{
136 int ret;
137 int value;
138
139 ret = cf_pair_parse_value(ctx, out, parent, ci, rule);
140 if (ret < 0) return ret;
141
142 value = *(int *) out;
143 if ((value > BROTLI_MAX_WINDOW_BITS) || (value < BROTLI_MIN_WINDOW_BITS)) {
144 cf_log_err(ci, "Allowed values are between %d-%d, got %d", BROTLI_MIN_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS, value);
145 return -1;
146 }
147
148 return 0;
149}
150
151static int block_bits_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
152{
153 int ret;
154 int value;
155
156 ret = cf_pair_parse_value(ctx, out, parent, ci, rule);
157 if (ret < 0) return ret;
158
159 value = *(int *) out;
160 if ((value > BROTLI_MAX_INPUT_BLOCK_BITS) || (value < BROTLI_MIN_INPUT_BLOCK_BITS)) {
161 cf_log_err(ci, "Allowed values are between %d-%d, got %d", BROTLI_MIN_INPUT_BLOCK_BITS, BROTLI_MAX_INPUT_BLOCK_BITS, value);
162 return -1;
163 }
164
165 return 0;
166}
167
169 { .required = true, .type = FR_TYPE_OCTETS }, /* Input converted to raw binary data. All inputs will be added to the same stream */
171};
172
173/** Produce a brotli compressed string
174 *
175 * Example:
176@verbatim
177%brotli.compress(<input>) == <compressed data>
178@endverbatim
179 *
180 * @ingroup xlat_functions
181 */
183 xlat_ctx_t const *xctx,
184 request_t *request, fr_value_box_list_t *args)
185{
187 fr_value_box_t const *data_vb;
188
189 BrotliEncoderState *state;
190 TALLOC_CTX *pool;
191
192 size_t available_out = 0, total_out = 0, total_in = 0;
193 fr_value_box_t *out_vb;
194 uint8_t *out_buff;
195
197
198 XLAT_ARGS(args, &data_vb);
199
200 fr_assert(fr_type_is_group(data_vb->type));
201
202 /*
203 * Calculate the maximum size of our output buffer
204 * and pre-allocate that. We'll shrink it later.
205 */
206 fr_value_box_list_foreach(&data_vb->vb_group, vb) {
207 total_in += vb->vb_length;
208 available_out += BrotliEncoderMaxCompressedSize(vb->vb_length);
209 }
210
211 MEM(out_vb = fr_value_box_alloc(ctx, FR_TYPE_OCTETS, NULL));
212 MEM(fr_value_box_mem_alloc(out_vb, &out_buff, out_vb, NULL, available_out, false) == 0);
213
214 pool = brotli_pool_get();
215 MEM(state = BrotliEncoderCreateInstance(brotli_talloc_alloc, brotli_talloc_free, pool));
216
217 BrotliEncoderSetParameter(state, BROTLI_PARAM_MODE, inst->compress.mode);
218 BrotliEncoderSetParameter(state, BROTLI_PARAM_QUALITY, inst->compress.quality);
219 BrotliEncoderSetParameter(state, BROTLI_PARAM_LGWIN, inst->compress.window_bits);
220 if (inst->compress.block_bits_is_set) BrotliEncoderSetParameter(state, BROTLI_PARAM_LGBLOCK, inst->compress.block_bits);
221 BrotliEncoderSetParameter(state, BROTLI_PARAM_LARGE_WINDOW, inst->large_window ? BROTLI_TRUE : BROTLI_FALSE);
222 BrotliEncoderSetParameter(state, BROTLI_PARAM_SIZE_HINT, total_in);
223 /*
224 * Loop over all the input data and ingest it into brotli
225 * which will add it to an internal buffer (hopefully
226 * allocated, in our thread local pool).
227 */
228 {
229 fr_value_box_list_foreach(&data_vb->vb_group, vb) {
230 size_t available_in = vb->vb_length;
231 const uint8_t *next_in = vb->vb_octets;
232 bool more = fr_value_box_list_next(&data_vb->vb_group, vb) != NULL;
233
234 /*
235 * In reality this loop is probably unnecessary,
236 * but the brotli docs state:
237 *
238 * "client should repeat BROTLI_OPERATION_FINISH operation until available_in becomes 0,
239 * and BrotliEncoderHasMoreOutput returns BROTLI_FALSE"
240 */
241 do {
242 BROTLI_BOOL bret;
243
244 bret = BrotliEncoderCompressStream(state,
245 more ? BROTLI_OPERATION_PROCESS : BROTLI_OPERATION_FINISH,
246 &available_in, &next_in, &available_out, &out_buff, &total_out);
247 if (bret == BROTLI_FALSE) {
248 fr_assert_msg(0, "BrotliEncoderCompressStream returned false, this shouldn't happen");
249 RERROR("BrotliEncoderCompressStream failed");
250 ret = XLAT_ACTION_FAIL;
251 goto finish;
252 }
253 } while (more && (available_in > 0) && (BrotliEncoderHasMoreOutput(state) == BROTLI_FALSE));
254
255 /*
256 * There's no reason brotli wouldn't consume the complete
257 * buffer on BROTLI_OPERATION_PROCESS.
258 */
259 fr_assert(available_in == 0);
260 }
261 }
262
263 /*
264 * Realloc to the correct size if necessary
265 */
266 if (available_out != 0) MEM(fr_value_box_mem_realloc(out_vb, NULL, out_vb, total_out) == 0);
267
268 fr_dcursor_insert(out, out_vb);
269
270finish:
271 BrotliEncoderDestroyInstance(state);
272 talloc_free_children(pool);
273
274 return ret;
275}
276
278 { .required = true, .single = true, .type = FR_TYPE_OCTETS },
280};
281
282/** Decompress a brotli string
283 *
284 * Example:
285@verbatim
286%brotli.decompress(<input>) == <decompressed data>
287@endverbatim
288 *
289 * @ingroup xlat_functions
290 */
292 xlat_ctx_t const *xctx,
293 request_t *request, fr_value_box_list_t *args)
294{
296 fr_value_box_t const *data_vb;
297
298 BrotliDecoderState *state;
299 TALLOC_CTX *pool;
300
301 fr_value_box_t *out_vb;
302
303 size_t total_in;
304 size_t available_out;
305 size_t total_out = 0;
306
307 uint8_t const *in_buff;
308 uint8_t *out_buff;
309
311
312 XLAT_ARGS(args, &data_vb);
313
314 MEM(out_vb = fr_value_box_alloc(ctx, FR_TYPE_OCTETS, NULL));
315 available_out = (data_vb->vb_length * 2);
316 MEM(fr_value_box_mem_alloc(out_vb, &out_buff, out_vb, NULL, available_out, false) == 0);
317
318 pool = brotli_pool_get();
319 MEM(state = BrotliDecoderCreateInstance(brotli_talloc_alloc, brotli_talloc_free, pool));
320
321 BrotliDecoderSetParameter(state, BROTLI_DECODER_PARAM_LARGE_WINDOW, inst->large_window ? BROTLI_TRUE : BROTLI_FALSE);
322
323 total_in = data_vb->vb_length;
324 in_buff = data_vb->vb_octets;
325
326 for (;;) {
327 switch (BrotliDecoderDecompressStream(state, &total_in, &in_buff, &available_out, &out_buff, &total_out)) {
328 default:
329 case BROTLI_DECODER_RESULT_ERROR:
330 {
331 BrotliDecoderErrorCode error = BrotliDecoderGetErrorCode(state);
332 REDEBUG("Decompressing brotli data failed - %s", BrotliDecoderErrorString(error));
333 ret = XLAT_ACTION_FAIL;
334 goto finish;
335 }
336
337 case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
338 REDEBUG("Incomplete or truncated brotli data provided. Decompressor wants more input...");
339 ret = XLAT_ACTION_FAIL;
340 goto finish;
341
342 case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
343 {
344 size_t extra = out_vb->vb_length;
345
346 /*
347 * Stop runaway brotli decodings...
348 */
349 if ((out_vb->vb_length + extra) > inst->decompress.max_size) {
350 RERROR("Decompressed data exceeds maximum size of %zu", inst->decompress.max_size);
351 ret = XLAT_ACTION_FAIL;
352 goto finish;
353 }
354
355 MEM(fr_value_box_mem_realloc(out_vb, &out_buff, out_vb, out_vb->vb_length + extra) == 0);
356 available_out += extra;
357 }
358 continue; /* Again! */
359
360 case BROTLI_DECODER_RESULT_SUCCESS:
361 if (BrotliDecoderIsFinished(state) == BROTLI_TRUE) {
362 MEM(fr_value_box_mem_realloc(out_vb, &out_buff, out_vb, total_out) == 0);
363 fr_dcursor_insert(out, out_vb);
364 goto finish;
365 }
366 continue; /* Again! */
367 }
368 }
369
370finish:
371 BrotliDecoderDestroyInstance(state);
372 talloc_free_children(pool);
373
374 return ret;
375}
376
377static int mod_bootstrap(module_inst_ctx_t const *mctx)
378{
379 xlat_t *xlat;
380
381 if (unlikely((xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "compress", brotli_xlat_compress,
382 FR_TYPE_OCTETS)) == NULL)) return -1;
384
385 if (unlikely((xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "decompress", brotli_xlat_decompress,
386 FR_TYPE_OCTETS)) == NULL)) return -1;
388
389 return 0;
390}
391
392/*
393 * The module name should be the only globally exported symbol.
394 * That is, everything else should be 'static'.
395 *
396 * If the module needs to temporarily modify it's instantiation
397 * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
398 * The server will then take care of ensuring that the module
399 * is single-threaded.
400 */
403 .common = {
404 .magic = MODULE_MAGIC_INIT,
405 .name = "brotli",
406 .inst_size = sizeof(rlm_brotli_t),
407 .bootstrap = mod_bootstrap,
409 }
410};
va_list args
Definition acutest.h:770
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition atexit.h:220
#define RCSID(id)
Definition build.h:488
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:210
#define STRINGIFY(x)
Definition build.h:198
#define unlikely(_x)
Definition build.h:384
#define UNUSED
Definition build.h:318
#define NUM_ELEMENTS(_t)
Definition build.h:340
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
Definition cf_parse.c:1635
int cf_pair_parse_value(TALLOC_CTX *ctx, void *out, UNUSED void *base, CONF_ITEM *ci, conf_parser_t const *rule)
Parses a CONF_PAIR into a C data type.
Definition cf_parse.c:213
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:611
#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
Definition cf_parse.h:280
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
Definition cf_parse.h:294
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Definition cf_parse.h:309
#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
Definition cf_parse.h:238
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
Common header for all CONF_* types.
Definition cf_priv.h:49
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:285
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition dcursor.h:435
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:212
#define MEM(x)
Definition debug.h:46
Test enumeration values.
Definition dict_test.h:92
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
static xlat_action_t brotli_xlat_decompress(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Decompress a brotli string.
Definition rlm_brotli.c:291
static xlat_action_t brotli_xlat_compress(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Produce a brotli compressed string.
Definition rlm_brotli.c:182
talloc_free(hp)
#define RERROR(fmt,...)
Definition log.h:310
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_OCTETS
Raw octets.
unsigned char uint8_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
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)
Definition module_rlm.c:247
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
static const conf_parser_t config[]
Definition base.c:163
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
static const conf_parser_t module_decompress_config[]
Definition rlm_brotli.c:78
static int block_bits_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Definition rlm_brotli.c:151
module_rlm_t rlm_brotli
Definition rlm_brotli.c:402
static void brotli_talloc_free(UNUSED void *uctx, void *to_free)
Definition rlm_brotli.c:112
static const conf_parser_t module_compress_config[]
Definition rlm_brotli.c:69
bool large_window
non-standard "large", window size.
Definition rlm_brotli.c:59
int quality
Default quality to use when compressing data.
Definition rlm_brotli.c:46
static xlat_arg_parser_t const brotli_xlat_compress_args[]
Definition rlm_brotli.c:168
static fr_table_num_sorted_t const brotli_mode[]
Definition rlm_brotli.c:62
static xlat_arg_parser_t const brotli_xlat_decompress_args[]
Definition rlm_brotli.c:277
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_brotli.c:377
static int window_bits_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Definition rlm_brotli.c:134
rlm_brotli_decompress_t decompress
Decompression settings.
Definition rlm_brotli.c:58
static int quality_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Definition rlm_brotli.c:117
size_t max_size
Maximum amount we attempt to decode.
Definition rlm_brotli.c:53
static size_t brotli_mode_len
Definition rlm_brotli.c:67
BrotliEncoderMode mode
Default mode to use when compressing data.
Definition rlm_brotli.c:45
static TALLOC_CTX * brotli_pool_get(void)
Definition rlm_brotli.c:94
bool block_bits_is_set
Whether block_bits has been set.
Definition rlm_brotli.c:49
int block_bits
Default block bits to use when compressing data.
Definition rlm_brotli.c:48
int window_bits
Default window bits to use when compressing data.
Definition rlm_brotli.c:47
rlm_brotli_compress_t compress
Compression settings.
Definition rlm_brotli.c:57
static _Thread_local TALLOC_CTX * brotli_pool
Thread-local pool for brotli state.
Definition rlm_brotli.c:91
static const conf_parser_t module_config[]
Definition rlm_brotli.c:83
static void * brotli_talloc_alloc(void *uctx, size_t size)
Definition rlm_brotli.c:106
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:291
void * boot
Data allocated during the boostrap phase.
Definition module.h:294
eap_aka_sim_process_conf_t * inst
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define talloc_get_type_abort_const
Definition talloc.h:110
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:383
unsigned int required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:145
static fr_slen_t parent
Definition pair.h:858
#define fr_type_is_group(_x)
Definition types.h:376
int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Pre-allocate an octets buffer for filling by the caller.
Definition value.c:4999
int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
Change the length of a buffer already allocated to a value box.
Definition value.c:5032
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:644
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:224
static size_t char ** out
Definition value.h:1030
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition xlat_ctx.h:52
An xlat calling ctx.
Definition xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:363