Beispiel #1
0
/**
 * @brief Get the XI information, ie. the X bit and the index value
 *
 * @param ps                    The PS bit
 * @param xi_index              The index of the XI
 * @param xi_1                  The XI 1 field if PS = 1 (4-bit XI)
 * @param data                  The data to parse
 * @param[out] is_item_present  Whether the XI item shall be present or not
 * @return                      The value of the XI index
 */
static uint8_t rohc_list_get_xi_type_2or3(const int ps,
                                          const size_t xi_index,
                                          const uint8_t xi_1,
                                          const uint8_t *const data,
                                          bool *const is_item_present)
{
	uint8_t xi_value;

	/* extract the value of the XI index */
	if(ps == 1)
	{
		/* ROHC header contains 8-bit XIs */
		*is_item_present = GET_BOOL(GET_BIT_7(data + xi_index));
		xi_value = GET_BIT_0_6(data + xi_index);
	}
	else
	{
		/* ROHC header contains 4-bit XIs: encoding type 2 and 3 store XI #1
		 * in their first byte, so next XIs are shifted by 4 bits */

		/* which type of XI do we parse ? first one, odd one or even one ? */
		if(xi_index == 0)
		{
			/* first XI is stored in the first byte of the header */
			*is_item_present = GET_BOOL(GET_BIT_3(&xi_1));
			xi_value = GET_BIT_0_2(&xi_1);
		}
		else if((xi_index % 2) != 0)
		{
			/* handle odd XI, ie. XI stored in MSB */
			*is_item_present = GET_BOOL(GET_BIT_7(data + (xi_index - 1) / 2));
			xi_value = GET_BIT_4_6(data + (xi_index - 1) / 2);
		}
		else
		{
			/* handle even XI, ie. XI stored in LSB */
			*is_item_present = GET_BOOL(GET_BIT_3(data + (xi_index - 1) / 2));
			xi_value = GET_BIT_0_2(data + (xi_index - 1) / 2);
		}
	}

	return xi_value;
}
Beispiel #2
0
/**
 * @brief Determine the number of bits set to 1 in the insertion/removal bit mask
 *
 * @param decomp          The list decompressor
 * @param descr           The name of bit mask being decoded
 * @param packet          The ROHC packet to decompress
 * @param packet_len      The length (in bytes) of the packet to decompress
 * @param[out] mask       The insertion/removal bit mask on 1-2 bytes
 * @param[out] mask_len   The length of the insertion/removal mask (in bits)
 * @return                \li In case of success, the number of bytes read in the
 *                            given packet, ie. the length of the compressed list
 *                        \li -1 in case of failure
 */
static int rohc_list_decode_mask(struct list_decomp *const decomp,
                                 const char *const descr,
                                 const uint8_t *const packet,
                                 const size_t packet_len,
                                 uint8_t mask[2],
                                 size_t *const mask_len)
{
	size_t parsed_bytes_nr;

	/* is there enough data in packet for minimal insertion bit mask field ? */
	if(packet_len < 1)
	{
		rd_list_warn(decomp, "packet too small for minimal %s bit mask field "
		             "(only %zu bytes while at least 1 byte is required)",
		             descr, packet_len);
		goto error;
	}

	/* determine the number of bits set to 1 in the insertion bit mask */
	mask[0] = packet[0];
	rd_list_debug(decomp, "%s bit mask (first byte) = 0x%02x", descr, mask[0]);
	if(GET_REAL(GET_BIT_7(mask)) == 1)
	{
		/* 15-bit mask */
		if(packet_len < 2)
		{
			rd_list_warn(decomp, "packet too small for a 2-byte %s bit mask "
			             "(only %zu bytes available)", descr, packet_len);
			goto error;
		}
		*mask_len = 15;
		mask[1] = packet[1];
		rd_list_debug(decomp, "%s bit mask (second byte) = 0x%02x", descr, mask[1]);
		parsed_bytes_nr = 2;
	}
	else
	{
		/* 7-bit mask */
		rd_list_debug(decomp, "no second byte of %s bit mask", descr);
		*mask_len = 7;
		mask[1] = 0; /* shut up compiler warning about read of uninitialized data */
		parsed_bytes_nr = 1;
	}

	return parsed_bytes_nr;

error:
	return -1;
}
Beispiel #3
0
/**
 * @brief Get the XI information, ie. the X bit and the index value
 *
 * @param ps                    The PS bit
 * @param xi_index              The index of the XI
 * @param data                  The data to parse
 * @param[out] is_item_present  Whether the XI item shall be present or not
 * @return                      The value of the XI index
 */
