Kernel: Fix TCP SYN option propagation

Listening socket now forwards TCP options to the newly created socket
This commit is contained in:
Bananymous 2026-02-23 23:00:47 +02:00
parent acf28d8170
commit 2ea0a24795
2 changed files with 17 additions and 9 deletions

View File

@ -135,6 +135,8 @@ namespace Kernel
{ {
ConnectionInfo target; ConnectionInfo target;
uint32_t target_start_seq; uint32_t target_start_seq;
uint16_t maximum_seqment_size;
uint8_t window_scale;
}; };
struct ListenKey struct ListenKey

View File

@ -25,6 +25,9 @@ namespace Kernel
static constexpr size_t s_recv_window_buffer_size = 16 * PAGE_SIZE; static constexpr size_t s_recv_window_buffer_size = 16 * PAGE_SIZE;
static constexpr size_t s_send_window_buffer_size = 16 * PAGE_SIZE; static constexpr size_t s_send_window_buffer_size = 16 * PAGE_SIZE;
// https://www.rfc-editor.org/rfc/rfc1122 4.2.2.6
static constexpr uint16_t s_default_mss = 536;
BAN::ErrorOr<BAN::RefPtr<TCPSocket>> TCPSocket::create(NetworkLayer& network_layer, const Info& info) BAN::ErrorOr<BAN::RefPtr<TCPSocket>> TCPSocket::create(NetworkLayer& network_layer, const Info& info)
{ {
auto socket = TRY(BAN::RefPtr<TCPSocket>::create(network_layer, info)); auto socket = TRY(BAN::RefPtr<TCPSocket>::create(network_layer, info));
@ -102,12 +105,13 @@ namespace Kernel
return_inode->m_listen_parent = this; return_inode->m_listen_parent = this;
return_inode->m_connection_info.emplace(connection.target); return_inode->m_connection_info.emplace(connection.target);
return_inode->m_recv_window.start_seq = connection.target_start_seq; return_inode->m_recv_window.start_seq = connection.target_start_seq;
return_inode->m_send_window.scale_shift = connection.window_scale;
return_inode->m_send_window.mss = connection.maximum_seqment_size;
return_inode->m_next_flags = SYN | ACK; return_inode->m_next_flags = SYN | ACK;
return_inode->m_next_state = State::SynReceived; return_inode->m_next_state = State::SynReceived;
return_inode->m_mutex.unlock();
if (!return_inode->m_connection_info->has_window_scale) if (!return_inode->m_connection_info->has_window_scale)
return_inode->m_recv_window.scale_shift = 0; return_inode->m_recv_window.scale_shift = 0;
return_inode->m_mutex.unlock();
TRY(m_listen_children.emplace(listen_key, return_inode)); TRY(m_listen_children.emplace(listen_key, return_inode));
@ -502,7 +506,7 @@ namespace Kernel
if (header.options[i] == TCPOption::NOP) if (header.options[i] == TCPOption::NOP)
continue; continue;
if (header.options[i] == TCPOption::MaximumSeqmentSize) if (header.options[i] == TCPOption::MaximumSeqmentSize)
result.maximum_seqment_size = BAN::host_to_network_endian(*reinterpret_cast<const uint16_t*>(&header.options[i + 2])); result.maximum_seqment_size = BAN::network_endian_to_host(*reinterpret_cast<const uint16_t*>(&header.options[i + 2]));
if (header.options[i] == TCPOption::WindowScale) if (header.options[i] == TCPOption::WindowScale)
result.window_scale = header.options[i + 2]; result.window_scale = header.options[i + 2];
if (header.options[i + 1] == 0) if (header.options[i + 1] == 0)
@ -551,7 +555,6 @@ namespace Kernel
add_tcp_header_option<4, TCPOption::WindowScale>(header, m_recv_window.scale_shift); add_tcp_header_option<4, TCPOption::WindowScale>(header, m_recv_window.scale_shift);
header.window_size = BAN::Math::min<size_t>(0xFFFF, m_recv_window.buffer->size()); header.window_size = BAN::Math::min<size_t>(0xFFFF, m_recv_window.buffer->size());
m_send_window.mss = 1440;
m_send_window.start_seq++; m_send_window.start_seq++;
m_send_window.current_seq = m_send_window.start_seq; m_send_window.current_seq = m_send_window.start_seq;
} }
@ -629,8 +632,7 @@ namespace Kernel
} }
auto options = parse_tcp_options(header); auto options = parse_tcp_options(header);
if (options.maximum_seqment_size.has_value()) m_send_window.mss = options.maximum_seqment_size.value_or(s_default_mss);
m_send_window.mss = *options.maximum_seqment_size;
if (options.window_scale.has_value()) if (options.window_scale.has_value())
m_send_window.scale_shift = *options.window_scale; m_send_window.scale_shift = *options.window_scale;
else else
@ -661,13 +663,17 @@ namespace Kernel
dprintln_if(DEBUG_TCP, "No storage to store pending connection"); dprintln_if(DEBUG_TCP, "No storage to store pending connection");
else else
{ {
const auto options = parse_tcp_options(header);
ConnectionInfo connection_info; ConnectionInfo connection_info;
memcpy(&connection_info.address, sender, sender_len); memcpy(&connection_info.address, sender, sender_len);
connection_info.address_len = sender_len; connection_info.address_len = sender_len;
connection_info.has_window_scale = parse_tcp_options(header).window_scale.has_value(); connection_info.has_window_scale = options.window_scale.has_value();
MUST(m_pending_connections.emplace( MUST(m_pending_connections.emplace(
connection_info, connection_info,
header.seq_number + 1 header.seq_number + 1,
options.maximum_seqment_size.value_or(s_default_mss),
options.window_scale.value_or(0)
)); ));
epoll_notify(EPOLLIN); epoll_notify(EPOLLIN);
@ -899,7 +905,7 @@ namespace Kernel
continue; continue;
} }
const bool should_retransmit = m_send_window.data_size > 0 && current_ms >= m_send_window.last_send_ms + retransmit_timeout_ms; const bool should_retransmit = m_send_window.sent_size > 0 && current_ms >= m_send_window.last_send_ms + retransmit_timeout_ms;
if (m_send_window.data_size > m_send_window.sent_size || should_retransmit) if (m_send_window.data_size > m_send_window.sent_size || should_retransmit)
{ {