RFC 4815

RObust Header Compression (ROHC): Corrections and Clarifications to RFC 3095

๐Ÿ“… published February 2007, from ietf

RFC 4815: RObust Header Compression (ROHC): Corrections and Clarifications to RFC 3095 ๐ŸŽ€

okay bestie, here's the title block tea โ˜•๐Ÿฆ‹

  • Network Working Group, Request for Comments: 4815
  • Authors: L-E. Jonsson, K. Sandlund, G. Pelletier, and P. Kremer
  • Category: Standards Track
  • Date: February 2007
  • Updates: RFC 3095, 3241, 3843, 4019, and 4362
  • Obsoletes: nothing is listed in the header

Status of This Memo โœจ

so this doc is an Internet standards track protocol for the Internet community ๐Ÿ’… It's open for discussion and suggestions for improvements. For the current standardization state and status of this protocol, check the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited ๐ŸŒˆ

Copyright (C) The IETF Trust (2007) ๐Ÿ”ฅ

Abstract ๐Ÿฆ‹

RFC 3095 is the one that defines the RObust Header Compression (ROHC) framework and its profiles for IP (Internet Protocol), UDP (User Datagram Protocol), RTP (Real-Time Transport Protocol), and ESP (Encapsulating Security Payload) ๐Ÿงš Some parts of that spec are unclear or have errors, and that can lead to misinterpretations that impair interoperability between implementations ๐Ÿ’€ This doc brings corrections, additions, and clarifications to RFC 3095, so it updates RFC 3095. It also has clarifications for RFC 3241 (ROHC over PPP), RFC 3843 (ROHC IP profile), and RFC 4109 (ROHC UDP-Lite profiles) โœจ

Table of Contents ๐Ÿ“

1. Introduction and Terminology ....................................3
2. CRC Calculation and Coverage ....................................4
   2.1. CRC Calculation ............................................4
   2.2. Padding Octet and CRC Calculations .........................4
   2.3. CRC Coverage in CRC Feedback Options .......................5
   2.4. CRC Coverage of the ESP NULL Header ........................5
3. Mode Transition .................................................5
   3.1. Feedback During Mode Transition to U- and O-Mode ...........5
        3.1.1. Mode Transition Procedures Allowing Sparse Feedback .6
        3.1.2. Transition from Reliable to Optimistic Mode .........7
        3.1.3. Transition to Unidirectional Mode ...................8
   3.2. Feedback During Mode Transition ............................8
   3.3. Packet Decoding During Mode Transition .....................9
4. Timestamp Encoding ..............................................9
   4.1. Encoding Used for Compressed TS Bits .......................9
   4.2. (De)compression of TS without Transmitted TS Bits .........10
   4.3. Interpretation Intervals for TS Encoding ..................11
   4.4. Scaled RTP Timestamp Encoding .............................11
        4.4.1. TS_STRIDE for Scaled Timestamp Encoding ............11
        4.4.2. TS Wraparound with Scaled Timestamp Encoding .......12
        4.4.3. Algorithm for Scaled Timestamp Encoding ............12
   4.5. Recalculating TS_OFFSET ...................................14
   4.6. TS_STRIDE and the Tsc Flag in Extension 3 .................14
   4.7. Using Timer-Based Compression .............................15
5. List Compression ...............................................15
   5.1. CSRC List Items in RTP Dynamic Chain ......................15
   5.2. Multiple Occurrences of the CC Field ......................15
   5.3. Bit Masks in List Compression .............................16
   5.4. Headers Compressed with List Compression ..................16
   5.5. ESP NULL Header List Compression ..........................17
   5.6. Translation Tables and Indexes for IP Extension Headers ...17
   5.7. Reference List ............................................17
   5.8. Compression of AH and GRE Sequence Numbers ................18
6. Updating Properties ............................................19
   6.1. Implicit Updates ..........................................19
   6.2. Updating Properties of UO-1* ..............................20
   6.3. Context Updating Properties for IR Packets ................20
   6.4. RTP Padding Field (R-P) in Extension 3 ....................20
   6.5. RTP eXtension bit (X) in dynamic part .....................21
7. Context management and CID/context Reuse .......................21
   7.1. Persistence of Decompressor Contexts ......................21
   7.2. CID/Context Reuse .........................................21
        7.2.1. Reusing a CID/Context with the Same Profile ........22
        7.2.2. Reusing a CID/Context with a Different Profile .....23
8. Other Protocol Clarifications ..................................23
   8.1. Meaning of NBO ............................................23
   8.2. IP-ID .....................................................23
   8.3. Extension-3 in UOR-2* Packets .............................24
   8.4. Multiple Occurrences of the M Bit .........................24
   8.5. Multiple SN options in one feedback packet ................24
   8.6. Multiple CRC Options in One Feedback Packet ...............25
   8.7. Responding to Lost Feedback Links .........................25
   8.8. UOR-2 in Profile 0x0002 (UDP) and Profile 0x0003 (ESP) ....25
   8.9. Sequence Number LSB's in IP Extension Headers .............25
   8.10. Expecting UOR-2 ACKs in O-Mode ...........................26
   8.11. Context Repairs, TS_STRIDE and TIME_STRIDE ...............26
9. ROHC Negotiation ...............................................27
10. PROFILES Sub-option in ROHC-over-PPP ..........................27
11. Constant IP-ID Encoding in IP-only and UPD-Lite Profiles ......27
12. Security Considerations .......................................28
13. Acknowledgments ...............................................28
14. References ....................................................28
   14.1. Normative References .....................................28
   14.2. Informative References ...................................29
Appendix A. Sample CRC Algorithm ..................................30

1. Introduction and Terminology ๐Ÿ’…

RFC 3095 [1] defines the ROHC framework and profiles for IP (Internet Protocol) [8][9], UDP (User Datagram Protocol) [10], RTP (Real-Time Transport Protocol) [11], and ESP (Encapsulating Security Payload) [12]. While RFC 3095 was being implemented and interop-tested, the team found some ambiguities, a few common misinterpretations, and some actual errors ๐Ÿ˜ญ

This doc sums up those issues and gives the fixes that implementations of RFC 3095 need in order to interoperate. In other words, it's an update to RFC 3095 ๐Ÿซถ It also has other clarifications about common misreadings of the spec. So anywhere you see a reference to RFC 3095, this doc should be included in that reference too, periodt โœจ

It's also giving for RFC 3241 (ROHC over PPP) [2], RFC 3843 (ROHC IP-only profile) [4], and RFC 4019 (ROHC UDP-Lite profiles) [5], which means they're updated by this document as well. And RFC 4362 (ROHC Link-Layer Assisted Profile) [7] gets implicitly updated here, since it's also based on RFC 3095 ๐Ÿฆ‹

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be read as described in RFC 2119 [6] ๐Ÿ‘‘

When this doc makes formal corrections, additions, or invalidations to text in RFC 3095, it's clearly summarized. The RFC 3095 text being fixed is quoted and labeled "INCOMPLETE", "INCORRECT", or "INCORRECT AND INVALIDATED". Then the corrected text comes after, labeled "CORRECTED" where that applies. If new text is added that doesn't just fix older text, it's labeled "FORMAL ADDITION" ๐ŸŒธ

In this doc, a reference to a section in RFC 3095 [1] is written as RFC 3095-Section <number> ๐Ÿงš

2. CRC Calculation and Coverage ๐Ÿ”ฅ

2.1. CRC Calculation ๐ŸŒˆ

RFC 3095-Section 5.9 defines polynomials for 3-, 7-, and 8-bit Cyclic Redundancy Checks (CRCs), but it never says what algorithm to use. The 3-, 7-, and 8-bit CRCs are computed with the CRC algorithm defined in [3] ๐Ÿ“

There's a Perl implementation of the algorithm in Appendix A of this document ๐Ÿ’–

2.2. Padding Octet and CRC Calculations ๐Ÿฆ‹

RFC 3095-Section 5.9.1 is incomplete, because it doesn't explain how to handle the padding octet in CRC calculations for IR and IR-DYN packets ๐Ÿ™ˆ Padding isn't supposed to be a meaningful part of a packet, so it's left out of the CRC calculation. That also means the CRC doesn't cover the Add-CID octet for CID 0 โœจ

