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

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