tcp: fix fin in syn-rcvd 41/16541/8
authorFlorin Coras <fcoras@cisco.com>
Wed, 19 Dec 2018 09:38:57 +0000 (01:38 -0800)
committerFlorin Coras <fcoras@cisco.com>
Thu, 20 Dec 2018 01:25:44 +0000 (17:25 -0800)
Change-Id: Iba7c08c9edcf76ea24d00d5ea9e0586e9f94df4e
Signed-off-by: Florin Coras <fcoras@cisco.com>
src/vnet/tcp/tcp.c
src/vnet/tcp/tcp_input.c

index 9a3c904..b1ed99a 100644 (file)
@@ -290,22 +290,21 @@ tcp_connection_reset (tcp_connection_t * tc)
       tcp_connection_timers_reset (tc);
       /* Set the cleanup timer, in case the session layer/app don't
        * cleanly close the connection */
-      tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
+      tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
       stream_session_reset_notify (&tc->connection);
       break;
     case TCP_STATE_CLOSE_WAIT:
     case TCP_STATE_FIN_WAIT_1:
     case TCP_STATE_FIN_WAIT_2:
     case TCP_STATE_CLOSING:
-      tc->state = TCP_STATE_CLOSED;
-      TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc);
       tcp_connection_timers_reset (tc);
-      tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
+      tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
       break;
     case TCP_STATE_CLOSED:
       return;
     }
   tc->state = TCP_STATE_CLOSED;
+  TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc);
 }
 
 /**
@@ -1252,7 +1251,7 @@ tcp_timer_waitclose_handler (u32 conn_index)
 
   /* Session didn't come back with a close(). Send FIN either way
    * and switch to LAST_ACK. */
-  if (tc->state == TCP_STATE_CLOSE_WAIT)
+  if (tc->state == TCP_STATE_CLOSE_WAIT && (tc->flags & TCP_CONN_FINPNDG))
     {
       /* Make sure we don't try to send unsent data */
       tcp_connection_timers_reset (tc);
@@ -1269,8 +1268,9 @@ tcp_timer_waitclose_handler (u32 conn_index)
     }
   else if (tc->state == TCP_STATE_FIN_WAIT_1)
     {
-      /* Wait for session layer to clean up tx events */
+      tcp_connection_timers_reset (tc);
       tc->state = TCP_STATE_CLOSED;
+      /* Wait for session layer to clean up tx events */
       tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
       return;
     }
index 8481c76..f1d0f01 100644 (file)
@@ -2725,7 +2725,8 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            }
 
          /* Make sure the ack is exactly right */
-         if (tc0->rcv_nxt != vnet_buffer (b0)->tcp.seq_number || is_fin0)
+         if (tc0->rcv_nxt != vnet_buffer (b0)->tcp.seq_number || is_fin0
+             || vnet_buffer (b0)->tcp.data_len)
            {
              tcp_connection_reset (tc0);
              error0 = TCP_ERROR_SEGMENT_INVALID;
@@ -2912,14 +2913,18 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       switch (tc0->state)
        {
        case TCP_STATE_ESTABLISHED:
+         tcp_rcv_fin (wrk, tc0, b0, &error0);
+         break;
        case TCP_STATE_SYN_RCVD:
-         /* Send FIN-ACK notify app and enter CLOSE-WAIT */
+         /* Send FIN-ACK, enter LAST-ACK and because the app was not
+          * notified yet, set a cleanup timer instead of relying on
+          * disconnect notify and the implicit close call. */
          tcp_connection_timers_reset (tc0);
+         tc0->rcv_nxt += 1;
          tcp_send_fin (tc0);
-         stream_session_disconnect_notify (&tc0->connection);
-         tc0->state = TCP_STATE_CLOSE_WAIT;
-         tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
+         tc0->state = TCP_STATE_LAST_ACK;
          TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
+         tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
          break;
        case TCP_STATE_CLOSE_WAIT:
        case TCP_STATE_CLOSING:
@@ -3601,6 +3606,7 @@ do {                                                              \
 } while (0)
 
   /* RFC 793: In LISTEN if RST drop and if ACK return RST */
+  _(LISTEN, 0, TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID);
   _(LISTEN, TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET, TCP_ERROR_ACK_INVALID);
   _(LISTEN, TCP_FLAG_RST, TCP_INPUT_NEXT_DROP, TCP_ERROR_INVALID_CONNECTION);
   _(LISTEN, TCP_FLAG_SYN, TCP_INPUT_NEXT_LISTEN, TCP_ERROR_NONE);
@@ -3697,6 +3703,7 @@ do {                                                              \
     TCP_ERROR_NONE);
   /* FIN in reply to our FIN from the other side */
   _(FIN_WAIT_1, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+  _(FIN_WAIT_1, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
   _(FIN_WAIT_1, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
   _(FIN_WAIT_1, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
     TCP_ERROR_NONE);