=== modified file 'src/comp/c_tcp.c' --- src/comp/c_tcp.c 2014-03-08 19:04:45 +0000 +++ src/comp/c_tcp.c 2014-04-03 16:24:04 +0000 @@ -44,7 +44,7 @@ #include "config.h" /* for WORDS_BIGENDIAN and ROHC_EXTRA_DEBUG */ -#define MAX_TCP_OPTION_INDEX 16 +#define MAX_TCP_OPTION_INDEX 8 // TODO #if ROHC_EXTRA_DEBUG == 1 #define TRACE_GOTO_CHOICE \ @@ -348,13 +348,17 @@ * Private datas. */ + +/** TODO */ +#define TCP_LIST_ITEM_MAP_LEN 16U + /** * @brief Table of TCP option index, from option Id * * See RFC4996 6.3.4 * Return item index of TCP option */ -int tcp_options_index[16] = +int tcp_options_index[TCP_LIST_ITEM_MAP_LEN] = { TCP_INDEX_EOL, // TCP_OPT_EOL 0 TCP_INDEX_NOP, // TCP_OPT_NOP 1 @@ -1426,6 +1430,13 @@ "ip_id = 0x%x\n", ip_inner_context.v4->ip_id_behavior, ip_inner_context.v4->last_ip_id, ip_id); + if(context->num_sent_packets == 0) + { + /* first packet, be optimistic: choose sequential behavior */ + ip_inner_context.v4->ip_id_behavior = IP_ID_BEHAVIOR_SEQUENTIAL; + } + else + { switch(ip_inner_context.v4->ip_id_behavior) { case IP_ID_BEHAVIOR_SEQUENTIAL: @@ -1533,6 +1544,7 @@ assert(0); /* should never happen */ break; } + } } /* parse TCP options */ @@ -3025,7 +3037,8 @@ /* doff is the size of tcp header using 32 bits */ /* TCP header is at least 20 bytes */ - if(tcp->data_offset > 5) + if(tcp->data_offset > 5) // TODO: put else before if + // TODO: put if/else in a function { uint8_t *pBeginList; uint8_t opt_idx; @@ -3352,12 +3365,155 @@ rohc_comp_debug(context, "TCP %d item(s) in list at %p\n", (*pBeginList) & 0x0f, debug_ptr); #endif + +#if 1 + /* encode items */ + options = ( (unsigned char *) tcp ) + sizeof(tcphdr_t); + options_length = (tcp->data_offset << 2) - sizeof(tcphdr_t); + for(i = options_length; i > 0; ) + { + uint8_t opt_type; + uint8_t opt_len; + + /* option type */ + if(i < 1) + { + rohc_warning(context->compressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP options: not " + "enough remaining bytes for option type\n"); + goto error; + } + opt_type = options[0]; + + /* option length */ + if(opt_type == TCP_OPT_EOL || opt_type == TCP_OPT_NOP) + { + opt_len = 1; + } + else if(i < 2) + { + rohc_warning(context->compressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP options: not " + "enough remaining bytes for option length\n"); + goto error; + } + else + { + opt_len = options[1]; + if(opt_len < 2) + { + rohc_warning(context->compressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP options: option " + "should be at least 2 bytes but length field is %u\n", + opt_len); + goto error; + } + } + + switch(opt_type) + { + case TCP_OPT_EOL: + /* COMPRESSED eol_list_item { + * pad_len =:= compressed_value(8, nbits-8) [ 8 ]; + * } + */ + *(mptr.uint8) = i - 1; + mptr.uint8++; + /* skip option */ + i = 0; + options++; + break; + case TCP_OPT_NOP: + /* COMPRESSED nop_list_item { + * } + */ + /* skip option */ + --i; + ++options; + break; + case TCP_OPT_MAXSEG: + /* COMPRESSED mss_list_item { + * mss =:= irregular(16) [ 16 ]; + * } + */ + memcpy(mptr.uint8, options + 2, sizeof(uint16_t)); + mptr.uint8 += sizeof(uint16_t); + /* skip option */ + i -= TCP_OLEN_MAXSEG; + options += TCP_OLEN_MAXSEG; + break; + case TCP_OPT_WINDOW: + /* COMPRESSED wscale_list_item { + * wscale =:= irregular(8) [ 8 ]; + * } + */ + *(mptr.uint8) = options[2]; + mptr.uint8++; + /* skip option */ + i -= TCP_OLEN_WINDOW; + options += TCP_OLEN_WINDOW; + break; + case TCP_OPT_TIMESTAMP: + /* COMPRESSED tsopt_list_item { + * tsval =:= irregular(32) [ 32 ]; + * tsecho =:= irregular(32) [ 32 ]; + * } + */ + memcpy(mptr.uint8, options + 2, sizeof(uint32_t) * 2); + mptr.uint8 += sizeof(uint32_t) * 2; + /* skip option */ + i -= TCP_OLEN_TIMESTAMP; + options += TCP_OLEN_TIMESTAMP; + break; + case TCP_OPT_SACK: + mptr.uint8 = c_tcp_opt_sack(context, mptr.uint8, + rohc_ntoh32(tcp->ack_number), opt_len, + (sack_block_t *) (options + 2)); + /* skip option */ + i -= opt_len; + options += opt_len; + break; + case TCP_OPT_SACK_PERMITTED: + /* COMPRESSED sack_permitted_list_item { + * } + */ + /* skip option */ + i -= TCP_OLEN_SACK_PERMITTED; + options += TCP_OLEN_SACK_PERMITTED; + break; + default: + rohc_comp_debug(context, "TCP option unknown = 0x%x\n", *options); + if(opt_type > 15) + { + rohc_comp_debug(context, "TCP invalid option = %d (0x%x)\n", + *options, *options); + goto error; + } + /* 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_lsb.UVALUE*8-16 ]; + * } + */ + memcpy(mptr.uint8, options, opt_len); + mptr.uint8[1] &= 0x7f; /* option_static = 0 */ + mptr.uint8 += opt_len; + /* skip option */ + i -= opt_len; + options += opt_len; + break; + } + } +#else /* init pointer to the begining of TCP options */ pBeginList = ( (unsigned char *) tcp ) + sizeof(tcphdr_t); /* copy all TCP options */ memcpy(mptr.uint8,pBeginList,options - pBeginList); /* update pointer */ mptr.uint8 += options - pBeginList; +#endif #if ROHC_EXTRA_DEBUG == 1 rohc_dump_packet(context->compressor->trace_callback, ROHC_TRACE_COMP, ROHC_TRACE_DEBUG, "debug_ptr", debug_ptr, @@ -3902,7 +4058,7 @@ tcp_opt_get_descr(opt_type), opt_type); /* determine the index of the TCP option */ - if(opt_type < MAX_TCP_OPTION_INDEX && tcp_options_index[opt_type] >= 0) + if(opt_type < TCP_LIST_ITEM_MAP_LEN && tcp_options_index[opt_type] >= 0) { /* TCP option got a reserved index */ opt_idx = tcp_options_index[opt_type]; === modified file 'src/decomp/d_tcp.c' --- src/decomp/d_tcp.c 2014-03-08 19:04:45 +0000 +++ src/decomp/d_tcp.c 2014-04-03 16:39:05 +0000 @@ -2547,8 +2547,7 @@ /* If TCP option list compression present */ if((remain_data[0] & 0x0f) != 0) { - const uint8_t *pBeginOptions; - const uint8_t *pBeginList; + const uint8_t *tcp_opts_indexes; uint8_t reserved; uint8_t PS; uint8_t present; @@ -2556,9 +2555,13 @@ uint8_t m; uint8_t i; uint8_t *tcp_options; +#if 0 /* TODO */ size_t opt_padding_len; +#endif size_t opts_full_len; size_t indexes_len; + uint8_t opt_type; + uint8_t opt_len; /* read number of XI item(s) in the compressed list */ reserved = remain_data[0] & 0xe0; @@ -2606,12 +2609,11 @@ indexes_len); goto error; } - pBeginList = remain_data; + tcp_opts_indexes = remain_data; remain_data += indexes_len; remain_len -= indexes_len; - /* save the begin of the item(s) */ - pBeginOptions = remain_data; + tcp_options = ((uint8_t *) tcp) + sizeof(tcphdr_t); /* for all item(s) in the list */ for(i = 0, opts_full_len = 0; i < m; ++i) @@ -2619,23 +2621,23 @@ /* if PS=1 indicating 8-bit XI field */ if(PS != 0) { - present = (*pBeginList) & 0x80; - opt_idx = (*pBeginList) & 0x0F; - ++pBeginList; + present = tcp_opts_indexes[0] & 0x80; + opt_idx = tcp_opts_indexes[0] & 0x0F; + tcp_opts_indexes++; } else { /* if odd position */ if(i & 1) { - present = (*pBeginList) & 0x08; - opt_idx = (*pBeginList) & 0x07; - ++pBeginList; + present = tcp_opts_indexes[0] & 0x08; + opt_idx = tcp_opts_indexes[0] & 0x07; + tcp_opts_indexes++; } else { - present = (*pBeginList) & 0x80; - opt_idx = ((*pBeginList) & 0x70) >> 4; + present = tcp_opts_indexes[0] & 0x80; + opt_idx = (tcp_opts_indexes[0] & 0x70) >> 4; } } rohc_decomp_debug(context, "TCP options list: XI #%u: item for " @@ -2651,330 +2653,305 @@ } tcp_context->is_tcp_opts_list_item_present[i] = true; - /* if known index (see RFC4996 page 27) */ - if(opt_idx <= TCP_INDEX_SACK) + rohc_decomp_debug(context, "TCP options list: XI #%u: item for " + "index %u is a known index\n", i, opt_idx); + + /* determine option type */ /* TODO: dedicated function */ + switch(opt_idx) { - uint8_t opt_type; - - rohc_decomp_debug(context, "TCP options list: XI #%u: item for " - "index %u is a known index\n", i, opt_idx); - - /* enough data for first byte of option? */ - if(remain_len < 1) + case TCP_INDEX_NOP: { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP dynamic " - "part: malformed TCP option items: only %zu " - "bytes available while at least 1 byte " - "required for next option\n", remain_len); - goto error; + rohc_decomp_debug(context, "TCP option NOP\n"); + opt_type = TCP_OPT_NOP; + opt_len = 1; + break; } - - /* retrieve option type */ - opt_type = remain_data[0]; - rohc_decomp_debug(context, "TCP option type 0x%02x (%u)\n", - opt_type, opt_type); - tcp_context->tcp_opts_list_struct[i] = opt_type; - opts_full_len++; - remain_data++; - remain_len--; - - /* save TCP option for this index */ - tcp_context->tcp_options_list[opt_idx] = opt_type; - - if(opt_type == TCP_OPT_EOL) + case TCP_INDEX_EOL: { - /* 1-byte EOL option */ rohc_decomp_debug(context, "TCP option EOL\n"); - tcp_context->tcp_opts_list_item_uncomp_length[i] = 1; - } - else if(opt_type == TCP_OPT_NOP) - { - /* 1-byte NOP option */ - rohc_decomp_debug(context, "TCP option NOP\n"); - tcp_context->tcp_opts_list_item_uncomp_length[i] = 1; - } - else - { - /* option with type + length + data */ - - uint8_t opt_len; - - /* enough data for the Length field? */ - if(remain_len < 1) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP dynamic " - "part: malformed TCP option items: only %zu " - "bytes available while at least 1 byte " - "required for next option\n", remain_len); - goto error; - } - - /* retrieve option length */ - opt_len = remain_data[0]; - rohc_decomp_debug(context, "TCP option is %u-byte long (type " - "and length fields included)\n", opt_len); + opt_type = TCP_OPT_EOL; + opt_len = remain_data[0] + 1; + if(remain_len < 1) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP dynamic " + "part: malformed TCP option items: only %zu " + "bytes available while at least %zu bytes " + "required for next option\n", remain_len, + sizeof(uint8_t)); + goto error; + } + memset(tcp_options + opts_full_len + 1, TCP_OPT_EOL, + remain_data[0]); + remain_data++; + remain_len--; + break; + } + case TCP_INDEX_MAXSEG: + { + opt_type = TCP_OPT_MAXSEG; + opt_len = TCP_OLEN_MAXSEG; + if(remain_len < sizeof(uint16_t)) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP dynamic " + "part: malformed TCP option items: only %zu " + "bytes available while at least %zu bytes " + "required for next option\n", remain_len, + sizeof(uint16_t)); + goto error; + } + memcpy(&tcp_context->tcp_option_maxseg, remain_data, + sizeof(uint16_t)); + memcpy(tcp_options + opts_full_len + 2, remain_data, + sizeof(uint16_t)); + remain_data += sizeof(uint16_t); + remain_len -= sizeof(uint16_t); + rohc_decomp_debug(context, "TCP option MAXSEG = %u (0x%x)\n", + rohc_ntoh16(tcp_context->tcp_option_maxseg), + rohc_ntoh16(tcp_context->tcp_option_maxseg)); + break; + } + case TCP_INDEX_WINDOW: + { + opt_type = TCP_OPT_WINDOW; + opt_len = TCP_OLEN_WINDOW; + if(remain_len < sizeof(uint8_t)) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP dynamic " + "part: malformed TCP option items: only %zu " + "bytes available while at least %zu bytes " + "required for next option\n", remain_len, + sizeof(uint8_t)); + goto error; + } + tcp_context->tcp_option_window = remain_data[0]; + tcp_options[opts_full_len + 2] = remain_data[0]; + remain_data++; + remain_len--; + rohc_decomp_debug(context, "TCP option WINDOW = %d\n", + tcp_context->tcp_option_window); + break; + } + case TCP_INDEX_TIMESTAMP: + { + const struct tcp_option_timestamp *const opt_ts = + (struct tcp_option_timestamp *) remain_data; + + rohc_decomp_debug(context, "TCP option SACK PERMITTED\n"); + opt_type = TCP_OPT_TIMESTAMP; + opt_len = TCP_OLEN_TIMESTAMP; + + if(remain_len < (sizeof(uint32_t) * 2)) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP dynamic " + "part: malformed TCP option items: only %zu " + "bytes available while at least %zu bytes " + "required for next option\n", remain_len, + sizeof(uint32_t) * 2); + goto error; + } + rohc_decomp_debug(context, "TCP option TIMESTAMP\n"); + tcp_context->tcp_option_timestamp.ts = opt_ts->ts; + tcp_context->tcp_option_timestamp.ts_reply = opt_ts->ts_reply; + rohc_lsb_set_ref(tcp_context->opt_ts_req_lsb_ctxt, + rohc_ntoh32(opt_ts->ts), false); + rohc_lsb_set_ref(tcp_context->opt_ts_reply_lsb_ctxt, + rohc_ntoh32(opt_ts->ts_reply), false); + memcpy(tcp_options + opts_full_len + 2, remain_data, sizeof(uint32_t) * 2); + remain_data += sizeof(uint32_t) * 2; + remain_len -= sizeof(uint32_t) * 2; + break; + } + case TCP_INDEX_SACK_PERMITTED: + { + rohc_decomp_debug(context, "TCP option SACK permitted\n"); + opt_type = TCP_OPT_SACK_PERMITTED; + opt_len = TCP_OLEN_SACK_PERMITTED; + break; + } + case TCP_INDEX_SACK: + { + const uint8_t *comp_sack_opt = remain_data; + uint8_t *uncomp_sack_opt = tcp_options + opts_full_len; + + remain_data = d_tcp_opt_sack(context, remain_data, + &uncomp_sack_opt, + rohc_ntoh32(tcp->ack_number)); + if(remain_data == NULL) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "failed to decompress " + "TCP SACK option\n"); + goto error; + } + remain_len -= remain_data - comp_sack_opt; + + opt_type = TCP_OPT_SACK; + opt_len = uncomp_sack_opt - (tcp_options + opts_full_len); + + tcp_context->tcp_option_sack_length = opt_len - 2; + rohc_decomp_debug(context, "TCP option SACK Length = 2 + %u\n", + tcp_context->tcp_option_sack_length); + if(tcp_context->tcp_option_sack_length > (8 * 4)) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "TCP dynamic part: " + "unexpected large %u-byte SACK option\n", + tcp_context->tcp_option_sack_length); + goto error; + } + memcpy(tcp_context->tcp_option_sackblocks, uncomp_sack_opt, + tcp_context->tcp_option_sack_length); + break; + } + default: /* generic options */ + { + uint8_t *save_opt; + + /* option type */ + if(remain_len < 1) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP dynamic " + "part: malformed TCP option items: only %zu " + "bytes available while at least 1 byte " + "required for next option\n", remain_len); + goto error; + } + opt_type = remain_data[0]; + remain_data++; + remain_len--; + + /* option length */ + if(remain_len < 1) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP dynamic " + "part: malformed TCP option items: only %zu " + "bytes available while at least 1 byte " + "required for next option\n", remain_len); + goto error; + } + opt_len = remain_data[0] & 0x7f; + remain_data++; + remain_len--; if(opt_len < 2) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, context->profile->id, "malformed TCP dynamic " - "part: malformed TCP option items: option " - "length should be at least 2 bytes, but is " - "only %u byte(s)\n", opt_len); - goto error; - } - tcp_context->tcp_opts_list_item_uncomp_length[i] = opt_len; - opts_full_len++; - remain_data++; - remain_len--; - - /* enough data for the remaining option data? */ - if(remain_len < ((size_t) (opt_len - 2))) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP dynamic " - "part: malformed TCP option items: only %zu " - "bytes available while at least %u bytes " - "required for next option\n", remain_len, - opt_len - 2); - goto error; - } - - switch(opt_type) - { - case TCP_OPT_MAXSEG: - if(opt_len != TCP_OLEN_MAXSEG) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP " - "dynamic part: malformed TCP option " - "items: TCP option MAXSEG is %u-byte " - "long instead of %u-byte long\n", - opt_len, TCP_OLEN_MAXSEG); - goto error; - } - memcpy(&tcp_context->tcp_option_maxseg, remain_data, 2); - rohc_decomp_debug(context, "TCP option MAXSEG = %d (0x%x)\n", - rohc_ntoh16(tcp_context->tcp_option_maxseg), - rohc_ntoh16(tcp_context->tcp_option_maxseg)); - break; - case TCP_OPT_WINDOW: - if(opt_len != TCP_OLEN_WINDOW) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP " - "dynamic part: malformed TCP option " - "items: TCP option WINDOW is %u-byte " - "long instead of %u-byte long\n", - opt_len, TCP_OLEN_WINDOW); - goto error; - } - tcp_context->tcp_option_window = remain_data[0]; - rohc_decomp_debug(context, "TCP option WINDOW = %d\n", - tcp_context->tcp_option_window); - break; - case TCP_OPT_SACK_PERMITTED: - if(opt_len != TCP_OLEN_SACK_PERMITTED) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP " - "dynamic part: malformed TCP option " - "items: TCP option SACK PERMITTED is " - "%u-byte long instead of %u-byte long\n", - opt_len, TCP_OLEN_SACK_PERMITTED); - goto error; - } - rohc_decomp_debug(context, "TCP option SACK PERMITTED\n"); - break; - case TCP_OPT_SACK: - tcp_context->tcp_option_sack_length = opt_len - 2; - rohc_decomp_debug(context, "TCP option SACK Length = 2 + %d\n", - tcp_context->tcp_option_sack_length); - if(tcp_context->tcp_option_sack_length > (8 * 4)) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "TCP dynamic " - "part: unexpected large %u-byte SACK " - "option\n", - tcp_context->tcp_option_sack_length); - goto error; - } - memcpy(tcp_context->tcp_option_sackblocks, remain_data, - tcp_context->tcp_option_sack_length); - break; - case TCP_OPT_TIMESTAMP: - { - const struct tcp_option_timestamp *const opt_ts = - (struct tcp_option_timestamp *) remain_data; - - if(opt_len != TCP_OLEN_TIMESTAMP) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP " - "dynamic part: malformed TCP option " - "items: TCP option TIMESTAMP is %u-byte " - "long instead of %u-byte long\n", - opt_len, TCP_OLEN_TIMESTAMP); - goto error; - } - rohc_decomp_debug(context, "TCP option TIMESTAMP\n"); - tcp_context->tcp_option_timestamp.ts = opt_ts->ts; - tcp_context->tcp_option_timestamp.ts_reply = opt_ts->ts_reply; - rohc_lsb_set_ref(tcp_context->opt_ts_req_lsb_ctxt, - rohc_ntoh32(opt_ts->ts), false); - rohc_lsb_set_ref(tcp_context->opt_ts_reply_lsb_ctxt, - rohc_ntoh32(opt_ts->ts_reply), false); - break; - } - default: - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "TCP options list: " - "ignore unknown %u-byte option type 0x%02x " - "(%u)\n", opt_len, opt_type, opt_type); - break; - } - - /* skip the remaining option data */ - opts_full_len += opt_len - 2; - remain_data += opt_len - 2; - remain_len -= opt_len - 2; - } - } - else /* unknown index */ - { - uint8_t opt_type; - uint8_t opt_len_lsb; - uint8_t *pValue; - - rohc_decomp_debug(context, "TCP options list: XI #%u: item for " - "index %u is an unknown index\n", i, opt_idx); - - /* enough data for first 2 bytes of option? */ - if(remain_len < 2) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP dynamic " - "part: malformed TCP option items: only %zu " - "bytes available while at least 2 bytes required " - "for next option\n", remain_len); - goto error; - } - - /* retrieve option type */ - opt_type = remain_data[0]; - tcp_context->tcp_opts_list_struct[i] = opt_type; - remain_data++; - remain_len--; - - /* retrieve option length */ - opt_len_lsb = remain_data[0] & 0x7f; - if(opt_len_lsb < 2) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP dynamic " - "part: malformed TCP option items: option length " - "should be at least 2 bytes, but is only %u " - "byte(s)\n", opt_len_lsb); - goto error; - } - tcp_context->tcp_opts_list_item_uncomp_length[i] = opt_len_lsb; - remain_data++; - remain_len--; - - /* was index already used? */ - if(tcp_context->tcp_options_list[opt_idx] == 0xff) - { - - /* index was never used before */ - /* save TCP option for this index */ - tcp_context->tcp_options_list[opt_idx] = opt_type; - tcp_context->tcp_options_offset[opt_idx] = - tcp_context->tcp_options_free_offset; - pValue = tcp_context->tcp_options_values + - tcp_context->tcp_options_free_offset; - /* save length (without option_static) */ - *pValue = opt_len_lsb - 2; - rohc_decomp_debug(context, "%d-byte TCP option of type %d\n", - *pValue, tcp_context->tcp_options_list[opt_idx]); - /* enough data for last bytes of option? */ - if(remain_len < (*pValue)) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP dynamic " - "part: malformed TCP option items: only %zu " - "bytes available while at least %u bytes " - "required for next option\n", remain_len, - (*pValue)); - goto error; - } - /* save value */ - memcpy(pValue + 1, remain_data, *pValue); - remain_data += *pValue; - remain_len -= *pValue; - /* update first free offset */ - tcp_context->tcp_options_free_offset += 1 + (*pValue); - if(tcp_context->tcp_options_free_offset >= MAX_TCP_OPT_SIZE) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "TCP options too large: " - "%u bytes while only %u are accepted\n", - tcp_context->tcp_options_free_offset, - MAX_TCP_OPT_SIZE); - goto error; - } - } - else /* index already used */ - { - /* verify the value with the recorded one */ - rohc_decomp_debug(context, "tcp_options_list[%u] = %d <=> %d\n", - opt_idx, - tcp_context->tcp_options_list[opt_idx], - opt_type); - if(tcp_context->tcp_options_list[opt_idx] != opt_type) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "unexpected TCP option " - "at index %u: 0x%02x received while 0x%02x " - "expected\n", opt_idx, opt_type, - tcp_context->tcp_options_list[opt_idx]); - goto error; - } - pValue = tcp_context->tcp_options_values + - tcp_context->tcp_options_offset[opt_idx]; - if((opt_len_lsb - 2) != (*pValue)) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP dynamic " - "part: unexpected TCP option with index %u: " - "option length in packet (%u) does not match " - "option length in context (%u)\n", opt_idx, - opt_len_lsb, (*pValue) + 2); - goto error; - } - if(memcmp(pValue + 1, remain_data, *pValue) != 0) - { - rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, - context->profile->id, "malformed TCP dynamic " - "part: unexpected TCP option with index %u: " - "option data in packet does not match option " - "option data in context\n", opt_idx); - goto error; - } - remain_data += *pValue; - remain_len -= *pValue; - } - } + "part: malformed TCP option items: option length " + "should be at least 2 bytes, but is only %u " + "byte(s)\n", opt_len); + goto error; + } + + /* was index already used? */ + if(tcp_context->tcp_options_list[opt_idx] == 0xff) + { + /* index was never used before */ + tcp_context->tcp_options_offset[opt_idx] = + tcp_context->tcp_options_free_offset; + save_opt = tcp_context->tcp_options_values + + tcp_context->tcp_options_free_offset; + /* save length (without option_static) */ + save_opt[0] = opt_len - 2; + rohc_decomp_debug(context, "%d-byte TCP option of type %d\n", + save_opt[0], opt_type); + /* enough data for last bytes of option? */ + if(remain_len < save_opt[0]) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP dynamic " + "part: malformed TCP option items: only %zu " + "bytes available while at least %u bytes " + "required for next option\n", remain_len, + save_opt[0]); + goto error; + } + /* save value */ + memcpy(save_opt + 1, remain_data, save_opt[0]); + memcpy(tcp_options + opts_full_len + 2, remain_data, save_opt[0]); + remain_data += save_opt[0]; + remain_len -= save_opt[0]; + /* update first free offset */ + tcp_context->tcp_options_free_offset += 1 + save_opt[0]; + if(tcp_context->tcp_options_free_offset >= MAX_TCP_OPT_SIZE) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "TCP options too large: " + "%u bytes while only %u are accepted\n", + tcp_context->tcp_options_free_offset, + MAX_TCP_OPT_SIZE); + goto error; + } + } + else /* index already used */ + { + /* verify the value with the recorded one */ + rohc_decomp_debug(context, "tcp_options_list[%u] = %d <=> %d\n", + opt_idx, tcp_context->tcp_options_list[opt_idx], + opt_type); + if(tcp_context->tcp_options_list[opt_idx] != opt_type) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "unexpected TCP option " + "at index %u: 0x%02x received while 0x%02x " + "expected\n", opt_idx, opt_type, + tcp_context->tcp_options_list[opt_idx]); + goto error; + } + save_opt = tcp_context->tcp_options_values + + tcp_context->tcp_options_offset[opt_idx]; + if((opt_len - 2) != save_opt[0]) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP dynamic " + "part: unexpected TCP option with index %u: " + "option length in packet (%u) does not match " + "option length in context (%u)\n", opt_idx, + opt_len, save_opt[0] + 2); + goto error; + } + if(memcmp(save_opt + 1, remain_data, save_opt[0]) != 0) + { + rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, + context->profile->id, "malformed TCP dynamic " + "part: unexpected TCP option with index %u: " + "option data in packet does not match option " + "option data in context\n", opt_idx); + goto error; + } + memcpy(tcp_options + opts_full_len + 2, remain_data, save_opt[0]); + remain_data += save_opt[0]; + remain_len -= save_opt[0]; + } + break; + } + } + rohc_decomp_debug(context, "TCP option type 0x%02x (%u)\n", + opt_type, opt_type); + tcp_options[opts_full_len] = opt_type; + rohc_decomp_debug(context, "TCP option is %u-byte long (type " + "and length fields included)\n", opt_len); + tcp_options[opts_full_len + 1] = opt_len; + opts_full_len += opt_len; + + /* save TCP option for this index */ + tcp_context->tcp_opts_list_struct[i] = opt_type; + tcp_context->tcp_options_list[opt_idx] = opt_type; + tcp_context->tcp_opts_list_item_uncomp_length[i] = opt_len; } memset(tcp_context->tcp_opts_list_struct + m, 0xff, 16 - m); - /* copy TCP options from the ROHC packet after the TCP base header */ - rohc_decomp_debug(context, "append %zu bytes of TCP options to the TCP " + rohc_decomp_debug(context, "%zu bytes of TCP options appended to the TCP " "base header\n", opts_full_len); - tcp_options = ((uint8_t *) tcp) + sizeof(tcphdr_t); - memcpy(tcp_options, pBeginOptions, opts_full_len); /* add padding after TCP options (they must be aligned on 32-bit words) */ +#if 0 + /* TODO: should not be required anymore */ opt_padding_len = sizeof(uint32_t) - (opts_full_len % sizeof(uint32_t)); opt_padding_len %= sizeof(uint32_t); for(i = 0; i < opt_padding_len; i++) @@ -2983,6 +2960,7 @@ tcp_options[opts_full_len + i] = TCP_OPT_EOL; } opts_full_len += opt_padding_len; +#endif assert((opts_full_len % sizeof(uint32_t)) == 0); /* print TCP options */