示例#1
0
文件: tcp_sack.c 项目: b12mihai/rohc
/**
 * @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;
}
示例#2
0
文件: tcp_ts.c 项目: swbrown/rohc
/**
 * @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;
}
示例#3
0
文件: tcp_sack.c 项目: b12mihai/rohc
/**
 * @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;
}
示例#4
0
文件: net_pkt.c 项目: swbrown/rohc
/**
 * @brief Parse a network packet
 *
 * @param[out] packet    The parsed packet
 * @param data           The data to parse
 * @param trace_cb       The function to call for printing traces
 * @param trace_cb_priv  An optional private context, may be NULL
 * @param trace_entity   The entity that emits the traces
 * @return               true if the packet was successfully parsed,
 *                       false if a problem occurred (a malformed packet is
 *                       not considered as an error)
 */
bool net_pkt_parse(struct net_pkt *const packet,
                   const struct rohc_buf data,
                   rohc_trace_callback2_t trace_cb,
                   void *const trace_cb_priv,
                   rohc_trace_entity_t trace_entity)
{
	packet->data = rohc_buf_data(data);
	packet->len = data.len;
	packet->ip_hdr_nr = 0;
	packet->key = 0;

	/* traces */
	packet->trace_callback = trace_cb;
	packet->trace_callback_priv = trace_cb_priv;

	/* create the outer IP packet from raw data */
	if(!ip_create(&packet->outer_ip, rohc_buf_data(data), data.len))
	{
		rohc_warning(packet, trace_entity, ROHC_PROFILE_GENERAL,
		             "cannot create the outer IP header");
		goto error;
	}
	packet->ip_hdr_nr++;
	rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
	           "outer IP header: %u bytes", ip_get_totlen(&packet->outer_ip));
	rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
	           "outer IP header: version %d", ip_get_version(&packet->outer_ip));
	if(packet->outer_ip.nh.data != NULL)
	{
		rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
		           "outer IP header: next header is of type %d",
		           packet->outer_ip.nh.proto);
		if(packet->outer_ip.nl.data != NULL)
		{
			rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
			           "outer IP header: next layer is of type %d",
			           packet->outer_ip.nl.proto);
		}
	}

	/* build the hash key for the packet */
	if(ip_get_version(&packet->outer_ip) == IPV4)
	{
		packet->key ^= ipv4_get_saddr(&packet->outer_ip);
		packet->key ^= ipv4_get_daddr(&packet->outer_ip);
	}
	else if(ip_get_version(&packet->outer_ip) == IPV6)
	{
		const struct ipv6_addr *const saddr = ipv6_get_saddr(&packet->outer_ip);
		const struct ipv6_addr *const daddr = ipv6_get_daddr(&packet->outer_ip);
		packet->key ^= saddr->addr.u32[0];
		packet->key ^= saddr->addr.u32[1];
		packet->key ^= saddr->addr.u32[2];
		packet->key ^= saddr->addr.u32[3];
		packet->key ^= daddr->addr.u32[0];
		packet->key ^= daddr->addr.u32[1];
		packet->key ^= daddr->addr.u32[2];
		packet->key ^= daddr->addr.u32[3];
	}

	/* get the transport protocol */
	packet->transport = &packet->outer_ip.nl;

	/* is there any inner IP header? */
	if(rohc_is_tunneling(packet->transport->proto))
	{
		/* create the second IP header */
		if(!ip_get_inner_packet(&packet->outer_ip, &packet->inner_ip))
		{
			rohc_warning(packet, trace_entity, ROHC_PROFILE_GENERAL,
			             "cannot create the inner IP header");
			goto error;
		}
		packet->ip_hdr_nr++;
		rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
		           "inner IP header: %u bytes", ip_get_totlen(&packet->inner_ip));
		rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
		           "inner IP header: version %d", ip_get_version(&packet->inner_ip));
		if(packet->inner_ip.nh.data != NULL)
		{
			rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
			           "inner IP header: next header is of type %d",
			           packet->inner_ip.nh.proto);
			if(packet->inner_ip.nl.data != NULL)
			{
				rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL,
				           "inner IP header: next layer is of type %d",
				           packet->inner_ip.nl.proto);
			}
		}

		/* get the transport protocol */
		packet->transport = &packet->inner_ip.nl;
	}

	return true;

error:
	return false;
}