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.
This commit is contained in:
Gunnar Beutner 2021-05-25 21:29:37 +02:00 committed by Andreas Kling
parent dce97678ae
commit c6299d1e5d
2 changed files with 10 additions and 4 deletions

View file

@ -9,6 +9,7 @@
#include <Kernel/Debug.h>
#include <Kernel/Devices/RandomDevice.h>
#include <Kernel/FileSystem/FileDescription.h>
#include <Kernel/Net/EthernetFrameHeader.h>
#include <Kernel/Net/IPv4.h>
#include <Kernel/Net/NetworkAdapter.h>
#include <Kernel/Net/Routing.h>
@ -167,7 +168,12 @@ KResultOr<size_t> TCPSocket::protocol_receive(ReadonlyBytes raw_ipv4_packet, Use
KResultOr<size_t> 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;

View file

@ -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;