Blame SOURCES/0052-tcpopt-split-tcpopt_hdr_fields-into-per-option-enum.patch

0341a5
From 9697436145bf374093dc61e3ad857f7122de08ee Mon Sep 17 00:00:00 2001
0341a5
From: Phil Sutter <psutter@redhat.com>
0341a5
Date: Mon, 12 Jul 2021 17:44:08 +0200
0341a5
Subject: [PATCH] tcpopt: split tcpopt_hdr_fields into per-option enum
0341a5
0341a5
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
0341a5
Upstream Status: nftables commit 2e1f821d713aa
0341a5
0341a5
commit 2e1f821d713aa44717b38901ee80cac8e2aa0335
0341a5
Author: Florian Westphal <fw@strlen.de>
0341a5
Date:   Mon Nov 2 15:22:40 2020 +0100
0341a5
0341a5
    tcpopt: split tcpopt_hdr_fields into per-option enum
0341a5
0341a5
    Currently we're limited to ten template fields in exthdr_desc struct.
0341a5
    Using a single enum for all tpc option fields thus won't work
0341a5
    indefinitely (TCPOPTHDR_FIELD_TSECR is 9) when new option templates get
0341a5
    added.
0341a5
0341a5
    Fortunately we can just use one enum per tcp option to avoid this.
0341a5
    As a side effect this also allows to simplify the sack offset
0341a5
    calculations.  Rather than computing that on-the-fly, just add extra
0341a5
    fields to the SACK template.
0341a5
0341a5
    expr->exthdr.offset now holds the 'raw' value, filled in from the option
0341a5
    template. This would ease implementation of 'raw option matching'
0341a5
    using offset and length to load from the option.
0341a5
0341a5
    Signed-off-by: Florian Westphal <fw@strlen.de>
0341a5
---
0341a5
 include/tcpopt.h          |  46 +++++++++++----
0341a5
 src/evaluate.c            |  16 ++---
0341a5
 src/exthdr.c              |   1 +
0341a5
 src/ipopt.c               |   2 +-
0341a5
 src/netlink_delinearize.c |   2 +-
0341a5
 src/netlink_linearize.c   |   4 +-
0341a5
 src/parser_bison.y        |  18 +++---
0341a5
 src/parser_json.c         |  36 ++++++++++--
0341a5
 src/tcpopt.c              | 119 ++++++++++++++++----------------------
0341a5
 9 files changed, 139 insertions(+), 105 deletions(-)
0341a5
0341a5
diff --git a/include/tcpopt.h b/include/tcpopt.h
0341a5
index 7f3fbb8..667c8a7 100644
0341a5
--- a/include/tcpopt.h
0341a5
+++ b/include/tcpopt.h
0341a5
@@ -33,16 +33,42 @@ enum tcpopt_kind {
0341a5
 	TCPOPT_KIND_SACK3 = 258,
0341a5
 };
0341a5
 
