Ejemplo n.º 1
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.º 2
0
/**
 * @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;
}
Ejemplo n.º 3
0
/**
 * @brief Decompress one ROHC packet and compare the result with a reference
 *
 * @param decomp           The decompressor to use to decompress the ROHC packet
 * @param num_packet       A number affected to the IP packet to compress/decompress
 * @param header           The PCAP header for the packet
 * @param packet           The packet to compress/decompress (link layer included)
 * @param link_len_src     The length of the link layer header before IP data
 * @param cmp_packet       The ROHC packet for comparison purpose
 * @param cmp_size         The size of the ROHC packet used for comparison
 *                         purpose
 * @param link_len_cmp     The length of the link layer header before ROHC data
 * @return                 0 if the process is successful
 *                         -1 if ROHC packet is malformed
 *                         -2 if decompression fails
 *                         -3 if the decompressed packet doesn't match the
 *                            reference
 */
static int test_decomp_one(struct rohc_decomp *const decomp,
                           const size_t num_packet,
                           const struct pcap_pkthdr header,
                           const unsigned char *const packet,
                           const size_t link_len_src,
                           const unsigned char *const cmp_packet,
                           const size_t cmp_size,
                           const size_t link_len_cmp)
{
	const struct rohc_ts arrival_time = { .sec = 0, .nsec = 0 };
	struct rohc_buf rohc_packet =
		rohc_buf_init_full((uint8_t *) packet, header.caplen, arrival_time);
	uint8_t uncomp_buffer[MAX_ROHC_SIZE];
	struct rohc_buf uncomp_packet =
		rohc_buf_init_empty(uncomp_buffer, MAX_ROHC_SIZE);
	rohc_status_t status;

	printf("=== decompressor packet #%zu:\n", num_packet);

	/* check Ethernet frame length */
	if(header.len <= link_len_src || header.len != header.caplen)
	{
		fprintf(stderr, "bad PCAP packet (len = %u, caplen = %u)\n",
		        header.len, header.caplen);
		goto error_fmt;
	}
	if(cmp_packet != NULL && cmp_size <= link_len_cmp)
	{
		fprintf(stderr, "bad comparison packet: too small for link header\n");
		goto error_fmt;
	}

	/* skip the link layer header */
	rohc_buf_pull(&rohc_packet, link_len_src);

	/* decompress the ROHC packet */
	printf("=== ROHC decompression: start\n");
	status = rohc_decompress3(decomp, rohc_packet, &uncomp_packet, NULL, NULL);
	if(status != ROHC_STATUS_OK)
	{
		size_t i;

		printf("=== ROHC decompression: failure\n");
		printf("=== original %zu-byte compressed packet:\n", rohc_packet.len);
		for(i = 0; i < rohc_packet.len; i++)
		{
			if(i > 0 && (i % 16) == 0)
			{
				printf("\n");
			}
			else if(i > 0 && (i % 8) == 0)
			{
				printf("  ");
			}
			printf("%02x ", rohc_buf_byte_at(rohc_packet, i));
		}
		printf("\n\n");
		goto error_decomp;
	}
	printf("=== ROHC decompression: success\n");

	/* compare the decompressed packet with the original one */
	printf("=== uncompressed packet comparison: start\n");
	if(cmp_packet && !compare_packets(rohc_buf_data(uncomp_packet),
	                                  uncomp_packet.len,
	                                  cmp_packet + link_len_cmp,
	                                  cmp_size - link_len_cmp))
	{
		printf("=== uncompressed packet comparison: failure\n");
		printf("\n");
		goto error_cmp;
	}
	printf("=== uncompressed packet comparison: success\n");

	printf("\n");
	return 0;

error_fmt:
	return -1;
error_decomp:
	return -2;
error_cmp:
	return -3;
}


/**
 * @brief Test the ROHC library decompression with a flow of ROHC packets
 *        generated by another ROHC implementation
 *
 * @param cid_type             The type of CIDs the compressor shall use
 * @param wlsb_width           The width of the WLSB window to use
 * @param max_contexts         The maximum number of ROHC contexts to use
 * @param src_filename         The name of the PCAP file that contains the
 *                             ROHC packets to decompress
 * @param cmp_filename         The name of the PCAP file that contains the
 *                             uncompressed packets used for comparison
 * @return                     0 in case of success,
 *                             1 in case of failure,
 *                             77 if test is skipped
 */
