Exemplo n.º 1
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;
}
Exemplo n.º 2
0
/**
 * @brief Parse the LSBs bits of one of the TS echo request/reply fields
 *
 * See RFC4996 page 65
 *
 * @param context        The decompression context
 * @param data           The data to decode
 * @param data_len       The length of the data to decode
 * @param[out] ts_field  The information of TS option field extracted from packet
 * @return               The number of data bytes parsed,
 *                       -1 if data is malformed
 */
int d_tcp_ts_lsb_parse(const struct rohc_decomp_ctxt *const context,
                       const uint8_t *const data,
                       const size_t data_len,
                       struct rohc_lsb_field32 *const ts_field)
{
	const uint8_t *remain_data;
	size_t remain_len;

	remain_data = data;
	remain_len = data_len;

	if(remain_len < 1)
	{
		rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP,
		             "packet too short for TS LSB: only %zu bytes available "
		             "while at least 1 byte required", remain_len);
		goto error;
	}

	if((remain_data[0] & 0x80) == 0)
	{
		/* discriminator '0' */
		rohc_decomp_debug(context, "TCP TS option: TS field is 1-byte long");
		ts_field->bits = remain_data[0];
		ts_field->bits_nr = 7;
		ts_field->p = ROHC_LSB_SHIFT_TCP_TS_1B;
		remain_len--;
	}
	else if((remain_data[0] & 0x40) == 0)
	{
		/* discriminator '10' */
		rohc_decomp_debug(context, "TCP TS option: TS field is 2-byte long");
		if(remain_len < 2)
		{
			rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP,
			             "packet too short for TS LSB: only %zu bytes available "
			             "while at least 2 bytes required", remain_len);
			goto error;
		}
		ts_field->bits = (remain_data[0] & 0x3f) << 8;
		ts_field->bits |= remain_data[1];
		ts_field->bits_nr = 14;
		ts_field->p = ROHC_LSB_SHIFT_TCP_TS_2B;
		remain_len -= 2;
	}
	else if((remain_data[0] & 0x20) == 0)
	{
		/* discriminator '110' */
		rohc_decomp_debug(context, "TCP TS option: TS field is 3-byte long");
		if(remain_len < 3)
		{
			rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP,
			             "packet too short for TS LSB: only %zu bytes available "
			             "while at least 3 bytes required", remain_len);
			goto error;
		}
		ts_field->bits = (remain_data[0] & 0x1f) << 16;
		ts_field->bits |= remain_data[1] << 8;
		ts_field->bits |= remain_data[2];
		ts_field->bits_nr = 21;
		ts_field->p = ROHC_LSB_SHIFT_TCP_TS_3B;
		remain_len -= 3;
	}
	else
	{
		/* discriminator '111' */
		rohc_decomp_debug(context, "TCP TS option: TS field is 4-byte long");
		if(remain_len < 4)
		{
			rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP,
			             "packet too short for TS LSB: only %zu bytes available "
			             "while at least 4 bytes required", remain_len);
			goto error;
		}
		ts_field->bits = (remain_data[0] & 0x1f) << 24;
		ts_field->bits |= remain_data[1] << 16;
		ts_field->bits |= remain_data[2] << 8;
		ts_field->bits |= remain_data[3];
		ts_field->bits_nr = 29;
		ts_field->p = ROHC_LSB_SHIFT_TCP_TS_4B;
		remain_len -= 4;
	}

	return (data_len - remain_len);

error:
	return -1;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
/**
 * @brief Decode the static IP header of the rohc packet.
 *
 * @param context       The decompression context
 * @param rohc_packet   The remaining part of the ROHC packet
 * @param rohc_length   The remaining length (in bytes) of the ROHC packet
 * @param[out] ip_bits  The bits extracted from the IP part of the static chain
 * @param[out] nh_proto The next header protocol of the last extension header
 * @return              The length of static IP header in case of success,
 *                      -1 if an error occurs
 */
