diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template index 12a745b997fe7bfee7bf455e5c2ab6e5aaadb0a0..5789c3eb5c531b5cae15788967f872159a4eebe2 100644 --- a/cmake_targets/epc_test/CMakeLists.template +++ b/cmake_targets/epc_test/CMakeLists.template @@ -1,11 +1,13 @@ cmake_minimum_required(VERSION 2.8) set ( CMAKE_BUILD_TYPE "RelWithDebInfo" ) +set ( ASN_DEBUG False) set ( ADDR_CONF False ) set ( DEBUG_OMG False ) set ( DISABLE_XER_PRINT False ) set ( DRIVER2013 True ) set ( EMOS False ) +set ( EMIT_ASN_DEBUG True ) set ( ENABLE_FXP True ) set ( ENABLE_ITTI True ) set ( ENABLE_NAS_UE_LOGGING True ) diff --git a/openair3/TEST/EPC_TEST/TEST_1MME_1ENB_1UE_ATTACH_GUTI/attach_complete.pdml b/openair3/TEST/EPC_TEST/TEST_1MME_1ENB_1UE_ATTACH_GUTI/attach_complete.pdml index fef45773f9d3d84bead50d213c4ba94baf5a5391..f7c27272aab199fceddadcd71d16f0cf09105d2f 100644 --- a/openair3/TEST/EPC_TEST/TEST_1MME_1ENB_1UE_ATTACH_GUTI/attach_complete.pdml +++ b/openair3/TEST/EPC_TEST/TEST_1MME_1ENB_1UE_ATTACH_GUTI/attach_complete.pdml @@ -1,7 +1,7 @@ <?xml version="1.0" ?> <?xml-stylesheet type="text/xsl" href="pdml2html.xsl"?> <!-- You can find pdml2html.xsl in /usr/share/wireshark or at http://anonsvn.wireshark.org/trunk/wireshark/pdml2html.xsl. --> -<pdml capture_file="./attach_complete.pcapng" creator="wireshark/1.10.6" time="Wed Oct 14 15:33:08 2015" version="0"> +<pdml capture_file="./attach_complete.pcapng" creator="wireshark/1.10.6" time="Mon Nov 2 09:22:48 2015" version="0"> <packet> <proto name="frame" pos="0" showname="Frame 9: 82 bytes on wire (656 bits), 82 bytes captured (656 bits) on interface 0" size="82"> <field name="frame.interface_id" pos="0" show="0" showname="Interface id: 0" size="0"/> diff --git a/openair3/TEST/EPC_TEST/generic_scenario.xsl b/openair3/TEST/EPC_TEST/generic_scenario.xsl index b1cadbcdfa21a8c42a88705a7d786c6eea2d335b..1d49b4942e703d89d69f76fa46fc943aa372b809 100644 --- a/openair3/TEST/EPC_TEST/generic_scenario.xsl +++ b/openair3/TEST/EPC_TEST/generic_scenario.xsl @@ -106,6 +106,7 @@ <xsl:template match="proto[@name='frame']"> <xsl:variable name="time_relative" select="field[@name='frame.time_relative']/@show"/> + <xsl:variable name="frame_number" select="field[@name='frame.number']/@show"/> <xsl:variable name="ip" select="proto[@name='ip']"/> <xsl:variable name="ip_src"> <xsl:call-template name="reverse_ip"> @@ -131,16 +132,17 @@ <xsl:for-each select="$ip/proto[@name='sctp']"> <xsl:variable name="sctp_data_sid" select="./field/field[@name='sctp.data_sid']/@show"/> <!-- TODO resolv problem of 2 SCTP packets in 1 IP packet: src and dst ports are not in the 2nd SCTP packet --> - <xsl:variable name="sctp_srcport" select="./field[@name='sctp.srcport']/@show"/> - <xsl:variable name="sctp_dstport" select="./field[@name='sctp.dstport']/@show"/> - <xsl:variable name="sctp_data_ssn" select="./field/field[@name='sctp.data_ssn']/@show"/> - <xsl:variable name="sctp_data_payload_proto_id" select="./field/field[@name='sctp.data_payload_proto_id']/@show"/> + <!--xsl:variable name="sctp_srcport" select="./field[@name='sctp.srcport']/@show"/--> + <!--xsl:variable name="sctp_dstport" select="./field[@name='sctp.dstport']/@show"/--> + <!--xsl:variable name="sctp_data_ssn" select="./field/field[@name='sctp.data_ssn']/@show"/--> + <!--xsl:variable name="sctp_data_payload_proto_id" select="./field/field[@name='sctp.data_payload_proto_id']/@show"/--> <xsl:variable name="sctp_chunk_type_str"> <xsl:call-template name="chunktype2str"> <xsl:with-param name="chunk_type" select="./field/field[@name='sctp.chunk_type']/@value"/> </xsl:call-template> </xsl:variable> <xsl:variable name="sctp_pos_offset" select="./@pos"/> + <xsl:variable name="sctp_node" select="."/> <xsl:choose> <xsl:when test="$sctp_chunk_type_str='DATA'"> @@ -148,59 +150,61 @@ <xsl:variable name="s1ap_pos_offset" select="./@pos"/> <packet name="{$sctp_chunk_type_str}" action="{$action}"> <frame.time_relative value="{$time_relative}"/> + <frame.number value="{$frame_number}"/> <!-- TODO: pos_offset(substract it from all pos_offsets in s1ap, may depend on which test scenario protocol target S1AP/NAS or NAS only...)--> <pos_offset value="{$s1ap_pos_offset}"/> <ip.src value="{$ip_src}"/> <ip.dst value="{$ip_dst}"/> - <sctp.data_sid value="{$sctp_data_sid}"/> - <sctp.srcport value="{$sctp_srcport}"/> - <sctp.dstport value="{$sctp_dstport}"/> - <sctp.data_ssn value="{$sctp_data_ssn}"/> - <sctp.data_payload_proto_id value="{$sctp_data_payload_proto_id}"/> + <!--sctp.data_sid value="{$sctp_data_sid}"/--> + <!--sctp.srcport value="{$sctp_srcport}"/--> + <!--sctp.dstport value="{$sctp_dstport}"/--> + <!--sctp.data_ssn value="{$sctp_data_ssn}"/--> + <!--sctp.data_payload_proto_id value="{$sctp_data_payload_proto_id}"/--> <sctp.chunk_type_str value="{$sctp_chunk_type_str}"/> - <xsl:copy-of select="node()"/> + <xsl:copy-of select="$sctp_node"/> </packet> </xsl:for-each> </xsl:when> <xsl:when test="$sctp_chunk_type_str='INIT'"> - <xsl:variable name="sctp_init_nr_out_streams" select="./field/field[@name='sctp.init_nr_out_streams']/@show"/> - <xsl:variable name="sctp_init_nr_in_streams" select="./field/field[@name='sctp.init_nr_in_streams']/@show"/> - <xsl:variable name="sctp_init_initial_tsn" select="./field/field[@name='sctp.init_initial_tsn']/@show"/> + <!--xsl:variable name="sctp_init_nr_out_streams" select="./field/field[@name='sctp.init_nr_out_streams']/@show"/--> + <!--xsl:variable name="sctp_init_nr_in_streams" select="./field/field[@name='sctp.init_nr_in_streams']/@show"/--> + <!--xsl:variable name="sctp_init_initial_tsn" select="./field/field[@name='sctp.init_initial_tsn']/@show"/--> <packet name="{$sctp_chunk_type_str}" action="{$action}"> <frame.time_relative value="{$time_relative}"/> + <frame.number value="{$frame_number}"/> <!-- TODO: pos_offset(substract it from all pos_offsets in s1ap, may depend on which test scenario protocol target S1AP/NAS or NAS only...)--> <pos_offset value="{$sctp_pos_offset}"/> <ip.src value="{$ip_src}"/> <ip.dst value="{$ip_dst}"/> - <sctp.data_sid value="{$sctp_data_sid}"/> - <sctp.srcport value="{$sctp_srcport}"/> - <sctp.dstport value="{$sctp_dstport}"/> - <sctp.init_nr_in_streams value="{$sctp_init_nr_in_streams}"/> - <sctp.init_nr_out_streams value="{$sctp_init_nr_out_streams}"/> - <sctp.init_initial_tsn value="{$sctp_init_initial_tsn}"/> + <!--sctp.srcport value="{$sctp_srcport}"/--> + <!--sctp.dstport value="{$sctp_dstport}"/--> + <!--sctp.init_nr_in_streams value="{$sctp_init_nr_in_streams}"/--> + <!--sctp.init_nr_out_streams value="{$sctp_init_nr_out_streams}"/--> + <!--sctp.init_initial_tsn value="{$sctp_init_initial_tsn}"/--> <sctp.chunk_type_str value="{$sctp_chunk_type_str}"/> - <!--xsl:copy-of select="node()"/--> + <xsl:copy-of select="$sctp_node"/> </packet> </xsl:when> <xsl:when test="$sctp_chunk_type_str='INIT_ACK'"> - <xsl:variable name="sctp_initack_nr_out_streams" select="./field/field[@name='sctp.initack_nr_out_streams']/@show"/> - <xsl:variable name="sctp_initack_nr_in_streams" select="./field/field[@name='sctp.initack_nr_in_streams']/@show"/> - <xsl:variable name="sctp_initack_initial_tsn" select="./field/field[@name='sctp.initack_initial_tsn']/@show"/> + <!--xsl:variable name="sctp_initack_nr_out_streams" select="./field/field[@name='sctp.initack_nr_out_streams']/@show"/--> + <!--xsl:variable name="sctp_initack_nr_in_streams" select="./field/field[@name='sctp.initack_nr_in_streams']/@show"/--> + <!--xsl:variable name="sctp_initack_initial_tsn" select="./field/field[@name='sctp.initack_initial_tsn']/@show"/--> <packet name="{$sctp_chunk_type_str}" action="{$action}"> <frame.time_relative value="{$time_relative}"/> + <frame.number value="{$frame_number}"/> <!-- TODO: pos_offset(substract it from all pos_offsets in s1ap, may depend on which test scenario protocol target S1AP/NAS or NAS only...)--> <pos_offset value="{$sctp_pos_offset}"/> <ip.src value="{$ip_src}"/> <ip.dst value="{$ip_dst}"/> - <sctp.data_sid value="{$sctp_data_sid}"/> - <sctp.srcport value="{$sctp_srcport}"/> - <sctp.dstport value="{$sctp_dstport}"/> - <sctp.initack_nr_in_streams value="{$sctp_initack_nr_in_streams}"/> - <sctp.initack_nr_out_streams value="{$sctp_initack_nr_out_streams}"/> - <sctp.initack_initial_tsn value="{$sctp_initack_initial_tsn}"/> + <!--sctp.data_sid value="{$sctp_data_sid}"/--> + <!--sctp.srcport value="{$sctp_srcport}"/--> + <!--sctp.dstport value="{$sctp_dstport}"/--> + <!--sctp.initack_nr_in_streams value="{$sctp_initack_nr_in_streams}"/--> + <!--sctp.initack_nr_out_streams value="{$sctp_initack_nr_out_streams}"/--> + <!--sctp.initack_initial_tsn value="{$sctp_initack_initial_tsn}"/--> <sctp.chunk_type_str value="{$sctp_chunk_type_str}"/> - <!--xsl:copy-of select="node()"/--> + <xsl:copy-of select="$sctp_node"/> </packet> </xsl:when> <!--xsl:when test="$sctp_chunk_type_str='SACK'"> </xsl:when--> @@ -209,44 +213,47 @@ <xsl:when test="$sctp_chunk_type_str='ABORT'"> <packet name="{$sctp_chunk_type_str}" action="{$action}"> <frame.time_relative value="{$time_relative}"/> + <frame.number value="{$frame_number}"/> <!-- TODO: pos_offset(substract it from all pos_offsets in s1ap, may depend on which test scenario protocol target S1AP/NAS or NAS only...)--> <pos_offset value="{$sctp_pos_offset}"/> <ip.src value="{$ip_src}"/> <ip.dst value="{$ip_dst}"/> - <sctp.data_sid value="{$sctp_data_sid}"/> - <sctp.srcport value="{$sctp_srcport}"/> - <sctp.dstport value="{$sctp_dstport}"/> + <!--sctp.data_sid value="{$sctp_data_sid}"/--> + <!--sctp.srcport value="{$sctp_srcport}"/--> + <!--sctp.dstport value="{$sctp_dstport}"/--> <sctp.chunk_type_str value="{$sctp_chunk_type_str}"/> - <xsl:copy-of select="node()"/> + <xsl:copy-of select="$sctp_node"/> </packet> </xsl:when> <xsl:when test="$sctp_chunk_type_str='SHUTDOWN'"> <packet name="{$sctp_chunk_type_str}" action="{$action}"> <frame.time_relative value="{$time_relative}"/> + <frame.number value="{$frame_number}"/> <!-- TODO: pos_offset(substract it from all pos_offsets in s1ap, may depend on which test scenario protocol target S1AP/NAS or NAS only...)--> <pos_offset value="{$sctp_pos_offset}"/> <ip.src value="{$ip_src}"/> <ip.dst value="{$ip_dst}"/> - <sctp.data_sid value="{$sctp_data_sid}"/> - <sctp.srcport value="{$sctp_srcport}"/> - <sctp.dstport value="{$sctp_dstport}"/> + <!--sctp.data_sid value="{$sctp_data_sid}"/--> + <!--sctp.srcport value="{$sctp_srcport}"/--> + <!--sctp.dstport value="{$sctp_dstport}"/--> <sctp.chunk_type_str value="{$sctp_chunk_type_str}"/> - <xsl:copy-of select="node()"/> + <xsl:copy-of select="$sctp_node"/> </packet> </xsl:when> <!--xsl:when test="$sctp_chunk_type_str='SHUTDOWN_ACK'"></xsl:when--> <xsl:when test="$sctp_chunk_type_str='ERROR'"> <packet name="{$sctp_chunk_type_str}" action="{$action}"> <frame.time_relative value="{$time_relative}"/> + <frame.number value="{$frame_number}"/> <!-- TODO: pos_offset(substract it from all pos_offsets in s1ap, may depend on which test scenario protocol target S1AP/NAS or NAS only...)--> <pos_offset value="{$sctp_pos_offset}"/> <ip.src value="{$ip_src}"/> <ip.dst value="{$ip_dst}"/> - <sctp.data_sid value="{$sctp_data_sid}"/> - <sctp.srcport value="{$sctp_srcport}"/> - <sctp.dstport value="{$sctp_dstport}"/> + <!--sctp.data_sid value="{$sctp_data_sid}"/--> + <!--sctp.srcport value="{$sctp_srcport}"/--> + <!--sctp.dstport value="{$sctp_dstport}"/--> <sctp.chunk_type_str value="{$sctp_chunk_type_str}"/> - <xsl:copy-of select="node()"/> + <xsl:copy-of select="$sctp_node"/> </packet> </xsl:when> <!--xsl:when test="$sctp_chunk_type_str='COOKIE_ECHO'"> </xsl:when--> diff --git a/openair3/TEST/EPC_TEST/play_scenario.c b/openair3/TEST/EPC_TEST/play_scenario.c index e73a41a68372a207f0da37bfd8b5782ec3c40e48..a32947c43960066afe17de1b4019bb7391a3e258 100644 --- a/openair3/TEST/EPC_TEST/play_scenario.c +++ b/openair3/TEST/EPC_TEST/play_scenario.c @@ -46,6 +46,7 @@ #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/time.h> #include <unistd.h> #include <libxml/xmlmemory.h> #include <libxml/debugXML.h> @@ -53,6 +54,7 @@ #include <libxml/DOCBparser.h> #include <libxml/xinclude.h> #include <libxml/catalog.h> +#include <libxml/xmlreader.h> #include <libxslt/xslt.h> #include <libxslt/xsltInternals.h> #include <libxslt/transform.h> @@ -60,9 +62,13 @@ #include "assertions.h" #include "play_scenario.h" -#include "s1ap_eNB.h" +//#include "s1ap_eNB.h" +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_eNB_decoder.h" #include "intertask_interface.h" #include "enb_config.h" +#include "log.h" //------------------------------------------------------------------------------ #define ENB_CONFIG_MAX_XSLT_PARAMS 32 #define PLAY_SCENARIO 1 @@ -73,8 +79,100 @@ char *g_openair_dir = NULL; //------------------------------------------------------------------------------ extern Enb_properties_array_t enb_properties; extern int xmlLoadExtDtdDefaultValue; - +extern int asn_debug; +extern int asn1_xer_print; //------------------------------------------------------------------------------ +void test_print_hex_octets(const unsigned char * const byte_stream, const unsigned long int num); +int is_file_exists ( const char const * file_nameP, const char const *file_roleP); +int strip_extension( char *in_filename); +int split_path ( char * pathP, char *** resP); +void display_node ( xmlNodePtr node, unsigned int indent); +void display_tree ( xmlNodePtr node, unsigned int indent); +//------------------------- +void free_packet(test_packet_t* packet); +void free_scenario(test_scenario_t* scenario); +//------------------------- +void display_packet_sctp_init(const sctp_inithdr_t * const sctp); +void display_packet_sctp_initack(const sctp_initackhdr_t * const sctp); +void display_packet_sctp_data(const sctp_datahdr_t * const sctp); +void display_packet_sctp(const test_sctp_hdr_t * const sctp); +void display_packet_ip(const test_ip_hdr_t * const ip); +void display_packet(const test_packet_t * const packet); +void display_scenario(const test_scenario_t * const scenario); +//------------------------- +char * test_ip2ip_str(const test_ip_t * const ip); +int hex2data(unsigned char * const data, const unsigned char * const hexstring, const unsigned int len); +sctp_cid_t chunk_type_str2cid(const xmlChar * const chunk_type_str); +const char * const chunk_type_cid2str(const sctp_cid_t chunk_type); +test_action_t action_str2test_action_t(const xmlChar * const action); +void ip_str2test_ip(const xmlChar * const ip_str, test_ip_t * const ip); +//------------------------- +int test_s1ap_decode_initiating_message(s1ap_message *message, S1ap_InitiatingMessage_t *initiating_p); +int test_s1ap_decode_successful_outcome(s1ap_message *message, S1ap_SuccessfulOutcome_t *successfullOutcome_p); +int test_s1ap_decode_unsuccessful_outcome(s1ap_message *message, S1ap_UnsuccessfulOutcome_t *unSuccessfullOutcome_p); +int test_s1ap_decode_pdu(s1ap_message *message, const uint8_t * const buffer,const uint32_t length); +void test_decode_s1ap(test_s1ap_t * const s1ap); +//------------------------- +void parse_s1ap(xmlDocPtr doc, const xmlNode const *s1ap_node, test_s1ap_t * const s1ap); +void parse_sctp_data_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_datahdr_t * const sctp_hdr); +void parse_sctp_init_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_inithdr_t * const sctp_hdr); +void parse_sctp_init_ack_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_initackhdr_t * const sctp_hdr); +void parse_sctp(xmlDocPtr doc, const xmlNode const *sctp_node, test_sctp_hdr_t * const sctp_hdr); +test_packet_t* parse_xml_packet(xmlDocPtr doc, xmlNodePtr node); +//------------------------- +int play_scenario(test_scenario_t* scenario); +int generate_xml_scenario( + const char const * test_dir_name, + const char const * test_scenario_filename, + const char const * enb_config_filename, + char const * play_scenario_filename /* OUT PARAM*/); + +//----------------------------------------------------------------------------- +void test_print_hex_octets(const unsigned char * const byte_stream, const unsigned long int num) +//----------------------------------------------------------------------------- +{ + unsigned long octet_index = 0; + + if (byte_stream == NULL) { + return; + } + + + + + fprintf(stdout, "+-----+-------------------------------------------------+\n"); + fprintf(stdout, "| | 0 1 2 3 4 5 6 7 8 9 a b c d e f |\n"); + fprintf(stdout, "+-----+-------------------------------------------------+\n"); + + for (octet_index = 0; octet_index < num; octet_index++) { + if ((octet_index % 16) == 0) { + if (octet_index != 0) { + fprintf(stdout, " |\n"); + } + + fprintf(stdout, " %04ld |", octet_index); + } + + /* + * Print every single octet in hexadecimal form + */ + fprintf(stdout, " %02x", byte_stream[octet_index]); + /* + * Align newline and pipes according to the octets in groups of 2 + */ + } + + /* + * Append enough spaces and put final pipe + */ + unsigned char index; + + for (index = octet_index; index < 16; ++index) { + fprintf(stdout, " "); + } + + fprintf(stdout, " |\n"); +} //------------------------------------------------------------------------------ // test if file exist in current directory @@ -138,9 +236,14 @@ int split_path( char * pathP, char *** resP) return n_spaces; } //------------------------------------------------------------------------------ -void display_node(xmlNodePtr node) { +void display_node(xmlNodePtr node, unsigned int indent) +{ + int i = 0; if (node->type == XML_ELEMENT_NODE) { xmlChar *path = xmlGetNodePath(node); + for (i=0; i<indent; i++) { + printf(" "); + } if (node->children != NULL && node->children->type == XML_TEXT_NODE) { xmlChar *content = xmlNodeGetContent(node); printf("%s -> %s\n", path, content); @@ -151,13 +254,229 @@ void display_node(xmlNodePtr node) { xmlFree(path); } } +/** + * print_element_names: + * @node: the initial xml node to consider. + * @indent: indentation level. + * + * Prints the names of the all the xml elements + * that are siblings or children of a given xml node. + */ +//------------------------------------------------------------------------------ +void display_tree(xmlNodePtr node, unsigned int indent) +{ + xmlNode *cur_node = NULL; + + for (cur_node = node; cur_node; cur_node = cur_node->next) { + if (cur_node->type == XML_ELEMENT_NODE) { + display_node(cur_node, indent); + } + display_tree(cur_node->children, indent++); + } +} +//------------------------------------------------------------------------------ +void free_packet(test_packet_t* packet) +{ + if (packet) { + switch (packet->sctp_hdr.chunk_type) { + case SCTP_CID_DATA: + free_pointer(packet->sctp_hdr.u.data_hdr.payload.binary_stream); + break; + default: + ; + } + free_pointer(packet); + } +} + //------------------------------------------------------------------------------ void free_scenario(test_scenario_t* scenario) { - //TODO + test_packet_t *packet = NULL; + test_packet_t *next_packet = NULL; + if (scenario) { + packet = scenario->list_packet; + while (packet) { + next_packet = packet->next; + free_packet(packet); + packet = next_packet->next; + } + free_pointer(scenario); + } +} + + +//------------------------------------------------------------------------------ +void display_packet_sctp_init(const sctp_inithdr_t * const sctp) +{ + + if (sctp) { + fprintf(stdout, "\t\tSCTP.init.init_tag : %u\n", sctp->init_tag); + fprintf(stdout, "\t\tSCTP.init.a_rwnd : %u\n", sctp->a_rwnd); + fprintf(stdout, "\t\tSCTP.init.num_inbound_streams : %u\n", sctp->num_inbound_streams); + fprintf(stdout, "\t\tSCTP.init.num_outbound_streams : %u\n", sctp->num_outbound_streams); + fprintf(stdout, "\t\tSCTP.init.initial_tsn : %u\n", sctp->initial_tsn); + } +} +//------------------------------------------------------------------------------ +void display_packet_sctp_initack(const sctp_initackhdr_t * const sctp) +{ + + if (sctp) { + fprintf(stdout, "\t\tSCTP.initack.init_tag : %u\n", sctp->init_tag); + fprintf(stdout, "\t\tSCTP.initack.a_rwnd : %u\n", sctp->a_rwnd); + fprintf(stdout, "\t\tSCTP.initack.num_inbound_streams : %u\n", sctp->num_inbound_streams); + fprintf(stdout, "\t\tSCTP.initack.num_outbound_streams : %u\n", sctp->num_outbound_streams); + fprintf(stdout, "\t\tSCTP.initack.initial_tsn : %u\n", sctp->initial_tsn); + } +} +//------------------------------------------------------------------------------ +void display_packet_sctp_data(const sctp_datahdr_t * const sctp) +{ + if (sctp) { + fprintf(stdout, "\t\tSCTP.data.tsn : %u\n", sctp->tsn); + fprintf(stdout, "\t\tSCTP.data.stream : %u\n", sctp->stream); + fprintf(stdout, "\t\tSCTP.data.ssn : %u\n", sctp->ssn); + fprintf(stdout, "\t\tSCTP.data.ppid : %u\n", sctp->ppid); + //fprintf(stdout, "\t\tSCTP.data.pdu_type : %u\n", sctp->payload.pdu_type); + //fprintf(stdout, "\t\tSCTP.data.procedure_code : %u\n", sctp->payload.procedure_code); + fprintf(stdout, "\t\tSCTP.data.binary_stream_allocated_size : %u\n", sctp->payload.binary_stream_allocated_size); + if (NULL != sctp->payload.binary_stream) { + fprintf(stdout, "\t\tSCTP.data.binary_stream :\n"); + test_print_hex_octets(sctp->payload.binary_stream, sctp->payload.binary_stream_allocated_size); + } else { + fprintf(stdout, "\t\tSCTP.data.binary_stream : NULL\n"); + } + } +} + +//------------------------------------------------------------------------------ +void display_packet_sctp(const test_sctp_hdr_t * const sctp) +{ + if (sctp) { + fprintf(stdout, "\t\tSCTP.src_port : %u\n", sctp->src_port); + fprintf(stdout, "\t\tSCTP.dst_port : %u\n", sctp->dst_port); + fprintf(stdout, "\t\tSCTP.chunk_type : %s\n", chunk_type_cid2str(sctp->chunk_type)); + switch (sctp->chunk_type) { + case SCTP_CID_DATA: + display_packet_sctp_data(&sctp->u.data_hdr); + break; + case SCTP_CID_INIT: + display_packet_sctp_initack(&sctp->u.init_hdr); + break; + case SCTP_CID_INIT_ACK: + display_packet_sctp_initack(&sctp->u.init_ack_hdr); + break; + default: + ; + } + } +} +//------------------------------------------------------------------------------ +void display_packet_ip(const test_ip_hdr_t * const ip) +{ + if (ip) { + fprintf(stdout, "\t\tSource address : %s\n", test_ip2ip_str(&ip->src)); + fprintf(stdout, "\t\tDestination address : %s\n", test_ip2ip_str(&ip->dst)); + } +} + +//------------------------------------------------------------------------------ +void display_packet(const test_packet_t * const packet) +{ + if (packet) { + fprintf(stdout, "\tPacket:\tnum %u | original frame number %u \n", packet->packet_number, packet->original_frame_number); + fprintf(stdout, "\tPacket:\ttime relative to 1st packet %ld.%06lu\n", + packet->time_relative_to_first_packet.tv_sec, packet->time_relative_to_first_packet.tv_usec); + fprintf(stdout, "\tPacket:\ttime relative to last tx packet %ld.%06lu\n", + packet->time_relative_to_last_sent_packet.tv_sec, packet->time_relative_to_last_sent_packet.tv_usec); + fprintf(stdout, "\tPacket:\ttime relative to last_received packet %ld.%06lu\n", + packet->time_relative_to_last_received_packet.tv_sec, packet->time_relative_to_last_received_packet.tv_usec); + + switch(packet->action) { + case ACTION_S1C_SEND: + fprintf(stdout, "\tPacket:\tAction SEND\n"); + break; + case ACTION_S1C_RECEIVE: + fprintf(stdout, "\tPacket:\tAction RECEIVE\n"); + break; + default: + fprintf(stdout, "\tPacket:\tAction UNKNOWN\n"); + } + display_packet_ip(&packet->ip_hdr); + display_packet_sctp(&packet->sctp_hdr); + } } //------------------------------------------------------------------------------ -sctp_cid_t chunk_type_str2cid(xmlChar *chunk_type_str) +void display_scenario(const test_scenario_t * const scenario) +{ + test_packet_t *packet = NULL; + if (scenario) { + fprintf(stdout, "Scenario: %s\n", (scenario->name != NULL) ? (char*)scenario->name:"UNKNOWN NAME"); + packet = scenario->list_packet; + while (packet) { + display_packet(packet); + packet = packet->next; + } + } +} + +//------------------------------------------------------------------------------ +char * test_ip2ip_str(const test_ip_t * const ip) +{ + static char str[INET6_ADDRSTRLEN]; + + sprintf(str, "ERROR"); + switch (ip->address_family) { + case AF_INET6: + inet_ntop(AF_INET6, &(ip->address.ipv6), str, INET6_ADDRSTRLEN); + break; + case AF_INET: + inet_ntop(AF_INET, &(ip->address.ipv4), str, INET_ADDRSTRLEN); + break; + default: + ; + } + return str; +} +//------------------------------------------------------------------------------ +//convert hexstring to len bytes of data +//returns 0 on success, negative on error +//data is a buffer of at least len bytes +//hexstring is upper or lower case hexadecimal, NOT prepended with "0x" +int hex2data(unsigned char * const data, const unsigned char * const hexstring, const unsigned int len) +{ + unsigned const char *pos = hexstring; + char *endptr = NULL; + size_t count = 0; + + fprintf(stdout, "%s(%s,%d)\n", __FUNCTION__, hexstring, len); + + if ((len > 1) && (strlen((const char*)hexstring) % 2)) { + //or hexstring has an odd length + return -3; + } + + if (len == 1) { + char buf[5] = {'0', 'x', 0, pos[0], '\0'}; + data[0] = strtol(buf, &endptr, 16); + /* Check for various possible errors */ + AssertFatal ((errno == 0) || (data[0] != 0), "ERROR %s() strtol: %s\n", __FUNCTION__, strerror(errno)); + AssertFatal (endptr != buf, "ERROR %s() No digits were found\n", __FUNCTION__); + return 0; + } + + for(count = 0; count < len/2; count++) { + char buf[5] = {'0', 'x', pos[0], pos[1], 0}; + data[count] = strtol(buf, &endptr, 16); + pos += 2 * sizeof(char); + AssertFatal (endptr[0] == '\0', "ERROR %s() non-hexadecimal character encountered buf %p endptr %p buf %s count %d pos %p\n", __FUNCTION__, buf, endptr, buf, count, pos); + AssertFatal (endptr != buf, "ERROR %s() No digits were found\n", __FUNCTION__); + } + return 0; +} +//------------------------------------------------------------------------------ +sctp_cid_t chunk_type_str2cid(const xmlChar * const chunk_type_str) { if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"DATA"))) { return SCTP_CID_DATA;} if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"INIT"))) { return SCTP_CID_INIT;} @@ -178,31 +497,599 @@ sctp_cid_t chunk_type_str2cid(xmlChar *chunk_type_str) if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"FWD_TSN"))) { return SCTP_CID_FWD_TSN;} if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"ASCONF"))) { return SCTP_CID_ASCONF;} if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"ASCONF_ACK"))) { return SCTP_CID_ASCONF_ACK;} - fprintf(stderr, "ERROR: Could not convert: %s\n", chunk_type_str); - exit(-1); + AssertFatal (0, "ERROR: %s() cannot convert: %s\n", __FUNCTION__, chunk_type_str); +} +//------------------------------------------------------------------------------ +const char * const chunk_type_cid2str(const sctp_cid_t chunk_type) +{ + switch (chunk_type) { + case SCTP_CID_DATA: return "DATA"; break; + case SCTP_CID_INIT: return "INIT"; break; + case SCTP_CID_INIT_ACK: return "INIT_ACK"; break; + case SCTP_CID_SACK: return "SACK"; break; + case SCTP_CID_HEARTBEAT: return "HEARTBEAT"; break; + case SCTP_CID_HEARTBEAT_ACK: return "HEARTBEAT_ACK"; break; + case SCTP_CID_ABORT: return "ABORT"; break; + case SCTP_CID_SHUTDOWN: return "SHUTDOWN"; break; + case SCTP_CID_SHUTDOWN_ACK: return "SHUTDOWN_ACK"; break; + case SCTP_CID_ERROR: return "ERROR"; break; + case SCTP_CID_COOKIE_ECHO: return "COOKIE_ECHO"; break; + case SCTP_CID_COOKIE_ACK: return "COOKIE_ACK"; break; + case SCTP_CID_ECN_ECNE: return "ECN_ECNE"; break; + case SCTP_CID_ECN_CWR: return "ECN_CWR"; break; + case SCTP_CID_SHUTDOWN_COMPLETE: return "SHUTDOWN_COMPLETE"; break; + case SCTP_CID_AUTH: return "AUTH"; break; + case SCTP_CID_FWD_TSN: return "FWD_TSN"; break; + case SCTP_CID_ASCONF: return "ASCONF"; break; + case SCTP_CID_ASCONF_ACK: return "ASCONF_ACK"; break; + default: + AssertFatal (0, "ERROR %s(): Unknown chunk_type %d!\n", __FUNCTION__, chunk_type); + } +} +//------------------------------------------------------------------------------ +test_action_t action_str2test_action_t(const xmlChar * const action) +{ + if ((!xmlStrcmp(action, (const xmlChar *)"SEND"))) { return ACTION_S1C_SEND;} + if ((!xmlStrcmp(action, (const xmlChar *)"RECEIVE"))) { return ACTION_S1C_RECEIVE;} + AssertFatal (0, "ERROR: %s cannot convert: %s\n", __FUNCTION__, action); + //if (NULL == action) {return ACTION_S1C_NULL;} +} +//------------------------------------------------------------------------------ +void ip_str2test_ip(const xmlChar * const ip_str, test_ip_t * const ip) +{ + AssertFatal (NULL != ip_str, "ERROR %s() Cannot convert null string to ip address!\n", __FUNCTION__); + AssertFatal (NULL != ip, "ERROR %s() out parameter pointer is NULL!\n", __FUNCTION__); + // store this IP address in sa: + if (inet_pton(AF_INET, (const char*)ip_str, (void*)&(ip->address.ipv4)) > 0) { + ip->address_family = AF_INET; + } else if (inet_pton(AF_INET6, (const char*)ip_str, (void*)&(ip->address.ipv6)) > 0) { + ip->address_family = AF_INET6; + } else { + ip->address_family = AF_UNSPEC; + AssertFatal (0, "ERROR %s() Could not parse ip address %s!\n", __FUNCTION__, ip_str); + } +} +//------------------------------------------------------------------------------ +int test_s1ap_decode_initiating_message(s1ap_message *message, + S1ap_InitiatingMessage_t *initiating_p) +{ + int ret = -1; + + DevAssert(initiating_p != NULL); + + message->procedureCode = initiating_p->procedureCode; + message->criticality = initiating_p->criticality; + + switch(initiating_p->procedureCode) { + case S1ap_ProcedureCode_id_downlinkNASTransport: + ret = s1ap_decode_s1ap_downlinknastransporties( + &message->msg.s1ap_DownlinkNASTransportIEs, + &initiating_p->value); + break; + + case S1ap_ProcedureCode_id_InitialContextSetup: + ret = s1ap_decode_s1ap_initialcontextsetuprequesties( + &message->msg.s1ap_InitialContextSetupRequestIEs, &initiating_p->value); + break; + + case S1ap_ProcedureCode_id_UEContextRelease: + ret = s1ap_decode_s1ap_uecontextreleasecommandies( + &message->msg.s1ap_UEContextReleaseCommandIEs, &initiating_p->value); + break; + + case S1ap_ProcedureCode_id_Paging: + ret = s1ap_decode_s1ap_pagingies( + &message->msg.s1ap_PagingIEs, &initiating_p->value); + break; + + case S1ap_ProcedureCode_id_uplinkNASTransport: { + ret = s1ap_decode_s1ap_uplinknastransporties (&message->msg.s1ap_UplinkNASTransportIEs, &initiating_p->value); + } + break; + + case S1ap_ProcedureCode_id_S1Setup: { + ret = s1ap_decode_s1ap_s1setuprequesties (&message->msg.s1ap_S1SetupRequestIEs, &initiating_p->value); + } + break; + + case S1ap_ProcedureCode_id_initialUEMessage: { + ret = s1ap_decode_s1ap_initialuemessageies (&message->msg.s1ap_InitialUEMessageIEs, &initiating_p->value); + } + break; + + case S1ap_ProcedureCode_id_UEContextReleaseRequest: { + ret = s1ap_decode_s1ap_uecontextreleaserequesties (&message->msg.s1ap_UEContextReleaseRequestIEs, &initiating_p->value); + } + break; + + case S1ap_ProcedureCode_id_UECapabilityInfoIndication: { + ret = s1ap_decode_s1ap_uecapabilityinfoindicationies (&message->msg.s1ap_UECapabilityInfoIndicationIEs, &initiating_p->value); + } + break; + + case S1ap_ProcedureCode_id_NASNonDeliveryIndication: { + ret = s1ap_decode_s1ap_nasnondeliveryindication_ies (&message->msg.s1ap_NASNonDeliveryIndication_IEs, &initiating_p->value); + } + break; + + default: + AssertFatal( 0 , "Unknown procedure ID (%d) for initiating message\n", + (int)initiating_p->procedureCode); + return -1; + } + return ret; +} + +//------------------------------------------------------------------------------ +int test_s1ap_decode_successful_outcome(s1ap_message *message, + S1ap_SuccessfulOutcome_t *successfullOutcome_p) +{ + int ret = -1; + + DevAssert(successfullOutcome_p != NULL); + + message->procedureCode = successfullOutcome_p->procedureCode; + message->criticality = successfullOutcome_p->criticality; + + switch(successfullOutcome_p->procedureCode) { + case S1ap_ProcedureCode_id_S1Setup: + ret = s1ap_decode_s1ap_s1setupresponseies( + &message->msg.s1ap_S1SetupResponseIEs, &successfullOutcome_p->value); + break; + + case S1ap_ProcedureCode_id_InitialContextSetup: { + ret = s1ap_decode_s1ap_initialcontextsetupresponseies (&message->msg.s1ap_InitialContextSetupResponseIEs, &successfullOutcome_p->value); + } + break; + + case S1ap_ProcedureCode_id_UEContextRelease: { + ret = s1ap_decode_s1ap_uecontextreleasecompleteies (&message->msg.s1ap_UEContextReleaseCompleteIEs, &successfullOutcome_p->value); + } + break; + + default: + AssertFatal(0, "Unknown procedure ID (%d) for successfull outcome message\n", + (int)successfullOutcome_p->procedureCode); + return -1; + } + return ret; +} + +//------------------------------------------------------------------------------ +int test_s1ap_decode_unsuccessful_outcome(s1ap_message *message, + S1ap_UnsuccessfulOutcome_t *unSuccessfullOutcome_p) +{ + int ret = -1; + DevAssert(unSuccessfullOutcome_p != NULL); + + message->procedureCode = unSuccessfullOutcome_p->procedureCode; + message->criticality = unSuccessfullOutcome_p->criticality; + + switch(unSuccessfullOutcome_p->procedureCode) { + case S1ap_ProcedureCode_id_S1Setup: + return s1ap_decode_s1ap_s1setupfailureies( + &message->msg.s1ap_S1SetupFailureIEs, &unSuccessfullOutcome_p->value); + + case S1ap_ProcedureCode_id_InitialContextSetup: { + ret = s1ap_decode_s1ap_initialcontextsetupfailureies (&message->msg.s1ap_InitialContextSetupFailureIEs, &unSuccessfullOutcome_p->value); + } + break; + + + default: + AssertFatal(0,"Unknown procedure ID (%d) for unsuccessfull outcome message\n", + (int)unSuccessfullOutcome_p->procedureCode); + break; + } + + return ret; +} + +//------------------------------------------------------------------------------ +int test_s1ap_decode_pdu(s1ap_message *message, const uint8_t * const buffer, + const uint32_t length) +{ + S1AP_PDU_t pdu; + S1AP_PDU_t *pdu_p = &pdu; + asn_dec_rval_t dec_ret; + + DevAssert(buffer != NULL); + + memset((void *)pdu_p, 0, sizeof(S1AP_PDU_t)); + + dec_ret = aper_decode(NULL, + &asn_DEF_S1AP_PDU, + (void **)&pdu_p, + buffer, + length, + 0, + 0); + + if (dec_ret.code != RC_OK) { + S1AP_ERROR("Failed to decode pdu\n"); + return -1; + } + + message->direction = pdu_p->present; + + switch(pdu_p->present) { + case S1AP_PDU_PR_initiatingMessage: + return test_s1ap_decode_initiating_message(message, + &pdu_p->choice.initiatingMessage); + + case S1AP_PDU_PR_successfulOutcome: + return test_s1ap_decode_successful_outcome(message, + &pdu_p->choice.successfulOutcome); + + case S1AP_PDU_PR_unsuccessfulOutcome: + return test_s1ap_decode_unsuccessful_outcome(message, + &pdu_p->choice.unsuccessfulOutcome); + + default: + AssertFatal(0, "Unknown presence (%d) or not implemented\n", (int)pdu_p->present); + break; + } + return -1; +} +//------------------------------------------------------------------------------ +void test_decode_s1ap(test_s1ap_t * const s1ap) +{ + if (NULL != s1ap) { + if (test_s1ap_decode_pdu(&s1ap->message, s1ap->binary_stream, s1ap->binary_stream_allocated_size) < 0) { + AssertFatal (0, "ERROR %s() Cannot decode S1AP message!\n", __FUNCTION__); + } + } +} +//------------------------------------------------------------------------------ +void parse_s1ap(xmlDocPtr doc, const xmlNode const *s1ap_node, test_s1ap_t * const s1ap) +{ + xmlNode *cur_node = NULL; + xmlChar *xml_char = NULL; + xmlChar *xml_char2 = NULL; + unsigned int size = 0; + int rc = 0; + unsigned int go_deeper_in_tree = 1; + + if ((NULL != s1ap_node) && (NULL != s1ap)) { + for (cur_node = (xmlNode *)s1ap_node; cur_node; cur_node = cur_node->next) { + go_deeper_in_tree = 1; + if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"field"))) { + // do not get hidden fields + xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"hide"); + if (NULL != xml_char) { + if ((!xmlStrcmp(xml_char, (const xmlChar *)"yes"))) { + xmlFree(xml_char); + return; + } + xmlFree(xml_char); + } + // first get size + xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"size"); + if (NULL != xml_char) { + size = strtoul((const char *)xml_char, NULL, 0); + xmlFree(xml_char); + // second: try to get value (always hex) + xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"value"); + if (NULL != xml_char) { + xml_char2 = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"name"); + fprintf(stdout, "s1ap %p field %s size %d value %s\n",s1ap, xml_char2, size, xml_char); + xmlFree(xml_char2); + // if success to get value, do not parse children + //AssertFatal ((xmlStrlen(xml_char) == size), "ERROR %s() mismatch in size %d and strlen %d\n", __FUNCTION__, size, xmlStrlen(xml_char)); + //if (xmlStrlen(xml_char) == size) { + AssertFatal ((s1ap->binary_stream_pos+xmlStrlen(xml_char)/2) <= s1ap->binary_stream_allocated_size, + "ERROR %s() in buffer size: binary_stream_pos %d xmlStrlen(xml_char)/2=%d\n", __FUNCTION__, s1ap->binary_stream_pos, xmlStrlen(xml_char)/2); + rc = hex2data( &s1ap->binary_stream[s1ap->binary_stream_pos], xml_char, xmlStrlen(xml_char)); + s1ap->binary_stream_pos += xmlStrlen(xml_char)/2; + display_node(cur_node, 0); + AssertFatal (rc >= 0, "ERROR %s() in converting hex string %s len %d size %d rc %d\n", __FUNCTION__, xml_char, xmlStrlen(xml_char), size, rc); + go_deeper_in_tree = 0; + //} + xmlFree(xml_char); + } + } + } + if (0 < go_deeper_in_tree) { + parse_s1ap(doc, cur_node->children, s1ap); + } + } + } } + //------------------------------------------------------------------------------ -test_packet_t* parse_xml_packet(xmlNodePtr node) { +void parse_sctp_data_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_datahdr_t * const sctp_hdr) +{ + xmlNode *cur_node = NULL; + xmlChar *xml_char = NULL; + xmlChar *xml_char2 = NULL; + + if ((NULL != sctp_node) && (NULL != sctp_hdr)) { + xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name"); + if (NULL != xml_char) { + if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.data_payload_proto_id"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show"); + if (NULL != xml_char2) { + sctp_hdr->ppid = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.data_sid"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show"); + if (NULL != xml_char2) { + sctp_hdr->stream = strtoul((const char *)xml_char2, NULL, 16); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.data_tsn"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show"); + if (NULL != xml_char2) { + sctp_hdr->tsn = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.data_ssn"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show"); + if (NULL != xml_char2) { + sctp_hdr->ssn = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } + xmlFree(xml_char); + } + for (cur_node = sctp_node->children; cur_node; cur_node = cur_node->next) { + parse_sctp_data_chunk(doc, cur_node, sctp_hdr); + } + } + +} +//------------------------------------------------------------------------------ +void parse_sctp_init_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_inithdr_t * const sctp_hdr) +{ + xmlNode *cur_node = NULL; + xmlChar *xml_char = NULL; + xmlChar *xml_char2 = NULL; - test_packet_t *packet = NULL; - xmlNode *cur_node = NULL; - xmlChar *xml_char = NULL; + if ((NULL != sctp_node) && (NULL != sctp_hdr)) { + xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name"); + if (NULL != xml_char) { + if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_nr_out_streams"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value"); + if (NULL != xml_char2) { + sctp_hdr->num_outbound_streams = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_nr_in_streams"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value"); + if (NULL != xml_char2) { + sctp_hdr->num_inbound_streams = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_credit"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value"); + if (NULL != xml_char2) { + sctp_hdr->a_rwnd = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_initial_tsn"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show"); + if (NULL != xml_char2) { + sctp_hdr->initial_tsn = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_initiate_tag"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show"); + if (NULL != xml_char2) { + sctp_hdr->init_tag = strtoul((const char *)xml_char2, NULL, 16); + xmlFree(xml_char2); + } + } + xmlFree(xml_char); + } + for (cur_node = sctp_node->children; cur_node; cur_node = cur_node->next) { + parse_sctp_init_chunk(doc, cur_node, sctp_hdr); + } + } +} +//------------------------------------------------------------------------------ +void parse_sctp_init_ack_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_initackhdr_t * const sctp_hdr) +{ + xmlNode *cur_node = NULL; + xmlChar *xml_char = NULL; + xmlChar *xml_char2 = NULL; + + if ((NULL != sctp_node) && (NULL != sctp_hdr)) { + xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name"); + if (NULL != xml_char) { + if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_nr_out_streams"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value"); + if (NULL != xml_char2) { + sctp_hdr->num_outbound_streams = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_nr_in_streams"))) { + xml_char2 = xmlGetProp((xmlNode *)(xmlNode *)sctp_node, (const xmlChar *)"value"); + if (NULL != xml_char2) { + sctp_hdr->num_inbound_streams = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_credit"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value"); + if (NULL != xml_char2) { + sctp_hdr->a_rwnd = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_initial_tsn"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show"); + if (NULL != xml_char2) { + sctp_hdr->initial_tsn = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_initiate_tag"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show"); + if (NULL != xml_char2) { + sctp_hdr->init_tag = strtoul((const char *)xml_char2, NULL, 16); + xmlFree(xml_char2); + } + } + xmlFree(xml_char); + } + for (cur_node = sctp_node->children; cur_node; cur_node = cur_node->next) { + parse_sctp_init_ack_chunk(doc, cur_node, sctp_hdr); + } + } +} +//------------------------------------------------------------------------------ +void parse_sctp(xmlDocPtr doc, const xmlNode const *sctp_node, test_sctp_hdr_t * const sctp_hdr) +{ + xmlNode *cur_node = NULL; + xmlChar *xml_char = NULL; + xmlChar *xml_char2 = NULL; + + if ((NULL != sctp_node) && (NULL != sctp_hdr)) { + if ((!xmlStrcmp(sctp_node->name, (const xmlChar *)"proto"))) { + xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name"); + if (NULL != xml_char) { + if ((!xmlStrcmp(xml_char, (const xmlChar *)"s1ap"))) { + xmlFree(xml_char); + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"size"); + if (NULL != xml_char2) { + sctp_hdr->u.data_hdr.payload.binary_stream_allocated_size = strtoul((const char *)xml_char2, NULL, 0); + sctp_hdr->u.data_hdr.payload.binary_stream = calloc(1, sctp_hdr->u.data_hdr.payload.binary_stream_allocated_size); + xmlFree(xml_char2); + } + parse_s1ap(doc, sctp_node, &sctp_hdr->u.data_hdr.payload); + test_decode_s1ap(&sctp_hdr->u.data_hdr.payload); + return; + } + xmlFree(xml_char); + } + } + //if ((cur_node->type == XML_ATTRIBUTE_NODE) || (cur_node->type == XML_ELEMENT_NODE)) { + xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name"); + if (NULL != xml_char) { + if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.srcport"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value"); + if (NULL != xml_char2) { + sctp_hdr->src_port = strtoul((const char *)xml_char2, NULL, 16); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.dstport"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value"); + if (NULL != xml_char2) { + sctp_hdr->dst_port = strtoul((const char *)xml_char2, NULL, 16); + xmlFree(xml_char2); + } + } else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.chunk_type"))) { + xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value"); + if (NULL != xml_char2) { + sctp_hdr->chunk_type = strtoul((const char *)xml_char2, NULL, 0); + xmlFree(xml_char2); + switch (sctp_hdr->chunk_type) { + case SCTP_CID_DATA: + parse_sctp_data_chunk(doc, sctp_node->parent, &sctp_hdr->u.data_hdr); + break; + case SCTP_CID_INIT: + parse_sctp_init_chunk(doc, sctp_node->parent, &sctp_hdr->u.init_hdr); + break; + case SCTP_CID_INIT_ACK: + parse_sctp_init_ack_chunk(doc, sctp_node->parent, &sctp_hdr->u.init_ack_hdr); + break; + default: + ; + } + } + } + } + for (cur_node = sctp_node->children; cur_node; cur_node = cur_node->next) { + parse_sctp(doc, cur_node, sctp_hdr); + } + } +} +//------------------------------------------------------------------------------ +test_packet_t* parse_xml_packet(xmlDocPtr doc, xmlNodePtr node) { + + test_packet_t *packet = NULL; + xmlNode *cur_node = NULL; + xmlChar *xml_char = NULL; + float afloat = (float)0.0; + static struct timeval initial_time = { .tv_sec = 0, .tv_usec = 0 }; + static struct timeval relative_last_sent_packet = { .tv_sec = 0, .tv_usec = 0 }; + static struct timeval relative_last_received_packet = { .tv_sec = 0, .tv_usec = 0 }; + static char first_packet = 1; + static char first_sent_packet = 1; + static char first_received_packet = 1; + static unsigned int packet_number = 1; if (NULL != node) { packet = calloc(1, sizeof(*packet)); + xml_char = xmlGetProp(node, (const xmlChar *)"action"); + packet->action = action_str2test_action_t(xml_char); + xmlFree(xml_char); + packet->packet_number = packet_number++; + for (cur_node = node->children; cur_node; cur_node = cur_node->next) { - if (cur_node->type == XML_ELEMENT_NODE) { - printf("node type: Element, name: %s\n", cur_node->name); + //if (cur_node->type == XML_ELEMENT_NODE) { if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"frame.time_relative"))) { + xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"value"); + afloat = atof((const char*)xml_char); + xmlFree(xml_char); + packet->time_relative_to_first_packet.tv_sec = (int)afloat; + packet->time_relative_to_first_packet.tv_usec = (int)((afloat - packet->time_relative_to_first_packet.tv_sec)*1000000); + + if (first_packet > 0) { + initial_time = packet->time_relative_to_first_packet; + packet->time_relative_to_first_packet.tv_sec = 0; + packet->time_relative_to_first_packet.tv_usec = 0; + first_packet = 0; + } else { + timersub(&packet->time_relative_to_first_packet, &initial_time, + &packet->time_relative_to_first_packet); + } + if (packet->action == ACTION_S1C_SEND) { + if (first_sent_packet > 0) { + relative_last_sent_packet = packet->time_relative_to_first_packet; + packet->time_relative_to_last_sent_packet.tv_sec = 0; + packet->time_relative_to_last_sent_packet.tv_usec = 0; + first_sent_packet = 0; + } else { + timersub(&packet->time_relative_to_first_packet, &relative_last_sent_packet, + &packet->time_relative_to_last_sent_packet); + relative_last_sent_packet = packet->time_relative_to_first_packet; + } + } else if (packet->action == ACTION_S1C_RECEIVE) { + if (first_received_packet > 0) { + relative_last_received_packet.tv_sec = packet->time_relative_to_first_packet.tv_sec; + relative_last_received_packet.tv_usec = packet->time_relative_to_first_packet.tv_usec; + packet->time_relative_to_last_received_packet.tv_sec = 0; + packet->time_relative_to_last_received_packet.tv_usec = 0; + first_received_packet = 0; + } else { + timersub(&packet->time_relative_to_first_packet, &relative_last_received_packet, + &packet->time_relative_to_last_received_packet); + relative_last_received_packet = packet->time_relative_to_first_packet; + } + } + + } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"frame.number"))) { + xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"value"); + packet->original_frame_number = strtoul((const char *)xml_char, NULL, 0); + xmlFree(xml_char); } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"ip.src"))) { + xml_char = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1); + ip_str2test_ip(xml_char, &packet->ip_hdr.src); + xmlFree(xml_char); } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"ip.dst"))) { - } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"sctp.chunk_type_str"))) { - xml_char = xmlGetProp(cur_node, (const xmlChar *)"value"); - packet->sctp_hdr.chunk_type = chunk_type_str2cid(xml_char); - fprintf(stdout, "chunk_type_str2cid: %s\n", xml_char); + xml_char = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1); + ip_str2test_ip(xml_char, &packet->ip_hdr.dst); + xmlFree(xml_char); + } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"proto"))) { + xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"name"); + if (NULL != xml_char) { + if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp"))) { + parse_sctp(doc, cur_node, &packet->sctp_hdr); + } + xmlFree(xml_char); + } } - } + //} } } return packet; @@ -210,11 +1097,12 @@ test_packet_t* parse_xml_packet(xmlNodePtr node) { //------------------------------------------------------------------------------ int play_scenario(test_scenario_t* scenario) { //TODO + display_scenario(scenario); return 0; } //------------------------------------------------------------------------------ test_scenario_t* generate_scenario( - const char const * play_scenario_filename ) + const char * const play_scenario_filename ) { xmlDocPtr doc = NULL; xmlNodePtr root = NULL; @@ -229,6 +1117,7 @@ test_scenario_t* generate_scenario( AssertFatal (0, "Could not parse scenario xml file %s!\n", play_scenario_filename); } else { fprintf(stdout, "Test scenario file to play: %s\n", play_scenario_filename); + //xmlDebugDumpDocument(NULL, doc); } // Get root @@ -242,13 +1131,13 @@ test_scenario_t* generate_scenario( next_packet = &scenario->list_packet; for (node = root->children; node != NULL; node = node->next) { if ((!xmlStrcmp(node->name, (const xmlChar *)"packet"))) { - packet = parse_xml_packet(node); + packet = parse_xml_packet(doc, node); if (NULL != packet) { *next_packet = packet; next_packet = &packet->next; } else { fprintf(stdout, "WARNING omitted packet:\n"); - display_node(node); + display_node(node, 0); } } } @@ -285,7 +1174,7 @@ int generate_xml_scenario( if (getcwd(astring, sizeof(astring)) != NULL) { fprintf(stdout, "working in %s directory\n", astring); } else { - perror("getcwd() error"); + perror("getcwd() ERROR"); exit(1); } @@ -332,22 +1221,22 @@ int generate_xml_scenario( if (NULL != res) { sprintf(play_scenario_filename,"%s",test_scenario_filename); if (strip_extension(play_scenario_filename) > 0) { - strcat(play_scenario_filename, ".tsml"); + strcat((char *)play_scenario_filename, ".tsml"); play_scenario_file = fopen( play_scenario_filename, "w+"); if (NULL != play_scenario_file) { xsltSaveResultToFile(play_scenario_file, res, cur); fclose(play_scenario_file); fprintf(stdout, "Wrote test scenario to %s\n", play_scenario_filename); } else { - fprintf(stderr, "Error in fopen(%s)\n", play_scenario_filename); + fprintf(stderr, "ERROR in fopen(%s)\n", play_scenario_filename); ret = -1; } } else { - fprintf(stderr, "Error in strip_extension()\n"); + fprintf(stderr, "ERROR in strip_extension()\n"); ret = -1; } } else { - fprintf(stderr, "Error in xsltApplyStylesheet()\n"); + fprintf(stderr, "ERROR in xsltApplyStylesheet()\n"); ret = -1; } xsltFreeStylesheet(cur); @@ -466,23 +1355,23 @@ config_parse_opt_line ( exit(1); } if (chdir(*test_dir_name) != 0) { - fprintf(stderr, "Error: chdir %s returned %s\n", *test_dir_name, strerror(errno)); + fprintf(stderr, "ERROR: chdir %s returned %s\n", *test_dir_name, strerror(errno)); exit(1); } if (rv & PLAY_SCENARIO) { if (NULL == *enb_config_file_name) { - fprintf(stderr, "Error: please provide the original eNB config file name that should be in %s\n", *test_dir_name); + fprintf(stderr, "ERROR: please provide the original eNB config file name that should be in %s\n", *test_dir_name); } if (is_file_exists(*enb_config_file_name, "eNB config file") != GS_IS_FILE) { - fprintf(stderr, "Error: original eNB config file name %s is not found in dir %s\n", *enb_config_file_name, *test_dir_name); + fprintf(stderr, "ERROR: original eNB config file name %s is not found in dir %s\n", *enb_config_file_name, *test_dir_name); } enb_properties_p = enb_config_init(*enb_config_file_name); if (NULL == *scenario_file_name) { - fprintf(stderr, "Error: please provide the scenario file name that should be in %s\n", *test_dir_name); + fprintf(stderr, "ERROR: please provide the scenario file name that should be in %s\n", *test_dir_name); } if (is_file_exists(*scenario_file_name, "Scenario file") != GS_IS_FILE) { - fprintf(stderr, "Error: Scenario file name %s is not found in dir %s\n", *scenario_file_name, *test_dir_name); + fprintf(stderr, "ERROR: Scenario file name %s is not found in dir %s\n", *scenario_file_name, *test_dir_name); } } return rv; @@ -503,21 +1392,29 @@ int main( int argc, char **argv ) memset(play_scenario_filename, 0, sizeof(play_scenario_filename)); g_openair_dir = getenv("OPENAIR_DIR"); if (NULL == g_openair_dir) { - fprintf(stderr, "Error: Could not get OPENAIR_DIR environment variable\n"); + fprintf(stderr, "ERROR: Could not get OPENAIR_DIR environment variable\n"); exit(1); } + // logging + logInit(); + set_comp_log(S1AP, LOG_TRACE, LOG_MED,1); + set_comp_log(SCTP, LOG_TRACE, LOG_MED,1); + asn_debug = 1; + asn1_xer_print = 1; + + //parameters actions = config_parse_opt_line (argc, argv, &test_dir_name, &scenario_file_name, &enb_config_file_name); //Command-line options if (actions & PLAY_SCENARIO) { if (generate_xml_scenario(test_dir_name, scenario_file_name,enb_config_file_name, play_scenario_filename) == 0) { if (NULL != (scenario = generate_scenario(play_scenario_filename))) { ret = play_scenario(scenario); } else { - fprintf(stderr, "Error: Could not generate scenario from tsml file\n"); + fprintf(stderr, "ERROR: Could not generate scenario from tsml file\n"); ret = -1; } } else { - fprintf(stderr, "Error: Could not generate tsml scenario from xml file\n"); + fprintf(stderr, "ERROR: Could not generate tsml scenario from xml file\n"); ret = -1; } free_pointer(test_dir_name); diff --git a/openair3/TEST/EPC_TEST/play_scenario.h b/openair3/TEST/EPC_TEST/play_scenario.h index 4916950783d3f3effb853ab0a2bc956cd2dcdece..2bf6cc4ccfdad6ac46a513114b08d5ac5f80d1b0 100644 --- a/openair3/TEST/EPC_TEST/play_scenario.h +++ b/openair3/TEST/EPC_TEST/play_scenario.h @@ -28,18 +28,22 @@ *******************************************************************************/ /* - generate_scenario.h + play_scenario.h ------------------- AUTHOR : Lionel GAUTHIER COMPANY : EURECOM EMAIL : Lionel.Gauthier@eurecom.fr */ -#ifndef GENERATE_SCENARIO_H_ -#define GENERATE_SCENARIO_H_ -# include <time.h> -# include <stdint.h> -#include <libxml/tree.h> +#ifndef PLAY_SCENARIO_H_ +#define PLAY_SCENARIO_H_ +# include <time.h> +# include <stdint.h> +# include <libxml/tree.h> +# include <netinet/in.h> + +#include "s1ap_ies_defs.h" + /** @defgroup _enb_app ENB APP * @ingroup _oai2 @@ -83,13 +87,32 @@ typedef enum { SCTP_CID_ASCONF_ACK = 0x80, } sctp_cid_t; /* enum */ +typedef enum { + TEST_S1AP_PDU_TYPE_START = 0, + TEST_S1AP_PDU_TYPE_UNKNOWN = TEST_S1AP_PDU_TYPE_START, + TEST_S1AP_PDU_TYPE_INITIATING, + TEST_S1AP_PDU_TYPE_SUCCESSFUL_OUTCOME, + TEST_S1AP_PDU_TYPE_UNSUCCESSFUL_OUTCOME, + TEST_S1AP_PDU_TYPE_END +} test_s1ap_pdu_type_t; + + +typedef struct test_s1ap_s { + //test_s1ap_pdu_type_t pdu_type; + uint16_t binary_stream_pos; + uint16_t binary_stream_allocated_size; + uint8_t *binary_stream; + s1ap_message message; +} test_s1ap_t; + + // from kernel source file 3.19/include/linux/sctp.h, Big Endians typedef struct sctp_datahdr_s { - uint32_t tsn; - uint16_t stream; - uint16_t ssn; - uint32_t ppid; - uint8_t payload[0]; + uint32_t tsn; + uint16_t stream; + uint16_t ssn; + uint32_t ppid; + test_s1ap_t payload; } sctp_datahdr_t; // from kernel source file 3.19/include/linux/sctp.h, Big Endians @@ -115,15 +138,28 @@ typedef struct test_sctp_hdr_s { } u; } test_sctp_hdr_t; +typedef struct test_ip_s { + unsigned int address_family; // AF_INET, AF_INET6 + union { + struct in6_addr ipv6; + in_addr_t ipv4; + }address; +}test_ip_t; + +typedef struct test_ip_hdr_s { + test_ip_t src; + test_ip_t dst; +} test_ip_hdr_t; + typedef struct test_packet_s { test_action_t action; struct timeval time_relative_to_first_packet; - struct timeval time_relative_to_last_packet; + struct timeval time_relative_to_last_sent_packet; + struct timeval time_relative_to_last_received_packet; + unsigned int original_frame_number; + unsigned int packet_number; + test_ip_hdr_t ip_hdr; test_sctp_hdr_t sctp_hdr; - uint16_t s1ap_byte_stream_count; - uint8_t *s1ap_byte_stream; - xmlNodePtr *s1ap_node; - struct test_packet_s *next; }test_packet_t;