Beispiel #1
0
/**
 * @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;
}
Beispiel #2
0
/**
 * @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;
}
Beispiel #3
0
/**
 * @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;
}