to->flags |= TCP_OPTS_FLAG_WSCALE;
to->wscale = data[2];
if (to->wscale > TCP_MAX_WND_SCALE)
- {
- clib_warning ("Illegal window scaling value: %d",
- to->wscale);
- to->wscale = TCP_MAX_WND_SCALE;
- }
+ to->wscale = TCP_MAX_WND_SCALE;
}
break;
case TCP_OPTION_TIMESTAMP:
tcp_time_now_w_thread (tc0->c_thread_index)))
{
tc0->tsval_recent = tc0->rcv_opts.tsval;
- clib_warning ("paws failed - really old segment. REALLY?");
+ clib_warning ("paws failed: 24-day old segment");
}
- else
+ /* Drop after ack if not rst. Resets can fail paws check as per
+ * RFC 7323 sec. 5.2: When an <RST> segment is received, it MUST NOT
+ * be subjected to the PAWS check by verifying an acceptable value in
+ * SEG.TSval */
+ else if (!tcp_rst (th0))
{
- /* Drop after ack if not rst */
- if (!tcp_rst (th0))
- {
- tcp_program_ack (wrk, tc0);
- TCP_EVT_DBG (TCP_EVT_DUPACK_SENT, tc0, vnet_buffer (b0)->tcp);
- }
+ tcp_program_ack (wrk, tc0);
+ TCP_EVT_DBG (TCP_EVT_DUPACK_SENT, tc0, vnet_buffer (b0)->tcp);
+ goto error;
}
- goto error;
}
/* 1st: check sequence number */
if (mrtt > 0 && mrtt < TCP_RTT_MAX)
tcp_estimate_rtt (tc, mrtt);
+ tcp_update_rto (tc);
}
/**
tc->burst_acked = 0;
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;
+ }
+
/* If everything has been acked, stop retransmit timer
* otherwise update. */
tcp_retransmit_timer_update (tc);
{
if (seq_lt (blk->start, blk->end)
&& seq_gt (blk->start, tc->snd_una)
- && seq_gt (blk->start, ack) && seq_leq (blk->end, tc->snd_una_max))
+ && seq_gt (blk->start, ack)
+ && seq_lt (blk->start, tc->snd_una_max)
+ && seq_leq (blk->end, tc->snd_una_max))
{
blk++;
continue;
{
tcp_cc_handle_event (tc, is_dack);
if (!tcp_in_cong_recovery (tc))
- return 0;
+ {
+ *error = TCP_ERROR_ACK_OK;
+ return 0;
+ }
*error = TCP_ERROR_ACK_DUP;
if (vnet_buffer (b)->tcp.data_len || tcp_is_fin (th))
return 0;
{
tc = tcp_connection_get (pending_disconnects[i], thread_index);
tcp_disconnect_pending_off (tc);
- stream_session_disconnect_notify (&tc->connection);
+ session_transport_closing_notify (&tc->connection);
}
_vec_len (wrk->pending_disconnects) = 0;
}
tcp_rcv_fin (tcp_worker_ctx_t * wrk, tcp_connection_t * tc, vlib_buffer_t * b,
u32 * error)
{
+ /* Account for the FIN and send ack */
+ tc->rcv_nxt += 1;
+ tcp_program_ack (wrk, tc);
/* Enter CLOSE-WAIT and notify session. To avoid lingering
* in CLOSE-WAIT, set timer (reuse WAITCLOSE). */
- /* Account for the FIN if nothing else was received */
- if (vnet_buffer (b)->tcp.data_len == 0)
- tc->rcv_nxt += 1;
- tcp_program_ack (wrk, tc);
- tc->state = TCP_STATE_CLOSE_WAIT;
+ tcp_connection_set_state (tc, TCP_STATE_CLOSE_WAIT);
tcp_program_disconnect (wrk, tc);
tcp_timer_update (tc, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
TCP_EVT_DBG (TCP_EVT_FIN_RCVD, tc);
tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index);
u32 n_left_from, *from, *first_buffer;
u16 err_counters[TCP_N_ERROR] = { 0 };
- u8 is_fin = 0;
if (node->flags & VLIB_NODE_FLAG_TRACE)
tcp_established_trace_frame (vm, node, frame, is_ip4);
{
u32 bi0, error0 = TCP_ERROR_ACK_OK;
vlib_buffer_t *b0;
- tcp_header_t *th0 = 0;
+ tcp_header_t *th0;
tcp_connection_t *tc0;
if (n_left_from > 1)
}
th0 = tcp_buffer_hdr (b0);
- /* N.B. buffer is rewritten if segment is ooo. Thus, th0 becomes a
- * dangling reference. */
- is_fin = tcp_is_fin (th0);
-
- /* SYNs, FINs and data consume sequence numbers */
- vnet_buffer (b0)->tcp.seq_end = vnet_buffer (b0)->tcp.seq_number
- + tcp_is_syn (th0) + is_fin + vnet_buffer (b0)->tcp.data_len;
/* TODO header prediction fast path */
error0 = tcp_segment_rcv (wrk, tc0, b0);
/* 8: check the FIN bit */
- if (PREDICT_FALSE (is_fin))
+ if (PREDICT_FALSE (tcp_is_fin (th0)))
tcp_rcv_fin (wrk, tc0, b0, &error0);
done:
errors = session_manager_flush_enqueue_events (TRANSPORT_PROTO_TCP,
thread_index);
- err_counters[TCP_ERROR_EVENT_FIFO_FULL] = errors;
+ err_counters[TCP_ERROR_MSG_QUEUE_FULL] = errors;
tcp_store_err_counters (established, err_counters);
tcp_handle_postponed_dequeues (wrk);
tcp_handle_disconnects (wrk);
goto drop;
}
- /* SYNs, FINs and data consume sequence numbers */
- vnet_buffer (b0)->tcp.seq_end =
- seq0 + tcp_is_syn (tcp0) + tcp_is_fin (tcp0) +
- vnet_buffer (b0)->tcp.data_len;
+ /* SYNs consume sequence numbers */
+ vnet_buffer (b0)->tcp.seq_end += tcp_is_syn (tcp0);
/*
* 1. check the ACK bit
new_tc0->c_thread_index = my_thread_index;
new_tc0->rcv_nxt = vnet_buffer (b0)->tcp.seq_end;
new_tc0->irs = seq0;
- new_tc0->timers[TCP_TIMER_ESTABLISH] = TCP_TIMER_HANDLE_INVALID;
+ new_tc0->timers[TCP_TIMER_ESTABLISH_AO] = TCP_TIMER_HANDLE_INVALID;
new_tc0->timers[TCP_TIMER_RETRANSMIT_SYN] = TCP_TIMER_HANDLE_INVALID;
new_tc0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
if (tcp_opts_wscale (&new_tc0->rcv_opts))
new_tc0->snd_wscale = new_tc0->rcv_opts.wscale;
+ else
+ new_tc0->rcv_wscale = 0;
new_tc0->snd_wnd = clib_net_to_host_u16 (tcp0->window)
<< new_tc0->snd_wscale;
errors = session_manager_flush_enqueue_events (TRANSPORT_PROTO_TCP,
my_thread_index);
- tcp_inc_counter (syn_sent, TCP_ERROR_EVENT_FIFO_FULL, errors);
+ tcp_inc_counter (syn_sent, TCP_ERROR_MSG_QUEUE_FULL, errors);
vlib_buffer_free (vm, first_buffer, from_frame->n_vectors);
return from_frame->n_vectors;
{
u32 thread_index = vm->thread_index, errors = 0, *first_buffer;
tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index);
- u32 n_left_from, *from;
+ u32 n_left_from, *from, max_dequeue;
from = first_buffer = vlib_frame_vector_args (from_frame);
n_left_from = from_frame->n_vectors;
tcp0 = tcp_buffer_hdr (b0);
is_fin0 = tcp_is_fin (tcp0);
- /* SYNs, FINs and data consume sequence numbers */
- vnet_buffer (b0)->tcp.seq_end = vnet_buffer (b0)->tcp.seq_number
- + tcp_is_syn (tcp0) + is_fin0 + vnet_buffer (b0)->tcp.data_len;
-
if (CLIB_DEBUG)
{
tcp_connection_t *tmp;
is_ip4);
if (tmp->state != tc0->state)
{
- clib_warning ("state changed");
+ if (tc0->state != TCP_STATE_CLOSED)
+ clib_warning ("state changed");
goto drop;
}
}
*/
if (!tcp_rcv_ack_is_acceptable (tc0, b0))
{
- TCP_DBG ("connection not accepted");
- tcp_send_reset_w_pkt (tc0, b0, is_ip4);
+ tcp_connection_reset (tc0);
error0 = TCP_ERROR_ACK_INVALID;
goto drop;
}
+ /* Make sure the ack is exactly right */
+ 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;
+ goto drop;
+ }
+
/* Update rtt and rto */
tcp_estimate_initial_rtt (tc0);
/* Reset SYN-ACK retransmit and SYN_RCV establish timers */
tcp_retransmit_timer_reset (tc0);
tcp_timer_reset (tc0, TCP_TIMER_ESTABLISH);
- stream_session_accept_notify (&tc0->connection);
+ if (stream_session_accept_notify (&tc0->connection))
+ {
+ error0 = TCP_ERROR_MSG_QUEUE_FULL;
+ tcp_connection_reset (tc0);
+ goto drop;
+ }
error0 = TCP_ERROR_ACK_OK;
break;
case TCP_STATE_ESTABLISHED:
if (tc0->flags & TCP_CONN_FINPNDG)
{
/* TX fifo finally drained */
- if (!session_tx_fifo_max_dequeue (&tc0->connection))
+ max_dequeue = session_tx_fifo_max_dequeue (&tc0->connection);
+ if (max_dequeue <= tc0->burst_acked)
tcp_send_fin (tc0);
}
/* If FIN is ACKed */
else if (tc0->snd_una == tc0->snd_una_max)
{
- tc0->state = TCP_STATE_FIN_WAIT_2;
- TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
+ tcp_connection_set_state (tc0, TCP_STATE_FIN_WAIT_2);
/* Stop all retransmit timers because we have nothing more
* to send. Enable waitclose though because we're willing to
* wait for peer's FIN but not indefinitely. */
tcp_connection_timers_reset (tc0);
- tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
/* Don't try to deq the FIN acked */
if (tc0->burst_acked > 1)
{
tcp_send_fin (tc0);
tcp_connection_timers_reset (tc0);
- tc0->state = TCP_STATE_LAST_ACK;
- tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
+ tcp_connection_set_state (tc0, TCP_STATE_LAST_ACK);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
}
}
break;
if (tcp_rcv_ack (wrk, tc0, b0, tcp0, &error0))
goto drop;
- tc0->state = TCP_STATE_TIME_WAIT;
- TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
- tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
+ tcp_connection_timers_reset (tc0);
+ tcp_connection_set_state (tc0, TCP_STATE_TIME_WAIT);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
goto drop;
break;
goto drop;
}
- tc0->state = TCP_STATE_CLOSED;
- TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
+ tcp_connection_set_state (tc0, TCP_STATE_CLOSED);
/* Don't free the connection from the data path since
* we can't ensure that we have no packets already enqueued
* to output. Rely instead on the waitclose timer */
tcp_connection_timers_reset (tc0);
- tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, 1);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
goto drop;
case TCP_STATE_FIN_WAIT_2:
if (vnet_buffer (b0)->tcp.data_len)
error0 = tcp_segment_rcv (wrk, tc0, b0);
- else if (is_fin0)
- tc0->rcv_nxt += 1;
break;
case TCP_STATE_CLOSE_WAIT:
case TCP_STATE_CLOSING:
if (!is_fin0)
goto drop;
+ TCP_EVT_DBG (TCP_EVT_FIN_RCVD, tc0);
+
switch (tc0->state)
{
case TCP_STATE_ESTABLISHED:
+ /* Account for the FIN and send ack */
+ tc0->rcv_nxt += 1;
+ tcp_program_ack (wrk, tc0);
+ tcp_connection_set_state (tc0, TCP_STATE_CLOSE_WAIT);
+ tcp_program_disconnect (wrk, tc0);
+ tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_CLOSEWAIT_TIME);
+ 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_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
+ tcp_connection_set_state (tc0, TCP_STATE_LAST_ACK);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
break;
case TCP_STATE_CLOSE_WAIT:
case TCP_STATE_CLOSING:
/* move along .. */
break;
case TCP_STATE_FIN_WAIT_1:
- tc0->state = TCP_STATE_CLOSING;
+ tc0->rcv_nxt += 1;
+ tcp_connection_set_state (tc0, TCP_STATE_CLOSING);
tcp_program_ack (wrk, tc0);
- TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
/* Wait for ACK but not forever */
tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_2MSL_TIME);
break;
case TCP_STATE_FIN_WAIT_2:
/* Got FIN, send ACK! Be more aggressive with resource cleanup */
- tc0->state = TCP_STATE_TIME_WAIT;
+ tc0->rcv_nxt += 1;
+ tcp_connection_set_state (tc0, TCP_STATE_TIME_WAIT);
tcp_connection_timers_reset (tc0);
- tcp_timer_update (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
+ tcp_timer_set (tc0, TCP_TIMER_WAITCLOSE, TCP_TIMEWAIT_TIME);
tcp_program_ack (wrk, tc0);
- TCP_EVT_DBG (TCP_EVT_STATE_CHANGE, tc0);
break;
case TCP_STATE_TIME_WAIT:
/* Remain in the TIME-WAIT state. Restart the time-wait
break;
}
error0 = TCP_ERROR_FIN_RCVD;
- TCP_EVT_DBG (TCP_EVT_FIN_RCVD, tc0);
drop:
errors = session_manager_flush_enqueue_events (TRANSPORT_PROTO_TCP,
thread_index);
- tcp_inc_counter (rcv_process, TCP_ERROR_EVENT_FIFO_FULL, errors);
+ tcp_inc_counter (rcv_process, TCP_ERROR_MSG_QUEUE_FULL, errors);
tcp_handle_postponed_dequeues (wrk);
vlib_buffer_free (vm, first_buffer, from_frame->n_vectors);
}
/* Create child session and send SYN-ACK */
- child0 = tcp_connection_new (my_thread_index);
+ child0 = tcp_connection_alloc (my_thread_index);
child0->c_lcl_port = th0->dst_port;
child0->c_rmt_port = th0->src_port;
child0->c_is_ip4 = is_ip4;
if (tcp_options_parse (th0, &child0->rcv_opts, 1))
{
- clib_warning ("options parse fail");
+ error0 = TCP_ERROR_OPTIONS;
+ tcp_connection_free (child0);
goto drop;
}
if (stream_session_accept (&child0->connection, lc0->c_s_index,
0 /* notify */ ))
{
- clib_warning ("session accept fail");
tcp_connection_cleanup (child0);
error0 = TCP_ERROR_CREATE_SESSION_FAIL;
goto drop;
vnet_buffer (b)->tcp.ack_number = clib_net_to_host_u32 (tcp->ack_number);
vnet_buffer (b)->tcp.data_offset = n_advance_bytes;
vnet_buffer (b)->tcp.data_len = n_data_bytes;
+ vnet_buffer (b)->tcp.seq_end = vnet_buffer (b)->tcp.seq_number
+ + n_data_bytes;
vnet_buffer (b)->tcp.flags = 0;
*error = is_filtered ? TCP_ERROR_FILTERED : *error;
vnet_buffer (b)->tcp.flags = tc->state;
if (*error == TCP_ERROR_DISPATCH)
- clib_warning ("disp error state %U flags %U", format_tcp_state,
- state, format_tcp_flags, (int) flags);
+ clib_warning ("tcp conn %u disp error state %U flags %U",
+ tc->c_c_index, format_tcp_state, state,
+ format_tcp_flags, (int) flags);
}
}
tm->dispatch_table[TCP_STATE_##t][f].error = (e); \
} while (0)
- /* SYNs for new connections -> tcp-listen. */
+ /* 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);
- _(LISTEN, TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET, TCP_ERROR_NONE);
- _(LISTEN, TCP_FLAG_RST, TCP_INPUT_NEXT_DROP, TCP_ERROR_RST_RCVD);
+ _(LISTEN, TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET,
+ TCP_ERROR_ACK_INVALID);
+ _(LISTEN, TCP_FLAG_SYN | TCP_FLAG_RST, TCP_INPUT_NEXT_DROP,
+ TCP_ERROR_SEGMENT_INVALID);
+ _(LISTEN, TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP,
+ TCP_ERROR_SEGMENT_INVALID);
+ _(LISTEN, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP,
+ TCP_ERROR_INVALID_CONNECTION);
+ _(LISTEN, TCP_FLAG_FIN, TCP_INPUT_NEXT_RESET, TCP_ERROR_SEGMENT_INVALID);
_(LISTEN, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET,
+ TCP_ERROR_SEGMENT_INVALID);
+ _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_RST, TCP_INPUT_NEXT_DROP,
+ TCP_ERROR_SEGMENT_INVALID);
+ _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP,
TCP_ERROR_NONE);
+ _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_SYN, TCP_INPUT_NEXT_DROP,
+ TCP_ERROR_SEGMENT_INVALID);
+ _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP,
+ TCP_ERROR_SEGMENT_INVALID);
+ _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST, TCP_INPUT_NEXT_DROP,
+ TCP_ERROR_SEGMENT_INVALID);
+ _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID);
/* ACK for for a SYN-ACK -> tcp-rcv-process. */
_(SYN_RCVD, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(SYN_RCVD, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(SYN_RCVD, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
_(SYN_RCVD, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_SYN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(SYN_RCVD, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_FIN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_FIN | TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(SYN_RCVD, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(SYN_RCVD, 0, TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID);
/* SYN-ACK for a SYN */
_(SYN_SENT, TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_SYN_SENT,
TCP_ERROR_NONE);
_(ESTABLISHED, TCP_FLAG_FIN, TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
_(ESTABLISHED, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_ESTABLISHED,
TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_FIN | TCP_FLAG_RST, TCP_INPUT_NEXT_ESTABLISHED,
+ TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_FIN | TCP_FLAG_SYN, TCP_INPUT_NEXT_ESTABLISHED,
+ TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST,
+ TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
_(ESTABLISHED, TCP_FLAG_RST, TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
_(ESTABLISHED, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_ESTABLISHED,
TCP_ERROR_NONE);
_(ESTABLISHED, TCP_FLAG_SYN, TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
_(ESTABLISHED, TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_ESTABLISHED,
TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_SYN | TCP_FLAG_RST, TCP_INPUT_NEXT_ESTABLISHED,
+ TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
+ _(ESTABLISHED, 0, TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID);
/* ACK or FIN-ACK to our FIN */
_(FIN_WAIT_1, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(FIN_WAIT_1, TCP_FLAG_ACK | TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
/* FIN in reply to our FIN from the other side */
+ _(FIN_WAIT_1, 0, TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID);
_(FIN_WAIT_1, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(FIN_WAIT_1, TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ 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_SYN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(FIN_WAIT_1, TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(FIN_WAIT_1, TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ 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);
_(CLOSING, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(CLOSING, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(CLOSING, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(CLOSING, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(CLOSING, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
/* FIN confirming that the peer (app) has closed */
_(FIN_WAIT_2, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(FIN_WAIT_2, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(FIN_WAIT_2, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
+ _(FIN_WAIT_2, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(FIN_WAIT_2, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
_(CLOSE_WAIT, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(CLOSE_WAIT, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
+ _(CLOSE_WAIT, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(CLOSE_WAIT, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(LAST_ACK, 0, TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID);
_(LAST_ACK, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(LAST_ACK, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(LAST_ACK, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
_(LAST_ACK, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_SYN | TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
+ _(LAST_ACK, TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK,
+ TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(TIME_WAIT, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(TIME_WAIT, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
_(TIME_WAIT, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
+ _(TIME_WAIT, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
+ TCP_ERROR_NONE);
_(TIME_WAIT, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
- _(CLOSED, TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP, TCP_ERROR_CONNECTION_CLOSED);
+ /* RFC793 CLOSED: An incoming segment containing a RST is discarded. An
+ * incoming segment not containing a RST causes a RST to be sent in
+ * response.*/
_(CLOSED, TCP_FLAG_RST, TCP_INPUT_NEXT_DROP, TCP_ERROR_CONNECTION_CLOSED);
- _(CLOSED, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP,
+ _(CLOSED, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP,
TCP_ERROR_CONNECTION_CLOSED);
+ _(CLOSED, TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET, TCP_ERROR_NONE);
+ _(CLOSED, TCP_FLAG_SYN, TCP_INPUT_NEXT_RESET, TCP_ERROR_NONE);
+ _(CLOSED, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET,
+ TCP_ERROR_NONE);
#undef _
}