0341a5
-enum tcpopt_hdr_fields {
0341a5
-	TCPOPTHDR_FIELD_INVALID,
0341a5
-	TCPOPTHDR_FIELD_KIND,
0341a5
-	TCPOPTHDR_FIELD_LENGTH,
0341a5
-	TCPOPTHDR_FIELD_SIZE,
0341a5
-	TCPOPTHDR_FIELD_COUNT,
0341a5
-	TCPOPTHDR_FIELD_LEFT,
0341a5
-	TCPOPTHDR_FIELD_RIGHT,
0341a5
-	TCPOPTHDR_FIELD_TSVAL,
0341a5
-	TCPOPTHDR_FIELD_TSECR,
0341a5
+/* Internal identifiers */
0341a5
+enum tcpopt_common {
0341a5
+	TCPOPT_COMMON_KIND,
0341a5
+	TCPOPT_COMMON_LENGTH,
0341a5
+};
0341a5
+
0341a5
+enum tcpopt_maxseg {
0341a5
+	TCPOPT_MAXSEG_KIND,
0341a5
+	TCPOPT_MAXSEG_LENGTH,
0341a5
+	TCPOPT_MAXSEG_SIZE,
0341a5
+};
0341a5
+
0341a5
+enum tcpopt_timestamp {
0341a5
+	TCPOPT_TS_KIND,
0341a5
+	TCPOPT_TS_LENGTH,
0341a5
+	TCPOPT_TS_TSVAL,
0341a5
+	TCPOPT_TS_TSECR,
0341a5
+};
0341a5
+
0341a5
+enum tcpopt_windowscale {
0341a5
+	TCPOPT_WINDOW_KIND,
0341a5
+	TCPOPT_WINDOW_LENGTH,
0341a5
+	TCPOPT_WINDOW_COUNT,
0341a5
+};
0341a5
+
0341a5
+enum tcpopt_hdr_field_sack {
0341a5
+	TCPOPT_SACK_KIND,
0341a5
+	TCPOPT_SACK_LENGTH,
0341a5
+	TCPOPT_SACK_LEFT,
0341a5
+	TCPOPT_SACK_RIGHT,
0341a5
+	TCPOPT_SACK_LEFT1,
0341a5
+	TCPOPT_SACK_RIGHT1,
0341a5
+	TCPOPT_SACK_LEFT2,
0341a5
+	TCPOPT_SACK_RIGHT2,
0341a5
+	TCPOPT_SACK_LEFT3,
0341a5
+	TCPOPT_SACK_RIGHT3,
0341a5
 };
0341a5
 
0341a5
 extern const struct exthdr_desc *tcpopt_protocols[__TCPOPT_KIND_MAX];
0341a5
diff --git a/src/evaluate.c b/src/evaluate.c
0341a5
index 0181750..99a66c2 100644
0341a5
--- a/src/evaluate.c
0341a5
+++ b/src/evaluate.c
0341a5
@@ -474,7 +474,7 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
0341a5
 					  &extra_len);
0341a5
 		break;
0341a5
 	case EXPR_EXTHDR:
0341a5
-		shift = expr_offset_shift(expr, expr->exthdr.tmpl->offset,
0341a5
+		shift = expr_offset_shift(expr, expr->exthdr.offset,
0341a5
 					  &extra_len);
0341a5
 		break;
0341a5
 	default:
0341a5
@@ -526,18 +526,16 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
0341a5
 	if (expr_evaluate_primary(ctx, exprp) < 0)
0341a5
 		return -1;
0341a5
 
0341a5
-	if (expr->exthdr.tmpl->offset % BITS_PER_BYTE != 0 ||
0341a5
+	if (expr->exthdr.offset % BITS_PER_BYTE != 0 ||
0341a5
 	    expr->len % BITS_PER_BYTE != 0)
0341a5
 		expr_evaluate_bits(ctx, exprp);
0341a5
 
0341a5
 	switch (expr->exthdr.op) {
0341a5
 	case NFT_EXTHDR_OP_TCPOPT: {
0341a5
 		static const unsigned int max_tcpoptlen = (15 * 4 - 20) * BITS_PER_BYTE;
0341a5
-		unsigned int totlen = 0;
0341a5
+		unsigned int totlen;
0341a5
 
0341a5
-		totlen += expr->exthdr.tmpl->offset;
0341a5
-		totlen += expr->exthdr.tmpl->len;
0341a5
-		totlen += expr->exthdr.offset;
0341a5
+		totlen = expr->exthdr.tmpl->len + expr->exthdr.offset;
0341a5
 
0341a5
 		if (totlen > max_tcpoptlen)
0341a5
 			return expr_error(ctx->msgs, expr,
0341a5
@@ -547,11 +545,9 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
0341a5
 	}
0341a5
 	case NFT_EXTHDR_OP_IPV4: {
0341a5
 		static const unsigned int max_ipoptlen = 40 * BITS_PER_BYTE;
0341a5
-		unsigned int totlen = 0;
0341a5
+		unsigned int totlen;
0341a5
 
0341a5
-		totlen += expr->exthdr.tmpl->offset;
0341a5
-		totlen += expr->exthdr.tmpl->len;
0341a5
-		totlen += expr->exthdr.offset;
0341a5
+		totlen = expr->exthdr.offset + expr->exthdr.tmpl->len;
0341a5
 
0341a5
 		if (totlen > max_ipoptlen)
0341a5
 			return expr_error(ctx->msgs, expr,
0341a5
diff --git a/src/exthdr.c b/src/exthdr.c
0341a5
index e1ec6f3..c28213f 100644
0341a5
--- a/src/exthdr.c
0341a5
+++ b/src/exthdr.c
0341a5
@@ -99,6 +99,7 @@ struct expr *exthdr_expr_alloc(const struct location *loc,
0341a5
 			  BYTEORDER_BIG_ENDIAN, tmpl->len);
0341a5
 	expr->exthdr.desc = desc;
0341a5
 	expr->exthdr.tmpl = tmpl;
0341a5
+	expr->exthdr.offset = tmpl->offset;
0341a5
 	return expr;
0341a5
 }
0341a5
 
0341a5
diff --git a/src/ipopt.c b/src/ipopt.c
0341a5
index b3d0279..7ecb8b9 100644
0341a5
--- a/src/ipopt.c
0341a5
+++ b/src/ipopt.c
0341a5
@@ -102,7 +102,7 @@ struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type,
0341a5
 	expr->exthdr.desc   = desc;
0341a5
 	expr->exthdr.tmpl   = tmpl;
0341a5
 	expr->exthdr.op     = NFT_EXTHDR_OP_IPV4;
0341a5
-	expr->exthdr.offset = calc_offset(desc, tmpl, ptr);
0341a5
+	expr->exthdr.offset = tmpl->offset + calc_offset(desc, tmpl, ptr);
0341a5
 
0341a5
 	return expr;
0341a5
 }
0341a5
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
0341a5
index 157a473..790336a 100644
0341a5
--- a/src/netlink_delinearize.c
0341a5
+++ b/src/netlink_delinearize.c
0341a5
@@ -727,8 +727,8 @@ static void netlink_parse_numgen(struct netlink_parse_ctx *ctx,
0341a5
 				 const struct location *loc,
0341a5
 				 const struct nftnl_expr *nle)
0341a5
 {
0341a5
-	enum nft_registers dreg;
0341a5
 	uint32_t type, until, offset;
0341a5
+	enum nft_registers dreg;
0341a5
 	struct expr *expr;
0341a5
 
0341a5
 	type  = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_TYPE);
0341a5
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
0341a5
index 25be634..9d1a064 100644
0341a5
--- a/src/netlink_linearize.c
0341a5
+++ b/src/netlink_linearize.c
0341a5
@@ -168,7 +168,7 @@ static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
0341a5
 			       const struct expr *expr,
0341a5
 			       enum nft_registers dreg)
0341a5
 {
0341a5
-	unsigned int offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
0341a5
+	unsigned int offset = expr->exthdr.offset;
0341a5
 	struct nftnl_expr *nle;
0341a5
 
0341a5
 	nle = alloc_nft_expr("exthdr");
0341a5
@@ -896,7 +896,7 @@ static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx,
0341a5
 
0341a5
 	expr = stmt->exthdr.expr;
0341a5
 
0341a5
-	offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
0341a5
+	offset = expr->exthdr.offset;
0341a5
 
0341a5
 	nle = alloc_nft_expr("exthdr");
0341a5
 	netlink_put_register(nle, NFTNL_EXPR_EXTHDR_SREG, sreg);
0341a5
diff --git a/src/parser_bison.y b/src/parser_bison.y
0341a5
index 8f77766..114b289 100644
0341a5
--- a/src/parser_bison.y
0341a5
+++ b/src/parser_bison.y
0341a5
@@ -4715,7 +4715,7 @@ tcp_hdr_expr		:	TCP	tcp_hdr_field
0341a5
 			}
0341a5
 			|	TCP	OPTION	tcp_hdr_option_type
0341a5
 			{
0341a5
-				$$ = tcpopt_expr_alloc(&@$, $3, TCPOPTHDR_FIELD_KIND);
0341a5
+				$$ = tcpopt_expr_alloc(&@$, $3, TCPOPT_COMMON_KIND);
0341a5
 				$$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
0341a5
 			}
0341a5
 			;
0341a5
@@ -4746,14 +4746,14 @@ tcp_hdr_option_type	:	EOL		{ $$ = TCPOPT_KIND_EOL; }
0341a5
 			|	TIMESTAMP	{ $$ = TCPOPT_KIND_TIMESTAMP; }
0341a5
 			;
0341a5
 
0341a5
-tcp_hdr_option_field	:	KIND		{ $$ = TCPOPTHDR_FIELD_KIND; }
0341a5
-			|	LENGTH		{ $$ = TCPOPTHDR_FIELD_LENGTH; }
0341a5
-			|	SIZE		{ $$ = TCPOPTHDR_FIELD_SIZE; }
0341a5
-			|	COUNT		{ $$ = TCPOPTHDR_FIELD_COUNT; }
0341a5
-			|	LEFT		{ $$ = TCPOPTHDR_FIELD_LEFT; }
0341a5
-			|	RIGHT		{ $$ = TCPOPTHDR_FIELD_RIGHT; }
0341a5
-			|	TSVAL		{ $$ = TCPOPTHDR_FIELD_TSVAL; }
0341a5
-			|	TSECR		{ $$ = TCPOPTHDR_FIELD_TSECR; }
0341a5
+tcp_hdr_option_field	:	KIND		{ $$ = TCPOPT_COMMON_KIND; }
0341a5
+			|	LENGTH		{ $$ = TCPOPT_COMMON_LENGTH; }
0341a5
+			|	SIZE		{ $$ = TCPOPT_MAXSEG_SIZE; }
0341a5
+			|	COUNT		{ $$ = TCPOPT_WINDOW_COUNT; }
0341a5
+			|	LEFT		{ $$ = TCPOPT_SACK_LEFT; }
0341a5
+			|	RIGHT		{ $$ = TCPOPT_SACK_RIGHT; }
0341a5
+			|	TSVAL		{ $$ = TCPOPT_TS_TSVAL; }
0341a5
+			|	TSECR		{ $$ = TCPOPT_TS_TSECR; }
0341a5
 			;
0341a5
 
0341a5
 dccp_hdr_expr		:	DCCP	dccp_hdr_field
0341a5
diff --git a/src/parser_json.c b/src/parser_json.c
0341a5
index 44b58a0..ab2375f 100644
0341a5
--- a/src/parser_json.c
0341a5
+++ b/src/parser_json.c
0341a5
@@ -466,8 +466,10 @@ static int json_parse_tcp_option_type(const char *name, int *val)
0341a5
 	}
0341a5
 	/* special case for sack0 - sack3 */
0341a5
 	if (sscanf(name, "sack%u", &i) == 1 && i < 4) {
0341a5
-		if (val)
0341a5
-			*val = TCPOPT_KIND_SACK + i;
0341a5
+		if (val && i == 0)
0341a5
+			*val = TCPOPT_KIND_SACK;
0341a5
+		else if (val && i > 0)
0341a5
+			*val = TCPOPT_KIND_SACK1 + i - 1;
0341a5
 		return 0;
0341a5
 	}
0341a5
 	return 1;
0341a5
@@ -475,12 +477,38 @@ static int json_parse_tcp_option_type(const char *name, int *val)
0341a5
 
0341a5
 static int json_parse_tcp_option_field(int type, const char *name, int *val)
0341a5
 {
0341a5
+	const struct exthdr_desc *desc;
0341a5
+	unsigned int block = 0;
0341a5
 	unsigned int i;
0341a5
-	const struct exthdr_desc *desc = tcpopt_protocols[type];
0341a5
+
0341a5
+	switch (type) {
0341a5
+	case TCPOPT_KIND_SACK1:
0341a5
+		type = TCPOPT_KIND_SACK;
0341a5
+		block = 1;
0341a5
+		break;
0341a5
+	case TCPOPT_KIND_SACK2:
0341a5
+		type = TCPOPT_KIND_SACK;
0341a5
+		block = 2;
0341a5
+		break;
0341a5
+	case TCPOPT_KIND_SACK3:
0341a5
+		type = TCPOPT_KIND_SACK;
0341a5
+		block = 3;
0341a5
+		break;
0341a5
+	}
0341a5
+
0341a5
+	if (type < 0 || type >= (int)array_size(tcpopt_protocols))
0341a5
+		return 1;
0341a5
+
0341a5
+	desc = tcpopt_protocols[type];
0341a5
 
0341a5
 	for (i = 0; i < array_size(desc->templates); i++) {
0341a5
 		if (desc->templates[i].token &&
0341a5
 		    !strcmp(desc->templates[i].token, name)) {
0341a5
+			if (block) {
0341a5
+				block--;
0341a5
+				continue;
0341a5
+			}
0341a5
+
0341a5
 			if (val)
0341a5
 				*val = i;
0341a5
 			return 0;
0341a5
@@ -585,7 +613,7 @@ static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx,
0341a5
 
0341a5
 	if (json_unpack(root, "{s:s}", "field", &field)) {
0341a5
 		expr = tcpopt_expr_alloc(int_loc, descval,
0341a5
-					 TCPOPTHDR_FIELD_KIND);
0341a5
+					 TCPOPT_COMMON_KIND);
0341a5
 		expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
0341a5
 
0341a5
 		return expr;
0341a5
diff --git a/src/tcpopt.c b/src/tcpopt.c
0341a5
index 17cb580..d1dd13b 100644
0341a5
--- a/src/tcpopt.c
0341a5
+++ b/src/tcpopt.c
0341a5
@@ -22,7 +22,7 @@ static const struct exthdr_desc tcpopt_eol = {
0341a5
 	.name		= "eol",
0341a5
 	.type		= TCPOPT_KIND_EOL,
0341a5
 	.templates	= {
0341a5
-		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",  0,    8),
0341a5
+		[TCPOPT_COMMON_KIND]		= PHT("kind",  0,    8),
0341a5
 	},
0341a5
 };
0341a5
 
0341a5
@@ -30,7 +30,7 @@ static const struct exthdr_desc tcpopt_nop = {
0341a5
 	.name		= "nop",
0341a5
 	.type		= TCPOPT_KIND_NOP,
0341a5
 	.templates	= {
0341a5
-		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,   8),
0341a5
+		[TCPOPT_COMMON_KIND]		= PHT("kind",  0,    8),
0341a5
 	},
0341a5
 };
0341a5
 
0341a5
@@ -38,9 +38,9 @@ static const struct exthdr_desc tcptopt_maxseg = {
0341a5
 	.name		= "maxseg",
0341a5
 	.type		= TCPOPT_KIND_MAXSEG,
0341a5
 	.templates	= {
0341a5
-		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,  8),
0341a5
-		[TCPOPTHDR_FIELD_LENGTH]	= PHT("length", 8,  8),
0341a5
-		[TCPOPTHDR_FIELD_SIZE]		= PHT("size",  16, 16),
0341a5
+		[TCPOPT_MAXSEG_KIND]	= PHT("kind",   0,  8),
0341a5
+		[TCPOPT_MAXSEG_LENGTH]	= PHT("length", 8,  8),
0341a5
+		[TCPOPT_MAXSEG_SIZE]	= PHT("size",  16, 16),
0341a5
 	},
0341a5
 };
0341a5
 
0341a5
@@ -48,9 +48,9 @@ static const struct exthdr_desc tcpopt_window = {
0341a5
 	.name		= "window",
0341a5
 	.type		= TCPOPT_KIND_WINDOW,
0341a5
 	.templates	= {
0341a5
-		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,  8),
0341a5
-		[TCPOPTHDR_FIELD_LENGTH]	= PHT("length", 8,  8),
0341a5
-		[TCPOPTHDR_FIELD_COUNT]		= PHT("count", 16,  8),
0341a5
+		[TCPOPT_WINDOW_KIND]	= PHT("kind",   0,  8),
0341a5
+		[TCPOPT_WINDOW_LENGTH]	= PHT("length", 8,  8),
0341a5
+		[TCPOPT_WINDOW_COUNT]	= PHT("count", 16,  8),
0341a5
 	},
0341a5
 };
0341a5
 
0341a5
@@ -58,8 +58,8 @@ static const struct exthdr_desc tcpopt_sack_permitted = {
0341a5
 	.name		= "sack-perm",
0341a5
 	.type		= TCPOPT_KIND_SACK_PERMITTED,
0341a5
 	.templates	= {
0341a5
-		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0, 8),
0341a5
-		[TCPOPTHDR_FIELD_LENGTH]	= PHT("length", 8, 8),
0341a5
+		[TCPOPT_COMMON_KIND]	= PHT("kind",   0, 8),
0341a5
+		[TCPOPT_COMMON_LENGTH]	= PHT("length", 8, 8),
0341a5
 	},
0341a5
 };
0341a5
 
0341a5
@@ -67,10 +67,16 @@ static const struct exthdr_desc tcpopt_sack = {
0341a5
 	.name		= "sack",
0341a5
 	.type		= TCPOPT_KIND_SACK,
0341a5
 	.templates	= {
0341a5
-		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,   8),
0341a5
-		[TCPOPTHDR_FIELD_LENGTH]		= PHT("length", 8,   8),
0341a5
-		[TCPOPTHDR_FIELD_LEFT]		= PHT("left",  16,  32),
0341a5
-		[TCPOPTHDR_FIELD_RIGHT]		= PHT("right", 48,  32),
0341a5
+		[TCPOPT_SACK_KIND]	= PHT("kind",   0,   8),
0341a5
+		[TCPOPT_SACK_LENGTH]	= PHT("length", 8,   8),
0341a5
+		[TCPOPT_SACK_LEFT]	= PHT("left",  16,  32),
0341a5
+		[TCPOPT_SACK_RIGHT]	= PHT("right", 48,  32),
0341a5
+		[TCPOPT_SACK_LEFT1]	= PHT("left",  80,  32),
0341a5
+		[TCPOPT_SACK_RIGHT1]	= PHT("right", 112,  32),
0341a5
+		[TCPOPT_SACK_LEFT2]	= PHT("left",  144,  32),
0341a5
+		[TCPOPT_SACK_RIGHT2]	= PHT("right", 176,  32),
0341a5
+		[TCPOPT_SACK_LEFT3]	= PHT("left",  208,  32),
0341a5
+		[TCPOPT_SACK_RIGHT3]	= PHT("right", 240,  32),
0341a5
 	},
0341a5
 };
