From 261dfdf01040bc5309a5b5636c4838fb7c583e6d Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 26 Apr 2009 12:27:11 +0000 Subject: [PATCH] fixed bug #24212: "Deadlocked tcp_retransmit due to exceeded pcb->cwnd": Fixed by sorting the unsent and unacked queues (segments are inserted at the right place in tcp_output and tcp_rexmit) --- CHANGELOG | 5 +++++ src/core/tcp_out.c | 29 +++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 95b8d9cf..c8feecfc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -92,6 +92,11 @@ HISTORY ++ Bugfixes: + 2009-04-25 Simon Goldschmidt, Oleg Tyshev + * tcp_out.c: bug #24212: Deadlocked tcp_retransmit due to exceeded pcb->cwnd + Fixed by sorting the unsent and unacked queues (segments are inserted at the + right place in tcp_output and tcp_rexmit). + 2009-04-25 Simon Goldschmidt * memp.c, mem.c, memp.h, mem_std.h: bug #26213 "Problem with memory allocation when debugging": memp_sizes contained the wrong sizes (including sanity diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index d13beb05..be53c55d 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -595,12 +595,17 @@ tcp_output(struct tcp_pcb *pcb) /* unacked list is not empty? */ } else { /* In the case of fast retransmit, the packet should not go to the tail - * of the unacked queue, but rather at the head. We need to check for + * of the unacked queue, but rather somewhere before it. We need to check for * this case. -STJ Jul 27, 2004 */ if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){ - /* add segment to head of unacked list */ - seg->next = pcb->unacked; - pcb->unacked = seg; + /* add segment to before tail of unacked list, keeping the list sorted */ + struct tcp_seg **cur_seg = &(pcb->unacked); + while (*cur_seg && + TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = (*cur_seg); + (*cur_seg) = seg; } else { /* add segment to tail of unacked list */ useg->next = seg; @@ -820,16 +825,24 @@ void tcp_rexmit(struct tcp_pcb *pcb) { struct tcp_seg *seg; + struct tcp_seg **cur_seg; if (pcb->unacked == NULL) { return; } /* Move the first unacked segment to the unsent queue */ - seg = pcb->unacked->next; - pcb->unacked->next = pcb->unsent; - pcb->unsent = pcb->unacked; - pcb->unacked = seg; + /* Keep the unsent queue sorted. */ + seg = pcb->unacked; + pcb->unacked = seg->next; + + cur_seg = &(pcb->unsent); + while (*cur_seg && + TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { + cur_seg = &((*cur_seg)->next ); + } + seg->next = *cur_seg; + *cur_seg = seg; pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);