summaryrefslogtreecommitdiffstats
path: root/src/evaluate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/evaluate.c')
-rw-r--r--src/evaluate.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/src/evaluate.c b/src/evaluate.c
index ab732616..fcd4ecda 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -362,7 +362,8 @@ conflict_resolution_gen_dependency(struct eval_ctx *ctx, int protocol,
return 0;
}
-static uint8_t expr_offset_shift(const struct expr *expr, unsigned int offset)
+static uint8_t expr_offset_shift(const struct expr *expr, unsigned int offset,
+ unsigned int *extra_len)
{
unsigned int new_offset, len;
int shift;
@@ -370,34 +371,38 @@ static uint8_t expr_offset_shift(const struct expr *expr, unsigned int offset)
new_offset = offset % BITS_PER_BYTE;
len = round_up(expr->len, BITS_PER_BYTE);
shift = len - (new_offset + expr->len);
- assert(shift >= 0);
-
+ while (shift < 0) {
+ shift += BITS_PER_BYTE;
+ *extra_len += BITS_PER_BYTE;
+ }
return shift;
}
static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
{
struct expr *expr = *exprp, *and, *mask, *lshift, *off;
- unsigned masklen;
+ unsigned masklen, len = expr->len, extra_len = 0;
uint8_t shift;
mpz_t bitmask;
switch (expr->ops->type) {
case EXPR_PAYLOAD:
- shift = expr_offset_shift(expr, expr->payload.offset);
+ shift = expr_offset_shift(expr, expr->payload.offset,
+ &extra_len);
break;
case EXPR_EXTHDR:
- shift = expr_offset_shift(expr, expr->exthdr.tmpl->offset);
+ shift = expr_offset_shift(expr, expr->exthdr.tmpl->offset,
+ &extra_len);
break;
default:
BUG("Unknown expression %s\n", expr->ops->name);
}
- masklen = expr->len + shift;
+ masklen = len + shift;
assert(masklen <= NFT_REG_SIZE * BITS_PER_BYTE);
mpz_init2(bitmask, masklen);
- mpz_bitmask(bitmask, expr->len);
+ mpz_bitmask(bitmask, len);
mpz_lshift_ui(bitmask, shift);
mask = constant_expr_alloc(&expr->location, expr_basetype(expr),
@@ -423,6 +428,9 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
*exprp = lshift;
} else
*exprp = and;
+
+ if (extra_len)
+ expr->len += extra_len;
}
static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)