INCOMPLETE RFC 3095 TEXT (RFC 3095-Section 5.9.1):

"The CRC in the IR and IR-DYN packet is calculated over the entire
 IR or IR-DYN packet, excluding Payload and including CID or any
 Add-CID octet."

CORRECTED TEXT:

"The CRC in the IR and IR-DYN packet is calculated over the entire
 IR or IR-DYN packet, excluding Payload, Padding and including CID
 or any Add-CID octet, except for the add-CID octet for CID 0."

2.3. CRC Coverage in CRC Feedback Options ๐ŸŽ€

RFC 3095-Section 5.7.6.3 is incomplete too, since it doesn't say how the "size" field gets handled when the 8-bit CRC for the CRC feedback option is calculated. The "size" field is an extension of the "code" field, so it has to be treated the same way ๐Ÿ’…

INCOMPLETE RFC 3095 TEXT (RFC 3095-Section 5.7.6.3):

"The CRC option contains an 8-bit CRC computed over the entire
 feedback payload, without the packet type and code octet, but
 including any CID fields, using the polynomial of section 5.9.1."

CORRECTED TEXT:

"The CRC option contains an 8-bit CRC computed over the entire
 feedback payload including any CID fields but excluding the
 packet type, the 'Size' field and the 'Code' octet, using the
 polynomial of Section 5.9.1."

2.4. CRC Coverage of the ESP NULL Header ๐Ÿงš

RFC 3095-Section 5.8.7 gives the CRC coverage of the ESP NULL [13] header as "Entire ESP header". This has to be read as covering only the initial part of the header (the Security Parameter Index (SPI) and sequence number), and not the trailer at the end of the payload ๐Ÿ‘‘ So the ESP NULL header has the same CRC coverage as the ESP header used in the ESP profile (RFC 3095-Section 5.7.7.7) ๐Ÿ’œ

Part 1 of 7 done, bestie ๐Ÿซถ Section 3 (Mode Transition) is next up in part 2 โœจ

3.1. Feedback During Mode Transition to U- and O-Mode ๐Ÿฆ‹

okay so RFC 3095-Section 5.6.1 says that during mode transitions, while D_TRANS is I, the decompressor sends feedback for every single packet it receives ๐Ÿ˜ญ. that's a LOT of feedback, and it blocks the decompressor from using sparse feedback during transitions ๐Ÿ’€.

To cut down on the transmission overhead and the computation (including CRC calculation) that comes with sending feedback for every decompressed packet during a transition, a decompressor MAY be implemented with slightly modified mode transition procedures compared to the ones in [1], as described in this section. โœจ

These enhanced procedures are only a possible improvement to a decompressor implementation, since interoperability is not affected in any way ๐Ÿซถ. A decompressor using the optimized procedures will still interoperate with an RFC 3095 compressor, and with a decompressor that follows the procedures in RFC 3095. periodt ๐Ÿ’…


3.1.1. Mode Transition Procedures Allowing Sparse Feedback ๐ŸŒธ

the whole point of these enhanced transition procedures is to let the decompressor sparsely send feedback for packets it decompresses during the second half of the transition, i.e., after an appropriate IR/IR-DYN/UOR-2 packet has been received from the compressor. it does this by setting the decompressor transition parameter (D_TRANS) to P (Pending) at that stage, as shown in the transition diagrams in Sections 3.1.2 and 3.1.3 below. ๐Ÿฆ‹

this enhanced transition, where feedback doesn't have to go out for every decompressed packet, does come with some considerations in case feedback messages get lost ๐Ÿ™ˆ. specifically, there's a risk of a deadlock when a transition from R-mode is performed. if no feedback message successfully reaches the compressor, the transition is never completed ๐Ÿ’€. for the transition between U-mode and O-mode, there's also a small risk of reduced compression efficiency.

so to avoid this, the decompressor MUST continue to send feedback at least periodically, as well as when in a Pending transition state. this is basically enhancing the definition of the D_TRANS parameter in RFC 3095-Section 5.6.1 to include a Pending state:

  • D_TRANS: Possible values for the D_TRANS parameter are (I)NITIATED, (P)ENDING, and (D)ONE. D_TRANS MUST be initialized to D, and a mode transition can be initiated only when D_TRANS is D. While D_TRANS is I, the decompressor sends a NACK or ACK carrying a CRC option for each packet received. When D_TRANS is set to P, the decompressor does not have to send a NACK or ACK for each packet received, but it MUST continue to send feedback with some periodicity, and all feedback packets sent MUST include the CRC option. This ensures that all mode transitions will be completed also in case of feedback losses. ๐Ÿซถ

the modifications affect transitions to Optimistic and Unidirectional modes of operation (i.e., the transitions described in RFC 3095-Section 5.6.5 and RFC 3095-Section 5.6.6), and they make those transition diagrams more consistent with the diagram for the transition to R-mode โœจ.


3.1.2. Transition from Reliable to Optimistic Mode ๐ŸŽ€

the enhanced procedure for transitioning from Reliable to Optimistic mode looks like this ๐Ÿ‘‘:

         Compressor                     Decompressor
        ----------------------------------------------
              |                               |
              |        ACK(O)/NACK(O) +-<-<-<-| D_TRANS = I
              |       +-<-<-<-<-<-<-<-+       |
  C_TRANS = P |-<-<-<-+                       |
  C_MODE = O  |                               |
              |->->->-+ IR/IR-DYN/UOR-2(SN,O) |
              |       +->->->->->->->-+       |
              |->-..                  +->->->-| D_TRANS = P
              |->-..                          | D_MODE = O
              |           ACK(SN,O)   +-<-<-<-|
              |       +-<-<-<-<-<-<-<-+       |
  C_TRANS = D |-<-<-<-+                       |
              |                               |
              |->->->-+  UO-0, UO-1*          |
              |       +->->->->->->->-+       |
              |                       +->->->-| D_TRANS = D
              |                               |

3.1.3. Transition to Unidirectional Mode ๐Ÿงš

and the enhanced procedure for transitioning to Unidirectional mode is shown in the following figure ๐ŸŒˆ:

             Compressor                     Decompressor
            ----------------------------------------------
              |                               |
              |        ACK(U)/NACK(U) +-<-<-<-| D_TRANS = I
              |       +-<-<-<-<-<-<-<-+       |
  C_TRANS = P |-<-<-<-+                       |
  C_MODE = U  |                               |
              |->->->-+ IR/IR-DYN/UOR-2(SN,U) |
              |       +->->->->->->->-+       |
              |->-..                  +->->->-| D_TRANS = P
              |->-..                          |
              |           ACK(SN,U)   +-<-<-<-|
              |       +-<-<-<-<-<-<-<-+       |
  C_TRANS = D |-<-<-<-+                       |
              |                               |
              |->->->-+  UO-0, UO-1*          |
              |       +->->->->->->->-+       |
              |                       +->->->-| D_TRANS = D
              |                               | D_MODE= U

3.2. Feedback During Mode Transition ๐ŸŒŸ

RFC 3095-Section 5.6.1 states that feedback is always used during mode transitions. however, the text then goes on to apply that rule in an inconsistent way, which makes it unclear when CRCs are used ๐Ÿ˜ตโ€๐Ÿ’ซ. on top of that, the text doesn't say how the compressor should act during mode transitions based on feedback that isn't protected by CRCs, i.e., whether or not to carry out mode transition actions. the proper behavior from the compressor is to perform any action related to mode transitions only when the feedback is protected by the CRC option ๐Ÿ’….

INCOMPLETE RFC 3095 TEXT (RFC 3095-Section 5.6.1):

"As a safeguard against residual errors, all feedback sent during
 a mode transition MUST be protected by a CRC, i.e., the CRC
 option MUST be used."

CORRECTED TEXT:

"As a safeguard against residual errors, all feedback sent by the
 decompressor during a mode transition MUST be protected by a CRC,
 i.e., the CRC option MUST be used.  The compressor MUST ignore
 feedback information related to mode transition if the feedback
 is not protected by the CRC option."

there's one more related issue that needs clarifying, and it comes from the following text at the end of RFC 3095-Section 5.6.1 ๐Ÿ™ˆ:

"While D_TRANS is I, the decompressor sends a NACK or ACK carrying
 a CRC option for each received packet."