0341a5
 
0341a5
@@ -78,12 +84,13 @@ static const struct exthdr_desc tcpopt_timestamp = {
0341a5
 	.name		= "timestamp",
0341a5
 	.type		= TCPOPT_KIND_TIMESTAMP,
0341a5
 	.templates	= {
0341a5
-		[TCPOPTHDR_FIELD_KIND]		= PHT("kind",   0,  8),
0341a5
-		[TCPOPTHDR_FIELD_LENGTH]	= PHT("length", 8,  8),
0341a5
-		[TCPOPTHDR_FIELD_TSVAL]		= PHT("tsval",  16, 32),
0341a5
-		[TCPOPTHDR_FIELD_TSECR]		= PHT("tsecr",  48, 32),
0341a5
+		[TCPOPT_TS_KIND]	= PHT("kind",   0,  8),
0341a5
+		[TCPOPT_TS_LENGTH]	= PHT("length", 8,  8),
0341a5
+		[TCPOPT_TS_TSVAL]	= PHT("tsval",  16, 32),
0341a5
+		[TCPOPT_TS_TSECR]	= PHT("tsecr",  48, 32),
0341a5
 	},
0341a5
 };
0341a5
+
0341a5
 #undef PHT
0341a5
 
0341a5
 const struct exthdr_desc *tcpopt_protocols[] = {
0341a5
@@ -96,65 +103,43 @@ const struct exthdr_desc *tcpopt_protocols[] = {
0341a5
 	[TCPOPT_KIND_TIMESTAMP]		= &tcpopt_timestamp,
0341a5
 };
0341a5
 
0341a5
-static unsigned int calc_offset(const struct exthdr_desc *desc,
0341a5
-				const struct proto_hdr_template *tmpl,
0341a5
-				unsigned int num)
0341a5
-{
0341a5
-	if (!desc || tmpl == &tcpopt_unknown_template)
0341a5
-		return 0;
0341a5
-
0341a5
-	switch (desc->type) {
0341a5
-	case TCPOPT_SACK:
0341a5
-		/* Make sure, offset calculations only apply to left and right
0341a5
-		 * fields
0341a5
-		 */
0341a5
-		return (tmpl->offset < 16) ? 0 : num * 64;
0341a5
-	default:
0341a5
-		return 0;
0341a5
-	}
0341a5
-}
0341a5
-
0341a5
-
0341a5
-static unsigned int calc_offset_reverse(const struct exthdr_desc *desc,
0341a5
-					const struct proto_hdr_template *tmpl,
0341a5
-					unsigned int offset)
0341a5
-{
0341a5
-	if (!desc || tmpl == &tcpopt_unknown_template)
0341a5
-		return offset;
0341a5
-
0341a5
-	switch (desc->type) {
0341a5
-	case TCPOPT_SACK:
0341a5
-		/* We can safely ignore the first left/right field */
0341a5
-		return offset < 80 ? offset : (offset % 64);
0341a5
-	default:
0341a5
-		return offset;
0341a5
-	}
0341a5
-}
0341a5
-
0341a5
 struct expr *tcpopt_expr_alloc(const struct location *loc,
0341a5
 			       unsigned int kind,
0341a5
 			       unsigned int field)
0341a5
 {
0341a5
 	const struct proto_hdr_template *tmpl;
0341a5
-	const struct exthdr_desc *desc;
0341a5
-	uint8_t optnum = 0;
0341a5
+	const struct exthdr_desc *desc = NULL;
0341a5
 	struct expr *expr;
0341a5
 
0341a5
 	switch (kind) {
0341a5
 	case TCPOPT_KIND_SACK1:
0341a5
 		kind = TCPOPT_KIND_SACK;
0341a5
-		optnum = 1;
0341a5
+		if (field == TCPOPT_SACK_LEFT)
0341a5
+			field = TCPOPT_SACK_LEFT1;
0341a5
+		else if (field == TCPOPT_SACK_RIGHT)
0341a5
+			field = TCPOPT_SACK_RIGHT1;
0341a5
 		break;
0341a5
 	case TCPOPT_KIND_SACK2:
0341a5
 		kind = TCPOPT_KIND_SACK;
0341a5
-		optnum = 2;
0341a5
+		if (field == TCPOPT_SACK_LEFT)
0341a5
+			field = TCPOPT_SACK_LEFT2;
0341a5
+		else if (field == TCPOPT_SACK_RIGHT)
0341a5
+			field = TCPOPT_SACK_RIGHT2;
0341a5
 		break;
0341a5
 	case TCPOPT_KIND_SACK3:
0341a5
 		kind = TCPOPT_KIND_SACK;
0341a5
-		optnum = 3;
0341a5
+		if (field == TCPOPT_SACK_LEFT)
0341a5
+			field = TCPOPT_SACK_LEFT3;
0341a5
+		else if (field == TCPOPT_SACK_RIGHT)
0341a5
+			field = TCPOPT_SACK_RIGHT3;
0341a5
+		break;
0341a5
 	}
0341a5
 
0341a5
-	desc = tcpopt_protocols[kind];
0341a5
+	if (kind < array_size(tcpopt_protocols))
0341a5
+		desc = tcpopt_protocols[kind];
0341a5
+
0341a5
+	if (!desc)
0341a5
+		return NULL;
0341a5
 	tmpl = &desc->templates[field];
0341a5
 	if (!tmpl)
0341a5
 		return NULL;
0341a5
@@ -164,34 +149,32 @@ struct expr *tcpopt_expr_alloc(const struct location *loc,
0341a5
 	expr->exthdr.desc   = desc;
0341a5
 	expr->exthdr.tmpl   = tmpl;
0341a5
 	expr->exthdr.op     = NFT_EXTHDR_OP_TCPOPT;
0341a5
-	expr->exthdr.offset = calc_offset(desc, tmpl, optnum);
0341a5
+	expr->exthdr.offset = tmpl->offset;
0341a5
 
0341a5
 	return expr;
0341a5
 }
0341a5
 
0341a5
-void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
0341a5
+void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
0341a5
 		     unsigned int len, uint32_t flags)
0341a5
 {
0341a5
 	const struct proto_hdr_template *tmpl;
0341a5
-	unsigned int i, off;
0341a5
+	unsigned int i;
0341a5
 
0341a5
 	assert(expr->etype == EXPR_EXTHDR);
0341a5
 
0341a5
 	expr->len = len;
0341a5
 	expr->exthdr.flags = flags;
0341a5
-	expr->exthdr.offset = offset;
0341a5
+	expr->exthdr.offset = off;
0341a5
+
0341a5
+	if (type >= array_size(tcpopt_protocols))
0341a5
+		return;
0341a5
 
0341a5
-	assert(type < array_size(tcpopt_protocols));
0341a5
 	expr->exthdr.desc = tcpopt_protocols[type];
0341a5
 	expr->exthdr.flags = flags;
0341a5
 	assert(expr->exthdr.desc != NULL);
0341a5
 
0341a5
 	for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
0341a5
 		tmpl = &expr->exthdr.desc->templates[i];
0341a5
-		/* We have to reverse calculate the offset for the sack options
0341a5
-		 * at this point
0341a5
-		 */
0341a5
-		off = calc_offset_reverse(expr->exthdr.desc, tmpl, offset);
0341a5
 		if (tmpl->offset != off || tmpl->len != len)
0341a5
 			continue;
0341a5
 
0341a5
-- 
0341a5
2.31.1
0341a5