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>
This commit is contained in:
parent
f3cce9082d
commit
3efe6b7ede
2 changed files with 28 additions and 1 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue