From 2ed5bc5195fec00b3e1877fd0f4b182ecf5ecd6e Mon Sep 17 00:00:00 2001 From: kieranm Date: Sun, 12 Sep 2004 16:34:06 +0000 Subject: [PATCH] Kieran Mansley - kjm25@cam.ac.uk - 12th September 2004 Applied patch from Sam Jansen as detailed in http://lists.gnu.org/archive/html/lwip-users/2004-07/msg00106.html to correctly handle retransmission after a retransmission timeout --- src/core/tcp.c | 6 ++++-- src/core/tcp_in.c | 5 ----- src/core/tcp_out.c | 40 ++++++++++++++++++++++++++++++++++++++-- src/include/lwip/tcp.h | 1 + 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index d53ce135..205af53d 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -590,7 +590,6 @@ tcp_slowtmr(void) if (pcb->state != SYN_SENT) { pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; } - tcp_rexmit(pcb); /* Reduce congestion window and ssthresh. */ eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); pcb->ssthresh = eff_wnd >> 1; @@ -600,7 +599,10 @@ tcp_slowtmr(void) pcb->cwnd = pcb->mss; LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %u ssthresh %u\n", pcb->cwnd, pcb->ssthresh)); - } + + /* The following needs to be called AFTER cwnd is set to one mss - STJ */ + tcp_rexmit_rto(pcb); + } } /* Check if this PCB has stayed too long in FIN-WAIT-2 */ if (pcb->state == FIN_WAIT_2) { diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index c51d2363..e008852d 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -818,10 +818,6 @@ tcp_receive(struct tcp_pcb *pcb) rationale is that lwIP puts all outstanding segments on the ->unsent list after a retransmission, so these segments may in fact have been sent once. */ - /* KJM 13th July 2004 - I don't think is is necessary as we no longer move all unacked - segments on the unsent queue when performing retransmit */ -#if 0 while (pcb->unsent != NULL && /*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) && TCP_SEQ_LEQ(ackno, pcb->snd_max)*/ @@ -846,7 +842,6 @@ tcp_receive(struct tcp_pcb *pcb) pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno); } } -#endif /* End of ACK for new data processing. */ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %u rtseq %lu ackno %lu\n", diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index bea45dee..8d6465eb 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -462,8 +462,16 @@ tcp_output(struct tcp_pcb *pcb) pcb->unacked = seg; useg = seg; } else { - useg->next = seg; - useg = useg->next; + /* In the case of fast retransmit, the packet should not go to the end + * of the unacked queue, but rather at the start. We need to check for + * this case. -STJ Jul 27, 2004 */ + if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){ + seg->next = pcb->unacked; + pcb->unacked = seg; + } else { + useg->next = seg; + useg = useg->next; + } } } else { tcp_seg_free(seg); @@ -568,6 +576,33 @@ tcp_rst(u32_t seqno, u32_t ackno, LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno)); } +void +tcp_rexmit_rto(struct tcp_pcb *pcb) +{ + struct tcp_seg *seg; + + if (pcb->unacked == NULL) { + return; + } + + /* Move all unacked segments to the unsent queue. */ + for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); + seg->next = pcb->unsent; + pcb->unsent = pcb->unacked; + pcb->unacked = NULL; + + pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno); + + ++pcb->nrtx; + + /* Don't take any rtt measurements after retransmitting. */ + pcb->rttest = 0; + + /* Do the actual retransmission. */ + tcp_output(pcb); + +} + void tcp_rexmit(struct tcp_pcb *pcb) { @@ -595,6 +630,7 @@ tcp_rexmit(struct tcp_pcb *pcb) } + void tcp_keepalive(struct tcp_pcb *pcb) { diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 483b2178..e9702a0c 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -105,6 +105,7 @@ void tcp_input (struct pbuf *p, struct netif *inp); /* Used within the TCP code only: */ err_t tcp_output (struct tcp_pcb *pcb); void tcp_rexmit (struct tcp_pcb *pcb); +void tcp_rexmit_rto (struct tcp_pcb *pcb);