static uint8_t rohc_list_get_xi_type_0(const int ps,
                                       const size_t xi_index,
                                       const uint8_t *const data,
                                       bool *const is_item_present)
{
	uint8_t xi_value;

	/* extract the value of the XI index */
	if(ps == 1)
	{
		/* ROHC header contains 8-bit XIs */
		*is_item_present = GET_BOOL(GET_BIT_7(data + xi_index));
		xi_value = GET_BIT_0_6(data + xi_index);
	}
	else
	{
		/* ROHC header contains 4-bit XIs: encoding type 0 stores XI #1
		 * with all other XIs */

		/* which type of XI do we parse ? even or odd one ? */
		if((xi_index % 2) == 0)
		{
			/* handle even XI, ie. XI stored in MSB */
			*is_item_present = GET_BOOL(GET_BIT_7(data + xi_index / 2));
			xi_value = GET_BIT_4_6(data + xi_index / 2);
		}
		else
		{
			/* handle odd XI, ie. XI stored in LSB */
			*is_item_present = GET_BOOL(GET_BIT_3(data + xi_index / 2));
			xi_value = GET_BIT_0_2(data + xi_index / 2);
		}
	}

	return xi_value;
}
Beispiel #4
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 #5
0
/**
 * @brief Process the insertion scheme of the list compression
 *
 * @param decomp         The list decompressor
 * @param packet         The ROHC packet to decompress
 * @param packet_len     The length (in bytes) of the packet to decompress
 * @param ps             The PS bit
 * @param xi_1           The XI 1 field if PS = 1 (4-bit XI)
 * @param items_nr       The number of items in the initial list
 * @param ref_list       The list to use as reference
 * @param[out] ins_list  The list with new items added
 * @return               \li In case of success, the number of bytes read in the
 *                           given packet, ie. the length of the insertion mask
 *                       \li -1 in case of failure
 */
static int rohc_list_parse_insertion_scheme(struct list_decomp *const decomp,
                                            const uint8_t *packet,
                                            size_t packet_len,
                                            const int ps,
                                            const int xi_1,
                                            const size_t items_nr,
                                            const struct rohc_list *const ref_list,
                                            struct rohc_list *const ins_list)
{
	size_t packet_read_len = 0;
	uint8_t mask[2]; /* removal bit mask on 1-2 bytes */
	size_t mask_len; /* length (in bits) of the removal mask */
	size_t item_read_len; /* the amount of bytes currently read in the item field */
	size_t ref_list_cur_pos; /* current position in reference list */
	size_t xi_index; /* the index of the current XI in XI list */
	size_t xi_len; /* the length (in bytes) of the XI list */
	size_t k; /* the number of ones in insertion mask and the number of elements in XI list */
	size_t i;
	int ret;

	assert(ps == 0 || ps == 1);

	/* parse the insertion bit mask */
	ret = rohc_list_decode_mask(decomp, "insertion", packet, packet_len,
	                            mask, &mask_len);
	if(ret < 0)
	{
		rd_list_warn(decomp, "failed to parse the insertion bit mask");
		goto error;
	}
	packet += ret;
	packet_read_len += ret;
	packet_len -= ret;

	/* determine the number of indexes in the XI list */
	k = rohc_list_get_xi_nr(mask, mask_len);

