/* All SCTP nodes have the same outgoing arcs */
#define foreach_sctp_state_next \
- _ (DROP, "error-drop") \
+ _ (DROP4, "ip4-drop") \
+ _ (DROP6, "ip6-drop") \
_ (SCTP4_OUTPUT, "sctp4-output") \
_ (SCTP6_OUTPUT, "sctp6-output")
#define sctp_next_output(is_ip4) (is_ip4 ? SCTP_NEXT_SCTP4_OUTPUT \
: SCTP_NEXT_SCTP6_OUTPUT)
+#define sctp_next_drop(is_ip4) (is_ip4 ? SCTP_NEXT_DROP4 \
+ : SCTP_NEXT_DROP6)
void
sctp_set_rx_trace_data (sctp_rx_trace_t * rx_trace,
{
sctp_init_ack_chunk_t *init_ack_chunk =
(sctp_init_ack_chunk_t *) (sctp_hdr);
- ip4_address_t *ip4_addr = 0;
- ip6_address_t *ip6_addr = 0;
sctp_state_cookie_param_t state_cookie;
char hostname[FQDN_MAX_LENGTH];
{
sctp_ipv4_addr_param_t *ipv4 =
(sctp_ipv4_addr_param_t *) opt_params_hdr;
- clib_memcpy (ip4_addr, &ipv4->address,
- sizeof (ip4_address_t));
sctp_sub_connection_add_ip4 (vlib_get_thread_index (), ipv4);
{
sctp_ipv6_addr_param_t *ipv6 =
(sctp_ipv6_addr_param_t *) opt_params_hdr;
- clib_memcpy (ip6_addr, &ipv6->address,
- sizeof (ip6_address_t));
sctp_sub_connection_add_ip6 (vlib_get_thread_index (), ipv6);
}
always_inline u8
-sctp_is_sack_delayable (sctp_connection_t * sctp_conn, u8 gapping)
+sctp_is_sack_delayable (sctp_connection_t * sctp_conn, u8 is_gapping)
{
- if (gapping != 0)
+ if (is_gapping != 0)
{
SCTP_CONN_TRACKING_DBG
("gapping != 0: CONN_INDEX = %u, sctp_conn->ack_state = %u",
sctp_conn->sub_conn[idx].connection.c_index, sctp_conn->ack_state);
- return 1;
+ return 0;
}
if (sctp_conn->ack_state >= MAX_ENQUEABLE_SACKS)
SCTP_CONN_TRACKING_DBG
("sctp_conn->ack_state >= MAX_ENQUEABLE_SACKS: CONN_INDEX = %u, sctp_conn->ack_state = %u",
sctp_conn->sub_conn[idx].connection.c_index, sctp_conn->ack_state);
- return 1;
+ return 0;
}
sctp_conn->ack_state += 1;
- return 0;
+ return 1;
}
always_inline void
always_inline u16
sctp_handle_data (sctp_payload_data_chunk_t * sctp_data_chunk,
- sctp_connection_t * sctp_conn, vlib_buffer_t * b,
+ sctp_connection_t * sctp_conn, u8 idx, vlib_buffer_t * b,
u16 * next0)
{
u32 error = 0, n_data_bytes;
- u8 idx = sctp_pick_conn_idx_on_state (sctp_conn->state);
u8 is_gapping = 0;
/* Check that the LOCALLY generated tag is being used by the REMOTE peer as the verification tag */
}
sctp_conn->last_rcvd_tsn = tsn;
- *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4);
+ *next0 = sctp_next_drop (sctp_conn->sub_conn[idx].c_is_ip4);
SCTP_ADV_DBG ("POINTER_WITH_DATA = %p", b->data);
- if (sctp_is_sack_delayable (sctp_conn, is_gapping) != 0)
+ if (!sctp_is_sack_delayable (sctp_conn, is_gapping))
sctp_prepare_sack_chunk (sctp_conn, b);
return error;
always_inline u16
sctp_handle_cookie_echo (sctp_header_t * sctp_hdr,
sctp_chunks_common_hdr_t * sctp_chunk_hdr,
- sctp_connection_t * sctp_conn, vlib_buffer_t * b0)
+ sctp_connection_t * sctp_conn, u8 idx,
+ vlib_buffer_t * b0, u16 * next0)
{
u32 now = sctp_time_now ();
- /* Build TCB */
- u8 idx = sctp_pick_conn_idx_on_chunk (COOKIE_ECHO);
-
sctp_cookie_echo_chunk_t *cookie_echo =
(sctp_cookie_echo_chunk_t *) sctp_hdr;
/* Change state */
sctp_conn->state = SCTP_STATE_ESTABLISHED;
+ *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4);
sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T4_HEARTBEAT,
sctp_conn->sub_conn[idx].RTO);
always_inline u16
sctp_handle_cookie_ack (sctp_header_t * sctp_hdr,
sctp_chunks_common_hdr_t * sctp_chunk_hdr,
- sctp_connection_t * sctp_conn, vlib_buffer_t * b0)
+ sctp_connection_t * sctp_conn, u8 idx,
+ vlib_buffer_t * b0, u16 * next0)
{
-
- /* Stop T1_COOKIE timer */
- u8 idx = sctp_pick_conn_idx_on_chunk (COOKIE_ACK);
-
/* Check that the LOCALLY generated tag is being used by the REMOTE peer as the verification tag */
if (sctp_conn->local_tag != sctp_hdr->verification_tag)
{
sctp_timer_reset (sctp_conn, idx, SCTP_TIMER_T1_COOKIE);
/* Change state */
sctp_conn->state = SCTP_STATE_ESTABLISHED;
+ *next0 = sctp_next_drop (sctp_conn->sub_conn[idx].c_is_ip4);
sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T4_HEARTBEAT,
sctp_conn->sub_conn[idx].RTO);
sctp_half_open_connection_get (vnet_buffer (b0)->
sctp.connection_index);
- if (PREDICT_FALSE (sctp_conn == 0))
- {
- error0 = SCTP_ERROR_INVALID_CONNECTION;
- goto drop;
- }
-
if (PREDICT_FALSE (sctp_conn == 0))
{
SCTP_ADV_DBG
*/
default:
error0 = SCTP_ERROR_UNKOWN_CHUNK;
- next0 = SCTP_NEXT_DROP;
+ next0 = sctp_next_drop (is_ip4);
goto drop;
}
{
clib_warning ("error while parsing chunk");
sctp_connection_cleanup (sctp_conn);
- next0 = SCTP_NEXT_DROP;
+ next0 = sctp_next_drop (is_ip4);
goto drop;
}
always_inline u16
sctp_handle_shutdown (sctp_header_t * sctp_hdr,
sctp_chunks_common_hdr_t * sctp_chunk_hdr,
- sctp_connection_t * sctp_conn, vlib_buffer_t * b0,
- u16 sctp_implied_length)
+ sctp_connection_t * sctp_conn, u8 idx,
+ vlib_buffer_t * b0, u16 sctp_implied_length,
+ u16 * next0)
{
sctp_shutdown_association_chunk_t *shutdown_chunk =
(sctp_shutdown_association_chunk_t *) (sctp_hdr);
case SCTP_STATE_ESTABLISHED:
if (sctp_check_outstanding_data_chunks (sctp_conn) == 0)
sctp_conn->state = SCTP_STATE_SHUTDOWN_RECEIVED;
+ sctp_send_shutdown_ack (sctp_conn, b0);
break;
case SCTP_STATE_SHUTDOWN_SENT:
- sctp_send_shutdown_ack (sctp_conn);
+ sctp_send_shutdown_ack (sctp_conn, b0);
break;
}
+ *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4);
+
return SCTP_ERROR_NONE;
}
always_inline u16
sctp_handle_shutdown_ack (sctp_header_t * sctp_hdr,
sctp_chunks_common_hdr_t * sctp_chunk_hdr,
- sctp_connection_t * sctp_conn, vlib_buffer_t * b0,
- u16 sctp_implied_length)
+ sctp_connection_t * sctp_conn, u8 idx,
+ vlib_buffer_t * b0, u16 sctp_implied_length,
+ u16 * next0)
{
sctp_shutdown_ack_chunk_t *shutdown_ack_chunk =
(sctp_shutdown_ack_chunk_t *) (sctp_hdr);
*/
sctp_timer_reset (sctp_conn, MAIN_SCTP_SUB_CONN_IDX,
SCTP_TIMER_T2_SHUTDOWN);
- sctp_send_shutdown_complete (sctp_conn);
+
+ sctp_send_shutdown_complete (sctp_conn, b0);
+
+ *next0 = sctp_next_output (sctp_conn->sub_conn[idx].c_is_ip4);
return SCTP_ERROR_NONE;
}
always_inline u16
sctp_handle_shutdown_complete (sctp_header_t * sctp_hdr,
sctp_chunks_common_hdr_t * sctp_chunk_hdr,
- sctp_connection_t * sctp_conn,
- vlib_buffer_t * b0, u16 sctp_implied_length)
+ sctp_connection_t * sctp_conn, u8 idx,
+ vlib_buffer_t * b0, u16 sctp_implied_length,
+ u16 * next0)
{
sctp_shutdown_complete_chunk_t *shutdown_complete =
(sctp_shutdown_complete_chunk_t *) (sctp_hdr);
stream_session_disconnect_notify (&sctp_conn->sub_conn
[MAIN_SCTP_SUB_CONN_IDX].connection);
+ *next0 = sctp_next_drop (sctp_conn->sub_conn[idx].c_is_ip4);
+
return SCTP_ERROR_NONE;
}
sctp_implied_length =
sctp_calculate_implied_length (ip4_hdr, ip6_hdr, is_ip4);
- switch (vnet_sctp_get_chunk_type (sctp_chunk_hdr))
+ u8 idx = sctp_pick_conn_idx_on_state (sctp_conn->state);
+
+ u8 chunk_type = vnet_sctp_get_chunk_type (sctp_chunk_hdr);
+ switch (chunk_type)
{
case SHUTDOWN:
error0 =
- sctp_handle_shutdown (sctp_hdr, sctp_chunk_hdr, sctp_conn, b0,
- sctp_implied_length);
- next0 = sctp_next_output (is_ip4);
+ sctp_handle_shutdown (sctp_hdr, sctp_chunk_hdr, sctp_conn,
+ idx, b0, sctp_implied_length, &next0);
break;
case SHUTDOWN_ACK:
error0 =
sctp_handle_shutdown_ack (sctp_hdr, sctp_chunk_hdr, sctp_conn,
- b0, sctp_implied_length);
- next0 = sctp_next_output (is_ip4);
+ idx, b0, sctp_implied_length,
+ &next0);
break;
case SHUTDOWN_COMPLETE:
error0 =
sctp_handle_shutdown_complete (sctp_hdr, sctp_chunk_hdr,
- sctp_conn, b0,
- sctp_implied_length);
+ sctp_conn, idx, b0,
+ sctp_implied_length, &next0);
sctp_connection_cleanup (sctp_conn);
- next0 = sctp_next_output (is_ip4);
break;
/*
case DATA:
error0 =
sctp_handle_data ((sctp_payload_data_chunk_t *) sctp_hdr,
- sctp_conn, b0, &next0);
- next0 = sctp_next_output (is_ip4);
+ sctp_conn, idx, b0, &next0);
break;
/* All UNEXPECTED scenarios (wrong chunk received per state-machine)
*/
default:
error0 = SCTP_ERROR_UNKOWN_CHUNK;
- next0 = SCTP_NEXT_DROP;
+ next0 = sctp_next_drop (is_ip4);
goto drop;
}
{
clib_warning ("error while parsing chunk");
sctp_connection_cleanup (sctp_conn);
- next0 = SCTP_NEXT_DROP;
+ next0 = sctp_next_drop (is_ip4);
goto drop;
}
{
sctp_trace =
vlib_add_trace (vm, node, b0, sizeof (*sctp_trace));
- clib_memcpy (&sctp_trace->sctp_header, sctp_hdr,
- sizeof (sctp_trace->sctp_header));
- clib_memcpy (&sctp_trace->sctp_connection, sctp_conn,
- sizeof (sctp_trace->sctp_connection));
+
+ if (sctp_hdr != NULL)
+ clib_memcpy (&sctp_trace->sctp_header, sctp_hdr,
+ sizeof (sctp_trace->sctp_header));
+
+ if (sctp_conn != NULL)
+ clib_memcpy (&sctp_trace->sctp_connection, sctp_conn,
+ sizeof (sctp_trace->sctp_connection));
}
b0->error = node->errors[error0];
sctp_conn->sub_conn[idx].RTO_pending = 0;
- *next0 = sctp_next_output (sctp_conn->sub_conn[idx].connection.is_ip4);
+ *next0 = sctp_next_drop (sctp_conn->sub_conn[idx].c_is_ip4);
return SCTP_ERROR_NONE;
}
sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T4_HEARTBEAT,
sctp_conn->sub_conn[idx].RTO);
- *next0 = sctp_next_output (sctp_conn->sub_conn[idx].connection.is_ip4);
+ *next0 = sctp_next_drop (sctp_conn->sub_conn[idx].c_is_ip4);
return SCTP_ERROR_NONE;
}
connection.c_index, sctp_chunk_to_string (chunk_type));
error0 = SCTP_ERROR_UNKOWN_CHUNK;
- next0 = SCTP_NEXT_DROP;
+ next0 = sctp_next_drop (is_ip4);
goto drop;
}
ip4_header_t *ip4_hdr = 0;
ip6_header_t *ip6_hdr = 0;
sctp_connection_t *sctp_conn;
- u16 error0 = SCTP_ERROR_NONE, next0 = SCTP_ESTABLISHED_PHASE_N_NEXT;
+ u16 error0 = SCTP_ERROR_ENQUEUED, next0 =
+ SCTP_ESTABLISHED_PHASE_N_NEXT;
u8 idx;
bi0 = from[0];
case COOKIE_ECHO:
error0 =
sctp_handle_cookie_echo (sctp_hdr, sctp_chunk_hdr, sctp_conn,
- b0);
- next0 = sctp_next_output (is_ip4);
+ idx, b0, &next0);
break;
case COOKIE_ACK:
error0 =
sctp_handle_cookie_ack (sctp_hdr, sctp_chunk_hdr, sctp_conn,
- b0);
- next0 = sctp_next_output (is_ip4);
+ idx, b0, &next0);
break;
case SACK:
case DATA:
error0 =
sctp_handle_data ((sctp_payload_data_chunk_t *) sctp_hdr,
- sctp_conn, b0, &next0);
+ sctp_conn, idx, b0, &next0);
break;
/* All UNEXPECTED scenarios (wrong chunk received per state-machine)
*/
default:
error0 = SCTP_ERROR_UNKOWN_CHUNK;
- next0 = SCTP_NEXT_DROP;
+ next0 = sctp_next_drop (is_ip4);
goto done;
}
sctp_conn = sctp_get_connection_from_transport (trans_conn);
vnet_sctp_common_hdr_params_net_to_host (sctp_chunk_hdr);
- u8 type = vnet_sctp_get_chunk_type (sctp_chunk_hdr);
+ u8 chunk_type = vnet_sctp_get_chunk_type (sctp_chunk_hdr);
+ if (chunk_type >= UNKNOWN)
+ {
+ clib_warning
+ ("Received an unrecognized chunk... something is really bad.");
+ error0 = SCTP_ERROR_UNKOWN_CHUNK;
+ next0 = SCTP_INPUT_NEXT_DROP;
+ goto done;
+ }
#if SCTP_DEBUG_STATE_MACHINE
u8 idx = sctp_pick_conn_idx_on_state (sctp_conn->state);
vnet_buffer (b0)->sctp.data_offset = n_advance_bytes0;
vnet_buffer (b0)->sctp.data_len = n_data_bytes0;
- next0 = tm->dispatch_table[sctp_conn->state][type].next;
- error0 = tm->dispatch_table[sctp_conn->state][type].error;
+ next0 = tm->dispatch_table[sctp_conn->state][chunk_type].next;
+ error0 = tm->dispatch_table[sctp_conn->state][chunk_type].error;
SCTP_DBG_STATE_MACHINE ("CONNECTION_INDEX = %u: "
"CURRENT_CONNECTION_STATE = %s,"
sctp_chunk_to_string (type),
phase_to_string (next0));
- if (type == DATA)
+ if (chunk_type == DATA)
SCTP_ADV_DBG ("n_advance_bytes0 = %u, n_data_bytes0 = %u",
n_advance_bytes0, n_data_bytes0);
* _(SHUTDOWN_RECEIVED, "SHUTDOWN_RECEIVED") \
* _(SHUTDOWN_ACK_SENT, "SHUTDOWN_ACK_SENT")
*/
- //_(CLOSED, DATA, SCTP_INPUT_NEXT_LISTEN_PHASE, SCTP_ERROR_NONE); /* UNEXPECTED DATA chunk which requires special handling */
+ _(CLOSED, DATA, SCTP_INPUT_NEXT_LISTEN_PHASE, SCTP_ERROR_NONE); /* UNEXPECTED DATA chunk which requires special handling */
_(CLOSED, INIT, SCTP_INPUT_NEXT_LISTEN_PHASE, SCTP_ERROR_NONE);
_(CLOSED, INIT_ACK, SCTP_INPUT_NEXT_DROP, SCTP_ERROR_ACK_DUP); /* UNEXPECTED INIT_ACK chunk */
_(CLOSED, SACK, SCTP_INPUT_NEXT_DROP, SCTP_ERROR_SACK_CHUNK_VIOLATION); /* UNEXPECTED SACK chunk */