tech-invite   World Map     

IETF     RFCs     Groups     SIP     ABNFs    |    3GPP     Specs     Glossaries     Architecture     IMS     UICC    |    search     info

RFC 7016

 
 
 

Adobe's Secure Real-Time Media Flow Protocol

Part 2 of 4, p. 13 to 44
Prev RFC Part       Next RFC Part

 


prevText      Top      Up      ToC       Page 13 
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;

Top      Up      ToC       Page 14 
   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

Top      Up      ToC       Page 15 
   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.

Top      Up      ToC       Page 16 
    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;

Top      Up      ToC       Page 17 
   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.

Top      Up      ToC       Page 18 
   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).

Top      Up      ToC       Page 19 
   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.

Top      Up      ToC       Page 20 
   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.

Top      Up      ToC       Page 21 
   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.

Top      Up      ToC       Page 22 
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.

Top      Up      ToC       Page 23 
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.

Top      Up      ToC       Page 24 
   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).

Top      Up      ToC       Page 25 
    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.

Top      Up      ToC       Page 26 
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.

Top      Up      ToC       Page 27 
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.

Top      Up      ToC       Page 28 
   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.

Top      Up      ToC       Page 29 
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.

Top      Up      ToC       Page 30 
   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.

Top      Up      ToC       Page 31 
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.

Top      Up      ToC       Page 32 
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.

Top      Up      ToC       Page 33 
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.

Top      Up      ToC       Page 34 
   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.

Top      Up      ToC       Page 35 
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.

Top      Up      ToC       Page 36 
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.

Top      Up      ToC       Page 37 
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.

Top      Up      ToC       Page 38 
               ...
               ----------+------------------------------------
               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.

Top      Up      ToC       Page 39 
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;

Top      Up      ToC       Page 40 
   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

Top      Up      ToC       Page 41 
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;

Top      Up      ToC       Page 42 
   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

Top      Up      ToC       Page 43 
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;

Top      Up      ToC       Page 44 
   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.


Next RFC Part