diff --git a/Kernel/Net/NetworkTask.cpp b/Kernel/Net/NetworkTask.cpp index 7484f297e3..70457c02c4 100644 --- a/Kernel/Net/NetworkTask.cpp +++ b/Kernel/Net/NetworkTask.cpp @@ -533,9 +533,16 @@ void handle_tcp(const IPv4Packet& ipv4_packet, const Time& packet_timestamp) if (tcp_packet.sequence_number() != socket->ack_number()) { dbgln_if(TCP_DEBUG, "Discarding out of order packet: seq {} vs. ack {}", tcp_packet.sequence_number(), socket->ack_number()); + if (socket->duplicate_acks() < TCPSocket::maximum_duplicate_acks) { + dbgln_if(TCP_DEBUG, "Sending ACK with same ack number to trigger fast retransmission"); + socket->set_duplicate_acks(socket->duplicate_acks() + 1); + unused_rc = socket->send_tcp_packet(TCPFlags::ACK); + } return; } + socket->set_duplicate_acks(0); + if (tcp_packet.has_fin()) { if (payload_size != 0) socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), { &ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size() }, packet_timestamp); diff --git a/Kernel/Net/TCPSocket.h b/Kernel/Net/TCPSocket.h index 37e03e26fa..cb490effbe 100644 --- a/Kernel/Net/TCPSocket.h +++ b/Kernel/Net/TCPSocket.h @@ -128,6 +128,11 @@ public: u32 packets_out() const { return m_packets_out; } u32 bytes_out() const { return m_bytes_out; } + // FIXME: Make this configurable? + static constexpr u32 maximum_duplicate_acks = 5; + void set_duplicate_acks(u32 acks) { m_duplicate_acks = acks; } + u32 duplicate_acks() const { return m_duplicate_acks; } + KResult send_tcp_packet(u16 flags, const UserOrKernelBuffer* = nullptr, size_t = 0); void send_outgoing_packets(RoutingDecision&); void receive_tcp_packet(const TCPPacket&, u16 size); @@ -187,6 +192,8 @@ private: Lock m_not_acked_lock { "TCPSocket unacked packets" }; SinglyLinkedList m_not_acked; + + u32 m_duplicate_acks { 0 }; }; }