Esempio n. 1
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;
}
Esempio n. 2
0
/**
 * @brief Decompress the compressed list in given packet if present
 *
 * @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
 */
int rohc_list_decode_maybe(struct list_decomp *decomp,
                           const unsigned char *packet,
                           size_t packet_len)
{
	size_t read_length = 0;
	int ret;

	assert(decomp != NULL);
	assert(packet != NULL);

	/* check for minimal size (1 byte) */
	if(packet_len < 1)
	{
		rd_list_warn(decomp, "packet too small for compressed list (only %zu "
		             "bytes while at least 1 byte is required)", packet_len);
		goto error;
	}

	if(GET_BIT_0_7(packet) == 0)
	{
		rd_list_debug(decomp, "no bit found for extension list, re-use last one");
		packet++;
		read_length++;
		packet_len--;
	}
	else
	{
		/* some bits were transmitted for the compressed list, decode them */
		ret = rohc_list_decode(decomp, packet, packet_len);
		if(ret < 0)
		{
			rd_list_warn(decomp, "failed to decode the compressed list");
			goto error;
		}
#ifndef __clang_analyzer__ /* silent warning about dead decrement */
		packet += ret;
		packet_len -= ret;
#endif
		read_length += ret;
	}

	return read_length;

error:
	return -1;
}
Esempio n. 3
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;
}
Esempio n. 4
0
/**
 * @brief Decode an extension list type 3
 *
 * @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 xi_1        The XI 1 field if PS = 1 (4-bit XI)
 * @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_3(struct list_decomp *const decomp,
                                   const unsigned char *packet,
                                   size_t packet_len,
                                   const unsigned int gen_id,
                                   const int ps,
                                   const int xi_1)
{
	size_t packet_read_len = 0;
	struct rohc_list removal_list; /* list after removal scheme but before insertion scheme */
	unsigned int ref_id;
	int ret;

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

	/* in case of 8-bit XI, the XI 1 field should be set to 0 */
	if(ps && xi_1 != 0)
	{
		rd_list_warn(decomp, "sender does not conform to ROHC standards: when "
		             "8-bit XIs are used, the 4-bit XI 1 field should be set "
		             "to 0, not 0x%x", xi_1);
#ifdef ROHC_RFC_STRICT_DECOMPRESSOR
		goto error;
#endif
	}

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

	/* parse ref_id */
	ref_id = GET_BIT_0_7(packet);
	packet++;
	packet_len--;
	packet_read_len++;
	rd_list_debug(decomp, "ref_id = 0x%02x", ref_id);
	/* reference list must be known */
	if(!rohc_list_is_gen_id_known(decomp, ref_id))
	{
		rd_list_warn(decomp, "unknown ID 0x%02x given for reference list",
		             ref_id);
		goto error;
	}
	/* reference list must not be empty (RFC 4815, §5.7) */
	if(decomp->lists[ref_id].items_nr == 0)
	{
		rd_list_warn(decomp, "list encoding type 3 must not be used with an "
		             "empty reference list, discard packet");
		goto error;
	}

	/* removal scheme */
	rohc_list_reset(&removal_list);
	ret = rohc_list_parse_removal_scheme(decomp, packet, packet_len,
	                                     &(decomp->lists[ref_id]), &removal_list);
	if(ret < 0)
	{
		if(gen_id == ROHC_LIST_GEN_ID_ANON)
		{
			rd_list_warn(decomp, "failed to anonymous decompress list based on "
			             "reference list %u: removal scheme failed", ref_id);
		}
		else
		{
			rd_list_warn(decomp, "failed to decompress list with ID %u based on "
			             "reference list %u: removal scheme failed", gen_id, ref_id);
		}
		goto error;
	}
	packet += ret;
	packet_len -= ret;
	packet_read_len += ret;

	/* insertion scheme */
	ret = rohc_list_parse_insertion_scheme(decomp, packet, packet_len, ps, xi_1,
	                                       removal_list.items_nr, &removal_list,
	                                       &decomp->pkt_list);
	if(ret < 0)
	{
		if(gen_id == ROHC_LIST_GEN_ID_ANON)
		{
			rd_list_warn(decomp, "failed to anonymous decompress list based on "
			             "reference list %u: removal scheme failed", ref_id);
		}
		else
		{
			rd_list_warn(decomp, "failed to decompress list with ID %u based on "
			             "reference list %u: insertion scheme failed", gen_id, ref_id);
		}
		goto error;
	}
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
	packet += ret;
	packet_len -= ret;
