Run the tests:

 # ./ksft_runner.sh ./tcp_purge_receive_queue_disabled.pkt
 TAP version 13
 1..3
 ok 1 ipv4
 ok 2 ipv6
 ok 3 ipv4-mapped-ipv6
 # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0

 # ./ksft_runner.sh ./tcp_purge_receive_queue_enabled.pkt
 TAP version 13
 1..3
 ok 1 ipv4
 ok 2 ipv6
 ok 3 ipv4-mapped-ipv6
 # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0

Assisted-by: Codex:gpt-5.5
Signed-off-by: Leon Hwang <[email protected]>
---
 .../tcp_purge_receive_queue_disabled.pkt      | 40 ++++++++++++++++++
 .../tcp_purge_receive_queue_enabled.pkt       | 42 +++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 
tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_disabled.pkt
 create mode 100644 
tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_enabled.pkt

diff --git 
a/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_disabled.pkt 
b/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_disabled.pkt
new file mode 100644
index 000000000000..a46f93eaab1f
--- /dev/null
+++ 
b/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_disabled.pkt
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+// Test: with tcp_purge_receive_queue disabled (default), receiving RST
+// in CLOSE_WAIT state does NOT purge the receive queue.
+// The unread data in the receive queue is still accessible to the
+// application.
+
+`./defaults.sh
+./set_sysctls.py /proc/sys/net/ipv4/tcp_purge_receive_queue=0`
+
+// Establish a connection (server side).
+    0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+   +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+   +0 bind(3, ..., ...) = 0
+   +0 listen(3, 1) = 0
+
+   +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
+   +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8>
+ +.1 < . 1:1(0) ack 1 win 257
+
+   +0 accept(3, ..., ...) = 4
+
+// Remote sends 4KiB data so that receive queue is populated.
+ +.1 < . 1:4097(4096) ack 1 win 257
+   +0 > . 1:1(0) ack 4097
+
+// Remote sends FIN -> socket enters CLOSE_WAIT.
+ +.1 < F. 4097:4097(0) ack 1 win 257
+   +0~+.04 > . 1:1(0) ack 4098
+
+// Inject RST directly while in CLOSE_WAIT.
+ +.1 < R. 4098:4098(0) ack 1 win 257
+
+// With tcp_purge_receive_queue=0, the receive queue is NOT purged.
+// Data is still in the receive queue; read returns data.
+   +0 read(4, ..., 1) = 1
+
+   +0 close(4) = 0
+
+// Restore sysctls.
+`/tmp/sysctl_restore_${PPID}.sh`
diff --git 
a/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_enabled.pkt 
b/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_enabled.pkt
new file mode 100644
index 000000000000..b1d1dff28f50
--- /dev/null
+++ 
b/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_enabled.pkt
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+// Test: with tcp_purge_receive_queue enabled, receiving RST in
+// CLOSE_WAIT state purges the receive queue immediately.
+// The unread data is discarded, so read() observes EOF.
+//
+// RFC 9293 Section 3.10.7.4:
+//   "all segment queues should be flushed"
+
+`./defaults.sh
+./set_sysctls.py /proc/sys/net/ipv4/tcp_purge_receive_queue=1`
+
+// Establish a connection (server side).
+    0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+   +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+   +0 bind(3, ..., ...) = 0
+   +0 listen(3, 1) = 0
+
+   +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
+   +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8>
+ +.1 < . 1:1(0) ack 1 win 257
+
+   +0 accept(3, ..., ...) = 4
+
+// Remote sends 4KiB data so that receive queue is populated.
+ +.1 < . 1:4097(4096) ack 1 win 257
+   +0 > . 1:1(0) ack 4097
+
+// Remote sends FIN -> socket enters CLOSE_WAIT.
+ +.1 < F. 4097:4097(0) ack 1 win 257
+   +0~+.04 > . 1:1(0) ack 4098
+
+// Inject RST directly while in CLOSE_WAIT.
+ +.1 < R. 4098:4098(0) ack 1 win 257
+
+// With tcp_purge_receive_queue=1, the receive queue IS purged.
+// Queue was purged by RST handler; read returns EOF.
+   +0 read(4, ..., 1) = 0
+
+   +0 close(4) = 0
+
+// Restore sysctls.
+`/tmp/sysctl_restore_${PPID}.sh`
-- 
2.55.0


Reply via email to