but RFC 3095-Section 5.5.2.2 already said that for R-mode, feedback is never sent for packets that don't update the context, i.e., for packets that don't carry a CRC, like R-0 and R-1* ๐Ÿค”.

so this means that when D_TRANS=I during a mode transition, a decompressor operating in R-mode sends an acknowledgement for each packet it receives, and it MUST use the sequence number that corresponds to the packet that last updated the context. i.e., the decompressor MUST NOT use the sequence number of the R-0 or the R-1* packet ๐Ÿซถ.


3.3. Packet Decoding During Mode Transition ๐Ÿฆ‹

the purpose of a mode transition is to make sure the compressor and the decompressor move from one mode of operation to another together, using a three-way handshake ๐Ÿค. at one point during the transition, the decompressor acknowledges the reception of one (or more) IR, IR-DYN or UOR-2 packet(s) that have mode bits set to the new mode. packets of type 0 or type 1 received up to this point are decompressed using the old mode, and after that they're decompressed using the new mode. if the enhanced transition procedures from Section 3.1 are used, setting D_TRANS to P marks this breakpoint ๐ŸŽฏ. the successful decompression of a packet of type 0 or type 1 completes the mode transition โœจ.


4. Timestamp Encoding โญ

4.1. Encoding Used for Compressed TS Bits ๐Ÿ’–

RTP Timestamp (TS) values are always encoded using W-LSB encoding, both when they're sent scaled and when they're sent unscaled ๐ŸŒธ. when no TS bits are transmitted in a compressed packet, TS is always scaled. if a compressed packet carries an Extension 3 and field(Tsc)=0, the compressed packet must thus always carry unscaled TS bits ๐Ÿ™ˆ. for TS values sent in Extension 3, W-LSB encoded values are sent using the self-describing variable-length format (RFC 3095-Section 4.5.6), and this applies to both scaled and unscaled values ๐Ÿงš.

4.2. (De)compression of TS without Transmitted TS Bits โœจ

Okay bestie, so when ROHC RTP is running its most efficient packet types, it's giving minimalism ๐Ÿ’…. Apart from the packet type ID and the error detection CRC, the only thing sent in an RTP compressed header is the RTP sequence number (SN) bits. Everything else gets left out, either because it hasn't changed or because it can be rebuilt from the SN plus the state stored in the context ๐Ÿงš. The fields that can be inferred from the SN are the IP Identification (IP-ID) and the RTP Timestamp (TS). Main character energy for the SN, ngl ๐Ÿ‘‘.

IP-ID compression and decompression are sorted out already, both with and without transmitted IP-ID bits in the compressed header. They're defined in RFC 3095-Section 4.5.5 (see Section 8.2) ๐ŸŽ€. The TS field is the tricky one ๐Ÿ˜ญ. RFC 3095 only explains how to decompress TS when there are actual TS bits in the compressed header, scaled or unscaled. It doesn't explain how to infer TS from the SN when no TS bits are present ๐Ÿ™ˆ.

So when no TS bits show up in the compressed header, the scaled TS value gets reconstructed by assuming a linear extrapolation from the SN. That's delta_TS = delta_SN * default-slope, where delta_SN and delta_TS are both signed integers. RFC 3095-Section 5.7 lists the possible values for default-slope ๐ŸŒˆ.

Incomplete RFC 3095 text (RFC 3095-Section 5.7):

"If value(Tsc) = 1, Scaled RTP Timestamp encoding is used before
 compression (see section 4.5.3), and default-slope(TS) = 1.

 If value(Tsc) = 0, the Timestamp value is compressed as-is, and
 default-slope(TS) = value(TS_STRIDE)."

Corrected text:

"When a compressed header with no TS bits is received, the scaled
 TS value is reconstructed assuming a linear extrapolation from
 the SN, i.e., delta_TS = delta_SN * default-slope(TS).

 If value(Tsc) = 1, Scaled RTP Timestamp encoding is used before
 compression (see Section 4.5.3), and default-slope(TS) = 1.

 If value(Tsc) = 0, the Timestamp value is compressed as-is, and
 default-slope(TS) = value(TS_STRIDE).  If a packet with no TS
 bits is received with Tsc = 0, the decompressor MUST discard the
 packet."

Incorrect and invalidated RFC 3095 text (Section RFC 3095-5.5.1.2):

"For example, in a typical case where the string pattern has the
 form of non-SN-field = SN * slope + offset, one ACK is enough if
 the slope has been previously established by the decompressor
 (i.e., only the new offset needs to be synchronized).  Otherwise,
 two ACKs are required since the decompressor needs two headers to
 learn both the new slope and the new offset."

Bottom line: there is no slope value other than the default-slope, as defined in RFC 3095-Section 5.7 ๐Ÿ’–.

4.3. Interpretation Intervals for TS Encoding ๐Ÿฆ‹

RFC 3095-Section 4.5.4 defines the interpretation interval, p, for timer-based compression of the RTP timestamp. But RFC 3095-Section 5.7 defines a different interpretation interval, described as the one to use for all TS values. So it's honestly confusing which p value to use, at least for timer-based compression ๐Ÿ˜ตโ€๐Ÿ’ซ.

The way this should be read is that the p value depends on whether timer-based compression is enabled or not โœจ.

For timer-based compression (TIME_STRIDE set to a non-zero value), the interpretation interval is:

p = 2^(k-1) - 1 (as per RFC 3095-Section 4.5.4)

Otherwise, the interpretation interval is:

p = 2^(k-2) - 1 (as per RFC 3095-Section 5.7)

4.4. Scaled RTP Timestamp Encoding ๐ŸŒธ

This section redefines the algorithm for scaled RTP timestamp encoding. In RFC 3095-Section 4.5.3 it's a 5-step procedure. Two formal errors got fixed, which are covered in sub-sections 4.4.1 and 4.4.2 below, and the whole algorithm got reworked to be more concise and use well-defined terminology. The end result is in 4.4.3 below ๐Ÿซถ.

4.4.1. TS_STRIDE for Scaled Timestamp Encoding ๐Ÿ“

RFC 3095 defines the timestamp stride (TS_STRIDE) as the expected increase in the timestamp value between two RTP packets with consecutive sequence numbers. The compressor sets TS_STRIDE and explicitly communicates it to the decompressor, and it's used as the scaling factor for scaled TS encoding ๐Ÿ”ฅ.

The relation between TS and TS_SCALED, given by the following equality in RFC 3095-Section 4.5.3, is what gives TS_STRIDE its mathematical meaning:

TS = TS_SCALED * TS_STRIDE + TS_OFFSET

TS_SCALED gets written incompletely as TS / TS_STRIDE in the compression step after that core equality. This formula is wrong for two reasons. It leaves out TS_OFFSET, and it would also stop TS_STRIDE from being 0, which the definition and core equality don't rule out ๐Ÿ™…โ€โ™€๏ธ. If "/" were a generally, unambiguously defined operation meaning "the integral part of the result from dividing X by Y", then the missing TS_OFFSET could be explained. But the formula would still have no proper output for TS_STRIDE equal to 0. So the formula in "2. Compression" is only valid with these requirements:

  • a) "/" means "the integral part of the result from dividing X by Y"
  • b) TS_STRIDE>0 (TS is never sent scaled when TS_STRIDE=0)

4.4.2. TS Wraparound with Scaled Timestamp Encoding ๐Ÿ’œ

RFC 3095-Section 4.5.3 says in points 4 and 5 that the compressor is not required to initialize TS_OFFSET at wraparound, but that it is required to increase the number of bits sent for the scaled TS value when there's a TS wraparound. The decompressor is also required to detect and cope with TS wraparound, including updating TS_OFFSET ๐Ÿ˜ค.

This method is not interoperable and not robust. The gain is also insignificant, since TS wraparound happens very seldomly ๐Ÿฅฑ. So the compressor should reinitialize TS_OFFSET upon TS wraparound, by sending an unscaled TS ๐Ÿ’….

4.4.3. Algorithm for Scaled Timestamp Encoding ๐Ÿงšโ€โ™€๏ธ

Incorrect RFC 3095 text (RFC 3095-Section 4.5.3):

