SCTP stack (RFC4960)
[vpp.git] / src / vnet / sctp / sctp_packet.h
1 /*
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  */
39 typedef 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
83 always_inline void
84 vnet_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
89 always_inline u16
90 vnet_get_sctp_src_port (sctp_header_t * h)
91 {
92   return (clib_net_to_host_u16 (h->src_port));
93 }
94
95 always_inline void
96 vnet_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
101 always_inline u16
102 vnet_get_sctp_dst_port (sctp_header_t * h)
103 {
104   return (clib_net_to_host_u16 (h->dst_port));
105 }
106
107 always_inline void
108 vnet_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
113 always_inline u32
114 vnet_get_sctp_verification_tag (sctp_header_t * h)
115 {
116   return (clib_net_to_host_u32 (h->verification_tag));
117 }
118
119 always_inline void
120 vnet_set_sctp_checksum (sctp_header_t * h, u32 checksum)
121 {
122   h->checksum = clib_host_to_net_u32 (checksum);
123 }
124
125 always_inline u32
126 vnet_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
150 typedef 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  */
176 typedef 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
257 typedef 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
273 always_inline void
274 vnet_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
279 always_inline void
280 vnet_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
285 always_inline void
286 vnet_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
292 always_inline u8
293 vnet_sctp_get_chunk_type (sctp_chunks_common_hdr_t * h)
294 {
295   return ((h->params & CHUNK_TYPE_MASK) >> CHUNK_TYPE_SHIFT);
296 }
297
298 always_inline void
299 vnet_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
305 always_inline u16
306 vnet_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  */
330 typedef 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
410 always_inline void
411 vnet_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
416 always_inline u8
417 vnet_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
423 always_inline void
424 vnet_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
429 always_inline u8
430 vnet_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
436 always_inline void
437 vnet_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
442 always_inline u8
443 vnet_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
449 always_inline void
450 vnet_sctp_set_tsn (sctp_payload_data_chunk_t * p, u32 tsn)
451 {
452   p->tsn = clib_host_to_net_u32 (tsn);
453 }
454
455 always_inline u32
456 vnet_sctp_get_tsn (sctp_payload_data_chunk_t * p)
457 {
458   return (clib_net_to_host_u32 (p->tsn));
459 }
460
461 always_inline void
462 vnet_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
467 always_inline u16
468 vnet_sctp_get_stream_id (sctp_payload_data_chunk_t * p)
469 {
470   return (clib_net_to_host_u16 (p->stream_id));
471 }
472
473 always_inline void
474 vnet_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
479 always_inline u16
480 vnet_sctp_get_stream_seq (sctp_payload_data_chunk_t * p)
481 {
482   return (clib_net_to_host_u16 (p->stream_seq));
483 }
484
485 always_inline void
486 vnet_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
491 always_inline u32
492 vnet_sctp_get_payload_id (sctp_payload_data_chunk_t * p)
493 {
494   return (clib_net_to_host_u32 (p->payload_id));
495 }
496
497 always_inline u16
498 vnet_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
506 always_inline u16
507 vnet_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  */
590 typedef 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  */
692 typedef 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  */
705 typedef struct
706 {
707   u16 type;
708   u16 length;
709
710 } sctp_opt_params_hdr_t;
711
712 typedef 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  */
738 typedef 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  */
755 typedef 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  */
769 typedef 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  */
797 typedef 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
809 always_inline void
810 vnet_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
817 always_inline u32
818 vnet_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  */
835 typedef 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
847 always_inline void
848 vnet_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
856 always_inline ip6_address_t
857 vnet_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  */
880 typedef 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
900 always_inline void
901 vnet_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
909 always_inline u32
910 vnet_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  */
934 typedef 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
950 always_inline void
951 vnet_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  */
976 typedef 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
984 always_inline void
985 vnet_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
1013 always_inline void
1014 vnet_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
1021 typedef struct
1022 {
1023   sctp_opt_params_hdr_t param_hdr;
1024
1025   u32 value[];
1026
1027 } sctp_unrecognized_param_t;
1028
1029 always_inline void
1030 vnet_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  */
1073 typedef 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
1128 always_inline void
1129 vnet_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
1136 always_inline u32
1137 vnet_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
1142 always_inline void
1143 vnet_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
1149 always_inline u32
1150 vnet_sctp_get_arwnd (sctp_selective_ack_chunk_t * s)
1151 {
1152   return clib_net_to_host_u32 (s->a_rwnd);
1153 }
1154
1155 always_inline void
1156 vnet_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
1170 always_inline u16
1171 vnet_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
1176 always_inline void
1177 vnet_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
1184 always_inline u16
1185 vnet_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  */
1202 typedef 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
1223 always_inline void
1224 vnet_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  */
1252 typedef 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
1260 always_inline void
1261 vnet_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  */
1288 typedef sctp_hb_req_chunk_t sctp_hb_ack_chunk_t;
1289
1290 always_inline void
1291 vnet_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 */
1311 typedef 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  */
1346 typedef 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
1354 always_inline void
1355 vnet_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
1361 always_inline void
1362 vnet_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  */
1383 typedef 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
1403 always_inline void
1404 vnet_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  */
1424 typedef struct
1425 {
1426   sctp_header_t sctp_hdr;
1427   sctp_chunks_common_hdr_t chunk_hdr;
1428 } sctp_shutdown_ack_chunk_t;
1429
1430 always_inline void
1431 vnet_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  */