static int test_decomp_all(const rohc_cid_type_t cid_type,
                           const size_t wlsb_width,
                           const size_t max_contexts,
                           const char *const src_filename,
                           const char *const cmp_filename)
{
	char errbuf[PCAP_ERRBUF_SIZE];

	pcap_t *handle;
	struct pcap_pkthdr header;
	int link_layer_type_src;
	size_t link_len_src;
	unsigned char *packet;

	pcap_t *cmp_handle;
	struct pcap_pkthdr cmp_header;
	int link_layer_type_cmp;
	size_t link_len_cmp = 0;
	unsigned char *cmp_packet;

	size_t counter;

	struct rohc_decomp *decomp;

	size_t nb_bad = 0;
	size_t nb_ok = 0;
	size_t err_decomp = 0;
	size_t nb_ref = 0;

	int status = 1;
	int ret;

	printf("=== initialization:\n");

	/* open the source dump file */
	handle = pcap_open_offline(src_filename, errbuf);
	if(handle == NULL)
	{
		printf("failed to open the source pcap file: %s\n", errbuf);
		goto error;
	}

	/* link layer in the source dump must be Ethernet */
	link_layer_type_src = pcap_datalink(handle);
	if(link_layer_type_src != DLT_EN10MB &&
	   link_layer_type_src != DLT_LINUX_SLL &&
	   link_layer_type_src != DLT_RAW &&
	   link_layer_type_src != DLT_NULL)
	{
		printf("link layer type %d not supported in source dump (supported = "
		       "%d, %d, %d, %d)\n", link_layer_type_src, DLT_EN10MB,
		       DLT_LINUX_SLL, DLT_RAW, DLT_NULL);
		status = 77; /* skip test */
		goto close_input;
	}

	if(link_layer_type_src == DLT_EN10MB)
	{
		link_len_src = ETHER_HDR_LEN;
	}
	else if(link_layer_type_src == DLT_LINUX_SLL)
	{
		link_len_src = LINUX_COOKED_HDR_LEN;
	}
	else if(link_layer_type_src == DLT_NULL)
	{
		link_len_src = BSD_LOOPBACK_HDR_LEN;
	}
	else /* DLT_RAW */
	{
		link_len_src = 0;
	}

	/* open the uncompressed comparison dump file if asked */
	if(cmp_filename != NULL)
	{
		cmp_handle = pcap_open_offline(cmp_filename, errbuf);
		if(cmp_handle == NULL)
		{
			printf("failed to open the comparison pcap file: %s\n", errbuf);
			goto close_input;
		}

		/* link layer in the rohc_comparison dump must be Ethernet */
		link_layer_type_cmp = pcap_datalink(cmp_handle);
		if(link_layer_type_cmp != DLT_EN10MB &&
		   link_layer_type_cmp != DLT_LINUX_SLL &&
		   link_layer_type_cmp != DLT_RAW &&
		   link_layer_type_cmp != DLT_NULL)
		{
			printf("link layer type %d not supported in comparision dump "
			       "(supported = %d, %d, %d, %d)\n", link_layer_type_cmp,
			       DLT_EN10MB, DLT_LINUX_SLL, DLT_RAW, DLT_NULL);
			status = 77; /* skip test */
			goto close_comparison;
		}

		if(link_layer_type_cmp == DLT_EN10MB)
		{
			link_len_cmp = ETHER_HDR_LEN;
		}
		else if(link_layer_type_cmp == DLT_LINUX_SLL)
		{
			link_len_cmp = LINUX_COOKED_HDR_LEN;
		}
		else if(link_layer_type_cmp == DLT_NULL)
		{
			link_len_cmp = BSD_LOOPBACK_HDR_LEN;
		}
		else /* DLT_RAW */
		{
			link_len_cmp = 0;
		}
	}
	else
	{
		cmp_handle = NULL;
	}

	/* create the decompressor */
	decomp = create_decompressor(cid_type, max_contexts);
	if(decomp == NULL)
	{
		printf("failed to create the decompressor 1\n");
		goto close_comparison;
	}

	printf("\n");

	/* for each ROHC packet in the dump */
	counter = 0;
	while((packet = (unsigned char *) pcap_next(handle, &header)) != NULL)
	{
		counter++;

		/* get next uncompressed packet from the comparison dump file if asked */
		if(cmp_handle != NULL)
		{
			cmp_packet = (unsigned char *) pcap_next(cmp_handle, &cmp_header);
		}
		else
		{
			cmp_packet = NULL;
			cmp_header.caplen = 0;
		}

		/* decompress one packet of the flow and compare it with the given
		 * reference */
		ret = test_decomp_one(decomp, counter,
		                      header, packet, link_len_src,
		                      cmp_packet, cmp_header.caplen, link_len_cmp);
		if(ret == 0)
		{
			nb_ok++;
		}
		else if(ret == -2)
		{
			err_decomp++;
		}
		else if(ret != -3)
		{
			nb_ref++;
		}
		else
		{
			nb_bad++;
		}
	}

	/* show the compression/decompression results */
	printf("=== summary:\n");
	printf("===\tpackets_processed:    %zu\n", counter);
	printf("===\tmalformed:            %zu\n", nb_bad);
	printf("===\tdecompression_failed: %zu\n", err_decomp);
	printf("===\tmatches:              %zu\n", nb_ok);
	printf("\n");

	/* show some info/stats about the decompressor */
	if(!show_rohc_decomp_stats(decomp))
	{
		fprintf(stderr, "failed to dump ROHC decompressor stats\n");
		goto free_decomp;
	}
	printf("\n");

	/* destroy the compressors and decompressors */
	printf("=== shutdown:\n");
	if(err_decomp == 0 && nb_bad == 0 && nb_ref == 0 && nb_ok == counter)
	{
		/* test is successful */
		status = 0;
	}

free_decomp:
	rohc_decomp_free(decomp);
close_comparison:
	if(cmp_handle != NULL)
	{
		pcap_close(cmp_handle);
	}
close_input:
	pcap_close(handle);
error:
	return status;
}