	/* determine the length (in bytes) of the XI list */
	xi_len = rohc_list_get_xi_len(k, ps);
	if(packet_len < xi_len)
	{
		rd_list_warn(decomp, "packet too small for k = %zu XI items (only %zu "
		             "bytes while at least %zu bytes are required)", k,
		             packet_len, xi_len);
		goto error;
	}

	/* will the decompressed list contain too many items? */
	if((items_nr + k) > ROHC_LIST_ITEMS_MAX)
	{
		rd_list_warn(decomp, "failed to decompress list based on reference list "
		             "with %zu existing items and %zu additional new items: too "
		             "many items for list (%u items max)", items_nr, k,
		             ROHC_LIST_ITEMS_MAX);
		goto error;
	}

	/* create current list with reference list and new provided items */
	xi_index = 0;
	item_read_len = 0;
	ref_list_cur_pos = 0;
	for(i = 0; i < mask_len; i++)
	{
		uint8_t new_item_to_insert;

		/* retrieve the corresponding bit in the insertion mask */
		if(i < 7)
		{
			/* bit is located in first byte of insertion mask */
			new_item_to_insert = rohc_get_bit(mask[0], 6 - i);
		}
		else
		{
			/* bit is located in 2nd byte of insertion mask */
			new_item_to_insert = rohc_get_bit(mask[1], 14 - i);
		}

		/* insert item if required */
		if(!new_item_to_insert)
		{
			/* take the next item from reference list (if there no more item in
			   reference list, do nothing) */
			if(ref_list_cur_pos < ref_list->items_nr)
			{
				/* new list, insert the item from reference list */
				rd_list_debug(decomp, "use item from reference list (index %zu) into "
				              "current list (index %zu)", ref_list_cur_pos, i);
				/* use next item from reference list */
				ins_list->items[i] = ref_list->items[ref_list_cur_pos];
				ins_list->items_nr++;
				/* skip item in removal list */
				ref_list_cur_pos++;
			}
		}
		else
		{
			unsigned int xi_x_value; /* the value of the X field in one XI field */
			unsigned int xi_index_value; /* the value of the Index field in one XI field */

			/* new item to insert in list, parse the related XI field */
			if(!ps)
			{
				/* ROHC header contains 4-bit XIs */

				/* which type of XI do we parse ? first one, odd one or even one ? */
				if(xi_index == 0)
				{
					/* first XI is stored in the first byte of the header */
					xi_x_value = GET_BIT_3(&xi_1);
					xi_index_value = GET_BIT_0_2(&xi_1);
				}
				else if((xi_index % 2) != 0)
				{
					/* handle odd XI, ie. XI stored in MSB */
					xi_x_value = GET_BIT_7(packet + (xi_index - 1) / 2);
					xi_index_value = GET_BIT_4_6(packet + (xi_index - 1) / 2);
				}
				else
				{
					/* handle even XI, ie. XI stored in LSB */
					xi_x_value = GET_BIT_3(packet + (xi_index - 1) / 2);
					xi_index_value = GET_BIT_0_2(packet + (xi_index - 1) / 2);
				}
			}
			else
			{
				/* ROHC header contains 8-bit XIs */
				xi_x_value = GET_BIT_7(packet + xi_index);
				xi_index_value = GET_BIT_0_6(packet + xi_index);
			}

			/* is the XI index valid? */
			if(!decomp->check_item(decomp, xi_index_value))
			{
				rd_list_warn(decomp, "XI #%zu got invalid index %u", xi_index,
				             xi_index_value);
				goto error;
			}

			/* parse the corresponding item if present */
			if(xi_x_value)
			{
				const uint8_t *const xi_item = packet + xi_len + item_read_len;
				const size_t xi_item_max_len = packet_len - xi_len - item_read_len;
				size_t item_len;

				rd_list_debug(decomp, "handle XI item #%zu", xi_index);

				/* create (or update if it already exists) the corresponding
				 * item with the item transmitted in the ROHC header */
				if(!rohc_decomp_list_create_item(decomp, xi_index, xi_index_value,
				                                 xi_item, xi_item_max_len,
				                                 &item_len))
				{
					rd_list_warn(decomp, "failed to create XI item #%zu from "
					             "packet", xi_index);
					goto error;
				}

				/* skip the item in ROHC header */
				item_read_len += item_len;
			}
			else
			{
				/* X bit not set in XI, so item is not provided in ROHC header,
				 * it must already be known by decompressor */
				if(!decomp->trans_table[xi_index_value].known)
				{
					rd_list_warn(decomp, "list item with index #%u referenced by "
					             "XI #%zu is not known yet", xi_index_value,
					             xi_index);
					goto error;
				}
			}

			/* use new item from packet */
			rd_list_debug(decomp, "use new item #%zu into current list (index "
			              "%zu)", xi_index, i);
			ins_list->items[i] = &(decomp->trans_table[xi_index_value]);
			ins_list->items_nr++;

			/* skip the XI we have just parsed */
			xi_index++;
		}
	}

	/* ensure that in case of an even number of 4-bit XIs, the 4 bits of
	 * padding are set to 0 */
	if(ps == 0 && (k % 2) == 0)
	{
		const uint8_t xi_padding = GET_BIT_0_3(packet + xi_len - 1);
		if(xi_padding != 0)
		{
			rd_list_warn(decomp, "sender does not conform to ROHC standards: "
			             "when an even number of 4-bit XIs is used, the last 4 "
			             "bits of the XI list should be set to 0, not 0x%x",
			             xi_padding);
#ifdef ROHC_RFC_STRICT_DECOMPRESSOR
			goto error;
#endif
		}
	}

	/* skip the XI list and the item list */
	packet_read_len += xi_len + item_read_len;
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
	packet_len -= xi_len + item_read_len;
#endif

	return packet_read_len;

error:
	return -1;
}
Beispiel #6
0
/**
 * @brief Decode an extension list type 0
 *
 * @param decomp      The list decompressor
 * @param packet      The ROHC packet to decompress
 * @param packet_len  The length (in bytes) of the packet to decompress
 * @param gen_id      The id of the current list,
 *                    maybe ROHC_LIST_GEN_ID_ANON if not defined
 * @param ps          The ps field
 * @param m           The m field
 * @return            \li In case of success, the number of bytes read in the given
 *                        packet, ie. the length of the compressed list
 *                    \li -1 in case of failure
 */
