diff --git a/CHANGELOG b/CHANGELOG index d6bd1552..ff08396d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -46,6 +46,9 @@ HISTORY ++ Bugfixes: + 2009-10-27: Kieran Mansley + * tcp_in.c: fix BUG#27445: grow cwnd with every duplicate ACK + 2009-10-25: Simon Goldschmidt * tcp.h: bug-fix in the TCP_EVENT_RECV macro (has to call tcp_recved if pcb->recv is NULL to keep rcv_wnd correct) diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index dc6d72ca..2efd3196 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -793,44 +793,44 @@ tcp_receive(struct tcp_pcb *pcb) pcb->acked = 0; if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ - if (pcb->unacked != NULL) { - ++pcb->dupacks; - if (pcb->dupacks >= 3) { - if (!(pcb->flags & TF_INFR)) { - /* This is fast retransmit. Retransmit the first unacked segment. */ - LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n", - (u16_t)pcb->dupacks, pcb->lastack, - ntohl(pcb->unacked->tcphdr->seqno))); - tcp_rexmit(pcb); - /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */ - /*pcb->ssthresh = LWIP_MAX((pcb->snd_max - - pcb->lastack) / 2, - 2 * pcb->mss);*/ - /* Set ssthresh to half of the minimum of the current cwnd and the advertised window */ - if (pcb->cwnd > pcb->snd_wnd) - pcb->ssthresh = pcb->snd_wnd / 2; - else - pcb->ssthresh = pcb->cwnd / 2; + ++pcb->dupacks; - /* The minimum value for ssthresh should be 2 MSS */ - if (pcb->ssthresh < 2*pcb->mss) { - LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: The minimum value for ssthresh %"U16_F" should be min 2 mss %"U16_F"...\n", pcb->ssthresh, 2*pcb->mss)); - pcb->ssthresh = 2*pcb->mss; - } - - pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; - pcb->flags |= TF_INFR; - } else { - /* Inflate the congestion window, but not if it means that - the value overflows. */ - if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { - pcb->cwnd += pcb->mss; - } + if (pcb->dupacks >= 3) { + if (!(pcb->flags & TF_INFR) && pcb->unacked != NULL) { + /* This is fast retransmit. Retransmit the first unacked segment. */ + LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n", + (u16_t)pcb->dupacks, pcb->lastack, + ntohl(pcb->unacked->tcphdr->seqno))); + tcp_rexmit(pcb); + /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */ + /*pcb->ssthresh = LWIP_MAX((pcb->snd_max - + pcb->lastack) / 2, + 2 * pcb->mss);*/ + /* Set ssthresh to half of the minimum of the current cwnd and the advertised window */ + if (pcb->cwnd > pcb->snd_wnd) + pcb->ssthresh = pcb->snd_wnd / 2; + else + pcb->ssthresh = pcb->cwnd / 2; + + /* The minimum value for ssthresh should be 2 MSS */ + if (pcb->ssthresh < 2*pcb->mss) { + LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: The minimum value for ssthresh %"U16_F" should be min 2 mss %"U16_F"...\n", pcb->ssthresh, 2*pcb->mss)); + pcb->ssthresh = 2*pcb->mss; + } + + pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; + pcb->flags |= TF_INFR; + } else { + /* Inflate the congestion window, but not if it means that + the value overflows. */ + if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { + pcb->cwnd += pcb->mss; } } - } else { - pcb->dupacks = 0; } + + if (pcb->unacked == NULL && pcb->unsent == NULL) + pcb->dupacks = 0; } else { LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n", pcb->snd_wl2 + pcb->snd_wnd, right_wnd_edge));