static int tcp_parse_static_ip(const struct rohc_decomp_ctxt *const context,
                               const uint8_t *const rohc_packet,
                               const size_t rohc_length,
                               struct rohc_tcp_extr_ip_bits *const ip_bits,
                               uint8_t *const nh_proto)
{
	const uint8_t *remain_data = rohc_packet;
	size_t remain_len = rohc_length;
	size_t read = 0;
	int ret;

	rohc_decomp_debug(context, "parse IP static part");

	/* at least 1 byte required to read the version flag */
	if(remain_len < 1)
	{
		rohc_decomp_warn(context, "malformed ROHC packet: too short for the "
		                 "version flag of the IP static part");
		goto error;
	}

	/* parse IPv4 static part or IPv6 static part? */
	if(GET_BIT_7(remain_data) == 0)
	{
		const ipv4_static_t *const ipv4_static = (ipv4_static_t *) remain_data;

		rohc_decomp_debug(context, "  IPv4 static part");
		ip_bits->version = IPV4;

		if(remain_len < sizeof(ipv4_static_t))
		{
			rohc_decomp_warn(context, "malformed ROHC packet: too short for the "
			                 "IPv4 static part");
			goto error;
		}

		ip_bits->proto = ipv4_static->protocol;
		ip_bits->proto_nr = 8;
		*nh_proto = ip_bits->proto;
		memcpy(ip_bits->saddr, &ipv4_static->src_addr, sizeof(uint32_t));
		ip_bits->saddr_nr = 32;
		memcpy(ip_bits->daddr, &ipv4_static->dst_addr, sizeof(uint32_t));
		ip_bits->daddr_nr = 32;

		/* IP extension headers not supported for IPv4 */
		ip_bits->opts_nr = 0;
		ip_bits->opts_len = 0;

		read += sizeof(ipv4_static_t);
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
		remain_data += sizeof(ipv4_static_t);
		remain_len -= sizeof(ipv4_static_t);
#endif
	}
	else
	{
		rohc_decomp_debug(context, "  IPv6 static part");
		ip_bits->version = IPV6;

		/* static 1 or static 2 variant? */
		if(GET_BIT_4(remain_data) == 0)
		{
			const ipv6_static1_t *const ipv6_static1 =
				(ipv6_static1_t *) remain_data;

			if(remain_len < sizeof(ipv6_static1_t))
			{
				rohc_decomp_warn(context, "malformed ROHC packet: too short for "
				                 "the IPv6 static part");
				goto error;
			}

			ip_bits->flowid = 0;
			ip_bits->flowid_nr = 20;
			ip_bits->proto = ipv6_static1->next_header;
			ip_bits->proto_nr = 8;
			memcpy(ip_bits->saddr, &ipv6_static1->src_addr, sizeof(uint32_t) * 4);
			ip_bits->saddr_nr = 128;
			memcpy(ip_bits->daddr, &ipv6_static1->dst_addr, sizeof(uint32_t) * 4);
			ip_bits->daddr_nr = 128;

			read += sizeof(ipv6_static1_t);
			remain_data += sizeof(ipv6_static1_t);
			remain_len -= sizeof(ipv6_static1_t);
		}
		else
		{
			const ipv6_static2_t *const ipv6_static2 =
				(ipv6_static2_t *) remain_data;

			if(remain_len < sizeof(ipv6_static2_t))
			{
				rohc_decomp_warn(context, "malformed ROHC packet: too short for "
				                 "the IPv6 static part");
				goto error;
			}

			ip_bits->flowid = (ipv6_static2->flow_label1 << 16) |
			                  rohc_ntoh16(ipv6_static2->flow_label2);
			assert((ip_bits->flowid & 0xfffff) == ip_bits->flowid);
			rohc_decomp_debug(context, "  IPv6 flow label = 0x%05x", ip_bits->flowid);
			ip_bits->flowid_nr = 20;
			ip_bits->proto = ipv6_static2->next_header;
			ip_bits->proto_nr = 8;
			memcpy(ip_bits->saddr, &ipv6_static2->src_addr, sizeof(uint32_t) * 4);
			ip_bits->saddr_nr = 128;
			memcpy(ip_bits->daddr, &ipv6_static2->dst_addr, sizeof(uint32_t) * 4);
			ip_bits->daddr_nr = 128;

			read += sizeof(ipv6_static2_t);
			remain_data += sizeof(ipv6_static2_t);
			remain_len -= sizeof(ipv6_static2_t);
		}

		*nh_proto = ip_bits->proto;
		ip_bits->opts_nr = 0;
		ip_bits->opts_len = 0;
		while(rohc_is_ipv6_opt(*nh_proto))
		{
			ip_option_context_t *opt;

			if(ip_bits->opts_nr >= ROHC_TCP_MAX_IP_EXT_HDRS)
			{
				rohc_decomp_warn(context, "too many IPv6 extension headers");
				goto error;
			}
			opt = &(ip_bits->opts[ip_bits->opts_nr]);

			ret = tcp_parse_static_ipv6_option(context, ip_bits, opt, *nh_proto,
			                                   remain_data, remain_len);
			if(ret < 0)
			{
				rohc_decomp_warn(context, "malformed ROHC packet: malformed "
				                 "IPv6 static option part");
				goto error;
			}
			rohc_decomp_debug(context, "IPv6 static option part is %d-byte length",
			                  ret);
			assert(remain_len >= ((size_t) ret));
			read += ret;
			remain_data += ret;
			remain_len -= ret;

			*nh_proto = opt->nh_proto;
			ip_bits->opts_nr++;
		}
		rohc_decomp_debug(context, "IPv6 header is followed by %zu extension "
		                  "headers", ip_bits->opts_nr);
	}
	rohc_decomp_dump_buf(context, "IP static part", rohc_packet, read);

	return read;

error:
	return -1;
}
Exemplo n.º 5
0
/**
 * @brief Decode the TCP dynamic part of the ROHC packet.
 *
 * @param context      The decompression context
 * @param rohc_packet  The remaining part of the ROHC packet
 * @param rohc_length  The remaining length (in bytes) of the ROHC packet
 * @param[out] bits    The bits extracted from the TCP part of the dynamic chain
 * @return             The number of bytes read in the ROHC packet,
 *                     -1 in case of failure
 */