#endif
	packet_read_len += ret;

	return packet_read_len;

error:
	return -1;
}
Esempio n. 5
0
/**
 * @brief Decode an extension list type 2
 *
 * @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
 * @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_2(struct list_decomp *const decomp,
                                   const unsigned char *packet,
                                   size_t packet_len,
                                   const unsigned int gen_id)
{
	size_t packet_read_len = 0;
	unsigned int ref_id;
	int ret;

	assert(decomp != NULL);
	assert(packet != NULL);
	assert(gen_id != ROHC_LIST_GEN_ID_NONE);

	/* is there enough data in packet for the ref_id and minimal removal
	   bit mask fields ? */
	if(packet_len < 2)
	{
		rd_list_warn(decomp, "packet too small for ref_id and minimal removal "
		             "bit mask fields (only %zu bytes while at least 2 bytes "
		             "are required)", packet_len);
		goto error;
	}

	/* parse ref_id */
	ref_id = GET_BIT_0_7(packet);
	packet++;
	packet_len--;
	packet_read_len++;
	rd_list_debug(decomp, "ref_id = 0x%02x", ref_id);
	/* reference list must be known */
	if(!rohc_list_is_gen_id_known(decomp, ref_id))
	{
		rd_list_warn(decomp, "unknown ID 0x%02x given for reference list",
		             ref_id);
		goto error;
	}
	/* reference list must not be empty (RFC 4815, §5.7) */
	if(decomp->lists[ref_id].items_nr == 0)
	{
		rd_list_warn(decomp, "list encoding type 2 must not be used with an "
		             "empty reference list, discard packet");
		goto error;
	}

	/* removal scheme */
	ret = rohc_list_parse_removal_scheme(decomp, packet, packet_len,
	                                     &(decomp->lists[ref_id]),
	                                     &(decomp->pkt_list));
	if(ret < 0)
	{
		if(gen_id == ROHC_LIST_GEN_ID_ANON)
		{
			rd_list_warn(decomp, "failed to anonymous decompress list based on "
			             "reference list %u: removal scheme failed", ref_id);
		}
		else
		{
			rd_list_warn(decomp, "failed to decompress list with ID %u based on "
			             "reference list %u: removal scheme failed", gen_id, ref_id);
		}
		goto error;
	}
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
	packet += ret;
	packet_len -= ret;
#endif
	packet_read_len += ret;

	return packet_read_len;

error:
	return -1;
}
Esempio n. 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;
}
Esempio n. 7
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;
}
Esempio n. 8
0
/**
 * @brief Process the removal 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 ref_list          The list to use as reference
 * @param[in,out] rem_list  in: the initial list,
 *                          out: the list with superfluous items removed
 * @return                  \li In case of success, the number of bytes read in the
 *                              given packet, ie. the length of the removal mask
 *                          \li -1 in case of failure
 */
static int rohc_list_parse_removal_scheme(struct list_decomp *const decomp,
                                          const uint8_t *packet,
                                          size_t packet_len,
                                          const struct rohc_list *const ref_list,
                                          struct rohc_list *const rem_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 i;
	int ret;

	/* parse the removal bit mask */
	ret = rohc_list_decode_mask(decomp, "removal", packet, packet_len,
	                            mask, &mask_len);
	if(ret < 0)
	{
		rd_list_warn(decomp, "failed to parse the removal bit mask");
		goto error;
	}
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
	packet += ret;
	packet_len -= ret;
#endif
	packet_read_len += ret;

	/* copy non-removed items from reference list */
	for(i = 0; i < mask_len; i++)
	{
		uint8_t item_to_remove;

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

		/* remove item if required */
		if(item_to_remove)
		{
			/* skip item only if reference list is large enough */
			if(i < ref_list->items_nr)
			{
				rd_list_debug(decomp, "skip item at index %zu of reference "
				              "list", i);
			}
		}
		else
		{
			rd_list_debug(decomp, "take item at index %zu of reference list "
			              "as item at index %zu of current list", i,
			              rem_list->items_nr);

			/* check that reference list is large enough */
			if(i >= ref_list->items_nr)
			{
				rd_list_warn(decomp, "reference list is too short: item at index "
				             "%zu requested while list contains only %zu items",
				             i, ref_list->items_nr);
				goto error;
			}

			/* take the item of the reference list */
			rem_list->items[rem_list->items_nr] = ref_list->items[i];
			rem_list->items_nr++;
		}
	}

	return packet_read_len;

error:
	return -1;
}