"1. Initialization: The compressor sends to the decompressor the
    value of TS_STRIDE and the absolute value of one or several TS
    fields.  The latter are used by the decompressor to initialize
    TS_OFFSET to (absolute value) modulo TS_STRIDE.  Note that
    TS_OFFSET is the same regardless of which absolute value is
    used, as long as the unscaled TS value does not wrap around;
    see 4) below.

 2. Compression: After initialization, the compressor no longer
    compresses the original TS values.  Instead, it compresses the
    downscaled values: TS_SCALED = TS / TS_STRIDE.  The compression
    method could be either W-LSB encoding or the timer-based
    encoding described in the next section.

 3. Decompression: When receiving the compressed value of
    TS_SCALED, the decompressor first derives the value of the
    original TS_SCALED.  The original RTP TS is then calculated as
    TS = TS_SCALED * TS_STRIDE + TS_OFFSET.

 4. Offset at wraparound: Wraparound of the unscaled 32-bit TS will
    invalidate the current value of TS_OFFSET used in the equation
    above.  For example, let us assume TS_STRIDE = 160 = 0xA0 and
    the current TS = 0xFFFFFFF0.  TS_OFFSET is then 0x50 = 80.
    Then if the next RTP TS = 0x00000130 (i.e., the increment is
    160 * 2 = 320), the new TS_OFFSET should be 0x00000130 modulo
    0xA0 = 0x90 = 144.  The compressor is not required to re-
    initialize TS_OFFSET at wraparound.  Instead, the decompressor
    MUST detect wraparound of the unscaled TS (which is trivial)
    and update TS_OFFSET to TS_OFFSET = (Wrapped around unscaled
    TS) modulo TS_STRIDE"

Corrected text:

"1. Initialization and updating of RTP TS scaling function:  The
    compressor sends to the decompressor the value of TS_STRIDE
    along with an unscaled TS.  These are both needed by the
    decompressor to initialize TS_OFFSET as hdr(TS) modulo
    field(TS_STRIDE).  Note that TS_OFFSET is the same for any TS
    as long as TS_STRIDE does not change and as long as the
    unscaled TS value does not wrap around; see 4) below.

 2. Compression: After initialization, the compressor no longer
    compresses the unscaled TS values.  Instead, it compresses the
    scaled values.  The compression method can be either W-LSB
    encoding or timer-based encoding.

 3. Decompression: When receiving a (compressed) TS_SCALED, the
    field is first decompressed, and the unscaled RTP TS is then
    calculated as TS = TS_SCALED * TS_STRIDE + TS_OFFSET.

 4. Offset at wraparound: If the value of TS_STRIDE is not equal to
    a power of two, wraparound of the unscaled 32-bit TS will
    change the value of TS_OFFSET.  When this happens, the
    compressor SHOULD reinitialize TS_OFFSET by sending unscaled
    TS, as in 1 above."

Incorrect and invalidated RFC 3095 text (RFC 3095-Section 4.5.3):

The entire point 5, i.e. the entire text starting from "5. Interpretation interval at wraparound ...", down to and including the block of text that starts with "Let a be the number of LSBs" and that ends with "...interpretation interval is b." is incorrect and is thus invalid ๐Ÿšซ.

4.5. Recalculating TS_OFFSET ๐ŸŽ€

TS can be sent unscaled when the TS value change doesn't match the established TS_STRIDE, but TS_STRIDE might still stay unchanged ๐Ÿคทโ€โ™€๏ธ. To make sure subsequent packets decompress correctly, the decompressor MUST therefore always recalculate TS_OFFSET (RTP TS modulo TS_STRIDE) whenever a packet with an unscaled TS value is received ๐Ÿ”.

4.6. TS_STRIDE and the Tsc Flag in Extension 3 ๐ŸŒˆ

The Tsc flag in Extension 3 tells you whether TS is scaled or not. The value of the Tsc flag applies to all TS bits, and also when there are no TS bits in the extension itself. When TS is scaled, it's always scaled using context(TS_STRIDE). The legend for Extension 3 in RFC 3095-Section 5.7.5 incorrectly says that value(TS_STRIDE) is used for scaled TS ๐Ÿ™ƒ.

If TS_STRIDE is present in Extension 3, which is indicated by the Tss flag being set, the compressed header SHOULD carry unscaled TS bits. In other words, the Tsc flag SHOULD NOT be set when Tss is set, because an unscaled TS is needed together with TS_STRIDE to recalculate TS_OFFSET ๐Ÿง . If TS_STRIDE is included in a compressed header with scaled TS, the decompressor must ignore and discard field(TS_STRIDE) ๐Ÿ—‘๏ธ.

Incorrect RFC 3095 text (RFC 3095-Section 5.7.5):

"Tsc: Tsc = 0 indicates that TS is not scaled;
      Tsc = 1 indicates that TS is scaled according to section
       4.5.3, using value(TS_STRIDE).
       Context(Tsc) is always 1.  If scaling is not desired, the
       compressor will establish TS_STRIDE = 1."

Corrected text:

"Tsc: Tsc = 0 indicates that TS is not scaled;
      Tsc = 1 indicates that TS is scaled according to Section
      4.5.3, using context(TS_STRIDE).

      Context(Tsc) is always 1.  If scaling is not desired, the
      compressor will establish TS_STRIDE = 1.

      If field(Tsc) = 1, and if TSS = 1 (meaning that TS_STRIDE is
      present in the extension), field(TS_STRIDE) MUST be ignored
      and discarded."

When the compressor re-establishes a new value for TS_STRIDE using Extension 3, it should send unscaled TS bits together with TS_STRIDE ๐ŸŽ‰.

4.7. Using Timer-Based Compression ๐Ÿ’–

okay so timer-based compression of the RTP timestamp, the way RFC 3095-Section 4.5.4 describes it, may be used to cut down on how many timestamp bits (bytes) get sent when the timestamp can't be inferred from the SN ๐Ÿ•ฐ๏ธโœจ Timer-based compression is only used when decompressing compressed headers that have a TS field. Otherwise, if no timestamp bits are there at all, the timestamp is linearly inferred from the SN (see Section 4.2 of this document) ๐Ÿง 

Whether or not to use it is controlled by the TIME_STRIDE control field, which can be set by an IR, an IR-DYN, or a compressed packet with Extension 3 ๐Ÿ’… Before timer-based compression can be used, the decompressor has to tell the compressor (per channel) about its clock resolution by sending a CLOCK feedback option for any CID on the channel ๐ŸŽ€ Then the compressor can start timer-based compression by sending (per context) a non-zero TIME_STRIDE to the decompressor. Once the compressor is confident that the decompressor has received the TIME_STRIDE value, it can switch over to timer-based compression ๐Ÿฆ‹

5. List Compression ๐ŸŒธ

5.1. CSRC List Items in RTP Dynamic Chain

