Subject: [rohc] Request for comments on ROHC-TCP packet formats

From: Kristofer Sandlund <[email-masked]>
Date: Tue, 18 Jan 2005 12:53:25 +0100

Hi all!

After some offline discussions between the ROHC-TCP authors, we have once again 
decided to revise the compressed base headers according to the following design 
criteria:

- Push bit is always sent

- 3-bit CRC always present unless fields that affect future packet format 
interpretation are present (such as ecn_used and ip_id_behavior), if so, a 7-bit 
CRC is used.

- MSN: 4 bits with p=4 to allow for reordering and losses.

- Sequence number: at least 14 bits of LSB when present. The reason for 14, is 
that we expect a delta_sn of about 1500 bytes, and adding room for 
retransmissions (negative offset) and for robustness this gives us 14 bits. For 
offset, the interval has been split in half to allow for retransmissions 
p=2^(k-1) - 1.
When scaled, 4 bits are used with p=3.

- Ack number: At least 15 bits of LSB when present. Similar analysis to that 
above, but since only every two packets are normally acked, we need one extra 
bit. Since Ack numbers increasing apart from when we have prelink reordering, we 
have set p=2^(k-2) - 1 (25% space negative offset). When scaled, 4 bits are used 
with p=3

- Window: Changes in window are expected to be similar to the changes in 
sequence number and therefore 14 bits of LSBs should be used, but it is 
preferrable to send all the 16 bits. p=2^(k -1) - 1.

- IP-ID (when sequential): 4 bits are preferrable, but 3 can be allowed and if 
there are "free bits", use up to 8 bits. For 4 or more bits, use p=3, if k<3 use 
p=1.

- Discriminator: The length of the discriminator for each packet format is 
decided upon based on the number of bits available to achieve byte alignemnt 
after all fields in the header have fulfilled their design criteria. Also, the 
packet formats deemed to be most important have often received the shortest 
discriminators to limit header size, but in some cases this was not possible.

The set of packet formats attached to this mail (co_rnd_<x> and co_seq_<x> plus 
co_common) have been made to meet these requirements, so comments on both the 
formats themselves and also on the requirements above are appreciated.

With the ROHC-TCP "development" now going on for a number of years, we would 
very much like to get this done and we feel that these packet formats are 
something that is nearing "last-callable". Therefore, now is a good time to 
comment on them since changes later on will be a lot harder to do.

If you do not like to read ROHC-FN to understand the packet formats, the 
attached text document also contains regular box notation ascii-pictures of the 
compressed base headers. The rest of the packet formats (chains & list 
compression) are still only expressed in ROHC-FN.

/Kristofer Sandlund, Effnet AB

% Packet formats for TCP-ROHC
%
% $Id: tcp-pf.txt,v 1.28 2005/01/12 13:44:30 ks Exp $
%
% TODO
% - Does ack and seq scaling have a zero-division issue since they appear in
%   the default_methods section?
% - ack scaling could be applied to a larger number of packet formats
%   Maybe let _10 and/or _8 use one bit to indicate of ack is scaled or not
%   andin that case use 8 bits less?
% - REVIEW OF PACKET FORMAT CONTENT!
        
% List of encoding methods that are expected to be predefined
% by the FN:
%
irregular (length)                 === "predefined by FN";
static                             === "predefined by FN";
compressed_value (length, value)   === "predefined by FN";
lsb (lsbs, offset)                 === "predefined by FN";
crc (b, p, i, d, l)                === "predefined by FN";
uncompressed_value (length, value) === "predefined by FN";

% Encoding methods not specified in FN syntax:

