blob: 8109efcafc17405fc6f248eee969ef2df7e1ef24 [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#ifndef included_vnet_sctp_packet_h
16#define included_vnet_sctp_packet_h
17
18#include <stdbool.h>
19
20#include <vnet/ip/ip4_packet.h>
21#include <vnet/ip/ip6_packet.h>
22
23/*
24 * As per RFC 4960
25 * https://tools.ietf.org/html/rfc4960
26 */
27
28/*
29 * 0 1 2 3
30 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
31 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 * | Source Port Number | Destination Port Number |
33 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 * | Verification Tag |
35 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 * | Checksum |
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 */
39typedef struct
40{
41 /*
42 * This is the SCTP sender's port number. It can be used by the
43 * receiver in combination with the source IP address, the SCTP
44 * destination port, and possibly the destination IP address to
45 * identify the association to which this packet belongs.
46 * The port number 0 MUST NOT be used.
47 */
48 u16 src_port;
49
50 /*
51 * This is the SCTP port number to which this packet is destined.
52 * The receiving host will use this port number to de-multiplex the
53 * SCTP packet to the correct receiving endpoint/application.
54 * The port number 0 MUST NOT be used.
55 */
56 u16 dst_port;
57
58 /*
59 * The receiver of this packet uses the Verification Tag to validate
60 * the sender of this SCTP packet. On transmit, the value of this
61 * Verification Tag MUST be set to the value of the Initiate Tag
62 * received from the peer endpoint during the association
63 * initialization, with the following exceptions:
64 * - A packet containing an INIT chunk MUST have a zero Verification
65 * Tag.
66 * - A packet containing a SHUTDOWN COMPLETE chunk with the T bit
67 * set MUST have the Verification Tag copied from the packet with
68 * the SHUTDOWN ACK chunk.
69 * - A packet containing an ABORT chunk may have the verification tag
70 * copied from the packet that caused the ABORT to be sent.
71 * An INIT chunk MUST be the only chunk in the SCTP packet carrying it.
72 */
73 u32 verification_tag;
74
75 /*
76 * This field contains the checksum of this SCTP packet.
77 * SCTP uses the CRC32c algorithm.
78 */
79 u32 checksum;
80
81} sctp_header_t;
82
83always_inline void
84vnet_set_sctp_src_port (sctp_header_t * h, u16 src_port)
85{
86 h->src_port = clib_host_to_net_u16 (src_port);
87}
88
89always_inline u16
90vnet_get_sctp_src_port (sctp_header_t * h)
91{
92 return (clib_net_to_host_u16 (h->src_port));
93}
94
95always_inline void
96vnet_set_sctp_dst_port (sctp_header_t * h, u16 dst_port)
97{
98 h->dst_port = clib_host_to_net_u16 (dst_port);
99}
100
101always_inline u16
102vnet_get_sctp_dst_port (sctp_header_t * h)
103{
104 return (clib_net_to_host_u16 (h->dst_port));
105}
106
107always_inline void
108vnet_set_sctp_verification_tag (sctp_header_t * h, u32 verification_tag)
109{
110 h->verification_tag = clib_host_to_net_u32 (verification_tag);
111}
112
113always_inline u32
114vnet_get_sctp_verification_tag (sctp_header_t * h)
115{
116 return (clib_net_to_host_u32 (h->verification_tag));
117}
118
119always_inline void
120vnet_set_sctp_checksum (sctp_header_t * h, u32 checksum)
121{
122 h->checksum = clib_host_to_net_u32 (checksum);
123}
124
125always_inline u32
126vnet_get_sctp_checksum (sctp_header_t * h)
127{
128 return (clib_net_to_host_u32 (h->checksum));
129}
130
131/*
132 * Multiple chunks can be bundled into one SCTP packet up to the MTU
133 * size, except for the INIT, INIT ACK, and SHUTDOWN COMPLETE chunks.
134 * These chunks MUST NOT be bundled with any other chunk in a packet.
135 *
136 *
137 * 0 1 2 3
138 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
139 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
140 * | Common Header |
141 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
142 * | Chunk #1 |
143 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144 * | ... |
145 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
146 * | Chunk #n |
147 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
148 */
149
150typedef enum
151{
152 DATA = 0,
153 INIT,
154 INIT_ACK,
155 SACK,
156 HEARTBEAT,
157 HEARTBEAT_ACK,
158 ABORT,
159 SHUTDOWN,
160 SHUTDOWN_ACK,
161 OPERATION_ERROR,
162 COOKIE_ECHO,
163 COOKIE_ACK,
164 ECNE,
165 CWR,
Marco Varlesefae40392018-02-14 15:38:35 +0100166 SHUTDOWN_COMPLETE,
167 UNKNOWN
Marco Varlese191a5942017-10-30 18:17:21 +0100168} sctp_chunk_type;
169
170/*
171 * 0 1 2 3
172 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
173 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174 * | Chunk Type | Chunk Flags | Chunk Length |
175 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176 */
177typedef struct
178{
179 /*
180 * This field identifies the type of information contained in the
181 * Chunk Value field. It takes a value from 0 to 254.
182 * The value of 255 is reserved for future use as an extension field.
183 *
184 * The values of Chunk Types are defined as follows:
185 * ID Value Chunk Type
186 * ----- ----------
187 * 0 - Payload Data (DATA)
188 * 1 - Initiation (INIT)
189 * 2 - Initiation Acknowledgement (INIT ACK)
190 * 3 - Selective Acknowledgement (SACK)
191 * 4 - Heartbeat Request (HEARTBEAT)
192 * 5 - Heartbeat Acknowledgement (HEARTBEAT ACK)
193 * 6 - Abort (ABORT)
194 * 7 - Shutdown (SHUTDOWN)
195 * 8 - Shutdown Acknowledgement (SHUTDOWN ACK)
196 * 9 - Operation Error (ERROR)
197 * 10 - State Cookie (COOKIE ECHO)
198 * 11 - Cookie Acknowledgement (COOKIE ACK)
199 * 12 - Reserved for Explicit Congestion Notification Echo (ECNE)
200 * 13 - Reserved for Congestion Window Reduced (CWR)
201 * 14 - Shutdown Complete (SHUTDOWN COMPLETE)
202 * 15 to 62 - available
203 * 63 - reserved for IETF-defined Chunk Extensions
204 * 64 to 126 - available
205 * 127 - reserved for IETF-defined Chunk Extensions
206 * 128 to 190 - available
207 * 191 - reserved for IETF-defined Chunk Extensions
208 * 192 to 254 - available
209 * 255 - reserved for IETF-defined Chunk Extensions
210 *
211 * Chunk Types are encoded such that the highest-order 2 bits specify
212 * the action that must be taken if the processing endpoint does not
213 * recognize the Chunk Type.
214 * 00 - Stop processing this SCTP packet and discard it, do not
215 * process any further chunks within it.
216 * 01 - Stop processing this SCTP packet and discard it, do not
217 * process any further chunks within it, and report the
218 * unrecognized chunk in an 'Unrecognized Chunk Type'.
219 * 10 - Skip this chunk and continue processing.
220 * 11 - Skip this chunk and continue processing, but report in an
221 * ERROR chunk using the 'Unrecognized Chunk Type' cause of error.
222 *
223 * Note: The ECNE and CWR chunk types are reserved for future use of
224 * Explicit Congestion Notification (ECN);
225 */
226 //u8 type;
227
228 /*
229 * The usage of these bits depends on the Chunk type as given by the
230 * Chunk Type field. Unless otherwise specified, they are set to 0 on
231 * transmit and are ignored on receipt.
232 */
233 //u8 flags;
234
235 /*
236 * This value represents the size of the chunk in bytes, including
237 * the Chunk Type, Chunk Flags, Chunk Length, and Chunk Value fields.
238 * Therefore, if the Chunk Value field is zero-length, the Length
239 * field will be set to 4.
240 * The Chunk Length field does not count any chunk padding.
241 * Chunks (including Type, Length, and Value fields) are padded out
242 * by the sender with all zero bytes to be a multiple of 4 bytes
243 * long. This padding MUST NOT be more than 3 bytes in total. The
244 * Chunk Length value does not include terminating padding of the
245 * chunk. However, it does include padding of any variable-length
246 * parameter except the last parameter in the chunk. The receiver
247 * MUST ignore the padding.
248 *
249 * Note: A robust implementation should accept the chunk whether or
250 * not the final padding has been included in the Chunk Length.
251 */
252 //u16 length;
253
254 u32 params;
255
256} sctp_chunks_common_hdr_t;
257
258typedef struct
259{
260 sctp_header_t hdr;
261 sctp_chunks_common_hdr_t common_hdr;
262
263} sctp_full_hdr_t;
264
265#define CHUNK_TYPE_MASK 0xFF000000
266#define CHUNK_TYPE_SHIFT 24
267
268#define CHUNK_FLAGS_MASK 0x00FF0000
269#define CHUNK_FLAGS_SHIFT 16
270
Marco Varlese54432f82018-02-15 17:01:56 +0100271#define CHUNK_UBIT_MASK 0x00040000
Marco Varlese91389ac2018-01-31 11:00:01 +0100272#define CHUNK_UBIT_SHIFT 18
273
Marco Varlese54432f82018-02-15 17:01:56 +0100274#define CHUNK_BBIT_MASK 0x00020000
Marco Varlese91389ac2018-01-31 11:00:01 +0100275#define CHUNK_BBIT_SHIFT 17
276
Marco Varlese54432f82018-02-15 17:01:56 +0100277#define CHUNK_EBIT_MASK 0x00010000
Marco Varlese91389ac2018-01-31 11:00:01 +0100278#define CHUNK_EBIT_SHIFT 16
279
Marco Varlese191a5942017-10-30 18:17:21 +0100280#define CHUNK_LENGTH_MASK 0x0000FFFF
281#define CHUNK_LENGTH_SHIFT 0
282
283always_inline void
284vnet_sctp_common_hdr_params_host_to_net (sctp_chunks_common_hdr_t * h)
285{
286 h->params = clib_host_to_net_u32 (h->params);
287}
288
289always_inline void
290vnet_sctp_common_hdr_params_net_to_host (sctp_chunks_common_hdr_t * h)
291{
292 h->params = clib_net_to_host_u32 (h->params);
293}
294
295always_inline void
Marco Varlese91389ac2018-01-31 11:00:01 +0100296vnet_sctp_set_ubit (sctp_chunks_common_hdr_t * h)
297{
298 h->params &= ~(CHUNK_UBIT_MASK);
299 h->params |= (1 << CHUNK_UBIT_SHIFT) & CHUNK_UBIT_MASK;
300}
301
302always_inline u8
303vnet_sctp_get_ubit (sctp_chunks_common_hdr_t * h)
304{
305 return ((h->params & CHUNK_UBIT_MASK) >> CHUNK_UBIT_SHIFT);
306}
307
308always_inline void
309vnet_sctp_set_bbit (sctp_chunks_common_hdr_t * h)
310{
311 h->params &= ~(CHUNK_BBIT_MASK);
312 h->params |= (1 << CHUNK_BBIT_SHIFT) & CHUNK_BBIT_MASK;
313}
314
315always_inline u8
316vnet_sctp_get_bbit (sctp_chunks_common_hdr_t * h)
317{
318 return ((h->params & CHUNK_BBIT_MASK) >> CHUNK_BBIT_SHIFT);
319}
320
321always_inline void
322vnet_sctp_set_ebit (sctp_chunks_common_hdr_t * h)
323{
324 h->params &= ~(CHUNK_EBIT_MASK);
325 h->params |= (1 << CHUNK_EBIT_SHIFT) & CHUNK_EBIT_MASK;
326}
327
328always_inline u8
329vnet_sctp_get_ebit (sctp_chunks_common_hdr_t * h)
330{
331 return ((h->params & CHUNK_EBIT_MASK) >> CHUNK_EBIT_SHIFT);
332}
333
334always_inline void
Marco Varlese191a5942017-10-30 18:17:21 +0100335vnet_sctp_set_chunk_type (sctp_chunks_common_hdr_t * h, sctp_chunk_type t)
336{
337 h->params &= ~(CHUNK_TYPE_MASK);
338 h->params |= (t << CHUNK_TYPE_SHIFT) & CHUNK_TYPE_MASK;
339}
340
341always_inline u8
342vnet_sctp_get_chunk_type (sctp_chunks_common_hdr_t * h)
343{
344 return ((h->params & CHUNK_TYPE_MASK) >> CHUNK_TYPE_SHIFT);
345}
346
347always_inline void
348vnet_sctp_set_chunk_length (sctp_chunks_common_hdr_t * h, u16 length)
349{
350 h->params &= ~(CHUNK_LENGTH_MASK);
351 h->params |= (length << CHUNK_LENGTH_SHIFT) & CHUNK_LENGTH_MASK;
352}
353
354always_inline u16
355vnet_sctp_get_chunk_length (sctp_chunks_common_hdr_t * h)
356{
357 return ((h->params & CHUNK_LENGTH_MASK) >> CHUNK_LENGTH_SHIFT);
358}
359
360/*
361 * Payload chunk
362 *
363 * 0 1 2 3
364 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
365 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366 * | Type = 0 | Reserved|U|B|E| Length |
367 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368 * | TSN |
369 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370 * | Stream Identifier S | Stream Sequence Number n |
371 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372 * | Payload Protocol Identifier |
373 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374 * \ \
375 * / User Data (seq n of Stream S) /
376 * \ \
377 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
378 */
379typedef struct
380{
381 sctp_header_t sctp_hdr;
382 /*
383 * Type (8 bits): 0
384 * Flags (8 bits):
385 * -- Reserved (5 bits): all 0s
386 * -- U bit
387 * -- B bit
388 * -- E bit
389 * Length (16 bits): This field indicates the length of the DATA chunk in
390 * bytes from the beginning of the type field to the end of the User Data
391 * field excluding any padding.
392 * A DATA chunk with one byte of user data will have Length set to 17
393 * (indicating 17 bytes). A DATA chunk with a User Data field of length L
394 * will have the Length field set to (16 + L) (indicating 16+L bytes) where
395 * L MUST be greater than 0.
396 */
397
398 /*
399 * Fragment Description Table:
400 *
401 * B E Description
402 * ============================================================
403 * | 1 0 | First piece of a fragmented user message |
404 * +----------------------------------------------------------+
405 * | 0 0 | Middle piece of a fragmented user message |
406 * +----------------------------------------------------------+
407 * | 0 1 | Last piece of a fragmented user message |
408 * +----------------------------------------------------------+
409 * | 1 1 | Unfragmented message |
410 * ============================================================
411 */
412 sctp_chunks_common_hdr_t chunk_hdr;
413
414 /*
415 * This value represents the TSN for this DATA chunk.
416 * The valid range of TSN is from 0 to 4294967295 (2**32 - 1).
417 * TSN wraps back to 0 after reaching 4294967295.
418 */
419 u32 tsn;
420
421 /*
422 * Identifies the stream to which the following user data belongs.
423 */
424 u16 stream_id;
425
426 /*
427 * This value represents the Stream Sequence Number of the following user data
428 * within the stream S. Valid range is 0 to 65535.
429 * When a user message is fragmented by SCTP for transport, the same Stream
430 * Sequence Number MUST be carried in each of the fragments of the message.
431 */
432 u16 stream_seq;
433
434 /*
435 * This value represents an application (or upper layer) specified protocol
436 * identifier. This value is passed to SCTP by its upper layer and sent to its
437 * peer. This identifier is not used by SCTP but can be used by certain network
438 * entities, as well as by the peer application, to identify the type of
439 * information being carried in this DATA chunk. This field must be sent even
440 * in fragmented DATA chunks (to make sure it is available for agents in the
441 * middle of the network). Note that this field is NOT touched by an SCTP
442 * implementation; therefore, its byte order is NOT necessarily big endian.
443 * The upper layer is responsible for any byte order conversions to this field.
444 * The value 0 indicates that no application identifier is specified by the
445 * upper layer for this payload data.
446 */
447 u32 payload_id;
448
449 /*
450 * This is the payload user data. The implementation MUST pad the end of the
451 * data to a 4-byte boundary with all-zero bytes. Any padding MUST NOT be
452 * included in the Length field. A sender MUST never add more than 3 bytes of
453 * padding.
454 */
455 u32 data[];
456
457} sctp_payload_data_chunk_t;
458
459always_inline void
Marco Varlese191a5942017-10-30 18:17:21 +0100460vnet_sctp_set_tsn (sctp_payload_data_chunk_t * p, u32 tsn)
461{
462 p->tsn = clib_host_to_net_u32 (tsn);
463}
464
465always_inline u32
466vnet_sctp_get_tsn (sctp_payload_data_chunk_t * p)
467{
468 return (clib_net_to_host_u32 (p->tsn));
469}
470
471always_inline void
472vnet_sctp_set_stream_id (sctp_payload_data_chunk_t * p, u16 stream_id)
473{
474 p->stream_id = clib_host_to_net_u16 (stream_id);
475}
476
477always_inline u16
478vnet_sctp_get_stream_id (sctp_payload_data_chunk_t * p)
479{
480 return (clib_net_to_host_u16 (p->stream_id));
481}
482
483always_inline void
484vnet_sctp_set_stream_seq (sctp_payload_data_chunk_t * p, u16 stream_seq)
485{
486 p->stream_seq = clib_host_to_net_u16 (stream_seq);
487}
488
489always_inline u16
490vnet_sctp_get_stream_seq (sctp_payload_data_chunk_t * p)
491{
492 return (clib_net_to_host_u16 (p->stream_seq));
493}
494
495always_inline void
496vnet_sctp_set_payload_id (sctp_payload_data_chunk_t * p, u32 payload_id)
497{
498 p->payload_id = clib_host_to_net_u32 (payload_id);
499}
500
501always_inline u32
502vnet_sctp_get_payload_id (sctp_payload_data_chunk_t * p)
503{
504 return (clib_net_to_host_u32 (p->payload_id));
505}
506
507always_inline u16
508vnet_sctp_calculate_padding (u16 base_length)
509{
510 if (base_length % 4 == 0)
511 return 0;
512
513 return (4 - base_length % 4);
514}
515
Marco Varlese191a5942017-10-30 18:17:21 +0100516#define INBOUND_STREAMS_COUNT 1
517#define OUTBOUND_STREAMS_COUNT 1
518
519/*
520 * INIT chunk
521 *
522 * This chunk is used to initiate an SCTP association between two
523 * endpoints.
524 *
525 * 0 1 2 3
526 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
527 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
528 * | Type = 1 | Chunk Flags | Chunk Length |
529 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
530 * | Initiate Tag |
531 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
532 * | Advertised Receiver Window Credit (a_rwnd) |
533 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
534 * | Number of Outbound Streams | Number of Inbound Streams |
535 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
536 * | Initial TSN |
537 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538 * \ \
539 * / Optional/Variable-Length Parameters /
540 * \ \
541 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
542 *
543 * The INIT chunk contains the following parameters. Unless otherwise
544 * noted, each parameter MUST only be included once in the INIT chunk.
545 *
546 * Fixed Parameters Status
547 * ----------------------------------------------
548 * Initiate Tag Mandatory
549 * Advertised Receiver Window Credit Mandatory
550 * Number of Outbound Streams Mandatory
551 * Number of Inbound Streams Mandatory
552 * Initial TSN Mandatory
553 *
554 * Variable Parameters Status Type Value
555 * -------------------------------------------------------------
556 * IPv4 Address (Note 1) Optional 5
557 * IPv6 Address (Note 1) Optional 6
558 * Cookie Preservative Optional 9
559 * Reserved for ECN Capable (Note 2) Optional 32768 (0x8000)
560 * Host Name Address (Note 3) Optional 11
561 * Supported Address Types (Note 4) Optional 12
562 *
563 * Note 1: The INIT chunks can contain multiple addresses that can be
564 * IPv4 and/or IPv6 in any combination.
565 *
566 * Note 2: The ECN Capable field is reserved for future use of Explicit
567 * Congestion Notification.
568 *
569 * Note 3: An INIT chunk MUST NOT contain more than one Host Name Address
570 * parameter. Moreover, the sender of the INIT MUST NOT combine any other
571 * address types with the Host Name Address in the INIT. The receiver of
572 * INIT MUST ignore any other address types if the Host Name Address parameter
573 * is present in the received INIT chunk.
574 *
575 * Note 4: This parameter, when present, specifies all the address types the
576 * sending endpoint can support. The absence of this parameter indicates that
577 * the sending endpoint can support any address type.
578 *
579 * IMPLEMENTATION NOTE: If an INIT chunk is received with known parameters that
580 * are not optional parameters of the INIT chunk, then the receiver SHOULD
581 * process the INIT chunk and send back an INIT ACK. The receiver of the INIT
582 * chunk MAY bundle an ERROR chunk with the COOKIE ACK chunk later.
583 * However, restrictive implementations MAY send back an ABORT chunk in response
584 * to the INIT chunk. The Chunk Flags field in INIT is reserved, and all bits
585 * in it should be set to 0 by the sender and ignored by the receiver.
586 * The sequence of parameters within an INIT can be processed in any order.
587 */
588typedef struct
589{
590 sctp_header_t sctp_hdr;
591 sctp_chunks_common_hdr_t chunk_hdr;
592
593 /*
594 * The receiver of the INIT (the responding end) records the value of
595 * the Initiate Tag parameter.
596 * This value MUST be placed into the Verification Tag field of every
597 * SCTP packet that the receiver of the INIT transmits within this association.
598 * The Initiate Tag is allowed to have any value except 0.
599 *
600 * If the value of the Initiate Tag in a received INIT chunk is found
601 * to be 0, the receiver MUST treat it as an error and close the
602 * association by transmitting an ABORT.
603 *
604 * The value of the INIT TAG is recommended to be random for security
605 * reasons. A good method is described in https://tools.ietf.org/html/rfc4086
606 */
607 u32 initiate_tag;
608
609 /*
610 * This value represents the dedicated buffer space, in number of bytes,
611 * the sender of the INIT has reserved in association with this window.
612 * During the life of the association, this buffer space SHOULD NOT be
613 * lessened (i.e., dedicated buffers taken away from this association);
614 * however, an endpoint MAY change the value of a_rwnd it sends in SACK
615 * chunks.
616 */
617 u32 a_rwnd;
618
619 /*
620 * Defines the number of outbound streams the sender of this INIT chunk
621 * wishes to create in this association.
622 * The value of 0 MUST NOT be used.
623 *
624 * Note: A receiver of an INIT with the OS value set to 0 SHOULD abort
625 * the association.
626 */
627 u16 outbound_streams_count;
628
629 /*
630 * Defines the maximum number of streams the sender of this INIT
631 * chunk allows the peer end to create in this association.
632 * The value 0 MUST NOT be used.
633 *
634 * Note: There is no negotiation of the actual number of streams but
635 * instead the two endpoints will use the min(requested, offered).
636 *
637 * Note: A receiver of an INIT with the MIS value of 0 SHOULD abort
638 * the association.
639 */
640 u16 inboud_streams_count;
641
642 /*
643 * Defines the initial TSN that the sender will use.
644 * The valid range is from 0 to 4294967295.
645 * This field MAY be set to the value of the Initiate Tag field.
646 */
647 u32 initial_tsn;
648
649 /* The following field allows to have multiple optional fields which are:
650 * - sctp_ipv4_address
651 * - sctp_ipv6_address
652 * - sctp_cookie_preservative
653 * - sctp_hostname_address
654 * - sctp_supported_address_types
655 */
656 u32 optional_fields[];
657
658} sctp_init_chunk_t;
659
660/*
661 * INIT ACK chunk
662 *
663 * The INIT ACK chunk is used to acknowledge the initiation of an SCTP
664 * association. The parameter part of INIT ACK is formatted similarly to the
665 * INIT chunk.
666 *
667 * It uses two extra variable parameters:
668 * - the State Cookie and
669 * - the Unrecognized Parameter:
670 */
671/*
672 * 0 1 2 3
673 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
674 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
675 * | Type = 2 | Chunk Flags | Chunk Length |
676 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
677 * | Initiate Tag |
678 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
679 * | Advertised Receiver Window Credit |
680 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
681 * | Number of Outbound Streams | Number of Inbound Streams |
682 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
683 * | Initial TSN |
684 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
685 * \ \
686 * / Optional/Variable-Length Parameters /
687 * \ \
688 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
689 */
690typedef sctp_init_chunk_t sctp_init_ack_chunk_t;
691
Marco Varlese91389ac2018-01-31 11:00:01 +0100692typedef struct
693{
694 u16 type;
695 u16 length;
696
697} sctp_opt_params_hdr_t;
698
699#define SHA1_OUTPUT_LENGTH 20
Marco Varlese191a5942017-10-30 18:17:21 +0100700/*
701 * 0 1 2 3
702 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
703 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
704 * | Parameter Type | Parameter Length |
705 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
706 * \ \
707 * / Parameter Value /
708 * \ \
709 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
710 */
711typedef struct
712{
Marco Varlese191a5942017-10-30 18:17:21 +0100713 sctp_opt_params_hdr_t param_hdr;
714
Marco Varlese91389ac2018-01-31 11:00:01 +0100715 unsigned char mac[SHA1_OUTPUT_LENGTH]; /* RFC 2104 */
Marco Varlese191a5942017-10-30 18:17:21 +0100716 u32 creation_time;
717 u32 cookie_lifespan;
718
719} sctp_state_cookie_param_t;
720
721/*
722 * This chunk is used only during the initialization of an association.
723 * It is sent by the initiator of an association to its peer to complete
724 * the initialization process. This chunk MUST precede any DATA chunk
725 * sent within the association, but MAY be bundled with one or more DATA
726 * chunks in the same packet.
727 *
728 * 0 1 2 3
729 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
730 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
731 * | Type = 10 |Chunk Flags | Length |
732 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
733 * / Cookie /
734 * \ \
735 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
736 */
737typedef struct
738{
739 sctp_header_t sctp_hdr;
740 sctp_chunks_common_hdr_t chunk_hdr;
741
742 sctp_state_cookie_param_t cookie;
743
744} sctp_cookie_echo_chunk_t;
745
746
747/*
748 * 0 1 2 3
749 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
750 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
751 * | Type = 11 |Chunk Flags | Length = 4 |
752 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
753 */
754typedef struct
755{
756 sctp_header_t sctp_hdr;
757 sctp_chunks_common_hdr_t chunk_hdr;
758
759} sctp_cookie_ack_chunk_t;
760
761/*
762 * 0 1 2 3
763 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
764 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
765 * | Type = 14 |Chunk Flags | Length = 4 |
766 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
767 */
768typedef struct
769{
770 sctp_header_t sctp_hdr;
771 sctp_chunks_common_hdr_t chunk_hdr;
772
773} sctp_shutdown_complete_chunk_t;
774
775/* OPTIONAL or VARIABLE-LENGTH parameters for INIT */
776#define SCTP_IPV4_ADDRESS_TYPE 5
777#define SCTP_IPV4_ADDRESS_TYPE_LENGTH 8
778#define SCTP_IPV6_ADDRESS_TYPE 6
779#define SCTP_IPV6_ADDRESS_TYPE_LENGTH 20
780#define SCTP_STATE_COOKIE_TYPE 7
781#define SCTP_UNRECOGNIZED_TYPE 8
782#define SCTP_COOKIE_PRESERVATIVE_TYPE 9
783#define SCTP_COOKIE_PRESERVATIVE_TYPE_LENGTH 8
784#define SCTP_HOSTNAME_ADDRESS_TYPE 11
785#define SCTP_SUPPORTED_ADDRESS_TYPES 12
786
787/*
788 * 0 1 2 3
789 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
790 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
791 * | Type = 5 | Length = 8 |
792 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
793 * | IPv4 Address |
794 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
795 */
796typedef struct
797{
798 sctp_opt_params_hdr_t param_hdr;
799
800 /*
801 * Contains an IPv4 address of the sending endpoint.
802 * It is binary encoded.
803 */
804 ip4_address_t address;
805
806} sctp_ipv4_addr_param_t;
807
808always_inline void
809vnet_sctp_set_ipv4_address (sctp_ipv4_addr_param_t * a, ip4_address_t address)
810{
811 a->param_hdr.type = clib_host_to_net_u16 (SCTP_IPV4_ADDRESS_TYPE);
812 a->param_hdr.length = clib_host_to_net_u16 (8);
813 a->address.as_u32 = clib_host_to_net_u32 (address.as_u32);
814}
815
816always_inline u32
817vnet_sctp_get_ipv4_address (sctp_ipv4_addr_param_t * a)
818{
819 return (clib_net_to_host_u32 (a->address.as_u32));
820}
821
822/*
823 * 0 1 2 3
824 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
825 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
826 * | Type = 6 | Length = 20 |
827 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
828 * | |
829 * | IPv6 Address |
830 * | |
831 * | |
832 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
833 */
834typedef struct
835{
836 sctp_opt_params_hdr_t param_hdr;
837
838 /*
839 * Contains an IPv6 address of the sending endpoint.
840 * It is binary encoded.
841 */
842 ip6_address_t address;
843
844} sctp_ipv6_addr_param_t;
845
846always_inline void
847vnet_sctp_set_ipv6_address (sctp_ipv6_addr_param_t * a, ip6_address_t address)
848{
849 a->param_hdr.type = clib_host_to_net_u16 (SCTP_IPV6_ADDRESS_TYPE);
850 a->param_hdr.length = clib_host_to_net_u16 (20);
851 a->address.as_u64[0] = clib_host_to_net_u64 (address.as_u64[0]);
852 a->address.as_u64[1] = clib_host_to_net_u64 (address.as_u64[1]);
853}
854
855always_inline ip6_address_t
856vnet_sctp_get_ipv6_address (sctp_ipv6_addr_param_t * a)
857{
858 ip6_address_t ip6_address;
859
860 ip6_address.as_u64[0] = clib_net_to_host_u64 (a->address.as_u64[0]);
861 ip6_address.as_u64[1] = clib_net_to_host_u64 (a->address.as_u64[1]);
862
863 return ip6_address;
864}
865
866/*
867 * The sender of the INIT shall use this parameter to suggest to the
868 * receiver of the INIT for a longer life-span of the State Cookie.
869 */
870/*
871 * 0 1 2 3
872 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
873 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
874 * | Type = 9 | Length = 8 |
875 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
876 * | Suggested Cookie Life-Span Increment (msec.) |
877 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
878 */
879typedef struct
880{
881 sctp_opt_params_hdr_t param_hdr;
882
883 /*
884 * This parameter indicates to the receiver how much increment in
885 * milliseconds the sender wishes the receiver to add to its default
886 * cookie life-span.
887 *
888 * This optional parameter should be added to the INIT chunk by the
889 * sender when it reattempts establishing an association with a peer
890 * to which its previous attempt of establishing the association
891 * failed due to a stale cookie operation error. The receiver MAY
892 * choose to ignore the suggested cookie life-span increase for its
893 * own security reasons.
894 */
895 u32 life_span_inc;
896
897} sctp_cookie_preservative_param_t;
898
899always_inline void
900vnet_sctp_set_cookie_preservative (sctp_cookie_preservative_param_t * c,
901 u32 life_span_inc)
902{
903 c->param_hdr.type = clib_host_to_net_u16 (SCTP_COOKIE_PRESERVATIVE_TYPE);
904 c->param_hdr.length = clib_host_to_net_u16 (8);
905 c->life_span_inc = clib_host_to_net_u32 (life_span_inc);
906}
907
908always_inline u32
909vnet_sctp_get_cookie_preservative (sctp_cookie_preservative_param_t * c)
910{
911 return (clib_net_to_host_u32 (c->life_span_inc));
912}
913
914#define FQDN_MAX_LENGTH 256
915
916/*
917 * The sender of INIT uses this parameter to pass its Host Name (in
918 * place of its IP addresses) to its peer.
919 * The peer is responsible for resolving the name.
920 * Using this parameter might make it more likely for the association to work
921 * across a NAT box.
922 */
923/*
924 * 0 1 2 3
925 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
926 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
927 * | Type = 11 | Length |
928 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
929 * / Host Name /
930 * \ \
931 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
932 */
933typedef struct
934{
935 sctp_opt_params_hdr_t param_hdr;
936
937
938 /*
939 * This field contains a host name in "host name syntax" per RFC 1123
940 * Section 2.1
941 *
942 * Note: At least one null terminator is included in the Host Name
943 * string and must be included in the length.
944 */
945 char hostname[FQDN_MAX_LENGTH];
946
947} sctp_hostname_param_t;
948
949always_inline void
950vnet_sctp_set_hostname_address (sctp_hostname_param_t * h, char *hostname)
951{
952 h->param_hdr.length = FQDN_MAX_LENGTH;
953 h->param_hdr.type = clib_host_to_net_u16 (SCTP_HOSTNAME_ADDRESS_TYPE);
954 memset (h->hostname, '0', FQDN_MAX_LENGTH);
955 memcpy (h->hostname, hostname, FQDN_MAX_LENGTH);
956}
957
958#define MAX_SUPPORTED_ADDRESS_TYPES 3
959
960/*
961 * The sender of INIT uses this parameter to list all the address types
962 * it can support.
963 */
964/*
965 * 0 1 2 3
966 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
967 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
968 * | Type = 12 | Length |
969 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
970 * | Address Type #1 | Address Type #2 |
971 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
972 * | ...... |
973 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+
974 */
975typedef struct
976{
977 sctp_opt_params_hdr_t param_hdr;
978
979 u16 address_type[MAX_SUPPORTED_ADDRESS_TYPES];
980
981} sctp_supported_addr_types_param_t;
982
983always_inline void
984vnet_sctp_set_supported_address_types (sctp_supported_addr_types_param_t * s)
985{
986 s->param_hdr.type = clib_host_to_net_u16 (SCTP_SUPPORTED_ADDRESS_TYPES);
987 s->param_hdr.length = 4 /* base = type + length */ +
988 MAX_SUPPORTED_ADDRESS_TYPES * 4; /* each address type is 4 bytes */
989
990 s->address_type[0] = clib_host_to_net_u16 (SCTP_IPV4_ADDRESS_TYPE);
991 s->address_type[1] = clib_host_to_net_u16 (SCTP_IPV6_ADDRESS_TYPE);
992 s->address_type[2] = clib_host_to_net_u16 (SCTP_HOSTNAME_ADDRESS_TYPE);
993}
994
995/*
996 * Error cause codes to be used for the sctp_error_cause.cause_code field
997 */
998#define INVALID_STREAM_IDENTIFIER 1
999#define MISSING_MANDATORY_PARAMETER 2
1000#define STALE_COOKIE_ERROR 3
1001#define OUT_OF_RESOURCE 4
1002#define UNRESOLVABLE_ADDRESS 5
1003#define UNRECOGNIZED_CHUNK_TYPE 6
1004#define INVALID_MANDATORY_PARAMETER 7
1005#define UNRECOGNIZED_PARAMETER 8
1006#define NO_USER_DATA 9
1007#define COOKIE_RECEIVED_WHILE_SHUTTING_DOWN 10
1008#define RESTART_OF_ASSOCIATION_WITH_NEW_ADDR 11
1009#define USER_INITIATED_ABORT 12
1010#define PROTOCOL_VIOLATION 13
1011
1012always_inline void
1013vnet_sctp_set_state_cookie (sctp_state_cookie_param_t * s)
1014{
1015 s->param_hdr.type = clib_host_to_net_u16 (SCTP_STATE_COOKIE_TYPE);
1016
1017 /* TODO: length & value to be populated */
1018}
1019
1020typedef struct
1021{
1022 sctp_opt_params_hdr_t param_hdr;
1023
1024 u32 value[];
1025
1026} sctp_unrecognized_param_t;
1027
1028always_inline void
1029vnet_sctp_set_unrecognized_param (sctp_unrecognized_param_t * u)
1030{
1031 u->param_hdr.type = clib_host_to_net_u16 (UNRECOGNIZED_PARAMETER);
1032
1033 /* TODO: length & value to be populated */
1034}
1035
1036/*
1037 * Selective ACK (SACK) chunk
1038 *
1039 * This chunk is sent to the peer endpoint to acknowledge received DATA
1040 * chunks and to inform the peer endpoint of gaps in the received
1041 * subsequences of DATA chunks as represented by their TSNs.
1042 */
1043/*
1044 * 0 1 2 3
1045 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1046 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1047 * | Type = 3 |Chunk Flags | Chunk Length |
1048 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1049 * | Cumulative TSN Ack |
1050 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1051 * | Advertised Receiver Window Credit (a_rwnd) |
1052 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1053 * | Number of Gap Ack Blocks = N | Number of Duplicate TSNs = X |
1054 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1055 * | Gap Ack Block #1 Start | Gap Ack Block #1 End |
1056 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1057 * / /
1058 * \ ... \
1059 * / /
1060 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1061 * | Gap Ack Block #N Start | Gap Ack Block #N End |
1062 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1063 * | Duplicate TSN 1 |
1064 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1065 * / /
1066 * \ ... \
1067 * / /
1068 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1069 * | Duplicate TSN X |
1070 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1071 */
1072typedef struct
1073{
1074 sctp_header_t sctp_hdr;
1075 sctp_chunks_common_hdr_t chunk_hdr;
1076 /*
1077 * This parameter contains the TSN of the last DATA chunk received in
1078 * sequence before a gap. In the case where no DATA chunk has been
1079 * received, this value is set to the peer's Initial TSN minus one.
1080 */
1081 u32 cumulative_tsn_ack;
1082
1083 /*
1084 * This field indicates the updated receive buffer space in bytes of
1085 * the sender of this SACK.
1086 */
1087 u32 a_rwnd;
1088
1089 /*
1090 * Indicates the number of Gap Ack Blocks included in this SACK.
1091 */
1092 u16 gap_ack_blocks_count;
1093
1094 /*
1095 * This field contains the number of duplicate TSNs the endpoint has
1096 * received. Each duplicate TSN is listed following the Gap Ack Block
1097 * list.
1098 */
1099 u16 duplicate_tsn_count;
1100
1101 /*
1102 * Indicates the Start offset TSN for this Gap Ack Block. To calculate
1103 * the actual TSN number the Cumulative TSN Ack is added to this offset
1104 * number. This calculated TSN identifies the first TSN in this Gap Ack
1105 * Block that has been received.
1106 */
1107 u16 *gap_ack_block_start;
1108
1109 /*
1110 * Indicates the End offset TSN for this Gap Ack Block. To calculate
1111 * the actual TSN number, the Cumulative TSN Ack is added to this offset
1112 * number. This calculated TSN identifies the TSN of the last DATA chunk
1113 * received in this Gap Ack Block.
1114 */
1115 u16 *gap_ack_block_end;
1116
1117 /*
1118 * Indicates the number of times a TSN was received in duplicate since
1119 * the last SACK was sent. Every time a receiver gets a duplicate TSN
1120 * (before sending the SACK), it adds it to the list of duplicates.
1121 * The duplicate count is reinitialized to zero after sending each SACK.
1122 */
1123 u32 duplicate_tsn;
1124
1125} sctp_selective_ack_chunk_t;
1126
1127always_inline void
1128vnet_sctp_set_cumulative_tsn_ack (sctp_selective_ack_chunk_t * s,
1129 u32 cumulative_tsn_ack)
1130{
1131 vnet_sctp_set_chunk_type (&s->chunk_hdr, SACK);
1132 s->cumulative_tsn_ack = clib_host_to_net_u32 (cumulative_tsn_ack);
1133}
1134
1135always_inline u32
1136vnet_sctp_get_cumulative_tsn_ack (sctp_selective_ack_chunk_t * s)
1137{
1138 return clib_net_to_host_u32 (s->cumulative_tsn_ack);
1139}
1140
1141always_inline void
1142vnet_sctp_set_arwnd (sctp_selective_ack_chunk_t * s, u32 a_rwnd)
1143{
1144 vnet_sctp_set_chunk_type (&s->chunk_hdr, SACK);
1145 s->a_rwnd = clib_host_to_net_u32 (a_rwnd);
1146}
1147
1148always_inline u32
1149vnet_sctp_get_arwnd (sctp_selective_ack_chunk_t * s)
1150{
1151 return clib_net_to_host_u32 (s->a_rwnd);
1152}
1153
1154always_inline void
1155vnet_sctp_set_gap_ack_blocks_count (sctp_selective_ack_chunk_t * s,
1156 u16 gap_ack_blocks_count)
1157{
1158 vnet_sctp_set_chunk_type (&s->chunk_hdr, SACK);
1159 s->gap_ack_blocks_count = clib_host_to_net_u16 (gap_ack_blocks_count);
1160
1161 if (s->gap_ack_block_start == NULL)
1162 s->gap_ack_block_start =
1163 clib_mem_alloc (sizeof (u16) * gap_ack_blocks_count);
1164 if (s->gap_ack_block_end == NULL)
1165 s->gap_ack_block_end =
1166 clib_mem_alloc (sizeof (u16) * gap_ack_blocks_count);
1167}
1168
1169always_inline u16
1170vnet_sctp_get_gap_ack_blocks_count (sctp_selective_ack_chunk_t * s)
1171{
1172 return clib_net_to_host_u32 (s->gap_ack_blocks_count);
1173}
1174
1175always_inline void
1176vnet_sctp_set_duplicate_tsn_count (sctp_selective_ack_chunk_t * s,
1177 u16 duplicate_tsn_count)
1178{
1179 vnet_sctp_set_chunk_type (&s->chunk_hdr, SACK);
1180 s->duplicate_tsn_count = clib_host_to_net_u16 (duplicate_tsn_count);
1181}
1182
1183always_inline u16
1184vnet_sctp_get_duplicate_tsn_count (sctp_selective_ack_chunk_t * s)
1185{
1186 return clib_net_to_host_u16 (s->duplicate_tsn_count);
1187}
1188
1189/*
1190 * Heartbeat Info
1191 *
1192 * 0 1 2 3
1193 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1194 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1195 * | Heartbeat Info Type=1 | HB Info Length |
1196 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1197 * / Sender-Specific Heartbeat Info /
1198 * \ \
1199 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1200 */
1201typedef struct
1202{
1203 sctp_opt_params_hdr_t param_hdr;
1204
1205 /*
1206 * The Sender-Specific Heartbeat Info field should normally include
1207 * information about the sender's current time when this HEARTBEAT
1208 * chunk is sent and the destination transport address to which this
1209 * HEARTBEAT is sent.
1210 * This information is simply reflected back by the receiver in the
1211 * HEARTBEAT ACK message.
1212 *
1213 * Note also that the HEARTBEAT message is both for reachability
1214 * checking and for path verification.
1215 * When a HEARTBEAT chunk is being used for path verification purposes,
1216 * it MUST hold a 64-bit random nonce.
1217 */
1218 u64 hb_info;
1219
1220} sctp_hb_info_param_t;
1221
1222always_inline void
1223vnet_sctp_set_heartbeat_info (sctp_hb_info_param_t * h, u64 hb_info,
1224 u16 hb_info_length)
1225{
1226 h->hb_info = clib_host_to_net_u16 (1);
1227 h->param_hdr.length = clib_host_to_net_u16 (hb_info_length);
1228 h->hb_info = clib_host_to_net_u64 (hb_info);
1229}
1230
1231/*
1232 * Heartbeat Request
1233 *
1234 * An endpoint should send this chunk to its peer endpoint to probe the
1235 * reachability of a particular destination transport address defined in
1236 * the present association.
1237 * The parameter field contains the Heartbeat Information, which is a
1238 * variable-length opaque data structure understood only by the sender.
1239 */
1240/*
1241 * 0 1 2 3
1242 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1243 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1244 * | Type = 4 | Chunk Flags | Heartbeat Length |
1245 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1246 * \ \
1247 * / Heartbeat Information TLV (Variable-Length) /
1248 * \ \
1249 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1250 */
1251typedef struct
1252{
1253 sctp_header_t sctp_hdr;
1254 sctp_chunks_common_hdr_t chunk_hdr;
1255 sctp_hb_info_param_t hb_info;
1256
1257} sctp_hb_req_chunk_t;
1258
1259always_inline void
1260vnet_sctp_set_hb_request_info (sctp_hb_req_chunk_t * h,
1261 sctp_hb_info_param_t * hb_info)
1262{
1263 vnet_sctp_set_chunk_type (&h->chunk_hdr, HEARTBEAT);
1264 memcpy (&h->hb_info, hb_info, sizeof (h->hb_info));
1265}
1266
1267/*
1268 * Heartbeat Acknowledgement
1269 *
1270 * An endpoint should send this chunk to its peer endpoint as a response
1271 * to a HEARTBEAT chunk.
1272 * A HEARTBEAT ACK is always sent to the source IP address of the IP datagram
1273 * containing the HEARTBEAT chunk to which this ack is responding.
1274 */
1275/*
1276 *
1277 * 0 1 2 3
1278 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1279 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1280 * | Type = 5 | Chunk Flags | Heartbeat Ack Length |
1281 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1282 * \ \
1283 * / Heartbeat Information TLV (Variable-Length) /
1284 * \ \
1285 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1286 */
1287typedef sctp_hb_req_chunk_t sctp_hb_ack_chunk_t;
1288
1289always_inline void
1290vnet_sctp_set_hb_ack_info (sctp_hb_ack_chunk_t * h,
1291 sctp_hb_info_param_t * hb_info)
1292{
1293 vnet_sctp_set_chunk_type (&h->chunk_hdr, HEARTBEAT_ACK);
1294 memcpy (&h->hb_info, hb_info, sizeof (h->hb_info));
1295}
1296
1297/*
1298 * Error cause
1299 */
1300/*
1301 * 0 1 2 3
1302 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1303 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1304 * | Cause Code | Cause Length |
1305 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1306 * / Cause-Specific Information /
1307 * \ \
1308 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1309*/
1310typedef struct
1311{
1312
1313 sctp_opt_params_hdr_t param_hdr;
1314 u64 cause_info;
1315
1316} sctp_err_cause_param_t;
1317
1318/*
1319 * Abort Association (ABORT)
1320 *
1321 * The ABORT chunk is sent to the peer of an association to close the
1322 * association. The ABORT chunk may contain Cause Parameters to inform
1323 * the receiver about the reason of the abort. DATA chunks MUST NOT be
1324 * bundled with ABORT. Control chunks (except for INIT, INIT ACK, and
1325 * SHUTDOWN COMPLETE) MAY be bundled with an ABORT, but they MUST be
1326 * placed before the ABORT in the SCTP packet or they will be ignored by
1327 * the receiver.
1328 *
1329 * If an endpoint receives an ABORT with a format error or no TCB is
1330 * found, it MUST silently discard it. Moreover, under any
1331 * circumstances, an endpoint that receives an ABORT MUST NOT respond to
1332 * that ABORT by sending an ABORT of its own.
1333 */
1334/*
1335 * 0 1 2 3
1336 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1337 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1338 * | Type = 6 |Reserved |T| Length |
1339 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1340 * \ \
1341 * / zero or more Error Causes /
1342 * \ \
1343 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1344 */
1345typedef struct
1346{
1347 sctp_header_t sctp_hdr;
1348 sctp_chunks_common_hdr_t chunk_hdr;
1349 sctp_err_cause_param_t err_causes[];
1350
1351} sctp_abort_chunk_t;
1352
1353always_inline void
1354vnet_sctp_set_tbit (sctp_abort_chunk_t * a)
1355{
1356 vnet_sctp_set_chunk_type (&a->chunk_hdr, ABORT);
1357 // a->chunk_hdr.flags = clib_host_to_net_u16 (1);
1358}
1359
1360always_inline void
1361vnet_sctp_unset_tbit (sctp_abort_chunk_t * a)
1362{
1363 vnet_sctp_set_chunk_type (&a->chunk_hdr, ABORT);
1364 // a->chunk_hdr.flags = clib_host_to_net_u16 (0);
1365}
1366
1367/*
1368 * Shutdown Association (SHUTDOWN)
1369 *
1370 * An endpoint in an association MUST use this chunk to initiate a
1371 * graceful close of the association with its peer.
1372 */
1373/*
1374 * 0 1 2 3
1375 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1376 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1377 * | Type = 7 | Chunk Flags | Length = 8 |
1378 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1379 * | Cumulative TSN Ack |
1380 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1381 */
1382typedef struct
1383{
1384 sctp_header_t sctp_hdr;
1385 sctp_chunks_common_hdr_t chunk_hdr;
1386 /*
1387 * This parameter contains the TSN of the last chunk received in
1388 * sequence before any gaps.
1389 *
1390 * Note: Since the SHUTDOWN message does not contain Gap Ack Blocks,
1391 * it cannot be used to acknowledge TSNs received out of order. In a
1392 * SACK, lack of Gap Ack Blocks that were previously included
1393 * indicates that the data receiver reneged on the associated DATA
1394 * chunks. Since SHUTDOWN does not contain Gap Ack Blocks, the
1395 * receiver of the SHUTDOWN shouldn't interpret the lack of a Gap Ack
1396 * Block as a renege.
1397 */
1398 u32 cumulative_tsn_ack;
1399
1400} sctp_shutdown_association_chunk_t;
1401
1402always_inline void
1403vnet_sctp_set_tsn_last_received_chunk (sctp_shutdown_association_chunk_t * s,
1404 u32 tsn_last_chunk)
1405{
1406 vnet_sctp_set_chunk_type (&s->chunk_hdr, SHUTDOWN);
1407 s->cumulative_tsn_ack = clib_host_to_net_u32 (tsn_last_chunk);
1408}
1409
1410/*
1411 * Shutdown Acknowledgement (SHUTDOWN ACK)
1412 *
1413 * This chunk MUST be used to acknowledge the receipt of the SHUTDOWN
1414 * chunk at the completion of the shutdown process.
1415 */
1416/*
1417 * 0 1 2 3
1418 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1419 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1420 * | Type = 8 |Chunk Flags | Length = 4 |
1421 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1422 */
1423typedef struct
1424{
1425 sctp_header_t sctp_hdr;
1426 sctp_chunks_common_hdr_t chunk_hdr;
1427} sctp_shutdown_ack_chunk_t;
1428
1429always_inline void
1430vnet_sctp_fill_shutdown_ack (sctp_shutdown_ack_chunk_t * s)
1431{
1432 vnet_sctp_set_chunk_type (&s->chunk_hdr, SHUTDOWN_ACK);
1433 vnet_sctp_set_chunk_length (&s->chunk_hdr, 4);
1434}
1435
1436#endif /* included_vnet_sctp_packet_h */
1437
1438/*
1439 * fd.io coding-style-patch-verification: ON
1440 *
1441 * Local Variables:
1442 * eval: (c-set-style "gnu")
1443 * End:
1444 */