static int tcp_parse_dynamic_tcp(const struct rohc_decomp_ctxt *const context,
                                 const uint8_t *const rohc_packet,
                                 const size_t rohc_length,
                                 struct rohc_tcp_extr_bits *const bits)
{
	const tcp_dynamic_t *tcp_dynamic;
	const uint8_t *remain_data = rohc_packet;
	size_t remain_len = rohc_length;
	int ret;

	rohc_decomp_debug(context, "parse TCP dynamic part");

	/* check the minimal length to decode the TCP dynamic part */
	if(remain_len < sizeof(tcp_dynamic_t))
	{
		rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu bytes "
		                 "available while at least %zu bytes required for "
		                 "mandatory fields of the TCP dynamic part",
		                 remain_len, sizeof(tcp_dynamic_t));
		goto error;
	}
	tcp_dynamic = (tcp_dynamic_t *) remain_data;
	remain_data += sizeof(tcp_dynamic_t);
	remain_len -= sizeof(tcp_dynamic_t);

	rohc_decomp_debug(context, "TCP res_flags = %d, ecn_flags = %d, "
	                  "rsf_flags = %d, URG = %d, ACK = %d, PSH = %d, ack_zero = %u",
	                  tcp_dynamic->tcp_res_flags, tcp_dynamic->tcp_ecn_flags,
	                  tcp_dynamic->rsf_flags, tcp_dynamic->urg_flag,
	                  tcp_dynamic->ack_flag, tcp_dynamic->psh_flag,
	                  tcp_dynamic->ack_zero);

	/* retrieve the TCP flags from the ROHC packet */
	bits->ecn_used_bits = tcp_dynamic->ecn_used;
	bits->ecn_used_bits_nr = 1;
	bits->res_flags_bits = tcp_dynamic->tcp_res_flags;
	bits->res_flags_bits_nr = 4;
	bits->ecn_flags_bits = tcp_dynamic->tcp_ecn_flags;
	bits->ecn_flags_bits_nr = 2;
	bits->urg_flag_bits = tcp_dynamic->urg_flag;
	bits->urg_flag_bits_nr = 1;
	bits->ack_flag_bits = tcp_dynamic->ack_flag;
	bits->ack_flag_bits_nr = 1;
	bits->psh_flag_bits = tcp_dynamic->psh_flag;
	bits->psh_flag_bits_nr = 1;
	bits->rsf_flags_bits = tcp_dynamic->rsf_flags;
	bits->rsf_flags_bits_nr = 3;

	/* retrieve the TCP sequence number from the ROHC packet */
	bits->seq.bits = rohc_ntoh32(tcp_dynamic->seq_num);
	bits->seq.bits_nr = 32;
	rohc_decomp_debug(context, "%zu bits of TCP sequence number 0x%08x",
	                  bits->seq.bits_nr, bits->seq.bits);

	/* retrieve the MSN from the ROHC packet */
	bits->msn.bits = rohc_ntoh16(tcp_dynamic->msn);
	bits->msn.bits_nr = 16;
	rohc_decomp_debug(context, "%zu bits of MSN 0x%04x",
	                  bits->msn.bits_nr, bits->msn.bits);

	/* optional ACK number */
	if(tcp_dynamic->ack_zero == 1)
	{
		bits->ack.bits = 0;
		bits->ack.bits_nr = 32; /* TODO */
	}
	else
	{
		if(remain_len < sizeof(uint32_t))
		{
			rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu "
			                 "bytes available while at least %zu bytes required "
			                 "for the ACK number", remain_len, sizeof(uint32_t));
			goto error;
		}
		memcpy(&(bits->ack.bits), remain_data, sizeof(uint32_t));
		bits->ack.bits = rohc_ntoh32(bits->ack.bits);
		bits->ack.bits_nr = 32;
		remain_data += sizeof(uint32_t);
		remain_len -= sizeof(uint32_t);

		if(bits->ack_flag_bits == 0)
		{
			rohc_decomp_debug(context, "ACK flag not set, but ACK number was "
			                  "transmitted anyway");
		}
	}
	rohc_decomp_debug(context, "seq_number = 0x%08x, ack_number = 0x%08x",
	                  bits->seq.bits, bits->ack.bits);

	/* window */
	if(remain_len < sizeof(uint16_t))
	{
		rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu bytes "
		                 "available while at least %zu bytes required for the "
		                 "window", remain_len, sizeof(uint16_t));
		goto error;
	}
	memcpy(&(bits->window.bits), remain_data, sizeof(uint16_t));
	bits->window.bits = rohc_ntoh16(bits->window.bits);
	bits->window.bits_nr = 16;
	remain_data += sizeof(uint16_t);
	remain_len -= sizeof(uint16_t);
	rohc_decomp_debug(context, "TCP window = 0x%04x", bits->window.bits);

	/* checksum */
	if(remain_len < sizeof(uint16_t))
	{
		rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu bytes "
		                 "available while at least %zu bytes required for the "
		                 "checksum", remain_len, sizeof(uint16_t));
		goto error;
	}
	memcpy(&(bits->tcp_check), remain_data, sizeof(uint16_t));
	bits->tcp_check = rohc_ntoh16(bits->tcp_check);
	remain_data += sizeof(uint16_t);
	remain_len -= sizeof(uint16_t);
	rohc_decomp_debug(context, "TCP checksum = 0x%04x", bits->tcp_check);

	/* URG pointer */
	if(tcp_dynamic->urp_zero == 1)
	{
		bits->urg_ptr.bits = 0;
		bits->urg_ptr.bits_nr = 16;
	}
	else
	{
		if(remain_len < sizeof(uint16_t))
		{
			rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu "
			                 "bytes available while at least %zu bytes required "
			                 "for the URG pointer", remain_len, sizeof(uint16_t));
			goto error;
		}
		memcpy(&(bits->urg_ptr.bits), remain_data, sizeof(uint16_t));
		bits->urg_ptr.bits = rohc_ntoh16(bits->urg_ptr.bits);
		bits->urg_ptr.bits_nr = 16;
		remain_data += sizeof(uint16_t);
		remain_len -= sizeof(uint16_t);
	}
	rohc_decomp_debug(context, "TCP urg_ptr = 0x%04x", bits->urg_ptr.bits);

	/* ACK stride */
	if(tcp_dynamic->ack_stride_flag == 0)
	{
		bits->ack_stride.bits_nr = 0;
		rohc_decomp_debug(context, "TCP ack_stride not present");
	}
	else
	{
		if(remain_len < sizeof(uint16_t))
		{
			rohc_decomp_warn(context, "malformed TCP dynamic part: only %zu "
			                 "bytes available while at least %zu bytes required "
			                 "for the ACK stride", remain_len, sizeof(uint16_t));
			goto error;
		}
		memcpy(&(bits->ack_stride.bits), remain_data, sizeof(uint16_t));
		bits->ack_stride.bits = rohc_ntoh16(bits->ack_stride.bits);
		bits->ack_stride.bits_nr = 16;
		remain_data += sizeof(uint16_t);
		remain_len -= sizeof(uint16_t);
		rohc_decomp_debug(context, "TCP ack_stride = 0x%04x", bits->ack_stride.bits);
	}
