From bd77bb41df51d635db435cd6e74072359dc3a818 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 12 Jul 2018 00:56:14 +0200 Subject: [PATCH] nic_router: improve handling of TCP termination Like suggested by RFC 2663, reprogram the dissolve timeout of a TCP link state to 2 times the maximum segment lifetime (by default 1 minute) when receiving a matching packet with the FIN flag set, or with the ACK flag set to acknowledge a FIN of the remote side. Mark a link state as closed (no further reprogramming of the dissolve timeout) and set the dissolve timeout to 2 times the maximum segment lifetime when receiving a packet with the RESET flag set. Issue #2953 --- repos/os/src/server/nic_router/link.cc | 58 ++++++++++---------------- repos/os/src/server/nic_router/link.h | 24 +++++++---- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/repos/os/src/server/nic_router/link.cc b/repos/os/src/server/nic_router/link.cc index 7c11bb2971..707d039f3b 100644 --- a/repos/os/src/server/nic_router/link.cc +++ b/repos/os/src/server/nic_router/link.cc @@ -218,46 +218,34 @@ Tcp_link::Tcp_link(Interface &cln_interface, { } -void Tcp_link::_fin_acked() +void Tcp_link::_tcp_packet(Tcp_packet &tcp, + Peer &sender, + Peer &receiver) { - if (_server_fin_acked && _client_fin_acked) { - _dissolve_timeout.schedule(Microseconds(_config().tcp_max_segm_lifetime().value << 1)); - _closed = true; - } -} - - -void Tcp_link::server_packet(Tcp_packet &tcp) -{ - if (_closed) { + if (_state == State::CLOSED) { return; } - if (tcp.fin()) { - _server_fin = true; } - - if (tcp.ack() && _client_fin) { - _client_fin_acked = true; - _fin_acked(); + if (tcp.rst()) { + _state = State::CLOSED; + } else { + if (tcp.fin()) { + sender.fin = true; + _state = State::CLOSING; + } + if (receiver.fin && tcp.ack()) { + receiver.fin_acked = true; + if (sender.fin_acked) { + _state = State::CLOSED; } + else { + _state = State::CLOSING; } + } } - if (!_closed) { - _packet(); } -} - - -void Tcp_link::client_packet(Tcp_packet &tcp) -{ - if (_closed) { - return; } - - if (tcp.fin()) { - _client_fin = true; } - - if (tcp.ack() && _server_fin) { - _server_fin_acked = true; - _fin_acked(); + if (_state == State::OPEN) { + _packet(); + } else { + _dissolve_timeout.schedule( + Microseconds(_config().tcp_max_segm_lifetime().value << 1)); } - if (!_closed) { - _packet(); } } diff --git a/repos/os/src/server/nic_router/link.h b/repos/os/src/server/nic_router/link.h index 079a742037..e531200068 100644 --- a/repos/os/src/server/nic_router/link.h +++ b/repos/os/src/server/nic_router/link.h @@ -200,13 +200,21 @@ class Net::Tcp_link : public Link { private: - bool _client_fin { false }; - bool _server_fin { false }; - bool _client_fin_acked { false }; - bool _server_fin_acked { false }; - bool _closed { false }; + enum class State : Genode::uint8_t { OPEN, CLOSING, CLOSED, }; - void _fin_acked(); + struct Peer + { + bool fin { false }; + bool fin_acked { false }; + }; + + State _state { State::OPEN }; + Peer _client { }; + Peer _server { }; + + void _tcp_packet(Tcp_packet &tcp, + Peer &sender, + Peer &receiver); public: @@ -219,9 +227,9 @@ class Net::Tcp_link : public Link Configuration &config, L3_protocol const protocol); - void client_packet(Tcp_packet &tcp); + void client_packet(Tcp_packet &tcp) { _tcp_packet(tcp, _client, _server); } - void server_packet(Tcp_packet &tcp); + void server_packet(Tcp_packet &tcp) { _tcp_packet(tcp, _server, _client); } };