/** * @brief Get the bit in the given byte at the given position * * @param byte The byte to analyse * @param pos The position between 0 and 7 * @return The requested bit */ static uint8_t rohc_get_bit(const unsigned char byte, const size_t pos) { uint8_t bit; switch(pos) { case 0: bit = GET_REAL(GET_BIT_0(&byte)); break; case 1: bit = GET_REAL(GET_BIT_1(&byte)); break; case 2: bit = GET_REAL(GET_BIT_2(&byte)); break; case 3: bit = GET_REAL(GET_BIT_3(&byte)); break; case 4: bit = GET_REAL(GET_BIT_4(&byte)); break; case 5: bit = GET_REAL(GET_BIT_5(&byte)); break; case 6: bit = GET_REAL(GET_BIT_6(&byte)); break; case 7: bit = GET_REAL(GET_BIT_7(&byte)); break; default: /* there is no such bit in a byte */ assert(0); /* should not happen */ bit = 0; break; } return bit; }
/** * @brief Decompress the compressed list in given packet * * @param decomp The list decompressor * @param packet The ROHC packet to decompress * @param packet_len The remaining length of the packet to decode (in bytes) * @return The size of the compressed list in packet in case of * success, -1 in case of failure */ static int rohc_list_decode(struct list_decomp *decomp, const unsigned char *packet, size_t packet_len) { size_t read_length = 0; uint8_t et; /* the type of list encoding */ bool gp; /* whether the gen_id field is present or not */ uint8_t ps; /* the type of XI field */ uint8_t m; /* the CC or Count field (share bits with XI 1) */ uint8_t xi_1; /* the XI 1 field (share bits with m) */ unsigned int gen_id; /* the gen_id if present, ROHC_LIST_GEN_ID_ANON otherwise */ int ret; /* reset the list of the current packet */ rohc_list_reset(&decomp->pkt_list); /* is there enough data in packet for the ET, PS, m/XI1 and gen_id * fields? */ if(packet_len < 2) { rd_list_warn(decomp, "packet too small for compressed list (only %zu " "bytes while at least 2 bytes are required)", packet_len); goto error; } /* parse ET, GP, PS, and m/XI1 fields */ et = GET_BIT_6_7(packet); gp = !!GET_BIT_5(packet); ps = GET_REAL(GET_BIT_4(packet)); m = GET_BIT_0_3(packet); xi_1 = m; /* m and XI 1 are the same field */ packet++; read_length++; packet_len--; rd_list_debug(decomp, "ET = %d, GP = %d, PS = %d, m = XI 1 = %d", et, gp, ps, m); assert(m <= ROHC_LIST_ITEMS_MAX); /* parse gen_id if present */ if(gp == 1) { gen_id = GET_BIT_0_7(packet); packet++; read_length++; packet_len--; rd_list_debug(decomp, "gen_id = 0x%02x", gen_id); } else { gen_id = ROHC_LIST_GEN_ID_ANON; rd_list_debug(decomp, "decode anonymous list"); } decomp->pkt_list.id = gen_id; /* decode the compressed list according to its type */ switch(et) { case 0: ret = rohc_list_decode_type_0(decomp, packet, packet_len, gen_id, ps, m); break; case 1: ret = rohc_list_decode_type_1(decomp, packet, packet_len, gen_id, ps, xi_1); break; case 2: ret = rohc_list_decode_type_2(decomp, packet, packet_len, gen_id); break; case 3: ret = rohc_list_decode_type_3(decomp, packet, packet_len, gen_id, ps, xi_1); break; default: /* should not happen */ rohc_error(decomp, ROHC_TRACE_DECOMP, decomp->profile_id, "unknown type of compressed list (ET = %u)", et); assert(0); goto error; } if(ret < 0) { rd_list_warn(decomp, "failed to decode compressed list type %d", et); goto error; } assert(((size_t) ret) <= packet_len); #ifndef __clang_analyzer__ /* silent warning about dead in/decrement */ packet += ret; packet_len -= ret; #endif read_length += ret; /* RFC3095, section 5.8.2.1 reads: * When the decompressor receives a compressed list, it retrieves the * proper ref_list from the sliding window based on the ref_id, and * decompresses the compressed list obtaining curr_list. * In U/O-mode, curr_list is inserted into the sliding window * together with its generation identifier if the compressed list had * a generation identifier and the sliding window does not contain a * list with that generation identifier. All lists with generations * older than ref_id are removed from the sliding window. */ if(gen_id == ROHC_LIST_GEN_ID_ANON) { /* list is not identified by a gen_id, so do not update the sliding * window of lists */ rd_list_debug(decomp, "anonymous list was received"); } else if(decomp->lists[gen_id].counter > 0) { /* list is identified by a gen_id, but the sliding window of lists * already contain a list with that generation identifier, so do * not update the sliding window of lists */ decomp->lists[gen_id].counter++; rd_list_debug(decomp, "list with gen_id %u is already present in " "reference lists (received for the #%zu times)", gen_id, decomp->lists[gen_id].counter); } else { /* list is identified by a gen_id and the sliding window of lists does * not contain a list with that generation identifier yet, so update * the sliding window of lists */ rd_list_debug(decomp, "list with gen_id %u is not present yet in " "reference lists, add it", gen_id); memcpy(decomp->lists[gen_id].items, decomp->pkt_list.items, ROHC_LIST_ITEMS_MAX * sizeof(struct decomp_list *)); decomp->lists[gen_id].items_nr = decomp->pkt_list.items_nr; decomp->lists[gen_id].counter = 1; /* TODO: remove all lists with gen_id < ref_id */ } return read_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; }