diff options
author | Andy Ross <andrew.j.ross@intel.com> | 2017-01-27 10:05:46 -0800 |
---|---|---|
committer | Jukka Rissanen <jukka.rissanen@linux.intel.com> | 2017-01-31 13:45:52 +0200 |
commit | de0f6256fae9be1bf7e4286a0a7de9bedaa57348 (patch) | |
tree | e703f545a1a40cb84663d76066c9d0a86a01a985 | |
parent | 3c3e5b1544caa03cf7027559214d272848169d72 (diff) |
net: tcp: Add optional TIME_WAIT support
The RFC requires we honor the 2MSL TIME_WAIT timeout, support for
which was just removed with the FIN cleanup. Add it back, but make it
optional (proper sequence number and ephemeral port randomization
makes true collisions a birthday problem in a ~80 bit space!).
Change-Id: I176c6250f43bba0c914da1ee7f0136dcb1008046
Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
-rw-r--r-- | subsys/net/ip/Kconfig | 12 | ||||
-rw-r--r-- | subsys/net/ip/tcp.c | 17 |
2 files changed, 28 insertions, 1 deletions
diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 8a5dfa24b..7fba56354 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -99,6 +99,18 @@ config NET_DEBUG_TCP help Enables TCP handler output debug messages +config NET_TCP_TIME_WAIT + bool "Enable TCP TIME_WAIT timeouts" + default n + help + Officially, the TCP standard requires a 4 minute timeout on + connection close before that particular port pair can be used + again. This requires that the net_context and net_tcp structs + persist for the full duration, so has non-trivial memory costs + and is optional. Modern systems with well-randomized sequence + numbers don't need this, but it is present for specification + compliance where needed. + config NET_UDP bool "Enable UDP" default y diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index cec7f702f..2909e89f5 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -44,6 +44,9 @@ static struct net_tcp tcp_context[NET_MAX_TCP_CONTEXT]; #define INIT_RETRY_MS 200 +/* 2MSL timeout, where "MSL" is arbitrarily 2 minutes in the RFC */ +#define TIME_WAIT_MS (2 * 2 * 60 * 1000) + struct tcp_segment { uint32_t seq; uint32_t ack; @@ -120,6 +123,10 @@ static void tcp_retry_expired(struct k_timer *timer) buf = CONTAINER_OF(sys_slist_peek_head(&tcp->sent_list), struct net_buf, sent_list); net_tcp_send_buf(net_buf_ref(buf)); + } else if (IS_ENABLED(CONFIG_NET_TCP_TIME_WAIT)) { + if (tcp->fin_sent && tcp->fin_rcvd) { + net_context_unref(tcp->context); + } } } @@ -637,10 +644,18 @@ int net_tcp_send_buf(struct net_buf *buf) static void restart_timer(struct net_tcp *tcp) { - if (sys_slist_is_empty(&tcp->sent_list)) { + if (!sys_slist_is_empty(&tcp->sent_list)) { tcp->flags |= NET_TCP_RETRYING; tcp->retry_timeout_shift = 0; k_timer_start(&tcp->retry_timer, retry_timeout(tcp), 0); + } else if (IS_ENABLED(CONFIG_NET_TCP_TIME_WAIT)) { + if (tcp->fin_sent && tcp->fin_rcvd) { + /* We know sent_list is empty, which means if + * fin_sent is true it must have been ACKd + */ + k_timer_start(&tcp->retry_timer, TIME_WAIT_MS, 0); + net_context_ref(tcp->context); + } } else { k_timer_stop(&tcp->retry_timer); tcp->flags &= ~NET_TCP_RETRYING; |