#if 0 /* TODO: handle ACK stride */
	if(tcp_context->ack_stride != 0)
	{
		// Calculate the Ack Number residue
		tcp_context->ack_num_residue = tcp_context->ack_num % tcp_context->ack_stride;
	}
	rohc_decomp_debug(context, "TCP ack_stride = 0x%04x, ack_number_residue = "
	                  "0x%04x", tcp_context->ack_stride,
	                  tcp_context->ack_num_residue);
#endif

	/* parse the compressed list of TCP options */
	ret = d_tcp_parse_tcp_opts_list_item(context, remain_data, remain_len, true,
	                                     &bits->tcp_opts);
	if(ret < 0)
	{
		rohc_decomp_warn(context, "failed to parse optional compressed list "
		                 "of TCP options");
		goto error;
	}
	rohc_decomp_debug(context, "compressed list of TCP options = %d bytes", ret);
#ifndef __clang_analyzer__ /* silent warning about dead in/decrement */
	remain_data += ret;
#endif
	remain_len -= ret;

	assert(remain_len <= rohc_length);
	rohc_dump_buf(context->decompressor->trace_callback,
	              context->decompressor->trace_callback_priv,
	              ROHC_TRACE_DECOMP, ROHC_TRACE_DEBUG, "TCP dynamic part",
	              (const uint8_t *const ) tcp_dynamic, rohc_length - remain_len);

	return (rohc_length - remain_len);

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