RFC 3095-Section 5.7.7.6 defines the static and dynamic parts of the RTP header ๐Ÿงš This section adds a 'Generic CSRC list' field to the dynamic chain. That field has a variable length (see RFC 3095-Section 5.8.6). It is always at least one octet in size, even when the list is empty. (The CSRC list in the uncompressed RTP header is different, because it isn't there at all when the RTP CC field is set to 0 ๐Ÿ™ˆ)

5.2. Multiple Occurrences of the CC Field

The static and the dynamic parts of the RTP header are defined in RFC 3095-Section 5.7.7.6 ๐Ÿ“ In the dynamic part, a CC field tells you how many CSRC items are in the 'Generic CSRC list'. Another CC field also shows up inside the 'Generic CSRC list' (RFC 3095-Section 5.8.6.1), because Encoding Type 0 is always used in the dynamic chain. Both CC fields mean the same thing: the value of the CC field sets the number of XI items in the CSRC list for Encoding Type 0, and it isn't used otherwise. So the following applies ๐Ÿ’œ

FORMAL ADDITION TO RFC 3095:

"The first octet in the dynamic part of the RTP header contains a
 CC field, as defined in Section 5.7.7.6.  A second occurrence
 appears in the 'Generic CSRC list', which is also in the dynamic
 part of the RTP header, where Encoding Type 0 is used according
 to the format defined in RFC 3095-5.8.6.1.

 The compressor MUST set both occurrences of the CC field to the
 same value.

 The decompressor MUST use the value of the CC field from the
 Encoding Type 0 within the Generic CRSC list, and it MUST thus
 ignore the first occurrence of the CC field."

5.3. Bit Masks in List Compression

The insertion and/or removal schemes, described in RFC 3095-Sections 5.8.6.2 - 5.8.6.4, use bit masks to show where items get inserted or removed in the reference list ๐Ÿ”ฅ The bit mask can be 7 bits or 15 bits.

The compressor MAY use a 7-bit mask, even if the reference list has more than seven items, as long as changes to the list only hit items within the first seven items of the reference list. Items with an index the 7-bit mask doesn't cover stay unchanged ๐Ÿ™Œ The decompressor MUST NOT modify items with an index not covered by the 7-bit mask, when a 7-bit mask comes in for a reference list that has more than seven items. No touching those ๐Ÿšซ

5.4. Headers Compressed with List Compression

In RFC 3095-Section 5.8, it says headers that can be part of extension header chains "include" AH [14], ESP NULL [13], minimal encapsulation (MINE) [15], GRE [16][17], and IPv6 [9] extensions ๐Ÿ“š This list of compressible headers is right, but the word "include" shouldn't be there, since only the header types listed can actually be handled ๐Ÿ’€ It's also worth noting that for the Minimal Encapsulation (MINE) header there's no explicit discussion of how to compress it, because the header is either sent uncompressed or compressed away completely ๐Ÿซ 

5.5. ESP NULL Header List Compression

Because of where the fields sit in the trailer part of the ESP header, a compressor MUST NOT compress packets containing more than one NULL ESP [13] header ๐Ÿ˜ญ The exception is when the second-outermost header is treated as a regular ESP [12] header and the packets are compressed using profile 0x0003 โœจ

5.6. Translation Tables and Indexes for IP Extension Headers

RFC 3095-Section 5.8.4 explains how list indexes get tied to list items and how table lists get built for IP extension headers ๐Ÿ—‚๏ธ The text wrongly says there's one index per type, since the same type can show up several times with different content in one chain.

In IP extension header list compression, each individual extension header in an extension header chain gets its own index. When there are multiple non-identical occurrences of the same extension type (Protocol Number) within a header chain, each MUST be given its own index ๐ŸŽ€

When there are multiple identical occurrences of the same extension type, the compressor can point them all to the same index. When the value of an item whose index shows up more than once in the list gets updated, the compressor MUST send the value for each occurrence of that index in the list ๐Ÿ’Œ

When the content of extension headers changes, an implementation can choose to either use a different index or update the existing one. Some extensions can be compressed away even when some fields change, since those changes can be conveyed to the decompressor implicitly (for example, sequence numbers in extension headers that can be inferred from the RTP SN) or explicitly (for example, as part of the 'IP extension header(s)' field in Extension 3) ๐Ÿงฉ

When there's more than one IP header, there's more than one list of extension headers, and a translation table is kept for each list separately from the others ๐ŸŒˆ

5.7. Reference List

A list compressed using encoding type 1 (insertion), type 2 (removal), or type 3 (removal/insertion) uses a coding scheme based on a reference list in the context (identified as ref_id) ๐Ÿซถ

Sending a type 1 list when ref_id is an empty list might seem fair, but there's nothing gained by doing that compared to using a type 0 list ๐Ÿคทโ€โ™€๏ธ Sending a type 2 list when ref_id is an empty list would lead to a failure, and sending a type 3 list has very little meaning. All of these alternatives could be seen as possible, based on how list compression is specified in RFC 3095 ๐Ÿค”

If these alternatives were allowed, a decompressor would become required to maintain a sliding window of ref_id lists in R-mode, even for the case where no items are sent in the compressed list. That is not a desirable requirement ๐Ÿ˜ค So using list encoding type 1, type 2, and type 3 is only allowed for non-empty reference lists ๐Ÿ™…โ€โ™€๏ธ

FORMAL ADDITION TO RFC 3095:

"Regardless of the operating mode, for list encoding of type 1,
 type 2, and type 3 lists, ref_id MUST refer to a non-empty list."

5.8. Compression of AH and GRE Sequence Numbers

RFC 3095-Section 5.8.4.2 and RFC 3095-Section 5.8.4.4 describe how to compress the Authentication Header (AH) [14] and the Generic Routing Encapsulation (GRE) [16][17] header ๐Ÿ” Both of these sections mention that the AH/GRE sequence number can be left out of the compressed header under certain circumstances. However, the specific conditions for leaving it out, and the concrete compression and decompression procedures to apply, aren't clearly defined. That's a robustness and interoperability problem ๐Ÿ˜ฌ

The proper rules are given for the ESP case:

"Sequence Number: Not sent when the offset from the sequence
 number of the compressed header is constant, when the compressor
 has confidence that the decompressor has established the correct
 offset.  When the offset is not constant, the sequence number may
 be compressed by sending LSBs"

The same logic applies to the AH/GRE sequence numbers ๐Ÿซง

INCORRECT RFC 3095 TEXT (RFC 3095-Section 5.8.4.2):

"If the sequence number in the AH linearly increases as the RTP
 Sequence Number increases, and the compressor is confident that
 the decompressor has obtained the pattern, the sequence number in
 AH need not be sent.  The decompressor applies linear
 extrapolation to reconstruct the sequence number in the AH."

CORRECTED TEXT:

"The AH sequence number can be omitted from the compressed header
 when the offset from the sequence number (SN) of the compressed
 header is constant, when the compressor has confidence that the
 decompressor has established the correct offset."

INCORRECT RFC 3095 TEXT (RFC 3095-Section 5.8.4.4):

"If the sequence number in the GRE header linearly increases as
 the RTP Sequence Number increases and the compressor is confident
 that the decompressor has received the pattern, the sequence
 number in GRE need not be sent.  The decompressor applies linear
 extrapolation to reconstruct the sequence number in the GRE
 header."

CORRECTED TEXT:

"The GRE sequence number can be omitted from the compressed header
 when the offset from the sequence number (SN) of the compressed
 header is constant, when the compressor has confidence that the
 decompressor has established the correct offset."

6. Updating Properties ๐Ÿ‘‘

6.1. Implicit Updates

A context updating packet that carries compressed sequence number information may also carry information about other fields. In those cases, those fields are updated according to what's in the packet ๐Ÿ”„ The updating packet also implicitly updates inferred fields (for example, the RTP Timestamp) according to the current mode and the appropriate mapping function of the updated and inferred fields ๐Ÿงƒ

So an updating packet updates the reference values of all header fields, either explicitly or implicitly, except for the UO-1-ID packet (see Section 6.2 of this document). In UO-mode, all packets are updating packets, while in R-mode, all packets with a CRC are updating packets ๐Ÿ’…

For example, a UO-0 packet contains the compressed RTP sequence number (SN). That packet also implicitly updates the RTP timestamp, IPv4 ID, and sequence numbers of IP extension headers โœจ

6.2. Updating Properties of UO-1* ๐Ÿ’…

okay bestie, so RFC 3095-Section 5.7.3 says the values in extensions carried by a UO-1-ID packet do not update the context, except for SN, TS, or IP-ID fields ๐Ÿซถ. But RFC 3095-Section 5.8.1 correctly says the translation table in the context gets updated whenever an (Index, item) pair is received. That totally contradicts 5.7.3, because a UO-1-ID packet can carry Extension 3 with (Index, item) pairs inside the 'Compressed CSRC list' field ๐Ÿ’€. On top of that, the text never says what to do with the other sequence numbers that get inferred from SN. Those also get implicitly updated ๐Ÿ™ˆ. So the updating properties of UO-1* in RFC 3095-Section 5.7.3 are incomplete ๐Ÿ˜ญ

INCOMPLETE RFC 3095 TEXT (RFC 3095-Section 5.7.3):

"Values provided in extensions, except those in other SN, TS, or
 IP-ID fields, do not update the context."

CORRECTED TEXT:

"UO-1-ID packets only updates TS, SN, IP-ID, and sequence numbers
 of IP extension headers.  Other values provided in extensions do
 not update the context.

 The decompressor MUST update its translation table whenever an
 (Index, item) pair is received, as per RFC 3095-Section 5.8.1,
 and this rule applies also to UO-1-ID packets."

6.3. Context Updating Properties for IR Packets ๐Ÿฆ‹

IR packets don't wipe the whole context ๐Ÿงš. They just update all the fields carried in the IR header. Same deal for an IR without a dynamic chain: it only updates the static part, and the rest of the context stays exactly as it was โœจ.

So here's the consequence, babe. Fields that the IR packet doesn't update, like the translation tables for list compression, MUST NOT be invalidated by the decompressor when it assumes context damage. Hands off those tables ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’–


6.4. RTP Padding Field (R-P) in Extension 3 ๐ŸŽ€

RFC 3095-Section 5.7.5 defines the properties of RTP header flags and fields in Extension 3. These only get updated when the rtp flag of Extension 3 is set, i.e., rtp = 1. Otherwise they're left alone. The confusing part is that it's unclear how Extension 3 updates the R-P bit in the context ๐Ÿค”

INCOMPLETE RFC 3095 TEXT (RFC 3095-Section 5.7.5):

"R-P: RTP Padding bit, absolute value (presumed zero if absent)."

CORRECTED TEXT:

"R-P: RTP Padding bit.  If R-PT = 1, R-P is the absolute value of
      the RTP padding bit and this value updates context(R-P).  If
      R-PT = 0, context(R-P) is updated to zero."

6.5. RTP eXtension bit (X) in dynamic part ๐ŸŒˆ

RFC 3095-Section 5.7.7.6 defines the properties of the RTP header flags and fields in the RTP part of the dynamic chain of IR and IR-DYN packets. Again, it's unclear how the X bit gets updated in the context ๐ŸŒธ

INCOMPLETE RFC 3095 TEXT (RFC 3095-Section 5.7.7.6):

"X: Copy of X bit from RTP header (presumed 0 if RX = 0)"

CORRECTED TEXT:

"X: X bit from RTP header.  If RX = 1, X is the X bit from the RTP
    header and this value updates context(X).  If RX = 0,
    context(X) is updated to zero."

7. Context management and CID/context Reuse ๐Ÿ‘‘

7.1. Persistence of Decompressor Contexts ๐Ÿงš

okay so as part of the negotiated channel parameters, the compressor and decompressor agree on the highest context identification (CID) number to use, through the MAX_CID parameter โœจ. By agreeing on MAX_CID, the decompressor also agrees to provide memory resources to host at least MAX_CID+1 contexts. An established context with a CID inside this negotiated space MUST be kept by the decompressor until either the CID gets reused, or the channel is taken down or renegotiated. No deleting it early, bestie ๐Ÿ’œ

7.2. CID/Context Reuse ๐Ÿ”ฅ

Right, so during channel negotiation, the maximal number of active contexts gets agreed on through MAX_CID ๐Ÿ’…. That value can be wildly different from one link application to another, and so can the load, meaning how many packet streams you're compressing. A ROHC channel's lifetime can also vary a ton, from almost permanent to pretty short-lived ๐Ÿฆ‹. Generally though, nobody's expected to allocate resources for more contexts than can reasonably be active on the link at once. So context identifiers (CIDs) and context memory are resources the compressor will have to reuse as part of totally normal operation ๐Ÿ”

How context resources get reused is left unspecified in RFC 3095 [1] and the subsequent 3095-based ROHC specifications. This document doesn't mean to change that. ROHC resource management is still an implementation detail ๐Ÿคทโ€โ™€๏ธ But reusing a CID and its allocated memory isn't always as simple as starting a context with a CID nobody has used before. Some profiles can run in different modes where the packet formats change depending on the current mode. So you have to make sure the old context data is completely and safely overwritten, so there's zero risk of weird side effects from old and new context data mixing ๐Ÿ˜ญ This document points out some important core aspects to think about when building resource management into ROHC compressors and decompressors ๐Ÿ“

Okay, so on a high level, CID/context reuse comes in two flavors: reusing for a new context based on the same profile as the old one, or reusing for a new context based on a different profile. The next two sub-sections cover each case separately ๐ŸŒˆ

7.2.1. Reusing a CID/Context with the Same Profile ๐Ÿ“

For multi-mode profiles, like the ones defined in RFC 3095 [1], mode transitions happen through a decompressor-initiated handshake procedure, as defined in RFC 3095-Section 5.6 ๐Ÿค. When a CID/context gets reused for a new context based on the same profile as the old one, the current mode of operation SHOULD be inherited from the old context to the new one. Specifically, the compressor SHOULD continue operating in the old context's mode with the new context too. Why? There's no reliable way for the compressor to tell the decompressor that a CID/context reuse is happening ๐Ÿ™ˆ. So the decompressor can't be expected to clear the context memory for that CID (see Section 6.3), and there's no way to trigger a safe mode switch, which needs that decompressor-initiated handshake ๐Ÿซ 

The mode inheritance rule also applies when the CONTEXT_REINITIALIZATION signal (RFC 3095-Section 6.3.1) is used to reinitiate an entire context โœจ

7.2.2. Reusing a CID/Context with a Different Profile ๐Ÿฆ‹

When a CID gets reused for a new context based on a different profile than the old one, both the compressor and the decompressor MUST start operation with that context in the initial mode of the profile (if it's a multi-mode profile) ๐Ÿ’–. This applies to both IR-initiated new contexts and profile downgrades with IR-DYN, like the 0x0001 -> profile 0x0002 downgrade in RFC 3095-Section 5.11.1.

Type 0 and type 1 packets have different formats in U/O- and R-mode, and these R-mode packets have no CRC ๐Ÿ˜ฌ. So if you initiate a new context on a reused R-mode CID and the initiating IR packets get lost, the decompressor could misinterpret the compressed packets. Yikes!

A CID for a context that's currently operating in R-mode SHOULD therefore not be reused for a new context based on a different profile than the old one. A compressor that does it anyway should cut down the risk of misreading R-0/R-1 by, e.g., not sending packets of types beginning with 00 or 10 until it's highly confident the new context has been successfully initiated at the decompressor ๐Ÿ›ก๏ธ๐Ÿ’…


8. Other Protocol Clarifications ๐ŸŒธ

8.1. Meaning of NBO ๐Ÿ’œ

In the IPv4 dynamic part (RFC 3095-Section 5.7.7.4), if the 'NBO' bit is set, it means network byte order is being used ๐ŸŒ

8.2. IP-ID ๐ŸŽ€

According to RFC 3095-Section 5.7, IP-ID means the compressed value of the IPv4 header's 'Identification' field. Compressed packets carry this compressed value (IP-ID), while IR packets with dynamic chain and IR-DYN packets send the original, uncompressed Identification field value ๐Ÿซถ. The IP-ID field always represents the Identification value of the innermost IPv4 header whose corresponding RND flag is not 1.

If RND or RND2 is set to 1, the corresponding IP-ID(s) get sent as 16-bit uncompressed Identification value(s) at the end of the compressed base header, following the IP-ID description (see the beginning of RFC 3095-Section 5.7). When there's no compressed IP-ID, like for IPv6, or when all IP Identification information is sent as is (indicated by RND/RND2 being set to 1), the decompressor ignores IP-ID bits sent within compressed base headers ๐Ÿ‘€

When RND=RND2=0, IP-ID is compressed, meaning it's expressed as an SN offset and byte-swapped if NBO=0. This is also the case when 16 bits of IP-ID are sent in Extension 3 โœจ

When RND=0 but no IP-ID bits are sent in the compressed header, the SN offset for IP-ID stays unchanged. That means Offset_m equals Offset_ref, as described in Section 4.5.5. Section 5.7 says the same thing in a slightly different way: "default-slope(IP-ID offset) = 0". So if no bits are sent for IP-ID, its SN offset slope defaults to 0 ๐Ÿ“

8.3. Extension-3 in UOR-2* Packets ๐Ÿงš

Some flags of the IP header in the extension, like NBO or RND, can change how fields in UOR-2* packets get interpreted ๐Ÿคฏ. So when a flag changes in Extension 3, a decompressor MUST re-parse the UOR-2* packet. No skipping that step, bestie ๐Ÿ’…

8.4. Multiple Occurrences of the M Bit ๐Ÿฆ‹

The RTP header part of Extension 3, as defined by RFC 3095-Section 5.7.5, includes a one-bit field for the RTP Marker bit. This field is also present in all compressed base header formats except for UO-1-ID. That means there can be two occurrences of the field within one single compressed header. In that case, the two M fields must have the same value ๐Ÿซ 

FORMAL ADDITION TO RFC 3095:

"When there are two occurrences of the M field in a compressed
 header (both in the compressed base header and in the RTP part of
 Extension 3), the compressor MUST set both these occurrences of
 the M field to the same value.

 At the decompressor, if the two M field values of such a packet
 are not identical, the packet MUST be discarded."
Two M fields, one value. No exceptions, iykyk ๐Ÿ˜ญ

8.5. Multiple SN options in one feedback packet ๐ŸŒˆ

The sequence number field in the original ESP [12] header is 32 bits long ๐Ÿ”ข. The SN feedback option (RFC 3095-Section 5.7.6.6) adds 8 more SN bits on top of the 12 SN bits of the FEEDBACK-2 format (RFC 3095-Section 5.7.6.1). So one single SN feedback option isn't enough for the decompressor to send back all 32 bits of the ESP sequence number in a feedback packet, unless it uses multiple SN options in one feedback packet ๐Ÿ™ƒ

RFC 3095-Section 5.7.6.1 says a FEEDBACK-2 packet can contain a variable number of feedback options, and the options can show up in any order ๐ŸŒธ

When processing multiple SN options in one feedback packet, the SN is given by concatenating the fields. And that's the whole vibe โœจ๐Ÿ’–

8.6. Multiple CRC Options in One Feedback Packet โœจ

okay so one CRC option in a feedback packet isn't really useful ๐Ÿ™ˆ but having more than one is still allowed, lowkey iconic of the spec. If there are multiple CRC options, they MUST all be identical, since they get calculated over the same header. Otherwise the compressor MUST discard the feedback packet. no cap, that's the rule ๐Ÿ’…

nobody wants this and it's not expected, but a link carrying feedback between two associated instances can go down ๐Ÿ˜ญ If the compressor can be told about it, it SHOULD restart compression for each flow running in R-mode. When it restarts, it SHOULD give each restarted flow a different CID. This is the move because it avoids misreading the packet type of the compressed header, since some packet type identifiers are shared between U/O-mode and R-mode, when the flow restarts in U-mode (see also Section 7.2). main character energy for sure ๐Ÿ‘‘

Feedback links aren't expected to just vanish once they're up, but it's worth knowing that some link technologies might do exactly that ๐ŸŒธ

8.8. UOR-2 in Profile 0x0002 (UDP) and Profile 0x0003 (ESP) ๐ŸŽ€

there's ONE new UOR-2 format for profile 0x0002 and profile 0x0003, and it replaces all three of the profile 0x0001 formats (UOR-2, UOR-2-ID, UOR-2-TS). It's giving simplicity ๐Ÿงš The same UOR-2 format gets used whether or not there are IP headers with a matching RND=1. This also applies to the IP profile [4] and the IP/UDP-Lite profile [5] โœจ

8.9. Sequence Number LSB's in IP Extension Headers ๐ŸŒˆ

so RFC 3095-Section 5.8.5 defines formats for compressing IP extension header fields. Those include compressed sequence number fields, and they carry the "LSB of sequence number". These sequence numbers aren't "LSB-encoded" the way the RTP sequence number is. Instead they're the LSBs of the uncompressed fields themselves. Tiny detail, big difference ๐Ÿซถ

8.10. Expecting UOR-2 ACKs in O-Mode ๐Ÿ’œ

using UOR-2 ACKs in O-mode (as discussed in RFC 3095-Section 5.4.1.1.2) is optional. A decompressor can also send ACKs for reasons other than acknowledging the UOR-2, and it doesn't have to keep sending ACKs for every single UOR-2. A compressor can also ignore UOR-2 ACKs when it's adapting its optimistic approach strategies. bestie, this flexibility is lowkey the whole point โœจ

So it is NOT RECOMMENDED to use the optional ACK mechanism in O-mode, on either the compressor side or the decompressor side. ๐Ÿ™…โ€โ™€๏ธ

Don't build compressor behaviour on the wrong idea about UOR-2 ACKs, or your compression performance will tank ๐Ÿ˜ญ Decompressors can send ACKs for other reasons too, like sending feedback about clock resolution or starting a mode transition, so an ACK doesn't always mean "got your UOR-2". If an implementation does use the optional acknowledgment algorithm from Section 5.4.1.1.2, it must set the k_3 and n_3 parameters to values much larger than 1, so the compressor's performance doesn't get degraded by that problem.

8.11. Context Repairs, TS_STRIDE and TIME_STRIDE ๐Ÿ“

the 7-bit CRC that checks the result of a decompression attempt covers the original uncompressed header. So the CRC check skips TS_STRIDE and TIME_STRIDE, because those fields aren't part of the original uncompressed header. Not checked, not counted ๐Ÿ™ˆ

The UOR-2 packet type can update the value of TS_STRIDE and/or TIME_STRIDE, using Extension 3. BUT these fields aren't used to decompress the RTP TS field for this packet type, so their values aren't verified, either implicitly or explicitly. Plot twist ๐Ÿ’€

So when the compressor gets a negative acknowledgement, it can't tell whether the failure was caused by an update to TS_STRIDE and/or TIME_STRIDE that didn't work. That's the case where an earlier header that last tried to update those values had already been acknowledged.

Here's the formal addition to RFC 3095:

"When the compressor receives a NACK and uses the UOR-2 header
 type to repair the decompressor context, it SHOULD include fields
 that update the value of both the TS_STRIDE and the TIME_STRIDE
 whose value it has updated at least once since the establishment
 of that context, i.e., since the CID was first associated with
 its current profile.

 When the compressor receives a static-NACK, it MUST include in
 the IR header fields for both the TS_STRIDE and the TIME_STRIDE
 whose value it has updated at least once since the establishment
 of that context, i.e., since the CID was first associated with
 its current profile."

9. ROHC Negotiation ๐ŸŽ€

RFC 3095-Section 4.1 says the link layer has to provide ways to negotiate things like the channel parameters listed in RFC 3095-Section 5.1.1. One of those parameters is PROFILES, which is a set of non-negative integers, where each integer is a profile the decompressor supports. ๐Ÿฆ‹

Each profile is a 16-bit value. The 8 LSBs are the actual profile, and the 8 MSBs are the variant of that profile (see RFC 3095-Section 8). In the ROHC headers sent over the link, only the 8 LSBs identify the profile, so the compressor and decompressor have to agree in advance on which variant to use for each profile ๐Ÿค

So the negotiation protocol has to be able to tell the compressor which profiles the decompressor supports. When a profile has multiple variants, the negotiation protocol has to give the decompressor a way to know which variant the compressor will use. Basically, the PROFILES set after negotiation MUST NOT include more than one variant of a profile. one variant per profile, periodt ๐Ÿ’…

10. PROFILES Sub-option in ROHC-over-PPP ๐ŸŒธ

the logical union of the sub-options for IPCP and IPV6CP negotiations (as specified in ROHC over PPP [2]) can't be used for the PROFILES suboption. The whole union would then have to be considered inside each of the two IPCP negotiations to avoid an ambiguous profile set, and that's messy ๐Ÿ˜ตโ€๐Ÿ’ซ So an implementation of RFC 3241 MUST ensure that the same profile set is negotiated for both IPv4 and IPv6 (IPCP/IPV6CP). consistency is everything โœจ

11. Constant IP-ID Encoding in IP-only and UPD-Lite Profiles ๐ŸŒˆ

in the ROHC IP-only profile (Section 3.3 of RFC 3843 [4]), there's a mechanism for encoding a constant Identification value in IPv4, called constant IP-ID. The ROHC UDP-Lite profiles (RFC 4019 [5]) use this same mechanism too ๐Ÿซถ

The "Constant IP-ID" mechanism applies to both the inner and the outer IP header when they're present. That means there will be both a SID and a SID2 context value. two IDs, one mechanism, zero drama ๐Ÿงš

12. Security Considerations ๐Ÿ’€

okay this one is serious, bestie ๐Ÿ˜ญ This document makes a bunch of corrections and clarifications to [1], but it doesn't change anything about the security aspects of the protocol. So the security considerations of [1] apply here with no additions. Read [1] before you ship anything!! ๐Ÿ”ฅ

13. Acknowledgments ๐Ÿ’–

huge thank yous to Vicknesan Ayadurai, Carsten Bormann, Mikael Degermark, Zhigang Liu, Abigail Surtees, Mark West, Tommy Lundemo, Alan Kennington, Remi Pelland, Lajos Zaccomer, Endre Szalai, Mark Kalmanczhelyi, and Arpad Szakacs for their contributions and comments ๐Ÿซถ Also a big shoutout to the committed document reviewers, Carl Knutsson and Biplab Sarkar, who reviewed the document during the working group last call ๐Ÿ‘‘

14. References ๐Ÿ“š

14.1. Normative References ๐Ÿฆ‹

[1]  Bormann, C., Burmeister, C., Degermark, M., Fukushima, H.,
     Hannu, H., Jonsson, L-E., Hakenberg, R., Koren, T., Le, K., Liu,
     Z., Martensson, A., Miyazaki, A., Svanbro, K., Wiebke, T.,
     Yoshimura, T., and H. Zheng, "RObust Header Compression (ROHC):
     Framework and four profiles: RTP, UDP, ESP, and uncompressed",
     RFC 3095, July 2001.

[2]  Bormann, C., "Robust Header Compression (ROHC) over PPP", RFC
     3241, April 2002.

[3]  Simpson, W., "PPP in HDLC-like Framing", STD 51, RFC 1662, July
     1994.

[4]  Jonsson, L-E. and G. Pelletier, "RObust Header Compression
     (ROHC): A Compression Profile for IP", RFC 3843, June 2004.

[5]  Pelletier, G., "RObust Header Compression (ROHC): Profiles for
     User Datagram Protocol (UDP) Lite", RFC 4019, April 2005.

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

14.2. Informative References ๐Ÿ“–

[7]  Jonsson, L-E., Pelletier, G., and K. Sandlund, "RObust Header
     Compression (ROHC): A Link-Layer Assisted Profile for
     IP/UDP/RTP", RFC 4362, January 2006.

[8]  Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.

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

[10] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August
     1980.

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

[12] Kent, S., "IP Encapsulating Security Payload (ESP)", RFC 4303,
     December 2005.

[13] Glenn, R. and S. Kent, "The NULL Encryption Algorithm and Its
     Use With IPsec", RFC 2410, November 1998.

[14] Kent, S., "IP Authentication Header", RFC 4302, December 2005.

[15] Perkins, C., "Minimal Encapsulation within IP", RFC 2004,
     October 1996.

[16] Farinacci, D., Li, T., Hanks, S., Meyer, D., and P. Traina,
     "Generic Routing Encapsulation (GRE)", RFC 2784, March 2000.

[17] Dommety, G., "Key and Sequence Number Extensions to GRE", RFC
     2890, September 2000.

Appendix A. Sample CRC Algorithm ๐Ÿงฎโœจ

okay bestie, this is the sample CRC code ๐Ÿ’… It's a little Perl demo by Carsten Bormann from 2001-08-02 that shows off the four CRC types used in RFC 3095 (the robust header compression spec). You type your data in hex and then hit Control+D ๐ŸŽ€

#!/usr/bin/perl -w
use strict;
#=================================
#
# ROHC CRC demo - Carsten Bormann cabo@tzi.org 2001-08-02
#
# This little demo shows the four types of CRCs in use in RFC 3095,
# the specification for robust header compression. Type your data in
# hexadecimal form and then press Control+D.
#
#---------------------------------
#
# utility
#
sub dump_bytes($) {
    my $x = shift;
    my $i;
    for ($i = 0; $i < length($x); ) {
  printf("%02x ", ord(substr($x, $i, 1)));
  printf("\n") if (++$i % 16 == 0);
    }
    printf("\n") if ($i % 16 != 0);
}

#---------------------------------
#
# The CRC calculation algorithm.
#
sub do_crc($$$) {
    my $nbits = shift;
    my $poly = shift;
    my $string = shift;

    my $crc = ($nbits == 32 ? 0xffffffff : (1 << $nbits) - 1);
    for (my $i = 0; $i < length($string); ++$i) {
      my $byte = ord(substr($string, $i, 1));
      for( my $b = 0; $b < 8; $b++ ) {
        if (($crc & 1) ^ ($byte & 1)) {
          $crc >>= 1;
          $crc ^= $poly;
        } else {
        $crc >>= 1;
        }
        $byte >>= 1;
      }
    }
    printf "%2d bits, ", $nbits;
    printf "CRC: %02x\n", $crc;
}

#---------------------------------
#
# Test harness
#
$/ = undef;
$_ = <>;         # read until EOF
my $string = ""; # extract all that looks hex:
s/([0-9a-fA-F][0-9a-fA-F])/$string .= chr(hex($1)), ""/eg;
dump_bytes($string);

#---------------------------------
#
# 32-bit segmentation CRC
# Note that the text implies that this is complemented like for PPP
# (this differs from 8-, 7-, and 3-bit CRCs)
#
#      C(x) = x^0 + x^1 + x^2 + x^4 + x^5 + x^7 + x^8 + x^10 +
#             x^11 + x^12 + x^16 + x^22 + x^23 + x^26 + x^32
#
do_crc(32, 0xedb88320, $string);

#---------------------------------
#
# 8-bit IR/IR-DYN CRC
#
#      C(x) = x^0 + x^1 + x^2 + x^8
#
do_crc(8, 0xe0, $string);

#---------------------------------
#
# 7-bit FO/SO CRC
#
#      C(x) = x^0 + x^1 + x^2 + x^3 + x^6 + x^7
#
do_crc(7, 0x79, $string);

#---------------------------------
#
# 3-bit FO/SO CRC
#
#      C(x) = x^0 + x^1 + x^3
#
do_crc(3, 0x6, $string);

Authors' Addresses ๐ŸŒธ

Meet the crew who wrote this! ๐Ÿซถ

Lars-Erik Jonsson
Optand 737
SE-831 92 Ostersund, Sweden
Phone: +46 70 365 20 58
EMail: lars-erik@lejonsson.com

Kristofer Sandlund
Ericsson AB
Box 920
SE-971 28 Lulea, Sweden
Phone: +46 8 404 41 58
EMail: kristofer.sandlund@ericsson.com

Ghyslain Pelletier
Ericsson AB
Box 920
SE-971 28 Lulea, Sweden
Phone: +46 8 404 29 43
EMail: ghyslain.pelletier@ericsson.com

Peter Kremer
Conformance and Software Test Laboratory
Ericsson Hungary
H-1300 Bp. 3., P.O. Box 107, HUNGARY
Phone: +36 1 437 7033
EMail: peter.kremer@ericsson.com

Copyright (C) The IETF Trust (2007) ๐Ÿ’œ

This document is subject to the rights, licenses and restrictions in BCP 78. Except as BCP 78 says otherwise, the authors keep all of their rights.

The document and the information in it are provided on an "AS IS" basis. The contributor, the organization they represent or are sponsored by (if any), the Internet Society, the IETF Trust and the Internet Engineering Task Force all disclaim every warranty, whether express or implied. That includes, but isn't limited to, any warranty that using the information won't infringe any rights, and any implied warranty of merchantability or fitness for a particular purpose. Yeah, it's a lot, but it's important ๐Ÿ˜ญ


Intellectual Property ๐Ÿ”ฅ

The IETF doesn't take a position on whether any Intellectual Property Rights (or other rights someone might claim) are valid or in scope for the technology in this document. It also doesn't say whether licenses are available, and it hasn't independently checked for any such rights. If you want the details on how rights work for RFC documents, check out BCP 78 and BCP 79 ๐ŸŒˆ

IPR disclosures that were sent to the IETF Secretariat are on the IETF online IPR repository at http://www.ietf.org/ipr. That's also where you'll find any licence assurances that have been made, and the results of any attempt to get a general license or permission for implementers or users of this spec to use the proprietary rights.

The IETF invites anyone who's interested to flag any copyrights, patents, patent applications, or other proprietary rights that might cover technology needed to implement this standard. Send that info to the IETF at ietf-ipr@ietf.org ๐Ÿ’Œ


Acknowledgement โญ

Funding for the RFC Editor function is currently provided by the Internet Society. Thank you for the support, Internet Society ๐Ÿงš๐Ÿ’–

๐Ÿ“ฆ where this page comes from