lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lwip-users] out-of-sequence FIN segment bug


From: Oleg Tychev
Subject: [lwip-users] out-of-sequence FIN segment bug
Date: Thu, 06 Apr 2006 13:13:42 +0200
User-agent: Thunderbird 1.5 (Windows/20051201)

Hello All,

I think I have found bug (Thanks to a slow hub:) ).
If TCP segment with FIN flag is received out-of-sequence,
it is processed as in-sequence fragment.

Modifications:
tcp_receive
forced passive close for FIN, that in-sequence after processing current fragment
  returns 1 if fragment in-sequence
tcp_process
    case CLOSE_WAIT:
    case ESTABLISHED:
       move to CLOSE_WAIT only if FIN fragment in-sequence

Oleg Tychev

Here is patch against version lwip-1.1.1

--- lwip-1.1.1/src/core/1/tcp_in.c    2006-03-01 16:53:42.000000000 +0100
+++ lwip-1.1.1/src/core/2/tcp_in.c    2006-04-06 11:08:37.359375000 +0200
@@ -74,7 +74,7 @@

/* Forward declarations. */
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 err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
@@ -436,6 +436,7 @@
 struct tcp_seg *rseg;
 u8_t acceptable = 0;
 err_t err;
+  u8_t accepted_inseq;


 err = ERR_OK;
@@ -545,8 +546,8 @@
 case CLOSE_WAIT:
   /* FALLTHROUGH */
 case ESTABLISHED:
-    tcp_receive(pcb);
-    if (flags & TCP_FIN) {
+    accepted_inseq = tcp_receive(pcb);
+    if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */
     tcp_ack_now(pcb);
     pcb->state = CLOSE_WAIT;
   }
@@ -618,7 +619,7 @@
* estimation, the RTT is estimated here as well.
*/

-static void
+static u8_t
tcp_receive(struct tcp_pcb *pcb)
{
 struct tcp_seg *next;
@@ -630,6 +631,7 @@
 s16_t m;
 u32_t right_wnd_edge;
 u16_t new_tot_len;
+  u8_t accepted_inseq = 0;


 if (flags & TCP_ACK) {
@@ -922,6 +924,7 @@
     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 (pcb->rcv_nxt == seqno) {
+        accepted_inseq = 1;
       /* The incoming segment is the next in sequence. We check if
          we have to trim the end of the segment and update rcv_nxt
          and pass the data to the application. */
@@ -1000,6 +1003,9 @@
         if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
           recv_flags = TF_GOT_FIN;
+ if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
+              pcb->state = CLOSE_WAIT;
+            }
         }


@@ -1144,6 +1150,7 @@
     tcp_ack_now(pcb);
   }
 }
+  return accepted_inseq;
}

/*

--- lwip-1.1.1/src/core/1/tcp_in.c      2006-03-01 16:53:42.000000000 +0100
+++ lwip-1.1.1/src/core/2/tcp_in.c      2006-04-06 11:08:37.359375000 +0200
@@ -74,7 +74,7 @@
 
 /* Forward declarations. */
 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 err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
@@ -436,6 +436,7 @@
   struct tcp_seg *rseg;
   u8_t acceptable = 0;
   err_t err;
+  u8_t accepted_inseq;
 
 
   err = ERR_OK;
@@ -545,8 +546,8 @@
   case CLOSE_WAIT:
     /* FALLTHROUGH */
   case ESTABLISHED:
-    tcp_receive(pcb);
-    if (flags & TCP_FIN) {
+    accepted_inseq = tcp_receive(pcb);
+    if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */
       tcp_ack_now(pcb);
       pcb->state = CLOSE_WAIT;
     }
@@ -618,7 +619,7 @@
  * estimation, the RTT is estimated here as well.
  */
 
-static void
+static u8_t
 tcp_receive(struct tcp_pcb *pcb)
 {
   struct tcp_seg *next;
@@ -630,6 +631,7 @@
   s16_t m;
   u32_t right_wnd_edge;
   u16_t new_tot_len;
+  u8_t accepted_inseq = 0;
 
 
   if (flags & TCP_ACK) {
@@ -922,6 +924,7 @@
       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 (pcb->rcv_nxt == seqno) {
+        accepted_inseq = 1; 
         /* The incoming segment is the next in sequence. We check if
            we have to trim the end of the segment and update rcv_nxt
            and pass the data to the application. */
@@ -1000,6 +1003,9 @@
           if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
             LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
             recv_flags = TF_GOT_FIN;
+            if (pcb->state == ESTABLISHED) { /* force passive close or we can 
move to active close */
+              pcb->state = CLOSE_WAIT;
+            } 
           }
 
 
@@ -1144,6 +1150,7 @@
       tcp_ack_now(pcb);
     }
   }
+  return accepted_inseq;
 }
 
 /*

reply via email to

[Prev in Thread] Current Thread [Next in Thread]