Ejemplo n.º 1
0
/**
 * @brief Parse the SACK TCP option
 *
 * See RFC6846 page 68
 * (and RFC2018 for Selective Acknowledgement option)
 *
 * @param context        The decompression context
 * @param data           The ROHC data to parse
 * @param data_len       The length of the ROHC data to parse
 * @param[out] opt_sack  The information of SACK option extracted from the packet
 * @return               The number of ROHC bytes parsed,
 *                       -1 if packet is malformed
 */
int d_tcp_sack_parse(const struct rohc_decomp_ctxt *const context,
                     const uint8_t *const data,
                     const size_t data_len,
                     struct d_tcp_opt_sack *const opt_sack)
{
	const uint8_t *remain_data;
	size_t remain_data_len;
	uint8_t discriminator;
	int i;

	rohc_decomp_debug(context, "parse SACK option");

	remain_data = data;
	remain_data_len = data_len;

	/* parse discriminator */
	if(remain_data_len < 1)
	{
		rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP,
		             "packet too short for the discriminator of the TCP SACK "
		             "option: only %zu bytes available while at least 1 byte "
		             "required", remain_data_len);
		goto error;
	}
	discriminator = remain_data[0];
	remain_data++;
	remain_data_len--;
	if(discriminator > TCP_SACK_BLOCKS_MAX_NR)
	{
		rohc_decomp_warn(context, "invalid discriminator value (%d)",
		                 discriminator);
		goto error;
	}

	/* parse up to 4 SACK blocks */
	for(i = 0; i < discriminator; i++)
	{
		const int ret = d_tcp_sack_block(context, remain_data, remain_data_len,
		                                 &(opt_sack->blocks[i]));
		if(ret < 0)
		{
			rohc_decomp_warn(context, "failed to parse block #%d of SACK "
			                 "option", i + 1);
			goto error;
		}
		remain_data += ret;
		remain_data_len -= ret;
		rohc_decomp_debug(context, "block #%d of SACK option: start bits = 0x%08x, "
		                  "end bits = 0x%08x", i + 1, opt_sack->blocks[i].block_start,
		                  opt_sack->blocks[i].block_end);
	}
	opt_sack->blocks_nr = discriminator;

	return (data_len - remain_data_len);

error:
	return -1;
}
Ejemplo n.º 2
0
/**
 * @brief Parse the dynamic chain of the IR/IR-DYN 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] parsed_len  The length (in bytes) of static chain in case of success
 * @param[out] bits        The bits extracted from the dynamic chain
 * @return                 true in the dynamic chain was successfully parsed,
 *                         false if the ROHC packet was malformed
 */
bool tcp_parse_dyn_chain(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,
                         size_t *const parsed_len)
{
	const uint8_t *remain_data = rohc_packet;
	size_t remain_len = rohc_length;
	size_t ip_hdrs_nr;
	int ret;

	(*parsed_len) = 0;

	/* parse dynamic IP part (IPv4/IPv6 headers and extension headers) */
	for(ip_hdrs_nr = 0; ip_hdrs_nr < bits->ip_nr; ip_hdrs_nr++)
	{
		struct rohc_tcp_extr_ip_bits *const ip_bits = &(bits->ip[ip_hdrs_nr]);

		ret = tcp_parse_dynamic_ip(context, remain_data, remain_len, ip_bits);
		if(ret < 0)
		{
			rohc_decomp_warn(context, "malformed ROHC packet: malformed IP "
			                 "dynamic part");
			goto error;
		}
		rohc_decomp_debug(context, "IPv%u dynamic part is %d-byte length",
		                  ip_bits->version, ret);
		assert(remain_len >= ((size_t) ret));
		remain_data += ret;
		remain_len -= ret;
		(*parsed_len) += ret;
	}

	/* parse TCP dynamic part */
	ret = tcp_parse_dynamic_tcp(context, remain_data, remain_len, bits);
	if(ret < 0)
	{
		rohc_decomp_warn(context, "malformed ROHC packet: malformed TCP "
		                 "dynamic part");
		goto error;
	}
	rohc_decomp_debug(context, "TCP dynamic part is %d-byte length", ret);
	assert(remain_len >= ((size_t) ret));
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
	remain_data += ret;
	remain_len -= ret;
#endif
	(*parsed_len) += ret;

	return true;

error:
	return false;
}
Ejemplo n.º 3
0
/**
 * @brief Check whether the CRC on uncompressed header is correct or not
 *
 * @param context      The decompression context
 * @param uncomp_hdrs  The uncompressed headers
 * @param crc_pkt      The CRC over uncompressed headers extracted from packet
 * @return             true if the CRC is correct, false otherwise
 */
