2.2. Network Layer
2.2.1. Encapsulation
RTMFP Multiplex packets are usually carried in UDP [RFC0768] datagrams so that they may transit commonly deployed NATs and firewalls, and so that RTMFP may be implemented on commonly deployed operating systems without special privileges or permissions. RTMFP Multiplex packets MAY be carried by any suitable datagram transport or encapsulation where endpoints are addressed by an Internet socket address (that is, an IPv4 or IPv6 address and a 16-bit port number). The choice of port numbers is not mandated by this specification. Higher protocol layers or the application define the port numbers used.2.2.2. Multiplex
0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Scrambled Session ID (SSID) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | e first32[0] | |- - - - - - n - - - - - - - - - - - - - - - - - - - - - - - -| | c first32[1] | +- - - - - - r - - - - - - - - - - - - - - - - - - - - - - - -+ | y | | pted packet | +---------------------------------------------------------------/ struct multiplex_t { uint32_t scrambledSessionID; // "SSID" union { uint32_t first32[2]; // see note uint8_t encryptedPacket[remainder()]; } :(encapsulation.length - 4)*8; // if encryptedPacket is less than 8 bytes long, treat it // as if it were end-padded with 0s for the following: sessionID = scrambledSessionID XOR first32[0] XOR first32[1]; } :encapsulation.length*8;
The 32-bit Scrambled Session ID is the 32-bit session ID modified by performing a bitwise exclusive-or with the bitwise exclusive-or of the first two 32-bit words of the encrypted packet. The session ID is a 32-bit value that the receiver has requested to be used by the sender when sending packets to this receiver (Sections 2.3.7 and 2.3.8). The session ID identifies the session to which this packet belongs and the decryption key to be used to decrypt the encrypted packet. Note: Session ID 0 (prior to scrambling) denotes the startup pseudo- session and implies the Default Session Key. Note: If the encrypted packet is less than 8 bytes long, then for the scrambling operation, perform the exclusive-or as though the encrypted packet were end-padded with enough 0-bytes to bring its length to 8.2.2.3. Encryption
RTMFP packets are encrypted according to a Cryptography Profile. This specification doesn't define a Cryptography Profile or mandate a particular choice of cryptography. The application defines the cryptographic syntax and algorithms. Packet encryption is RECOMMENDED to be a block cipher operating in Cipher Block Chaining [CBC] or similar mode. Encrypted packets MUST be decipherable without inter-packet dependency, since packets may be lost, duplicated, or reordered in the network. The packet encryption layer is responsible for data integrity and authenticity of packets, for example by means of a checksum or cryptographic message authentication code. To mitigate replay attacks, data integrity SHOULD comprise duplicate packet detection, for example by means of a session-wide packet sequence number. The packet encryption layer SHALL discard a received packet that does not pass integrity or authenticity tests. Note that the structures described below are of plain, unencrypted packets. Encrypted packets MUST be decrypted according to the Session Key associated with the Multiplex Session ID before being interpreted according to this specification. The Cryptography Profile defines a well-known Default Session Key that is used at session startup, during which per-session key(s) are negotiated by the two endpoints. A session ID of zero denotes use of the Default Session Key. The Default Session Key is also used with
non-zero session IDs during the latter phases of session startup (Sections 2.3.6 and 2.3.8). See Security Considerations (Section 5) for more about the Default Session Key.2.2.4. Packet
An (unencrypted, plain) RTMFP packet consists of a variable sized common header, zero or more chunks, and padding. Padding can be inserted by the encryption layer of the sender to meet cipher block size constraints and is ignored by the receiver. A sender's encryption layer MAY pad the end of a packet with bytes with value 0xff such that the resulting packet is a natural and appropriate size for the cipher. Alternatively, the Cryptography Profile MAY define its own framing and padding scheme, if needed, such that decrypted packets are compatible with the syntax defined in this section.
0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |T|T| r |T|T| M | |C|C| s |S|S| O | | |R| v | |E| D | +-+-+-+-+-+-+-+-+ +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+ | if(TS) timestamp | if(TSE) timestampEcho | +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | Chunk | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ : : +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | Chunk | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | padding | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ struct packet_t { bool_t timeCritical :1; // "TC" bool_t timeCriticalReverse :1; // "TCR" uintn_t reserved :2; // "rsv" bool_t timestampPresent :1; // "TS" bool_t timestampEchoPresent :1; // "TSE" uintn_t mode :2; // "MOD" if(0 != mode) { if(timestampPresent) uint16_t timestamp; if(timestampEchoPresent) uint16_t timestampEcho; while(remainder() > 2) { uint8_t chunkType; uint16_t chunkLength; if(remainder() < chunkLength) break; uint8_t chunkPayload[chunkLength]; } // chunks uint8_t padding[remainder()]; } } :plainPacket.length*8;
timeCritical: Time Critical Forward Notification. If set, indicates that this packet contains real-time user data. timeCriticalReverse: Time Critical Reverse Notification. If set, indicates that the sender is currently receiving packets on other sessions that have the timeCritical flag set. timestampPresent: If set, indicates that the timestamp field is present. If clear, there is no timestamp field. timestampEchoPresent: If set, indicates that the timestamp echo field is present. If clear, there is no timestamp echo field. mode: The mode of this packet. See below for additional discussion of packet modes. Possible values are: 0: Forbidden value 1: Initiator Mark 2: Responder Mark 3: Startup timestamp: If the timestampPresent flag is set, this field is present and contains the low 16 bits of the sender's 250 Hz clock (4 milliseconds per tick) at transmit time. The sender's clock MAY have its origin at any time in the past. timestampEcho: If the timestampEchoPresent flag is set, this field is present and contains the sender's estimate of what the timestamp field of a packet received from the other end would be at the time this packet was transmitted, using the method described in Section 3.5.2.2. chunks: Zero or more chunks follow the header. It is RECOMMENDED that a packet contain at least one chunk. padding: Zero or more bytes of padding follow the chunks. The following conditions indicate padding: * Fewer than three bytes (the size of a chunk header) remain in the packet. * The chunkLength field of what would be the current chunk header indicates that the hypothetical chunk payload wouldn't fit in the remaining bytes of the packet.
Packet mode 0 is not allowed. Packets marked with this mode are invalid and MUST be discarded. The original initiator of a session MUST mark all non-startup packets it sends in that session with packet mode 1 ("Initiator Mark"). It SHOULD ignore any packet received in that session with packet mode 1. The original responder of a session MUST mark all non-startup packets it sends in that session with packet mode 2 ("Responder Mark"). It SHOULD ignore any packet received in that session with packet mode 2. Packet mode 3 is for session startup. Session startup chunks are only allowed in packets with this mode. Chunks that are not for session startup are only allowed in packets with modes 1 or 2.2.3. Chunks
0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | chunkType | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | chunkPayload (chunkLength bytes, may be zero) | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ struct chunk_t { uint8_t chunkType; uint16_t chunkLength; uint8_t chunkPayload[chunkLength]; } :variable*8; chunkType: The chunk type code. chunkLength: The size, in bytes, of the chunk payload. chunkPayload: The type-specific payload of this chunk, chunkLength bytes in length (may be empty).
Defined chunk types are enumerated here in the order they might be encountered in the course of a typical session. The following chunk type codes are defined: 0x7f: Packet Fragment (Section 2.3.1) 0x30: Initiator Hello (Section 2.3.2) 0x0f: Forwarded Initiator Hello (Section 2.3.3) 0x70: Responder Hello (Section 2.3.4) 0x71: Responder Redirect (Section 2.3.5) 0x79: RHello Cookie Change (Section 2.3.6) 0x38: Initiator Initial Keying (Section 2.3.7) 0x78: Responder Initial Keying (Section 2.3.8) 0x01: Ping (Section 2.3.9) 0x41: Ping Reply (Section 2.3.10) 0x10: User Data (Section 2.3.11) 0x11: Next User Data (Section 2.3.12) 0x50: Data Acknowledgement Bitmap (Section 2.3.13) 0x51: Data Acknowledgement Ranges (Section 2.3.14) 0x18: Buffer Probe (Section 2.3.15) 0x5e: Flow Exception Report (Section 2.3.16) 0x0c: Session Close Request (Section 2.3.17) 0x4c: Session Close Acknowledgement (Section 2.3.18) 0x00: Ignore/Padding 0xff: Ignore/Padding A receiver MUST ignore a chunk having an unrecognized chunk type code. A receiver MUST ignore a chunk appearing in a packet having a mode inappropriate to that chunk type.
Unless specified otherwise, if a chunk has a syntax or processing error (for example, the chunk's payload field is not long enough to contain the specified syntax elements), the chunk SHALL be ignored as though it was not present in the packet, and parsing and processing SHALL commence with the next chunk in the packet, if any.2.3.1. Packet Fragment Chunk
This chunk is used to divide a plain RTMFP packet (Section 2.2.4) that is unavoidably larger than the path MTU (such as session startup packets containing Responder Hello (Section 2.3.4) or Initiator Initial Keying (Section 2.3.7) chunks with large certificates) into segments that do not exceed the path MTU, and to allow the segments to be sent through the network at a moderated rate to avoid jamming interfaces, links, or paths. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x7f | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-------------/-+-------------/-+ |M| reserved | packetID \ | fragmentNum \ | +-+-+-+-+-+-+-+-+-------------/-+-------------/-+ +---------------------------------------------------------------+ | packetFragment | +---------------------------------------------------------------/ struct fragmentChunkPayload_t { bool_t moreFragments :1; // M uintn_t reserved :7; vlu_t packetID :variable*8; vlu_t fragmentNum :variable*8; uint8_t packetFragment[remainder()]; } :chunkLength*8; moreFragments: If set, the indicated packet comprises additional fragments. If clear, this fragment is the final fragment of the packet. reserved: Reserved for future use. packetID: VLU, the identifier of this segmented packet. All fragments of the same packet have the same packetID. fragmentNum: VLU, the index of this fragment of the indicated packet. The first fragment of the packet MUST be index 0. Fragments are numbered consecutively.
packetFragment: The bytes of the indicated segment of the indicated original plain RTMFP packet. A packetFragment MUST NOT be empty. The use of this mechanism is detailed in Section 3.4.2.3.2. Initiator Hello Chunk (IHello)
This chunk is sent by the initiator of a new session to begin the startup handshake. This chunk is only allowed in a packet with Session ID 0, encrypted with the Default Session Key, and having packet mode 3 (Startup). 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x30 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-----------------------------------------------+ | epdLength \ | endpointDiscriminator (epdLength bytes) | +-------------/-+-----------------------------------------------/ +---------------------------------------------------------------+ | tag | +---------------------------------------------------------------/ struct ihelloChunkPayload_t { vlu_t epdLength :variable*8; uint8_t endpointDiscriminator[epdLength]; uint8_t tag[remainder()]; } :chunkLength*8; epdLength: VLU, the length of the following endpointDiscriminator field in bytes. endpointDiscriminator: The Endpoint Discriminator for the identity with which the initiator wants to communicate. tag: Initiator-provided data to be returned in a Responder Hello's tagEcho field. The tag/tagEcho is used to match Responder Hellos to the initiator's session startup state independent of the responder's address. The use of IHello is detailed in Section 3.5.1.
2.3.3. Forwarded Initiator Hello Chunk (FIHello)
This chunk is sent on behalf of an initiator by a Forwarder. It is only allowed in packets of an established session having packet mode 1 or 2. A receiver MAY treat this chunk as though it was an Initiator Hello received directly from replyAddress. Alternatively, if the receiver is selected by the Endpoint Discriminator, it MAY respond to replyAddress with an Implied Redirect (Section 2.3.5). 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x0f | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-----------------------------------------------+ | epdLength \ | endpointDiscriminator (epdLength bytes) | +-------------/-+-----------------------------------------------/ +---------------------------------------------------------------+ | replyAddress | +---------------------------------------------------------------/ +---------------------------------------------------------------+ | tag | +---------------------------------------------------------------/ struct fihelloChunkPayload_t { vlu_t epdLength :variable*8; uint8_t endpointDiscriminator[epdLength]; address_t replyAddress :variable*8; uint8_t tag[remainder()]; } :chunkLength*8; epdLength: VLU, the length of the following endpointDiscriminator field in bytes. endpointDiscriminator: The Endpoint Discriminator for the identity with which the original initiator wants to communicate, copied from the original Initiator Hello. replyAddress: Address format (Section 2.1.5), the address that the forwarding node derived from the received Initiator Hello, to which the receiver should respond. tag: Copied from the original Initiator Hello. The use of FIHello is detailed in Section 3.5.1.5.
2.3.4. Responder Hello Chunk (RHello)
This chunk is sent by a responder in response to an Initiator Hello or Forwarded Initiator Hello if the Endpoint Discriminator indicates the responder's identity. This chunk is only allowed in a packet with Session ID 0, encrypted with the Default Session Key, and having packet mode 3 (Startup). 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x70 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-----------------------------------------------+ | tagLength \ | tagEcho (tagLength bytes) | +-------------/-+-----------------------------------------------/ +-------------/-+-----------------------------------------------+ | cookieLength\ | cookie (cookieLength bytes) | +-------------/-+-----------------------------------------------/ +---------------------------------------------------------------+ | responderCertificate | +---------------------------------------------------------------/ struct rhelloChunkPayload_t { vlu_t tagLength :variable*8; uint8_t tagEcho[tagLength]; vlu_t cookieLength :variable*8; uint8_t cookie[cookieLength]; uint8_t responderCertificate[remainder()]; } :chunkLength*8; tagLength: VLU, the length of the following tagEcho field in bytes. tagEcho: The tag from the Initiator Hello, unaltered. cookieLength: VLU, the length of the following cookie field in bytes. cookie: Responder-created state data to authenticate a future Initiator Initial Keying message (in order to prevent denial-of- service attacks). responderCertificate: The responder's cryptographic credentials.
Note: This specification doesn't mandate a specific choice of certificate format. The Cryptography Profile determines the syntax, algorithms, and interpretation of the responderCertificate. The use of RHello is detailed in Section 3.5.1.2.3.5. Responder Redirect Chunk (Redirect)
This chunk is sent in response to an Initiator Hello or Forwarded Initiator Hello to indicate that the requested endpoint can be reached at one or more of the indicated addresses. A receiver can add none, some, or all of the indicated addresses to the set of addresses to which it is sending Initiator Hello messages for the opening session associated with tagEcho. This chunk is only allowed in a packet with Session ID 0, encrypted with the Default Session Key, and having packet mode 3 (Startup).
0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x71 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-----------------------------------------------+ | tagLength \ | tagEcho (tagLength bytes) | +-------------/-+-----------------------------------------------/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | redirectDestination 1 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ : : +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | redirectDestination N | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ struct responderRedirectChunkPayload_t { vlu_t tagLength :variable*8; uint8_t tagEcho[tagLength]; addressCount = 0; while(remainder() > 0) { address_t redirectDestination :variable*8; addressCount++; } if(0 == addressCount) redirectDestination = packetSourceAddress(); } :chunkLength*8; tagLength: VLU, the length of the following tagEcho field in bytes. tagEcho: The tag from the Initiator Hello, unaltered. redirectDestination: (Zero or more) Address format (Section 2.1.5) addresses to add to the opening set for the indicated session. If this chunk lists zero redirectDestination addresses, then this is an Implied Redirect, and the indicated address is the address from which the packet containing this chunk was received. The use of Redirect is detailed in Sections 3.5.1.1.1, 3.5.1.1.2, and 3.5.1.4.
2.3.6. RHello Cookie Change Chunk
This chunk SHOULD be sent by a responder to an initiator in response to an Initiator Initial Keying if that chunk's cookie appears to have been created by the responder but the cookie is incorrect (for example, it includes a hash of the initiator's address, but the initiator's address is different than the one that elicited the Responder Hello containing the original cookie). This chunk is only allowed in a packet encrypted with the Default Session Key and having packet mode 3, and with the session ID indicated in the initiatorSessionID field of the Initiator Initial Keying to which this is a response. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x79 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-----------------------------------------------+ | oldCookieLen\ | oldCookie (oldCookieLen bytes) | +-------------/-+-----------------------------------------------/ +---------------------------------------------------------------+ | newCookie | +---------------------------------------------------------------/ struct rhelloCookieChangeChunkPayload_t { vlu_t oldCookieLen :variable*8; uint8_t oldCookie[oldCookieLen]; uint8_t newCookie[remainder()]; } :chunkLength*8; oldCookieLen: VLU, the length of the following oldCookie field in bytes. oldCookie: The cookie that was sent in a previous Responder Hello and Initiator Initial Keying. newCookie: The new cookie that the responder would like sent (and signed) in a replacement Initiator Initial Keying. The old and new cookies need not have the same lengths. On receipt of this chunk, the initiator SHOULD compute, sign, and send a new Initiator Initial Keying having newCookie in place of oldCookie. The use of this chunk is detailed in Section 3.5.1.2.
2.3.7. Initiator Initial Keying Chunk (IIKeying)
This chunk is sent by an initiator to establish a session with a responder. The initiator MUST have obtained a valid cookie to use with the responder, typically by receiving a Responder Hello from it. This chunk is only allowed in a packet with Session ID 0, encrypted with the Default Session Key, and having packet mode 3 (Startup). 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x38 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | initiatorSessionID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-----------------------------------------------+ | cookieLength\ | cookieEcho | +-------------/-+-----------------------------------------------/ +-------------/-+-----------------------------------------------+ | certLength \ | initiatorCertificate | +-------------/-+-----------------------------------------------/ +-------------/-+-----------------------------------------------+ | skicLength \ | sessionKeyInitiatorComponent | +-------------/-+-----------------------------------------------/ +---------------------------------------------------------------+ | signature | +---------------------------------------------------------------/ struct iikeyingChunkPayload_t { struct { uint32_t initiatorSessionID; vlu_t cookieLength :variable*8; uint8_t cookieEcho[cookieLength]; vlu_t certLength :variable*8; uint8_t initiatorCertificate[certLength]; vlu_t skicLength :variable*8; uint8_t sessionKeyInitiatorComponent[skicLength]; } initiatorSignedParameters :variable*8; uint8_t signature[remainder()]; } :chunkLength*8; initiatorSessionID: The session ID to be used by the responder when sending packets to the initiator.
cookieLength: VLU, the length of the following cookieEcho field in bytes. cookieEcho: The cookie from the Responder Hello, unaltered. certLength: VLU, the length of the following initiatorCertificate field in bytes. initiatorCertificate: The initiator's identity credentials. skicLength: VLU, the length of the following sessionKeyInitiatorComponent field in bytes. sessionKeyInitiatorComponent: The initiator's portion of the session key negotiation according to the Cryptography Profile. initiatorSignedParameters: The payload portion of this chunk up to the signature field. signature: The initiator's digital signature of the initiatorSignedParameters according to the Cryptography Profile. Note: This specification doesn't mandate a specific choice of cryptography. The Cryptography Profile determines the syntax, algorithms, and interpretation of the initiatorCertificate, responderCertificate, sessionKeyInitiatorComponent, sessionKeyResponderComponent, and signature, and how the sessionKeyInitiatorComponent and sessionKeyResponderComponent are combined to derive the session keys. The use of IIKeying is detailed in Section 3.5.1.
2.3.8. Responder Initial Keying Chunk (RIKeying)
This chunk is sent by a responder in response to an Initiator Initial Keying as the final phase of session startup. This chunk is only allowed in a packet encrypted with the Default Session Key, having packet mode 3 (Startup), and sent to the initiator with the session ID specified by the initiatorSessionID field from the Initiator Initial Keying. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x78 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | responderSessionID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-----------------------------------------------+ | skrcLength \ | sessionKeyResponderComponent | +-------------/-+-----------------------------------------------/ +---------------------------------------------------------------+ | signature | +---------------------------------------------------------------/ struct rikeyingChunkPayload_t { struct { uint32_t responderSessionID; vlu_t skrcLength :variable*8; uint8_t sessionKeyResponderComponent[skrcLength]; } responderSignedParametersPortion :variable*8; uint8_t signature[remainder()]; } :chunkLength*8; struct { responderSignedParametersPortion; sessionKeyInitiatorComponent; } responderSignedParameters; responderSessionID: The session ID to be used by the initiator when sending packets to the responder. skrcLength: VLU, the length of the following sessionKeyResponderComponent field in bytes. sessionKeyResponderComponent: The responder's portion of the session key negotiation according to the Cryptography Profile.
responderSignedParametersPortion: The payload portion of this chunk up to the signature field. signature: The responder's digital signature of the responderSignedParameters (see below) according to the Cryptography Profile. responderSignedParameters: The concatenation of the responderSignedParametersPortion (the payload portion of this chunk up to the signature field) and the sessionKeyInitiatorComponent from the Initiator Initial Keying to which this chunk is a response. Note: This specification doesn't mandate a specific choice of cryptography. The Cryptography Profile determines the syntax, algorithms, and interpretation of the initiatorCertificate, responderCertificate, sessionKeyInitiatorComponent, sessionKeyResponderComponent, and signature, and how the sessionKeyInitiatorComponent and sessionKeyResponderComponent are combined to derive the session keys. Once the responder has computed the sessionKeyResponderComponent, it has all of the information and state necessary for an established session with the initiator. Once the responder has sent this chunk to the initiator, the session is established and ready to carry flows of user data. Once the initiator receives, verifies, and processes this chunk, it has all of the information and state necessary for an established session with the responder. The session is established and ready to carry flows of user data. The use of RIKeying is detailed in Section 3.5.1.
2.3.9. Ping Chunk
This chunk is sent in order to elicit a Ping Reply from the receiver. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x01 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | message | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ struct pingChunkPayload_t { uint8_t message[chunkLength]; } :chunkLength*8; message: The (potentially empty) message that is expected to be returned by the other end of the session in a Ping Reply. The receiver of this chunk SHOULD reply as immediately as is practical with a Ping Reply. Ping and the expected Ping Reply are typically used for session keepalive, endpoint address change verification, and path MTU discovery. See Section 3.5.4 for details.
2.3.10. Ping Reply Chunk
This chunk is sent in response to a Ping chunk. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x41 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | messageEcho | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ struct pingReplyChunkPayload_t { uint8_t messageEcho[chunkLength]; } :chunkLength*8; messageEcho: The message from the Ping to which this is a response, unaltered.
2.3.11. User Data Chunk
This chunk is the basic unit of transmission for the user messages of a flow. A user message comprises one or more fragments. Each fragment is carried in its own chunk and has a unique sequence number in its flow. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x10 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ |O|r| F | r |A|F| |P|s| R | s |B|I| |T|v| A | v |N|N| +-+-+-+-+-+-+-+-+ +-------------/-+-------------/-+-------------/-+ | flowID \ | seq# \ | fsnOffset \ | +-------------/-+-------------/-+-------------/-+ +~~~/~~~/~~~~~~~+ +~~~/~~~/~~~~~~~+-------------/-+ | L \ T \ V |... options ...| L \ T \ V | 0 \ | \~~~/~~~/~~~~~~~+ [if(OPT)] +~~~/~~~/~~~~~~~+-------------/-/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | userData | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ struct userDataChunkPayload_t { bool_t optionsPresent :1; // "OPT" uintn_t reserved1 :1; // "rsv" uintn_t fragmentControl :2; // "FRA" // 0=whole, 1=begin, 2=end, 3=middle uintn_t reserved2 :2; // "rsv" bool_t abandon :1; // "ABN" bool_t final :1; // "FIN" vlu_t flowID :variable*8; vlu_t sequenceNumber :variable*8; // "seq#" vlu_t fsnOffset :variable*8; forwardSequenceNumber = sequenceNumber - fsnOffset; if(optionsPresent) optionList_t options :variable*8; uint8_t userData[remainder()]; } :chunkLength*8; optionsPresent: If set, indicates the presence of an option list before the user data. If clear, there is no option list in this chunk.
fragmentControl: Indicates how this fragment is assembled, potentially with others, into a complete user message. Possible values: 0: This fragment is a complete message. 1: This fragment is the first of a multi-fragment message. 2: This fragment is the last of a multi-fragment message. 3: This fragment is in the middle of a multi-fragment message. A single-fragment user message has a fragment control of "0-whole". When a message has more than one fragment, the first fragment has a fragment control of "1-begin", then zero or more "3-middle" fragments, and finally a "2-end" fragment. The sequence numbers of a multi-fragment message MUST be contiguous. abandon: If set, this sequence number has been abandoned by the sender. The userData, if any, MUST be ignored. final: If set, this is the last sequence number of the flow. flowID: VLU, the flow identifier. sequenceNumber: VLU, the sequence number of this fragment. Fragments are assigned contiguous increasing sequence numbers in a flow. The first sequence number of a flow SHOULD be 1. The first sequence number of a flow MUST be greater than zero. Sequence numbers are unbounded and do not wrap. fsnOffset: VLU, the difference between the sequence number and the Forward Sequence Number. This field MUST NOT be zero if the abandon flag is not set. This field MUST NOT be greater than sequenceNumber. forwardSequenceNumber: The flow sender will not send (or resend) any fragment with a sequence number less than or equal to the Forward Sequence Number. options: If the optionsPresent flag is set, a list of zero or more Options terminated by a Marker is present. See Section 2.3.11.1 for defined options. userData: The actual user data for this fragment. The use of User Data is detailed in Section 3.6.2.
2.3.11.1. Options for User Data
This section lists options that may appear in User Data option lists. A conforming implementation MUST support the options in this section. A flow receiver MUST reject a flow containing a flow option that is not understood if the option type is less than 8192 (0x2000). A flow receiver MUST ignore any flow option that is not understood if the option type is 8192 or greater. The following option type codes are defined for User Data: 0x00: User's Per-Flow Metadata (Section 2.3.11.1.1) 0x0a: Return Flow Association (Section 2.3.11.1.2)2.3.11.1.1. User's Per-Flow Metadata
This option conveys the user's per-flow metadata for the flow to which it's attached. +-------------/-+-------------/-+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | length \ | 0x00 \ | userMetadata | +-------------/-+-------------/-+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ struct userMetadataOptionValue_t { uint8_t userMetadata[remainder()]; } :remainder()*8; The user associates application-defined metadata with each flow. The metadata does not change over the life of the flow. Every flow MUST have metadata. A flow sender MUST send this option with the first User Data chunk for this flow in each packet until an acknowledgement for this flow is received. A flow sender SHOULD NOT send this option more than once for each flow in any one packet. A flow sender SHOULD NOT send this option for a flow once the flow has been acknowledged. This specification doesn't mandate the encoding, syntax, or interpretation of the user's per-flow metadata; this is determined by the application. The userMetadata SHOULD NOT exceed 512 bytes. The userMetadata MAY be 0 bytes in length.
2.3.11.1.2. Return Flow Association
A new flow can be considered to be in return (or response) to a flow sent by the other endpoint. This option encodes the receive flow identifier to which this new sending flow is a response. +-------------/-+-------------/-+-------------/-+ | length \ | 0x0a \ | flowID \ | +-------------/-+-------------/-+-------------/-+ struct returnFlowAssociationOptionValue_t { vlu_t flowID :variable*8; } :variable*8; Consider endpoints A and B. Endpoint A begins a flow with identifier 5 to endpoint B. A is the flow sender for A's flowID=5, and B is the flow receiver for A's flowID=5. B begins a return flow with identifier 7 to A in response to A's flowID=5. B is the flow sender for B's flowID=7, and A is the flow receiver for B's flowID=7. B sends this option with flowID set to 5 to indicate that B's flowID=7 is in response to and associated with A's flowID=5. If there is a return association, the flow sender MUST send this option with the first User Data chunk for this flow in each packet until an acknowledgement for this flow is received. A flow sender SHOULD NOT send this option more than once for each flow in any one packet. A flow sender SHOULD NOT send this option for a flow once the flow has been acknowledged. A flow MUST NOT indicate more than one return association. A flow MUST indicate its return association, if any, upon its first transmission of a User Data chunk. A return association can't be added to a sending flow after it begins. A flow receiver MUST reject a new receiving flow having a return flow association that does not indicate an F_OPEN sending flow.
2.3.12. Next User Data Chunk
This chunk is equivalent to the User Data chunk for purposes of sending the user messages of a flow. When used, it MUST follow a User Data chunk or another Next User Data chunk in the same packet. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x11 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ |O|r| F | r |A|F| |P|s| R | s |B|I| |T|v| A | v |N|N| +-+-+-+-+-+-+-+-+ +~~~/~~~/~~~~~~~+ +~~~/~~~/~~~~~~~+-------------/-+ | L \ T \ V |... options ...| L \ T \ V | 0 \ | \~~~/~~~/~~~~~~~+ [if(OPT)] +~~~/~~~/~~~~~~~+-------------/-/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ | userData | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ struct nextUserDataChunkPayload_t { bool_t optionsPresent :1; // "OPT" uintn_t reserved1 :1; // "rsv" uintn_t fragmentControl :2; // "FRA" // 0=whole, 1=begin, 2=end, 3=middle uintn_t reserved2 :2; // "rsv" bool_t abandon :1; // "ABN" bool_t final :1; // "FIN" if(optionsPresent) optionList_t options :variable*8; uint8_t userData[remainder()]; } :chunkLength*8; This chunk is considered to be for the same flowID as the most recently preceding User Data or Next User Data chunk in the same packet, having the same Forward Sequence Number, and having the next sequence number. The optionsPresent, fragmentControl, abandon, and final flags, and the options (if present), have the same interpretation as for the User Data chunk.
... ----------+------------------------------------ 10 00 07 | User Data chunk, length=7 00 | OPT=0, FRA=0 "whole", ABN=0, FIN=0 02 05 03 | flowID=2, seq#=5, fsn=(5-3)=2 00 01 02 | data 3 bytes: 00, 01, 02 ----------+------------------------------------ 11 00 04 | Next User Data chunk,length=4 00 | OPT=0, FRA=0 "whole", ABN=0, FIN=0 | flowID=2, seq#=6, fsn=2 03 04 05 | data 3 bytes: 03, 04, 05 ----------+------------------------------------ 11 00 04 | Next User Data chunk, length=4 00 | OPT=0, FRA=0 "whole", ABN=0, FIN=0 | flowID=2, seq#=7, fsn=2 06 07 08 | data 3 bytes: 06, 07, 08 ----------+------------------------------------ Figure 3: Sequential Messages in One Packet Using Next User Data The use of Next User Data is detailed in Section 3.6.2.3.2.
2.3.13. Data Acknowledgement Bitmap Chunk (Bitmap Ack)
This chunk is sent by the flow receiver to indicate to the flow sender the User Data fragment sequence numbers that have been received for one flow. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2. The flow receiver can choose to acknowledge User Data with this chunk or with a Range Ack. It SHOULD choose whichever format has the most compact encoding of the sequence numbers received. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x50 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-------------/-+-------------/-+ | flowID \ | bufAvail \ | cumAck \ | +-------------/-+-------------/-+-------------/-+ +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+ |C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C| |+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+| |9|8|7|6|5|4|3|2|1|1|1|1|1|1|1|1|2|2|2|2|2|2|1|1| .... | | | | | | | | |7|6|5|4|3|2|1|0|5|4|3|2|1|0|9|8| +~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+ struct dataAckBitmapChunkPayload_t { vlu_t flowID :variable*8; vlu_t bufferBlocksAvailable :variable*8; // "bufAvail" vlu_t cumulativeAck :variable*8; // "cumAck" bufferBytesAvailable = bufferBlocksAvailable * 1024; acknowledge(0 through cumulativeAck); ackCursor = cumulativeAck + 1; while(remainder() > 0) { for(bitPosition = 8; bitPosition > 0; bitPosition--) { bool_t bit :1; if(bit) acknowledge(ackCursor + bitPosition); } ackCursor += 8; } } :chunkLength*8;
flowID: VLU, the flow identifier. bufferBlocksAvailable: VLU, the number of 1024-byte blocks of User Data that the receiver is currently able to accept. Section 3.6.3.5 describes how to calculate this value. cumulativeAck: VLU, the acknowledgement of every fragment sequence number in this flow that is less than or equal to this value. This MUST NOT be less than the highest Forward Sequence Number received in this flow. bit field: A sequence of zero or more bytes representing a bit field of received fragment sequence numbers after the cumulative acknowledgement, least significant bit first. A set bit indicates receipt of a sequence number. A clear bit indicates that sequence number was not received. The least significant bit of the first byte is the second sequence number following the cumulative acknowledgement, the next bit is the third sequence number following, and so on. Figure 4 shows an example Bitmap Ack indicating acknowledgement of fragment sequence numbers 0 through 16, 18, 21 through 24, 27, and 28. 50 00 05 | Bitmap Ack, length=5 bytes 05 7f 10 | flowID=5, bufAvail=127*1024 bytes, cumAck=0..16 79 06 | 01111001 00000110 = 18, 21, 22, 23, 24, 27, 28 Figure 4: Example Bitmap Ack
2.3.14. Data Acknowledgement Ranges Chunk (Range Ack)
This chunk is sent by the flow receiver to indicate to the flow sender the User Data fragment sequence numbers that have been received for one flow. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2. The flow receiver can choose to acknowledge User Data with this chunk or with a Bitmap Ack. It SHOULD choose whichever format has the most compact encoding of the sequence numbers received. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x51 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-------------/-+-------------/-+ | flowID \ | bufAvail \ | cumAck \ | +-------------/-+-------------/-+-------------/-+ +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+ | #holes-1 \ | #recv-1 \ | +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+ : : +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+ | #holes-1 \ | #recv-1 \ | +~~~~~~~~~~~~~/~+~~~~~~~~~~~~~/~+ struct dataAckRangesChunkPayload_t { vlu_t flowID :variable*8; vlu_t bufferBlocksAvailable :variable*8; // "bufAvail" vlu_t cumulativeAck :variable*8; // "cumAck" bufferBytesAvailable = bufferBlocksAvailable * 1024; acknowledge(0 through cumulativeAck); ackCursor = cumulativeAck; while(remainder() > 0) { vlu_t holesMinusOne :variable*8; // "#holes-1" vlu_t receivedMinusOne :variable*8; // "#recv-1" ackCursor++; rangeFrom = ackCursor + holesMinusOne + 1; rangeTo = rangeFrom + receivedMinusOne; acknowledge(rangeFrom through rangeTo); ackCursor = rangeTo; } } :chunkLength*8;
flowID: VLU, the flow identifier. bufferBlocksAvailable: VLU, the number of 1024-byte blocks of User Data that the receiver is currently able to accept. Section 3.6.3.5 describes how to calculate this value. cumulativeAck: VLU, the acknowledgement of every fragment sequence number in this flow that is less than or equal to this value. This MUST NOT be less than the highest Forward Sequence Number received in this flow. holesMinusOne / receivedMinusOne: Zero or more acknowledgement ranges, run-length encoded. Runs are encoded as zero or more pairs of VLUs indicating the number (minus one) of missing sequence numbers followed by the number (minus one) of received sequence numbers, starting at the cumulative acknowledgement. NOTE: If a parser syntax error is encountered here (that is, if the chunk is truncated such that not enough bytes remain to completely encode both VLUs of the acknowledgement range), then treat and process this chunk as though it was properly formed up to the last completely encoded range. Figure 5 shows an example Range Ack indicating acknowledgement of fragment sequence numbers 0 through 16, 18, 21, 22, 23, and 24. 51 00 07 | Range Ack, length=7 05 7f 10 | flowID=5, bufAvail=127*1024 bytes, cumAck=0..16 00 00 | holes=1, received=1 -- missing 17, received 18 01 03 | holes=2, received=4 -- missing 19..20, received 21..24 Figure 5: Example Range Ack Figure 6 shows an example Range Ack indicating acknowledgement of fragment sequence numbers 0 through 16 and 18, with a truncated last range. Note that the truncation and parse error does not abort the entire chunk in this case. 51 00 07 | Range Ack, length=9 05 7f 10 | flowID=5, bufAvail=127*1024 bytes, cumAck=0..16 00 00 | holes=1, received=1 -- missing 17, received 18 01 83 | holes=2, received=VLU parse error, ignore this range Figure 6: Example Truncated Range Ack
2.3.15. Buffer Probe Chunk
This chunk is sent by the flow sender in order to request the current available receive buffer (in the form of a Data Acknowledgement) for a flow. It is only allowed in a packet belonging to an established session and having packet mode 1 or 2. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x18 | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+ | flowID \ | +-------------/-+ struct bufferProbeChunkPayload_t { vlu_t flowID :variable*8; } :chunkLength*8; flowID: VLU, the flow identifier. The receiver of this chunk SHOULD reply as immediately as is practical with a Data Acknowledgement.2.3.16. Flow Exception Report Chunk
This chunk is sent by the flow receiver to indicate that it is not (or is no longer) interested in the flow and would like the flow sender to close the flow. This chunk SHOULD precede every Data Acknowledgement chunk for the same flow in this condition. This chunk is only allowed in a packet belonging to an established session and having packet mode 1 or 2. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x5e | chunkLength | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------/-+-------------/-+ | flowID \ | exception \ | +-------------/-+-------------/-+ struct flowExceptionReportChunkPayload_t { vlu_t flowID :variable*8; vlu_t exception :variable*8; } :chunkLength*8;
flowID: VLU, the flow identifier. exception: VLU, the application-defined exception code being reported. A receiving RTMFP might reject a flow automatically, for example if it is missing metadata, or if an invalid return association is specified. In circumstances where an RTMFP rejects a flow automatically, the exception code MUST be 0. The application can specify any exception code, including 0, when rejecting a flow. All non-zero exception codes are reserved for the application.2.3.17. Session Close Request Chunk (Close)
This chunk is sent to cleanly terminate a session. It is only allowed in a packet belonging to an established or closing session and having packet mode 1 or 2. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x0c | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ This chunk has no payload. The use of Close is detailed in Section 3.5.5.2.3.18. Session Close Acknowledgement Chunk (Close Ack)
This chunk is sent in response to a Session Close Request to indicate that the sender has terminated the session. It is only allowed in a packet belonging to an established or closing session and having packet mode 1 or 2. 0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x4c | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ This chunk has no payload. The use of Close Ack is detailed in Section 3.5.5.