mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-01-30 12:32:37 +00: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,6 +454,58 @@ tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Send an ACK without data.
|
||||||
|
*
|
||||||
|
* @param pcb Protocol control block for the TCP connection to send the ACK
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
tcp_send_empty_ack(struct tcp_pcb *pcb)
|
||||||
|
{
|
||||||
|
struct pbuf *p;
|
||||||
|
struct tcp_hdr *tcphdr;
|
||||||
|
u8_t optlen = 0;
|
||||||
|
|
||||||
|
#if LWIP_TCP_TIMESTAMPS
|
||||||
|
if (pcb->flags & TF_TIMESTAMP) {
|
||||||
|
optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, PBUF_RAM);
|
||||||
|
if (p == NULL) {
|
||||||
|
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
|
||||||
|
return ERR_BUF;
|
||||||
|
}
|
||||||
|
LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
|
||||||
|
("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
|
||||||
|
/* remove ACK flags from the PCB, as we send an empty ACK now */
|
||||||
|
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||||
|
|
||||||
|
tcphdr = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt));
|
||||||
|
|
||||||
|
/* NB. MSS option is only sent on SYNs, so ignore it here */
|
||||||
|
#if LWIP_TCP_TIMESTAMPS
|
||||||
|
pcb->ts_lastacksent = pcb->rcv_nxt;
|
||||||
|
|
||||||
|
if (pcb->flags & TF_TIMESTAMP) {
|
||||||
|
tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CHECKSUM_GEN_TCP
|
||||||
|
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
||||||
|
IP_PROTO_TCP, p->tot_len);
|
||||||
|
#endif
|
||||||
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
|
ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||||
|
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||||
|
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||||
|
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||||
|
IP_PROTO_TCP);
|
||||||
|
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||||
|
pbuf_free(p);
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find out what we can send and send it
|
* Find out what we can send and send it
|
||||||
@ -465,14 +517,11 @@ tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
|
|||||||
err_t
|
err_t
|
||||||
tcp_output(struct tcp_pcb *pcb)
|
tcp_output(struct tcp_pcb *pcb)
|
||||||
{
|
{
|
||||||
struct pbuf *p;
|
|
||||||
struct tcp_hdr *tcphdr;
|
|
||||||
struct tcp_seg *seg, *useg;
|
struct tcp_seg *seg, *useg;
|
||||||
u32_t wnd, snd_nxt;
|
u32_t wnd, snd_nxt;
|
||||||
#if TCP_CWND_DEBUG
|
#if TCP_CWND_DEBUG
|
||||||
s16_t i = 0;
|
s16_t i = 0;
|
||||||
#endif /* TCP_CWND_DEBUG */
|
#endif /* TCP_CWND_DEBUG */
|
||||||
u8_t optlen = 0;
|
|
||||||
|
|
||||||
/* First, check if we are invoked by the TCP input processing
|
/* First, check if we are invoked by the TCP input processing
|
||||||
code. If so, we do not output anything. Instead, we rely on the
|
code. If so, we do not output anything. Instead, we rely on the
|
||||||
@ -486,12 +535,6 @@ tcp_output(struct tcp_pcb *pcb)
|
|||||||
|
|
||||||
seg = pcb->unsent;
|
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
|
/* 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
|
* because the ->unsent queue is empty or because the window does
|
||||||
* not allow it), construct an empty ACK segment and send it.
|
* not allow it), construct an empty ACK segment and send it.
|
||||||
@ -501,44 +544,13 @@ tcp_output(struct tcp_pcb *pcb)
|
|||||||
if (pcb->flags & TF_ACK_NOW &&
|
if (pcb->flags & TF_ACK_NOW &&
|
||||||
(seg == NULL ||
|
(seg == NULL ||
|
||||||
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
|
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
|
||||||
#if LWIP_TCP_TIMESTAMPS
|
return tcp_send_empty_ack(pcb);
|
||||||
if (pcb->flags & TF_TIMESTAMP)
|
}
|
||||||
optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
|
|
||||||
#endif
|
|
||||||
p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, PBUF_RAM);
|
|
||||||
if (p == NULL) {
|
|
||||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
|
|
||||||
return ERR_BUF;
|
|
||||||
}
|
|
||||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
|
|
||||||
("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
|
|
||||||
/* remove ACK flags from the PCB, as we send an empty ACK now */
|
|
||||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
|
||||||
|
|
||||||
tcphdr = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt));
|
/* useg should point to last segment on unacked queue */
|
||||||
|
useg = pcb->unacked;
|
||||||
/* NB. MSS option is only sent on SYNs, so ignore it here */
|
if (useg != NULL) {
|
||||||
#if LWIP_TCP_TIMESTAMPS
|
for (; useg->next != NULL; useg = useg->next);
|
||||||
pcb->ts_lastacksent = pcb->rcv_nxt;
|
|
||||||
|
|
||||||
if (pcb->flags & TF_TIMESTAMP)
|
|
||||||
tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CHECKSUM_GEN_TCP
|
|
||||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
|
||||||
IP_PROTO_TCP, p->tot_len);
|
|
||||||
#endif
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
|
||||||
IP_PROTO_TCP, &(pcb->addr_hint));
|
|
||||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
|
||||||
IP_PROTO_TCP);
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
pbuf_free(p);
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TCP_OUTPUT_DEBUG
|
#if TCP_OUTPUT_DEBUG
|
||||||
|
@ -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