bool rohc_decomp_check_uncomp_crc(const struct rohc_decomp_ctxt *const context,
                                  struct rohc_buf *const uncomp_hdrs,
                                  const struct rohc_decomp_crc_one *const crc_pkt)
{
	uint8_t crc_computed;

	/* determine the initial value and the pre-computed table for the CRC */
	switch(crc_pkt->type)
	{
		case ROHC_CRC_TYPE_3:
			crc_computed = CRC_INIT_3;
			break;
		case ROHC_CRC_TYPE_7:
			crc_computed = CRC_INIT_7;
			break;
		case ROHC_CRC_TYPE_8:
			rohc_decomp_warn(context, "unexpected CRC type %d", crc_pkt->type);
			assert(0);
			goto error;
		case ROHC_CRC_TYPE_NONE:
		default:
			rohc_decomp_warn(context, "unknown CRC type %d", crc_pkt->type);
			assert(0);
			goto error;
	}

	/* compute the CRC from built uncompressed headers */
	crc_computed =
		crc_calculate(crc_pkt->type, rohc_buf_data(*uncomp_hdrs), uncomp_hdrs->len,
		              crc_computed);
	rohc_decomp_debug(context, "CRC-%d on uncompressed header = 0x%x",
	                  crc_pkt->type, crc_computed);

	/* does the computed CRC match the one in packet? */
	if(crc_computed != crc_pkt->bits)
	{
		rohc_decomp_warn(context, "CRC failure (computed = 0x%02x, packet = "
		                 "0x%02x)", crc_computed, crc_pkt->bits);
		goto error;
	}

	/* computed CRC matches the one in packet */
	return true;

error:
	return false;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
/**
 * @brief Decompress the lower bits of IP-ID
 *
 * See RFC4996 page 75
 *
 * @param context            The decompression context
 * @param ip_id_lsb_ctxt     The LSB decoding context for the IP-ID offset
 * @param msn                The Master Sequence Number
 * @param ip_id_bits         The received IP-ID offset bits to decode
 * @param ip_id_bits_nr      The number of received IP-ID offset bits to decode
 * @param p                  The offset parameter p to use for LSB decoding
 * @param[out] ip_id         The decoded IP-ID value
 * @return                   true if IP-ID was successfully decoded,
 *                           false if decoding failed
 *
 * @todo TODO: could be merged with decomp/schemes/ip_id_offset.[ch] module
 */
bool d_ip_id_lsb(const struct rohc_decomp_ctxt *const context,
                 const struct rohc_lsb_decode *const ip_id_lsb_ctxt,
                 const uint16_t msn,
                 const uint32_t ip_id_bits,
                 const size_t ip_id_bits_nr,
                 const rohc_lsb_shift_t p,
                 uint16_t *const ip_id)
{
	bool decode_ok;
	uint32_t ip_id_offset32;
	uint16_t ip_id_offset;

	assert(context != NULL);
	assert(ip_id_lsb_ctxt != NULL);
	assert(ip_id != NULL);

	decode_ok = rohc_lsb_decode(ip_id_lsb_ctxt, ROHC_LSB_REF_0, 0,
	                            ip_id_bits, ip_id_bits_nr, p, &ip_id_offset32);
	if(!decode_ok)
	{
		rohc_decomp_warn(context, "failed to decode %zu innermost IP-ID offset "
		                 "bits 0x%x with p = %u", ip_id_bits_nr, ip_id_bits, p);
		goto error;
	}
	ip_id_offset = (uint16_t) (ip_id_offset32 & 0xffff);
	rohc_decomp_debug(context, "decoded IP-ID offset = 0x%x (%zu bits 0x%x with "
	                  "p = %d)", ip_id_offset, ip_id_bits_nr, ip_id_bits, p);

	/* add the decoded offset with SN, taking care of overflow */
	*ip_id = (msn + ip_id_offset) & 0xffff;
	rohc_decomp_debug(context, "decoded IP-ID = 0x%04x (MSN = 0x%04x)", *ip_id, msn);

	return true;

error:
	return false;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
0
/**
 * @brief Parse a SACK field of a SACK block of the TCP SACK option
 *
 * See RFC6846 page 67
 * (and RFC2018 for Selective Acknowledgement option)
 *
 * @param context          The decompression context
 * @param data             The ROHC data to parse
 * @param data_len         The length of the ROHC data to parse
 * @param[out] sack_field  The uncompressed SACK field
 * @return                 The number of data bytes parsed,
 *                         -1 if data is malformed
 */
static int d_tcp_sack_pure_lsb(const struct rohc_decomp_ctxt *const context,
                               const uint8_t *const data,
                               const size_t data_len,
                               uint32_t *const sack_field)
{
	const uint8_t *remain_data = data;
	size_t remain_len = data_len;

	if(remain_len < 2)
	{
		rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP,
		             "packet too short for the discriminator of the TCP pure "
		             "field: only %zu bytes available while at least 2 bytes "
		             "required", remain_len);
		goto error;
	}

	if((remain_data[0] & 0x80) == 0)
	{
		/* discriminator '0' */
		rohc_decomp_debug(context, "SACK block is 2-byte long");
		(*sack_field) = *(remain_data++) & 0x7f;
		(*sack_field) <<= 8;
		(*sack_field) |= *(remain_data++);
		remain_len -= 2;
	}
	else if((remain_data[0] & 0x40) == 0)
	{
		/* discriminator '10' */
		rohc_decomp_debug(context, "SACK block is 3-byte long");
		if(remain_len < 3)
		{
			rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP,
			             "packet too short for the discriminator of the TCP pure "
			             "field: only %zu bytes available while at least 3 bytes "
			             "required", remain_len);
			goto error;
		}
		(*sack_field) = *(remain_data++) & 0x3f;
		(*sack_field) <<= 8;
		(*sack_field) |= *(remain_data++);
		(*sack_field) <<= 8;
		(*sack_field) |= *(remain_data++);
		remain_len -= 3;
	}
	else if((remain_data[0] & 0x20) == 0)
	{
		/* discriminator '110' */
		rohc_decomp_debug(context, "SACK block is 4-byte long");
		if(remain_len < 4)
		{
			rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP,
			             "packet too short for the discriminator of the TCP pure "
			             "field: only %zu bytes available while at least 4 bytes "
			             "required", remain_len);
			goto error;
		}
		(*sack_field) = *(remain_data++) & 0x1f;
		(*sack_field) <<= 8;
		(*sack_field) |= *(remain_data++);
		(*sack_field) <<= 8;
		(*sack_field) |= *(remain_data++);
		(*sack_field) <<= 8;
		(*sack_field) |= *(remain_data++);
		remain_len -= 4;
	}
	else if(remain_data[0] == 0xff)
	{
		/* discriminator '11111111' */
		rohc_decomp_debug(context, "SACK block is 5-byte long");
		if(remain_len < 5)
		{
			rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP,
			             "packet too short for the discriminator of the TCP pure "
			             "field: only %zu bytes available while at least 5 bytes "
			             "required", remain_len);
			goto error;
		}
		remain_data++; /* skip discriminator */
		(*sack_field) = *(remain_data++);
		(*sack_field) <<= 8;
		(*sack_field) |= *(remain_data++);
		(*sack_field) <<= 8;
		(*sack_field) |= *(remain_data++);
		(*sack_field) <<= 8;
		(*sack_field) |= *(remain_data++);
		remain_len -= 5;
	}
	else
	{
		rohc_decomp_warn(context, "malformed SACK block: unexpected "
		                 "discriminator 0x%02x", remain_data[0]);
		goto error;
	}

	return (data_len - remain_len);

