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

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