summaryrefslogtreecommitdiffstats
path: root/src/netlink_linearize.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2015-12-05 20:04:21 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2015-12-14 20:32:55 +0100
commit4a9a38727957731e56b5302960da5ef1e0275d61 (patch)
treeb3d3c546cc6db893866c8d4707861dd06c2a8963 /src/netlink_linearize.c
parent210f479bff5b6cf8483383aa27ad9ded3925326c (diff)
src: fix sub-byte protocol header definitions
Update bitfield definitions to match according to the way they are expressed in RFC and IEEE specifications. This required a bit of update for c3f0501 ("src: netlink_linearize: handle sub-byte lengths"). >From the linearize step, to calculate the shift based on the bitfield offset, we need to obtain the length of the word in bytes: len = round_up(expr->len, BITS_PER_BYTE); Then, we substract the offset bits and the bitfield length. shift = len - (offset + expr->len); From the delinearize, payload_expr_trim() needs to obtain the real offset through: off = round_up(mask->len, BITS_PER_BYTE) - mask_len; For vlan id (offset 12), this gets the position of the last bit set in the mask (ie. 12), then we substract the length we fetch in bytes (16), so we obtain the real bitfield offset (4). Then, we add that to the original payload offset that was expressed in bytes: payload_offset += off; Note that payload_expr_trim() now also adjusts the payload expression to its real length and offset so we don't need to propagate the mask expression. Reported-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/netlink_linearize.c')
-rw-r--r--src/netlink_linearize.c35
1 files changed, 22 insertions, 13 deletions
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 0790dce3..131c3f95 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -103,27 +103,37 @@ static void netlink_gen_concat(struct netlink_linearize_ctx *ctx,
}
}
+static unsigned int payload_shift_calc(const struct expr *expr)
+{
+ unsigned int offset, len;
+ int shift;
+
+ offset = expr->payload.offset % BITS_PER_BYTE;
+ len = round_up(expr->len, BITS_PER_BYTE);
+ shift = len - (offset + expr->len);
+ assert(shift >= 0);
+
+ return shift;
+}
+
static void netlink_gen_payload_mask(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
{
struct nft_data_linearize nld, zero = {};
+ unsigned int shift, len, masklen;
struct nftnl_expr *nle;
- unsigned int offset, len, masklen;
mpz_t mask;
- offset = expr->payload.offset % BITS_PER_BYTE;
- masklen = expr->len + offset;
-
- if (masklen > 128)
- BUG("expr mask length is %u (len %u, offset %u)\n",
- masklen, expr->len, offset);
+ shift = payload_shift_calc(expr);
+ if (!shift && expr->payload.offset % BITS_PER_BYTE == 0)
+ return;
+ masklen = expr->len + shift;
+ assert(masklen <= NFT_REG_SIZE * BITS_PER_BYTE);
mpz_init2(mask, masklen);
mpz_bitmask(mask, expr->len);
-
- if (offset)
- mpz_lshift_ui(mask, offset);
+ mpz_lshift_ui(mask, shift);
nle = alloc_nft_expr("bitwise");
@@ -158,8 +168,7 @@ static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
nftnl_rule_add_expr(ctx->nlr, nle);
- if (expr->len % BITS_PER_BYTE)
- netlink_gen_payload_mask(ctx, expr, dreg);
+ netlink_gen_payload_mask(ctx, expr, dreg);
}
static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
@@ -287,7 +296,7 @@ static void payload_shift_value(const struct expr *left, struct expr *right)
left->ops->type != EXPR_PAYLOAD)
return;
- mpz_lshift_ui(right->value, left->payload.offset % BITS_PER_BYTE);
+ mpz_lshift_ui(right->value, payload_shift_calc(left));
}
static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx,