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