error:
	return -1;
}
Ejemplo n.º 8
0
/**
 * @brief Parse the static chain of the IR 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 static chain
 * @param[out] parsed_len  The length (in bytes) of static chain in case of success
 * @return                 true in the static chain was successfully parsed,
 *                         false if the ROHC packet was malformed
 */
bool tcp_parse_static_chain(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,
                            size_t *const parsed_len)
{
	const uint8_t *remain_data = rohc_packet;
	size_t remain_len = rohc_length;
	size_t ip_hdrs_nr;
	uint8_t protocol;
	int ret;

	(*parsed_len) = 0;

	/* parse static IP part (IPv4/IPv6 headers and extension headers) */
	ip_hdrs_nr = 0;
	do
	{
		struct rohc_tcp_extr_ip_bits *const ip_bits = &(bits->ip[ip_hdrs_nr]);

		ret = tcp_parse_static_ip(context, remain_data, remain_len, ip_bits,
		                          &protocol);
		if(ret < 0)
		{
			rohc_decomp_warn(context, "malformed ROHC packet: malformed IP "
			                 "static part");
			goto error;
		}
		rohc_decomp_debug(context, "IPv%u static part is %d-byte length",
		                  ip_bits->version, ret);
		assert(remain_len >= ((size_t) ret));
		remain_data += ret;
		remain_len -= ret;
		(*parsed_len) += ret;

		ip_hdrs_nr++;
	}
	while(rohc_is_tunneling(protocol) && ip_hdrs_nr < ROHC_TCP_MAX_IP_HDRS);

	if(rohc_is_tunneling(protocol) && ip_hdrs_nr >= ROHC_TCP_MAX_IP_HDRS)
	{
		rohc_decomp_warn(context, "too many IP headers to decompress");
		goto error;
	}
	bits->ip_nr = ip_hdrs_nr;

	/* parse TCP static part */
	ret = tcp_parse_static_tcp(context, remain_data, remain_len, bits);
	if(ret < 0)
	{
		rohc_decomp_warn(context, "malformed ROHC packet: malformed TCP static "
		                 "part");
		goto error;
	}
	rohc_decomp_debug(context, "TCP static part is %d-byte length", ret);
	assert(remain_len >= ((size_t) ret));
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
	remain_data += ret;
	remain_len -= ret;
#endif
	(*parsed_len) += ret;

	return true;

error:
	return false;
}
Ejemplo n.º 9
0
/**
 * @brief Decode the static IPv6 option header of the rohc packet.
 *
 * @param context           The decompression context
 * @param[out] ip_bits      The bits extracted from the IP part of the static chain
 * @param[out] opt_context  The specific IPv6 option decompression context
 * @param protocol          The protocol of the IPv6 option
 * @param rohc_packet       The remaining part of the ROHC packet
 * @param rohc_length       The remaining length (in bytes) of the ROHC packet
 * @return                  The length of static IP header in case of success,
 *                          -1 if an error occurs
 */
static int tcp_parse_static_ipv6_option(const struct rohc_decomp_ctxt *const context,
                                        struct rohc_tcp_extr_ip_bits *const ip_bits,
                                        ip_option_context_t *const opt_context,
                                        const uint8_t protocol,
                                        const uint8_t *const rohc_packet,
                                        const size_t rohc_length)
{
	const ip_opt_static_t *ip_opt_static;
	size_t size;

	rohc_decomp_debug(context, "parse static part of the IPv6 extension header "
	                  "'%s' (%u)", rohc_get_ip_proto_descr(protocol), protocol);

	/* at least 2 bytes required to read the next header and length */
	if(rohc_length < sizeof(ip_opt_static_t))
	{
		rohc_decomp_warn(context, "malformed ROHC packet: too short for the "
		                 "IP extension header static part");
		goto error;
	}
	ip_opt_static = (ip_opt_static_t *) rohc_packet;
	opt_context->proto = protocol;
	opt_context->nh_proto = ip_opt_static->next_header;

	switch(protocol)
	{
		case ROHC_IPPROTO_HOPOPTS:  // IPv6 Hop-by-Hop options
		{
			size = sizeof(ip_hop_opt_static_t);
			if(rohc_length < size)
			{
				rohc_decomp_warn(context, "malformed ROHC packet: too short for "
				                 "the static part of the IPv6 Hop-by-Hop option");
				goto error;
			}
			opt_context->len = ipv6_opt_get_length((struct ipv6_opt *) ip_opt_static);
			rohc_decomp_debug(context, "  IPv6 option Hop-by-Hop is %zu-byte long",
			                  opt_context->len);
			break;
		}
		case ROHC_IPPROTO_ROUTING:  // IPv6 routing header
		{
			const ip_rout_opt_static_t *const ip_rout_opt_static =
				(ip_rout_opt_static_t *) ip_opt_static;
			size = ipv6_opt_get_length((struct ipv6_opt *) ip_rout_opt_static);
			if(rohc_length < size)
			{
				rohc_decomp_warn(context, "malformed ROHC packet: too short for "
				                 "the static part of the IPv6 Routing option");
				goto error;
			}
			opt_context->len = size;
			opt_context->generic.data_len = size - 2;
			memcpy(&opt_context->generic.data, &ip_rout_opt_static->value,
			       opt_context->generic.data_len);
			rohc_decomp_debug(context, "  IPv6 option Routing is %zu-byte long",
			                  opt_context->len);
			break;
		}
		case ROHC_IPPROTO_GRE:  /* TODO: GRE not yet supported */
		{
			rohc_decomp_warn(context, "GRE extension header not supported yet");
			goto error;
		}
		case ROHC_IPPROTO_DSTOPTS:  // IPv6 destination options
		{
			size = sizeof(ip_dest_opt_static_t);
			if(rohc_length < size)
			{
				rohc_decomp_warn(context, "malformed ROHC packet: too short for "
				                 "the static part of the IPv6 Destination option");
				goto error;
			}
			opt_context->len = ipv6_opt_get_length((struct ipv6_opt *) ip_opt_static);
			rohc_decomp_debug(context, "  IPv6 option Destination is %zu-byte long",
			                  opt_context->len);
			break;
		}
		case ROHC_IPPROTO_MINE:  /* TODO: MINE not yet supported */
		{
			rohc_decomp_warn(context, "GRE extension header not supported yet");
			goto error;
		}
		case ROHC_IPPROTO_AH:  /* TODO: AH not yet supported */
		{
			rohc_decomp_warn(context, "GRE extension header not supported yet");
			goto error;
		}
		default:
		{
			goto error;
		}
	}
	ip_bits->opts_len += opt_context->len;

	rohc_decomp_dump_buf(context, "IPv6 option static part", rohc_packet, size);

	return size;

error:
	return -1;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
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;
}
Ejemplo n.º 12
0
/**
 * @brief Decode the dynamic IPv6 option header of the rohc packet.
 *
 * @param context        The decompression context
 * @param opt_context    The specific IPv6 option decompression context
 * @param protocol       The IPv6 protocol option
 * @param rohc_packet    The remaining part of the ROHC packet
 * @param rohc_length    The remaining length (in bytes) of the ROHC packet
 * @return               The length of dynamic IP header
 *                       0 if an error occurs
 */
static int tcp_parse_dynamic_ipv6_option(const struct rohc_decomp_ctxt *const context,
                                         ipv6_option_context_t *const opt_context,
                                         const uint8_t protocol,
                                         const uint8_t *const rohc_packet,
                                         const size_t rohc_length)
{
	size_t remain_len = rohc_length;
	size_t size = 0;

	assert(context != NULL);
	assert(rohc_packet != NULL);

	rohc_decomp_debug(context, "parse dynamic part of IPv6 extension header");

	switch(protocol)
	{
		case ROHC_IPPROTO_HOPOPTS:  // IPv6 Hop-by-Hop options
		case ROHC_IPPROTO_DSTOPTS:  // IPv6 destination options
		{
			size += ((opt_context->generic.length + 1) << 3) - 2;
			if(remain_len < size)
			{
				rohc_decomp_warn(context, "malformed IPv6 option: malformed "
				                 "option %u: %zu bytes available while %zu bytes "
				                 "required", protocol, remain_len, size);
				goto error;
			}
			memcpy(opt_context->generic.data, rohc_packet, size);
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
			remain_len -= size;
#endif
			break;
		}
		case ROHC_IPPROTO_ROUTING:  // IPv6 routing header
		{
			break;
		}
		case ROHC_IPPROTO_GRE:  /* TODO: GRE not yet supported */
		{
			rohc_decomp_warn(context, "GRE extension header not supported yet");
			goto error;
		}
		case ROHC_IPPROTO_MINE:  /* TODO: MINE not yet supported */
		{
			rohc_decomp_warn(context, "MINE extension header not supported yet");
			goto error;
		}
		case ROHC_IPPROTO_AH:  /* TODO: AH not yet supported */
		{
			rohc_decomp_warn(context, "AH extension header not supported yet");
			goto error;
		}
		default:
		{
			break;
		}
	}

#if ROHC_EXTRA_DEBUG == 1
	rohc_dump_buf(context->decompressor->trace_callback,
	              context->decompressor->trace_callback_priv,
	              ROHC_TRACE_DECOMP, ROHC_TRACE_DEBUG,
	              "IPv6 option dynamic part", rohc_packet, size);
#endif

	return size;

error:
	return -1;
}
Ejemplo n.º 13
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;
}