Remove TimeWait socket if a new Syn is received

This commit is contained in:
Jianfeng Jiang
2024-11-05 11:35:02 +00:00
committed by Tate, Hongliang Tian
parent 438dad888e
commit c1fd09fd41

View File

@ -12,9 +12,9 @@ use core::{
use ostd::sync::{LocalIrqDisabled, RwLock, SpinLock, SpinLockGuard}; use ostd::sync::{LocalIrqDisabled, RwLock, SpinLock, SpinLockGuard};
use smoltcp::{ use smoltcp::{
iface::Context, iface::Context,
socket::{udp::UdpMetadata, PollAt}, socket::{tcp::State, udp::UdpMetadata, PollAt},
time::Instant, time::Instant,
wire::{IpAddress, IpEndpoint, IpRepr, TcpRepr, UdpRepr}, wire::{IpAddress, IpEndpoint, IpRepr, TcpControl, TcpRepr, UdpRepr},
}; };
use super::{event::SocketEventObserver, RawTcpSocket, RawUdpSocket}; use super::{event::SocketEventObserver, RawTcpSocket, RawUdpSocket};
@ -103,6 +103,16 @@ impl TcpSocket {
self.is_dead.store(true, Ordering::Relaxed); self.is_dead.store(true, Ordering::Relaxed);
} }
} }
/// Sets the TCP socket in [`TimeWait`] state as dead.
///
/// See [`BoundTcpSocketInner::is_dead`] for the definition of dead TCP sockets.
///
/// [`TimeWait`]: smoltcp::socket::tcp::State::TimeWait
fn set_dead_timewait(&self, socket: &RawTcpSocketExt) {
debug_assert!(socket.in_background && socket.state() == smoltcp::socket::tcp::State::TimeWait);
self.is_dead.store(true, Ordering::Relaxed);
}
} }
impl AnySocket for TcpSocket { impl AnySocket for TcpSocket {
@ -451,6 +461,27 @@ impl<E> BoundTcpSocketInner<E> {
return TcpProcessResult::NotProcessed; return TcpProcessResult::NotProcessed;
} }
// If the socket is in the TimeWait state and a new packet arrives that is a SYN packet
// without ack number, the TimeWait socket will be marked as dead,
// and the packet will be passed on to any other listening sockets for processing.
//
// FIXME: Directly marking the TimeWait socket dead is not the correct approach.
// In Linux, a TimeWait socket remains alive to handle "old duplicate segments".
// If a TimeWait socket receives a new SYN packet, Linux will select a suitable
// listening socket from the socket table to respond to that SYN request.
// (https://elixir.bootlin.com/linux/v6.0.9/source/net/ipv4/tcp_ipv4.c#L2137)
// Moreover, the Initial Sequence Number (ISN) will be set to prevent the TimeWait socket
// from erroneously handling packets from the new connection.
// (https://elixir.bootlin.com/linux/v6.0.9/source/net/ipv4/tcp_minisocks.c#L194)
// Implementing such behavior is challenging with the current smoltcp APIs.
if socket.state() == State::TimeWait
&& tcp_repr.control == TcpControl::Syn
&& tcp_repr.ack_number.is_none()
{
self.socket.set_dead_timewait(&socket);
return TcpProcessResult::NotProcessed;
}
let result = match socket.process(cx, ip_repr, tcp_repr) { let result = match socket.process(cx, ip_repr, tcp_repr) {
None => TcpProcessResult::Processed, None => TcpProcessResult::Processed,
Some((ip_repr, tcp_repr)) => TcpProcessResult::ProcessedWithReply(ip_repr, tcp_repr), Some((ip_repr, tcp_repr)) => TcpProcessResult::ProcessedWithReply(ip_repr, tcp_repr),