RFC 9260
Stream Control Transmission Protocol
Stream Control Transmission Protocol โจ
Okay bestie, this is RFC 9260 ๐, and it's titled Stream Control Transmission Protocol (SCTP). It was published in June 2022 by the IETF. The authors are R. Stewart from Netflix, Inc., M. Tรผxen from Mรผnster Univ. of Appl. Sciences, and K. Nielsen from Kamstrup A/S. It's an Internet Standards Track document, with ISSN 2070-1721 ๐ .
It obsoletes RFC 4460, RFC 4960, RFC 6096, RFC 7053, and RFC 8540. There's no Updates line in the header, so nothing gets updated ๐ฆ.
Abstract โจ
This doc describes SCTP and replaces RFC 4960 ๐. It also brings in the chunk flags registry spec from RFC 6096 and the I bit spec for DATA chunks from RFC 7053, so those two are obsoleted too ๐. And since RFCs 4460 and 8540 are errata for SCTP, this document obsoletes them as well ๐.
SCTP was originally built to carry PSTN signaling messages over IP networks, which is very old-school phone-network energy ๐. It's also a good fit for other stuff, like WebRTC ๐ธ.
SCTP is a reliable transport protocol that runs on top of a connectionless packet network, like IP ๐. It gives its users these services:
- acknowledged, error-free, non-duplicated transfer of user data ๐
- data fragmentation so it fits the discovered Path Maximum Transmission Unit (PMTU) size ๐งฉ
- sequenced delivery of user messages within multiple streams, with an option for order-of-arrival delivery of individual user messages โจ
- optional bundling of multiple user messages into a single SCTP packet ๐
- network-level fault tolerance through support for multi-homing at either or both ends of an association ๐
The design also has solid congestion avoidance behavior and resists flooding and masquerade attacks. Iconic, honestly ๐ฅ.
Status of This Memo โจ
This is an Internet Standards Track document ๐.
This document is a product of the Internet Engineering Task Force (IETF) ๐. It reflects the consensus of the IETF community, got public review, and was approved for publication by the Internet Engineering Steering Group (IESG) ๐. For more on Internet Standards, check Section 2 of RFC 7841 ๐.
For the current status of this document, any errata, and how to send feedback, go to https://www.rfc-editor.org/info/rfc9260 ๐ฆ.
Copyright Notice โจ
Copyright (c) 2022 IETF Trust and the persons identified as the document authors. All rights reserved ๐.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents, which are at https://trustee.ietf.org/license-info and apply on the date this document was published. Please read these carefully, because they spell out your rights and restrictions for this document ๐. Code Components pulled out of this document must include Revised BSD License text, as described in Section 4.e of the Trust Legal Provisions. Those components come without warranty, as described in the Revised BSD License ๐.
This document may contain material from IETF Documents or IETF Contributions that were published or made publicly available before November 10, 2008 ๐ฐ๏ธ. The people who control the copyright in some of that material may not have given the IETF Trust permission to allow modifications outside the IETF Standards Process. Unless you get an adequate license from those copyright holders, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside that process. The only exceptions are formatting it for publication as an RFC or translating it into languages other than English ๐ โโ๏ธ.
Table of Contents โจ
1. Introduction
1.1. Motivation
1.2. Architectural View of SCTP
1.3. Key Terms
1.4. Abbreviations
1.5. Functional View of SCTP
1.5.1. Association Startup and Takedown
1.5.2. Sequenced Delivery within Streams
1.5.3. User Data Fragmentation
1.5.4. Acknowledgement and Congestion Avoidance
1.5.5. Chunk Bundling
1.5.6. Packet Validation
1.5.7. Path Management
1.6. Serial Number Arithmetic
1.7. Changes from RFC 4960
2. Conventions
3. SCTP Packet Format
3.1. SCTP Common Header Field Descriptions
3.2. Chunk Field Descriptions
3.2.1. Optional/Variable-Length Parameter Format
3.2.2. Reporting of Unrecognized Parameters
3.3. SCTP Chunk Definitions
3.3.1. Payload Data (DATA) (0)
3.3.2. Initiation (INIT) (1)
3.3.2.1. Optional or Variable-Length Parameters in INIT
chunks
3.3.3. Initiation Acknowledgement (INIT ACK) (2)
3.3.3.1. Optional or Variable-Length Parameters in INIT ACK
Chunks
3.3.4. Selective Acknowledgement (SACK) (3)
3.3.5. Heartbeat Request (HEARTBEAT) (4)
3.3.6. Heartbeat Acknowledgement (HEARTBEAT ACK) (5)
3.3.7. Abort Association (ABORT) (6)
3.3.8. Shutdown Association (SHUTDOWN) (7)
3.3.9. Shutdown Acknowledgement (SHUTDOWN ACK) (8)
3.3.10. Operation Error (ERROR) (9)
3.3.10.1. Invalid Stream Identifier (1)
3.3.10.2. Missing Mandatory Parameter (2)
3.3.10.3. Stale Cookie (3)
3.3.10.4. Out of Resource (4)
3.3.10.5. Unresolvable Address (5)
3.3.10.6. Unrecognized Chunk Type (6)
3.3.10.7. Invalid Mandatory Parameter (7)
3.3.10.8. Unrecognized Parameters (8)
3.3.10.9. No User Data (9)
3.3.10.10. Cookie Received While Shutting Down (10)
3.3.10.11. Restart of an Association with New Addresses (11)
3.3.10.12. User-Initiated Abort (12)
3.3.10.13. Protocol Violation (13)
3.3.11. Cookie Echo (COOKIE ECHO) (10)
3.3.12. Cookie Acknowledgement (COOKIE ACK) (11)
3.3.13. Shutdown Complete (SHUTDOWN COMPLETE) (14)
4. SCTP Association State Diagram
5. Association Initialization
5.1. Normal Establishment of an Association
5.1.1. Handle Stream Parameters
5.1.2. Handle Address Parameters
5.1.3. Generating State Cookie
5.1.4. State Cookie Processing
5.1.5. State Cookie Authentication
5.1.6. An Example of Normal Association Establishment
5.2. Handle Duplicate or Unexpected INIT, INIT ACK, COOKIE ECHO,
and COOKIE ACK Chunks
5.2.1. INIT Chunk Received in COOKIE-WAIT or COOKIE-ECHOED
State (Item B)
5.2.2. Unexpected INIT Chunk in States Other than CLOSED,
COOKIE-ECHOED, COOKIE-WAIT, and SHUTDOWN-ACK-SENT
5.2.3. Unexpected INIT ACK Chunk
5.2.4. Handle a COOKIE ECHO Chunk When a TCB Exists
5.2.4.1. An Example of an Association Restart
5.2.5. Handle Duplicate COOKIE ACK Chunk
5.2.6. Handle Stale Cookie Error
5.3. Other Initialization Issues
5.3.1. Selection of Tag Value
5.4. Path Verification
6. User Data Transfer
6.1. Transmission of DATA Chunks
6.2. Acknowledgement on Reception of DATA Chunks
6.2.1. Processing a Received SACK Chunk
6.3. Management of Retransmission Timer
6.3.1. RTO Calculation
6.3.2. Retransmission Timer Rules
6.3.3. Handle T3-rtx Expiration
6.4. Multi-Homed SCTP Endpoints
6.4.1. Failover from an Inactive Destination Address
6.5. Stream Identifier and Stream Sequence Number
6.6. Ordered and Unordered Delivery
6.7. Report Gaps in Received DATA TSNs
6.8. CRC32c Checksum Calculation
6.9. Fragmentation and Reassembly
6.10. Bundling
7. Congestion Control
7.1. SCTP Differences from TCP Congestion Control
7.2. SCTP Slow-Start and Congestion Avoidance
7.2.1. Slow-Start
7.2.2. Congestion Avoidance
7.2.3. Congestion Control
7.2.4. Fast Retransmit on Gap Reports
7.2.5. Reinitialization
7.2.5.1. Change of Differentiated Services Code Points
7.2.5.2. Change of Routes
7.3. PMTU Discovery
8. Fault Management
8.1. Endpoint Failure Detection
8.2. Path Failure Detection
8.3. Path Heartbeat
8.4. Handle "Out of the Blue" Packets
8.5. Verification Tag
8.5.1. Exceptions in Verification Tag Rules
9. Termination of Association
9.1. Abort of an Association
9.2. Shutdown of an Association
10. ICMP Handling
11. Interface with Upper Layer
11.1. ULP-to-SCTP
11.1.1. Initialize
11.1.2. Associate
11.1.3. Shutdown
11.1.4. Abort
11.1.5. Send
11.1.6. Set Primary
11.1.7. Receive
11.1.8. Status
11.1.9. Change Heartbeat
11.1.10. Request Heartbeat
11.1.11. Get SRTT Report
11.1.12. Set Failure Threshold
11.1.13. Set Protocol Parameters
11.1.14. Receive Unsent Message
11.1.15. Receive Unacknowledged Message
11.1.16. Destroy SCTP Instance
11.2. SCTP-to-ULP
11.2.1. DATA ARRIVE Notification
11.2.2. SEND FAILURE Notification
11.2.3. NETWORK STATUS CHANGE Notification
11.2.4. COMMUNICATION UP Notification
11.2.5. COMMUNICATION LOST Notification
11.2.6. COMMUNICATION ERROR Notification
11.2.7. RESTART Notification
11.2.8. SHUTDOWN COMPLETE Notification
12. Security Considerations
12.1. Security Objectives
12.2. SCTP Responses to Potential Threats
12.2.1. Countering Insider Attacks
12.2.2. Protecting against Data Corruption in the Network
12.2.3. Protecting Confidentiality
12.2.4. Protecting against Blind Denial-of-Service Attacks
12.2.4.1. Flooding
12.2.4.2. Blind Masquerade
12.2.4.3. Improper Monopolization of Services
12.3. SCTP Interactions with Firewalls
12.4. Protection of Non-SCTP-capable Hosts
13. Network Management Considerations
14. Recommended Transmission Control Block (TCB) Parameters
14.1. Parameters Necessary for the SCTP Instance
14.2. Parameters Necessary per Association (i.e., the TCB)
14.3. Per Transport Address Data
14.4. General Parameters Needed
15. IANA Considerations
15.1. IETF-Defined Chunk Extension
15.2. IETF-Defined Chunk Flags Registration
15.3. IETF-Defined Chunk Parameter Extension
15.4. IETF-Defined Additional Error Causes
15.5. Payload Protocol Identifiers
15.6. Port Numbers Registry
16. Suggested SCTP Protocol Parameter Values
17. References
17.1. Normative References
17.2. Informative References
Appendix A. CRC32c Checksum Calculation
Acknowledgements
Authors' Addresses
1. Introduction โจ
This section explains where SCTP came from, what services it offers, and the basic concepts you need before the detailed protocol description makes sense ๐ง .
This document obsoletes [RFC4960] ๐ . On top of that, it brings in the chunk flags registry spec from [RFC6096] and the I bit spec for DATA chunks from [RFC7053] ๐. So [RFC6096] and [RFC7053] are obsoleted by this document too โจ.
To be continued in part 2 ๐ฆ
1.1. Motivation โจ
okay so, TCP [RFC0793] has been the main queen of reliable data transfer on IP networks for ages, and honestly it has earned that crown ๐. But more and more apps were like "ugh, TCP is lowkey too limiting" and just built their own reliable transfer on top of UDP [RFC0768] ๐ . Here's what they wanted to get away from:
- TCP gives you reliable transfer AND strict in-order delivery, bundled together. Some apps only need reliability and don't care about sequence, and others would be happy with partial ordering. Either way, TCP's head-of-line blocking adds delay nobody asked for ๐ญ.
- TCP is a stream, and that's often a vibe-killer ๐. Apps end up adding their own record marking to show where each message starts and ends, and they use the push facility on purpose so a full message gets sent in a reasonable amount of time ๐ซถ.
- TCP sockets have a limited scope, which makes it harder to get highly available data transfer when you're using multi-homed hosts ๐.
- TCP is pretty vulnerable to denial-of-service attacks, like SYN attacks. Not it ๐.
Transporting PSTN signaling over the IP network is an app where every single one of these TCP limitations shows up ๐จ. That's what directly motivated SCTP, but other apps might find SCTP a really good match for what they need too โจ. A great example is the use of data channels in the WebRTC infrastructure ๐.
1.2. Architectural View of SCTP ๐ฆ
okay, picture this. SCTP sits as a layer between the SCTP user application (the "SCTP user" for short) and a connectionless packet network service, like IP ๐ง. The rest of this document assumes SCTP runs on top of IP. The main thing SCTP does is reliably transfer user messages between peer SCTP users, and it does that inside an association between two SCTP endpoints ๐. Section 11 of this document sketches the API at the boundary between SCTP and the SCTP upper layers, so check that out too ๐ธ.
SCTP is connection oriented, but an SCTP association is a much bigger concept than a TCP connection, and that's the main thing to get ๐. During association startup, each SCTP endpoint (see Section 1.3) gives the other endpoint a list of transport addresses (multiple IP addresses paired with an SCTP port) that it can be reached at and that it will send SCTP packets from ๐ฌ. The association covers transfers over all of the possible source/destination combinations you can make from each endpoint's lists. Main character energy, honestly ๐โจ.
_____________ _____________
| SCTP User | | SCTP User |
| Application | | Application |
|-------------| |-------------|
| SCTP | | SCTP |
| Transport | | Transport |
| Service | | Service |
|-------------| |-------------|
| |One or more ---- One or more| |
| IP Network |IP address \/ IP address| IP Network |
| Service |appearances /\ appearances| Service |
|_____________| ---- |_____________|
SCTP Node A |<-------- Network transport ------->| SCTP Node B
Figure 1: An SCTP Association ๐
Okay, and in addition to wrapping SCTP packets in IPv4 or IPv6, you can also encapsulate SCTP packets in UDP as specified in [RFC6951], or encapsulate them in DTLS as specified in [RFC8261] ๐ ๐. So many options, bestie, I'm obsessed ๐ญ๐ซถ.
1.3. Key Terms ๐
Okay bestie, some of these words already popped up in the earlier sections, so this is the glossary, all in one place. Read it once and we'll all be speaking the same language ๐ซถ
- Active Destination Transport Address: A transport address on a peer endpoint that a transmitting endpoint considers available for receiving user messages. โจ
- Association Maximum DATA Chunk Size (AMDCS): The smallest Path Maximum DATA Chunk Size (PMDCS) of all destination addresses. ๐
- Bundling of Chunks: An optional multiplexing operation, whereby more than one chunk can be carried in the same SCTP packet. ๐
- Bundling of User Messages: An optional multiplexing operation, whereby more than one user message can be carried in the same SCTP packet. Each user message occupies its own DATA chunk. ๐ง
- Chunk: A unit of information within an SCTP packet, consisting of a chunk header and chunk-specific content. ๐
- Congestion Window (cwnd): An SCTP variable that limits outstanding data, in number of bytes, that a sender can send to a particular destination transport address before receiving an acknowledgement. ๐ฆ
- Control Chunk: A chunk not being used for transmitting user data, i.e., every chunk that is not a DATA chunk. ๐ โโ๏ธ
- Cumulative TSN Ack Point: The Transmission Sequence Number (TSN) of the last DATA chunk acknowledged via the Cumulative TSN Ack field of a SACK chunk. ๐
- Flightsize: The number of bytes of outstanding data to a particular destination transport address at any given time. โ๏ธ
- Idle Destination Address: An address that has not had user messages sent to it within some length of time, normally the
'HB.interval'or greater. ๐ด - Inactive Destination Transport Address: An address that is considered inactive due to errors and unavailable to transport user messages. ๐ค
- Message (or User Message): Data submitted to SCTP by the Upper-Layer Protocol (ULP). ๐
- Network Byte Order: Most significant byte first, a.k.a., big endian. ๐ข
- Ordered Message: A user message that is delivered in order with respect to all previous user messages sent within the stream on which the message was sent. ๐
- Outstanding Data (or Data Outstanding or Data In Flight): The total size of the DATA chunks associated with outstanding TSNs. A retransmitted DATA chunk is counted once in outstanding data. A DATA chunk that is classified as lost but that has not yet been retransmitted is not in outstanding data. ๐ซ
- Outstanding TSN (at an SCTP Endpoint): A TSN (and the associated DATA chunk) that has been sent by the endpoint but for which it has not yet received an acknowledgement. โณ
- "Out of the Blue" (OOTB) Packet: A correctly formed packet, for which the receiver cannot identify the association it belongs to. See Section 8.4. ๐ธ
- Path: The route taken by the SCTP packets sent by one SCTP endpoint to a specific destination transport address of its peer SCTP endpoint. Sending to different destination transport addresses does not necessarily guarantee getting separate paths. Within this specification, a path is identified by the destination transport address, since the routing is assumed to be stable. This includes, in particular, the source address being selected when sending packets to the destination address. ๐ค๏ธ
- Path Maximum DATA Chunk Size (PMDCS): The maximum size (including the DATA chunk header) of a DATA chunk that fits into an SCTP packet not exceeding the PMTU of a particular destination address. ๐งฉ
- Path Maximum Transmission Unit (PMTU): The maximum size (including the SCTP common header and all chunks including their paddings) of an SCTP packet that can be sent to a particular destination address without using IP-level fragmentation. ๐ฆ
- Primary Path: The destination and source address that will be put into a packet outbound to the peer endpoint by default. The definition includes the source address since an implementation MAY wish to specify both destination and source address to better control the return path taken by reply chunks and on which interface the packet is transmitted when the data sender is multi-homed. ๐
- Receiver Window (rwnd): An SCTP variable a data sender uses to store the most recently calculated receiver window of its peer, in number of bytes. This gives the sender an indication of the space available in the receiver's inbound buffer. ๐ช
- SCTP Association: A protocol relationship between SCTP endpoints, composed of the two SCTP endpoints and protocol state information, including Verification Tags and the currently active set of Transmission Sequence Numbers (TSNs), etc. An association can be uniquely identified by the transport addresses used by the endpoints in the association. Two SCTP endpoints MUST NOT have more than one SCTP association between them at any given time. ๐ค
- SCTP Endpoint: The logical sender/receiver of SCTP packets. On a multi-homed host, an SCTP endpoint is represented to its peers as a combination of a set of eligible destination transport addresses to which SCTP packets can be sent and a set of eligible source transport addresses from which SCTP packets can be received. All transport addresses used by an SCTP endpoint MUST use the same port number but can use multiple IP addresses. A transport address used by an SCTP endpoint MUST NOT be used by another SCTP endpoint. In other words, a transport address is unique to an SCTP endpoint. ๐โโ๏ธ
- SCTP Packet (or Packet): The unit of data delivery across the interface between SCTP and the connectionless packet network (e.g., IP). An SCTP packet includes the common SCTP header, possible SCTP control chunks, and user data encapsulated within SCTP DATA chunks. ๐
- SCTP User Application (or SCTP User): The logical higher-layer application entity that uses the services of SCTP, also called the Upper-Layer Protocol (ULP). ๐ฉโ๐ป
- Slow-Start Threshold (ssthresh): An SCTP variable. This is the threshold that the endpoint will use to determine whether to perform slow-start or congestion avoidance on a particular destination transport address. Ssthresh is in number of bytes. ๐ฑ
- State Cookie: A container of all information needed to establish an association. ๐ช
- Stream: A unidirectional logical channel established from one to another associated SCTP endpoint, within which all user messages are delivered in sequence, except for those submitted to the unordered delivery service. ๐ฃ๏ธ
- Note: The relationship between stream numbers in opposite directions is strictly a matter of how the applications use them. It is the responsibility of the SCTP user to create and manage these correlations if they are so desired. ๐๏ธ
- Stream Sequence Number: A 16-bit sequence number used internally by SCTP to ensure sequenced delivery of the user messages within a given stream. One Stream Sequence Number is attached to each ordered user message. ๐
- Tie-Tags: Two 32-bit random numbers that together make a 64-bit nonce. These tags are used within a State Cookie and TCB so that a newly restarting association can be linked to the original association within the endpoint that did not restart and yet not reveal the true Verification Tags of an existing association. ๐๏ธ
- Transmission Control Block (TCB): An internal data structure created by an SCTP endpoint for each of its existing SCTP associations to other SCTP endpoints. TCB contains all the status and operational information for the endpoint to maintain and manage the corresponding association. ๐๏ธ
- Transmission Sequence Number (TSN): A 32-bit sequence number used internally by SCTP. One TSN is attached to each chunk containing user data to permit the receiving SCTP endpoint to acknowledge its receipt and detect duplicate deliveries. ๐ข
- Transport Address: A transport address is typically defined by a network-layer address, a transport-layer protocol, and a transport-layer port number. In the case of SCTP running over IP, a transport address is defined by the combination of an IP address and an SCTP port number (where SCTP is the transport protocol). ๐ฌ
- Unordered Message: Unordered messages are "unordered" with respect to any other message; this includes both other unordered messages as well as other ordered messages. An unordered message might be delivered prior to or later than ordered messages sent on the same stream. ๐ฒ
- User Message: The unit of data delivery across the interface between SCTP and its user. ๐ฌ
- Verification Tag: A 32-bit unsigned integer that is randomly generated. The Verification Tag provides a key that allows a receiver to verify that the SCTP packet belongs to the current association and is not an old or stale packet from a previous association. ๐
1.4. Abbreviations ๐ค
Here's the cheat sheet for all the acronyms we've been throwing around, so nobody gets lost in the alphabet soup ๐ฒ
MAC Message Authentication Code [RFC2104]
RTO Retransmission Timeout
RTT Round-Trip Time
RTTVAR Round-Trip Time Variation
SCTP Stream Control Transmission Protocol
SRTT Smoothed RTT
TCB Transmission Control Block
TLV Type-Length-Value coding format
TSN Transmission Sequence Number
ULP Upper-Layer Protocol
1.5. Functional View of SCTP ๐ฆ
Okay so the SCTP transport service is lowkey a big multitasker, and it can be broken down into a bunch of functions. The diagram below shows them all, and we'll walk through each one in the rest of this section ๐
SCTP User Application
-----------------------------------------------------
_____________ ____________________
| | | Sequenced Delivery |
| Association | | within Streams |
| | |____________________|
| Startup |
| | ____________________________
| and | | User Data Fragmentation |
| | |____________________________|
| Takedown |
| | ____________________________
| | | Acknowledgement |
| | | and |
| | | Congestion Avoidance |
| | |____________________________|
| |
| | ____________________________
| | | Chunk Bundling |
| | |____________________________|
| |
| | ________________________________
| | | Packet Validation |
| | |________________________________|
| |
| | ________________________________
| | | Path Management |
|_____________| |________________________________|
Figure 2: Functional View of the SCTP Transport Service
1.5.1. Association Startup and Takedown ๐
okay so an association gets started when the SCTP user asks for it (peep the ASSOCIATE (or SEND) primitive in Section 11 ๐).
a cookie mechanism, similar to the one Karn and Simpson described in [RFC2522], gets used during initialization to protect against synchronization attacks ๐ก๏ธ. it's a four-way handshake, and the last two legs are allowed to carry user data so setup is extra quick โก. the startup sequence is in Section 5 of this document.
SCTP also does graceful close (aka shutdown) of an active association when the SCTP user requests it. check out the SHUTDOWN primitive in Section 11 ๐ . it can also do an ungraceful close (aka abort), either because the user hit the ABORT primitive or because the SCTP layer spotted an error ๐. Section 9 covers both the graceful and the ungraceful close procedures.
SCTP does NOT do a half-open state like TCP, where one side keeps sending while the other end is closed ๐ โโ๏ธ. the word NOT here is just me being loud. wait, that's wrong, it isn't in caps in the original, so let me say it properly: SCTP does not support a half-open state (like TCP) where one side keeps sending data while the other end is closed. when either endpoint does a shutdown, the association on each peer stops accepting new data from its user and only delivers the data already queued at the time of the graceful close (see Section 9) ๐ธ.
1.5.2. Sequenced Delivery within Streams ๐
the word "stream" in SCTP means a sequence of user messages that have to be delivered to the upper-layer protocol in order, compared to the other messages in that same stream. this is different from TCP, where a stream is a sequence of bytes (in this document, a byte is assumed to be 8 bits) ๐ง.
at association startup, the SCTP user can say how many streams the association should support. this number gets negotiated with the remote end (see Section 5.1.1) ๐ค. user messages are tied to stream numbers (SEND and RECEIVE primitives; Section 11). internally, SCTP gives each message the SCTP user passes in a Stream Sequence Number. on the receiving side, SCTP makes sure messages reach the SCTP user in sequence within a given stream โจ. the cute part is that while one stream is stuck waiting for the next in-sequence message, delivery from the other streams can keep going ๐ฆ.
SCTP also has a way to skip the sequenced delivery service. user messages sent this way get delivered to the SCTP user the moment they arrive ๐โโ๏ธ.
1.5.3. User Data Fragmentation ๐งฉ
when it's needed, SCTP fragments user messages so the SCTP packet handed to the lower layer doesn't go over the PMTU ๐. once a user message has been fragmented, that fragmentation can't be changed anymore ๐. on receipt, fragments get reassembled into complete messages before they're passed to the SCTP user ๐.
1.5.4. Acknowledgement and Congestion Avoidance ๐
SCTP gives each user data fragment or unfragmented message a Transmission Sequence Number (TSN). the TSN is independent of any Stream Sequence Number assigned at the stream level ๐. the receiving end acknowledges every TSN it receives, even if there are gaps in the sequence. if a user data fragment or unfragmented message needs a retransmit, the TSN it was given is reused. that's how reliable delivery stays functionally separate from sequenced stream delivery ๐.
the acknowledgement and congestion avoidance function handles packet retransmission when a timely acknowledgement hasn't come back. retransmission is governed by congestion avoidance procedures that are similar to the ones used for TCP. see Sections 6 and 7 for the detailed protocol procedures for this function ๐ฆข.
1.5.5. Chunk Bundling ๐ฆ
as Section 3 describes, the SCTP packet handed to the lower layer is a common header followed by one or more chunks. each chunk holds either user data or SCTP control information ๐ . an SCTP implementation that supports bundling on the sender side might hold back sending user messages so the matching DATA chunks can be bundled together ๐.
the SCTP user can choose to ask that an SCTP implementation does not delay sending a user message just for this purpose. even when the user picks that option, the implementation might still delay the sending for other reasons (for example, congestion control or flow control), and it might also bundle multiple DATA chunks if it can ๐.
1.5.6. Packet Validation ๐
the SCTP common header includes a mandatory Verification Tag field and a 32-bit checksum field (see Appendix A for a description of the 32-bit Cyclic Redundancy Check (CRC32c) checksum) ๐. each end of the association picks the Verification Tag value during association startup. packets that show up without the expected Verification Tag value get discarded, which protects against blind masquerade attacks and stale SCTP packets from a previous association ๐ก๏ธ. the sender of each SCTP packet sets the CRC32c checksum to add more protection against data corruption in the network. the receiver of an SCTP packet with an invalid CRC32c checksum silently discards that packet ๐คซ.
1.5.7. Path Management ๐ฃ๏ธ
the sending SCTP user can change the set of transport addresses used as destinations for SCTP packets, using the primitives in Section 11 ๐บ๏ธ. the SCTP path management function monitors reachability with heartbeats when other packet traffic isn't enough to tell, and it tells the SCTP user whenever the reachability of any transport address of the peer endpoint changes ๐ก. for each outgoing SCTP packet, the path management function picks the destination transport address based on the SCTP user's instructions and the currently perceived reachability status of the eligible destination set ๐ฏ. it's also in charge of reporting the eligible set of local transport addresses to the peer endpoint during association startup, and of passing the transport addresses returned from the peer endpoint on to the SCTP user ๐.
at association startup, a primary path is defined for each SCTP endpoint, and it's used to send SCTP packets normally ๐.
on the receiving end, path management is responsible for checking that a valid SCTP association exists for an inbound SCTP packet before the packet gets passed on for further processing ๐ต๏ธโโ๏ธ.
Note: Path Management and Packet Validation are done at the same time; although described separately above, in reality, they cannot be performed as separate items. ๐ซถ
1.6. Serial Number Arithmetic ๐ข
it's super important to remember that the Transmission Sequence Number space is finite, even though it's very large. this space ranges from 0 to 2^32 - 1. because the space is finite, all arithmetic dealing with Transmission Sequence Numbers MUST be performed modulo 2^32. this unsigned arithmetic keeps the relationship between sequence numbers intact as they cycle from 2^32 - 1 back to 0. computer modulo arithmetic has some subtleties, so you have to be really careful when you program comparisons of these values ๐ญ. when referring to TSNs, the symbol <= means "less than or equal" (modulo 2^32).
comparisons and arithmetic on TSNs in this document SHOULD use Serial Number Arithmetic, as defined in [RFC1982], where SERIAL_BITS = 32.
an endpoint SHOULD NOT transmit a DATA chunk with a TSN that is more than 2^31 - 1 above the beginning TSN of its current send window. doing that will cause problems when comparing TSNs ๐.
Transmission Sequence Numbers wrap around when they reach 2^32 - 1. that means the next TSN a DATA chunk MUST use after transmitting TSN = 2^32 - 1 is TSN = 0 ๐.
any arithmetic done on Stream Sequence Numbers SHOULD use Serial Number Arithmetic, as defined in [RFC1982], where SERIAL_BITS = 16. all other arithmetic and comparisons in this document use normal arithmetic ๐งฎ.
1.7. Changes from RFC 4960 ๐
SCTP was originally defined in [RFC4960], which this document obsoletes. if you're curious about the details of the various changes this document includes, go check out [RFC8540] ๐.
on top of these and some further editorial changes, this document also includes the following changes:
- Update references. ๐
- Improve the language related to requirements levels. ๐ฌ
- Allow the ASSOCIATE primitive to take multiple remote addresses; also refer to the socket API specification. ๐
- Refer to the Packetization Layer Path MTU Discovery (PLPMTUD) specification for path MTU discovery. ๐ค๏ธ
- Move the description of ICMP handling from the Appendix to the main text. ๐
- Remove the Appendix describing Explicit Congestion Notification (ECN) handling from the document. ๐
- Describe the packet size handling more precisely by introducing PMTU, PMDCS, and AMDCS. ๐
- Add the definition of control chunk. ๐งธ
- Improve the description of the handling of INIT and INIT ACK chunks with invalid mandatory parameters. ๐ซง
- Allow using
L > 1for Appropriate Byte Counting (ABC) during slow start. ๐ข - Explicitly describe the reinitialization of the congestion controller on route changes. ๐บ๏ธ
- Improve the terminology to make it clear that this specification does not describe a full mesh architecture. ๐ธ๏ธ
- Improve the description of sequence number generation (Transmission Sequence Number and Stream Sequence Number). ๐ข
- Improve the description of reneging. ๐ โโ๏ธ
- Don't require the change of the Cumulative TSN Ack anymore for increasing the congestion window. This improves the consistency with the handling in congestion avoidance. ๐
- Improve the description of the State Cookie. ๐ช
- Fix the API for retrieving messages in case of association failures. ๐ ๏ธ
2. Conventions ๐
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here โจ.
3. SCTP Packet Format โจ
okay so an SCTP packet is basically a little package ๐ with a common header up front and then a bunch of chunks after it. Each chunk holds either control info or user data, so the chunks are the actual juicy stuff and the header is the wrapper that says who it's from and where it's headed ๐
Here's the layout (it's giving boxes ๐ฆ):
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Okay, the big bundling rule ๐จ: INIT, INIT ACK, and SHUTDOWN COMPLETE chunks MUST NOT be bundled with any other chunk into an SCTP packet. They're solo-only, no exceptions ๐ โโ๏ธ Everything else MAY be bundled together to form an SCTP packet, as long as that packet does not exceed the PMTU. For the full bundling tea, check Section 6.10 ๐ง
If a user data message is too big to fit into one SCTP packet, no panic ๐ญ it can be fragmented into multiple chunks using the procedure defined in Section 6.9.
And one more thing that's non-negotiable: all integer fields in an SCTP packet MUST be transmitted in network byte order, unless otherwise stated ๐ขโจ
3.1. SCTP Common Header Field Descriptions
Let's meet the header fields, bestie ๐ซถ here's the picture first:
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Source Port Number: 16 bits (unsigned integer) ๐ธ This is the SCTP sender's port number. The receiver can use it together with the source IP address, the SCTP Destination Port Number, and possibly the destination IP address to figure out which association this packet belongs to. The Source Port Number 0 MUST NOT be used ๐ โโ๏ธ
Destination Port Number: 16 bits (unsigned integer) ๐ฆ This is the SCTP port number the packet is destined for. The receiving host uses this port number to de-multiplex the SCTP packet to the correct receiving endpoint/application, so it's basically the address label on the envelope ๐ The Destination Port Number 0 MUST NOT be used.
Verification Tag: 32 bits (unsigned integer) ๐ The receiver of an SCTP packet uses the Verification Tag to validate the sender of the packet. It's the secret handshake ๐คซ On transmit, the value of the Verification Tag MUST be set to the value of the Initiate Tag received from the peer endpoint during 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 chunk to be sent. For details, see Sections 8.4 and 8.5.
Checksum: 32 bits (unsigned integer) ๐งฎ This field contains the checksum of the SCTP packet. Its calculation is discussed in Section 6.8. SCTP uses the CRC32c algorithm, as described in Appendix A, to calculate the checksum. Math never looked so iconic ๐
3.2. Chunk Field Descriptions โจ
okay bestie, every chunk in an SCTP packet gets the same four-part outfit: a Chunk Type, Chunk Flags, a Chunk Length, and a Chunk Value ๐ Here's how it's laid out:
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\ \
/ Chunk Value /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Type: 8 bits (unsigned integer) ๐ฆ This tells you what kind of info is inside the Chunk Value. It runs from 0 to 254. The value 255 is saved for future use as an extension field, so it's giving "reserved, don't touch" ๐
The chunk types defined in this document are:
+==========+===========================================+
| 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 | Unassigned |
+----------+-------------------------------------------+
| 63 | Reserved for IETF-defined Chunk |
| | Extensions |
+----------+-------------------------------------------+
| 64 to | Unassigned |
| 126 | |
+----------+-------------------------------------------+
| 127 | Reserved for IETF-defined Chunk |
| | Extensions |
+----------+-------------------------------------------+
| 128 to | Unassigned |
| 190 | |
+----------+-------------------------------------------+
| 191 | Reserved for IETF-defined Chunk |
| | Extensions |
+----------+-------------------------------------------+
| 192 to | Unassigned |
| 254 | |
+----------+-------------------------------------------+
| 255 | Reserved for IETF-defined Chunk |
| | Extensions |
+----------+-------------------------------------------+
Table 1: Chunk Types
โ ๏ธ Heads up: the ECNE and CWR chunk types are reserved for future use of Explicit Congestion Notification (ECN). Not in use yet, so don't go looking for them in your packets ๐
Chunk Types are encoded so that the top 2 bits tell the processing endpoint what to do if it doesn't recognize the Chunk Type. It's like a built-in instruction manual, honestly iconic ๐
+----+--------------------------------------------------+
| 00 | Stop processing this SCTP packet and discard the |
| | unrecognized chunk and all further chunks. |
+----+--------------------------------------------------+
| 01 | Stop processing this SCTP packet, discard the |
| | unrecognized chunk and all further chunks, and |
| | report the unrecognized chunk in an ERROR chunk |
| | using the 'Unrecognized Chunk Type' error cause. |
+----+--------------------------------------------------+
| 10 | Skip this chunk and continue processing. |
+----+--------------------------------------------------+
| 11 | Skip this chunk and continue processing, but |
| | report it in an ERROR chunk using the |
| | 'Unrecognized Chunk Type' error cause. |
+----+--------------------------------------------------+
Table 2: Processing of Unknown Chunks
Chunk Flags: 8 bits ๐ธ What these bits mean depends on the Chunk Type. Unless a chunk says otherwise, they get set to 0 when you send and get ignored when you receive. Chill vibes ๐ง
Chunk Length: 16 bits (unsigned integer) ๐ This is the chunk's total size in bytes, counting the Chunk Type, Chunk Flags, Chunk Length, and Chunk Value fields. So if the Chunk Value is empty, the Length is 4. Chunk padding doesn't count toward this number, but padding on variable-length parameters, except the last parameter in the chunk, does get included ๐
๐ Note: a robust implementation is expected to accept the chunk whether or not the final padding was included in the Chunk Length. Be generous, bestie ๐ซถ
Chunk Value: variable length ๐ This is the actual info being delivered in the chunk. Its usage and format depend on the Chunk Type, so it changes like an outfit for every occasion โจ
The total length of a chunk (Type, Length, and Value fields included) MUST be a multiple of 4 bytes. If it isn't, the sender MUST pad the chunk with all-zero bytes, and that padding is NOT counted in the Chunk Length field. The sender MUST NOT pad with more than 3 bytes. The receiver MUST ignore the padding bytes. Padding rules, locked in ๐
SCTP-defined chunks get the full tea in Section 3.3, and the guidelines for IETF-defined chunk extensions live in Section 15.1 of this document ๐ฆ
3.2.1. Optional/Variable-Length Parameter Format ๐ง
Okay so every SCTP control chunk's value starts with a chunk-type-specific header full of required fields, and then zero or more parameters come after it ๐. The optional and variable-length parameters all use a Type-Length-Value format, and it looks like this:
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 /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Parameter Type: 16 bits (unsigned integer) ๐ The Type field is a 16-bit ID for what kind of parameter it is. It goes from 0 to 65534.
The value 65535 is reserved for IETF-defined extensions. Anything not defined in a specific SCTP chunk's description is reserved for use by IETF, so hands off ๐ โโ๏ธ
Parameter Length: 16 bits (unsigned integer) ๐ธ The Parameter Length field holds the size of the whole parameter in bytes. That counts the Parameter Type, Parameter Length, and Parameter Value fields. So a parameter with a zero-length Parameter Value would have a Parameter Length of 4. The Parameter Length does not include any padding bytes.
Parameter Value: variable length ๐ฆ This is where the actual info being carried in the parameter lives.
The total length of a parameter (counting the Parameter Type, Parameter Length, and Parameter Value fields) MUST be a multiple of 4 bytes. If it isn't, the sender pads the end of the parameter (after the Parameter Value field) with all zero bytes. That padding isn't counted in the Parameter Length field. A sender MUST NOT pad with more than 3 bytes, and the receiver MUST ignore the padding bytes. Padding rules are a lowkey big deal ๐ซถ
The Parameter Types are encoded so that the highest-order 2 bits tell you what to do if the processing endpoint doesn't recognize the Parameter Type. Here's the breakdown:
+----+--------------------------------------------------------+
| 00 | Stop processing this parameter and do not process any |
| | further parameters within this chunk. |
+----+--------------------------------------------------------+
| 01 | Stop processing this parameter, do not process any |
| | further parameters within this chunk, and report the |
| | unrecognized parameter, as described in Section 3.2.2. |
+----+--------------------------------------------------------+
| 10 | Skip this parameter and continue processing. |
+----+--------------------------------------------------------+
| 11 | Skip this parameter and continue processing, but |
| | report the unrecognized parameter, as described in |
| | Section 3.2.2. |
+----+--------------------------------------------------------+
Table 3: Processing of Unknown Parameters
Please note ๐ that when an INIT or INIT ACK chunk is received, in all four cases an INIT ACK or COOKIE ECHO chunk gets sent back in response, respectively. In the 00 or 01 case, the processing of the parameters after the unknown one gets canceled, but nothing that was already processed gets rolled back. Main character processing energy ๐
The actual SCTP parameters are defined in the specific SCTP chunk sections. The rules for IETF-defined parameter extensions are in Section 15.3. Parameter types MUST be unique across all chunks. For example, the parameter type '5' is used to represent an IPv4 address (see Section 3.3.2.1.1). That means '5' is reserved across all chunks to mean an IPv4 address, and it MUST NOT be reused with a different meaning in any other chunk. Don't be that person who recycles type numbers ๐
3.2.2. Reporting of Unrecognized Parameters โจ
Okay so if the receiver of an INIT chunk spots unrecognized parameters and has to report them under Section 3.2.1, it MUST put the "Unrecognized Parameter" parameter(s) in the INIT ACK chunk sent back in response to the INIT chunk. Also, if the receiver of the INIT chunk isn't going to establish an association (for example, because it's out of resources), an "Unrecognized Parameters" error cause would NOT be included with any ABORT chunk sent to the INIT chunk's sender. Wait, let me restate that properly: it would not be included, full stop ๐
Now, if the receiver of any other chunk (like INIT ACK) detects unrecognized parameters and has to report them under Section 3.2.1, it SHOULD bundle the ERROR chunk with the "Unrecognized Parameters" error cause together with the chunk sent in response (like COOKIE ECHO). If the receiver of an INIT ACK chunk can't bundle the COOKIE ECHO chunk with the ERROR chunk, the ERROR chunk MAY be sent separately, but not before the COOKIE ACK chunk has been received. Bundling is giving organized ๐
Any time a COOKIE ECHO chunk is sent in a packet, it MUST be the first chunk. No exceptions, bestie ๐
3.3. SCTP Chunk Definitions ๐ฆ
This section defines the format of the different SCTP chunk types. Let's get into the good stuff โจ
3.3.1. Payload Data (DATA) (0) ๐
The following format MUST be used for the DATA 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 | Res |I|U|B|E| Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TSN |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stream Identifier S | Stream Sequence Number n |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload Protocol Identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\ \
/ User Data (seq n of Stream S) /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Res: 4 bits ๐ All set to 0 on transmit and ignored on receipt.
I bit: 1 bit ๐ฅ The (I)mmediate bit MAY be set by the sender whenever the sender of a DATA chunk can benefit from the corresponding SACK chunk being sent back without delay. See Section 4 of [RFC7053] for a discussion of the benefits.
U bit: 1 bit ๐ง The (U)nordered bit, if set to 1, means this is an unordered DATA chunk, and there's no Stream Sequence Number assigned to it. So the receiver MUST ignore the Stream Sequence Number field.
After reassembly (if it's needed), unordered DATA chunks MUST be dispatched to the upper layer by the receiver without any attempt to reorder them. Chaotic good energy ๐ช๏ธ
If an unordered user message is fragmented, each fragment of the message MUST have its U bit set to 1. Every piece has to match, no exceptions ๐
B bit: 1 bit ๐ The (B)eginning fragment bit, if set, marks the first fragment of a user message.
E bit: 1 bit ๐ธ The (E)nding fragment bit, if set, marks the last fragment of a user message.
Length: 16 bits (unsigned integer) ๐ This field is the length of the DATA chunk in bytes, from the start of the type field to the end of the User Data field, not counting any padding. A DATA chunk with one byte of user data will have the Length field set to 17 (meaning 17 bytes).
A DATA chunk with a User Data field of length L will have the Length field set to (16 + L), meaning 16 + L bytes, where L MUST be greater than 0. Zero-length user data is not it ๐ โโ๏ธ
TSN: 32 bits (unsigned integer) ๐ฆ This value is the TSN for this DATA chunk. The valid range is from 0 to 4294967295 (2^32 - 1). TSN wraps back to 0 after reaching 4294967295, which is very plot twist of it ๐
Stream Identifier S: 16 bits (unsigned integer) ๐ท Identifies the stream that the following user data belongs to.
Stream Sequence Number n: 16 bits (unsigned integer) ๐ This value is the Stream Sequence Number of the following user data within stream S. The valid range is 0 to 65535.
When a user message gets fragmented by SCTP for transport, the same Stream Sequence Number MUST be carried in each of the fragments of the message. Same number, every fragment, always ๐ซถ
Payload Protocol Identifier: 32 bits (unsigned integer) ๐ง This value is an application (or upper layer) specified protocol identifier. The upper layer hands it to SCTP, and SCTP sends it along to its peer. SCTP doesn't use this identifier itself, but certain network entities, as well as the peer application, can use it to figure out what kind of information is in this DATA chunk. This field MUST be sent even in fragmented DATA chunks (so it's still available for agents sitting in the middle of the network). Also, this field isn't touched by an SCTP implementation. The upper layer is responsible for the host to network byte order conversion of this field ๐ง
The value 0 means that the upper layer didn't specify any application identifier for this payload data. Zero is the "no label" vibe โจ
User Data: variable length ๐ 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. Padding is literally the unsung hero ๐
An unfragmented user message MUST have both the B and E bits set to 1. Setting both the B and E bits to 0 means it's a middle fragment of a multi-fragment user message. Here's the summary:
+===+===+===========================================+
| 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 |
+---+---+-------------------------------------------+
Table 4: Fragment Description Flags
When a user message gets fragmented into multiple chunks, the receiver uses the TSNs to reassemble it. That means the TSNs for each fragment of a fragmented user message MUST be strictly sequential. Tiny detail, huge impact ๐ฅ
The TSNs of DATA chunks sent SHOULD be strictly sequential. Aim for it, it's the vibe โจ
Note: The extension described in [RFC8260] can be used to mitigate head of line blocking when transferring large user messages. If your messages are huge and everything's getting stuck behind them, go check that one out ๐
3.3.2. Initiation (INIT) (1) ๐
okay bestie, this is the INIT chunk and it's literally how an SCTP association gets started ๐ฆ two endpoints use it to say "hiii, wanna talk?" ๐ Here's the layout:
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 fixed-length parameters are the must-haves ๐ Unless otherwise noted, each parameter MUST only be included once in the INIT chunk. Obsessed with that rule ๐
+===================================+===========+
| Fixed-Length Parameter | Status |
+===================================+===========+
| Initiate Tag | Mandatory |
+-----------------------------------+-----------+
| Advertised Receiver Window Credit | Mandatory |
+-----------------------------------+-----------+
| Number of Outbound Streams | Mandatory |
+-----------------------------------+-----------+
| Number of Inbound Streams | Mandatory |
+-----------------------------------+-----------+
| Initial TSN | Mandatory |
+-----------------------------------+-----------+
Table 5: Fixed-Length Parameters of INIT Chunks
+===================================+============+================+
| Variable-Length Parameter | 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) | Deprecated | 11 |
+-----------------------------------+------------+----------------+
| Supported Address Types (Note 4) | Optional | 12 |
+-----------------------------------+------------+----------------+
Table 6: Variable-Length Parameters of INIT Chunks
Note 1: INIT chunks can carry multiple addresses, IPv4 and/or IPv6, in any combination. So many options ๐
Note 2: The ECN Capable field is reserved for future use of Explicit Congestion Notification. ๐
Note 3: An INIT chunk MUST NOT contain the Host Name Address parameter. The receiver of an INIT chunk containing a Host Name Address parameter MUST send an ABORT chunk and MAY include an "Unresolvable Address" error cause. Nope, not doing that ๐
Note 4: This parameter, when present, specifies all the address types the sending endpoint can support. If it's absent, that means the sending endpoint can support any address type. โจ
If an INIT chunk shows up with all the mandatory parameters for it, the receiver SHOULD process it and send back an INIT ACK. The receiver 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 instead. Some are just picky, periodt ๐
The Chunk Flags field in INIT chunks is reserved. All bits in it SHOULD be set to 0 by the sender and ignored by the receiver. ๐ง
Initiate Tag: 32 bits (unsigned integer)
The receiver of the INIT chunk (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 chunk transmits within this association. Main character energy for that tag ๐
The Initiate Tag is allowed to have any value except 0. Check Section 5.3.1 for more on picking the tag value. ๐ซถ
If the value of the Initiate Tag in a received INIT chunk is 0, the receiver MUST silently discard the packet. Zero is a no-go, bestie ๐ญ
Advertised Receiver Window Credit (a_rwnd): 32 bits (unsigned integer)
This value is the dedicated buffer space, in number of bytes, that the sender of the INIT chunk has reserved for this association along with this window. Buffer space, but make it a reservation ๐
The Advertised Receiver Window Credit MUST NOT be smaller than 1500.
If a receiver gets an INIT chunk with a_rwnd set to less than 1500, it MUST discard the packet. It SHOULD send back a packet containing an ABORT chunk, using the Initiate Tag as the Verification Tag. And it MUST NOT change the state of any existing association. Not on my watch ๐
โโ๏ธ
During the life of the association, this buffer space SHOULD NOT be reduced. Dedicated buffers shouldn't get taken away from the association ๐ However, an endpoint MAY change the value of a_rwnd it sends in SACK chunks, so it's not totally frozen ๐ฆ
Number of Outbound Streams (OS): 16 bits (unsigned integer)
This defines how many outbound streams the sender of this INIT chunk wants to create in this association. The value 0 MUST NOT be used. Zero streams is not it ๐
If a receiver gets an INIT chunk with OS set to 0, it MUST discard the packet. It SHOULD send back a packet containing an ABORT chunk, using the Initiate Tag as the Verification Tag. And it MUST NOT change the state of any existing association. ๐ซ
Number of Inbound Streams (MIS): 16 bits (unsigned integer)
This defines the maximum number of streams the sender of this INIT chunk allows the peer to create in this association. The value 0 MUST NOT be used.
Note: There is no negotiation of the actual number of streams. Instead, the two endpoints use min(requested, offered). See Section 5.1.1 for the details. It's giving "whoever asks for less wins" ๐
If a receiver gets an INIT chunk with MIS set to 0, it MUST discard the packet. It SHOULD send back a packet containing an ABORT chunk, using the Initiate Tag as the Verification Tag. And it MUST NOT change the state of any existing association. Same energy as before, no cap ๐ง
Initial TSN (I-TSN): 32 bits (unsigned integer)
This defines the TSN that the sender of the INIT chunk will use initially. The valid range is 0 to 4294967295, and the Initial TSN SHOULD be set to a random value in that range. The methods in [RFC4086] can be used for the Initial TSN randomization. Randomness is a whole vibe ๐ฒโจ
3.3.2.1. Optional or Variable-Length Parameters in INIT chunks
These parameters follow the Type-Length-Value format from Section 3.2.1. Any Type-Length-Value fields MUST be placed after the fixed-length fields. (The fixed-length fields are defined in the previous section.) Fixed first, then extras, that's the order, bestie ๐ธ
3.3.2.1.1. IPv4 Address (5)
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
IPv4 Address: 32 bits (unsigned integer). This contains an IPv4 address of the sending endpoint, binary encoded. Simple and clean ๐
3.3.2.1.2. IPv6 Address (6)
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 |
| |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
IPv6 Address: 128 bits (unsigned integer). This contains an IPv6 address [RFC8200] of the sending endpoint, binary encoded.
A sender MUST NOT use an IPv4-mapped IPv6 address [RFC4291]. Instead, it SHOULD use an IPv4 Address parameter for an IPv4 address. Use the right tool, babe ๐ง
Together with the Source Port Number in the SCTP common header, the value in an IPv4 or IPv6 Address parameter gives a transport address that the sender of the INIT chunk will support for the association being started. That means that during the lifetime of this association, this IP address can show up in the source address field of an IP datagram sent by the sender of the INIT chunk. It can also be used as the destination address of an IP datagram sent by the receiver of the INIT chunk. Address swapping, but make it cute ๐ฆ
More than one IP Address parameter can be in an INIT chunk when the sender is multi-homed. A multi-homed endpoint might have access to different kinds of networks, so one INIT chunk can hold more than one address type. IPv4 and IPv6 addresses are both allowed in the same INIT chunk. Double the options, double the fun ๐
If the INIT chunk has at least one IP Address parameter, then the source address of the IP datagram carrying the INIT chunk, plus any extra addresses in the INIT, can be used as destinations by the endpoint receiving the INIT chunk. If the INIT chunk has no IP Address parameters, the receiving endpoint MUST use the source address of the received IP datagram as its only destination address for the association. Just one address, but it's the right one ๐
Not using any IP Address parameters in the INIT and INIT ACK chunks is a way to make an association more likely to work with Network Address Translation (NAT). NAT stans, rise up ๐ซถโจ
3.3.2.1.3. Cookie Preservative (9) ๐
okay so bestie, this parameter is how the INIT sender politely asks the receiver to give its State Cookie a longer life span ๐ง the sender suggests an increment, and the receiver gets the final say ๐
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.) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Suggested Cookie Life-Span Increment: 32 bits (unsigned integer) โจ This parameter tells the receiver how many milliseconds the sender would like added to its default cookie life span. Super specific, very chic ๐
This optional parameter MAY be added to the INIT chunk by the sender when it reattempts establishing an association with a peer to which its previous attempt 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 ๐ฅ the receiver is the boss here, no debate ๐
3.3.2.1.4. Host Name Address (11) ๐
okay this one is giving "do NOT do this anymore" energy ๐ The sender of an INIT chunk or INIT ACK chunk MUST NOT include this parameter. The usage of the Host Name Address parameter is deprecated ๐ฅ The receiver of an INIT chunk or an INIT ACK containing a Host Name Address parameter MUST send an ABORT chunk and MAY include an "Unresolvable Address" 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type = 11 | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ / Host Name / \ \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Host Name: variable length ๐ This field contains a host name in "host name syntax" per Section 2.1 of [RFC1123]. The method for resolving the host name is out of scope of SCTP, so that's not SCTP's problem bestie ๐ฆ
At least one null terminator is included in the Host Name string and MUST be included in the length.
3.3.2.1.5. Supported Address Types (12) ๐
the sender of the INIT chunk uses this parameter to list every address type it can support. Main character energy, all the options on display ๐ โจ
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ...... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+
Address Type: 16 bits (unsigned integer) ๐ This is filled with the type value of the corresponding address TLV (e.g., 5 for indicating IPv4, and 6 for indicating IPv6). The value indicating the Host Name Address parameter MUST NOT be used when sending this parameter and MUST be ignored when receiving this parameter. Don't send the deprecated one, and if you spot it, just ignore it ๐ โโ๏ธ๐
3.3.3. Initiation Acknowledgement (INIT ACK) (2) ๐ฆ
okay bestie, the INIT ACK chunk is the reply that says "yep, got your INIT!" ๐ It acknowledges the start of an SCTP association. Here's the shape:
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 /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The parameter part of INIT ACK is set up pretty much like the INIT chunk ๐ Here are the fixed-length parameters for INIT ACK chunks:
+===================================+===========+
| Fixed-Length Parameter | Status |
+===================================+===========+
| Initiate Tag | Mandatory |
+-----------------------------------+-----------+
| Advertised Receiver Window Credit | Mandatory |
+-----------------------------------+-----------+
| Number of Outbound Streams | Mandatory |
+-----------------------------------+-----------+
| Number of Inbound Streams | Mandatory |
+-----------------------------------+-----------+
| Initial TSN | Mandatory |
+-----------------------------------+-----------+
Table 7: Fixed-Length Parameters of INIT ACK
Chunks
It also brings two extra variable-length parameters to the party ๐: the State Cookie and the Unrecognized Parameter. Here's the full list:
+===================================+============+================+
| Variable-Length Parameter | Status | Type Value |
+===================================+============+================+
| State Cookie | Mandatory | 7 |
+-----------------------------------+------------+----------------+
| IPv4 Address (Note 1) | Optional | 5 |
+-----------------------------------+------------+----------------+
| IPv6 Address (Note 1) | Optional | 6 |
+-----------------------------------+------------+----------------+
| Unrecognized Parameter | Optional | 8 |
+-----------------------------------+------------+----------------+
| Reserved for ECN Capable (Note 2) | Optional | 32768 (0x8000) |
+-----------------------------------+------------+----------------+
| Host Name Address (Note 3) | Deprecated | 11 |
+-----------------------------------+------------+----------------+
Table 8: Variable-Length Parameters of INIT ACK Chunks
Some notes on those, because they matter ๐
Note 1: an INIT ACK chunk can hold any number of IP Address parameters, IPv4 and/or IPv6, in any combination. Mix and match, no judgment ๐
Note 2: the ECN Capable field is reserved for future use of Explicit Congestion Notification. So it's just sitting there, waiting for its moment โจ
Note 3: this one is serious. An INIT ACK chunk MUST NOT contain the Host Name Address parameter. If you're the receiver and you get an INIT ACK chunk that has a Host Name Address parameter, you MUST send an ABORT chunk, and you MAY include an "Unresolvable Address" error cause. Not a vibe ๐
The Chunk Flags field in INIT ACK chunks is reserved. All of its bits SHOULD be set to 0 by the sender and ignored by the receiver ๐ซถ
Initiate Tag: 32 bits (unsigned integer)
The receiver of the INIT ACK chunk records the value of the Initiate Tag parameter. That value MUST be placed into the Verification Tag field of every SCTP packet the receiver transmits within this association. It's the association's secret handshake ๐
The Initiate Tag MUST NOT take the value 0. For more on how to pick the Initiate Tag value, check out Section 5.3.1.
If an endpoint in the COOKIE-WAIT state receives an INIT ACK chunk with the Initiate Tag set to 0, it MUST destroy the TCB and SHOULD send an ABORT chunk with the T bit set. If an INIT ACK chunk like that shows up in any state other than CLOSED or COOKIE-WAIT, it SHOULD be discarded silently (see Section 5.2.3). Bye bye, no drama ๐ โโ๏ธ
Advertised Receiver Window Credit (a_rwnd): 32 bits (unsigned integer)
This value is the dedicated buffer space, in number of bytes, that the sender of the INIT ACK chunk has reserved for this association along with this window. It's the room saved just for you, bestie ๐๏ธ
The Advertised Receiver Window Credit MUST NOT be smaller than 1500.
If a receiver gets an INIT ACK chunk with an a_rwnd value smaller than 1500, it MUST discard the packet. It SHOULD send back a packet containing an ABORT chunk, using the Initiate Tag as the Verification Tag, and it MUST NOT change the state of any existing association. Too small, not it ๐ โโ๏ธ
During the life of the association, this buffer space SHOULD NOT be reduced. In other words, dedicated buffers ought not to get taken away from this association ๐ค However, an endpoint MAY change the value of the a_rwnd it sends in SACK chunks. Flexibility, but make it respectful.
Number of Outbound Streams (OS): 16 bits (unsigned integer)
This defines the number of outbound streams the sender of this INIT ACK chunk wants to create in this association. The value 0 MUST NOT be used, and the value MUST NOT be greater than the MIS value sent in the INIT chunk. So you can't invite more streams than the other side asked for, lowkey rude ๐
If an endpoint in the COOKIE-WAIT state receives an INIT ACK chunk with the OS value set to 0, it MUST destroy the TCB and SHOULD send an ABORT chunk. If such an INIT ACK chunk is received in any state other than CLOSED or COOKIE-WAIT, it SHOULD be discarded silently (see Section 5.2.3).
Number of Inbound Streams (MIS): 16 bits (unsigned integer)
This defines the maximum number of streams the sender of this INIT ACK chunk lets the peer create in this association. The value 0 MUST NOT be used.
Note: there's no negotiation of the actual number of streams. Instead, the two endpoints will use the min(requested, offered). See Section 5.1.1 for details. Not a debate, just math ๐งฎ
If an endpoint in the COOKIE-WAIT state receives an INIT ACK chunk with the MIS value set to 0, it MUST destroy the TCB and SHOULD send an ABORT chunk. If such an INIT ACK chunk is received in any state other than CLOSED or COOKIE-WAIT, it SHOULD be discarded silently (see Section 5.2.3).
Initial TSN (I-TSN): 32 bits (unsigned integer)
This defines the TSN that the sender of the INIT ACK chunk will use initially. The valid range is from 0 to 4294967295, and the Initial TSN SHOULD be set to a random value in that range. The methods described in [RFC4086] can be used for the Initial TSN randomization ๐ฒ
Implementation Note: an implementation MUST be prepared to receive an INIT ACK chunk that is quite large (more than 1500 bytes). That's because the State Cookie and the address list can be variable in size. For example, if a responder to the INIT chunk has 1000 IPv4 addresses it wants to send, it would need at least 8,000 bytes to encode them in the INIT ACK chunk. That's a lot of addresses, queen ๐
If an INIT ACK chunk arrives with all of the mandatory parameters specified for the INIT ACK chunk, then the receiver SHOULD process it and send back a COOKIE ECHO chunk. The receiver MAY bundle an ERROR chunk with the COOKIE ECHO chunk. However, restrictive implementations MAY send back an ABORT chunk in response to the INIT ACK chunk instead. Some implementations are just picky like that ๐
Together with the Source Port Number in the SCTP common header, each IP Address parameter in the INIT ACK chunk tells the receiver a valid transport address the sender supports for the whole life of the association being initiated. Basically, a little address book ๐
If the INIT ACK chunk has at least one IP Address parameter, then the source address of the IP datagram carrying the INIT ACK chunk, plus any additional addresses provided within the INIT ACK chunk, MAY be used as destinations by the receiver. If the INIT ACK chunk has no IP Address parameters, the receiver MUST use the source address associated with the received IP datagram as its sole destination address for the association. No addresses? Then you just use the one you got it from ๐ซ
The State Cookie and Unrecognized Parameters use the Type-Length-Value format, as defined in Section 3.2.1, and are described below. All the other fields are defined the same way as their counterparts in the INIT chunk. Copy-paste energy, but make it make sense โจ
3.3.3.1. Optional or Variable-Length Parameters in INIT ACK Chunks ๐
The State Cookie and Unrecognized Parameters use the Type-Length-Value format, as defined in Section 3.2.1, and are described below. The IPv4 Address parameter is described in Section 3.3.2.1.1, and the IPv6 Address parameter is described in Section 3.3.2.1.2. The Host Name Address parameter is described in Section 3.3.2.1.4, and it MUST NOT be included in an INIT ACK chunk. Any Type-Length-Value fields MUST be placed after the fixed-length fields. (The fixed-length fields are defined in the previous section.) Order matters, babe ๐
3.3.3.1.1. State Cookie (7) ๐ช
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 | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ Cookie /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Cookie: variable length
This parameter value MUST contain all the necessary state and parameter information the sender of this INIT ACK chunk needs to create the association, along with a Message Authentication Code (MAC). For more on how the State Cookie is defined, see Section 5.1.3. The cookie is the treasure chest ๐ง๐
3.3.3.1.2. Unrecognized Parameter (8) ๐
okay so this parameter is how the receiver tells the originator of the INIT chunk "hey, you sent me a parameter I don't recognize, and its type says I SHOULD report it back to you" ๐ซถ it's giving honesty, no cap.
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 | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ Unrecognized Parameter /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Unrecognized Parameter: variable length ๐ The Parameter Value field will contain an unrecognized parameter copied from the INIT chunk complete with Parameter Type, Length, and Value fields. Like, the whole thing gets copied back, type and length and value all included ๐ง
3.3.4. Selective Acknowledgement (SACK) (3) ๐
bestie, this is the chunk that says "got it!" for DATA chunks and also tells the peer where the holes are ๐ณ๏ธ it's literally the most important acknowledgment in the whole protocol, iykyk ๐ญ
The SACK chunk MUST contain the Cumulative TSN Ack, Advertised Receiver Window Credit (a_rwnd), Number of Gap Ack Blocks, and Number of Duplicate TSNs fields. โจ
By definition, the Cumulative TSN Ack is the last TSN received before a break in the sequence shows up. The next TSN after that one hasn't been received yet by the endpoint sending the SACK ๐ธ so this value acknowledges receipt of all TSNs less than or equal to it. Main character energy for the cumulative ack ๐
The way the receiver of the SACK handles a_rwnd is discussed in detail in Section 6.2.1. Go read that one, it's the good stuff ๐
The SACK chunk also has zero or more Gap Ack Blocks ๐ Each Gap Ack Block acknowledges a subsequence of TSNs that were received after a break. The Gap Ack Blocks SHOULD be isolated, which means the TSN right before each Gap Ack Block and the TSN right after it have NOT been received. And by definition, every TSN acknowledged by a Gap Ack Block is greater than the Cumulative TSN Ack โจ
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 = M |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 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 M |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bits ๐ฆ All set to 0 on transmit and ignored on receipt.
Cumulative TSN Ack: 32 bits (unsigned integer) ๐ The largest TSN such that all TSNs smaller than or equal to it have been received and the next one has not. If no DATA chunk has been received yet, this value is set to the peer's Initial TSN minus one ๐
Advertised Receiver Window Credit (a_rwnd): 32 bits (unsigned integer) ๐ช This field shows the updated receive buffer space in bytes of the sender of this SACK chunk. See Section 6.2.1 for the details ๐
Number of Gap Ack Blocks: 16 bits (unsigned integer) ๐ฌ Tells you how many Gap Ack Blocks are included in this SACK chunk.
Number of Duplicate TSNs: 16 bit ๐ฏ This is how many duplicate TSNs the endpoint has received. Each duplicate TSN gets listed after the Gap Ack Block list ๐
Gap Ack Blocks: ๐งฉ These fields hold the Gap Ack Blocks, repeated once for each block, up to the number given in the Number of Gap Ack Blocks field. All DATA chunks with TSNs greater than or equal to (Cumulative TSN Ack + Gap Ack Block Start) and less than or equal to (Cumulative TSN Ack + Gap Ack Block End) of each Gap Ack Block are assumed to have been received correctly. Lowkey the most satisfying math in the whole spec โจ
Gap Ack Block Start: 16 bits (unsigned integer) ๐ช The Start offset TSN for this Gap Ack Block. To get the actual TSN, you add the Cumulative TSN Ack to this offset. The calculated TSN is the lowest TSN in this Gap Ack Block that has been received ๐ซ
Gap Ack Block End: 16 bits (unsigned integer) ๐ฏ The End offset TSN for this Gap Ack Block. Same deal, add the Cumulative TSN Ack to this offset, and the result is the highest TSN in this Gap Ack Block that has been received ๐
For example, imagine the receiver has the following DATA chunks newly arrived at the moment it decides to send a Selective ACK:
------------
| TSN = 17 |
------------
| | <- still missing
------------
| TSN = 15 |
------------
| TSN = 14 |
------------
| | <- still missing
------------
| TSN = 12 |
------------
| TSN = 11 |
------------
| TSN = 10 |
------------
Then, the parameter part of the SACK chunk MUST be constructed as follows (assuming the new a_rwnd is set to 4660 by the sender): ๐ง
+-------------------+-------------------+
| Cumulative TSN Ack = 12 |
+-------------------+-------------------+
| a_rwnd = 4660 |
+-------------------+-------------------+
| num of block = 2 | num of dup = 0 |
+-------------------+-------------------+
|block #1 start = 2 | block #1 end = 3 |
+-------------------+-------------------+
|block #2 start = 5 | block #2 end = 5 |
+-------------------+-------------------+
Duplicate TSN: 32 bits (unsigned integer) ๐ซง Indicates the number of times a TSN was received in duplicate since the last SACK chunk was sent. Every time a receiver gets a duplicate TSN (before sending the SACK chunk), it adds it to the list of duplicates. The duplicate count gets reset to zero after each SACK chunk is sent ๐
For example, if a receiver gets TSN 19 three times, it would list 19 twice in the outbound SACK chunk. After sending the SACK chunk, if it receives yet one more TSN 19, it would list 19 as a duplicate once in the next outgoing SACK chunk. The math is giving chaos but the logic is so clean ๐ค
3.3.5. Heartbeat Request (HEARTBEAT) (4) ๐
okay bestie, an endpoint SHOULD send a HEARTBEAT (HB) chunk to its peer to probe the reachability of a particular destination transport address defined in the present association ๐ฐ๏ธ it's like a little "u up?" ping but make it protocol ๐ก
The parameter field holds the Heartbeat Information, which is a variable-length opaque data structure understood only by the sender. Only the sender knows what's inside, so it's giving secret diary energy ๐คซ๐
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) /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bits ๐ Set to 0 on transmit and ignored on receipt.
Heartbeat Length: 16 bits (unsigned integer) ๐ Set to the size of the chunk in bytes, including the chunk header and the Heartbeat Information field.
Heartbeat Information: variable length ๐ง This is defined as a variable-length parameter using the format described in Section 3.2.1, which looks like this:
+=====================+===========+============+
| Variable Parameters | Status | Type Value |
+=====================+===========+============+
| Heartbeat Info | Mandatory | 1 |
+---------------------+-----------+------------+
Table 9: Variable-Length Parameters of
HEARTBEAT Chunks
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 /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The Sender-Specific Heartbeat Info field SHOULD include information about the sender's current time when this HEARTBEAT chunk is sent, plus the destination transport address this HEARTBEAT chunk is sent to (see Section 8.3). The receiver just reflects this info straight back in the HEARTBEAT ACK chunk (see Section 3.3.6) ๐ช Also, the HEARTBEAT chunk does double duty, both for reachability checking and for path verification (see Section 5.4) ๐ฏโโ๏ธ
When a HEARTBEAT chunk is used for path verification, it MUST include a random nonce of length 64 bits or longer ([RFC4086] provides some information on randomness guidelines). A nonce that's random enough is non-negotiable, bestie ๐โจ
3.3.6. Heartbeat Acknowledgement (HEARTBEAT ACK) (5) โจ
okay so an endpoint MUST send this chunk to its peer as a reply to a HEARTBEAT chunk (see Section 8.3) ๐. A packet carrying the HEARTBEAT ACK chunk always goes back to the source IP address of the IP datagram that had the HEARTBEAT chunk it's answering ๐ฆ
The parameter field holds a variable-length opaque data structure ๐
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) /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bits Set to 0 on transmit and ignored on receipt. ๐ธ
Heartbeat Ack Length: 16 bits (unsigned integer) Set to the size of the chunk in bytes, including the chunk header and the Heartbeat Information field. ๐
Heartbeat Information: variable length This field MUST contain the Heartbeat Info parameter (as defined in Section 3.3.5) of the Heartbeat Request to which this Heartbeat Acknowledgement is responding. this part is non-negotiable bestie ๐ซถ
+=====================+===========+============+
| Variable Parameters | Status | Type Value |
+=====================+===========+============+
| Heartbeat Info | Mandatory | 1 |
+---------------------+-----------+------------+
Table 10: Variable-Length Parameters of
HEARTBEAT ACK Chunks
3.3.7. Abort Association (ABORT) (6) ๐
the ABORT chunk gets sent to the peer of an association to close it ๐. The ABORT chunk MAY contain error causes so the receiver knows why it's being aborted. DATA chunks MUST NOT be bundled with ABORT chunks, no exceptions ๐ซ. Control chunks (except for INIT, INIT ACK, and SHUTDOWN COMPLETE) MAY be bundled with an ABORT chunk, but they MUST be placed before the ABORT chunk in the SCTP packet, or the receiver just ignores them ๐ญ
if an endpoint gets an ABORT chunk with a format error or no TCB is found, it MUST silently discard it ๐คซ. And honestly, no matter what, an endpoint that receives an ABORT chunk MUST NOT respond to it by sending an ABORT chunk of its own. we do not start drama ๐ โจ
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 /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bits
Reserved: 7 bits Set to 0 on transmit and ignored on receipt.
T bit: 1 bit The T bit is set to 0 if the sender filled in the Verification Tag expected by the peer. If the Verification Tag is reflected, the T bit MUST be set to 1. Reflecting means that the sent Verification Tag is the same as the received one. reflecting = copying the vibe back exactly ๐ช
Length: 16 bits (unsigned integer) Set to the size of the chunk in bytes, including the chunk header and all the Error Cause fields present.
See Section 3.3.10 for Error Cause definitions ๐
Note: Special rules apply to this chunk for verification, so please see Section 8.5.1 for details. don't skip this one, it's giving important โ ๏ธ
3.3.8. Shutdown Association (SHUTDOWN) (7) ๐
An endpoint in an association MUST use this chunk to start a graceful close of the association with its peer. it's the polite goodbye ๐ This chunk has the following format.
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bits Set to 0 on transmit and ignored on receipt.
Length: 16 bits (unsigned integer) Indicates the length of the parameter. Set to 8.
Cumulative TSN Ack: 32 bits (unsigned integer) The largest TSN, such that all TSNs smaller than or equal to it have been received and the next one has not been received. basically "I've got everything up to here" ๐งบ
Note: Since the SHUTDOWN chunk does not contain Gap Ack Blocks, it cannot be used to acknowledge TSNs received out of order. In a SACK chunk, lack of Gap Ack Blocks that were previously included indicates that the data receiver reneged on the associated DATA chunks. yikes, reneging is a whole thing ๐ฌ
Since the SHUTDOWN chunk does not contain Gap Ack Blocks, the receiver of the SHUTDOWN chunk MUST NOT interpret the lack of a Gap Ack Block as a renege. (See Section 6.2 for information on reneging.) no false accusations allowed ๐ โโ๏ธ
The sender of the SHUTDOWN chunk MAY bundle a SACK chunk to indicate any gaps in the received TSNs ๐
3.3.9. Shutdown Acknowledgement (SHUTDOWN ACK) (8) ๐
This chunk MUST be used to acknowledge the receipt of the SHUTDOWN chunk at the completion of the shutdown process; see Section 9.2 for details. the closing ceremony, basically โจ
The SHUTDOWN ACK chunk has no parameters.
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bits Set to 0 on transmit and ignored on receipt.
3.3.10. Operation Error (ERROR) (9) ๐จ
An endpoint sends this chunk to its peer endpoint to notify it of certain error conditions. It contains one or more error causes. An Operation Error is not considered fatal in and of itself, but the corresponding error cause MAY be used with an ABORT chunk to report a fatal condition. so it's a heads-up, not a funeral ๐ชฆ An ERROR chunk has the following format:
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 | Chunk Flags | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\ \
/ one or more Error Causes /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bits Set to 0 on transmit and ignored on receipt.
Length: 16 bits (unsigned integer) Set to the size of the chunk in bytes, including the chunk header and all the Error Cause fields present.
Error causes are defined as variable-length parameters using the format described in Section 3.2.1, that is:
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 /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Cause Code: 16 bits (unsigned integer) Defines the type of error conditions being reported.
+=======+==============================================+
| Value | Cause Code |
+=======+==============================================+
| 1 | Invalid Stream Identifier |
+-------+----------------------------------------------+
| 2 | Missing Mandatory Parameter |
+-------+----------------------------------------------+
| 3 | Stale Cookie |
+-------+----------------------------------------------+
| 4 | Out of Resource |
+-------+----------------------------------------------+
| 5 | Unresolvable Address |
+-------+----------------------------------------------+
| 6 | Unrecognized Chunk Type |
+-------+----------------------------------------------+
| 7 | Invalid Mandatory Parameter |
+-------+----------------------------------------------+
| 8 | Unrecognized Parameters |
+-------+----------------------------------------------+
| 9 | No User Data |
+-------+----------------------------------------------+
| 10 | Cookie Received While Shutting Down |
+-------+----------------------------------------------+
| 11 | Restart of an Association with New Addresses |
+-------+----------------------------------------------+
| 12 | User-Initiated Abort |
+-------+----------------------------------------------+
| 13 | Protocol Violation |
+-------+----------------------------------------------+
Table 11: Cause Code
Cause Length: 16 bits (unsigned integer) Set to the size of the parameter in bytes, including the Cause Code, Cause Length, and Cause-Specific Information fields.
Cause-Specific Information: variable length This field carries the details of the error condition. ๐
Sections 3.3.10.1 - 3.3.10.13 define error causes for SCTP. Guidelines for the IETF to define new error cause values are discussed in Section 15.4. โจ
3.3.10.1. Invalid Stream Identifier (1) ๐
Indicates that the endpoint received a DATA chunk sent using a nonexistent stream. someone was texting a stream that doesn't exist ๐ญ
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 = 1 | Cause Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stream Identifier | (Reserved) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Stream Identifier: 16 bits (unsigned integer) Contains the Stream Identifier of the DATA chunk received in error.
Reserved: 16 bits This field is reserved. It is set to all 0's on transmit and ignored on receipt.
3.3.10.2. Missing Mandatory Parameter (2) ๐
Okay bestie, this one is for when an INIT or INIT ACK chunk shows up and one or more mandatory TLV parameters are missing ๐ฅบ. The receiver is basically like "wait, where's the thing I needed??" ๐ This error cause is how it tells the sender which ones went missing.
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 = 2 | Cause Length = 8 + N * 2 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Number of missing params = N |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Missing Param Type #1 | Missing Param Type #2 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Missing Param Type #N-1 | Missing Param Type #N |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Here's the breakdown ๐ง โจ:
- Number of Missing params: 32 bits (unsigned integer). This field contains the number of parameters contained in the Cause-Specific Information field.
- Missing Param Type: 16 bits (unsigned integer). Each field will contain the missing mandatory parameter number.
3.3.10.3. Stale Cookie (3) โฐ
This one is for when the receiver gets a valid State Cookie, but it has already expired. Valid but expired is so relatable honestly ๐ญ.
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 = 3 | Cause Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Measure of Staleness (usec.) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Measure of Staleness: 32 bits (unsigned integer). This field contains the difference, rounded up in microseconds, between the current time and the time the State Cookie expired.
The sender of this error cause MAY choose to report how long past expiration the State Cookie is by including a non-zero value in the Measure of Staleness field. If the sender does not wish to provide the Measure of Staleness, it SHOULD set this field to the value of zero. ๐ซถ
3.3.10.4. Out of Resource (4) ๐ชซ
This means the sender is out of resource. It's usually sent together with, or inside of, an ABORT chunk, so it's giving "I'm tapped out, bye" energy ๐ .
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 = 4 | Cause Length = 4 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3.3.10.5. Unresolvable Address (5) ๐บ๏ธ
This one means the sender can't resolve the address parameter it was given. Maybe the address type isn't supported by the sender, for example ๐. It's usually sent together with, or inside of, an ABORT 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Cause Code = 5 | Cause Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ Unresolvable Address /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Unresolvable Address: variable length. The Unresolvable Address field contains the complete Type, Length, and Value of the address parameter (or Host Name parameter) that contains the unresolvable address or host name. ๐งฉ
3.3.10.6. Unrecognized Chunk Type (6) ๐คทโโ๏ธ
This error cause goes back to the originator of the chunk when the receiver doesn't understand it and the upper bits of the 'Chunk Type' are set to 01 or 11. Basically "I don't know this one, babe" ๐.
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 = 6 | Cause Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ Unrecognized Chunk /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Unrecognized Chunk: variable length. The Unrecognized Chunk field contains the unrecognized chunk from the SCTP packet complete with Chunk Type, Chunk Flags, and Chunk Length. ๐ฆ
3.3.10.7. Invalid Mandatory Parameter (7) ๐ซ
This error cause is returned to the originator of an INIT or INIT ACK chunk when one of the mandatory parameters is set to an invalid value. Not the vibe ๐ค.
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 = 7 | Cause Length = 4 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3.3.10.8. Unrecognized Parameters (8) ๐ง
This one goes back to the originator of the INIT ACK chunk if the receiver doesn't recognize one or more Optional TLV parameters in that INIT ACK chunk. Real ones know what's up ๐.
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 = 8 | Cause Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ Unrecognized Parameters /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Unrecognized Parameters: variable length. The Unrecognized Parameters field contains the unrecognized parameters copied from the INIT ACK chunk complete with TLV. This error cause is normally contained in an ERROR chunk bundled with the COOKIE ECHO chunk when responding to the INIT ACK chunk, when the sender of the COOKIE ECHO chunk wishes to report unrecognized parameters. ๐
3.3.10.9. No User Data (9) ๐ซฅ
This is for when a received DATA chunk shows up with no user data inside. Empty DATA chunk, no cap, that's a problem ๐.
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 = 9 | Cause Length = 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TSN |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
TSN: 32 bits (unsigned integer). This parameter contains the TSN of the DATA chunk received with no User Data field. ๐ข
This cause code is normally returned in an ABORT chunk (see Section 6.2). ๐
3.3.10.10. Cookie Received While Shutting Down (10) ๐
A COOKIE ECHO chunk was received while the endpoint was in the SHUTDOWN-ACK-SENT state. Wrong timing, bestie ๐ฌ. This error is usually returned in an ERROR chunk bundled with the retransmitted SHUTDOWN ACK 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Cause Code = 10 | Cause Length = 4 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3.3.10.11. Restart of an Association with New Addresses (11) ๐
This one happens when an INIT chunk is received on an existing association, but the INIT chunk added addresses that weren't previously part of the association. The new addresses get listed in the error cause ๐. It's normally sent as part of an ABORT chunk refusing the INIT chunk (see Section 5.2).
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 = 11 | Cause Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ New Address TLVs /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Note: Each New Address TLV is an exact copy of the TLV that was found in the INIT chunk that was new, including the Parameter Type and the Parameter Length. ๐
3.3.10.12. User-Initiated Abort (12) ๐โโ๏ธ
This error cause MAY be included in ABORT chunks that are sent because of an upper-layer request. The upper layer can specify an Upper Layer Abort Reason that is transported by SCTP transparently and MAY be delivered to the upper-layer protocol at the peer. So the upper layer gets to say "I'm leaving" and it gets passed along ๐คโจ.
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 = 12 | Cause Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ Upper Layer Abort Reason /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3.3.10.13. Protocol Violation (13) ๐จ
This error cause MAY be included in ABORT chunks that are sent because an SCTP endpoint detects a protocol violation of the peer that isn't covered by the error causes described in Sections 3.3.10.1 - 3.3.10.12. An implementation MAY provide additional information specifying what kind of protocol violation has been detected. Catch-all for when the other causes don't fit, and it's giving major rule-breaker energy ๐ฅ.
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 = 13 | Cause Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ Additional Information /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3.3.11. Cookie Echo (COOKIE ECHO) (10) ๐
okay bestie, the COOKIE ECHO chunk only shows up during setup ๐ง The initiator sends it to its peer to complete initialization, and that's the whole job. 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 /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bits. Set to 0 on transmit and ignored on receipt. ๐ธ
Length: 16 bits (unsigned integer). Set to the size of the chunk in bytes, including the 4 bytes of the chunk header and the size of the cookie. ๐
Cookie: variable size. This field MUST contain the exact cookie received in the State Cookie parameter from the previous INIT ACK chunk. ๐
An implementation SHOULD make the cookie as small as possible to ensure interoperability. ๐
Note: A Cookie Echo does not contain a State Cookie parameter. Instead, the data within the State Cookie's Parameter Value becomes the data within the Cookie Echo's Chunk Value. This allows an implementation to change only the first 2 bytes of the State Cookie parameter to become a COOKIE ECHO chunk. the glow-up trick is literally just swapping two bytes ๐ฆ iconic
3.3.12. Cookie Acknowledgement (COOKIE ACK) (11) ๐
This chunk is also only for initialization. It's the reply that says "got your cookie, bestie" ๐ซถ It is used to acknowledge the receipt of a COOKIE ECHO chunk. This chunk MUST precede any DATA or SACK chunk sent within the association but MAY be bundled with one or more DATA chunks or SACK chunk's in the same SCTP 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 = 11 | Chunk Flags | Length = 4 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bits. Set to 0 on transmit and ignored on receipt. ๐
3.3.13. Shutdown Complete (SHUTDOWN COMPLETE) (14) ๐
this one is the closing ceremony ๐ This chunk MUST be used to acknowledge the receipt of the SHUTDOWN ACK chunk at the completion of the shutdown process; see Section 9.2 for details.
The SHUTDOWN COMPLETE chunk has no parameters. ๐
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 | Reserved |T| Length = 4 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk Flags: 8 bitsReserved: 7 bits- Set to 0 on transmit and ignored on receipt.
T bit: 1 bit- The T bit is set to 0 if the sender filled in the Verification Tag expected by the peer. If the Verification Tag is reflected, the T bit MUST be set to 1. Reflecting means that the sent Verification Tag is the same as the received one. ๐ฅ
Note: Special rules apply to this chunk for verification; please see Section 8.5.1 for details. ๐
4. SCTP Association State Diagram ๐ฆ
During the life time of an SCTP association, the SCTP endpoint's association progresses from one state to another in response to various events. the vibes shift depending on what's happening, so let's look at the plot twists The events that might potentially advance an association's state include:
- SCTP user primitive calls, e.g., [ASSOCIATE], [SHUTDOWN], or [ABORT],
- reception of INIT, COOKIE ECHO, ABORT, SHUTDOWN, etc., and control chunks, or
- some timeout events.
The state diagram in the figures below illustrates state changes, together with the causing events and resulting actions. Note that some of the error conditions are not shown in the state diagram. Full descriptions of all special cases are found in the text. ๐ธ
Note: Chunk names are given in all capital letters, while parameter names have the first letter capitalized, e.g., COOKIE ECHO chunk type vs. State Cookie parameter. If more than one event/message can occur that causes a state transition, it is labeled (A) or (B). ๐
----- -------- (from any state)
/ \ /receive ABORT [ABORT]
receive INIT | | |-------------- or ----------
---------------------| v v delete TCB send ABORT
generate State Cookie \ +---------+ delete TCB
send INIT ACK ---| CLOSED |
+---------+
/ \
/ \ [ASSOCIATE]
| |-----------------
| | create TCB
| | send INIT
receive valid | | start T1-init timer
COOKIE ECHO | v
(1) -----------------| +-----------+
create TCB | |COOKIE-WAIT| (2)
send COOKIE ACK | +-----------+
| |
| | receive INIT ACK
| |-------------------
| | send COOKIE ECHO
| | stop T1-init timer
| | start T1-cookie timer
| v
| +-------------+
| |COOKIE-ECHOED| (3)
| +-------------+
| |
| | receive COOKIE ACK
| |-------------------
| | stop T1-cookie timer
v v
+---------------+
| ESTABLISHED |
+---------------+
|
|
/--------+--------\
[SHUTDOWN] / \
-------------------| |
check outstanding | |
DATA chunks | |
v |
+----------------+ |
|SHUTDOWN-PENDING| | receive SHUTDOWN
+----------------+ |------------------
| check outstanding
| | DATA chunks
No more outstanding | |
-----------------------| |
send SHUTDOWN | |
start T2-shutdown timer| |
v v
+-------------+ +-----------------+
(4) |SHUTDOWN-SENT| |SHUTDOWN-RECEIVED| (5,6)
+-------------+ +-----------------+
| \ |
receive SHUTDOWN ACK | \ |
-----------------------| \ |
stop T2-shutdown timer | \ |
send SHUTDOWN COMPLETE | \ |
delete TCB | \ |
| \ | No more outstanding
| \ |--------------------
| \ | send SHUTDOWN ACK
receive SHUTDOWN -|- \ | start T2-shutdown timer
--------------------/ | \----------\ |
send SHUTDOWN ACK | \ |
start T2-shutdown timer| \ |
| \ |
| | |
| v v
| +-----------------+
| |SHUTDOWN-ACK-SENT| (7)
| +-----------------+
| | (A)
| |receive SHUTDOWN COMPLETE
| |-------------------------
| | stop T2-shutdown timer
| | delete TCB
| |
| | (B)
| | receive SHUTDOWN ACK
| |-----------------------
| | stop T2-shutdown timer
| | send SHUTDOWN COMPLETE
| | delete TCB
| |
\ +---------+ /
\-->| CLOSED |<--/
+---------+
Figure 3: State Transition Diagram of SCTP ๐ง
The following applies: these are the big rules, bestie, so pay attention ๐
- If the State Cookie in the received COOKIE ECHO chunk is invalid (i.e., failed to pass the integrity check), the receiver MUST silently discard the packet. Or, if the received State Cookie is expired (see Section 5.1.5), the receiver MUST send back an ERROR chunk. In either case, the receiver stays in the CLOSED state. ๐
- If the T1-init timer expires, the endpoint MUST retransmit the INIT chunk and restart the T1-init timer. The endpoint stays in the COOKIE-WAIT state. This MUST be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint MUST abort the initialization process and report the error to the SCTP user. โฐ
- If the T1-cookie timer expires, the endpoint MUST retransmit COOKIE ECHO chunk and restart the T1-cookie timer. The endpoint stays in the COOKIE-ECHOED state. This MUST be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint MUST abort the initialization process and report the error to the SCTP user. โฐ
- In the SHUTDOWN-SENT state, the endpoint MUST acknowledge any received DATA chunks without delay. ๐
- In the SHUTDOWN-RECEIVED state, the endpoint MUST NOT accept any new send requests from its SCTP user. ๐ซ
- In the SHUTDOWN-RECEIVED state, the endpoint MUST transmit or retransmit data and leave this state when all data in queue is transmitted. ๐ค
- In the SHUTDOWN-ACK-SENT state, the endpoint MUST NOT accept any new send requests from its SCTP user. ๐ซ
The CLOSED state is used to indicate that an association is not created (i.e., does not exist). that's the "not me... not even existing" state ๐
5. Association Initialization โจ
Okay bestie, so before any actual data can move from one SCTP endpoint ("A") to another ("Z"), the two of them MUST go through an initialization process to set up an SCTP association between them. ๐
The SCTP user at an endpoint can use the ASSOCIATE primitive to start an association with another SCTP endpoint. ๐
Implementation Note: From the SCTP user's point of view, an association might get opened without anyone calling the ASSOCIATE primitive (see Section 11.1.2). That happens when the initiating endpoint sends the first user data to the destination endpoint. The initiating SCTP just assumes default values for every mandatory and optional parameter in the INIT/INIT ACK chunk. It's giving effortless. โจ
Once the association is established, unidirectional streams are open for data transfer on both ends (see Section 5.1.1). ๐
5.1. Normal Establishment of an Association
Here's the handshake, assuming endpoint "A" tries to set up an association with endpoint "Z" and "Z" says yes to the new association. ๐ซถ
A) First, "A" builds a TCB and sends an INIT chunk to "Z". In that INIT chunk, "A" MUST put its Verification Tag (Tag_A) in the Initiate Tag field. Tag_A SHOULD be a random number somewhere in the range of 1 to 4294967295 (see Section 5.3.1 for how Tag values get picked). After sending the INIT chunk, "A" starts the T1-init timer and enters the COOKIE-WAIT state. โฐ
B) "Z" responds right away with an INIT ACK chunk. The destination IP address of that INIT ACK chunk MUST be set to the source IP address of the INIT chunk it's answering. In the response, besides filling in other parameters, "Z" MUST set the Verification Tag field to Tag_A, and it also has to put its own Verification Tag (Tag_Z) in the Initiate Tag field. ๐ฆ
Also, "Z" MUST generate a State Cookie and send it along with the INIT ACK chunk. See Section 5.1.3 for how that State Cookie gets generated. ๐ช
Now here's the big one. After sending an INIT ACK chunk with the State Cookie parameter, "Z" MUST NOT allocate any resources or keep any state for the new association. Otherwise, "Z" is vulnerable to resource attacks, and nobody wants that. ๐จ
C) When "A" gets the INIT ACK chunk from "Z", it stops the T1-init timer and leaves the COOKIE-WAIT state. Then "A" sends the State Cookie it received in the INIT ACK chunk back inside a COOKIE ECHO chunk, starts the T1-cookie timer, and enters the COOKIE-ECHOED state. ๐ฅ
The COOKIE ECHO chunk MAY be bundled with any pending outbound DATA chunks, but it MUST be the first chunk in the packet. Until the COOKIE ACK chunk comes back, the sender MUST NOT send any other packets to the peer. Hands off until that ack lands! ๐ โโ๏ธ
D) When endpoint "Z" gets the COOKIE ECHO chunk, it builds a TCB, moves to the ESTABLISHED state, and replies with a COOKIE ACK chunk. A COOKIE ACK chunk MAY be bundled with any pending DATA chunks (and/or SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the packet. ๐
Implementation Note: An implementation can choose to send the COMMUNICATION UP notification to the SCTP user as soon as it receives a valid COOKIE ECHO chunk. ๐
E) When "A" gets the COOKIE ACK chunk, it moves from the COOKIE-ECHOED state to the ESTABLISHED state and stops the T1-cookie timer. It can also tell its ULP about the successful establishment of the association with a COMMUNICATION UP notification (see Section 11). Iconic, we're connected! ๐
An INIT or INIT ACK chunk MUST NOT be bundled with any other chunk. ๐ โโ๏ธ They MUST be the only chunks in the SCTP packets that carry them. Solo chunks only, no sharing! ๐ง
An endpoint MUST send the INIT ACK chunk to the IP address that it got the INIT chunk from. ๐ฌ
The T1-init timer and the T1-cookie timer SHOULD follow the same rules given in Section 6.3. If the application gave multiple IP addresses for the peer, there SHOULD be a T1-init timer and a T1-cookie timer for each of the peer's addresses. Retransmissions of INIT chunks and COOKIE ECHO chunks SHOULD use all of the peer's addresses, the same way retransmissions of DATA chunks do. ๐
If an endpoint gets an INIT, INIT ACK, or COOKIE ECHO chunk but decides NOT to establish the new association (because of missing mandatory parameters in the INIT or INIT ACK chunk, invalid parameter values, or a lack of local resources), it SHOULD respond with an ABORT chunk. It SHOULD also say what caused the abort, like which mandatory parameters were missing, by putting an error cause in the ABORT chunk. The Verification Tag field in the common header of the outgoing SCTP packet that holds the ABORT chunk MUST be set to the Initiate Tag value from the INIT or INIT ACK chunk that this ABORT chunk is replying to. ๐ซ
Quick note: a COOKIE ECHO chunk that fails the integrity check is NOT counted as an "invalid mandatory parameter." It needs its own special handling, so check Section 5.1.5 for that. ๐
After the first DATA chunk shows up in an association, the endpoint MUST immediately respond with a SACK chunk to acknowledge it. Later acknowledgements SHOULD be done as described in Section 6.2. ๐
When the TCB gets created, each endpoint MUST set its internal Cumulative TSN Ack Point to its transmitted Initial TSN minus one. Math with a purpose! ๐งฎ
Implementation Note: The IP addresses and SCTP port are usually the key used to find a TCB within an SCTP instance. ๐
5.1.1. Handle Stream Parameters
In the INIT and INIT ACK chunks, the sender MUST say how many outbound streams (OS) it wants in the association, plus the maximum inbound streams (MIS) it's willing to accept from the other endpoint. Give your numbers, babe! ๐ธ
After getting the stream configuration from the other side, each endpoint MUST run this check: if the peer's MIS is less than the endpoint's OS (meaning the peer can't support all the outbound streams the endpoint wants to set up), the endpoint MUST use MIS outbound streams. It MAY report any shortage to the upper layer. The upper layer can then decide to abort the association if the resource shortage is unacceptable. Not the vibe, so bye bye association. ๐
After the association is initialized, the valid outbound stream identifier range for either endpoint MUST be 0 to min(local OS, remote MIS) - 1. ๐ข
5.1.2. Handle Address Parameters
During association initialization, an endpoint follows these rules to discover and collect the destination transport address(es) of its peer. Let's find everyone's address! ๐บ๏ธ
A) If there are no address parameters in the received INIT or INIT ACK chunk, the endpoint MUST take the source IP address the chunk arrived from. It records that address, together with the SCTP Source Port Number, as the only destination transport address for this peer. ๐
B) If there's a Host Name Address parameter in the received INIT or INIT ACK chunk, the endpoint MUST immediately send an ABORT chunk. It MAY include an "Unresolvable Address" error cause for its peer. The ABORT chunk SHOULD go to the source IP address the last peer packet came from. ๐
C) If there are only IPv4/IPv6 addresses in the received INIT or INIT ACK chunk, the receiver MUST derive and record ALL the transport addresses from the received chunk AND the source IP address that sent the INIT or INIT ACK chunk. The transport addresses are built by combining the SCTP Source Port Number (from the common header), the IP Address parameter(s) in the INIT or INIT ACK chunk, and the source IP address of the IP datagram. After that, the receiver SHOULD use ONLY these transport addresses as destination transport addresses when it sends later packets to its peer. Focus, only these ones! ๐ฏ
D) An INIT or INIT ACK chunk MUST be treated as belonging to an already established association (or one that's in the middle of being established) if using any of the valid address parameters in the chunk would identify an existing TCB. No double dipping! ๐ โโ๏ธ
Implementation Note: In some cases (for example, when the implementation doesn't control which source IP address gets used for sending), an endpoint might need to include every possible IP address that packets to the peer could be sent from in its INIT or INIT ACK chunk. ๐
Once all the transport addresses are derived from the INIT or INIT ACK chunk using the rules above, the endpoint picks one of them as the initial primary path. ๐
The packet containing the INIT ACK chunk MUST be sent to the source address of the packet that contained the INIT chunk. ๐ฎ
The sender of INIT chunks MAY include a 'Supported Address Types' parameter in the INIT chunk to say which types of addresses it's cool with. ๐
Implementation Note: If the receiver of an INIT ACK chunk fails to resolve the address parameter because the type isn't supported, it can abort the initiation process. Then it can try again by sending a new INIT chunk with a 'Supported Address Types' parameter that says which address types it prefers. Second chances are iconic! ๐
If an SCTP endpoint that only supports IPv4 or IPv6 gets both IPv4 and IPv6 addresses in an INIT or INIT ACK chunk from its peer, it MUST use all the addresses that belong to the family it supports. It MAY ignore the other addresses. The endpoint SHOULD NOT respond with any kind of error indication. Chill, no drama. ๐ซถ
If an SCTP endpoint lists either IPv4 or IPv6 in the 'Supported Address Types' parameter but uses the other family to send the packet containing the INIT chunk, or if it also lists addresses of the other family in the INIT chunk, then the address family that isn't listed in the 'Supported Address Types' parameter SHOULD also be considered supported by the receiver of the INIT chunk. The receiver of the INIT chunk SHOULD NOT respond with any kind of error indication. Mixed signals are still a vibe, so no errors please! ๐
5.1.3. Generating State Cookie ๐ช
Okay so when an INIT ACK chunk is sent back as a reply to an INIT chunk, the sender makes a State Cookie and tucks it into the State Cookie parameter of that INIT ACK ๐. Inside this cookie the sender MUST include a MAC (see [RFC2104] for an example) so the cookie has integrity protection. The State Cookie SHOULD also carry a timestamp for when it was created and how long it lives, plus everything needed to set up the association, like the port numbers and the Verification Tags ๐.
How the MAC gets generated is strictly a private matter for the receiver of the INIT chunk ๐. The MAC is mandatory because it helps prevent denial-of-service attacks ๐ญ. Different MAC algorithms can perform differently depending on the platform, and picking a high-performance one makes you more resistant to cookie flooding attacks ๐ฅ. A MAC with acceptable security properties SHOULD be used. The secret key SHOULD be random, and [RFC4086] has some info on randomness guidelines ๐ฒ. The secret keys also need to be an appropriate size ๐. The secret key SHOULD be changed reasonably frequently (e.g., hourly), and the timestamp in the State Cookie MAY be used to figure out which key was used to verify the MAC โฐ.
If the State Cookie is not encrypted, it MUST NOT contain information that isn't meant to be shared ๐. And an implementation SHOULD make the cookie as small as possible so everyone stays interoperable ๐ฆ.
5.1.4. State Cookie Processing ๐ง
When an endpoint in the COOKIE-WAIT state gets an INIT ACK chunk with a State Cookie parameter, it MUST immediately send a COOKIE ECHO chunk to its peer with that received State Cookie ๐ . It MAY also tack any pending DATA chunks onto the packet after the COOKIE ECHO chunk โจ.
The endpoint MUST also start the T1-cookie timer after sending the COOKIE ECHO chunk โฑ๏ธ. If that timer expires, the endpoint MUST retransmit the COOKIE ECHO chunk and restart the T1-cookie timer. This keeps happening until either a COOKIE ACK chunk comes back or 'Max.Init.Retransmits' (see Section 16) is reached. At that point the peer endpoint gets marked unreachable, and the association enters the CLOSED state ๐.
5.1.5. State Cookie Authentication ๐
When an endpoint gets a COOKIE ECHO chunk from another endpoint it has no association with, it does the following ๐:
- Compute a MAC using the information carried in the State Cookie and the secret key. The timestamp in the State Cookie MAY be used to determine which secret key to use. If secrets are only kept for a limited amount of time and the secret key to use isn't available anymore, the packet containing the COOKIE ECHO chunk MUST be silently discarded. [RFC2104] can be used as a guideline for generating the MAC ๐งพ.
- Authenticate the State Cookie as one it previously generated by comparing the computed MAC against the one carried in the State Cookie. If this comparison fails, the SCTP packet, including the COOKIE ECHO chunk and any DATA chunks, MUST be silently discarded ๐ซ.
- Compare the port numbers and the Verification Tag inside the COOKIE ECHO chunk to the actual port numbers and the Verification Tag in the SCTP common header of the received packet. If these values don't match, the packet MUST be silently discarded ๐ โโ๏ธ.
- Compare the creation timestamp in the State Cookie to the current local time. If the elapsed time is longer than the lifespan carried in the State Cookie, then the packet, including the COOKIE ECHO chunk and any attached DATA chunks, SHOULD be discarded, and the endpoint MUST transmit an ERROR chunk with a "Stale Cookie" error cause to the peer endpoint ๐ฅ.
- If the State Cookie is valid, create an association to the sender of the COOKIE ECHO chunk using the information in the State Cookie carried in that COOKIE ECHO chunk, and enter the ESTABLISHED state ๐.
- Send a COOKIE ACK chunk to the peer to acknowledge receipt of the COOKIE ECHO chunk. The COOKIE ACK chunk MAY be bundled with an outbound DATA chunk or SACK chunk; however, the COOKIE ACK chunk MUST be the first chunk in the SCTP packet ๐ฅ.
- Immediately acknowledge any DATA chunk bundled with the COOKIE ECHO chunk with a SACK chunk (subsequent DATA chunk acknowledgement SHOULD follow the rules defined in Section 6.2). As mentioned in step 6, if the SACK chunk is bundled with the COOKIE ACK chunk, the COOKIE ACK chunk MUST appear first in the SCTP packet ๐ซถ.
If a COOKIE ECHO chunk comes in from an endpoint the receiver already has an existing association with, the procedures in Section 5.2 SHOULD be followed ๐.
5.1.6. An Example of Normal Association Establishment ๐ฌ
In this example, "A" starts the association and then sends a user message to "Z". After that, "Z" sends two user messages back to "A" (assuming no bundling or fragmentation happens) ๐.
Endpoint A Endpoint Z
{app sets association with Z}
(build TCB)
INIT [I-Tag=Tag_A
& other info] ------\
(Start T1-init timer) \
(Enter COOKIE-WAIT state) \---> (compose Cookie_Z)
/-- INIT ACK [Veri Tag=Tag_A,
/ I-Tag=Tag_Z,
(Cancel T1-init timer) <------/ Cookie_Z, & other info]
COOKIE ECHO [Cookie_Z] ------\
(Start T1-cookie timer) \
(Enter COOKIE-ECHOED state) \---> (build TCB, enter ESTABLISHED
state)
/---- COOKIE ACK
/
(Cancel T1-cookie timer, <---/
enter ESTABLISHED state)
{app sends 1st user data; strm 0}
DATA [TSN=init TSN_A
Strm=0,Seq=0 & user data]--\
(Start T3-rtx timer) \
\->
/----- SACK [TSN Ack=init TSN_A,
Block=0]
(Cancel T3-rtx timer) <------/
...
{app sends 2 messages;strm 0}
/---- DATA
/ [TSN=init TSN_Z,
<--/ Strm=0,Seq=0 & user data 1]
SACK [TSN Ack=init TSN_Z, /---- DATA
Block=0] --------\ / [TSN=init TSN_Z +1,
\/ Strm=0,Seq=1 & user data 2]
<------/\
\
\------>
Figure 4: A Setup Example
If the T1-init timer expires at "A" after the INIT or COOKIE ECHO chunks are sent, the same INIT or COOKIE ECHO chunk gets retransmitted with the same Initiate Tag (i.e., Tag_A) or State Cookie, and the timer restarts โณ. This repeats 'Max.Init.Retransmits' times before "A" decides "Z" is unreachable and reports the failure to its upper layer. At that point the association enters the CLOSED state ๐ช.
When retransmitting the INIT chunk, the endpoint MUST follow the rules defined in Section 6.3 to figure out the right timer value โฒ๏ธ.
5.2. Handle Duplicate or Unexpected INIT, INIT ACK, COOKIE ECHO, and COOKIE ACK Chunks ๐
During the lifetime of an association (in any of its possible states), an endpoint can get one of the setup chunks (INIT, INIT ACK, COOKIE ECHO, or COOKIE ACK) from its peer. The receiver treats that setup chunk as a duplicate and processes it the way this section describes ๐.
Note: An endpoint won't receive the chunk unless it was sent to an SCTP transport address and came from an SCTP transport address associated with this endpoint. So the endpoint processes such a chunk as part of its current association ๐ก.
These scenarios can cause duplicated or unexpected chunks ๐ค:
- A) the peer crashed without anyone noticing, restarted itself, and sent a new INIT chunk trying to restore the association ๐,
- B) both sides are trying to initialize the association at about the same time ๐ฅ,
- C) the chunk comes from a stale packet that was used to set up the present association, or from a past association that doesn't exist anymore ๐ฐ๏ธ,
- D) the chunk is a fake packet made by an attacker ๐, or
- E) the peer never received the COOKIE ACK chunk and is retransmitting its COOKIE ECHO chunk ๐ฃ.
The rules in the following sections get applied in order to identify and correctly handle these cases ๐.
5.2.1. INIT Chunk Received in COOKIE-WAIT or COOKIE-ECHOED State (Item B) ๐ค
This usually means there's an initialization collision, which is when each endpoint is trying to set up an association with the other one at about the same time ๐ฅ.
When an endpoint in the COOKIE-WAIT state gets an INIT chunk, it MUST respond with an INIT ACK chunk that uses the same parameters it sent in its original INIT chunk (including its Initiate Tag, unchanged). When responding, the following rules MUST be applied ๐:
- The packet containing the INIT ACK chunk MUST only be sent to an address passed by the upper layer in the request to initialize the association ๐ฌ.
- The packet containing the INIT ACK chunk MUST only be sent to an address reported in the incoming INIT chunk ๐ซ.
- The packet containing the INIT ACK chunk SHOULD be sent to the source address of the received packet containing the INIT chunk ๐ฏ.
When an endpoint in the COOKIE-ECHOED state gets an INIT chunk, it MUST respond with an INIT ACK chunk that uses the same parameters it sent in its original INIT chunk (including its Initiate Tag, unchanged), as long as no new address has been added to the forming association ๐งฉ. If the INIT chunk says a new address has been added to the association, then the entire INIT chunk MUST be discarded, and the state of the existing association SHOULD NOT be changed. An ABORT chunk SHOULD be sent in a response that MAY include the "Restart of an Association with New Addresses" error cause. The error SHOULD list the addresses that were added to the restarting association ๐จ.
When responding in either state (COOKIE-WAIT or COOKIE-ECHOED) with an INIT ACK chunk, the original parameters get combined with the ones from the newly received INIT chunk ๐น. The endpoint MUST also generate a State Cookie with the INIT ACK chunk, and it uses the parameters sent in its INIT chunk to calculate that State Cookie ๐ช.
After all that, the endpoint MUST NOT change its state, the T1-init timer MUST be left running, and the corresponding TCB MUST NOT be destroyed. The normal procedures for handling State Cookies when a TCB exists will resolve the duplicate INIT chunks into a single association ๐ซง.
For an endpoint in the COOKIE-ECHOED state, it MUST populate its Tie-Tags within both the association TCB and inside the State Cookie (see Section 5.2.2 for a description of the Tie-Tags) ๐ท๏ธ.
5.2.2. Unexpected INIT Chunk in States Other than CLOSED, COOKIE-ECHOED, COOKIE-WAIT, and SHUTDOWN-ACK-SENT โจ
Okay bestie, unless the spec says otherwise ๐ซถ, when an unexpected INIT chunk shows up for this association, the endpoint MUST generate an INIT ACK chunk with a State Cookie ๐. Before it replies, the endpoint MUST check whether that unexpected INIT chunk adds new addresses to the association ๐.
If new addresses do get added, the endpoint MUST respond with an ABORT chunk ๐ซ. It copies the Initiate Tag from the unexpected INIT chunk into the Verification Tag of the outbound packet carrying that ABORT chunk. In the ABORT chunk, the error cause MAY be set to Restart of an Association with New Addresses โจ. The error SHOULD list the addresses that got added to the restarting association ๐.
If no new addresses get added, then when the endpoint answers the INIT chunk with the outbound INIT ACK chunk, it MUST copy its current Tie-Tags into a reserved spot inside the State Cookie and the association's TCB ๐. We call these spots inside the cookie the Peer's-Tie-Tag and the Local-Tie-Tag. The copy inside the association's TCB gets called the Local Tag and Peer's Tag ๐ง. The outbound SCTP packet holding this INIT ACK chunk MUST carry a Verification Tag equal to the Initiate Tag found in the unexpected INIT chunk. And the INIT ACK chunk MUST contain a brand new Initiate Tag (randomly generated; see Section 5.3.1) ๐ฒ. Other parameters for the endpoint SHOULD get copied from the association's existing parameters (like the number of outbound streams) into the INIT ACK chunk and the cookie ๐
.
After sending the INIT ACK or ABORT chunk, the endpoint MUST take no further actions ๐. That means the existing association, its current state, and the matching TCB MUST NOT be changed.
Only when a TCB exists and the association is not in COOKIE-WAIT or SHUTDOWN-ACK-SENT are the Tie-Tags filled with a random value other than 0 ๐ฐ. For a normal association INIT chunk (aka the endpoint is in the CLOSED state), the Tie-Tags MUST be set to 0, which means no previous TCB existed ๐ธ.
5.2.3. Unexpected INIT ACK Chunk ๐
If an INIT ACK chunk gets received by an endpoint in any state other than COOKIE-WAIT or CLOSED, the endpoint SHOULD discard the INIT ACK chunk. An unexpected INIT ACK chunk usually means the endpoint is processing an old or duplicated INIT chunk ๐ฐ๏ธ.
5.2.4. Handle a COOKIE ECHO Chunk When a TCB Exists ๐
When a COOKIE ECHO chunk gets received by an endpoint in any state for an existing association (aka not in the CLOSED state), these rules apply:
- Compute a MAC as described in step 1 of Section 5.1.5.
- Authenticate the State Cookie as described in step 2 of Section 5.1.5 (this is case C or D above).
- Compare the timestamp in the State Cookie to the current time. If the State Cookie is older than the lifespan carried in the State Cookie and the Verification Tags contained in the State Cookie do not match the current association's Verification Tags, the packet, including the COOKIE ECHO chunk and any DATA chunks, SHOULD be discarded. The endpoint also MUST transmit an ERROR chunk with a
Stale Cookieerror cause to the peer endpoint (this is case C or D in Section 5.2).
If both Verification Tags in the State Cookie match the Verification Tags of the current association, the State Cookie is valid (this is case E in Section 5.2), even if the lifespan is exceeded ๐ซถ.
- If the State Cookie proves to be valid, unpack the TCB into a temporary TCB.
- Refer to Table 12 to determine the correct action to be taken.
+===========+============+===============+================+========+
| Local Tag | Peer's Tag | Local-Tie-Tag | Peer's-Tie-Tag | Action |
+===========+============+===============+================+========+
| X | X | M | M | (A) |
+-----------+------------+---------------+----------------+--------+
| M | X | A | A | (B) |
+-----------+------------+---------------+----------------+--------+
| M | 0 | A | A | (B) |
+-----------+------------+---------------+----------------+--------+
| X | M | 0 | 0 | (C) |
+-----------+------------+---------------+----------------+--------+
| M | M | A | A | (D) |
+-----------+------------+---------------+----------------+--------+
Table 12: Handling of a COOKIE ECHO Chunk When a TCB Exists
Legend:
X- Tag does not match the existing TCB.M- Tag matches the existing TCB.0- Tag unknown (Peer's Tag not known yet / No Tie-Tag in cookie).A- All cases, i.e., M, X, or 0.
For any case not shown in Table 12, the cookie SHOULD be silently discarded ๐คซ.
Action:
A) In this case, the peer might have restarted. When the endpoint recognizes this potential 'restart', the existing session is treated the same as if it received an ABORT chunk followed by a new COOKIE ECHO chunk, with these exceptions:
- Any SCTP DATA chunks MAY be retained (this is an implementation-specific option).
- A RESTART notification SHOULD be sent to the ULP instead of a COMMUNICATION LOST notification.
All the congestion control parameters (e.g., cwnd, ssthresh) related to this peer MUST be reset to their initial values (see Section 6.2.1) ๐.
After this, the endpoint enters the ESTABLISHED state ๐.
If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes that the peer has restarted (Action A), it MUST NOT set up a new association. Instead, it resends the SHUTDOWN ACK chunk and sends an ERROR chunk with a Cookie Received While Shutting Down error cause to its peer ๐.
B) In this case, both sides might be trying to start an association at about the same time, but the peer endpoint sent its INIT chunk after responding to the local endpoint's INIT chunk. So it might have picked a new Verification Tag, not being aware of the previous tag it had sent this endpoint ๐. The endpoint SHOULD stay in or enter the ESTABLISHED state, but it MUST update its peer's Verification Tag from the State Cookie, stop any T1-init or T1-cookie timers that might be running, and send a COOKIE ACK chunk โ .
C) In this case, the local endpoint's cookie has arrived late. Before it arrived, the local endpoint sent an INIT chunk, received an INIT ACK chunk, and finally sent a COOKIE ECHO chunk with the peer's same tag but a new tag of its own ๐ข. The cookie SHOULD be silently discarded. The endpoint SHOULD NOT change states and SHOULD leave any timers running โฑ๏ธ.
D) When both local and remote tags match, the endpoint SHOULD enter the ESTABLISHED state if it is in the COOKIE-ECHOED state. It SHOULD stop any T1-cookie timer that is running and send a COOKIE ACK chunk ๐.
Note: The "peer's Verification Tag" is the tag received in the Initiate Tag field of the INIT or INIT ACK chunk ๐.
5.2.4.1. An Example of an Association Restart ๐ฌ
In the following example, "A" starts the association after a restart has happened. Endpoint "Z" didn't know about the restart until this exchange (aka Heartbeats hadn't yet detected the failure of "A") (assuming no bundling or fragmentation occurs) ๐ป:
Endpoint A Endpoint Z
<-------------- Association is established---------------------->
Tag=Tag_A Tag=Tag_Z
<--------------------------------------------------------------->
{A crashes and restarts}
{app sets up an association with Z}
(build TCB)
INIT [I-Tag=Tag_A'
& other info] --------\
(Start T1-init timer) \
(Enter COOKIE-WAIT state) \---> (find an existing TCB,
populate TieTags if needed,
compose Cookie_Z with Tie-Tags
and other info)
/--- INIT ACK [Veri Tag=Tag_A',
/ I-Tag=Tag_Z',
(Cancel T1-init timer) <------/ Cookie_Z]
(leave original TCB in place)
COOKIE ECHO [Veri=Tag_Z',
Cookie_Z]-------\
(Start T1-init timer) \
(Enter COOKIE-ECHOED state) \---> (Find existing association,
Tie-Tags in Cookie_Z match
Tie-Tags in TCB,
Tags do not match, i.e.,
case X X M M above,
Announce Restart to ULP
and reset association).
/---- COOKIE ACK
(Cancel T1-init timer, <------/
Enter ESTABLISHED state)
{app sends 1st user data; strm 0}
DATA [TSN=Initial TSN_A
Strm=0,Seq=0 & user data]--\
(Start T3-rtx timer) \
\->
/--- SACK [TSN Ack=init TSN_A,Block=0]
(Cancel T3-rtx timer) <------/
Figure 5: A Restart Example
5.2.5. Handle Duplicate COOKIE ACK Chunk ๐
At any state other than COOKIE-ECHOED, an endpoint SHOULD silently discard a received COOKIE ACK chunk ๐.
5.2.6. Handle Stale Cookie Error ๐ช
Receiving an ERROR chunk with a Stale Cookie error cause tells you that one of a few possible things happened:
A) The association failed to completely set up before the State Cookie issued by the sender was processed.
B) An old State Cookie was processed after setup completed.
C) An old State Cookie came from someone the receiver isn't interested in having an association with, and the ABORT chunk got lost ๐ฌ.
When processing an ERROR chunk with a Stale Cookie error cause, an endpoint SHOULD first check whether an association is in the process of being set up, aka whether the association is in the COOKIE-ECHOED state ๐. In all cases, if the association is not in the COOKIE-ECHOED state, the ERROR chunk SHOULD be silently discarded.
If the association is in the COOKIE-ECHOED state, the endpoint MAY pick one of these three options:
- Send a new INIT chunk to the endpoint to generate a new State Cookie and try the setup procedure again ๐.
- Discard the TCB and report to the upper layer that the association couldn't be set up ๐ .
- Send a new INIT chunk to the endpoint, adding a Cookie Preservative parameter that requests an extension to the life time of the State Cookie. When calculating the time extension, an implementation SHOULD use the RTT information measured from the previous COOKIE ECHO/ERROR chunk exchange, and SHOULD add no more than 1 second beyond the measured RTT. Long State Cookie life times make the endpoint more subject to a replay attack, so keep it tight ๐โ ๏ธ.
5.3. Other Initialization Issues ๐
5.3.1. Selection of Tag Value โจ
Okay so, Initiate Tag values SHOULD be picked from the range of 1 to 2^32 - 1 ๐ข. It is super important that the Initiate Tag be randomized so off-path attackers can't guess it ๐ก๏ธ. The methods in [RFC4086] can be used for the Initiate Tag randomization. Picking Initiate Tags carefully is also necessary, bestie, so that old duplicate packets from previous associations don't get mistakenly processed as belonging to the current one ๐ญ.
Moreover, the Verification Tag value used by either endpoint in a given association MUST NOT change during the life time of an association. A new Verification Tag value MUST be used each time the endpoint tears down and then reestablishes an association to the same peer ๐ โจ.
5.4. Path Verification ๐
During association establishment, the two peers swap a list of addresses ๐ค. In the predominant case, these lists accurately represent the addresses owned by each peer. But a misbehaving peer might supply addresses that it does not own, which is so not it ๐ โโ๏ธ. To prevent this, the following rules get applied to all addresses of the new association:
- Any addresses passed to the sender of the INIT chunk by its upper layer in the request to initialize an association are automatically considered to be CONFIRMED.
- For the receiver of the COOKIE ECHO chunk, the only CONFIRMED address is the address to which the packet containing the INIT ACK chunk was sent.
- All other addresses not covered by rules 1 and 2 are considered UNCONFIRMED and are subject to probing for verification.
To probe an address for verification, an endpoint will send HEARTBEAT chunks including a 64-bit random nonce and a path indicator (to identify the address that the HEARTBEAT chunk is sent to) within the Heartbeat Info parameter ๐งช.
Upon receipt of the HEARTBEAT ACK chunk, a verification is made that the nonce included in the Heartbeat Info parameter is the one sent to the address indicated inside the Heartbeat Info parameter. When this match occurs, the address that the original HEARTBEAT was sent to is now considered CONFIRMED and available for normal data transfer ๐.
These probing procedures are started when an association moves to the ESTABLISHED state and are ended when all paths are confirmed ๐.
In each RTO, a probe MAY be sent on an active UNCONFIRMED path in an attempt to move it to the CONFIRMED state. If during this probing the path becomes inactive, this rate is lowered to the normal HEARTBEAT rate ๐ข. At the expiration of the RTO timer, the error counter of any path that was probed but not CONFIRMED is incremented by one and subjected to path failure detection, as defined in Section 8.2. When probing UNCONFIRMED addresses, however, the association overall error count is not incremented ๐.
The number of packets containing HEARTBEAT chunks sent at each RTO SHOULD be limited by the 'HB.Max.Burst' parameter. It is an implementation decision as to how to distribute packets containing HEARTBEAT chunks to the peer's addresses for path verification ๐งฉ.
Whenever a path is confirmed, an indication MAY be given to the upper layer ๐ฌ.
An endpoint MUST NOT send any chunks to an UNCONFIRMED address, with the following exceptions:
- A HEARTBEAT chunk including a nonce MAY be sent to an UNCONFIRMED address.
- A HEARTBEAT ACK chunk MAY be sent to an UNCONFIRMED address.
- A COOKIE ACK chunk MAY be sent to an UNCONFIRMED address, but it MUST be bundled with a HEARTBEAT chunk including a nonce. An implementation that does not support bundling MUST NOT send a COOKIE ACK chunk to an UNCONFIRMED address.
- A COOKIE ECHO chunk MAY be sent to an UNCONFIRMED address, but it MUST be bundled with a HEARTBEAT chunk including a nonce, and the size of the SCTP packet MUST NOT exceed the PMTU. If the implementation does not support bundling or if the bundled COOKIE ECHO chunk plus HEARTBEAT chunk (including nonce) would result in an SCTP packet larger than the PMTU, then the implementation MUST NOT send a COOKIE ECHO chunk to an UNCONFIRMED address ๐ซ.
6. User Data Transfer ๐
Data transmission MUST only happen in the ESTABLISHED, SHUTDOWN-PENDING, and SHUTDOWN-RECEIVED states. The only exception to this is that DATA chunks are allowed to be bundled with an outbound COOKIE ECHO chunk when in the COOKIE-WAIT state ๐.
DATA chunks MUST only be received according to the rules below in ESTABLISHED, SHUTDOWN-PENDING, and SHUTDOWN-SENT states. A DATA chunk received in CLOSED is out of the blue and SHOULD be handled per Section 8.4. A DATA chunk received in any other state SHOULD be discarded ๐๏ธ.
A SACK chunk MUST be processed in ESTABLISHED, SHUTDOWN-PENDING, and SHUTDOWN-RECEIVED states. An incoming SACK chunk MAY be processed in COOKIE-ECHOED. A SACK chunk in the CLOSED state is out of the blue and SHOULD be processed according to the rules in Section 8.4. A SACK chunk received in any other state SHOULD be discarded ๐ง.
For transmission efficiency, SCTP defines mechanisms for bundling of small user messages and fragmentation of large user messages ๐ฆ. The following diagram depicts the flow of user messages through SCTP.
In this section, the term "data sender" refers to the endpoint that transmits a DATA chunk, and the term "data receiver" refers to the endpoint that receives a DATA chunk. A data receiver will transmit SACK chunks ๐ฌ.
+-------------------------+
| User Messages |
+-------------------------+
SCTP user ^ |
==================|==|=======================================
| v (1)
+------------------+ +---------------------+
| SCTP DATA Chunks | | SCTP Control Chunks |
+------------------+ +---------------------+
^ | ^ |
| v (2) | v (2)
+--------------------------+
| SCTP packets |
+--------------------------+
SCTP ^ |
===========================|==|===========================
| v
Connectionless Packet Transfer Service (e.g., IP)
Figure 6: Illustration of User Data Transfer ๐
The following applies:
- When converting user messages into DATA chunks, an endpoint MUST fragment large user messages into multiple DATA chunks. The size of each DATA chunk SHOULD be smaller than or equal to the Association Maximum DATA Chunk Size (AMDCS). The data receiver will normally reassemble the fragmented message from DATA chunks before delivery to the user (see Section 6.9 for details) ๐งธ.
- Multiple DATA and control chunks MAY be bundled by the sender into a single SCTP packet for transmission, as long as the final size of the SCTP packet does not exceed the current PMTU. The receiver will unbundle the packet back into the original chunks. Control chunks MUST come before DATA chunks in the packet ๐.
The fragmentation and bundling mechanisms, as detailed in Sections 6.9 and 6.10, are OPTIONAL to implement by the data sender, but they MUST be implemented by the data receiver. In other words, an endpoint MUST properly receive and process bundled or fragmented data ๐ซถ.
6.1. Transmission of DATA Chunks โจ
okay bestie, this section is where the data sender gets its rules ๐ It spells out how DATA chunks get sent and resent, and it also defines zero window probing. That's the trick that keeps an association from stalling forever when packets carrying SACK chunks (the window updates) go missing ๐ซถ
This document is written as if there's a single retransmission timer per destination transport address, but implementations MAY have a retransmission timer for each DATA chunk ๐ฆ
The data sender has to follow these general rules when it transmits or retransmits outbound DATA chunks, and they MUST be applied ๐
- A) At any given time, the data sender MUST NOT send new data to any destination transport address if its peer's rwnd says the peer has no buffer space (aka rwnd is smaller than the size of the next DATA chunk, see Section 6.2.1) ๐ The only exception is zero window probes.
- A zero window probe is a DATA chunk sent when the receiver has no buffer space ๐ It lets the sender check for a change in rwnd it missed, because the SACK chunks carrying that update got lost on the way from the data receiver back to the sender.
- A zero window probe MUST only be sent when the cwnd allows it (see rule B below) ๐
- A zero window probe SHOULD only be sent when all outstanding DATA chunks have been cumulatively acknowledged and no DATA chunks are in flight โจ
- Senders MUST support zero window probing ๐
- If the sender keeps getting SACK chunks from the peer while it's zero window probing, the unacknowledged window probes SHOULD NOT increment the error counter for the association or any destination transport address ๐ญ Why? Because the receiver could keep its window closed for an indefinite time, and that shouldn't count against anyone.
- Section 6.2 describes what the receiver does when it advertises a zero window ๐ธ
- The sender SHOULD send the first zero window probe after 1 RTO when it detects that the receiver has closed its window, and SHOULD increase the probe interval exponentially afterwards ๐ฅ
- Also, the cwnd SHOULD be adjusted according to Section 7.2.1. Zero window probing does not affect the calculation of cwnd ๐ง
- The sender MUST also have an algorithm for sending new DATA chunks that avoids silly window syndrome (SWS), as described in [RFC1122] ๐ The algorithm can be similar to the one in Section 4.2.3.4 of [RFC1122].
- B) At any given time, the sender MUST NOT send new data to a given transport address if it has cwnd + (PMDCS - 1) or more bytes of data outstanding to that transport address ๐ซ If data is available, the sender SHOULD exceed cwnd by up to (PMDCS - 1) bytes on a new data transmission if the flightsize doesn't currently reach cwnd ๐ The breach of cwnd MUST constitute one packet only โญ
- C) When it's time to transmit, the sender MUST first transmit any DATA chunks marked for retransmission (limited by the current cwnd) before it sends any new DATA chunks ๐ฆ
- D) When it's time to transmit new DATA chunks, the protocol parameter 'Max.Burst' SHOULD be used to limit the number of packets sent ๐ The limit MAY be applied by adjusting cwnd temporarily, like this:
if ((flightsize + Max.Burst * PMDCS) < cwnd)
cwnd = flightsize + Max.Burst * PMDCS
Or it MAY be applied by strictly limiting the number of packets emitted by the output routine ๐ When you're working out how many packets to send, and especially when using the formula above, cwnd SHOULD NOT be changed permanently ๐
- E) After that, the sender can send as many new DATA chunks as rule A and rule B allow ๐
Multiple DATA chunks committed for transmission MAY be bundled in a single packet โจ Also, DATA chunks being retransmitted MAY be bundled with new DATA chunks, as long as the resulting SCTP packet size doesn't go over the PMTU ๐ซถ A ULP can ask that no bundling happens, but that only turns off any delays an SCTP implementation might use to boost bundling efficiency ๐ It doesn't stop all bundling by itself, though (like during congestion or retransmission) ๐ธ
Before an endpoint transmits a DATA chunk, if any received DATA chunks haven't been acknowledged yet (for example, because of delayed ack), the sender SHOULD create a SACK chunk and bundle it with the outbound DATA chunk, as long as the final SCTP packet size doesn't exceed the current PMTU ๐ See Section 6.2 for more.
When the window is full (meaning rule A and/or rule B disallows transmission), the sender MAY still accept send requests from its upper layer ๐ง But it MUST transmit no more DATA chunks until some or all of the outstanding DATA chunks are acknowledged and rules A and B allow transmission again ๐ญ
Whenever a transmission or retransmission goes to any address, if the T3-rtx timer for that address isn't running, the sender MUST start that timer ๐ฅ If the timer for that address is already running, the sender MUST restart it if the earliest (aka lowest TSN) outstanding DATA chunk sent to that address is being retransmitted โจ Otherwise, the data sender MUST NOT restart the timer ๐
When starting or restarting the T3-rtx timer, the timer value SHOULD be adjusted according to the timer rules in Sections 6.3.2 and 6.3.3 ๐ฆ
The data sender MUST NOT use a TSN that is more than 2^31 - 1 above the beginning TSN of the current send window ๐ซ
For each stream, the data sender MUST NOT have more than 2^16 - 1 ordered user messages in the current send window ๐
Whenever the sender of a DATA chunk can benefit from the corresponding SACK chunk coming back without delay, the sender MAY set the I bit in the DATA chunk header ๐ Heads up: why the sender set the I bit doesn't matter to the receiver ๐
Reasons for setting the I bit include, but aren't limited to, the following (see Section 4 of [RFC7053] for a discussion of the benefits) ๐
- The application requests that the I bit of the last DATA chunk of a user message be set when it hands the user message to the SCTP implementation (see Section 11.1) ๐
- The sender is in the SHUTDOWN-PENDING state ๐
- The sending of a DATA chunk fills the congestion or receiver window ๐ง
6.2. Acknowledgement on Reception of DATA Chunks โจ
Okay bestie, this is the part where the receiver gets to be the hero ๐ฆ Every SCTP endpoint MUST always acknowledge the reception of each valid DATA chunk, as long as that chunk lands inside its receive window ๐
Now the window stuff gets spicy ๐ถ๏ธ When the receiver's advertised window is 0, it MUST drop any new incoming DATA chunk with a TSN larger than the largest TSN received so far. And if the new chunk has a TSN lower than the largest TSN received so far, the receiver SHOULD drop the largest TSN it's holding for reordering and accept the new chunk instead ๐ Either way, if a chunk gets dropped, the receiver MUST immediately send back a SACK chunk. That SACK shows the current receive window and only the DATA chunks received and accepted so far. The dropped DATA chunk(s) MUST NOT be included in the SACK chunk, because they weren't accepted ๐ โโ๏ธ The receiver MUST also have an algorithm for advertising its receive window so it avoids receiver silly window syndrome (SWS), as described in [RFC1122]. That algorithm can be similar to the one in Section 4.2.3.3 of [RFC1122] ๐ง
Next up is the delayed acknowledgement stuff ๐ธ The guidelines in Section 4.2 of [RFC5681] SHOULD be followed. Specifically, an acknowledgement SHOULD be generated for at least every second packet (not every second DATA chunk) received, and SHOULD be generated within 200 ms of the arrival of any unacknowledged DATA chunk. Sometimes an SCTP transmitter wants to be more careful than these algorithms allow, and that can be a good call ๐ But an SCTP transmitter MUST NOT be more aggressive about sending SACK chunks than the following algorithms allow. No speed-running the ACKs, babe ๐
An SCTP receiver MUST NOT generate more than one SACK chunk for every incoming packet, except to update the offered window as the receiving application consumes new data โจ When the window opens up, an SCTP receiver SHOULD send additional SACK chunks to update the window, even if no new data arrived. The receiver MUST avoid sending a large number of window updates, especially big bursts of them ๐ One way to do this is to send a window update only if the window can grow by at least a quarter of the receive buffer size of the association. That's the kind of restraint I'm obsessed with ๐ซถ
Implementation Note: The maximum delay for generating an acknowledgement MAY be configured by the SCTP administrator, either statically or dynamically, so it can meet the specific timing requirements of the protocol being carried ๐ฐ๏ธ
Okay, now the cap on that delay ๐ An implementation MUST NOT allow the maximum delay (protocol parameter 'SACK.Delay') to be configured to more than 500 ms. In other words, an implementation MAY lower the value of 'SACK.Delay' below 500 ms, but it MUST NOT raise it above 500 ms. Lower is fine, higher is a no ๐ซ
Acknowledgements MUST be sent in SACK chunks, unless the ULP requested a shutdown. In that case, an endpoint MAY send an acknowledgement in the SHUTDOWN chunk ๐ A SACK chunk can acknowledge the reception of multiple DATA chunks at once. See Section 3.3.4 for the SACK chunk format ๐ฆ The SCTP endpoint MUST fill in the Cumulative TSN Ack field to show the latest sequential TSN (of a valid DATA chunk) it has received. Any received DATA chunks with a TSN greater than the value in the Cumulative TSN Ack field get reported in the Gap Ack Block fields. The SCTP endpoint MUST report as many Gap Ack Blocks as can fit in a single SACK chunk, as long as the size of the SCTP packet does not exceed the current PMTU ๐งฉ
The SHUTDOWN chunk doesn't have Gap Ack Block fields, so the endpoint SHOULD use a SACK chunk instead of the SHUTDOWN chunk to acknowledge DATA chunks received out of order ๐
Upon receipt of an SCTP packet containing a DATA chunk with the I bit set, the receiver SHOULD NOT delay sending the corresponding SACK chunk. In other words, the receiver SHOULD immediately respond with the corresponding SACK chunk โก
When a packet arrives with duplicate DATA chunk(s) and no new DATA chunk(s), the endpoint MUST immediately send a SACK chunk with no delay ๐ญ If a packet arrives with duplicate DATA chunk(s) bundled with new DATA chunks, the endpoint MAY immediately send a SACK chunk. Normally, duplicate DATA chunks show up when the original SACK chunk was lost and the peer's RTO has expired. The duplicate TSN number(s) SHOULD be reported in the SACK chunk as duplicate ๐
When an endpoint receives a SACK chunk, it MAY use the duplicate TSN information to figure out whether SACK chunk loss is happening. Further use of this data is for future study ๐ญ
The data receiver is responsible for maintaining its receive buffers ๐ชฃ It SHOULD notify the data sender in a timely manner about changes in its ability to receive data. How an implementation manages its receive buffers depends on lots of factors (for example, operating system, memory management system, amount of memory, and so on). Still, the data sender strategy defined in Section 6.2.1 assumes the receiver works something like the following:
A) At initialization of the association, the endpoint tells the peer how much receive buffer space it has allocated to the association in the INIT or INIT ACK chunk. The endpoint sets a_rwnd to this value ๐
B) As DATA chunks are received and buffered, decrement a_rwnd by the number of bytes received and buffered. This is, in effect, closing rwnd at the data sender and restricting how much data it can transmit ๐
C) As DATA chunks are delivered to the ULP and released from the receive buffers, increment a_rwnd by the number of bytes delivered to the upper layer. This is, in effect, opening up rwnd on the data sender and letting it send more data ๐ The data receiver SHOULD NOT increment a_rwnd unless it has released bytes from its receive buffer. For example, if the receiver is holding fragmented DATA chunks in a reassembly queue, it SHOULD NOT increment a_rwnd ๐งต
D) When sending a SACK chunk, the data receiver SHOULD place the current value of a_rwnd into the a_rwnd field. The data receiver SHOULD take into account that the data sender will not retransmit DATA chunks that are acked via the Cumulative TSN Ack (i.e., will drop them from its retransmit queue) ๐๏ธ
Under certain circumstances, the data receiver MAY drop DATA chunks that it has received but has not released from its receive buffers (i.e., delivered to the ULP). These DATA chunks might have been acked in Gap Ack Blocks. For example, the data receiver might be holding data in its receive buffers while reassembling a fragmented user message from its peer when it runs out of receive buffer space. It MAY drop these DATA chunks even though it has acknowledged them in Gap Ack Blocks. If a data receiver drops DATA chunks, it MUST NOT include them in Gap Ack Blocks in subsequent SACK chunks until they are received again via retransmission. On top of that, the endpoint SHOULD take the dropped data into account when calculating its a_rwnd ๐งฎ
An endpoint SHOULD NOT revoke a SACK chunk and discard data. Only in extreme circumstances (such as being out of buffer space) might an endpoint use this procedure ๐จ The data receiver SHOULD take into account that dropping data that has been acked in Gap Ack Blocks can lead to suboptimal retransmission strategies in the data sender, and therefore to suboptimal performance ๐
Here's the delayed acknowledgement example, so you can see how it plays out ๐
Endpoint A Endpoint Z
{App sends 3 messages; strm 0}
DATA [TSN=7,Strm=0,Seq=3] ------------> (ack delayed)
(Start T3-rtx timer)
DATA [TSN=8,Strm=0,Seq=4] ------------> (send ack)
/------- SACK [TSN Ack=8,block=0]
(cancel T3-rtx timer) <-----/
DATA [TSN=9,Strm=0,Seq=5] ------------> (ack delayed)
(Start T3-rtx timer)
...
{App sends 1 message; strm 1}
(bundle SACK with DATA)
/----- SACK [TSN Ack=9,block=0] \
/ DATA [TSN=6,Strm=1,Seq=2]
(cancel T3-rtx timer) <------/ (Start T3-rtx timer)
(ack delayed)
(send ack)
SACK [TSN Ack=6,block=0] -------------> (cancel T3-rtx timer)
Figure 7: Delayed Acknowledgement Example
If an endpoint receives a DATA chunk with no user data (i.e., the Length field is set to 16), it SHOULD send an ABORT chunk with a "No User Data" error cause. Yikes, empty DATA chunks are not the vibe ๐ฌ
An endpoint SHOULD NOT send a DATA chunk with no user data part ๐ โโ๏ธ This avoids the need to be able to return a zero-length user message in the API, especially in the socket API as specified in [RFC6458] for details. Zero-length messages are a whole mess, so just don't ๐ง
6.2.1. Processing a Received SACK Chunk โจ
Okay so every SACK chunk an endpoint gets carries an a_rwnd value ๐ซถ That's how much buffer space the data receiver had left when it sent that SACK, out of its total receive buffer (the one set up in the INIT/INIT ACK chunk) ๐ Put a_rwnd together with the Cumulative TSN Ack and the Gap Ack Blocks and the data sender can build a picture of the peer's receive buffer space ๐ฆ
Here's the drama though ๐ญ SACK chunks can arrive out of order. A SACK the receiver sent later can pass an earlier one and show up first. If that happens, the sender can end up with a totally wrong view of the peer's buffer space ๐
There's no explicit identifier that lets you spot an out-of-order SACK, so the sender uses heuristics to figure out whether a SACK is new ๐ง
An endpoint SHOULD use the following rules to calculate the rwnd, using the a_rwnd value, the Cumulative TSN Ack, and Gap Ack Blocks in a received SACK chunk.
- A) At association setup, the endpoint sets rwnd to the Advertised Receiver Window Credit (a_rwnd) the peer gave in the INIT or INIT ACK chunk.
- B) Any time a DATA chunk is sent (or resent) to a peer, the endpoint subtracts that chunk's data size from that peer's rwnd.
- C) Any time a DATA chunk gets marked for retransmission, either because the T3-rtx timer expired (Section 6.3.3) or via Fast Retransmit (Section 7.2.4), the endpoint adds those chunks' data sizes back to rwnd.
- D) Any time a SACK chunk arrives, the endpoint does the following:
- i) If Cumulative TSN Ack is less than the Cumulative TSN Ack Point, drop the SACK chunk. Cumulative TSN Ack only ever goes up, so a SACK whose Cumulative TSN Ack is below the Cumulative TSN Ack Point is an out-of-order SACK, and that's the whole tea โ
- ii) Set rwnd equal to the newly received a_rwnd minus the number of bytes still outstanding after processing the Cumulative TSN Ack and the Gap Ack Blocks.
- iii) If the SACK chunk is missing a TSN that was previously acknowledged via a Gap Ack Block (for example, the data receiver reneged on the data), then consider the matching DATA as possibly missing. Count one miss indication toward Fast Retransmit as described in Section 7.2.4. If no retransmit timer is running for the destination address the DATA chunk was originally sent to, start T3-rtx for that destination address.
- iv) If the Cumulative TSN Ack matches or exceeds the Fast Recovery exit point (Section 7.2.4), Fast Recovery is exited ๐
6.3. Management of Retransmission Timer
An SCTP endpoint uses a retransmission timer T3-rtx to make sure data gets delivered even when there's zero feedback from its peer ๐ธ The length of this timer is called the RTO (retransmission timeout).
When an endpoint's peer is multi-homed, the endpoint calculates a separate RTO for each different destination transport address of that peer endpoint ๐บ๏ธ
SCTP's RTO management basically follows how TCP handles its retransmission timer, so it's giving dรฉjร vu for anyone who knows TCP ๐ To compute the current RTO, an endpoint keeps two state variables per destination transport address: SRTT (smoothed round-trip time) and RTTVAR (round-trip time variation).
6.3.1. RTO Calculation
Here's how SRTT, RTTVAR, and RTO get computed, bestie ๐งฎ
C1) Until an RTT measurement has been made for a packet sent to the given destination transport address, set RTO to the protocol parameter RTO.Initial.
C2) When the first RTT measurement R is made, perform:
SRTT = R
RTTVAR = R/2
RTO = SRTT + 4 * RTTVAR
C3) When a new RTT measurement R' is made, perform:
RTTVAR = (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'|
SRTT = (1 - RTO.Alpha) * SRTT + RTO.Alpha * R'
Note: The value of SRTT used in the update to RTTVAR is its value before updating SRTT itself using the second assignment. ๐
After the computation, update:
RTO = SRTT + 4 * RTTVAR
C4) When data is in flight and when rule C5 below allows it, a new RTT measurement MUST be made each round trip. Furthermore, new RTT measurements SHOULD be made no more than once per round trip for a given destination transport address. There are two reasons for this recommendation. First, measuring more often doesn't really give you any significant benefit in practice [ALLMAN99]. Second, if measurements are made more often, then the values of RTO.Alpha and RTO.Beta in rule C3 above SHOULD be adjusted so that SRTT and RTTVAR still adjust to changes at roughly the same rate (in terms of how many round trips it takes them to reflect new values) as they would if making only one measurement per round trip and using RTO.Alpha and RTO.Beta as given in rule C3. Still, the exact nature of those adjustments is a research issue ๐ฌ
C5) Karn's algorithm: RTT measurements MUST NOT be made using chunks that were retransmitted, since it's ambiguous whether the reply was for the first instance of the chunk or for a later one ๐
RTT measurements SHOULD only be made using a DATA chunk with TSN r if no DATA chunk with TSN less than or equal to r was retransmitted since the DATA chunk with TSN r was first sent.
C6) Whenever RTO is computed, if it is less than RTO.Min seconds, then it gets rounded up to RTO.Min seconds. The reason for this rule is that RTOs without a high enough minimum are susceptible to unnecessary timeouts [ALLMAN99] ๐ค
C7) A maximum value MAY be placed on RTO, provided it is at least RTO.Max seconds.
There's no requirement for the clock granularity G used for computing RTT measurements and the different state variables, other than:
G1) Whenever RTTVAR is computed, if RTTVAR == 0, then adjust RTTVAR = G.
Experience [ALLMAN99] has shown that finer clock granularities (less than 100 msec) perform somewhat better than coarser ones โฑ๏ธ
See Section 16 for suggested parameter values ๐
6.3.2. Retransmission Timer Rules
The rules for managing the retransmission timer are as follows:
R1) Every time a DATA chunk is sent to any address (including a retransmission), if the T3-rtx timer of that address is not running, start it so that it expires after the RTO of that address. The RTO used here is the one obtained after any doubling from previous T3-rtx timer expirations on the corresponding destination address, as discussed in rule E2 below.
R2) Whenever all outstanding data sent to an address has been acknowledged, turn off the T3-rtx timer of that address.
R3) Whenever a SACK chunk is received that acknowledges the DATA chunk with the earliest outstanding TSN for that address, restart the T3-rtx timer for that address with its current RTO (if there's still outstanding data on that address).
R4) Whenever a SACK chunk is received missing a TSN that was previously acknowledged via a Gap Ack Block, start the T3-rtx for the destination address the DATA chunk was originally sent to, if it isn't already running.
Here's an example showing the timer rules in action (assuming the receiver uses delayed acks) ๐ฌ
Endpoint A Endpoint Z
{App begins to send}
Data [TSN=7,Strm=0,Seq=3] ------------> (ack delayed)
(Start T3-rtx timer)
{App sends 1 message; strm 1}
(bundle ack with data)
DATA [TSN=8,Strm=0,Seq=4] ----\ /-- SACK [TSN Ack=7,Block=0]
\ / DATA [TSN=6,Strm=1,Seq=2]
\ / (Start T3-rtx timer)
\
/ \
(Restart T3-rtx timer) <------/ \--> (ack delayed)
(ack delayed)
{send ack}
SACK [TSN Ack=6,Block=0] --------------> (Cancel T3-rtx timer)
..
(send ack)
(Cancel T3-rtx timer) <-------------- SACK [TSN Ack=8,Block=0]
Figure 8: Timer Rule Examples
6.3.3. Handle T3-rtx Expiration
Whenever the retransmission timer T3-rtx expires for a destination address, do the following ๐ฅ
E1) For the destination address whose timer expired, adjust its ssthresh using the rules in Section 7.2.3 and set cwnd = PMDCS.
E2) For the destination address whose timer expired, set RTO = RTO * 2 ("back off the timer"). The maximum value from rule C7 above (RTO.Max) MAY be used to provide an upper bound to this doubling operation.
E3) Figure out how many of the earliest (i.e., lowest TSN) outstanding DATA chunks for the address whose T3-rtx expired will fit into a single SCTP packet, subject to the PMTU corresponding to the destination transport address the retransmission is being sent to. This might be different from the address whose timer expired; see Section 6.4. Call this value K. Bundle and retransmit those K DATA chunks in a single packet to the destination endpoint ๐ฆ
E4) Start the retransmission timer T3-rtx on the destination address the retransmission is sent to, if rule R1 above says to do so. The RTO used for starting T3-rtx SHOULD be the one for the destination address the retransmission is sent to. When the receiver is multi-homed, that might be different from the destination address whose timer expired (see Section 6.4 below).
After retransmitting, once a new RTT measurement is obtained, the computation in rule C3 gets performed, including the computation of RTO. That measurement can only happen when new data has been sent and acknowledged (per rule C5), or for a measurement made from a HEARTBEAT chunk (see Section 8.3). This might end up "collapsing" RTO back down after it was doubled (rule E2) ๐
Any DATA chunks that were sent to the address whose T3-rtx timer expired, but didn't fit in an SCTP packet of size smaller than or equal to the PMTU (rule E3 above), SHOULD be marked for retransmission and sent as soon as cwnd allows (normally, when a SACK chunk arrives) ๐โโ๏ธ
The final rule for managing the retransmission timer is about failover (see Section 6.4.1) ๐ฆ
F1) Whenever an endpoint switches from the current destination transport address to a different one, the current retransmission timers are left running. As soon as the endpoint transmits a packet containing DATA chunk(s) to the new transport address, start the timer on that transport address, using the RTO value of the destination address the data is being sent to, if rule R1 indicates to do so. ๐
6.4. Multi-Homed SCTP Endpoints ๐ฆ
okay so bestie, an SCTP endpoint is considered multi-homed if there is more than one transport address that can be used as a destination address to reach that endpoint. like, it has multiple doors into the house ๐ โจ
moreover, the ULP of an endpoint selects one of the multiple destination addresses of a multi-homed peer endpoint as the primary path (see Sections 5.1.2 and 11.1 for details). the primary path is the main character ๐
by default, an endpoint SHOULD always transmit to the primary path, unless the SCTP user explicitly specifies the destination transport address (and possibly source transport address) to use. so the default is giving main path, periodt ๐
an endpoint SHOULD transmit reply chunks (e.g., INIT ACK, COOKIE ACK, and HEARTBEAT ACK) in response to control chunks to the same destination transport address from which it received the control chunk to which it is replying. so when someone texts you, you reply to the same number they texted from ๐ฑ๐ซถ
the selection of the destination transport address for packets containing SACK chunks is implementation dependent. however, an endpoint SHOULD NOT vary the destination transport address of a SACK chunk when it receives DATA chunks coming from the same source address. so basically don't randomly switch your reply address when the texts are coming from the same sender ๐
when acknowledging multiple DATA chunks received in packets from different source addresses in a single SACK chunk, the SACK chunk MAY be transmitted to one of the destination transport addresses from which the DATA or control chunks being acknowledged were received. you get to pick any of the numbers that actually sent you stuff ๐ธ
when a receiver of a duplicate DATA chunk sends a SACK chunk to a multi-homed endpoint, it MAY be beneficial to vary the destination address and not use the source address of the DATA chunk. the reason is that receiving a duplicate from a multi-homed endpoint might indicate that the return path (as specified in the source address of the DATA chunk) for the SACK chunk is broken. ngl this one is giving detective energy ๐ต๏ธโโ๏ธ๐
furthermore, when its peer is multi-homed, an endpoint SHOULD try to retransmit a chunk that timed out to an active destination transport address that is different from the last destination address to which the chunk was sent. so if it got lost on one door, try a different door that's still open ๐ช๐ฆ
when its peer is multi-homed, an endpoint SHOULD send fast retransmissions to the same destination transport address to which the original data was sent. if the primary path has been changed and the original data was sent to the old primary path before the Fast Retransmit, the implementation MAY send it to the new primary path. fast retransmits stay on the same door, unless the main path switched, then you have options โจ
retransmissions do not affect the total outstanding data count. however, if the DATA chunk is retransmitted onto a different destination address, both the outstanding data counts on the new destination address and the old destination address to which the data chunk was last sent is adjusted accordingly. the math gets updated on both doors so nobody's count is wrong ๐งฎ๐
6.4.1. Failover from an Inactive Destination Address ๐ง
okay this part is so iconic. some of the transport addresses of a multi-homed SCTP endpoint might become inactive due to either the occurrence of certain error conditions (see Section 8.2) or adjustments from the SCTP user. doors can close, periodt ๐ญ
when there is outbound data to send and the primary path becomes inactive (e.g., due to failures) or where the SCTP user explicitly requests to send data to an inactive destination transport address before reporting an error to its ULP, the SCTP endpoint SHOULD try to send the data to an alternate active destination transport address if one exists. so if the main door is shut, the endpoint should try the next open door first before it tells the app something went wrong ๐ซถ๐
when retransmitting data that timed out, if the endpoint is multi-homed, it needs to consider each source-destination address pair in its retransmission selection policy. when retransmitting timed-out data, the endpoint SHOULD attempt to pick the most divergent source-destination pair from the original source-destination pair to which the packet was transmitted. so pick a route that's really different from the one that failed, not just a tiny tweak ๐ฆโจ
Note: Rules for picking the most divergent source-destination pair are an implementation decision and are not specified within this document. so the RFC is like "figure that part out yourself" ๐
6.5. Stream Identifier and Stream Sequence Number ๐
okay every DATA chunk MUST carry a valid stream identifier. if an endpoint receives a DATA chunk with an invalid stream identifier, it SHOULD acknowledge the reception of the DATA chunk following the normal procedure, immediately send an ERROR chunk with cause set to "Invalid Stream Identifier" (see Section 3.3.10), and discard the DATA chunk. the endpoint MAY bundle the ERROR chunk and the SACK chunk in the same packet. so you still say "got it" to the message, tell them the stream number is wrong, and toss the message ๐
the Stream Sequence Number in all the outgoing streams MUST start from 0 when the association is established. the Stream Sequence Number of an outgoing stream MUST be incremented by 1 for each ordered user message sent on that outgoing stream. in particular, when the Stream Sequence Number reaches the value 65535, the next Stream Sequence Number MUST be set to 0. for unordered user messages, the Stream Sequence Number MUST NOT be changed. every stream keeps its own little counter, starting at 0, going up with each ordered message, and wrapping back to 0 after 65535 ๐ข๐ธ
6.6. Ordered and Unordered Delivery ๐
within a stream, an endpoint MUST deliver DATA chunks received with the U flag set to 0 to the upper layer according to the order of their Stream Sequence Number. if DATA chunks arrive out of order of their Stream Sequence Number, the endpoint MUST hold the received DATA chunks from delivery to the ULP until they are reordered. so the ordered messages have to line up in the right order before anyone sees them, no cap ๐๐
however, an SCTP endpoint can indicate that no ordered delivery is required for a particular DATA chunk transmitted within the stream by setting the U flag of the DATA chunk to 1. so you can flip the U flag to say "this one doesn't need to wait in line" ๐โโ๏ธ๐จ
when an endpoint receives a DATA chunk with the U flag set to 1, it bypasses the ordering mechanism and immediately deliver the data to the upper layer (after reassembly if the user data is fragmented by the data sender). the U flag ones skip the line and go straight to the app, after being put back together if they were chopped up ๐ฆ
this provides an effective way of transmitting "out-of-band" data in a given stream. also, a stream can be used as an "unordered" stream by simply setting the U flag to 1 in all DATA chunks sent through that stream. so you can use a stream as a no-line-zone the whole time, which is so fun ๐โจ
Implementation Note: When sending an unordered DATA chunk, an implementation MAY choose to place the DATA chunk in an outbound packet that is at the head of the outbound transmission queue if possible. basically you can cut to the front of the queue if it's doable ๐
the 'Stream Sequence Number' field in a DATA chunk with U flag set to 1 has no significance. the sender can fill the 'Stream Sequence Number' with arbitrary value, but the receiver MUST ignore the field. so for unordered chunks that field is just vibes, and the receiver has to ignore it ๐
Note: When transmitting ordered and unordered data, an endpoint does not increment its Stream Sequence Number when transmitting a DATA chunk with U flag set to 1. the counter only ticks up for the ordered ones, bestie ๐ข๐
6.7. Report Gaps in Received DATA TSNs ๐ต๏ธโโ๏ธ
upon the reception of a new DATA chunk, an endpoint examines the continuity of the TSNs received. if the endpoint detects a gap in the received DATA chunk sequence, it SHOULD send a SACK chunk with Gap Ack Blocks immediately. the data receiver continues sending a SACK chunk after receipt of each SCTP packet that does not fill the gap. so when there's a hole in the sequence, you shout about it right away with a SACK and keep shouting until the hole gets filled ๐ฃ๐ญ
based on the Gap Ack Block from the received SACK chunk, the endpoint can calculate the missing DATA chunks and make decisions on whether to retransmit them (see Section 6.2.1 for details). the gap info is how you figure out what's missing and whether to resend it ๐ง
multiple gaps can be reported in one single SACK chunk (see Section 3.3.4). one SACK can carry a whole list of holes, iykyk ๐ธ
when its peer is multi-homed, the SCTP endpoint SHOULD always try to send the SACK chunk to the same destination address from which the last DATA chunk was received. so reply to the door the most recent DATA came through ๐ช๐
upon the reception of a SACK chunk, the endpoint MUST remove all DATA chunks that have been acknowledged by the SACK chunk's Cumulative TSN Ack from its transmit queue. all DATA chunks with TSNs not included in the Gap Ack Blocks that are smaller than the highest-acknowledged TSN reported in the SACK chunk MUST be treated as "missing" by the sending endpoint. the number of "missing" reports for each outstanding DATA chunk MUST be recorded by the data sender to make retransmission decisions. see Section 7.2.4 for details. so when a SACK comes in, the sender cleans up everything that's been confirmed and counts the missing reports for the rest ๐๐
the following example shows the use of SACK chunk to report a gap. ๐
Endpoint A Endpoint Z
{App sends 3 messages; strm 0}
DATA [TSN=6,Strm=0,Seq=2] ---------------> (ack delayed)
(Start T3-rtx timer)
DATA [TSN=7,Strm=0,Seq=3] --------> X (lost)
DATA [TSN=8,Strm=0,Seq=4] ---------------> (gap detected,
immediately send ack)
/----- SACK [TSN Ack=6,Block=1,
/ Start=2,End=2]
<-----/
(remove 6 from out-queue,
and mark 7 as "1" missing report)
Figure 9: Reporting a Gap Using SACK Chunk
the maximum number of Gap Ack Blocks that can be reported within a single SACK chunk is limited by the current PMTU. when a single SACK chunk cannot cover all the Gap Ack Blocks needed to be reported due to the PMTU limitation, the endpoint MUST send only one SACK chunk. this single SACK chunk MUST report the Gap Ack Blocks from the lowest to highest TSNs, within the size limit set by the PMTU, and leave the remaining highest TSN numbers unacknowledged. so if the PMTU is too small for all the gap blocks, you send one SACK with the lowest ones that fit and leave the top ones unacked ๐ฆ๐
6.8. CRC32c Checksum Calculation ๐
when sending an SCTP packet, the endpoint MUST strengthen the data integrity of the transmission by including the CRC32c checksum value calculated on the packet, as described below. this is your bodyguard for the packet, no cap ๐ก๏ธโจ
after the packet is constructed (containing the SCTP common header and one or more control or DATA chunks), the transmitter MUST:
- fill in the proper Verification Tag in the SCTP common header and initialize the checksum field to 0,
- calculate the CRC32c checksum of the whole packet, including the SCTP common header and all the chunks (refer to Appendix A for details of the CRC32c algorithm), and
- put the resultant value into the checksum field in the common header and leave the rest of the bits unchanged.
so the steps are: set the Verification Tag, zero the checksum, run the math over everything, then drop the answer into the checksum slot ๐งฎ๐
when an SCTP packet is received, the receiver MUST first check the CRC32c checksum as follows:
- store the received CRC32c checksum value aside.
- replace the 32 bits of the checksum field in the received SCTP packet with 0 and calculate a CRC32c checksum value of the whole received packet.
- verify that the calculated CRC32c checksum is the same as the received CRC32c checksum. if it is not, the receiver MUST treat the packet as an invalid SCTP packet.
the receiver checks the bodyguard first, the way you'd check a text's vibe before replying ๐๐
the default procedure for handling invalid SCTP packets is to silently discard them. so if the checksum doesn't match, it just gets ghosted ๐ป๐
any hardware implementation SHOULD permit alternative verification of the CRC in software. so hardware should let you double-check the CRC in software too, just in case ๐ธ๐ซถ
6.9. Fragmentation and Reassembly โจ
okay bestie, so fragmentation is basically how SCTP handles a user message that's too big to fit in one packet ๐ an endpoint MAY support fragmentation when sending DATA chunks, but it MUST support reassembly when receiving DATA chunks ๐ like, you can choose whether you slice stuff up on the way out, but you have to be able to stitch it back together when it comes in ๐งต
if your endpoint DOES support fragmentation, it MUST fragment a user message whenever the outbound SCTP packet size would go over the current PMTU ๐ธ and if your endpoint does NOT support fragmentation and somebody asks it to send a message that would blow past the current PMTU, it MUST return an error to its upper layer and MUST NOT attempt to send the user message ๐ญ no sneaking it through, periodt ๐
An endpoint MAY support fragmentation when sending DATA chunks, but
it MUST support reassembly when receiving DATA chunks.
An SCTP implementation MAY give the upper layer a way to turn fragmentation of DATA chunks off ๐ฆ when that's disabled, the SCTP implementation MUST act exactly like one that doesn't support fragmentation at all, which means it rejects any call that would send SCTP packets bigger than the current PMTU ๐
Implementation Note: in this error case, the SEND primitive from Section 11.1.5 would need to return an error to the upper layer ๐ซถ
if the peer is multi-homed, the endpoint SHOULD choose a DATA chunk size that is smaller than or equal to the AMDCS โจ and once a user message has been fragmented, it can't be re-fragmented ๐ โโ๏ธ instead, if the PMTU has gone down, IP fragmentation MUST be used ๐ฅ which is kinda scary, because it means an SCTP association can fail if IP fragmentation isn't working on any path ๐ see Section 7.3 for the details of PMTU discovery ๐ง
when you're figuring out whether to fragment, the SCTP implementation MUST count the SCTP packet header AND the DATA chunk header(s) ๐ and if it's bundling a SACK chunk with the DATA chunk, it MUST also count the space the SACK chunk needs ๐
here's how fragmentation goes down, step by step ๐
- the data sender MUST break the user message into a series of DATA chunks, and it SHOULD pick a DATA chunk size that's smaller than or equal to the AMDCS ๐
- the transmitter MUST then give each DATA chunk its own TSN, in sequence, and it assigns the same Stream Sequence Number to every single one of them ๐ฆ if the user wants unordered delivery, the U flag of each DATA chunk in that message MUST be set to 1 โจ
- the transmitter MUST also set the B/E bits of the first DATA chunk in the series to 10, the last one to 01, and every chunk in the middle to 00 ๐
on the receiving end, an endpoint MUST recognize fragmented DATA chunks by checking the B/E bits in each received DATA chunk, and then queue them up for reassembly ๐งฉ once the whole user message is put back together, SCTP hands it to the specific stream for possible reordering and final dispatching ๐
and if the data receiver runs out of buffer space while it's still waiting on more fragments, it SHOULD dispatch part of its inbound message through a partial delivery API (see Section 11) ๐ธ that frees up some receive buffer space so the rest of the message can come in ๐ซง
6.10. Bundling ๐
okay so bundling just means you pack multiple chunks into one outbound SCTP packet ๐ฆ the total size of the resulting SCTP packet MUST be less that or equal to the current PMTU ๐
(Note: the original text says "less that or equal to," which is a typo for "less than or equal to." The meaning is the same.)
if the peer endpoint is multi-homed, the sending endpoint SHOULD choose a size no larger than the PMTU of the current primary path โจ
when you're bundling control chunks with DATA chunks, the endpoint MUST put the control chunks FIRST in the outbound SCTP packet ๐ซถ and the transmitter MUST send DATA chunks within a packet in increasing order of TSN ๐ฅ
Note: since control chunks go first in a packet, and DATA chunks get sent before SHUTDOWN or SHUTDOWN ACK chunks, DATA chunks cannot be bundled with SHUTDOWN or SHUTDOWN ACK chunks ๐
partial chunks MUST NOT be placed in an SCTP packet ๐ซ a partial chunk is one that isn't completely inside the SCTP packet, meaning the packet is too short to hold all the bytes the chunk length says it should have ๐
an endpoint MUST process received chunks in the order they appear in the packet ๐ the receiver uses the Chunk Length field to figure out where a chunk ends and the next one starts, remembering that all chunks end on a 4-byte boundary ๐ง and if the receiver spots a partial chunk, it MUST drop that chunk ๐ญ
an endpoint MUST NOT bundle INIT, INIT ACK, or SHUTDOWN COMPLETE chunks with any other chunks ๐ โโ๏ธ no mixing those, bestie ๐
- Congestion Control ๐
congestion control is one of the basic jobs of SCTP ๐ to manage congestion, the mechanisms and algorithms in this section are to be employed ๐ฆ
Implementation Note: as long as its specific performance requirements are met, an implementation is always allowed to use a more conservative congestion control algorithm than the one defined below ๐ซถ
the congestion control algorithms SCTP uses are based on [RFC5681] โจ this section explains how the algorithms defined in [RFC5681] get adapted for SCTP ๐ it lists the differences in protocol design between TCP and SCTP first, and then describes SCTP's congestion control scheme ๐ it uses the same terminology as TCP congestion control whenever that makes sense ๐ธ
SCTP congestion control is always applied to the entire association, never to individual streams ๐ง
7.1. SCTP Differences from TCP Congestion Control ๐
Gap Ack Blocks in the SCTP SACK chunk carry the same semantic meaning as the TCP SACK ๐ TCP treats the info in the SACK as advisory only, and SCTP treats the info in the Gap Ack Blocks in the SACK chunk as advisory too ๐ซง in SCTP, any DATA chunk acknowledged by a SACK chunk, including DATA that arrived out of order, is NOT considered fully delivered until the Cumulative TSN Ack Point passes its TSN (aka the DATA chunk has been acknowledged by the Cumulative TSN Ack field in the SACK chunk) ๐ญ so the value of cwnd controls the amount of outstanding data, rather than (as in non-SACK TCP) the upper bound between the highest acknowledged sequence number and the latest DATA chunk that can be sent within the congestion window ๐ฆ SCTP SACK leads to different implementations of Fast Retransmit and Fast Recovery than non-SACK TCP ๐ฅ for an example, see [FALL96] โจ
the biggest difference between SCTP and TCP, though, is multi-homing ๐ SCTP is designed to set up robust communication associations between two endpoints, each of which might be reachable by more than one transport address ๐ different addresses might lead to different data paths between the two endpoints, so ideally you'd want a separate set of congestion control parameters for each path ๐ the treatment of congestion control for multi-homed receivers is new with SCTP and might need refinement later ๐ the current algorithms make these assumptions:
- the sender usually uses the same destination address until the upper layer tells it to do otherwise ๐ however, SCTP MAY change to an alternate destination if an address is marked inactive (see Section 8.2) ๐ซถ also, SCTP MAY retransmit to a different transport address than the original transmission ๐ง
- the sender keeps a separate congestion control parameter set for each destination address it can send to (not each source-destination pair, but each destination) ๐ the parameters SHOULD decay if the address isn't used for a long enough time period ๐ [RFC5681] specifies this period of time as a retransmission timeout โฐ
- for each destination address, an endpoint does slow start upon the first transmission to that address ๐
Note: TCP guarantees in-sequence delivery of data to its upper-layer protocol within a single TCP session ๐ธ so when TCP notices a gap in the received sequence number, it waits until the gap is filled before delivering the data received with sequence numbers higher than the missing data ๐ โโ๏ธ SCTP, on the other hand, can deliver data to its upper-layer protocol even with a gap in TSN, as long as the Stream Sequence Numbers are in sequence for a particular stream (i.e., the missing DATA chunks are for a different stream) or if unordered delivery is indicated ๐ this doesn't affect cwnd, but it might affect the rwnd calculation ๐ซง
7.2. SCTP Slow-Start and Congestion Avoidance ๐ฃ
the slow-start and congestion avoidance algorithms MUST be used by an endpoint to control how much data gets injected into the network ๐ congestion control in SCTP is handled per association, not per individual stream ๐ฆ in some situations it might be smart for an SCTP sender to be more conservative than the algorithms allow ๐ however, an SCTP sender MUST NOT be more aggressive than the following algorithms allow ๐
like TCP, an SCTP endpoint uses these three control variables to regulate its transmission rate ๐
- receiver advertised window size (rwnd, in bytes), which is set by the receiver based on its available buffer space for incoming packets ๐
Note: this variable is kept on the entire association ๐
- congestion control window (cwnd, in bytes), which is adjusted by the sender based on observed network conditions ๐ธ
Note: this variable is maintained on a per-destination-address basis ๐ง
- slow-start threshold (ssthresh, in bytes), which the sender uses to tell the slow-start and congestion avoidance phases apart ๐
Note: this variable is maintained on a per-destination-address basis ๐ซถ
SCTP also requires one more control variable, partial_bytes_acked, which is used during the congestion avoidance phase to help adjust cwnd ๐ฅ
unlike TCP, an SCTP sender MUST keep a set of the control variables cwnd, ssthresh, and partial_bytes_acked for EACH destination address of its peer (when its peer is multi-homed) ๐ when calculating one of these variables, the length of the DATA chunk, including the padding, SHOULD be used ๐
only one rwnd is kept for the whole association (no matter if the peer is multi-homed or has a single address) โจ
7.2.1. Slow-Start ๐ฃ
Okay so, before you start blasting data into a network with unknown conditions (or after it's been idle for ages), SCTP has to probe the network to figure out how much room it actually has ๐ซฃ. Slow-start is the move for that. It runs at the beginning of a transfer, or after fixing loss that the retransmission timer caught.
- The initial cwnd before data transmission MUST be set to
min(4 * PMDCS, max(2 * PMDCS, 4404))bytes if the peer address is an IPv4 address and tomin(4 * PMDCS, max(2 * PMDCS, 4344))bytes if the peer address is an IPv6 address. - The initial cwnd after a retransmission timeout MUST be no more than PMDCS, and only one packet is allowed to be in flight until successful acknowledgement. Very cautious, very iconic ๐ .
- The initial value of ssthresh SHOULD be arbitrarily high (e.g., the size of the largest-possible advertised window).
- Whenever cwnd is greater than zero, the endpoint is allowed to have cwnd bytes of data outstanding on that transport address. A limited overbooking as described in rule B in Section 6.1 SHOULD be supported.
- When cwnd is less than or equal to ssthresh, an SCTP endpoint MUST use the slow-start algorithm to increase cwnd only if the current congestion window is being fully utilized and the data sender is not in Fast Recovery. Only when these two conditions are met can the cwnd be increased; otherwise, the cwnd MUST NOT be increased. If these conditions are met, then cwnd MUST be increased by, at most, the lesser of
- the total size of the previously outstanding DATA chunk(s) acknowledged and
- L times the destination's PMDCS.
The first upper bound protects against the ACK-Splitting attack outlined in [SAVAGE99]. The positive integer L SHOULD be 1 and MAY be larger than 1. See [RFC3465] for details of choosing L. ๐ก๏ธ
In instances where its peer endpoint is multi-homed, if an endpoint receives a SACK chunk that results in updating the cwnd, then it SHOULD update its cwnd (or cwnds) apportioned to the destination addresses to which it transmitted the acknowledged data.
- While the endpoint does not transmit data on a given transport address, the cwnd of the transport address SHOULD be adjusted to
max(cwnd / 2, 4 * PMDCS)once per RTO. Before the first cwnd adjustment, the ssthresh of the transport address SHOULD be set to the cwnd.
7.2.2. Congestion Avoidance ๐ธ
So once cwnd is greater than ssthresh, we're in congestion avoidance mode, which is a much calmer, more chill vibe. cwnd SHOULD be incremented by PMDCS per RTT, but only if the sender has cwnd or more bytes outstanding for that transport address. The basic recommendations go like this:
- SCTP MAY increment cwnd by PMDCS.
- SCTP SHOULD increment cwnd by PMDCS once per RTT when the sender has cwnd or more bytes of data outstanding for the corresponding transport address.
- SCTP MUST NOT increment cwnd by more than PMDCS per RTT.
In practice, an implementation can hit this goal in the following way:
- partial_bytes_acked is initialized to 0.
- Whenever cwnd is greater than ssthresh, upon each SACK chunk arrival, increase partial_bytes_acked by the total number of bytes (including the chunk header and the padding) of all new DATA chunks acknowledged in that SACK chunk, including chunks acknowledged by the new Cumulative TSN Ack, by Gap Ack Blocks, and by the number of bytes of duplicated chunks reported in Duplicate TSNs.
- When (1) partial_bytes_acked is greater than cwnd and (2) before the arrival of the SACK chunk the sender had less than cwnd bytes of data outstanding (i.e., before the arrival of the SACK chunk, flightsize was less than cwnd), reset partial_bytes_acked to cwnd.
- When (1) partial_bytes_acked is equal to or greater than cwnd and (2) before the arrival of the SACK chunk the sender had cwnd or more bytes of data outstanding (i.e., before the arrival of the SACK chunk, flightsize was greater than or equal to cwnd), partial_bytes_acked is reset to (partial_bytes_acked - cwnd). Next, cwnd is increased by PMDCS.
- Same as in the slow start, when the sender does not transmit DATA chunks on a given transport address, the cwnd of the transport address SHOULD be adjusted to
max(cwnd / 2, 4 * PMDCS)per RTO. - When all of the data transmitted by the sender has been acknowledged by the receiver, partial_bytes_acked is initialized to 0.
7.2.3. Congestion Control ๐ฅ
Upon detecting packet losses from SACK chunks (see Section 7.2.4), an endpoint SHOULD do the following:
ssthresh = max(cwnd / 2, 4 * PMDCS)
cwnd = ssthresh
partial_bytes_acked = 0
Basically, a packet loss causes cwnd to get cut in half. Ouch, but it's the rule ๐ญ.
When the T3-rtx timer expires on an address, SCTP SHOULD perform slow start by:
ssthresh = max(cwnd / 2, 4 * PMDCS)
cwnd = PMDCS
partial_bytes_acked = 0
and ensure that no more than one SCTP packet will be in flight for that address until the endpoint receives acknowledgement for successful delivery of data to that address.
7.2.4. Fast Retransmit on Gap Reports ๐โโ๏ธ
When there's no data loss, an endpoint does delayed acknowledgement. However, whenever an endpoint notices a hole in the arriving TSN sequence, it SHOULD start sending a SACK chunk back every time a packet arrives carrying data until the hole is filled. Hole spotted, alarm bells on ๐จ.
Whenever an endpoint receives a SACK chunk that indicates some TSNs are missing, it SHOULD wait for two further miss indications (via subsequent SACK chunks, for a total of three missing reports) on the same TSNs before taking action with regard to Fast Retransmit. Patience, bestie.
Miss indications SHOULD follow the Highest TSN Newly Acknowledged (HTNA) algorithm. For each incoming SACK chunk, miss indications are incremented only for missing TSNs prior to the HTNA in the SACK chunk. A newly acknowledged DATA chunk is one not previously acknowledged in a SACK chunk. If an endpoint is in Fast Recovery and a SACK chunk arrives that advances the Cumulative TSN Ack Point, the miss indications are incremented for all TSNs reported missing in the SACK chunk.
When the third consecutive miss indication is received for one or more TSNs, the data sender does the following:
- Mark the DATA chunk(s) with three miss indications for retransmission.
- If not in Fast Recovery, adjust the ssthresh and cwnd of the destination address(es) to which the missing DATA chunks were last sent, according to the formula described in Section 7.2.3.
- If not in Fast Recovery, determine how many of the earliest (i.e., lowest TSN) DATA chunks marked for retransmission will fit into a single packet, subject to constraint of the PMTU of the destination transport address to which the packet is being sent. Call this value K. Retransmit those K DATA chunks in a single packet. When a Fast Retransmit is being performed, the sender SHOULD ignore the value of cwnd and SHOULD NOT delay retransmission for this single packet.
- Restart the T3-rtx timer only if the last SACK chunk acknowledged the lowest outstanding TSN number sent to that address or the endpoint is retransmitting the first outstanding DATA chunk sent to that address.
- Mark the DATA chunk(s) as being fast retransmitted and thus ineligible for a subsequent Fast Retransmit. Those TSNs marked for retransmission due to the Fast-Retransmit algorithm that did not fit in the sent datagram carrying K other TSNs are also marked as ineligible for a subsequent Fast Retransmit. However, as they are marked for retransmission, they will be retransmitted later on as soon as cwnd allows.
- If not in Fast Recovery, enter Fast Recovery and mark the highest outstanding TSN as the Fast Recovery exit point. When a SACK chunk acknowledges all TSNs up to and including this exit point, Fast Recovery is exited. While in Fast Recovery, the ssthresh and cwnd SHOULD NOT change for any destinations due to a subsequent Fast Recovery event (i.e., one SHOULD NOT reduce the cwnd further due to a subsequent Fast Retransmit).
Note: Before the above adjustments, if the received SACK chunk also acknowledges new DATA chunks and advances the Cumulative TSN Ack Point, the cwnd adjustment rules defined in Sections 7.2.1 and 7.2.2 MUST be applied first. Order of operations matters, iykyk ๐.
7.2.5. Reinitialization ๐
During the lifetime of an SCTP association, events can happen that put the network under unknown new conditions. When an SCTP implementation detects this, the congestion control MUST be reinitialized. Fresh start, no drama ๐งผ.
7.2.5.1. Change of Differentiated Services Code Points ๐
SCTP implementations MAY allow an application to configure the Differentiated Services Code Point (DSCP) used for sending packets. If a DSCP change might result in outgoing packets being queued in different queues, the congestion control parameters for all affected destination addresses MUST be reset to their initial values.
7.2.5.2. Change of Routes ๐ฃ๏ธ
SCTP implementations MAY be aware of routing changes affecting packets sent to a destination address. In particular, this includes the selection of a different source address used for sending packets to a destination address. If such a routing change happens, the congestion control parameters for the affected destination addresses MUST be reset to their initial values.
7.3. PMTU Discovery ๐งญ
[RFC8899], [RFC8201], and [RFC1191] specify "Packetization Layer Path MTU Discovery," where an endpoint keeps an estimate of the PMTU along a given Internet path and avoids sending packets along that path that exceed the PMTU, except for the occasional attempt to probe for a change in the PMTU. [RFC8899] is thorough in its discussion of the PMTU discovery mechanism and strategies for determining the current end-to-end PMTU setting, as well as detecting changes in this value. Go read it if you're curious, it's a whole vibe ๐ค.
An endpoint SHOULD apply these techniques, and SHOULD do so on a per-destination-address basis.
There are two important SCTP-specific points regarding PMTU discovery:
- SCTP associations can span multiple addresses. An endpoint MUST maintain separate PMTU estimates for each destination address of its peer.
- The sender SHOULD track an AMDCS that will be the smallest PMDCS discovered for all of the peer's destination addresses. When fragmenting messages into multiple parts, this AMDCS SHOULD be used to calculate the size of each DATA chunk. This will allow retransmissions to be seamlessly sent to an alternate address without encountering IP fragmentation. Main character energy for real โจ.
8. Fault Management ๐ ๏ธ
8.1. Endpoint Failure Detection ๐
okay bestie, so an endpoint SHOULD keep a counter ๐
of the total number of consecutive retransmissions to its peer. That counts data retransmissions to every destination transport address of the peer if it's multi-homed, plus the number of unacknowledged HEARTBEAT chunks seen on the path that's currently carrying data. ๐
Unacknowledged HEARTBEAT chunks on any other path SHOULD NOT increment the association error counter ๐
โโ๏ธ. Otherwise the association could get closed even while the path that's actually carrying data is fine (just idle). If the counter goes over the limit in the protocol parameter 'Association.Max.Retrans', the endpoint SHOULD consider the peer unreachable and SHALL stop sending it any more data, and the association enters the CLOSED state ๐. On top of that, the endpoint SHOULD report the failure to the upper layer and can optionally hand back all the user data still sitting in its outbound queue ๐ฆ. The association gets closed automatically once the peer becomes unreachable. no cap, it's giving dramatic but it's also very logical ๐ซถ
The counter used for endpoint failure detection MUST be reset every time a DATA chunk sent to that peer is acknowledged (when a SACK chunk comes back) โจ. When a HEARTBEAT ACK chunk arrives from the peer, the counter SHOULD be reset too. The receiver of that HEARTBEAT ACK chunk MAY choose not to clear the counter if there's still outstanding data on the association ๐ค. This is the bit that handles the fact that reachability through DATA chunks and reachability through HEARTBEAT chunks can be a little different ๐ฆ
8.2. Path Failure Detection ๐ค๏ธ
when the peer endpoint is multi-homed, an endpoint SHOULD keep an error counter for each of the peer's destination transport addresses ๐ ๐
every time the T3-rtx timer expires on any address, or a HEARTBEAT chunk sent to an idle address isn't acknowledged within an RTO, that address's error counter goes up ๐. Once that counter goes over the protocol parameter 'Path.Max.Retrans' for that destination address, the endpoint SHOULD mark that destination transport address as inactive, and a notification SHOULD go to the upper layer ๐จ
when an outstanding TSN gets acknowledged, or a HEARTBEAT chunk sent to that address gets acknowledged with a HEARTBEAT ACK chunk, the endpoint SHOULD clear the error counter of the destination transport address the DATA chunk was last sent to (or the HEARTBEAT chunk, if that was the last one sent) ๐งน. It SHOULD also report to the upper layer when an inactive destination address gets marked as active again ๐. Now here's the tea โ: if the peer is multi-homed and the last chunk sent was a retransmission to an alternate address, it's honestly unclear whether the acknowledgement should count toward the address that chunk was actually sent on. BUT this ambiguity doesn't seem to cause any big consequences for SCTP behavior ๐. If it does bother you, the transmitter MAY choose not to clear the error counter when the last chunk sent was a retransmission ๐
Note: When configuring the SCTP endpoint, the user ought to avoid having the value of'Association.Max.Retrans'larger than the summation of the'Path.Max.Retrans'of all the destination addresses for the remote endpoint. Otherwise, all the destination addresses might become inactive while the endpoint still considers the peer endpoint reachable. When this condition occurs, how SCTP chooses to function is implementation specific. ๐
when the primary path gets marked inactive (because of too many retransmissions, for instance), the sender MAY automatically transmit new packets to an alternate destination address, as long as one exists and is active ๐. If more than one alternate address is active at that moment, only ONE transport address SHOULD be chosen and used as the new destination transport address ๐
8.3. Path Heartbeat ๐
by default, an SCTP endpoint SHOULD keep an eye on the reachability of its peer's idle destination transport addresses ๐. It does this by sending a HEARTBEAT chunk to those addresses periodically ๐ซ. Sending HEARTBEAT chunks MAY begin once the ESTABLISHED state is reached, and it stops after a SHUTDOWN chunk or SHUTDOWN ACK chunk gets sent ๐. A receiver of a HEARTBEAT chunk MUST respond with a HEARTBEAT ACK chunk once it's in the COOKIE-ECHOED state (the sender of the INIT chunk) or the ESTABLISHED state (the receiver of the INIT chunk). This keeps going until the endpoint reaches the SHUTDOWN-SENT state (the sender of the SHUTDOWN chunk) or the SHUTDOWN-ACK-SENT state (the receiver of the SHUTDOWN chunk) ๐ง
a destination transport address counts as "idle" if no new chunk that can be used for updating path RTT has been sent to it, and no HEARTBEAT chunk has gone to it within the current heartbeat period of that address. Chunks that can update path RTT usually include first transmission DATA, INIT, COOKIE ECHO, or HEARTBEAT chunks, and so on ๐ก. This applies to both active and inactive destination addresses, so it's not just the healthy ones ๐
the upper layer can optionally kick off these functions ๐:
- A) Disable heartbeat on a specific destination transport address of a given association,
- B) Change the
'HB.interval', - C) Re-enable heartbeat on a specific destination transport address of a given association, and
- D) Request the sending of an on-demand
HEARTBEATchunk on a specific destination transport address of a given association.
the endpoint SHOULD increment the matching error counter for a destination transport address each time a HEARTBEAT chunk goes to that address and isn't acknowledged within one RTO ๐
once that counter goes over the protocol parameter 'Path.Max.Retrans', the endpoint SHOULD mark the destination address as inactive (if it isn't already) and SHOULD also tell the upper layer about the change in its reachability ๐ฉ. After that, the endpoint SHOULD keep sending HEARTBEAT chunks to that destination address, but it SHOULD stop increasing the counter. so it keeps checking without spiraling ๐งโโ๏ธ
the sender of a HEARTBEAT chunk SHOULD put the current time at which the packet is sent, plus the destination address the packet goes to, into the Heartbeat Information field of the chunk โฐ
Implementation Note: An alternative implementation of the heartbeat mechanism that can be used is to increment the error counter variable every time aHEARTBEATchunk is sent to a destination. Whenever aHEARTBEAT ACKchunk arrives, the sender SHOULD clear the error counter of the destination that theHEARTBEATchunk was sent to. This, in effect, would clear the previously stroked error (and any other error counts as well). ๐ช
the receiver of a HEARTBEAT chunk SHOULD reply right away with a HEARTBEAT ACK chunk. That reply carries the Heartbeat Information TLV, along with any other TLVs it received, copied over unchanged from the HEARTBEAT chunk ๐ช
when a HEARTBEAT ACK chunk arrives, the sender of the HEARTBEAT chunk SHOULD clear the error counter of the destination transport address the HEARTBEAT chunk went to, and mark that address as active if it isn't already โ
. The endpoint SHOULD report to the upper layer when an inactive destination address becomes active because of that latest HEARTBEAT ACK chunk ๐. The receiver of the HEARTBEAT ACK chunk SHOULD also clear the association overall error count (as defined in Section 8.1) ๐งฝ
the receiver of the HEARTBEAT ACK chunk SHOULD also run an RTT measurement for that destination transport address, using the time value carried in the HEARTBEAT ACK chunk โฑ๏ธ
on an idle destination address that's allowed to heartbeat, it is RECOMMENDED that a HEARTBEAT chunk gets sent once per RTO of that address plus the protocol parameter 'HB.interval' ๐๏ธ. It should also jitter by +/- 50% of the RTO value, and back off exponentially if the previous HEARTBEAT chunk went unanswered ๐ฒ
there's a primitive the SCTP user can call to change the 'HB.interval' and to turn heartbeat on or off for a given destination address ๐ง. The 'HB.interval' the user sets gets added to that destination's RTO (including any exponential backoff) โ. Only one heartbeat SHOULD be sent each time the heartbeat timer expires (when multiple destinations are idle). How to pick which idle destination to heartbeat is an implementation decision, if more than one is idle ๐ฏ
When tuning the'HB.interval', there is a side effect that SHOULD be taken into account. When this value goes up (so the time betweenHEARTBEATchunks gets longer), detecting lostABORTchunks takes longer too. If a peer endpoint sends anABORTchunk for any reason and thatABORTchunk is lost, the local endpoint will only discover the loss by sending aDATAchunk orHEARTBEATchunk, which makes the peer send anotherABORTchunk ๐. Keep this in mind when you tune the heartbeat timer โฒ๏ธ. If sendingHEARTBEATchunks is disabled, only sendingDATAchunks to the association will discover a lostABORTchunk from the peer ๐
8.4. Handle "Out of the Blue" Packets โจ
okay so an SCTP packet is called an "Out of the Blue" (OOTB) packet ๐ซฃ if it's correctly formed (aka it passed the receiver's CRC32c check, see Section 6.8 ๐) but the receiver just can't figure out which association it belongs to. literally lost ๐
the receiver of an OOTB packet does the following, bestie ๐ :
- If the OOTB packet is to or from a non-unicast address, a receiver SHOULD silently discard the packet. Otherwise,
- If the OOTB packet contains an ABORT chunk, the receiver MUST silently discard the OOTB packet and take no further action. Otherwise,
- If the packet contains an INIT chunk with a Verification Tag set to 0, it SHOULD be processed as described in Section 5.1. If, for whatever reason, the INIT chunk cannot be processed normally and an ABORT chunk has to be sent in response, the Verification Tag of the packet containing the ABORT chunk MUST be the Initiate Tag of the received INIT chunk, and the T bit of the ABORT chunk has to be set to 0, indicating that the Verification Tag is not reflected. Otherwise,
- If the packet contains a COOKIE ECHO chunk as the first chunk, it MUST be processed as described in Section 5.1. Otherwise,
- If the packet contains a SHUTDOWN ACK chunk, the receiver SHOULD respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE chunk. When sending the SHUTDOWN COMPLETE chunk, the receiver of the OOTB packet MUST fill in the Verification Tag field of the outbound packet with the Verification Tag received in the SHUTDOWN ACK chunk and set the T bit in the Chunk Flags to indicate that the Verification Tag is reflected. Otherwise,
- If the packet contains a SHUTDOWN COMPLETE chunk, the receiver SHOULD silently discard the packet and take no further action. Otherwise,
- If the packet contains an ERROR chunk with the "Stale Cookie" error cause or a COOKIE ACK chunk, the SCTP packet SHOULD be silently discarded. Otherwise,
- The receiver SHOULD respond to the sender of the OOTB packet with an ABORT chunk. When sending the ABORT chunk, the receiver of the OOTB packet MUST fill in the Verification Tag field of the outbound packet with the value found in the Verification Tag field of the OOTB packet and set the T bit in the Chunk Flags to indicate that the Verification Tag is reflected. After sending this ABORT chunk, the receiver of the OOTB packet MUST discard the OOTB packet and MUST NOT take any further action. ๐ง
8.5. Verification Tag ๐
the Verification Tag rules in this section apply when you're sending or receiving SCTP packets that do NOT contain an INIT, SHUTDOWN COMPLETE, COOKIE ECHO (see Section 5.1), ABORT, or SHUTDOWN ACK chunk. the rules for packets carrying one of those chunk types get their own treatment in Section 8.5.1, so don't mix them up ๐
when sending an SCTP packet, the endpoint MUST fill in the Verification Tag field of the outbound packet with the tag value in the Initiate Tag parameter of the INIT or INIT ACK chunk received from its peer.
when receiving an SCTP packet, the endpoint MUST ensure that the value in the Verification Tag field of the received SCTP packet matches its own tag. if the received Verification Tag value does not match the receiver's own tag value, the receiver MUST silently discard the packet and MUST NOT process it any further, except for those cases listed in Section 8.5.1 below. it's giving strict bouncer energy ๐ซ
8.5.1. Exceptions in Verification Tag Rules ๐ฆ
A) Rules for packets carrying an INIT chunk:
- The sender MUST set the Verification Tag of the packet to 0.
- When an endpoint receives an SCTP packet with the Verification Tag set to 0, it SHOULD verify that the packet contains only an INIT chunk. Otherwise, the receiver MUST silently discard the packet.
B) Rules for packets carrying an ABORT chunk:
- The endpoint MUST always fill in the Verification Tag field of the outbound packet with the destination endpoint's tag value if it is known.
- If the ABORT chunk is sent in response to an OOTB packet, the endpoint MUST follow the procedure described in Section 8.4.
- The receiver of an ABORT chunk MUST accept the packet if the Verification Tag field of the packet matches its own tag and the T bit is not set OR if it is set to its Peer's Tag and the T bit is set in the Chunk Flags. Otherwise, the receiver MUST silently discard the packet and take no further action.
C) Rules for packets carrying a SHUTDOWN COMPLETE chunk:
- When sending a SHUTDOWN COMPLETE chunk, if the receiver of the SHUTDOWN ACK chunk has a TCB, then the destination endpoint's tag MUST be used and the T bit MUST NOT be set. Only where no TCB exists SHOULD the sender use the Verification Tag from the SHUTDOWN ACK chunk and MUST set the T bit.
- The receiver of a SHUTDOWN COMPLETE chunk accepts the packet if the Verification Tag field of the packet matches its own tag and the T bit is not set OR if it is set to its Peer's Tag and the T bit is set in the Chunk Flags. Otherwise, the receiver MUST silently discard the packet and take no further action. An endpoint MUST ignore the SHUTDOWN COMPLETE chunk if it is not in the SHUTDOWN-ACK-SENT state.
D) Rules for packets carrying a COOKIE ECHO chunk:
- When sending a COOKIE ECHO chunk, the endpoint MUST use the value of the Initiate Tag received in the INIT ACK chunk.
- The receiver of a COOKIE ECHO chunk follows the procedures in Section 5.
E) Rules for packets carrying a SHUTDOWN ACK chunk:
- If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state, the procedures in Section 8.4 SHOULD be followed; in other words, it is treated as an OOTB packet. ๐ซถ
9. Termination of Association ๐
an endpoint SHOULD terminate its association when it exits from service. an association can be ended by either abort or shutdown.
an abort is abortive by definition ๐ค, meaning any data pending on either end of the association gets thrown out and never delivered to the peer. a shutdown is the graceful version ๐ธ, where all data in queue by either endpoint gets delivered to the respective peers.
BUT, and this is the tea โ, SCTP does not support a half-open state (unlike TCP), where one side keeps sending data while the other end is closed. when either endpoint performs a shutdown, the association on each peer stops accepting new data from its user and only delivers data that was in queue at the time of sending or receiving the SHUTDOWN chunk.
9.1. Abort of an Association ๐
when an endpoint decides to abort an existing association, it MUST send an ABORT chunk to its peer endpoint. the sender MUST fill in the peer's Verification Tag in the outbound packet and MUST NOT bundle any DATA chunk with the ABORT chunk. if the association is aborted on request of the upper layer, a "User-Initiated Abort" error cause (see Section 3.3.10.12) SHOULD be present in the ABORT chunk. ๐ฅ
an endpoint MUST NOT respond to any received packet that contains an ABORT chunk (also see Section 8.4). no replying to the ABORT, no drama ๐ โโ๏ธ
an endpoint receiving an ABORT chunk MUST apply the special Verification Tag check rules described in Section 8.5.1.
after checking the Verification Tag, the receiving endpoint MUST remove the association from its record and SHOULD report the termination to its upper layer. if a "User-Initiated Abort" error cause is present in the ABORT chunk, the Upper Layer Abort Reason SHOULD be made available to the upper layer. โจ๐
9.2. Shutdown of an Association ๐ฆ
Okay bestie, this is the polite way to leave the party ๐ Using the SHUTDOWN primitive (check Section 11.1 for the deets), the upper layer of an endpoint in an association can gracefully close it. The vibe is that every outstanding DATA chunk from the shutdown initiator's peer gets delivered before the association fully terminates ๐ซถ
Once an endpoint gets the SHUTDOWN primitive from its upper layer, it drops into the SHUTDOWN-PENDING state and chills there until its peer has acknowledged all the outstanding data ๐ Meanwhile it takes no new data from its upper layer, but it will retransmit data to the peer if needed to fill gaps ๐ฅ
When everything's acked, the endpoint sends a SHUTDOWN chunk to its peer, and in the Cumulative TSN Ack field it puts the last sequential TSN it received from the peer ๐ It SHOULD then start the T2-shutdown timer and enter the SHUTDOWN-SENT state. If that timer goes off, the endpoint MUST resend the SHUTDOWN chunk with the updated last sequential TSN it received from its peer ๐ญ
Timer math: the rules in Section 6.3 MUST be followed to figure out the proper value for T2-shutdown ๐งฎ To flag any gaps in the TSN, the endpoint MAY also bundle a SACK chunk with the SHUTDOWN chunk in the same SCTP packet ๐
Retransmission limits: an endpoint SHOULD limit how many times it resends the SHUTDOWN chunk to the protocol parameter 'Association.Max.Retrans'. If that threshold gets blown past, the endpoint SHOULD destroy the TCB and SHOULD report the peer endpoint as unreachable to the upper layer, and the association goes to the CLOSED state ๐ Also, receiving any packet from its peer (like when the peer is sending all its queued DATA chunks) SHOULD clear the endpoint's retransmission count and restart the T2-shutdown timer. That gives the peer plenty of room to send the queued DATA chunks that haven't gone out yet ๐ธ
When the peer gets the SHUTDOWN chunk, it does three things:
- hops into the SHUTDOWN-RECEIVED state,
- stops taking new data from its SCTP user, and
- double-checks, using the Cumulative TSN Ack field of the chunk, that every one of its outstanding DATA chunks has been received by the SHUTDOWN chunk sender.
Once you're in SHUTDOWN-RECEIVED, you MUST ignore ULP shutdown requests, but you MUST keep answering SHUTDOWN chunks from your peer ๐
If there's still outstanding DATA hanging around, the SHUTDOWN chunk receiver MUST keep following the normal data transmission procedures from Section 6 until everything is acknowledged. However, it MUST NOT accept new data from its SCTP user ๐ง
While in SHUTDOWN-SENT, the SHUTDOWN chunk sender MUST immediately respond to each received packet containing one or more DATA chunks with a SHUTDOWN chunk, and restart the T2-shutdown timer. If a SHUTDOWN chunk by itself can't acknowledge all the received DATA chunks (meaning there are TSNs that can be acknowledged that are larger than the cumulative TSN, so gaps exist in the TSN sequence), or if duplicate TSNs have been received, then a SACK chunk MUST also be sent ๐
The sender of the SHUTDOWN chunk MAY also start an overall guard timer, T5-shutdown-guard, to bound the whole shutdown sequence. When that timer expires, the sender SHOULD abort the association by sending an ABORT chunk. If T5-shutdown-guard is used, it SHOULD be set to the RECOMMENDED value of 5 times 'RTO.Max' โฑ๏ธ
If the receiver of the SHUTDOWN chunk has no more outstanding DATA chunks, it MUST send a SHUTDOWN ACK chunk and start a T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If that timer expires, the endpoint MUST resend the SHUTDOWN ACK chunk ๐ฅน
The sender of the SHUTDOWN ACK chunk SHOULD limit its retransmissions of that chunk to 'Association.Max.Retrans'. If that threshold is exceeded, the endpoint SHOULD destroy the TCB and SHOULD report the peer endpoint unreachable to the upper layer, and the association enters the CLOSED state ๐ช
When the SHUTDOWN chunk sender gets the SHUTDOWN ACK chunk, it MUST stop the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and remove all record of the association ๐
When a SHUTDOWN COMPLETE chunk arrives, the endpoint checks that it's in SHUTDOWN-ACK-SENT. If it isn't, the chunk SHOULD be discarded. If it is in SHUTDOWN-ACK-SENT, the endpoint SHOULD stop the T2-shutdown timer and remove all knowledge of the association, so the association enters the CLOSED state โจ
An endpoint SHOULD make sure all its outstanding DATA chunks have been acknowledged before it starts the shutdown procedure ๐งผ
An endpoint SHOULD reject any new data request from its upper layer if it is in SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, or SHUTDOWN-ACK-SENT ๐
If an endpoint in SHUTDOWN-ACK-SENT receives an INIT chunk (say the SHUTDOWN COMPLETE chunk got lost) whose source and destination transport addresses (either in the IP addresses or in the INIT chunk) belong to this association, it SHOULD discard the INIT chunk and retransmit the SHUTDOWN ACK chunk ๐
Note: Receipt of a packet containing an INIT chunk with the same source and destination IP addresses as used in transport addresses assigned to an endpoint, but with a different port number, indicates the initialization of a separate association. ๐
The sender of the INIT or COOKIE ECHO chunk SHOULD respond to a SHUTDOWN ACK chunk with a stand-alone SHUTDOWN COMPLETE chunk, in an SCTP packet whose common header's Verification Tag field is set to the same tag that was received in the packet containing the SHUTDOWN ACK chunk. This counts as an OOTB packet, as defined in Section 8.4. The sender of the INIT chunk lets T1-init keep running and stays in the COOKIE-WAIT or COOKIE-ECHOED state. When T1-init expires as normal, the INIT or COOKIE chunk gets retransmitted, which starts a new association ๐
If a SHUTDOWN chunk is received in the COOKIE-WAIT or COOKIE ECHOED state, the SHUTDOWN chunk SHOULD be silently discarded ๐คซ
If an endpoint in SHUTDOWN-SENT receives a SHUTDOWN chunk from its peer, the endpoint SHOULD respond immediately with a SHUTDOWN ACK chunk to its peer, move into the SHUTDOWN-ACK-SENT state, and restart its T2-shutdown timer ๐ค
If an endpoint in SHUTDOWN-ACK-SENT receives a SHUTDOWN ACK, it MUST stop the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and remove all record of the association ๐
10. ICMP Handling ๐ธ
Whenever an SCTP endpoint receives an ICMP message, the following procedures MUST be followed so the info layer 3 is providing gets used properly ๐ง
ICMP1)An implementation MAY ignore all ICMPv4 messages where the type field is not set to "Destination Unreachable".ICMP2)An implementation MAY ignore all ICMPv6 messages where the type field is not "Destination Unreachable", "Parameter Problem", or "Packet Too Big".ICMP3)An implementation SHOULD ignore any ICMP messages where the code indicates "Port Unreachable".ICMP4)An implementation MAY ignore all ICMPv6 messages of type "Parameter Problem" if the code is not "Unrecognized Next Header Type Encountered".ICMP5)An implementation MUST use the payload of the ICMP message (v4 or v6) to locate the association that sent the message to which ICMP is responding. If the association cannot be found, an implementation SHOULD ignore the ICMP message.ICMP6)An implementation MUST validate that the Verification Tag contained in the ICMP message matches the Verification Tag of the peer. If the Verification Tag is not 0 and does not match, discard the ICMP message. If it is 0 and the ICMP message contains enough bytes to verify that the chunk type is an INIT chunk and that the Initiate Tag matches the tag of the peer, continue with ICMP7. If the ICMP message is too short, or the chunk type or the Initiate Tag does not match, silently discard the packet.ICMP7)If the ICMP message is either an ICMPv6 message of type "Packet Too Big" or an ICMPv4 message of type "Destination Unreachable" and code "Fragmentation Needed", an implementation SHOULD process this information as defined for PMTU discovery.ICMP8)If the ICMP code is "Unrecognized Next Header Type Encountered" or "Protocol Unreachable", an implementation MUST treat this message as an abort with the T bit set if it does not contain an INIT chunk. If it does contain an INIT chunk and the association is in the COOKIE-WAIT state, handle the ICMP message like an ABORT chunk.ICMP9)If the ICMP type is "Destination Unreachable", the implementation MAY move the destination to the unreachable state or, alternatively, increment the path error counter. SCTP MAY provide information to the upper layer indicating the reception of ICMP messages when reporting a network status change.
These procedures differ from [RFC1122] and from its requirements for processing of port-unreachable messages, and from the requirements that an implementation MUST abort associations in response to a protocol unreachable message. Port-unreachable messages are not processed, since an implementation will send an ABORT chunk, not a port-unreachable message. The stricter handling of the protocol unreachable message is due to security concerns for hosts that do not support SCTP ๐ก๏ธ
11. Interface with Upper Layer ๐
The Upper Layer Protocols (ULPs) request services by passing primitives to SCTP, and they receive notifications from SCTP about various events ๐ฃ
The primitives and notifications described in this section can be used as a guideline for implementing SCTP. The functional description of the ULP interface primitives below is shown for illustrative purposes. Different SCTP implementations can have different ULP interfaces. However, all SCTP implementations are expected to provide a certain minimum set of services, so that every SCTP implementation can support the same protocol hierarchy ๐งฉ
Heads up: this section is informational only ๐
[RFC6458] and Section 7 ("Socket API Considerations") of [RFC7053] define an extension of the socket API for SCTP as described in this document ๐
11.1. ULP-to-SCTP ๐
The following sections functionally characterize a ULP/SCTP interface. The notation is similar to most procedure or function calls in high-level languages ๐
The ULP primitives below describe the basic functions SCTP performs to support inter-process communication. Individual implementations define their own exact format and provide combinations or subsets of the basic functions in single calls โจ
11.1.1. Initialize
INITIALIZE ([local port],[local eligible address list])
-> local SCTP instance name
Okay bestie, INITIALIZE is the setup moment ๐ It lets SCTP set up its internal data structures and grab the resources it needs for its operating environment โจ Once SCTP is initialized, the ULP can talk straight to other endpoints without calling this again, which is so efficient ๐ซถ SCTP hands the ULP back a local SCTP instance name ๐
Mandatory attributes: None.
Optional attributes:
- local port: SCTP port number, if ULP wants it to be specified.
- local eligible address list: an address list that the local SCTP endpoint binds. By default, if an address list is not included, all IP addresses assigned to the host are used by the local endpoint ๐ธ
Implementation Note: If this optional attribute is supported by an implementation, it will be the responsibility of the implementation to enforce that the IP source address field of any SCTP packets sent by this endpoint contains one of the IP addresses indicated in the local eligible address list ๐ฆ
11.1.2. Associate
ASSOCIATE(local SCTP instance name,
initial destination transport addr list, outbound stream count)
-> association id [,destination transport addr list]
[,outbound stream count]
This primitive lets the upper layer start an association with a specific peer endpoint ๐ง The peer endpoint is specified by one or more of the transport addresses that define the endpoint (see Section 1.3). If the local SCTP instance has not been initialized, the ASSOCIATE is considered an error ๐
An association id, which is a local handle to the SCTP association, will be returned on successful establishment of the association. If SCTP is not able to open an SCTP association with the peer endpoint, an error is returned ๐ญ
Other association parameters can be returned, including the complete destination transport addresses of the peer as well as the outbound stream count of the local endpoint. One of the transport addresses from the returned destination addresses will be selected by the local endpoint as the default primary path for sending SCTP packets to this peer ๐ The returned "destination transport addr list" can be used by the ULP to change the default primary path or to force sending a packet to a specific transport address ๐
Implementation Note: If the ASSOCIATE primitive is implemented as a blocking function call, the ASSOCIATE primitive can return association parameters in addition to the association id upon successful establishment. If ASSOCIATE primitive is implemented as a non-blocking call, only the association id is returned and association parameters are passed using the COMMUNICATION UP notification ๐
Mandatory attributes:
- local SCTP instance name: obtained from the INITIALIZE operation.
- initial destination transport addr list: a non-empty list of transport addresses of the peer endpoint with which the association is to be established.
- outbound stream count: the number of outbound streams the ULP would like to open towards this peer endpoint.
Optional attributes: None.
11.1.3. Shutdown
SHUTDOWN(association id) -> result
SHUTDOWN is the gentle exit ๐ธ It gracefully closes an association. Any locally queued user data will be delivered to the peer. The association will be terminated only after the peer acknowledges all the SCTP packets sent. A success code will be returned on successful termination of the association. If attempting to terminate the association results in a failure, an error code is returned ๐
Mandatory attributes:
- association id: local handle to the SCTP association.
Optional attributes: None.
11.1.4. Abort
ABORT(association id [, Upper Layer Abort Reason]) -> result
ABORT is the dramatic exit ๐ It ungracefully closes an association. Any locally queued user data will be discarded, and an ABORT chunk is sent to the peer. A success code will be returned on successful abort of the association. If attempting to abort the association results in a failure, an error code is returned ๐ญ
Mandatory attributes:
- association id: local handle to the SCTP association.
Optional attributes:
- Upper Layer Abort Reason: reason of the abort to be passed to the peer.
11.1.5. Send
SEND(association id, buffer address, byte count [,context]
[,stream id] [,life time] [,destination transport address]
[,unordered flag] [,no-bundle flag] [,payload protocol-id]
[,sack-immediately flag]) -> result
This is the main method for sending user data via SCTP, so it's giving main character energy ๐
Mandatory attributes:
- association id: local handle to the SCTP association.
- buffer address: the location where the user message to be transmitted is stored.
- byte count: the size of the user data in number of bytes.
Optional attributes:
- context: optional information provided that will be carried in the SEND FAILURE notification to the ULP if the transportation of this user message fails.
- stream id: indicates which stream to send the data on. If not specified, stream 0 will be used ๐
- life time: specifies the life time of the user data. The user data will not be sent by SCTP after the life time expires. This parameter can be used to avoid efforts to transmit stale user messages. SCTP notifies the ULP if the data cannot be initiated to transport (i.e., sent to the destination via SCTP's SEND primitive) within the life time variable. However, the user data will be transmitted if SCTP has attempted to transmit a chunk before the life time expired โณ
Implementation Note: In order to better support the data life time option, the transmitter can hold back the assigning of the TSN number to an outbound DATA chunk to the last moment. And, for implementation simplicity, once a TSN number has been assigned, the sender considers the send of this DATA chunk as committed, overriding any life time option attached to the DATA chunk ๐ง
- destination transport address: specified as one of the destination transport addresses of the peer endpoint to which this packet is sent. Whenever possible, SCTP uses this destination transport address for sending the packets, instead of the current primary path ๐ฆ
- unordered flag: this flag, if present, indicates that the user would like the data delivered in an unordered fashion to the peer (i.e., the U flag is set to 1 on all DATA chunks carrying this message) ๐
- no-bundle flag: instructs SCTP not to delay the sending of DATA chunks for this user data just to allow it to be bundled with other outbound DATA chunks. When faced with network congestion, SCTP might still bundle the data, even when this flag is present ๐ซถ
- payload protocol-id: a 32-bit unsigned integer that is to be passed to the peer, indicating the type of payload protocol data being transmitted. Note that the upper layer is responsible for the host to network byte order conversion of this field, which is passed by SCTP as 4 bytes of opaque data ๐ฅ
- sack-immediately flag: set the I bit on the last DATA chunk used for the user message to be transmitted โจ
11.1.6. Set Primary
SETPRIMARY(association id, destination transport address,
[source transport address]) -> result
SETPRIMARY tells the local SCTP to use the specified destination transport address as the primary path for sending packets ๐
The result of attempting this operation is returned. If the specified destination transport address is not present in the "destination transport address list" returned earlier in an ASSOCIATE primitive or COMMUNICATION UP notification, an error is returned ๐
Mandatory attributes:
- association id: local handle to the SCTP association.
- destination transport address: specified as one of the transport addresses of the peer endpoint, which is used as the primary address for sending packets. This overrides the current primary address information maintained by the local SCTP endpoint.
Optional attributes:
- source transport address: optionally, some implementations can allow you to set the default source address placed in all outgoing IP datagrams.
11.1.7. Receive
RECEIVE(association id, buffer address, buffer size [,stream id])
-> byte count [,transport address] [,stream id]
[,stream sequence number] [,partial flag] [,payload protocol-id]
This primitive reads the first user message in the SCTP in-queue into the buffer specified by ULP, if there is one available ๐ฅ The size of the message read, in bytes, will be returned. Depending on the specific implementation, it might also return other info, such as the sender's address, the stream id on which it is received, whether there are more messages available for retrieval, etc. For ordered messages, their Stream Sequence Number might also be returned ๐ธ
Depending upon the implementation, if this primitive is invoked when no message is available, the implementation returns an indication of this condition or blocks the invoking process until data does become available ๐
Mandatory attributes:
- association id: local handle to the SCTP association.
- buffer address: the memory location indicated by the ULP to store the received message.
- buffer size: the maximum size of data to be received, in bytes.
Optional attributes:
- stream id: to indicate which stream to receive the data on.
- stream sequence number: the Stream Sequence Number assigned by the sending SCTP peer.
- partial flag: if this returned flag is set to 1, then this primitive contains a partial delivery of the whole message. When this flag is set, the stream id and stream sequence number accompanies this primitive. When this flag is set to 0, it indicates that no more deliveries will be received for this stream sequence number ๐
- payload protocol-id: a 32-bit unsigned integer that is received from the peer indicating the type of payload protocol of the received data. Note that the upper layer is responsible for the host to network byte order conversion of this field, which is passed by SCTP as 4 bytes of opaque data ๐ง
11.1.8. Status
STATUS(association id) -> status data
This primitive returns a data block containing the following information ๐
- association connection state,
- destination transport address list,
- destination transport address reachability states,
- current receiver window size,
- current congestion window sizes,
- number of unacknowledged DATA chunks,
- number of DATA chunks pending receipt,
- primary path,
- most recent SRTT on primary path,
- RTO on primary path,
- SRTT and RTO on other destination addresses, etc.
Mandatory attributes:
- association id: local handle to the SCTP association.
Optional attributes: None.
11.1.9. Change Heartbeat ๐
CHANGE HEARTBEAT(association id, destination transport address,
new state [,interval]) -> result
okay so this primitive is how the local endpoint turns heartbeat on or off for a specific destination transport address ๐ซถ it's giving control!!
The result of trying this is returned to you ๐
Note: even when heartbeat is enabled, it won't actually happen if the destination transport address is not idle ๐ so enabled doesn't always mean it's running rn
Mandatory attributes:
association id: your local handle to the SCTP association ๐destination transport address: has to be one of the transport addresses of the peer endpoint ๐ธnew state: the new heartbeat state for this destination transport address, either enabled or disabled โจ
Optional attributes:
interval: if you include it, it sets how often the heartbeat happens when you're turning heartbeat on for a destination transport address ๐ฆ this value gets added to the RTO of that destination transport address, and if it's included it affects all destinations, so be careful bestie ๐
11.1.10. Request Heartbeat ๐
REQUESTHEARTBEAT(association id, destination transport address)
-> result
this one tells the local endpoint to do a heartbeat right now on a specific destination transport address of the association ๐ the result tells you whether sending the HEARTBEAT chunk to that destination address worked or not ๐
Mandatory attributes:
association id: your local handle to the SCTP association ๐destination transport address: the transport address of the association where the heartbeat gets sent ๐
Optional attributes:
- None. ๐ซ
11.1.11. Get SRTT Report ๐
GETSRTTREPORT(association id, destination transport address)
-> srtt result
this primitive asks the local SCTP to report the current SRTT measurement on a given destination transport address of the association โจ the result can be an integer holding the most recent SRTT, in milliseconds ๐
Mandatory attributes:
association id: your local handle to the SCTP association ๐destination transport address: the transport address of the association where the SRTT measurement should be reported ๐ธ
Optional attributes:
- None. ๐
11.1.12. Set Failure Threshold ๐จ
SETFAILURETHRESHOLD(association id, destination transport address,
failure threshold) -> result
this one lets the local SCTP customize the reachability failure detection threshold, which is called 'Path.Max.Retrans', for a specific destination address ๐ง quick heads up, you can also do this with the SETPROTOCOLPARAMETERS primitive (Section 11.1.13) so pick your fave way ๐
Mandatory attributes:
association id: your local handle to the SCTP association ๐destination transport address: the transport address of the association where the failure detection threshold is getting set ๐ฆfailure threshold: the new value of 'Path.Max.Retrans' for that destination address ๐ฅ
Optional attributes:
- None. ๐ซถ
11.1.13. Set Protocol Parameters โ๏ธ
SETPROTOCOLPARAMETERS(association id,
[destination transport address,] protocol parameter list)
-> result
this primitive is the big glow-up tool ๐ซ it lets the local SCTP customize the protocol parameters
Mandatory attributes:
association id: your local handle to the SCTP association ๐protocol parameter list: the specific names and values of the protocol parameters that the SCTP user wants to customize, like 'Association.Max.Retrans' (see Section 16) or other stuff like the DSCP ๐
Optional attributes:
destination transport address: some protocol parameters might be set per destination transport address, so this is where that happens ๐ธ
11.1.14. Receive Unsent Message ๐ญ
RECEIVE_UNSENT(data retrieval id, buffer address, buffer size
[,stream id] [, stream sequence number] [,partial flag]
[,payload protocol-id])
this primitive reads a user message that has never been sent, and drops it into the buffer the ULP specified ๐งบ it's kinda like rescuing a text you never hit send on ๐ญ
Mandatory attributes:
data retrieval id: the identification passed to the ULP in the SEND FAILURE notification ๐ชชbuffer address: the memory location the ULP indicated for storing the received message ๐buffer size: the maximum size of data to be received, in bytes ๐
Optional attributes:
stream id: this is a return value that gets set to show which stream the data was sent to ๐stream sequence number: this value is returned, showing the Stream Sequence Number that went with the message ๐ขpartial flag: if this returned flag is set to 1, then the message is a partial delivery of the whole message ๐งฉ when this flag is set, the stream id and stream sequence number come along with this primitive ๐ when the flag is set to 0, it means no more deliveries are coming for that stream sequence number ๐payload protocol-id: the 32-bit unsigned integer that was set to be sent to the peer, showing the type of payload protocol for the received data ๐งพ
11.1.15. Receive Unacknowledged Message ๐ฌ
RECEIVE_UNACKED(data retrieval id, buffer address, buffer size,
[,stream id] [,stream sequence number] [,partial flag]
[,payload protocol-id])
this one is kinda the sibling of the last primitive ๐ฏโโ๏ธ it reads a user message that has been sent but has not been acknowledged by the peer, and puts it into the buffer the ULP specified ๐ซง
Mandatory attributes:
data retrieval id: the identification passed to the ULP in the SEND FAILURE notification ๐ชชbuffer address: the memory location the ULP indicated for storing the received message ๐buffer size: the maximum size of data to be received, in bytes ๐
Optional attributes:
stream id: a return value that gets set to show which stream the data was sent to ๐stream sequence number: this value is returned, showing the Stream Sequence Number that went with the message ๐ขpartial flag: if this returned flag is set to 1, the message is a partial delivery of the whole message ๐งฉ when this flag is set, the stream id and stream sequence number come along with this primitive ๐ when it's set to 0, no more deliveries will be received for that stream sequence number ๐payload protocol-id: the 32-bit unsigned integer that was sent to the peer, showing the type of payload protocol for the received data ๐งพ
11.1.16. Destroy SCTP Instance ๐ฅ
DESTROY(local SCTP instance name)
this is the clean-up primitive, bestie ๐งนโจ
Mandatory attributes:
local SCTP instance name: the value that was passed to the application in the initialize primitive, showing which SCTP instance is getting destroyed ๐
Optional attributes:
- None. ๐ท
11.2. SCTP-to-ULP ๐ฃ
okay now we flip it, so this is the SCTP telling the ULP stuff ๐ it's assumed that the operating system or application environment gives SCTP a way to signal the ULP process asynchronously ๐ when SCTP does signal a ULP process, certain information gets passed along to the ULP ๐
Implementation Note: in some cases this might happen through a separate socket or error channel ๐งฆ
11.2.1. DATA ARRIVE Notification ๐ฉ
SCTP invokes this notification on the ULP when a user message has been successfully received and is ready for retrieval ๐
The following might optionally be passed with the notification:
association id: your local handle to the SCTP association ๐stream id: shows which stream the data was received on ๐
11.2.2. SEND FAILURE Notification ๐ซ
if a message can't be delivered, SCTP invokes this notification on the ULP ๐ญ
The following might optionally be passed with the notification:
association id: your local handle to the SCTP association ๐data retrieval id: an identification used to retrieve unsent and unacknowledged data ๐ชชmode: indicates whether no part of the message never has been sent, or if at least part of it has been sent but it is not completely acknowledged ๐คcause code: indicates the reason for the failure, e.g., size too large, message life time expiration, etc. ๐งพcontext: optional information associated with this message (see Section 11.1.5) ๐ง
11.2.3. NETWORK STATUS CHANGE Notification ๐ก
when a destination transport address gets marked inactive (like when SCTP detects a failure) or marked active (like when SCTP detects a recovery), SCTP invokes this notification on the ULP ๐
The following is passed with the notification:
association id: your local handle to the SCTP association ๐destination transport address: the destination transport address of the peer endpoint affected by the change ๐ธnew-status: indicates the new status ๐ฆ
11.2.4. COMMUNICATION UP Notification ๐ฅณ
this notification is used when SCTP becomes ready to send or receive user messages, or when a lost communication to an endpoint gets restored ๐
Implementation Note: if the ASSOCIATE primitive is implemented as a blocking function call, the association parameters are returned as a result of the ASSOCIATE primitive itself ๐งฉ in that case, the COMMUNICATION UP notification is optional at the association initiator's side ๐ซถ
The following is passed with the notification:
association id: your local handle to the SCTP association ๐status: indicates what type of event has occurred โจdestination transport address list: the complete set of transport addresses of the peer ๐บ๏ธoutbound stream count: the maximum number of streams the ULP is allowed to use in this association ๐inbound stream count: the number of streams the peer endpoint has requested with this association (this might not be the same number as 'outbound stream count') ๐ข
11.2.5. COMMUNICATION LOST Notification ๐
when SCTP loses communication to an endpoint completely (e.g., via Heartbeats) or detects that the endpoint has performed an abort operation, it invokes this notification on the ULP ๐ข
The following is passed with the notification:
association id: your local handle to the SCTP association ๐status: indicates what type of event has occurred; the status might show that a failure OR a normal termination event happened in response to a shutdown or abort request ๐ฅ
The following might be passed with the notification:
last-acked: the TSN last acked by that peer endpoint ๐ฎlast-sent: the TSN last sent to that peer endpoint ๐คUpper Layer Abort Reason: the abort reason specified in case of a user-initiated abort ๐
11.2.6. COMMUNICATION ERROR Notification โ ๏ธ
when SCTP receives an ERROR chunk from its peer and decides to notify its ULP, it can invoke this notification on the ULP ๐
The following can be passed with the notification:
association id: your local handle to the SCTP association ๐error info: indicates the type of error, and optionally some additional info received through the ERROR chunk ๐งพ
11.2.7. RESTART Notification ๐
when SCTP detects that the peer has restarted, it might send this notification to its ULP ๐
The following can be passed with the notification:
association id: your local handle to the SCTP association ๐
11.2.8. SHUTDOWN COMPLETE Notification ๐
when SCTP completes the shutdown procedures (Section 9.2), this notification is passed to the upper layer ๐ฌ
The following can be passed with the notification:
association id: your local handle to the SCTP association ๐
12. Security Considerations ๐โจ
12.1. Security Objectives
okay so SCTP is basically the reliable transport bestie for time-sensitive messages between two networked endpoints, like billing or signaling messages for telephony ๐โจ. Its security goals are:
- availability of reliable and timely data transport services ๐
- integrity of the user-to-user information carried by SCTP ๐
12.2. SCTP Responses to Potential Threats
ngl SCTP could end up in a lot of risky situations ๐ญ. The operators running it need to look at their own setup and pick the right countermeasures for it, no shortcuts ๐ .
Operators running SCTP might check out [RFC2196] for tips on securing their site ๐ก๏ธ.
12.2.1. Countering Insider Attacks
The principles from [RFC2196] might be applied to cut down the risk of insiders stealing info or sabotaging stuff ๐ต๏ธโโ๏ธ. This includes publishing security policies, controlling access at the physical, software, and network levels, and separating services ๐งฑ.
12.2.2. Protecting against Data Corruption in the Network
If the risk of undetected errors in datagrams from the lower-layer transport services feels too high ๐ฌ, extra integrity protection is needed ๐. If that extra protection lived in the application layer, the SCTP header would still be open to deliberate integrity attacks ๐. The existing SCTP ways of catching replayed packets are considered good enough for normal operation โ , but when there's a real chance of deliberate attacks from a sophisticated adversary, stronger protections are needed to keep SCTP safe ๐.
The SCTP Authentication extension SCTP-AUTH [RFC4895] MAY be used when the threat environment needs stronger integrity protections but doesn't need confidentiality ๐.
12.2.3. Protecting Confidentiality
Most of the time, the confidentiality risk is about the signaling data payload, not the SCTP or lower-layer protocol overheads ๐ง. If that's the case, encrypting only the SCTP user data might be worth considering ๐ค. Just like with the supplementary checksum service, user data encryption MAY be performed by the SCTP user application ๐ธ. [RFC6083] MAY be used for this ๐. Alternatively, the user application MAY use an implementation-specific API to ask for the IP Encapsulating Security Payload (ESP) [RFC4303] to be used for confidentiality and integrity ๐ฆ.
Mobile users especially might need confidentiality that also masks IP addresses and ports ๐ฑ. In that case, ESP SHOULD be used instead of application-level confidentiality ๐. If ESP is protecting the confidentiality of SCTP traffic, an ESP cryptographic transform that includes cryptographic integrity protection MUST be used ๐จ. The reason is simple: if there's a confidentiality threat, there's also a strong integrity threat ๐.
No matter where confidentiality is provided, the Internet Key Exchange Protocol version 2 (IKEv2) [RFC7296] SHOULD be used for key management of ESP ๐.
Operators might look at [RFC4301] for more on the security services available at and right above the Internet Protocol layer ๐.
12.2.4. Protecting against Blind Denial-of-Service Attacks
A blind attack is one where the attacker can't intercept or otherwise see the content of the data flows going to and from the target SCTP node ๐. Blind denial-of-service attacks can look like flooding, masquerade, or improper monopolization of services ๐ค.
12.2.4.1. Flooding
The goal of flooding is to break service and cause incorrect behavior at target systems by exhausting resources, getting in the way of legitimate transactions, and exploiting buffer-related software bugs ๐ฅ. Flooding can aim at the SCTP node itself or at resources in the intervening IP Access Links or the Internet ๐. When those in-between entities are the target, the flooding shows up as loss of network services, possibly including a breach of any firewalls in place ๐งฑ๐.
Generally, protection against flooding starts at the equipment design level ๐ ๏ธ. That includes things like:
- avoiding committing limited resources before deciding the request for service is legitimate ๐ โโ๏ธ
- giving priority to finishing work already in progress over accepting new work ๐
- identifying and removing duplicate or stale queued requests for service ๐๏ธ
- not responding to unexpected packets sent to non-unicast addresses ๐ซ
Network equipment is expected to be able to generate an alarm and a log when there's a suspicious jump in traffic ๐จ. The log shares info like the identity of the incoming link and the source address(es) used, which helps the network or SCTP system operator take protective measures ๐. Procedures are expected to be in place so the operator can act on those alarms if a clear pattern of abuse shows up ๐.
The design of SCTP is resistant to flooding attacks, and it's honestly iconic for that ๐. It uses a four-way startup handshake, a cookie to delay committing resources at the responding SCTP node until the handshake is done, and a Verification Tag to stop extraneous packets from getting into the flow of an established association ๐ .
ESP might be useful for reducing the risk of certain kinds of denial-of-service attacks ๐ฆ.
Support for the Host Name Address parameter has been removed from the protocol ๐๏ธ. Endpoints that receive INIT or INIT ACK chunks containing the Host Name Address parameter MUST send an ABORT chunk in response ๐ and MAY include an "Unresolvable Address" error cause ๐.
12.2.4.2. Blind Masquerade
Masquerade can be used to deny service in a few different ways ๐ญ:
- by tying up resources at the target SCTP node that the impersonated node has limited access to ๐งถ. For example, the target node can, by policy, allow a maximum of one SCTP association with the impersonated SCTP node ๐ช. The masquerading attacker can try to set up an association pretending to come from the impersonated node, so the real node can't do it when it actually needs to ๐ฉ.
- by deliberately letting the impersonation get detected, which provokes countermeasures that lock the impersonated node out of the target SCTP node ๐.
- by interfering with an established association by inserting extraneous content, like a SHUTDOWN chunk ๐.
SCTP cuts down the risk of blind masquerade attacks through IP spoofing by using the four-way startup handshake ๐ค. The initial exchange is memoryless, so no lockout mechanism gets triggered by blind masquerade attacks ๐. Also, the packet carrying the INIT ACK chunk with the State Cookie goes back to the IP address that sent the packet with the INIT chunk ๐ฌ. So the attacker never receives the INIT ACK chunk with the State Cookie ๐ โโ๏ธ. SCTP protects against extraneous packets getting into an established association by using the Verification Tag ๐ท๏ธ.
Logging received INIT chunks and abnormalities, like unexpected INIT ACK chunks, might be considered as a way to spot patterns of hostile activity ๐. But the usefulness of that logging has to be weighed against the extra SCTP startup processing it adds, which makes the SCTP node more vulnerable to flooding attacks ๐ฌ. Logging is pointless unless there are operating procedures to review and analyze the logs on a routine basis ๐.
12.2.4.3. Improper Monopolization of Services
These attacks are done openly and legitimately by the attacker ๐. They target fellow users of the target SCTP node, or shared resources between the attacker and the target node ๐๏ธ. Possible attacks include opening a large number of associations between the attacker's node and the target, or transferring large volumes of information within a legitimately established association ๐ฆ.
Policy limits are expected to be placed on the number of associations per adjoining SCTP node ๐ง. SCTP user applications are expected to be able to detect large volumes of illegitimate or "no-op" messages within a given association, and then either log it or terminate the association, based on local policy ๐งน.
12.3. SCTP Interactions with Firewalls
Some firewalls really benefit if they can inspect just the first fragment of a fragmented SCTP packet and clearly tell whether it's an INIT chunk (for more, check out [RFC1858]) ๐ฅ. So we're stressing the requirements from Section 3.1: (1) an INIT chunk MUST NOT be bundled with any other chunk in a packet, and (2) a packet containing an INIT chunk MUST have a zero Verification Tag ๐. The receiver of an INIT chunk MUST silently discard the INIT chunk and all further chunks if the INIT chunk is bundled with other chunks or if the packet has a non-zero Verification Tag ๐ โโ๏ธ.
12.4. Protection of Non-SCTP-capable Hosts
To give a non-SCTP-capable host the same level of protection against attacks as SCTP-capable ones, all SCTP implementations MUST implement the ICMP handling described in Section 10 ๐ซถ.
When an SCTP implementation gets a packet with multiple control or DATA chunks, and processing that packet would mean sending multiple chunks back, the sender of the response chunk(s) MUST NOT send more than one packet containing chunks other than DATA chunks ๐ฆ. This keeps the network from getting hit with a packet burst in response to a single packet ๐. If bundling is supported, multiple response chunks that fit into a single packet MAY be bundled together into one response packet ๐. If bundling isn't supported, the sender MUST NOT send more than one response chunk and MUST discard all other responses ๐๏ธ. Note that this rule doesn't apply to a SACK chunk, since a SACK chunk is itself a response to DATA chunks, and it doesn't need a response of more DATA chunks ๐.
An SCTP implementation MUST abort the association if it receives a SACK chunk acknowledging a TSN that hasn't been sent ๐.
If an SCTP implementation gets an INIT chunk that would need a large packet in response, because it includes multiple "Unrecognized Parameter" parameters, it MAY (at its discretion) choose to omit some or all of the "Unrecognized Parameter" parameters to shrink the INIT ACK chunk ๐ช. Because of the size of the State Cookie parameter combined with the number of addresses a receiver of an INIT chunk tells a peer about, the INIT ACK chunk can always end up bigger than the original INIT chunk ๐. An SCTP implementation SHOULD try to make the INIT ACK chunk as small as possible to reduce the chance of byte amplification attacks ๐ง.
13. Network Management Considerations
The MIB module for SCTP defined in [RFC3873] applies to the version of the protocol specified in this document ๐.
14. Recommended Transmission Control Block (TCB) Parameters
This section details a set of parameters that are expected to be in the TCB for an implementation ๐ง . It's just for illustration ๐จ and isn't considered requirements on an implementation, nor is it an exhaustive list of all parameters inside an SCTP TCB ๐. Each implementation might need its own extra parameters for optimization โก.
14.1. Parameters Necessary for the SCTP Instance โจ
- Associations: okay so this is your list of current associations plus the mapping to the data consumers for each one ๐ It can be a hash table or some other implementation-dependent structure, whatever fits. The data consumers might be process identification info, like file descriptors, a named pipe pointer, or table pointers, depending on how SCTP is implemented ๐ง
- Secret Key: the secret key this endpoint uses to compute the MAC ๐ This SHOULD be a cryptographic quality random number with a sufficient length. [RFC4086] can be super helpful when picking the key ๐
- Address List: the list of IP addresses this instance has bound. It gets passed to your peer(s) in INIT and INIT ACK chunks ๐ฆ
- SCTP Port: the local SCTP port number the endpoint is bound to ๐
14.2. Parameters Necessary per Association (i.e., the TCB) ๐
- Peer Verification Tag: the tag value that gets sent in every packet, and it's received in the INIT or INIT ACK chunk ๐ธ
- My Verification Tag: the tag expected in every inbound packet, and it's sent in the INIT or INIT ACK chunk ๐ธ
- State:
COOKIE-WAIT,COOKIE-ECHOED,ESTABLISHED,SHUTDOWN-PENDING,SHUTDOWN-SENT,SHUTDOWN-RECEIVED,SHUTDOWN-ACK-SENT๐
Note: there's no "CLOSED" state in this list, because if an association is "CLOSED", its TCB SHOULD be removed. Bye bye, TCB ๐
- Peer Transport Address List: a list of SCTP transport addresses the peer is bound to. This comes from the INIT or INIT ACK chunk and it's how an inbound packet gets matched to its association. Normally this is hashed or keyed so the TCB is quick to look up and access ๐
- Primary Path: the current primary destination transport address of the peer endpoint. It might also specify a source transport address on this endpoint ๐ค๏ธ
- Overall Error Count: the overall association error count ๐
- Overall Error Threshold: the threshold for this association. If the Overall Error Count reaches it, the association gets torn down ๐
- Peer Rwnd: the current calculated value of the peer's
rwnd๐ช - Next TSN: the next TSN to be assigned to a new DATA chunk. It's sent to the peer in the INIT or INIT ACK chunk, and it goes up each time a DATA chunk gets assigned a TSN (usually right before transmit or during fragmentation) ๐ข
- Last Rcvd TSN: the last TSN received in sequence. It starts out by taking the peer's Initial TSN (received in the INIT or INIT ACK chunk) and subtracting one from it ๐ฏ
- Mapping Array: an array of bits or bytes showing which out-of-order TSNs have been received, relative to the Last Rcvd TSN. If there are no gaps (no out-of-order packets have arrived), this array is all zeros. It might be a circular buffer or a bit array ๐งฉ
- Ack State: a flag that says whether the next received packet gets answered with a SACK chunk. It starts at 0, goes up with each packet received, and once it hits 2 or more, a SACK chunk goes out and the value resets to 0. Note: this is only used when no DATA chunks arrive out of order. When they do, SACK chunks are not delayed (see Section 6) ๐
- Inbound Streams: an array of structures tracking the inbound streams. It normally includes the next sequence number expected and possibly the stream number ๐ฅ
- Outbound Streams: an array of structures tracking the outbound streams. It normally includes the next sequence number to be sent on the stream ๐ค
- Reasm Queue: a reassembly queue ๐งต
- Receive Buffer: a buffer that stores received user data that hasn't been delivered to the upper layer yet ๐ฆ
- Local Transport Address List: the list of local IP addresses bound into this association ๐
- Association Maximum DATA Chunk Size: the smallest Path Maximum DATA Chunk Size across all destination addresses ๐
14.3. Per Transport Address Data ๐ฆ
For each destination transport address in the peer's address list (the one derived from the INIT or INIT ACK chunk), a bunch of data elements need to be maintained, including:
- Error Count: the current error count for this destination ๐
- Error Threshold: the current error threshold for this destination. In other words, the value that marks the destination down if the error count reaches it โฌ๏ธ
- cwnd: the current congestion window ๐ช
- ssthresh: the current ssthresh value ๐๏ธ
- RTO: the current retransmission timeout value โฑ๏ธ
- SRTT: the current smoothed round-trip time ๐
- RTTVAR: the current RTT variation ๐
- partial bytes acked: the tracking method for increasing cwnd when you're in congestion avoidance mode (see Section 7.2.2) ๐งฎ
- state: the current state of this destination, i.e., DOWN, UP, ALLOW-HEARTBEAT, NO-HEARTBEAT, etc. ๐ฆ
- PMTU: the current known PMTU ๐
- PMDCS: the current known PMDCS ๐
- Per Destination Timer: a timer used by each destination โฐ
- RTO-Pending: a flag that tracks whether one of the DATA chunks sent to this address is currently being used to compute an RTT. If this flag is 0, the next DATA chunk sent to this destination is expected to be used for the RTT computation, and this flag is expected to be set. Every time the RTT calculation completes (aka the DATA chunk gets acknowledged), clear this flag ๐
- last-time: the time this destination was last sent to. It can be used to figure out whether a HEARTBEAT chunk needs to be sent ๐
14.4. General Parameters Needed ๐
- Out Queue: a queue of outbound DATA chunks ๐ฎ
- In Queue: a queue of inbound DATA chunks ๐ฌ
15. IANA Considerations โจ
okay bestie, IANA is the one keeping track of all the registries ๐๏ธ, and this document defines five of them ๐ . Registries can grow in these ways:
- through definition of additional chunk types,
- through definition of additional chunk flags,
- through definition of additional parameter types,
- through definition of additional cause codes within ERROR chunks, or
- through definition of additional payload protocol identifiers.
IANA has already done a bunch of updates for those five registries, and it's giving organized ๐:
- In the
Chunk Typesregistry, IANA swapped the registry reference to [RFC4960] and [RFC6096] for a reference to this document ๐ฆ.
In the Notes section too, the reference to Section 3.2 of [RFC6096] got updated to point at Section 15.2 of this document โจ.
And every reference to [RFC4960] got replaced with this document for these chunk types:
- Payload Data (DATA)
- Initiation (INIT)
- Initiation Acknowledgement (INIT ACK)
- Selective Acknowledgement (SACK)
- Heartbeat Request (HEARTBEAT)
- Heartbeat Acknowledgement (HEARTBEAT ACK)
- Abort (ABORT)
- Shutdown (SHUTDOWN)
- Shutdown Acknowledgement (SHUTDOWN ACK)
- Operation Error (ERROR)
- State Cookie (COOKIE ECHO)
- Cookie Acknowledgement (COOKIE ACK)
- Reserved for Explicit Congestion Notification Echo (ECNE)
- Reserved for Congestion Window Reduced (CWR)
- Shutdown Complete (SHUTDOWN COMPLETE)
- Reserved for IETF-defined Chunk Extensions
- In the
Chunk Parameter Typesregistry, IANA swapped the registry reference to [RFC4960] for a reference to this document ๐ธ.
IANA also renamed the Unrecognized Parameters chunk parameter type to Unrecognized Parameter in that registry, so the name is now a bit tidier ๐ซถ.
Every reference to [RFC4960] got replaced with this document for these chunk parameter types:
- Heartbeat Info
- IPv4 Address
- IPv6 Address
- State Cookie
- Unrecognized Parameter
- Cookie Preservative
- Host Name Address
- Supported Address Types
IANA added a reference to this document for this one, which is new to the list:
- Reserved for ECN Capable (0x8000)
And the value 65535 is now reserved for IETF-defined extensions ๐ง.
- In the
Chunk Flagsregistry, IANA replaced the registry reference to [RFC6096] with a reference to this document ๐.
Every reference to [RFC4960] got replaced with this document for these DATA chunk flags:
- E bit
- B bit
- U bit
The reference to [RFC7053] got replaced with this document for this DATA chunk flag:
- I bit
The reference to [RFC4960] got replaced with this document for this ABORT chunk flag:
- T bit
And the reference to [RFC4960] got replaced with this document for this SHUTDOWN COMPLETE chunk flag:
- T bit
- In the
Error Cause Codesregistry, IANA swapped the registry reference to [RFC4960] for a reference to this document ๐.
IANA also renamed two causes, which is a whole glow-up ๐: User Initiated Abort is now User-Initiated Abort, and Stale Cookie Error is now Stale Cookie.
Every reference to [RFC4960] got replaced with this document for these cause codes:
- Invalid Stream Identifier
- Missing Mandatory Parameter
- Stale Cookie
- Out of Resource
- Unresolvable Address
- Unrecognized Chunk Type
- Invalid Mandatory Parameter
- Unrecognized Parameters
- No User Data
- Cookie Received While Shutting Down
- Restart of an Association with New Addresses
IANA also replaced each reference to [RFC4460] with a reference to this document for these cause codes:
- User-Initiated Abort
- Protocol Violation
- In the
SCTP Payload Protocol Identifiersregistry, IANA swapped the registry reference to [RFC4960] for a reference to this document ๐.
The reference to [RFC4960] got replaced with this document for this SCTP payload protocol identifier:
- Reserved by SCTP
SCTP needs the IANA Port Numbers registry to be opened up for SCTP port registrations, and Section 15.6 explains how ๐ฅ. An IESG-appointed Expert Reviewer helps IANA evaluate SCTP port allocation requests ๐.
In the Service Name and Transport Protocol Port Number Registry, IANA replaced each reference to [RFC4960] with a reference to this document for these SCTP port numbers:
9 (discard)20 (ftp-data)21 (ftp)22 (ssh)80 (http)179 (bgp)443 (https)
Over in the Hypertext Transfer Protocol (HTTP) Digest Algorithm Values registry, IANA swapped the reference to Appendix B of [RFC4960] for a reference to Appendix A of this document ๐ฆ.
In the ONC RPC Netids (Standards Action) registry, IANA replaced each reference to [RFC4960] with a reference to this document for these netids:
sctpsctp6
In the IPFIX Information Elements registry, IANA replaced each reference to [RFC4960] with a reference to this document for these elements with the name:
sourceTransportPortdestinationTransportPortcollectorTransportPortexporterTransportPortpostNAPTSourceTransportPortpostNAPTDestinationTransportPort
15.1. IETF-Defined Chunk Extension
Okay, so new chunk type codes are assigned through an IETF Review action, as defined in [RFC8126] ๐. Documentation for a new chunk MUST contain the following information:
- a) A long and short name for the new chunk type.
- b) A detailed description of the structure of the chunk, which MUST conform to the basic structure defined in Section 3.2.
- c) A detailed definition and description of intended use of each field within the chunk, including the chunk flags if any. Defined chunk flags will be used as initial entries in the chunk flags table for the new chunk type.
- d) A detailed procedural description of the use of the new chunk type within the operation of the protocol.
The last chunk type (255) is reserved for future extension if necessary ๐.
For each new chunk type, IANA creates a registration table for the chunk flags of that type ๐. The procedure for registering particular chunk flags is described in Section 15.2.
15.2. IETF-Defined Chunk Flags Registration
New chunk flags are assigned through an RFC Required action, as defined in [RFC8126] ๐. Documentation for the chunk flags MUST contain the following information:
- a) A name for the new chunk flag.
- b) A detailed procedural description of the use of the new chunk flag within the operation of the protocol. It MUST be considered that implementations not supporting the flag will send 0 on transmit and just ignore it on receipt.
IANA selects a chunk flags value ๐ฅ. This MUST be one of 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, or 0x80, which MUST be unique within the chunk flag values for the specific chunk type.
15.3. IETF-Defined Chunk Parameter Extension
New chunk parameter type codes are assigned through an IETF Review action, as defined in [RFC8126] ๐ง. Documentation of the chunk parameter MUST contain the following information:
- a) Name of the parameter type.
- b) Detailed description of the structure of the parameter field. This structure MUST conform to the general Type-Length-Value format described in Section 3.2.1.
- c) Detailed definition of each component of the parameter value.
- d) Detailed description of the intended use of this parameter type and an indication of whether and under what circumstances multiple instances of this parameter type can be found within the same chunk.
- e) Each parameter type MUST be unique across all chunks.
15.4. IETF-Defined Additional Error Causes
Additional cause codes can be allocated through a Specification Required action, as defined in [RFC8126] ๐ . Provided documentation MUST include the following information:
- a) Name of the error condition.
- b) Detailed description of the conditions under which an SCTP endpoint issues an ERROR (or ABORT) chunk with this cause code.
- c) Expected action by the SCTP endpoint that receives an ERROR (or ABORT) chunk containing this cause code.
- d) Detailed description of the structure and content of data fields that accompany this cause code.
The initial word (32 bits) of a cause code parameter MUST conform to the format shown in Section 3.3.10, which means:
- first 2 bytes contain the cause code value
- last 2 bytes contain the length of the error cause
15.5. Payload Protocol Identifiers
Payload protocol identifiers are assigned using the First Come First Served policy, as defined in [RFC8126] ๐ธ.
Except for value 0, which is reserved to indicate an unspecified payload protocol identifier in a DATA chunk, an SCTP implementation will not be responsible for standardizing or verifying any payload protocol identifiers ๐ซถ. An SCTP implementation simply receives the identifier from the upper layer and carries it with the corresponding payload data.
The upper layer, which is the SCTP user, SHOULD standardize any specific protocol identifier with IANA if it is so desired ๐. The use of any specific payload protocol identifier is out of the scope of this specification.
15.6. Port Numbers Registry
SCTP services can use contact port numbers to provide service to unknown callers, just like TCP and UDP do ๐ฆ. An IESG-appointed Expert Reviewer supports IANA in evaluating SCTP port allocation requests, following the procedure defined in [RFC8126]. The details of this process are defined in [RFC6335] โจ.
16. Suggested SCTP Protocol Parameter Values
The following protocol parameters are RECOMMENDED ๐:
RTO.Initial: 1 second
RTO.Min: 1 second
RTO.Max: 60 seconds
Max.Burst: 4
RTO.Alpha: 1/8
RTO.Beta: 1/4
Valid.Cookie.Life: 60 seconds
Association.Max.Retrans: 10 attempts
Path.Max.Retrans: 5 attempts (per destination address)
Max.Init.Retransmits: 8 attempts
HB.interval: 30 seconds
HB.Max.Burst: 1
SACK.Delay: 200 milliseconds
Implementation Note: The SCTP implementation can let the ULP customize some of these protocol parameters, see Section 11 ๐.
RTO.Min SHOULD be set as described above in this section ๐ฅ.
17. References
17.1. Normative References โจ
Okay bestie, these are the docs SCTP straight up needs you to read first ๐ no cap, every single one is listed below exactly as it appears in the spec:
[ITU.V42.1994]
International Telecommunications Union, "Error-correcting
Procedures for DCEs Using Asynchronous-to-Synchronous
Conversion", ITU-T Recommendation V.42, 1994.
[RFC1122] Braden, R., Ed., "Requirements for Internet Hosts -
Communication Layers", STD 3, RFC 1122,
DOI 10.17487/RFC1122, October 1989,
<https://www.rfc-editor.org/info/rfc1122>.
[RFC1123] Braden, R., Ed., "Requirements for Internet Hosts -
Application and Support", STD 3, RFC 1123,
DOI 10.17487/RFC1123, October 1989,
<https://www.rfc-editor.org/info/rfc1123>.
[RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", RFC 1191,
DOI 10.17487/RFC1191, November 1990,
<https://www.rfc-editor.org/info/rfc1191>.
[RFC1982] Elz, R. and R. Bush, "Serial Number Arithmetic", RFC 1982,
DOI 10.17487/RFC1982, August 1996,
<https://www.rfc-editor.org/info/rfc1982>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC4291] Hinden, R. and S. Deering, "IP Version 6 Addressing
Architecture", RFC 4291, DOI 10.17487/RFC4291, February
2006, <https://www.rfc-editor.org/info/rfc4291>.
[RFC4303] Kent, S., "IP Encapsulating Security Payload (ESP)",
RFC 4303, DOI 10.17487/RFC4303, December 2005,
<https://www.rfc-editor.org/info/rfc4303>.
[RFC4895] Tuexen, M., Stewart, R., Lei, P., and E. Rescorla,
"Authenticated Chunks for the Stream Control Transmission
Protocol (SCTP)", RFC 4895, DOI 10.17487/RFC4895, August
2007, <https://www.rfc-editor.org/info/rfc4895>.
[RFC5681] Allman, M., Paxson, V., and E. Blanton, "TCP Congestion
Control", RFC 5681, DOI 10.17487/RFC5681, September 2009,
<https://www.rfc-editor.org/info/rfc5681>.
[RFC6335] Cotton, M., Eggert, L., Touch, J., Westerlund, M., and S.
Cheshire, "Internet Assigned Numbers Authority (IANA)
Procedures for the Management of the Service Name and
Transport Protocol Port Number Registry", BCP 165,
RFC 6335, DOI 10.17487/RFC6335, August 2011,
<https://www.rfc-editor.org/info/rfc6335>.
[RFC6083] Tuexen, M., Seggelmann, R., and E. Rescorla, "Datagram
Transport Layer Security (DTLS) for Stream Control
Transmission Protocol (SCTP)", RFC 6083,
DOI 10.17487/RFC6083, January 2011,
<https://www.rfc-editor.org/info/rfc6083>.
[RFC7296] Kaufman, C., Hoffman, P., Nir, Y., Eronen, P., and T.
Kivinen, "Internet Key Exchange Protocol Version 2
(IKEv2)", STD 79, RFC 7296, DOI 10.17487/RFC7296, October
2014, <https://www.rfc-editor.org/info/rfc7296>.
[RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for
Writing an IANA Considerations Section in RFCs", BCP 26,
RFC 8126, DOI 10.17487/RFC8126, June 2017,
<https://www.rfc-editor.org/info/rfc8126>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC8200] Deering, S. and R. Hinden, "Internet Protocol, Version 6
(IPv6) Specification", STD 86, RFC 8200,
DOI 10.17487/RFC8200, July 2017,
<https://www.rfc-editor.org/info/rfc8200>.
[RFC8201] McCann, J., Deering, S., Mogul, J., and R. Hinden, Ed.,
"Path MTU Discovery for IP version 6", STD 87, RFC 8201,
DOI 10.17487/RFC8201, July 2017,
<https://www.rfc-editor.org/info/rfc8201>.
[RFC8899] Fairhurst, G., Jones, T., Tรผxen, M., Rรผngeler, I., and T.
Vรถlker, "Packetization Layer Path MTU Discovery for
Datagram Transports", RFC 8899, DOI 10.17487/RFC8899,
September 2020, <https://www.rfc-editor.org/info/rfc8899>.
17.2. Informative References ๐
These ones are the background reading ๐ the spec points to for extra context, all listed exactly as written:
[FALL96] Fall, K. and S. Floyd, "Simulation-based Comparisons of
Tahoe, Reno, and SACK TCP", SIGCOM 99, V. 26, N. 3, pp
5-21, July 1996.
[SAVAGE99] Savage, S., Cardwell, N., Wetherall, D., and T. Anderson,
"TCP Congestion Control with a Misbehaving Receiver", ACM
Computer Communications Review 29(5), October 1999.
[ALLMAN99] Allman, M. and V. Paxson, "On Estimating End-to-End
Network Path Properties", SIGCOM 99, October 1999.
[WILLIAMS93]
Williams, R., "A PAINLESS GUIDE TO CRC ERROR DETECTION
ALGORITHMS", SIGCOM 99, August 1993,
<https://archive.org/stream/PainlessCRC/crc_v3.txt>.
[RFC0768] Postel, J., "User Datagram Protocol", STD 6, RFC 768,
DOI 10.17487/RFC0768, August 1980,
<https://www.rfc-editor.org/info/rfc768>.
[RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
RFC 793, DOI 10.17487/RFC0793, September 1981,
<https://www.rfc-editor.org/info/rfc793>.
[RFC1858] Ziemba, G., Reed, D., and P. Traina, "Security
Considerations for IP Fragment Filtering", RFC 1858,
DOI 10.17487/RFC1858, October 1995,
<https://www.rfc-editor.org/info/rfc1858>.
[RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
Hashing for Message Authentication", RFC 2104,
DOI 10.17487/RFC2104, February 1997,
<https://www.rfc-editor.org/info/rfc2104>.
[RFC2196] Fraser, B., "Site Security Handbook", FYI 8, RFC 2196,
DOI 10.17487/RFC2196, September 1997,
<https://www.rfc-editor.org/info/rfc2196>.
[RFC2522] Karn, P. and W. Simpson, "Photuris: Session-Key Management
Protocol", RFC 2522, DOI 10.17487/RFC2522, March 1999,
<https://www.rfc-editor.org/info/rfc2522>.
[RFC2960] Stewart, R., Xie, Q., Morneault, K., Sharp, C.,
Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, M.,
Zhang, L., and V. Paxson, "Stream Control Transmission
Protocol", RFC 2960, DOI 10.17487/RFC2960, October 2000,
<https://www.rfc-editor.org/info/rfc2960>.
[RFC3465] Allman, M., "TCP Congestion Control with Appropriate Byte
Counting (ABC)", RFC 3465, DOI 10.17487/RFC3465, February
2003, <https://www.rfc-editor.org/info/rfc3465>.
[RFC3873] Pastor, J. and M. Belinchon, "Stream Control Transmission
Protocol (SCTP) Management Information Base (MIB)",
RFC 3873, DOI 10.17487/RFC3873, September 2004,
<https://www.rfc-editor.org/info/rfc3873>.
[RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker,
"Randomness Requirements for Security", BCP 106, RFC 4086,
DOI 10.17487/RFC4086, June 2005,
<https://www.rfc-editor.org/info/rfc4086>.
[RFC4301] Kent, S. and K. Seo, "Security Architecture for the
Internet Protocol", RFC 4301, DOI 10.17487/RFC4301,
December 2005, <https://www.rfc-editor.org/info/rfc4301>.
[RFC4460] Stewart, R., Arias-Rodriguez, I., Poon, K., Caro, A., and
M. Tuexen, "Stream Control Transmission Protocol (SCTP)
Specification Errata and Issues", RFC 4460,
DOI 10.17487/RFC4460, April 2006,
<https://www.rfc-editor.org/info/rfc4460>.
[RFC4960] Stewart, R., Ed., "Stream Control Transmission Protocol",
RFC 4960, DOI 10.17487/RFC4960, September 2007,
<https://www.rfc-editor.org/info/rfc4960>.
[RFC6096] Tuexen, M. and R. Stewart, "Stream Control Transmission
Protocol (SCTP) Chunk Flags Registration", RFC 6096,
DOI 10.17487/RFC6096, January 2011,
<https://www.rfc-editor.org/info/rfc6096>.
[RFC6458] Stewart, R., Tuexen, M., Poon, K., Lei, P., and V.
Yasevich, "Sockets API Extensions for the Stream Control
Transmission Protocol (SCTP)", RFC 6458,
DOI 10.17487/RFC6458, December 2011,
<https://www.rfc-editor.org/info/rfc6458>.
[RFC6951] Tuexen, M. and R. Stewart, "UDP Encapsulation of Stream
Control Transmission Protocol (SCTP) Packets for End-Host
to End-Host Communication", RFC 6951,
DOI 10.17487/RFC6951, May 2013,
<https://www.rfc-editor.org/info/rfc6951>.
[RFC7053] Tuexen, M., Ruengeler, I., and R. Stewart, "SACK-
IMMEDIATELY Extension for the Stream Control Transmission
Protocol", RFC 7053, DOI 10.17487/RFC7053, November 2013,
<https://www.rfc-editor.org/info/rfc7053>.
[RFC8260] Stewart, R., Tuexen, M., Loreto, S., and R. Seggelmann,
"Stream Schedulers and User Message Interleaving for the
Stream Control Transmission Protocol", RFC 8260,
DOI 10.17487/RFC8260, November 2017,
<https://www.rfc-editor.org/info/rfc8260>.
[RFC8261] Tuexen, M., Stewart, R., Jesup, R., and S. Loreto,
"Datagram Transport Layer Security (DTLS) Encapsulation of
SCTP Packets", RFC 8261, DOI 10.17487/RFC8261, November
2017, <https://www.rfc-editor.org/info/rfc8261>.
[RFC8540] Stewart, R., Tuexen, M., and M. Proshin, "Stream Control
Transmission Protocol: Errata and Issues in RFC 4960",
RFC 8540, DOI 10.17487/RFC8540, February 2019,
<https://www.rfc-editor.org/info/rfc8540>.
Appendix A. CRC32c Checksum Calculation ๐ฅ
Okay so a "reflected value" is one that's flipped from the normal bit order of the machine ๐. The 32-bit CRC (Cyclic Redundancy Check) gets calculated the way CRC32c describes, using the polynomial code 0x11EDC6F41 (Castagnoli93), or x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+x^8+x^6+x^0. It's kinda like the ETHERNET CRC [ITU.V42.1994] but tweaked for transport-level usage ๐
.
CRC computation is all about polynomial division ๐งฎ. A message bit-string M gets turned into a polynomial, M(X), and then the CRC is worked out from M(X) using polynomial arithmetic ๐ฆ.
When CRCs are used at the link layer, the polynomial is derived from on-the-wire bit ordering: the first bit on the wire is the high-order coefficient. But SCTP is a transport-level protocol, so it can't know the actual serial-media bit ordering ๐. Plus, different links in the path between SCTP endpoints can use different link-level bit orders ๐ญ.
So a convention gets established for mapping SCTP transport messages to polynomials for CRC computation ๐. The bit-ordering is that bytes are taken most-significant first, but within each byte, bits are taken least-significant first. The first byte of the message provides the eight highest coefficients. Within each byte, the least-significant SCTP bit gives the most-significant polynomial coefficient in that byte, and the most-significant SCTP bit is the least-significant polynomial coefficient in that byte. (This bit ordering is sometimes called 'mirrored' or 'reflected' [WILLIAMS93].) CRC polynomials are then transformed back into SCTP transport-level byte values, using a consistent mapping ๐ธ.
Heads up, bestie: that bit-ordering trick is the whole game here ๐
The SCTP transport-level CRC value can be calculated as follows:
- okay so first things first ๐
the CRC input data gets assigned to a byte stream, numbered from
0toN-1๐ง - the transport-level byte stream gets mapped to a polynomial value ๐ฆ an
N-byte PDU withjbytes numbered0toN-1is treated as the coefficients of a polynomialM(x)of order8*N-1. bit0of bytejis the coefficient ofx^(8*(N-j)-8), and bit7of bytejis the coefficient ofx^(8*(N-j)-1)๐ธ - the CRC remainder register starts with all
1s, and the CRC gets computed with an algorithm that multiplies byx^32and divides by the CRC polynomial simultaneously โจ so efficient, ngl - the polynomial gets multiplied by
x^32and divided byG(x), the generator polynomial, which leaves a remainderR(x)of degree less than or equal to31๐ฅ - the coefficients of
R(x)get treated as a 32-bit sequence ๐ - the bit sequence gets complemented, and the result is the CRC polynomial ๐ plot twist
- the CRC polynomial gets mapped back into SCTP transport-level bytes ๐ the coefficient of
x^31gives bit7of SCTP byte0, and the coefficient ofx^24gives bit0of byte0. the coefficient ofx^7gives bit7of byte3, and the coefficient ofx^0gives bit0of byte3. that resulting 4-byte transport-level sequence is the 32-bit SCTP checksum value ๐
Implementation Note: this part is a whole vibe ๐ standards docs, textbooks, and vendor literature on CRCs often follow an alternative formulation, where the register used to hold the remainder of the long-division algorithm starts at zero instead of all ones, and the first 32 bits of the message get complemented instead. the long-division algorithm in our formulation is specified so that the initial multiplication by 2^32 and the long-division get combined into one simultaneous operation. for those algorithms, and for messages longer than 64 bits, the two specifications are precisely equivalent ๐ซถ that equivalence is the whole intent of this doc
implementors of SCTP, listen up ๐จ both specifications show up in the literature, sometimes with no restriction on the long-division algorithm. the reason this doc picked its formulation is to allow non-SCTP usage, where the same CRC algorithm can be used to protect messages shorter than 64 bits ๐
there can be a computational advantage in validating the association against the Verification Tag before doing a checksum ๐ง since invalid tags will result in the same action as a bad checksum in most cases. the exceptions for this trick are packets containing INIT chunks and some SHUTDOWN-COMPLETE chunks, as well as stale COOKIE ECHO chunks. these special-case exchanges are small packets, so they'll minimize the effect of the checksum calculation ๐
the following non-normative sample code is taken from an open-source CRC generator [WILLIAMS93] ๐ it uses the "mirroring" technique and yields a lookup table for SCTP CRC32c with 256 entries, each 32 bits wide. it's neither especially slow nor especially fast, as software table-lookup CRCs go, but it has the advantage of working on both big-endian and little-endian CPUs, using the same (host-order) lookup tables, and using only the predefined ntohl() and htonl() operations ๐ฆ the code is somewhat modified from [WILLIAMS93] to ensure portability between big-endian and little-endian architectures, use fixed-sized types to allow portability between 32-bit and 64-bit platforms, and use general C code improvements. (psst, if the byte endian-ness of the target architecture is known to be little endian, the final bit-reversal and byte-reversal steps can be folded into a single operation ๐ง)
<CODE BEGINS>
/****************************************************************/
/* Note: The definitions for Ross Williams's table generator */
/* would be TB_WIDTH=4, TB_POLY=0x1EDC6F41, TB_REVER=TRUE. */
/* For Mr. Williams's direct calculation code, use the settings */
/* cm_width=32, cm_poly=0x1EDC6F41, cm_init=0xFFFFFFFF, */
/* cm_refin=TRUE, cm_refot=TRUE, cm_xorot=0x00000000. */
/****************************************************************/
/* Example of the crc table file */
#ifndef __crc32cr_h__
#define __crc32cr_h__
#define CRC32C_POLY 0x1EDC6F41UL
#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
uint32_t crc_c[256] = {
0x00000000UL, 0xF26B8303UL, 0xE13B70F7UL, 0x1350F3F4UL,
0xC79A971FUL, 0x35F1141CUL, 0x26A1E7E8UL, 0xD4CA64EBUL,
0x8AD958CFUL, 0x78B2DBCCUL, 0x6BE22838UL, 0x9989AB3BUL,
0x4D43CFD0UL, 0xBF284CD3UL, 0xAC78BF27UL, 0x5E133C24UL,
0x105EC76FUL, 0xE235446CUL, 0xF165B798UL, 0x030E349BUL,
0xD7C45070UL, 0x25AFD373UL, 0x36FF2087UL, 0xC494A384UL,
0x9A879FA0UL, 0x68EC1CA3UL, 0x7BBCEF57UL, 0x89D76C54UL,
0x5D1D08BFUL, 0xAF768BBCUL, 0xBC267848UL, 0x4E4DFB4BUL,
0x20BD8EDEUL, 0xD2D60DDDUL, 0xC186FE29UL, 0x33ED7D2AUL,
0xE72719C1UL, 0x154C9AC2UL, 0x061C6936UL, 0xF477EA35UL,
0xAA64D611UL, 0x580F5512UL, 0x4B5FA6E6UL, 0xB93425E5UL,
0x6DFE410EUL, 0x9F95C20DUL, 0x8CC531F9UL, 0x7EAEB2FAUL,
0x30E349B1UL, 0xC288CAB2UL, 0xD1D83946UL, 0x23B3BA45UL,
0xF779DEAEUL, 0x05125DADUL, 0x1642AE59UL, 0xE4292D5AUL,
0xBA3A117EUL, 0x4851927DUL, 0x5B016189UL, 0xA96AE28AUL,
0x7DA08661UL, 0x8FCB0562UL, 0x9C9BF696UL, 0x6EF07595UL,
0x417B1DBCUL, 0xB3109EBFUL, 0xA0406D4BUL, 0x522BEE48UL,
0x86E18AA3UL, 0x748A09A0UL, 0x67DAFA54UL, 0x95B17957UL,
0xCBA24573UL, 0x39C9C670UL, 0x2A993584UL, 0xD8F2B687UL,
0x0C38D26CUL, 0xFE53516FUL, 0xED03A29BUL, 0x1F682198UL,
0x5125DAD3UL, 0xA34E59D0UL, 0xB01EAA24UL, 0x42752927UL,
0x96BF4DCCUL, 0x64D4CECFUL, 0x77843D3BUL, 0x85EFBE38UL,
0xDBFC821CUL, 0x2997011FUL, 0x3AC7F2EBUL, 0xC8AC71E8UL,
0x1C661503UL, 0xEE0D9600UL, 0xFD5D65F4UL, 0x0F36E6F7UL,
0x61C69362UL, 0x93AD1061UL, 0x80FDE395UL, 0x72966096UL,
0xA65C047DUL, 0x5437877EUL, 0x4767748AUL, 0xB50CF789UL,
0xEB1FCBADUL, 0x197448AEUL, 0x0A24BB5AUL, 0xF84F3859UL,
0x2C855CB2UL, 0xDEEEDFB1UL, 0xCDBE2C45UL, 0x3FD5AF46UL,
0x7198540DUL, 0x83F3D70EUL, 0x90A324FAUL, 0x62C8A7F9UL,
0xB602C312UL, 0x44694011UL, 0x5739B3E5UL, 0xA55230E6UL,
0xFB410CC2UL, 0x092A8FC1UL, 0x1A7A7C35UL, 0xE811FF36UL,
0x3CDB9BDDUL, 0xCEB018DEUL, 0xDDE0EB2AUL, 0x2F8B6829UL,
0x82F63B78UL, 0x709DB87BUL, 0x63CD4B8FUL, 0x91A6C88CUL,
0x456CAC67UL, 0xB7072F64UL, 0xA457DC90UL, 0x563C5F93UL,
0x082F63B7UL, 0xFA44E0B4UL, 0xE9141340UL, 0x1B7F9043UL,
0xCFB5F4A8UL, 0x3DDE77ABUL, 0x2E8E845FUL, 0xDCE5075CUL,
0x92A8FC17UL, 0x60C37F14UL, 0x73938CE0UL, 0x81F80FE3UL,
0x55326B08UL, 0xA759E80BUL, 0xB4091BFFUL, 0x466298FCUL,
0x1871A4D8UL, 0xEA1A27DBUL, 0xF94AD42FUL, 0x0B21572CUL,
0xDFEB33C7UL, 0x2D80B0C4UL, 0x3ED04330UL, 0xCCBBC033UL,
0xA24BB5A6UL, 0x502036A5UL, 0x4370C551UL, 0xB11B4652UL,
0x65D122B9UL, 0x97BAA1BAUL, 0x84EA524EUL, 0x7681D14DUL,
0x2892ED69UL, 0xDAF96E6AUL, 0xC9A99D9EUL, 0x3BC21E9DUL,
0xEF087A76UL, 0x1D63F975UL, 0x0E330A81UL, 0xFC588982UL,
0xB21572C9UL, 0x407EF1CAUL, 0x532E023EUL, 0xA145813DUL,
0x758FE5D6UL, 0x87E466D5UL, 0x94B49521UL, 0x66DF1622UL,
0x38CC2A06UL, 0xCAA7A905UL, 0xD9F75AF1UL, 0x2B9CD9F2UL,
0xFF56BD19UL, 0x0D3D3E1AUL, 0x1E6DCDEEUL, 0xEC064EEDUL,
0xC38D26C4UL, 0x31E6A5C7UL, 0x22B65633UL, 0xD0DDD530UL,
0x0417B1DBUL, 0xF67C32D8UL, 0xE52CC12CUL, 0x1747422FUL,
0x49547E0BUL, 0xBB3FFD08UL, 0xA86F0EFCUL, 0x5A048DFFUL,
0x8ECEE914UL, 0x7CA56A17UL, 0x6FF599E3UL, 0x9D9E1AE0UL,
0xD3D3E1ABUL, 0x21B862A8UL, 0x32E8915CUL, 0xC083125FUL,
0x144976B4UL, 0xE622F5B7UL, 0xF5720643UL, 0x07198540UL,
0x590AB964UL, 0xAB613A67UL, 0xB831C993UL, 0x4A5A4A90UL,
0x9E902E7BUL, 0x6CFBAD78UL, 0x7FAB5E8CUL, 0x8DC0DD8FUL,
0xE330A81AUL, 0x115B2B19UL, 0x020BD8EDUL, 0xF0605BEEUL,
0x24AA3F05UL, 0xD6C1BC06UL, 0xC5914FF2UL, 0x37FACCF1UL,
0x69E9F0D5UL, 0x9B8273D6UL, 0x88D28022UL, 0x7AB90321UL,
0xAE7367CAUL, 0x5C18E4C9UL, 0x4F48173DUL, 0xBD23943EUL,
0xF36E6F75UL, 0x0105EC76UL, 0x12551F82UL, 0xE03E9C81UL,
0x34F4F86AUL, 0xC69F7B69UL, 0xD5CF889DUL, 0x27A40B9EUL,
0x79B737BAUL, 0x8BDCB4B9UL, 0x988C474DUL, 0x6AE7C44EUL,
0xBE2DA0A5UL, 0x4C4623A6UL, 0x5F16D052UL, 0xAD7D5351UL,
};
#endif
/* Example of table build routine */
#include <stdio.h>
#include <stdlib.h>
#define OUTPUT_FILE "crc32cr.h"
#define CRC32C_POLY 0x1EDC6F41UL
static FILE *tf;
static uint32_t
reflect_32(uint32_t b)
{
int i;
uint32_t rw = 0UL;
for (i = 0; i < 32; i++) {
if (b & 1)
rw |= 1UL << (31 - i);
b >>= 1;
}
return (rw);
}
static uint32_t
build_crc_table (int index)
{
int i;
uint32_t rb;
rb = reflect_32(index);
for (i = 0; i < 8; i++) {
if (rb & 0x80000000UL)
rb = (rb << 1) ^ (uint32_t)CRC32C_POLY;
else
rb <<= 1;
}
return (reflect_32(rb));
}
int
main (void)
{
int i;
printf("\nGenerating CRC32c table file <%s>.\n",
OUTPUT_FILE);
if ((tf = fopen(OUTPUT_FILE, "w")) == NULL) {
printf("Unable to open %s.\n", OUTPUT_FILE);
exit (1);
}
fprintf(tf, "#ifndef __crc32cr_h__\n");
fprintf(tf, "#define __crc32cr_h__\n\n");
fprintf(tf, "#define CRC32C_POLY 0x%08XUL\n",
(uint32_t)CRC32C_POLY);
fprintf(tf,
"#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])\n");
fprintf(tf, "\nuint32_t crc_c[256] =\n{\n");
for (i = 0; i < 256; i++) {
fprintf(tf, "0x%08XUL,", build_crc_table (i));
if ((i & 3) == 3)
fprintf(tf, "\n");
else
fprintf(tf, " ");
}
fprintf(tf, "};\n\n#endif\n");
if (fclose(tf) != 0)
printf("Unable to close <%s>.\n", OUTPUT_FILE);
else
printf("\nThe CRC32c table has been written to <%s>.\n",
OUTPUT_FILE);
return (0);
}
/* Example of crc insertion */
#include "crc32cr.h"
uint32_t
generate_crc32c(unsigned char *buffer, unsigned int length)
{
unsigned int i;
uint32_t crc32 = 0xffffffffUL;
uint32_t result;
uint32_t byte0, byte1, byte2, byte3;
for (i = 0; i < length; i++) {
CRC32C(crc32, buffer[i]);
}
result = ~crc32;
/* result now holds the negated polynomial remainder,
* since the table and algorithm are "reflected" [williams95].
* That is, result has the same value as if we mapped the message
* to a polynomial, computed the host-bit-order polynomial
* remainder, performed final negation, and then did an
* end-for-end bit-reversal.
* Note that a 32-bit bit-reversal is identical to four in-place
* 8-bit bit-reversals followed by an end-for-end byteswap.
* In other words, the bits of each byte are in the right order,
* but the bytes have been byteswapped. So, we now do an explicit
* byteswap. On a little-endian machine, this byteswap and
* the final ntohl cancel out and could be elided.
*/
byte0 = result & 0xff;
byte1 = (result>>8) & 0xff;
byte2 = (result>>16) & 0xff;
byte3 = (result>>24) & 0xff;
crc32 = ((byte0 << 24) |
(byte1 << 16) |
(byte2 << 8) |
byte3);
return (crc32);
}
int
insert_crc32(unsigned char *buffer, unsigned int length)
{
SCTP_message *message;
uint32_t crc32;
message = (SCTP_message *)buffer;
message->common_header.checksum = 0UL;
crc32 = generate_crc32c(buffer,length);
/* and insert it into the message */
message->common_header.checksum = htonl(crc32);
return (1);
}
int
validate_crc32(unsigned char *buffer, unsigned int length)
{
SCTP_message *message;
unsigned int i;
uint32_t original_crc32;
uint32_t crc32;
/* save and zero checksum */
message = (SCTP_message *)buffer;
original_crc32 = ntohl(message->common_header.checksum);
message->common_header.checksum = 0L;
crc32 = generate_crc32c(buffer, length);
return ((original_crc32 == crc32) ? 1 : -1);
}
Acknowledgements ๐ซถ
okay bestie, this updated doc is not a small feat ๐ญโจ it's the whole summation of the original coauthors of [RFC2960]: Q. Xie, K. Morneault, C. Sharp, H. Schwarzbauer, T. Taylor, I. Rytina, M. Kalla, L. Zhang, and V. Paxson ๐
then add everyone who gave comments on [RFC2960]: Mark Allman, R. J. Atkinson, Richard Band, Scott Bradner, Steve Bellovin, Peter Butler, Ram Dantu, R. Ezhirpavai, Mike Fisk, Sally Floyd, Atsushi Fukumoto, Matt Holdrege, Henry Houh, Christian Huitema, Gary Lehecka, Jonathan Lee, David Lehmann, John Loughney, Daniel Luan, Barry Nagelberg, Thomas Narten, Erik Nordmark, Lyndon Ong, Shyamal Prasad, Kelvin Porter, Heinz Prantner, Jarno Rajahalme, Raymond E. Reeves, Renee Revis, Ivan Arias Rodriguez, A. Sankar, Greg Sidebottom, Brian Wyld, La Monte Yarroll, and many others for their invaluable comments ๐
next up, the coauthors of [RFC4460]: I. Arias-Rodriguez, K. Poon, and A. Caro ๐ธ
then add the efforts of all the subsequent seven SCTP interoperability tests and everyone who commented on [RFC4460], as shown in its acknowledgements: Barry Zuckerman, La Monte Yarroll, Qiaobing Xie, Wang Xiaopeng, Jonathan Wood, Jeff Waskow, Mike Turner, John Townsend, Sabina Torrente, Cliff Thomas, Yuji Suzuki, Manoj Solanki, Sverre Slotte, Keyur Shah, Jan Rovins, Ben Robinson, Renee Revis, Ian Periam, RC Monee, Sanjay Rao, Sujith Radhakrishnan, Heinz Prantner, Biren Patel, Nathalie Mouellic, Mitch Miers, Bernward Meyknecht, Stan McClellan, Oliver Mayor, Tomas Orti Martin, Sandeep Mahajan, David Lehmann, Jonathan Lee, Philippe Langlois, Karl Knutson, Joe Keller, Gareth Keily, Andreas Jungmaier, Janardhan Iyengar, Mutsuya Irie, John Hebert, Kausar Hassan, Fred Hasle, Dan Harrison, Jon Grim, Laurent Glaude, Steven Furniss, Atsushi Fukumoto, Ken Fujita, Steve Dimig, Thomas Curran, Serkan Cil, Melissa Campbell, Peter Butler, Rob Brennan, Harsh Bhondwe, Brian Bidulock, Caitlin Bestler, Jon Berger, Robby Benedyk, Stephen Baucke, Sandeep Balani, and Ronnie Sellar ๐ฆ
a special shoutout to Mark Allman, who really should have been a coauthor of [RFC4460] for his work on the max-burst but somehow wiggled out on a technicality ๐ ๐
also, we see you Lyndon Ong and Phil Conrad, thank you for your valuable input and many contributions ๐ง
furthermore, there's [RFC4960] and everyone who commented on it, including Alfred Hรถnes and Ronnie Sellars ๐
then add the coauthor of [RFC8540]: Maksim Proshin ๐
and the people who commented on [RFC8540]: Pontus Andersson, Eric W. Biederman, Cedric Bonnet, Spencer Dawkins, Gorry Fairhurst, Benjamin Kaduk, Mirja Kรผhlewind, Peter Lei, Gyula Marosi, Lionel Morand, Jeff Morriss, Tom Petch, Kacheong Poon, Julien Pourtet, Irene Rรผngeler, Michael Welzl, and Qiaobing Xie ๐
and last but definitely not least, the people who commented on this document: Gorry Fairhurst, Martin Duke, Benjamin Kaduk, Tero Kivinen, Eliot Lear, Marcelo Ricardo Leitner, David Mandelberg, John Preuร Mattsson, Claudio Porfiri, Maksim Proshin, Ines Robles, Timo Vรถlker, Magnus Westerlund, and Zhouming ๐
honestly, our thanks can't be fully expressed to everyone who joined in on the coding, testing, and updating of this document. all we can say is, Thank You! ๐ฅนโจ๐ซถโจ
Authors' Addresses ๐
Randall R. Stewart Netflix, Inc. 2455 Heritage Green Ave Davenport, FL 33837 United States of America Email: randall@lakerest.net
Michael Tรผxen Mรผnster University of Applied Sciences Stegerwaldstrasse 39 48565 Steinfurt Germany Email: tuexen@fh-muenster.de
Karen E. E. Nielsen Kamstrup A/S Industrivej 28 DK-8660 Skanderborg Denmark Email: kee@kamstrup.com
๐ฆ where this page comes from
- ietf: rfc9260 2022-06
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms