mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-04 05:39:53 +00:00
Fix for out-of-sequence FIN handling, patch by Oleg Tychev.
This commit is contained in:
parent
6cb19d7e34
commit
313743c833
@ -74,7 +74,7 @@ struct tcp_pcb *tcp_input_pcb;
|
|||||||
|
|
||||||
/* Forward declarations. */
|
/* Forward declarations. */
|
||||||
static err_t tcp_process(struct tcp_pcb *pcb);
|
static err_t tcp_process(struct tcp_pcb *pcb);
|
||||||
static void tcp_receive(struct tcp_pcb *pcb);
|
static u8_t tcp_receive(struct tcp_pcb *pcb);
|
||||||
static void tcp_parseopt(struct tcp_pcb *pcb);
|
static void tcp_parseopt(struct tcp_pcb *pcb);
|
||||||
|
|
||||||
static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
|
static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
|
||||||
@ -434,7 +434,7 @@ tcp_process(struct tcp_pcb *pcb)
|
|||||||
struct tcp_seg *rseg;
|
struct tcp_seg *rseg;
|
||||||
u8_t acceptable = 0;
|
u8_t acceptable = 0;
|
||||||
err_t err;
|
err_t err;
|
||||||
|
u8_t accepted_inseq;
|
||||||
|
|
||||||
err = ERR_OK;
|
err = ERR_OK;
|
||||||
|
|
||||||
@ -543,8 +543,8 @@ tcp_process(struct tcp_pcb *pcb)
|
|||||||
case CLOSE_WAIT:
|
case CLOSE_WAIT:
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case ESTABLISHED:
|
case ESTABLISHED:
|
||||||
tcp_receive(pcb);
|
accepted_inseq = tcp_receive(pcb);
|
||||||
if (flags & TCP_FIN) {
|
if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
pcb->state = CLOSE_WAIT;
|
pcb->state = CLOSE_WAIT;
|
||||||
}
|
}
|
||||||
@ -614,9 +614,11 @@ tcp_process(struct tcp_pcb *pcb)
|
|||||||
*
|
*
|
||||||
* If the incoming segment constitutes an ACK for a segment that was used for RTT
|
* If the incoming segment constitutes an ACK for a segment that was used for RTT
|
||||||
* estimation, the RTT is estimated here as well.
|
* estimation, the RTT is estimated here as well.
|
||||||
|
*
|
||||||
|
* @return 1 if
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static u8_t
|
||||||
tcp_receive(struct tcp_pcb *pcb)
|
tcp_receive(struct tcp_pcb *pcb)
|
||||||
{
|
{
|
||||||
struct tcp_seg *next;
|
struct tcp_seg *next;
|
||||||
@ -628,7 +630,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
s16_t m;
|
s16_t m;
|
||||||
u32_t right_wnd_edge;
|
u32_t right_wnd_edge;
|
||||||
u16_t new_tot_len;
|
u16_t new_tot_len;
|
||||||
|
u8_t accepted_inseq = 0;
|
||||||
|
|
||||||
if (flags & TCP_ACK) {
|
if (flags & TCP_ACK) {
|
||||||
right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;
|
right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;
|
||||||
@ -650,7 +652,6 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
#endif /* TCP_WND_DEBUG */
|
#endif /* TCP_WND_DEBUG */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pcb->lastack == ackno) {
|
if (pcb->lastack == ackno) {
|
||||||
pcb->acked = 0;
|
pcb->acked = 0;
|
||||||
|
|
||||||
@ -668,7 +669,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
pcb->lastack) / 2,
|
pcb->lastack) / 2,
|
||||||
2 * pcb->mss);*/
|
2 * pcb->mss);*/
|
||||||
/* Set ssthresh to half of the minimum of the currenct cwnd and the advertised window */
|
/* Set ssthresh to half of the minimum of the currenct cwnd and the advertised window */
|
||||||
if(pcb->cwnd > pcb->snd_wnd)
|
if (pcb->cwnd > pcb->snd_wnd)
|
||||||
pcb->ssthresh = pcb->snd_wnd / 2;
|
pcb->ssthresh = pcb->snd_wnd / 2;
|
||||||
else
|
else
|
||||||
pcb->ssthresh = pcb->cwnd / 2;
|
pcb->ssthresh = pcb->cwnd / 2;
|
||||||
@ -690,7 +691,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
} else
|
} else
|
||||||
/*if (TCP_SEQ_LT(pcb->lastack, ackno) &&
|
/*if (TCP_SEQ_LT(pcb->lastack, ackno) &&
|
||||||
TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */
|
TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */
|
||||||
if(TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, 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
|
||||||
@ -859,7 +860,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
segment is larger than rcv_nxt. */
|
segment is larger than rcv_nxt. */
|
||||||
/* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
|
/* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
|
||||||
if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
|
if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
|
||||||
if(TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno+1, seqno+tcplen-1)){
|
if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
|
||||||
/* Trimming the first edge is done by pushing the payload
|
/* Trimming the first edge is done by pushing the payload
|
||||||
pointer in the pbuf downwards. This is somewhat tricky since
|
pointer in the pbuf downwards. This is somewhat tricky since
|
||||||
we do not want to discard the full contents of the pbuf up to
|
we do not want to discard the full contents of the pbuf up to
|
||||||
@ -882,6 +883,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
|
|
||||||
off = pcb->rcv_nxt - seqno;
|
off = pcb->rcv_nxt - seqno;
|
||||||
p = inseg.p;
|
p = inseg.p;
|
||||||
|
LWIP_ASSERT("inseg.p != NULL", inseg.p);
|
||||||
if (inseg.p->len < off) {
|
if (inseg.p->len < off) {
|
||||||
new_tot_len = inseg.p->tot_len - off;
|
new_tot_len = inseg.p->tot_len - off;
|
||||||
while (p->len < off) {
|
while (p->len < off) {
|
||||||
@ -903,8 +905,8 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
inseg.len -= pcb->rcv_nxt - seqno;
|
inseg.len -= pcb->rcv_nxt - seqno;
|
||||||
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
|
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
if(TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
|
if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
|
||||||
/* the whole segment is < rcv_nxt */
|
/* the whole segment is < rcv_nxt */
|
||||||
/* must be a duplicate of a packet that has already been correctly handled */
|
/* must be a duplicate of a packet that has already been correctly handled */
|
||||||
|
|
||||||
@ -918,8 +920,9 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
processed. */
|
processed. */
|
||||||
/*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
|
/*if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
|
||||||
TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
|
TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
|
||||||
if(TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){
|
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){
|
||||||
if (pcb->rcv_nxt == seqno) {
|
if (pcb->rcv_nxt == seqno) {
|
||||||
|
accepted_inseq = 1;
|
||||||
/* 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. */
|
||||||
@ -998,6 +1001,9 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
|
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
|
||||||
recv_flags = TF_GOT_FIN;
|
recv_flags = TF_GOT_FIN;
|
||||||
|
if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
|
||||||
|
pcb->state = CLOSE_WAIT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1142,6 +1148,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return accepted_inseq;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user