mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-01 04:12:07 +00:00
BUG27209: handle trimming of segments when out of window or out of
order properly
This commit is contained in:
parent
fa2dbc2b1b
commit
0b75917121
@ -115,6 +115,9 @@ HISTORY
|
|||||||
|
|
||||||
|
|
||||||
++ Bugfixes:
|
++ Bugfixes:
|
||||||
|
2009-08-12 Kieran Mansley
|
||||||
|
* tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when
|
||||||
|
out of window or out of order properly
|
||||||
|
|
||||||
2009-08-12 Kieran Mansley
|
2009-08-12 Kieran Mansley
|
||||||
* tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1
|
* tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include "lwip/memp.h"
|
#include "lwip/memp.h"
|
||||||
#include "lwip/snmp.h"
|
#include "lwip/snmp.h"
|
||||||
#include "lwip/tcp.h"
|
#include "lwip/tcp.h"
|
||||||
|
#include "lwip/debug.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -423,6 +424,9 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
|||||||
{
|
{
|
||||||
int wnd_inflation;
|
int wnd_inflation;
|
||||||
|
|
||||||
|
LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
|
||||||
|
len <= 0xffff - pcb->rcv_wnd );
|
||||||
|
|
||||||
pcb->rcv_wnd += len;
|
pcb->rcv_wnd += len;
|
||||||
if (pcb->rcv_wnd > TCP_WND)
|
if (pcb->rcv_wnd > TCP_WND)
|
||||||
pcb->rcv_wnd = TCP_WND;
|
pcb->rcv_wnd = TCP_WND;
|
||||||
|
@ -1055,35 +1055,73 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
/* The incoming segment is the next in sequence. We check if
|
/* The incoming segment is the next in sequence. We check if
|
||||||
we have to trim the end of the segment and update rcv_nxt
|
we have to trim the end of the segment and update rcv_nxt
|
||||||
and pass the data to the application. */
|
and pass the data to the application. */
|
||||||
|
tcplen = TCP_TCPLEN(&inseg);
|
||||||
|
|
||||||
|
if (tcplen > pcb->rcv_wnd) {
|
||||||
|
LWIP_DEBUGF(TCP_INPUT_DEBUG,
|
||||||
|
("tcp_receive: other end overran receive window"
|
||||||
|
"seqno %"U32_F" len %"U32_F" right edge %"U32_F"\n",
|
||||||
|
seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
|
||||||
|
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
|
||||||
|
/* Must remove the FIN from the header as we're trimming
|
||||||
|
* that byte of sequence-space from the packet */
|
||||||
|
TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
|
||||||
|
}
|
||||||
|
/* Adjust length of segment to fit in the window. */
|
||||||
|
inseg.len = pcb->rcv_wnd;
|
||||||
|
if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
|
||||||
|
inseg.len -= 1;
|
||||||
|
}
|
||||||
|
pbuf_realloc(inseg.p, inseg.len);
|
||||||
|
tcplen = TCP_TCPLEN(&inseg);
|
||||||
|
LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
|
||||||
|
(seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
|
||||||
|
}
|
||||||
#if TCP_QUEUE_OOSEQ
|
#if TCP_QUEUE_OOSEQ
|
||||||
if (pcb->ooseq != NULL &&
|
if (pcb->ooseq != NULL) {
|
||||||
TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {
|
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
|
||||||
if (pcb->ooseq->len > 0) {
|
LWIP_DEBUGF(TCP_INPUT_DEBUG,
|
||||||
/* We have to trim the second edge of the incoming
|
("tcp_receive: received in-order FIN, binning ooseq queue\n"));
|
||||||
segment. */
|
/* Received in-order FIN means anything that was received
|
||||||
inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);
|
* out of order must now have been received in-order, so
|
||||||
pbuf_realloc(inseg.p, inseg.len);
|
* bin the ooseq queue */
|
||||||
} else {
|
while (pcb->ooseq != NULL) {
|
||||||
/* does the ooseq segment contain only flags that are in inseg also? */
|
|
||||||
if ((TCPH_FLAGS(inseg.tcphdr) & (TCP_FIN|TCP_SYN)) ==
|
|
||||||
(TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {
|
|
||||||
struct tcp_seg *old_ooseq = pcb->ooseq;
|
struct tcp_seg *old_ooseq = pcb->ooseq;
|
||||||
pcb->ooseq = pcb->ooseq->next;
|
pcb->ooseq = pcb->ooseq->next;
|
||||||
memp_free(MEMP_TCP_SEG, old_ooseq);
|
memp_free(MEMP_TCP_SEG, old_ooseq);
|
||||||
|
}
|
||||||
|
} else if (TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + tcplen)) {
|
||||||
|
if (pcb->ooseq->len > 0) {
|
||||||
|
/* We have to trim the second edge of the incoming segment. */
|
||||||
|
LWIP_ASSERT("tcp_receive: trimmed segment would have zero length\n",
|
||||||
|
TCP_SEQ_GT(pcb->ooseq->tcphdr->seqno, seqno));
|
||||||
|
/* FIN in inseg already handled by dropping whole ooseq queue */
|
||||||
|
inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);
|
||||||
|
if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
|
||||||
|
inseg.len -= 1;
|
||||||
|
}
|
||||||
|
pbuf_realloc(inseg.p, inseg.len);
|
||||||
|
tcplen = TCP_TCPLEN(&inseg);
|
||||||
|
LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
|
||||||
|
(seqno + tcplen) == pcb->ooseq->tcphdr->seqno);
|
||||||
|
} else {
|
||||||
|
/* does the ooseq segment contain only flags that are in inseg also? */
|
||||||
|
if ((TCPH_FLAGS(inseg.tcphdr) & (TCP_FIN|TCP_SYN)) ==
|
||||||
|
(TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {
|
||||||
|
struct tcp_seg *old_ooseq = pcb->ooseq;
|
||||||
|
pcb->ooseq = pcb->ooseq->next;
|
||||||
|
memp_free(MEMP_TCP_SEG, old_ooseq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* TCP_QUEUE_OOSEQ */
|
#endif /* TCP_QUEUE_OOSEQ */
|
||||||
|
|
||||||
tcplen = TCP_TCPLEN(&inseg);
|
|
||||||
pcb->rcv_nxt = seqno + tcplen;
|
pcb->rcv_nxt = seqno + tcplen;
|
||||||
|
|
||||||
/* Update the receiver's (our) window. */
|
/* Update the receiver's (our) window. */
|
||||||
if (pcb->rcv_wnd < tcplen) {
|
LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
|
||||||
pcb->rcv_wnd = 0;
|
pcb->rcv_wnd -= tcplen;
|
||||||
} else {
|
|
||||||
pcb->rcv_wnd -= tcplen;
|
|
||||||
}
|
|
||||||
|
|
||||||
tcp_update_rcv_ann_wnd(pcb);
|
tcp_update_rcv_ann_wnd(pcb);
|
||||||
|
|
||||||
@ -1118,11 +1156,9 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
seqno = pcb->ooseq->tcphdr->seqno;
|
seqno = pcb->ooseq->tcphdr->seqno;
|
||||||
|
|
||||||
pcb->rcv_nxt += TCP_TCPLEN(cseg);
|
pcb->rcv_nxt += TCP_TCPLEN(cseg);
|
||||||
if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
|
LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
|
||||||
pcb->rcv_wnd = 0;
|
pcb->rcv_wnd >= TCP_TCPLEN(cseg));
|
||||||
} else {
|
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
|
||||||
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
|
|
||||||
}
|
|
||||||
|
|
||||||
tcp_update_rcv_ann_wnd(pcb);
|
tcp_update_rcv_ann_wnd(pcb);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user