From d27641a443113d3af55e05df7f433b54fd0a6bc5 Mon Sep 17 00:00:00 2001
From: gauthier <lionel.gauthier@eurecom.fr>
Date: Tue, 17 Nov 2015 16:56:24 +0100
Subject: [PATCH] Begin to begin sending packets (many things to do hash assoc
 id, mme_ue_id, nas security, etc)

---
 cmake_targets/CMakeLists.txt                  |   30 +-
 cmake_targets/epc_test/CMakeLists.template    |    4 +-
 cmake_targets/tools/build_test_epc_tools      |    2 +-
 openair3/S1AP/s1ap_eNB.c                      |    7 +-
 openair3/TEST/EPC_TEST/play_scenario.c        | 1203 +++--------------
 openair3/TEST/EPC_TEST/play_scenario.h        |  221 ++-
 openair3/TEST/EPC_TEST/play_scenario_decode.c |  214 +++
 .../TEST/EPC_TEST/play_scenario_display.c     |  292 ++++
 openair3/TEST/EPC_TEST/play_scenario_fsm.c    |  127 ++
 openair3/TEST/EPC_TEST/play_scenario_parse.c  |  561 ++++++++
 openair3/TEST/EPC_TEST/play_scenario_s1ap.c   |  162 +++
 openair3/TEST/EPC_TEST/play_scenario_sctp.c   |   45 +
 openair3/UTILS/conversions.h                  |    1 -
 13 files changed, 1811 insertions(+), 1058 deletions(-)
 create mode 100644 openair3/TEST/EPC_TEST/play_scenario_decode.c
 create mode 100644 openair3/TEST/EPC_TEST/play_scenario_display.c
 create mode 100644 openair3/TEST/EPC_TEST/play_scenario_fsm.c
 create mode 100644 openair3/TEST/EPC_TEST/play_scenario_parse.c
 create mode 100644 openair3/TEST/EPC_TEST/play_scenario_s1ap.c
 create mode 100644 openair3/TEST/EPC_TEST/play_scenario_sctp.c

diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 5fb722ee9d7..148aae24195 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -216,18 +216,20 @@ add_definitions("-DPACKAGE_BUGREPORT=\"openair4g-devel@lists.eurecom.fr\"")
 
 # Debug related options
 #########################################
-add_boolean_option(MSG_PRINT  False "print debug messages")
-add_boolean_option(DISABLE_XER_PRINT False "print XER Format")
-add_boolean_option(XER_PRINT False "print XER Format")
-add_boolean_option(RRC_MSG_PRINT False "print RRC messages")
-add_boolean_option(PDCP_MSG_PRINT False "print PDCP messages to /tmp/pdcp.log")
-add_boolean_option(DEBUG_PDCP_PAYLOAD False "print PDCP PDU to stdout")  # if true, make sure that global and PDCP log levels are trace 
+add_boolean_option(ASN_DEBUG           False "ASN1 coder/decoder Debug")
+add_boolean_option(EMIT_ASN_DEBUG      False "ASN1 coder/decoder Debug")
+add_boolean_option(MSG_PRINT           False "print debug messages")
+add_boolean_option(DISABLE_XER_PRINT   False "print XER Format")
+add_boolean_option(XER_PRINT           False "print XER Format")
+add_boolean_option(RRC_MSG_PRINT       False "print RRC messages")
+add_boolean_option(PDCP_MSG_PRINT      False "print PDCP messages to /tmp/pdcp.log")
+add_boolean_option(DEBUG_PDCP_PAYLOAD  False "print PDCP PDU to stdout")  # if true, make sure that global and PDCP log levels are trace 
 add_boolean_option(DEBUG_MAC_INTERFACE False "print MAC-RLC PDU exchange to stdout") # if true, make sure that global and PDCP log levels are trace 
-add_boolean_option(TRACE_RLC_PAYLOAD False "print RLC PDU to stdout") # if true, make sure that global and PDCP log levels are trace 
-add_boolean_option(TEST_OMG False "???")
-add_boolean_option(DEBUG_OMG False "???")
-add_boolean_option(XFORMS False "This adds the possibility to see the signal oscilloscope")
-add_boolean_option(PRINT_STATS False "This adds the possibility to see the status")
+add_boolean_option(TRACE_RLC_PAYLOAD   False "print RLC PDU to stdout") # if true, make sure that global and PDCP log levels are trace 
+add_boolean_option(TEST_OMG            False "???")
+add_boolean_option(DEBUG_OMG           False "???")
+add_boolean_option(XFORMS              False "This adds the possibility to see the signal oscilloscope")
+add_boolean_option(PRINT_STATS         False "This adds the possibility to see the status")
 
 add_boolean_option(DEBUG_CONSOLE False "makes debugging easier, disables stdout/stderr buffering")
 
@@ -1660,6 +1662,12 @@ target_link_libraries (test_epc_generate_scenario
 
 add_executable(test_epc_play_scenario
   ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario.c
+  ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_decode.c
+  ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_display.c
+  ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_fsm.c
+  ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_parse.c
+  ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_s1ap.c
+  ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_sctp.c
   ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario.h
   ${OPENAIR2_DIR}/ENB_APP/enb_config.h
   ${OPENAIR2_DIR}/COMMON/commonDef.h
diff --git a/cmake_targets/epc_test/CMakeLists.template b/cmake_targets/epc_test/CMakeLists.template
index 5789c3eb5c5..8a8223e4ae6 100644
--- a/cmake_targets/epc_test/CMakeLists.template
+++ b/cmake_targets/epc_test/CMakeLists.template
@@ -7,7 +7,7 @@ set (  DEBUG_OMG False )
 set (  DISABLE_XER_PRINT False )
 set (  DRIVER2013 True )
 set (  EMOS False )
-set (  EMIT_ASN_DEBUG True )
+set (  EMIT_ASN_DEBUG False )
 set (  ENABLE_FXP True )
 set (  ENABLE_ITTI True )
 set (  ENABLE_NAS_UE_LOGGING True )
@@ -76,4 +76,4 @@ set (  SMBV False )
 set (  TEST_OMG False )
 set (  USE_MME "R10" )
 set (  USER_MODE True )
-set (  XER_PRINT False )
+set (  XER_PRINT True )
diff --git a/cmake_targets/tools/build_test_epc_tools b/cmake_targets/tools/build_test_epc_tools
index 10dc4fd2564..db49fa017b6 100755
--- a/cmake_targets/tools/build_test_epc_tools
+++ b/cmake_targets/tools/build_test_epc_tools
@@ -22,7 +22,7 @@
 #  Contact Information
 #  OpenAirInterface Admin: openair_admin@eurecom.fr
 #  OpenAirInterface Tech : openair_tech@eurecom.fr
-#  OpenAirInterface Dev  : openair4g-devel@eurecom.fr
+#  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
 #
 #  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
 #
diff --git a/openair3/S1AP/s1ap_eNB.c b/openair3/S1AP/s1ap_eNB.c
index c880c3f3b4b..1b683d4aa34 100644
--- a/openair3/S1AP/s1ap_eNB.c
+++ b/openair3/S1AP/s1ap_eNB.c
@@ -72,9 +72,9 @@ s1ap_eNB_config_t s1ap_config;
 static int s1ap_eNB_generate_s1_setup_request(
   s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p);
 
-static
+
 void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB);
-static
+
 void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
 
 uint32_t s1ap_generate_eNB_id(void)
@@ -150,7 +150,7 @@ static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
   itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p);
 }
 
-static
+
 void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB)
 {
   s1ap_eNB_instance_t *new_instance;
@@ -210,7 +210,6 @@ void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *
   }
 }
 
-static
 void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
 {
   s1ap_eNB_instance_t *instance_p;
diff --git a/openair3/TEST/EPC_TEST/play_scenario.c b/openair3/TEST/EPC_TEST/play_scenario.c
index 982c1ffb402..fda38dbcb8b 100644
--- a/openair3/TEST/EPC_TEST/play_scenario.c
+++ b/openair3/TEST/EPC_TEST/play_scenario.c
@@ -48,133 +48,28 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <unistd.h>
-#include <libxml/xmlmemory.h>
-#include <libxml/debugXML.h>
-#include <libxml/xmlIO.h>
-#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>
-#include <libxslt/xsltutils.h>
+
 
 #include "intertask_interface_init.h"
+#include "timer.h"
 #include "assertions.h"
-#include "play_scenario.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 "play_scenario.h"
+#include "sctp_eNB_task.h"
 #include "log.h"
 //------------------------------------------------------------------------------
-#define ENB_CONFIG_MAX_XSLT_PARAMS 32
 #define PLAY_SCENARIO              1
 #define GS_IS_FILE                 1
 #define GS_IS_DIR                  2
 //------------------------------------------------------------------------------
 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
 int is_file_exists( const char const * file_nameP, const char const *file_roleP)
@@ -202,7 +97,7 @@ int is_file_exists( const char const * file_nameP, const char const *file_roleP)
 
 
 //------------------------------------------------------------------------------
-int strip_extension(char *in_filename)
+int et_strip_extension(char *in_filename)
 {
   static const uint8_t name_min_len = 1;
   static const uint8_t max_ext_len = 5; // .pdml !
@@ -237,193 +132,38 @@ int split_path( char * pathP, char *** resP)
   return n_spaces;
 }
 //------------------------------------------------------------------------------
-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);
-      xmlFree(content);
-    } else {
-      printf("%s\n", path);
-    }
-    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)
+void et_free_packet(et_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);
+        et_free_pointer(packet->sctp_hdr.u.data_hdr.payload.binary_stream);
         break;
       default:
         ;
     }
-    free_pointer(packet);
+    et_free_pointer(packet);
   }
 }
 
 //------------------------------------------------------------------------------
