tcp: (fixes #1326) Fix PersistTimeout null deref on drained tx buffer

This MR addresses #1326 (closed).

Summary

Fixes a SIGSEGV in TcpSocketBase::PersistTimeout(). When the receiver advertises a zero window and the sender has no unsent data, TcpTxBuffer::CopyFromSequence(1, m_nextTxSequence) returns nullptr, which the existing code dereferenced unconditionally.

In that case the sender now sends a zero-length window probe with an already acknowledged sequence number (SND.UNA - 1). The receiver finds it unacceptable and must answer with an ACK carrying its current window (RFC 9293 §3.8.6.1, §3.10.7.4), the same approach as Linux's tcp_xmit_probe_skb().

ResetLastSegmentSent() is now called only when a 1-byte probe was actually taken from the tx buffer. The persist timer can fire with data still in flight, and the unconditional call would have moved the last in-flight segment back into the unsent list.

Changes

  • src/internet/model/tcp-socket-base.cc: null-guard in PersistTimeout(); zero-length probe at SND.UNA - 1 when there is no unsent data; ResetLastSegmentSent() only on the 1-byte probe path.
  • src/internet/test/tcp-zero-window-test.cc: new test TcpPersistEmptyTxBufferTest. It holds the receiver window at zero after the sender's only segment is acknowledged, and checks that the probes are zero-length, use the already acknowledged sequence number, and are each acknowledged with a zero window.
  • RELEASE_NOTES.md: bug-fix entry for #1326 (closed).

The follow-up commits from review will be squashed into the original commit before merge.

Verification

  • Without the fix, the new test crashes with SIGSEGV in PersistTimeout(); with it, the test passes alongside the existing TcpZeroWindowTest.
  • The CI pipeline on the current head passes.

AI tool disclosure

Per the ns-3 AI tool policy, this contribution was prepared with AI assistance and reviewed by the submitter. The commit carries the trailer Assisted-by: Claude Code.

Edited by Sergio Andreozzi

Merge request reports

Loading
Loading