blob: e76f67b3e3e15b0b2d4774c812b8456b6e246ebd [file] [log] [blame]
Marco Varlese191a5942017-10-30 18:17:21 +01001/*
2 * Copyright (c) 2017 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>
Marco Varlese91389ac2018-01-31 11:00:01 +010018#include <openssl/hmac.h>
Marco Varlese191a5942017-10-30 18:17:21 +010019
Marco Varlese191a5942017-10-30 18:17:21 +010020/**
21 * Flush tx frame populated by retransmits and timer pops
22 */
23void
24sctp_flush_frame_to_output (vlib_main_t * vm, u8 thread_index, u8 is_ip4)
25{
26 if (sctp_main.tx_frames[!is_ip4][thread_index])
27 {
28 u32 next_index;
29 next_index = is_ip4 ? sctp4_output_node.index : sctp6_output_node.index;
30 vlib_put_frame_to_node (vm, next_index,
31 sctp_main.tx_frames[!is_ip4][thread_index]);
32 sctp_main.tx_frames[!is_ip4][thread_index] = 0;
33 }
34}
35
36/**
37 * Flush ip lookup tx frames populated by timer pops
38 */
39always_inline void
40sctp_flush_frame_to_ip_lookup (vlib_main_t * vm, u8 thread_index, u8 is_ip4)
41{
42 if (sctp_main.ip_lookup_tx_frames[!is_ip4][thread_index])
43 {
44 u32 next_index;
45 next_index = is_ip4 ? ip4_lookup_node.index : ip6_lookup_node.index;
46 vlib_put_frame_to_node (vm, next_index,
47 sctp_main.ip_lookup_tx_frames[!is_ip4]
48 [thread_index]);
49 sctp_main.ip_lookup_tx_frames[!is_ip4][thread_index] = 0;
50 }
51}
52
53/**
54 * Flush v4 and v6 sctp and ip-lookup tx frames for thread index
55 */
56void
57sctp_flush_frames_to_output (u8 thread_index)
58{
59 vlib_main_t *vm = vlib_get_main ();
60 sctp_flush_frame_to_output (vm, thread_index, 1);
61 sctp_flush_frame_to_output (vm, thread_index, 0);
62 sctp_flush_frame_to_ip_lookup (vm, thread_index, 1);
63 sctp_flush_frame_to_ip_lookup (vm, thread_index, 0);
64}
65
66u32
67ip4_sctp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
68 ip4_header_t * ip0)
69{
70 ip_csum_t checksum;
71 u32 ip_header_length, payload_length_host_byte_order;
72 u32 n_this_buffer, n_bytes_left, n_ip_bytes_this_buffer;
73 void *data_this_buffer;
74
75 /* Initialize checksum with ip header. */
76 ip_header_length = ip4_header_bytes (ip0);
77 payload_length_host_byte_order =
78 clib_net_to_host_u16 (ip0->length) - ip_header_length;
79 checksum =
80 clib_host_to_net_u32 (payload_length_host_byte_order +
81 (ip0->protocol << 16));
82
83 if (BITS (uword) == 32)
84 {
85 checksum =
86 ip_csum_with_carry (checksum,
87 clib_mem_unaligned (&ip0->src_address, u32));
88 checksum =
89 ip_csum_with_carry (checksum,
90 clib_mem_unaligned (&ip0->dst_address, u32));
91 }
92 else
93 checksum =
94 ip_csum_with_carry (checksum,
95 clib_mem_unaligned (&ip0->src_address, u64));
96
97 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
98 data_this_buffer = (void *) ip0 + ip_header_length;
99 n_ip_bytes_this_buffer =
100 p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
101 if (n_this_buffer + ip_header_length > n_ip_bytes_this_buffer)
102 {
103 n_this_buffer = n_ip_bytes_this_buffer > ip_header_length ?
104 n_ip_bytes_this_buffer - ip_header_length : 0;
105 }
106 while (1)
107 {
108 checksum =
109 ip_incremental_checksum (checksum, data_this_buffer, n_this_buffer);
110 n_bytes_left -= n_this_buffer;
111 if (n_bytes_left == 0)
112 break;
113
114 ASSERT (p0->flags & VLIB_BUFFER_NEXT_PRESENT);
115 p0 = vlib_get_buffer (vm, p0->next_buffer);
116 data_this_buffer = vlib_buffer_get_current (p0);
117 n_this_buffer = p0->current_length;
118 }
119
120 return checksum;
121}
122
123u32
124ip6_sctp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
125 ip6_header_t * ip0, int *bogus_lengthp)
126{
127 ip_csum_t checksum;
128 u16 payload_length_host_byte_order;
129 u32 i, n_this_buffer, n_bytes_left;
130 u32 headers_size = sizeof (ip0[0]);
131 void *data_this_buffer;
132
133 ASSERT (bogus_lengthp);
134 *bogus_lengthp = 0;
135
136 /* Initialize checksum with ip header. */
137 checksum = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
138 payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
139 data_this_buffer = (void *) (ip0 + 1);
140
141 for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
142 {
143 checksum = ip_csum_with_carry (checksum,
144 clib_mem_unaligned (&ip0->
145 src_address.as_uword
146 [i], uword));
147 checksum =
148 ip_csum_with_carry (checksum,
149 clib_mem_unaligned (&ip0->dst_address.as_uword[i],
150 uword));
151 }
152
153 /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
154 * or UDP-Ping packets */
155 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
156 {
157 u32 skip_bytes;
158 ip6_hop_by_hop_ext_t *ext_hdr =
159 (ip6_hop_by_hop_ext_t *) data_this_buffer;
160
161 /* validate really icmp6 next */
162 ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_SCTP));
163
164 skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
165 data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
166
167 payload_length_host_byte_order -= skip_bytes;
168 headers_size += skip_bytes;
169 }
170
171 n_bytes_left = n_this_buffer = payload_length_host_byte_order;
172 if (p0 && n_this_buffer + headers_size > p0->current_length)
173 n_this_buffer =
174 p0->current_length >
175 headers_size ? p0->current_length - headers_size : 0;
176 while (1)
177 {
178 checksum =
179 ip_incremental_checksum (checksum, data_this_buffer, n_this_buffer);
180 n_bytes_left -= n_this_buffer;
181 if (n_bytes_left == 0)
182 break;
183
184 if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
185 {
186 *bogus_lengthp = 1;
187 return 0xfefe;
188 }
189 p0 = vlib_get_buffer (vm, p0->next_buffer);
190 data_this_buffer = vlib_buffer_get_current (p0);
191 n_this_buffer = p0->current_length;
192 }
193
194 return checksum;
195}
196
197void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100198sctp_push_ip_hdr (sctp_main_t * tm, sctp_sub_connection_t * sctp_sub_conn,
Marco Varlese191a5942017-10-30 18:17:21 +0100199 vlib_buffer_t * b)
200{
201 sctp_header_t *th = vlib_buffer_get_current (b);
202 vlib_main_t *vm = vlib_get_main ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100203 if (sctp_sub_conn->c_is_ip4)
Marco Varlese191a5942017-10-30 18:17:21 +0100204 {
205 ip4_header_t *ih;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100206 ih = vlib_buffer_push_ip4 (vm, b, &sctp_sub_conn->c_lcl_ip4,
207 &sctp_sub_conn->c_rmt_ip4, IP_PROTOCOL_SCTP,
208 1);
Marco Varlese191a5942017-10-30 18:17:21 +0100209 th->checksum = ip4_sctp_compute_checksum (vm, b, ih);
210 }
211 else
212 {
213 ip6_header_t *ih;
214 int bogus = ~0;
215
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100216 ih = vlib_buffer_push_ip6 (vm, b, &sctp_sub_conn->c_lcl_ip6,
217 &sctp_sub_conn->c_rmt_ip6, IP_PROTOCOL_SCTP);
Marco Varlese191a5942017-10-30 18:17:21 +0100218 th->checksum = ip6_sctp_compute_checksum (vm, b, ih, &bogus);
219 ASSERT (!bogus);
220 }
221}
222
223always_inline void *
224sctp_reuse_buffer (vlib_main_t * vm, vlib_buffer_t * b)
225{
226 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
227 vlib_buffer_free_one (vm, b->next_buffer);
228 /* Zero all flags but free list index and trace flag */
229 b->flags &= VLIB_BUFFER_NEXT_PRESENT - 1;
230 b->current_data = 0;
231 b->current_length = 0;
232 b->total_length_not_including_first_buffer = 0;
233 vnet_buffer (b)->sctp.flags = 0;
Marco Varlese15cc6a82018-02-21 12:39:52 +0100234 vnet_buffer (b)->sctp.subconn_idx = MAX_SCTP_CONNECTIONS;
Marco Varlese191a5942017-10-30 18:17:21 +0100235
236 /* Leave enough space for headers */
Florin Coras1ee78302019-02-05 15:51:15 -0800237 return vlib_buffer_make_headroom (b, TRANSPORT_MAX_HDRS_LEN);
Marco Varlese191a5942017-10-30 18:17:21 +0100238}
239
240always_inline void *
241sctp_init_buffer (vlib_main_t * vm, vlib_buffer_t * b)
242{
243 ASSERT ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
Marco Varlese191a5942017-10-30 18:17:21 +0100244 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
245 b->total_length_not_including_first_buffer = 0;
246 vnet_buffer (b)->sctp.flags = 0;
Marco Varlese15cc6a82018-02-21 12:39:52 +0100247 vnet_buffer (b)->sctp.subconn_idx = MAX_SCTP_CONNECTIONS;
Marco Varlese191a5942017-10-30 18:17:21 +0100248 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b);
249 /* Leave enough space for headers */
Florin Coras1ee78302019-02-05 15:51:15 -0800250 return vlib_buffer_make_headroom (b, TRANSPORT_MAX_HDRS_LEN);
Marco Varlese191a5942017-10-30 18:17:21 +0100251}
252
253always_inline int
254sctp_alloc_tx_buffers (sctp_main_t * tm, u8 thread_index, u32 n_free_buffers)
255{
256 vlib_main_t *vm = vlib_get_main ();
257 u32 current_length = vec_len (tm->tx_buffers[thread_index]);
258 u32 n_allocated;
259
260 vec_validate (tm->tx_buffers[thread_index],
261 current_length + n_free_buffers - 1);
262 n_allocated =
263 vlib_buffer_alloc (vm, &tm->tx_buffers[thread_index][current_length],
264 n_free_buffers);
265 _vec_len (tm->tx_buffers[thread_index]) = current_length + n_allocated;
266 /* buffer shortage, report failure */
267 if (vec_len (tm->tx_buffers[thread_index]) == 0)
268 {
269 clib_warning ("out of buffers");
270 return -1;
271 }
272 return 0;
273}
274
275always_inline int
276sctp_get_free_buffer_index (sctp_main_t * tm, u32 * bidx)
277{
278 u32 *my_tx_buffers;
279 u32 thread_index = vlib_get_thread_index ();
280 if (PREDICT_FALSE (vec_len (tm->tx_buffers[thread_index]) == 0))
281 {
282 if (sctp_alloc_tx_buffers (tm, thread_index, VLIB_FRAME_SIZE))
283 return -1;
284 }
285 my_tx_buffers = tm->tx_buffers[thread_index];
286 *bidx = my_tx_buffers[vec_len (my_tx_buffers) - 1];
287 _vec_len (my_tx_buffers) -= 1;
288 return 0;
289}
290
291always_inline void
292sctp_enqueue_to_output_i (vlib_main_t * vm, vlib_buffer_t * b, u32 bi,
293 u8 is_ip4, u8 flush)
294{
295 sctp_main_t *tm = vnet_get_sctp_main ();
296 u32 thread_index = vlib_get_thread_index ();
297 u32 *to_next, next_index;
298 vlib_frame_t *f;
299
300 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
301 b->error = 0;
302
303 /* Decide where to send the packet */
304 next_index = is_ip4 ? sctp4_output_node.index : sctp6_output_node.index;
305 sctp_trajectory_add_start (b, 2);
306
307 /* Get frame to v4/6 output node */
308 f = tm->tx_frames[!is_ip4][thread_index];
309 if (!f)
310 {
311 f = vlib_get_frame_to_node (vm, next_index);
312 ASSERT (f);
313 tm->tx_frames[!is_ip4][thread_index] = f;
314 }
315 to_next = vlib_frame_vector_args (f);
316 to_next[f->n_vectors] = bi;
317 f->n_vectors += 1;
318 if (flush || f->n_vectors == VLIB_FRAME_SIZE)
319 {
320 vlib_put_frame_to_node (vm, next_index, f);
321 tm->tx_frames[!is_ip4][thread_index] = 0;
322 }
323}
324
325always_inline void
326sctp_enqueue_to_output_now (vlib_main_t * vm, vlib_buffer_t * b, u32 bi,
327 u8 is_ip4)
328{
329 sctp_enqueue_to_output_i (vm, b, bi, is_ip4, 1);
330}
331
332always_inline void
333sctp_enqueue_to_ip_lookup_i (vlib_main_t * vm, vlib_buffer_t * b, u32 bi,
Marco Varlesee17bb712018-03-28 12:06:10 +0200334 u8 is_ip4, u32 fib_index, u8 flush)
Marco Varlese191a5942017-10-30 18:17:21 +0100335{
336 sctp_main_t *tm = vnet_get_sctp_main ();
337 u32 thread_index = vlib_get_thread_index ();
338 u32 *to_next, next_index;
339 vlib_frame_t *f;
340
341 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
342 b->error = 0;
343
Marco Varlesee17bb712018-03-28 12:06:10 +0200344 vnet_buffer (b)->sw_if_index[VLIB_TX] = fib_index;
345 vnet_buffer (b)->sw_if_index[VLIB_RX] = 0;
Marco Varlese191a5942017-10-30 18:17:21 +0100346
347 /* Send to IP lookup */
348 next_index = is_ip4 ? ip4_lookup_node.index : ip6_lookup_node.index;
349 if (VLIB_BUFFER_TRACE_TRAJECTORY > 0)
350 {
351 b->pre_data[0] = 2;
352 b->pre_data[1] = next_index;
353 }
354
355 f = tm->ip_lookup_tx_frames[!is_ip4][thread_index];
356 if (!f)
357 {
358 f = vlib_get_frame_to_node (vm, next_index);
359 ASSERT (f);
360 tm->ip_lookup_tx_frames[!is_ip4][thread_index] = f;
361 }
362
363 to_next = vlib_frame_vector_args (f);
364 to_next[f->n_vectors] = bi;
365 f->n_vectors += 1;
366 if (flush || f->n_vectors == VLIB_FRAME_SIZE)
367 {
368 vlib_put_frame_to_node (vm, next_index, f);
369 tm->ip_lookup_tx_frames[!is_ip4][thread_index] = 0;
370 }
371}
372
373always_inline void
374sctp_enqueue_to_ip_lookup (vlib_main_t * vm, vlib_buffer_t * b, u32 bi,
Marco Varlesee17bb712018-03-28 12:06:10 +0200375 u8 is_ip4, u32 fib_index)
Marco Varlese191a5942017-10-30 18:17:21 +0100376{
Marco Varlesee17bb712018-03-28 12:06:10 +0200377 sctp_enqueue_to_ip_lookup_i (vm, b, bi, is_ip4, fib_index, 0);
Florin Corasfd542f12018-05-16 19:28:24 -0700378 if (vm->thread_index == 0 && vlib_num_workers ())
379 session_flush_frames_main_thread (vm);
Marco Varlese191a5942017-10-30 18:17:21 +0100380}
381
Marco Varlese191a5942017-10-30 18:17:21 +0100382/**
383 * Convert buffer to INIT
384 */
385void
Marco Varlese54432f82018-02-15 17:01:56 +0100386sctp_prepare_init_chunk (sctp_connection_t * sctp_conn, u8 idx,
387 vlib_buffer_t * b)
Marco Varlese191a5942017-10-30 18:17:21 +0100388{
389 u32 random_seed = random_default_seed ();
390 u16 alloc_bytes = sizeof (sctp_init_chunk_t);
Marco Varlese54432f82018-02-15 17:01:56 +0100391 sctp_sub_connection_t *sub_conn = &sctp_conn->sub_conn[idx];
Marco Varlese191a5942017-10-30 18:17:21 +0100392
393 sctp_ipv4_addr_param_t *ip4_param = 0;
394 sctp_ipv6_addr_param_t *ip6_param = 0;
395
396 if (sub_conn->c_is_ip4)
397 alloc_bytes += sizeof (sctp_ipv4_addr_param_t);
398 else
399 alloc_bytes += sizeof (sctp_ipv6_addr_param_t);
400
401 /* As per RFC 4960 the chunk_length value does NOT contemplate
402 * the size of the first header (see sctp_header_t) and any padding
403 */
404 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
405
406 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
407
408 sctp_init_chunk_t *init_chunk = vlib_buffer_push_uninit (b, alloc_bytes);
409
410 u16 pointer_offset = sizeof (init_chunk);
411 if (sub_conn->c_is_ip4)
412 {
413 ip4_param = (sctp_ipv4_addr_param_t *) init_chunk + pointer_offset;
414 ip4_param->address.as_u32 = sub_conn->c_lcl_ip.ip4.as_u32;
415
416 pointer_offset += sizeof (sctp_ipv4_addr_param_t);
417 }
418 else
419 {
420 ip6_param = (sctp_ipv6_addr_param_t *) init_chunk + pointer_offset;
421 ip6_param->address.as_u64[0] = sub_conn->c_lcl_ip.ip6.as_u64[0];
422 ip6_param->address.as_u64[1] = sub_conn->c_lcl_ip.ip6.as_u64[1];
423
424 pointer_offset += sizeof (sctp_ipv6_addr_param_t);
425 }
426
427 init_chunk->sctp_hdr.src_port = sub_conn->c_lcl_port; /* No need of host_to_net conversion, already in net-byte order */
428 init_chunk->sctp_hdr.dst_port = sub_conn->c_rmt_port; /* No need of host_to_net conversion, already in net-byte order */
429 init_chunk->sctp_hdr.checksum = 0;
430 /* The sender of an INIT must set the VERIFICATION_TAG to 0 as per RFC 4960 Section 8.5.1 */
431 init_chunk->sctp_hdr.verification_tag = 0x0;
432
433 vnet_sctp_set_chunk_type (&init_chunk->chunk_hdr, INIT);
434 vnet_sctp_set_chunk_length (&init_chunk->chunk_hdr, chunk_len);
435 vnet_sctp_common_hdr_params_host_to_net (&init_chunk->chunk_hdr);
436
Marco Varlese6e4d4a32018-03-12 12:36:59 +0100437 sctp_init_cwnd (sctp_conn);
438
Marco Varlesef3ab4892018-02-19 15:23:13 +0100439 init_chunk->a_rwnd = clib_host_to_net_u32 (sctp_conn->sub_conn[idx].cwnd);
Marco Varlese191a5942017-10-30 18:17:21 +0100440 init_chunk->initiate_tag = clib_host_to_net_u32 (random_u32 (&random_seed));
441 init_chunk->inboud_streams_count =
442 clib_host_to_net_u16 (INBOUND_STREAMS_COUNT);
443 init_chunk->outbound_streams_count =
444 clib_host_to_net_u16 (OUTBOUND_STREAMS_COUNT);
445
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100446 init_chunk->initial_tsn =
447 clib_host_to_net_u32 (sctp_conn->local_initial_tsn);
448 SCTP_CONN_TRACKING_DBG ("sctp_conn->local_initial_tsn = %u",
449 sctp_conn->local_initial_tsn);
450
Marco Varlese191a5942017-10-30 18:17:21 +0100451 sctp_conn->local_tag = init_chunk->initiate_tag;
452
453 vnet_buffer (b)->sctp.connection_index = sub_conn->c_c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +0100454 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese191a5942017-10-30 18:17:21 +0100455
456 SCTP_DBG_STATE_MACHINE ("CONN_INDEX = %u, CURR_CONN_STATE = %u (%s), "
457 "CHUNK_TYPE = %s, "
458 "SRC_PORT = %u, DST_PORT = %u",
459 sub_conn->connection.c_index,
460 sctp_conn->state,
461 sctp_state_to_string (sctp_conn->state),
462 sctp_chunk_to_string (INIT),
463 init_chunk->sctp_hdr.src_port,
464 init_chunk->sctp_hdr.dst_port);
465}
466
Marco Varlese91389ac2018-01-31 11:00:01 +0100467void
468sctp_compute_mac (sctp_connection_t * sctp_conn,
469 sctp_state_cookie_param_t * state_cookie)
Marco Varlese191a5942017-10-30 18:17:21 +0100470{
Marco Varlese91389ac2018-01-31 11:00:01 +0100471#if OPENSSL_VERSION_NUMBER >= 0x10100000L
472 HMAC_CTX *ctx;
473#else
474 HMAC_CTX ctx;
Marco Varlese91389ac2018-01-31 11:00:01 +0100475#endif
476 unsigned int len = 0;
Marco Varlese18b63152018-02-12 09:08:21 +0100477 const EVP_MD *md = EVP_sha1 ();
Marco Varlese91389ac2018-01-31 11:00:01 +0100478#if OPENSSL_VERSION_NUMBER >= 0x10100000L
479 ctx = HMAC_CTX_new ();
Marco Varlese18b63152018-02-12 09:08:21 +0100480 HMAC_Init_ex (ctx, &state_cookie->creation_time,
Marco Varlese91389ac2018-01-31 11:00:01 +0100481 sizeof (state_cookie->creation_time), md, NULL);
482 HMAC_Update (ctx, (const unsigned char *) &sctp_conn, sizeof (sctp_conn));
483 HMAC_Final (ctx, state_cookie->mac, &len);
484#else
485 HMAC_CTX_init (&ctx);
486 HMAC_Init_ex (&ctx, &state_cookie->creation_time,
487 sizeof (state_cookie->creation_time), md, NULL);
Marco Varlese91389ac2018-01-31 11:00:01 +0100488 HMAC_Update (&ctx, (const unsigned char *) &sctp_conn, sizeof (sctp_conn));
489 HMAC_Final (&ctx, state_cookie->mac, &len);
490 HMAC_CTX_cleanup (&ctx);
491#endif
492
493 ENDIANESS_SWAP (state_cookie->mac);
Marco Varlese191a5942017-10-30 18:17:21 +0100494}
495
496void
Marco Varlese54432f82018-02-15 17:01:56 +0100497sctp_prepare_cookie_ack_chunk (sctp_connection_t * sctp_conn, u8 idx,
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100498 vlib_buffer_t * b)
Marco Varlese191a5942017-10-30 18:17:21 +0100499{
500 vlib_main_t *vm = vlib_get_main ();
Marco Varlese191a5942017-10-30 18:17:21 +0100501
502 sctp_reuse_buffer (vm, b);
503
504 u16 alloc_bytes = sizeof (sctp_cookie_ack_chunk_t);
505
506 /* As per RFC 4960 the chunk_length value does NOT contemplate
507 * the size of the first header (see sctp_header_t) and any padding
508 */
509 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
510
511 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
512
513 sctp_cookie_ack_chunk_t *cookie_ack_chunk =
514 vlib_buffer_push_uninit (b, alloc_bytes);
515
516 cookie_ack_chunk->sctp_hdr.checksum = 0;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100517 cookie_ack_chunk->sctp_hdr.src_port =
518 sctp_conn->sub_conn[idx].connection.lcl_port;
519 cookie_ack_chunk->sctp_hdr.dst_port =
520 sctp_conn->sub_conn[idx].connection.rmt_port;
521 cookie_ack_chunk->sctp_hdr.verification_tag = sctp_conn->remote_tag;
Marco Varlese191a5942017-10-30 18:17:21 +0100522 vnet_sctp_set_chunk_type (&cookie_ack_chunk->chunk_hdr, COOKIE_ACK);
523 vnet_sctp_set_chunk_length (&cookie_ack_chunk->chunk_hdr, chunk_len);
524
525 vnet_buffer (b)->sctp.connection_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100526 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +0100527 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese191a5942017-10-30 18:17:21 +0100528}
529
530void
Marco Varlese54432f82018-02-15 17:01:56 +0100531sctp_prepare_cookie_echo_chunk (sctp_connection_t * sctp_conn, u8 idx,
Marco Varlese9e09ff32018-03-05 12:31:45 +0100532 vlib_buffer_t * b, u8 reuse_buffer)
Marco Varlese191a5942017-10-30 18:17:21 +0100533{
534 vlib_main_t *vm = vlib_get_main ();
Marco Varlese191a5942017-10-30 18:17:21 +0100535
Marco Varlese9e09ff32018-03-05 12:31:45 +0100536 if (reuse_buffer)
537 sctp_reuse_buffer (vm, b);
Marco Varlese191a5942017-10-30 18:17:21 +0100538
539 /* The minimum size of the message is given by the sctp_init_ack_chunk_t */
540 u16 alloc_bytes = sizeof (sctp_cookie_echo_chunk_t);
541 /* As per RFC 4960 the chunk_length value does NOT contemplate
542 * the size of the first header (see sctp_header_t) and any padding
543 */
544 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
545 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
546 sctp_cookie_echo_chunk_t *cookie_echo_chunk =
547 vlib_buffer_push_uninit (b, alloc_bytes);
548 cookie_echo_chunk->sctp_hdr.checksum = 0;
549 cookie_echo_chunk->sctp_hdr.src_port =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100550 sctp_conn->sub_conn[idx].connection.lcl_port;
Marco Varlese191a5942017-10-30 18:17:21 +0100551 cookie_echo_chunk->sctp_hdr.dst_port =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100552 sctp_conn->sub_conn[idx].connection.rmt_port;
553 cookie_echo_chunk->sctp_hdr.verification_tag = sctp_conn->remote_tag;
Marco Varlese191a5942017-10-30 18:17:21 +0100554 vnet_sctp_set_chunk_type (&cookie_echo_chunk->chunk_hdr, COOKIE_ECHO);
555 vnet_sctp_set_chunk_length (&cookie_echo_chunk->chunk_hdr, chunk_len);
Dave Barach178cf492018-11-13 16:34:13 -0500556 clib_memcpy_fast (&(cookie_echo_chunk->cookie), &sctp_conn->cookie_param,
557 sizeof (sctp_state_cookie_param_t));
Marco Varlese21c8baf2018-02-02 17:17:51 +0100558
Marco Varlese191a5942017-10-30 18:17:21 +0100559 vnet_buffer (b)->sctp.connection_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100560 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +0100561 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese191a5942017-10-30 18:17:21 +0100562}
563
Marco Varlese9e09ff32018-03-05 12:31:45 +0100564
565/*
566 * Send COOKIE_ECHO
567 */
568void
569sctp_send_cookie_echo (sctp_connection_t * sctp_conn)
570{
571 vlib_buffer_t *b;
572 u32 bi;
573 sctp_main_t *tm = vnet_get_sctp_main ();
574 vlib_main_t *vm = vlib_get_main ();
575
576 if (PREDICT_FALSE (sctp_conn->init_retransmit_err > SCTP_MAX_INIT_RETRANS))
577 {
578 clib_warning ("Reached MAX_INIT_RETRANS times. Aborting connection.");
579
580 session_stream_connect_notify (&sctp_conn->sub_conn
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100581 [SCTP_PRIMARY_PATH_IDX].connection, 1);
Marco Varlese9e09ff32018-03-05 12:31:45 +0100582
583 sctp_connection_timers_reset (sctp_conn);
584
585 sctp_connection_cleanup (sctp_conn);
586 }
587
588 if (PREDICT_FALSE (sctp_get_free_buffer_index (tm, &bi)))
589 return;
590
591 b = vlib_get_buffer (vm, bi);
Marco Varlesec7fe4f32018-03-05 15:12:29 +0100592 u8 idx = SCTP_PRIMARY_PATH_IDX;
Marco Varlese9e09ff32018-03-05 12:31:45 +0100593
594 sctp_init_buffer (vm, b);
595 sctp_prepare_cookie_echo_chunk (sctp_conn, idx, b, 0);
596 sctp_enqueue_to_output_now (vm, b, bi, sctp_conn->sub_conn[idx].c_is_ip4);
597
598 /* Start the T1_INIT timer */
599 sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T1_INIT,
600 sctp_conn->sub_conn[idx].RTO);
601
602 /* Change state to COOKIE_WAIT */
603 sctp_conn->state = SCTP_STATE_COOKIE_WAIT;
604
605 /* Measure RTT with this */
606 sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
607}
608
609
Marco Varlese191a5942017-10-30 18:17:21 +0100610/**
Marco Varlese8c5f67f2018-02-27 09:38:31 +0100611 * Convert buffer to ERROR
Marco Varleseeacf3cf2018-02-26 14:52:25 +0100612 */
Marco Varlese200fa322018-02-26 16:33:54 +0100613void
614sctp_prepare_operation_error (sctp_connection_t * sctp_conn, u8 idx,
Marco Varlese8c5f67f2018-02-27 09:38:31 +0100615 vlib_buffer_t * b, u8 err_cause)
Marco Varlese200fa322018-02-26 16:33:54 +0100616{
617 vlib_main_t *vm = vlib_get_main ();
618
619 sctp_reuse_buffer (vm, b);
620
Marco Varlese8c5f67f2018-02-27 09:38:31 +0100621 /* The minimum size of the message is given by the sctp_operation_error_t */
622 u16 alloc_bytes =
623 sizeof (sctp_operation_error_t) + sizeof (sctp_err_cause_param_t);
Marco Varlese200fa322018-02-26 16:33:54 +0100624
Marco Varlese8c5f67f2018-02-27 09:38:31 +0100625 /* As per RFC 4960 the chunk_length value does NOT contemplate
626 * the size of the first header (see sctp_header_t) and any padding
627 */
Marco Varlese200fa322018-02-26 16:33:54 +0100628 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
629
630 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
631
632 sctp_operation_error_t *err_chunk =
633 vlib_buffer_push_uninit (b, alloc_bytes);
634
Marco Varlese8c5f67f2018-02-27 09:38:31 +0100635 /* src_port & dst_port are already in network byte-order */
Marco Varlese200fa322018-02-26 16:33:54 +0100636 err_chunk->sctp_hdr.checksum = 0;
637 err_chunk->sctp_hdr.src_port = sctp_conn->sub_conn[idx].connection.lcl_port;
638 err_chunk->sctp_hdr.dst_port = sctp_conn->sub_conn[idx].connection.rmt_port;
Marco Varlese8c5f67f2018-02-27 09:38:31 +0100639 /* As per RFC4960 Section 5.2.2: copy the INITIATE_TAG into the VERIFICATION_TAG of the ABORT chunk */
Marco Varlese200fa322018-02-26 16:33:54 +0100640 err_chunk->sctp_hdr.verification_tag = sctp_conn->local_tag;
641
Marco Varlese8c5f67f2018-02-27 09:38:31 +0100642 err_chunk->err_causes[0].param_hdr.length =
643 clib_host_to_net_u16 (sizeof (err_chunk->err_causes[0].param_hdr.type) +
644 sizeof (err_chunk->err_causes[0].param_hdr.length));
645 err_chunk->err_causes[0].param_hdr.type = clib_host_to_net_u16 (err_cause);
646
Marco Varlese200fa322018-02-26 16:33:54 +0100647 vnet_sctp_set_chunk_type (&err_chunk->chunk_hdr, OPERATION_ERROR);
648 vnet_sctp_set_chunk_length (&err_chunk->chunk_hdr, chunk_len);
649
650 vnet_buffer (b)->sctp.connection_index =
651 sctp_conn->sub_conn[idx].connection.c_index;
652 vnet_buffer (b)->sctp.subconn_idx = idx;
653}
Marco Varlese200fa322018-02-26 16:33:54 +0100654
655/**
656 * Convert buffer to ABORT
657 */
Marco Varleseeacf3cf2018-02-26 14:52:25 +0100658void
659sctp_prepare_abort_for_collision (sctp_connection_t * sctp_conn, u8 idx,
660 vlib_buffer_t * b, ip4_address_t * ip4_addr,
661 ip6_address_t * ip6_addr)
662{
663 vlib_main_t *vm = vlib_get_main ();
664
665 sctp_reuse_buffer (vm, b);
666
667 /* The minimum size of the message is given by the sctp_abort_chunk_t */
668 u16 alloc_bytes = sizeof (sctp_abort_chunk_t);
669
670 /* As per RFC 4960 the chunk_length value does NOT contemplate
671 * the size of the first header (see sctp_header_t) and any padding
672 */
673 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
674
675 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
676
677 sctp_abort_chunk_t *abort_chunk = vlib_buffer_push_uninit (b, alloc_bytes);
678
679 /* src_port & dst_port are already in network byte-order */
680 abort_chunk->sctp_hdr.checksum = 0;
681 abort_chunk->sctp_hdr.src_port =
682 sctp_conn->sub_conn[idx].connection.lcl_port;
683 abort_chunk->sctp_hdr.dst_port =
684 sctp_conn->sub_conn[idx].connection.rmt_port;
685 /* As per RFC4960 Section 5.2.2: copy the INITIATE_TAG into the VERIFICATION_TAG of the ABORT chunk */
686 abort_chunk->sctp_hdr.verification_tag = sctp_conn->local_tag;
687
688 vnet_sctp_set_chunk_type (&abort_chunk->chunk_hdr, ABORT);
689 vnet_sctp_set_chunk_length (&abort_chunk->chunk_hdr, chunk_len);
690
691 vnet_buffer (b)->sctp.connection_index =
692 sctp_conn->sub_conn[idx].connection.c_index;
693 vnet_buffer (b)->sctp.subconn_idx = idx;
694}
695
696/**
697 * Convert buffer to INIT-ACK
698 */
699void
700sctp_prepare_initack_chunk_for_collision (sctp_connection_t * sctp_conn,
701 u8 idx, vlib_buffer_t * b,
702 ip4_address_t * ip4_addr,
703 ip6_address_t * ip6_addr)
704{
705 vlib_main_t *vm = vlib_get_main ();
706 sctp_ipv4_addr_param_t *ip4_param = 0;
707 sctp_ipv6_addr_param_t *ip6_param = 0;
708
709 sctp_reuse_buffer (vm, b);
710
711 /* The minimum size of the message is given by the sctp_init_ack_chunk_t */
712 u16 alloc_bytes =
713 sizeof (sctp_init_ack_chunk_t) + sizeof (sctp_state_cookie_param_t);
714
715 if (PREDICT_TRUE (ip4_addr != NULL))
716 {
717 /* Create room for variable-length fields in the INIT_ACK chunk */
718 alloc_bytes += SCTP_IPV4_ADDRESS_TYPE_LENGTH;
719 }
720 if (PREDICT_TRUE (ip6_addr != NULL))
721 {
722 /* Create room for variable-length fields in the INIT_ACK chunk */
723 alloc_bytes += SCTP_IPV6_ADDRESS_TYPE_LENGTH;
724 }
725
726 if (sctp_conn->sub_conn[idx].connection.is_ip4)
727 alloc_bytes += sizeof (sctp_ipv4_addr_param_t);
728 else
729 alloc_bytes += sizeof (sctp_ipv6_addr_param_t);
730
731 /* As per RFC 4960 the chunk_length value does NOT contemplate
732 * the size of the first header (see sctp_header_t) and any padding
733 */
734 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
735
736 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
737
738 sctp_init_ack_chunk_t *init_ack_chunk =
739 vlib_buffer_push_uninit (b, alloc_bytes);
740
741 u16 pointer_offset = sizeof (sctp_init_ack_chunk_t);
742
743 /* Create State Cookie parameter */
744 sctp_state_cookie_param_t *state_cookie_param =
745 (sctp_state_cookie_param_t *) ((char *) init_ack_chunk + pointer_offset);
746
747 state_cookie_param->param_hdr.type =
748 clib_host_to_net_u16 (SCTP_STATE_COOKIE_TYPE);
749 state_cookie_param->param_hdr.length =
750 clib_host_to_net_u16 (sizeof (sctp_state_cookie_param_t));
Marco Varlese93826732018-09-27 16:43:57 +0200751 state_cookie_param->creation_time = clib_host_to_net_u64 (sctp_time_now ());
Marco Varleseeacf3cf2018-02-26 14:52:25 +0100752 state_cookie_param->cookie_lifespan =
753 clib_host_to_net_u32 (SCTP_VALID_COOKIE_LIFE);
754
755 sctp_compute_mac (sctp_conn, state_cookie_param);
756
757 pointer_offset += sizeof (sctp_state_cookie_param_t);
758
759 if (PREDICT_TRUE (ip4_addr != NULL))
760 {
761 sctp_ipv4_addr_param_t *ipv4_addr =
762 (sctp_ipv4_addr_param_t *) init_ack_chunk + pointer_offset;
763
764 ipv4_addr->param_hdr.type =
765 clib_host_to_net_u16 (SCTP_IPV4_ADDRESS_TYPE);
766 ipv4_addr->param_hdr.length =
767 clib_host_to_net_u16 (SCTP_IPV4_ADDRESS_TYPE_LENGTH);
768 ipv4_addr->address.as_u32 = ip4_addr->as_u32;
769
770 pointer_offset += SCTP_IPV4_ADDRESS_TYPE_LENGTH;
771 }
772 if (PREDICT_TRUE (ip6_addr != NULL))
773 {
774 sctp_ipv6_addr_param_t *ipv6_addr =
775 (sctp_ipv6_addr_param_t *) init_ack_chunk + pointer_offset;
776
777 ipv6_addr->param_hdr.type =
778 clib_host_to_net_u16 (SCTP_IPV6_ADDRESS_TYPE);
779 ipv6_addr->param_hdr.length =
780 clib_host_to_net_u16 (SCTP_IPV6_ADDRESS_TYPE_LENGTH);
781 ipv6_addr->address.as_u64[0] = ip6_addr->as_u64[0];
782 ipv6_addr->address.as_u64[1] = ip6_addr->as_u64[1];
783
784 pointer_offset += SCTP_IPV6_ADDRESS_TYPE_LENGTH;
785 }
786
787 if (sctp_conn->sub_conn[idx].connection.is_ip4)
788 {
789 ip4_param = (sctp_ipv4_addr_param_t *) init_ack_chunk + pointer_offset;
790 ip4_param->address.as_u32 =
791 sctp_conn->sub_conn[idx].connection.lcl_ip.ip4.as_u32;
792
793 pointer_offset += sizeof (sctp_ipv4_addr_param_t);
794 }
795 else
796 {
797 ip6_param = (sctp_ipv6_addr_param_t *) init_ack_chunk + pointer_offset;
798 ip6_param->address.as_u64[0] =
799 sctp_conn->sub_conn[idx].connection.lcl_ip.ip6.as_u64[0];
800 ip6_param->address.as_u64[1] =
801 sctp_conn->sub_conn[idx].connection.lcl_ip.ip6.as_u64[1];
802
803 pointer_offset += sizeof (sctp_ipv6_addr_param_t);
804 }
805
806 /* src_port & dst_port are already in network byte-order */
807 init_ack_chunk->sctp_hdr.checksum = 0;
808 init_ack_chunk->sctp_hdr.src_port =
809 sctp_conn->sub_conn[idx].connection.lcl_port;
810 init_ack_chunk->sctp_hdr.dst_port =
811 sctp_conn->sub_conn[idx].connection.rmt_port;
812 /* the sctp_conn->verification_tag is already in network byte-order (being a copy of the init_tag coming with the INIT chunk) */
813 init_ack_chunk->sctp_hdr.verification_tag = sctp_conn->remote_tag;
814 init_ack_chunk->initial_tsn =
815 clib_host_to_net_u32 (sctp_conn->local_initial_tsn);
816 SCTP_CONN_TRACKING_DBG ("init_ack_chunk->initial_tsn = %u",
817 init_ack_chunk->initial_tsn);
818
819 vnet_sctp_set_chunk_type (&init_ack_chunk->chunk_hdr, INIT_ACK);
820 vnet_sctp_set_chunk_length (&init_ack_chunk->chunk_hdr, chunk_len);
821
822 init_ack_chunk->initiate_tag = sctp_conn->local_tag;
823
824 init_ack_chunk->a_rwnd =
825 clib_host_to_net_u32 (sctp_conn->sub_conn[idx].cwnd);
826 init_ack_chunk->inboud_streams_count =
827 clib_host_to_net_u16 (INBOUND_STREAMS_COUNT);
828 init_ack_chunk->outbound_streams_count =
829 clib_host_to_net_u16 (OUTBOUND_STREAMS_COUNT);
830
831 vnet_buffer (b)->sctp.connection_index =
832 sctp_conn->sub_conn[idx].connection.c_index;
833 vnet_buffer (b)->sctp.subconn_idx = idx;
834}
835
836/**
Marco Varlese191a5942017-10-30 18:17:21 +0100837 * Convert buffer to INIT-ACK
838 */
839void
Marco Varlese54432f82018-02-15 17:01:56 +0100840sctp_prepare_initack_chunk (sctp_connection_t * sctp_conn, u8 idx,
841 vlib_buffer_t * b, ip4_address_t * ip4_addr,
Marco Varlese216c35b2018-04-17 16:41:51 +0200842 u8 add_ip4, ip6_address_t * ip6_addr, u8 add_ip6)
Marco Varlese191a5942017-10-30 18:17:21 +0100843{
844 vlib_main_t *vm = vlib_get_main ();
845 sctp_ipv4_addr_param_t *ip4_param = 0;
846 sctp_ipv6_addr_param_t *ip6_param = 0;
Marco Varlese191a5942017-10-30 18:17:21 +0100847 u32 random_seed = random_default_seed ();
848
849 sctp_reuse_buffer (vm, b);
850
851 /* The minimum size of the message is given by the sctp_init_ack_chunk_t */
852 u16 alloc_bytes =
853 sizeof (sctp_init_ack_chunk_t) + sizeof (sctp_state_cookie_param_t);
854
Marco Varlese216c35b2018-04-17 16:41:51 +0200855 if (PREDICT_FALSE (add_ip4 == 1))
Marco Varlese191a5942017-10-30 18:17:21 +0100856 {
857 /* Create room for variable-length fields in the INIT_ACK chunk */
858 alloc_bytes += SCTP_IPV4_ADDRESS_TYPE_LENGTH;
859 }
Marco Varlese216c35b2018-04-17 16:41:51 +0200860 if (PREDICT_FALSE (add_ip6 == 1))
Marco Varlese191a5942017-10-30 18:17:21 +0100861 {
862 /* Create room for variable-length fields in the INIT_ACK chunk */
863 alloc_bytes += SCTP_IPV6_ADDRESS_TYPE_LENGTH;
864 }
865
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100866 if (sctp_conn->sub_conn[idx].connection.is_ip4)
Marco Varlese191a5942017-10-30 18:17:21 +0100867 alloc_bytes += sizeof (sctp_ipv4_addr_param_t);
868 else
869 alloc_bytes += sizeof (sctp_ipv6_addr_param_t);
870
871 /* As per RFC 4960 the chunk_length value does NOT contemplate
872 * the size of the first header (see sctp_header_t) and any padding
873 */
874 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
875
876 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
877
878 sctp_init_ack_chunk_t *init_ack_chunk =
879 vlib_buffer_push_uninit (b, alloc_bytes);
880
881 u16 pointer_offset = sizeof (sctp_init_ack_chunk_t);
882
883 /* Create State Cookie parameter */
884 sctp_state_cookie_param_t *state_cookie_param =
885 (sctp_state_cookie_param_t *) ((char *) init_ack_chunk + pointer_offset);
886
887 state_cookie_param->param_hdr.type =
888 clib_host_to_net_u16 (SCTP_STATE_COOKIE_TYPE);
889 state_cookie_param->param_hdr.length =
890 clib_host_to_net_u16 (sizeof (sctp_state_cookie_param_t));
Marco Varlese93826732018-09-27 16:43:57 +0200891 state_cookie_param->creation_time = clib_host_to_net_u64 (sctp_time_now ());
Marco Varlese191a5942017-10-30 18:17:21 +0100892 state_cookie_param->cookie_lifespan =
893 clib_host_to_net_u32 (SCTP_VALID_COOKIE_LIFE);
Marco Varlese91389ac2018-01-31 11:00:01 +0100894
895 sctp_compute_mac (sctp_conn, state_cookie_param);
Marco Varlese191a5942017-10-30 18:17:21 +0100896
897 pointer_offset += sizeof (sctp_state_cookie_param_t);
898
899 if (PREDICT_TRUE (ip4_addr != NULL))
900 {
901 sctp_ipv4_addr_param_t *ipv4_addr =
902 (sctp_ipv4_addr_param_t *) init_ack_chunk + pointer_offset;
903
904 ipv4_addr->param_hdr.type =
905 clib_host_to_net_u16 (SCTP_IPV4_ADDRESS_TYPE);
906 ipv4_addr->param_hdr.length =
907 clib_host_to_net_u16 (SCTP_IPV4_ADDRESS_TYPE_LENGTH);
908 ipv4_addr->address.as_u32 = ip4_addr->as_u32;
909
910 pointer_offset += SCTP_IPV4_ADDRESS_TYPE_LENGTH;
911 }
912 if (PREDICT_TRUE (ip6_addr != NULL))
913 {
914 sctp_ipv6_addr_param_t *ipv6_addr =
Marco Varlesef429a932018-02-06 17:31:06 +0100915 (sctp_ipv6_addr_param_t *) init_ack_chunk + pointer_offset;
Marco Varlese191a5942017-10-30 18:17:21 +0100916
917 ipv6_addr->param_hdr.type =
918 clib_host_to_net_u16 (SCTP_IPV6_ADDRESS_TYPE);
919 ipv6_addr->param_hdr.length =
920 clib_host_to_net_u16 (SCTP_IPV6_ADDRESS_TYPE_LENGTH);
921 ipv6_addr->address.as_u64[0] = ip6_addr->as_u64[0];
922 ipv6_addr->address.as_u64[1] = ip6_addr->as_u64[1];
923
924 pointer_offset += SCTP_IPV6_ADDRESS_TYPE_LENGTH;
925 }
926
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100927 if (sctp_conn->sub_conn[idx].connection.is_ip4)
Marco Varlese191a5942017-10-30 18:17:21 +0100928 {
929 ip4_param = (sctp_ipv4_addr_param_t *) init_ack_chunk + pointer_offset;
930 ip4_param->address.as_u32 =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100931 sctp_conn->sub_conn[idx].connection.lcl_ip.ip4.as_u32;
Marco Varlese191a5942017-10-30 18:17:21 +0100932
933 pointer_offset += sizeof (sctp_ipv4_addr_param_t);
934 }
935 else
936 {
937 ip6_param = (sctp_ipv6_addr_param_t *) init_ack_chunk + pointer_offset;
938 ip6_param->address.as_u64[0] =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100939 sctp_conn->sub_conn[idx].connection.lcl_ip.ip6.as_u64[0];
Marco Varlese191a5942017-10-30 18:17:21 +0100940 ip6_param->address.as_u64[1] =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100941 sctp_conn->sub_conn[idx].connection.lcl_ip.ip6.as_u64[1];
Marco Varlese191a5942017-10-30 18:17:21 +0100942
943 pointer_offset += sizeof (sctp_ipv6_addr_param_t);
944 }
945
946 /* src_port & dst_port are already in network byte-order */
947 init_ack_chunk->sctp_hdr.checksum = 0;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100948 init_ack_chunk->sctp_hdr.src_port =
949 sctp_conn->sub_conn[idx].connection.lcl_port;
950 init_ack_chunk->sctp_hdr.dst_port =
951 sctp_conn->sub_conn[idx].connection.rmt_port;
952 /* the sctp_conn->verification_tag is already in network byte-order (being a copy of the init_tag coming with the INIT chunk) */
953 init_ack_chunk->sctp_hdr.verification_tag = sctp_conn->remote_tag;
954 init_ack_chunk->initial_tsn =
955 clib_host_to_net_u32 (sctp_conn->local_initial_tsn);
956 SCTP_CONN_TRACKING_DBG ("init_ack_chunk->initial_tsn = %u",
957 init_ack_chunk->initial_tsn);
Marco Varlese191a5942017-10-30 18:17:21 +0100958
959 vnet_sctp_set_chunk_type (&init_ack_chunk->chunk_hdr, INIT_ACK);
960 vnet_sctp_set_chunk_length (&init_ack_chunk->chunk_hdr, chunk_len);
961
962 init_ack_chunk->initiate_tag =
963 clib_host_to_net_u32 (random_u32 (&random_seed));
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100964
Marco Varlesef3ab4892018-02-19 15:23:13 +0100965 init_ack_chunk->a_rwnd =
966 clib_host_to_net_u32 (sctp_conn->sub_conn[idx].cwnd);
Marco Varlese191a5942017-10-30 18:17:21 +0100967 init_ack_chunk->inboud_streams_count =
968 clib_host_to_net_u16 (INBOUND_STREAMS_COUNT);
969 init_ack_chunk->outbound_streams_count =
970 clib_host_to_net_u16 (OUTBOUND_STREAMS_COUNT);
971
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100972 sctp_conn->local_tag = init_ack_chunk->initiate_tag;
Marco Varlese191a5942017-10-30 18:17:21 +0100973
974 vnet_buffer (b)->sctp.connection_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +0100975 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +0100976 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese191a5942017-10-30 18:17:21 +0100977}
978
979/**
980 * Convert buffer to SHUTDOWN
981 */
982void
Marco Varlese54432f82018-02-15 17:01:56 +0100983sctp_prepare_shutdown_chunk (sctp_connection_t * sctp_conn, u8 idx,
984 vlib_buffer_t * b)
Marco Varlese191a5942017-10-30 18:17:21 +0100985{
Marco Varlese191a5942017-10-30 18:17:21 +0100986 u16 alloc_bytes = sizeof (sctp_shutdown_association_chunk_t);
987
Marco Varlese191a5942017-10-30 18:17:21 +0100988 /* As per RFC 4960 the chunk_length value does NOT contemplate
989 * the size of the first header (see sctp_header_t) and any padding
990 */
991 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
992
993 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
994
995 sctp_shutdown_association_chunk_t *shutdown_chunk =
996 vlib_buffer_push_uninit (b, alloc_bytes);
997
998 shutdown_chunk->sctp_hdr.checksum = 0;
999 /* No need of host_to_net conversion, already in net-byte order */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001000 shutdown_chunk->sctp_hdr.src_port =
1001 sctp_conn->sub_conn[idx].connection.lcl_port;
1002 shutdown_chunk->sctp_hdr.dst_port =
1003 sctp_conn->sub_conn[idx].connection.rmt_port;
1004 shutdown_chunk->sctp_hdr.verification_tag = sctp_conn->remote_tag;
Marco Varlese191a5942017-10-30 18:17:21 +01001005 vnet_sctp_set_chunk_type (&shutdown_chunk->chunk_hdr, SHUTDOWN);
1006 vnet_sctp_set_chunk_length (&shutdown_chunk->chunk_hdr, chunk_len);
1007
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001008 shutdown_chunk->cumulative_tsn_ack = sctp_conn->last_rcvd_tsn;
Marco Varlese191a5942017-10-30 18:17:21 +01001009
1010 vnet_buffer (b)->sctp.connection_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001011 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +01001012 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese191a5942017-10-30 18:17:21 +01001013}
1014
1015/*
1016 * Send SHUTDOWN
1017 */
1018void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001019sctp_send_shutdown (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +01001020{
1021 vlib_buffer_t *b;
1022 u32 bi;
1023 sctp_main_t *tm = vnet_get_sctp_main ();
1024 vlib_main_t *vm = vlib_get_main ();
1025
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001026 if (sctp_check_outstanding_data_chunks (sctp_conn) > 0)
Marco Varlese191a5942017-10-30 18:17:21 +01001027 return;
1028
1029 if (PREDICT_FALSE (sctp_get_free_buffer_index (tm, &bi)))
1030 return;
1031
Marco Varlesec7fe4f32018-03-05 15:12:29 +01001032 u8 idx = SCTP_PRIMARY_PATH_IDX;
Marco Varlese54432f82018-02-15 17:01:56 +01001033
Marco Varlese191a5942017-10-30 18:17:21 +01001034 b = vlib_get_buffer (vm, bi);
1035 sctp_init_buffer (vm, b);
Marco Varlese54432f82018-02-15 17:01:56 +01001036 sctp_prepare_shutdown_chunk (sctp_conn, idx, b);
Marco Varlese191a5942017-10-30 18:17:21 +01001037
Marco Varlesebe2251b2018-02-07 12:22:41 +01001038 sctp_enqueue_to_output_now (vm, b, bi,
1039 sctp_conn->sub_conn[idx].connection.is_ip4);
Marco Varlese191a5942017-10-30 18:17:21 +01001040}
1041
1042/**
1043 * Convert buffer to SHUTDOWN_ACK
1044 */
1045void
Marco Varlese54432f82018-02-15 17:01:56 +01001046sctp_prepare_shutdown_ack_chunk (sctp_connection_t * sctp_conn, u8 idx,
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001047 vlib_buffer_t * b)
Marco Varlese191a5942017-10-30 18:17:21 +01001048{
Marco Varlese191a5942017-10-30 18:17:21 +01001049 u16 alloc_bytes = sizeof (sctp_shutdown_association_chunk_t);
1050 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
1051
1052 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
1053
1054 sctp_shutdown_ack_chunk_t *shutdown_ack_chunk =
1055 vlib_buffer_push_uninit (b, alloc_bytes);
1056
1057 shutdown_ack_chunk->sctp_hdr.checksum = 0;
1058 /* No need of host_to_net conversion, already in net-byte order */
1059 shutdown_ack_chunk->sctp_hdr.src_port =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001060 sctp_conn->sub_conn[idx].connection.lcl_port;
Marco Varlese191a5942017-10-30 18:17:21 +01001061 shutdown_ack_chunk->sctp_hdr.dst_port =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001062 sctp_conn->sub_conn[idx].connection.rmt_port;
1063 shutdown_ack_chunk->sctp_hdr.verification_tag = sctp_conn->remote_tag;
Marco Varlese191a5942017-10-30 18:17:21 +01001064
1065 vnet_sctp_set_chunk_type (&shutdown_ack_chunk->chunk_hdr, SHUTDOWN_ACK);
1066 vnet_sctp_set_chunk_length (&shutdown_ack_chunk->chunk_hdr, chunk_len);
1067
1068 vnet_buffer (b)->sctp.connection_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001069 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +01001070 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese191a5942017-10-30 18:17:21 +01001071}
1072
1073/*
1074 * Send SHUTDOWN_ACK
1075 */
1076void
Marco Varlese54432f82018-02-15 17:01:56 +01001077sctp_send_shutdown_ack (sctp_connection_t * sctp_conn, u8 idx,
1078 vlib_buffer_t * b)
Marco Varlese191a5942017-10-30 18:17:21 +01001079{
Marco Varlese191a5942017-10-30 18:17:21 +01001080 vlib_main_t *vm = vlib_get_main ();
1081
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001082 if (sctp_check_outstanding_data_chunks (sctp_conn) > 0)
Marco Varlese191a5942017-10-30 18:17:21 +01001083 return;
1084
Marco Varlesebe2251b2018-02-07 12:22:41 +01001085 sctp_reuse_buffer (vm, b);
Marco Varlese191a5942017-10-30 18:17:21 +01001086
Marco Varlese54432f82018-02-15 17:01:56 +01001087 sctp_prepare_shutdown_ack_chunk (sctp_conn, idx, b);
Marco Varlese191a5942017-10-30 18:17:21 +01001088}
1089
1090/**
1091 * Convert buffer to SACK
1092 */
1093void
Marco Varlese54432f82018-02-15 17:01:56 +01001094sctp_prepare_sack_chunk (sctp_connection_t * sctp_conn, u8 idx,
1095 vlib_buffer_t * b)
Marco Varlese191a5942017-10-30 18:17:21 +01001096{
1097 vlib_main_t *vm = vlib_get_main ();
Marco Varlese191a5942017-10-30 18:17:21 +01001098
1099 sctp_reuse_buffer (vm, b);
1100
1101 u16 alloc_bytes = sizeof (sctp_selective_ack_chunk_t);
1102
1103 /* As per RFC 4960 the chunk_length value does NOT contemplate
1104 * the size of the first header (see sctp_header_t) and any padding
1105 */
1106 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
1107
1108 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
1109
1110 sctp_selective_ack_chunk_t *sack = vlib_buffer_push_uninit (b, alloc_bytes);
1111
1112 sack->sctp_hdr.checksum = 0;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001113 sack->sctp_hdr.src_port = sctp_conn->sub_conn[idx].connection.lcl_port;
1114 sack->sctp_hdr.dst_port = sctp_conn->sub_conn[idx].connection.rmt_port;
1115 sack->sctp_hdr.verification_tag = sctp_conn->remote_tag;
Marco Varlese191a5942017-10-30 18:17:21 +01001116 vnet_sctp_set_chunk_type (&sack->chunk_hdr, SACK);
1117 vnet_sctp_set_chunk_length (&sack->chunk_hdr, chunk_len);
1118
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001119 sack->cumulative_tsn_ack = sctp_conn->next_tsn_expected;
1120
1121 sctp_conn->ack_state = 0;
1122
Marco Varlese191a5942017-10-30 18:17:21 +01001123 vnet_buffer (b)->sctp.connection_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001124 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +01001125 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001126}
1127
1128/**
Marco Varlesedf5a99c2018-02-06 13:48:30 +01001129 * Convert buffer to HEARTBEAT_ACK
1130 */
1131void
Marco Varlese54432f82018-02-15 17:01:56 +01001132sctp_prepare_heartbeat_ack_chunk (sctp_connection_t * sctp_conn, u8 idx,
Marco Varlesedf5a99c2018-02-06 13:48:30 +01001133 vlib_buffer_t * b)
1134{
1135 vlib_main_t *vm = vlib_get_main ();
1136
Marco Varlesedf5a99c2018-02-06 13:48:30 +01001137 u16 alloc_bytes = sizeof (sctp_hb_ack_chunk_t);
1138
1139 sctp_reuse_buffer (vm, b);
1140
1141 /* As per RFC 4960 the chunk_length value does NOT contemplate
1142 * the size of the first header (see sctp_header_t) and any padding
1143 */
1144 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
1145
1146 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
1147
1148 sctp_hb_ack_chunk_t *hb_ack = vlib_buffer_push_uninit (b, alloc_bytes);
1149
1150 hb_ack->sctp_hdr.checksum = 0;
1151 /* No need of host_to_net conversion, already in net-byte order */
1152 hb_ack->sctp_hdr.src_port = sctp_conn->sub_conn[idx].connection.lcl_port;
1153 hb_ack->sctp_hdr.dst_port = sctp_conn->sub_conn[idx].connection.rmt_port;
1154 hb_ack->sctp_hdr.verification_tag = sctp_conn->remote_tag;
1155 hb_ack->hb_info.param_hdr.type = clib_host_to_net_u16 (1);
1156 hb_ack->hb_info.param_hdr.length =
1157 clib_host_to_net_u16 (sizeof (hb_ack->hb_info.hb_info));
1158
1159 vnet_sctp_set_chunk_type (&hb_ack->chunk_hdr, HEARTBEAT_ACK);
1160 vnet_sctp_set_chunk_length (&hb_ack->chunk_hdr, chunk_len);
1161
1162 vnet_buffer (b)->sctp.connection_index =
1163 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +01001164 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlesedf5a99c2018-02-06 13:48:30 +01001165}
1166
1167/**
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001168 * Convert buffer to HEARTBEAT
1169 */
1170void
Marco Varlese54432f82018-02-15 17:01:56 +01001171sctp_prepare_heartbeat_chunk (sctp_connection_t * sctp_conn, u8 idx,
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001172 vlib_buffer_t * b)
1173{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001174 u16 alloc_bytes = sizeof (sctp_hb_req_chunk_t);
1175
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001176 /* As per RFC 4960 the chunk_length value does NOT contemplate
1177 * the size of the first header (see sctp_header_t) and any padding
1178 */
1179 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
1180
1181 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
1182
1183 sctp_hb_req_chunk_t *hb_req = vlib_buffer_push_uninit (b, alloc_bytes);
1184
1185 hb_req->sctp_hdr.checksum = 0;
1186 /* No need of host_to_net conversion, already in net-byte order */
1187 hb_req->sctp_hdr.src_port = sctp_conn->sub_conn[idx].connection.lcl_port;
1188 hb_req->sctp_hdr.dst_port = sctp_conn->sub_conn[idx].connection.rmt_port;
1189 hb_req->sctp_hdr.verification_tag = sctp_conn->remote_tag;
1190 hb_req->hb_info.param_hdr.type = clib_host_to_net_u16 (1);
1191 hb_req->hb_info.param_hdr.length =
1192 clib_host_to_net_u16 (sizeof (hb_req->hb_info.hb_info));
1193
1194 vnet_sctp_set_chunk_type (&hb_req->chunk_hdr, HEARTBEAT);
1195 vnet_sctp_set_chunk_length (&hb_req->chunk_hdr, chunk_len);
1196
1197 vnet_buffer (b)->sctp.connection_index =
1198 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +01001199 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001200}
1201
1202void
1203sctp_send_heartbeat (sctp_connection_t * sctp_conn)
1204{
1205 vlib_buffer_t *b;
1206 u32 bi;
1207 sctp_main_t *tm = vnet_get_sctp_main ();
1208 vlib_main_t *vm = vlib_get_main ();
1209
Marco Varlese54432f82018-02-15 17:01:56 +01001210 u8 i;
Marco Varlese93826732018-09-27 16:43:57 +02001211 u64 now = sctp_time_now ();
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001212
Marco Varlese54432f82018-02-15 17:01:56 +01001213 for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
1214 {
1215 if (sctp_conn->sub_conn[i].state == SCTP_SUBCONN_STATE_DOWN)
1216 continue;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001217
Marco Varlese54432f82018-02-15 17:01:56 +01001218 if (now > (sctp_conn->sub_conn[i].last_seen + SCTP_HB_INTERVAL))
1219 {
1220 if (PREDICT_FALSE (sctp_get_free_buffer_index (tm, &bi)))
1221 return;
Marco Varlesedf5a99c2018-02-06 13:48:30 +01001222
Marco Varlese54432f82018-02-15 17:01:56 +01001223 b = vlib_get_buffer (vm, bi);
1224 sctp_init_buffer (vm, b);
1225 sctp_prepare_heartbeat_chunk (sctp_conn, i, b);
1226
1227 sctp_enqueue_to_output_now (vm, b, bi,
1228 sctp_conn->sub_conn[i].
1229 connection.is_ip4);
1230
1231 sctp_conn->sub_conn[i].unacknowledged_hb += 1;
1232 }
1233 }
Marco Varlese191a5942017-10-30 18:17:21 +01001234}
1235
1236/**
1237 * Convert buffer to SHUTDOWN_COMPLETE
1238 */
1239void
Marco Varlese54432f82018-02-15 17:01:56 +01001240sctp_prepare_shutdown_complete_chunk (sctp_connection_t * sctp_conn, u8 idx,
Marco Varlese191a5942017-10-30 18:17:21 +01001241 vlib_buffer_t * b)
1242{
Marco Varlese191a5942017-10-30 18:17:21 +01001243 u16 alloc_bytes = sizeof (sctp_shutdown_association_chunk_t);
1244 alloc_bytes += vnet_sctp_calculate_padding (alloc_bytes);
1245
1246 u16 chunk_len = alloc_bytes - sizeof (sctp_header_t);
1247
1248 sctp_shutdown_complete_chunk_t *shutdown_complete =
1249 vlib_buffer_push_uninit (b, alloc_bytes);
1250
1251 shutdown_complete->sctp_hdr.checksum = 0;
1252 /* No need of host_to_net conversion, already in net-byte order */
1253 shutdown_complete->sctp_hdr.src_port =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001254 sctp_conn->sub_conn[idx].connection.lcl_port;
Marco Varlese191a5942017-10-30 18:17:21 +01001255 shutdown_complete->sctp_hdr.dst_port =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001256 sctp_conn->sub_conn[idx].connection.rmt_port;
1257 shutdown_complete->sctp_hdr.verification_tag = sctp_conn->remote_tag;
Marco Varlese191a5942017-10-30 18:17:21 +01001258
1259 vnet_sctp_set_chunk_type (&shutdown_complete->chunk_hdr, SHUTDOWN_COMPLETE);
1260 vnet_sctp_set_chunk_length (&shutdown_complete->chunk_hdr, chunk_len);
1261
1262 vnet_buffer (b)->sctp.connection_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001263 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese15cc6a82018-02-21 12:39:52 +01001264 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese191a5942017-10-30 18:17:21 +01001265}
1266
1267void
Marco Varlese54432f82018-02-15 17:01:56 +01001268sctp_send_shutdown_complete (sctp_connection_t * sctp_conn, u8 idx,
Marco Varlesefae40392018-02-14 15:38:35 +01001269 vlib_buffer_t * b0)
Marco Varlese191a5942017-10-30 18:17:21 +01001270{
Marco Varlese191a5942017-10-30 18:17:21 +01001271 vlib_main_t *vm = vlib_get_main ();
1272
Marco Varlesefae40392018-02-14 15:38:35 +01001273 if (sctp_check_outstanding_data_chunks (sctp_conn) > 0)
Marco Varlese191a5942017-10-30 18:17:21 +01001274 return;
1275
Marco Varlesefae40392018-02-14 15:38:35 +01001276 sctp_reuse_buffer (vm, b0);
Marco Varlese191a5942017-10-30 18:17:21 +01001277
Marco Varlese54432f82018-02-15 17:01:56 +01001278 sctp_prepare_shutdown_complete_chunk (sctp_conn, idx, b0);
Marco Varlese191a5942017-10-30 18:17:21 +01001279}
1280
Marco Varlese191a5942017-10-30 18:17:21 +01001281/*
1282 * Send INIT
1283 */
1284void
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001285sctp_send_init (sctp_connection_t * sctp_conn)
Marco Varlese191a5942017-10-30 18:17:21 +01001286{
1287 vlib_buffer_t *b;
1288 u32 bi;
1289 sctp_main_t *tm = vnet_get_sctp_main ();
1290 vlib_main_t *vm = vlib_get_main ();
1291
Marco Varlese9e09ff32018-03-05 12:31:45 +01001292 if (PREDICT_FALSE (sctp_conn->init_retransmit_err > SCTP_MAX_INIT_RETRANS))
1293 {
1294 clib_warning ("Reached MAX_INIT_RETRANS times. Aborting connection.");
1295
1296 session_stream_connect_notify (&sctp_conn->sub_conn
Marco Varlesec7fe4f32018-03-05 15:12:29 +01001297 [SCTP_PRIMARY_PATH_IDX].connection, 1);
Marco Varlese9e09ff32018-03-05 12:31:45 +01001298
1299 sctp_connection_timers_reset (sctp_conn);
1300
1301 sctp_connection_cleanup (sctp_conn);
1302
1303 return;
1304 }
1305
Marco Varlese191a5942017-10-30 18:17:21 +01001306 if (PREDICT_FALSE (sctp_get_free_buffer_index (tm, &bi)))
1307 return;
1308
1309 b = vlib_get_buffer (vm, bi);
Marco Varlesec7fe4f32018-03-05 15:12:29 +01001310 u8 idx = SCTP_PRIMARY_PATH_IDX;
Marco Varlese191a5942017-10-30 18:17:21 +01001311
1312 sctp_init_buffer (vm, b);
Marco Varlese54432f82018-02-15 17:01:56 +01001313 sctp_prepare_init_chunk (sctp_conn, idx, b);
Marco Varlese191a5942017-10-30 18:17:21 +01001314
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001315 sctp_push_ip_hdr (tm, &sctp_conn->sub_conn[idx], b);
Marco Varlesee17bb712018-03-28 12:06:10 +02001316 sctp_enqueue_to_ip_lookup (vm, b, bi, sctp_conn->sub_conn[idx].c_is_ip4,
1317 sctp_conn->sub_conn[idx].c_fib_index);
Marco Varlese191a5942017-10-30 18:17:21 +01001318
1319 /* Start the T1_INIT timer */
Marco Varlese21c8baf2018-02-02 17:17:51 +01001320 sctp_timer_set (sctp_conn, idx, SCTP_TIMER_T1_INIT,
1321 sctp_conn->sub_conn[idx].RTO);
1322
Marco Varlese191a5942017-10-30 18:17:21 +01001323 /* Change state to COOKIE_WAIT */
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001324 sctp_conn->state = SCTP_STATE_COOKIE_WAIT;
Marco Varlesea38783e2018-02-13 12:38:52 +01001325
1326 /* Measure RTT with this */
1327 sctp_conn->sub_conn[idx].rtt_ts = sctp_time_now ();
Marco Varlese191a5942017-10-30 18:17:21 +01001328}
1329
Marco Varlese191a5942017-10-30 18:17:21 +01001330/**
1331 * Push SCTP header and update connection variables
1332 */
1333static void
Marco Varlesef3ab4892018-02-19 15:23:13 +01001334sctp_push_hdr_i (sctp_connection_t * sctp_conn, vlib_buffer_t * b,
Marco Varlese191a5942017-10-30 18:17:21 +01001335 sctp_state_t next_state)
1336{
Sirshak dasfb6c7522019-03-06 09:51:02 -05001337 u16 data_len = b->current_length;
1338
1339 if (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
1340 data_len += b->total_length_not_including_first_buffer;
Marco Varlese87971682018-10-04 15:46:05 +02001341
Marco Varlese191a5942017-10-30 18:17:21 +01001342 ASSERT (!b->total_length_not_including_first_buffer
1343 || (b->flags & VLIB_BUFFER_NEXT_PRESENT));
1344
1345 SCTP_ADV_DBG_OUTPUT ("b->current_length = %u, "
1346 "b->current_data = %p "
1347 "data_len = %u",
1348 b->current_length, b->current_data, data_len);
1349
Marco Varlese87971682018-10-04 15:46:05 +02001350 u16 data_padding = vnet_sctp_calculate_padding (b->current_length);
1351 if (data_padding > 0)
1352 {
1353 u8 *p_tail = vlib_buffer_put_uninit (b, data_padding);
1354 clib_memset_u8 (p_tail, 0, data_padding);
1355 }
1356
Marco Varlese191a5942017-10-30 18:17:21 +01001357 u16 bytes_to_add = sizeof (sctp_payload_data_chunk_t);
1358 u16 chunk_length = data_len + bytes_to_add - sizeof (sctp_header_t);
1359
Marco Varlese191a5942017-10-30 18:17:21 +01001360 sctp_payload_data_chunk_t *data_chunk =
1361 vlib_buffer_push_uninit (b, bytes_to_add);
1362
Marco Varlesef3ab4892018-02-19 15:23:13 +01001363 u8 idx = sctp_data_subconn_select (sctp_conn);
Marco Varlese15cc6a82018-02-21 12:39:52 +01001364 SCTP_DBG_OUTPUT
Marco Varlese04e5d642018-02-23 17:43:06 +01001365 ("SCTP_CONN = %p, IDX = %u, S_INDEX = %u, C_INDEX = %u, sctp_conn->[...].LCL_PORT = %u, sctp_conn->[...].RMT_PORT = %u",
Marco Varlese15cc6a82018-02-21 12:39:52 +01001366 sctp_conn, idx, sctp_conn->sub_conn[idx].connection.s_index,
1367 sctp_conn->sub_conn[idx].connection.c_index,
1368 sctp_conn->sub_conn[idx].connection.lcl_port,
1369 sctp_conn->sub_conn[idx].connection.rmt_port);
Marco Varlese191a5942017-10-30 18:17:21 +01001370 data_chunk->sctp_hdr.checksum = 0;
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001371 data_chunk->sctp_hdr.src_port =
1372 sctp_conn->sub_conn[idx].connection.lcl_port;
1373 data_chunk->sctp_hdr.dst_port =
1374 sctp_conn->sub_conn[idx].connection.rmt_port;
1375 data_chunk->sctp_hdr.verification_tag = sctp_conn->remote_tag;
Marco Varlese191a5942017-10-30 18:17:21 +01001376
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001377 data_chunk->tsn = clib_host_to_net_u32 (sctp_conn->next_tsn);
Marco Varlese191a5942017-10-30 18:17:21 +01001378 data_chunk->stream_id = clib_host_to_net_u16 (0);
1379 data_chunk->stream_seq = clib_host_to_net_u16 (0);
1380
1381 vnet_sctp_set_chunk_type (&data_chunk->chunk_hdr, DATA);
1382 vnet_sctp_set_chunk_length (&data_chunk->chunk_hdr, chunk_length);
1383
Marco Varlese91389ac2018-01-31 11:00:01 +01001384 vnet_sctp_set_bbit (&data_chunk->chunk_hdr);
1385 vnet_sctp_set_ebit (&data_chunk->chunk_hdr);
1386
Marco Varlese191a5942017-10-30 18:17:21 +01001387 SCTP_ADV_DBG_OUTPUT ("POINTER_WITH_DATA = %p, DATA_OFFSET = %u",
1388 b->data, b->current_data);
1389
Marco Varlese6e4d4a32018-03-12 12:36:59 +01001390 if (sctp_conn->sub_conn[idx].state != SCTP_SUBCONN_AWAITING_SACK)
1391 {
1392 sctp_conn->sub_conn[idx].state = SCTP_SUBCONN_AWAITING_SACK;
1393 sctp_conn->last_unacked_tsn = sctp_conn->next_tsn;
1394 }
1395
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001396 sctp_conn->next_tsn += data_len;
1397
Marco Varlesef3ab4892018-02-19 15:23:13 +01001398 u32 inflight = sctp_conn->next_tsn - sctp_conn->last_unacked_tsn;
1399 /* Section 7.2.2; point (3) */
1400 if (sctp_conn->sub_conn[idx].partially_acked_bytes >=
1401 sctp_conn->sub_conn[idx].cwnd
1402 && inflight >= sctp_conn->sub_conn[idx].cwnd)
1403 {
1404 sctp_conn->sub_conn[idx].cwnd += sctp_conn->sub_conn[idx].PMTU;
1405 sctp_conn->sub_conn[idx].partially_acked_bytes -=
1406 sctp_conn->sub_conn[idx].cwnd;
1407 }
1408
1409 sctp_conn->sub_conn[idx].last_data_ts = sctp_time_now ();
1410
Marco Varlese191a5942017-10-30 18:17:21 +01001411 vnet_buffer (b)->sctp.connection_index =
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001412 sctp_conn->sub_conn[idx].connection.c_index;
Marco Varlese54432f82018-02-15 17:01:56 +01001413
Marco Varlese15cc6a82018-02-21 12:39:52 +01001414 vnet_buffer (b)->sctp.subconn_idx = idx;
Marco Varlese191a5942017-10-30 18:17:21 +01001415}
1416
1417u32
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001418sctp_push_header (transport_connection_t * trans_conn, vlib_buffer_t * b)
Marco Varlese191a5942017-10-30 18:17:21 +01001419{
Marco Varlese8ad6a2d2018-01-26 16:50:01 +01001420 sctp_connection_t *sctp_conn =
1421 sctp_get_connection_from_transport (trans_conn);
Marco Varlese191a5942017-10-30 18:17:21 +01001422
Marco Varlese15cc6a82018-02-21 12:39:52 +01001423 SCTP_DBG_OUTPUT ("TRANS_CONN = %p, SCTP_CONN = %p, "
1424 "S_INDEX = %u, C_INDEX = %u,"
Marco Varlese04e5d642018-02-23 17:43:06 +01001425 "trans_conn->LCL_PORT = %u, trans_conn->RMT_PORT = %u",
Marco Varlese15cc6a82018-02-21 12:39:52 +01001426 trans_conn,
1427 sctp_conn,
1428 trans_conn->s_index,
1429 trans_conn->c_index,
1430 trans_conn->lcl_port, trans_conn->rmt_port);
1431
Marco Varlesef3ab4892018-02-19 15:23:13 +01001432 sctp_push_hdr_i (sctp_conn, b, SCTP_STATE_ESTABLISHED);
Marco Varlese21c8baf2018-02-02 17:17:51 +01001433
Stevenb95bc052018-02-27 10:29:32 -08001434 sctp_trajectory_add_start (b, 3);
Marco Varlese191a5942017-10-30 18:17:21 +01001435
1436 return 0;
Marco Varlese191a5942017-10-30 18:17:21 +01001437}
1438
Marco Varlese3e9b4652018-03-13 15:44:56 +01001439u32
1440sctp_prepare_data_retransmit (sctp_connection_t * sctp_conn,
1441 u8 idx,
1442 u32 offset,
1443 u32 max_deq_bytes, vlib_buffer_t ** b)
1444{
1445 sctp_main_t *tm = vnet_get_sctp_main ();
1446 vlib_main_t *vm = vlib_get_main ();
1447 int n_bytes = 0;
1448 u32 bi, available_bytes, seg_size;
1449 u8 *data;
1450
1451 ASSERT (sctp_conn->state >= SCTP_STATE_ESTABLISHED);
1452 ASSERT (max_deq_bytes != 0);
1453
1454 /*
1455 * Make sure we can retransmit something
1456 */
1457 available_bytes =
Florin Coras31c99552019-03-01 13:00:58 -08001458 transport_max_tx_dequeue (&sctp_conn->sub_conn[idx].connection);
Marco Varlese3e9b4652018-03-13 15:44:56 +01001459 ASSERT (available_bytes >= offset);
1460 available_bytes -= offset;
1461 if (!available_bytes)
1462 return 0;
1463 max_deq_bytes = clib_min (sctp_conn->sub_conn[idx].cwnd, max_deq_bytes);
1464 max_deq_bytes = clib_min (available_bytes, max_deq_bytes);
1465
1466 seg_size = max_deq_bytes;
1467
1468 /*
1469 * Allocate and fill in buffer(s)
1470 */
1471
1472 if (PREDICT_FALSE (sctp_get_free_buffer_index (tm, &bi)))
1473 return 0;
1474 *b = vlib_get_buffer (vm, bi);
1475 data = sctp_init_buffer (vm, *b);
1476
1477 /* Easy case, buffer size greater than mss */
1478 if (PREDICT_TRUE (seg_size <= tm->bytes_per_buffer))
1479 {
1480 n_bytes =
Florin Coras31c99552019-03-01 13:00:58 -08001481 session_tx_fifo_peek_bytes (&sctp_conn->sub_conn[idx].connection,
1482 data, offset, max_deq_bytes);
Marco Varlese3e9b4652018-03-13 15:44:56 +01001483 ASSERT (n_bytes == max_deq_bytes);
1484 b[0]->current_length = n_bytes;
1485 sctp_push_hdr_i (sctp_conn, *b, sctp_conn->state);
1486 }
1487
1488 return n_bytes;
1489}
1490
Marco Varlese9e09ff32018-03-05 12:31:45 +01001491void
1492sctp_data_retransmit (sctp_connection_t * sctp_conn)
1493{
Marco Varlese3e9b4652018-03-13 15:44:56 +01001494 vlib_main_t *vm = vlib_get_main ();
1495 vlib_buffer_t *b = 0;
1496 u32 bi, n_bytes = 0;
1497
Marco Varlesebaf74052018-09-27 11:58:34 +02001498 u8 idx = sctp_data_subconn_select (sctp_conn);
1499
Marco Varlese9e09ff32018-03-05 12:31:45 +01001500 SCTP_DBG_OUTPUT
1501 ("SCTP_CONN = %p, IDX = %u, S_INDEX = %u, C_INDEX = %u, sctp_conn->[...].LCL_PORT = %u, sctp_conn->[...].RMT_PORT = %u",
1502 sctp_conn, idx, sctp_conn->sub_conn[idx].connection.s_index,
1503 sctp_conn->sub_conn[idx].connection.c_index,
1504 sctp_conn->sub_conn[idx].connection.lcl_port,
1505 sctp_conn->sub_conn[idx].connection.rmt_port);
1506
Marco Varlese3e9b4652018-03-13 15:44:56 +01001507 if (sctp_conn->state >= SCTP_STATE_ESTABLISHED)
1508 {
1509 return;
1510 }
1511
Marco Varlese3e9b4652018-03-13 15:44:56 +01001512 n_bytes =
1513 sctp_prepare_data_retransmit (sctp_conn, idx, 0,
1514 sctp_conn->sub_conn[idx].cwnd, &b);
1515 if (n_bytes > 0)
1516 SCTP_DBG_OUTPUT ("We have data (%u bytes) to retransmit", n_bytes);
1517
1518 bi = vlib_get_buffer_index (vm, b);
1519
1520 sctp_enqueue_to_output_now (vm, b, bi,
1521 sctp_conn->sub_conn[idx].connection.is_ip4);
1522
Marco Varlese9e09ff32018-03-05 12:31:45 +01001523 return;
1524}
1525
Marco Varlesefae40392018-02-14 15:38:35 +01001526#if SCTP_DEBUG_STATE_MACHINE
Marco Varlesea38783e2018-02-13 12:38:52 +01001527always_inline u8
1528sctp_validate_output_state_machine (sctp_connection_t * sctp_conn,
1529 u8 chunk_type)
1530{
1531 u8 result = 0;
1532 switch (sctp_conn->state)
1533 {
1534 case SCTP_STATE_CLOSED:
1535 if (chunk_type != INIT && chunk_type != INIT_ACK)
1536 result = 1;
1537 break;
1538 case SCTP_STATE_ESTABLISHED:
1539 if (chunk_type != DATA && chunk_type != HEARTBEAT &&
1540 chunk_type != HEARTBEAT_ACK && chunk_type != SACK &&
1541 chunk_type != COOKIE_ACK && chunk_type != SHUTDOWN)
1542 result = 1;
1543 break;
1544 case SCTP_STATE_COOKIE_WAIT:
1545 if (chunk_type != COOKIE_ECHO)
1546 result = 1;
1547 break;
1548 case SCTP_STATE_SHUTDOWN_SENT:
1549 if (chunk_type != SHUTDOWN_COMPLETE)
1550 result = 1;
1551 break;
1552 case SCTP_STATE_SHUTDOWN_RECEIVED:
1553 if (chunk_type != SHUTDOWN_ACK)
1554 result = 1;
1555 break;
1556 }
1557 return result;
1558}
Marco Varlesefae40392018-02-14 15:38:35 +01001559#endif
Marco Varlesea38783e2018-02-13 12:38:52 +01001560
Marco Varlese191a5942017-10-30 18:17:21 +01001561/*
1562 * fd.io coding-style-patch-verification: ON
1563 *
1564 * Local Variables:
1565 * eval: (c-set-style "gnu")
1566 * End:
1567 */