-void free_scenario(test_scenario_t* scenario)
+void et_free_scenario(et_scenario_t* scenario)
 {
-  test_packet_t *packet = NULL;
-  test_packet_t *next_packet = NULL;
+  et_packet_t *packet = NULL;
+  et_packet_t *next_packet = NULL;
   if (scenario) {
     packet = scenario->list_packet;
     while (packet) {
       next_packet = packet->next;
-      free_packet(packet);
+      et_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");
-    }
+    et_free_pointer(scenario);
   }
 }
 
 //------------------------------------------------------------------------------
-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);
-  }
-}
-//------------------------------------------------------------------------------
-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)
+char * et_ip2ip_str(const et_ip_t * const ip)
 {
   static char str[INET6_ADDRSTRLEN];
 
@@ -445,7 +185,7 @@ char * test_ip2ip_str(const test_ip_t * const ip)
 //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)
+int et_hex2data(unsigned char * const data, const unsigned char * const hexstring, const unsigned int len)
 {
   unsigned const char *pos = hexstring;
   char *endptr = NULL;
@@ -477,7 +217,7 @@ int hex2data(unsigned char * const data, const unsigned char * const hexstring,
   return 0;
 }
 //------------------------------------------------------------------------------
-sctp_cid_t chunk_type_str2cid(const xmlChar * const chunk_type_str)
+sctp_cid_t et_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;}
@@ -501,7 +241,7 @@ sctp_cid_t chunk_type_str2cid(const xmlChar * const chunk_type_str)
   AssertFatal (0, "ERROR: %s() cannot convert: %s\n", __FUNCTION__, chunk_type_str);
 }
 //------------------------------------------------------------------------------
-const char * const chunk_type_cid2str(const sctp_cid_t chunk_type)
+const char * const et_chunk_type_cid2str(const sctp_cid_t chunk_type)
 {
   switch (chunk_type) {
     case  SCTP_CID_DATA:              return "DATA"; break;
@@ -528,15 +268,15 @@ const char * const chunk_type_cid2str(const sctp_cid_t chunk_type)
   }
 }
 //------------------------------------------------------------------------------
-test_action_t action_str2test_action_t(const xmlChar * const action)
+et_packet_action_t et_action_str2et_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;}
+  if ((!xmlStrcmp(action, (const xmlChar *)"SEND")))              { return ET_PACKET_ACTION_S1C_SEND;}
+  if ((!xmlStrcmp(action, (const xmlChar *)"RECEIVE")))              { return ET_PACKET_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)
+void et_ip_str2et_ip(const xmlChar  * const ip_str, et_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__);
@@ -550,732 +290,207 @@ void ip_str2test_ip(const xmlChar  * const ip_str, test_ip_t * const ip)
     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)
-{
-  char       *message_string = NULL;
-  int         ret = -1;
-
-  DevAssert(initiating_p != NULL);
-
-  message_string = calloc(20000, sizeof(char));
-  AssertFatal (NULL != message_string, "ERROR malloc()failed!\n");
-  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);
-    s1ap_xer_print_s1ap_downlinknastransport(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_InitialContextSetup:
-    ret = s1ap_decode_s1ap_initialcontextsetuprequesties(
-            &message->msg.s1ap_InitialContextSetupRequestIEs, &initiating_p->value);
-    s1ap_xer_print_s1ap_initialcontextsetuprequest(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_UEContextRelease:
-    ret = s1ap_decode_s1ap_uecontextreleasecommandies(
-            &message->msg.s1ap_UEContextReleaseCommandIEs, &initiating_p->value);
-    s1ap_xer_print_s1ap_uecontextreleasecommand(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_Paging:
-    ret = s1ap_decode_s1ap_pagingies(
-            &message->msg.s1ap_PagingIEs, &initiating_p->value);
-    s1ap_xer_print_s1ap_paging(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_uplinkNASTransport:
-    ret = s1ap_decode_s1ap_uplinknastransporties (&message->msg.s1ap_UplinkNASTransportIEs, &initiating_p->value);
-    s1ap_xer_print_s1ap_uplinknastransport(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_S1Setup:
-    ret = s1ap_decode_s1ap_s1setuprequesties (&message->msg.s1ap_S1SetupRequestIEs, &initiating_p->value);
-    s1ap_xer_print_s1ap_s1setuprequest(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_initialUEMessage:
-    ret = s1ap_decode_s1ap_initialuemessageies (&message->msg.s1ap_InitialUEMessageIEs, &initiating_p->value);
-    s1ap_xer_print_s1ap_initialuemessage(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_UEContextReleaseRequest:
-    ret = s1ap_decode_s1ap_uecontextreleaserequesties (&message->msg.s1ap_UEContextReleaseRequestIEs, &initiating_p->value);
-    s1ap_xer_print_s1ap_uecontextreleaserequest(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_UECapabilityInfoIndication:
-    ret = s1ap_decode_s1ap_uecapabilityinfoindicationies (&message->msg.s1ap_UECapabilityInfoIndicationIEs, &initiating_p->value);
-    //s1ap_xer_print_s1ap_uecapabilityinfoindication(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_NASNonDeliveryIndication:
-    ret = s1ap_decode_s1ap_nasnondeliveryindication_ies (&message->msg.s1ap_NASNonDeliveryIndication_IEs, &initiating_p->value);
-    s1ap_xer_print_s1ap_nasnondeliveryindication_(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  default:
-    free(message_string);
-    AssertFatal( 0 , "Unknown procedure ID (%d) for initiating message\n",
-                 (int)initiating_p->procedureCode);
-    return -1;
-  }
-  fprintf(stdout, "s1ap_xer_print:\n%s\n", message_string);
-  free(message_string);
-  return ret;
-}
+/*------------------------------------------------------------------------------*/
+uint32_t et_eNB_app_register(const Enb_properties_array_t *enb_properties)
+{
+  uint32_t         enb_id;
+  uint32_t         mme_id;
+  MessageDef      *msg_p;
+  uint32_t         register_enb_pending = 0;
+  char            *str                  = NULL;
+  struct in_addr   addr;
+
+
+  for (enb_id = 0; (enb_id < enb_properties->number) ; enb_id++) {
+    {
+      s1ap_register_enb_req_t *s1ap_register_eNB;
+
+      /* note:  there is an implicit relationship between the data structure and the message name */
+      msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ);
+
+      s1ap_register_eNB = &S1AP_REGISTER_ENB_REQ(msg_p);
+
+      /* Some default/random parameters */
+      s1ap_register_eNB->eNB_id           = enb_properties->properties[enb_id]->eNB_id;
+      s1ap_register_eNB->cell_type        = enb_properties->properties[enb_id]->cell_type;
+      s1ap_register_eNB->eNB_name         = enb_properties->properties[enb_id]->eNB_name;
+      s1ap_register_eNB->tac              = enb_properties->properties[enb_id]->tac;
+      s1ap_register_eNB->mcc              = enb_properties->properties[enb_id]->mcc;
+      s1ap_register_eNB->mnc              = enb_properties->properties[enb_id]->mnc;
+      s1ap_register_eNB->mnc_digit_length = enb_properties->properties[enb_id]->mnc_digit_length;
+      s1ap_register_eNB->default_drx      = enb_properties->properties[enb_id]->pcch_defaultPagingCycle[0];
+
+      s1ap_register_eNB->nb_mme =         enb_properties->properties[enb_id]->nb_mme;
+      AssertFatal (s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS, "Too many MME for eNB %d (%d/%d)!", enb_id, s1ap_register_eNB->nb_mme,
+                   S1AP_MAX_NB_MME_IP_ADDRESS);
+
+      for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++) {
+        s1ap_register_eNB->mme_ip_address[mme_id].ipv4 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4;
+        s1ap_register_eNB->mme_ip_address[mme_id].ipv6 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6;
+        strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
+                 enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4_address,
+                 sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address));
+        strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address,
+                 enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6_address,
+                 sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
+      }
 
-//------------------------------------------------------------------------------
-int test_s1ap_decode_successful_outcome(s1ap_message *message,
-    S1ap_SuccessfulOutcome_t *successfullOutcome_p)
-{
-  char       *message_string = NULL;
-  int         ret = -1;
-
-  DevAssert(successfullOutcome_p != NULL);
-  message_string = calloc(20000, sizeof(char));
-  AssertFatal (NULL != message_string, "ERROR malloc()failed!\n");
-
-  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);
-    s1ap_xer_print_s1ap_s1setupresponse(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_InitialContextSetup:
-    ret = s1ap_decode_s1ap_initialcontextsetupresponseies (&message->msg.s1ap_InitialContextSetupResponseIEs, &successfullOutcome_p->value);
-    s1ap_xer_print_s1ap_initialcontextsetupresponse(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_UEContextRelease:
-      ret = s1ap_decode_s1ap_uecontextreleasecompleteies (&message->msg.s1ap_UEContextReleaseCompleteIEs, &successfullOutcome_p->value);
-      s1ap_xer_print_s1ap_uecontextreleasecomplete(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  default:
-    free(message_string);
-    AssertFatal(0, "Unknown procedure ID (%d) for successfull outcome message\n",
-               (int)successfullOutcome_p->procedureCode);
-    return -1;
-  }
-  fprintf(stdout, "s1ap_xer_print:\n%s\n", message_string);
-  free(message_string);
-  return ret;
-}
+      s1ap_register_eNB->sctp_in_streams       = enb_properties->properties[enb_id]->sctp_in_streams;
+      s1ap_register_eNB->sctp_out_streams      = enb_properties->properties[enb_id]->sctp_out_streams;
 
-//------------------------------------------------------------------------------
-int test_s1ap_decode_unsuccessful_outcome(s1ap_message *message,
-    S1ap_UnsuccessfulOutcome_t *unSuccessfullOutcome_p)
-{
-  char       *message_string = NULL;
-  int ret = -1;
-
-  DevAssert(unSuccessfullOutcome_p != NULL);
-  message_string = calloc(20000, sizeof(char));
-  AssertFatal (NULL != message_string, "ERROR malloc()failed!\n");
-
-  message->procedureCode = unSuccessfullOutcome_p->procedureCode;
-  message->criticality   = unSuccessfullOutcome_p->criticality;
-
-  switch(unSuccessfullOutcome_p->procedureCode) {
-  case S1ap_ProcedureCode_id_S1Setup:
-    ret = s1ap_decode_s1ap_s1setupfailureies(
-             &message->msg.s1ap_S1SetupFailureIEs, &unSuccessfullOutcome_p->value);
-    s1ap_xer_print_s1ap_s1setupfailure(s1ap_xer__print2sp, message_string, message);
-    break;
-
-  case S1ap_ProcedureCode_id_InitialContextSetup:
-    ret = s1ap_decode_s1ap_initialcontextsetupfailureies (&message->msg.s1ap_InitialContextSetupFailureIEs, &unSuccessfullOutcome_p->value);
-    s1ap_xer_print_s1ap_initialcontextsetupfailure(s1ap_xer__print2sp, message_string, message);
-    break;
-
-
-  default:
-    free(message_string);
-    AssertFatal(0,"Unknown procedure ID (%d) for unsuccessfull outcome message\n",
-               (int)unSuccessfullOutcome_p->procedureCode);
-    break;
+
+      s1ap_register_eNB->enb_ip_address.ipv6 = 0;
+      s1ap_register_eNB->enb_ip_address.ipv4 = 1;
+      addr.s_addr = enb_properties->properties[enb_id]->enb_ipv4_address_for_S1_MME;
+      str = inet_ntoa(addr);
+      strcpy(s1ap_register_eNB->enb_ip_address.ipv4_address, str);
+
+      itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
+
+      register_enb_pending++;
+    }
   }
-  fprintf(stdout, "s1ap_xer_print:\n%s\n", message_string);
-  free(message_string);
-  return ret;
-}
 
-//------------------------------------------------------------------------------
-int test_s1ap_decode_pdu(s1ap_message *message, const uint8_t * const buffer,
-                        const uint32_t length)
+  return register_enb_pending;
+}
+/*------------------------------------------------------------------------------*/
+void *et_eNB_app_task(void *args_p)
 {
-  S1AP_PDU_t  pdu;
-  S1AP_PDU_t *pdu_p = &pdu;
-  asn_dec_rval_t dec_ret;
+  const Enb_properties_array_t   *enb_properties_p  = NULL;
+  uint32_t                        register_enb_pending;
+  uint32_t                        registered_enb;
+  long                            enb_register_retry_timer_id;
+  uint32_t                        enb_id;
+  MessageDef                     *msg_p           = NULL;
+  const char                     *msg_name        = NULL;
+  instance_t                      instance;
+  int                             result;
 
-  DevAssert(buffer != NULL);
+  itti_mark_task_ready (TASK_ENB_APP);
 
-  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);
+  enb_properties_p = enb_config_get();
 
-  if (dec_ret.code != RC_OK) {
-    S1AP_ERROR("Failed to decode pdu\n");
-    return -1;
-  }
 
-  message->direction = pdu_p->present;
+  /* Try to register each eNB */
+  registered_enb = 0;
+  register_enb_pending = et_eNB_app_register (enb_properties_p);
 
-  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);
+  do {
+    // Wait for a message
+    itti_receive_msg (TASK_ENB_APP, &msg_p);
 
-  case S1AP_PDU_PR_unsuccessfulOutcome:
-    return test_s1ap_decode_unsuccessful_outcome(message,
-           &pdu_p->choice.unsuccessfulOutcome);
+    msg_name = ITTI_MSG_NAME (msg_p);
+    instance = ITTI_MSG_INSTANCE (msg_p);
 
-  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"))) {
-            go_deeper_in_tree = 0;
-          }
-          xmlFree(xml_char);
-        }
-        if (0 < go_deeper_in_tree) {
-          // 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);
-      }
-    }
-  }
-}
+    switch (ITTI_MSG_ID(msg_p)) {
+    case TERMINATE_MESSAGE:
+      itti_exit_task ();
+      break;
 
-//------------------------------------------------------------------------------
-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;
-
-  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);
+
+    case S1AP_REGISTER_ENB_CNF:
+      LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
+            S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
+
+      DevAssert(register_enb_pending > 0);
+      register_enb_pending--;
+
+      /* Check if at least eNB is registered with one MME */
+      if (S1AP_REGISTER_ENB_CNF(msg_p).nb_mme > 0) {
+        registered_enb++;
       }
