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