| >>= | Perform right shift. The value of the _<attribute>_ is shifted right by the value of _<rhs>_
|=====
+There are also _filtering_operators. These operators ensure that the
+value of the attribute passes the filter. If the attribute being
+checked does not exist, it is created.
+
+.Attribute Filtering Operators
+[options="header"]
+[cols="10%,90%"]
+|=====
+| Operator | Description
+| < | Ensure that the _<lhs>_ attribute exists, and has value less than the _<rhs>_
+| <= | Ensure that the _<lhs>_ attribute exists, and has value less than or equal to the _<rhs>_
+| > | Ensure that the _<lhs>_ attribute exists, and has value greater than the _<rhs>_
+| >= | Ensure that the _<lhs>_ attribute exists, and has value greater than than or equal to the _<rhs>_
+|=====
+
The _<rhs>_ can be a reference to another attribute
(e.g. `request.Filter-Id`). If the field is a double-quoted string,
it undergoes xref:xlat/index.adoc[dynamic expansion], and the resulting
#
expiration {
if (&control.Expiration) {
- if (&control.Expiration < "%l") {
+ time_delta timeout
+
+ #
+ # %l is "when the server received the reuest"
+ #
+ if (&control.Expiration < %l) {
disallow
+ return
}
- elsif (!&reply.Session-Timeout || (&Session-Timeout > "%{expr:%{Expiration} - %l}")) {
- &reply.Session-Timeout := %{expr:%{Expiration} - %l}
- }
+ &timeout = &control.Expiration - %l
+
+ &reply.Session-Timeout <= &timeout
}
}
/*
* Create the attribute, including any necessary parents.
*/
- if (map->op == T_OP_EQ) {
+ if ((map->op == T_OP_EQ) ||
+ (fr_type_is_leaf(tmpl_attr_tail_da(current->lhs.vpt)->type) && fr_comparison_op[map->op])) {
if (tmpl_attr_tail_num(current->lhs.vpt) == NUM_UNSPEC) {
current->lhs.create = true;
*/
int fr_edit_list_apply_pair_assignment(fr_edit_list_t *el, fr_pair_t *vp, fr_token_t op, fr_value_box_t const *in)
{
+ fr_value_box_t box;
+
+ switch (op) {
+ case T_OP_LE:
+ case T_OP_LT:
+ case T_OP_GT:
+ case T_OP_GE:
+ if (fr_value_calc_binary_op(vp, &box, FR_TYPE_BOOL, &vp->data, op, in) < 0) return -1;
+
+ if (box.vb_bool) return 0;
+
+ if (el && (fr_edit_list_save_pair_value(el, vp) < 0)) return -1;
+
+ fr_value_box_clear_value(&vp->data);
+
+ /*
+ * The input type may be different, so we can't just copy it.
+ */
+ return fr_value_box_cast(vp, &vp->data, vp->vp_type, vp->data.enumv, in);
+
+ default:
+ break;
+
+ }
+
if (el && (fr_edit_list_save_pair_value(el, vp) < 0)) return -1;
return fr_value_calc_assignment_op(vp, &vp->data, op, in);
--- /dev/null
+group {
+ uint32 small
+ uint32 large
+
+ &User-Name := 'foo'
+
+# &large = 10000
+ &small = 10
+
+ #
+ # Enforce it
+ #
+ &large <= &small
+
+ if !(&large == &small) {
+ test_fail
+ }
+
+}
+success