RFC 4340

Datagram Congestion Control Protocol (DCCP)

๐Ÿ“… published March 2006, from ietf

Part 1 of 29: the intro, the fine print, and the map ๐ŸŽ€

Okay bestie, welcome to RFC 4340, the spec for DCCP (the Datagram Congestion Control Protocol) โœจ. This is part 1 of 29. Part 1 covers the title block, the boring-but-important legal stuff, the abstract, and the table of contents. We'll get into the actual protocol in later parts ๐Ÿ’…

Title block tea ๐Ÿต: this one is from the Network Working Group, it's RFC 4340, and it's a Standards Track document, so it's an actual Internet standard and not just vibes. It was written by E. Kohler (UCLA), M. Handley (UCL), and S. Floyd (ICIR), and it's dated March 2006. The title block I was given doesn't list any RFCs that it obsoletes or updates, so I'm not making any up ๐Ÿ™ˆ


Status of This Memo ๐Ÿ“œ

Okay so this doc is an Internet standards track protocol for the whole Internet community, and the authors are literally asking for discussion and suggestions to make it better ๐Ÿซถ To find out where it stands officially, check the current edition of "Internet Official Protocol Standards" (STD 1), which is the source of truth for standardization state and status. And the best part: distribution of this memo is unlimited ๐ŸŒธ

The copyright belongs to the Internet Society, and the notice reads: Copyright (C) The Internet Society (2006). Legal stuff, but it's giving official โœจ

Abstract ๐Ÿฆ‹

Okay, the main event. DCCP is a transport protocol that gives you bidirectional unicast connections of congestion-controlled unreliable datagrams ๐Ÿ”ฅ Translation: two-way one-to-one chats where the data is sent as individual packets with no delivery guarantee, but it still keeps an eye on congestion so it doesn't wreck the network ๐Ÿ’–

It's a great fit for apps that send pretty big chunks of data and want a say in the trade-off between timeliness (getting it there fast) and reliability (making sure it arrives) ๐Ÿ‘‘ Like, you get to pick your vibe ๐Ÿ˜ญ


Table of Contents ๐Ÿ—บ๏ธ

Here's the full map, copied exactly so you can navigate later parts:

1. Introduction ....................................................5
2. Design Rationale ................................................6
3. Conventions and Terminology .....................................7
   3.1. Numbers and Fields .........................................7
   3.2. Parts of a Connection ......................................8
   3.3. Features ...................................................9
   3.4. Round-Trip Times ...........................................9
   3.5. Security Limitation ........................................9
   3.6. Robustness Principle ......................................10
4. Overview .......................................................10
   4.1. Packet Types ..............................................10
   4.2. Packet Sequencing .........................................11
   4.3. States ....................................................12
   4.4. Congestion Control Mechanisms .............................14
   4.5. Feature Negotiation Options ...............................15
   4.6. Differences from TCP ......................................16
   4.7. Example Connection ........................................17
5. Packet Formats .................................................18
   5.1. Generic Header ............................................19
   5.2. DCCP-Request Packets ......................................22
   5.3. DCCP-Response Packets .....................................23
   5.4. DCCP-Data, DCCP-Ack, and DCCP-DataAck Packets .............23
   5.5. DCCP-CloseReq and DCCP-Close Packets ......................25
   5.6. DCCP-Reset Packets ........................................25
   5.7. DCCP-Sync and DCCP-SyncAck Packets ........................28
   5.8. Options ...................................................29
        5.8.1. Padding Option .....................................31
        5.8.2. Mandatory Option ...................................31
6. Feature Negotiation ............................................32
   6.1. Change Options ............................................32
   6.2. Confirm Options ...........................................33
   6.3. Reconciliation Rules ......................................33
        6.3.1. Server-Priority ....................................34
        6.3.2. Non-Negotiable .....................................34
   6.4. Feature Numbers ...........................................35
   6.5. Feature Negotiation Examples ..............................36
   6.6. Option Exchange ...........................................37
        6.6.1. Normal Exchange ....................................38
        6.6.2. Processing Received Options ........................38
        6.6.3. Loss and Retransmission ............................40
        6.6.4. Reordering .........................................41
        6.6.5. Preference Changes .................................42
        6.6.6. Simultaneous Negotiation ...........................42
        6.6.7. Unknown Features ...................................43
        6.6.8. Invalid Options ....................................43
        6.6.9. Mandatory Feature Negotiation ......................44
7. Sequence Numbers ...............................................44
   7.1. Variables .................................................45
   7.2. Initial Sequence Numbers ..................................45
   7.3. Quiet Time ................................................46
   7.4. Acknowledgement Numbers ...................................47
   7.5. Validity and Synchronization ..............................47
        7.5.1. Sequence and Acknowledgement Number Windows ........48
        7.5.2. Sequence Window Feature ............................49
        7.5.3. Sequence-Validity Rules ............................49
        7.5.4. Handling Sequence-Invalid Packets ..................51
        7.5.5. Sequence Number Attacks ............................52
        7.5.6. Sequence Number Handling Examples ..................54
   7.6. Short Sequence Numbers ....................................55
        7.6.1. Allow Short Sequence Numbers Feature ...............55
        7.6.2. When to Avoid Short Sequence Numbers ...............56
   7.7. NDP Count and Detecting Application Loss ..................56
        7.7.1. NDP Count Usage Notes ..............................57
        7.7.2. Send NDP Count Feature .............................57
8. Event Processing ...............................................58
   8.1. Connection Establishment ..................................58
        8.1.1. Client Request .....................................58
        8.1.2. Service Codes ......................................59
        8.1.3. Server Response ....................................61
        8.1.4. Init Cookie Option .................................62
        8.1.5. Handshake Completion ...............................63
   8.2. Data Transfer .............................................63
   8.3. Termination ...............................................64
        8.3.1. Abnormal Termination ...............................66
   8.4. DCCP State Diagram ........................................66
   8.5. Pseudocode ................................................67
9. Checksums ......................................................72
   9.1. Header Checksum Field .....................................73
   9.2. Header Checksum Coverage Field ............................73
        9.2.1. Minimum Checksum Coverage Feature ..................74
   9.3. Data Checksum Option ......................................75
        9.3.1. Check Data Checksum Feature ........................76
        9.3.2. Checksum Usage Notes ...............................76
10. Congestion Control ............................................76
   10.1. TCP-like Congestion Control ..............................77
   10.2. TFRC Congestion Control ..................................78
   10.3. CCID-Specific Options, Features, and Reset Codes .........78
   10.4. CCID Profile Requirements ................................80
   10.5. Congestion State .........................................81
11. Acknowledgements ..............................................81
   11.1. Acks of Acks and Unidirectional Connections ..............82
   11.2. Ack Piggybacking .........................................83
   11.3. Ack Ratio Feature ........................................84
   11.4. Ack Vector Options .......................................85
        11.4.1. Ack Vector Consistency ............................88
        11.4.2. Ack Vector Coverage ...............................89
   11.5. Send Ack Vector Feature ..................................90
   11.6. Slow Receiver Option .....................................90
   11.7. Data Dropped Option ......................................91
        11.7.1. Data Dropped and Normal Congestion Response .......94
        11.7.2. Particular Drop Codes .............................95
12. Explicit Congestion Notification ..............................96
   12.1. ECN Incapable Feature ....................................96
   12.2. ECN Nonces ...............................................97
   12.3. Aggression Penalties .....................................98
13. Timing Options ................................................99
   13.1. Timestamp Option .........................................99
   13.2. Elapsed Time Option ......................................99
   13.3. Timestamp Echo Option ...................................100
14. Maximum Packet Size ..........................................101
   14.1. Measuring PMTU ..........................................102
   14.2. Sender Behavior .........................................103
15. Forward Compatibility ........................................104
16. Middlebox Considerations .....................................105
17. Relations to Other Specifications ............................106
   17.1. RTP .....................................................106
   17.2. Congestion Manager and Multiplexing .....................108
18. Security Considerations ......................................108
   18.1. Security Considerations for Partial Checksums ...........109
19. IANA Considerations ..........................................110
   19.1. Packet Types Registry ...................................110
   19.2. Reset Codes Registry ....................................110
   19.3. Option Types Registry ...................................110
   19.4. Feature Numbers Registry ................................111
   19.5. Congestion Control Identifiers Registry .................111
   19.6. Ack Vector States Registry ..............................111
   19.7. Drop Codes Registry .....................................112
   19.8. Service Codes Registry ..................................112
   19.9. Port Numbers Registry ...................................112
20. Thanks .......................................................114
A.  Appendix: Ack Vector Implementation Notes ....................116
    A.1. Packet Arrival ..........................................118
         A.1.1. New Packets ......................................118
         A.1.2. Old Packets ......................................119
    A.2. Sending Acknowledgements ................................120
    A.3. Clearing State ..........................................120
    A.4. Processing Acknowledgements .............................122
B.  Appendix: Partial Checksumming Design Motivation .............123
Normative References .............................................124
Informative References ...........................................125

That's the whole roadmap ๐Ÿงš Next up in part 2: Section 1, Introduction, and the good stuff starts there ๐Ÿ’œ

1. Introduction โœจ

okay bestie, let's talk about DCCP ๐Ÿ’– The Datagram Congestion Control Protocol is a transport protocol that gives you bidirectional, unicast connections of congestion-controlled, unreliable datagrams. It's giving "best of both worlds" ๐Ÿฆ‹ Specifically, DCCP gives you:

  • Unreliable flows of datagrams.
  • Reliable handshakes for connection setup and teardown.
  • Reliable negotiation of options, including negotiation of a suitable congestion control mechanism.
  • Mechanisms allowing servers to avoid holding state for unacknowledged connection attempts and already-finished connections.
  • Congestion control incorporating Explicit Congestion Notification (ECN) [RFC3168] and the ECN Nonce [RFC3540].
  • Acknowledgement mechanisms communicating packet loss and ECN information. Acks are transmitted as reliably as the relevant congestion control mechanism requires, possibly completely reliably. ๐ŸŒธ
  • Optional mechanisms that tell the sending application, with high reliability, which data packets reached the receiver, and whether those packets were ECN marked, corrupted, or dropped in the receive buffer. ๐Ÿ”ฅ
  • Path Maximum Transmission Unit (PMTU) discovery [RFC1191].
  • A choice of modular congestion control mechanisms. Two mechanisms are currently specified: TCP-like Congestion Control [RFC4341] and TCP-Friendly Rate Control (TFRC) [RFC4342]. DCCP is easily extensible to further forms of unicast congestion control. ๐Ÿ‘‘

DCCP is intended for applications such as streaming media that can benefit from control over the tradeoffs between delay and reliable in-order delivery. TCP isn't really it for these apps, because reliable in-order delivery and congestion control can cause arbitrarily long delays ๐Ÿ’€ UDP avoids long delays, but UDP applications that implement congestion control have to do it all on their own. DCCP gives you built-in congestion control, including ECN support, for unreliable datagram flows, so you avoid the arbitrary delays that come with TCP. It also handles reliable connection setup, teardown, and feature negotiation. ๐Ÿงš

2. Design Rationale ๐Ÿ’…

One DCCP design goal was to give most streaming UDP applications little reason not to switch to DCCP once it's deployed. So DCCP was designed to have as little overhead as possible, both in terms of packet header size and in terms of the state and CPU overhead required at end hosts. Only the minimal necessary functionality made it in. Other stuff, like forward error correction (FEC), semi-reliability, and multiple streams, can be layered on top of DCCP as desired. Main character restraint ๐Ÿซถ

Different forms of conformant congestion control suit different applications. For example, online games might want to make quick use of any available bandwidth, while streaming media might trade off that responsiveness for a steadier, less bursty rate. (Sudden rate changes can cause unacceptable UI glitches, like audible pauses or clicks in the playout stream ๐Ÿ˜ญ) So DCCP lets applications choose from a set of congestion control mechanisms. One alternative, TCP-like Congestion Control, halves the congestion window in response to a packet drop or mark, just like TCP. Applications using it will respond quickly to changes in available bandwidth, but they must tolerate the abrupt changes in congestion window that are typical of TCP. A second alternative, TCP-Friendly Rate Control (TFRC) [RFC3448], is a form of equation-based congestion control. It minimizes abrupt changes in the sending rate while maintaining longer-term fairness with TCP. โœจ Other alternatives can be added as future congestion control mechanisms are standardized.

DCCP also lets unreliable traffic safely use ECN. A UDP kernel Application Programming Interface (API) might not allow applications to set UDP packets as ECN capable, since the API couldn't guarantee that the application would properly detect or respond to congestion ๐Ÿ™ˆ DCCP kernel APIs won't have that problem, since DCCP implements congestion control itself. Iconic ๐Ÿฆ‹

We chose not to require the use of the Congestion Manager [RFC3124], which lets multiple concurrent streams between the same sender and receiver share congestion control. The current Congestion Manager can only be used by applications that have their own end-to-end feedback about packet losses, and that isn't the case for many of the applications using UDP right now. On top of that, the current Congestion Manager doesn't easily support multiple congestion control mechanisms, or mechanisms where the state about past packet drops or marks is kept at the receiver rather than the sender. DCCP should be able to make use of CM where the application wants it, but we don't see any benefit in making DCCP deployment depend on CM deployment itself. Not gonna tie those two together ๐Ÿ™…โ€โ™€๏ธ

We intend for DCCP's protocol mechanisms, which are described in this document, to suit any application that wants unicast congestion-controlled streams of unreliable datagrams ๐ŸŒˆ However, the congestion control mechanisms currently approved for use with DCCP, described in separate Congestion Control ID Profiles [RFC4341, RFC4342], may cause problems for some applications, including high-bandwidth interactive video. Those apps should be able to use DCCP once suitable Congestion Control ID Profiles are standardized. Soon, hopefully ๐Ÿ“

3. Conventions and Terminology ๐Ÿ“–

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].

3.1. Numbers and Fields ๐Ÿ”ข

All multi-byte numerical quantities in DCCP, such as port numbers, Sequence Numbers, and arguments to options, are transmitted in network byte order (most significant byte first).

We sometimes say "left" and "right" when we talk about a bit field. "Left" means towards the most significant bit, and "right" means towards the least significant bit. ๐ŸŽ€

Random numbers in DCCP are used for their security properties and SHOULD be chosen according to the guidelines in [RFC4086]. Very important, very serious ๐Ÿ”

All operations on DCCP sequence numbers use circular arithmetic modulo 2^48, and so do comparisons like "greater" and "greatest". This form of arithmetic preserves the relationships between sequence numbers as they roll over from 2^48 - 1 to 0. Implementation strategies for DCCP sequence numbers will look a lot like those for other circular arithmetic spaces, including TCP's sequence numbers [RFC793] and DNS's serial numbers [RFC1982]. It may make sense to store DCCP sequence numbers in the most significant 48 bits of 64-bit integers and set the least significant 16 bits to zero, since this supports a common technique: implementing circular comparison A < B by testing whether (A - B) < 0 using conventional two's-complement arithmetic. Math is sooo iconic ๐Ÿงฎ

Reserved bitfields in DCCP packet headers MUST be set to zero by senders and MUST be ignored by receivers, unless otherwise specified. This leaves room for future protocol extensions. In particular, DCCP processors MUST NOT reset a DCCP connection simply because a Reserved field has a non-zero value [RFC3360]. Don't you dare reset the connection over a reserved field ๐Ÿ˜ค

3.2. Parts of a Connection ๐Ÿงฉ

Each DCCP connection runs between two hosts, which we often call DCCP A and DCCP B. Each connection is actively initiated by one of the hosts, which we call the client. The other host, which is initially passive, is called the server. The term "DCCP endpoint" refers to either of the two hosts explicitly named by the connection (the client and the server). The term "DCCP processor" refers more generally to any host that might need to process a DCCP header. That includes the endpoints and any middleboxes on the path, like firewalls and network address translators ๐Ÿ‘€

DCCP connections are bidirectional: data can pass from either endpoint to the other. This means data and acknowledgements can flow in both directions at the same time. Logically, though, a DCCP connection is made of two separate unidirectional connections, called half-connections. Each half-connection consists of the application data sent by one endpoint and the corresponding acknowledgements sent by the other endpoint. Here's a picture ๐Ÿฆ‹

   +--------+  A-to-B half-connection:         +--------+
   |        |    -->  application data  -->    |        |
   |        |    <--  acknowledgements  <--    |        |
   | DCCP A |                                  | DCCP B |
   |        |  B-to-A half-connection:         |        |
   |        |    <--  application data  <--    |        |
   +--------+    -->  acknowledgements  -->    +--------+

Even though they're logically distinct, in practice the half-connections overlap. A DCCP-DataAck packet, for example, carries application data for one half-connection and acknowledgement information for the other. Multitasking queen ๐Ÿ‘‘

In the context of a single half-connection, the terms "HC-Sender" and "HC-Receiver" denote the endpoints sending application data and acknowledgements, respectively. For example, DCCP A is the HC-Sender and DCCP B is the HC-Receiver in the A-to-B half-connection. ๐Ÿ’œ

3.3. Features ๐ŸŽ›๏ธ

A DCCP feature is a connection attribute whose value the two endpoints agree on. Lots of properties of a DCCP connection are controlled by features, including the congestion control mechanisms in use on the two half-connections. The endpoints reach agreement by exchanging feature negotiation options in DCCP headers. Negotiation era ๐Ÿค

DCCP features are identified by a feature number and an endpoint. The notation F/X represents the feature with feature number F located at DCCP endpoint X. Each valid feature number therefore corresponds to two features, which are negotiated separately and don't need to have the same value. The two endpoints know, and agree on, the value of every valid feature. DCCP A is the "feature location" for all features F/A, and the "feature remote" for all features F/B. โœจ

3.4. Round-Trip Times โฑ๏ธ

DCCP round-trip time measurements are performed by congestion control mechanisms. Different mechanisms may measure round-trip time in different ways, or not measure it at all. However, the main DCCP protocol does use round-trip times occasionally, such as for the initial values of certain timers. So each DCCP implementation defines a default round-trip time to use when no estimate is available. This parameter should default to not less than 0.2 seconds, a reasonably conservative round-trip time for Internet TCP connections. Protocol behavior specified in terms of "round-trip time" values actually refers to "a current round-trip time estimate taken by some CCID, or, if no estimate is available, the default round-trip time parameter". Ngl this is a lot of nuance, but it's all there for a reason ๐Ÿง 

The maximum segment lifetime, or MSL, is the maximum length of time a packet can survive in the network. The DCCP MSL should equal that of TCP, which is normally two minutes. โณ

3.5. Security Limitation ๐Ÿ”

okay real talk bestie, DCCP does NOT protect you from attackers who can snoop on a connection while it's happening, or who can guess valid sequence numbers some other way ๐Ÿ˜ญ if you need stronger security, go use IPsec [RFC2401] ๐Ÿ›ก๏ธ depending on how locked down you need to be, app-level cryptography might be enough too. we dig into this more in Sections 7.5.5 and 18 ๐Ÿ’…

3.6. Robustness Principle ๐Ÿง 

DCCP implementations are gonna follow TCP's "general principle of robustness" ๐ŸŒธ the vibe is: "be conservative in what you do, be liberal in what you accept from others" [RFC793] ๐Ÿซถ very iconic energy, honestly.

4. Overview โœจ

okay so DCCP's high-level connection dynamics are basically giving TCP ๐Ÿ’– connections go through three phases: initiation (which includes a three-way handshake ๐Ÿค), data transfer, and termination ๐Ÿฆ‹ data can flow both ways over the connection. there's an acknowledgement framework so senders can figure out how much data got lost, which helps them avoid unfairly congesting the network ๐ŸŒˆ BUT ngl, DCCP is unreliable datagram semantics, NOT TCP's reliable bytestream semantics ๐Ÿ’€ so the application has to package its data into explicit frames and retransmit its own data when needed. it's kinda like thinking of DCCP as TCP minus bytestream semantics and reliability, or as UDP plus congestion control, handshakes, and acknowledgements ๐ŸŽ€

4.1. Packet Types ๐Ÿ“ฆ

there are ten packet types that run DCCP's protocol functions ๐Ÿ‘‘ like, every new connection attempt starts with a DCCP-Request packet from the client. so a DCCP-Request kinda looks like a TCP SYN, but since DCCP-Request is its own packet type, you literally can't send a weird flag combo like TCP's SYN+FIN+ACK+RST ๐Ÿ™ˆ no cap, that's so clean.

eight packet types show up during a typical connection, pictured here. watch for the three-way handshakes during initiation and termination ๐Ÿ‘€

   Client                                      Server
   ------                                      ------
                    (1) Initiation
   DCCP-Request -->
                                    <-- DCCP-Response
   DCCP-Ack -->
                    (2) Data transfer
   DCCP-Data, DCCP-Ack, DCCP-DataAck -->
               <-- DCCP-Data, DCCP-Ack, DCCP-DataAck
                    (3) Termination
                                    <-- DCCP-CloseReq
   DCCP-Close -->
                                       <-- DCCP-Reset

the last two packet types are for resyncing after big bursts of loss ๐Ÿ”„

every DCCP packet starts with a fixed-size generic header ๐Ÿงš some packet types tack on extra fixed-size header data too. like, DCCP-Acks include an Acknowledgement Number ๐Ÿ’œ DCCP options and any application data come right after the fixed-size header.

here's the rundown of the packet types:

  • DCCP-Request: sent by the client to start a connection (the first part of the three-way initiation handshake) ๐Ÿš€
  • DCCP-Response: sent by the server in reply to a DCCP-Request (the second part of the three-way initiation handshake) ๐Ÿ™Œ
  • DCCP-Data: used to send application data ๐Ÿ“ฌ
  • DCCP-Ack: used to send pure acknowledgements ๐Ÿ“
  • DCCP-DataAck: used to send application data with piggybacked acknowledgement info ๐ŸŽ
  • DCCP-CloseReq: sent by the server to ask the client to close the connection ๐Ÿฅบ
  • DCCP-Close: used by the client or the server to close the connection; it gets a DCCP-Reset back ๐Ÿ’…
  • DCCP-Reset: used to terminate the connection, either normally or abnormally ๐Ÿชฆ
  • DCCP-Sync, DCCP-SyncAck: used to resync sequence numbers after large bursts of loss ๐Ÿ”

4.2. Packet Sequencing ๐Ÿ”ข

every DCCP packet carries a sequence number so losses can be detected and reported ๐Ÿ” unlike TCP's sequence numbers (which count bytes), DCCP sequence numbers go up by one per packet ๐ŸŒŸ for example:

   DCCP A                                      DCCP B
   ------                                      ------
   DCCP-Data(seqno 1) -->
   DCCP-Data(seqno 2) -->
                      <-- DCCP-Ack(seqno 10, ackno 2)
   DCCP-DataAck(seqno 3, ackno 10) -->
                              <-- DCCP-Data(seqno 11)

so every DCCP packet bumps the sequence number, whether or not it has application data in it ๐Ÿ’– even pure DCCP-Ack acks bump it. like, DCCP B's second packet above uses sequence number 11, because sequence number 10 went to an acknowledgement ๐Ÿง this is how endpoints can catch all packet loss, even ack loss ๐Ÿ‘€ but it also means endpoints can get out of sync after long bursts of loss ๐Ÿ˜ต the DCCP-Sync and DCCP-SyncAck packet types are how they recover (Section 7.5) ๐Ÿซก

since DCCP is unreliable, there are no retransmissions, so a TCP-style cumulative acknowledgement field doesn't make any sense here ๐Ÿ™…โ€โ™€๏ธ DCCP's Acknowledgement Number field is equal to the greatest sequence number received, instead of the smallest sequence number not received ๐ŸŒˆ separate options show any in-between sequence numbers that weren't received โœจ

4.3. States ๐ŸŒธ

DCCP endpoints move through different states during a connection, roughly matching the three phases of initiation, data transfer, and termination ๐Ÿฆ‹ here's the usual progression for a client and server:

   Client                                             Server
   ------                                             ------
                     (0) No connection
   CLOSED                                             LISTEN

                     (1) Initiation
   REQUEST      DCCP-Request -->
                                <-- DCCP-Response     RESPOND
   PARTOPEN     DCCP-Ack or DCCP-DataAck -->

                     (2) Data transfer
   OPEN          <-- DCCP-Data, Ack, DataAck -->      OPEN

                     (3) Termination
                                <-- DCCP-CloseReq     CLOSEREQ
   CLOSING      DCCP-Close -->
                                   <-- DCCP-Reset     CLOSED
   TIMEWAIT
   CLOSED

there are nine possible states ๐ŸŽ€ they're listed in increasing order, so "state >= CLOSEREQ" means the same thing as "state = CLOSEREQ or state = CLOSING or state = TIMEWAIT" ๐Ÿง  Section 8 goes into the states in more detail.

  • CLOSED: represents nonexistent connections ๐Ÿ‘ป
  • LISTEN: represents server sockets in the passive listening state ๐Ÿ‘‚ LISTEN and CLOSED aren't tied to any specific DCCP connection ๐Ÿซถ
  • REQUEST: a client socket enters this state from CLOSED after sending a DCCP-Request packet to try to start a connection ๐Ÿš€
  • RESPOND: a server socket enters this state from LISTEN after getting a DCCP-Request from a client ๐Ÿ™‹โ€โ™€๏ธ
  • PARTOPEN: a client socket enters this state from REQUEST after getting a DCCP-Response from the server ๐Ÿค this is the third phase of the three-way handshake. the client may send application data in this state, but it MUST include an Acknowledgement Number on all of its packets ๐Ÿซข
  • OPEN: the central data transfer part of a DCCP connection ๐Ÿ’ซ client and server sockets enter this state from PARTOPEN and RESPOND, respectively. sometimes we say SERVER-OPEN and CLIENT-OPEN, which match the server's OPEN state and the client's OPEN state ๐Ÿงš
  • CLOSEREQ: a server socket enters this state from SERVER-OPEN to order the client to close the connection and to hold TIMEWAIT state ๐Ÿ›‘
  • CLOSING: server and client sockets can both enter this state to close the connection ๐Ÿšช
  • TIMEWAIT: a server or client socket stays in this state for 2MSL (4 minutes) after the connection has been torn down, so mistakes from old packets showing up late don't happen ๐Ÿ•ฐ๏ธ only one of the endpoints has to enter TIMEWAIT (the other can go straight to CLOSED), and a server can ask its client to hold TIMEWAIT state using the DCCP-CloseReq packet type ๐Ÿ’œ

4.4. Congestion Control Mechanisms ๐Ÿšฆ

DCCP connections are congestion controlled, but unlike TCP, DCCP apps get to pick their congestion control mechanism ๐Ÿ‘‘ in fact, the two half-connections can be run by different mechanisms ๐ŸŒˆ mechanisms are labeled with one-byte congestion control identifiers, aka CCIDs ๐Ÿท๏ธ the endpoints negotiate their CCIDs during connection initiation ๐Ÿค each CCID describes how the HC-Sender limits its data packet rates, how the HC-Receiver sends congestion feedback through acknowledgements, and so on ๐Ÿง CCIDs 2 and 3 are currently defined; CCIDs 0, 1, and 4-255 are reserved ๐Ÿ”’ other CCIDs might get defined in the future ๐Ÿ”ฎ

CCID 2 gives you TCP-like Congestion Control, which is similar to TCP's ๐Ÿ‘ the sender keeps a congestion window and keeps sending packets until that window is full ๐Ÿ“ค the receiver acknowledges packets. dropped packets and ECN [RFC3168] are signs of congestion, and the response to congestion is to halve the congestion window ๐Ÿ“‰ acknowledgements in CCID 2 contain the sequence numbers of all received packets within some window, kinda like a selective acknowledgement (SACK) [RFC2018] ๐Ÿงฉ

CCID 3 gives you TCP-Friendly Rate Control (TFRC) ๐ŸŒŠ it's an equation-based form of congestion control that's meant to respond to congestion more smoothly than CCID 2 โœจ the sender keeps a transmit rate and updates it using the receiver's estimate of the packet loss and mark rate ๐Ÿ“Š CCID 3 acts somewhat differently than TCP in the short term, but it's designed to stay fair with TCP over the long term ๐Ÿ’–

Section 10 goes into DCCP's CCIDs in more detail ๐Ÿ“š the behaviors of CCIDs 2 and 3 are fully defined in separate profile documents [RFC4341, RFC4342] ๐ŸŽ€

4.5. Feature Negotiation Options โœจ

okay so DCCP endpoints use Change and Confirm options to negotiate and agree on feature values ๐ŸŽ€ Feature negotiation almost always happens on the connection initiation handshake, but it can kick off at any time ๐Ÿ’…

There are four feature negotiation options in all: Change L, Confirm L, Change R, and Confirm R. The "L" options are sent by the feature location, and the "R" options are sent by the feature remote. A Change R option basically says to the feature location, "change this feature value as follows" ๐Ÿฆ‹ The feature location responds with Confirm L, which means "I've changed it" ๐Ÿ’– Some features let Change R options hold multiple values sorted in preference order. For example:

      Client                                        Server
      ------                                        ------
      Change R(CCID, 2) -->
                                    <-- Confirm L(CCID, 2)
                 * agreement that CCID/Server = 2 *

      Change R(CCID, 3 4) -->
                               <-- Confirm L(CCID, 4, 4 2)
                 * agreement that CCID/Server = 4 *

Both exchanges negotiate the CCID/Server feature's value, which is the CCID in use on the server-to-client half-connection ๐ŸŒˆ In the second exchange, the client asks the server to use either CCID 3 or CCID 4, with 3 preferred. The server picks 4 and sends back its own preference list, "4 2" โœจ

The Change L and Confirm R options are used for feature negotiations initiated by the feature location. In the next example, the server asks for CCID/Server to be set to 3 or 2, with 3 preferred, and the client says yes ๐Ÿซถ

      Client                                       Server
      ------                                       ------
                                  <-- Change L(CCID, 3 2)
      Confirm R(CCID, 3, 3 2)  -->
                 * agreement that CCID/Server = 3 *

Section 6 goes deeper into the feature negotiation options, including the retransmission strategies that make negotiation reliable ๐Ÿงš


4.6. Differences from TCP ๐Ÿ’…

DCCP is different from TCP in a bunch of ways beyond the ones we've already covered, and honestly it's giving main character energy ๐Ÿ‘‘ Here's the tea:

  • Copious space for options. Up to 1008 bytes or the PMTU ๐Ÿ“
  • Different acknowledgement formats. The CCID for a connection decides how much acknowledgement information needs to be sent. For example, in CCID 2 (TCP-like), that's about one ack per 2 packets, and each ack has to say exactly which packets were received. In CCID 3 (TFRC), it's about one ack per round-trip time, and acks only need to declare at minimum the lengths of recent loss intervals ๐Ÿฆ‹
  • Denial of Service (DoS) protection. Several mechanisms limit how much state possibly-misbehaving clients can force DCCP servers to keep track of ๐Ÿ›ก๏ธ An Init Cookie option, which is analogous to TCP's SYN Cookies [SYNCOOKIES], helps avoid SYN-flood-like attacks. Only one connection endpoint has to hold TIMEWAIT state, because the DCCP-CloseReq packet (which may only be sent by the server) passes that state over to the client. Various rate limits let servers dodge attacks that might force heavy computation or packet generation ๐Ÿ™ˆ
  • Distinguishing different kinds of loss. A Data Dropped option (Section 11.7) lets an endpoint say a packet was dropped because of corruption, because of receive buffer overflow, and so on ๐ŸŽ€ This makes research into better rate-control responses for these non-network-congestion losses easier (although right now, such losses still cause a congestion response) ๐Ÿ”ฌ
  • Acknowledgeability. In TCP, a packet can only be acknowledged once its data is reliably queued for application delivery. That doesn't make sense in DCCP, where an application might, for example, ask for a drop-from-front receive buffer ๐Ÿซ  A DCCP packet can be acknowledged as soon as its header has been successfully processed. Concretely, a packet becomes acknowledgeable at Step 8 of Section 8.5's packet processing pseudocode. Acknowledgeability doesn't guarantee data delivery, though: the Data Dropped option may later report that the packet's application data was thrown away ๐Ÿ’€
  • No receive window. DCCP is a congestion control protocol, not a flow control protocol ๐ŸŒธ
  • No simultaneous open. Every connection has exactly one client and one server ๐Ÿ‘ฏโ€โ™€๏ธ
  • No half-closed states. DCCP has no states like TCP's FINWAIT and CLOSEWAIT, where one half-connection is explicitly closed while the other is still active. The Data Dropped option's Drop Code 1, Application Not Listening (Section 11.7), can get you a similar effect, though โœจ

4.7. Example Connection ๐Ÿงšโ€โ™€๏ธ

