mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2025-08-03 04:54:38 +08:00
Fixed bug #28106: dup ack for fast retransmit could have non-zero length
This commit is contained in:
parent
32acb82bc0
commit
7d46e06824
@ -46,6 +46,10 @@ HISTORY
|
|||||||
|
|
||||||
++ Bugfixes:
|
++ Bugfixes:
|
||||||
|
|
||||||
|
2009-12-03: Simon Goldschmidt
|
||||||
|
* tcp.h, tcp_in.c, tcp_out.c: Fixed bug #28106: dup ack for fast retransmit
|
||||||
|
could have non-zero length
|
||||||
|
|
||||||
2009-12-02: Simon Goldschmidt
|
2009-12-02: Simon Goldschmidt
|
||||||
* tcp_in.c: Fixed bug #27904: TCP sends too many ACKs: delay resetting
|
* tcp_in.c: Fixed bug #27904: TCP sends too many ACKs: delay resetting
|
||||||
tcp_input_pcb until after calling the pcb's callbacks
|
tcp_input_pcb until after calling the pcb's callbacks
|
||||||
|
@ -1267,7 +1267,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* We get here if the incoming segment is out-of-sequence. */
|
/* We get here if the incoming segment is out-of-sequence. */
|
||||||
tcp_ack_now(pcb);
|
tcp_send_empty_ack(pcb);
|
||||||
#if TCP_QUEUE_OOSEQ
|
#if TCP_QUEUE_OOSEQ
|
||||||
/* We queue the segment on the ->ooseq queue. */
|
/* We queue the segment on the ->ooseq queue. */
|
||||||
if (pcb->ooseq == NULL) {
|
if (pcb->ooseq == NULL) {
|
||||||
@ -1376,7 +1376,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* The incoming segment is not withing the window. */
|
/* The incoming segment is not withing the window. */
|
||||||
tcp_ack_now(pcb);
|
tcp_send_empty_ack(pcb);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Segments with length 0 is taken care of here. Segments that
|
/* Segments with length 0 is taken care of here. Segments that
|
||||||
|
@ -454,56 +454,21 @@ tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Send an ACK without data.
|
||||||
/**
|
|
||||||
* Find out what we can send and send it
|
|
||||||
*
|
*
|
||||||
* @param pcb Protocol control block for the TCP connection to send data
|
* @param pcb Protocol control block for the TCP connection to send the ACK
|
||||||
* @return ERR_OK if data has been sent or nothing to send
|
|
||||||
* another err_t on error
|
|
||||||
*/
|
*/
|
||||||
err_t
|
err_t
|
||||||
tcp_output(struct tcp_pcb *pcb)
|
tcp_send_empty_ack(struct tcp_pcb *pcb)
|
||||||
{
|
{
|
||||||
struct pbuf *p;
|
struct pbuf *p;
|
||||||
struct tcp_hdr *tcphdr;
|
struct tcp_hdr *tcphdr;
|
||||||
struct tcp_seg *seg, *useg;
|
|
||||||
u32_t wnd, snd_nxt;
|
|
||||||
#if TCP_CWND_DEBUG
|
|
||||||
s16_t i = 0;
|
|
||||||
#endif /* TCP_CWND_DEBUG */
|
|
||||||
u8_t optlen = 0;
|
u8_t optlen = 0;
|
||||||
|
|
||||||
/* First, check if we are invoked by the TCP input processing
|
|
||||||
code. If so, we do not output anything. Instead, we rely on the
|
|
||||||
input processing code to call us when input processing is done
|
|
||||||
with. */
|
|
||||||
if (tcp_input_pcb == pcb) {
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
|
|
||||||
|
|
||||||
seg = pcb->unsent;
|
|
||||||
|
|
||||||
/* useg should point to last segment on unacked queue */
|
|
||||||
useg = pcb->unacked;
|
|
||||||
if (useg != NULL) {
|
|
||||||
for (; useg->next != NULL; useg = useg->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the TF_ACK_NOW flag is set and no data will be sent (either
|
|
||||||
* because the ->unsent queue is empty or because the window does
|
|
||||||
* not allow it), construct an empty ACK segment and send it.
|
|
||||||
*
|
|
||||||
* If data is to be sent, we will just piggyback the ACK (see below).
|
|
||||||
*/
|
|
||||||
if (pcb->flags & TF_ACK_NOW &&
|
|
||||||
(seg == NULL ||
|
|
||||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
|
|
||||||
#if LWIP_TCP_TIMESTAMPS
|
#if LWIP_TCP_TIMESTAMPS
|
||||||
if (pcb->flags & TF_TIMESTAMP)
|
if (pcb->flags & TF_TIMESTAMP) {
|
||||||
optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
|
optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, PBUF_RAM);
|
p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, PBUF_RAM);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
@ -521,8 +486,9 @@ tcp_output(struct tcp_pcb *pcb)
|
|||||||
#if LWIP_TCP_TIMESTAMPS
|
#if LWIP_TCP_TIMESTAMPS
|
||||||
pcb->ts_lastacksent = pcb->rcv_nxt;
|
pcb->ts_lastacksent = pcb->rcv_nxt;
|
||||||
|
|
||||||
if (pcb->flags & TF_TIMESTAMP)
|
if (pcb->flags & TF_TIMESTAMP) {
|
||||||
tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
|
tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CHECKSUM_GEN_TCP
|
#if CHECKSUM_GEN_TCP
|
||||||
@ -541,6 +507,52 @@ tcp_output(struct tcp_pcb *pcb)
|
|||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find out what we can send and send it
|
||||||
|
*
|
||||||
|
* @param pcb Protocol control block for the TCP connection to send data
|
||||||
|
* @return ERR_OK if data has been sent or nothing to send
|
||||||
|
* another err_t on error
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcp_output(struct tcp_pcb *pcb)
|
||||||
|
{
|
||||||
|
struct tcp_seg *seg, *useg;
|
||||||
|
u32_t wnd, snd_nxt;
|
||||||
|
#if TCP_CWND_DEBUG
|
||||||
|
s16_t i = 0;
|
||||||
|
#endif /* TCP_CWND_DEBUG */
|
||||||
|
|
||||||
|
/* First, check if we are invoked by the TCP input processing
|
||||||
|
code. If so, we do not output anything. Instead, we rely on the
|
||||||
|
input processing code to call us when input processing is done
|
||||||
|
with. */
|
||||||
|
if (tcp_input_pcb == pcb) {
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
|
||||||
|
|
||||||
|
seg = pcb->unsent;
|
||||||
|
|
||||||
|
/* If the TF_ACK_NOW flag is set and no data will be sent (either
|
||||||
|
* because the ->unsent queue is empty or because the window does
|
||||||
|
* not allow it), construct an empty ACK segment and send it.
|
||||||
|
*
|
||||||
|
* If data is to be sent, we will just piggyback the ACK (see below).
|
||||||
|
*/
|
||||||
|
if (pcb->flags & TF_ACK_NOW &&
|
||||||
|
(seg == NULL ||
|
||||||
|
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
|
||||||
|
return tcp_send_empty_ack(pcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* useg should point to last segment on unacked queue */
|
||||||
|
useg = pcb->unacked;
|
||||||
|
if (useg != NULL) {
|
||||||
|
for (; useg->next != NULL; useg = useg->next);
|
||||||
|
}
|
||||||
|
|
||||||
#if TCP_OUTPUT_DEBUG
|
#if TCP_OUTPUT_DEBUG
|
||||||
if (seg == NULL) {
|
if (seg == NULL) {
|
||||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
|
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
|
||||||
|
@ -125,6 +125,7 @@ void tcp_fasttmr (void);
|
|||||||
/* Only used by IP to pass a TCP segment to TCP: */
|
/* Only used by IP to pass a TCP segment to TCP: */
|
||||||
void tcp_input (struct pbuf *p, struct netif *inp);
|
void tcp_input (struct pbuf *p, struct netif *inp);
|
||||||
/* Used within the TCP code only: */
|
/* Used within the TCP code only: */
|
||||||
|
err_t tcp_send_empty_ack(struct tcp_pcb *pcb);
|
||||||
err_t tcp_output (struct tcp_pcb *pcb);
|
err_t tcp_output (struct tcp_pcb *pcb);
|
||||||
void tcp_rexmit (struct tcp_pcb *pcb);
|
void tcp_rexmit (struct tcp_pcb *pcb);
|
||||||
void tcp_rexmit_rto (struct tcp_pcb *pcb);
|
void tcp_rexmit_rto (struct tcp_pcb *pcb);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user