/** * @brief Decode the TCP static 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 CO packet * @return The number of bytes read in the ROHC packet, * -1 in case of failure */ static int tcp_parse_static_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_static_t *tcp_static; assert(rohc_packet != NULL); rohc_decomp_debug(context, "parse TCP static part"); /* check the minimal length to decode the TCP static part */ if(rohc_length < sizeof(tcp_static_t)) { rohc_decomp_warn(context, "ROHC packet too small (len = %zu)", rohc_length); goto error; } rohc_decomp_dump_buf(context, "TCP static part", rohc_packet, sizeof(tcp_static_t)); tcp_static = (tcp_static_t *) rohc_packet; /* TCP source port */ bits->src_port = rohc_ntoh16(tcp_static->src_port); bits->src_port_nr = 16; rohc_decomp_debug(context, "TCP source port = %u", bits->src_port); /* TCP destination port */ bits->dst_port = rohc_ntoh16(tcp_static->dst_port); bits->dst_port_nr = 16; rohc_decomp_debug(context, "TCP dest port = %u", bits->dst_port); /* number of bytes read from the packet */ rohc_decomp_debug(context, "TCP static part is %zu-byte long", sizeof(tcp_static_t)); return sizeof(tcp_static_t); error: return -1; }
/** * @brief Decompress the 16-bit given value, according to the indicator * * @param rohc_data The ROHC data to parse * @param rohc_len The length of the ROHC data to parse (in bytes) * @param indicator The indicator of compression * @param[out] lsb The LSB bits extracted from the ROHC packet * @return The length (in bytes) of the compressed value, * -1 if ROHC data is malformed */ int d_static_or_irreg16(const uint8_t *const rohc_data, const size_t rohc_len, const int indicator, struct rohc_lsb_field16 *const lsb) { size_t length = 0; if(indicator == 1) { if(rohc_len < 2) { goto error; } memcpy(&(lsb->bits), rohc_data, sizeof(uint16_t)); lsb->bits = rohc_ntoh16(lsb->bits); lsb->bits_nr = 16; length += sizeof(uint16_t); } return length; error: return -1; }
/** * @brief Decompress the IP-ID * * See RFC4996 page 76 * * @param context The decompression context * @param rohc_data The ROHC data to parse * @param data_len The length of the ROHC data to parse (in bytes) * @param behavior The IP-ID behavior * @param indicator The compression indicator * @param[out] lsb The LSB bits extracted from the ROHC packet * @return The length (in bytes) of the compressed value, * -1 if ROHC data is malformed */ int d_optional_ip_id_lsb(const struct rohc_decomp_ctxt *const context, const uint8_t *const rohc_data, const size_t data_len, const int behavior, const int indicator, struct rohc_lsb_field16 *const lsb) { int length; assert(context != NULL); switch(behavior) { case IP_ID_BEHAVIOR_SEQ: case IP_ID_BEHAVIOR_SEQ_SWAP: { if(indicator == 0) { if(data_len < 1) { rohc_decomp_warn(context, "ROHC packet too small for optional_ip_id " "(len = %zu)", data_len); goto error; } lsb->bits = rohc_data[0]; lsb->bits_nr = 8; lsb->p = 3; length = 1; } else { if(data_len < 2) { rohc_decomp_warn(context, "ROHC packet too small for optional_ip_id " "(len = %zu)", data_len); goto error; } memcpy(&(lsb->bits), rohc_data, sizeof(uint16_t)); lsb->bits = rohc_ntoh16(lsb->bits); lsb->bits_nr = 16; lsb->p = 3; length = sizeof(uint16_t); } break; } case IP_ID_BEHAVIOR_RAND: case IP_ID_BEHAVIOR_ZERO: { rohc_decomp_debug(context, "IP-ID not present since IP-ID behavior is %d", behavior); length = 0; break; } default: { rohc_decomp_warn(context, "failed to decode innermost IP-ID offset: " "unexpected behavior %d", behavior); goto error; } } return length; 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 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; }