The progress of a typical DCCP connection goes like this. (This description is informative, not normative. ๐Ÿ™ˆ)

          Client                                  Server
          ------                                  ------
      0.  [CLOSED]                              [LISTEN]
      1.  DCCP-Request -->
      2.                               <-- DCCP-Response
      3.  DCCP-Ack -->
      4.  DCCP-Data, DCCP-Ack, DCCP-DataAck -->
                   <-- DCCP-Data, DCCP-Ack, DCCP-DataAck
      5.                               <-- DCCP-CloseReq
      6.  DCCP-Close -->
      7.                                  <-- DCCP-Reset
      8.  [TIMEWAIT]
  1. The client sends the server a DCCP-Request packet with the client and server ports, the service being requested, and any features being negotiated, including the CCID the client would like the server to use. The client may optionally piggyback an application request on the DCCP-Request packet, and the server may ignore that application request ๐Ÿ’Œ
  2. The server sends the client a DCCP-Response packet saying it's willing to talk. This response shows any features and options the server agrees to, starts other feature negotiations if it wants, and optionally includes Init Cookies that wrap up all this info. The client has to send those cookies back for the connection to complete ๐Ÿช
  3. The client sends the server a DCCP-Ack packet that acknowledges the DCCP-Response packet. This acknowledges the server's initial sequence number and returns any Init Cookies in the DCCP-Response. It may also keep going with feature negotiation. The client may piggyback an application-level request on this ack, which makes a DCCP-DataAck packet ๐ŸŽ€
  4. The server and client then swap DCCP-Data packets, DCCP-Ack packets acknowledging that data, and, optionally, DCCP-DataAck packets that carry data with piggybacked acknowledgements ๐Ÿ” If the client has no data to send, the server will send DCCP-Data and DCCP-DataAck packets, while the client sends DCCP-Acks exclusively. (However, the client may not send DCCP-Data packets before receiving at least one non-DCCP-Response packet from the server. ๐Ÿšซ)
  5. The server sends a DCCP-CloseReq packet asking for a close ๐Ÿ‘‹
  6. The client sends a DCCP-Close packet acknowledging the close ๐Ÿฅน
  7. The server sends a DCCP-Reset packet with Reset Code 1, "Closed", and clears its connection state. DCCP-Resets are part of normal connection termination; see Section 5.6 ๐Ÿ’…
  8. The client receives the DCCP-Reset packet and holds state for two maximum segment lifetimes, or 2MSL, so any remaining packets can clear the network ๐ŸŒ™

An alternative connection closedown sequence is started by the client:

5b. The client sends a DCCP-Close packet closing the connection.

6b. The server sends a DCCP-Reset packet with Reset Code 1, "Closed", and clears its connection state.

7b. The client receives the DCCP-Reset packet and holds state for 2MSL to allow any remaining packets to clear the network. ๐Ÿซถ


5. Packet Formats ๐ŸŽ€

The DCCP header can be from 12 to 1020 bytes long ๐Ÿ“ฆ The initial part of the header has the same semantics for all currently defined packet types. After that come any additional fixed-length fields the packet type needs, and then a variable-length list of options. The application data area follows the header. In some packet types, this area holds data for the application; in other packet types, its contents are ignored ๐ŸŒธ

      +---------------------------------------+  -.
      |            Generic Header             |   |
      +---------------------------------------+   |
      | Additional Fields (depending on type) |   +- DCCP Header
      +---------------------------------------+   |
      |          Options (optional)           |   |
      +=======================================+  -'
      |         Application Data Area         |
      +---------------------------------------+

5.1. Generic Header โœจ

Okay bestie, so the generic header changes shape depending on X, the Extended Sequence Numbers bit ๐Ÿฆ‹. If X is one, the Sequence Number field is 48 bits long and the generic header takes 16 bytes total, 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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |          Source Port          |           Dest Port           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Data Offset  | CCVal | CsCov |           Checksum            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |     |       |X|               |                               .
      | Res | Type  |=|   Reserved    |  Sequence Number (high bits)  .
      |     |       |1|               |                               .
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      .                  Sequence Number (low bits)                   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

If X is zero, only the low 24 bits of the Sequence Number are transmitted, and the generic header is 12 bytes long ๐ŸŒธ

       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          |           Dest Port           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  Data Offset  | CCVal | CsCov |           Checksum            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |     |       |X|                                               |
      | Res | Type  |=|          Sequence Number (low bits)           |
      |     |       |0|                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Now the fields, one by one ๐Ÿ’…

Source and Destination Ports: 16 bits each ๐Ÿšช These fields identify the connection, just like the matching fields in TCP and UDP. The Source Port is the port on the endpoint that sent the packet, and the Destination Port is the port on the other endpoint. When starting a connection, the client SHOULD choose its Source Port randomly to reduce the likelihood of attack ๐Ÿ”’

DCCP APIs should treat port numbers similarly to TCP and UDP port numbers. For example, machines that distinguish between "privileged" and "unprivileged" ports for TCP and UDP should do the same for DCCP.

Data Offset: 8 bits ๐Ÿ“ This is the offset from the start of the packet's DCCP header to the start of its application data area, counted in 32-bit words. The receiver MUST ignore packets whose Data Offset is smaller than the minimum-sized header for the given Type, or larger than the DCCP packet itself ๐Ÿ™…โ€โ™€๏ธ

CCVal: 4 bits ๐ŸŽ€ Used by the HC-Sender CCID. For example, the A-to-B CCID's sender, which is active at DCCP A, MAY send 4 bits of information per packet to its receiver by encoding that information in CCVal. The sender MUST set CCVal to zero unless its HC-Sender CCID specifies otherwise, and the receiver MUST ignore the CCVal field unless its HC-Receiver CCID specifies otherwise.

Checksum Coverage (CsCov): 4 bits ๐Ÿงฉ Checksum Coverage decides which parts of the packet the Checksum field covers. It always includes the DCCP header and options, but some or all of the application data may be left out. This can improve performance on noisy links for applications that can tolerate corruption. See Section 9.

Checksum: 16 bits โœ… The Internet checksum of the packet's DCCP header (including options), a network-layer pseudoheader, and, depending on Checksum Coverage, all, some, or none of the application data. See Section 9.

Reserved (Res): 3 bits ๐Ÿซ™ Senders MUST set this field to all zeroes on generated packets, and receivers MUST ignore its value.

Type: 4 bits ๐Ÿท๏ธ The Type field tells you what kind of packet this is. These values are defined:

                     Type   Meaning
                     ----   -------
                       0    DCCP-Request
                       1    DCCP-Response
                       2    DCCP-Data
                       3    DCCP-Ack
                       4    DCCP-DataAck
                       5    DCCP-CloseReq
                       6    DCCP-Close
                       7    DCCP-Reset
                       8    DCCP-Sync
                       9    DCCP-SyncAck
                     10-15  Reserved

                 Table 1: DCCP Packet Types

Receivers MUST ignore any packets with reserved type. Put simply, packets with reserved type MUST NOT be processed, and they MUST NOT be acknowledged as received ๐Ÿšซ

Extended Sequence Numbers (X): 1 bit ๐Ÿ”ข Set this to one to indicate an extended generic header with 48-bit Sequence and Acknowledgement Numbers. DCCP-Data, DCCP-DataAck, and DCCP-Ack packets MAY set X to zero or one. All DCCP-Request, DCCP-Response, DCCP-CloseReq, DCCP-Close, DCCP-Reset, DCCP-Sync, and DCCP-SyncAck packets MUST set X to one, and endpoints MUST ignore any such packets with X set to zero. High-rate connections SHOULD set X to one on all packets to gain increased protection against wrapped sequence numbers and attacks. See Section 7.6. ๐Ÿ›ก๏ธ

Sequence Number: 48 or 24 bits ๐Ÿงญ This identifies the packet uniquely in the sequence of all packets the source sent on this connection. The Sequence Number goes up by one with every packet sent, including packets like DCCP-Ack that carry no application data. See Section 7.

All currently defined packet types except DCCP-Request and DCCP-Data carry an Acknowledgement Number Subheader in the four or eight bytes right after the generic header. When X=1, its format is:

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |           Reserved            |    Acknowledgement Number     .
      |                               |          (high bits)          .
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      .               Acknowledgement Number (low bits)               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

When X=0, only the low 24 bits of the Acknowledgement Number are transmitted, so the Acknowledgement Number Subheader looks like this:

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |   Reserved    |       Acknowledgement Number (low bits)       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Reserved: 16 or 8 bits ๐Ÿซง Senders MUST set this field to all zeroes on generated packets, and receivers MUST ignore its value.

Acknowledgement Number: 48 or 24 bits ๐Ÿ’Œ This generally holds GSR, the Greatest Sequence Number Received on any acknowledgeable packet so far. A packet is acknowledgeable if and only if its header was successfully processed by the receiver. Section 7.4 goes into this more. Options such as Ack Vector (Section 11.4) work together with the Acknowledgement Number to give precise info about which packets have arrived ๐ŸŽฏ

Acknowledgement Numbers on DCCP-Sync and DCCP-SyncAck packets need not equal GSR. See Section 5.7.


5.2. DCCP-Request Packets ๐Ÿš€

A client starts a DCCP connection by sending a DCCP-Request packet. These packets MAY contain application data and MUST use 48-bit sequence numbers (X=1) ๐Ÿ’ซ

       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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      /            Generic DCCP Header with X=1 (16 bytes)            /
      /                   with Type=0 (DCCP-Request)                  /
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         Service Code                          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      /                      Options and Padding                      /
      +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
      /                       Application Data                        /
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Service Code: 32 bits ๐ŸŽซ This describes the application-level service the client application wants to connect to. Service Codes are meant to give info about which application protocol a connection plans to use, which helps middleboxes and cuts down on reliance on globally well-known ports. See Section 8.1.2.


5.3. DCCP-Response Packets ๐Ÿ’ฌ

The server answers valid DCCP-Request packets with DCCP-Response packets. This is the second phase of the three-way handshake ๐Ÿค DCCP-Response packets MAY contain application data and MUST use 48-bit sequence numbers (X=1) ๐Ÿ”

       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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      /            Generic DCCP Header with X=1 (16 bytes)            /
      /                  with Type=1 (DCCP-Response)                  /
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      /          Acknowledgement Number Subheader (8 bytes)           /
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         Service Code                          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      /                      Options and Padding                      /
      +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
      /                       Application Data                        /
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Acknowledgement Number: 48 bits ๐Ÿ“ฌ This contains GSR. Since DCCP-Response packets are only sent during connection initiation, this will always equal the Sequence Number on a received DCCP-Request.

Service Code: 32 bits ๐ŸŽ€ MUST equal the Service Code on the corresponding DCCP-Request.

5.4. DCCP-Data, DCCP-Ack, and DCCP-DataAck Packets ๐Ÿ’–

Okay so the main data-moving part of every DCCP connection runs on DCCP-Data, DCCP-Ack, and DCCP-DataAck packets ๐ŸŽ€. These packets MAY use 24-bit sequence numbers, depending on the Allow Short Sequence Numbers feature (see Section 7.6.1) โœจ. DCCP-Data packets carry application data with no acknowledgements attached ๐ŸŒธ.

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /              Generic DCCP Header (16 or 12 bytes)             /
   /                    with Type=2 (DCCP-Data)                    /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                      Options and Padding                      /
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   /                       Application Data                        /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

DCCP-Ack packets ditch the data but still carry an Acknowledgement Number ๐Ÿฆ‹. They're the go-to for pure acknowledgements, 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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /              Generic DCCP Header (16 or 12 bytes)             /
   /                    with Type=3 (DCCP-Ack)                     /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /        Acknowledgement Number Subheader (8 or 4 bytes)        /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                      Options and Padding                      /
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   /                Application Data Area (Ignored)                /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

DCCP-DataAck packets are the multitaskers ๐Ÿ‘‘. They carry application data and an Acknowledgement Number, so the ack info piggybacks right onto a data 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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /              Generic DCCP Header (16 or 12 bytes)             /
   /                  with Type=4 (DCCP-DataAck)                   /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /        Acknowledgement Number Subheader (8 or 4 bytes)        /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                      Options and Padding                      /
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   /                       Application Data                        /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

A DCCP-Data or DCCP-DataAck packet may have a zero-length application data area ๐Ÿงš. That means the app sent a zero-length datagram. This is different from DCCP-Request and DCCP-Response packets, where an empty application data area means there's no application data at all, not zero-length application data ๐Ÿ™ˆ. The API SHOULD report any received zero-length datagrams to the receiving application ๐Ÿ’….

A DCCP-Ack packet MAY have a non-zero-length application data area, which basically pads the DCCP-Ack out to a desired length ๐Ÿ“. Receivers MUST ignore the content of the application data area in DCCP-Ack packets ๐ŸŒˆ.

DCCP-Ack and DCCP-DataAck packets often include extra acknowledgement options, like Ack Vector, whenever the congestion control mechanism in use needs them โญ.


5.5. DCCP-CloseReq and DCCP-Close Packets ๐ŸŒ™

DCCP-CloseReq and DCCP-Close packets kick off the handshake that usually wraps up a connection ๐Ÿฅ€. Either the client or the server may send a DCCP-Close packet, and it'll elicit a DCCP-Reset packet in return ๐Ÿ’œ. Only the server can send a DCCP-CloseReq packet, which basically says "I want to close, but I don't want to hold my TIMEWAIT state" ๐Ÿ’€. Both packet types MUST use 48-bit sequence numbers (X=1) ๐Ÿ”ฅ.

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /            Generic DCCP Header with X=1 (16 bytes)            /
   /         with Type=5 (DCCP-CloseReq) or 6 (DCCP-Close)         /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /          Acknowledgement Number Subheader (8 bytes)           /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                      Options and Padding                      /
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   /                Application Data Area (Ignored)                /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Just like DCCP-Ack packets, DCCP-CloseReq and DCCP-Close packets MAY have non-zero-length application data areas, and receivers MUST ignore whatever's in them ๐Ÿซง.


5.6. DCCP-Reset Packets ๐Ÿšช

DCCP-Reset packets unconditionally shut down a connection ๐Ÿ’ฅ. Connections normally end with a DCCP-Reset, but resets can also be sent for other reasons, including bad port numbers, bad option behavior, incorrect ECN Nonce Echoes, and so forth ๐Ÿฅฒ. DCCP-Resets MUST use 48-bit sequence numbers (X=1) ๐Ÿ”’.

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /            Generic DCCP Header with X=1 (16 bytes)            /
   /                   with Type=7 (DCCP-Reset)                    /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /          Acknowledgement Number Subheader (8 bytes)           /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Reset Code   |    Data 1     |    Data 2     |    Data 3     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                      Options and Padding                      /
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   /              Application Data Area (Error Text)               /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Reset Code: 8 bits ๐ŸŽ€ Represents the reason the sender reset the DCCP connection.

Data 1, Data 2, and Data 3: 8 bits each ๐Ÿงฉ The Data fields give extra info about why the sender reset the DCCP connection. What they mean depends on the value of Reset Code.

Application Data Area: Error Text ๐Ÿ“ If present, Error Text is a human-readable text string encoded in Unicode UTF-8, and preferably in English, that describes the error in more detail. For example, a DCCP-Reset with Reset Code 11, "Aggression Penalty", might contain Error Text such as "Aggression Penalty: Received 3 bad ECN Nonce Echoes, assuming misbehavior" ๐Ÿ•ต๏ธโ€โ™€๏ธ.

Here are the Reset Codes that are currently defined ๐Ÿ“‹. Unless otherwise specified, the Data 1, 2, and 3 fields MUST be set to 0 by the sender of the DCCP-Reset and ignored by its receiver ๐Ÿ™…โ€โ™€๏ธ. Section references describe concrete situations that will cause each Reset Code to be generated, but they're not meant to be exhaustive ๐Ÿ”.

0, "Unspecified" ๐ŸŒซ๏ธ Indicates the absence of a meaningful Reset Code. Use of Reset Code 0 is NOT RECOMMENDED: the sender should choose a Reset Code that more clearly defines why the connection is being reset.

1, "Closed" ๐ŸŒท Normal connection close. See Section 8.3.

2, "Aborted" ๐ŸฅŠ The sending endpoint gave up on the connection because of lack of progress. See Sections 8.1.1 and 8.1.5.

3, "No Connection" ๐Ÿ‘ป No connection exists. See Section 8.3.1.

4, "Packet Error" ๐Ÿ“ฆ A valid packet arrived with an unexpected type. For example, a DCCP-Data packet with a valid header checksum and sequence numbers arrived at a connection in the REQUEST state. See Section 8.3.1. The Data 1 field equals the offending packet type as an eight-bit number, so an offending packet with Type 2 will result in a Data 1 value of 2 ๐Ÿ”ข.

5, "Option Error" โš ๏ธ An option was erroneous, and the error was serious enough to warrant resetting the connection. See Sections 6.6.7, 6.6.8, and 11.4. The Data 1 field equals the offending option type. Data 2 and Data 3 equal the first two bytes of option data (or zero if the option had less than two bytes of data) ๐Ÿงพ.

6, "Mandatory Error" ๐Ÿšจ The sending endpoint could not process an option O that was immediately preceded by Mandatory. The Data fields report the option type and data of option O, using the format of Reset Code 5, "Option Error". See Section 5.8.2.

7, "Connection Refused" ๐Ÿ™…โ€โ™€๏ธ The Destination Port didn't correspond to a port open for listening. Sent only in response to DCCP-Requests. See Section 8.1.3.

8, "Bad Service Code" ๐Ÿท๏ธ The Service Code didn't equal the service code attached to the Destination Port. Sent only in response to DCCP-Requests. See Section 8.1.3.

9, "Too Busy" ๐Ÿ˜ต The server is too busy to accept new connections. Sent only in response to DCCP-Requests. See Section 8.1.3.

10, "Bad Init Cookie" ๐Ÿช The Init Cookie echoed by the client was incorrect or missing. See Section 8.1.4.

11, "Aggression Penalty" ๐Ÿ˜ค This endpoint has detected congestion control-related misbehavior on the part of the other endpoint. See Section 12.3.

12-127, Reserved ๐Ÿ” Receivers should treat these codes as they do Reset Code 0, "Unspecified".

128-255, CCID-specific codes ๐Ÿงฌ Semantics depend on the connection's CCIDs. See Section 10.3. Receivers should treat unknown CCID-specific Reset Codes as they do Reset Code 0, "Unspecified".

The following table summarizes all of this ๐Ÿ“Š.

       Reset
       Code   Name                    Data 1     Data 2 & 3
       -----  ----                    ------     ----------
         0    Unspecified               0            0
         1    Closed                    0            0
         2    Aborted                   0            0
         3    No Connection             0            0
         4    Packet Error           pkt type        0
         5    Option Error           option #   option data
         6    Mandatory Error        option #   option data
         7    Connection Refused        0            0
         8    Bad Service Code          0            0
         9    Too Busy                  0            0
        10    Bad Init Cookie           0            0
        11    Aggression Penalty        0            0
       12-127 Reserved
      128-255 CCID-specific codes

                     Table 2: DCCP Reset Codes

Options on DCCP-Reset packets get processed before the connection shuts down โณ. This means certain combinations of options, especially ones involving Mandatory, may cause an endpoint to respond to a valid DCCP-Reset with another DCCP-Reset ๐Ÿ”. This can't lead to a reset storm, though ๐Ÿ™Œ: since the first endpoint has already reset the connection, the second DCCP-Reset will be ignored โœจ.

5.7. DCCP-Sync and DCCP-SyncAck Packets โœจ

okay bestie, DCCP-Sync packets are the ones that help endpoints get back in sync after big bursts of loss, and they also help recover from half-open connections ๐Ÿซถ Every valid DCCP-Sync that shows up immediately gets a DCCP-SyncAck back, no cap. Both packet types MUST use 48-bit sequence numbers (X=1). ๐Ÿ”ฅ

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /            Generic DCCP Header with X=1 (16 bytes)            /
   /          with Type=8 (DCCP-Sync) or 9 (DCCP-SyncAck)          /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /          Acknowledgement Number Subheader (8 bytes)           /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                      Options and Padding                      /
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   /                Application Data Area (Ignored)                /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The Acknowledgement Number field is extra special here ๐Ÿ’… First, the packet that a DCCP-Sync's Acknowledgement Number points at doesn't have to have been acknowledgeable at all. So receivers MUST NOT assume a packet was processed just because it shows up in the Acknowledgement Number field of a DCCP-Sync. That's different from every other packet type, where the Acknowledgement Number always points at an acknowledgeable packet ๐Ÿ™ˆ Second, the Acknowledgement Number on any DCCP-SyncAck MUST correspond to the Sequence Number on an acknowledgeable DCCP-Sync. With reordering in the mix, this might not equal GSR.

Just like DCCP-Ack packets, DCCP-Sync and DCCP-SyncAck packets MAY have non-zero-length application data areas, and receivers MUST ignore whatever is in them ๐Ÿงš Padded DCCP-Sync packets may be useful when performing Path MTU discovery; see Section 14.


5.8. Options ๐ŸŽ€

Any DCCP packet can carry options, which live in the space at the end of the DCCP header. Each option is a multiple of 8 bits long. Individual options don't get padded out to multiples of 32 bits, and any option may begin on any byte boundary. BUT the combination of all options MUST add up to a multiple of 32 bits, so Padding options MUST be added as needed to fill the option space out to a word boundary. Any options present are included in the header checksum. ๐Ÿ’–

The first byte of an option is the option type. Options with types 0 through 31 are single-byte options. Everything else is followed by a byte saying how long the option is. That length value counts the two bytes of option-type and option-length plus any option-data bytes, so it must therefore be greater than or equal to two.

Options MUST be processed sequentially, starting with the first option in the packet header. Options with unknown types MUST be ignored. Options with nonsensical lengths (a length byte less than two, or more than the remaining space in the options portion of the header) MUST be ignored too, and any option space following an option with a nonsensical length MUST likewise be ignored. Unless otherwise specified, multiple occurrences of the same option MUST be processed independently. For some options, that means in practice the last valid occurrence takes precedence. ๐Ÿ‘‘

The following options are currently defined:

            Option                           DCCP-  Section
    Type    Length     Meaning               Data?  Reference
    ----    ------     -------               -----  ---------
      0        1       Padding                 Y      5.8.1
      1        1       Mandatory               N      5.8.2
      2        1       Slow Receiver           Y      11.6
    3-31       1       Reserved
     32     variable   Change L                N      6.1
     33     variable   Confirm L               N      6.2
     34     variable   Change R                N      6.1
     35     variable   Confirm R               N      6.2
     36     variable   Init Cookie             N      8.1.4
     37       3-8      NDP Count               Y      7.7
     38     variable   Ack Vector [Nonce 0]    N      11.4
     39     variable   Ack Vector [Nonce 1]    N      11.4
     40     variable   Data Dropped            N      11.7
     41        6       Timestamp               Y      13.1
     42      6/8/10    Timestamp Echo          Y      13.3
     43       4/6      Elapsed Time            N      13.2
     44        6       Data Checksum           Y      9.3
    45-127  variable   Reserved
   128-255  variable   CCID-specific options   -      10.3

                     Table 3: DCCP Options

Not every option works on every packet type, ngl ๐Ÿ™ƒ For example, the Ack Vector option is read relative to the Acknowledgement Number, so it isn't suitable on DCCP-Request and DCCP-Data packets, which have no Acknowledgement Number. If an option shows up on an unexpected packet type, it MUST generally be ignored, and any real restrictions are mentioned in each option's description. The table covers the most common restriction: when the DCCP-Data? column says N, the option MUST be ignored when received on a DCCP-Data packet. (Section 7.5.5 explains why these options get ignored instead of, say, causing a reset.) ๐ŸŒธ

Options with invalid values MUST be ignored unless otherwise specified. For example, any Data Checksum option with option length 4 MUST be ignored, since all valid Data Checksum options have option length 6. ๐Ÿ’…

This section describes two generic options, Padding and Mandatory. The other options get their own descriptions later. โœจ

5.8.1. Padding Option

+--------+
|00000000|
+--------+
  Type=0

Padding is a single-byte "no-operation" option used to pad between or after options. If the length of a packet's other options isn't a multiple of 32 bits, Padding options are REQUIRED to pad the options area out to the length implied by Data Offset. Padding can also go between options, for example to line up the start of a later option on a 32-bit boundary. There's no guarantee that senders will use this option, so receivers must be prepared to process options even if they don't begin on a word boundary. ๐Ÿงธ

5.8.2. Mandatory Option

+--------+
|00000001|
+--------+
  Type=1

Mandatory is a single-byte option that marks the immediately following option as mandatory. Say the immediately following option is O. Then the Mandatory option has no effect if the receiving DCCP endpoint understands and processes O. If the endpoint doesn't understand or process O, though, it MUST reset the connection using Reset Code 6, "Mandatory Failure". For instance, the endpoint would reset the connection if it didn't understand O's type; if it understood O's type but not O's data; if O's data was invalid for O's type; if O was a feature negotiation option and the endpoint didn't understand the enclosed feature number; or if the endpoint understood O but chose not to perform the action O implies. This list isn't exhaustive. Individual option specifications may describe extra situations where the endpoint should reset the connection, and situations where it should not. ๐Ÿฆ‹

Mandatory options MUST NOT be sent on DCCP-Data packets, and any Mandatory options received on DCCP-Data packets MUST be ignored. ๐Ÿšจ

The connection is in error and should be reset with Reset Code 5, "Option Error", if option O is absent (Mandatory was the last byte of the option list), or if option O equals Mandatory. However, the combination "Mandatory Padding" is valid, and MUST behave like two bytes of Padding. ๐Ÿ’€

Section 6.6.9 describes the behavior of Mandatory feature negotiation options in more detail. ๐Ÿ”


6. Feature Negotiation ๐ŸŒˆ

Four DCCP options, Change L, Confirm L, Change R, and Confirm R, are used to negotiate feature values. Change options start a negotiation, and Confirm options complete it. The "L" options are sent by the feature location, and the "R" options are sent by the feature remote. Change options get retransmitted to make sure they're reliable. ๐Ÿ“

All of these options have the same format. The first byte of option data is the feature number, and the second and later data bytes hold one or more feature values. The exact format of the feature value area depends on the feature type; see Section 6.3.

+--------+--------+--------+--------+--------
|  Type  | Length |Feature#| Value(s) ...
+--------+--------+--------+--------+--------

Together, the feature number and the option type ("L" or "R") uniquely identify the feature an option applies to. The exact format of the Value(s) area depends on the feature number. ๐ŸŽฏ

Feature negotiation options MUST NOT be sent on DCCP-Data packets, and any feature negotiation options received on DCCP-Data packets MUST be ignored. ๐Ÿ™…โ€โ™€๏ธ

6.1. Change Options

Change L and Change R options initiate feature negotiation. Which one you use depends on the relevant feature's location: to start a negotiation for feature F/A, DCCP A sends a Change L option; to start a negotiation for F/B, it sends a Change R option. Change options get retransmitted until some response is received. They contain at least one Value, so they have a length of at least 4. ๐Ÿฆ„

           +--------+--------+--------+--------+--------
Change L:  |00100000| Length |Feature#| Value(s) ...
           +--------+--------+--------+--------+--------
            Type=32

           +--------+--------+--------+--------+--------
Change R:  |00100010| Length |Feature#| Value(s) ...
           +--------+--------+--------+--------+--------
            Type=34

6.2. Confirm Options

Confirm L and Confirm R options complete feature negotiation, and they're sent in response to Change R and Change L options, respectively. Confirm options MUST NOT be generated except in response to Change options. Confirm options don't need to be retransmitted, since Change options get retransmitted as necessary. The first byte of the Confirm option holds the feature number from the matching Change. After that comes the selected Value, and then possibly the sender's preference list. ๐ŸŒท

           +--------+--------+--------+--------+--------
Confirm L: |00100001| Length |Feature#| Value(s) ...
           +--------+--------+--------+--------+--------
            Type=33

           +--------+--------+--------+--------+--------
Confirm R: |00100011| Length |Feature#| Value(s) ...
           +--------+--------+--------+--------+--------
            Type=35

If an endpoint receives an invalid Change option (one with an unknown feature number, or an invalid value), it responds with an empty Confirm option that contains the problematic feature number but no value. Those options have length 3. ๐Ÿ˜ฌ

6.3. Reconciliation Rules

Reconciliation rules decide how the two sets of preferences for a given feature get resolved into one unique result. The reconciliation rule depends only on the feature number. Each reconciliation rule must have the property that the result is uniquely determined by the contents of the Change options sent by the two endpoints. ๐Ÿง 

All current DCCP features use one of two reconciliation rules: server-priority ("SP") and non-negotiable ("NN"). ๐Ÿ’œ

6.3.1. Server-Priority

okay so the feature value is a fixed-length byte string, and the length depends on the feature number ๐Ÿ’… Each Change option carries a list of values ordered by preference, with the most preferred value first. Each Confirm option carries the confirmed value, followed by the confirmer's preference list. So the feature's current value usually shows up twice in Confirm options' data: once as the current value, and once in the confirmer's preference list ๐Ÿซถ

To reconcile the two preference lists, you pick the first entry in the server's list that also appears in the client's list โœจ If there's no shared entry, the feature's value MUST NOT change, and the Confirm option confirms the feature's previous value (unless the Change option was Mandatory; see Section 6.6.9) ๐Ÿ™ˆ

6.3.2. Non-Negotiable

the feature value is a byte string, and each option holds exactly one feature value ๐ŸŽ€ The feature location signals a new value by sending a Change L option. The feature remote MUST accept any valid value and respond with a Confirm R option containing the new value. It MUST send empty Confirm R options in response to invalid values (unless the Change L option was Mandatory; see Section 6.6.9) ๐Ÿ˜ญ Change R and Confirm L options MUST NOT be sent for non-negotiable features; see Section 6.6.8. Non-negotiable features use the feature negotiation mechanism to achieve reliability ๐Ÿ”ฅ

6.4. Feature Numbers

this section defines the following feature numbers, and this is the big table ๐Ÿฆ‹

                                      Rec'n Initial        Section
   Number   Meaning                       Rule   Value  Req'd Reference
   ------   -------                       -----  -----  ----- ---------
      0     Reserved
      1     Congestion Control ID (CCID)   SP      2      Y     10
      2     Allow Short Seqnos             SP      0      Y     7.6.1
      3     Sequence Window                NN     100     Y     7.5.2
      4     ECN Incapable                  SP      0      N     12.1
      5     Ack Ratio                      NN      2      N     11.3
      6     Send Ack Vector                SP      0      N     11.5
      7     Send NDP Count                 SP      0      N     7.7.2
      8     Minimum Checksum Coverage      SP      0      N     9.2.1
      9     Check Data Checksum            SP      0      N     9.3.1
    10-127  Reserved
   128-255  CCID-specific features                              10.3

                  Table 4: DCCP Feature Numbers

Rec'n Rule: this is the reconciliation rule for the feature. SP means server-priority, and NN means non-negotiable ๐ŸŒธ

Initial Value: the starting value for the feature. Every feature has a known initial value ๐Ÿ“

Req'd: this column is "Y" if and only if every DCCP implementation MUST understand the feature ๐Ÿ‘‘ If it's "N", the feature acts like an extension (see Section 15), and it's totally safe to answer Change options for it with empty Confirm options ๐Ÿ’œ Of course, a CCID might require the feature. For example, a DCCP that implements CCID 2 MUST support Ack Ratio and Send Ack Vector ๐Ÿงš

6.5. Feature Negotiation Examples

here are three example feature negotiations for features located at the server. The first two are for the Congestion Control ID feature, and the last one is for Ack Ratio ๐Ÿฆ‹

             Client                     Server
             ------                     ------
  1. Change R(CCID, 2 3 1)  -->
     ("2 3 1" is client's preference list)
  2.                        <--  Confirm L(CCID, 3, 3 2 1)
                           (3 is the negotiated value;
                           "3 2 1" is server's pref list)
              * agreement that CCID/Server = 3 *


  1.                   XXX  <--  Change L(CCID, 3 2 1)
  2.                             Retransmission:
                            <--  Change L(CCID, 3 2 1)
  3. Confirm R(CCID, 3, 2 3 1)  -->
              * agreement that CCID/Server = 3 *


  1.                        <--  Change L(Ack Ratio, 3)
  2. Confirm R(Ack Ratio, 3)  -->
           * agreement that Ack Ratio/Server = 3 *

this one shows a simultaneous negotiation, and it's giving teamwork ๐Ÿค

              Client                     Server
              ------                     ------
  1a. Change R(CCID, 2 3 1)  -->
   b.                        <--  Change L(CCID, 3 2 1)
  2a.                        <--  Confirm L(CCID, 3, 3 2 1)
   b. Confirm R(CCID, 3, 2 3 1)  -->
               * agreement that CCID/Server = 3 *

here are the byte encodings for several Change and Confirm options. Each option is sent by DCCP A ๐Ÿ’–

Change L(CCID, 2 3) = 32,5,1,2,3
   DCCP B should change CCID/A's value (feature number 1, a server-
   priority feature); DCCP A's preferred values are 2 and 3, in that
   preference order.

Change L(Sequence Window, 1024) = 32,9,3,0,0,0,0,4,0
   DCCP B should change Sequence Window/A's value (feature number 3,
   a non-negotiable feature) to the 6-byte string 0,0,0,0,4,0 (the
   value 1024).

