Fix for out-of-sequence FIN handling, patch by Oleg Tychev.

This commit is contained in:
likewise 2006-04-08 00:36:25 +00:00
parent 6cb19d7e34
commit 313743c833

View File

@ -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;
@ -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) {
@ -920,6 +922,7 @@ tcp_receive(struct tcp_pcb *pcb)
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;
} }
/* /*