tcp_opt_wscale { UNCOMPRESSED { type =:= uncompressed_value(8, 3) [ 8 ]; length =:= uncompressed_value(8, 3) [ 8 ]; wscale [ 8 ]; } COMPRESSED wscale_list_item { wscale =:= irregular(8) [ 8 ]; } COMPRESSED wscale_irregular { wscale =:= static; } } ts_lsb { UNCOMPRESSED { tsval [ 32 ]; } COMPRESSED tsval_7 { discriminator =:= '0' [ 1 ]; tsval =:= lsb(7, -1) [ 7 ]; } COMPRESSED tsval_14 { discriminator =:= '10' [ 2 ]; tsval =:= lsb(14, -1) [ 14 ]; } COMPRESSED tsval_21 { discriminator =:= '110' [ 3 ]; tsval =:= lsb(21, 0x00040000) [ 21 ]; } COMPRESSED tsval_29 { discriminator =:= '111' [ 3 ]; tsval =:= lsb(29, 0x04000000) [ 29 ]; } } tcp_opt_ts { UNCOMPRESSED { type =:= uncompressed_value(8, 8) [ 8 ];
length =:= uncompressed_value(8, 10) [ 8 ]; tsval [ 32 ]; tsecho [ 32 ]; } COMPRESSED tsopt_list_item { tsval =:= irregular(32) [ 32 ]; tsecho =:= irregular(32) [ 32 ]; } COMPRESSED tsopt_irregular { tsval =:= ts_lsb [ 8, 16, 24, 32 ]; tsecho =:= ts_lsb [ 8, 16, 24, 32 ]; } } sack_var_length_enc(base) { UNCOMPRESSED { sack_field [ 32 ]; } CONTROL { sack_offset [ 32 ]; ENFORCE(sack_offset.UVALUE == (sack_field.UVALUE - base)); } COMPRESSED lsb_15 { discriminator =:= '0' [ 1 ]; sack_offset =:= lsb(15, -1) [ 15 ]; } COMPRESSED lsb_22 { discriminator =:= '10' [ 2 ]; sack_offset =:= lsb(22, -1) [ 22 ]; } COMPRESSED lsb_30 { discriminator =:= '11' [ 2 ]; sack_offset =:= lsb(30, -1) [ 30 ]; } } sack_block(prev_block_end) { UNCOMPRESSED { block_start [ 32 ];
block_end [ 32 ]; } COMPRESSED { block_start =:= sack_var_length_enc(prev_block_end) [ 16, 24, 32 ]; block_end =:= sack_var_length_enc(block_start) [ 16, 24, 32 ]; } } // The value of the parameter is set to the ack_number value // of the TCP header tcp_opt_sack(ack_value) { UNCOMPRESSED { type =:= uncompressed_value(8, 5) [ 8 ]; length [ 8 ]; block_1 [ 64 ]; block_2 [ 0, 64 ]; block_3 [ 0, 64 ]; block_4 [ 0, 64 ]; } DEFAULT { length =:= static; block_2 =:= uncompressed_value(0, 0); block_3 =:= uncompressed_value(0, 0); block_4 =:= uncompressed_value(0, 0); } COMPRESSED sack1_list_item { discriminator =:= '00000001'; block_1 =:= sack_block(ack_value); ENFORCE(length.UVALUE == 10); } COMPRESSED sack2_list_item { discriminator =:= '00000010'; block_1 =:= sack_block(ack_value); block_2 =:= sack_block(block_1_end.UVALUE); ENFORCE(length.UVALUE == 18); } COMPRESSED sack3_list_item { discriminator =:= '00000011'; block_1 =:= sack_block(ack_value);
block_2 =:= sack_block(block_1_end.UVALUE); block_3 =:= sack_block(block_2_end.UVALUE); ENFORCE(length.UVALUE == 26); } COMPRESSED sack4_list_item { discriminator =:= '00000100'; block_1 =:= sack_block(ack_value); block_2 =:= sack_block(block_1_end.UVALUE); block_3 =:= sack_block(block_2_end.UVALUE); block_4 =:= sack_block(block_3_end.UVALUE); ENFORCE(length.UVALUE == 34); } COMPRESSED sack_unchanged_irregular { discriminator =:= '00000000'; block_1 =:= static; block_2 =:= static; block_3 =:= static; block_4 =:= static; } COMPRESSED sack1_irregular { discriminator =:= '00000001'; block_1 =:= sack_block(ack_value); ENFORCE(length.UVALUE == 10); } COMPRESSED sack2_irregular { discriminator =:= '00000010'; block_1 =:= sack_block(ack_value); block_2 =:= sack_block(block_1_end.UVALUE); ENFORCE(length.UVALUE == 18); } COMPRESSED sack3_irregular { discriminator =:= '00000011'; block_1 =:= sack_block(ack_value); block_2 =:= sack_block(block_1_end.UVALUE); block_3 =:= sack_block(block_2_end.UVALUE); ENFORCE(length.UVALUE == 26); } COMPRESSED sack4_irregular { discriminator =:= '00000100'; block_1 =:= sack_block(ack_value); block_2 =:= sack_block(block_1_end.UVALUE); block_3 =:= sack_block(block_2_end.UVALUE);
block_4 =:= sack_block(block_3_end.UVALUE); ENFORCE(length.UVALUE == 34); } } tcp_opt_sack_permitted { UNCOMPRESSED { type =:= uncompressed_value(8, 4) [ 8 ]; length =:= uncompressed_value(8, 2) [ 8 ]; } COMPRESSED sack_permitted_list_item { } COMPRESSED sack_permitted_irregular { } } tcp_opt_generic { UNCOMPRESSED { type [ 8 ]; length_msb =:= uncompressed_value(1, 0) [ 1 ]; length_lsb [ 7 ]; contents [ length_len.UVALUE*8-16 ]; } CONTROL { option_static [ 1 ]; } DEFAULT { type =:= static; length_lsb =:= static; contents =:= static; } COMPRESSED generic_list_item { type =:= irregular(8) [ 8 ]; option_static =:= one_bit_choice [ 1 ]; length_lsb =:= irregular(7) [ 7 ]; contents =:= irregular(length_lsb.UVALUE*8-16) [ length_len.UVALUE*8-16 ]; } // Used when context of option has option_static set to one COMPRESSED generic_static_irregular {
ENFORCE(option_static.UVALUE == 1); } // An item that can change, but currently is unchanged COMPRESSED generic_stable_irregular { discriminator =:= '11111111' [ 8 ]; ENFORCE(option_static.UVALUE == 0); } // An item that is assumed to change constantly. // Length is not allowed to change here, since a length change is // most likely to cause new NOPs or an EOL length change. COMPRESSED generic_full_irregular { discriminator =:= '00000000' [ 8 ]; contents =:= irregular(length_lsb.UVALUE*8-16) [ length_lsb.UVALUE*8-16 ]; ENFORCE(option_static.UVALUE == 0); } } tcp_list_presence_enc(presence) { UNCOMPRESSED { tcp_options; } COMPRESSED list_not_present { tcp_options =:= static [ 0 ]; ENFORCE(presence == 0); } COMPRESSED list_present { tcp_options =:= list_tcp_options [ VARIABLE ]; ENFORCE(presence == 1); } } ///////////////////////////////////////////// // TCP Header ///////////////////////////////////////////// port_replicate(flags) { UNCOMPRESSED { port [ 16 ]; } COMPRESSED port_static_enc {
port =:= static [ 0 ]; ENFORCE(flags == 0b00); } COMPRESSED port_lsb8 { port =:= lsb(8, 64) [ 8 ]; ENFORCE(flags == 0b01); } COMPRESSED port_irr_enc { port =:= irregular(16) [ 16 ]; ENFORCE(flags == 0b10); } } tcp_irreg_ip_ecn(ip_inner_ecn) { UNCOMPRESSED { ip_ecn_flags [ 2 ]; } COMPRESSED ecn_present { // This field does not exist in the uncompressed header // and therefore cannot use uncompressed_value. ip_ecn_flags =:= compressed_value(2, ip_inner_ecn) [ 2 ]; ENFORCE(ecn_used.UVALUE == 1); } COMPRESSED ecn_not_present { ip_ecn_flags =:= static [ 0 ]; ENFORCE(ecn_used.UVALUE == 0); } } rsf_index_enc { UNCOMPRESSED { rsf_flag [ 3 ]; } COMPRESSED none { rsf_idx =:= '00' [ 2 ]; rsf_flag =:= uncompressed_value(3, 0x00); } COMPRESSED rst_only { rsf_idx =:= '01' [ 2 ];
rsf_flag =:= uncompressed_value(3, 0x04); } COMPRESSED syn_only { rsf_idx =:= '10' [ 2 ]; rsf_flag =:= uncompressed_value(3, 0x02); } COMPRESSED fin_only { rsf_idx =:= '11' [ 2 ]; rsf_flag =:= uncompressed_value(3, 0x01); } } optional_2bit_padding(used_flag) { UNCOMPRESSED { } COMPRESSED used { padding =:= compressed_value(2, 0x0) [ 2 ]; ENFORCE(used_flag == 1); } COMPRESSED unused { padding =:= compressed_value(0, 0x0); ENFORCE(used_flag == 0); } } // ack_stride_value is the user-selected stride for scaling the // TCP ack_number // ip_inner_ecn is the value bound when processing the innermost // IP header (ipv4 or ipv6 encoding method) tcp(payload_size, ack_stride_value, ip_inner_ecn) { UNCOMPRESSED { src_port [ 16 ]; dst_port [ 16 ]; seq_number [ 32 ]; ack_number [ 32 ]; data_offset [ 4 ]; tcp_res_flags [ 4 ]; tcp_ecn_flags [ 2 ]; urg_flag [ 1 ]; ack_flag [ 1 ]; psh_flag [ 1 ]; rsf_flags [ 3 ];
window [ 16 ]; checksum [ 16 ]; urg_ptr [ 16 ]; options [ (data_offset.UVALUE-5)*32 ]; } CONTROL { seq_number_scaled [ 32 ]; seq_number_residue =:= field_scaling(payload_size, seq_number_scaled.UVALUE, seq_number.UVALUE) [ 32 ]; ack_stride [ 16 ]; ack_number_scaled [ 32 ]; ack_number_residue =:= field_scaling(ack_stride.UVALUE, ack_number_scaled.UVALUE, ack_number.UVALUE) [ 32 ]; ENFORCE(ack_stride.UVALUE == ack_stride_value); } INITIAL { ack_stride =:= uncompressed_value(16, 0); } DEFAULT { src_port =:= static; dst_port =:= static; seq_number =:= static; ack_number =:= static; data_offset =:= inferred_offset; tcp_res_flags =:= static; tcp_ecn_flags =:= static; urg_flag =:= static; ack_flag =:= uncompressed_value(1, 1); rsf_flags =:= uncompressed_value(3, 0); window =:= static; urg_ptr =:= static; } COMPRESSED tcp_static { src_port =:= irregular(16) [ 16 ]; dst_port =:= irregular(16) [ 16 ]; } COMPRESSED tcp_dynamic { ecn_used =:= one_bit_choice [ 1 ]; ack_stride_flag =:= irregular(1) [ 1 ]; ack_zero =:= irregular(1) [ 1 ]; urp_zero =:= irregular(1) [ 1 ];
tcp_res_flags =:= irregular(4) [ 4 ]; tcp_ecn_flags =:= irregular(2) [ 2 ]; urg_flag =:= irregular(1) [ 1 ]; ack_flag =:= irregular(1) [ 1 ]; psh_flag =:= irregular(1) [ 1 ]; rsf_flags =:= irregular(3) [ 3 ]; msn =:= irregular(16) [ 16 ]; seq_number =:= irregular(32) [ 32 ]; ack_number =:= zero_or_irreg(ack_zero.CVALUE, 32) [ 0, 32 ]; window =:= irregular(16) [ 16 ]; checksum =:= irregular(16) [ 16 ]; urg_ptr =:= zero_or_irreg(urp_zero.CVALUE, 16) [ 0, 16 ]; ack_stride =:= static_or_irreg(ack_stride_flag.CVALUE, 16) [ 0, 16 ]; options =:= list_tcp_options [ VARIABLE ]; } COMPRESSED tcp_replicate { reserved =:= '0' [ 1 ]; window_presence =:= irregular(1) [ 1 ]; list_present =:= irregular(1) [ 1 ]; src_port_presence =:= irregular(2) [ 2 ]; dst_port_presence =:= irregular(2) [ 2 ]; ack_stride_flag =:= irregular(1) [ 1 ]; ack_presence =:= irregular(1) [ 1 ]; urp_presence =:= irregular(1) [ 1 ]; urg_flag =:= irregular(1) [ 1 ]; ack_flag =:= irregular(1) [ 1 ]; psh_flag =:= irregular(1) [ 1 ]; rsf_flags =:= rsf_index_enc [ 2 ]; ecn_used =:= one_bit_choice [ 1 ]; msn =:= irregular(16) [ 16 ]; seq_number =:= irregular(32) [ 32 ]; src_port =:= port_replicate(src_port_presence) [ 0, 8, 16 ]; dst_port =:= port_replicate(dst_port_presence) [ 0, 8, 16 ]; window =:= static_or_irreg(window_presence, 16) [ 0, 16 ]; urg_point =:= static_or_irreg(urp_presence, 16) [ 0, 16 ]; ack_number =:= static_or_irreg(ack_presence, 32) [ 0, 32 ]; ecn_padding =:= optional_2bit_padding(ecn_used.CVALUE) [ 0, 2 ]; tcp_res_flags =:=
static_or_irreg(ecn_used.CVALUE, 4) [ 0, 4 ]; tcp_ecn_flags =:= static_or_irreg(ecn_used.CVALUE, 2) [ 0, 2 ]; checksum =:= irregular(16) [ 16 ]; ack_stride =:= static_or_irreg(ack_stride_flag.CVALUE, 16) [ 0, 16 ]; options =:= tcp_list_presence_enc(list_present.CVALUE) [ VARIABLE ]; } COMPRESSED tcp_irregular { ip_ecn_flags =:= tcp_irreg_ip_ecn(ip_inner_ecn) [ 0, 2 ]; tcp_res_flags =:= static_or_irreg(ecn_used.CVALUE, 4) [ 0, 4 ]; tcp_ecn_flags =:= static_or_irreg(ecn_used.CVALUE, 2) [ 0, 2 ]; checksum =:= irregular(16) [ 16 ]; } } /////////////////////////////////////////////////// // Encoding methods used in compressed base headers /////////////////////////////////////////////////// dscp_enc(flag) { UNCOMPRESSED { dscp [ 6 ]; } COMPRESSED static_enc { dscp =:= static [ 0 ]; ENFORCE(flag == 0); } COMPRESSED irreg { dscp =:= irregular(6) [ 6 ]; padding =:= compressed_value(2, 0) [ 2 ]; ENFORCE(flag == 1); } } ip_id_lsb(behavior, k, p) { UNCOMPRESSED { ip_id [ 16 ]; }
CONTROL { ip_id_offset [ 16 ]; ip_id_nbo [ 16 ]; } COMPRESSED nbo { ip_id_offset =:= lsb(k, p) [ k ]; ENFORCE(behavior == IP_ID_BEHAVIOR_SEQUENTIAL); ENFORCE(ip_id_offset.UVALUE == ip_id.UVALUE - msn.UVALUE); } COMPRESSED non_nbo { ip_id_offset =:= lsb(k, p) [ k ]; ENFORCE(behavior == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED); ENFORCE(ip_id_nbo.UVALUE == (ip_id.UVALUE / 256) + (ip_id.UVALUE % 256) * 256); ENFORCE(ip_id_nbo.ULENGTH == 16); ENFORCE(ip_id_offset.UVALUE == ip_id_nbo.UVALUE - msn.UVALUE); } } optional_ip_id_lsb(behavior, indicator) { UNCOMPRESSED { ip_id [ 16 ]; } COMPRESSED short { ip_id =:= ip_id_lsb(behavior, 8, 3) [ 8 ]; ENFORCE((behavior == IP_ID_BEHAVIOR_SEQUENTIAL) || (behavior == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); ENFORCE(indicator == 0); } COMPRESSED long { ip_id =:= irregular(16) [ 16 ]; ENFORCE((behavior == IP_ID_BEHAVIOR_SEQUENTIAL) || (behavior == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); ENFORCE(indicator == 1); } COMPRESSED not_present { ENFORCE((behavior == IP_ID_BEHAVIOR_RANDOM) || (behavior == IP_ID_BEHAVIOR_ZERO)); } } dont_fragment(version)
{ UNCOMPRESSED { df [ 1 ]; } COMPRESSED v4 { df =:= irregular(1) [ 1 ]; ENFORCE(version == 4); } COMPRESSED v6 { df =:= compressed_value(1, 0) [ 1 ]; ENFORCE(version == 6); } } ////////////////////////////////// // 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 set by the user if the TTL/Hop Limit // of an outer header has changed. The same value must be passed as // an argument to the ipv4/ipv6 encoding methods when extracting // the irregular chain items. co_baseheader(payload_size, ack_stride_value, ttl_irregular_chain_flag) { UNCOMPRESSED v4 { outer_headers =:= baseheader_outer_headers [ VARIABLE ]; version =:= uncompressed_value(4, 4) [ 4 ]; header_length =:= uncompressed_value(4, 5) [ 4 ]; dscp [ 6 ]; ip_ecn_flags [ 2 ]; length [ 16 ]; ip_id [ 16 ]; rf =:= uncompressed_value(1, 0) [ 1 ]; df [ 1 ]; mf =:= uncompressed_value(1, 0) [ 1 ]; frag_offset =:= uncompressed_value(13, 0) [ 13 ]; ttl_hopl [ 8 ]; next_header [ 8 ]; checksum [ 16 ]; src_addr [ 32 ]; dest_addr [ 32 ]; extension_headers =:= baseheader_extension_headers [ VARIABLE ];
src_port [ 16 ]; dest_port [ 16 ]; seq_number [ 32 ]; ack_number [ 32 ]; data_offset [ 4 ]; tcp_res_flags [ 4 ]; tcp_ecn_flags [ 2 ]; urg_flag [ 1 ]; ack_flag [ 1 ]; psh_flag [ 1 ]; rsf_flags [ 3 ]; window [ 16 ]; tcp_checksum [ 16 ]; urg_ptr [ 16 ]; options [ (data_offset.UVALUE-5)*32 ]; } UNCOMPRESSED v6 { outer_headers =:= baseheader_outer_headers [ VARIABLE ]; version =:= uncompressed_value(4, 6) [ 4 ]; dscp [ 6 ]; ip_ecn_flags [ 2 ]; flow_label [ 20 ]; payload_length [ 16 ]; next_header [ 8 ]; ttl_hopl [ 8 ]; src_addr [ 128 ]; dest_addr [ 128 ]; extension_headers =:= baseheader_extension_headers [ VARIABLE ]; src_port [ 16 ]; dest_port [ 16 ]; seq_number [ 32 ]; ack_number [ 32 ]; data_offset [ 4 ]; tcp_res_flags [ 4 ]; tcp_ecn_flags [ 2 ]; urg_flag [ 1 ]; ack_flag [ 1 ]; psh_flag [ 1 ]; rsf_flags [ 3 ]; window [ 16 ]; tcp_checksum [ 16 ]; urg_ptr [ 16 ]; options [ (data_offset.UVALUE-5)*32 ]; ENFORCE(ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_RANDOM); } CONTROL {
ip_id_behavior [ 2 ]; seq_number_scaled [ 32 ]; seq_number_residue =:= field_scaling(payload_size, seq_number_scaled.UVALUE, seq_number.UVALUE) [ 32 ]; ack_stride [ 16 ]; ack_number_scaled [ 32 ]; ack_number_residue =:= field_scaling(ack_stride.UVALUE, ack_number_scaled.UVALUE, ack_number.UVALUE) [ 32 ]; ENFORCE(ack_stride_value == ack_stride.UVALUE); } INITIAL { ack_stride =:= uncompressed_value(16, 0); } DEFAULT { tcp_ecn_flags =:= static; data_offset =:= inferred_offset; tcp_res_flags =:= static; rsf_flags =:= uncompressed_value(3, 0); dest_port =:= static; dscp =:= static; src_port =:= static; urg_flag =:= uncompressed_value(1, 0); window =:= static; dest_addr =:= static; version =:= static; ttl_hopl =:= static; src_addr =:= static; df =:= static; ack_number =:= static; urg_ptr =:= static; seq_number =:= static; ack_flag =:= uncompressed_value(1, 1); // The default for "options" is case 2) and 3) from // the list in section 6.3.1 (i.e. nothing present in the // baseheader itself). payload_length =:= inferred_ip_v6_length; checksum =:= inferred_ip_v4_header_checksum; length =:= inferred_ip_v4_length; flow_label =:= static; next_header =:= static; ip_ecn_flags =:= static; // The tcp_checksum has no default, // it is considered a part of tcp_irregular ip_id_behavior =:= static;
ecn_used =:= static; // Default is to have no TTL in irregular chain // Can only be nonzero if co_common is used ENFORCE(ttl_irregular_chain_flag == 0); } //////////////////////////////////////////// // Common compressed packet format //////////////////////////////////////////// COMPRESSED co_common { discriminator =:= '1111101' [ 7 ]; ttl_hopl_outer_flag =:= compressed_value(1, ttl_irregular_chain_flag) [ 1 ]; ack_flag =:= irregular(1) [ 1 ]; psh_flag =:= irregular(1) [ 1 ]; rsf_flags =:= rsf_index_enc [ 2 ]; msn =:= lsb(4, 4) [ 4 ]; seq_indicator =:= irregular(2) [ 2 ]; ack_indicator =:= irregular(2) [ 2 ]; ack_stride_indicator =:= irregular(1) [ 1 ]; window_indicator =:= irregular(1) [ 1 ]; ip_id_indicator =:= irregular(1) [ 1 ]; urg_ptr_present =:= irregular(1) [ 1 ]; reserved =:= compressed_value(1, 0) [ 1 ]; ecn_used =:= one_bit_choice [ 1 ]; dscp_present =:= irregular(1) [ 1 ]; ttl_hopl_present =:= irregular(1) [ 1 ]; list_present =:= irregular(1) [ 1 ]; ip_id_behavior =:= ip_id_behavior_choice(true) [ 2 ]; urg_flag =:= irregular(1) [ 1 ]; df =:= dont_fragment(version.UVALUE) [ 1 ]; header_crc =:= crc7(THIS.UVALUE, THIS.ULENGTH) [ 7 ]; seq_number =:= variable_length_32_enc(seq_indicator.CVALUE) [ 0, 8, 16, 32 ]; ack_number =:= variable_length_32_enc(ack_indicator.CVALUE) [ 0, 8, 16, 32 ]; ack_stride =:= static_or_irreg(ack_stride_indicator.CVALUE, 16) [ 0, 16 ]; window =:= static_or_irreg(window_indicator.CVALUE, 16) [ 0, 16 ]; ip_id =:= optional_ip_id_lsb(ip_id_behavior.UVALUE, ip_id_indicator.CVALUE) [ 0, 8, 16 ]; urg_ptr =:= static_or_irreg(urg_ptr_present.CVALUE, 16) [ 0, 16 ]; dscp =:=
dscp_enc(dscp_present.CVALUE) [ 0, 8 ]; ttl_hopl =:= static_or_irreg(ttl_hopl_present.CVALUE, 8) [ 0, 8 ]; options =:= tcp_list_presence_enc(list_present.CVALUE) [ VARIABLE ]; } // Send LSBs of sequence number COMPRESSED rnd_1 { discriminator =:= '101110' [ 6 ]; seq_number =:= lsb(18, 65535) [ 18 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_RANDOM) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_ZERO)); } // Send scaled sequence number LSBs COMPRESSED rnd_2 { discriminator =:= '1100' [ 4 ]; seq_number_scaled =:= lsb(4, 7) [ 4 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE(payload_size != 0); ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_RANDOM) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_ZERO)); } // Send acknowledgment number LSBs COMPRESSED rnd_3 { discriminator =:= '0' [ 1 ]; ack_number =:= lsb(15, 8191) [ 15 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_RANDOM) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_ZERO)); } // Send acknowledgment number scaled COMPRESSED rnd_4 { discriminator =:= '1101' [ 4 ]; ack_number_scaled =:= lsb(4, 3) [ 4 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ];
ENFORCE(ack_stride.UVALUE != 0); ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_RANDOM) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_ZERO)); } // Send ACK and sequence number COMPRESSED rnd_5 { discriminator =:= '100' [ 3 ]; psh_flag =:= irregular(1) [ 1 ]; msn =:= lsb(4, 4) [ 4 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; seq_number =:= lsb(14, 8191) [ 14 ]; ack_number =:= lsb(15, 8191) [ 15 ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_RANDOM) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_ZERO)); } // Send both ACK and scaled sequence number LSBs COMPRESSED rnd_6 { discriminator =:= '1010' [ 4 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; psh_flag =:= irregular(1) [ 1 ]; ack_number =:= lsb(16, 16383) [ 16 ]; msn =:= lsb(4, 4) [ 4 ]; seq_number_scaled =:= lsb(4, 7) [ 4 ]; ENFORCE(payload_size != 0); ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_RANDOM) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_ZERO)); } // Send ACK and window COMPRESSED rnd_7 { discriminator =:= '101111' [ 6 ]; ack_number =:= lsb(18, 65535) [ 18 ]; window =:= irregular(16) [ 16 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_RANDOM) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_ZERO)); } // An extended packet type for seldom-changing fields // Can send LSBs of TTL, RSF flags, change ECN behavior, and // options list COMPRESSED rnd_8 { discriminator =:= '10110' [ 5 ]; rsf_flags =:= rsf_index_enc [ 2 ];
list_present =:= irregular(1) [ 1 ]; header_crc =:= crc7(THIS.UVALUE, THIS.ULENGTH) [ 7 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; ttl_hopl =:= lsb(3, 3) [ 3 ]; ecn_used =:= one_bit_choice [ 1 ]; seq_number =:= lsb(16, 65535) [ 16 ]; ack_number =:= lsb(16, 16383) [ 16 ]; options =:= tcp_list_presence_enc(list_present.CVALUE) [ VARIABLE ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_RANDOM) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_ZERO)); } // Send LSBs of sequence number COMPRESSED seq_1 { discriminator =:= '1010' [ 4 ]; ip_id =:= ip_id_lsb(ip_id_behavior.UVALUE, 4, 3) [ 4 ]; seq_number =:= lsb(16, 32767) [ 16 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); } // Send scaled sequence number LSBs COMPRESSED seq_2 { discriminator =:= '11010' [ 5 ]; ip_id =:= ip_id_lsb(ip_id_behavior.UVALUE, 7, 3) [ 7 ]; seq_number_scaled =:= lsb(4, 7) [ 4 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE(payload_size != 0); ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); } // Send acknowledgment number LSBs COMPRESSED seq_3 { discriminator =:= '1001' [ 4 ]; ip_id =:= ip_id_lsb(ip_id_behavior.UVALUE, 4, 3) [ 4 ]; ack_number =:= lsb(16, 16383) [ 16 ]; msn =:= lsb(4, 4) [ 4 ];
psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); } // Send scaled acknowledgment number scaled COMPRESSED seq_4 { discriminator =:= '0' [ 1 ]; ack_number_scaled =:= lsb(4, 3) [ 4 ]; // Due to having very few ip_id bits, no negative offset ip_id =:= ip_id_lsb(ip_id_behavior.UVALUE, 3, 1) [ 3 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE(ack_stride.UVALUE != 0); ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); } // Send ACK and sequence number COMPRESSED seq_5 { discriminator =:= '1000' [ 4 ]; ip_id =:= ip_id_lsb(ip_id_behavior.UVALUE, 4, 3) [ 4 ]; ack_number =:= lsb(16, 16383) [ 16 ]; seq_number =:= lsb(16, 32767) [ 16 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); } // Send both ACK and scaled sequence number LSBs COMPRESSED seq_6 { discriminator =:= '11011' [ 5 ]; seq_number_scaled =:= lsb(4, 7) [ 4 ]; ip_id =:= ip_id_lsb(ip_id_behavior.UVALUE, 7, 3) [ 7 ]; ack_number =:= lsb(16, 16383) [ 16 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE(payload_size != 0); ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL) || (ip_id_behavior.UVALUE ==
IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); } // Send ACK and window COMPRESSED seq_7 { discriminator =:= '1100' [ 4 ]; window =:= lsb(15, 16383) [ 15 ]; ip_id =:= ip_id_lsb(ip_id_behavior.UVALUE, 5, 3) [ 5 ]; ack_number =:= lsb(16, 32767) [ 16 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; header_crc =:= crc3(THIS.UVALUE, THIS.ULENGTH) [ 3 ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); } // An extended packet type for seldom-changing fields // Can send LSBs of TTL, RSF flags, change ECN behavior, and // options list COMPRESSED seq_8 { discriminator =:= '1011' [ 4 ]; ip_id =:= ip_id_lsb(ip_id_behavior.UVALUE, 4, 3) [ 4 ]; list_present =:= irregular(1) [ 1 ]; header_crc =:= crc7(THIS.UVALUE, THIS.ULENGTH) [ 7 ]; msn =:= lsb(4, 4) [ 4 ]; psh_flag =:= irregular(1) [ 1 ]; ttl_hopl =:= lsb(3, 3) [ 3 ]; ecn_used =:= one_bit_choice [ 1 ]; ack_number =:= lsb(15, 8191) [ 15 ]; rsf_flags =:= rsf_index_enc [ 2 ]; seq_number =:= lsb(14, 8191) [ 14 ]; options =:= tcp_list_presence_enc(list_present.CVALUE) [ VARIABLE ]; ENFORCE((ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL) || (ip_id_behavior.UVALUE == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED)); } }
8.3. Feedback Formats and Options
8.3.1. Feedback Formats
This section describes the feedback formats for the ROHC-TCP profile, following the general ROHC feedback format described in Section 5.2.3 of [RFC4995]. All feedback formats carry a field labeled MSN. The MSN field contains LSBs of the MSN control field described in Section 6.1.1. The sequence number to use is the MSN corresponding to the last header that was successfully CRC-8 validated or CRC verified. FEEDBACK-1 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | MSN | +---+---+---+---+---+---+---+---+ MSN: The LSB-encoded master sequence number. A FEEDBACK-1 is an ACK. In order to send a NACK or a STATIC-NACK, FEEDBACK-2 must be used. FEEDBACK-2 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ |Acktype| MSN | +---+---+---+---+---+---+---+---+ | MSN | +---+---+---+---+---+---+---+---+ | CRC | +---+---+---+---+---+---+---+---+ / Feedback options / +---+---+---+---+---+---+---+---+ Acktype: 0 = ACK 1 = NACK 2 = STATIC-NACK 3 is reserved (MUST NOT be used for parsability)
MSN: The LSB-encoded master sequence number. CRC: 8-bit CRC computed over the entire feedback element (as defined in Section 5.3.1.1 of [RFC4995]). For the purpose of computing the CRC, the CRC field is zero. The CRC is calculated using the polynomial defined in [RFC4995]. Feedback options: A variable number of feedback options, see Section 8.3.2. Options may appear in any order. A FEEDBACK-2 of type NACK or STATIC-NACK is always implicitly an acknowledgment for a successfully decompressed packet, which packet corresponds to the MSN of the feedback element, unless the MSN-NOT- VALID option (Section 8.3.2.2) appears in the feedback element. The FEEDBACK-2 format always carries a CRC and is thus more robust than the FEEDBACK-1 format. When receiving FEEDBACK-2, the compressor MUST verify the information by computing the CRC and by comparing the result with the CRC carried in the feedback format. If the two are not identical, the feedback element MUST be discarded.8.3.2. Feedback Options
A ROHC-TCP feedback option has variable length and the following general format: 0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | Opt Type | Opt Len | +---+---+---+---+---+---+---+---+ / option data / Opt Length (octets) +---+---+---+---+---+---+---+---+ Each ROHC-TCP feedback option can appear at most once within a FEEDBACK-2.8.3.2.1. The REJECT Option
The REJECT option informs the compressor that the decompressor does not have sufficient resources to handle the flow. +---+---+---+---+---+---+---+---+ | Opt Type = 2 | Opt Len = 0 | +---+---+---+---+---+---+---+---+ When receiving a REJECT option, the compressor MUST stop compressing the packet flow, and SHOULD refrain from attempting to increase the number of compressed packet flows for some time. The REJECT option
MUST NOT appear more than once in the FEEDBACK-2 format; otherwise, the compressor MUST discard the entire feedback element.8.3.2.2. The MSN-NOT-VALID Option
The MSN-NOT-VALID option indicates that the MSN of the feedback is not valid. +---+---+---+---+---+---+---+---+ | Opt Type = 3 | Opt Len = 0 | +---+---+---+---+---+---+---+---+ A compressor MUST ignore the MSN of the feedback element when this option is present. Consequently, a NACK or a STATIC-NACK feedback type sent with the MSN-NOT-VALID option is equivalent to a STATIC- NACK with respect to the semantics of the feedback message. The MSN-NOT-VALID option MUST NOT appear more than once in the FEEDBACK-2 format and MUST NOT appear in the same feedback element as the MSN option; otherwise, the compressor MUST discard the entire feedback element.8.3.2.3. The MSN Option
The MSN option provides 2 additional bits of MSN. +---+---+---+---+---+---+---+---+ | Opt Type = 4 | Opt Len = 1 | +---+---+---+---+---+---+---+---+ | MSN | Reserved | +---+---+---+---+---+---+---+---+ These 2 bits are the least significant bits of the MSN and are thus concatenated with the 14 bits already present in the FEEDBACK-2 format. The MSN option MUST NOT appear more than once in the FEEDBACK-2 format and MUST NOT appear in the same feedback element as the MSN- NOT-VALID option; otherwise, the compressor MUST discard the entire feedback element.8.3.2.4. The CONTEXT_MEMORY Feedback Option
The CONTEXT_MEMORY option means that the decompressor does not have sufficient memory resources to handle the context of the packet flow, as the flow is currently compressed.
0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | Opt Type = 9 | Opt Len = 0 | +---+---+---+---+---+---+---+---+ When receiving a CONTEXT_MEMORY option, the compressor SHOULD take actions to compress the packet flow in a way that requires less decompressor memory resources, or stop compressing the packet flow. The CONTEXT_MEMORY option MUST NOT appear more than once in the FEEDBACK-2 format; otherwise, the compressor MUST discard the entire feedback element.8.3.2.5. Unknown Option Types
If an option type unknown to the compressor is encountered, the compressor MUST continue parsing the rest of the FEEDBACK element, which is possible since the length of the option is explicit, but MUST otherwise ignore the unknown option.9. Security Considerations
A malfunctioning or malicious header compressor could cause the header decompressor to reconstitute packets that do not match the original packets but still have valid IP and TCP headers, and possibly also valid TCP checksums. Such corruption may be detected with end-to-end authentication and integrity mechanisms that will not be affected by the compression. Moreover, this header compression scheme uses an internal checksum for verification of reconstructed headers. This reduces the probability of producing decompressed headers not matching the original ones without this being noticed. Denial-of-service attacks are possible if an intruder can introduce (for example) bogus IR, CO, or FEEDBACK packets onto the link and thereby cause compression efficiency to be reduced. However, an intruder having the ability to inject arbitrary packets at the link layer in this manner raises additional security issues that dwarf those related to the use of header compression.10. IANA Considerations
The ROHC profile identifier 0x0006 has been reserved by the IANA for the profile defined in this document. A ROHC profile identifier has been reserved by the IANA for the profile defined in this document. Profiles 0x0000-0x0005 have previously been reserved; this profile is 0x0006. As for previous
ROHC profiles, profile numbers 0xnn06 have been reserved for future updates of this profile. Profile Usage Document identifier 0x0006 ROHC TCP [RFC4996] 0xnn06 Reserved11. Acknowledgments
The authors would like to thank Qian Zhang, Hong Bin Liao, Richard Price, and Fredrik Lindstroem for their work with early versions of this specification. Thanks also to Robert Finking and Carsten Bormann for valuable input. Additional thanks: this document was reviewed during working group last-call by committed reviewers Joe Touch and Ted Faber, as well as by Sally Floyd, who provided a review at the request of the Transport Area Directors.12. References
12.1. Normative References
[RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981. [RFC0793] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981. [RFC2004] Perkins, C., "Minimal Encapsulation within IP", RFC 2004, October 1996. [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 (IPv6) Specification", RFC 2460, December 1998. [RFC2784] Farinacci, D., Li, T., Hanks, S., Meyer, D., and P. Traina, "Generic Routing Encapsulation (GRE)", RFC 2784, March 2000. [RFC2890] Dommety, G., "Key and Sequence Number Extensions to GRE", RFC 2890, September 2000.
[RFC4164] Pelletier, G., "RObust Header Compression (ROHC): Context Replication for ROHC Profiles", RFC 4164, August 2005. [RFC4302] Kent, S., "IP Authentication Header", RFC 4302, December 2005. [RFC4303] Kent, S., "IP Encapsulating Security Payload (ESP)", RFC 4303, December 2005. [RFC4995] Jonsson, L-E., Pelletier, G., and K. Sandlund, "The RObust Header Compression (ROHC) Framework", RFC 4995, July 2007. [RFC4997] Finking, R. and G. Pelletier, "Formal Notation for Robust Header Compression (ROHC-FN)", RFC 4997, July 2007.12.2. Informative References
[RFC1144] Jacobson, V., "Compressing TCP/IP headers for low-speed serial links", RFC 1144, February 1990. [RFC1323] Jacobson, V., Braden, B., and D. Borman, "TCP Extensions for High Performance", RFC 1323, May 1992. [RFC2018] Mathis, M., Mahdavi, J., Floyd, S., and A. Romanow, "TCP Selective Acknowledgment Options", RFC 2018, October 1996. [RFC2507] Degermark, M., Nordgren, B., and S. Pink, "IP Header Compression", RFC 2507, February 1999. [RFC2581] Allman, M., Paxson, V., and W. Stevens, "TCP Congestion Control", RFC 2581, April 1999. [RFC2883] Floyd, S., Mahdavi, J., Mathis, M., and M. Podolsky, "An Extension to the Selective Acknowledgement (SACK) Option for TCP", RFC 2883, July 2000. [RFC3095] Bormann, C., Burmeister, C., Degermark, M., Fukushima, H., Hannu, H., Jonsson, L-E., Hakenberg, R., Koren, T., Le, K., Liu, Z., Martensson, A., Miyazaki, A., Svanbro, K., Wiebke, T., Yoshimura, T., and H. Zheng, "RObust Header Compression (ROHC): Framework and four profiles: RTP, UDP, ESP, and uncompressed", RFC 3095, July 2001. [RFC3168] Ramakrishnan, K., Floyd, S., and D. Black, "The Addition of Explicit Congestion Notification (ECN) to IP", RFC 3168, September 2001.
[RFC3759] Jonsson, L-E., "RObust Header Compression (ROHC): Terminology and Channel Mapping Examples", RFC 3759, April 2004. [RFC4163] Jonsson, L-E., "RObust Header Compression (ROHC): Requirements on TCP/IP Header Compression", RFC 4163, August 2005. [RFC4224] Pelletier, G., Jonsson, L-E., and K. Sandlund, "RObust Header Compression (ROHC): ROHC over Channels That Can Reorder Packets", RFC 4224, January 2006. [RFC4413] West, M. and S. McCann, "TCP/IP Field Behavior", RFC 4413, March 2006.
Authors' Addresses
Ghyslain Pelletier Ericsson Box 920 Lulea SE-971 28 Sweden Phone: +46 (0) 8 404 29 43 EMail: ghyslain.pelletier@ericsson.com Kristofer Sandlund Ericsson Box 920 Lulea SE-971 28 Sweden Phone: +46 (0) 8 404 41 58 EMail: kristofer.sandlund@ericsson.com Lars-Erik Jonsson Optand 737 Ostersund SE-831 92 Sweden Phone: +46 70 365 20 58 EMail: lars-erik@lejonsson.com Mark A West Siemens/Roke Manor Roke Manor Research Ltd. Romsey, Hampshire SO51 0ZN UK Phone: +44 1794 833311 EMail: mark.a.west@roke.co.uk URI: http://www.roke.co.uk
Full Copyright Statement Copyright (C) The IETF Trust (2007). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Intellectual Property The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org. Acknowledgement Funding for the RFC Editor function is currently provided by the Internet Society.