diff options
author | Marco Varlese <marco.varlese@suse.com> | 2017-10-30 18:17:21 +0100 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2018-01-24 15:45:35 +0000 |
commit | 191a59401c0552e5ea79041f34456eb9fcc1f311 (patch) | |
tree | 286d871aee72cb37e6d751715e89c6b178c7b527 /src/vnet/sctp/sctp_packet.h | |
parent | ce111d2ee3bacec2a09d8f5b664dcfafa0dd50c7 (diff) |
SCTP stack (RFC4960)
== CONTENT ==
* SCTP chunks definition as per RFC4960;
* Helper functions to set/get values to/from the corresponding chunks;
* Hooks to the session/application layers;
* Complete state-machine handling;
* Implementation for unexpected chunk received in a certain
state (state-machine error handling)
* Support for 1-single connection;
* Sample application to test receive/transmit data-path;
* Test to validate SCTP stack;
Change-Id: I1b55c455ab400be9513f4e094dadfc3181d2ebc9
Signed-off-by: Marco Varlese <marco.varlese@suse.com>
Diffstat (limited to 'src/vnet/sctp/sctp_packet.h')
-rw-r--r-- | src/vnet/sctp/sctp_packet.h | 1445 |
1 files changed, 1445 insertions, 0 deletions
diff --git a/src/vnet/sctp/sctp_packet.h b/src/vnet/sctp/sctp_packet.h new file mode 100644 index 00000000000..4c358db6d3b --- /dev/null +++ b/src/vnet/sctp/sctp_packet.h @@ -0,0 +1,1445 @@ +/* + * Copyright (c) 2017 SUSE LLC. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef included_vnet_sctp_packet_h +#define included_vnet_sctp_packet_h + +#include <stdbool.h> + +#include <vnet/ip/ip4_packet.h> +#include <vnet/ip/ip6_packet.h> + +/* + * As per RFC 4960 + * https://tools.ietf.org/html/rfc4960 + */ + +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source Port Number | Destination Port Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Verification Tag | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + /* + * This is the SCTP sender's port number. It can be used by the + * receiver in combination with the source IP address, the SCTP + * destination port, and possibly the destination IP address to + * identify the association to which this packet belongs. + * The port number 0 MUST NOT be used. + */ + u16 src_port; + + /* + * This is the SCTP port number to which this packet is destined. + * The receiving host will use this port number to de-multiplex the + * SCTP packet to the correct receiving endpoint/application. + * The port number 0 MUST NOT be used. + */ + u16 dst_port; + + /* + * The receiver of this packet uses the Verification Tag to validate + * the sender of this SCTP packet. On transmit, the value of this + * Verification Tag MUST be set to the value of the Initiate Tag + * received from the peer endpoint during the association + * initialization, with the following exceptions: + * - A packet containing an INIT chunk MUST have a zero Verification + * Tag. + * - A packet containing a SHUTDOWN COMPLETE chunk with the T bit + * set MUST have the Verification Tag copied from the packet with + * the SHUTDOWN ACK chunk. + * - A packet containing an ABORT chunk may have the verification tag + * copied from the packet that caused the ABORT to be sent. + * An INIT chunk MUST be the only chunk in the SCTP packet carrying it. + */ + u32 verification_tag; + + /* + * This field contains the checksum of this SCTP packet. + * SCTP uses the CRC32c algorithm. + */ + u32 checksum; + +} sctp_header_t; + +always_inline void +vnet_set_sctp_src_port (sctp_header_t * h, u16 src_port) +{ + h->src_port = clib_host_to_net_u16 (src_port); +} + +always_inline u16 +vnet_get_sctp_src_port (sctp_header_t * h) +{ + return (clib_net_to_host_u16 (h->src_port)); +} + +always_inline void +vnet_set_sctp_dst_port (sctp_header_t * h, u16 dst_port) +{ + h->dst_port = clib_host_to_net_u16 (dst_port); +} + +always_inline u16 +vnet_get_sctp_dst_port (sctp_header_t * h) +{ + return (clib_net_to_host_u16 (h->dst_port)); +} + +always_inline void +vnet_set_sctp_verification_tag (sctp_header_t * h, u32 verification_tag) +{ + h->verification_tag = clib_host_to_net_u32 (verification_tag); +} + +always_inline u32 +vnet_get_sctp_verification_tag (sctp_header_t * h) +{ + return (clib_net_to_host_u32 (h->verification_tag)); +} + +always_inline void +vnet_set_sctp_checksum (sctp_header_t * h, u32 checksum) +{ + h->checksum = clib_host_to_net_u32 (checksum); +} + +always_inline u32 +vnet_get_sctp_checksum (sctp_header_t * h) +{ + return (clib_net_to_host_u32 (h->checksum)); +} + +/* + * Multiple chunks can be bundled into one SCTP packet up to the MTU + * size, except for the INIT, INIT ACK, and SHUTDOWN COMPLETE chunks. + * These chunks MUST NOT be bundled with any other chunk in a packet. + * + * + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Common Header | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Chunk #1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Chunk #n | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +typedef enum +{ + DATA = 0, + INIT, + INIT_ACK, + SACK, + HEARTBEAT, + HEARTBEAT_ACK, + ABORT, + SHUTDOWN, + SHUTDOWN_ACK, + OPERATION_ERROR, + COOKIE_ECHO, + COOKIE_ACK, + ECNE, + CWR, + SHUTDOWN_COMPLETE +} sctp_chunk_type; + +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Chunk Type | Chunk Flags | Chunk Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + /* + * This field identifies the type of information contained in the + * Chunk Value field. It takes a value from 0 to 254. + * The value of 255 is reserved for future use as an extension field. + * + * The values of Chunk Types are defined as follows: + * ID Value Chunk Type + * ----- ---------- + * 0 - Payload Data (DATA) + * 1 - Initiation (INIT) + * 2 - Initiation Acknowledgement (INIT ACK) + * 3 - Selective Acknowledgement (SACK) + * 4 - Heartbeat Request (HEARTBEAT) + * 5 - Heartbeat Acknowledgement (HEARTBEAT ACK) + * 6 - Abort (ABORT) + * 7 - Shutdown (SHUTDOWN) + * 8 - Shutdown Acknowledgement (SHUTDOWN ACK) + * 9 - Operation Error (ERROR) + * 10 - State Cookie (COOKIE ECHO) + * 11 - Cookie Acknowledgement (COOKIE ACK) + * 12 - Reserved for Explicit Congestion Notification Echo (ECNE) + * 13 - Reserved for Congestion Window Reduced (CWR) + * 14 - Shutdown Complete (SHUTDOWN COMPLETE) + * 15 to 62 - available + * 63 - reserved for IETF-defined Chunk Extensions + * 64 to 126 - available + * 127 - reserved for IETF-defined Chunk Extensions + * 128 to 190 - available + * 191 - reserved for IETF-defined Chunk Extensions + * 192 to 254 - available + * 255 - reserved for IETF-defined Chunk Extensions + * + * Chunk Types are encoded such that the highest-order 2 bits specify + * the action that must be taken if the processing endpoint does not + * recognize the Chunk Type. + * 00 - Stop processing this SCTP packet and discard it, do not + * process any further chunks within it. + * 01 - Stop processing this SCTP packet and discard it, do not + * process any further chunks within it, and report the + * unrecognized chunk in an 'Unrecognized Chunk Type'. + * 10 - Skip this chunk and continue processing. + * 11 - Skip this chunk and continue processing, but report in an + * ERROR chunk using the 'Unrecognized Chunk Type' cause of error. + * + * Note: The ECNE and CWR chunk types are reserved for future use of + * Explicit Congestion Notification (ECN); + */ + //u8 type; + + /* + * The usage of these bits depends on the Chunk type as given by the + * Chunk Type field. Unless otherwise specified, they are set to 0 on + * transmit and are ignored on receipt. + */ + //u8 flags; + + /* + * This value represents the size of the chunk in bytes, including + * the Chunk Type, Chunk Flags, Chunk Length, and Chunk Value fields. + * Therefore, if the Chunk Value field is zero-length, the Length + * field will be set to 4. + * The Chunk Length field does not count any chunk padding. + * Chunks (including Type, Length, and Value fields) are padded out + * by the sender with all zero bytes to be a multiple of 4 bytes + * long. This padding MUST NOT be more than 3 bytes in total. The + * Chunk Length value does not include terminating padding of the + * chunk. However, it does include padding of any variable-length + * parameter except the last parameter in the chunk. The receiver + * MUST ignore the padding. + * + * Note: A robust implementation should accept the chunk whether or + * not the final padding has been included in the Chunk Length. + */ + //u16 length; + + u32 params; + +} sctp_chunks_common_hdr_t; + +typedef struct +{ + sctp_header_t hdr; + sctp_chunks_common_hdr_t common_hdr; + +} sctp_full_hdr_t; + +#define CHUNK_TYPE_MASK 0xFF000000 +#define CHUNK_TYPE_SHIFT 24 + +#define CHUNK_FLAGS_MASK 0x00FF0000 +#define CHUNK_FLAGS_SHIFT 16 + +#define CHUNK_LENGTH_MASK 0x0000FFFF +#define CHUNK_LENGTH_SHIFT 0 + +always_inline void +vnet_sctp_common_hdr_params_host_to_net (sctp_chunks_common_hdr_t * h) +{ + h->params = clib_host_to_net_u32 (h->params); +} + +always_inline void +vnet_sctp_common_hdr_params_net_to_host (sctp_chunks_common_hdr_t * h) +{ + h->params = clib_net_to_host_u32 (h->params); +} + +always_inline void +vnet_sctp_set_chunk_type (sctp_chunks_common_hdr_t * h, sctp_chunk_type t) +{ + h->params &= ~(CHUNK_TYPE_MASK); + h->params |= (t << CHUNK_TYPE_SHIFT) & CHUNK_TYPE_MASK; +} + +always_inline u8 +vnet_sctp_get_chunk_type (sctp_chunks_common_hdr_t * h) +{ + return ((h->params & CHUNK_TYPE_MASK) >> CHUNK_TYPE_SHIFT); +} + +always_inline void +vnet_sctp_set_chunk_length (sctp_chunks_common_hdr_t * h, u16 length) +{ + h->params &= ~(CHUNK_LENGTH_MASK); + h->params |= (length << CHUNK_LENGTH_SHIFT) & CHUNK_LENGTH_MASK; +} + +always_inline u16 +vnet_sctp_get_chunk_length (sctp_chunks_common_hdr_t * h) +{ + return ((h->params & CHUNK_LENGTH_MASK) >> CHUNK_LENGTH_SHIFT); +} + +/* + * Payload chunk + * + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 0 | Reserved|U|B|E| Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | TSN | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Stream Identifier S | Stream Sequence Number n | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Payload Protocol Identifier | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / User Data (seq n of Stream S) / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_header_t sctp_hdr; + /* + * Type (8 bits): 0 + * Flags (8 bits): + * -- Reserved (5 bits): all 0s + * -- U bit + * -- B bit + * -- E bit + * Length (16 bits): This field indicates the length of the DATA chunk in + * bytes from the beginning of the type field to the end of the User Data + * field excluding any padding. + * A DATA chunk with one byte of user data will have Length set to 17 + * (indicating 17 bytes). A DATA chunk with a User Data field of length L + * will have the Length field set to (16 + L) (indicating 16+L bytes) where + * L MUST be greater than 0. + */ + + /* + * Fragment Description Table: + * + * B E Description + * ============================================================ + * | 1 0 | First piece of a fragmented user message | + * +----------------------------------------------------------+ + * | 0 0 | Middle piece of a fragmented user message | + * +----------------------------------------------------------+ + * | 0 1 | Last piece of a fragmented user message | + * +----------------------------------------------------------+ + * | 1 1 | Unfragmented message | + * ============================================================ + */ + sctp_chunks_common_hdr_t chunk_hdr; + + /* + * This value represents the TSN for this DATA chunk. + * The valid range of TSN is from 0 to 4294967295 (2**32 - 1). + * TSN wraps back to 0 after reaching 4294967295. + */ + u32 tsn; + + /* + * Identifies the stream to which the following user data belongs. + */ + u16 stream_id; + + /* + * This value represents the Stream Sequence Number of the following user data + * within the stream S. Valid range is 0 to 65535. + * When a user message is fragmented by SCTP for transport, the same Stream + * Sequence Number MUST be carried in each of the fragments of the message. + */ + u16 stream_seq; + + /* + * This value represents an application (or upper layer) specified protocol + * identifier. This value is passed to SCTP by its upper layer and sent to its + * peer. This identifier is not used by SCTP but can be used by certain network + * entities, as well as by the peer application, to identify the type of + * information being carried in this DATA chunk. This field must be sent even + * in fragmented DATA chunks (to make sure it is available for agents in the + * middle of the network). Note that this field is NOT touched by an SCTP + * implementation; therefore, its byte order is NOT necessarily big endian. + * The upper layer is responsible for any byte order conversions to this field. + * The value 0 indicates that no application identifier is specified by the + * upper layer for this payload data. + */ + u32 payload_id; + + /* + * This is the payload user data. The implementation MUST pad the end of the + * data to a 4-byte boundary with all-zero bytes. Any padding MUST NOT be + * included in the Length field. A sender MUST never add more than 3 bytes of + * padding. + */ + u32 data[]; + +} sctp_payload_data_chunk_t; + +always_inline void +vnet_sctp_set_ebit (sctp_payload_data_chunk_t * p, u8 enable) +{ + //p->chunk_hdr.flags = clib_host_to_net_u16 (enable); +} + +always_inline u8 +vnet_sctp_get_ebit (sctp_payload_data_chunk_t * p) +{ + //return (clib_net_to_host_u16 (p->chunk_hdr.flags)); + return 0; +} + +always_inline void +vnet_sctp_set_bbit (sctp_payload_data_chunk_t * p, u8 enable) +{ + //p->chunk_hdr.flags = clib_host_to_net_u16 (enable << 1); +} + +always_inline u8 +vnet_sctp_get_bbit (sctp_payload_data_chunk_t * p) +{ + //return (clib_net_to_host_u16 (p->chunk_hdr.flags >> 1)); + return 0; +} + +always_inline void +vnet_sctp_set_ubit (sctp_payload_data_chunk_t * p, u8 enable) +{ + //p->chunk_hdr.flags = clib_host_to_net_u16 (enable << 2); +} + +always_inline u8 +vnet_sctp_get_ubit (sctp_payload_data_chunk_t * p) +{ + //return (clib_net_to_host_u16 (p->chunk_hdr.flags >> 2)); + return 0; +} + +always_inline void +vnet_sctp_set_tsn (sctp_payload_data_chunk_t * p, u32 tsn) +{ + p->tsn = clib_host_to_net_u32 (tsn); +} + +always_inline u32 +vnet_sctp_get_tsn (sctp_payload_data_chunk_t * p) +{ + return (clib_net_to_host_u32 (p->tsn)); +} + +always_inline void +vnet_sctp_set_stream_id (sctp_payload_data_chunk_t * p, u16 stream_id) +{ + p->stream_id = clib_host_to_net_u16 (stream_id); +} + +always_inline u16 +vnet_sctp_get_stream_id (sctp_payload_data_chunk_t * p) +{ + return (clib_net_to_host_u16 (p->stream_id)); +} + +always_inline void +vnet_sctp_set_stream_seq (sctp_payload_data_chunk_t * p, u16 stream_seq) +{ + p->stream_seq = clib_host_to_net_u16 (stream_seq); +} + +always_inline u16 +vnet_sctp_get_stream_seq (sctp_payload_data_chunk_t * p) +{ + return (clib_net_to_host_u16 (p->stream_seq)); +} + +always_inline void +vnet_sctp_set_payload_id (sctp_payload_data_chunk_t * p, u32 payload_id) +{ + p->payload_id = clib_host_to_net_u32 (payload_id); +} + +always_inline u32 +vnet_sctp_get_payload_id (sctp_payload_data_chunk_t * p) +{ + return (clib_net_to_host_u32 (p->payload_id)); +} + +always_inline u16 +vnet_sctp_calculate_padding (u16 base_length) +{ + if (base_length % 4 == 0) + return 0; + + return (4 - base_length % 4); +} + +always_inline u16 +vnet_sctp_calculate_payload_data_padding (sctp_payload_data_chunk_t * p) +{ + u16 payload_length = vnet_sctp_get_chunk_length (&p->chunk_hdr) - + sizeof (p->chunk_hdr) - + sizeof (p->tsn) - + sizeof (p->stream_id) - sizeof (p->stream_seq) - sizeof (p->payload_id); + + return vnet_sctp_calculate_padding (payload_length); +} + +#define DEFAULT_A_RWND 1480 +#define INBOUND_STREAMS_COUNT 1 +#define OUTBOUND_STREAMS_COUNT 1 + +/* + * INIT chunk + * + * This chunk is used to initiate an SCTP association between two + * endpoints. + * + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 1 | Chunk Flags | Chunk Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Initiate Tag | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Advertised Receiver Window Credit (a_rwnd) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Number of Outbound Streams | Number of Inbound Streams | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Initial TSN | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / Optional/Variable-Length Parameters / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * The INIT chunk contains the following parameters. Unless otherwise + * noted, each parameter MUST only be included once in the INIT chunk. + * + * Fixed Parameters Status + * ---------------------------------------------- + * Initiate Tag Mandatory + * Advertised Receiver Window Credit Mandatory + * Number of Outbound Streams Mandatory + * Number of Inbound Streams Mandatory + * Initial TSN Mandatory + * + * Variable Parameters Status Type Value + * ------------------------------------------------------------- + * IPv4 Address (Note 1) Optional 5 + * IPv6 Address (Note 1) Optional 6 + * Cookie Preservative Optional 9 + * Reserved for ECN Capable (Note 2) Optional 32768 (0x8000) + * Host Name Address (Note 3) Optional 11 + * Supported Address Types (Note 4) Optional 12 + * + * Note 1: The INIT chunks can contain multiple addresses that can be + * IPv4 and/or IPv6 in any combination. + * + * Note 2: The ECN Capable field is reserved for future use of Explicit + * Congestion Notification. + * + * Note 3: An INIT chunk MUST NOT contain more than one Host Name Address + * parameter. Moreover, the sender of the INIT MUST NOT combine any other + * address types with the Host Name Address in the INIT. The receiver of + * INIT MUST ignore any other address types if the Host Name Address parameter + * is present in the received INIT chunk. + * + * Note 4: This parameter, when present, specifies all the address types the + * sending endpoint can support. The absence of this parameter indicates that + * the sending endpoint can support any address type. + * + * IMPLEMENTATION NOTE: If an INIT chunk is received with known parameters that + * are not optional parameters of the INIT chunk, then the receiver SHOULD + * process the INIT chunk and send back an INIT ACK. The receiver of the INIT + * chunk MAY bundle an ERROR chunk with the COOKIE ACK chunk later. + * However, restrictive implementations MAY send back an ABORT chunk in response + * to the INIT chunk. The Chunk Flags field in INIT is reserved, and all bits + * in it should be set to 0 by the sender and ignored by the receiver. + * The sequence of parameters within an INIT can be processed in any order. + */ +typedef struct +{ + sctp_header_t sctp_hdr; + sctp_chunks_common_hdr_t chunk_hdr; + + /* + * The receiver of the INIT (the responding end) records the value of + * the Initiate Tag parameter. + * This value MUST be placed into the Verification Tag field of every + * SCTP packet that the receiver of the INIT transmits within this association. + * The Initiate Tag is allowed to have any value except 0. + * + * If the value of the Initiate Tag in a received INIT chunk is found + * to be 0, the receiver MUST treat it as an error and close the + * association by transmitting an ABORT. + * + * The value of the INIT TAG is recommended to be random for security + * reasons. A good method is described in https://tools.ietf.org/html/rfc4086 + */ + u32 initiate_tag; + + /* + * This value represents the dedicated buffer space, in number of bytes, + * the sender of the INIT has reserved in association with this window. + * During the life of the association, this buffer space SHOULD NOT be + * lessened (i.e., dedicated buffers taken away from this association); + * however, an endpoint MAY change the value of a_rwnd it sends in SACK + * chunks. + */ + u32 a_rwnd; + + /* + * Defines the number of outbound streams the sender of this INIT chunk + * wishes to create in this association. + * The value of 0 MUST NOT be used. + * + * Note: A receiver of an INIT with the OS value set to 0 SHOULD abort + * the association. + */ + u16 outbound_streams_count; + + /* + * Defines the maximum number of streams the sender of this INIT + * chunk allows the peer end to create in this association. + * The value 0 MUST NOT be used. + * + * Note: There is no negotiation of the actual number of streams but + * instead the two endpoints will use the min(requested, offered). + * + * Note: A receiver of an INIT with the MIS value of 0 SHOULD abort + * the association. + */ + u16 inboud_streams_count; + + /* + * Defines the initial TSN that the sender will use. + * The valid range is from 0 to 4294967295. + * This field MAY be set to the value of the Initiate Tag field. + */ + u32 initial_tsn; + + /* The following field allows to have multiple optional fields which are: + * - sctp_ipv4_address + * - sctp_ipv6_address + * - sctp_cookie_preservative + * - sctp_hostname_address + * - sctp_supported_address_types + */ + u32 optional_fields[]; + +} sctp_init_chunk_t; + +/* + * INIT ACK chunk + * + * The INIT ACK chunk is used to acknowledge the initiation of an SCTP + * association. The parameter part of INIT ACK is formatted similarly to the + * INIT chunk. + * + * It uses two extra variable parameters: + * - the State Cookie and + * - the Unrecognized Parameter: + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 2 | Chunk Flags | Chunk Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Initiate Tag | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Advertised Receiver Window Credit | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Number of Outbound Streams | Number of Inbound Streams | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Initial TSN | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / Optional/Variable-Length Parameters / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef sctp_init_chunk_t sctp_init_ack_chunk_t; + +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Parameter Type | Parameter Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / Parameter Value / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + u16 type; + u16 length; + +} sctp_opt_params_hdr_t; + +typedef struct +{ + sctp_opt_params_hdr_t param_hdr; + + u64 mac; /* RFC 2104 */ + u32 creation_time; + u32 cookie_lifespan; + +} sctp_state_cookie_param_t; + +/* + * This chunk is used only during the initialization of an association. + * It is sent by the initiator of an association to its peer to complete + * the initialization process. This chunk MUST precede any DATA chunk + * sent within the association, but MAY be bundled with one or more DATA + * chunks in the same packet. + * + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 10 |Chunk Flags | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / Cookie / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_header_t sctp_hdr; + sctp_chunks_common_hdr_t chunk_hdr; + + sctp_state_cookie_param_t cookie; + +} sctp_cookie_echo_chunk_t; + + +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 11 |Chunk Flags | Length = 4 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_header_t sctp_hdr; + sctp_chunks_common_hdr_t chunk_hdr; + +} sctp_cookie_ack_chunk_t; + +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 14 |Chunk Flags | Length = 4 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_header_t sctp_hdr; + sctp_chunks_common_hdr_t chunk_hdr; + +} sctp_shutdown_complete_chunk_t; + +/* OPTIONAL or VARIABLE-LENGTH parameters for INIT */ +#define SCTP_IPV4_ADDRESS_TYPE 5 +#define SCTP_IPV4_ADDRESS_TYPE_LENGTH 8 +#define SCTP_IPV6_ADDRESS_TYPE 6 +#define SCTP_IPV6_ADDRESS_TYPE_LENGTH 20 +#define SCTP_STATE_COOKIE_TYPE 7 +#define SCTP_UNRECOGNIZED_TYPE 8 +#define SCTP_COOKIE_PRESERVATIVE_TYPE 9 +#define SCTP_COOKIE_PRESERVATIVE_TYPE_LENGTH 8 +#define SCTP_HOSTNAME_ADDRESS_TYPE 11 +#define SCTP_SUPPORTED_ADDRESS_TYPES 12 + +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 5 | Length = 8 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IPv4 Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_opt_params_hdr_t param_hdr; + + /* + * Contains an IPv4 address of the sending endpoint. + * It is binary encoded. + */ + ip4_address_t address; + +} sctp_ipv4_addr_param_t; + +always_inline void +vnet_sctp_set_ipv4_address (sctp_ipv4_addr_param_t * a, ip4_address_t address) +{ + a->param_hdr.type = clib_host_to_net_u16 (SCTP_IPV4_ADDRESS_TYPE); + a->param_hdr.length = clib_host_to_net_u16 (8); + a->address.as_u32 = clib_host_to_net_u32 (address.as_u32); +} + +always_inline u32 +vnet_sctp_get_ipv4_address (sctp_ipv4_addr_param_t * a) +{ + return (clib_net_to_host_u32 (a->address.as_u32)); +} + +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 6 | Length = 20 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | IPv6 Address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_opt_params_hdr_t param_hdr; + + /* + * Contains an IPv6 address of the sending endpoint. + * It is binary encoded. + */ + ip6_address_t address; + +} sctp_ipv6_addr_param_t; + +always_inline void +vnet_sctp_set_ipv6_address (sctp_ipv6_addr_param_t * a, ip6_address_t address) +{ + a->param_hdr.type = clib_host_to_net_u16 (SCTP_IPV6_ADDRESS_TYPE); + a->param_hdr.length = clib_host_to_net_u16 (20); + a->address.as_u64[0] = clib_host_to_net_u64 (address.as_u64[0]); + a->address.as_u64[1] = clib_host_to_net_u64 (address.as_u64[1]); +} + +always_inline ip6_address_t +vnet_sctp_get_ipv6_address (sctp_ipv6_addr_param_t * a) +{ + ip6_address_t ip6_address; + + ip6_address.as_u64[0] = clib_net_to_host_u64 (a->address.as_u64[0]); + ip6_address.as_u64[1] = clib_net_to_host_u64 (a->address.as_u64[1]); + + return ip6_address; +} + +/* + * The sender of the INIT shall use this parameter to suggest to the + * receiver of the INIT for a longer life-span of the State Cookie. + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 9 | Length = 8 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Suggested Cookie Life-Span Increment (msec.) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_opt_params_hdr_t param_hdr; + + /* + * This parameter indicates to the receiver how much increment in + * milliseconds the sender wishes the receiver to add to its default + * cookie life-span. + * + * This optional parameter should be added to the INIT chunk by the + * sender when it reattempts establishing an association with a peer + * to which its previous attempt of establishing the association + * failed due to a stale cookie operation error. The receiver MAY + * choose to ignore the suggested cookie life-span increase for its + * own security reasons. + */ + u32 life_span_inc; + +} sctp_cookie_preservative_param_t; + +always_inline void +vnet_sctp_set_cookie_preservative (sctp_cookie_preservative_param_t * c, + u32 life_span_inc) +{ + c->param_hdr.type = clib_host_to_net_u16 (SCTP_COOKIE_PRESERVATIVE_TYPE); + c->param_hdr.length = clib_host_to_net_u16 (8); + c->life_span_inc = clib_host_to_net_u32 (life_span_inc); +} + +always_inline u32 +vnet_sctp_get_cookie_preservative (sctp_cookie_preservative_param_t * c) +{ + return (clib_net_to_host_u32 (c->life_span_inc)); +} + +#define FQDN_MAX_LENGTH 256 + +/* + * The sender of INIT uses this parameter to pass its Host Name (in + * place of its IP addresses) to its peer. + * The peer is responsible for resolving the name. + * Using this parameter might make it more likely for the association to work + * across a NAT box. + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 11 | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / Host Name / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_opt_params_hdr_t param_hdr; + + + /* + * This field contains a host name in "host name syntax" per RFC 1123 + * Section 2.1 + * + * Note: At least one null terminator is included in the Host Name + * string and must be included in the length. + */ + char hostname[FQDN_MAX_LENGTH]; + +} sctp_hostname_param_t; + +always_inline void +vnet_sctp_set_hostname_address (sctp_hostname_param_t * h, char *hostname) +{ + h->param_hdr.length = FQDN_MAX_LENGTH; + h->param_hdr.type = clib_host_to_net_u16 (SCTP_HOSTNAME_ADDRESS_TYPE); + memset (h->hostname, '0', FQDN_MAX_LENGTH); + memcpy (h->hostname, hostname, FQDN_MAX_LENGTH); +} + +#define MAX_SUPPORTED_ADDRESS_TYPES 3 + +/* + * The sender of INIT uses this parameter to list all the address types + * it can support. + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 12 | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Address Type #1 | Address Type #2 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ...... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+ + */ +typedef struct +{ + sctp_opt_params_hdr_t param_hdr; + + u16 address_type[MAX_SUPPORTED_ADDRESS_TYPES]; + +} sctp_supported_addr_types_param_t; + +always_inline void +vnet_sctp_set_supported_address_types (sctp_supported_addr_types_param_t * s) +{ + s->param_hdr.type = clib_host_to_net_u16 (SCTP_SUPPORTED_ADDRESS_TYPES); + s->param_hdr.length = 4 /* base = type + length */ + + MAX_SUPPORTED_ADDRESS_TYPES * 4; /* each address type is 4 bytes */ + + s->address_type[0] = clib_host_to_net_u16 (SCTP_IPV4_ADDRESS_TYPE); + s->address_type[1] = clib_host_to_net_u16 (SCTP_IPV6_ADDRESS_TYPE); + s->address_type[2] = clib_host_to_net_u16 (SCTP_HOSTNAME_ADDRESS_TYPE); +} + +/* + * Error cause codes to be used for the sctp_error_cause.cause_code field + */ +#define INVALID_STREAM_IDENTIFIER 1 +#define MISSING_MANDATORY_PARAMETER 2 +#define STALE_COOKIE_ERROR 3 +#define OUT_OF_RESOURCE 4 +#define UNRESOLVABLE_ADDRESS 5 +#define UNRECOGNIZED_CHUNK_TYPE 6 +#define INVALID_MANDATORY_PARAMETER 7 +#define UNRECOGNIZED_PARAMETER 8 +#define NO_USER_DATA 9 +#define COOKIE_RECEIVED_WHILE_SHUTTING_DOWN 10 +#define RESTART_OF_ASSOCIATION_WITH_NEW_ADDR 11 +#define USER_INITIATED_ABORT 12 +#define PROTOCOL_VIOLATION 13 + +always_inline void +vnet_sctp_set_state_cookie (sctp_state_cookie_param_t * s) +{ + s->param_hdr.type = clib_host_to_net_u16 (SCTP_STATE_COOKIE_TYPE); + + /* TODO: length & value to be populated */ +} + +typedef struct +{ + sctp_opt_params_hdr_t param_hdr; + + u32 value[]; + +} sctp_unrecognized_param_t; + +always_inline void +vnet_sctp_set_unrecognized_param (sctp_unrecognized_param_t * u) +{ + u->param_hdr.type = clib_host_to_net_u16 (UNRECOGNIZED_PARAMETER); + + /* TODO: length & value to be populated */ +} + +/* + * Selective ACK (SACK) chunk + * + * This chunk is sent to the peer endpoint to acknowledge received DATA + * chunks and to inform the peer endpoint of gaps in the received + * subsequences of DATA chunks as represented by their TSNs. + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 3 |Chunk Flags | Chunk Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Cumulative TSN Ack | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Advertised Receiver Window Credit (a_rwnd) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Number of Gap Ack Blocks = N | Number of Duplicate TSNs = X | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Gap Ack Block #1 Start | Gap Ack Block #1 End | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / / + * \ ... \ + * / / + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Gap Ack Block #N Start | Gap Ack Block #N End | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Duplicate TSN 1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / / + * \ ... \ + * / / + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Duplicate TSN X | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_header_t sctp_hdr; + sctp_chunks_common_hdr_t chunk_hdr; + /* + * This parameter contains the TSN of the last DATA chunk received in + * sequence before a gap. In the case where no DATA chunk has been + * received, this value is set to the peer's Initial TSN minus one. + */ + u32 cumulative_tsn_ack; + + /* + * This field indicates the updated receive buffer space in bytes of + * the sender of this SACK. + */ + u32 a_rwnd; + + /* + * Indicates the number of Gap Ack Blocks included in this SACK. + */ + u16 gap_ack_blocks_count; + + /* + * This field contains the number of duplicate TSNs the endpoint has + * received. Each duplicate TSN is listed following the Gap Ack Block + * list. + */ + u16 duplicate_tsn_count; + + /* + * Indicates the Start offset TSN for this Gap Ack Block. To calculate + * the actual TSN number the Cumulative TSN Ack is added to this offset + * number. This calculated TSN identifies the first TSN in this Gap Ack + * Block that has been received. + */ + u16 *gap_ack_block_start; + + /* + * Indicates the End offset TSN for this Gap Ack Block. To calculate + * the actual TSN number, the Cumulative TSN Ack is added to this offset + * number. This calculated TSN identifies the TSN of the last DATA chunk + * received in this Gap Ack Block. + */ + u16 *gap_ack_block_end; + + /* + * Indicates the number of times a TSN was received in duplicate since + * the last SACK was sent. Every time a receiver gets a duplicate TSN + * (before sending the SACK), it adds it to the list of duplicates. + * The duplicate count is reinitialized to zero after sending each SACK. + */ + u32 duplicate_tsn; + +} sctp_selective_ack_chunk_t; + +always_inline void +vnet_sctp_set_cumulative_tsn_ack (sctp_selective_ack_chunk_t * s, + u32 cumulative_tsn_ack) +{ + vnet_sctp_set_chunk_type (&s->chunk_hdr, SACK); + s->cumulative_tsn_ack = clib_host_to_net_u32 (cumulative_tsn_ack); +} + +always_inline u32 +vnet_sctp_get_cumulative_tsn_ack (sctp_selective_ack_chunk_t * s) +{ + return clib_net_to_host_u32 (s->cumulative_tsn_ack); +} + +always_inline void +vnet_sctp_set_arwnd (sctp_selective_ack_chunk_t * s, u32 a_rwnd) +{ + vnet_sctp_set_chunk_type (&s->chunk_hdr, SACK); + s->a_rwnd = clib_host_to_net_u32 (a_rwnd); +} + +always_inline u32 +vnet_sctp_get_arwnd (sctp_selective_ack_chunk_t * s) +{ + return clib_net_to_host_u32 (s->a_rwnd); +} + +always_inline void +vnet_sctp_set_gap_ack_blocks_count (sctp_selective_ack_chunk_t * s, + u16 gap_ack_blocks_count) +{ + vnet_sctp_set_chunk_type (&s->chunk_hdr, SACK); + s->gap_ack_blocks_count = clib_host_to_net_u16 (gap_ack_blocks_count); + + if (s->gap_ack_block_start == NULL) + s->gap_ack_block_start = + clib_mem_alloc (sizeof (u16) * gap_ack_blocks_count); + if (s->gap_ack_block_end == NULL) + s->gap_ack_block_end = + clib_mem_alloc (sizeof (u16) * gap_ack_blocks_count); +} + +always_inline u16 +vnet_sctp_get_gap_ack_blocks_count (sctp_selective_ack_chunk_t * s) +{ + return clib_net_to_host_u32 (s->gap_ack_blocks_count); +} + +always_inline void +vnet_sctp_set_duplicate_tsn_count (sctp_selective_ack_chunk_t * s, + u16 duplicate_tsn_count) +{ + vnet_sctp_set_chunk_type (&s->chunk_hdr, SACK); + s->duplicate_tsn_count = clib_host_to_net_u16 (duplicate_tsn_count); +} + +always_inline u16 +vnet_sctp_get_duplicate_tsn_count (sctp_selective_ack_chunk_t * s) +{ + return clib_net_to_host_u16 (s->duplicate_tsn_count); +} + +/* + * Heartbeat Info + * + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Heartbeat Info Type=1 | HB Info Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / Sender-Specific Heartbeat Info / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_opt_params_hdr_t param_hdr; + + /* + * The Sender-Specific Heartbeat Info field should normally include + * information about the sender's current time when this HEARTBEAT + * chunk is sent and the destination transport address to which this + * HEARTBEAT is sent. + * This information is simply reflected back by the receiver in the + * HEARTBEAT ACK message. + * + * Note also that the HEARTBEAT message is both for reachability + * checking and for path verification. + * When a HEARTBEAT chunk is being used for path verification purposes, + * it MUST hold a 64-bit random nonce. + */ + u64 hb_info; + +} sctp_hb_info_param_t; + +always_inline void +vnet_sctp_set_heartbeat_info (sctp_hb_info_param_t * h, u64 hb_info, + u16 hb_info_length) +{ + h->hb_info = clib_host_to_net_u16 (1); + h->param_hdr.length = clib_host_to_net_u16 (hb_info_length); + h->hb_info = clib_host_to_net_u64 (hb_info); +} + +/* + * Heartbeat Request + * + * An endpoint should send this chunk to its peer endpoint to probe the + * reachability of a particular destination transport address defined in + * the present association. + * The parameter field contains the Heartbeat Information, which is a + * variable-length opaque data structure understood only by the sender. + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 4 | Chunk Flags | Heartbeat Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / Heartbeat Information TLV (Variable-Length) / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_header_t sctp_hdr; + sctp_chunks_common_hdr_t chunk_hdr; + sctp_hb_info_param_t hb_info; + +} sctp_hb_req_chunk_t; + +always_inline void +vnet_sctp_set_hb_request_info (sctp_hb_req_chunk_t * h, + sctp_hb_info_param_t * hb_info) +{ + vnet_sctp_set_chunk_type (&h->chunk_hdr, HEARTBEAT); + memcpy (&h->hb_info, hb_info, sizeof (h->hb_info)); +} + +/* + * Heartbeat Acknowledgement + * + * An endpoint should send this chunk to its peer endpoint as a response + * to a HEARTBEAT chunk. + * A HEARTBEAT ACK is always sent to the source IP address of the IP datagram + * containing the HEARTBEAT chunk to which this ack is responding. + */ +/* + * + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 5 | Chunk Flags | Heartbeat Ack Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / Heartbeat Information TLV (Variable-Length) / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef sctp_hb_req_chunk_t sctp_hb_ack_chunk_t; + +always_inline void +vnet_sctp_set_hb_ack_info (sctp_hb_ack_chunk_t * h, + sctp_hb_info_param_t * hb_info) +{ + vnet_sctp_set_chunk_type (&h->chunk_hdr, HEARTBEAT_ACK); + memcpy (&h->hb_info, hb_info, sizeof (h->hb_info)); +} + +/* + * Error cause + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Cause Code | Cause Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * / Cause-Specific Information / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +typedef struct +{ + + sctp_opt_params_hdr_t param_hdr; + u64 cause_info; + +} sctp_err_cause_param_t; + +/* + * Abort Association (ABORT) + * + * The ABORT chunk is sent to the peer of an association to close the + * association. The ABORT chunk may contain Cause Parameters to inform + * the receiver about the reason of the abort. DATA chunks MUST NOT be + * bundled with ABORT. Control chunks (except for INIT, INIT ACK, and + * SHUTDOWN COMPLETE) MAY be bundled with an ABORT, but they MUST be + * placed before the ABORT in the SCTP packet or they will be ignored by + * the receiver. + * + * If an endpoint receives an ABORT with a format error or no TCB is + * found, it MUST silently discard it. Moreover, under any + * circumstances, an endpoint that receives an ABORT MUST NOT respond to + * that ABORT by sending an ABORT of its own. + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 6 |Reserved |T| Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / zero or more Error Causes / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_header_t sctp_hdr; + sctp_chunks_common_hdr_t chunk_hdr; + sctp_err_cause_param_t err_causes[]; + +} sctp_abort_chunk_t; + +always_inline void +vnet_sctp_set_tbit (sctp_abort_chunk_t * a) +{ + vnet_sctp_set_chunk_type (&a->chunk_hdr, ABORT); + // a->chunk_hdr.flags = clib_host_to_net_u16 (1); +} + +always_inline void +vnet_sctp_unset_tbit (sctp_abort_chunk_t * a) +{ + vnet_sctp_set_chunk_type (&a->chunk_hdr, ABORT); + // a->chunk_hdr.flags = clib_host_to_net_u16 (0); +} + +/* + * Shutdown Association (SHUTDOWN) + * + * An endpoint in an association MUST use this chunk to initiate a + * graceful close of the association with its peer. + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 7 | Chunk Flags | Length = 8 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Cumulative TSN Ack | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_header_t sctp_hdr; + sctp_chunks_common_hdr_t chunk_hdr; + /* + * This parameter contains the TSN of the last chunk received in + * sequence before any gaps. + * + * Note: Since the SHUTDOWN message does not contain Gap Ack Blocks, + * it cannot be used to acknowledge TSNs received out of order. In a + * SACK, lack of Gap Ack Blocks that were previously included + * indicates that the data receiver reneged on the associated DATA + * chunks. Since SHUTDOWN does not contain Gap Ack Blocks, the + * receiver of the SHUTDOWN shouldn't interpret the lack of a Gap Ack + * Block as a renege. + */ + u32 cumulative_tsn_ack; + +} sctp_shutdown_association_chunk_t; + +always_inline void +vnet_sctp_set_tsn_last_received_chunk (sctp_shutdown_association_chunk_t * s, + u32 tsn_last_chunk) +{ + vnet_sctp_set_chunk_type (&s->chunk_hdr, SHUTDOWN); + s->cumulative_tsn_ack = clib_host_to_net_u32 (tsn_last_chunk); +} + +/* + * Shutdown Acknowledgement (SHUTDOWN ACK) + * + * This chunk MUST be used to acknowledge the receipt of the SHUTDOWN + * chunk at the completion of the shutdown process. + */ +/* + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 8 |Chunk Flags | Length = 4 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct +{ + sctp_header_t sctp_hdr; + sctp_chunks_common_hdr_t chunk_hdr; +} sctp_shutdown_ack_chunk_t; + +always_inline void +vnet_sctp_fill_shutdown_ack (sctp_shutdown_ack_chunk_t * s) +{ + vnet_sctp_set_chunk_type (&s->chunk_hdr, SHUTDOWN_ACK); + vnet_sctp_set_chunk_length (&s->chunk_hdr, 4); +} + +#endif /* included_vnet_sctp_packet_h */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |