/** * @brief Check that the decompression of the ROHC feedback-only packets is * successful. * * @param argc The number of program arguments * @param argv The program arguments * @return The unix return code: * \li 0 in case of success, * \li 1 in case of failure */ int main(int argc, char *argv[]) { /* a ROHC feedback-only packet */ const struct rohc_ts arrival_time = { .sec = 0, .nsec = 0 }; uint8_t rohc_feedback_data[] = { 0xf4, 0x20, 0x00, 0x11, 0xe9 }; const size_t rohc_feedback_len = 5; const struct rohc_buf rohc_feedback = rohc_buf_init_full(rohc_feedback_data, rohc_feedback_len, arrival_time); int status = 1; /* parse program arguments, print the help message in case of failure */ if(argc != 1) { usage(); goto error; } /* test ROHC feedback-only decompression */ status = test_decomp(rohc_feedback); error: return status; } /** * @brief Print usage of the application */ static void usage(void) { fprintf(stderr, "Check that feedback-only packets are decompressed as expected\n" "\n" "usage: test_decompress_feedback_only [OPTIONS]\n" "\n" "options:\n" " -h Print this usage and exit\n"); }
/** * @brief Test the robustness of the compression API * * @param argc The number of command line arguments * @param argv The command line arguments * @return 0 if test succeeds, non-zero if test fails */ int main(int argc, char *argv[]) { struct rohc_comp *comp; bool verbose; /* whether to run in verbose mode or not */ int is_failure = 1; /* test fails by default */ /* do we run in verbose mode ? */ if(argc == 1) { /* no argument, run in silent mode */ verbose = false; } else if(argc == 2 && strcmp(argv[1], "verbose") == 0) { /* run in verbose mode */ verbose = true; } else { /* invalid usage */ printf("test the robustness of the compression API\n"); printf("usage: %s [verbose]\n", argv[0]); goto error; } /* rohc_comp_new2() */ CHECK(rohc_comp_new2(-1, ROHC_SMALL_CID_MAX, random_cb, NULL) == NULL); CHECK(rohc_comp_new2(ROHC_SMALL_CID + 1, ROHC_SMALL_CID_MAX, random_cb, NULL) == NULL); comp = rohc_comp_new2(ROHC_SMALL_CID, 0, random_cb, NULL); CHECK(comp != NULL); rohc_comp_free(comp); comp = rohc_comp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX, random_cb, NULL); CHECK(comp != NULL); rohc_comp_free(comp); CHECK(rohc_comp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX + 1, random_cb, NULL) == NULL); comp = rohc_comp_new2(ROHC_LARGE_CID, 0, random_cb, NULL); CHECK(comp != NULL); rohc_comp_free(comp); comp = rohc_comp_new2(ROHC_LARGE_CID, ROHC_LARGE_CID_MAX, random_cb, NULL); CHECK(comp != NULL); rohc_comp_free(comp); CHECK(rohc_comp_new2(ROHC_LARGE_CID, ROHC_LARGE_CID_MAX + 1, random_cb, NULL) == NULL); CHECK(rohc_comp_new2(ROHC_LARGE_CID, ROHC_LARGE_CID_MAX, NULL, NULL) == NULL); comp = rohc_comp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX, random_cb, NULL); CHECK(comp != NULL); /* rohc_comp_set_traces_cb2() */ { rohc_trace_callback2_t fct = (rohc_trace_callback2_t) NULL; CHECK(rohc_comp_set_traces_cb2(NULL, fct, NULL) == false); CHECK(rohc_comp_set_traces_cb2(comp, fct, NULL) == true); CHECK(rohc_comp_set_traces_cb2(comp, fct, comp) == true); } /* rohc_comp_profile_enabled() */ CHECK(rohc_comp_profile_enabled(NULL, ROHC_PROFILE_IP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_GENERAL) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UNCOMPRESSED) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_RTP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UDP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_ESP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_IP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_TCP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UDPLITE) == false); /* rohc_comp_enable_profile() */ CHECK(rohc_comp_enable_profile(NULL, ROHC_PROFILE_IP) == false); CHECK(rohc_comp_enable_profile(comp, ROHC_PROFILE_GENERAL) == false); CHECK(rohc_comp_enable_profile(comp, ROHC_PROFILE_IP) == true); /* rohc_comp_disable_profile() */ CHECK(rohc_comp_disable_profile(NULL, ROHC_PROFILE_IP) == false); CHECK(rohc_comp_disable_profile(comp, ROHC_PROFILE_GENERAL) == false); CHECK(rohc_comp_disable_profile(comp, ROHC_PROFILE_IP) == true); /* rohc_comp_enable_profiles() */ CHECK(rohc_comp_enable_profiles(NULL, ROHC_PROFILE_IP, -1) == false); CHECK(rohc_comp_enable_profiles(comp, ROHC_PROFILE_GENERAL, -1) == false); CHECK(rohc_comp_enable_profiles(comp, ROHC_PROFILE_IP, -1) == true); CHECK(rohc_comp_enable_profiles(comp, ROHC_PROFILE_IP, ROHC_PROFILE_UDP, ROHC_PROFILE_RTP, -1) == true); /* rohc_comp_disable_profiles() */ CHECK(rohc_comp_disable_profiles(NULL, ROHC_PROFILE_IP, -1) == false); CHECK(rohc_comp_disable_profiles(comp, ROHC_PROFILE_GENERAL, -1) == false); CHECK(rohc_comp_disable_profiles(comp, ROHC_PROFILE_UDP, -1) == true); CHECK(rohc_comp_disable_profiles(comp, ROHC_PROFILE_UDP, ROHC_PROFILE_RTP, -1) == true); /* rohc_comp_profile_enabled() */ CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UNCOMPRESSED) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_RTP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UDP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_ESP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_IP) == true); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_TCP) == false); CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UDPLITE) == false); /* rohc_comp_get_segment2() */ { unsigned char buf1[1]; struct rohc_buf pkt1 = rohc_buf_init_empty(buf1, 1); CHECK(rohc_comp_get_segment2(NULL, &pkt1) == ROHC_STATUS_ERROR); CHECK(rohc_comp_get_segment2(comp, NULL) == ROHC_STATUS_ERROR); pkt1.max_len = 0; pkt1.offset = 0; pkt1.len = 0; CHECK(rohc_comp_get_segment2(comp, &pkt1) == ROHC_STATUS_ERROR); pkt1.max_len = 1; pkt1.offset = 0; pkt1.len = 0; CHECK(rohc_comp_get_segment2(comp, &pkt1) == ROHC_STATUS_ERROR); pkt1.max_len = 2; pkt1.offset = 0; pkt1.len = 0; CHECK(rohc_comp_get_segment2(comp, &pkt1) == ROHC_STATUS_ERROR); } /* rohc_comp_force_contexts_reinit() */ CHECK(rohc_comp_force_contexts_reinit(NULL) == false); CHECK(rohc_comp_force_contexts_reinit(comp) == true); /* rohc_comp_set_wlsb_window_width() */ CHECK(rohc_comp_set_wlsb_window_width(NULL, 16) == false); CHECK(rohc_comp_set_wlsb_window_width(comp, 0) == false); CHECK(rohc_comp_set_wlsb_window_width(comp, 15) == false); CHECK(rohc_comp_set_wlsb_window_width(comp, 16) == true); /* rohc_comp_set_periodic_refreshes() */ CHECK(rohc_comp_set_periodic_refreshes(NULL, 1700, 700) == false); CHECK(rohc_comp_set_periodic_refreshes(comp, 0, 700) == false); CHECK(rohc_comp_set_periodic_refreshes(comp, 1700, 0) == false); CHECK(rohc_comp_set_periodic_refreshes(comp, 5, 10) == false); CHECK(rohc_comp_set_periodic_refreshes(comp, 10, 5) == true); /* rohc_comp_set_list_trans_nr() */ CHECK(rohc_comp_set_list_trans_nr(NULL, 5) == false); CHECK(rohc_comp_set_list_trans_nr(comp, 0) == false); CHECK(rohc_comp_set_list_trans_nr(comp, 1) == true); CHECK(rohc_comp_set_list_trans_nr(comp, 5) == true); /* rohc_comp_set_rtp_detection_cb() */ { rohc_rtp_detection_callback_t fct = (rohc_rtp_detection_callback_t) NULL; CHECK(rohc_comp_set_rtp_detection_cb(NULL, fct, NULL) == false); CHECK(rohc_comp_set_rtp_detection_cb(comp, fct, NULL) == true); } /* rohc_comp_set_mrru() */ CHECK(rohc_comp_set_mrru(NULL, 10) == false); CHECK(rohc_comp_set_mrru(comp, 65535 + 1) == false); CHECK(rohc_comp_set_mrru(comp, 0) == true); CHECK(rohc_comp_set_mrru(comp, 65535) == true); /* rohc_comp_get_mrru() */ { size_t mrru; CHECK(rohc_comp_get_mrru(NULL, &mrru) == false); CHECK(rohc_comp_get_mrru(comp, NULL) == false); CHECK(rohc_comp_get_mrru(comp, &mrru) == true); CHECK(mrru == 65535); } /* disable MRRU for next tests */ CHECK(rohc_comp_set_mrru(comp, 0) == true); /* rohc_comp_get_max_cid() */ { size_t max_cid; CHECK(rohc_comp_get_max_cid(NULL, &max_cid) == false); CHECK(rohc_comp_get_max_cid(comp, NULL) == false); CHECK(rohc_comp_get_max_cid(comp, &max_cid) == true); CHECK(max_cid == ROHC_SMALL_CID_MAX); } /* rohc_comp_get_cid_type() */ { rohc_cid_type_t cid_type; CHECK(rohc_comp_get_cid_type(NULL, &cid_type) == false); CHECK(rohc_comp_get_cid_type(comp, NULL) == false); CHECK(rohc_comp_get_cid_type(comp, &cid_type) == true); CHECK(cid_type == ROHC_SMALL_CID); } /* rohc_comp_get_last_packet_info2() before any compressed packet */ { rohc_comp_last_packet_info2_t info; memset(&info, 0, sizeof(rohc_comp_last_packet_info2_t)); info.version_major = 0; info.version_minor = 0; CHECK(rohc_comp_get_last_packet_info2(comp, &info) == false); } /* rohc_compress4() */ { const struct rohc_ts ts = { .sec = 0, .nsec = 0 }; unsigned char buf1[1] = { 0x00 }; struct rohc_buf pkt1 = rohc_buf_init_full(buf1, 1, ts); unsigned char buf2[100]; struct rohc_buf pkt2 = rohc_buf_init_empty(buf2, 100); unsigned char buf[] = { 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x93, 0x52, 0xc0, 0xa8, 0x13, 0x01, 0xc0, 0xa8, 0x13, 0x05, 0x08, 0x00, 0xe9, 0xc2, 0x9b, 0x42, 0x00, 0x01, 0x66, 0x15, 0xa6, 0x45, 0x77, 0x9b, 0x04, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 }; struct rohc_buf pkt = rohc_buf_init_full(buf, sizeof(buf), ts); CHECK(rohc_compress4(NULL, pkt1, &pkt2) == ROHC_STATUS_ERROR); pkt1.len = 0; CHECK(rohc_compress4(comp, pkt1, &pkt2) == ROHC_STATUS_ERROR); pkt1.len = 1; CHECK(rohc_compress4(comp, pkt1, NULL) == ROHC_STATUS_ERROR); pkt2.max_len = 0; pkt2.offset = 0; pkt2.len = 0; CHECK(rohc_compress4(comp, pkt1, &pkt2) == ROHC_STATUS_ERROR); for(size_t i = 0; i <= pkt.len; i++) { pkt2.max_len = i; pkt2.offset = 0; pkt2.len = 0; CHECK(rohc_compress4(comp, pkt, &pkt2) == ROHC_STATUS_ERROR); } pkt2.max_len = pkt.len + 1; pkt2.offset = 0; pkt2.len = 0; CHECK(rohc_compress4(comp, pkt, &pkt2) == ROHC_STATUS_OK); } /* rohc_comp_get_last_packet_info2() */ { rohc_comp_last_packet_info2_t info; memset(&info, 0, sizeof(rohc_comp_last_packet_info2_t)); CHECK(rohc_comp_get_last_packet_info2(NULL, &info) == false); CHECK(rohc_comp_get_last_packet_info2(comp, NULL) == false); info.version_major = 0xffff; CHECK(rohc_comp_get_last_packet_info2(comp, &info) == false); info.version_major = 0; info.version_minor = 0xffff; CHECK(rohc_comp_get_last_packet_info2(comp, &info) == false); info.version_minor = 0; CHECK(rohc_comp_get_last_packet_info2(comp, &info) == true); } /* rohc_comp_get_general_info() */ { rohc_comp_general_info_t info; memset(&info, 0, sizeof(rohc_comp_general_info_t)); CHECK(rohc_comp_get_general_info(NULL, &info) == false); CHECK(rohc_comp_get_general_info(comp, NULL) == false); info.version_major = 0xffff; CHECK(rohc_comp_get_general_info(comp, &info) == false); info.version_major = 0; info.version_minor = 0xffff; CHECK(rohc_comp_get_general_info(comp, &info) == false); info.version_minor = 0; CHECK(rohc_comp_get_general_info(comp, &info) == true); } /* rohc_comp_get_state_descr() */ CHECK(strcmp(rohc_comp_get_state_descr(ROHC_COMP_STATE_IR), "IR") == 0); CHECK(strcmp(rohc_comp_get_state_descr(ROHC_COMP_STATE_FO), "FO") == 0); CHECK(strcmp(rohc_comp_get_state_descr(ROHC_COMP_STATE_SO), "SO") == 0); CHECK(strcmp(rohc_comp_get_state_descr(ROHC_COMP_STATE_SO + 1), "no description") == 0); /* rohc_comp_force_contexts_reinit() with some contexts init'ed */ CHECK(rohc_comp_force_contexts_reinit(comp) == true); /* rohc_comp_set_features */ CHECK(rohc_comp_set_features(comp, ROHC_COMP_FEATURE_COMPAT_1_6_x) == false); CHECK(rohc_comp_set_features(comp, ROHC_COMP_FEATURE_NO_IP_CHECKSUMS) == true); CHECK(rohc_comp_set_features(comp, ROHC_COMP_FEATURE_NONE) == true); /* rohc_comp_deliver_feedback2() */ { const struct rohc_ts ts = { .sec = 0, .nsec = 0 }; uint8_t buf[] = { 0xf4, 0x20, 0x01, 0x11, 0x39 }; struct rohc_buf pkt = rohc_buf_init_full(buf, 5, ts); CHECK(rohc_comp_deliver_feedback2(NULL, pkt) == false); pkt.len = 0; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == true); pkt.len = 1; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == false); pkt.len = 2; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == false); pkt.len = 3; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == false); pkt.len = 4; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == false); pkt.len = 5; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == true); } /* several functions with some packets already compressed */ { rohc_trace_callback2_t fct = (rohc_trace_callback2_t) NULL; CHECK(rohc_comp_set_traces_cb2(comp, fct, comp) == false); CHECK(rohc_comp_set_wlsb_window_width(comp, 16) == false); CHECK(rohc_comp_set_periodic_refreshes(comp, 10, 5) == false); CHECK(rohc_comp_set_list_trans_nr(comp, 5) == false); } /* rohc_comp_free() */ rohc_comp_free(NULL); rohc_comp_free(comp); /* test succeeds */ trace(verbose, "all tests are successful\n"); is_failure = 0; error: return is_failure; } /** * @brief Fake random callback: always send 0 * * @param comp The compressor * @param user_context Private data * @return Always 0 */ static int random_cb(const struct rohc_comp *const comp __attribute__((unused)), void *const user_context __attribute__((unused))) { return 0; /* fake */ }
/** * @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); } }
/** * @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; }