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
This commit is contained in:
Martin Stein 2018-07-12 00:56:14 +02:00 committed by Christian Helmuth
parent 3db7181104
commit bd77bb41df
2 changed files with 39 additions and 43 deletions

View File

@ -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.rst()) {
_state = State::CLOSED;
} else {
if (tcp.fin()) {
_server_fin = true; }
if (tcp.ack() && _client_fin) {
_client_fin_acked = true;
_fin_acked();
sender.fin = true;
_state = State::CLOSING;
}
if (!_closed) {
_packet(); }
if (receiver.fin && tcp.ack()) {
receiver.fin_acked = true;
if (sender.fin_acked) {
_state = State::CLOSED; }
else {
_state = State::CLOSING; }
}
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 (!_closed) {
_packet(); }
if (_state == State::OPEN) {
_packet();
} else {
_dissolve_timeout.schedule(
Microseconds(_config().tcp_max_segm_lifetime().value << 1));
}
}

View File

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