static int rohc_list_decode_type_0(struct list_decomp *const decomp,
                                   const unsigned char *packet,
                                   size_t packet_len,
                                   const unsigned int gen_id,
                                   const int ps,
                                   const uint8_t m)
{
	size_t packet_read_len = 0;
	size_t xi_len; /* the length (in bytes) of the XI list */
	unsigned int xi_index; /* the index of the current XI in XI list */
	size_t item_read_len; /* the amount of bytes currently read in the item field */

	assert(decomp != NULL);
	assert(packet != NULL);
	assert(gen_id != ROHC_LIST_GEN_ID_NONE);
	assert(ps == 0 || ps == 1);
	assert(m <= ROHC_LIST_ITEMS_MAX);

	/* determine the length (in bytes) of the XI list */
	if(!ps)
	{
		/* 4-bit XIs */
		if((m % 2) == 0)
		{
			/* even number of XI fields */
			xi_len = m / 2;
		}
		else
		{
			/* odd number of XI fields, there are 4 bits of padding */
			xi_len = (m + 1) / 2;
		}
	}
	else
	{
		/* 8-bit XIs */
		xi_len = m;
	}

	/* is there enough room in packet for all the XI list ? */
	if(packet_len < xi_len)
	{
		rd_list_warn(decomp, "packet too small for m = %d XI items (only %zu "
		             "bytes while at least %zu bytes are required)", m,
		             packet_len, xi_len);
		goto error;
	}

	/* creation of the list from the m XI items */
	item_read_len = 0;
	for(xi_index = 0; xi_index < m; xi_index++)
	{
		unsigned int xi_x_value; /* the value of the X field in one XI field */
		unsigned int xi_index_value; /* the value of the Index field in one XI field */

		/* extract the value of the XI index */
		if(!ps)
		{
			/* 4-bit XI */
			if((xi_index % 2) == 0)
			{
				/* 4-bit XI is stored in MSB */
				xi_x_value = GET_BIT_7(packet + xi_index / 2);
				xi_index_value = GET_BIT_4_6(packet + xi_index / 2);
			}
			else
			{
				/* 4-bit XI is stored in LSB */
				xi_x_value = GET_BIT_3(packet + xi_index / 2);
				xi_index_value = GET_BIT_0_2(packet + xi_index / 2);
			}
			rd_list_debug(decomp, "0x%02x: XI #%u got index %u",
			              packet[xi_index / 2], xi_index, xi_index_value);
		}
		else
		{
			/* 8-bit XI */
			xi_x_value = GET_BIT_7(packet + xi_index);
			xi_index_value = GET_BIT_0_6(packet + xi_index);
			rd_list_debug(decomp, "0x%02x: XI #%u got index %u",
			              packet[xi_index], xi_index, xi_index_value);
		}

		/* is the XI index valid? */
		if(!decomp->check_item(decomp, xi_index_value))
		{
			rd_list_warn(decomp, "XI #%u got invalid index %u", xi_index,
			             xi_index_value);
			goto error;
		}

		/* is there a corresponding item in packet after the XI list? */
		if(xi_x_value)
		{
			const uint8_t *const xi_item = packet + xi_len + item_read_len;
			const size_t xi_item_max_len = packet_len - xi_len - item_read_len;
			size_t item_len;

			rd_list_debug(decomp, "handle XI item #%u", xi_index);

			/* create (or update if it already exists) the corresponding item
			 * with the item transmitted in the ROHC header */
			if(!rohc_decomp_list_create_item(decomp, xi_index, xi_index_value,
			                                 xi_item, xi_item_max_len, &item_len))
			{
				rd_list_warn(decomp, "failed to create XI item #%u from packet",
				             xi_index);
				goto error;
			}

			/* skip the item in ROHC header */
			item_read_len += item_len;
		}
		else
		{
			/* X bit not set in XI, so item is not provided in ROHC header,
			 * it must already be known by decompressor */
			if(!decomp->trans_table[xi_index_value].known)
			{
				rd_list_warn(decomp, "list item with index #%u referenced by XI "
				             "#%d is not known yet", xi_index_value, xi_index);
				goto error;
			}
		}

		/* record the structure of the list of the current packet */
		assert(decomp->pkt_list.items_nr < ROHC_LIST_ITEMS_MAX);
		decomp->pkt_list.items[decomp->pkt_list.items_nr] =
			&decomp->trans_table[xi_index_value];
		decomp->pkt_list.items_nr++;
		rd_list_debug(decomp, "  XI #%u: use item of type 0x%02x (index %u in "
		              "translation table) in list", xi_index,
		              decomp->trans_table[xi_index_value].type, xi_index_value);
	}

	/* ensure that in case of an odd number of 4-bit XIs, the 4 bits of padding
	   are set to 0 */
	if(ps == 0 && (m % 2) != 0)
	{
		const uint8_t xi_padding = GET_BIT_0_3(packet + xi_len - 1);
		if(xi_padding != 0)
		{
			rd_list_warn(decomp, "sender does not conform to ROHC standards: "
			             "when an odd number of 4-bit XIs is used, the last 4 "
			             "bits of the XI list should be set to 0, not 0x%x",
			             xi_padding);
#ifdef ROHC_RFC_STRICT_DECOMPRESSOR
			goto error;
#endif
		}
	}

	/* skip the XI list and the item list */
	packet_read_len += xi_len + item_read_len;
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
	packet_len -= xi_len + item_read_len;
#endif

	return packet_read_len;

error:
	return -1;
}
Beispiel #7
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;
}