/** * @brief Parse the static chain of the IR packet * * @param context The decompression context * @param rohc_packet The remaining part of the ROHC packet * @param rohc_length The remaining length (in bytes) of the ROHC packet * @param[out] bits The bits extracted from the static chain * @param[out] parsed_len The length (in bytes) of static chain in case of success * @return true in the static chain was successfully parsed, * false if the ROHC packet was malformed */ bool tcp_parse_static_chain(const struct rohc_decomp_ctxt *const context, const uint8_t *const rohc_packet, const size_t rohc_length, struct rohc_tcp_extr_bits *const bits, size_t *const parsed_len) { const uint8_t *remain_data = rohc_packet; size_t remain_len = rohc_length; size_t ip_hdrs_nr; uint8_t protocol; int ret; (*parsed_len) = 0; /* parse static IP part (IPv4/IPv6 headers and extension headers) */ ip_hdrs_nr = 0; do { struct rohc_tcp_extr_ip_bits *const ip_bits = &(bits->ip[ip_hdrs_nr]); ret = tcp_parse_static_ip(context, remain_data, remain_len, ip_bits, &protocol); if(ret < 0) { rohc_decomp_warn(context, "malformed ROHC packet: malformed IP " "static part"); goto error; } rohc_decomp_debug(context, "IPv%u static part is %d-byte length", ip_bits->version, ret); assert(remain_len >= ((size_t) ret)); remain_data += ret; remain_len -= ret; (*parsed_len) += ret; ip_hdrs_nr++; } while(rohc_is_tunneling(protocol) && ip_hdrs_nr < ROHC_TCP_MAX_IP_HDRS); if(rohc_is_tunneling(protocol) && ip_hdrs_nr >= ROHC_TCP_MAX_IP_HDRS) { rohc_decomp_warn(context, "too many IP headers to decompress"); goto error; } bits->ip_nr = ip_hdrs_nr; /* parse TCP static part */ ret = tcp_parse_static_tcp(context, remain_data, remain_len, bits); if(ret < 0) { rohc_decomp_warn(context, "malformed ROHC packet: malformed TCP static " "part"); goto error; } rohc_decomp_debug(context, "TCP static part is %d-byte length", ret); assert(remain_len >= ((size_t) ret)); #ifndef __clang_analyzer__ /* silent warning about dead in/decrement */ remain_data += ret; remain_len -= ret; #endif (*parsed_len) += ret; return true; error: return false; }
/** * @brief Parse the LSBs bits of one of the TS echo request/reply fields * * See RFC4996 page 65 * * @param context The decompression context * @param data The data to decode * @param data_len The length of the data to decode * @param[out] ts_field The information of TS option field extracted from packet * @return The number of data bytes parsed, * -1 if data is malformed */ int d_tcp_ts_lsb_parse(const struct rohc_decomp_ctxt *const context, const uint8_t *const data, const size_t data_len, struct rohc_lsb_field32 *const ts_field) { const uint8_t *remain_data; size_t remain_len; remain_data = data; remain_len = data_len; if(remain_len < 1) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for TS LSB: only %zu bytes available " "while at least 1 byte required", remain_len); goto error; } if((remain_data[0] & 0x80) == 0) { /* discriminator '0' */ rohc_decomp_debug(context, "TCP TS option: TS field is 1-byte long"); ts_field->bits = remain_data[0]; ts_field->bits_nr = 7; ts_field->p = ROHC_LSB_SHIFT_TCP_TS_1B; remain_len--; } else if((remain_data[0] & 0x40) == 0) { /* discriminator '10' */ rohc_decomp_debug(context, "TCP TS option: TS field is 2-byte long"); if(remain_len < 2) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for TS LSB: only %zu bytes available " "while at least 2 bytes required", remain_len); goto error; } ts_field->bits = (remain_data[0] & 0x3f) << 8; ts_field->bits |= remain_data[1]; ts_field->bits_nr = 14; ts_field->p = ROHC_LSB_SHIFT_TCP_TS_2B; remain_len -= 2; } else if((remain_data[0] & 0x20) == 0) { /* discriminator '110' */ rohc_decomp_debug(context, "TCP TS option: TS field is 3-byte long"); if(remain_len < 3) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for TS LSB: only %zu bytes available " "while at least 3 bytes required", remain_len); goto error; } ts_field->bits = (remain_data[0] & 0x1f) << 16; ts_field->bits |= remain_data[1] << 8; ts_field->bits |= remain_data[2]; ts_field->bits_nr = 21; ts_field->p = ROHC_LSB_SHIFT_TCP_TS_3B; remain_len -= 3; } else { /* discriminator '111' */ rohc_decomp_debug(context, "TCP TS option: TS field is 4-byte long"); if(remain_len < 4) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for TS LSB: only %zu bytes available " "while at least 4 bytes required", remain_len); goto error; } ts_field->bits = (remain_data[0] & 0x1f) << 24; ts_field->bits |= remain_data[1] << 16; ts_field->bits |= remain_data[2] << 8; ts_field->bits |= remain_data[3]; ts_field->bits_nr = 29; ts_field->p = ROHC_LSB_SHIFT_TCP_TS_4B; remain_len -= 4; } return (data_len - remain_len); error: return -1; }
/** * @brief Decode the static IPv6 option header of the rohc packet. * * @param context The decompression context * @param[out] ip_bits The bits extracted from the IP part of the static chain * @param[out] opt_context The specific IPv6 option decompression context * @param protocol The protocol of the IPv6 option * @param rohc_packet The remaining part of the ROHC packet * @param rohc_length The remaining length (in bytes) of the ROHC packet * @return The length of static IP header in case of success, * -1 if an error occurs */ static int tcp_parse_static_ipv6_option(const struct rohc_decomp_ctxt *const context, struct rohc_tcp_extr_ip_bits *const ip_bits, ip_option_context_t *const opt_context, const uint8_t protocol, const uint8_t *const rohc_packet, const size_t rohc_length) { const ip_opt_static_t *ip_opt_static; size_t size; rohc_decomp_debug(context, "parse static part of the IPv6 extension header " "'%s' (%u)", rohc_get_ip_proto_descr(protocol), protocol); /* at least 2 bytes required to read the next header and length */ if(rohc_length < sizeof(ip_opt_static_t)) { rohc_decomp_warn(context, "malformed ROHC packet: too short for the " "IP extension header static part"); goto error; } ip_opt_static = (ip_opt_static_t *) rohc_packet; opt_context->proto = protocol; opt_context->nh_proto = ip_opt_static->next_header; switch(protocol) { case ROHC_IPPROTO_HOPOPTS: // IPv6 Hop-by-Hop options { size = sizeof(ip_hop_opt_static_t); if(rohc_length < size) { rohc_decomp_warn(context, "malformed ROHC packet: too short for " "the static part of the IPv6 Hop-by-Hop option"); goto error; } opt_context->len = ipv6_opt_get_length((struct ipv6_opt *) ip_opt_static); rohc_decomp_debug(context, " IPv6 option Hop-by-Hop is %zu-byte long", opt_context->len); break; } case ROHC_IPPROTO_ROUTING: // IPv6 routing header { const ip_rout_opt_static_t *const ip_rout_opt_static = (ip_rout_opt_static_t *) ip_opt_static; size = ipv6_opt_get_length((struct ipv6_opt *) ip_rout_opt_static); if(rohc_length < size) { rohc_decomp_warn(context, "malformed ROHC packet: too short for " "the static part of the IPv6 Routing option"); goto error; } opt_context->len = size; opt_context->generic.data_len = size - 2; memcpy(&opt_context->generic.data, &ip_rout_opt_static->value, opt_context->generic.data_len); rohc_decomp_debug(context, " IPv6 option Routing is %zu-byte long", opt_context->len); break; } case ROHC_IPPROTO_GRE: /* TODO: GRE not yet supported */ { rohc_decomp_warn(context, "GRE extension header not supported yet"); goto error; } case ROHC_IPPROTO_DSTOPTS: // IPv6 destination options { size = sizeof(ip_dest_opt_static_t); if(rohc_length < size) { rohc_decomp_warn(context, "malformed ROHC packet: too short for " "the static part of the IPv6 Destination option"); goto error; } opt_context->len = ipv6_opt_get_length((struct ipv6_opt *) ip_opt_static); rohc_decomp_debug(context, " IPv6 option Destination is %zu-byte long", opt_context->len); break; } case ROHC_IPPROTO_MINE: /* TODO: MINE not yet supported */ { rohc_decomp_warn(context, "GRE extension header not supported yet"); goto error; } case ROHC_IPPROTO_AH: /* TODO: AH not yet supported */ { rohc_decomp_warn(context, "GRE extension header not supported yet"); goto error; } default: { goto error; } } ip_bits->opts_len += opt_context->len; rohc_decomp_dump_buf(context, "IPv6 option static part", rohc_packet, size); return size; error: return -1; }
/** * @brief Decode the static IP header of the rohc packet. * * @param context The decompression context * @param rohc_packet The remaining part of the ROHC packet * @param rohc_length The remaining length (in bytes) of the ROHC packet * @param[out] ip_bits The bits extracted from the IP part of the static chain * @param[out] nh_proto The next header protocol of the last extension header * @return The length of static IP header in case of success, * -1 if an error occurs */ static int tcp_parse_static_ip(const struct rohc_decomp_ctxt *const context, const uint8_t *const rohc_packet, const size_t rohc_length, struct rohc_tcp_extr_ip_bits *const ip_bits, uint8_t *const nh_proto) { const uint8_t *remain_data = rohc_packet; size_t remain_len = rohc_length; size_t read = 0; int ret; rohc_decomp_debug(context, "parse IP static part"); /* at least 1 byte required to read the version flag */ if(remain_len < 1) { rohc_decomp_warn(context, "malformed ROHC packet: too short for the " "version flag of the IP static part"); goto error; } /* parse IPv4 static part or IPv6 static part? */ if(GET_BIT_7(remain_data) == 0) { const ipv4_static_t *const ipv4_static = (ipv4_static_t *) remain_data; rohc_decomp_debug(context, " IPv4 static part"); ip_bits->version = IPV4; if(remain_len < sizeof(ipv4_static_t)) { rohc_decomp_warn(context, "malformed ROHC packet: too short for the " "IPv4 static part"); goto error; } ip_bits->proto = ipv4_static->protocol; ip_bits->proto_nr = 8; *nh_proto = ip_bits->proto; memcpy(ip_bits->saddr, &ipv4_static->src_addr, sizeof(uint32_t)); ip_bits->saddr_nr = 32; memcpy(ip_bits->daddr, &ipv4_static->dst_addr, sizeof(uint32_t)); ip_bits->daddr_nr = 32; /* IP extension headers not supported for IPv4 */ ip_bits->opts_nr = 0; ip_bits->opts_len = 0; read += sizeof(ipv4_static_t); #ifndef __clang_analyzer__ /* silent warning about dead in/decrement */ remain_data += sizeof(ipv4_static_t); remain_len -= sizeof(ipv4_static_t); #endif } else { rohc_decomp_debug(context, " IPv6 static part"); ip_bits->version = IPV6; /* static 1 or static 2 variant? */ if(GET_BIT_4(remain_data) == 0) { const ipv6_static1_t *const ipv6_static1 = (ipv6_static1_t *) remain_data; if(remain_len < sizeof(ipv6_static1_t)) { rohc_decomp_warn(context, "malformed ROHC packet: too short for " "the IPv6 static part"); goto error; } ip_bits->flowid = 0; ip_bits->flowid_nr = 20; ip_bits->proto = ipv6_static1->next_header; ip_bits->proto_nr = 8; memcpy(ip_bits->saddr, &ipv6_static1->src_addr, sizeof(uint32_t) * 4); ip_bits->saddr_nr = 128; memcpy(ip_bits->daddr, &ipv6_static1->dst_addr, sizeof(uint32_t) * 4); ip_bits->daddr_nr = 128; read += sizeof(ipv6_static1_t); remain_data += sizeof(ipv6_static1_t); remain_len -= sizeof(ipv6_static1_t); } else { const ipv6_static2_t *const ipv6_static2 = (ipv6_static2_t *) remain_data; if(remain_len < sizeof(ipv6_static2_t)) { rohc_decomp_warn(context, "malformed ROHC packet: too short for " "the IPv6 static part"); goto error; } ip_bits->flowid = (ipv6_static2->flow_label1 << 16) | rohc_ntoh16(ipv6_static2->flow_label2); assert((ip_bits->flowid & 0xfffff) == ip_bits->flowid); rohc_decomp_debug(context, " IPv6 flow label = 0x%05x", ip_bits->flowid); ip_bits->flowid_nr = 20; ip_bits->proto = ipv6_static2->next_header; ip_bits->proto_nr = 8; memcpy(ip_bits->saddr, &ipv6_static2->src_addr, sizeof(uint32_t) * 4); ip_bits->saddr_nr = 128; memcpy(ip_bits->daddr, &ipv6_static2->dst_addr, sizeof(uint32_t) * 4); ip_bits->daddr_nr = 128; read += sizeof(ipv6_static2_t); remain_data += sizeof(ipv6_static2_t); remain_len -= sizeof(ipv6_static2_t); } *nh_proto = ip_bits->proto; ip_bits->opts_nr = 0; ip_bits->opts_len = 0; while(rohc_is_ipv6_opt(*nh_proto)) { ip_option_context_t *opt; if(ip_bits->opts_nr >= ROHC_TCP_MAX_IP_EXT_HDRS) { rohc_decomp_warn(context, "too many IPv6 extension headers"); goto error; } opt = &(ip_bits->opts[ip_bits->opts_nr]); ret = tcp_parse_static_ipv6_option(context, ip_bits, opt, *nh_proto, remain_data, remain_len); if(ret < 0) { rohc_decomp_warn(context, "malformed ROHC packet: malformed " "IPv6 static option part"); goto error; } rohc_decomp_debug(context, "IPv6 static option part is %d-byte length", ret); assert(remain_len >= ((size_t) ret)); read += ret; remain_data += ret; remain_len -= ret; *nh_proto = opt->nh_proto; ip_bits->opts_nr++; } rohc_decomp_debug(context, "IPv6 header is followed by %zu extension " "headers", ip_bits->opts_nr); } rohc_decomp_dump_buf(context, "IP static part", rohc_packet, read); return read; error: return -1; }
/** * @brief Decode the TCP dynamic part of the ROHC packet. * * @param context The decompression context * @param rohc_packet The remaining part of the ROHC packet * @param rohc_length The remaining length (in bytes) of the ROHC packet * @param[out] bits The bits extracted from the TCP part of the dynamic chain * @return The number of bytes read in the ROHC packet, * -1 in case of failure */ static int tcp_parse_dynamic_tcp(const struct rohc_decomp_ctxt *const context, const uint8_t *const rohc_packet, const size_t rohc_length, struct rohc_tcp_extr_bits *const bits) { const tcp_dynamic_t *tcp_dynamic; const uint8_t *remain_data = rohc_packet; size_t remain_len = rohc_length; int ret; rohc_decomp_debug(context, "parse TCP dynamic part"); /* check the minimal length to decode the TCP dynamic part */ if(remain_len < sizeof(tcp_dynamic_t)) { rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu bytes " "available while at least %zu bytes required for " "mandatory fields of the TCP dynamic part", remain_len, sizeof(tcp_dynamic_t)); goto error; } tcp_dynamic = (tcp_dynamic_t *) remain_data; remain_data += sizeof(tcp_dynamic_t); remain_len -= sizeof(tcp_dynamic_t); rohc_decomp_debug(context, "TCP res_flags = %d, ecn_flags = %d, " "rsf_flags = %d, URG = %d, ACK = %d, PSH = %d, ack_zero = %u", tcp_dynamic->tcp_res_flags, tcp_dynamic->tcp_ecn_flags, tcp_dynamic->rsf_flags, tcp_dynamic->urg_flag, tcp_dynamic->ack_flag, tcp_dynamic->psh_flag, tcp_dynamic->ack_zero); /* retrieve the TCP flags from the ROHC packet */ bits->ecn_used_bits = tcp_dynamic->ecn_used; bits->ecn_used_bits_nr = 1; bits->res_flags_bits = tcp_dynamic->tcp_res_flags; bits->res_flags_bits_nr = 4; bits->ecn_flags_bits = tcp_dynamic->tcp_ecn_flags; bits->ecn_flags_bits_nr = 2; bits->urg_flag_bits = tcp_dynamic->urg_flag; bits->urg_flag_bits_nr = 1; bits->ack_flag_bits = tcp_dynamic->ack_flag; bits->ack_flag_bits_nr = 1; bits->psh_flag_bits = tcp_dynamic->psh_flag; bits->psh_flag_bits_nr = 1; bits->rsf_flags_bits = tcp_dynamic->rsf_flags; bits->rsf_flags_bits_nr = 3; /* retrieve the TCP sequence number from the ROHC packet */ bits->seq.bits = rohc_ntoh32(tcp_dynamic->seq_num); bits->seq.bits_nr = 32; rohc_decomp_debug(context, "%zu bits of TCP sequence number 0x%08x", bits->seq.bits_nr, bits->seq.bits); /* retrieve the MSN from the ROHC packet */ bits->msn.bits = rohc_ntoh16(tcp_dynamic->msn); bits->msn.bits_nr = 16; rohc_decomp_debug(context, "%zu bits of MSN 0x%04x", bits->msn.bits_nr, bits->msn.bits); /* optional ACK number */ if(tcp_dynamic->ack_zero == 1) { bits->ack.bits = 0; bits->ack.bits_nr = 32; /* TODO */ } else { if(remain_len < sizeof(uint32_t)) { rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu " "bytes available while at least %zu bytes required " "for the ACK number", remain_len, sizeof(uint32_t)); goto error; } memcpy(&(bits->ack.bits), remain_data, sizeof(uint32_t)); bits->ack.bits = rohc_ntoh32(bits->ack.bits); bits->ack.bits_nr = 32; remain_data += sizeof(uint32_t); remain_len -= sizeof(uint32_t); if(bits->ack_flag_bits == 0) { rohc_decomp_debug(context, "ACK flag not set, but ACK number was " "transmitted anyway"); } } rohc_decomp_debug(context, "seq_number = 0x%08x, ack_number = 0x%08x", bits->seq.bits, bits->ack.bits); /* window */ if(remain_len < sizeof(uint16_t)) { rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu bytes " "available while at least %zu bytes required for the " "window", remain_len, sizeof(uint16_t)); goto error; } memcpy(&(bits->window.bits), remain_data, sizeof(uint16_t)); bits->window.bits = rohc_ntoh16(bits->window.bits); bits->window.bits_nr = 16; remain_data += sizeof(uint16_t); remain_len -= sizeof(uint16_t); rohc_decomp_debug(context, "TCP window = 0x%04x", bits->window.bits); /* checksum */ if(remain_len < sizeof(uint16_t)) { rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu bytes " "available while at least %zu bytes required for the " "checksum", remain_len, sizeof(uint16_t)); goto error; } memcpy(&(bits->tcp_check), remain_data, sizeof(uint16_t)); bits->tcp_check = rohc_ntoh16(bits->tcp_check); remain_data += sizeof(uint16_t); remain_len -= sizeof(uint16_t); rohc_decomp_debug(context, "TCP checksum = 0x%04x", bits->tcp_check); /* URG pointer */ if(tcp_dynamic->urp_zero == 1) { bits->urg_ptr.bits = 0; bits->urg_ptr.bits_nr = 16; } else { if(remain_len < sizeof(uint16_t)) { rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu " "bytes available while at least %zu bytes required " "for the URG pointer", remain_len, sizeof(uint16_t)); goto error; } memcpy(&(bits->urg_ptr.bits), remain_data, sizeof(uint16_t)); bits->urg_ptr.bits = rohc_ntoh16(bits->urg_ptr.bits); bits->urg_ptr.bits_nr = 16; remain_data += sizeof(uint16_t); remain_len -= sizeof(uint16_t); } rohc_decomp_debug(context, "TCP urg_ptr = 0x%04x", bits->urg_ptr.bits); /* ACK stride */ if(tcp_dynamic->ack_stride_flag == 0) { bits->ack_stride.bits_nr = 0; rohc_decomp_debug(context, "TCP ack_stride not present"); } else { if(remain_len < sizeof(uint16_t)) { rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu " "bytes available while at least %zu bytes required " "for the ACK stride", remain_len, sizeof(uint16_t)); goto error; } memcpy(&(bits->ack_stride.bits), remain_data, sizeof(uint16_t)); bits->ack_stride.bits = rohc_ntoh16(bits->ack_stride.bits); bits->ack_stride.bits_nr = 16; remain_data += sizeof(uint16_t); remain_len -= sizeof(uint16_t); rohc_decomp_debug(context, "TCP ack_stride = 0x%04x", bits->ack_stride.bits); } #if 0 /* TODO: handle ACK stride */ if(tcp_context->ack_stride != 0) { // Calculate the Ack Number residue tcp_context->ack_num_residue = tcp_context->ack_num % tcp_context->ack_stride; } rohc_decomp_debug(context, "TCP ack_stride = 0x%04x, ack_number_residue = " "0x%04x", tcp_context->ack_stride, tcp_context->ack_num_residue); #endif /* parse the compressed list of TCP options */ ret = d_tcp_parse_tcp_opts_list_item(context, remain_data, remain_len, true, &bits->tcp_opts); if(ret < 0) { rohc_decomp_warn(context, "failed to parse optional compressed list " "of TCP options"); goto error; } rohc_decomp_debug(context, "compressed list of TCP options = %d bytes", ret); #ifndef __clang_analyzer__ /* silent warning about dead in/decrement */ remain_data += ret; #endif remain_len -= ret; assert(remain_len <= rohc_length); rohc_dump_buf(context->decompressor->trace_callback, context->decompressor->trace_callback_priv, ROHC_TRACE_DECOMP, ROHC_TRACE_DEBUG, "TCP dynamic part", (const uint8_t *const ) tcp_dynamic, rohc_length - remain_len); return (rohc_length - remain_len); error: return -1; }
/** * @brief Decode the dynamic IPv6 option header of the rohc packet. * * @param context The decompression context * @param opt_context The specific IPv6 option decompression context * @param protocol The IPv6 protocol option * @param rohc_packet The remaining part of the ROHC packet * @param rohc_length The remaining length (in bytes) of the ROHC packet * @return The length of dynamic IP header * 0 if an error occurs */ static int tcp_parse_dynamic_ipv6_option(const struct rohc_decomp_ctxt *const context, ipv6_option_context_t *const opt_context, const uint8_t protocol, const uint8_t *const rohc_packet, const size_t rohc_length) { size_t remain_len = rohc_length; size_t size = 0; assert(context != NULL); assert(rohc_packet != NULL); rohc_decomp_debug(context, "parse dynamic part of IPv6 extension header"); switch(protocol) { case ROHC_IPPROTO_HOPOPTS: // IPv6 Hop-by-Hop options case ROHC_IPPROTO_DSTOPTS: // IPv6 destination options { size += ((opt_context->generic.length + 1) << 3) - 2; if(remain_len < size) { rohc_decomp_warn(context, "malformed IPv6 option: malformed " "option %u: %zu bytes available while %zu bytes " "required", protocol, remain_len, size); goto error; } memcpy(opt_context->generic.data, rohc_packet, size); #ifndef __clang_analyzer__ /* silent warning about dead in/decrement */ remain_len -= size; #endif break; } case ROHC_IPPROTO_ROUTING: // IPv6 routing header { break; } case ROHC_IPPROTO_GRE: /* TODO: GRE not yet supported */ { rohc_decomp_warn(context, "GRE extension header not supported yet"); goto error; } case ROHC_IPPROTO_MINE: /* TODO: MINE not yet supported */ { rohc_decomp_warn(context, "MINE extension header not supported yet"); goto error; } case ROHC_IPPROTO_AH: /* TODO: AH not yet supported */ { rohc_decomp_warn(context, "AH extension header not supported yet"); goto error; } default: { break; } } #if ROHC_EXTRA_DEBUG == 1 rohc_dump_buf(context->decompressor->trace_callback, context->decompressor->trace_callback_priv, ROHC_TRACE_DECOMP, ROHC_TRACE_DEBUG, "IPv6 option dynamic part", rohc_packet, size); #endif return size; error: return -1; }
/** * @brief Decode the dynamic IP header of the rohc packet. * * @param context The decompression context * @param rohc_packet The remaining part of the ROHC packet * @param rohc_length The remaining length (in bytes) of the ROHC packet * @param[out] ip_bits The bits extracted from the IP part of the dynamic chain * @return The length of dynamic IP header in case of success, * -1 if an error occurs */ static int tcp_parse_dynamic_ip(const struct rohc_decomp_ctxt *const context, const uint8_t *const rohc_packet, const size_t rohc_length, struct rohc_tcp_extr_ip_bits *const ip_bits) { const uint8_t *remain_data = rohc_packet; size_t remain_len = rohc_length; size_t size = 0; int ret; rohc_decomp_debug(context, "parse IP dynamic part"); if(ip_bits->version == IPV4) { const ipv4_dynamic1_t *const ipv4_dynamic1 = (ipv4_dynamic1_t *) remain_data; if(remain_len < sizeof(ipv4_dynamic1_t)) { rohc_decomp_warn(context, "malformed ROHC packet: too short for " "IPv4 dynamic part"); goto error; } ip_bits->df = ipv4_dynamic1->df; ip_bits->df_nr = 1; ip_bits->id_behavior = ipv4_dynamic1->ip_id_behavior; ip_bits->id_behavior_nr = 2; rohc_decomp_debug(context, "ip_id_behavior = %d", ip_bits->id_behavior); ip_bits->dscp_bits = ipv4_dynamic1->dscp; ip_bits->dscp_bits_nr = 6; ip_bits->ecn_flags_bits = ipv4_dynamic1->ip_ecn_flags; ip_bits->ecn_flags_bits_nr = 2; ip_bits->ttl_hl.bits = ipv4_dynamic1->ttl_hopl; ip_bits->ttl_hl.bits_nr = 8; rohc_decomp_debug(context, "DSCP = 0x%x, ip_ecn_flags = %d, " "ttl_hopl = 0x%x", ip_bits->dscp_bits, ip_bits->ecn_flags_bits, ip_bits->ttl_hl.bits); // cf RFC4996 page 60/61 ip_id_enc_dyn() if(ipv4_dynamic1->ip_id_behavior != IP_ID_BEHAVIOR_ZERO) { const ipv4_dynamic2_t *const ipv4_dynamic2 = (ipv4_dynamic2_t *) remain_data; if(remain_len < sizeof(ipv4_dynamic2_t)) { rohc_decomp_warn(context, "malformed ROHC packet: too short for " "IPv4 dynamic part"); goto error; } ip_bits->id.bits = rohc_ntoh16(ipv4_dynamic2->ip_id); ip_bits->id.bits_nr = 16; rohc_decomp_debug(context, "IP-ID = 0x%04x", ip_bits->id.bits); size += sizeof(ipv4_dynamic2_t); #ifndef __clang_analyzer__ /* silent warning about dead in/decrement */ remain_data += sizeof(ipv4_dynamic2_t); remain_len -= sizeof(ipv4_dynamic2_t); #endif } else { size += sizeof(ipv4_dynamic1_t); #ifndef __clang_analyzer__ /* silent warning about dead in/decrement */ remain_data += sizeof(ipv4_dynamic1_t); remain_len -= sizeof(ipv4_dynamic1_t); #endif } } else { const ipv6_dynamic_t *const ipv6_dynamic = (ipv6_dynamic_t *) remain_data; uint8_t protocol; size_t opts_nr; if(remain_len < sizeof(ipv6_dynamic_t)) { rohc_decomp_warn(context, "malformed ROHC packet: too short for " "IPv6 dynamic part"); goto error; } ip_bits->dscp_bits = ipv6_dynamic->dscp; ip_bits->dscp_bits_nr = 6; ip_bits->ecn_flags_bits = ipv6_dynamic->ip_ecn_flags; ip_bits->ecn_flags_bits_nr = 2; ip_bits->ttl_hl.bits = ipv6_dynamic->ttl_hopl; ip_bits->ttl_hl.bits_nr = 8; ip_bits->id_behavior = IP_ID_BEHAVIOR_RAND; ip_bits->id_behavior_nr = 2; size += sizeof(ipv6_dynamic_t); remain_data += sizeof(ipv6_dynamic_t); remain_len -= sizeof(ipv6_dynamic_t); rohc_decomp_debug(context, "parse the dynamic parts of the %zu IPv6 " "extension headers", ip_bits->opts_nr); assert(ip_bits->proto_nr == 8); protocol = ip_bits->proto; for(opts_nr = 0; opts_nr < ip_bits->opts_nr; opts_nr++) { ipv6_option_context_t *const opt = &(ip_bits->opts[opts_nr]); ret = tcp_parse_dynamic_ipv6_option(context, opt, protocol, remain_data, remain_len); if(ret < 0) { rohc_decomp_warn(context, "malformed ROHC packet: malformed " "IPv6 dynamic option part"); goto error; } rohc_decomp_debug(context, "IPv6 dynamic option part is %d-byte " "length", ret); assert(remain_len >= ((size_t) ret)); size += ret; remain_data += ret; remain_len -= ret; protocol = opt->generic.next_header; } } rohc_dump_buf(context->decompressor->trace_callback, context->decompressor->trace_callback_priv, ROHC_TRACE_DECOMP, ROHC_TRACE_DEBUG, "IP dynamic part", rohc_packet, size); return size; error: return -1; }