-    }
-    //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:
-              ;
+
+      /* Check if all register eNB requests have been processed */
+      if (register_enb_pending == 0) {
+        if (registered_enb == enb_properties_p->number) {
+          /* If all eNB are registered, start scenario */
+
+        } else {
+          uint32_t not_associated = enb_properties_p->number - registered_enb;
+
+          LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
+                not_associated, not_associated > 1 ? "are" : "is", ET_ENB_REGISTER_RETRY_DELAY);
+
+          /* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */
+          if (timer_setup (ET_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
+                           NULL, &enb_register_retry_timer_id) < 0) {
+            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
+
+            sleep(ET_ENB_REGISTER_RETRY_DELAY);
+            /* Restart the registration process */
+            registered_enb = 0;
+            register_enb_pending = et_eNB_app_register (enb_properties_p);
           }
         }
       }
-    }
-    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) {
-        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"))) {
-          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;
-}
-//------------------------------------------------------------------------------
-int play_scenario(test_scenario_t* scenario) {
-  //TODO
-  display_scenario(scenario);
-  return 0;
-}
-//------------------------------------------------------------------------------
-test_scenario_t* generate_scenario(
-    const char  * const play_scenario_filename )
-{
-  xmlDocPtr         doc      = NULL;
-  xmlNodePtr        root     = NULL;
-  xmlNodePtr        node     = NULL;
-  xmlChar          *xml_char = NULL;
-  test_scenario_t  *scenario = NULL;
-  test_packet_t    *packet   = NULL;
-  test_packet_t   **next_packet   = NULL;
-
-  doc = xmlParseFile(play_scenario_filename);
-  if (NULL == doc) {
-    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);
-  }
+      break;
 
-  // Get root
-  root = xmlDocGetRootElement(doc);
-  if (NULL != root) {
-    if ((!xmlStrcmp(root->name, (const xmlChar *)"scenario"))) {
-      xml_char = xmlGetProp(root, (const xmlChar *)"name");
-      printf("scenario name: %s\n", xml_char);
-      scenario = calloc(1, sizeof(*scenario));
-      scenario->name = xml_char; // nodup nofree
-      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(doc, node);
-          if (NULL != packet) {
-            *next_packet = packet;
-            next_packet = &packet->next;
-          } else {
-            fprintf(stdout, "WARNING omitted packet:\n");
-            display_node(node, 0);
-          }
-        }
+    case S1AP_DEREGISTERED_ENB_IND:
+      LOG_W(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
+            S1AP_DEREGISTERED_ENB_IND(msg_p).nb_mme);
+
+      /* TODO handle recovering of registration */
+      break;
+
+    case TIMER_HAS_EXPIRED:
+      LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
+
+      if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id) {
+        /* Restart the registration process */
+        registered_enb = 0;
+        register_enb_pending = et_eNB_app_register (enb_properties_p);
       }
+      break;
+
+    default:
+      LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
+      break;
     }
-  } else {
-    fprintf(stderr, "Empty xml document\n");
-  }
-  xmlFreeDoc(doc);
-  xmlCleanupParser();
-  return scenario;
+
+    result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
+    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+  } while (1);
+  return NULL;
 }
 
 //------------------------------------------------------------------------------
-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*/)
-//------------------------------------------------------------------------------
+int et_play_scenario(et_scenario_t* const scenario)
 {
-  //int fd_pdml_in;
-  xsltStylesheetPtr cur = NULL;
-  xmlDocPtr         doc, res;
-  FILE             *play_scenario_file = NULL;
-  const char       *params[2*ENB_CONFIG_MAX_XSLT_PARAMS];
-  int               nb_params = 0;
-  int               i,j;
-  char              astring[1024];
-  struct in_addr    addr;
-  int               ret      = 0;
-
-  memset(astring, 0, sizeof(astring));
-  if (getcwd(astring, sizeof(astring)) != NULL) {
-    fprintf(stdout, "working in %s directory\n", astring);
-  } else {
-    perror("getcwd() ERROR");
-    exit(1);
-  }
-
-  memset(astring, 0, sizeof(astring));
-  strcat(astring, g_openair_dir);
-  strcat(astring, "/openair3/TEST/EPC_TEST/play_scenario.xsl");
+  et_event_t        event;
+  et_display_scenario(scenario);
 
-  xmlSubstituteEntitiesDefault(1);
-  xmlLoadExtDtdDefaultValue = 1;
-  cur = xsltParseStylesheetFile((const xmlChar *)astring);
-  if (NULL == cur) {
-    AssertFatal (0, "Could not parse stylesheet file %s (check OPENAIR_DIR env variable)!\n", astring);
-  } else {
-    fprintf(stdout, "XSLT style sheet: %s\n", astring);
+  // create SCTP ITTI task: same as eNB code
+  if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) {
+    LOG_E(SCTP, "Create task for SCTP failed\n");
+    return -1;
   }
 
-  doc = xmlParseFile(test_scenario_filename);
-  if (NULL == doc) {
-    AssertFatal (0, "Could not parse scenario xml file %s!\n", test_scenario_filename);
-  } else {
-    fprintf(stdout, "Test scenario file: %s\n", test_scenario_filename);
+  // create S1AP ITTI task: not as same as eNB code
+  if (itti_create_task (TASK_S1AP, et_s1ap_eNB_task, NULL) < 0) {
+    LOG_E(S1AP, "Create task for S1AP failed\n");
+    return -1;
   }
 
-  for (i = 0; i < enb_properties.number; i++) {
-    // eNB S1-C IPv4 address
-    sprintf(astring, "enb_s1c%d", i);
-    params[nb_params++] = strdup(astring);
-    addr.s_addr = enb_properties.properties[i]->enb_ipv4_address_for_S1_MME;
-    sprintf(astring, "\"%s\"", inet_ntoa(addr));
-    params[nb_params++] = strdup(astring);
-
-    // MME S1-C IPv4 address
-    for (j = 0; j < enb_properties.properties[i]->nb_mme; j++) {
-      sprintf(astring, "mme_s1c%d_%d", i, j);
-      params[nb_params++] = strdup(astring);
-      AssertFatal (enb_properties.properties[i]->mme_ip_address[j].ipv4_address,
-          "Only support MME IPv4 address\n");
-      sprintf(astring, "\"%s\"", enb_properties.properties[i]->mme_ip_address[j].ipv4_address);
-      params[nb_params++] = strdup(astring);
-    }
-  }
-  params[nb_params] = NULL;
-  res = xsltApplyStylesheet(cur, doc, params);
-  if (NULL != res) {
-    sprintf((char *)play_scenario_filename,"%s",test_scenario_filename);
-    if (strip_extension((char *)play_scenario_filename) > 0) {
-      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);
-        ret = -1;
-      }
-    } else {
-      fprintf(stderr, "ERROR in strip_extension()\n");
-      ret = -1;
-    }
-  } else {
-    fprintf(stderr, "ERROR in xsltApplyStylesheet()\n");
-    ret = -1;
+  // create ENB_APP ITTI task: not as same as eNB code
+  if (itti_create_task (TASK_ENB_APP, et_eNB_app_task, NULL) < 0) {
+    LOG_E(ENB_APP, "Create task for ENB_APP failed\n");
+    return -1;
   }
-  xsltFreeStylesheet(cur);
-  xmlFreeDoc(doc);
-  xmlFreeDoc(res);
 
-  xsltCleanupGlobals();
-  xmlCleanupParser();
-  return ret;
+  event.code = ET_EVENT_INIT;
+  event.u.init.scenario = scenario;
+  et_scenario_fsm_notify_event(event);
+
+
+  return 0;
 }
 
 //------------------------------------------------------------------------------