Confirm L(CCID, 2, 2 3) = 33,6,1,2,2,3
   DCCP A has changed CCID/A's value to 2; its preferred values are 2
   and 3, in that preference order.

Empty Confirm L(126) = 33,3,126
   DCCP A doesn't implement feature number 126, or DCCP B's proposed
   value for feature 126/A was invalid.

Change R(CCID, 3 2) = 34,5,1,3,2
   DCCP B should change CCID/B's value; DCCP A's preferred values are
   3 and 2, in that preference order.

Confirm R(CCID, 2, 3 2) = 35,6,1,2,3,2
   DCCP A has changed CCID/B's value to 2; its preferred values were
   3 and 2, in that preference order.

Confirm R(Sequence Window, 1024) = 35,9,3,0,0,0,0,4,0
   DCCP A has changed Sequence Window/B's value to the 6-byte string
   0,0,0,0,4,0 (the value 1024).

Empty Confirm R(126) = 35,3,126
   DCCP A doesn't implement feature number 126, or DCCP B's proposed
   value for feature 126/B was invalid.

6.6. Option Exchange

a few basic rules run feature negotiation option exchange, so let's go through them ๐Ÿ“

  1. Every non-reordered Change option gets a Confirm option in response.
  2. Change options are retransmitted until a response for the latest Change is received.
  3. Feature negotiation options are processed in strictly-increasing order by Sequence Number.

the rest of this section explains what these rules mean in more detail ๐ŸŒˆ

6.6.1. Normal Exchange

Change options get generated when a DCCP endpoint wants to change the value of some feature ๐ŸŽ€ This usually happens at the start of a connection, though it can happen any time. We say the endpoint "generates" or "sends" a Change L or Change R option, but obviously the option has to be attached to a packet โœจ The endpoint can attach it to a packet it would've sent anyway (like a DCCP-Request), or it can create a "feature negotiation packet", often a DCCP-Ack or DCCP-Sync, just to carry the option ๐Ÿฆ‹ Feature negotiation packets are controlled by the relevant congestion control mechanism. For example, DCCP A may send a DCCP-Ack or DCCP-Sync for feature negotiation only if the B-to-A CCID would allow sending a DCCP-Ack. Also, an endpoint SHOULD generate at most one feature negotiation packet per round-trip time ๐Ÿ•ฐ๏ธ

When a DCCP endpoint receives a Change L or Change R option, it looks at the included preference list, reconciles that with its own preference list, works out the new value, and sends back a Confirm R or Confirm L option. That tells its peer the new value, or that the feature wasn't understood ๐Ÿ’… Every non-reordered Change option MUST result in a corresponding Confirm option, and any packet including a Confirm option MUST carry an Acknowledgement Number ๐Ÿซถ (Section 6.6.4 describes how Change reordering is detected and handled.) Generated Confirm options can be attached to packets that would've been sent anyway (like DCCP-Response or DCCP-SyncAck), or to new feature negotiation packets, as described above ๐Ÿ’œ

the Change-sending endpoint MUST wait to receive a corresponding Confirm option before it changes its stored feature value. The Confirm-sending endpoint changes its stored feature value as soon as it sends the Confirm. ๐Ÿ™ˆ

one packet MAY contain more than one feature negotiation option, and those can even include two options that refer to the same feature. As usual, the options get processed one at a time, in order ๐Ÿ“

6.6.2. Processing Received Options โœจ

okay so DCCP endpoints can be in one of three states for each feature ๐ŸŽ€ STABLE is the chill default, where the endpoint knows the feature's value and thinks the other endpoint agrees too ๐Ÿฆ‹ An endpoint enters CHANGING when it first sends a Change for the feature, and it goes back to STABLE once it gets a matching Confirm ๐Ÿ’… The last one is UNSTABLE, which means an endpoint in CHANGING changed its preference list but hasn't sent a Change option with the new list yet ๐Ÿ˜ญ

Feature state transitions at a feature location work exactly like this diagram ๐Ÿ’œ It skips the sequence number and option validity stuff, because that gets handled properly in the pseudocode right after ๐Ÿงš

                                                          timeout/
 rcv Confirm R      app/protocol evt : snd Change L       rcv non-ack
 : ignore      +---------------------------------------+  : snd Change L
      +----+   |                                       |  +----+
      |    v   |                   rcv Change R        v  |    v
   +------------+  rcv Confirm R   : calc new value, +------------+
   |            |  : accept value    snd Confirm L   |            |
   |   STABLE   |<-----------------------------------|  CHANGING  |
   |            |        rcv empty Confirm R         |            |
   +------------+        : revert to old value       +------------+
       |    ^                                            |    ^
       +----+                                  pref list |    | snd
 rcv Change R                                  changes   |    | Change L
 : calc new value, snd Confirm L                         v    |
                                                     +------------+
                                                 +---|            |
                            rcv Confirm/Change R |   |  UNSTABLE  |
                            : ignore             +-->|            |
                                                     +------------+

Feature locations SHOULD use the following pseudocode to match the state diagram ๐ŸŒธ It reacts to every feature negotiation option on each valid non-Data packet received. It leans on a few things: P.seqno and P.ackno are properties of the packet, O.type and O.len are properties of the option, FGSR and FGSS are properties of the connection (and they handle reordering as explained in Section 6.6.4), F.state is the feature's state (STABLE, CHANGING, or UNSTABLE), and F.value is the feature's value ๐Ÿซถ

   First, check for unknown features (Section 6.6.7);
      If F is unknown,
         If the option was Mandatory,   /* Section 6.6.9 */
            Reset connection and return
         Otherwise, if O.type == Change R,
            Send Empty Confirm L on a future packet

         Return

   Second, check for reordering (Section 6.6.4);
      If F.state == UNSTABLE or P.seqno <= FGSR
              or (O.type == Confirm R and P.ackno < FGSS),
         Ignore option and return

   Third, process Change R options;
      If O.type == Change R,
         If the option's value is valid,   /* Section 6.6.8 */
            Calculate new value
            Send Confirm L on a future packet
            Set F.state := STABLE
         Otherwise, if the option was Mandatory,
            Reset connection and return
         Otherwise,
            Send Empty Confirm L on a future packet
            /* Remain in existing state.  If that's CHANGING, this
               endpoint will retransmit its Change L option later. */

   Fourth, process Confirm R options (but only in CHANGING state).
      If F.state == CHANGING and O.type == Confirm R,
         If O.len > 3,   /* nonempty */
            If the option's value is valid,
               Set F.value := new value
            Otherwise,
               Reset connection and return
         Set F.state := STABLE

Versions of this diagram and pseudocode are also used by feature remotes ๐Ÿฆ‹ Just swap the "L"s and "R"s, so the relevant options become Change R and Confirm L ๐Ÿ’–


6.6.3. Loss and Retransmission โœจ

Packets with Change and Confirm options can get lost or delayed by the network, which is a lot ๐Ÿ˜ญ So Change options get sent over and over to make things reliable ๐ŸŽ€ We call this "retransmission," but ngl there are no packet-level retransmissions in DCCP. A Change option that gets sent again goes out on a brand new packet with a brand new sequence number ๐Ÿงš

A CHANGING endpoint sends another Change option once it realizes the other endpoint hasn't gotten back to it ๐Ÿ’… The new one doesn't have to carry the same payload as the first. Reordering protection makes sure agreement is reached based on the most recently sent option, so it's fine ๐Ÿซถ

A CHANGING endpoint MUST keep retransmitting Change options until it gets some kind of response or the connection ends ๐Ÿ”ฅ

Endpoints SHOULD use an exponential-backoff timer to decide when to retransmit Change options ๐Ÿ’œ (Packets made specifically for feature negotiation MUST use such a timer.) The timer starts at not less than one round-trip time and should back off to not less than 64 seconds ๐ŸŒˆ The backoff protects against delayed agreement caused by the reordering protection algorithms in the next section ๐Ÿ‘‘ Endpoints can also piggyback Change options on packets they'd send anyway, or make new packets to carry them ๐Ÿ“ Any new packets are controlled by the relevant congestion-control mechanism โœจ

Confirm options are never retransmitted ๐Ÿ™ˆ But the endpoint sending a Confirm MUST generate a Confirm option after every non-reordered Change ๐Ÿ’–


6.6.4. Reordering โœจ

Reordering can make packets with Change and Confirm options show up in a weird order ๐Ÿ’€ Endpoints MUST ignore feature negotiation options that don't arrive in strictly-increasing order by Sequence Number ๐ŸŽ€ This section has two algorithms that do this job ๐Ÿฆ‹

The first algorithm has two sequence number variables that each endpoint keeps for the connection ๐Ÿ’…

  • FGSR (Feature Greatest Sequence Number Received): the greatest sequence number received, but only counting valid packets that had one or more feature negotiation options (Change and/or Confirm). It starts at ISR - 1 ๐ŸŒธ
  • FGSS (Feature Greatest Sequence Number Sent): the greatest sequence number sent, but only counting packets that had one or more new Change options. A Change option is new if and only if it was generated during a transition from the STABLE or UNSTABLE state to the CHANGING state. Change options generated inside the CHANGING state are retransmissions, so they MUST have exactly the same contents as the previously transmitted options, which gives some tolerance for reordering ๐Ÿงš FGSS starts at ISS ๐Ÿ‘‘

Each endpoint checks two conditions on sequence numbers to decide whether to process received feature negotiation options ๐Ÿซถ

  1. If a packet's Sequence Number is less than or equal to FGSR, then its Change options MUST be ignored.
  2. If a packet's Sequence Number is less than or equal to FGSR, if it has no Acknowledgement Number, OR if its Acknowledgement Number is less than FGSS, then its Confirm options MUST be ignored.

Alternatively, an endpoint MAY keep separate FGSR and FGSS values for every feature ๐Ÿฆ‹ FGSR(F/X) would equal the greatest sequence number received, counting only packets that had Change or Confirm options applying to feature F/X, and FGSS(F/X) would be defined similarly ๐Ÿ’œ This one needs more state, but it's a bit more forgiving with multiple overlapped feature negotiations ๐ŸŒˆ Either algorithm MAY be used, but the first one (with connection-wide FGSR and FGSS variables) is RECOMMENDED ๐Ÿ’–

One consequence of these rules is that a CHANGING endpoint ignores any Confirm option that doesn't acknowledge the latest Change option it sent ๐Ÿ˜ญ This makes sure that once agreement is reached, it used the most recent info about the endpoints' preferences ๐Ÿ‘‘


6.6.5. Preference Changes โœจ

Endpoints are allowed to change their preference lists at any time ๐ŸŒธ But an endpoint that changes its preference list while in the CHANGING state MUST transition to the UNSTABLE state ๐Ÿ”ฅ It goes back to CHANGING once it has sent a Change option with the new preference list ๐Ÿ’… This makes sure agreement is based on active preference lists ๐Ÿซถ Without the UNSTABLE state, simultaneous negotiation (where the endpoints start independent negotiations for the same feature at the same time) could end with both endpoints thinking the feature has different values ๐Ÿ˜ญ


6.6.6. Simultaneous Negotiation โœจ

The two endpoints might open negotiation for the same feature at the same time ๐Ÿ™ˆ After that, an endpoint in the CHANGING state will receive a Change option for that same feature ๐Ÿฆ‹ Those received Change options can act as responses to the original Change options ๐Ÿงš The CHANGING endpoint MUST examine the received Change's preference list, reconcile it with its own preference list (as shown in its generated Change options), and generate the matching Confirm option ๐Ÿ’– Then it can move to the STABLE state ๐ŸŽ€


6.6.7. Unknown Features โœจ

Endpoints can receive Change options that mention feature numbers they don't understand ๐ŸŒˆ For example, that happens when an extended DCCP talks to a non-extended DCCP ๐Ÿ“ Endpoints MUST respond to unknown Change options with Empty Confirm options (that is, Confirm options with no data), which tell the CHANGING endpoint that the feature wasn't understood ๐Ÿ’… But if the Change option was Mandatory, the connection MUST be reset. See Section 6.6.9 ๐Ÿ‘‘

When an endpoint gets an empty Confirm option for some feature, the CHANGING endpoint MUST transition back to the STABLE state and leave the feature's value unchanged ๐Ÿซถ Section 15 suggests that the default value for any extension feature should correspond to "extension not available" ๐ŸŒธ

Some features have to be understood by all DCCPs (see Section 6.4). If the CHANGING endpoint gets an empty Confirm option for one of those, it SHOULD reset the connection with Reset Code 5, "Option Error" ๐Ÿ’€

Since Confirm options are only generated in response to Change options, an endpoint should never receive a Confirm option referring to a feature number it doesn't understand ๐Ÿงš Even so, endpoints MUST ignore any such options they receive ๐Ÿ™ˆ๐Ÿ’œ

6.6.8. Invalid Options โœจ

Okay so a DCCP endpoint might get a Change or Confirm option for a feature it knows, but the option lists one or more values it doesn't understand ๐Ÿง. Some of those options are invalid and some aren't, depending on the relevant reconciliation rule (see Section 6.3). For instance:

  • All features have length limits, and options with invalid lengths are invalid ๐Ÿ“. Like, the Ack Ratio feature takes 16-bit values, so valid "Confirm R(Ack Ratio)" options have option length 5 ๐Ÿ’….
  • Some non-negotiable features have value limits ๐Ÿ™…โ€โ™€๏ธ. The Ack Ratio feature takes two-byte, non-zero integers, so a "Change L(Ack Ratio, 0)" option is never valid, periodt. Note that server-priority features don't have value limits, since unknown values are handled as a matter of course ๐Ÿงš.
  • Any Confirm option that picks the wrong value, based on the two preference lists and the relevant reconciliation rule, is invalid ๐Ÿ’€.

