diff options
-rw-r--r-- | include/netlink.h | 6 | ||||
-rw-r--r-- | src/netlink_delinearize.c | 45 |
2 files changed, 46 insertions, 5 deletions
diff --git a/include/netlink.h b/include/netlink.h index e8e0f68a..71c888fa 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -42,10 +42,16 @@ struct netlink_parse_ctx { struct netlink_ctx *nlctx; }; + +#define RULE_PP_IN_CONCATENATION (1 << 0) + +#define RULE_PP_REMOVE_OP_AND (RULE_PP_IN_CONCATENATION) + struct rule_pp_ctx { struct proto_ctx pctx; struct payload_dep_ctx pdctx; struct stmt *stmt; + unsigned int flags; }; extern const struct input_descriptor indesc_netlink; diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 3835b3e5..42221f8c 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -2260,12 +2260,13 @@ static void binop_adjust(const struct expr *binop, struct expr *right, } } -static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr, - struct expr **expr_binop) +static void __binop_postprocess(struct rule_pp_ctx *ctx, + struct expr *expr, + struct expr *left, + struct expr *mask, + struct expr **expr_binop) { struct expr *binop = *expr_binop; - struct expr *left = binop->left; - struct expr *mask = binop->right; unsigned int shift; assert(binop->etype == EXPR_BINOP); @@ -2301,15 +2302,26 @@ static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr, assert(binop->left == left); *expr_binop = expr_get(left); - expr_free(binop); if (left->etype == EXPR_PAYLOAD) payload_match_postprocess(ctx, expr, left); else if (left->etype == EXPR_EXTHDR && right) expr_set_type(right, left->dtype, left->byteorder); + + expr_free(binop); } } +static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr, + struct expr **expr_binop) +{ + struct expr *binop = *expr_binop; + struct expr *left = binop->left; + struct expr *mask = binop->right; + + __binop_postprocess(ctx, expr, left, mask, expr_binop); +} + static void map_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr) { struct expr *binop = expr->map; @@ -2542,6 +2554,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) LIST_HEAD(tmp); struct expr *n; + ctx->flags |= RULE_PP_IN_CONCATENATION; list_for_each_entry_safe(i, n, &expr->expressions, list) { if (type) { dtype = concat_subtype_lookup(type, --off); @@ -2553,6 +2566,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) ntype = concat_subtype_add(ntype, i->dtype->type); } + ctx->flags &= ~RULE_PP_IN_CONCATENATION; list_splice(&tmp, &expr->expressions); datatype_set(expr, concat_type_alloc(ntype)); break; @@ -2569,6 +2583,27 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) expr_set_type(expr->right, &integer_type, BYTEORDER_HOST_ENDIAN); break; + case OP_AND: + expr_set_type(expr->right, expr->left->dtype, + expr->left->byteorder); + + /* Do not process OP_AND in ordinary rule context. + * + * Removal needs to be performed as part of the relational + * operation because the RHS constant might need to be adjusted + * (shifted). + * + * This is different in set element context or concatenations: + * There is no relational operation (eq, neq and so on), thus + * it needs to be processed right away. + */ + if ((ctx->flags & RULE_PP_REMOVE_OP_AND) && + expr->left->etype == EXPR_PAYLOAD && + expr->right->etype == EXPR_VALUE) { + __binop_postprocess(ctx, expr, expr->left, expr->right, exprp); + return; + } + break; default: expr_set_type(expr->right, expr->left->dtype, expr->left->byteorder); |