blob: b36c49d3d24028207398fe36948eae77d3b67929 [file] [log] [blame]
Filip Tehlara5a458f2019-03-05 06:50:19 -08001/*
2 * Copyright (c) 2018 SUSE LLC.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <vnet/sctp/sctp.h>
16#include <vnet/sctp/sctp_debug.h>
17#include <vppinfra/random.h>
18#include <openssl/hmac.h>
19
20u32
21ip6_sctp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
22 ip6_header_t * ip0, int *bogus_lengthp);
23
24u32
25ip4_sctp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
26 ip4_header_t * ip0);
27
28#define foreach_sctp4_output_next \
29 _ (DROP, "error-drop") \
30 _ (IP_LOOKUP, "ip4-lookup")
31
32#define foreach_sctp6_output_next \
33 _ (DROP, "error-drop") \
34 _ (IP_LOOKUP, "ip6-lookup")
35
36static char *sctp_error_strings[] = {
37#define sctp_error(n,s) s,
38#include <vnet/sctp/sctp_error.def>
39#undef sctp_error
40};
41
42typedef enum _sctp_output_next
43{
44 SCTP_OUTPUT_NEXT_DROP,
45 SCTP_OUTPUT_NEXT_IP_LOOKUP,
46 SCTP_OUTPUT_N_NEXT
47} sctp_output_next_t;
48
49typedef struct
50{
51 sctp_header_t sctp_header;
52 sctp_connection_t sctp_connection;
53} sctp_tx_trace_t;
54
55always_inline u8
56sctp_is_retransmitting (sctp_connection_t * sctp_conn, u8 idx)
57{
58 return sctp_conn->sub_conn[idx].is_retransmitting;
59}
60
61always_inline uword
62sctp46_output_inline (vlib_main_t * vm,
63 vlib_node_runtime_t * node,
64 vlib_frame_t * from_frame, int is_ip4)
65{
66 u32 n_left_from, next_index, *from, *to_next;
67 u32 my_thread_index = vm->thread_index;
68
69 from = vlib_frame_vector_args (from_frame);
70 n_left_from = from_frame->n_vectors;
71 next_index = node->cached_next_index;
72 sctp_set_time_now (my_thread_index);
73
74 while (n_left_from > 0)
75 {
76 u32 n_left_to_next;
77
78 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
79
80 while (n_left_from > 0 && n_left_to_next > 0)
81 {
82 u32 bi0;
83 vlib_buffer_t *b0;
84 sctp_header_t *sctp_hdr = 0;
85 sctp_connection_t *sctp_conn;
86 sctp_tx_trace_t *t0;
87 sctp_header_t *th0 = 0;
88 u32 error0 = SCTP_ERROR_PKTS_SENT, next0 =
89 SCTP_OUTPUT_NEXT_IP_LOOKUP;
90
91#if SCTP_DEBUG_STATE_MACHINE
92 u16 packet_length = 0;
93#endif
94
95 bi0 = from[0];
96 to_next[0] = bi0;
97 from += 1;
98 to_next += 1;
99 n_left_from -= 1;
100 n_left_to_next -= 1;
101
102 b0 = vlib_get_buffer (vm, bi0);
103
104 sctp_conn =
105 sctp_connection_get (vnet_buffer (b0)->sctp.connection_index,
106 my_thread_index);
107
108 if (PREDICT_FALSE (sctp_conn == 0))
109 {
110 error0 = SCTP_ERROR_INVALID_CONNECTION;
111 next0 = SCTP_OUTPUT_NEXT_DROP;
112 goto done;
113 }
114
115 u8 idx = vnet_buffer (b0)->sctp.subconn_idx;
116
117 th0 = vlib_buffer_get_current (b0);
118
119 if (is_ip4)
120 {
121 ip4_header_t *iph4 = vlib_buffer_push_ip4 (vm,
122 b0,
123 &sctp_conn->sub_conn
124 [idx].connection.
125 lcl_ip.ip4,
126 &sctp_conn->
127 sub_conn
128 [idx].connection.
129 rmt_ip.ip4,
130 IP_PROTOCOL_SCTP, 1);
131
132 u32 checksum = ip4_sctp_compute_checksum (vm, b0, iph4);
133
134 sctp_hdr = ip4_next_header (iph4);
135 sctp_hdr->checksum = checksum;
136
137 vnet_buffer (b0)->l4_hdr_offset = (u8 *) th0 - b0->data;
138
139#if SCTP_DEBUG_STATE_MACHINE
140 packet_length = clib_net_to_host_u16 (iph4->length);
141#endif
142 }
143 else
144 {
145 ip6_header_t *iph6 = vlib_buffer_push_ip6 (vm,
146 b0,
147 &sctp_conn->sub_conn
148 [idx].
149 connection.lcl_ip.
150 ip6,
151 &sctp_conn->sub_conn
152 [idx].
153 connection.rmt_ip.
154 ip6,
155 IP_PROTOCOL_SCTP);
156
157 int bogus = ~0;
158 u32 checksum = ip6_sctp_compute_checksum (vm, b0, iph6, &bogus);
159 ASSERT (!bogus);
160
161 sctp_hdr = ip6_next_header (iph6);
162 sctp_hdr->checksum = checksum;
163
164 vnet_buffer (b0)->l3_hdr_offset = (u8 *) iph6 - b0->data;
165 vnet_buffer (b0)->l4_hdr_offset = (u8 *) th0 - b0->data;
166
167#if SCTP_DEBUG_STATE_MACHINE
168 packet_length = clib_net_to_host_u16 (iph6->payload_length);
169#endif
170 }
171
172 sctp_full_hdr_t *full_hdr = (sctp_full_hdr_t *) sctp_hdr;
173 u8 chunk_type = vnet_sctp_get_chunk_type (&full_hdr->common_hdr);
174 if (chunk_type >= UNKNOWN)
175 {
176 clib_warning
177 ("Trying to send an unrecognized chunk... something is really bad.");
178 error0 = SCTP_ERROR_UNKNOWN_CHUNK;
179 next0 = SCTP_OUTPUT_NEXT_DROP;
180 goto done;
181 }
182
183#if SCTP_DEBUG_STATE_MACHINE
184 u8 is_valid =
185 (sctp_conn->sub_conn[idx].connection.lcl_port ==
186 sctp_hdr->src_port
187 || sctp_conn->sub_conn[idx].connection.lcl_port ==
188 sctp_hdr->dst_port)
189 && (sctp_conn->sub_conn[idx].connection.rmt_port ==
190 sctp_hdr->dst_port
191 || sctp_conn->sub_conn[idx].connection.rmt_port ==
192 sctp_hdr->src_port);
193
194 if (!is_valid)
195 {
196 SCTP_DBG_STATE_MACHINE ("BUFFER IS INCORRECT: conn_index = %u, "
197 "packet_length = %u, "
198 "chunk_type = %u [%s], "
199 "connection.lcl_port = %u, sctp_hdr->src_port = %u, "
200 "connection.rmt_port = %u, sctp_hdr->dst_port = %u",
201 sctp_conn->sub_conn[idx].
202 connection.c_index, packet_length,
203 chunk_type,
204 sctp_chunk_to_string (chunk_type),
205 sctp_conn->sub_conn[idx].
206 connection.lcl_port, sctp_hdr->src_port,
207 sctp_conn->sub_conn[idx].
208 connection.rmt_port,
209 sctp_hdr->dst_port);
210
211 error0 = SCTP_ERROR_UNKNOWN_CHUNK;
212 next0 = SCTP_OUTPUT_NEXT_DROP;
213 goto done;
214 }
215#endif
216 SCTP_DBG_STATE_MACHINE
217 ("SESSION_INDEX = %u, CONN_INDEX = %u, CURR_CONN_STATE = %u (%s), "
218 "CHUNK_TYPE = %s, " "SRC_PORT = %u, DST_PORT = %u",
219 sctp_conn->sub_conn[idx].connection.s_index,
220 sctp_conn->sub_conn[idx].connection.c_index,
221 sctp_conn->state, sctp_state_to_string (sctp_conn->state),
222 sctp_chunk_to_string (chunk_type), full_hdr->hdr.src_port,
223 full_hdr->hdr.dst_port);
224
225 /* Let's make sure the state-machine does not send anything crazy */
226#if SCTP_DEBUG_STATE_MACHINE
227 if (sctp_validate_output_state_machine (sctp_conn, chunk_type) != 0)
228 {
229 SCTP_DBG_STATE_MACHINE
230 ("Sending the wrong chunk (%s) based on state-machine status (%s)",
231 sctp_chunk_to_string (chunk_type),
232 sctp_state_to_string (sctp_conn->state));
233
234 error0 = SCTP_ERROR_UNKNOWN_CHUNK;
235 next0 = SCTP_OUTPUT_NEXT_DROP;
236 goto done;
237
238 }
239#endif
240
241 /* Karn's algorithm: RTT measurements MUST NOT be made using
242 * packets that were retransmitted
243 */
244 if (!sctp_is_retransmitting (sctp_conn, idx))
245 {
246 /* Measure RTT with this */
247 if (chunk_type == DATA
248 && sctp_conn->sub_conn[idx].RTO_pending == 0)
249 {
250 sctp_conn->sub_conn[idx].RTO_pending = 1;
251 sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
252 }
253 else
254 sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
255 }
256
257 /* Let's take care of TIMERS */
258 switch (chunk_type)
259 {
260 case COOKIE_ECHO:
261 {
262 sctp_conn->state = SCTP_STATE_COOKIE_ECHOED;
263 break;
264 }
265 case DATA:
266 {
267 SCTP_ADV_DBG_OUTPUT ("PACKET_LENGTH = %u", packet_length);
268
269 sctp_timer_update (sctp_conn, idx, SCTP_TIMER_T3_RXTX,
270 sctp_conn->sub_conn[idx].RTO);
271 break;
272 }
273 case SHUTDOWN:
274 {
275 /* Start the SCTP_TIMER_T2_SHUTDOWN timer */
276 sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
277 sctp_conn->sub_conn[idx].RTO);
278 sctp_conn->state = SCTP_STATE_SHUTDOWN_SENT;
279 break;
280 }
281 case SHUTDOWN_ACK:
282 {
283 /* Start the SCTP_TIMER_T2_SHUTDOWN timer */
284 sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T2_SHUTDOWN,
285 sctp_conn->sub_conn[idx].RTO);
286 sctp_conn->state = SCTP_STATE_SHUTDOWN_ACK_SENT;
287 break;
288 }
289 case SHUTDOWN_COMPLETE:
290 {
291 sctp_conn->state = SCTP_STATE_CLOSED;
292 break;
293 }
294 }
295
296 vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
297 vnet_buffer (b0)->sw_if_index[VLIB_TX] =
298 sctp_conn->sub_conn[idx].c_fib_index;
299
300 b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
301
302 SCTP_DBG_STATE_MACHINE
303 ("SESSION_INDEX = %u, CONNECTION_INDEX = %u, " "NEW_STATE = %s, "
304 "CHUNK_SENT = %s", sctp_conn->sub_conn[idx].connection.s_index,
305 sctp_conn->sub_conn[idx].connection.c_index,
306 sctp_state_to_string (sctp_conn->state),
307 sctp_chunk_to_string (chunk_type));
308
309 vnet_sctp_common_hdr_params_host_to_net (&full_hdr->common_hdr);
310
311 done:
312 b0->error = node->errors[error0];
313 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
314 {
315 t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
316 if (th0)
317 {
318 clib_memcpy_fast (&t0->sctp_header, th0,
319 sizeof (t0->sctp_header));
320 }
321 else
322 {
323 clib_memset (&t0->sctp_header, 0, sizeof (t0->sctp_header));
324 }
325 clib_memcpy_fast (&t0->sctp_connection, sctp_conn,
326 sizeof (t0->sctp_connection));
327 }
328
329 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
330 n_left_to_next, bi0, next0);
331 }
332
333 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
334 }
335
336 return from_frame->n_vectors;
337}
338
339VLIB_NODE_FN (sctp4_output_node) (vlib_main_t * vm,
340 vlib_node_runtime_t * node,
341 vlib_frame_t * from_frame)
342{
343 return sctp46_output_inline (vm, node, from_frame, 1 /* is_ip4 */ );
344}
345
346VLIB_NODE_FN (sctp6_output_node) (vlib_main_t * vm,
347 vlib_node_runtime_t * node,
348 vlib_frame_t * from_frame)
349{
350 return sctp46_output_inline (vm, node, from_frame, 0 /* is_ip4 */ );
351}
352
353/* *INDENT-OFF* */
354VLIB_REGISTER_NODE (sctp4_output_node) =
355{
356 .name = "sctp4-output",
357 /* Takes a vector of packets. */
358 .vector_size = sizeof (u32),
359 .n_errors = SCTP_N_ERROR,
360 .error_strings = sctp_error_strings,
361 .n_next_nodes = SCTP_OUTPUT_N_NEXT,
362 .next_nodes = {
363#define _(s,n) [SCTP_OUTPUT_NEXT_##s] = n,
364 foreach_sctp4_output_next
365#undef _
366 },
367 .format_buffer = format_sctp_header,
368 .format_trace = format_sctp_tx_trace,
369};
370/* *INDENT-ON* */
371
372/* *INDENT-OFF* */
373VLIB_REGISTER_NODE (sctp6_output_node) =
374{
375 .name = "sctp6-output",
376 /* Takes a vector of packets. */
377 .vector_size = sizeof (u32),
378 .n_errors = SCTP_N_ERROR,
379 .error_strings = sctp_error_strings,
380 .n_next_nodes = SCTP_OUTPUT_N_NEXT,
381 .next_nodes = {
382#define _(s,n) [SCTP_OUTPUT_NEXT_##s] = n,
383 foreach_sctp6_output_next
384#undef _
385 },
386 .format_buffer = format_sctp_header,
387 .format_trace = format_sctp_tx_trace,
388};
389/* *INDENT-ON* */
390
391/*
392 * fd.io coding-style-patch-verification: ON
393 *
394 * Local Variables:
395 * eval: (c-set-style "gnu")
396 * End:
397 */