git: 4287b7caa921 - stable/13 - LRO: Don't merge ACK and non-ACK packets together

From: Hans Petter Selasky <hselasky_at_FreeBSD.org>
Date: Tue, 08 Feb 2022 15:13:41 UTC
The branch stable/13 has been updated by hselasky:

URL: https://cgit.FreeBSD.org/src/commit/?id=4287b7caa921131845837dd394581d0246f38eb1

commit 4287b7caa921131845837dd394581d0246f38eb1
Author:     Ryan Stone <rstone@FreeBSD.org>
AuthorDate: 2022-02-08 15:08:50 +0000
Commit:     Hans Petter Selasky <hselasky@FreeBSD.org>
CommitDate: 2022-02-08 15:08:50 +0000

    LRO: Don't merge ACK and non-ACK packets together
    
    LRO was willing to merge ACK and non-ACK packets together.  This
    can cause incorrect th_ack values to be reported up the stack.
    While non-ACKs are quite unlikely to appear in practice, LRO's
    behaviour is against the spec.  Make LRO unwilling to merge
    packets with different TH_ACK flag values in order to fix the
    issue.
    
    Found by: Sysunit test
    Differential Revision:  https://reviews.freebsd.org/D33775
    Reviewed by: rrs
    
    (cherry picked from commit 3284f4925f697ad7cc2aa4761ff5cf6ce98fd623)
---
 sys/netinet/tcp_lro.c | 5 ++++-
 sys/netinet/tcp_lro.h | 5 +++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/sys/netinet/tcp_lro.c b/sys/netinet/tcp_lro.c
index feec8c36ab69..cfc84707abd2 100644
--- a/sys/netinet/tcp_lro.c
+++ b/sys/netinet/tcp_lro.c
@@ -895,6 +895,7 @@ tcp_set_entry_to_mbuf(struct lro_ctrl *lc, struct lro_entry *le,
 	le->next_seq = ntohl(th->th_seq) + tcp_data_len;
 	le->ack_seq = th->th_ack;
 	le->window = th->th_win;
+	le->flags = th->th_flags;
 	le->needs_merge = 0;
 
 	/* Setup new data pointers. */
@@ -1066,10 +1067,12 @@ again:
 		}
 		/* Try to append the new segment. */
 		if (__predict_false(ntohl(th->th_seq) != le->next_seq ||
+				    ((th->th_flags & TH_ACK) !=
+				      (le->flags & TH_ACK)) ||
 				    (tcp_data_len == 0 &&
 				     le->ack_seq == th->th_ack &&
 				     le->window == th->th_win))) {
-			/* Out of order packet or duplicate ACK. */
+			/* Out of order packet, non-ACK + ACK or dup ACK. */
 			tcp_push_and_replace(lc, le, m);
 			goto again;
 		}
diff --git a/sys/netinet/tcp_lro.h b/sys/netinet/tcp_lro.h
index 97819596231e..b8abc2fa1ab3 100644
--- a/sys/netinet/tcp_lro.h
+++ b/sys/netinet/tcp_lro.h
@@ -146,8 +146,9 @@ struct lro_entry {
 	uint16_t		compressed;
 	uint16_t		uncompressed;
 	uint16_t		window;
-	uint16_t		timestamp : 1;
-	uint16_t		needs_merge : 1;
+	uint8_t			flags;
+	uint8_t			timestamp : 1;
+	uint8_t			needs_merge : 1;
 	struct bintime		alloc_time;	/* time when entry was allocated */
 };