From 2452bc93363f1af4dcfa7cf4439b0b58fcb67d8f Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Tue, 7 Mar 2017 20:53:02 -0600 Subject: [PATCH] bug #50476: initialize ssthresh to TCP_SND_BUF This commit changes ssthresh to be the largest effective congestion window (amount of in-flight data). This follows the guidance of RFC 5681 which recommends setting ssthresh arbitrarily high. LwIP was previously using the receive window value at the end of the 3-way handshake and in the case of an active open where the receiver used window scaling and/or window auto-tuning, this resulted in a very small ssthresh value even though the window ramped up once the connection was established (cherry picked from commit b90a54f989d0edafa36b29bb0c346d1b30e1bf8f) --- src/core/tcp.c | 9 ++++++++- src/core/tcp_in.c | 11 ----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index 2c875d43..40f4c1d3 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -948,7 +948,6 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; - pcb->ssthresh = TCP_WND; #if LWIP_CALLBACK_API pcb->connected = connected; #else /* LWIP_CALLBACK_API */ @@ -1615,6 +1614,14 @@ tcp_alloc(u8_t prio) pcb->tmr = tcp_ticks; pcb->last_timer = tcp_timer_ctr; + /* RFC 5681 recommends setting ssthresh abritrarily high and gives an example + of using the largest advertised receive window. We've seen complications with + receiving TCPs that use window scaling and/or window auto-tuning where the + initial advertised window is very small and then grows rapidly once the + connection is established. To avoid these complications, we set ssthresh to the + largest effective cwnd (amount of in-flight data) that the sender can have. */ + pcb->ssthresh = TCP_SND_BUF; + #if LWIP_CALLBACK_API pcb->recv = tcp_recv_null; #endif /* LWIP_CALLBACK_API */ diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 6ec306cc..902b038b 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -61,8 +61,6 @@ /** Initial CWND calculation as defined RFC 2581 */ #define LWIP_TCP_CALC_INITIAL_CWND(mss) LWIP_MIN((4U * (mss)), LWIP_MAX((2U * (mss)), 4380U)); -/** Initial slow start threshold value: we use the full window */ -#define LWIP_TCP_INITIAL_SSTHRESH(pcb) ((pcb)->snd_wnd) /* These variables are global to all functions involved in the input processing of TCP segments. They are set by the tcp_input() @@ -615,7 +613,6 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) tcp_parseopt(npcb); npcb->snd_wnd = tcphdr->wnd; npcb->snd_wnd_max = npcb->snd_wnd; - npcb->ssthresh = LWIP_TCP_INITIAL_SSTHRESH(npcb); #if TCP_CALCULATE_EFF_SEND_MSS npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip); @@ -771,9 +768,6 @@ tcp_process(struct tcp_pcb *pcb) pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ - /* Set ssthresh again after changing 'mss' and 'snd_wnd' */ - pcb->ssthresh = LWIP_TCP_INITIAL_SSTHRESH(pcb); - pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SENT): cwnd %"TCPWNDSIZE_F " ssthresh %"TCPWNDSIZE_F"\n", @@ -855,11 +849,6 @@ tcp_process(struct tcp_pcb *pcb) * we'd better pass it on to the application as well. */ tcp_receive(pcb); - /* passive open: update initial ssthresh now that the correct window is - known: if the remote side supports window scaling, the window sent - with the initial SYN can be smaller than the one used later */ - pcb->ssthresh = LWIP_TCP_INITIAL_SSTHRESH(pcb); - /* Prevent ACK for SYN to generate a sent event */ if (recv_acked != 0) { recv_acked--;