interface: add capabilities flags
[vpp.git] / src / vnet / tcp / tcp_input.c
index 91a4fca..509732f 100644 (file)
@@ -404,7 +404,7 @@ tcp_rcv_ack_no_cc (tcp_connection_t * tc, vlib_buffer_t * b, u32 * error)
   if (!(seq_leq (tc->snd_una, vnet_buffer (b)->tcp.ack_number)
        && seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_nxt)))
     {
-      if (seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_una_max)
+      if (seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_nxt)
          && seq_gt (vnet_buffer (b)->tcp.ack_number, tc->snd_una))
        {
          tc->snd_nxt = vnet_buffer (b)->tcp.ack_number;
@@ -580,13 +580,7 @@ tcp_handle_postponed_dequeues (tcp_worker_ctx_t * wrk)
 
       /* Dequeue the newly ACKed bytes */
       session_tx_fifo_dequeue_drop (&tc->connection, tc->burst_acked);
-      tcp_validate_txf_size (tc, tc->snd_una_max - tc->snd_una);
-
-      if (PREDICT_FALSE (tc->flags & TCP_CONN_PSH_PENDING))
-       {
-         if (seq_leq (tc->psh_seq, tc->snd_una))
-           tc->flags &= ~TCP_CONN_PSH_PENDING;
-       }
+      tcp_validate_txf_size (tc, tc->snd_nxt - tc->snd_una);
 
       if (tcp_is_descheduled (tc))
        tcp_reschedule (tc);
@@ -999,7 +993,7 @@ tcp_rcv_ack (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, vlib_buffer_t * b,
     {
       /* We've probably entered recovery and the peer still has some
        * of the data we've sent. Update snd_nxt and accept the ack */
-      if (seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_una_max)
+      if (seq_leq (vnet_buffer (b)->tcp.ack_number, tc->snd_nxt)
          && seq_gt (vnet_buffer (b)->tcp.ack_number, tc->snd_una))
        {
          tc->snd_nxt = vnet_buffer (b)->tcp.ack_number;
@@ -1298,6 +1292,10 @@ tcp_segment_rcv (tcp_worker_ctx_t * wrk, tcp_connection_t * tc,
   ASSERT (n_data_bytes);
   tc->data_segs_in += 1;
 
+  /* Make sure we don't consume trailing bytes */
+  if (PREDICT_FALSE (b->current_length > n_data_bytes))
+    b->current_length = n_data_bytes;
+
   /* Handle out-of-order data */
   if (PREDICT_FALSE (vnet_buffer (b)->tcp.seq_number != tc->rcv_nxt))
     {
@@ -1778,7 +1776,7 @@ tcp_check_tx_offload (tcp_connection_t * tc, int is_ipv4)
     return;
 
   hw_if = vnet_get_sup_hw_interface (vnm, sw_if_idx);
-  if (hw_if->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO)
+  if (hw_if->caps & VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO)
     tc->cfg_flags |= TCP_CFG_F_TSO;
 }
 
@@ -1814,13 +1812,10 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          goto drop;
        }
 
-      /* Half-open completed recently but the connection was't removed
-       * yet by the owning thread */
+      /* Half-open completed or cancelled recently but the connection
+       * was't removed yet by the owning thread */
       if (PREDICT_FALSE (tc0->flags & TCP_CONN_HALF_OPEN_DONE))
        {
-         /* Make sure the connection actually exists */
-         ASSERT (tcp_lookup_connection (tc0->c_fib_index, b0,
-                                        my_thread_index, is_ip4));
          error0 = TCP_ERROR_SPURIOUS_SYN_ACK;
          goto drop;
        }
@@ -1963,6 +1958,7 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              goto cleanup_ho;
            }
 
+         transport_fifos_init_ooo (&new_tc0->connection);
          new_tc0->tx_fifo_size =
            transport_tx_fifo_size (&new_tc0->connection);
          /* Update rtt with the syn-ack sample */
@@ -1986,6 +1982,7 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              goto cleanup_ho;
            }
 
+         transport_fifos_init_ooo (&new_tc0->connection);
          new_tc0->tx_fifo_size =
            transport_tx_fifo_size (&new_tc0->connection);
          new_tc0->rtt_ts = 0;
@@ -2380,6 +2377,9 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
        case TCP_STATE_FIN_WAIT_2:
          if (vnet_buffer (b0)->tcp.data_len)
            error0 = tcp_segment_rcv (wrk, tc0, b0);
+         /* Don't accept out of order fins lower */
+         if (vnet_buffer (b0)->tcp.seq_end != tc0->rcv_nxt)
+           goto drop;
          break;
        case TCP_STATE_CLOSE_WAIT:
        case TCP_STATE_CLOSING:
@@ -2561,14 +2561,19 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
 
       b = vlib_get_buffer (vm, bi);
 
-      lc = tcp_listener_get (vnet_buffer (b)->tcp.connection_index);
-      if (PREDICT_FALSE (lc == 0))
+      /* Flags initialized with connection state after lookup */
+      if (vnet_buffer (b)->tcp.flags == TCP_STATE_LISTEN)
+       {
+         lc = tcp_listener_get (vnet_buffer (b)->tcp.connection_index);
+       }
+      else
        {
          tcp_connection_t *tc;
          tc = tcp_connection_get (vnet_buffer (b)->tcp.connection_index,
                                   thread_index);
          if (tc->state != TCP_STATE_TIME_WAIT)
            {
+             lc = 0;
              error = TCP_ERROR_CREATE_EXISTS;
              goto done;
            }
@@ -2642,6 +2647,7 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          goto done;
        }
 
+      transport_fifos_init_ooo (&child->connection);
       child->tx_fifo_size = transport_tx_fifo_size (&child->connection);
 
       tcp_send_synack (child);
@@ -2801,6 +2807,10 @@ tcp_input_dispatch_buffer (tcp_main_t * tm, tcp_connection_t * tc,
   error = tm->dispatch_table[tc->state][flags].error;
   tc->segs_in += 1;
 
+  /* Track connection state when packet was received. It helps
+   * @ref tcp46_listen_inline detect port reuse */
+  vnet_buffer (b)->tcp.flags = tc->state;
+
   if (PREDICT_FALSE (error != TCP_ERROR_NONE))
     {
       b->error = error_node->errors[error];