However, unexpected Confirm options (the ones that refer to unknown feature numbers, or that don't seem to be part of a current negotiation) are not invalid, although the receiver ignores them ๐Ÿ™ˆ.

An endpoint that gets an invalid Change option MUST respond with the matching empty Confirm option ๐Ÿ’Œ. An endpoint that gets an invalid Confirm option MUST reset the connection, with Reset Code 5, "Option Error" ๐Ÿ˜ญ.


6.6.9. Mandatory Feature Negotiation

Change options may be preceded by Mandatory options (Section 5.8.2) ๐ŸŽ€. Mandatory Change options get processed like normal Change options, except that the following failure cases make the receiver reset the connection with Reset Code 6, "Mandatory Failure", instead of sending a Confirm option. The connection MUST be reset if:

  • the Change option's feature number was not understood;
  • the Change option's value was invalid, and the receiver would normally have sent an empty Confirm option in response; or
  • for server-priority features, there was no shared entry in the two endpoints' preference lists.

Other failure cases don't reset the connection. In particular, reordering protection may cause a Mandatory Change option to be ignored without resetting the connection ๐Ÿ™ƒ.

Confirm options behave identically and have the same reset conditions whether or not they are Mandatory ๐Ÿซถ.


7. Sequence Numbers ๐Ÿ”ข

DCCP uses sequence numbers to line packets up, spot losses and network duplicates, and protect against attackers, half-open connections, and really old packets showing up late ๐Ÿ•ฐ๏ธ. Every packet carries a Sequence Number, and most packet types carry an Acknowledgement Number too.

DCCP sequence numbers are packet based. That means each endpoint's Sequence Numbers go up by one per packet, modulo 2^48 โœจ. Even DCCP-Ack and DCCP-Sync packets, and other packets that don't carry user data, bump the Sequence Number. DCCP is an unreliable protocol, so there are no true retransmissions, but effective retransmissions (like resending DCCP-Request packets) also increment the Sequence Number. This is what lets DCCP implementations detect network duplication, retransmissions, and acknowledgement loss, and it's a big departure from TCP practice ๐Ÿ’….

7.1. Variables ๐Ÿ“ฆ

DCCP endpoints keep a set of sequence number variables for each connection:

ISS     The Initial Sequence Number Sent by this endpoint.  This
        equals the Sequence Number of the first DCCP-Request or
        DCCP-Response sent.

ISR     The Initial Sequence Number Received from the other endpoint.
        This equals the Sequence Number of the first DCCP-Request or
        DCCP-Response received.

GSS     The Greatest Sequence Number Sent by this endpoint.  Here,
        and elsewhere, "greatest" is measured in circular sequence
        space.

GSR     The Greatest Sequence Number Received from the other endpoint
        on an acknowledgeable packet.  (Section 7.4 defines this
        term.)

GAR     The Greatest Acknowledgement Number Received from the other
        endpoint on an acknowledgeable packet that was not a DCCP-
        Sync.

Some other variables are derived from these primitives.

SWL and SWH
        (Sequence Number Window Low and High)  The extremes of the
        validity window for received packets' Sequence Numbers.

AWL and AWH
        (Acknowledgement Number Window Low and High)  The extremes of
        the validity window for received packets' Acknowledgement
        Numbers.

7.2. Initial Sequence Numbers ๐ŸŒธ

The endpoints' initial sequence numbers get set by the first DCCP-Request and DCCP-Response packets sent. Initial sequence numbers MUST be chosen to dodge two problems:

  • delivery of old packets, where packets lingering in the network from an old connection get delivered to a new connection with the same addresses and port numbers; and
  • sequence number attacks, where an attacker can guess the sequence numbers that a future connection would use [M85].

These are the same problems TCP faces, so DCCP implementations SHOULD use TCP's strategies to avoid them [RFC793, RFC1948]. The rest of this section spells those strategies out ๐Ÿ”.

To address the first problem, an implementation MUST ensure that the initial sequence number for a given <source address, source port, destination address, destination port> 4-tuple doesn't overlap with recent sequence numbers on previous connections with the same 4-tuple. ("Recent" means sent within 2 maximum segment lifetimes, or 4 minutes.) The implementation MUST additionally ensure that the lower 24 bits of the initial sequence number don't overlap with the lower 24 bits of recent sequence numbers (unless the implementation plans to avoid short sequence numbers; see Section 7.6). An implementation that has state for a recent connection with the same 4-tuple can pick a good initial sequence number explicitly. Otherwise, it could tie initial sequence number selection to some clock, such as the 4-microsecond clock TCP uses [RFC793]. Two separate clocks may be required, one for the upper 24 bits and one for the lower 24 bits โฐ.

To address the second problem, an implementation MUST provide each 4-tuple with an independent initial sequence number space. Then, opening a connection doesn't reveal anything about initial sequence numbers on other connections to the same host ๐Ÿ•ต๏ธโ€โ™€๏ธ. [RFC1948] achieves this by adding a cryptographic hash of the 4-tuple and a secret to each initial sequence number. For the secret, [RFC1948] recommends a combination of some truly random data [RFC4086], an administratively installed passphrase, the endpoint's IP address, and the endpoint's boot time, but truly random data is sufficient. Care should be taken when the secret is changed. Such a change alters all initial sequence number spaces, which might make an initial sequence number for some 4-tuple equal a recently sent sequence number for the same 4-tuple. To avoid this problem, the endpoint might remember dead connection state for each 4-tuple, or stay quiet for 2 maximum segment lifetimes around such a change.

7.3. Quiet Time ๐Ÿฅฑ

DCCP endpoints, like TCP endpoints, must take care before initiating connections when they boot. In particular, they MUST NOT send packets whose sequence numbers are close to the sequence numbers of packets lingering in the network from before the boot. The simplest way to enforce this rule is for DCCP endpoints to avoid sending any packets until one maximum segment lifetime (2 minutes) after boot.

Other enforcement mechanisms include remembering recent sequence numbers across boots, and reserving the upper 8 or so bits of initial sequence numbers for a persistent counter that decrements by two each boot. (The latter mechanism would require disallowing packets with short sequence numbers; see Section 7.6.1.)

7.4. Acknowledgement Numbers ๐Ÿ’Œ

Cumulative acknowledgements are meaningless in an unreliable protocol ๐Ÿ™…, so DCCP's Acknowledgement Number field has a different meaning from TCP's.

A received packet is classified as acknowledgeable if and only if its header was successfully processed by the receiving DCCP. In terms of the pseudocode in Section 8.5, a received packet becomes acknowledgeable when the receiving endpoint reaches Step 8. This means, for example, that all acknowledgeable packets have valid header checksums and sequence numbers. A sent packet's Acknowledgement Number MUST equal the sending endpoint's GSR, the Greatest Sequence Number Received on an acknowledgeable packet, for all packet types except DCCP-Sync and DCCP-SyncAck.

"Acknowledgeable" does not refer to data processing. Even acknowledgeable packets may have their application data dropped, due to receive buffer overflow or corruption, for instance. Data Dropped options report these data losses when necessary, letting congestion control mechanisms distinguish between network losses and endpoint losses. This issue is discussed further in Sections 11.4 and 11.7.

DCCP-Sync and DCCP-SyncAck packets' Acknowledgement Numbers differ as follows: the Acknowledgement Number on a DCCP-Sync packet corresponds to a received packet, but not necessarily to an acknowledgeable packet. In particular, it might correspond to an out-of-sync packet whose options were not processed. The Acknowledgement Number on a DCCP-SyncAck packet always corresponds to an acknowledgeable DCCP-Sync packet; it might be less than GSR in the presence of reordering ๐Ÿ”.

7.5. Validity and Synchronization ๐Ÿซง

Any DCCP endpoint might receive packets that are not actually part of the current connection. For instance, the network might deliver an old packet, an attacker might attempt to hijack a connection, or the other endpoint might crash, causing a half-open connection ๐Ÿ‘ป.

DCCP, like TCP, uses sequence number checks to detect these cases. Packets whose Sequence and/or Acknowledgement Numbers are out of range are called sequence-invalid and are not processed normally ๐Ÿšซ.

Unlike TCP, DCCP requires a synchronization mechanism to recover from large bursts of loss ๐ŸŒช๏ธ. One endpoint might send so many packets during a burst of loss that when one of its packets finally got through, the other endpoint would label its Sequence Number as invalid. A handshake of DCCP-Sync and DCCP-SyncAck packets recovers from this case, and that's iconic ๐ŸŒˆ

7.5.1. Sequence and Acknowledgement Number Windows โœจ

Okay, so every DCCP endpoint sets up its own sequence validity windows ๐Ÿฆ‹. These are little slices of the Sequence and Acknowledgement Number spaces, and they line up with the packets the endpoint expects to see over the next few round-trip times. The Sequence and Acknowledgement Number windows always hold GSR and GSS, respectively ๐Ÿ’–. The window widths come from the Sequence Window features for the two half-connections ๐ŸŽ€.

The Sequence Number validity window for packets from DCCP B is [SWL, SWH]. This window always contains GSR, the Greatest Sequence Number Received on a sequence-valid packet from DCCP B ๐ŸŒธ. It's W packets wide, where W is the value of the Sequence Window/B feature. The one-fourth mark (rounded down) sits at or below GSR, and the three-fourths mark sits above GSR. (This lopsided placement assumes that bursts of loss are more common in the network than significant reorderings ๐Ÿ™ˆ.)

  invalid  |       valid Sequence Numbers        |  invalid
<---------*|*===========*=======================*|*--------->
      GSR -|GSR + 1 -   GSR                 GSR +|GSR + 1 +
 floor(W/4)|floor(W/4)                 ceil(3W/4)|ceil(3W/4)
            = SWL                           = SWH

The Acknowledgement Number validity window for packets from DCCP B is [AWL, AWH]. Its high end, AWH, equals GSS, the Greatest Sequence Number Sent by DCCP A ๐Ÿซถ. The window is W' packets wide, where W' is the value of the Sequence Window/A feature.

  invalid  |    valid Acknowledgement Numbers    |  invalid
<---------*|*===================================*|*--------->
   GSS - W'|GSS + 1 - W'                      GSS|GSS + 1
            = AWL                           = AWH

SWL and AWL get an initial adjustment so they're never less than the initial Sequence Numbers received and sent, respectively ๐Ÿ‘‘:

SWL := max(GSR + 1 - floor(W/4), ISR),
AWL := max(GSS + 1 - W', ISS).

These adjustments MUST be applied only at the beginning of the connection. (Long-lived connections may wrap sequence numbers so that they appear to be less than ISR or ISS; the adjustments MUST NOT be applied in that case.) ๐Ÿ˜ญ


7.5.2. Sequence Window Feature ๐Ÿงš

The Sequence Window/A feature decides how wide the Sequence Number validity window is for DCCP B, and how wide the Acknowledgement Number validity window is for DCCP A ๐Ÿ’…. To tell DCCP B that the Sequence Window/A value is W, DCCP A sends a "Change L(Sequence Window, W)" option.

Sequence Window is feature number 3 and it's non-negotiable ๐Ÿ”ฅ. It takes 48-bit (6-byte) integer values, just like DCCP sequence numbers, so Change and Confirm options for Sequence Window are 9 bytes long. New connections start with Sequence Window 100 for both endpoints. The minimum valid value is Wmin = 32, and the maximum valid value is Wmax = 2^46 - 1 = 70368744177663. Change options that suggest a Sequence Window value outside this range are invalid and MUST be handled accordingly ๐Ÿ™…โ€โ™€๏ธ.

A proper Sequence Window/A value has to match the number of packets DCCP A expects to have in flight โœˆ๏ธ. Only DCCP A can predict that number. Values that are too small raise the risk of the endpoints getting out of sync after bursts of loss, and values that are much too small can stop productive communication whether or not there's any loss ๐Ÿ˜ฌ. Too-large values, on the other hand, raise the risk of connection hijacking, and Section 7.5.5 quantifies that risk. A good rule of thumb is for each endpoint to set Sequence Window to about five times the maximum number of packets it expects to send in a round-trip time ๐Ÿ’œ. Endpoints SHOULD send Change L(Sequence Window) options as necessary while the connection progresses. Also, an endpoint MUST NOT persistently send more than its Sequence Window number of packets per round-trip time. In other words, DCCP A MUST NOT persistently send more than Sequence Window/A packets per RTT ๐Ÿ“.


7.5.3. Sequence-Validity Rules ๐Ÿ’–

Sequence-validity depends on the packet type that was received ๐ŸŽ€. The table below shows which sequence and acknowledgement number checks apply to each packet. A packet is sequence-valid if it passes both tests, and sequence-invalid if it fails either one. Lots of these checks refer to the validity windows [SWL, SWH] and [AWL, AWH] from Section 7.5.1 ๐Ÿฆ‹.

                                         Acknowledgement Number
Packet Type      Sequence Number Check   Check
-----------      ---------------------   ----------------------
DCCP-Request     SWL <= seqno <= SWH (*) N/A
DCCP-Response    SWL <= seqno <= SWH (*) AWL <= ackno <= AWH
DCCP-Data        SWL <= seqno <= SWH     N/A
DCCP-Ack         SWL <= seqno <= SWH     AWL <= ackno <= AWH
DCCP-DataAck     SWL <= seqno <= SWH     AWL <= ackno <= AWH
DCCP-CloseReq    GSR <  seqno <= SWH     GAR <= ackno <= AWH
DCCP-Close       GSR <  seqno <= SWH     GAR <= ackno <= AWH
DCCP-Reset       GSR <  seqno <= SWH     GAR <= ackno <= AWH
DCCP-Sync        SWL <= seqno            AWL <= ackno <= AWH
DCCP-SyncAck     SWL <= seqno            AWL <= ackno <= AWH

(*) Check not applied if connection is in LISTEN or REQUEST state.

Generally speaking, packets are sequence-valid when their Sequence and Acknowledgement Numbers land inside the matching valid windows, [SWL, SWH] and [AWL, AWH] โœจ. There are a couple of exceptions, though ๐Ÿ‘€:

  • Since DCCP-CloseReq, DCCP-Close, and DCCP-Reset packets end a connection, they can't have Sequence Numbers less than or equal to GSR, or Acknowledgement Numbers less than GAR ๐Ÿ›‘.
  • DCCP-Sync and DCCP-SyncAck Sequence Numbers aren't checked strictly. These packet types exist specifically to get the endpoints back in sync, and checking their Sequence Numbers would kill their usefulness ๐Ÿงฏ.

The lenient checks on DCCP-Sync and DCCP-SyncAck packets let things keep going after weird events, like endpoint crashes or huge bursts of loss ๐Ÿ’ฅ. But there's no need for leniency when nothing unusual is happening, meaning during ongoing successful communication ๐Ÿ˜Œ. So DCCP implementations SHOULD use the following, stricter checks for active connections. A connection counts as active if it has received valid packets from the other endpoint within the last three round-trip times ๐Ÿ”ฅ.

                                         Acknowledgement Number
Packet Type      Sequence Number Check   Check
-----------      ---------------------   ----------------------
DCCP-Sync        SWL <= seqno <= SWH     AWL <= ackno <= AWH
DCCP-SyncAck     SWL <= seqno <= SWH     AWL <= ackno <= AWH

Finally, an endpoint MAY apply the following stricter checks to DCCP-CloseReq, DCCP-Close, and DCCP-Reset packets. This further lowers the odds of a successful blind attack using those packet types ๐Ÿ›ก๏ธ.

These checks can cause extra synchronization overhead and delay connection closing when packets get lost, so they should be considered experimental ๐Ÿงช.

                                         Acknowledgement Number
Packet Type      Sequence Number Check   Check
-----------      ---------------------   ----------------------
DCCP-CloseReq    seqno == GSR + 1        GAR <= ackno <= AWH
DCCP-Close       seqno == GSR + 1        GAR <= ackno <= AWH
DCCP-Reset       seqno == GSR + 1        GAR <= ackno <= AWH

Keep in mind that sequence-validity is only one of the validity checks applied to received packets ๐Ÿ’….


7.5.4. Handling Sequence-Invalid Packets ๐Ÿ™ˆ

Here's how endpoints react to received sequence-invalid packets ๐ŸŒˆ.

  • Any sequence-invalid DCCP-Sync or DCCP-SyncAck packet MUST be ignored ๐Ÿซฅ.
  • A sequence-invalid DCCP-Reset packet MUST elicit a DCCP-Sync packet in response (subject to a possible rate limit). That response MUST use a new Sequence Number, so GSS goes up. GSR stays the same, though, since the packet that came in was sequence-invalid. The response's Acknowledgement Number MUST equal GSR ๐Ÿ”„.
  • Any other sequence-invalid packet MUST elicit a similar DCCP-Sync packet. The only difference is that the response's Acknowledgement Number MUST equal the sequence-invalid packet's Sequence Number ๐ŸŽฏ.

When a sequence-valid DCCP-Sync arrives, the peer endpoint (say, DCCP B) MUST update its GSR variable and reply with a DCCP-SyncAck packet. The DCCP-SyncAck's Acknowledgement Number will equal the DCCP-Sync's Sequence Number, which isn't necessarily GSR ๐Ÿฆ‹. When DCCP A gets that DCCP-SyncAck, it's sequence-valid because it acknowledges the DCCP-Sync. So DCCP A updates its GSR variable, and the endpoints are back in sync ๐Ÿฅณ. There's one exception: if the peer endpoint is in the REQUEST state, it MUST respond with a DCCP-Reset instead of a DCCP-SyncAck. That cleans up DCCP A's half-open connection ๐Ÿงน.

To guard against denial-of-service attacks, DCCP implementations SHOULD impose a rate limit on DCCP-Syncs sent in response to sequence-invalid packets, such as not more than eight DCCP-Syncs per second ๐Ÿšฆ.

DCCP endpoints MUST NOT process sequence-invalid packets, except that they might generate a DCCP-Sync. For instance, options MUST NOT be processed ๐Ÿšซ. An endpoint MAY temporarily keep sequence-invalid packets in case they become valid later. This can reduce the impact of bursts of loss by handing more packets up to the application ๐Ÿฐ. Specifically, an endpoint MAY preserve sequence-invalid packets for up to 2 round-trip times. If the relevant sequence windows shift during that time so the packets become sequence-valid, the endpoint MAY process them again โณ.

Here's why sequence-invalid DCCP-Reset packets cause DCCP-Syncs to be generated ๐Ÿง . Endpoints in an unsynchronized state (CLOSED, REQUEST, and LISTEN) might not have enough info to build a proper DCCP-Reset on the first try. Say a peer endpoint is in CLOSED state and gets a DCCP-Data packet. It can't guess the right Sequence Number for the DCCP-Reset it generates, because a DCCP-Data packet has no Acknowledgement Number ๐Ÿ˜ตโ€๐Ÿ’ซ. The DCCP-Sync generated in response to that bad reset works like a challenge. It contains enough information for the peer to generate a proper DCCP-Reset ๐ŸŽ. Heads up, though: the new DCCP-Reset might carry a different Reset Code than the original one. Probably the new Reset Code will be 3, "No Connection". The endpoint SHOULD use information from the original DCCP-Reset when possible ๐Ÿ’œ.

7.5.5. Sequence Number Attacks โœจ

Okay so Sequence and Acknowledgement Numbers are DCCP's main line of defense ๐Ÿ›ก๏ธ bestie. If an attacker can't guess your sequence numbers, they can't easily mess with or hijack your connection ๐Ÿ’…, and careful initial sequence number choice wipes out the most serious attacks ๐Ÿ™Œ.

Still, a sneaky attacker could spam packets with random Sequence and Acknowledgement Numbers ๐Ÿ™ˆ. If one of those random probes happens to be sequence-valid, it could shut the connection down or cause other drama ๐Ÿ’€. The easiest ones to pull off are:

  • Send DCCP-Data packets with random Sequence Numbers. If one of these packets lands in the valid sequence number window, the attack packet's application data may be inserted into the data stream.
  • Send DCCP-Sync packets with random Sequence and Acknowledgement Numbers. If one of these packets lands in the valid acknowledgement number window, the receiver will shift its sequence number window accordingly, getting out of sync with the correct endpoint -- perhaps permanently ๐Ÿ˜ญ.

Either way, the attacker needs to guess both the Source and Destination Ports for any of these to work ๐ŸŽฏ. Plus, the connection has to be inactive for the DCCP-Sync attack to land, assuming the victim implemented the more stringent checks for active connections recommended in Section 7.5.3 ๐Ÿ”’.

Now for the math, because it's kind of iconic ๐Ÿงฎ. Let N be the number of attack packets the attacker is willing to send, W be the relevant sequence window width, and L be the length of sequence numbers (24 or 48). The attacker's best strategy is to space the attack packets evenly over sequence space. Then the probability of hitting one sequence number window is P = WN/2^L.

The success probability for a DCCP-Data attack using short sequence numbers is therefore P = WN/2^24. For W = 100, the attacker must send more than 83,000 packets to get a 50% chance of success. For reference, the easiest TCP attack (sending a SYN with a random sequence number, which causes a connection reset if it falls within the window) with W = 8760 (a common default) and L = 32 requires more than 245,000 packets to get a 50% chance of success ๐Ÿ˜ณ.

A fast connection's W will generally be high, which increases the attack success probability for a fixed N. If this probability gets uncomfortably high with L = 24, the endpoint SHOULD prevent the use of short sequence numbers by manipulating the Allow Short Sequence Numbers feature (see Section 7.6.1) ๐Ÿšซ. The probability limit depends on the application, though. Some applications, such as those already designed to handle corruption, are pretty resilient to data injection attacks ๐Ÿงฝ.

The DCCP-Sync attack has L = 48, since DCCP-Sync packets use long sequence numbers exclusively. On top of that, the success probability is halved, since only half the Sequence Number space is valid. So these attacks have a correspondingly smaller probability of success. For a large W of 2000 packets, the attacker must send more than 10^11 packets to get a 50% chance of success ๐Ÿฅต.

Attacks involving DCCP-Ack, DCCP-DataAck, DCCP-CloseReq, DCCP-Close, and DCCP-Reset packets are harder, since Sequence and Acknowledgement Numbers must both be guessed. The probability of attack success for these packet types is P = WXN/2^(2L), where W is the Sequence Number window, X is the Acknowledgement Number window, and N and L are as before ๐Ÿง .

Since DCCP-Data attacks with short sequence numbers are relatively easy to execute, DCCP has been engineered so these attacks can't escalate into connection resets or other serious consequences ๐Ÿฅฐ. In particular, any options whose processing might cause the connection to be reset are ignored when they appear on DCCP-Data packets ๐Ÿซถ.

7.5.6. Sequence Number Handling Examples

Let's look at some examples ๐Ÿ‘€. In the first one, DCCP A and DCCP B recover from a huge burst of loss that runs DCCP A's sequence numbers out of DCCP B's appropriate sequence number window.

DCCP A                                           DCCP B
(GSS=1,GSR=10)                                   (GSS=10,GSR=1)
            -->   DCCP-Data(seq 2)     XXX
                      ...
            -->   DCCP-Data(seq 100)   XXX
            -->   DCCP-Data(seq 101)           -->  ???
                                                 seqno out of range;
                                                 send Sync
   OK       <--   DCCP-Sync(seq 11, ack 101)   <--
                                                 (GSS=11,GSR=1)
            -->   DCCP-SyncAck(seq 102, ack 11)   -->   OK
(GSS=102,GSR=11)                                 (GSS=11,GSR=102)

In the next example, a DCCP connection recovers from a simple blind attack ๐Ÿ•ต๏ธโ€โ™€๏ธ.

DCCP A                                           DCCP B
(GSS=1,GSR=10)                                   (GSS=10,GSR=1)
             *ATTACKER*  -->  DCCP-Data(seq 10^6)  -->  ???
                                                 seqno out of range;
                                                 send Sync
   ???      <--   DCCP-Sync(seq 11, ack 10^6)  <--
ackno out of range; ignore
(GSS=1,GSR=10)                                   (GSS=11,GSR=1)

The final example shows recovery from a half-open connection ๐ŸŒธ.

DCCP A                                           DCCP B
(GSS=1,GSR=10)                                   (GSS=10,GSR=1)
(Crash)
CLOSED                                               OPEN
REQUEST     -->   DCCP-Request(seq 400)        -->   ???
!!          <--   DCCP-Sync(seq 11, ack 400)   <--   OPEN
REQUEST     -->   DCCP-Reset(seq 401, ack 11)  -->   (Abort)
REQUEST                                              CLOSED
REQUEST     -->   DCCP-Request(seq 402)        -->   ...

7.6. Short Sequence Numbers ๐Ÿฆ‹

DCCP sequence numbers are 48 bits long ๐Ÿ’œ. This huge sequence space protects DCCP connections against some blind attacks, like injecting DCCP-Resets into the connection. However, DCCP-Data, DCCP-Ack, and DCCP-DataAck packets make up the body of any DCCP connection, and they can save header space by carrying only the lower 24 bits of the relevant Sequence and Acknowledgement Numbers ๐Ÿ“ฆ. The receiving endpoint extends these numbers back to 48 bits using this pseudocode:

procedure Extend_Sequence_Number(S, REF)
   /* S is a 24-bit sequence number from the packet header.
      REF is the relevant 48-bit reference sequence number:
      GSS if S is an Acknowledgement Number, and GSR if S is a
      Sequence Number. */
   Set REF_low := low 24 bits of REF
   Set REF_hi := high 24 bits of REF
   If REF_low (<) S           /* circular comparison mod 2^24 */
         and S |<| REF_low,   /* conventional, non-circular
                                 comparison */
      Return (((REF_hi + 1) mod 2^24) << 24) | S
   Otherwise, if S (<) REF_low and REF_low |<| S,
      Return (((REF_hi - 1) mod 2^24) << 24) | S
   Otherwise,
      Return (REF_hi << 24) | S

The two kinds of comparison in the if statements detect when the low-order bits of the sequence space have wrapped around ๐Ÿ”„. (The circular comparison "REF_low (<) S" returns true if and only if (S - REF_low), calculated using two's-complement arithmetic and then represented as an unsigned number, is less than or equal to 2^23 (mod 2^24).) When that happens, the high-order bits get incremented or decremented, as appropriate โœจ.

7.6.1. Allow Short Sequence Numbers Feature ๐ŸŽ€

Endpoints can require that all packets use long sequence numbers by leaving the Allow Short Sequence Numbers feature value at its default of zero ๐Ÿ”. This can reduce the risk that data gets injected into the connection inappropriately. DCCP A sends a Change L(Allow Short Seqnos, 1) option to say it wants to send packets with short sequence numbers ๐Ÿ’Œ.

Allow Short Sequence Numbers has feature number 2 and is server-priority. It takes one-byte Boolean values. When Allow Short Seqnos/B is zero, DCCP B MUST NOT send packets with short sequence numbers, and DCCP A MUST ignore any packets with short sequence numbers that it receives ๐Ÿ™…โ€โ™€๏ธ. Values of two or more are reserved ๐Ÿšง. New connections start with Allow Short Sequence Numbers 0 for both endpoints ๐ŸŒฑ.

7.6.2. When to Avoid Short Sequence Numbers ๐Ÿ™ˆ

Short sequence numbers lower the rate DCCP connections can safely reach, and they make certain attacks, like blind data injection, riskier ๐Ÿ“‰. Very-high-rate DCCP connections, and connections with large sequence windows (Section 7.5.2), SHOULD NOT use short sequence numbers on their data packets ๐Ÿšซ. We already talked about the attack risks in Section 7.5.5, so here we're focusing on the rate limit ๐ŸŽ๏ธ.

The sequence-validity mechanism assumes the network doesn't deliver extremely old data ๐Ÿง“. Specifically, it assumes the network must have dropped any packet by the time the connection wraps around and reuses that sequence number. This constraint caps the maximum connection rate that can be safely achieved. Let MSL equal the maximum segment lifetime, P equal the average DCCP packet size in bits, and L equal the length of sequence numbers (24 or 48 bits). Then the maximum safe rate, in bits per second, is R = P*(2^L)/2MSL.

For the default MSL of 2 minutes, 1500-byte DCCP packets, and short sequence numbers, the safe rate is roughly 800 Mb/s ๐Ÿคฏ. Sure, 2 minutes is a very big MSL for any network that could sustain that rate with such small packets ๐Ÿ˜…. But long sequence numbers allow way higher rates under the same constraints: up to 14 petabits a second for 1500-byte packets and the default MSL ๐Ÿš€๐Ÿ’–.

7.7. NDP Count and Detecting Application Loss ๐Ÿ”

DCCP's sequence numbers go up by one on every packet, including non-data packets (packets that don't carry application data) ๐Ÿ”ข. That makes DCCP sequence numbers great for detecting any network loss, but not for detecting loss of application data ๐Ÿ™ƒ. The NDP Count option reports the length of each burst of non-data packets. This lets the receiving DCCP reliably figure out when a burst of loss included application data ๐ŸŽฏ.

+--------+--------+-------- ... --------+
|00100101| Length |      NDP Count      |
+--------+--------+-------- ... --------+
 Type=37  Len=3-8       (1-6 bytes)

If a DCCP endpoint's Send NDP Count feature is one (see below), then that endpoint MUST send an NDP Count option on every packet whose immediate predecessor was a non-data packet ๐Ÿ“จ. Non-data packets are DCCP packet types DCCP-Ack, DCCP-Close, DCCP-CloseReq, DCCP-Reset, DCCP-Sync, and DCCP-SyncAck ๐Ÿซฅ. The other packet types, namely DCCP-Request, DCCP-Response, DCCP-Data, and DCCP-DataAck, count as data packets, though not every DCCP-Request and DCCP-Response packet will actually carry application data ๐Ÿคทโ€โ™€๏ธ.

The value stored in NDP Count equals the number of consecutive non-data packets in the run immediately before the current packet ๐Ÿงฎ. Packets with no NDP Count option are treated as having NDP Count zero ๐Ÿ’….

The NDP Count option can carry one to six bytes of data ๐Ÿ“. The smallest option format that can hold the NDP Count SHOULD be used ๐Ÿชถ.

With NDP Count, the receiver can reliably tell only whether a burst of loss contained at least one data packet ๐Ÿฅบ. For example, the receiver can't always tell whether a burst of loss contained a non-data packet ๐Ÿ˜ญ.

7.7.1. NDP Count Usage Notes โœจ

Okay so, say K consecutive sequence numbers go missing in some burst of loss and Send NDP Count is turned on. Then some application data was lost inside those sequence numbers, unless the packet right after the hole has an NDP Count option whose value is greater than or equal to K. ๐Ÿ’€

Let's look at an example! Say an endpoint sent this sequence of non-data packets (Nx) and data packets (Dx):

N0  N1  D2  N3  D4  D5  N6  D7  D8  D9  D10 N11 N12 D13

Those packets would have NDP Counts like this:

N0  N1  D2  N3  D4  D5  N6  D7  D8  D9  D10 N11 N12 D13
-   1   2   -   1   -   -   1   -   -   -   -   1   2

NDP Count is not useful for applications that include their own sequence numbers in their packet headers. ๐Ÿ™ˆ

7.7.2. Send NDP Count Feature ๐ŸŽ€

The Send NDP Count feature lets DCCP endpoints negotiate whether they should send NDP Count options on their packets. DCCP A sends a "Change R(Send NDP Count, 1)" option to ask DCCP B to send NDP Count options. ๐Ÿฆ‹

Send NDP Count has feature number 7 and is server-priority. It takes one-byte Boolean values. DCCP B MUST send NDP Count options as described above when Send NDP Count/B is one, although it MAY send NDP Count options even when Send NDP Count/B is zero. Values of two or more are reserved. New connections start with Send NDP Count 0 for both endpoints.

8. Event Processing โœจ

This section is about how DCCP connections move between states and which packets get sent when. Note that feature negotiation happens in parallel with the connection-wide state transitions described here. ๐ŸŒˆ

8.1. Connection Establishment

Okay, the initiation phase of a DCCP connection is a three-way handshake. First there's an initial DCCP-Request packet from the client, then a DCCP-Response from the server, and finally an acknowledgement from the client, usually in a DCCP-Ack or DCCP-DataAck packet. The client goes REQUEST, then PARTOPEN, then OPEN. The server goes LISTEN, then RESPOND, then OPEN. ๐Ÿ’–

  Client State                             Server State
     CLOSED                                   LISTEN
1.   REQUEST   -->       Request        -->
2.             <--       Response       <--   RESPOND
3.   PARTOPEN  -->     Ack, DataAck     -->
4.             <--  Data, Ack, DataAck  <--   OPEN
5.   OPEN      <->  Data, Ack, DataAck  <->   OPEN

8.1.1. Client Request

When a client decides to start a connection, it enters the REQUEST state, picks an initial sequence number (Section 7.2), and sends a DCCP-Request packet using that sequence number to the intended server. ๐Ÿ“

DCCP-Request packets will commonly carry feature negotiation options that open negotiations for various connection parameters, like preferred congestion control IDs for each half-connection. They may also carry application data, but the client should be aware that the server may not accept that data. ๐Ÿค”

A client in the REQUEST state SHOULD use an exponential-backoff timer to send new DCCP-Request packets if no response comes back. The first retransmission should happen after about one second, backing off to no less than one packet every 64 seconds. Or the endpoint can use whatever retransmission strategy it follows for retransmitting TCP SYNs. Each new DCCP-Request MUST increment the Sequence Number by one and MUST contain the same Service Code and application data as the original DCCP-Request. ๐Ÿ”ฅ

A client MAY give up on its DCCP-Requests after some time (3 minutes, for example). When it does, it SHOULD send a DCCP-Reset packet to the server with Reset Code 2, "Aborted", to clean up state in case one or more of the Requests actually arrived. A client in REQUEST state has never received an initial sequence number from its peer, so the DCCP-Reset's Acknowledgement Number MUST be set to zero. ๐Ÿงน

The client leaves the REQUEST state for PARTOPEN when it receives a DCCP-Response from the server. โœจ

8.1.2. Service Codes

Each DCCP-Request contains a 32-bit Service Code, which identifies the application-level service the client application is trying to connect to. Service Codes should match up with application services and protocols. For example, there might be one Service Code for SIP control connections and another for RTP audio connections. Middleboxes, like firewalls, can use the Service Code to figure out which application is running on a nonstandard port (assuming the DCCP header hasn't been encrypted). ๐Ÿ•ต๏ธโ€โ™€๏ธ

Endpoints MUST associate a Service Code with every DCCP socket, both actively and passively opened. The application will usually supply this Service Code. Each active socket MUST have exactly one Service Code. Passive sockets MAY, at the implementation's discretion, be associated with more than one Service Code. This might let multiple applications, or multiple versions of the same application, listen on the same port, told apart by Service Code. If the DCCP-Request's Service Code doesn't match any of the server's Service Codes for the given port, the server MUST reject the request by sending a DCCP-Reset packet with Reset Code 8, "Bad Service Code". A middlebox MAY also send such a DCCP-Reset in response to packets whose Service Code is considered unsuitable. ๐Ÿšซ

Service Codes aren't meant to be DCCP-specific, and they're allocated by IANA. Following the policies outlined in [RFC2434], most Service Codes are allocated First Come First Served, subject to the following guidelines. ๐Ÿ“‹

  • Service Codes are allocated one at a time, or in small blocks. A short English description of the intended service is REQUIRED to obtain a Service Code assignment, but no specification, standards track or otherwise, is necessary. IANA maintains an association of Service Codes to the corresponding phrases.
  • Users request specific Service Code values. We suggest that users request Service Codes that can be represented using the "SC:" formatting convention described below. So the "Frobodyne Plotz Protocol" might correspond to Service Code 17178548426 or, equivalently, "SC:fdpz". The canonical interpretation of a Service Code field is numeric.
  • Service Codes whose bytes each have values in the set {32, 45-57, 65-90} use a Specification Required allocation policy. That means these Service Codes are used for international standard or standards-track specifications, IETF or otherwise. (This set consists of the ASCII digits, uppercase letters, and the characters space, '-', '.', and '/'.)
  • Service Codes whose high-order byte equals 63 (ASCII '?') are reserved for Private Use.
  • Service Code 0 represents the absence of a meaningful Service Code and MUST NOT be allocated.
  • The value 4294967295 is an invalid Service Code. Servers MUST reject any DCCP-Request with this Service Code value by sending a DCCP-Reset packet with Reset Code 8, "Bad Service Code".

This design for Service Code allocation is based on the allocation of 4-byte identifiers for Macintosh resources, PNG chunks, and TrueType and OpenType tables. Iconic history ๐ŸŽ

In text settings, we recommend that Service Codes be written in one of three forms, prefixed by the ASCII letters SC and either a colon ":" or an equals sign "=". These forms are interpreted as follows. ๐Ÿ’…

SC:     Indicates a Service Code representable using a subset of the
        ASCII characters.  The colon is followed by one to four
        characters taken from the following set: letters, digits, and
        the characters in "-_+.*/?@" (not including quotes).
        Numerically, these characters have values in {42-43, 45-57,
        63-90, 95, 97-122}.  The Service Code is calculated by
        padding the string on the right with spaces (value 32) and
        intepreting the four-character result as a 32-bit big-endian
        number.

SC=     Indicates a decimal Service Code.  The equals sign is
        followed by any number of decimal digits, which specify the
        Service Code.  Values above 4294967294 are illegal.

SC=x or SC=X
        Indicates a hexadecimal Service Code.  The "x" or "X" is
        followed by any number of hexadecimal digits (upper or lower
        case), which specify the Service Code.  Values above
        4294967294 are illegal.

Thus, the Service Code 1717858426 might be represented in text as
either SC:fdpz, SC=1717858426, or SC=x6664707A.

8.1.3. Server Response

In the second phase of the three-way handshake, the server moves from the LISTEN state to RESPOND and sends a DCCP-Response message to the client. In this phase, the server will often specify the features it would like to use, either from among those the client requested or in addition to them. Among these options is the congestion control mechanism the server expects to use. ๐ŸŽ€

The server MAY respond to a DCCP-Request packet with a DCCP-Reset packet to refuse the connection. Relevant Reset Codes for refusing a connection include 7, "Connection Refused", when the DCCP-Request's Destination Port did not correspond to a DCCP port open for listening; 8, "Bad Service Code", when the DCCP-Request's Service Code did not correspond to the service code registered with the Destination Port; and 9, "Too Busy", when the server is currently too busy to respond to requests. The server SHOULD limit the rate at which it generates these resets, for example to not more than 1024 per second. ๐Ÿšฆ

The server SHOULD NOT retransmit DCCP-Response packets. The client will retransmit the DCCP-Request if necessary. (Note that the "retransmitted" DCCP-Request will have, at least, a different sequence number from the "original" DCCP-Request. The server can thus tell true retransmissions apart from network duplicates.) The server will know that the retransmitted DCCP-Request belongs to an existing connection because of its Source and Destination Ports. Every valid DCCP-Request received while the server is in the RESPOND state MUST elicit a new DCCP-Response. Each new DCCP-Response MUST increment the server's Sequence Number by one and MUST include the same application data, if any, as the original DCCP-Response. ๐Ÿ”

The server MUST NOT accept more than one piece of DCCP-Request application data per connection. In particular, the DCCP-Response sent in reply to a retransmitted DCCP-Request with application data SHOULD contain a Data Dropped option, in which the retransmitted DCCP-Request data is reported with Drop Code 0, Protocol Constraints. The original DCCP-Request SHOULD also be reported in the Data Dropped option, either in a Normal Block (if the server accepted the data or there was no data) or in a Drop Code 0 Drop Block (if the server refused the data the first time as well). ๐Ÿ“ฆ

The Data Dropped and Init Cookie options are especially useful for DCCP-Response packets (Sections 11.7 and 8.1.4). ๐Ÿช

The server leaves the RESPOND state for OPEN when it receives a valid DCCP-Ack from the client, which completes the three-way handshake. It MAY also leave the RESPOND state for CLOSED after a timeout of not less than 4MSL (8 minutes). When doing so, it SHOULD send a DCCP-Reset with Reset Code 2, "Aborted", to clean up state at the client. ๐Ÿ‘‘

   +--------+--------+--------+--------+--------+--------
   |00100100| Length |         Init Cookie Value   ...
   +--------+--------+--------+--------+--------+--------
    Type=36

Okay so the Init Cookie option is giving main character server energy ๐Ÿ‘‘. The server doesn't hold ANY state until the three-way handshake is done, kind of like TCP SYN cookies [SYNCOOKIES] ๐Ÿงš. It packs the Service Code, the server port, and any options it cares about from both the DCCP-Request and DCCP-Response into one opaque cookie. Usually that cookie is encrypted with a secret only the server knows, and it has a cryptographic checksum or magic value so the server can verify it decrypted correctly ๐Ÿ”. When the cookie comes back in a response, the server decrypts it and builds all the state it had been skipping. Until then, it doesn't have to leave the LISTEN state ๐Ÿ’….

The Init Cookie option MUST NOT be sent on DCCP-Request or DCCP-Data packets. Any Init Cookie options received on DCCP-Request or DCCP-Data packets, or after the connection has been established (when the connection's state is >= OPEN), MUST be ignored ๐Ÿ™…โ€โ™€๏ธ. The server MAY include Init Cookie options in its DCCP-Response. If it does, then the client MUST echo the same Init Cookie options, in the same order, in each succeeding DCCP packet until one of those packets is acknowledged (showing that the three-way handshake has completed) or the connection is reset ๐Ÿซถ. Because of that, the client MUST NOT use DCCP-Data packets until the three-way handshake completes or the connection is reset ๐Ÿšซ. The Init Cookie options on a client packet MUST equal those received on the DCCP-Request indicated by the client packet's Acknowledgement Number โœ…. The server SHOULD design its Init Cookie format so that Init Cookies can be checked for tampering. It SHOULD respond to a tampered Init Cookie option by resetting the connection with Reset Code 10, "Bad Init Cookie" ๐Ÿšจ.

The exact implementation of Init Cookie doesn't need to be specified here. Since Init Cookies are opaque to the client, there are no interoperability concerns ๐ŸŽ€. An example cookie format might encrypt (using a secret key) the connection's initial sequence and acknowledgement numbers, ports, Service Code, any options included on the DCCP-Request packet and the corresponding DCCP-Response, a random salt, and a magic number โœจ. When the server gets a reflected Init Cookie, it decrypts the cookie and validates it by checking its magic number, sequence numbers, and ports. If it's valid, it creates a corresponding socket using the options ๐Ÿฆ‹.

Each individual Init Cookie option can hold at most 253 bytes of data, but a server can send multiple Init Cookie options to gain more space ๐ŸŒˆ.

8.1.5. Handshake Completion ๐Ÿค

When the client receives a DCCP-Response from the server, it moves from the REQUEST state to PARTOPEN and finishes the three-way handshake by sending a DCCP-Ack packet to the server ๐Ÿ’Œ. The client stays in PARTOPEN until it can be sure that the server has received some packet the client sent from PARTOPEN (either the initial DCCP-Ack or a later packet) ๐Ÿ‘€. Clients in the PARTOPEN state that want to send data MUST do so using DCCP-DataAck packets, not DCCP-Data packets. This is because DCCP-Data packets lack Acknowledgement Numbers, so the server can't tell from a DCCP-Data packet whether the client saw its DCCP-Response ๐Ÿ˜ญ. Also, if the DCCP-Response included an Init Cookie, that Init Cookie MUST be included on every packet sent in PARTOPEN ๐Ÿช.

The single DCCP-Ack sent when entering the PARTOPEN state might, of course, get dropped by the network ๐Ÿ’€. The client SHOULD make sure that some packet gets through eventually. The preferred mechanism is a roughly 200-millisecond timer, set every time a packet is transmitted in PARTOPEN โฐ. If this timer goes off and the client is still in PARTOPEN, the client generates another DCCP-Ack and backs off the timer. If the client remains in PARTOPEN for more than 4MSL (8 minutes), it SHOULD reset the connection with Reset Code 2, "Aborted" ๐Ÿฅ€.

The client leaves the PARTOPEN state for OPEN when it receives a valid packet other than DCCP-Response, DCCP-Reset, or DCCP-Sync from the server ๐ŸŽ‰.

8.2. Data Transfer ๐ŸŒธ

In the main data transfer phase of the connection, both server and client are in the OPEN state ๐Ÿ’–.

DCCP A sends DCCP-Data and DCCP-DataAck packets to DCCP B because of application events on host A. These packets are congestion-controlled by the CCID for the A-to-B half-connection. In contrast, DCCP-Ack packets sent by DCCP A are controlled by the CCID for the B-to-A half-connection. Generally, DCCP A piggybacks acknowledgement information on DCCP-Data packets when that's acceptable, creating DCCP-DataAck packets ๐Ÿ“. DCCP-Ack packets get used when there's no data to send from DCCP A to DCCP B, or when the congestion state of the A-to-B CCID won't allow data to be sent ๐Ÿ™ˆ.

DCCP-Sync and DCCP-SyncAck packets may also show up in the data transfer phase. Some cases that cause DCCP-Sync generation are discussed in Section 7.5. One important difference between DCCP-Sync packets and other packet types is that DCCP-Sync gets an immediate acknowledgement โšก. On receiving a valid DCCP-Sync packet, a DCCP endpoint MUST immediately generate and send a DCCP-SyncAck response (subject to any implementation rate limits). The Acknowledgement Number on that DCCP-SyncAck MUST equal the Sequence Number of the DCCP-Sync ๐Ÿซง.

A particular DCCP implementation might decide to start feature negotiation only once the OPEN state is reached. In that case, it might not allow data transfer until some time later. Data received during that time SHOULD be rejected and reported using a Data Dropped Drop Block with Drop Code 0, Protocol Constraints (see Section 11.7) ๐Ÿšซ.

8.3. Termination ๐Ÿฆ‹

DCCP connection termination uses a handshake made up of an optional DCCP-CloseReq packet, a DCCP-Close packet, and a DCCP-Reset packet. The server moves from the OPEN state, possibly through the CLOSEREQ state, to CLOSED. The client moves from OPEN through CLOSING to TIMEWAIT, and after the 2MSL wait time (4 minutes) it goes to CLOSED ๐Ÿ•ฐ๏ธ.

The sequence DCCP-CloseReq, DCCP-Close, DCCP-Reset is used when the server decides to close the connection but doesn't want to hold TIMEWAIT state:

     Client State                             Server State
        OPEN                                     OPEN
   1.             <--       CloseReq       <--   CLOSEREQ
   2.   CLOSING   -->        Close         -->
   3.             <--        Reset         <--   CLOSED (LISTEN)
   4.   TIMEWAIT
   5.   CLOSED

A shorter sequence happens when the client decides to close the connection:

     Client State                             Server State
        OPEN                                     OPEN
   1.   CLOSING   -->        Close         -->
   2.             <--        Reset         <--   CLOSED (LISTEN)
   3.   TIMEWAIT
   4.   CLOSED

Finally, the server can decide to hold TIMEWAIT state:

     Client State                             Server State
        OPEN                                     OPEN
   1.             <--        Close         <--   CLOSING
   2.   CLOSED    -->        Reset         -->
   3.                                            TIMEWAIT
   4.                                            CLOSED (LISTEN)

In every case, the receiver of the DCCP-Reset packet holds TIMEWAIT state for the connection. Just like TCP, TIMEWAIT state is where an endpoint quietly keeps a socket around for 2MSL (4 minutes) after its connection has closed. That makes sure no new connection with the same source and destination addresses and ports can start up while old packets might still be floating around the network ๐Ÿ‘ป.

The termination handshake goes like this. The receiver of a valid DCCP-CloseReq packet MUST respond with a DCCP-Close packet. The receiver of a valid DCCP-Close packet MUST respond with a DCCP-Reset packet with Reset Code 1, "Closed". The receiver of a valid DCCP-Reset packet (which is also the sender of the DCCP-Close packet, and possibly the receiver of the DCCP-CloseReq packet) will hold TIMEWAIT state for the connection ๐ŸŽ€.

A DCCP-Reset packet completes every DCCP connection, whether the termination is clean (due to application close; Reset Code 1, "Closed") or unclean. Unlike TCP, which has two separate termination mechanisms (FIN and RST), DCCP ends all connections in one uniform way โœจ. That works because some parts of connection termination are the same whether or not it was clean. For instance, the endpoint that receives a valid DCCP-Reset SHOULD hold TIMEWAIT state for the connection. Processors that need to tell clean and unclean termination apart can look at the Reset Code ๐Ÿ”. DCCP implementations generally move to the CLOSED state after sending a DCCP-Reset packet ๐Ÿ’….

Endpoints in the CLOSEREQ and CLOSING states MUST retransmit DCCP-CloseReq and DCCP-Close packets, respectively, until they leave those states ๐Ÿ”. The retransmission timer should start out set to go off in two round-trip times, and should back off to not less than once every 64 seconds if no relevant response comes back โณ.

Only the server can send a DCCP-CloseReq packet or enter the CLOSEREQ state. A server that receives a sequence-valid DCCP-CloseReq packet MUST respond with a DCCP-Sync packet and otherwise ignore the DCCP-CloseReq ๐Ÿ™ƒ.

DCCP-Data, DCCP-DataAck, and DCCP-Ack packets received in CLOSEREQ or CLOSING states MAY be either processed or ignored ๐Ÿคทโ€โ™€๏ธ.

8.3.1. Abnormal Termination ๐Ÿ’ฅ

DCCP endpoints generate DCCP-Reset packets to end connections abnormally. A DCCP-Reset packet may be generated from any state. Resets sent in the CLOSED, LISTEN, and TIMEWAIT states use Reset Code 3, "No Connection", unless otherwise specified. Resets sent in the REQUEST or RESPOND states use Reset Code 4, "Packet Error", unless otherwise specified ๐Ÿงจ.

DCCP endpoints in CLOSED, LISTEN, or TIMEWAIT state may need to generate a DCCP-Reset packet in response to a packet received from a peer. Since these states don't have any sequence number variables tied to them, the Sequence and Acknowledgement Numbers on the DCCP-Reset packet R are taken from the received packet P, like this ๐Ÿชž:

  1. If P.ackno exists, then set R.seqno := P.ackno + 1. Otherwise, set R.seqno := 0.
  2. Set R.ackno := P.seqno.
  3. If the packet used short sequence numbers (P.X == 0), then set the upper 24 bits of R.seqno and R.ackno to 0.

8.4. DCCP State Diagram โœจ

okay so this diagram is basically the highlight reel of everything we just covered ๐Ÿ’… it's illustrative, which means it's a vibe check and not the official rulebook. Section 8.5 and the rest of the text are the definitive ones bestie ๐Ÿซถ also heads up, there are arcs (not shown!) from literally every state except CLOSED over to TIMEWAIT, but only when a valid DCCP-Reset shows up ๐Ÿ’€

   +---------------------------+    +---------------------------+
   |                           v    v                           |
   |                        +----------+                        |
   |          +-------------+  CLOSED  +------------+           |
   |          | passive     +----------+  active    |           |
   |          |  open                      open     |           |
   |          |                         snd Request |           |
   |          v                                     v           |
   |     +----------+                          +----------+     |
   |     |  LISTEN  |                          | REQUEST  |     |
   |     +----+-----+                          +----+-----+     |
   |          | rcv Request            rcv Response |           |
   |          | snd Response             snd Ack    |           |
   |          v                                     v           |
   |     +----------+                          +----------+     |
   |     | RESPOND  |                          | PARTOPEN |     |
   |     +----+-----+                          +----+-----+     |
   |          | rcv Ack/DataAck         rcv packet  |           |
   |          |                                     |           |
   |          |             +----------+            |           |
   |          +------------>|   OPEN   |<-----------+           |
   |                        +--+-+--+--+                        |
   |       server active close | |  |   active close            |
   |           snd CloseReq    | |  | or rcv CloseReq           |
   |                           | |  |    snd Close              |
   |                           | |  |                           |
   |     +----------+          | |  |          +----------+     |
   |     | CLOSEREQ |<---------+ |  +--------->| CLOSING  |     |
   |     +----+-----+            |             +----+-----+     |
   |          | rcv Close        |        rcv Reset |           |
   |          | snd Reset        |                  |           |
   |<---------+                  |                  v           |
   |                             |             +----+-----+     |
   |                   rcv Close |             | TIMEWAIT |     |
   |                   snd Reset |             +----+-----+     |
   +-----------------------------+                  |           |
                                                    +-----------+
                                                 2MSL timer expires

8.5. Pseudocode โœจ

okay now the pseudocode ๐Ÿงš this section walks through the steps a DCCP endpoint must go through the moment a packet lands. real talk, your implementation doesn't have to copy this algorithm word for word ๐Ÿ™ˆ BUT any implementation MUST generate observable effects exactly as this pseudocode says, unless another part of this document says otherwise. no cap, that's main character energy ๐Ÿ‘‘

here's the cast of characters first ๐ŸŽ€

The received packet is written as P, the socket as S.  Socket
variables are:

S.SWL - sequence number window low
S.SWH - sequence number window high
S.AWL - acknowledgement number window low
S.AWH - acknowledgement number window high
S.ISS - initial sequence number sent
S.ISR - initial sequence number received
S.OSR - first OPEN sequence number received
S.GSS - greatest sequence number sent
S.GSR - greatest valid sequence number received
S.GAR - greatest valid acknowledgement number received on a
        non-Sync; initialized to S.ISS
"Send packet" actions always use, and increment, S.GSS.

and now the steps, bestie ๐Ÿ’– it's a whole checklist so grab a snack ๐Ÿ“

Step 1: Check header basics
   /* This step checks for malformed packets.  Packets that fail
      these checks are ignored -- they do not receive Resets in
      response */
   If the packet is shorter than 12 bytes, drop packet and return
   If P.type is not understood, drop packet and return
   If P.Data Offset is smaller than the given packet type's
         fixed header length or larger than the packet's length,
         drop packet and return
   If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet
         has short sequence numbers), drop packet and return
   If the header checksum is incorrect, drop packet and return
   If P.CsCov is too large for the packet size, drop packet and
         return

Step 2: Check ports and process TIMEWAIT state
   /* Flow ID is <src addr, src port, dst addr, dst port> 4-tuple */
   Look up flow ID in table and get corresponding socket
   If no socket, or S.state == TIMEWAIT,
      /* The following Reset's Sequence and Acknowledgement Numbers
         are taken from the input packet; see Section 8.3.1. */
      Generate Reset(No Connection) unless P.type == Reset
      Drop packet and return

Step 3: Process LISTEN state
   If S.state == LISTEN,
      If P.type == Request or P contains a valid Init Cookie option,
         /* Must scan the packet's options to check for Init
            Cookies.  Only Init Cookies are processed here,
            however; other options are processed in Step 8.  This
            scan need only be performed if the endpoint uses Init
            Cookies */
         /* Generate a new socket and switch to that socket */
         Set S := new socket for this port pair
         S.state = RESPOND
         Choose S.ISS (initial seqno) or set from Init Cookies
         Initialize S.GAR := S.ISS
         Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
         Continue with S.state == RESPOND
         /* A Response packet will be generated in Step 11 */
      Otherwise,
         Generate Reset(No Connection) unless P.type == Reset
         Drop packet and return

Step 4: Prepare sequence numbers in REQUEST
   If S.state == REQUEST,
      If (P.type == Response or P.type == Reset)
            and S.AWL <= P.ackno <= S.AWH,
         /* Set sequence number variables corresponding to the
            other endpoint, so P will pass the tests in Step 6 */
         Set S.GSR, S.ISR, S.SWL, S.SWH
         /* Response processing continues in Step 10; Reset
            processing continues in Step 9 */
      Otherwise,
         /* Only Response and Reset are valid in REQUEST state */
         Generate Reset(Packet Error)
         Drop packet and return

Step 5: Prepare sequence numbers for Sync
   If P.type == Sync or P.type == SyncAck,
      If S.AWL <= P.ackno <= S.AWH and P.seqno >= S.SWL,
         /* P is valid, so update sequence number variables
            accordingly.  After this update, P will pass the tests
            in Step 6.  A SyncAck is generated if necessary in
            Step 15 */
         Update S.GSR, S.SWL, S.SWH
      Otherwise,
         Drop packet and return

Step 6: Check sequence numbers
   If P.X == 0 and the relevant Allow Short Seqnos feature is 0,
      /* Packet has short seqnos, but short seqnos not allowed */
      Drop packet and return
   Otherwise, if P.X == 0,
      Extend P.seqno and P.ackno to 48 bits using the procedure
      in Section 7.6
   Let LSWL = S.SWL and LAWL = S.AWL
   If P.type == CloseReq or P.type == Close or P.type == Reset,
      LSWL := S.GSR + 1, LAWL := S.GAR
   If LSWL <= P.seqno <= S.SWH
         and (P.ackno does not exist or LAWL <= P.ackno <= S.AWH),
      Update S.GSR, S.SWL, S.SWH
      If P.type != Sync,
         Update S.GAR
   Otherwise,
      If P.type == Reset,
         Send Sync packet acknowledging S.GSR
      Otherwise,
         Send Sync packet acknowledging P.seqno
      Drop packet and return

Step 7: Check for unexpected packet types
   If (S.is_server and P.type == CloseReq)
        or (S.is_server and P.type == Response)
        or (S.is_client and P.type == Request)
        or (S.state >= OPEN and P.type == Request
            and P.seqno >= S.OSR)
        or (S.state >= OPEN and P.type == Response
            and P.seqno >= S.OSR)
        or (S.state == RESPOND and P.type == Data),
      Send Sync packet acknowledging P.seqno
      Drop packet and return

Step 8: Process options and mark acknowledgeable
   /* Option processing is not specifically described here.
      Certain options, such as Mandatory, may cause the connection
      to be reset, in which case Steps 9 and on are not executed */
   Mark packet as acknowledgeable (in Ack Vector terms, Received
        or Received ECN Marked)

Step 9: Process Reset
   If P.type == Reset,
      Tear down connection
      S.state := TIMEWAIT
      Set TIMEWAIT timer
      Drop packet and return

Step 10: Process REQUEST state (second part)
   If S.state == REQUEST,
      /* If we get here, P is a valid Response from the server (see
         Step 4), and we should move to PARTOPEN state.  PARTOPEN
         means send an Ack, don't send Data packets, retransmit
         Acks periodically, and always include any Init Cookie from
         the Response */
      S.state := PARTOPEN
      Set PARTOPEN timer
      Continue with S.state == PARTOPEN
      /* Step 12 will send the Ack completing the three-way
         handshake */

Step 11: Process RESPOND state
   If S.state == RESPOND,
      If P.type == Request,
         Send Response, possibly containing Init Cookie
         If Init Cookie was sent,
            Destroy S and return
            /* Step 3 will create another socket when the client
               completes the three-way handshake */
      Otherwise,
         S.OSR := P.seqno
         S.state := OPEN

Step 12: Process PARTOPEN state
   If S.state == PARTOPEN,
      If P.type == Response,
         Send Ack
      Otherwise, if P.type != Sync,
         S.OSR := P.seqno
         S.state := OPEN

Step 13: Process CloseReq
   If P.type == CloseReq and S.state < CLOSEREQ,
      Generate Close
      S.state := CLOSING
      Set CLOSING timer

Step 14: Process Close
   If P.type == Close,
      Generate Reset(Closed)
      Tear down connection
      Drop packet and return

Step 15: Process Sync
   If P.type == Sync,
      Generate SyncAck

Step 16: Process data
   /* At this point any application data on P can be passed to the
      application, except that the application MUST NOT receive
      data from more than one Request or Response */

9. Checksums โœจ

okay so DCCP uses a header checksum to protect its header from corruption ๐Ÿ›ก๏ธ and, generally, this checksum also covers any application data ๐Ÿ’…. BUT DCCP apps can ask for the header checksum to cover only part of the application data, or maybe none of it at all ๐Ÿฆ‹. Then link layers are allowed to ease up on protecting the unprotected parts of DCCP packets. For some noisy links, and for apps that can handle a little corruption, this can seriously boost delivery rates and perceived performance ๐Ÿš€. Main character energy, fr.

Checksum coverage may eventually affect congestion control too ๐Ÿ‘€. A packet with corrupt application data and complete checksum coverage gets treated as lost. That triggers a heavy-duty loss response from the sender's congestion control, which can unfairly punish connections on links with high background corruption ๐Ÿ˜ญ. The combo of reduced checksum coverage and Data Checksum options may let endpoints report packets as corrupt instead of dropped, using Data Dropped options and Drop Code 3 (see Section 11.7) ๐ŸŽ€. This may eventually help apps. However, more research is needed to figure out the right response to corruption, since it can sometimes correlate with congestion ๐Ÿค”. Right now, corrupt packets still get a loss response ๐Ÿ’€.

The Data Checksum option, which holds a strong CRC, lets endpoints detect application data corruption โœจ. An API can then be used to keep corrupt data away from the app, even if links hand corrupt data to the endpoint because of reduced checksum coverage ๐Ÿซถ. BUT reduced checksum coverage for apps that demand correct data is currently considered experimental ๐Ÿงช. That's because the combined loss-plus-corruption rate for packets with reduced checksum coverage may be way higher than for packets with full coverage, although the loss rate will generally be lower. Actual behavior depends on link design, so further research and experience is required.

Reduced checksum coverage brings some security considerations, so check out Section 18.1 ๐Ÿ”. See Appendix B for more motivation and discussion. DCCP's version of reduced checksum coverage was inspired by UDP-Lite [RFC3828] ๐Ÿ’œ.


9.1. Header Checksum Field

DCCP uses the TCP/IP checksum algorithm ๐Ÿงฎ. The Checksum field in the DCCP generic header (see Section 5.1) equals the 16-bit one's complement of the one's complement sum of all 16-bit words in the DCCP header, DCCP options, a pseudoheader taken from the network-layer header, and, depending on the value of the Checksum Coverage field, some or all of the application data. When calculating the checksum, the Checksum field itself is treated as 0. If a packet contains an odd number of header and payload bytes to be checksummed, 8 zero bits are added on the right to form a 16-bit word for checksum purposes. The pad byte is NOT transmitted as part of the packet, so it's just a math trick, bestie ๐Ÿ™ˆ.

The pseudoheader is calculated the same way as it is for TCP ๐ŸŒธ. For IPv4, it's 96 bits long and consists of the IPv4 source and destination addresses, the IP protocol number for DCCP (padded on the left with 8 zero bits), and the DCCP length as a 16-bit quantity (the length of the DCCP header with options, plus the length of any data). See [RFC793], Section 3.1. For IPv6, it's 320 bits long and consists of the IPv6 source and destination addresses, the DCCP length as a 32-bit quantity, and the IP protocol number for DCCP (padded on the left with 24 zero bits). See [RFC2460], Section 8.1.

Packets with invalid header checksums MUST be ignored. In particular, their options MUST NOT be processed. no notes, that's the rule ๐Ÿšซ.


9.2. Header Checksum Coverage Field

The Checksum Coverage field in the DCCP generic header (see Section 5.1) specifies what parts of the packet are covered by the Checksum field, as follows ๐Ÿ“:

CsCov = 0      The Checksum field covers the DCCP header, DCCP
               options, network-layer pseudoheader, and all
               application data in the packet, possibly padded on the
               right with zeros to an even number of bytes.

CsCov = 1-15   The Checksum field covers the DCCP header, DCCP
               options, network-layer pseudoheader, and the initial
               (CsCov-1)*4 bytes of the packet's application data.

So, if CsCov is 1, none of the application data is protected by the header checksum ๐Ÿ˜ฌ. The value (CsCov-1)*4 MUST be less than or equal to the length of the application data. Packets with invalid CsCov values MUST be ignored; in particular, their options MUST NOT be processed. The meanings of values other than 0 and 1 should be considered experimental ๐Ÿงช.

Values other than 0 mean corruption is acceptable in some or all of the DCCP packet's application data ๐Ÿซฃ. Honestly, DCCP can't even detect corruption in areas outside the header checksum unless the Data Checksum option is used. Apps should not make any assumptions about the correctness of received data that isn't covered by the checksum and should, if necessary, add their own validity checks. Trust but verify, babe ๐Ÿ’….

A DCCP application interface should let sending apps suggest a value for CsCov for sent packets, defaulting to 0 (full coverage) ๐ŸŽ€. The Minimum Checksum Coverage feature, described below, lets an endpoint refuse delivery of application data on packets with partial checksum coverage. By default, only fully covered application data is accepted. Lower layers that support partial error detection MAY use the Checksum Coverage field as a hint of where errors do not need to be detected. Lower layers MUST use a strong error detection mechanism to detect at least errors that occur in the sensitive part of the packet, and to discard damaged packets. The sensitive part consists of the bytes between the first byte of the IP header and the last byte identified by Checksum Coverage.

For more details on application and lower-layer interface issues relating to partial checksumming, see [RFC3828] ๐Ÿ“š.

9.2.1. Minimum Checksum Coverage Feature

The Minimum Checksum Coverage feature lets a DCCP endpoint figure out whether its peer is willing to accept packets with reduced Checksum Coverage ๐Ÿฆ‹. For example, DCCP A sends a "Change R(Minimum Checksum Coverage, 1)" option to DCCP B to check whether B is willing to accept packets with Checksum Coverage set to 1.

Minimum Checksum Coverage has feature number 8 and is server-priority. It takes one-byte integer values between 0 and 15; values of 16 or more are reserved. Minimum Checksum Coverage/B reflects values of Checksum Coverage that DCCP B finds unacceptable. Say that the value of Minimum Checksum Coverage/B is MinCsCov. Then:

  • If MinCsCov = 0, then DCCP B only finds packets with CsCov = 0 acceptable.
  • If MinCsCov > 0, then DCCP B additionally finds packets with CsCov >= MinCsCov acceptable.

DCCP B MAY refuse to process application data from packets with unacceptable Checksum Coverage ๐Ÿ™…โ€โ™€๏ธ. Such packets SHOULD be reported using Data Dropped options (Section 11.7) with Drop Code 0, Protocol Constraints. New connections start with Minimum Checksum Coverage 0 for both endpoints ๐ŸŒˆ.


9.3. Data Checksum Option

The Data Checksum option holds a 32-bit CRC-32c cyclic redundancy-check code of a DCCP packet's application data ๐Ÿง .

+--------+--------+--------+--------+--------+--------+
|00101100|00000110|              CRC-32c              |
+--------+--------+--------+--------+--------+--------+
 Type=44  Length=6

The sending DCCP computes the CRC of the bytes that make up the application data area and stores it in the option data. The CRC-32c algorithm used for Data Checksum is the same one used for SCTP [RFC3309]. Note that the CRC-32c of zero bytes of data equals zero ๐Ÿค“. The DCCP header checksum will cover the Data Checksum option, so the data checksum must be computed before the header checksum. ordering matters, babe โญ.

A DCCP endpoint receiving a packet with a Data Checksum option either MUST or MAY check the Data Checksum. The choice depends on the value of the Check Data Checksum feature described below. If it checks the checksum, it computes the received application data's CRC-32c using the same algorithm as the sender, then compares the result with the Data Checksum value. If the CRCs differ, the endpoint reacts in one of two ways ๐Ÿ‘€:

  • The receiving application may have requested delivery of known-corrupt data via some optional API. In this case, the packet's data MUST be delivered to the application, with a note that it is known to be corrupt. Furthermore, the receiving endpoint MUST report the packet as delivered corrupt using a Data Dropped option (Drop Code 7, Delivered Corrupt).
  • Otherwise, the receiving endpoint MUST drop the application data and report that data as dropped due to corruption using a Data Dropped option (Drop Code 3, Corrupt).

In either case, the packet is considered acknowledgeable (since its header was processed) and will therefore be acknowledged using the equivalent of Ack Vector's Received or Received ECN Marked states ๐Ÿซถ.

Although Data Checksum is intended for packets containing application data, it may be included on other packets, such as DCCP-Ack, DCCP-Sync, and DCCP-SyncAck. The receiver SHOULD calculate the application data area's CRC-32c on such packets, just as it does for DCCP-Data and similar packets. If the CRCs differ, the packets similarly MUST be reported using Data Dropped options (Drop Code 3), although their application data areas would not be delivered to the application in any case ๐Ÿ’–.

9.3.1. Check Data Checksum Feature

The Check Data Checksum feature lets a DCCP endpoint figure out whether its peer will DEFINITELY check Data Checksum options ๐Ÿ”ฅ. DCCP A sends a Mandatory "Change R(Check Data Checksum, 1)" option to DCCP B to require it to check Data Checksum options (the connection will be reset if it can't).

Check Data Checksum has feature number 9 and is server-priority. It takes one-byte Boolean values. DCCP B MUST check any received Data Checksum options when Check Data Checksum/B is one, although it MAY check them even when Check Data Checksum/B is zero. Values of two or more are reserved. New connections start with Check Data Checksum 0 for both endpoints ๐Ÿฌ.

9.3.2. Checksum Usage Notes

Internet links must normally apply strong integrity checks to the packets they transmit [RFC3828, RFC3819] ๐Ÿ”’. This is the default case when the DCCP header's Checksum Coverage value equals zero (full coverage). However, the DCCP Checksum Coverage value might not be zero. By setting partial Checksum Coverage, the application indicates that it can tolerate corruption in the unprotected part of the application data. Recognizing this, link layers may reduce error detection and/or correction strength when transmitting this unprotected part. This, in turn, can significantly increase the likelihood of the endpoint receiving corrupt data. Data Checksum lets the receiver detect that corruption with very high probability ๐ŸŽฏ.

10. Congestion Control ๐Ÿ’…

Okay bestie, so every congestion control mechanism DCCP supports gets its own CCID (congestion control identifier) ๐Ÿฆ‹, which is just a number from 0 to 255. During connection setup, and optionally later on, the endpoints negotiate which mechanisms they'll use by negotiating their Congestion Control ID features. Congestion Control ID is feature number 1. The CCID/A value equals the CCID in use for the A-to-B half-connection. If DCCP B wants DCCP A to switch to CCID K for its data packets, B sends a "Change R(CCID, K)" option. Iconic behavior, honestly ๐Ÿซถ

CCID is a server-priority feature, so CCID negotiation options can list several acceptable CCIDs, sorted from most to least preferred. For example, the option "Change R(CCID, 2 3 4)" asks the receiver to use CCID 2 for its packets, but CCIDs 3 and 4 are also fine. (In bytes that's "35, 6, 1, 2, 3, 4": Change R option (35), option length (6), feature ID (1), CCIDs (2, 3, 4).) Similarly, "Confirm L(CCID, 2, 2 3 4)" tells the receiver that the sender is using CCID 2 for its packets, but that CCIDs 3 and 4 might also work. Main character energy ๐Ÿ‘‘

Here are the CCIDs that are currently allocated:

        CCID   Meaning                      Reference
        ----   -------                      ---------
         0-1   Reserved
          2    TCP-like Congestion Control  [RFC4341]
          3    TCP-Friendly Rate Control    [RFC4342]
        4-255  Reserved

        Table 5: DCCP Congestion Control Identifiers

New connections start with CCID 2 for both endpoints. โœจ If that's unacceptable for a DCCP endpoint, that endpoint MUST send Mandatory Change(CCID) options on its first packets.

Every CCID that gets standardized for DCCP will match a congestion control mechanism the IETF already standardized ๐Ÿ“ We expect that for quite a while, all of them will be TCP friendly, but being TCP-friendly is not an explicit DCCP requirement. Not a rule, just a vibe.

A DCCP implementation meant for general use, like one in a general-purpose operating system kernel, SHOULD implement at least CCID 2. The goal is to make CCID 2 widely available for interoperability, though particular applications might disallow it. ๐ŸŒˆ

10.1. TCP-like Congestion Control

CCID 2, TCP-like Congestion Control, means Additive Increase, Multiplicative Decrease (AIMD) congestion control, with behavior modeled directly on TCP. That includes the congestion window, slow start, timeouts, and so on [RFC2581]. CCID 2 gets maximum bandwidth over the long term, which fits with end-to-end congestion control, but it halves its congestion window after every congestion event. That's where the abrupt rate changes typical of TCP come from ๐Ÿ˜ญ Applications should use CCID 2 if they'd rather have maximum bandwidth utilization than a steady rate. This is often the case for apps that aren't playing their data directly to the user.

For example, imagine a hypothetical app that transfers files over DCCP and handles lost packets with its own application-level retransmissions. It would prefer CCID 2 over CCID 3. ๐Ÿ’– On-line games may also prefer CCID 2.

CCID 2 is described further in [RFC4341].

10.2. TFRC Congestion Control

CCID 3 is TCP-Friendly Rate Control (TFRC) ๐Ÿงš, an equation-based, rate-controlled congestion control mechanism. TFRC is designed to be reasonably fair when it competes for bandwidth with TCP-like flows. A flow counts as "reasonably fair" if its sending rate is generally within a factor of two of the sending rate of a TCP flow under the same conditions. The big perk is that TFRC's throughput varies way less over time than TCP's does, which makes CCID 3 a better pick than CCID 2 for things like streaming media, where a fairly smooth sending rate really matters ๐ŸŽ€

CCID 3 is described further in [RFC4342]. The TFRC congestion control algorithms were first described in [RFC3448].

10.3. CCID-Specific Options, Features, and Reset Codes

Half of the option types, feature numbers, and Reset Codes are reserved for CCID-specific use. โœจ CCIDs often need new options, for example to communicate acknowledgement or rate information. Reserved option spaces let CCIDs make their own options without cluttering the global option space. So option 128 could mean one thing on a half-connection using CCID 4 and something totally different on one using CCID 8. Chaotic but make it organized ๐Ÿ™ˆ CCID-specific options and features will never conflict with global options and features added by later versions of this specification.

Any packet can carry information meant for either half-connection, so CCID-specific option types, feature numbers, and Reset Codes explicitly say which half-connection they apply to:

  • Option numbers 128 through 191 are for options sent from the HC-Sender to the HC-Receiver. Option numbers 192 through 255 are for options sent from the HC-Receiver to the HC-Sender.
  • Reset Codes 128 through 191 mean the HC-Sender reset the connection (most likely because of some problem with acknowledgements sent by the HC-Receiver). Reset Codes 192 through 255 mean the HC-Receiver reset the connection (most likely because of some problem with data packets sent by the HC-Sender).
  • Feature numbers 128 through 191 are for features located at the HC-Sender. Feature numbers 192 through 255 are for features located at the HC-Receiver. Change L and Confirm L options for a feature are sent by the feature's location, so any Change L(128) option came from the HC-Sender, while any Change L(192) option came from the HC-Receiver. Similarly, Change R(128) options are sent by the HC-Receiver, and Change R(192) options are sent by the HC-Sender.

Let's look at an example: a DCCP connection where the A-to-B half-connection uses CCID 4 and the B-to-A half-connection uses CCID 5. Here's how a sampling of CCID-specific options gets assigned to half-connections:

                             Relevant    Relevant
  Packet  Option             Half-conn.  CCID
  ------  ------             ----------  ----
  A > B   128                  A-to-B     4
  A > B   192                  B-to-A     5
  A > B   Change L(128, ...)   A-to-B     4
  A > B   Change R(192, ...)   A-to-B     4
  A > B   Confirm L(128, ...)  A-to-B     4
  A > B   Confirm R(192, ...)  A-to-B     4
  A > B   Change R(128, ...)   B-to-A     5
  A > B   Change L(192, ...)   B-to-A     5
  A > B   Confirm R(128, ...)  B-to-A     5
  A > B   Confirm L(192, ...)  B-to-A     5
  B > A   128                  B-to-A     5
  B > A   192                  A-to-B     4
  B > A   Change L(128, ...)   B-to-A     5
  B > A   Change R(192, ...)   B-to-A     5
  B > A   Confirm L(128, ...)  B-to-A     5
  B > A   Confirm R(192, ...)  B-to-A     5
  B > A   Change R(128, ...)   A-to-B     4
  B > A   Change L(192, ...)   A-to-B     4
  B > A   Confirm R(128, ...)  A-to-B     4
  B > A   Confirm L(192, ...)  A-to-B     4

Using CCID-specific options and feature options during negotiation for the matching CCID feature is NOT RECOMMENDED ๐Ÿ™…โ€โ™€๏ธ It's hard to predict which CCID will be in force when the option gets processed. For example, if a DCCP-Request contains the option sequence "Change L(CCID, 3), 128", the CCID-specific option "128" might be processed by CCID 3 (if the server supports CCID 3) or by the default CCID 2 (if it doesn't). It IS safe to include CCID-specific options after certain Mandatory Change(CCID) options, though. For example, if a DCCP-Request contains "Mandatory, Change L(CCID, 3), 128", then either the "128" option gets processed by CCID 3, or the connection gets reset. Clean and predictable ๐Ÿ’œ

Servers that don't implement the default CCID 2 might still receive CCID 2-specific options on a DCCP-Request packet. (Such a server MUST send Mandatory Change(CCID) options on its DCCP-Response, so CCID-specific options on any other packet won't refer to CCID 2.) The server MUST treat such options as non-understood. So it will reset the connection when it hits a Mandatory CCID-specific option or feature negotiation request, send an empty Confirm for a non-Mandatory Change option for a CCID-specific feature, and ignore any other CCID-specific options. ๐Ÿฆ‹

10.4. CCID Profile Requirements

Each CCID Profile document MUST address at least the following requirements:

  • The profile MUST include the name and number of the CCID being described.
  • The profile MUST describe the conditions in which it is likely to be useful. Often the best way to do this is by comparing it to existing CCIDs.
  • The profile MUST list and describe any CCID-specific options, features, and Reset Codes, and SHOULD list those general options and features described in this document that are especially relevant to the CCID.
  • Any newly defined acknowledgement mechanism MUST include a way to transmit ECN Nonce Echoes back to the sender. ๐ŸŒธ
  • The profile MUST describe the format of data packets, including any options that should be included and the setting of the CCval header field.
  • The profile MUST describe the format of acknowledgement packets, including any options that should be included.
  • The profile MUST define how data packets are congestion controlled. This includes responses to congestion events, to idle and application-limited periods, and to the DCCP Data Dropped and Slow Receiver options. CCIDs that implement per-packet congestion control SHOULD discuss how packet size factors into congestion control decisions.
  • The profile MUST specify when acknowledgement packets are generated and how they are congestion controlled.
  • The profile MUST define when a sender using the CCID is considered quiescent.
  • The profile MUST say whether its CCID's acknowledgements ever need to be acknowledged and, if so, how often.

10.5. Congestion State โœจ

Okay bestie, most congestion control algorithms look at the past to figure out how fast they're allowed to send right now ๐Ÿ•ฐ๏ธ. In CCID 2, that memory is a congestion window plus a count of how many packets are still floating around in the network. In CCID 3, it's the lengths of recent loss intervals. Both CCIDs also keep an estimate of the round-trip time ๐ŸŒธ.

But here's the tea ๐Ÿซ–: congestion state depends on the network path, so it becomes invalid whenever the path changes ๐Ÿ˜ญ. That's why DCCP senders and receivers SHOULD reset their congestion state (basically restart congestion control from "slow start" or something equivalent ๐Ÿ”„) on significant changes in the end-to-end path. For example, an endpoint that sends or receives a Mobile IPv6 Binding Update message [RFC3775] SHOULD reset its congestion state for any corresponding DCCP connections ๐Ÿฆ‹.

A DCCP implementation MAY also reset its congestion state when a CCID changes (that is, when a negotiation for the CCID feature completes successfully and the new feature value differs from the old value) ๐Ÿ’…. Now, a connection in a heavily congested environment could try to dodge end-to-end congestion control by renegotiating its CCID over and over, the same way it could dodge it by opening new connections for the same session. Not meโ€ฆ this behavior is prohibited ๐Ÿ™…โ€โ™€๏ธ. To stop it, DCCP implementations MAY limit the rate at which CCID can be changed, for instance by refusing to change a CCID feature value more than once per minute โณ.


11. Acknowledgements ๐ŸŽ€

Congestion control needs receivers to send information about packet losses and ECN marks back to senders ๐Ÿ“ฌ. DCCP receivers MUST report all congestion they see, as defined by the relevant CCID profile. Each CCID says when acknowledgements should be sent, what options they must use, and so on ๐Ÿ“‹. DCCP acknowledgements are congestion controlled too, although the acknowledgement stream doesn't have to be more than very roughly TCP friendly ๐ŸŒˆ. Each CCID defines how its acknowledgements are congestion controlled.

Most acknowledgements ride along in DCCP options. For example, on a half-connection with CCID 2 (TCP-like), the receiver reports acknowledgement information using the Ack Vector option ๐Ÿงš. This section covers the common acknowledgement options and shows how acks using them usually work. The full descriptions of the ack mechanisms for each CCID live in the CCID profile specifications ๐Ÿ“š.

Acknowledgement options, like Ack Vector, depend on the DCCP Acknowledgement Number, so they're only allowed on packet types that carry that number ๐Ÿ”. Acknowledgement options received on other packet types, namely DCCP-Request and DCCP-Data, MUST be ignored ๐Ÿ™ˆ. Detailed acknowledgement options aren't necessarily required on every packet that carries an Acknowledgement Number, though ๐Ÿคทโ€โ™€๏ธ.

11.1. Acks of Acks and Unidirectional Connections ๐Ÿ”

DCCP was built to work well for both bidirectional and unidirectional flows of data, and for connections that switch between the two ๐Ÿ’œ. But the acknowledgements a unidirectional connection needs are very different from the ones a bidirectional connection needs. Specifically, unidirectional connections have to worry about acks of acks ๐Ÿ˜ณ.

The ack-of-acks problem shows up because some acknowledgement mechanisms are reliable. For example, an HC-Receiver using CCID 2, TCP-like Congestion Control, sends Ack Vectors containing completely reliable acknowledgement information ๐Ÿ’ฏ. The HC-Sender should occasionally tell the HC-Receiver that it got an ack. If it didn't, the HC-Receiver might keep resending the complete Ack Vector information, going all the way back to the start of the connection, with every DCCP-Ack packet! ๐Ÿ˜ฑ Note though that acks-of-acks don't need to be reliable themselves: if an ack-of-acks gets lost, the HC-Receiver will just keep old acknowledgement-related state around a little longer and retransmit it periodically ๐Ÿซ . So there's no need for acks-of-acks-of-acks ๐Ÿ™…โ€โ™€๏ธ.

When communication is bidirectional, any required acks-of-acks ride automatically inside normal acknowledgements for data packets ๐Ÿ’–. On a unidirectional connection, though, the receiving DCCP sends no data, so the sender wouldn't normally send acknowledgements at all ๐Ÿ‘€. That means the CCID in force on that half-connection has to explicitly say whether, when, and how the HC-Sender should generate acks-of-acks.

For example, picture a bidirectional connection where both half-connections use the same CCID (either 2 or 3), and where DCCP B goes "quiescent" ๐Ÿ˜ด. This means the connection turns unidirectional:

DCCP B stops sending data and sends only DCCP-Ack packets to DCCP A. In CCID 2, TCP-like Congestion Control, DCCP B uses Ack Vector to reliably communicate which packets it has received ๐Ÿ“ฆ. As described above, DCCP A must occasionally acknowledge a pure acknowledgement from DCCP B so that B can free old Ack Vector state. For instance, A might send a DCCP-DataAck packet instead of DCCP-Data every now and then ๐ŸŽ. In CCID 3, however, acknowledgement state is generally bounded, so A doesn't need to acknowledge B's acknowledgements ๐ŸŒŸ.

When communication is unidirectional, a single CCID (in the example, the A-to-B CCID) controls both DCCPs' acknowledgements, in terms of their content, their frequency, and so forth ๐ŸŽ›๏ธ. For bidirectional connections, the A-to-B CCID governs DCCP B's acknowledgements (including its acks of DCCP A's acks), and the B-to-A CCID governs DCCP A's acknowledgements ๐Ÿงฉ.

DCCP A switches its ack pattern from bidirectional to unidirectional when it notices that DCCP B has gone quiescent ๐ŸŒ™. It switches back from unidirectional to bidirectional when it has to acknowledge even a single DCCP-Data or DCCP-DataAck packet from DCCP B ๐Ÿ”„.

Each CCID defines how to detect quiescence on that CCID, and how that CCID handles acks-of-acks on unidirectional connections ๐Ÿ•ต๏ธโ€โ™€๏ธ. The B-to-A CCID defines when DCCP B has gone quiescent. Usually this happens when a period passes without B sending any data packets. In CCID 2, for example, that period is the maximum of 0.2 seconds and two round-trip times โฑ๏ธ. The A-to-B CCID defines how DCCP A handles acks-of-acks once DCCP B has gone quiescent ๐Ÿ‘‘.

11.2. Ack Piggybacking ๐Ÿท

Acknowledgements of A-to-B data MAY be piggybacked on data sent by DCCP B, as long as that doesn't delay the acknowledgement longer than the A-to-B CCID would find acceptable ๐Ÿฅฐ. However, data acknowledgements often need more than 4 bytes to express. A big set of acknowledgements prepended to a big data packet might go over the allowed maximum packet size ๐Ÿ˜ฌ. In this case, DCCP B SHOULD send separate DCCP-Data and DCCP-Ack packets, or wait, but not too long, for a smaller datagram โณ.

Piggybacking is especially common at DCCP A when the B-to-A half-connection is quiescent, that is, when DCCP A is just acknowledging DCCP B's acknowledgements ๐Ÿซถ. There are three reasons to acknowledge DCCP B's acknowledgements: to let DCCP B free up information about previously acknowledged data packets from A, to shrink the size of future acknowledgements, and to manipulate the rate at which future acknowledgements are sent ๐ŸŽฏ. Since those are secondary concerns, DCCP A can generally afford to wait indefinitely for a data packet to piggyback its acknowledgement onto. If DCCP B wants to force an acknowledgement, it can send a DCCP-Sync ๐Ÿงšโ€โ™€๏ธ.

Any restrictions on ack piggybacking are described in the relevant CCID's profile ๐Ÿ’Œ.

11.3. Ack Ratio Feature โœจ

Okay bestie, so the Ack Ratio feature lets HC-Senders influence how often HC-Receivers generate DCCP-Ack packets ๐Ÿ’…, which means it's how you control congestion on the reverse path ๐Ÿฆ‹. This is different from TCP, which currently has no congestion control for pure acknowledgement traffic ๐Ÿ˜ญ. Ack Ratio reverse-path congestion control isn't trying to be TCP friendly, no cap ๐Ÿ™ˆ. It just wants to avoid congestion collapse, and to be somewhat better than TCP when there's a high packet loss or mark rate on the reverse path ๐Ÿซถ.

Ack Ratio applies to CCIDs whose HC-Receivers clock acknowledgements off the receipt of data packets ๐ŸŒธ. The value of Ack Ratio/A is the rough ratio of data packets sent by DCCP A to DCCP-Ack packets sent by DCCP B ๐ŸŽ€. Higher Ack Ratios mean lower DCCP-Ack rates, so the sender raises Ack Ratio when the reverse path is congested and lowers it when it isn't โœจ. Each CCID profile defines how it controls congestion on the acknowledgement path, and in particular whether Ack Ratio is used at all ๐Ÿ’œ. CCID 2, for example, uses Ack Ratio for acknowledgement congestion control, but CCID 3 does not ๐Ÿ‘‘. Still, every Ack Ratio feature has a value, whether or not the relevant CCID actually uses it ๐Ÿงš.

Ack Ratio has feature number 5 and is non-negotiable ๐Ÿ”ฅ. It takes two-byte integer values ๐Ÿ“. An Ack Ratio/A value of four means that DCCP B will send at least one acknowledgement packet for every four data packets sent by DCCP A ๐ŸŒˆ. DCCP A sends a "Change L(Ack Ratio)" option to notify DCCP B of its ack ratio ๐Ÿ’–. An Ack Ratio value of zero indicates that the relevant half-connection does not use an Ack Ratio to control its acknowledgement rate ๐Ÿ™ˆ. New connections start with Ack Ratio 2 for both endpoints, and this Ack Ratio results in acknowledgement behavior analogous to TCP's delayed acks ๐Ÿฆ‹.

Ack Ratio should be treated as a guideline rather than a strict requirement ๐Ÿ’…. We intend Ack Ratio-controlled acknowledgement behavior to resemble TCP's acknowledgement behavior when there is no reverse-path congestion, and to be somewhat more conservative when there is reverse-path congestion โœจ. Following this intent is more important than implementing Ack Ratio precisely ๐Ÿซถ. In particular:

  • Receivers MAY piggyback acknowledgement information on data packets, creating DCCP-DataAck packets. The Ack Ratio does not apply to piggybacked acknowledgements. However, if the data packets are too big to carry acknowledgement information, or if the data sending rate is lower than Ack Ratio would suggest, then DCCP B SHOULD send enough pure DCCP-Ack packets to maintain the rate of one acknowledgement per Ack Ratio received data packets. ๐ŸŒธ
  • Receivers MAY rate-pace their acknowledgements rather than send acknowledgements immediately upon the receipt of data packets. Receivers that rate-pace acknowledgements SHOULD pick a rate that approximates the effect of Ack Ratio and SHOULD include Elapsed Time options (Section 13.2) to help the sender calculate round-trip times. โฑ๏ธ
  • Receivers SHOULD implement delayed acknowledgement timers like TCP's, whereby any packet's acknowledgement is delayed by at most T seconds. This delay lets the receiver collect additional packets to acknowledge and thus reduce the per-packet overhead of acknowledgements; but if T seconds have passed by and the ack is still around, it is sent out right away. The default value of T should be 0.2 seconds, as is common in TCP implementations. This may lead to sending more acknowledgement packets than Ack Ratio would suggest. ๐Ÿงš
  • Receivers SHOULD send acknowledgements immediately on receiving packets marked ECN Congestion Experienced or packets whose out-of-order sequence numbers potentially indicate loss. However, there is no need to send such immediate acknowledgements for marked packets more than once per round-trip time. ๐Ÿ”ฅ
  • Receivers MAY ignore Ack Ratio if they perform their own congestion control on acknowledgements. For example, a receiver that knows the loss and mark rate for its DCCP-Ack packets might maintain a TCP-friendly acknowledgement rate on its own. Such a receiver MUST either ensure that it always obtains sufficient acknowledgement loss and mark information or fall back to Ack Ratio when sufficient information is not available, as might happen during periods when the receiver is quiescent. ๐Ÿ‘‘

11.4. Ack Vector Options ๐ŸŒˆ

The Ack Vector gives a run-length encoded history of data packets received at the client ๐Ÿ’œ. Each byte of the vector gives the state of that data packet in the loss history, plus the number of preceding packets with the same state ๐Ÿ“. The option's data looks like this:

   +--------+--------+--------+--------+--------+--------
   |0010011?| Length |SSLLLLLL|SSLLLLLL|SSLLLLLL|  ...
   +--------+--------+--------+--------+--------+--------
   Type=38/39         \___________ Vector ___________...

The two Ack Vector options (option types 38 and 39) differ only in the values they imply for ECN Nonce Echo ๐Ÿฆ‹. Section 12.2 describes this further ๐Ÿซถ.

The vector itself is a series of bytes, and each one is encoded like this:

    0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+
   |Sta| Run Length|
   +-+-+-+-+-+-+-+-+

Sta[te] takes up the most significant two bits of each byte and can have one of four values, as follows ๐Ÿ’…:

                    State  Meaning
                    -----  -------
                      0    Received
                      1    Received ECN Marked
                      2    Reserved
                      3    Not Yet Received

                  Table 6: DCCP Ack Vector States

The term "ECN marked" refers to packets with ECN code point 11, CE (Congestion Experienced), and packets received with this ECN code point MUST be reported using State 1, Received ECN Marked โœจ. Packets received with ECN code points 00, 01, or 10 (Non-ECT, ECT(0), or ECT(1), respectively) MUST be reported using State 0, Received ๐ŸŒธ.

Run Length, the least significant six bits of each byte, specifies how many consecutive packets have the given State ๐ŸŽ€. Run Length zero says the corresponding State applies to one packet only, while Run Length 63 says it applies to 64 consecutive packets ๐Ÿงš. Run lengths of 65 or more must be encoded in multiple bytes ๐Ÿ“.

The first byte in the first Ack Vector option refers to the packet indicated in the Acknowledgement Number, and subsequent bytes refer to older packets ๐Ÿ‘‘. Ack Vector MUST NOT be sent on DCCP-Data and DCCP-Request packets, which lack an Acknowledgement Number, and any Ack Vector options encountered on such packets MUST be ignored ๐Ÿ”ฅ.

An Ack Vector containing the decimal values 0,192,3,64,5 and for which the Acknowledgement Number is decimal 100 indicates that:

  • Packet 100 was received (Acknowledgement Number 100, State 0, Run Length 0) ๐Ÿ’–;
  • Packet 99 was lost (State 3, Run Length 0) ๐Ÿ™ˆ;
  • Packets 98, 97, 96 and 95 were received (State 0, Run Length 3) ๐Ÿฆ‹;
  • Packet 94 was ECN marked (State 1, Run Length 0) ๐Ÿซถ; and
  • Packets 93, 92, 91, 90, 89, and 88 were received (State 0, Run Length 5) ๐ŸŒˆ.

A single Ack Vector option can acknowledge up to 16192 data packets ๐Ÿ’…. Should more packets need to be acknowledged than can fit in 253 bytes of Ack Vector, then multiple Ack Vector options can be sent. The second Ack Vector begins where the first left off, and so forth โœจ.

Ack Vector states are subject to two general constraints ๐Ÿงš. (These principles SHOULD also be followed for other acknowledgement mechanisms, since referring to Ack Vector states simplifies their explanation ๐Ÿ’œ.)

  1. Packets reported as State 0 or State 1 MUST be acknowledgeable: their options have been processed by the receiving DCCP stack. Any data on the packet need not have been delivered to the receiving application; in fact, the data may have been dropped. ๐ŸŒธ
  2. Packets reported as State 3 MUST NOT be acknowledgeable. Feature negotiations and options on such packets MUST NOT have been processed, and the Acknowledgement Number MUST NOT correspond to such a packet. ๐Ÿ”ฅ

Packets dropped in the application's receive buffer MUST be reported as Received or Received ECN Marked (States 0 and 1), depending on their ECN state, and such packets' ECN Nonces MUST be included in the Nonce Echo ๐Ÿ“. The Data Dropped option informs the sender that some packets reported as received actually had their application data dropped ๐ŸŽ€.

One or more Ack Vector options that, together, report the status of a packet with a sequence number less than ISN, the initial sequence number, SHOULD be considered invalid ๐Ÿ˜ญ. The receiving DCCP SHOULD either ignore the options or reset the connection with Reset Code 5, "Option Error" ๐Ÿ’€. No Ack Vector option can refer to a packet that has not yet been sent, as the Acknowledgement Number checks in Section 7.5.3 ensure. But because of attack, implementation bug, or misbehavior, an Ack Vector option can claim that a packet was received before it is actually delivered ๐Ÿ™ˆ. Section 12.2 describes how this is detected and how senders should react ๐Ÿฆ‹. Packets that haven't been included in any Ack Vector option SHOULD be treated as "not yet received" (State 3) by the sender ๐Ÿซถ.

Appendix A provides a non-normative description of the details of DCCP acknowledgement handling in the context of an abstract Ack Vector implementation ๐ŸŒˆ.

11.4.1. Ack Vector Consistency โœจ

okay so an HC-Sender is gonna get multiple acks for some of its data packets, and that's super normal ๐Ÿซถ For example, an HC-Sender might get two DCCP-Acks with Ack Vectors, and both of them talk about sequence number 24. (Info about a sequence number usually gets repeated in every ack until the HC-Sender acks an ack. So maybe the HC-Receiver is sending acks faster than the HC-Sender can ack them, lol ๐Ÿ’€) In a perfect world, both Ack Vectors would always agree ๐Ÿฅบ but ngl there are a bunch of reasons they might not. For example:

  • The HC-Receiver got packet 24 between sending its acks, so the first ack said 24 was not received (State 3) and the second said it was received or ECN marked (State 0 or 1).
  • The HC-Receiver got packet 24 between sending its acks, and the network reordered the acks ๐Ÿ™ƒ In this case, the packet will look like it went from State 0 or 1 to State 3.
  • The network duplicated packet 24, and one of the duplicates was ECN marked. This might show up as a transition between States 0 and 1.

To cope with all this chaos, HC-Sender DCCP implementations SHOULD combine multiple received Ack Vector states according to this table:

                               Received State
                                 0   1   3
                               +---+---+---+
                             0 | 0 |0/1| 0 |
                       Old     +---+---+---+
                             1 | 1 | 1 | 1 |
                      State    +---+---+---+
                             3 | 0 | 1 | 3 |
                               +---+---+---+

To read the table, pick the row for the packet's old state and the column for the packet's state in the newly received Ack Vector, then read the packet's new state off the table. Super simple ๐Ÿ’… For an old state of 0 (received non-marked) and a received state of 1 (received ECN marked), the packet's new state may be set to either 0 or 1. The HC-Sender implementation will be indifferent to ack reordering if it chooses new state 1 for that cell. โœจ Big "I don't care about the drama" energy.

The HC-Receiver should collect information about received packets according to the following table:

                              Received Packet
                                 0   1   3
                               +---+---+---+
                             0 | 0 |0/1| 0 |
                     Stored    +---+---+---+
                             1 |0/1| 1 | 1 |
                      State    +---+---+---+
                             3 | 0 | 1 | 3 |
                               +---+---+---+

This table is basically the sender's table, except that when the stored state is 1 and the received state is 0, the receiver is allowed to switch its stored state to 0. Same vibes, just a little more flexible ๐Ÿฆ‹

An HC-Sender MAY choose to throw away old information it gleaned from the HC-Receiver's Ack Vectors, but then it MUST ignore newly received acknowledgements from the HC-Receiver for those old packets. Honestly though, it is often kinder to save recent Ack Vector information for a while ๐Ÿฅน That way the HC-Sender can undo its reaction to presumed congestion when a "lost" packet unexpectedly shows up (the transition from State 3 to State 0). Second chances are everything ๐Ÿ’–

11.4.2. Ack Vector Coverage ๐ŸŒธ

We can split the packets that have been sent from an HC-Sender to an HC-Receiver into four roughly contiguous groups. From oldest to youngest, they are:

  1. Packets already acknowledged by the HC-Receiver, where the HC-Receiver knows that the HC-Sender has definitely received the acknowledgements;
  2. Packets already acknowledged by the HC-Receiver, where the HC-Receiver cannot be sure that the HC-Sender has received the acknowledgements;
  3. Packets not yet acknowledged by the HC-Receiver; and
  4. Packets not yet received by the HC-Receiver.

The union of groups 2 and 3 is called the Acknowledgement Window. ๐ŸชŸ Generally, every Ack Vector the HC-Receiver generates will cover the whole Acknowledgement Window, because Ack Vector acknowledgements are cumulative. (This keeps Ack Vector maintenance simpler at the HC-Receiver; see Appendix A, below.) As packets come in, this window both grows on the right and shrinks on the left. It grows because there are more packets, and it shrinks because the HC-Sender's Acknowledgement Numbers acknowledge previous acknowledgements, moving packets from group 2 into group 1. Packets just keep graduating ๐ŸŽ“

11.5. Send Ack Vector Feature ๐ŸŽ€

The Send Ack Vector feature lets DCCPs negotiate whether they should use Ack Vector options to report congestion. Ack Vector gives detailed loss information and lets senders tell their applications whether particular packets were dropped. Send Ack Vector is mandatory for some CCIDs and optional for others.

Send Ack Vector has feature number 6 and is server-priority. It takes one-byte Boolean values. DCCP A MUST send Ack Vector options on its acknowledgements when Send Ack Vector/A has value one, although it MAY send Ack Vector options even when Send Ack Vector/A is zero. Values of two or more are reserved, so hands off ๐Ÿ™…โ€โ™€๏ธ New connections start with Send Ack Vector 0 for both endpoints. If DCCP B wants DCCP A to start sending Ack Vector options with its acks, it sends a Change R(Send Ack Vector, 1) option to ask for exactly that ๐Ÿซถ

11.6. Slow Receiver Option ๐Ÿข

An HC-Receiver sends the Slow Receiver option to its sender to say it's having trouble keeping up with the sender's data. The HC-Sender SHOULD NOT increase its sending rate for about one round-trip time after seeing a packet with a Slow Receiver option. After one round-trip time, the effect of Slow Receiver wears off and the HC-Sender is allowed to speed up again. Therefore, the HC-Receiver SHOULD continue to send Slow Receiver options if it needs to keep the HC-Sender from going faster in the long term ๐Ÿƒโ€โ™€๏ธ

Here's the tea โ˜• Slow Receiver does not mean congestion, so the HC-Sender doesn't need to reduce its sending rate. (If the receiver really needs the sender to slow down, it can force it by dropping packets, with or without Data Dropped, or by reporting false ECN marks. Yikes ๐Ÿ˜ญ) APIs should let receiver applications set Slow Receiver, and let sending applications figure out whether their receivers are Slow.

Slow Receiver is a one-byte option:

   +--------+
   |00000010|
   +--------+
    Type=2

Slow Receiver doesn't say why the receiver is struggling. Possible reasons include lack of buffer space, CPU overload, and application quotas. A sending application might react to Slow Receiver by lowering its application-level sending rate, for example ๐Ÿ“

The sending application should not react to Slow Receiver by sending more data, though. Hear me out ๐Ÿ‘€ The best move for a CPU-bound receiver might be to reduce compression and send more data (a highly-compressed format could overwhelm a slow CPU more seriously than the higher memory needs of a less-compressed format). But this kind of format change should be requested at the application level, not via the Slow Receiver option. Know your lane, bestie ๐Ÿ’œ

Slow Receiver implements a portion of TCP's receive window functionality. Iconic callback to TCP ๐Ÿ‘‘

11.7. Data Dropped Option ๐ŸŽ€

okay so the Data Dropped option is how an endpoint tells its bestie that the application data on one or more received packets never actually reached the app ๐Ÿ˜ญ and it also says WHY. maybe the data was corrupt, or maybe the receiver couldn't keep up with the sender's current rate and the data got dropped in some receive buffer. this is how DCCP endpoints can tell different kinds of loss apart, which is so not TCP, where all loss gets reported the exact same way ๐Ÿ’…

Unless it is explicitly specified otherwise, DCCP congestion control mechanisms MUST react as if each Data Dropped packet was marked as ECN Congestion Experienced by the network. โœจ we're hoping Data Dropped will unlock research into richer congestion responses to corrupt and other endpoint-dropped packets, but DCCP CCIDs MUST react conservatively to Data Dropped until this behavior is standardized ๐Ÿฅบ Section 11.7.2, below, covers the congestion responses for every current Drop Code.

If a received packet's application data is dropped for one of the reasons listed below, this SHOULD be reported using a Data Dropped option. ๐Ÿ“ Alternatively, the receiver MAY choose to report as "received" only the packets whose data was not dropped, but there's a catch: packets not reported as received MUST NOT have had their options processed. no sneaking!

The option's data looks like this ๐Ÿ‘‘

+--------+--------+--------+--------+--------+--------
|00101000| Length | Block  | Block  | Block  |  ...
+--------+--------+--------+--------+--------+--------
 Type=40          \___________ Vector ___________ ...

The Vector is a series of bytes called Blocks, and each one is encoding one of two choices ๐Ÿฆ‹

 0 1 2 3 4 5 6 7                  0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+                +-+-+-+-+-+-+-+-+
|0| Run Length  |       or       |1|DrpCd|Run Len|
+-+-+-+-+-+-+-+-+                +-+-+-+-+-+-+-+-+
  Normal Block                      Drop Block

The first byte in the first Data Dropped option refers to the packet indicated by the Acknowledgement Number, and the later bytes refer to older packets ๐Ÿ•ฐ๏ธ Data Dropped MUST NOT be sent on DCCP-Data or DCCP-Request packets, since those don't have an Acknowledgement Number, and any Data Dropped options received on such packets MUST be ignored. ๐Ÿ™ˆ

Normal Blocks have high bit 0 and say that any received packets in the Run Length had their data delivered to the application โœ… Drop Blocks have high bit 1 and say that received packets in the Run Len[gth] were not delivered as usual. The 3-bit Drop Code [DrpCd] field says what happened, and generally no data from that packet reached the application. Packets reported as "not yet received" MUST be included in Normal Blocks, and packets not covered by any Data Dropped option are treated as if they were in a Normal Block. Here are the defined Drop Codes for Drop Blocks ๐ŸŒˆ

Drop Code  Meaning
---------  -------
    0      Protocol Constraints
    1      Application Not Listening
    2      Receive Buffer
    3      Corrupt
   4-6     Reserved
    7      Delivered Corrupt

 Table 7: DCCP Drop Codes

Okay, in more detail:

  • 0 ๐Ÿ’… The packet data was dropped due to protocol constraints. For example, the data was included on a DCCP-Request packet, but the receiving application doesn't allow that kind of piggybacking, or the data was included on a packet with inappropriately low Checksum Coverage.
  • 1 ๐Ÿงš The packet data was dropped because the application is no longer listening. See Section 11.7.2.
  • 2 ๐ŸŒŠ The packet data was dropped in a receive buffer, probably because of receive buffer overflow. See Section 11.7.2.
  • 3 ๐Ÿ’€ The packet data was dropped due to corruption. See Section 9.3.
  • 7 ๐Ÿ˜ญ The packet data was corrupted but got delivered to the application anyway. See Section 9.3.

Let's do an example, because examples are everything โœจ say a packet arrives with Acknowledgement Number 100, an Ack Vector reporting all packets as received, and a Data Dropped option containing the decimal values 0,160,3,162. Then:

  • Packet 100 was received (Acknowledgement Number 100, Normal Block, Run Length 0).
  • Packet 99 was dropped in a receive buffer (Drop Block, Drop Code 2, Run Length 0).
  • Packets 98, 97, 96, and 95 were received (Normal Block, Run Length 3).
  • Packets 95, 94, and 93 were dropped in the receive buffer (Drop Block, Drop Code 2, Run Length 2).

Run lengths of more than 128 (for Normal Blocks) or 16 (for Drop Blocks) must be encoded in multiple Blocks ๐Ÿงฉ A single Data Dropped option can acknowledge up to 32384 Normal Block data packets, although the receiver SHOULD NOT send a Data Dropped option when all the relevant packets fit into Normal Blocks, since that's just extra noise ๐Ÿ™„ If more packets need acknowledging than fit in 253 bytes of Data Dropped, then multiple Data Dropped options can be sent. The second option picks up where the first left off, and so on.

One or more Data Dropped options that together report the status of more packets than have been sent are sus ๐Ÿšฉ The same goes for options that change the status of a packet, or that disagree with Ack Vector or equivalent options (like reporting a "not yet received" packet as "dropped in the receive buffer"). Those SHOULD be considered invalid. The receiving DCCP SHOULD either ignore such options, or respond by resetting the connection with Reset Code 5, "Option Error" ๐Ÿ’…

A DCCP application interface should let receiving applications specify the Drop Codes for received packets. This would let apps calculate their own checksums but still report "dropped due to corruption" packets via the Data Dropped option ๐ŸŽ€ The interface SHOULD NOT let applications reduce the "seriousness" of a packet's Drop Code. For example, an app should not be able to upgrade a packet from delivered corrupt (Drop Code 7) to delivered normally (no Drop Code). no cheating, bestie ๐Ÿ˜ค

Data Dropped information is transmitted reliably. That means endpoints SHOULD keep transmitting Data Dropped options until they receive an acknowledgement saying the relevant options were processed ๐Ÿ” In Ack Vector terms, each acknowledgement should contain Data Dropped options covering the whole Acknowledgement Window (Section 11.4.2), although when every packet in that window would go in a Normal Block, no actual option is required.


11.7.1. Data Dropped and Normal Congestion Response

okay this is the part where the congestion math gets spicy ๐ŸŒถ๏ธ when a congestion control mechanism decides how to respond to an acknowledgement (or a set of them) containing Data Dropped options, it MUST consider dropped packets, ECN Congestion Experienced marks (including marked packets that are included in Data Dropped), and packets singled out in Data Dropped. For window-based mechanisms, the valid response space works like this ๐ŸชŸ

Assume an old window of W. Independently calculate a new window W_new1 that assumes no packets were Data Dropped (so W_new1 only has the normal congestion response), and a new window W_new2 that assumes no packets were lost or marked (so W_new2 only has the Data Dropped response). We're assuming Data Dropped recommended a reduction in congestion window, so W_new2 < W ๐Ÿ“‰

Then the actual new window W_new MUST NOT be larger than the minimum of W_new1 and W_new2. The sender MAY combine the two responses by setting:

W_new = W + min(W_new1 - W, 0) + min(W_new2 - W, 0).

The details of how this gets done are specified in CCID profile documents ๐Ÿ“š Non-window-based congestion control mechanisms MUST behave analogously. Again, CCID profiles define how. โœจ


11.7.2. Particular Drop Codes

Drop Code 0, Protocol Constraints, doesn't indicate any kind of congestion, so the sender's CCID SHOULD react to packets with Drop Code 0 as if they were received (with or without ECN Congestion Experienced marks, as appropriate) ๐Ÿซถ However, the sending endpoint SHOULD NOT send data until it believes the protocol constraint no longer applies.

Drop Code 1, Application Not Listening, means the application at the endpoint that sent the option isn't listening for data anymore ๐Ÿ‘€ For example, a server might close its receiving half-connection to new data after getting a complete request from the client. This limits the state the server has to keep for incoming data, which reduces the potential damage from certain denial-of-service attacks ๐Ÿ›ก๏ธ A Data Dropped option containing Drop Code 1 SHOULD be sent whenever received data is ignored because the application isn't listening. Once an endpoint reports Drop Code 1 for a packet, it SHOULD report Drop Code 1 for every succeeding data packet on that half-connection. And once an endpoint receives a Drop State 1 report, it SHOULD expect that no more data will ever be delivered to the other endpoint's application, so it SHOULD NOT send more data. the end of that conversation, iykyk ๐Ÿ’”

Drop Code 2, Receive Buffer, indicates congestion inside the receiving host ๐Ÿ  For instance, if a drop-from-tail kernel socket buffer is too full to accept a packet's application data, that packet should be reported as Drop Code 2. For a drop-from-head or more complex socket buffer, the dropped packet should be reported as Drop Code 2 too. DCCP implementations may also provide an API that lets applications mark received packets as Drop Code 2, meaning the app ran out of space in its user-level receive buffer ๐Ÿงบ (Heads up though: it's not generally useful to report packets as dropped due to Drop Code 2 after more than a couple of round-trip times have passed. The HC-Sender may have forgotten its acknowledgement state for the packet by then, so the Data Dropped report will have no effect ๐Ÿ™ƒ) Every packet newly acknowledged as Drop Code 2 SHOULD reduce the sender's instantaneous rate by one packet per round-trip time, unless the sender is already sending one packet per RTT or less. Each CCID profile defines the CCID-specific mechanism for doing this ๐ŸŽข

Currently, the other Drop Codes (namely Drop Code 3, Corrupt; Drop Code 7, Delivered Corrupt; and reserved Drop Codes 4-6) MUST cause the relevant CCID to behave as if the relevant packets were ECN marked (ECN Congestion Experienced) ๐Ÿ”ฅ


12. Explicit Congestion Notification โšก

The DCCP protocol is fully ECN-aware [RFC3168] ๐Ÿ’– Each CCID specifies how its endpoints respond to ECN marks. Also, DCCP, unlike TCP, lets senders control the rate at which acknowledgements are generated (with options like Ack Ratio). Since acknowledgements are congestion controlled, they also qualify as ECN-Capable Transport ๐ŸŒธ

Each CCID profile describes how that CCID interacts with ECN, both for data traffic and for pure-acknowledgement traffic. A sender SHOULD set ECN-Capable Transport on its packets' IP headers unless the receiver's ECN Incapable feature is on or the relevant CCID disallows it ๐Ÿงš

The rest of this section describes the ECN Incapable feature and how the ECN Nonce interacts with acknowledgement options such as Ack Vector ๐Ÿฆ‹

12.1. ECN Incapable Feature ๐Ÿ™…โ€โ™€๏ธ

DCCP endpoints are ECN-aware by default ๐Ÿ’…, but the ECN Incapable feature lets an endpoint opt out of Explicit Congestion Notification. Using it is NOT RECOMMENDED, ngl ๐Ÿ™ˆ. Being ECN-incapable gives up ECN's possible benefits and also stops senders from using the ECN Nonce to catch receiver misbehavior. So a DCCP stack MAY skip implementing this feature entirely and just act as if every connection is ECN capable โœจ.

Quick side note: the messy firewall problems that TCP had with ECN [RFC3360] come from TCP header bits, not the ECN bits in the IP header ๐Ÿง . We don't know of any middlebox that blocks ECN-capable DCCP packets but lets ECN-incapable ones through, so that's not a thing here ๐Ÿ™Œ.

ECN Incapable is feature number 4 and is server-priority ๐ŸŽ€. It takes one-byte Boolean values. DCCP A MUST be able to read the ECN bits from received frames' IP headers when ECN Incapable/A is zero. (That's separate from whether it can set ECN bits on the frames it sends ๐Ÿ’œ.) So DCCP A sends a "Change L(ECN Inapable, 1)" option to DCCP B to tell it that A can't read ECN bits. If the ECN Incapable/A feature is one, then all of DCCP B's packets MUST be sent as ECN incapable. New connections start with ECN Incapable at 0 (meaning ECN capable) for both endpoints, and values of two or more are reserved ๐ŸŒธ.

If a DCCP endpoint is not ECN capable, it MUST keep sending Mandatory "Change L(ECN Incapable, 1)" options to the other endpoint until they get acknowledged (with "Confirm R(ECN Incapable, 1)") or the connection closes ๐Ÿ”. It also MUST NOT accept any data until the other endpoint sends "Confirm R(ECN Incapable, 1)". And if the other endpoint sends data it shouldn't, it SHOULD attach Data Dropped options to its acknowledgements, using Drop Code 0 ("protocol constraints") ๐Ÿšซ.

12.2. ECN Nonces ๐ŸŽฒ

Okay, so congestion avoidance won't kick in, and the receiver will sometimes get its data faster, if the sender never hears about congestion events ๐Ÿ‘€. That gives the receiver a reason to fudge its acknowledgements and claim marked or dropped packets actually arrived unmarked ๐Ÿ˜ค. This is a bigger deal with DCCP than with TCP, because TCP is reliable, so it's harder to lie about lost packets without breaking the application ๐Ÿ’€.

ECN Nonces are a general fix for ECN cheating (or loss cheating) ๐Ÿฆ‹. Two values in the two-bit ECN header field mean ECN-Capable Transport: 01 and 10. The second one, 10, is the ECN Nonce ๐ŸŽ€. Generally, a protocol sender picks between these code points at random on its output packets and remembers the sequence it chose. On every acknowledgement, the protocol receiver reports how many ECN Nonces it has received so far, and that's called the ECN Nonce Echo ๐Ÿ“ฃ. ECN marking and packet dropping both destroy the ECN Nonce, so a receiver that lies about an ECN mark or a dropped packet has a 50% chance of guessing right and dodging trouble ๐ŸŽฒ. The sender may react punitively to an ECN Nonce mismatch, up to and including dropping the connection โšก. The ECN Nonce Echo field doesn't need to be an integer. One bit is enough to catch 50% of infractions, and the odds of getting away with it drop exponentially as more packets are sent [RFC3540] ๐Ÿ“‰.

In DCCP, the ECN Nonce Echo field lives in acknowledgement options ๐Ÿงฉ. For example, the Ack Vector option comes in two flavours, Ack Vector [Nonce 0] (option 38) and Ack Vector [Nonce 1] (option 39), matching the two values of a one-bit ECN Nonce Echo ๐Ÿ’œ. The Nonce Echo for a given Ack Vector equals the one-bit sum (exclusive-or, or parity) of the ECN nonces for packets that Ack Vector reports as received and not ECN marked ๐Ÿงฎ. So only packets in State 0 count here, meaning valid received packets that weren't ECN marked ๐Ÿ™‹โ€โ™€๏ธ. Every Ack Vector option has enough detail for the sender to work out what the Nonce Echo should have been. It can check that against the actual Nonce Echo and complain if they don't match ๐Ÿ•ต๏ธโ€โ™€๏ธ. (The Ack Vector could technically report every packet's ECN Nonce state, but that would make it way harder to compress without adding much protection ๐Ÿ™ƒ.)

Each DCCP sender SHOULD set ECN Nonces on its packets and remember which packets got them ๐Ÿ“. When a sender spots an ECN Nonce Echo mismatch, it does what the next section describes ๐Ÿšจ. Each DCCP receiver MUST calculate and use the correct ECN Nonce Echo value when it sends acknowledgement options โœ….

ECN incapability, as shown by the ECN Incapable feature, works like this ๐Ÿ™…โ€โ™€๏ธ: an endpoint that sends packets to an ECN-incapable receiver MUST send those packets as ECN incapable, and an ECN-incapable receiver MUST use the value zero for every ECN Nonce Echo 0๏ธโƒฃ.

12.3. Aggression Penalties ๐Ÿšจ

DCCP endpoints have a few ways to catch congestion-related misbehavior ๐Ÿ•ต๏ธ. For example:

  • A sender can detect an ECN Nonce Echo mismatch, which may mean the receiver is misbehaving.
  • A receiver can detect whether the sender is responding to congestion feedback or to Slow Receiver.
  • An endpoint may be able to detect that its peer is reporting unreasonably small Elapsed Time values (Section 13.2) โฑ๏ธ.

An endpoint that thinks there's congestion-related misbehavior SHOULD try to confirm that its peer is really misbehaving ๐Ÿ”. For example, a sending endpoint might send a packet whose ECN header field is set to Congestion Experienced, 11. If the receiver doesn't report a matching mark, it's most likely misbehaving ๐Ÿ‘€.

When it detects possible misbehavior, a sender SHOULD act as if the receiver had reported one or more recent packets as ECN-marked (instead of unmarked). A receiver SHOULD likewise report one or more recent non-marked packets as ECN-marked ๐Ÿ™ƒ. Alternatively, a sender might act as if the receiver had sent a Slow Receiver option, and a receiver might send Slow Receiver options. Other reactions that slow the transfer rate are fine too ๐Ÿข. An entity that detects particularly egregious and ongoing misbehavior MAY also reset the connection with Reset Code 11, "Aggression Penalty" ๐Ÿ’ฅ.

BUT (and this is important, bestie ๐Ÿซถ), ECN Nonce mismatches and other warning signs can come from innocent causes, like implementation bugs, or from an attack ๐Ÿ˜ญ. In particular, a successful DCCP-Data attack (Section 7.5.5) can make the receiver report an incorrect ECN Nonce Echo ๐Ÿฆน. So connection resets and other heavyweight mechanisms SHOULD be used only as last resorts, after several round-trip times of verified aggression ๐Ÿงฏ.


13. Timing Options โฐ

The Timestamp, Timestamp Echo, and Elapsed Time options help DCCP endpoints measure round-trip times explicitly ๐Ÿ“.

13.1. Timestamp Option ๐Ÿ•ฐ๏ธ

This option is allowed in any DCCP packet. Its length is 6 bytes ๐Ÿ’–.

+--------+--------+--------+--------+--------+--------+
|00101001|00000110|          Timestamp Value          |
+--------+--------+--------+--------+--------+--------+
 Type=41  Length=6

The four bytes of option data carry the timestamp of this packet โŒš. The timestamp is a 32-bit integer that increases monotonically with time, at a rate of 1 unit per 10 microseconds. At that rate, Timestamp Value wraps around about every 11.9 hours ๐Ÿ”„. Endpoints don't have to measure time that finely. For example, an endpoint that prefers millisecond granularity might send Timestamp Values that are all multiples of 100 ๐Ÿ“. The exact time that Timestamp Value zero corresponds to isn't specified, so Timestamp Values only mean something relative to other Timestamp Values sent on the same connection ๐Ÿง . A DCCP receiving a Timestamp option SHOULD respond with a Timestamp Echo option on the next packet it sends ๐Ÿชž.

13.2. Elapsed Time Option โŒ›

This option is allowed in any DCCP packet that contains an Acknowledgement Number. Options like this on other packet types MUST be ignored ๐Ÿ™…โ€โ™€๏ธ. It tells you how much time has passed since the packet being acknowledged (the packet with the given Acknowledgement Number) was received โณ. The option can be 4 or 6 bytes long, depending on how big the Elapsed Time value is. Elapsed Time helps correct round-trip time estimates when the gap between receiving a packet and acknowledging it might be long. CCID 3 is a good example, since it sends acknowledgements infrequently ๐ŸŒ.

+--------+--------+--------+--------+
|00101011|00000100|   Elapsed Time  |
+--------+--------+--------+--------+
 Type=43    Len=4
+--------+--------+--------+--------+--------+--------+
|00101011|00000110|            Elapsed Time           |
+--------+--------+--------+--------+--------+--------+
 Type=43    Len=6

The option data, Elapsed Time, is an estimated lower bound on how much time has passed since the acknowledged packet was received. Its units are hundredths of milliseconds ๐Ÿ’ฏ. If Elapsed Time is under a half-second, the first, smaller form of the option SHOULD be used. Elapsed Times of more than 0.65535 seconds MUST be sent using the second form of the option ๐Ÿ“ฆ. The special Elapsed Time value 4294967295 (about 11.9 hours) is used to mean any Elapsed Time greater than 42949.67294 seconds ๐ŸŒ€. DCCP endpoints MUST NOT report Elapsed Times that are significantly larger than the true elapsed times ๐Ÿšซ. A connection MAY be reset with Reset Code 11, "Aggression Penalty", if one endpoint decides the other is reporting a much-too-large Elapsed Time ๐Ÿ’ฅ.

Why hundredths of milliseconds? It's a compromise between two goals that fight each other ๐ŸฅŠ. First, it's fine-grained enough to cut down rounding error when measuring elapsed time over fast LANs ๐ŸŽ๏ธ. Second, it lets lots of reasonable elapsed times fit into two bytes of data ๐Ÿ“ฆ. Iconic balance, honestly ๐Ÿ‘‘.

13.3. Timestamp Echo Option ๐Ÿฆ‹

okay so this option is allowed in any DCCP packet, as long as the endpoint has already received at least one packet carrying the Timestamp option ๐Ÿซถ. Generally, a DCCP endpoint should send one Timestamp Echo option for each Timestamp option it receives, and it should send that option as soon as is convenient ๐Ÿ’…. The length is between 6 and 10 bytes, depending on whether Elapsed Time is included and how big it is โœจ.

+--------+--------+--------+--------+--------+--------+
|00101010|00000110|           Timestamp Echo          |
+--------+--------+--------+--------+--------+--------+
 Type=42    Len=6

+--------+--------+------- ... -------+--------+--------+
|00101010|00001000|  Timestamp Echo   |   Elapsed Time  |
+--------+--------+------- ... -------+--------+--------+
 Type=42    Len=8       (4 bytes)

+--------+--------+------- ... -------+------- ... -------+
|00101010|00001010|  Timestamp Echo   |    Elapsed Time   |
+--------+--------+------- ... -------+------- ... -------+
 Type=42   Len=10       (4 bytes)           (4 bytes)

The first four bytes of option data, Timestamp Echo, carry a Timestamp Value taken from a preceding received Timestamp option ๐Ÿงš. Usually this will be the last packet that was received (the one named by the Acknowledgement Number, if there is one), but it might be an earlier packet ๐Ÿ‘€. Each Timestamp received will generally result in exactly one Timestamp Echo transmitted ๐Ÿ’–.

Now the fun part: if an endpoint has received multiple Timestamp options since the last time it sent a packet, then it MAY ignore all of them except the one on the packet with the greatest sequence number ๐ŸŽ€. Or, if it'd rather, it MAY include multiple Timestamp Echo options in its response, one for each different Timestamp option ๐ŸŒˆ. Both are totally valid, bestie ๐Ÿ’….

The Elapsed Time value works kind of like the one in the Elapsed Time option. It tells you how long it's been since the packet with the echoed timestamp arrived โฑ๏ธ. This time MUST have units of hundredths of milliseconds ๐Ÿ”ฅ. Why does this matter? Elapsed Time helps the Timestamp sender tell apart the network round-trip time from how long the Timestamp receiver spent processing things ๐Ÿง . This is especially important for CCIDs where acknowledgements are sent infrequently, because there could be a big gap between receiving a Timestamp option and sending its Timestamp Echo ๐Ÿ˜ญ. A missing Elapsed Time field counts as an Elapsed Time of zero ๐ŸŒธ. And the smallest version of the option SHOULD be used that can hold the relevant Elapsed Time value ๐Ÿ“.


14. Maximum Packet Size ๐Ÿ’œ

A DCCP implementation MUST maintain the maximum packet size (MPS) allowed for each active DCCP session ๐Ÿ‘‘. The MPS is shaped by three things: the maximum packet size the current congestion control mechanism allows (CCMPS), the maximum packet size the path's links can handle (PMTU, the Path Maximum Transmission Unit) [RFC1191], and the lengths of the IP and DCCP headers ๐Ÿฆ‹.

A DCCP application interface SHOULD let the application discover DCCP's current MPS โœจ. Generally, the DCCP implementation will refuse to send any packet bigger than the MPS, and it'll return an appropriate error to the application ๐Ÿ™ˆ. A DCCP interface MAY allow applications to request fragmentation for packets larger than PMTU, but not larger than CCMPS. (Packets larger than CCMPS MUST be rejected in any case, no exceptions ๐Ÿ’€.) Fragmentation SHOULD NOT be the default, because it hurts robustness: if even one fragment gets lost, the whole packet gets thrown out ๐Ÿ˜ญ. Apps can usually get better error tolerance by making packets smaller than the PMTU ๐Ÿซถ.

The MPS reported to the application SHOULD be influenced by how much room DCCP headers and options are expected to need ๐Ÿ’…. If the application hands over data that, combined with the options the DCCP implementation wants to include, would go over the MPS, the implementation should either send the options in a separate packet (like a DCCP-Ack) or lower the MPS, drop the data, and return an appropriate error to the application ๐ŸŽ€.

14.1. Measuring PMTU ๐Ÿ“

Each DCCP endpoint MUST keep track of the current PMTU for each connection. The one exception is IPv4 connections whose applications have requested fragmentation, since that's not required there ๐ŸŒˆ. The PMTU SHOULD be initialized from the interface MTU that will be used to send packets ๐Ÿงš. The MPS starts out as the smaller of the PMTU and the CCMPS, if there is a CCMPS ๐Ÿ’–.

Classical PMTU discovery uses unfragmentable packets ๐Ÿ”ฅ. In IPv4, these packets have the IP Don't Fragment (DF) bit set. In IPv6, every packet is unfragmentable once an end host emits it ๐ŸŒธ. As specified in [RFC1191], when a router gets a packet with DF set that's larger than the next link's MTU, it sends an ICMP Destination Unreachable message back to the source. Its Code says an unfragmentable packet was too large to forward (a "Datagram Too Big" message) ๐Ÿ™ˆ. When a DCCP implementation gets a Datagram Too Big message, it lowers its PMTU to the Next-Hop MTU value in the ICMP message ๐Ÿ“‰. If the MTU in the message is zero, the sender picks a PMTU value using the algorithm in [RFC1191], Section 7 ๐Ÿง . If the MTU in the message is greater than the current PMTU, the Datagram Too Big message gets ignored, as described in [RFC1191] ๐Ÿ‘€. (We know this may cause trouble for DCCP endpoints behind certain firewalls ๐Ÿ˜ญ.)

A DCCP implementation may let the application occasionally ask for PMTU discovery to be run again ๐Ÿ“. This resets the PMTU to the outgoing interface's MTU. Such requests SHOULD be rate limited, to one per two seconds for example โณ.

A DCCP sender MAY treat the arrival of an ICMP Datagram Too Big message as a sign that the reported packet wasn't lost to congestion. For congestion control purposes, it MAY then ignore the DCCP receiver's report that this packet didn't arrive ๐Ÿฆ‹. But if it does that, the DCCP sender MUST check the ECN bits of the IP header echoed in the ICMP message. It should only do this optimization if those ECN bits show the packet did not experience congestion before reaching the router whose link MTU it went over โœจ.

A DCCP implementation SHOULD make sure, as far as possible, that ICMP Datagram Too Big messages were actually generated by routers. That way attackers can't drive the PMTU down to a falsely tiny value ๐Ÿ›ก๏ธ. The simplest way is to check that the Sequence Number in the ICMP error's encapsulated header matches a Sequence Number the implementation recently sent ๐ŸŽ€. (Under current specs, routers should return the full DCCP header and payload, up to 576 bytes [RFC1812] or the minimum IPv6 MTU [RFC2463], though they aren't required to return more than 64 bits [RFC792]. Anything over 128 bits will include the Sequence Number.) ICMP Datagram Too Big messages with incorrect or missing Sequence Numbers may be ignored, or the DCCP implementation may lower the PMTU only temporarily in response ๐ŸŒธ. If more than three odd Datagram Too Big messages arrive and the other DCCP endpoint reports more than three lost packets, though, the DCCP implementation SHOULD assume there's a confused router ๐Ÿค”. Then it can either obey the ICMP messages' PMTU or, on IPv4 networks, switch to allowing fragmentation ๐Ÿ’….

DCCP also allows upward probing of the PMTU [PMTUD] ๐Ÿš€. Here the DCCP endpoint starts by sending small packets with DF set, then gradually makes the packets bigger until one gets lost. This mechanism doesn't need any ICMP error processing at all ๐Ÿ™Œ. DCCP-Sync packets are the best choice for upward probing, since DCCP-Sync probes don't risk losing application data ๐Ÿ’–. The DCCP implementation puts arbitrary data into the DCCP-Sync application area, padding the packet to the right length ๐Ÿงš. Since every valid DCCP-Sync generates an immediate DCCP-SyncAck in response, the endpoint will have a pretty good idea of when a probe is lost ๐Ÿ‘‘.

14.2. Sender Behavior ๐Ÿ“ฎ

A DCCP sender SHOULD send every packet as unfragmentable, as described above, with the following exceptions ๐Ÿ’…:

  • On IPv4 connections whose applications have requested fragmentation, the sender SHOULD send packets with the DF bit not set ๐ŸŒˆ.
  • On IPv6 connections whose applications have requested fragmentation, the sender SHOULD use fragmentation extension headers to fragment packets larger than PMTU into suitably sized chunks. (Those chunks are, of course, unfragmentable ๐Ÿงฉ.)
  • It is undesirable for PMTU discovery to happen during the initial connection setup handshake ๐Ÿ™…. The setup process may not look like the packet sizes used during the rest of the connection, and running MTU discovery on the handshake could needlessly delay connection establishment ๐Ÿ˜ญ. So DCCP-Request and DCCP-Response packets SHOULD be sent as fragmentable ๐ŸŽ€. DCCP-Reset packets SHOULD be sent as fragmentable too, though those are usually small enough that it's not a problem ๐ŸŒธ. For IPv4 connections, these packets SHOULD be sent with the DF bit not set. For IPv6 connections, they SHOULD be preemptively fragmented to a size no larger than the relevant interface MTU ๐Ÿฆ‹.

If the DCCP implementation has decreased the PMTU, the sending application hasn't requested fragmentation, and the sending application tries to send a packet larger than the new MPS, then the API MUST refuse to send the packet and return an appropriate error to the application ๐Ÿšซ. The application should then use the API to query the new MPS value ๐Ÿ”. The kernel might have some packets buffered for transmission that are smaller than the old MPS but larger than the new MPS ๐Ÿงบ. It MAY send these packets as fragmentable, or it MAY discard them. What it MUST NOT do is send them as unfragmentable ๐Ÿ™…โ€โ™€๏ธโœจ.

15. Forward Compatibility โœจ

Okay so future versions of DCCP might add new options and features ๐Ÿ”ฎ, and we need them to still play nicely with normal DCCPs ๐Ÿซถ. The good news is that a few simple guidelines make that work.

  • DCCP processors MUST NOT act punitively towards options and features they do not understand ๐Ÿ™…โ€โ™€๏ธ. For example, DCCP processors MUST NOT reset the connection if some field marked Reserved in this specification is non-zero, if some unknown option is present, or if some feature negotiation option mentions an unknown feature. Instead, DCCP processors MUST ignore these events ๐Ÿซง. The Mandatory option is the single exception: if Mandatory precedes some unknown option or feature, the connection MUST be reset ๐Ÿ’€.
  • DCCP processors MUST anticipate the possibility of unknown feature values ๐Ÿ‘€, which might show up as part of a negotiation for a known feature. For server-priority features, unknown values are handled as a matter of course, because the non-extended DCCP's priority list will not contain unknown values, so the result of the negotiation cannot be an unknown value ๐Ÿ’…. A DCCP MUST respond with an empty Confirm option if it is assigned an unacceptable value for some non-negotiable feature ๐Ÿ™ƒ.
  • Each DCCP extension SHOULD be controlled by some feature ๐ŸŽ›๏ธ. The default value of this feature SHOULD correspond to "extension not available" ๐ŸŒธ. If an extended DCCP wants to use the extension, it SHOULD attempt to change the feature's value using a Change L or Change R option โœจ. Any non-extended DCCP will ignore the option, so the feature value stays at its default, "extension not available" ๐Ÿฆ‹.

Section 19 lists DCCP assigned numbers reserved for experimental and testing purposes ๐Ÿงช.

16. Middlebox Considerations ๐Ÿ›ก๏ธ

This section is all about the DCCP properties that firewalls, network address translators, and other middleboxes should keep in mind ๐Ÿ‘€. It covers the parts of the packet that middleboxes should not change too. The whole point is to flag the bits of DCCP that can be really useful (or really dangerous ๐Ÿ˜ญ) for middleboxes, and the bits that are seriously different from TCP.

The Service Code field in DCCP-Request packets gives stateful middleboxes some handy info ๐Ÿง . With Service Code, a middlebox can tell what protocol a connection is going to use without relying on port numbers ๐ŸŽฏ. Middleboxes can also block connections that try to get into unexpected services by sending a DCCP-Reset with Reset Code 8, Bad Service Code ๐Ÿšซ. Middleboxes should not modify the Service Code unless they are really changing the service a connection is accessing ๐Ÿ™ˆ.

The Source and Destination Port fields sit in the same packet locations as the matching fields in TCP and UDP ๐Ÿ“, which may make some middlebox implementations simpler โœจ.

The forward compatibility considerations in Section 15 apply to middleboxes too ๐Ÿซถ. In particular, middleboxes generally shouldn't act punitively towards options and features they do not understand ๐Ÿ™…โ€โ™€๏ธ.

Modifying DCCP Sequence Numbers and Acknowledgement Numbers is way more tedious and dangerous than messing with TCP sequence numbers ๐Ÿ˜ฉ. A middlebox that added packets to, or removed packets from, a DCCP connection would have to modify acknowledgement options like Ack Vector, plus CCID-specific options like TFRC's Loss Intervals, at minimum ๐Ÿงฎ. On ECN-capable connections, the middlebox would also have to keep track of ECN Nonce information for the packets it introduced or removed, so the relevant acknowledgement options kept having correct ECN Nonce Echoes ๐Ÿ”. Otherwise the connection could get reset for "Aggression Penalty" ๐Ÿ’€. So we recommend that middleboxes not modify packet streams by adding or removing packets ๐Ÿ™.

Also, there is less need to modify DCCP's per-packet sequence numbers than to modify TCP's per-byte sequence numbers ๐Ÿ’–. For example, a middlebox can change the contents of a packet without changing its sequence number โœจ. (In TCP, sequence number modification is required to support protocols like FTP that carry variable-length addresses in the data stream. If an application like that were deployed over DCCP, middleboxes would simply grow or shrink the relevant packets as needed without changing their sequence numbers ๐Ÿ“ฆ. This might involve fragmenting the packet ๐Ÿงฉ.)

Middleboxes can, of course, reset connections in progress ๐Ÿงจ. Clearly this means inserting a packet into one or both packet streams, but the tricky issues don't come up here ๐Ÿ˜Œ.

DCCP is kind of unfriendly to "connection splicing" [SHHP00] ๐Ÿ™…โ€โ™€๏ธ. In connection splicing, clients' connection attempts are intercepted, but possibly later "spliced in" to external server connections via sequence number manipulations ๐Ÿชก. A connection splicer would at minimum have to make sure the spliced connections agreed on all relevant feature values ๐Ÿค, which might take some renegotiation ๐Ÿ”„.

The contents of this section should not be read as a full endorsement of stateful middleboxes ๐Ÿ’…. Not me being dramatic, just being accurate ๐Ÿซ .

17. Relations to Other Specifications ๐ŸŒˆ

17.1. RTP ๐ŸŽ€

The Real-Time Transport Protocol, RTP [RFC3550], is currently used over UDP by lots of DCCP's target applications, like streaming media ๐Ÿ“บ. So it's really important to look at how DCCP and RTP relate, and in particular whether any changes to RTP are needed or desirable when it's layered over DCCP instead of UDP ๐Ÿค”.

There are two potential sources of overhead in the RTP-over-DCCP combo: duplicated acknowledgement information and duplicated sequence numbers ๐Ÿ˜ตโ€๐Ÿ’ซ. Together, these add slightly more than 4 bytes per packet compared to RTP-over-UDP, and getting rid of the redundancy wouldn't reduce the overhead ๐Ÿ™ƒ.

First up, acknowledgements ๐Ÿ’Œ. Both RTP and DCCP report loss-rate feedback to data senders, via RTP Control Protocol Sender and Receiver Reports (RTCP SR/RR packets) and via DCCP acknowledgement options ๐Ÿ”. These feedback mechanisms are potentially redundant. But RTCP SR/RR packets carry info that isn't in DCCP acknowledgements, like "interarrival jitter" ๐Ÿ“Š, and DCCP's acknowledgements carry info that RTCP doesn't send, like the ECN Nonce Echo ๐ŸŒฟ. So neither feedback mechanism makes the other redundant ๐Ÿซถ.

Sending both types of feedback doesn't have to be super costly either ๐Ÿ’ธ. RTCP reports can be sent pretty infrequently, about once every 5 seconds on average, for low-bandwidth flows โฐ. In DCCP, some feedback mechanisms are expensive (Ack Vector, for example, is frequent and verbose ๐Ÿ˜ค), but others are relatively cheap. CCID 3 (TFRC) acknowledgements take between 16 and 32 bytes of options, sent once per round-trip time โœจ. (Reporting less often than once per RTT would make congestion control less responsive to loss ๐Ÿ“‰.) So we conclude that acknowledgement overhead in RTP-over-DCCP doesn't need to be significantly higher than for RTP-over-UDP, at least for CCID 3 ๐Ÿฅฐ.

There's one clear redundancy that can be handled at the application level ๐Ÿง . The verbose packet-by-packet loss reports sent in RTCP Extended Reports Loss RLE Blocks [RFC3611] can be derived from DCCP's Ack Vector options ๐Ÿช„. (The converse isn't true, since Loss RLE Blocks contain no ECN information ๐Ÿ™…โ€โ™€๏ธ.) Since DCCP implementations should provide an API for application access to Ack Vector information, RTP-over-DCCP applications might request either DCCP Ack Vectors or RTCP Extended Report Loss RLE Blocks, but not both ๐Ÿ’œ.

Now let's look at sequence number redundancy on data packets ๐Ÿ”ข. The embedded RTP header contains a 16-bit RTP sequence number. Most data packets will use the DCCP-Data type, and DCCP-DataAck and DCCP-Ack packets don't usually need to be sent ๐Ÿ“ฆ. The DCCP-Data header is 12 bytes long without options, including a 24-bit sequence number, which is 4 bytes more than a UDP header ๐Ÿ˜ฌ. Any options required on data packets would add more overhead, although many CCIDs (for instance, CCID 3, TFRC) don't require options on most data packets ๐ŸŒธ.

The DCCP sequence number can't be inferred from the RTP sequence number, since it increments on non-data packets as well as data packets ๐Ÿ™…โ€โ™€๏ธ. The RTP sequence number can't be inferred from the DCCP sequence number either [RFC3550]. And removing RTP's sequence number wouldn't save any header space because of alignment issues ๐Ÿ“. So we recommend that RTP transmitted over DCCP use the same headers currently defined ๐Ÿ’–. The 4 byte header cost is a reasonable tradeoff for DCCP's congestion control features and access to ECN โšก. Truly bandwidth-starved endpoints should use some header compression scheme ๐Ÿ—œ๏ธ.

17.2. Congestion Manager and Multiplexing ๐Ÿงฉ

Since DCCP doesn't provide reliable, ordered delivery, multiple application sub-flows can be multiplexed over a single DCCP connection with no inherent performance penalty ๐Ÿ™Œ. So there's no need for DCCP to have built-in support for multiple sub-flows ๐Ÿซถ. This is different from SCTP [RFC2960] ๐Ÿ”€.

Some applications might want to share congestion control state among multiple DCCP flows that share the same source and destination addresses ๐Ÿค. That could be handled by the Congestion Manager [RFC3124], a generic multiplexing facility ๐Ÿงฐ. However, the CM wouldn't fully support DCCP without changes. For example, it doesn't gracefully handle multiple congestion control mechanisms ๐Ÿ˜ฌ.

18. Security Considerations ๐Ÿ”

DCCP doesn't provide cryptographic security guarantees ๐Ÿ™ˆ. Applications that want cryptographic security services (integrity, authentication, confidentiality, access control, and anti-replay protection) should use IPsec or some other kind of end-to-end security ๐Ÿ”’. Secure RTP is one candidate protocol [RFC3711] ๐Ÿ’œ.

That said, DCCP is designed to protect against some classes of attackers ๐Ÿ›ก๏ธ. Attackers can't hijack a DCCP connection (closing it unexpectedly, or getting attacker data accepted by an endpoint as if it came from the sender) unless they can guess valid sequence numbers ๐ŸŽฏ. So as long as endpoints choose initial sequence numbers well, a DCCP attacker has to snoop on data packets to have any reasonable chance of success ๐Ÿ‘€. Sequence number validity checks provide this guarantee โœ…. Section 7.5.5 describes sequence number security further ๐Ÿ“–. This security property only holds if DCCP's random numbers are chosen according to the guidelines in [RFC4086] ๐ŸŽฒ.

DCCP also provides mechanisms to limit the potential impact of some denial-of-service attacks ๐Ÿšจ. These mechanisms include Init Cookie (Section 8.1.4), the DCCP-CloseReq packet (Section 5.5), the Application Not Listening Drop Code (Section 11.7.2), limitations on the processing of options that might cause connection reset (Section 7.5.5), limitations on the processing of some ICMP messages (Section 14.1), and various rate limits, which let servers avoid extensive computation or packet generation (Sections 7.5.3, 8.1.3, and others) ๐Ÿงฑ.

DCCP provides no protection against attackers that can snoop on data packets ๐Ÿ˜ฑ. If someone can read the packets, DCCP can't save you on its own ๐Ÿšซ๐Ÿซ .

18.1. Security Considerations for Partial Checksums

okay so partial checksums have their own security drama ๐Ÿ˜ญ๐ŸŽ€, especially when they mix with authentication and encryption. It's the same story in DCCP as in UDP-Lite, and this part was adapted from the matching UDP-Lite text [RFC3828] ๐Ÿฆ‹.

When a DCCP packet's Checksum Coverage field is not zero, the uncovered part of the packet can change in transit ๐Ÿ‘€. That's kinda the opposite of what authentication wants, bestie ๐Ÿ’€, because authentication only passes if the packet hasn't changed in transit. Unless authentication mechanisms that only look at the sensitive part of packets get developed and actually used, authentication will always fail for partially-checksummed DCCP packets whose uncovered part got damaged ๐Ÿ˜ญ.

The IPsec integrity check (Encapsulation Security Protocol, ESP, or Authentication Header, AH) covers (at least) the entire IP packet payload ๐Ÿ”. So if any bit in that area gets corrupted, the IP receiver throws the DCCP packet away, even when the corruption landed in the uncovered part of the DCCP application data ๐Ÿ’….

When IPsec is used with ESP payload encryption, a link can't figure out the specific transport protocol of a forwarded packet just by peeking at the IP packet payload ๐Ÿ™ˆ. In that case the link MUST provide a standard integrity check covering the entire IP packet and payload. DCCP partial checksums give no benefit here, periodt ๐Ÿ’….

Encryption (at the transport or application levels, for example) may be used ๐ŸŒธ. Note that skipping an integrity check can, in some circumstances, compromise confidentiality [B98] โœจ.

If a few bits of an encrypted packet get damaged, the decryption transform will typically spread the errors around until the packet is too wrecked to be useful ๐Ÿ˜ญ. Lots of encryption transforms today act exactly like this. There are stream ciphers that don't cause error propagation, but using them properly is genuinely tricky, especially when authentication checking gets skipped [BB01] ๐Ÿงš. The scary part is that an attacker can cause predictable changes to the final plaintext, even without being able to decrypt the ciphertext ๐Ÿ’€.

Main character attacker energy alert ๐Ÿšจ: predictable plaintext changes can happen without the attacker ever decrypting anything. Don't skip the checks! ๐Ÿ˜ค

19. IANA Considerations

IANA has assigned IP Protocol Number 33 to DCCP ๐Ÿฆ‹.

DCCP brings in eight sets of numbers that IANA should allocate values for ๐Ÿ”ข. We point to allocation policies, like Standards Action, outlined in [RFC2434], and most registries keep some values aside for experimental and testing use [RFC3692] ๐Ÿงช. DCCP also needs the IANA Port Numbers registry opened up for DCCP port registrations, and Section 19.9 explains how ๐ŸŒธ. IANA should feel totally free to contact the DCCP Expert Reviewer with questions on any registry, whatever the registry policy, for clarification or if there's a problem with a request ๐Ÿซถ.

19.1. Packet Types Registry

Each entry in the DCCP Packet Types registry has a packet type, which is a number in the range 0-15; a packet type name, like DCCP-Request; and a reference to the RFC that defines the packet type ๐Ÿ“‹. The registry starts out populated with the values from Table 1 (Section 5.1). This document allocates packet types 0-9, and packet type 14 is permanently reserved for experimental and testing use ๐Ÿงช. Packet types 10-13 and 15 are currently reserved and should be allocated with the Standards Action policy, which requires IESG review and approval and standards-track IETF RFC publication ๐Ÿ’….

19.2. Reset Codes Registry

Each entry in the DCCP Reset Codes registry has a Reset Code, which is a number in the range 0-255; a short description of the Reset Code, like "No Connection"; and a reference to the RFC that defines the Reset Code ๐Ÿ“‹. The registry starts out populated with the values from Table 2 (Section 5.6). This document allocates Reset Codes 0-11, and Reset Codes 120-126 are permanently reserved for experimental and testing use ๐Ÿงช. Reset Codes 12-119 and 127 are currently reserved and should be allocated with the IETF Consensus policy, which requires an IETF RFC publication (standards track or not) with IESG review and approval ๐Ÿ’…. Reset Codes 128-255 are permanently reserved for CCID-specific registries, and each CCID Profile document describes how its registry gets managed ๐ŸŒˆ.

19.3. Option Types Registry

Each entry in the DCCP option types registry has an option type, which is a number in the range 0-255; the name of the option, like "Slow Receiver"; and a reference to the RFC that defines the option type ๐Ÿ“‹. The registry starts out populated with the values from Table 3 (Section 5.8). This document allocates option types 0-2 and 32-44, and option types 31 and 120-126 are permanently reserved for experimental and testing use ๐Ÿงช. Option types 3-30, 45-119, and 127 are currently reserved and should be allocated with the IETF Consensus policy, which requires an IETF RFC publication (standards track or not) with IESG review and approval ๐Ÿ’…. Option types 128-255 are permanently reserved for CCID-specific registries, and each CCID Profile document describes how its registry gets managed ๐ŸŒˆ.

19.4. Feature Numbers Registry

Each entry in the DCCP feature numbers registry has a feature number, which is a number in the range 0-255; the name of the feature, like "ECN Incapable"; and a reference to the RFC that defines the feature number ๐Ÿ“‹. The registry starts out populated with the values from Table 4 (Section 6). This document allocates feature numbers 0-9, and feature numbers 120-126 are permanently reserved for experimental and testing use ๐Ÿงช. Feature numbers 10-119 and 127 are currently reserved and should be allocated with the IETF Consensus policy, which requires an IETF RFC publication (standards track or not) with IESG review and approval ๐Ÿ’…. Feature numbers 128-255 are permanently reserved for CCID-specific registries, and each CCID Profile document describes how its registry gets managed ๐ŸŒˆ.

19.5. Congestion Control Identifiers Registry

Each entry in the DCCP Congestion Control Identifiers (CCIDs) registry has a CCID, which is a number in the range 0-255; the name of the CCID, like "TCP-like Congestion Control"; and a reference to the RFC that defines the CCID ๐Ÿ“‹. The registry starts out populated with the values from Table 5 (Section 10). CCIDs 2 and 3 are allocated by concurrently published profiles, and CCIDs 248-254 are permanently reserved for experimental and testing use ๐Ÿงช. CCIDs 0, 1, 4-247, and 255 are currently reserved and should be allocated with the IETF Consensus policy, which requires an IETF RFC publication (standards track or not) with IESG review and approval ๐Ÿ’….

19.6. Ack Vector States Registry

Each entry in the DCCP Ack Vector States registry has an Ack Vector State, which is a number in the range 0-3; the name of the State, like "Received ECN Marked"; and a reference to the RFC that defines the State ๐Ÿ“‹. The registry starts out populated with the values from Table 6 (Section 11.4). This document allocates States 0, 1, and 3. State 2 is currently reserved and should be allocated with the Standards Action policy, which requires IESG review and approval and standards-track IETF RFC publication ๐Ÿ’….

19.7. Drop Codes Registry

Each entry in the DCCP Drop Codes registry has a Data Dropped Drop Code, which is a number in the range 0-7; the name of the Drop Code, like "Application Not Listening"; and a reference to the RFC that defines the Drop Code ๐Ÿ“‹. The registry starts out populated with the values from Table 7 (Section 11.7). This document allocates Drop Codes 0-3 and 7. Drop Codes 4-6 are currently reserved and should be allocated with the Standards Action policy, which requires IESG review and approval and standards-track IETF RFC publication ๐Ÿ’….

19.8. Service Codes Registry

Each entry in the Service Codes registry has a Service Code, which is a number in the range 0-4294967294; a short English description of the intended service; and an optional reference to an RFC or other publicly available specification that defines the Service Code ๐Ÿ“‹. The registry should list the Service Code's numeric value as a decimal number ๐Ÿ”ข. When the Service Code may be represented in "SC:" format under the rules in Section 8.1.2, the registry should also show the matching ASCII interpretation of the Service Code minus the "SC:" prefix. So the number 1717858426 would also show up as "fdpz" โœจ. Service Codes aren't DCCP-specific ๐ŸŒ. Service Code 0 is permanently reserved (it stands for the absence of a meaningful Service Code), and Service Codes 1056964608-1073741823 (high byte ASCII "?") are reserved for Private Use ๐Ÿ”’. Note that 4294967295 is not a valid Service Code ๐Ÿšซ. Most of the remaining Service Codes are allocated First Come First Served, with no RFC publication required, and the exceptions are listed in Section 8.1.2 ๐ŸŽ€. This document allocates a single Service Code, 1145656131 ("DISC") ๐ŸŽง. It corresponds to the discard service, which throws away all data sent to it and sends no data in reply ๐Ÿ—‘๏ธ๐Ÿ’–.

19.9. Port Numbers Registry ๐ŸŽ€

okay bestie, DCCP services can use contact port numbers to serve unknown callers, just like TCP and UDP ๐Ÿฆ‹ so IANA is being asked to open up the existing Port Numbers registry for DCCP using some rules that are meant to mesh nicely with the existing Port Numbers registration procedures โœจ

Port numbers are split into three ranges. The Well Known Ports are 0 through 1023 ๐ŸŒธ, the Registered Ports are 1024 through 49151 ๐Ÿ’œ, and the Dynamic and/or Private Ports are 49152 through 65535 โœจ. Well Known and Registered Ports are meant for server apps that want a default contact point on a system. On most systems, Well Known Ports can only be used by system (or root) processes or by programs run by privileged users, while Registered Ports can be used by ordinary user processes or programs run by ordinary users ๐Ÿ’…. Dynamic and/or Private Ports are for temporary stuff, like client-side ports, out-of-band negotiated ports, and app testing before a dedicated port gets registered, so they MUST NOT be registered ๐Ÿ™ˆ

The Port Numbers registry should accept registrations for DCCP ports in the Well Known Ports and Registered Ports ranges. Well Known and Registered Ports SHOULD NOT be used without registration. I know it can feel totally natural to grab a DCCP port before registration finishes, especially when you're porting an app from UDP to DCCP ๐Ÿซถ but we really want to emphasize that IANA will not guarantee registration of particular Well Known and Registered Ports. So request your registrations as early as possible, bestie ๐Ÿ“

Each port registration SHALL include the following information:

  • A short port name, consisting entirely of letters (A-Z and a-z), digits (0-9), and punctuation characters from "-_+./*" (not including the quotes).
  • The port number that is requested to be registered.
  • A short English phrase describing the port's purpose. This MUST include one or more space-separated textual Service Code descriptors naming the port's corresponding Service Codes (see Section 8.1.2).
  • Name and contact information for the person or entity performing the registration, and possibly a reference to a document defining the port's use. Registrations coming from IETF working groups need only name the working group, but indicating a contact person is recommended ๐ŸŒˆ

Registrants are encouraged to follow these guidelines when submitting a registration. Here's the vibe check:

  • A port name SHOULD NOT be registered for more than one DCCP port number.
  • A port name registered for UDP MAY be registered for DCCP as well. Any such registration SHOULD use the same port number as the existing UDP registration.
  • Concrete intent to use a port SHOULD precede port registration. For example, existing UDP ports SHOULD NOT be registered in advance of any intent to use those ports for DCCP ๐Ÿงš
  • A port name generally associated with TCP and/or SCTP SHOULD NOT be registered for DCCP, since that port name implies reliable transport. For example, we discourage registration of any "http" port for DCCP. However, if such a registration makes sense (that is, if there is concrete intent to use such a port), the DCCP registration SHOULD use the same port number as the existing registration.
  • Multiple DCCP registrations for the same port number are allowed as long as the registrations' Service Codes do not overlap.

This document registers the following port. (This should be considered a model registration.)

discard    9/dccp    Discard SC:DISC
# IETF dccp WG, Eddie Kohler <kohler@cs.ucla.edu>, [RFC4340]

The discard service, which accepts DCCP connections on port 9, discards all incoming application data and sends no data in response. So DCCP's discard port is analogous to TCP's discard port, and it might be used to check the health of a DCCP stack ๐Ÿซง


20. Thanks ๐Ÿซถ

Thanks to Jitendra Padhye for his help with early versions of this specification ๐Ÿ’–

Thanks to Junwen Lai and Arun Venkataramani, who, as interns at ICIR, built a prototype DCCP implementation. In particular, Junwen Lai recommended that the old feature negotiation mechanism be scrapped and co-designed the current mechanism ๐Ÿ‘‘ Arun Venkataramani's feedback improved Appendix A.

We thank the staff and interns of ICIR and, formerly, ACIRI, the members of the End-to-End Research Group, and the members of the Transport Area Working Group for their feedback on DCCP. We especially thank the DCCP expert reviewers Greg Minshall, Eric Rescorla, and Magnus Westerlund for detailed written comments and problem spotting, and Rob Austein and Steve Bellovin for verbal comments and written notes. We also especially thank Aaron Falk, the working group chair during the development of this specification ๐ŸŒธ

We also thank those who provided comments and suggestions via the DCCP BOF, Working Group, and mailing lists, including Damon Lanphear, Patrick McManus, Colin Perkins, Sara Karlberg, Kevin Lai, Bernard Aboba, Youngsoo Choi, Pengfei Di, Dan Duchamp, Lars Eggert, Gorry Fairhurst, Derek Fawcus, David Timothy Fleeman, John Loughney, Ghyslain Pelletier, Hagen Paul Pfeifer, Tom Phelan, Stanislav Shalunov, Somsak Vanit-Anunchai, David Vos, Yufei Wang, and Michael Welzl. In particular, Colin Perkins provided extensive, detailed feedback, Michael Welzl suggested the Data Checksum option, Gorry Fairhurst provided extensive feedback on various checksum issues, and Somsak Vanit-Anunchai, Jonathan Billington, and Tul Kongprakaiwoot's Colored Petri Net model [VBK05] discovered several problems with message exchange ๐Ÿฅน๐Ÿ’œ


A. Appendix: Ack Vector Implementation Notes ๐ŸŒˆ

This appendix discusses particulars of DCCP acknowledgement handling in the context of an abstract implementation for Ack Vector. It is informative and not normative.

The first part of our implementation runs at the HC-Receiver, and therefore acknowledges data packets. It generates Ack Vector options. The implementation has the following characteristics:

  • At most one byte of state per acknowledged packet.
  • O(1) time to update that state when a new packet arrives (normal case).
  • Cumulative acknowledgements.
  • Quick removal of old state.

The basic data structure is a circular buffer containing information about acknowledged packets. Each byte in this buffer contains a state and run length; the state can be 0 (packet received), 1 (packet ECN marked), or 3 (packet not yet received). The buffer grows from right to left. The implementation maintains five variables, aside from the buffer contents:

  • "buf_head" and "buf_tail", which mark the live portion of the buffer.
  • "buf_ackno", the Acknowledgement Number of the most recent packet acknowledged in the buffer. This corresponds to the "head" pointer.
  • "buf_nonce", the one-bit sum (exclusive-or, or parity) of the ECN Nonces received on all packets acknowledged by the buffer with State 0.

We draw acknowledgement buffers like this:

      +---------------------------------------------------------------+
      |S,L|S,L|S,L|S,L|   |   |   |   |S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|
      +---------------------------------------------------------------+
                    ^                   ^
                 buf_tail     buf_head, buf_ackno = A     buf_nonce = E

                <=== buf_head and buf_tail move this way <===

Each S,L represents a State/Run length byte. We will draw these buffers showing only their live portion and will add an annotation showing the Acknowledgement Number for the last live byte in the buffer. For example:

        +-----------------------------------------------+
      A |S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L|S,L| T    BN[E]
        +-----------------------------------------------+

Here, buf_nonce equals E and buf_ackno equals A.

We will use this buffer as a running example. ๐Ÿฆ‹

         +---------------------------+
      10 |0,0|3,0|3,0|3,0|0,4|1,0|0,0| 0    BN[1]   [Example Buffer]
         +---------------------------+

In concrete terms, its meaning is as follows:

Packet 10 was received. (The head of the buffer has sequence number 10, state 0, and run length 0.)

Packets 9, 8, and 7 have not yet been received. (The three bytes preceding the head each have state 3 and run length 0.)

Packets 6, 5, 4, 3, and 2 were received.

Packet 1 was ECN marked.

Packet 0 was received.

The one-bit sum of the ECN Nonces on packets 10, 6, 5, 4, 3, 2, and 0 equals 1.

Additionally, the HC-Receiver must keep some information about the Ack Vectors it has recently sent. For each packet sent carrying an Ack Vector, it remembers four variables:

  • "ack_seqno", the Sequence Number used for the packet. This is an HC-Receiver sequence number.
  • "ack_ptr", the value of buf_head at the time of acknowledgement.
  • "ack_runlen", the run length stored in the byte of buffer data at buf_head at the time of acknowledgement.
  • "ack_ackno", the Acknowledgement Number used for the packet. This is an HC-Sender sequence number. Since acknowledgements are cumulative, this single number completely specifies all necessary information about the packets acknowledged by this Ack Vector.
  • "ack_nonce", the one-bit sum of the ECN Nonces for all State 0 packets in the buffer from buf_head to ack_ackno, inclusive. Initially, this equals the Nonce Echo of the acknowledgement's Ack Vector (or, if the ack packet contained more than one Ack Vector, the exclusive-or of all the acknowledgement's Ack Vectors). It changes as information about old acknowledgements is removed (so ack_ptr and buf_head diverge) and as old packets arrive (so they change from State 3 or State 1 to State 0). this one is a bit of a brain-melter, but it's giving careful bookkeeping ๐Ÿง โœจ

A.1. Packet Arrival ๐Ÿ’…

This section describes how the HC-Receiver updates its acknowledgement buffer as packets arrive from the HC-Sender.

A.1.1. New Packets

okay bestie ๐Ÿ’– picture this: a packet shows up with a Sequence Number bigger than buf_ackno ๐Ÿฆ‹ that's a brand new arrival! The HC-Receiver has to update its bookkeeping: it moves buf_head to the left as needed, sets buf_ackno to the new packet's Sequence Number โœจ, and maybe updates buf_nonce if the packet came in unmarked with ECN Nonce 1. The buffer itself gets updated too, obviously ๐Ÿ’….

Say HC-Sender packet 11 arrived ECN marked. The Example Buffer above would enter this new state, with the changes shown as stars โญ:

         ** +***----------------------------+
         11 |1,0|0,0|3,0|3,0|3,0|0,4|1,0|0,0| 0    BN[1]
         ** +***----------------------------+

If the new packet's state matches the state at the head of the buffer, the HC-Receiver may choose to bump its run length (up to the maximum) ๐Ÿ“. So if HC-Sender packet 11 arrived without ECN marking and with ECN Nonce 0, the Example Buffer might enter this state instead:

             ** +--*------------------------+
             11 |0,1|3,0|3,0|3,0|0,4|1,0|0,0| 0    BN[1]
             ** +--*------------------------+

Of course, the new packet's sequence number might not be the one we expected ๐Ÿ™ˆ. In that case, the HC-Receiver will enter the packets in between as State 3. If several packets are missing, the HC-Receiver may prefer to enter multiple bytes with run length 0, instead of one byte with a bigger run length. This is lowkey genius because it makes table updates easier if one of the missing packets shows up later ๐Ÿงš. For example, if HC-Sender packet 12 arrived with ECN Nonce 1, the Example Buffer would enter this state:

      ** +*******----------------------------+         *
      12 |0,0|3,0|0,1|3,0|3,0|3,0|0,4|1,0|0,0| 0    BN[0]
      ** +*******----------------------------+         *

Also, the circular buffer can overflow ๐Ÿ˜ญ. That happens when the HC-Sender is sending data at a very high rate, when the HC-Receiver's acknowledgements aren't reaching the HC-Sender, or when the HC-Sender keeps forgetting to acknowledge those acks (so the HC-Receiver can't clean up old state). When that happens, the HC-Receiver should either compress the buffer (by increasing run lengths when possible), move its state to a larger buffer, or, as a last resort, drop all received packets without processing them at all until its buffer shrinks again ๐Ÿ’€.

A.1.2. Old Packets

When a packet with Sequence Number S <= buf_ackno arrives, the HC-Receiver will scan the table for the byte that matches S. (Indexing structures could make this scan faster ๐ŸŒˆ.) If S was previously lost (State 3) and it was stored in a byte with run length 0, the HC-Receiver can simply change that byte's state. For example, if HC-Sender packet 8 was received with ECN Nonce 0, the Example Buffer would enter this state:

               +--------*------------------+
            10 |0,0|3,0|0,0|3,0|0,4|1,0|0,0| 0    BN[1]
               +--------*------------------+

If S wasn't marked as lost, or if it wasn't in the table at all, the packet is probably a duplicate and should be ignored ๐Ÿ™…โ€โ™€๏ธ. (The new packet's ECN marking state might differ from the state in the buffer. Section 11.4.1 describes what's allowed then.) If S's buffer byte has a non-zero run length, then the buffer might need to be reshuffled to make room for one or two new bytes.

The ack_nonce fields may also need some work when old packets show up ๐Ÿฆ‹. In particular, when S moves from State 3 or State 1 to State 0, and S had ECN Nonce 1, then the implementation should flip the value of ack_nonce for every acknowledgement with ack_ackno >= S.

It is impossible with this data structure to move packets from State 0 to State 1, since the buffer doesn't store each packet's ECN Nonce ๐Ÿ™ƒ.

A.2. Sending Acknowledgements

Whenever the HC-Receiver needs to generate an acknowledgement, the buffer's contents can be copied straight into one or more Ack Vector options ๐ŸŽ€. Copied Ack Vectors might not be maximally compressed, though. For example, the Example Buffer above has three adjacent 3,0 bytes that could be combined into one 3,2 byte. So the HC-Receiver might compress the buffer in place before sending the option, or compress it while copying. Either way, it's simple ๐Ÿ’….

Every acknowledgement sent by the HC-Receiver SHOULD include the entire state of the buffer. That means acknowledgements are cumulative ๐Ÿซถ.

If the acknowledgement fits in one Ack Vector, that Ack Vector's Nonce Echo is just equal to buf_nonce. For multiple Ack Vectors, it takes more care ๐Ÿง . The Ack Vectors should be split at points that match previous acknowledgements, since the stored ack_nonce fields have enough info to calculate correct Nonce Echoes. So the implementation should acknowledge data at least once per 253 bytes of buffer state. (Otherwise there'd be no way to calculate a Nonce Echo ๐Ÿ˜ญ.)

For each acknowledgement it sends, the HC-Receiver adds an acknowledgement record โœจ. Here's how the fields get filled in: ack_seqno equals the HC-Receiver sequence number it used for the ack packet; ack_ptr equals buf_head; ack_runlen equals the run length stored in the buffer's buf_head byte; ack_ackno equals buf_ackno; and ack_nonce equals buf_nonce.

A.3. Clearing State

Some of the HC-Sender's packets include acknowledgement numbers, which ack the HC-Receiver's acknowledgements ๐Ÿ’Œ. When one of those acks arrives, the HC-Receiver finds the acknowledgement record R with the matching ack_seqno and then does the following:

  • If the run length in the buffer's R.ack_ptr byte is greater than R.ack_runlen, then it decrements that run length by R.ack_runlen + 1 and sets buf_tail to R.ack_ptr. Otherwise, it sets buf_tail to R.ack_ptr + 1.
  • If R.ack_nonce is 1, it flips buf_nonce, and the value of ack_nonce for every later ack record.
  • It throws away R and every preceding ack record.

(The HC-Receiver may choose to keep some older info, in case a lost packet shows up late ๐Ÿ•ฐ๏ธ.) Let's say the HC-Receiver storing the Example Buffer had already sent two acknowledgements:

  1. ack_seqno = 59, ack_runlen = 1, ack_ackno = 3, ack_nonce = 1.
  2. ack_seqno = 60, ack_runlen = 0, ack_ackno = 10, ack_nonce = 0.

Now say the HC-Receiver gets a DCCP-DataAck packet with Acknowledgement Number 59 from the HC-Sender ๐Ÿ“ฌ. This tells the HC-Receiver that the HC-Sender got and processed all the info in HC-Receiver packet 59. That packet acknowledged HC-Sender packet 3, so the HC-Sender has now received HC-Receiver's acknowledgements for packets 0, 1, 2, and 3. The Example Buffer should enter this state:

               +------------------*+ *       *
            10 |0,0|3,0|3,0|3,0|0,2| 4    BN[0]
               +------------------*+ *       *

The tail byte's run length got adjusted, since packet 3 was in the middle of that byte. Since R.ack_nonce was 1, the buf_nonce field got flipped, and so did the ack_nonce fields for the later acknowledgements (here, the HC-Receiver Ack 60 record, not shown, has its ack_nonce flipped to 1) ๐Ÿ”„. The HC-Receiver can also throw away stored info about HC-Receiver Ack 59 and any earlier acknowledgements.

A careful implementation might try to stay reasonably robust to reordering ๐ŸŽข. Suppose the Example Buffer is the same as before, but packet 9 now arrives out of sequence. The buffer would enter this state:

                +----*----------------------+
             10 |0,0|0,0|3,0|3,0|0,4|1,0|0,0| 0     BN[1]
                +----*----------------------+

Here's the danger ๐Ÿ˜ฑ: the HC-Sender might acknowledge the HC-Receiver's previous acknowledgement (with sequence number 60), which says packet 9 wasn't received, before the HC-Receiver gets a chance to send a new acknowledgement saying packet 9 actually was received. So when packet 9 arrived, the HC-Receiver might change its acknowledgement records like this:

  1. ack_seqno = 59, ack_ackno = 3, ack_nonce = 1.
  2. ack_seqno = 60, ack_ackno = 3, ack_nonce = 1.

That means Ack 60 is now treated like a duplicate of Ack 59 ๐Ÿ‘ฏ. This keeps the Tail pointer from moving past packet 9 until the HC-Receiver knows the HC-Sender has seen an Ack Vector showing that packet's arrival ๐Ÿซง.

A.4. Processing Acknowledgements

When the HC-Sender gets an acknowledgement, it mostly cares about how many packets were dropped and/or ECN marked ๐Ÿ“Š. It just reads that straight off the Ack Vector. It should also check the ECN Nonce for correctness ๐Ÿ”. (As described in Section 11.4.1, it may want to keep more detailed info about acknowledged packets, in case packets change states between acknowledgements, or in case the application asks whether a packet arrived.)

The HC-Sender must also acknowledge the HC-Receiver's acknowledgements so the HC-Receiver can free old Ack Vector state ๐Ÿงน. (Since Ack Vector acknowledgements are reliable, the HC-Receiver must keep and resend Ack Vector info until it's sure the HC-Sender got that info.) A simple algorithm does the job: since Ack Vector acknowledgements are cumulative, a single acknowledgement number tells the HC-Receiver how much ack info has arrived. Assuming the HC-Receiver sends no data, the HC-Sender can make sure that at least once per round-trip time, it sends a DCCP-DataAck packet acknowledging the latest DCCP-Ack packet it has received ๐Ÿ”. Of course, the HC-Sender only needs to acknowledge the HC-Receiver's acknowledgements if it's also sending data. If the HC-Sender isn't sending data, the HC-Receiver's Ack Vector state is stable, so there's no need to shrink it ๐Ÿ˜Œ. The HC-Sender must also watch for drops and ECN marks on received DCCP-Ack packets, so it can adjust the HC-Receiver's ack-sending rate in response to congestion, for example, with Ack Ratio ๐Ÿšฆ.

If the other half-connection is not quiescent -- that is, the HC-Receiver is sending data to the HC-Sender, possibly using another CCID -- then the acknowledgements on that half-connection are enough for the HC-Receiver to free its state ๐ŸŒธ.

B. Appendix: Partial Checksumming Design Motivation ๐ŸŽ€

okay so there has been SO much debate ๐Ÿ˜ญ about letting a DCCP sender limit the checksum so it doesn't cover the whole packet. this appendix is where we dump the reasoning behind some of the specific DCCP design choices ๐Ÿ’…

Lots of the apps we're imagining for DCCP can handle some data loss, or they would've just picked a reliable transport ๐Ÿ™„. Some can even handle data corruption (think audio payloads ๐ŸŽง). These chill apps might honestly prefer getting corrupted data over having DCCP toss the corrupted packets. The big reason is congestion control. DCCP can't tell the difference between packets dropped because of corruption and packets dropped because of congestion, so it has to lower its sending rate accordingly ๐Ÿ“‰. That response might leave the connection with less bandwidth than it's due, since corruption on some networking technologies is independent of congestion, or at least not always linked to it. So corrupted packets don't need to cause as strong a rate reduction as the congestion response would dictate (as long as the DCCP header and options aren't corrupt) โœจ.

So DCCP lets the checksum cover all of the packet, just the DCCP header, or the DCCP header plus some number of bytes from the application data. If the app can't handle any corruption, the checksum must cover the whole packet ๐Ÿšซ. If the app would rather tolerate some corruption than have the packet dropped, it can set the checksum to cover only part of the packet (but always the DCCP header, periodt ๐Ÿ’–). And if the app wants to decouple checksumming of the DCCP header from checksumming of the application data, it may do so by including the Data Checksum option. That lets DCCP discard corrupted application data without mistaking the corruption for network congestion ๐Ÿ™Œ.

From the app's point of view, partial checksums seem like a lowkey iconic feature ๐Ÿ‘‘. BUT they only work if partially corrupted packets actually get delivered to the receiver. If the link-layer CRC always discards corrupted packets, then that never happens, and partial checksums would only matter for corruption that happens in routers and other places not covered by link CRCs ๐Ÿคท. There isn't consensus on how likely it is that future network links with serious corruption won't cover the entire packet with a single strong CRC. DCCP makes it possible to tailor such links to the application, but it's hard to predict whether that'll be compelling for future link technologies ๐Ÿ”ฎ.

Partial checksums also don't vibe well with IP-level authentication mechanisms like IPsec AH, which cover the entire packet with a cryptographic hash ๐Ÿ’€. So if cryptographic authentication has to co-exist with partial checksums, the authentication must be carried in the application data. A possible mode of usage would look similar to Secure RTP ๐Ÿ”. However, that "application-level" authentication does not protect the DCCP option negotiation and state machine from forged packets ๐Ÿ˜ฌ. An alternative is to use IPsec ESP and use encryption to protect the DCCP headers against attack, while using the DCCP header validity checks to authenticate that the header is from someone who had the correct key. This is resistant to replay (thanks to the DCCP sequence number), but it's not by itself resistant to some forms of man-in-the-middle attacks, because the application data isn't tightly coupled to the packet header ๐Ÿซ . So application-level authentication probably needs to be coupled with IPsec ESP or a similar mechanism to provide a reasonably complete security solution. The overhead of such a solution might be unacceptable for some apps that would otherwise want to use partial checksums ๐Ÿ’ธ.

On balance, the authors believe DCCP partial checksums have the potential to enable some future uses that would otherwise be difficult ๐Ÿฆ‹. Since the cost and complexity of supporting them is small, it seems worth including them at this time. Whether they're actually useful in practice remains to be seen ๐Ÿงš.


Normative References ๐Ÿ“š

   [RFC793]       Postel, J., "Transmission Control Protocol", STD 7,
                  RFC 793, September 1981.

   [RFC1191]      Mogul, J. and S. Deering, "Path MTU discovery", RFC
                  1191, November 1990.

   [RFC2119]      Bradner, S., "Key words for use in RFCs to Indicate
                  Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC2434]      Narten, T. and H. Alvestrand, "Guidelines for Writing
                  an IANA Considerations Section in RFCs", BCP 26, RFC
                  2434, October 1998.

   [RFC2460]      Deering, S. and R. Hinden, "Internet Protocol, Version
                  6 (IPv6) Specification", RFC 2460, December 1998.

   [RFC3168]      Ramakrishnan, K., Floyd, S., and D. Black, "The
                  Addition of Explicit Congestion Notification (ECN) to
                  IP", RFC 3168, September 2001.

   [RFC3309]      Stone, J., Stewart, R., and D. Otis, "Stream Control
                  Transmission Protocol (SCTP) Checksum Change", RFC
                  3309, September 2002.

   [RFC3692]      Narten, T., "Assigning Experimental and Testing
                  Numbers Considered Useful", BCP 82, RFC 3692, January
                  2004.

   [RFC3775]      Johnson, D., Perkins, C., and J. Arkko, "Mobility
                  Support in IPv6", RFC 3775, June 2004.

   [RFC3828]      Larzon, L-A., Degermark, M., Pink, S., Jonsson, L-E.,
                  and G. Fairhurst, "The Lightweight User Datagram
                  Protocol (UDP-Lite)", RFC 3828, July 2004.

Informative References ๐Ÿ”

   [B98]          Bellovin, S.M., "Cryptography and the Internet",
                  CRYPTO '98 (LNCS 1462), pp 46-55, August 1988.

   [BB01]         Bellovin, S.M. and M. Blaze, "Cryptographic Modes of
                  Operation for the Internet", 2nd NIST Workshop on
                  Modes of Operation, August 2001.

   [M85]          Morris, R.T., "A Weakness in the 4.2BSD Unix TCP/IP
                  Software", Computer Science Technical Report 117, AT&T
                  Bell Laboratories, Murray Hill, NJ, February 1985.

   [PMTUD]        Mathis, M. and J. Heffner, "Path MTU Discovery", Work
                  in Progress, March 2006.

   [RFC792]       Postel, J., "Internet Control Message Protocol", STD
                  5, RFC 792, September 1981.

   [RFC1812]      Baker, F., "Requirements for IP Version 4 Routers",
                  RFC 1812, June 1995.

   [RFC1948]      Bellovin, S., "Defending Against Sequence Number
                  Attacks", RFC 1948, May 1996.

   [RFC1982]      Elz, R. and R. Bush, "Serial Number Arithmetic", RFC
                  1982, August 1996.

   [RFC2018]      Mathis, M., Mahdavi, J., Floyd, S., and A. Romanow,
                  "TCP Selective Acknowledgement Options", RFC 2018,
                  October 1996.

   [RFC2401]      Kent, S. and R. Atkinson, "Security Architecture for
                  the Internet Protocol", RFC 2401, November 1998.

   [RFC2463]      Conta, A. and S. Deering, "Internet Control Message
                  Protocol (ICMPv6) for the Internet Protocol Version 6
                  (IPv6) Specification", RFC 2463, December 1998.

   [RFC2581]      Allman, M., Paxson, V., and W. Stevens, "TCP
                  Congestion Control", RFC 2581, April 1999.

   [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, October 2000.

   [RFC3124]      Balakrishnan, H. and S. Seshan, "The Congestion
                  Manager", RFC 3124, June 2001.

   [RFC3360]      Floyd, S., "Inappropriate TCP Resets Considered
                  Harmful", BCP 60, RFC 3360, August 2002.

   [RFC3448]      Handley, M., Floyd, S., Padhye, J., and J. Widmer,
                  "TCP Friendly Rate Control (TFRC): Protocol
                  Specification", RFC 3448, January 2003.

   [RFC3540]      Spring, N., Wetherall, D., and D. Ely, "Robust
                  Explicit Congestion Notification (ECN) Signaling with
                  Nonces", RFC 3540, June 2003.

   [RFC3550]      Schulzrinne, H., Casner, S., Frederick, R., and V.
                  Jacobson, "RTP: A Transport Protocol for Real-Time
                  Applications", STD 64, RFC 3550, July 2003.

   [RFC3611]      Friedman, T., Caceres, R., and A. Clark, "RTP Control
                  Protocol Extended Reports (RTCP XR)", RFC 3611,
                  November 2003.

   [RFC3711]      Baugher, M., McGrew, D., Naslund, M., Carrara, E., and
                  K. Norrman, "The Secure Real-time Transport Protocol
                  (SRTP)", RFC 3711, March 2004.

   [RFC3819]      Karn, P., Bormann, C., Fairhurst, G., Grossman, D.,
                  Ludwig, R., Mahdavi, J., Montenegro, G., Touch, J.,
                  and L. Wood, "Advice for Internet Subnetwork
                  Designers", BCP 89, RFC 3819, July 2004.

   [RFC4086]      Eastlake, D., 3rd, Schiller, J., and S. Crocker,
                  "Randomness Requirements for Security", BCP 106, RFC
                  4086, June 2005.

   [RFC4341]      Floyd, S. and E. Kohler, "Profile for Datagram
                  Congestion Control Protocol (DCCP) Congestion Control
                  ID 2: TCP-like Congestion Control", RFC 4341, March
                  2006.

   [RFC4342]      Floyd, S., Kohler, E., and J. Padhye, "Profile for
                  Datagram Congestion Control Protocol (DCCP) Congestion
                  Control ID 3: TCP-Friendly Rate Control (TFRC)", RFC
                  4342, March 2006.

   [SHHP00]       Spatscheck, O., Hansen, J.S., Hartman, J.H., and L.L.
                  Peterson, "Optimizing TCP Forwarder Performance",
                  IEEE/ACM Transactions on Networking 8(2):146-157,
                  April 2000.

   [SYNCOOKIES]   Bernstein, D.J., "SYN Cookies",
                  http://cr.yp.to/syncookies.html, as of March 2006.

   [VBK05]        Vanit-Anunchai, S., Billington, J., and T.
                  Kongprakaiwoot, "Discovering Chatter and
                  Incompleteness in the Datagram Congestion Control
                  Protocol", FORTE 2005, pp 143-158, October 2005.

Authors' Addresses ๐Ÿ–‹๏ธ

   Eddie Kohler
   4531C Boelter Hall
   UCLA Computer Science Department
   Los Angeles, CA 90095
   USA

   EMail: kohler@cs.ucla.edu


   Mark Handley
   Department of Computer Science
   University College London
   Gower Street
   London WC1E 6BT
   UK

   EMail: M.Handley@cs.ucl.ac.uk


   Sally Floyd
   ICSI Center for Internet Research
   1947 Center Street, Suite 600
   Berkeley, CA 94704
   USA

   EMail: floyd@icir.org

okay so the Internet Society owns the copyright here, 2006, bestie ๐ŸŽ€ This document is subject to the rights, licenses and restrictions in BCP 78, and the authors keep all their rights except where BCP 78 says otherwise ๐Ÿ“œ

THIS DOCUMENT AND THE INFORMATION CONTAINED HEREIN ARE PROVIDED ON AN "AS IS" BASIS AND THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

the TL;DR of that block is "it's provided as is, and nobody's promising it's perfect or non-infringing" ๐Ÿ™ˆ


Intellectual Property ๐Ÿฆ‹

the IETF takes no position on whether any IPR (intellectual property rights) claimed for the tech in this document are valid, how far they reach, or whether any license for them is actually available. it also doesn't claim it has searched for any such rights on its own ๐Ÿ’… if you want the procedures for rights in RFC docs, check BCP 78 and BCP 79 โœจ

copies of IPR disclosures sent to the IETF Secretariat, and any assurances of licenses that may be available, can be found in the IETF on-line IPR repository at http://www.ietf.org/ipr. this also covers any attempt to get a general license or permission for implementers or users of this spec ๐Ÿซถ

and the IETF is literally inviting anyone to say something if they know about copyrights, patents, patent applications, or other proprietary rights that might cover tech needed to implement this standard ๐Ÿ”ฅ send that info to the IETF at ietf-ipr@ietf.org ๐Ÿ’œ


Acknowledgement ๐ŸŒธ

funding for the RFC Editor function comes from the IETF Administrative Support Activity (IASA) ๐Ÿงš literally the people keeping the lights on for all the RFCs โœจ

๐Ÿ“ฆ where this page comes from