Exemplo n.º 1
0
/**
 * @brief Decode the add-CID byte of a ROHC packet (if the add-CID byte is
 *        present)
 *
 * @param data The ROHC packet with a possible add-CID byte
 * @param len  The length of the ROHC packet
 * @return     UINT8_MAX if no add-CID byte is present, the CID value otherwise
 */
uint8_t rohc_add_cid_decode(const uint8_t *const data, const size_t len)
{
	uint8_t cid;

	if(rohc_add_cid_is_present(data, len))
	{
		cid = GET_BIT_0_3(data);
	}
	else
	{
		cid = UINT8_MAX;
	}

	return cid;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
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;
}