/** * @brief Test the ROHC library with the given ROHC feedback packet * * @param rohc_feedback The ROHC feedback data * @return 0 in case of success, * 1 in case of failure */ static int test_decomp(const struct rohc_buf rohc_feedback) { struct rohc_decomp *decomp; uint8_t ip_buffer[MAX_ROHC_SIZE]; struct rohc_buf ip_packet = rohc_buf_init_empty(ip_buffer, MAX_ROHC_SIZE); uint8_t feedback_buffer[MAX_ROHC_SIZE]; struct rohc_buf feedback_packet = rohc_buf_init_empty(feedback_buffer, MAX_ROHC_SIZE); int is_failure = 1; rohc_status_t status; /* create the ROHC decompressor in bi-directional mode */ decomp = rohc_decomp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX, ROHC_O_MODE); if(decomp == NULL) { fprintf(stderr, "failed to create the ROHC decompressor\n"); goto error; } /* set the callback for traces on decompressor */ if(!rohc_decomp_set_traces_cb2(decomp, print_rohc_traces, NULL)) { fprintf(stderr, "cannot set trace callback for decompressor\n"); goto destroy_decomp; } /* decompress the ROHC feedback with the ROHC decompressor */ status = rohc_decompress3(decomp, rohc_feedback, &ip_packet, &feedback_packet, NULL); if(status != ROHC_STATUS_OK) { fprintf(stderr, "failed to decompress ROHC feedback\n"); goto destroy_decomp; } if(!rohc_buf_is_empty(ip_packet)) { fprintf(stderr, "ROHC packet was not a feedback-only packet\n"); } if(rohc_buf_is_empty(feedback_packet)) { fprintf(stderr, "ROHC packet contained no feedback data\n"); } fprintf(stderr, "decompression is successful\n"); /* everything went fine */ is_failure = 0; destroy_decomp: rohc_decomp_free(decomp); error: return is_failure; }
/** * @brief Create and configure a ROHC decompressor * * @param cid_type The type of CIDs the compressor shall use * @param max_contexts The maximum number of ROHC contexts to use * @return The new ROHC decompressor */ static struct rohc_decomp * create_decompressor(const rohc_cid_type_t cid_type, const size_t max_contexts) { struct rohc_decomp *decomp; /* create the decompressor */ decomp = rohc_decomp_new2(cid_type, max_contexts - 1, ROHC_U_MODE); if(decomp == NULL) { printf("failed to create decompressor\n"); goto error; } /* set the callback for traces */ if(!rohc_decomp_set_traces_cb2(decomp, print_rohc_traces, NULL)) { printf("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)) { printf("failed to enable the profiles\n"); goto destroy_decomp; } return decomp; destroy_decomp: rohc_decomp_free(decomp); error: return NULL; }
/** * @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); } }