* tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission

timer is reset to fix bug#19434, with help from Oleg Tyshev.
This commit is contained in:
kieranm 2007-04-12 14:56:07 +00:00
parent 58b3b0603d
commit 79be888b6f
4 changed files with 42 additions and 18 deletions

View File

@ -500,11 +500,13 @@ tcp_slowtmr(void)
++pcb_remove; ++pcb_remove;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
} else { } else {
/* Increase the retransmission timer if it is running */
if(pcb->rtime >= 0)
++pcb->rtime; ++pcb->rtime;
if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
/* Time for a retransmission. */ /* Time for a retransmission. */
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"U16_F" pcb->rto %"U16_F"\n", LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F" pcb->rto %"S16_F"\n",
pcb->rtime, pcb->rto)); pcb->rtime, pcb->rto));
/* Double retransmission time-out unless we are trying to /* Double retransmission time-out unless we are trying to
@ -512,6 +514,10 @@ tcp_slowtmr(void)
if (pcb->state != SYN_SENT) { if (pcb->state != SYN_SENT) {
pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
} }
/* Reset the retransmission timer. */
pcb->rtime = 0;
/* Reduce congestion window and ssthresh. */ /* Reduce congestion window and ssthresh. */
eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
pcb->ssthresh = eff_wnd >> 1; pcb->ssthresh = eff_wnd >> 1;
@ -844,7 +850,7 @@ tcp_alloc(u8_t prio)
pcb->rto = 3000 / TCP_SLOW_INTERVAL; pcb->rto = 3000 / TCP_SLOW_INTERVAL;
pcb->sa = 0; pcb->sa = 0;
pcb->sv = 3000 / TCP_SLOW_INTERVAL; pcb->sv = 3000 / TCP_SLOW_INTERVAL;
pcb->rtime = 0; pcb->rtime = -1;
pcb->cwnd = 1; pcb->cwnd = 1;
iss = tcp_next_iss(); iss = tcp_next_iss();
pcb->snd_wl2 = iss; pcb->snd_wl2 = iss;
@ -994,6 +1000,10 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
} }
/* Stop the retransmission timer as it will expect data on unacked
queue if it fires */
pcb->rtime = -1;
tcp_segs_free(pcb->ooseq); tcp_segs_free(pcb->ooseq);
pcb->ooseq = NULL; pcb->ooseq = NULL;
#endif /* TCP_QUEUE_OOSEQ */ #endif /* TCP_QUEUE_OOSEQ */

View File

@ -504,6 +504,14 @@ tcp_process(struct tcp_pcb *pcb)
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
rseg = pcb->unacked; rseg = pcb->unacked;
pcb->unacked = rseg->next; pcb->unacked = rseg->next;
/* If there's nothing left to acknowledge, stop the retransmit
timer, otherwise reset it to start again */
if(pcb->unacked == NULL)
pcb->rtime = -1;
else
pcb->rtime = 0;
tcp_seg_free(rseg); tcp_seg_free(rseg);
/* Parse any options in the SYNACK. */ /* Parse any options in the SYNACK. */
@ -700,10 +708,7 @@ tcp_receive(struct tcp_pcb *pcb)
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n", LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",
pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge)); pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));
} }
} else } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){
/*if (TCP_SEQ_LT(pcb->lastack, ackno) &&
TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */
if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){
/* We come here when the ACK acknowledges new data. */ /* We come here when the ACK acknowledges new data. */
/* Reset the "IN Fast Retransmit" flag, since we are no longer /* Reset the "IN Fast Retransmit" flag, since we are no longer
@ -775,6 +780,14 @@ tcp_receive(struct tcp_pcb *pcb)
pcb->unsent != NULL); pcb->unsent != NULL);
} }
} }
/* If there's nothing left to acknowledge, stop the retransmit
timer, otherwise reset it to start again */
if(pcb->unacked == NULL)
pcb->rtime = -1;
else
pcb->rtime = 0;
pcb->polltmr = 0; pcb->polltmr = 0;
} }

View File

@ -551,6 +551,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
ip_addr_set(&(pcb->local_ip), &(netif->ip_addr)); ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));
} }
/* Set retransmission timer running if it is not currently enabled */
if(pcb->rtime == -1)
pcb->rtime = 0; pcb->rtime = 0;
if (pcb->rttest == 0) { if (pcb->rttest == 0) {
@ -674,7 +676,6 @@ tcp_rexmit(struct tcp_pcb *pcb)
/* Do the actual retransmission. */ /* Do the actual retransmission. */
snmp_inc_tcpretranssegs(); snmp_inc_tcpretranssegs();
tcp_output(pcb); tcp_output(pcb);
} }

View File

@ -253,7 +253,7 @@ struct tcp_pcb {
u8_t polltmr, pollinterval; u8_t polltmr, pollinterval;
/* Retransmission timer. */ /* Retransmission timer. */
u16_t rtime; s16_t rtime;
u16_t mss; /* maximum segment size */ u16_t mss; /* maximum segment size */
@ -262,7 +262,7 @@ struct tcp_pcb {
u32_t rtseq; /* sequence number being timed */ u32_t rtseq; /* sequence number being timed */
s16_t sa, sv; /* @todo document this */ s16_t sa, sv; /* @todo document this */
u16_t rto; /* retransmission time-out */ s16_t rto; /* retransmission time-out */
u8_t nrtx; /* number of retransmissions */ u8_t nrtx; /* number of retransmissions */
/* fast retransmit/recovery */ /* fast retransmit/recovery */