From c6299d1e5d7bf268770cf74cd13a856b60f14de9 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 25 May 2021 21:29:37 +0200 Subject: [PATCH] Kernel: Don't try to send TCP packets larger than the MSS Previously TCPSocket::send_tcp_packet() would try to send TCP packets which matched whatever size the userspace program specified. We'd try to break those packets up into smaller fragments, however a much better approach is to limit TCP packets to the maximum segment size and avoid fragmentation altogether. --- Kernel/Net/TCPSocket.cpp | 12 +++++++++--- Kernel/Net/TCPSocket.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Kernel/Net/TCPSocket.cpp b/Kernel/Net/TCPSocket.cpp index be9d9e4976..b771bc7586 100644 --- a/Kernel/Net/TCPSocket.cpp +++ b/Kernel/Net/TCPSocket.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -167,7 +168,12 @@ KResultOr TCPSocket::protocol_receive(ReadonlyBytes raw_ipv4_packet, Use KResultOr TCPSocket::protocol_send(const UserOrKernelBuffer& data, size_t data_length) { - int err = send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, &data, data_length); + RoutingDecision routing_decision = route_to(peer_address(), local_address(), bound_interface()); + if (routing_decision.is_zero()) + return EHOSTUNREACH; + size_t mss = routing_decision.adapter->mtu() - sizeof(IPv4Packet) - sizeof(TCPPacket); + data_length = min(data_length, mss); + int err = send_tcp_packet(TCPFlags::PUSH | TCPFlags::ACK, &data, data_length, &routing_decision); if (err < 0) return KResult((ErrnoCode)-err); return data_length; @@ -180,7 +186,7 @@ KResult TCPSocket::send_ack(bool allow_duplicate) return send_tcp_packet(TCPFlags::ACK); } -KResult TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload, size_t payload_size) +KResult TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload, size_t payload_size, RoutingDecision* user_routing_decision) { const bool has_mss_option = flags == TCPFlags::SYN; const size_t options_size = has_mss_option ? sizeof(TCPOptionMSS) : 0; @@ -211,7 +217,7 @@ KResult TCPSocket::send_tcp_packet(u16 flags, const UserOrKernelBuffer* payload, m_sequence_number += payload_size; } - auto routing_decision = route_to(peer_address(), local_address(), bound_interface()); + RoutingDecision routing_decision = user_routing_decision ? *user_routing_decision : route_to(peer_address(), local_address(), bound_interface()); if (routing_decision.is_zero()) return EHOSTUNREACH; diff --git a/Kernel/Net/TCPSocket.h b/Kernel/Net/TCPSocket.h index f1b92e0b30..f6c5511b13 100644 --- a/Kernel/Net/TCPSocket.h +++ b/Kernel/Net/TCPSocket.h @@ -136,7 +136,7 @@ public: u32 duplicate_acks() const { return m_duplicate_acks; } KResult send_ack(bool allow_duplicate = false); - KResult send_tcp_packet(u16 flags, const UserOrKernelBuffer* = nullptr, size_t = 0); + KResult send_tcp_packet(u16 flags, const UserOrKernelBuffer* = nullptr, size_t = 0, RoutingDecision* = nullptr); void receive_tcp_packet(const TCPPacket&, u16 size); bool should_delay_next_ack() const;