예제 #1
0
/**
 * @brief Test the ROHC library with a flow of ROHC packets
 *
 * @param filename       The name of the PCAP file that contains the ROHC packets
 * @param failure_start  The first packet that shall fail to be decompressed
 * @return               0 in case of success,
 *                       1 in case of failure
 */
static int test_decomp(const char *const filename,
                       const size_t failure_start)
{
	char errbuf[PCAP_ERRBUF_SIZE];
	pcap_t *handle;
	int link_layer_type;
	int link_len;
	struct pcap_pkthdr header;
	unsigned char *packet;
	struct rohc_decomp *decomp;
	unsigned int counter;
	int is_failure = 1;

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

	/* link layer in the source dump must be Ethernet */
	link_layer_type = pcap_datalink(handle);
	if(link_layer_type != DLT_EN10MB &&
	   link_layer_type != DLT_LINUX_SLL &&
	   link_layer_type != DLT_RAW)
	{
		fprintf(stderr, "link layer type %d not supported in source dump (supported = "
		       "%d, %d, %d)\n", link_layer_type, DLT_EN10MB, DLT_LINUX_SLL,
		       DLT_RAW);
		goto close_input;
	}

	if(link_layer_type == DLT_EN10MB)
	{
		link_len = ETHER_HDR_LEN;
	}
	else if(link_layer_type == DLT_LINUX_SLL)
	{
		link_len = LINUX_COOKED_HDR_LEN;
	}
	else /* DLT_RAW */
	{
		link_len = 0;
	}

	/* create the decompressor */
	decomp = rohc_decomp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX, ROHC_O_MODE);
	if(decomp == NULL)
	{
		fprintf(stderr, "cannot create the decompressor\n");
		goto close_input;
	}

	/* set the callback for traces */
	if(!rohc_decomp_set_traces_cb2(decomp, print_rohc_traces, NULL))
	{
		fprintf(stderr, "failed to set trace callback\n");
		goto destroy_decomp;
	}

	/* enable decompression profiles */
	if(!rohc_decomp_enable_profiles(decomp, ROHC_PROFILE_UNCOMPRESSED,
	                                ROHC_PROFILE_UDP, ROHC_PROFILE_IP,
	                                ROHC_PROFILE_UDPLITE, ROHC_PROFILE_RTP,
	                                ROHC_PROFILE_ESP, ROHC_PROFILE_TCP, -1))
	{
		fprintf(stderr, "failed to enable the decompression profiles\n");
		goto destroy_decomp;
	}

	/* for each packet in the dump */
	counter = 0;
	while((packet = (unsigned char *) pcap_next(handle, &header)) != NULL)
	{
		const struct rohc_ts arrival_time = { .sec = 0, .nsec = 0 };
		struct rohc_buf rohc_packet =
			rohc_buf_init_full(packet, header.caplen, arrival_time);
		uint8_t ip_buffer[MAX_ROHC_SIZE];
		struct rohc_buf ip_packet =
			rohc_buf_init_empty(ip_buffer, MAX_ROHC_SIZE);
		uint8_t rcvd_feedback_buf[6];
		struct rohc_buf rcvd_feedback = rohc_buf_init_empty(rcvd_feedback_buf, 6);
		uint8_t send_feedback_buf[6];
		struct rohc_buf send_feedback = rohc_buf_init_empty(send_feedback_buf, 6);
		rohc_status_t status;

		counter++;

		/* check Ethernet frame length */
		if(header.len < link_len || header.len != header.caplen)
		{
			fprintf(stderr, "bad PCAP packet (len = %d, caplen = %d)\n",
			       header.len, header.caplen);
			goto destroy_decomp;
		}

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

		fprintf(stderr, "decompress malformed packet #%u:\n", counter);

		/* decompress the ROHC packet */
		status = rohc_decompress3(decomp, rohc_packet, &ip_packet, &rcvd_feedback,
		                          &send_feedback);
		fprintf(stderr, "\tdecompression status: %s\n", rohc_strerror(status));
		if(status == ROHC_STATUS_OK)
		{
			if(counter >= failure_start)
			{
				fprintf(stderr, "\tunexpected successful decompression\n");
				goto destroy_decomp;
			}
			else
			{
				fprintf(stderr, "\texpected successful decompression\n");
			}
		}
		else
		{
			if(counter >= failure_start)
			{
				fprintf(stderr, "\texpected decompression failure\n");
			}
			else
			{
				fprintf(stderr, "\tunexpected decompression failure\n");
				goto destroy_decomp;
			}
		}

		/* be ready to get the next feedback to send */
		rohc_buf_reset(&send_feedback);
	}

	is_failure = 0;

destroy_decomp:
	rohc_decomp_free(decomp);
close_input:
	pcap_close(handle);
error:
	return is_failure;
}


/**
 * @brief Callback to print traces of the ROHC library
 *
 * @param priv_ctxt  An optional private context, may be NULL
 * @param level      The priority level of the trace
 * @param entity     The entity that emitted the trace among:
 *                    \li ROHC_TRACE_COMP
 *                    \li ROHC_TRACE_DECOMP
 * @param profile    The ID of the ROHC compression/decompression profile
 *                   the trace is related to
 * @param format     The format string of the trace
 */
static void print_rohc_traces(void *const priv_ctxt,
                              const rohc_trace_level_t level,
                              const rohc_trace_entity_t entity,
                              const int profile,
                              const char *const format,
                              ...)
{
	const char *level_descrs[] =
	{
		[ROHC_TRACE_DEBUG]   = "DEBUG",
		[ROHC_TRACE_INFO]    = "INFO",
		[ROHC_TRACE_WARNING] = "WARNING",
		[ROHC_TRACE_ERROR]   = "ERROR"
	};

	if(level >= ROHC_TRACE_WARNING || is_verbose)
	{
		va_list args;
		fprintf(stdout, "[%s] ", level_descrs[level]);
		va_start(args, format);
		vfprintf(stdout, format, args);
		va_end(args);
	}
}
예제 #2
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;
}