inferred_mine_header_checksum   === "insert reference here";
inferred_ip_v6_length           === "insert reference here";
inferred_ip_v4_header_checksum  === "insert reference here";
inferred_ip_v4_length           === "insert reference here";
inferred_offset                 === "insert reference here";

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Global control fields
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The control fields here reside in the context and are persistent between
% packets. Some of these (such as the sequence number scaling/residue are
% never transmitted explicitly, but are inferred from other values.
control_fields  = ecn_used,           %[ 1 ]
                  msn,                %[ 16 ]
                  ip_inner_ecn,       %[ 2 ]
                  seq_number_scaled,  %[ 32 ]
                  seq_number_residue, %[ 32 ]
                  ack_stride,         %[ 16 ]
                  ack_number_scaled,  %[ 16 ]
                  ack_number_residue; %[ 16 ]

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% General structures
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

static_or_irreg32(flag) ===
{
        uncompressed_format =        field;     %[ 32 ]
   
        format_irreg_enc =        field,     %[ 32 ]
        {
           let (flag == 1);
           field ::= irregular(32);
        };
        
        format_static_enc =       field,     %[ 0 ]
        {
           let (flag == 0);
           field ::= static;
        };
};

static_or_irreg16(flag) === 
{
        uncompressed_format =        field;     %[ 16 ]
  
        format_irreg_enc =        field,     %[ 16 ]
        {
           let (flag == 1);
           field ::= irregular(16);
        };
        
        format_static_enc =       field,     %[ 0 ]
        {
           let (flag == 0);
           field ::= static;
        };
};

static_or_irreg8(flag) === 
{
        uncompressed_format = field;            %[ 8 ]
  
        format_irreg_enc =        field,     %[ 8 ]
        {
           let (flag == 1);
           field ::= irregular(8);
        };
        format_static_enc =       field,     %[ 0 ]
        {
           let (flag == 0);
           field ::= static;
        };
};

variable_length_32_enc(flag) ===
{
        uncompressed_format = field; %[ 32 ]

        format_not_present = field, %[ 0 ]
        {
           let(flag == 0);
           field ::= static;
        };
        format_8_bit = field, %[ 8 ]
        {
           let(flag == 1);
           field ::= lsb(8, 63);
        };
        format_16_bit = field, %[ 16 ]
        {
           let(flag == 2);
           field ::= lsb(16, 16383);
        };
        format_32_bit = field, %[ 32 ]
        {
           let(flag == 3);
           field ::= irregular(32);
        };
};

variable_length_16_enc(flag) ===
{
        uncompressed_format = field; %[ 16 ]

        format_not_present = field, %[ 0 ]
        {
           let(flag == 0);
           field ::= static;
        };
        format_8_bit = field, %[ 8 ]
        {
           let(flag == 1);
           field ::= lsb(8, 63);
        };
        format_16_bit = field, %[ 16 ]
        {
           let(flag == 2);
           field ::= irregular(16);
        };
};

optional32 (flag) ===
{
        uncompressed_format = item; % 0 or 32 bits

        format_present = item, %[ 32 ]
        {
           let (flag == 1);
           item ::= irregular (32);
        };

        format_not_present = item, %[ 0 ]
        {
           let (flag == 0);
           item ::= compressed_value (0, 0);
        };
};

lsb_7_or_31 ===
{
        uncompressed_format = item; % 7 or 31 bits

        format_lsb_7  = discriminator, %[ 1 ]
                        item,          %[ 7 ]
        {
                discriminator ::= '0';
                item          ::= lsb (7, 8);
        };

        format_lsb_31 = discriminator, %[ 1 ]
                        item,          %[ 31 ]
        {
                discriminator ::= '1';
                item          ::= lsb (31, 256);
        };
};

opt_lsb_7_or_31 (flag) ===
{
        uncompressed_format = item;  % 32 bits

        format_present = item, % 8 or 32 bits
        {
           let (flag == 1);
           item ::= lsb_7_or_31;
        };

        format_not_present = item, %[ 0 ]
        {
           let (flag == 0);
           item ::= compressed_value (0, 0);
        };
};

crc3 (data_value, data_length) ===
{
        uncompressed_format = ;

        compressed_format = crc_value, %[ 3 ]
        {
                crc_value ::= crc(3, 0x06, 0x07, data_value, data_length);
        };
};

crc7 (data_value, data_length) ===
{
        uncompressed_format = ;

        compressed_format = crc_value, %[ 7 ]
        {
                crc_value ::= crc(7, 0x79, 0x7f, data_value, data_length);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% IPv6 Destination options header
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ip_dest_opt ===
{
        uncompressed_format = next_header,           %[ 8 ]
                              length,                %[ 8 ]
                              value;                 % n bits

        default_methods =
        {
                next_header      ::= static;
                length           ::= static;
                value            ::= static;
        };

        format_dest_opt_static = next_header,        %[ 8 ]
                                 length,             %[ 8 ]
        {
                next_header      ::= irregular(8);
                length           ::= irregular(8);
        };

        format_dest_opt_dynamic = value,     % n bits
        {
                value ::= irregular(length:uncomp_value * 64 + 48);
        };

        format_dest_opt_replicate_0 = discriminator, %[ 8 ]
        {
                discriminator ::= '00000000';
        };

        format_dest_opt_replicate_1 = discriminator, %[ 8 ]
                                      length,        %[ 8 ]
                                      value,         % n bits
        {
                discriminator    ::= '10000000';
                length           ::= irregular(8);
                value            ::= irregular(length:uncomp_value * 64 + 48);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% IPv6 Hop-by-Hop options header
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ip_hop_opt ===
{
        uncompressed_format = next_header,           %[ 8 ]
                              length,                %[ 8 ]
                              value;                 % n bits

        default_methods =
        {
                next_header      ::= static;
                length           ::= static;
                value            ::= static;
        };

        format_hop_opt_static = next_header,         %[ 8 ]
                                length,              %[ 8 ]
        {
                next_header      ::= irregular(8);
                length           ::= irregular(8);
        };

        format_hop_opt_dynamic = value,     % n bits
        {
                value ::= irregular(length:uncomp_value * 64 + 48);
        };

        format_hop_opt_replicate_0 = discriminator,  %[ 8 ]
        {
                discriminator ::= '00000000';
        };

        format_hop_opt_replicate_1 = discriminator,  %[ 8 ]
                                     length,         %[ 8 ]
                                     value,          % n bits
        {
                discriminator    ::= '10000000';
                length           ::= irregular(8);
                value            ::= irregular(length:uncomp_value * 64 + 48);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% IPv6 Routing header
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ip_rout_opt ===
{
        uncompressed_format = next_header,           %[ 8 ]
                              length,                %[ 8 ]
                              value;                 % n bits

        default_methods     =
        {
           next_header ::= static;
           length      ::= static;
           value       ::= static;
        };

        format_rout_opt_static = next_header,        %[ 8 ]
                                 length,             %[ 8 ]
                                 value,              % n bits
        {
           next_header ::= irregular(8);
           length      ::= irregular(8);
           value       ::= irregular(length:uncomp_value * 64 + 48);       
        };

        format_rout_opt_dynamic =
        {
        };

        format_rout_opt_replicate_0 = discriminator, %[ 8 ]
        {
           discriminator  ::= '00000000';
        };

        format_rout_opt_replicate_1 = discriminator, %[ 8 ]
                                      length,        %[ 8 ]
                                      value,         % n bits
        {
           discriminator    ::= '10000000';
           length           ::= irregular(8);
           value            ::= irregular(length:uncomp_value * 64 + 48);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% GRE Header
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

optional_checksum (flag_value) ===
{
        uncompressed_format = value,     % 0 or 16 bits
                              reserved1; % 0 or 16 bits

        format_cs_present = value,     %[ 16 ]
                            reserved1, %[ 0 ]
        {
           let (flag_value == 1);
           value     ::= irregular (16);
           reserved1 ::= uncompressed_value (16, 0);
        };

        format_not_present = value,     %[ 0 ]
                             reserved1, %[ 0 ]
        {
           let (flag_value == 0);
           value     ::= compressed_value (0, 0);
           reserved1 ::= compressed_value (0, 0);
        };
};

gre_proto ===
{
        uncompressed_format = protocol; %[ 16 ]

        default_methods =
        {
        };

        format_ether_v4 = discriminator, %[ 1 ]
        {
                discriminator ::= compressed_value (1, 0);
                protocol      ::= uncompressed_value (16, 0x0800);
        };

        format_ether_v6 = discriminator, %[ 1 ]
        {
                discriminator ::= compressed_value (1, 1);
                protocol      ::= uncompressed_value (16, 0x86DD);
        };
};

gre ===
{
        uncompressed_format = c_flag,              %[ 1 ]
                              r_flag,              %[ 1 ]
                              k_flag,              %[ 1 ]
                              s_flag,              %[ 1 ]
                              reserved0,           %[ 9 ]
                              version,             %[ 3 ]
                              protocol,            %[ 16 ]
                              checksum_and_res,    % 0 or 32 bits
                              key,                 % 0 or 32 bits
                              sequence_number;     % 0 or 32 bits

        default_methods =
        {
                c_flag     ::= static;
                r_flag     ::= static;
                k_flag     ::= static;
                s_flag     ::= static;
                reserved0  ::= uncompressed_value (9, 0);
                version    ::= static;
                protocol   ::= static;
                key        ::= static;
                checksum_and_res ::= optional_checksum (c_flag);
        };

        format_gre_static = protocol,                %[ 1 ]
                            c_flag,                  %[ 1 ]
                            r_flag,                  %[ 1 ]
                            k_flag,                  %[ 1 ]
                            s_flag,                  %[ 1 ]
                            version,                 %[ 3 ]
                            key,                     % 0 or 32 bits
        {
                protocol ::= gre_proto;

                c_flag  ::= irregular (1);
                r_flag  ::= irregular (1);
                k_flag  ::= irregular (1);
                s_flag  ::= irregular (1);
                version ::= irregular (3);

                key ::= optional32 (k_flag);
                sequence_number ::= static;
        };

        format_gre_dynamic = checksum_and_res,% 0 or 16 bits
                             sequence_number, % 0 or 32 bits
        {
                sequence_number ::= optional32 (s_flag);
        };

        format_gre_replicate_0 = discriminator,   %[ 8 ]
                                 checksum_and_res,% 0 or 16 bits
                                 sequence_number, % 0, 8 or 32 bits
        {
                discriminator ::= '00000000';

                sequence_number ::= opt_lsb_7_or_31 (s_flag);
        };

        format_gre_replicate_1 =
                               discriminator,   %[ 8 ]
                               c_flag,          %[ 1 ]
                               r_flag,          %[ 1 ]
                               k_flag,          %[ 1 ]
                               s_flag,          %[ 1 ]
                               reserved,        %[ 1 ]
                               version,         %[ 3 ]
                               checksum_and_res,% 0 or 16 bits
                               key,             % 0 or 32 bits
                               sequence_number, % 0 or 32 bits
        {
                discriminator   ::= '10000000';

                c_flag          ::= irregular (1);
                r_flag          ::= irregular (1);
                k_flag          ::= irregular (1);
                s_flag          ::= irregular (1);
                reserved        ::= '0';
                version         ::= irregular (3);

                key             ::= optional32 (k_flag);
                sequence_number ::= optional32 (s_flag);
        };

        format_gre_irregular = checksum_and_res,% 0 or 16 bits
                               sequence_number, % 0, 8 or 32 bits
        {
                sequence_number ::= opt_lsb_7_or_31 (s_flag);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MINE header
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

mine ===
{
        uncompressed_format = next_header, %[ 8 ]
                              s_bit,       %[ 1 ]
                              res_bits,    %[ 7 ]
                              checksum,    %[ 16 ]
                              orig_dest,   %[ 32 ]
                              orig_src;    %  0 or 32 bits

        default_methods =
        {
                next_header  ::= static;
                s_bit     ::= static;
                res_bits  ::= static;
                checksum  ::= inferred_mine_header_checksum;
                orig_dest ::= static;
                orig_src  ::= static;
        };

        format_mine_static = next_header,%[ 8 ]
                             s_bit,      %[ 1 ],
                             res_bits,   %[ 7 ],
                             orig_dest,  %[ 32 ]
                             orig_src,   %  0 or 32 bits
        {
                next_header ::= irregular (8);
                s_bit       ::= irregular (1);
                res_bits    ::= irregular (7);
                       % include reserved - no benefit in removing them
                orig_dest   ::= irregular (32);
                orig_src    ::= optional32 (s_bit);
        };

        format_mine_dynamic =
        {
        };

        format_mine_replicate_0 = discriminator, %[ 8 ]
                                  checksum,      %[ 0 ]
        {
                discriminator ::= '00000000';
        };

        format_mine_replicate_1 = discriminator,  %[ 8 ]
                                  s_bit,          %[ 1 ]
                                  res_bits,       %[ 7 ]
                                  orig_dest,      %[ 32 ]
                                  orig_src,       %  0 or 32 bits
        {
                discriminator ::= '10000000';

                s_bit         ::= irregular (1);
                res_bits      ::= irregular (7);
                orig_dest     ::= irregular (32);
                orig_src      ::= optional32 (s_bit);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Authentication Header (AH)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ah ===
{
        uncompressed_format = next_header,          %[ 8 ]
                              length,               %[ 8 ]
                              res_bits,             %[ 16 ]
                              spi,                  %[ 32 ]
                              sequence_number,      %[ 32 ]
                              auth_data;            % n bits

        default_methods   =
        {
           next_header     ::= static;
           length          ::= static;
           res_bits        ::= static;
           spi             ::= static;
           sequence_number ::= static;
           auth_data       ::= irregular (length:uncomp_value * 32 - 32);
        };

        format_ah_static =   next_header,           %[  8 ]
                             length,                %[  8 ]
                             spi,                   %[ 32 ]
        {
           next_header ::= irregular(8);
           length      ::= irregular (8);
           spi         ::= irregular (32);
        };

        format_ah_dynamic =   res_bits,             %[ 16 ]
                              sequence_number,      %[ 32 ]
                              auth_data,            %  n bits
        {
           res_bits        ::= irregular (16);
           sequence_number ::= irregular (32);
        };

        format_ah_replicate_0 =   discriminator,    %[ 8 ]
                                  sequence_number,  % 8 or 32 bits
                                  auth_data,        % n bits
        {
           discriminator   ::= '00000000';
           sequence_number ::= lsb_7_or_31;
        };

        format_ah_replicate_1 =   discriminator,    %[ 8 ]
                                  length,           %[ 8 ]
                                  res_bits,         %[ 16 ]
                                  spi,              %[ 32 ]
                                  sequence_number,  %[ 32 ]
                                  auth_data,        %  n bits
        {
           discriminator   ::= '10000000';
           length          ::= irregular (8);
           res_bits        ::= irregular (16);
           spi             ::= irregular (32);
           sequence_number ::= irregular (32);
        };

        format_ah_irregular =   sequence_number,    % 8 or 32 bits
                                auth_data,          % n bits
        {
           sequence_number ::= lsb_7_or_31;
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ESP header (NULL encrypted)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

esp_null ===
{
        uncompressed_format = spi,             %[ 32 ]
                              sequence_number, %[ 32 ]
                              next_header;     %[ 8 ]

        default_methods =
        {
                spi         ::= static;
                % Next header will always be present in the trailer part,
                % but sometimes it will ALSO be present in the header
                % (static chain only).
                nh_field ::= static; % Control field
                next_header ::= static;
                sequence_number ::= static;
        };

        format_esp_static = nh_field, %[ 8 ]
                            spi,      %[ 32 ]
        {
                % identify next header assume next 96 bits skipped
                % to get to end of packet (i.e. this is anchored from the end
                %  of the packet, not the start)
                nh_field ::= compressed_value(8, next_header);
                next_header ::= irregular (8); % At packet end!
                spi ::= irregular (32);
        };

        format_esp_dynamic = sequence_number, %[ 32 ]
        {
                sequence_number  ::= irregular (32);
        };

        format_esp_replicate_0 = discriminator,   %[ 8 ]
                                 sequence_number, % 8 or 32 bits
        {
                discriminator   ::= '00000000';

                sequence_number ::= lsb_7_or_31;
        };

        format_esp_replicate_1 = discriminator,    %[ 8 ]
                                 spi,              %[ 32 ]
                                 sequence_number,  %[ 32 ]
        {
                discriminator   ::= '10000000';

                spi             ::= irregular (32);
                sequence_number ::= irregular (32);
        };

        format_esp_irregular = sequence_number, % 8 or 32 bits
        {
                sequence_number ::= lsb_7_or_31;
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Structures common for IPv4 and IPv6
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

irreg_tos_tc ===
{
        uncompressed_format = tos_tc;        %[ 6 ]

        format_tos_tc_present = tos_tc ,     %[ 6 ]
        {
           let(ecn_used:uncomp_value == 1);
           tos_tc  ::= irregular (6);
        };

        format_tos_tc_not_present = tos_tc , %[ 0 ]
        {
           let(ecn_used:uncomp_value == 0);
           tos_tc  ::= static;
        };
};

ip_irreg_ecn ===
{
        uncompressed_format = ip_ecn_flags;     %[ 2 ]

        format_tc_present = ip_ecn_flags,       %[ 2 ]
        {
           let(ecn_used:uncomp_value == 1);
           ip_ecn_flags ::= irregular (2);
        };

        format_tc_not_present = ip_ecn_flags, %[ 0 ]
        {
           let(ecn_used:uncomp_value == 0);
           ip_ecn_flags ::= static;
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% IPv6 Header
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

fl_enc ===
{
        uncompressed_format = flow_label;

        format_fl_zero = discriminator, %[ 1 ]
                         flow_label,    %[ 0 ]
                         reserved,      %[ 4 ]
        {
                discriminator ::= '0';
                flow_label    ::= uncompressed_value (20, 0);
                reserved      ::= '0000';
        };

        format_fl_non_zero = discriminator, %[ 1 ]
                             flow_label,    %[ 20 ]
        {
                discriminator ::= '1';
                flow_label    ::= irregular (20);
        };
};

% The argument flag should only be used if this flag was set when processing
% a compressed base header, if not, the flag should be zero.
ipv6 (ttl_irregular_chain_flag) ===
{
        uncompressed_format = version,        %[ 4 ]
                              tos_tc,         %[ 6 ]
                              ip_ecn_flags,   %[ 2 ]
                              flow_label,     %[ 20 ]
                              payload_length, %[ 16 ]
                              next_header,    %[ 8 ]
                              ttl_hopl,       %[ 8 ]
                              src_addr,       %[ 128 ]
                              dst_addr;       %[ 128 ]

        default_methods =
        {
                version        ::= uncompressed_value (4, 6);
                tos_tc         ::= static;
                ip_ecn_flags   ::= static;
                flow_label     ::= static;
                payload_length ::= inferred_ip_v6_length;
                next_header    ::= static;
                ttl_hopl       ::= static;
                src_addr       ::= static;
                dst_addr       ::= static;
        };

        format_ipv6_static = version_flag,    %[ 1 ]
                             reserved,        %[ 2 ]
                             flow_label,      % 5 or 21 bits
                             next_header,     %[ 8 ]
                             src_addr,        %[ 128 ]
                             dst_addr,        %[ 128 ]
        {
                   version_flag        ::=   '1';
                   reserved            ::=   '00';
                   flow_label          ::=   fl_enc;
                   next_header         ::=   irregular (8);
                   src_addr            ::=   irregular(128);
                   dst_addr            ::=   irregular(128);
        };

        format_ipv6_dynamic = tos_tc,        %[ 6 ]
                              ip_ecn_flags,  %[ 2 ]
                              ttl_hopl,      %[ 8 ]
        {
                tos_tc       ::= irregular (6);
                ip_ecn_flags ::= irregular (2);
                ttl_hopl     ::= irregular (8);
        };

        format_ipv6_replicate = tos_tc,       %[ 6 ]
                                ip_ecn_flags, %[ 2 ]
        {
                tos_tc       ::= irregular (6);
                ip_ecn_flags ::= irregular (2);
        };

        format_ipv6_outer_irregular_without_ttl
                                    = tos_tc,       % 0 or 6 bits
                                      ip_ecn_flags, % 0 or 2 bits
        {
                % for 'outer' headers only, irregular chain is required
                tos_tc        ::= irreg_tos_tc;
                ip_ecn_flags  ::= ip_irreg_ecn;
                let(ttl_irregular_chain_flag == 0);
        };
        
        format_ipv6_outer_irregular_with_ttl
                                    = tos_tc,       % 0 or 6 bits
                                      ip_ecn_flags, % 0 or 2 bits
                                      ttl_hopl,     %[ 8 ]
        {
                % for 'outer' headers only, irregular chain is required
                tos_tc        ::= irreg_tos_tc;
                ip_ecn_flags  ::= ip_irreg_ecn;
                let(ttl_irregular_chain_flag == 1);
                ttl_hopl       ::= irregular(8);
        };

        % Note that the ECN bits are stored in the global control field
        % so that they can be output in TCP irregular chain.
        format_ipv6_innermost_irregular = 
        {
                let(ip_inner_ecn:uncomp_value ==
                    ip_ecn_flags:uncomp_value);
        };

};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% IPv4 Header
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ip_id_enc_dyn (behavior) ===
{
        uncompressed_format = ip_id; %[ 16 ]

        format_ip_id_seq = ip_id, %[ 16 ]
        {
              let ((behavior == 0) || (behavior == 1) || (behavior == 2));
              % In dynamic chain, but random, seq, and seq-swapped are 16 bits
              ip_id ::= irregular(16);
        };

        format_ip_id_zero = ip_id, %[ 0 ]
        {
              let (behavior == 3);
              % Zero IPID
              ip_id ::= uncompressed_value (16, 0);
        };
};

ip_id_enc_irreg (behavior) ===
{
        uncompressed_format = ip_id; %[ 16 ]

        format_ip_id_seq = ip_id, %[ 0 ]
        {
           let (behavior == 0); % sequential
           ip_id ::= static;    % Nothing to send in irregular chain
        };

        format_ip_id_seq_swapped = ip_id, %[ 0 ]
        {
           let (behavior == 1); % sequential-swapped
           ip_id ::= static;    % Nothing to send in irregular chain
        };
        
        format_ip_id_rand = ip_id, %[ 16 ]
        {
           let (behavior == 2); % random
           ip_id ::= irregular (16);
        };

        format_ip_id_zero = ip_id, %[ 0 ]
        {
           let (behavior == 3); % zero
           ip_id ::= uncompressed_value (16, 0);
        };
};

ip_id_behavior_enc ===
{
        uncompressed_format = ip_id_behavior; %[ 2 ]

        format_sequential = ip_id_behavior, %[ 2 ]
        {
           ip_id_behavior ::= '00';
        };

        format_sequential_swapped = ip_id_behavior, %[ 2 ]
        {
           ip_id_behavior ::= '01';
        };

        format_random = ip_id_behavior, %[ 2 ]
        {
           ip_id_behavior ::= '10';
        };

        format_zero = ip_id_behavior, %[ 2 ]
        {
           ip_id_behavior ::= '11';
        };
};

% The argument flag should only be used if this flag was set when processing
% a compressed base header, if not, the flag should be zero.
ipv4 (ttl_irregular_chain_flag) ===
{
        uncompressed_format =   version,     %[ 4 ]
                                hdr_length,  %[ 4 ]
                                protocol,    %[ 8 ]
                                tos_tc,      %[ 6 ]
                                ip_ecn_flags,%[ 2 ]
                                ttl_hopl,    %[ 8 ]
                                df,          %[ 1 ]
                                mf,          %[ 1 ]
                                rf,          %[ 1 ]
                                frag_offset, %[ 13 ]
                                ip_id,       %[ 16 ]
                                src_addr,    %[ 32 ]
                                dst_addr,    %[ 32 ]
                                checksum,    %[ 16 ]
                                length;      %[ 16 ]
                                
        control_fields  = ip_id_behavior;    %[ 2 ]

        default_methods =
        {
                version          ::= static;
                hdr_length       ::= uncompressed_value (4, 5);
                protocol         ::= static;
                tos_tc           ::= static;
                ip_ecn_flags     ::= static;
                ttl_hopl         ::= static;
                df               ::= static;
                mf               ::= uncompressed_value (1, 0);
                rf               ::= static;
                frag_offset      ::= uncompressed_value (13, 0);
                ip_id            ::= uncompressed_value (16, 0);
                ip_id_behavior   ::= static;
                src_addr         ::= static;
                dst_addr         ::= static;
                checksum         ::= inferred_ip_v4_header_checksum;
                length           ::= inferred_ip_v4_length;
        };

        format_ipv4_static = version_flag, %[ 1 ]
                             reserved,     %[ 7 ]
                             protocol,     %[ 8 ]
                             src_addr,     %[ 32 ]
                             dst_addr,     %[ 32 ]
        {
                version_flag     ::= '0';
                reserved         ::= '0000000';
                protocol         ::=  irregular (8);
                src_addr         ::=  irregular(32);
                dst_addr         ::=  irregular(32);
        };

        format_ipv4_dynamic = reserved,       %[ 5 ]
                              df,             %[ 1 ]
                              ip_id_behavior, %[ 2 ]
                              tos_tc,         %[ 6 ]
                              ip_ecn_flags,   %[ 2 ]
                              ttl_hopl,       %[ 8 ]
                              ip_id,          % 0/16 bits
        {
                reserved       ::= '00000';
                %
                % compressor chooses behavior of IP-ID
                %   00 = sequential
                %   01 = sequential byteswapped
                %   10 = random
                %   11 = zero
                %
                ip_id_behavior ::= ip_id_behavior_enc;
                df             ::= irregular (1);
                tos_tc         ::= irregular (6);
                ip_ecn_flags   ::= irregular (2);
                ttl_hopl       ::= irregular (8);
                ip_id          ::= ip_id_enc_dyn (ip_id_behavior);
        };

        format_ipv4_replicate_0 = discriminator, %[ 8 ]
                                  ip_id,         % 0 or 16 bits
                                  tos_tc,        %[ 6 ]
                                  ip_ecn_flags,  %[ 2 ]
        {
                discriminator  ::= '00000000';

                ip_id_behavior ::= static;
                ip_id          ::= ip_id_enc_irreg (ip_id_behavior);
                tos_tc         ::= irregular (6);
                ip_ecn_flags   ::= irregular (2);
        };

        format_ipv4_replicate_1 = discriminator,  %[ 5 ]
                                  df,             %[ 1 ]
                                  ip_id_behavior, %[ 2 ]
                                  tos_tc,         %[ 6 ]
                                  ip_ecn_flags,   %[ 2 ]
                                  ttl_hopl,       %[ 8 ]
                                  ip_id,          % 0/16 bits
        {
                discriminator  ::= '10000';

                df             ::= irregular (1);
                tos_tc         ::= irregular (6);
                ip_ecn_flags   ::= irregular (2);
                ttl_hopl       ::= irregular (8);

                %
                % compressor chooses behavior of IP-ID
                %   00 = sequential
                %   01 = sequential byteswapped
                %   10 = random
                %   11 = zero
                %
                ip_id_behavior ::= ip_id_behavior_enc;
                ip_id ::= ip_id_enc_dyn (ip_id_behavior);
        };

        format_ipv4_outer_irregular_without_ttl =
                                      ip_id,        % 0 or 16 bits
                                      tos_tc,       % 0 or 6 bits
                                      ip_ecn_flags, % 0 or 2 bits
        {
                ip_id_behavior ::= static;
                ip_id          ::= ip_id_enc_irreg (ip_id_behavior);
                tos_tc         ::= irreg_tos_tc;
                ip_ecn_flags   ::= ip_irreg_ecn;
                let(ttl_irregular_chain_flag == 0);
        };

        format_ipv4_outer_irregular_with_ttl =
                                      ip_id,        % 0 or 16 bits
                                      tos_tc,       % 0 or 6 bits
                                      ip_ecn_flags, % 0 or 2 bits
                                      ttl_hopl,     %[ 8 ]
        {
                ip_id_behavior ::= static;
                ip_id          ::= ip_id_enc_irreg (ip_id_behavior);
                tos_tc         ::= irreg_tos_tc;
                ip_ecn_flags   ::= ip_irreg_ecn;
                let(ttl_irregular_chain_flag == 1);
                ttl_hopl       ::= irregular(8);
        };
        
        % Note that the ECN bits are stored in the global control field
        % so that they can be output in TCP irregular chain.
        format_ipv4_innermost_irregular = ip_id,        % 0 or 16 bits
        {
                ip_id_behavior ::= static;
                ip_id          ::= ip_id_enc_irreg (ip_id_behavior);
                let(ip_inner_ecn:uncomp_value ==
                    ip_ecn_flags:uncomp_value);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% TCP Options
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%
% EOL marks the end of the option list and, based on
% the description in RFC 793 and the BSB TCP code,
% nothing after this should be processed...
% So, ignore everything after the EOL option 
% (according to 793 it must be 0)
%
% The length of the padding needs to be transmitted with the compressed list
% since the length of the list can be unknown to the decompressor.
%
tcp_opt_eol(nbits) ===   {
        uncompressed_format = type,          %[ 8 ]
                              padding;       % (nbits - 8) bits

        default_methods =
        {
                type    ::= uncompressed_value (8, 0);
                pad_len ::= static;
                padding ::= uncompressed_value (nbits - 8, 0);
        };

        format_eol_list_item =  pad_len,      %  8 bits
                                padding,      %[ 0 ]
        {
                pad_len ::= compressed_value(8, nbits - 8);
        };
        format_eol_irregular =
        {
                let(nbits - 8 == pad_len:uncomp_value);
        };
};

tcp_opt_nop ===
{
        uncompressed_format = type; %[ 8 ]

        default_methods =
        {
                type ::= uncompressed_value (8, 1);
        };

        format_nop_list_item =
        {
        };
        
        format_nop_irregular =
        {
        };
};

tcp_opt_mss ===
{
        uncompressed_format = type,   %[ 8 ]
                              length, %[ 8 ]
                              mss;    %[ 16 ]

        default_methods =
        {
                type   ::= uncompressed_value (8, 2);
                length ::= uncompressed_value (8, 4);
                mss    ::= static;
        };

        format_mss_list_item = mss, %[ 16 ]
        {
                mss ::= irregular (16);
        };

        format_mss_irregular = 
        {
        };
};

tcp_opt_wscale ===
{
        uncompressed_format = type,    %[ 8 ]
                              length,  %[ 8 ]
                              wscale;  %[ 8 ]

        default_methods =
        {
                type    ::= uncompressed_value (8, 3);
                length  ::= uncompressed_value (8, 3);
                wscale  ::= static;
        };

        format_wscale_list_item = wscale,  %[ 8 ]
        {
                wscale ::= irregular (8);
        };
        
        format_wscale_irregular =
        {
        };
};

ts_lsb ===
{
        uncompressed_format = tsval;

        format_tsval_15 = discriminator, %[ 1 ]
                          tsval,         %[ 15 ]
        {
                discriminator ::= '0';
                tsval         ::= lsb (15, -1);
        };

        format_tsval_22 = discriminator, %[ 2 ]
                          tsval,         %[ 22 ]
        {
                discriminator ::= '10';
                tsval         ::= lsb (22, -1);
        };

        format_tsval_30 = discriminator, %[ 2 ]
                          tsval,         %[ 30 ]
        {
                discriminator ::= '11';
                % Large negative LSB offset, so that the 30-bit format
                % can handle possible prelink reordering
                tsval         ::= lsb (30, 0x08000000);
        };
};

tcp_opt_tsopt ===
{
        uncompressed_format = type,   %[ 8 ]
                              length, %[ 8 ]
                              tsval,  %[ 32 ]
                              tsecho; %[ 32 ]

        default_methods =
        {
                type   ::= uncompressed_value (8, 8);
                length ::= uncompressed_value (8, 10);
        };

        format_tsopt_list_item = tsval,   %[ 32 ]
                                 tsecho,  %[ 32 ]
        {
                tsval  ::= irregular (32);
                tsecho ::= irregular (32);
        };

        format_tsopt_irregular = tsval,  % 16, 24 or 32 bits
                                 tsecho, % 16, 24 or 32 bits
        {
                tsval  ::= ts_lsb;
                tsecho ::= ts_lsb;
        };
};

sack_var_length_enc (base) ===
{
        uncompressed_format = sack_field; %[ 32 ]

        default_methods =
        {
                let (sack_offset:uncomp_value ==
                     sack_field:uncomp_value - base);
                let (sack_offset:uncomp_length == 32);
        };

        format_lsb_15 = discriminator,  %[ 1 ]
                        sack_offset,    %[ 15 ]
        {
                discriminator    ::= '0';
                sack_offset      ::= lsb (15, -1);
        };

        format_lsb_22 = discriminator,  %[ 2 ]
                        sack_offset,    %[ 22 ]
        {
                discriminator    ::= '10';
                sack_offset      ::= lsb (22, -1);
        };

        format_lsb_30 = discriminator,  %[ 2 ]
                        sack_offset,    %[ 30 ]
        {
                discriminator    ::= '11';
                sack_offset      ::= lsb (30, -1);
        };
};

tcp_opt_sack_block (prev_block_end) ===
{
        uncompressed_format = block_start, %[ 32 ]
                              block_end;   %[ 32 ]

        format_0 = block_start, % 16, 24 or 32 bits
                   block_end,   % 16, 24 or 32 bits
        {
                block_start ::= sack_var_length_enc (prev_block_end);
                block_end   ::= sack_var_length_enc (block_start);
        };
};

tcp_opt_sack(ack_value) ===
{
        % The ACK value from the TCP header is needed as input parameter.
        uncompressed_format = type,    %[ 8 ]
                              length,  %[ 8 ]
                              block_1, %[ 64 ]
                              block_2, % 0 or 64 bits
                              block_3, % 0 or 64 bits
                              block_4; % 0 or 64 bits

        default_methods =
        {
                length  ::= static;
                type    ::= uncompressed_value (8, 5);
                block_2 ::= uncompressed_value (0, 0);
                block_3 ::= uncompressed_value (0, 0);
                block_4 ::= uncompressed_value (0, 0);
        };

        format_sack1_list_item = discriminator,
                                 block_1,
        {
                let(length:uncomp_value == 10);
                discriminator ::= '00000001';
                block_1 ::= tcp_opt_sack_block (ack_value);
        };

        format_sack2_list_item = discriminator,
                                 block_1,
                                 block_2,
        {
                let(length:uncomp_value == 18);
                discriminator ::= '00000010';
                block_1 ::= tcp_opt_sack_block (ack_value);
                block_2 ::= tcp_opt_sack_block (block_1_end:uncomp_value);
        };

        format_sack3_list_item = discriminator,
                                 block_1,
                                 block_2,
                                 block_3,
        {
                let(length:uncomp_value == 26);
                discriminator ::= '00000011';
                block_1 ::= tcp_opt_sack_block (ack_value);
                block_2 ::= tcp_opt_sack_block (block_1_end:uncomp_value);
                block_3 ::= tcp_opt_sack_block (block_2_end:uncomp_value);
        };

        format_sack4_list_item = discriminator,
                                 block_1,
                                 block_2,
                                 block_3,
                                 block_4,
        {
                let(length:uncomp_value == 34);
                discriminator ::= '00000100';
                block_1 ::= tcp_opt_sack_block (ack_value);
                block_2 ::= tcp_opt_sack_block (block_1_end:uncomp_value);
                block_3 ::= tcp_opt_sack_block (block_2_end:uncomp_value);
                block_4 ::= tcp_opt_sack_block (block_3_end:uncomp_value);
        };

        format_sack_unchanged_irregular = discriminator,
                                          block_1,
                                          block_2,
                                          block_3,
                                          block_4,
        {
                discriminator ::= '00000000';
                block_1 ::= static;
                block_2 ::= static;
                block_3 ::= static;
                block_4 ::= static;
        };
        
        format_sack1_irregular = discriminator,
                                 block_1,
        {
                let(length:uncomp_value == 10);
                discriminator ::= '00000001';
                block_1 ::= tcp_opt_sack_block (ack_value);
        };

        format_sack2_irregular = discriminator,
                                 block_1,
                                 block_2,
        {
                let(length:uncomp_value == 18);
                discriminator ::= '00000010';
                block_1 ::= tcp_opt_sack_block (ack_value);
                block_2 ::= tcp_opt_sack_block (block_1_end:uncomp_value);
        };

        format_sack3_irregular = discriminator,
                                 block_1,
                                 block_2,
                                 block_3,
        {
                let(length:uncomp_value == 26);
                discriminator ::= '00000011';
                block_1 ::= tcp_opt_sack_block (ack_value);
                block_2 ::= tcp_opt_sack_block (block_1_end:uncomp_value);
                block_3 ::= tcp_opt_sack_block (block_2_end:uncomp_value);
        };

        format_sack4_irregular = discriminator,
                                 block_1,
                                 block_2,
                                 block_3,
                                 block_4,
        {
                let(length:uncomp_value == 34);
                discriminator ::= '00000100';
                block_1 ::= tcp_opt_sack_block (ack_value);
                block_2 ::= tcp_opt_sack_block (block_1_end:uncomp_value);
                block_3 ::= tcp_opt_sack_block (block_2_end:uncomp_value);
                block_4 ::= tcp_opt_sack_block (block_3_end:uncomp_value);
        };
        
};

tcp_opt_sack_permitted ===
{
        uncompressed_format = type, %[ 8 ]
                              length; %[ 8 ]

        default_methods =
        {
                type   ::= uncompressed_value (8, 4);
                length ::= uncompressed_value (8, 2);
        };
        format_sack_permitted_list_item =
        {
        };
        
        format_sack_permitted_irregular =
        {
        };

};

tcp_opt_generic ===
{
        uncompressed_format = type,       %[ 8 ]
                              length_msb, %[ 1 ]
                              length_lsb, %[ 7 ]
                              contents;   % n bits

        control_fields = option_static; %[ 1 ]                        

        default_methods =
        {
                type      ::= static;
                %
                % lengths are always < 128
                % (i.e. the msb is always 0)
                %
                length_msb    ::= uncompressed_value (1, 0);
                length_lsb    ::= static;
                contents      ::= static;
        };

        format_generic_list_item = type,            %[ 8 ]
                                   option_static,   %[ 1 ]
                                   length_lsb,      %[ 7 ]
                                   contents,        % n bits
        {
                type          ::= irregular (8);
                option_static ::= irregular (1);
                length_lsb    ::= irregular (7);
                contents  ::= irregular (length_len:uncomp_value * 8 - 16);
        };

        % Used when context of option has option_static set to one
        format_generic_irregular_static = 
        {
                let(option_static:uncomp_value == 1);
        };

        % An item that can change, but currently is unchanged
        format_generic_irregular_stable = discriminator, %[ 8 ]
        {
                let(option_static:uncomp_value == 0);
                discriminator ::= '11111111';
        };
        
        % An item that can change, and has changed compared to context.
        % Length is not allowed to change here, since a length change is
        % most likely to cause new NOPs or an EOL length change.
        format_generic_irregular_full = discriminator, %[ 8 ]
                                        contents,      % n bits
        {
                let(option_static:uncomp_value == 0);
                discriminator ::= '00000000';
                contents      ::= irregular (length_lsb:uncomp_value * 8 - 16);
        };

};

list_tcp_options(nbits) ===     {
        uncompressed_format = item, tail;

        default_methods =       {
           let(nbits >= item:uncomp_length);
           tail ::= list_tcp_options(nbits - item:uncomp_length);
        };

        compressed_format_list_end =       {
           let(nbits == 0);
           item ::= irregular(0);
           tail ::= irregular(0);
        };

        compressed_format_eol = item, tail       {
           let(nbits == item:uncomp_length); % redundant
           item ::= tcp_opt_eol(nbits);
           tail ::= irregular(0);
        };

        compressed_format_nop = item, tail       {
           item ::= tcp_opt_nop;
        };

        compressed_format_mss  = item, tail       {
           item ::= tcp_opt_mss;
        };

        compressed_format_wscale = item, tail       {
           item ::= tcp_opt_wscale;
        };

        compressed_format_tsopt = item, tail       {
           item ::= tcp_opt_tsopt;
        };

        compressed_format_sack = item, tail       {
           item ::= tcp_opt_sack;
        };

        compressed_format_permitted = item, tail       {
           item ::= tcp_opt_sack_permitted;
        };

        compressed_format_generic = item, tail       {
           item ::= tcp_opt_generic;
        };
};

tcp_list_presence_enc(list_length, presence) ===
{
        uncompressed_format = tcp_options;

        format_list_not_present = tcp_options, %[ 0 ] 
        {
           let (presence == 0);
           tcp_options ::= static;
        };

        format_list_present = tcp_options, % 8 + n*8 bits
        {
           let (presence == 1);
           tcp_options ::= list_tcp_options(list_length);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% TCP Header
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

port_replicate(flags) ===
{
        uncompressed_format  =   port;        %[ 16 ]

        format_port_static_enc   = port,      %[ 0 ]
        {
           let(flags == 00);
           port          ::= static;
        };

        format_port_lsb8         = port,      %[ 8 ]
        {
           let(flags == 01);
           port          ::= lsb (8, 64);
        };

        format_port_irr_enc      = port,      %[ 16 ]
        {
           let(flags == 10);
           port          ::= irregular (16);
        };
};

zero_or_irr16_enc(flag) ===
{
        uncompressed_format = field; %[ 16 ]

        format_non_zero = field, %[ 16 ]
        {
           let(flag == 0);
           field ::= irregular (16);
        };

        format_zero = field, %[ 0 ]
        {
           let(flag == 1);
           field ::= uncompressed_value (16, 0);
        };
};

ack_enc_dyn(flag) ===
{
        uncompressed_format = ack_number; %[ 32 ]

        format_ack_non_zero = ack_number, %[ 32 ]
        {
           let(flag == 0);
           ack_number ::= irregular (32);
        };

        format_ack_zero = ack_number, %[ 0 ]
        {
           let(flag == 1);
           ack_number ::= uncompressed_value (32, 0);
        };
};

tcp_ecn_flags_enc ===
{
        uncompressed_format = tcp_ecn_flags; %[ 2 ]

        format_irreg = tcp_ecn_flags, %[ 2 ]
        {
           let(ecn_used:uncomp_value == 1);
           tcp_ecn_flags ::= irregular(2);
        };

        format_unused =
        {
           let(ecn_used:uncomp_value == 0);
           tcp_ecn_flags ::= static;
        };
};

tcp_res_flags_enc ===
{
        uncompressed_format = tcp_res_flags; %[ 4 ]

        format_irreg = tcp_res_flags, %[ 4 ]
        {
           let(ecn_used:uncomp_value == 1);
           tcp_res_flags     ::= irregular(4);
        };

        format_unused =
        {
           let(ecn_used:uncomp_value == 0);
           tcp_res_flags     ::= uncompressed_value(4, 0);
        };
};

tcp_irreg_ip_ecn ===
{
        uncompressed_format = ip_ecn_flags;     %[ 2 ]

        format_tc_present = ip_ecn_flags,       %[ 2 ]
        {
           let(ecn_used:uncomp_value == 1);
           ip_ecn_flags ::= compressed_value(2, ip_inner_ecn:uncomp_value);
        };

        format_tc_not_present = ip_ecn_flags, %[ 0 ]
        {
           let(ecn_used:uncomp_value == 0);
           ip_inner_ecn ::= static; % Global control field
           ip_ecn_flags ::= compressed_value(0,0); % Nothing transmit
        };
};

rsf_index_enc ===
{
        uncompressed_format = rsf_flag; %[ 3 ]

        format_none     = rsf_idx, %[ 2 ]
        {
                rsf_idx  ::= '00';
                rsf_flag ::= uncompressed_value (3, 0x00);
        };

        format_rst_only = rsf_idx, %[ 2 ]
        {
                rsf_idx  ::= '01';
                rsf_flag ::= uncompressed_value (3, 0x01);
        };

        format_syn_only = rsf_idx, %[ 2 ]
        {
                rsf_idx  ::= '10';
                rsf_flag ::= uncompressed_value (3, 0x02);
        };

        format_fin_only = rsf_idx, %[ 2 ]
        {
                rsf_idx  ::= '11';
                rsf_flag ::= uncompressed_value (3, 0x04);
        };
};

optional_2bit_padding(used_flag) ===
{
        uncompressed_format = padding; % 0 or 2 bits

        format_used = padding, %[ 2 ]
        {
                let(used_flag == 1);
                padding ::= compressed_value (2, 0x0);
        };

        format_unused = padding,
        {
                let(used_flag == 0);
                padding ::= compressed_value (0, 0x0);
        };

};

tcp ===
{
        uncompressed_format = src_port,     %[ 16 ]
                              dst_port,     %[ 16 ]
                              rsf_flags,    %[ 3 ]
                              psh_flag,     %[ 1 ]
                              urg_flag,     %[ 1 ]
                              ack_flag,     %[ 1 ]
                              data_offset,  %[ 4 ]
                              tcp_res_flags,%[ 4 ]
                              tcp_ecn_flags,%[ 2 ]
                              urg_ptr,      %[ 16 ]
                              window,       %[ 16 ]
                              checksum,     %[ 16 ]
                              seq_number,   %[ 32 ]
                              ack_number,   %[ 32 ]
                              options;      %  n bits

        default_methods =
        {
                src_port      ::= static;
                dst_port      ::= static;
                seq_number    ::= static;
                ack_number    ::= static;
                rsf_flags     ::= static;
                psh_flag      ::= irregular (1);
                urg_flag      ::= static;
                ack_flag      ::= uncompressed_value (1, 1);
                urg_ptr       ::= static;
                window        ::= static;
                checksum      ::= irregular (16);
                tcp_ecn_flags ::= static;
                tcp_res_flags ::= static;
        };

        format_tcp_static = src_port,     %[ 16 ]
                            dst_port,     %[ 16 ]
        {
                src_port      ::=   irregular(16);
                dst_port      ::=   irregular(16);
        };

        format_tcp_dynamic =  ecn_used,              %[ 1 ]
                              ack_stride_zero,       %[ 1 ]
                              ack_zero,              %[ 1 ]
                              urp_zero,              %[ 1 ]
                              tcp_res_flags,         %[ 4 ]
                              tcp_ecn_flags,         %[ 2 ]
                              urg_flag,              %[ 1 ]
                              ack_flag,              %[ 1 ]
                              psh_flag,              %[ 1 ]
                              rsf_flags,             %[ 3 ]
                              msn,                   %[ 16 ]
                              seq_number,            %[ 32 ]
                              ack_number,            %  0 or 32 bits
                              window,                %[ 16 ]
                              checksum,              %[ 16 ]
                              urg_ptr,               %  0 or 16 bits
                              ack_stride,            %  0 or 16 bits
                              options,               %  n bits
        {
                   ecn_used          ::= irregular (1);
                   ack_stride_zero   ::= irregular (1);
                   ack_zero          ::= irregular (1);
                   urp_zero          ::= irregular (1);
                   ack_flag          ::= irregular (1);
                   urg_flag          ::= irregular (1);
                   psh_flag          ::= irregular (1);
                   tcp_ecn_flags     ::= irregular (2);
                   padding           ::= '0';
                   rsf_flags         ::= irregular (3);
                   tcp_res_flags     ::= irregular (4);
                   msn               ::= irregular (16);
                   seq_number        ::= irregular (32);
                   window            ::= irregular (16);
                   checksum          ::= irregular (16);
                   urg_ptr           ::= zero_or_irr16_enc(urp_zero);
                   ack_number        ::= ack_enc_dyn(ack_zero);
                   ack_stride        ::= zero_or_irr16_enc(ack_stride_zero);
                   options           ::= list_tcp_options(list_length);
        };

        format_tcp_replicate = reserved,            %[ 3 ]
                               list_present,        %[ 1 ]
                               src_port_presence,   %[ 2 ]
                               dst_port_presence,   %[ 2 ]
                               ack_number,          %[ 1 ]
                               urp_presence,        %[ 1 ]
                               urg_flag,            %[ 1 ]
                               ack_flag,            %[ 1 ]
                               psh_flag,            %[ 1 ]
                               rsf_flags,           %[ 2 ]
                               ecn_used,            %[ 1 ]
                               msn,                 %[ 16 ]
                               seq_number,          %[ 32 ]
                               src_port,            %  0, 8 or 16 bits
                               dst_port,            %  0, 8 or 16 bits
                               urg_point,           %  0 or 16 bits
                               ack_number,          %  0 or 32 bits
                               ecn_padding,         %  0 or 2 bits
                               tcp_res_flags,       %  0 or 4 bits
                               tcp_ecn_flags,       %  0 or 2 bits
                               options_list,        %  n bits
        {
                reserved            ::=   '000';
                options_replicate   ::=   irregular (1);
                msn                 ::=   irregular (16);
                urg_flag            ::=   irregular (1);
                ack_flag            ::=   irregular (1);
                psh_flag            ::=   irregular (1);
                rsf_flags           ::=   rsf_index_enc;
                ecn_used            ::=   irregular (1);
                src_port            ::=   port_replicate(src_port_presence);
                dst_port            ::=   port_replicate(dst_port_presence);
                seq_number          ::=   irregular(32);
                ack_number          ::=   static_or_irreg32(ack_presence);
                window              ::=   static_or_irreg16(window_presence);
                urg_point           ::=   static_or_irreg16(urp_presence);
                ecn_padding         ::=   optional_2bit_padding(ecn_used);
                tcp_res_flags       ::=   tcp_res_flags_enc;
                tcp_ecn_flags       ::=   tcp_ecn_flags_enc;
                options_list        ::=   tcp_list_presence_enc
                                           ((data_offset:uncomp_value + 20) / 4,
                                            list_present);
        };

        % ECN from innermost IP header is taken from global control field.
        format_tcp_irregular = ip_ecn_flags,  % 0 or 2 bits
                               tcp_res_flags, % 0 or 4 bits
                               tcp_ecn_flags, % 0 or 2 bits
                               checksum,      %[ 16 ]
        {
                ip_ecn_flags   ::= tcp_irreg_ip_ecn;
                tcp_ecn_flags  ::= tcp_ecn_flags_enc;
                tcp_res_flags  ::= tcp_res_flags_enc;
                checksum       ::= irregular (16);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Structures used in compressed base headers
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

tos_tc_enc(flag) ===
{
        uncompressed_format = tos_tc;      %[ 6 ]
    
        format_static       = tos_tc,      %[ 0 ]
        {
           let (flag == 0);
           tos_tc             ::= static;
        };
    
        format_irreg     = tos_tc,         %[ 6 ]
                           padding,
        {
           let (flag == 1);
           tos_tc             ::= irregular(6);
           padding            ::= compressed_value (2, 0);
        };
};

ip_id_lsb (behavior, k, p) ===
{
        uncompressed_format = ip_id; %[ 16 ]

        default_methods =
        {
           let (ip_id:uncomp_length == 16);
        };

        format_nbo = ip_id_offset, % k bits
        {
           let (behavior == 0);
           let (ip_id_offset:uncomp_value == 
                   ip_id:uncomp_value - msn:uncomp_value);
           let (ip_id_offset:uncomp_length == 16);

           ip_id_offset ::= lsb (k, p);
        };

        format_non_nbo = ip_id_offset, % k bits
        {
           let (behavior == 1);

           let (ip_id_nbo:uncomp_value == 
                (ip_id:uncomp_value / 256) + (ip_id:uncomp_value & 255) * 256);
           let (ip_id_nbo:uncomp_length == 16);
           let (ip_id_offset:uncomp_value == 
                ip_id_nbo:uncomp_value - msn:uncomp_value);
           let (ip_id_offset:uncomp_length == 16);

           ip_id_offset ::= lsb (k, p);
        };
};

dont_fragment(version) ===
{
        uncompressed_format = df; %[ 1 ]
   
        compressed_format_v4 = df, %[ 1 ]
        {
           let (version == 4);
           df ::= irregular(1);
        };
   
        compressed_format_v6 = df,
        {
           let (version == 6);
           df ::= compressed_value(1,0);
        };
};

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Actual start of compressed packet formats
% Important note: The base header is the compressed representation of
% the innermost IP header AND the TCP header.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% ttl_irregular_chain_flag is an "output argument" that should be passed to the
% processing of the irregular chain for outer IP headers.
co_baseheader(payload_size, ttl_irregular_chain_flag) ===
{
   uncompressed_format_v4 = version,
                            header_length,
                            tos_tc,
                            ip_ecn_flags,
                            length,
                            ip_id,
                            df,
                            mf,
                            rf,
                            frag_offset,
                            ttl_hopl,
                            next_header,
                            checksum,
                            src_addr,
                            dest_addr,
                            src_port,
                            dest_port,
                            seq_number,
                            ack_number,
                            data_offset,
                            tcp_res_flags,
                            tcp_ecn_flags,
                            urg_flag,
                            ack_flag,
                            psh_flag,
                            rsf_flags,
                            tcp_checksum,
                            urg_ptr,
                            window,
                            tcp_options,
   {
      let (version:uncomp_value == 4);
   };

   uncompressed_format_v6 = version,
                            tos_tc,
                            ip_ecn_flags,
                            flow_label,
                            payload_length,
                            next_header,
                            ttl_hopl,
                            src_addr,
                            dest_addr,
                            src_port,
                            dest_port,
                            seq_number,
                            ack_number,
                            data_offset,
                            tcp_res_flags,
                            tcp_ecn_flags,
                            urg_flag,
                            ack_flag,
                            psh_flag,
                            rsf_flags,
                            tcp_checksum,
                            urg_ptr,
                            window,
                            tcp_options,
   {
      let (version:uncomp_value == 6);
   };

   control_fields  = ip_id_behavior;   % 2 bits
                              
   default_methods = 
   {

      version                      ::= static;
      tos_tc                       ::= static;
      ip_ecn_flags                 ::= static;
      ttl_hopl                     ::= static;
      next_header                  ::= static;
      src_addr                     ::= static;
      dest_addr                    ::= static;

      flow_label                   ::= static;

      header_length                ::= uncompressed_value (4,5);
      length                       ::= inferred_ip_v4_length;
      ip_id                        ::= irregular(16);
      rf                           ::= static;
      df                           ::= static;
      mf                           ::= static;
      frag_offset                  ::= static;
      checksum                     ::= inferred_ip_checksum;

      src_port                     ::= static;
      dest_port                    ::= static;
      seq_number                   ::= static;
      ack_number                   ::= static;
      data_offset                  ::= inferred_offset;
      tcp_ecn                      ::= static;
      psh_flag                     ::= irregular (1);
      urg_flag                     ::= uncompressed_value (1, 0);
      ack_flag                     ::= uncompressed_value (1, 1);
      window                       ::= static;
      tcp_checksum                 ::= irregular(16);
      urg_ptr                      ::= static;
      rsf_flags                    ::= uncompressed_value (3, 0);

      let (version:uncomp_length == 4);

      let (seq_number_scaled:uncomp_value == 
               seq_number:uncomp_value / payload_size);
      let (seq_number_residue:uncomp_value ==
               mod(seq_number:uncomp_value, payload_size));
      let (ack_number:uncomp_value == 
               (ack_stride:uncomp_value * ack_number_scaled:uncomp_value) +
               ack_number_residue:uncomp_value);
      let (ack_number_residue:uncomp_value ==
               mod(ack_number:uncomp_value, ack_stride:uncomp_value));
   };

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Common compressed packet format
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

   format_co_common             =   discriminator,       %[ 7 ]
                                    ttl_hopl_outer_flag, %[ 1 ]
                                    ack_flag,            %[ 1 ]
                                    psh_flag,            %[ 1 ]
                                    rsf_flags,           %[ 2 ]

                                    msn,                 %[ 4 ]

                                    seq_indicator,       %[ 2 ]
                                    ack_indicator,       %[ 2 ]
                                    ack_stride_indicator,%[ 1 ]
                                    window_indicator,    %[ 1 ]
                                    ip_id_indicator,     %[ 2 ]

                                    urg_ptr_present,     %[ 1 ]
                                    ecn_used,            %[ 1 ]
                                    tos_tc_present,      %[ 1 ]
                                    ttl_hopl_present,    %[ 1 ]
                                    list_present,        %[ 1 ]

                                    ip_id_behavior,      %[ 2 ]

                                    urg_flag,            %[ 1 ]
                                    df,                  %[ 1 ]

                                    header_crc,          %[ 7 ]

                                    seq_number,          % 0, 8, 16, 32 bits
                                    ack_number,          % 0, 8, 16, 32 bits
                                    ack_stride,          % 0 or 16 bits
                                    window,              % 0 or 16 bits
                                    ip_id,               % 0, 8, 16 bits
                                    urg_ptr,             % 0 or 16 bits
                                    tos_tc,              % 0 or 8 bits
                                    ttl_hopl,            % 0 or 8 bits
                                    options_list,        % n bits
   {
             discriminator      ::= '1111101';
             
             ttl_hopl_outer_flag::= irregular(1);
             % Need to bind argument so that user can pass it on to the
             % structure for IPv4/IPv6 irregular chain.
             let(ttl_irregular_chain_flag:uncomp_value == ttl_hopl_outer_flag);
             
             tos_tc_present     ::= irregular(1);
             ttl_hopl_present   ::= irregular(1);
             ack_flag           ::= irregular(1);
             psh_flag           ::= irregular(1);
             msn                ::= lsb (4, 3);
             df                 ::= dont_fragment(version:uncomp_value);
             header_crc         ::= crc7(this:uncomp_value,
                                         this:uncomp_length);
             urg_flag           ::= irregular(1);
             urg_ptr_present    ::= irregular(1);
             ecn_used           ::= irregular(1);
             list_present       ::= irregular(1);
             ip_id_behavior     ::= ip_id_behavior_enc;
             rsf_flags          ::= rsf_index_enc;

             window_indicator   ::= irregular(1);
             ip_id_indicator    ::= irregular(2);
             seq_indicator      ::= irregular(2);
             ack_indicator      ::= irregular(2);
             ack_stride_indicator ::= irregular(1);

             seq_number         ::= variable_length_32_enc(seq_indicator);
             ack_number         ::= variable_length_32_enc(ack_indicator);
             ack_stride         ::= static_or_irreg16(ack_stride_indicator);
             window             ::= static_or_irreg16(window_indicator);
             ip_id              ::= variable_length_16_enc(ip_id_indicator);
             urg_ptr            ::= static_or_irreg16(urg_ptr_present);
             ttl_hops           ::= static_or_irreg8(ttl_hopl_present);
             tos_tc             ::= tos_tc_enc(tos_tc_present);
             options_list       ::= tcp_list_presence_enc
                                           ((data_offset:uncomp_value + 20) / 4,
                                            list_present);
   };

%   0   1   2   3   4   5   6   7
% +---+---+---+---+---+---+---+---+
% | 1   1   1   1   1   0   1 |tho| tho controls irregular chain TTL/Hoplimit
% +===+===+===+===+===+===+===+===+
% |ACK|PSH|  RSF  |     MSN       |
% +---+---+---+---+---+---+---+---+
% |  sn   | a_sn  |ast|win| ip_id |
% +---+---+---+---+---+---+---+---+
% |urg|ecn|tos|ttl|lst|IPIDbeh|URG|
% +---+---+---+---+---+---+---+---+
% |DF |            CRC            |
% +---+---+---+---+---+---+---+---+
% /              SN               /  0, 8, 16, 32 bits, indicated by sn
%  --- --- --- --- --- --- --- ---
% /            ACK_SN             /  0, 8, 16, 32 bits, indicated by a_sn
%  --- --- --- --- --- --- --- ---
% /          ACK_STRIDE           /  0 or 16 bits, indicated by ast
%  --- --- --- --- --- --- --- ---
% /            WINDOW             /  0 or 16 bits, indicated by win
%  --- --- --- --- --- --- --- ---
% /             IP-ID             /  0, 8, 16 bits, indicated by ip_id
%  --- --- --- --- --- --- --- ---
% /            URG-PTR            /  16 bits, if urg=1
%  --- --- --- --- --- --- --- ---
% /IP-ECN |TCP-ECN|    TCP_RES    /  8 bits, if ecn=1
%  --- --- --- --- --- --- --- ---
% /              TOS              /  8 bits, if tos=1
%  --- --- --- --- --- --- --- ---
% /              TTL              /  8 bits, if ttl=1
%  --- --- --- --- --- --- --- ---
% /         options_list          /  n*8 bits, if lst=1
%  --- --- --- --- --- --- --- ---

% NON-SEQUENTIAL PACKET FORMATS

% +------+--------+-----+-----+-----+---------+---------+
% |Name  |Disc    |MSN  |SN   |ACK  |Window   |Comment  |
% +------+--------+-----+-----+-----+---------+---------+
% |_1    |10111110|4    |16   |0    |         |         |
% +------+--------+-----+-----+-----+---------+---------+
% |_2    |1100    |4    |*4   |0    |         |         |
% +------+--------+-----+-----+-----+---------+---------+
% |_3    |0       |4    |0    |15   |         |         |
% +------+--------+-----+-----+-----+---------+---------+
% |_4    |1101    |4    |0    |4*   |         |         |
% +------+--------+-----+-----+-----+---------+---------+
% |_5    |100     |4    |14   |15   |         |         |
% +------+--------+-----+-----+-----+---------+---------+
% |_6    |10110   |4    |*4   |15   |         |         |
% +------+--------+-----+-----+-----+---------+---------+
% |_7    |1010    |4    |14   |0    |14       |         |
% +------+--------+-----+-----+-----+---------+---------+
% |_8    |10111111|4    |0    |16   |16       |         |
% +------+--------+-----+-----+-----+---------+---------+
% |_9    |101110  |4    |*4   |0    |14       |         |
% +------+--------+-----+-----+-----+---------+---------+
% |_10   |1011110 |4    |14   |16   |         |and more |
% +------+--------+-----+-----+-----+---------+---------+

   % Send LSBs of sequence number
   format_rnd_1 = discriminator, %[ 8 ]
                  seq_number,    %[ 16 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '10111110';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      seq_number          ::= lsb(16, 32767);
   };

%   0   1   2   3   4   5   6   7
% +---+---+---+---+---+---+---+---+
% | 1   0   1   1   1   1   1   0 |
% +===+===+===+===+===+===+===+===+
% |              SN...            |
% +---+---+---+---+---+---+---+---+
% |              ...SN            |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send scaled sequence number LSBs
   format_rnd_2 = discriminator, %[ 4 ]
                  seq_number_scaled, %[ 4 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '1100';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      seq_number_scaled   ::= lsb(4, 7);
      seq_number_residue  ::= static;
   };

%   0   1   2   3   4   5   6   7
% +---+---+---+---+---+---+---+---+
% | 1   1   0   0 |   SN_SCALED   |
% +===+===+===+===+===+===+===+===+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send acknowledgement number LSBs
   format_rnd_3 = discriminator, %[ 1 ]
                  ack_number,    %[ 15 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '0';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      ack_number          ::= lsb(15, 8191);
   };

%   0   1   2   3   4   5   6   7
% +---+---+---+---+---+---+---+---+
% | 0 |          ACK_SN...        |
% +===+===+===+===+===+===+===+===+
% |         ...ACK_SN             |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send acknowledgement number scaled
   format_rnd_4 = discriminator,     %[ 4 ]
                  ack_number_scaled, %[ 4 ]
                  msn,               %[ 4 ]
                  psh_flag,          %[ 1 ]
                  header_crc,        %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '1101';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      ack_number_scaled   ::= lsb(4, 3);
      ack_number_residue  ::= static;
   };

%   0   1   2   3   4   5   6   7
% +---+---+---+---+---+---+---+---+
% | 1   1   0   1 | ACK_SN_SCALED |
% +===+===+===+===+===+===+===+===+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send ACK and sequence number
   format_rnd_5 = discriminator, %[ 3 ]
                  psh_flag,      %[ 1 ]
                  msn,           %[ 4 ]
                  header_crc,    %[ 3 ]
                  seq_number,    %[ 14 ]
                  ack_number,    %[ 15 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '100';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      ack_number          ::= lsb(15, 8191);
      seq_number          ::= lsb(14, 8191);
   };

%   0   1   2   3   4   5   6   7
% +---+---+---+---+---+---+---+---+
% | 1   0   0 |PSH|     MSN       |
% +===+===+===+===+===+===+===+===+
% |      MSN      |    CRC    |A..|
% +---+---+---+---+---+---+---+---+
% |         ...ACK_SN...          |
% +---+---+---+---+---+---+---+---+
% |..A|          SN...            |
% +---+---+---+---+---+---+---+---+
% |           ...SN               |
% +---+---+---+---+---+---+---+---+

   % Send both ACK and scaled sequence number LSBs
   format_rnd_6 = discriminator, %[ 5 ]
                  header_crc,    %[ 3 ]
                  psh_flag,      %[ 1 ]
                  ack_number,    %[ 15 ]
                  msn,           %[ 4 ]
                  seq_number_scaled, %[ 4 ],
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '10110';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      ack_number          ::= lsb(15, 8191);
      seq_number_scaled   ::= lsb(4, 7);
      seq_number_residue  ::= static;
   };

% +---+---+---+---+---+---+---+---+
% | 1   0   1   1   0 |    CRC    |
% +===+===+===+===+===+===+===+===+
% |PSH|       ACK_SN...           |
% +---+---+---+---+---+---+---+---+
% |  ...ACK_SN...                 |
% +---+---+---+---+---+---+---+---+
% |      MSN      |   SN_SCALED   |
% +---+---+---+---+---+---+---+---+

   % Send sequence number and window
   format_rnd_7 = discriminator, %[ 4 ]
                  seq_number,    %[ 14 ]
                  window,        %[ 14 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '1010';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      seq_number          ::= lsb(14, 8191);
      window              ::= lsb(14, 8191);
   };

% +---+---+---+---+---+---+---+---+
% | 1   0   1   0 |      SN...    |
% +===+===+===+===+===+===+===+===+
% |              SN...
% +---+---+---+---+---+---+---+---+
% | ...SN |     WINDOW...         |
% +---+---+---+---+---+---+---+---+
% |            WINDOW             |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send ACK and window
   format_rnd_8 = discriminator, %[ 8 ]
                  ack_number,    %[ 16 ]
                  window,        %[ 16 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '10111111';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      ack_number          ::= lsb(16, 16383);
      window              ::= irregular(16);
   };

% +---+---+---+---+---+---+---+---+
% | 1   0   1   1   1   1   1   1 |
% +===+===+===+===+===+===+===+===+
% |                               |
% +            ACK_SN             +
% |                               |
% +---+---+---+---+---+---+---+---+
% |                               |
% +            WINDOW             +
% |                               |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send scaled sequence number and window.
   format_rnd_9 = discriminator, %[ 6 ]
                  seq_number_scaled, %[ 4 ]
                  window,        %[ 14 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '101110';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      window              ::= lsb(14, 8191);
      seq_number_scaled   ::= lsb(4, 3);
      seq_number_residue  ::= static;
   };

% +---+---+---+---+---+---+---+---+
% | 1   0   1   1   1   0 |SN_SC..|
% +===+===+===+===+===+===+===+===+
% |..SN_SC|      WINDOW...        |
% +---+---+---+---+---+---+---+---+
% |           ...WINDOW           |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % A packet halfway between co_common and compressed packets
   % Can send LSBs of TTL, RSF flags, change ECN behavior and options list
   format_rnd_10 = discriminator, %[ 7 ]
                   ecn_used,      %[ 1 ]
                   list_present,  %[ 1 ]
                   header_crc,    %[ 7 ]
                   msn,           %[ 4 ]
                   psh_flag,      %[ 1 ]
                   ttl_hopl,      %[ 3 ]
                   rsf_flags,     %[ 2 ]
                   seq_number,    %[ 14 ]
                   ack_number,    %[ 16 ]
                   options_list,  % 0 or X bits
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '1011110';
      msn                 ::= lsb(4, 4);
      header_crc          ::= crc7 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      list_present        ::= irregular(1);
      options_list        ::= tcp_list_presence_enc
                                      ((data_offset:uncomp_value + 20) / 4,
                                       list_present);
      rsf_flags           ::= rsf_index_enc;
      ecn_used            ::= irregular(1);
      ttl_hopl            ::= lsb(3, 3);
      seq_number          ::= lsb(14, 8191);
      ack_number          ::= lsb(16, 16383);
   };

% +---+---+---+---+---+---+---+---+
% | 1   0   1   1   1   1   1 |ECN|
% +===+===+===+===+===+===+===+===+
% |lst|            CRC            |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    TTL    |
% +---+---+---+---+---+---+---+---+
% |  RSF  |        SN...          |
% +---+---+---+---+---+---+---+---+
% |             ..SN              |
% +---+---+---+---+---+---+---+---+
% |                               |
% +            ACK_SN             +
% |                               |
% +---+---+---+---+---+---+---+---+
% /         options_list          /  n*8 bits, if lst=1
%  --- --- --- --- --- --- --- ---

% SEQUENTIAL PACKET FORMATS

% +------+------+-----+-----+-----+-----+-----+---------+
% |Name  |Disc  |MSN  |ID   |SN   |ACK  |Win  |Comment  |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_1    |1010  |4    |4    |16   |0    |     |         |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_2    |11001 |4    |7    |*4   |0    |     |         |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_3    |1001  |4    |4    |0    |16   |     |         |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_4    |0     |4    |3    |0    |*4   |     |         |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_5    |1000  |4    |4    |16   |16   |     |         |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_6    |110110|4    |6    |*4   |16   |     |         |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_7    |11010 |4    |5    |14   |0    |16   |         |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_8    |11000 |4    |5    |0    |16   |14   |         |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_9    |110111|4    |6    |*4   |0    |16   |         |
% +------+------+-----+-----+-----+-----+-----+---------+
% |_10   |1011  |4    |4    |14   |15   |     |and more |
% +------+------+-----+-----+-----+-----+-----+---------+

   % Send LSBs of sequence number
   format_seq_1 = discriminator, %[ 4 ]
                  ip_id,         %[ 4 ]
                  seq_number,    %[ 16 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '1010';
      msn                 ::= lsb(4, 4);
      ip_id               ::= ip_id_lsb (ip_id_behavior, 4, 3);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      seq_number          ::= lsb(16, 32767);
   };

% +---+---+---+---+---+---+---+---+
% | 1   0   1   0 |     IP-ID     |
% +===+===+===+===+===+===+===+===+
% |                               |
% +              SN               +
% |                               |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send scaled sequence number LSBs
   format_seq_2 = discriminator, %[ 5 ]
                  ip_id,         %[ 7 ]
                  seq_number_scaled, %[ 4 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '11001';
      msn                 ::= lsb(4, 4);
      ip_id               ::= ip_id_lsb (ip_id_behavior, 7, 3);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      seq_number_scaled   ::= lsb(4, 7);
      seq_number_residue  ::= static;
   };

% +---+---+---+---+---+---+---+---+
% | 1   1   0   0   1 |  IP-ID... |
% +===+===+===+===+===+===+===+===+
% | ...IP-ID      |  SN_SCALED    |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send acknowledgement number LSBs
   format_seq_3 = discriminator, %[ 4 ]
                  ip_id,         %[ 4 ]
                  ack_number,    %[ 16 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '1001';
      msn                 ::= lsb(4, 4);
      ip_id               ::= ip_id_lsb (ip_id_behavior, 4, 3);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      ack_number          ::= lsb(16, 16383);
   };

% +---+---+---+---+---+---+---+---+
% | 1   0   0   1 |     IP-ID     |
% +===+===+===+===+===+===+===+===+
% |                               |
% +            ACK_SN             +
% |                               |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send scaled acknowledgement number scaled
   format_seq_4 = discriminator,    %[ 1 ]
                  ack_number_scaled,%[ 4 ]
                  ip_id,            %[ 3 ]
                  msn,              %[ 4 ]
                  psh_flag,         %[ 1 ]
                  header_crc,       %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '0';
      msn                 ::= lsb(4, 4);
      % Note that due to having very few ip_id bits, no reordering offset
      ip_id               ::= ip_id_lsb (ip_id_behavior, 3, 1);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      ack_number_scaled   ::= lsb(4, 3);
      ack_number_residue  ::= static;
   };

% +---+---+---+---+---+---+---+---+
% | 0 | ACK_SN_SCALED |   IP-ID   |
% +===+===+===+===+===+===+===+===+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send ACK and sequence number
   format_seq_5 = discriminator, %[ 4 ]
                  ip_id,         %[ 4 ]
                  ack_number,    %[ 16 ]
                  seq_number,    %[ 16 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '1000';
      msn                 ::= lsb(4, 4);
      ip_id               ::= ip_id_lsb (ip_id_behavior, 4, 3);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      ack_number          ::= lsb(16, 16383);
      seq_number          ::= lsb(16, 32767);
   };

% +---+---+---+---+---+---+---+---+
% | 1   0   0   0 |     IP-ID     |
% +===+===+===+===+===+===+===+===+
% |                               |
% +           ACK_SN              +
% |                               |
% +---+---+---+---+---+---+---+---+
% |                               |
% +             SN                +
% |                               |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send both ACK and scaled sequence number LSBs
   format_seq_6 = discriminator, %[ 6 ]
                  seq_number_scaled, %[ 4 ]
                  ip_id,         %[ 6 ]
                  ack_number,    %[ 16 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '110110';
      seq_number_scaled   ::= lsb(4, 7);
      seq_number_residue  ::= static;
      ip_id               ::= ip_id_lsb (ip_id_behavior, 6, 3);
      ack_number          ::= lsb(16, 16383);
      msn                 ::= lsb(4, 4);
      psh_flag            ::= irregular (1);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
   };

% +---+---+---+---+---+---+---+---+
% | 1   1   0   1   0   0 |SN_SC..|
% +===+===+===+===+===+===+===+===+
% |..SN_SC|         IP-ID         |
% +---+---+---+---+---+---+---+---+
% |                               |
% +           ACK_SN              +
% |                               |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send sequence number and window
   format_seq_7 = discriminator, %[ 5 ]
                  seq_number,    %[ 14 ]
                  ip_id,         %[ 5 ]
                  window,        %[ 16 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '11010';
      msn                 ::= lsb(4, 4);
      ip_id               ::= ip_id_lsb (ip_id_behavior, 5, 3);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      seq_number          ::= lsb(14, 8191);
      window              ::= irregular(16);
   };

% +---+---+---+---+---+---+---+---+
% | 1   1   0   1   0 |    SN..   |
% +===+===+===+===+===+===+===+===+
% |            ..SN..             |
% +---+---+---+---+---+---+---+---+
% |    ..SN   |       IP-ID       |
% +---+---+---+---+---+---+---+---+
% |                               |
% +            WINDOW             +
% |                               |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send ACK and window
   format_seq_8 = discriminator, %[ 5 ]
                  window,        %[ 14 ]
                  ip_id,         %[ 5 ]
                  ack_number,    %[ 16 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '110';
      msn                 ::= lsb(4, 4);
      ip_id               ::= ip_id_lsb (ip_id_behavior, 5, 3);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      ack_number          ::= lsb(16, 32767);
      window              ::= irregular(16);
   };

% +---+---+---+---+---+---+---+---+
% | 1   1   0   0   0 |  WINDOW.. |
% +===+===+===+===+===+===+===+===+
% |          ..WINDOW..           |
% +---+---+---+---+---+---+---+---+
% | ..WINDOW  |       IP-ID       |
% +---+---+---+---+---+---+---+---+
% |                               |
% +              ACK              +
% |                               |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % Send scaled sequence number and window.
   format_seq_9 = discriminator, %[ 6 ]
                  ip_id,         %[ 6 ]
                  seq_number_scaled, %[ 4 ]
                  window,        %[ 16 ]
                  msn,           %[ 4 ]
                  psh_flag,      %[ 1 ]
                  header_crc,    %[ 3 ]
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '00101';
      msn                 ::= lsb(4, 4);
      ip_id               ::= ip_id_lsb (ip_id_behavior, 3, 3);
      header_crc          ::= crc3 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      window              ::= lsb(11, 1023);
      seq_number_scaled   ::= lsb(5, 31);
      seq_number_residue  ::= static;
   };

% +---+---+---+---+---+---+---+---+
% | 1   1   0   1   1   1 |IP-ID..|
% +===+===+===+===+===+===+===+===+
% |    ..IP-ID    |   SN_SCALED   |
% +---+---+---+---+---+---+---+---+
% |                               |
% +             WINDOW            +
% |                               |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    CRC    |
% +---+---+---+---+---+---+---+---+

   % A packet halfway between co_common and compressed packets
   % Can send LSBs of TTL, RSF flags, change ECN behavior and options list
   format_seq_10 = discriminator, %[ 4 ]
                   ip_id,         %[ 4 ]
                   list_present,  %[ 1 ]
                   header_crc,    %[ 7 ]
                   msn,           %[ 4 ]
                   psh_flag,      %[ 1 ]
                   ttl_hopl,      %[ 3 ]
                   ecn_used,      %[ 1 ]
                   ack_number,    %[ 15 ]
                   rsf_flags,     %[ 2 ]
                   seq_number,    %[ 14 ]
                   options_list,  % Nx8 bits
   {
      let ((ip_id_behavior:uncomp_value == 2) ||
           (ip_id_behavior:uncomp_value == 3));
      discriminator       ::= '1011';
      msn                 ::= lsb(4, 4);
      ip_id               ::= ip_id_lsb (ip_id_behavior, 4, 3);
      header_crc          ::= crc7 (this:uncomp_value,
                                    this:uncomp_length);
      psh_flag            ::= irregular (1);
      list_present        ::= irregular(1);
      options_list        ::= tcp_list_presence_enc
                                      ((data_offset:uncomp_value + 20) / 4,
                                       list_present);
      rsf_flags           ::= rsf_index_enc;
      ecn_used            ::= irregular(1);
      ttl_hopl            ::= lsb(3, 3);
      seq_number          ::= lsb(14, 8191);
      ack_number          ::= lsb(15, 8191);
   };

% +---+---+---+---+---+---+---+---+
% | 1   0   1   1 |     IP-ID     |
% +===+===+===+===+===+===+===+===+
% |lst|            CRC            |
% +---+---+---+---+---+---+---+---+
% |      MSN      |PSH|    TTL    |
% +---+---+---+---+---+---+---+---+
% |ECN|          ACK_SN...        |
% +---+---+---+---+---+---+---+---+
% |            ..ACK_SN           |
% +---+---+---+---+---+---+---+---+
% |  RSF  |       SN..            |
% +---+---+---+---+---+---+---+---+
% |             ..SN              |
% +---+---+---+---+---+---+---+---+
% /         options_list          /  n*8 bits, if lst=1
%  --- --- --- --- --- --- --- ---

};
_______________________________________________
Rohc mailing list
[email-masked]
https://www1.ietf.org/mailman/listinfo/rohc