call_env_parsed->rule = call_env;
call_env_parsed->opt_count = opt_count;
call_env_parsed->multi_index = multi_index;
+ if (call_env->pair.type == CALL_ENV_TYPE_TMPL_ONLY) call_env_parsed->tmpl_only = true;
if (cp) {
value = cf_pair_value(cp);
void **tmpl_out, call_env_parsed_t const *env,
fr_value_box_list_t *tmpl_expanded)
{
- fr_value_box_t *vb = fr_value_box_list_head(tmpl_expanded);
+ fr_value_box_t *vb;
+ if (tmpl_out) *tmpl_out = env->tmpl;
+ if (env->tmpl_only) return 0;
+
+ vb = fr_value_box_list_head(tmpl_expanded);
if (!vb) {
if (!env->rule->pair.nullable) {
RPEDEBUG("Failed to evaluate required module option %s", env->rule->name);
if (!fr_value_box_list_initialised((fr_value_box_list_t *)out)) fr_value_box_list_init((fr_value_box_list_t *)out);
fr_value_box_list_insert_tail((fr_value_box_list_t *)out, vb);
break;
+
+ case CALL_ENV_TYPE_TMPL_ONLY:
+ fr_assert(0);
+ break;
}
}
- if (tmpl_out) *tmpl_out = env->tmpl;
-
return 0;
}
void **env_data; //!< Final destination structure for value boxes.
} call_env_ctx_t;
+static unlang_action_t call_env_expand_repeat(rlm_rcode_t *p_result, int *priority, request_t *request, void *uctx);
+
/** Start the expansion of a call environment tmpl.
*
*/
ctx = *call_env_ctx->env_data;
env = call_env_ctx->last_expanded;
+ /*
+ * If we only need the tmpl, use the repeat function to set the pointer.
+ */
+ if (env->tmpl_only) {
+ if (unlang_function_repeat_set(request, call_env_expand_repeat) < 0) return UNLANG_ACTION_FAIL;
+ return UNLANG_ACTION_CALCULATE_RESULT;
+ }
+
/*
* Multi pair options should allocate boxes in the context of the array
*/
static unlang_action_t call_env_expand_repeat(UNUSED rlm_rcode_t *p_result, UNUSED int *priority,
request_t *request, void *uctx)
{
- void *out, *tmpl_out = NULL;
+ void *out = NULL, *tmpl_out = NULL;
call_env_ctx_t *call_env_ctx = talloc_get_type_abort(uctx, call_env_ctx_t);
call_env_parsed_t const *env;
env = call_env_ctx->last_expanded;
if (!env) return UNLANG_ACTION_CALCULATE_RESULT;
+ if (env->tmpl_only) goto tmpl_only;
/*
* Find the location of the output
*/
out = ((uint8_t *)array) + env->rule->pair.size * env->multi_index;
}
+tmpl_only:
if (env->rule->pair.tmpl_offset) tmpl_out = ((uint8_t *)*call_env_ctx->env_data) + env->rule->pair.tmpl_offset;
if (call_env_value_parse(*call_env_ctx->env_data, request, out, tmpl_out, env,
typedef enum {
CALL_ENV_TYPE_VALUE_BOX = 1,
- CALL_ENV_TYPE_VALUE_BOX_LIST
+ CALL_ENV_TYPE_VALUE_BOX_LIST,
+ CALL_ENV_TYPE_TMPL_ONLY
} call_env_dest_t;
/** Per method call config
size_t opt_count; //!< Number of instances found of this option.
size_t multi_index; //!< Array index for this instance.
call_env_t const *rule; //!< Used to produce this.
+ bool tmpl_only; //!< Don't evaluate before module / xlat call.
+ ///< Only the tmpl reference is needed.
};
FR_DLIST_FUNCS(call_env_parsed, call_env_parsed_t, entry)
.type_name = FR_CALL_ENV_DST_TYPE_NAME(_struct, _field), \
.tmpl_offset = offsetof(_struct, _tmpl_field) }
+/** Version of the above which only sets the field for a pointer to the tmpl
+ */
+#define FR_CALL_ENV_TMPL_ONLY_OFFSET(_name, _cast_type, _struct, _tmpl_field, _dflt, _dflt_quote, _required) \
+ .name = _name, \
+ .type = _cast_type, \
+ .dflt = _dflt, \
+ .dflt_quote = _dflt_quote, \
+ .pair = { .required = _required, \
+ .type = CALL_ENV_TYPE_TMPL_ONLY, \
+ .tmpl_offset = offsetof(_struct, _tmpl_field) }
+
#define FR_CALL_ENV_SUBSECTION(_name, _ident2, _subcs ) \
.name = _name, \
.type = FR_TYPE_SUBSECTION, \