-static void usage (
+static void et_usage (
     int argc,
     char *argv[])
 //------------------------------------------------------------------------------
@@ -1298,10 +513,10 @@ static void usage (
 
 //------------------------------------------------------------------------------
 int
-config_parse_opt_line (
+et_config_parse_opt_line (
   int argc,
   char *argv[],
-  char **test_dir_name,
+  char **et_dir_name,
   char **scenario_file_name,
   char **enb_config_file_name)
 //------------------------------------------------------------------------------
@@ -1354,12 +569,12 @@ config_parse_opt_line (
       case LONG_OPTION_TEST_DIR:
       case 'd':
         if (optarg) {
-          *test_dir_name = strdup(optarg);
-          if (is_file_exists(*test_dir_name, "test dirname") != GS_IS_DIR) {
-            fprintf(stderr, "Please provide a valid test dirname, %s is not a valid directory name\n", *test_dir_name);
+          *et_dir_name = strdup(optarg);
+          if (is_file_exists(*et_dir_name, "test dirname") != GS_IS_DIR) {
+            fprintf(stderr, "Please provide a valid test dirname, %s is not a valid directory name\n", *et_dir_name);
             exit(1);
           }
-          printf("Test dir name is %s\n", *test_dir_name);
+          printf("Test dir name is %s\n", *et_dir_name);
         }
         break;
 
@@ -1372,32 +587,32 @@ config_parse_opt_line (
       case LONG_OPTION_HELP:
       case 'h':
       default:
-        usage (argc, argv);
+        et_usage (argc, argv);
         exit (0);
     }
   }
-  if (NULL == *test_dir_name) {
+  if (NULL == *et_dir_name) {
     fprintf(stderr, "Please provide a valid test dirname\n");
     exit(1);
   }
-  if (chdir(*test_dir_name) != 0) {
-    fprintf(stderr, "ERROR: chdir %s returned %s\n", *test_dir_name, strerror(errno));
+  if (chdir(*et_dir_name) != 0) {
+    fprintf(stderr, "ERROR: chdir %s returned %s\n", *et_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", *et_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, *et_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", *et_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, *et_dir_name);
     }
   }
   return rv;
@@ -1408,12 +623,12 @@ int main( int argc, char **argv )
 //------------------------------------------------------------------------------
 {
   int              actions              = 0;
-  char            *test_dir_name        = NULL;
+  char            *et_dir_name          = NULL;
   char            *scenario_file_name   = NULL;
   char            *enb_config_file_name = NULL;
-  char             play_scenario_filename[NAME_MAX];
   int              ret                  = 0;
-  test_scenario_t *scenario             = NULL;
+  et_scenario_t   *scenario             = NULL;
+  char             play_scenario_filename[NAME_MAX];
 
   memset(play_scenario_filename, 0, sizeof(play_scenario_filename));
   g_openair_dir = getenv("OPENAIR_DIR");
@@ -1428,15 +643,15 @@ int main( int argc, char **argv )
 
   set_comp_log(S1AP, LOG_TRACE, LOG_MED, 1);
   set_comp_log(SCTP, LOG_TRACE, LOG_MED, 1);
-  asn_debug      = 1;
+  asn_debug      = 0;
   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
+  actions = et_config_parse_opt_line (argc, argv, &et_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);
+    if (et_generate_xml_scenario(et_dir_name, scenario_file_name,enb_config_file_name, play_scenario_filename) == 0) {
+      if (NULL != (scenario = et_generate_scenario(play_scenario_filename))) {
+        ret = et_play_scenario(scenario);
       } else {
         fprintf(stderr, "ERROR: Could not generate scenario from tsml file\n");
         ret = -1;
@@ -1445,9 +660,9 @@ int main( int argc, char **argv )
       fprintf(stderr, "ERROR: Could not generate tsml scenario from xml file\n");
       ret = -1;
     }
-    free_pointer(test_dir_name);
-    free_pointer(scenario_file_name);
-    free_pointer(enb_config_file_name);
+    et_free_pointer(et_dir_name);
+    et_free_pointer(scenario_file_name);
+    et_free_pointer(enb_config_file_name);
   }
 
   return ret;
diff --git a/openair3/TEST/EPC_TEST/play_scenario.h b/openair3/TEST/EPC_TEST/play_scenario.h
index 2bf6cc4ccfd..725b5abc0e9 100644
--- a/openair3/TEST/EPC_TEST/play_scenario.h
+++ b/openair3/TEST/EPC_TEST/play_scenario.h
@@ -28,7 +28,7 @@
 *******************************************************************************/
 
 /*
-                                play_scenario.h
+                                et_scenario.h
                              -------------------
   AUTHOR  : Lionel GAUTHIER
   COMPANY : EURECOM
@@ -42,21 +42,44 @@
 #  include <libxml/tree.h>
 #  include <netinet/in.h>
 
+#include "enb_config.h"
 #include "s1ap_ies_defs.h"
 
+#   define ET_ENB_REGISTER_RETRY_DELAY 3
 
-/** @defgroup _enb_app ENB APP 
- * @ingroup _oai2
- * @{
- */
 
 typedef enum {
-  ACTION_S1C_START = 0,
-  ACTION_S1C_NULL  = ACTION_S1C_START,
-  ACTION_S1C_SEND,
-  ACTION_S1C_RECEIVE,
-  ACTION_S1C_END
-} test_action_t;
+  ET_PACKET_STATUS_START = 0,
+  ET_PACKET_STATUS_NONE = ET_PACKET_STATUS_START,
+  ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT,
+  ET_PACKET_STATUS_SCHEDULED_FOR_SENDING,
+  ET_PACKET_STATUS_SENT,
+  ET_PACKET_STATUS_SENT_WITH_ERRORS,
+  ET_PACKET_STATUS_SCHEDULED_FOR_RECEIVING,
+  ET_PACKET_STATUS_RECEIVED,
+  ET_PACKET_STATUS_RECEIVED_WITH_ERRORS,
+  ET_PACKET_STATUS_END
+} et_packet_status_t;
+
+typedef enum {
+  ET_FSM_STATE_START = 0,
+  ET_FSM_STATE_NULL = ET_FSM_STATE_START,
+  ET_FSM_STATE_CONNECTING_SCTP,
+  ET_FSM_STATE_WAITING_TX_EVENT,
+  ET_FSM_STATE_WAITING_RX_EVENT,
+  ET_FSM_STATE_END
+} et_fsm_state_t;
+
+
+
+
+typedef enum {
+  ET_PACKET_ACTION_S1C_START = 0,
+  ET_PACKET_ACTION_S1C_NULL  = ET_PACKET_ACTION_S1C_START,
+  ET_PACKET_ACTION_S1C_SEND,
+  ET_PACKET_ACTION_S1C_RECEIVE,
+  ET_PACKET_ACTION_S1C_END
+} et_packet_action_t;
 
 // from kernel source file 3.19/include/linux/sctp.h
 typedef enum {
@@ -94,16 +117,17 @@ typedef enum {
   TEST_S1AP_PDU_TYPE_SUCCESSFUL_OUTCOME,
   TEST_S1AP_PDU_TYPE_UNSUCCESSFUL_OUTCOME,
   TEST_S1AP_PDU_TYPE_END
-} test_s1ap_pdu_type_t;
+} et_s1ap_pdu_type_t;
 
 
-typedef struct test_s1ap_s {
-  //test_s1ap_pdu_type_t pdu_type;
+typedef struct et_s1ap_s {
+  //et_s1ap_pdu_type_t pdu_type;
+  S1AP_PDU_t           pdu; // decoded ASN1 C type: choice of initiatingMessage, successfulOutcome, unsuccessfulOutcome
   uint16_t             binary_stream_pos;
   uint16_t             binary_stream_allocated_size;
   uint8_t             *binary_stream;
-  s1ap_message        message;
-} test_s1ap_t;
+  s1ap_message         message; // decoded message: information elements
+} et_s1ap_t;
 
 
 // from kernel source file 3.19/include/linux/sctp.h, Big Endians
@@ -112,7 +136,7 @@ typedef struct sctp_datahdr_s {
   uint16_t    stream;
   uint16_t    ssn;
   uint32_t    ppid;
-  test_s1ap_t payload;
+  et_s1ap_t   payload;
 } sctp_datahdr_t;
 
 // from kernel source file 3.19/include/linux/sctp.h, Big Endians
@@ -127,7 +151,7 @@ typedef struct sctp_inithdr {
 
 typedef sctp_inithdr_t sctp_initackhdr_t;
 
-typedef struct test_sctp_hdr_s {
+typedef struct et_sctp_hdr_s {
   unsigned int src_port;
   unsigned int dst_port;
   sctp_cid_t   chunk_type;
@@ -136,38 +160,145 @@ typedef struct test_sctp_hdr_s {
     sctp_inithdr_t    init_hdr;
     sctp_initackhdr_t init_ack_hdr;
   } u;
-} test_sctp_hdr_t;
+} et_sctp_hdr_t;
 
-typedef struct test_ip_s {
+typedef struct et_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_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;
-  struct test_packet_s *next;
-}test_packet_t;
-
-typedef struct test_scenario_s {
+}et_ip_t;
+
+typedef struct et_ip_hdr_s {
+  et_ip_t  src;
+  et_ip_t  dst;
+} et_ip_hdr_t;
+
+typedef struct et_packet_s {
+  et_packet_action_t   action;
+  struct timeval       time_relative_to_first_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;
+  et_ip_hdr_t          ip_hdr;
+  et_sctp_hdr_t        sctp_hdr;
+  struct et_packet_s  *next;
+  //scenario running vars
+  et_packet_status_t   status;
+}et_packet_t;
+
+
+typedef struct sctp_epoll_s {
+  /* Array of events monitored by the task.
+   * By default only one fd is monitored (the one used to received messages
+   * from other tasks).
+   * More events can be suscribed later by the task itself.
+   */
+  struct epoll_event *events;
+
+  int epoll_nb_events;
+
+} thread_desc_t;
+
+typedef struct et_scenario_s {
   xmlChar        *name;
-  test_packet_t  *list_packet;
-}test_scenario_t;
+  et_packet_t   *list_packet;
+
+  // playing scenario
+  et_packet_t   *waited_packet;
+  et_packet_t   *current_packet;
+} et_scenario_t;
+
+
+typedef enum {
+  ET_EVENT_START = 0,
+  ET_EVENT_INIT = ET_EVENT_START,
+  ET_EVENT_RX_SCTP_EVENT,
+  ET_EVENT_RX_S1AP,
+  ET_EVENT_RX_X2AP,
+  ET_EVENT_RX_PACKET_TIME_OUT,
+  ET_EVENT_TX_PACKET,
+  ET_EVENT_STOP,
+  ET_EVENT_END
+} et_event_code_t;
+
+typedef struct et_event_init_s {
+  et_scenario_t *scenario;
+} et_event_init_t;
+
+typedef struct et_event_s1ap_data_ind_s {
+  sctp_datahdr_t sctp_datahdr;
+} et_event_s1ap_data_ind_t;
+
+typedef struct et_event_s1ap_data_req_s {
+
+} et_event_s1ap_data_req_t;
+
+typedef struct et_event_s {
+  et_event_code_t code;
+  union {
+    et_event_init_t           init;
+    et_event_s1ap_data_ind_t  s1ap_data_ind;
+    et_event_s1ap_data_req_t  s1ap_data_req;
+  } u;
+} et_event_t;
+
+inline void et_free_pointer(void *p) {if (NULL != p) {free(p); p=NULL;}};
+
+//-------------------------
+void et_free_packet(et_packet_t* packet);
+void et_free_scenario(et_scenario_t* scenario);
+//-------------------------
+void et_display_packet_s1ap_data(const et_s1ap_t * const s1ap);
+void et_display_packet_sctp_init(const sctp_inithdr_t * const sctp);
+void et_display_packet_sctp_initack(const sctp_initackhdr_t * const sctp);
+void et_display_packet_sctp_data(const sctp_datahdr_t * const sctp);
+void et_display_packet_sctp(const et_sctp_hdr_t * const sctp);
+void et_display_packet_ip(const et_ip_hdr_t * const ip);
+void et_display_packet(const et_packet_t * const packet);
+void et_display_scenario(const et_scenario_t * const scenario);
+//-------------------------
+int et_s1ap_decode_initiating_message(s1ap_message *message, S1ap_InitiatingMessage_t *initiating_p);
+int et_s1ap_decode_successful_outcome(s1ap_message *message, S1ap_SuccessfulOutcome_t *successfullOutcome_p);
+int et_s1ap_decode_unsuccessful_outcome(s1ap_message *message, S1ap_UnsuccessfulOutcome_t *unSuccessfullOutcome_p);
+int et_s1ap_decode_pdu(S1AP_PDU_t * const pdu, s1ap_message * const message, const uint8_t * const buffer, const uint32_t length);
+void et_decode_s1ap(et_s1ap_t * const s1ap);
+//-------------------------
+void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind);
+void * et_s1ap_eNB_task(void *arg);
+int et_generate_xml_scenario(
+    const char const * xml_in_dir_name,
+    const char const * xml_in_scenario_filename,
+    const char const * enb_config_filename,
+          char const * tsml_out_scenario_filename);
+//-------------------------
+int et_scenario_fsm_notify_event_state_null(et_event_t event);
+int et_scenario_fsm_notify_event(et_event_t event);
+//-------------------------
+void et_parse_s1ap(xmlDocPtr doc, const xmlNode const *s1ap_node, et_s1ap_t * const s1ap);
+void et_parse_sctp_data_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_datahdr_t * const sctp_hdr);
+void et_parse_sctp_init_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_inithdr_t * const sctp_hdr);
+void et_parse_sctp_init_ack_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_initackhdr_t * const sctp_hdr);
+void et_parse_sctp(xmlDocPtr doc, const xmlNode const *sctp_node, et_sctp_hdr_t * const sctp_hdr);
+et_packet_t* et_parse_xml_packet(xmlDocPtr doc, xmlNodePtr node);
+et_scenario_t* et_generate_scenario(const char  * const et_scenario_filename );
+//-------------------------
+void et_print_hex_octets(const unsigned char * const byte_stream, const unsigned long int num);
+int  et_is_file_exists ( const char const * file_nameP, const char const *file_roleP);
+int  et_strip_extension( char *in_filename);
+int  et_split_path     ( char * pathP, char *** resP);
+void et_display_node   ( xmlNodePtr node, unsigned int indent);
+void et_display_tree   ( xmlNodePtr node, unsigned int indent);
+char * et_ip2ip_str(const et_ip_t * const ip);
+int et_hex2data(unsigned char * const data, const unsigned char * const hexstring, const unsigned int len);
+sctp_cid_t et_chunk_type_str2cid(const xmlChar * const chunk_type_str);
+const char * const et_chunk_type_cid2str(const sctp_cid_t chunk_type);
+et_packet_action_t et_action_str2et_action_t(const xmlChar * const action);
+void et_ip_str2et_ip(const xmlChar  * const ip_str, et_ip_t * const ip);
+uint32_t et_eNB_app_register(const Enb_properties_array_t *enb_properties);
+void *et_eNB_app_task(void *args_p);
+int et_play_scenario(et_scenario_t* const scenario);
 
-inline void free_pointer(void *p) {if (NULL != p) {free(p); p=NULL;}};
-#endif /* ENB_CONFIG_H_ */
-/** @} */
+#endif /* PLAY_SCENARIO_H_ */
diff --git a/openair3/TEST/EPC_TEST/play_scenario_decode.c b/openair3/TEST/EPC_TEST/play_scenario_decode.c
new file mode 100644
index 00000000000..aba1703eb3f
--- /dev/null
+++ b/openair3/TEST/EPC_TEST/play_scenario_decode.c
@@ -0,0 +1,214 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2014 Eurecom
+
+    OpenAirInterface is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+
+    OpenAirInterface is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenAirInterface.The full GNU General Public License is
+    included in this distribution in the file called "COPYING". If not,
+    see <http://www.gnu.org/licenses/>.
+
+  Contact Information
+  OpenAirInterface Admin: openair_admin@eurecom.fr
+  OpenAirInterface Tech : openair_tech@eurecom.fr
+  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
+
+  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+ *******************************************************************************/
+
+/*
+                                play_scenario_decode.c
+                                -------------------
+  AUTHOR  : Lionel GAUTHIER
+  COMPANY : EURECOM
+  EMAIL   : Lionel.Gauthier@eurecom.fr
+ */
+
+#include "intertask_interface.h"
+#include "platform_types.h"
+#include "s1ap_ies_defs.h"
+#include "s1ap_eNB_decoder.h"
+#include "assertions.h"
+#include "play_scenario.h"
+
+//------------------------------------------------------------------------------
+int et_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 et_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 et_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:
+    ret = s1ap_decode_s1ap_s1setupfailureies(&message->msg.s1ap_S1SetupFailureIEs, &unSuccessfullOutcome_p->value);
+    break;
+
+  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 et_s1ap_decode_pdu(S1AP_PDU_t * const pdu, s1ap_message * const message, const uint8_t * const buffer, const uint32_t length)
+{
+  asn_dec_rval_t dec_ret;
+
+  DevAssert(buffer != NULL);
+
+  memset((void *)pdu, 0, sizeof(S1AP_PDU_t));
+
+  dec_ret = aper_decode(NULL,
+                        &asn_DEF_S1AP_PDU,
+                        (void **)&pdu,
+                        buffer,
+                        length,
+                        0,
+                        0);
+
+  if (dec_ret.code != RC_OK) {
+    S1AP_ERROR("Failed to decode pdu\n");
+    return -1;
+  }
+
+  message->direction = pdu->present;
+
+  switch(pdu->present) {
+  case S1AP_PDU_PR_initiatingMessage:
+    return et_s1ap_decode_initiating_message(message,
+           &pdu->choice.initiatingMessage);
+
+  case S1AP_PDU_PR_successfulOutcome:
+    return et_s1ap_decode_successful_outcome(message,
+           &pdu->choice.successfulOutcome);
+
+  case S1AP_PDU_PR_unsuccessfulOutcome:
+    return et_s1ap_decode_unsuccessful_outcome(message,
+           &pdu->choice.unsuccessfulOutcome);
+
+  default:
+    AssertFatal(0, "Unknown presence (%d) or not implemented\n", (int)pdu->present);
+    break;
+  }
+  return -1;
+}
+//------------------------------------------------------------------------------
+void et_decode_s1ap(et_s1ap_t * const s1ap)
+{
+  if (NULL != s1ap) {
+    if (et_s1ap_decode_pdu(&s1ap->pdu, &s1ap->message, s1ap->binary_stream, s1ap->binary_stream_allocated_size) < 0) {
+      AssertFatal (0, "ERROR %s() Cannot decode S1AP message!\n", __FUNCTION__);
+    }
+  }
+}
diff --git a/openair3/TEST/EPC_TEST/play_scenario_display.c b/openair3/TEST/EPC_TEST/play_scenario_display.c
new file mode 100644
index 00000000000..406c69c8587
--- /dev/null
+++ b/openair3/TEST/EPC_TEST/play_scenario_display.c
@@ -0,0 +1,292 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2014 Eurecom
+
+    OpenAirInterface is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+
+    OpenAirInterface is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenAirInterface.The full GNU General Public License is
+    included in this distribution in the file called "COPYING". If not,
+    see <http://www.gnu.org/licenses/>.
+
+  Contact Information
+  OpenAirInterface Admin: openair_admin@eurecom.fr
+  OpenAirInterface Tech : openair_tech@eurecom.fr
+  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
+
+  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+ *******************************************************************************/
+
+/*
+                                play_scenario_display.c
+                                -------------------
+  AUTHOR  : Lionel GAUTHIER
+  COMPANY : EURECOM
+  EMAIL   : Lionel.Gauthier@eurecom.fr
+ */
+#include <string.h>
+#include <stdio.h>
+
+#include "intertask_interface.h"
+#include "platform_types.h"
+#include "assertions.h"
+#include "s1ap_ies_defs.h"
+#include "s1ap_eNB_decoder.h"
+#include "play_scenario.h"
+//-----------------------------------------------------------------------------
+void et_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");
+}
+
+//------------------------------------------------------------------------------
+void et_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);
+      xmlFree(content);
+    } else {
+      printf("%s\n", path);
+    }
+    xmlFree(path);
+  }
+}
+//------------------------------------------------------------------------------
+void et_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) {
+      et_display_node(cur_node, indent);
+    }
+    et_display_tree(cur_node->children, indent++);
+  }
+}
+//------------------------------------------------------------------------------
+void et_display_packet_s1ap_data(const et_s1ap_t * const s1ap)
+{
+  char       *message_string = NULL;
+
+  if (s1ap) {
+    message_string = calloc(20000, sizeof(char));
+    AssertFatal (NULL != message_string, "ERROR malloc()failed!\n");
+    s1ap_string_total_size = 0;
+    switch(s1ap->pdu.present) {
+    case S1AP_PDU_PR_initiatingMessage:
+      switch(s1ap->pdu.choice.initiatingMessage.procedureCode) {
+      case S1ap_ProcedureCode_id_downlinkNASTransport:      s1ap_xer_print_s1ap_downlinknastransport(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_InitialContextSetup:       s1ap_xer_print_s1ap_initialcontextsetuprequest(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_UEContextRelease:          s1ap_xer_print_s1ap_uecontextreleasecommand(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_Paging:                    s1ap_xer_print_s1ap_paging(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_uplinkNASTransport:        s1ap_xer_print_s1ap_uplinknastransport(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_S1Setup:                   s1ap_xer_print_s1ap_s1setuprequest(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_initialUEMessage:          s1ap_xer_print_s1ap_initialuemessage(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_UEContextReleaseRequest:   s1ap_xer_print_s1ap_uecontextreleaserequest(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_UECapabilityInfoIndication:s1ap_xer_print_s1ap_uecapabilityinfoindication(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_NASNonDeliveryIndication:  s1ap_xer_print_s1ap_nasnondeliveryindication_(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      default:
+        AssertFatal( 0 , "Unknown procedure ID (%d) for initiating message\n",
+                     (int)s1ap->pdu.choice.initiatingMessage.procedureCode);
+      }
+      break;
+    case S1AP_PDU_PR_successfulOutcome:
+      switch(s1ap->pdu.choice.successfulOutcome.procedureCode) {
+      case S1ap_ProcedureCode_id_S1Setup:                   s1ap_xer_print_s1ap_s1setupresponse(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_InitialContextSetup:       s1ap_xer_print_s1ap_initialcontextsetupresponse(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_UEContextRelease:          s1ap_xer_print_s1ap_uecontextreleasecomplete(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      default:
+        AssertFatal(0, "Unknown procedure ID (%d) for successfull outcome message\n",
+                   (int)s1ap->pdu.choice.successfulOutcome.procedureCode);
+      }
+      break;
+
+    case S1AP_PDU_PR_unsuccessfulOutcome:
+      switch(s1ap->pdu.choice.unsuccessfulOutcome.procedureCode) {
+      case S1ap_ProcedureCode_id_S1Setup:                   s1ap_xer_print_s1ap_s1setupfailure(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      case S1ap_ProcedureCode_id_InitialContextSetup:       s1ap_xer_print_s1ap_initialcontextsetupfailure(s1ap_xer__print2sp, message_string, (s1ap_message *)&s1ap->message);break;
+      default:
+        et_free_pointer(message_string);
+        AssertFatal(0,"Unknown procedure ID (%d) for unsuccessfull outcome message\n",
+                   (int)s1ap->pdu.choice.unsuccessfulOutcome.procedureCode);
+        break;
+      }
+      break;
+    default:
+      AssertFatal(0, "Unknown presence (%d) or not implemented\n", (int)s1ap->pdu.present);
+      break;
+    }
+    fprintf(stdout, "\t\tSCTP.data XML dump:\n%s\n", message_string);
+    et_free_pointer(message_string);
+  }
+}
+//------------------------------------------------------------------------------
+void et_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 et_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 et_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);
+    if (sctp->ppid == 18) {
+      et_display_packet_s1ap_data(&sctp->payload);
+    }
+    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");
+      et_print_hex_octets(sctp->payload.binary_stream, sctp->payload.binary_stream_allocated_size);
+    } else {
+      fprintf(stdout, "\t\tSCTP.data.binary_stream       : NULL\n");
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+void et_display_packet_sctp(const et_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", et_chunk_type_cid2str(sctp->chunk_type));
+    switch (sctp->chunk_type) {
+      case SCTP_CID_DATA:
+        et_display_packet_sctp_data(&sctp->u.data_hdr);
+        break;
+      case SCTP_CID_INIT:
+        et_display_packet_sctp_initack(&sctp->u.init_hdr);
+        break;
+      case SCTP_CID_INIT_ACK:
+        et_display_packet_sctp_initack(&sctp->u.init_ack_hdr);
+        break;
+      default:
+        ;
+    }
+  }
+}
+//------------------------------------------------------------------------------
+void et_display_packet_ip(const et_ip_hdr_t * const ip)
+{
+  if (ip) {
+    fprintf(stdout, "\t\tSource address      : %s\n", et_ip2ip_str(&ip->src));
+    fprintf(stdout, "\t\tDestination address : %s\n", et_ip2ip_str(&ip->dst));
+  }
+}
+
+//------------------------------------------------------------------------------
+void et_display_packet(const et_packet_t * const packet)
+{
+  if (packet) {
+    fprintf(stdout, "-------------------------------------------------------------------------------\n");
+    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   ET_PACKET_ACTION_S1C_SEND:
+      fprintf(stdout, "\tPacket:\tAction SEND\n");
+      break;
+    case   ET_PACKET_ACTION_S1C_RECEIVE:
+      fprintf(stdout, "\tPacket:\tAction RECEIVE\n");
+      break;
+    default:
+      fprintf(stdout, "\tPacket:\tAction UNKNOWN\n");
+    }
+    et_display_packet_ip(&packet->ip_hdr);
+    et_display_packet_sctp(&packet->sctp_hdr);
+  }
+}
+//------------------------------------------------------------------------------
+void et_display_scenario(const et_scenario_t * const scenario)
+{
+  et_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) {
+      et_display_packet(packet);
+      packet = packet->next;
+    }
+  }
+}
diff --git a/openair3/TEST/EPC_TEST/play_scenario_fsm.c b/openair3/TEST/EPC_TEST/play_scenario_fsm.c
new file mode 100644
index 00000000000..6c73793f4df
--- /dev/null
+++ b/openair3/TEST/EPC_TEST/play_scenario_fsm.c
@@ -0,0 +1,127 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2014 Eurecom
+
+    OpenAirInterface is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+
+    OpenAirInterface is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenAirInterface.The full GNU General Public License is
+    included in this distribution in the file called "COPYING". If not,
+    see <http://www.gnu.org/licenses/>.
+
+  Contact Information
+  OpenAirInterface Admin: openair_admin@eurecom.fr
+  OpenAirInterface Tech : openair_tech@eurecom.fr
+  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
+
+  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+ *******************************************************************************/
+
+/*
+                                play_scenario_fsm.c
+                                -------------------
+  AUTHOR  : Lionel GAUTHIER
+  COMPANY : EURECOM
+  EMAIL   : Lionel.Gauthier@eurecom.fr
+ */
+#include <stdio.h>
+
+#include "intertask_interface.h"
+#include "platform_types.h"
+#include "assertions.h"
+#include "play_scenario.h"
+
+
+et_scenario_t  *g_scenario  = NULL;
+et_fsm_state_t  g_fsm_state = ET_FSM_STATE_NULL;
+//------------------------------------------------------------------------------
+int et_scenario_fsm_notify_event_state_null(et_event_t event)
+{
+  et_packet_t                    *packet            = NULL;
+  const Enb_properties_array_t   *enb_properties_p  = NULL;
+  uint32_t                        register_enb_pending;
+
+  switch (event.code){
+    case ET_EVENT_INIT:
+      AssertFatal(NULL == g_scenario, "Current scenario not ended");
+      g_scenario = event.u.init.scenario;
+      packet = g_scenario->list_packet;
+      while (NULL != packet) {
+        switch (packet->sctp_hdr.chunk_type) {
+
+          case SCTP_CID_DATA :
+            // no init in this scenario, may be sub-scenario
+            if (packet->action == ET_PACKET_ACTION_S1C_SEND) {
+            } else if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
+              g_scenario->waited_packet = packet;
+            } else {
+              packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
+              packet = packet->next;
+            }
+            break;
+          case SCTP_CID_INIT:
+          case SCTP_CID_INIT_ACK:
+            enb_properties_p = enb_config_get();
+            /* Try to register each eNB */
+            g_fsm_state = ET_FSM_STATE_CONNECTING_SCTP;
+            register_enb_pending = et_eNB_app_register (enb_properties_p);
+            break;
+          case SCTP_CID_HEARTBEAT:
+          case SCTP_CID_HEARTBEAT_ACK:
+          case SCTP_CID_COOKIE_ECHO:
+          case SCTP_CID_COOKIE_ACK:
+          case SCTP_CID_ECN_ECNE:
+          case SCTP_CID_ECN_CWR:
+            packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
+            packet = packet->next;
+            break;
+          case SCTP_CID_ABORT:
+          case SCTP_CID_SHUTDOWN:
+          case SCTP_CID_SHUTDOWN_ACK:
+          case SCTP_CID_ERROR:
+          case SCTP_CID_SHUTDOWN_COMPLETE:
+            AssertFatal(0, "The scenario should be cleaned (packet %s cannot be processed at this time)", et_chunk_type_cid2str(packet->sctp_hdr.chunk_type));
+            break;
+
+          default:
+            packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
+            packet = packet->next;
+        }
+      }
+      fprintf(stderr, "No Packet found in this scenario: %s\n", g_scenario->name);
+      return -1;
+      break;
+
+    case ET_EVENT_STOP:
+      break;
+
+    default:
+      AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_NULL", event.code);
+  }
+  return 0;
+}
+
+//------------------------------------------------------------------------------
+int et_scenario_fsm_notify_event(et_event_t event)
+{
+  AssertFatal((event.code >= ET_EVENT_START) && (event.code < ET_EVENT_END), "Unknown et_event_t.code %d", event.code);
+
+  switch (g_fsm_state){
+    case ET_FSM_STATE_NULL: return et_scenario_fsm_notify_event_state_null(event); break;
+    case ET_FSM_STATE_CONNECTING_SCTP: return et_scenario_fsm_notify_event_state_null(event); break;
+    case ET_FSM_STATE_WAITING_TX_EVENT: return et_scenario_fsm_notify_event_state_null(event); break;
+    case ET_FSM_STATE_WAITING_RX_EVENT: return et_scenario_fsm_notify_event_state_null(event); break;
+    default:
+      return -1;
+  }
+}
diff --git a/openair3/TEST/EPC_TEST/play_scenario_parse.c b/openair3/TEST/EPC_TEST/play_scenario_parse.c
new file mode 100644
index 00000000000..236c17963ab
--- /dev/null
+++ b/openair3/TEST/EPC_TEST/play_scenario_parse.c
@@ -0,0 +1,561 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2014 Eurecom
+
+    OpenAirInterface is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+
+    OpenAirInterface is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenAirInterface.The full GNU General Public License is
+    included in this distribution in the file called "COPYING". If not,
+    see <http://www.gnu.org/licenses/>.
+
+  Contact Information
+  OpenAirInterface Admin: openair_admin@eurecom.fr
+  OpenAirInterface Tech : openair_tech@eurecom.fr
+  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
+
+  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+ *******************************************************************************/
+
+/*
+                                play_scenario_parse.c
+                                -------------------
+  AUTHOR  : Lionel GAUTHIER
+  COMPANY : EURECOM
+  EMAIL   : Lionel.Gauthier@eurecom.fr
+ */
+
+#include <libxml/xmlmemory.h>
+#include <libxml/debugXML.h>
+#include <libxml/xmlIO.h>
+#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>
+#include <libxslt/xsltutils.h>
+#include <sys/time.h>
+
+#include "intertask_interface.h"
+#include "platform_types.h"
+#include "enb_config.h"
+#include "assertions.h"
+#include "play_scenario.h"
+//------------------------------------------------------------------------------
+#define ENB_CONFIG_MAX_XSLT_PARAMS 32
+//------------------------------------------------------------------------------
+extern char                  *g_openair_dir;
+extern Enb_properties_array_t enb_properties;
+//------------------------------------------------------------------------------
+void et_parse_s1ap(xmlDocPtr doc, const xmlNode const *s1ap_node, et_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"))) {
+            go_deeper_in_tree = 0;
+          }
+          xmlFree(xml_char);
+        }
+        if (0 < go_deeper_in_tree) {
+          // 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 = et_hex2data( &s1ap->binary_stream[s1ap->binary_stream_pos], xml_char, xmlStrlen(xml_char));
+              s1ap->binary_stream_pos += xmlStrlen(xml_char)/2;
+              et_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) {
+        et_parse_s1ap(doc, cur_node->children, s1ap);
+      }
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+void et_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) {
+      et_parse_sctp_data_chunk(doc, cur_node, sctp_hdr);
+    }
+  }
+
+}
+//------------------------------------------------------------------------------
+void et_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;
+
+  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) {
+      et_parse_sctp_init_chunk(doc, cur_node, sctp_hdr);
+    }
+  }
+}
+//------------------------------------------------------------------------------
+void et_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) {
+      et_parse_sctp_init_ack_chunk(doc, cur_node, sctp_hdr);
+    }
+  }
+}
+//------------------------------------------------------------------------------
+void et_parse_sctp(xmlDocPtr doc, const xmlNode const *sctp_node, et_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);
+          }
+          et_parse_s1ap(doc, sctp_node, &sctp_hdr->u.data_hdr.payload);
+          et_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:
+              et_parse_sctp_data_chunk(doc, sctp_node->parent, &sctp_hdr->u.data_hdr);
+              break;
+            case SCTP_CID_INIT:
+              et_parse_sctp_init_chunk(doc, sctp_node->parent, &sctp_hdr->u.init_hdr);
+              break;
+            case SCTP_CID_INIT_ACK:
+              et_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) {
+      et_parse_sctp(doc, cur_node, sctp_hdr);
+    }
+  }
+}
+//------------------------------------------------------------------------------
+et_packet_t* et_parse_xml_packet(xmlDocPtr doc, xmlNodePtr node) {
+
+  et_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 = et_action_str2et_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) {
+        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 == ET_PACKET_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 == ET_PACKET_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);
+          et_ip_str2et_ip(xml_char, &packet->ip_hdr.src);
+          xmlFree(xml_char);
+        } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"ip.dst"))) {
+          xml_char = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+          et_ip_str2et_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"))) {
+              et_parse_sctp(doc, cur_node, &packet->sctp_hdr);
+            }
+            xmlFree(xml_char);
+          }
+        }
+      //}
+    }
+  }
+  return packet;
+}
+//------------------------------------------------------------------------------
+et_scenario_t* et_generate_scenario(
+    const char  * const tsml_out_scenario_filename )
+{
+  xmlDocPtr         doc      = NULL;
+  xmlNodePtr        root     = NULL;
+  xmlNodePtr        node     = NULL;
+  xmlChar          *xml_char = NULL;
+  et_scenario_t  *scenario = NULL;
+  et_packet_t    *packet   = NULL;
+  et_packet_t   **next_packet   = NULL;
+
+  doc = xmlParseFile(tsml_out_scenario_filename);
+  if (NULL == doc) {
+    AssertFatal (0, "Could not parse scenario xml file %s!\n", tsml_out_scenario_filename);
+  } else {
+    fprintf(stdout, "Test scenario file to play: %s\n", tsml_out_scenario_filename);
+    //xmlDebugDumpDocument(NULL, doc);
+  }
+
+  // Get root
+  root = xmlDocGetRootElement(doc);
+  if (NULL != root) {
+    if ((!xmlStrcmp(root->name, (const xmlChar *)"scenario"))) {
+      xml_char = xmlGetProp(root, (const xmlChar *)"name");
+      printf("scenario name: %s\n", xml_char);
+      scenario = calloc(1, sizeof(*scenario));
+      scenario->name = xml_char; // nodup nofree
+      next_packet = &scenario->list_packet;
+      for (node = root->children; node != NULL; node = node->next) {
+        if ((!xmlStrcmp(node->name, (const xmlChar *)"packet"))) {
+          packet = et_parse_xml_packet(doc, node);
+          if (NULL != packet) {
+            *next_packet = packet;
+            next_packet = &packet->next;
+          } else {
+            fprintf(stdout, "WARNING omitted packet:\n");
+            et_display_node(node, 0);
+          }
+        }
+      }
+    }
+  } else {
+    fprintf(stderr, "Empty xml document\n");
+  }
+  xmlFreeDoc(doc);
+  xmlCleanupParser();
+  return scenario;
+}
+//------------------------------------------------------------------------------
+int et_generate_xml_scenario(
+    const char const * xml_in_dir_name,
+    const char const * xml_in_scenario_filename,
+    const char const * enb_config_filename,
+          char const * tsml_out_scenario_filename)
+//------------------------------------------------------------------------------
+{
+  //int fd_pdml_in;
+  xsltStylesheetPtr cur = NULL;
+  xmlDocPtr         doc, res;
+  FILE             *play_scenario_file = NULL;
+  const char       *params[2*ENB_CONFIG_MAX_XSLT_PARAMS];
+  int               nb_params = 0;
+  int               i,j;
+  char              astring[1024];
+  struct in_addr    addr;
+  int               ret      = 0;
+
+  memset(astring, 0, sizeof(astring));
+  if (getcwd(astring, sizeof(astring)) != NULL) {
+    fprintf(stdout, "working in %s directory\n", astring);
+  } else {
+    perror("getcwd() ERROR");
+    exit(1);
+  }
+
+  memset(astring, 0, sizeof(astring));
+  strcat(astring, g_openair_dir);
+  strcat(astring, "/openair3/TEST/EPC_TEST/play_scenario.xsl");
+
+  xmlSubstituteEntitiesDefault(1);
+  xmlLoadExtDtdDefaultValue = 1;
+  cur = xsltParseStylesheetFile((const xmlChar *)astring);
+  if (NULL == cur) {
+    AssertFatal (0, "Could not parse stylesheet file %s (check OPENAIR_DIR env variable)!\n", astring);
+  } else {
+    fprintf(stdout, "XSLT style sheet: %s\n", astring);
+  }
+
+  doc = xmlParseFile(xml_in_scenario_filename);
+  if (NULL == doc) {
+    AssertFatal (0, "Could not parse scenario xml file %s!\n", xml_in_scenario_filename);
+  } else {
+    fprintf(stdout, "Test scenario file: %s\n", xml_in_scenario_filename);
+  }
+
+  for (i = 0; i < enb_properties.number; i++) {
+    // eNB S1-C IPv4 address
+    sprintf(astring, "enb_s1c%d", i);
+    params[nb_params++] = strdup(astring);
+    addr.s_addr = enb_properties.properties[i]->enb_ipv4_address_for_S1_MME;
+    sprintf(astring, "\"%s\"", inet_ntoa(addr));
+    params[nb_params++] = strdup(astring);
+
+    // MME S1-C IPv4 address
+    for (j = 0; j < enb_properties.properties[i]->nb_mme; j++) {
+      sprintf(astring, "mme_s1c%d_%d", i, j);
+      params[nb_params++] = strdup(astring);
+      AssertFatal (enb_properties.properties[i]->mme_ip_address[j].ipv4_address,
+          "Only support MME IPv4 address\n");
+      sprintf(astring, "\"%s\"", enb_properties.properties[i]->mme_ip_address[j].ipv4_address);
+      params[nb_params++] = strdup(astring);
+    }
+  }
+  params[nb_params] = NULL;
+  res = xsltApplyStylesheet(cur, doc, params);
+  if (NULL != res) {
+    sprintf((char *)tsml_out_scenario_filename,"%s",xml_in_scenario_filename);
+    if (et_strip_extension((char *)tsml_out_scenario_filename) > 0) {
+      strcat((char *)tsml_out_scenario_filename, ".tsml");
+      play_scenario_file = fopen( tsml_out_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", tsml_out_scenario_filename);
+      } else {
+        fprintf(stderr, "ERROR in fopen(%s)\n", tsml_out_scenario_filename);
+        ret = -1;
+      }
+    } else {
+      fprintf(stderr, "ERROR in strip_extension()\n");
+      ret = -1;
+    }
+  } else {
+    fprintf(stderr, "ERROR in xsltApplyStylesheet()\n");
+    ret = -1;
+  }
+  xsltFreeStylesheet(cur);
+  xmlFreeDoc(doc);
+  xmlFreeDoc(res);
+
+  xsltCleanupGlobals();
+  xmlCleanupParser();
+  return ret;
+}
+
diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
new file mode 100644
index 00000000000..cb5571c28b6
--- /dev/null
+++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
@@ -0,0 +1,162 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2014 Eurecom
+
+    OpenAirInterface is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+
+    OpenAirInterface is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenAirInterface.The full GNU General Public License is
+    included in this distribution in the file called "COPYING". If not,
+    see <http://www.gnu.org/licenses/>.
+
+  Contact Information
+  OpenAirInterface Admin: openair_admin@eurecom.fr
+  OpenAirInterface Tech : openair_tech@eurecom.fr
+  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
+
+  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+ *******************************************************************************/
+
+/*
+                                play_scenario_s1ap.c
+                                -------------------
+  AUTHOR  : Lionel GAUTHIER
+  COMPANY : EURECOM
+  EMAIL   : Lionel.Gauthier@eurecom.fr
+ */
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "tree.h"
+#include "queue.h"
+
+
+#include "intertask_interface.h"
+#include "messages_types.h"
+#include "platform_types.h"
+#include "s1ap_common.h"
+#include "s1ap_eNB_defs.h"
+#include "s1ap_eNB_default_values.h"
+#include "s1ap_eNB_management_procedures.h"
+#include "s1ap_eNB.h"
+#include "play_scenario.h"
+#include "msc.h"
+#include "assertions.h"
+#include "conversions.h"
+
+
+//------------------------------------------------------------------------------
+extern void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
+extern void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB);
+//------------------------------------------------------------------------------
+void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind)
+{
+  int            result = 0;
+  et_event_t     event;
+
+  DevAssert(sctp_data_ind != NULL);
+
+  memset((void*)&event, 0, sizeof(event));
+
+  event.code = ET_EVENT_RX_S1AP;
+  event.u.s1ap_data_ind.sctp_datahdr.tsn                       = 0;
+  event.u.s1ap_data_ind.sctp_datahdr.stream                    = sctp_data_ind->stream;
+  event.u.s1ap_data_ind.sctp_datahdr.ssn                       = 0;
+  event.u.s1ap_data_ind.sctp_datahdr.ppid                      = 18; // find constant
+
+  event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream_pos = 0;
+  event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream_allocated_size = sctp_data_ind->buffer_length;
+  event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream = NULL;
+  if ((sctp_data_ind->buffer_length > 0) && (NULL != sctp_data_ind->buffer)) {
+    event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream   = calloc(1, sctp_data_ind->buffer_length);
+    memcpy(event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream,
+           sctp_data_ind->buffer,
+           sctp_data_ind->buffer_length);
+
+    if (et_s1ap_decode_pdu(
+           &event.u.s1ap_data_ind.sctp_datahdr.payload.pdu,
+           &event.u.s1ap_data_ind.sctp_datahdr.payload.message,
+           event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream,
+           event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream_allocated_size) < 0) {
+      AssertFatal (0, "ERROR %s() Cannot decode RX S1AP message!\n", __FUNCTION__);
+    }
+
+  }
+
+  result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
+  AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+
+  et_scenario_fsm_notify_event(event);
+
+}
+//------------------------------------------------------------------------------
+void *et_s1ap_eNB_task(void *arg)
+{
+  MessageDef *received_msg = NULL;
+  int         result;
+
+  S1AP_DEBUG("Starting S1AP layer\n");
+
+  s1ap_eNB_prepare_internal_data();
+
+  itti_mark_task_ready(TASK_S1AP);
+  MSC_START_USE();
+
+  while (1) {
+    itti_receive_msg(TASK_S1AP, &received_msg);
+
+    switch (ITTI_MSG_ID(received_msg)) {
+    case TERMINATE_MESSAGE:
+      itti_exit_task();
+      break;
+
+    case S1AP_REGISTER_ENB_REQ: {
+      /* Register a new eNB.
+       * in Virtual mode eNBs will be distinguished using the mod_id/
+       * Each eNB has to send an S1AP_REGISTER_ENB message with its
+       * own parameters.
+       */
+      s1ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
+                                   &S1AP_REGISTER_ENB_REQ(received_msg));
+    }
+    break;
+
+    case SCTP_NEW_ASSOCIATION_RESP: {
+      s1ap_eNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
+                                            &received_msg->ittiMsg.sctp_new_association_resp);
+    }
+    break;
+
+    case SCTP_DATA_IND: {
+      et_s1ap_eNB_handle_sctp_data_ind(&received_msg->ittiMsg.sctp_data_ind);
+    }
+    break;
+
+
+    default:
+      S1AP_ERROR("Received unhandled message: %d:%s\n",
+                 ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
+      break;
+    }
+
+    result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
+    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+
+    received_msg = NULL;
+  }
+
+  return NULL;
+}
+
+
diff --git a/openair3/TEST/EPC_TEST/play_scenario_sctp.c b/openair3/TEST/EPC_TEST/play_scenario_sctp.c
new file mode 100644
index 00000000000..6856cb29336
--- /dev/null
+++ b/openair3/TEST/EPC_TEST/play_scenario_sctp.c
@@ -0,0 +1,45 @@
+/*******************************************************************************
+    OpenAirInterface
+    Copyright(c) 1999 - 2014 Eurecom
+
+    OpenAirInterface is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+
+    OpenAirInterface is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenAirInterface.The full GNU General Public License is
+    included in this distribution in the file called "COPYING". If not,
+    see <http://www.gnu.org/licenses/>.
+
+  Contact Information
+  OpenAirInterface Admin: openair_admin@eurecom.fr
+  OpenAirInterface Tech : openair_tech@eurecom.fr
+  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
+
+  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+ *******************************************************************************/
+
+/*
+                                play_scenario_sctp.c
+                                -------------------
+  AUTHOR  : Lionel GAUTHIER
+  COMPANY : EURECOM
+  EMAIL   : Lionel.Gauthier@eurecom.fr
+ */
+
+
+#include <errno.h>
+
+#include "intertask_interface.h"
+#include "platform_types.h"
+#include "assertions.h"
+#include "play_scenario.h"
+
diff --git a/openair3/UTILS/conversions.h b/openair3/UTILS/conversions.h
index aaa2b9714f1..47912f0d92e 100644
--- a/openair3/UTILS/conversions.h
+++ b/openair3/UTILS/conversions.h
@@ -275,7 +275,6 @@ do {                                                    \
     (bITsTRING)->size = 3;                              \
     (bITsTRING)->bits_unused = 4;                       \
 } while(0)
-/*
 /* TS 36.413 v10.9.0 section 9.2.1.38:
  * E-UTRAN CGI/Cell Identity
  * The leftmost bits of the Cell
-- 
GitLab