diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index bcf90bdb83e65e41b8bf0aa12f4352aac039b735..9c5bbad0de9013aac449953598daa12a2c6c9217 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -337,6 +337,7 @@ set(S1AP_OAI_generated
   ${S1AP_C_DIR}/s1ap_decoder.c
   ${S1AP_C_DIR}/s1ap_encoder.c
   ${S1AP_C_DIR}/s1ap_xer_print.c
+  ${S1AP_C_DIR}/s1ap_compare.c
   ${S1AP_C_DIR}/s1ap_ies_defs.h
   )
 file(GLOB s1ap_h ${S1AP_C_DIR}/*.h)
@@ -1667,6 +1668,7 @@ add_executable(test_epc_play_scenario
   ${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_s1ap_compare_ie.c
   ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h
   ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_sctp.c
   ${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario.h
diff --git a/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py b/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py
index c298e8ae87e3f0a5af5ed860a57906ad1caf4060..f5daf03c254de78f1b979d6137b4dddec21014fc 100644
--- a/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py
+++ b/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py
@@ -250,20 +250,31 @@ for key in iesDefs:
     asn1cStruct = re.sub('Item', 'List', asn1cStruct)
     keylowerunderscore = re.sub('-', '_', key.lower())
     firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct)))
+
+    f.write("/* %s in iesDefs not in ieofielist.values()  */\n" % (key))
     f.write("/** \\brief Decode function for %s ies.\n" % (key))
     if len(iesDefs[key]["ies"]) != 0:
         f.write(" * \\param %s Pointer to ASN1 structure in which data will be stored\n" % (lowerFirstCamelWord(re.sub('-', '_', key))))
     f.write(" *  \\param any_p Pointer to the ANY value to decode.\n")
     f.write(" **/\n")
     f.write("int %s_decode_%s(\n" % (fileprefix, keylowerunderscore))
-
     if len(iesDefs[key]["ies"]) != 0:
         f.write("    %s_t *%s,\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key))))
     f.write("    ANY_t *any_p);\n\n")
 
+    f.write("/* %s in iesDefs not in ieofielist.values()  */\n" % (key))
+    f.write("/** \\brief Compare function for %s ies.\n" % (key))
+    f.write(" *  \\param %s Pointer to the ASN1 structure.\n" % (firstlower))
+    f.write(" *  \\param %s Pointer to the ASN1 structure.\n" % (firstlower))
+    f.write(" **/\n")
+    f.write("long %s_compare_%s(\n" % (fileprefix, keylowerunderscore))
+    f.write("    %s_t *%s1,\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key))))
+    f.write("    %s_t *%s2);\n\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key))))
+
     if len(iesDefs[key]["ies"]) == 0:
         continue
 
+    f.write("/* %s in iesDefs not in ieofielist.values()  */\n" % (key))
     f.write("/** \\brief Encode function for %s ies.\n" % (key))
     f.write(" *  \\param %s Pointer to the ASN1 structure.\n" % (firstlower))
     f.write(" *  \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key))))
@@ -272,16 +283,19 @@ for key in iesDefs:
     f.write("    %s_t *%s,\n" % (asn1cStruct, firstlower))
     f.write("    %s_t *%s);\n\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key))))
 
+
 for key in iesDefs:
     if key not in ieofielist.values():
         continue
     asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key))
     asn1cStruct = re.sub('Item', 'List', asn1cStruct)
     firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct)))
+    f.write("/* %s in iesDefs in ieofielist.values()  */\n" % (key))
     f.write("/** \\brief Encode function for %s ies.\n" % (key))
     f.write(" *  \\param %s Pointer to the ASN1 structure.\n" % (firstlower))
     f.write(" *  \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key))))
     f.write(" **/\n")
+    f.write("/* %s in iesDefs in ieofielist.values()  */\n" % (key))
     f.write("int %s_encode_%s(\n" % (fileprefix, firstlower.lower()))
     f.write("    %s_t *%s,\n" % (asn1cStruct, firstlower))
     f.write("    %sIEs_t *%sIEs);\n\n" % (asn1cStruct, firstlower))
@@ -289,9 +303,19 @@ for key in iesDefs:
     f.write(" *  \\param any_p Pointer to the ANY value to decode.\n")
     f.write(" *  \\param callback Callback function called when any_p is successfully decoded.\n")
     f.write(" **/\n")
+    f.write("/* %s in iesDefs in ieofielist.values()  */\n" % (key))
     f.write("int %s_decode_%s(\n" % (fileprefix, firstlower.lower()))
     f.write("    %sIEs_t *%sIEs,\n" % (asn1cStruct, firstlower))
     f.write("    %s_t *%s);\n\n" % (asn1cStruct, lowerFirstCamelWord(asn1cStruct)))
+    f.write("/** \\brief Compare function for %s ies.\n" % (key))
+    f.write(" *  \\param %s Pointer to the IES structure.\n" % (firstlower))
+    f.write(" *  \\param %s Pointer to the IES structure.\n" % (firstlower))
+    f.write(" **/\n")
+    f.write("long %s_compare_%s(\n" % (fileprefix, firstlower.lower()))
+    f.write("    %sIEs_t *%s1,\n"    % (asn1cStruct, firstlower))
+    f.write("    %sIEs_t *%s2);\n\n" % (asn1cStruct, firstlower))
+
+
 
 for key in iesDefs:
     asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key))
@@ -704,3 +728,123 @@ for (key, value) in iesDefs.items():
         #f.write("cb_failed:\n")
         #f.write("    return er;\n")
     f.write("}\n\n")
+
+
+#Generate xer print functions
+f = open(outdir + fileprefix + '_compare.c', 'w')
+outputHeaderToFile(f, filename)
+f.write("#include <stdlib.h>\n")
+f.write("#include <stdio.h>\n\n")
+f.write("#include <asn_application.h>\n#include <asn_internal.h>\n\n")
+f.write("#include \"%s_common.h\"\n#include \"%s_ies_defs.h\"\n" % (fileprefix, fileprefix))
+f.write("#include \"%s-ProtocolIE-ID.h\"\n\n" % (fileprefix_first_upper))
+
+
+for key in iesDefs:
+    if key in ieofielist.values():
+        continue
+    structName = re.sub('ies', '', key)
+    asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key))
+    asn1cStruct = re.sub('Item', 'List', asn1cStruct)
+    if asn1cStruct.rfind('_') == len(asn1cStruct) - 1:
+        asn1cStruct = asn1cStruct[:-1]
+    asn1cStructfirstlower = asn1cStruct[:1].lower() + asn1cStruct[1:]
+    firstwordlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct)))
+
+    iesaccess = ""
+    if key not in ieofielist.values():
+        iesaccess = "%s_ies." % (firstwordlower)
+
+    keyName = re.sub('-', '_', key)
+    keyupperunderscore = keyName.upper()
+    # No IE to encode...
+    if len(iesDefs[key]["ies"]) == 0:
+        continue
+
+    f.write("long %s_compare_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower())))
+    f.write("    %s_t *%s1,\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key))))
+    f.write("    %s_t *%s2) {\n\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key))))
+
+    f.write("    long rv = 0;\n\n")
+
+    f.write("    assert(%s1 != NULL);\n" % (lowerFirstCamelWord(re.sub('-', '_', key))));
+    f.write("    assert(%s2 != NULL);\n" % (lowerFirstCamelWord(re.sub('-', '_', key))));
+
+    loop = 0
+    for ie in iesDefs[key]["ies"]:
+        iename = re.sub('-', '_', re.sub('id-', '', ie[0]))
+        ienameunderscore = re.sub('-', '_', iename)
+        ienamefirstwordlower = lowerFirstCamelWord(iename)
+        ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper()
+        ietypeunderscore = re.sub('-', '_', ie[2])
+
+        if ie[3] != "mandatory":
+
+            loop = loop + 1
+            if loop == 1:
+                #f.write("    %s_IE_t *ie1 = NULL;\n" % (fileprefix_first_upper))
+                #f.write("    %s_IE_t *ie2 = NULL;\n" % (fileprefix_first_upper))
+                f.write("    if (%s1->presenceMask != %s2->presenceMask) return -1;\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), lowerFirstCamelWord(re.sub('-', '_', key))))
+
+            if ie[3] == "optional":
+                f.write("    /* Optional field */\n")
+            elif ie[3] == "conditional":
+                f.write("    /* Conditional field */\n")
+            f.write("    if (%s1->presenceMask & %s_%s_PRESENT) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), keyupperunderscore, ieupperunderscore))
+
+
+            if ie[2] in ieofielist.keys():
+                f.write("        /* collection field */\n")
+                f.write("        rv = %s_compare_%s(&%s1->%s, &%s2->%s);\n" % (fileprefix, ietypeunderscore.lower(), lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower ))
+                f.write("        if (rv != 0) {rv = rv << 8; rv |= %s_ProtocolIE_ID_id_%s; return rv;}\n" % (fileprefix_first_upper, ienameunderscore))
+            else:
+                f.write("        /* simple field */\n")
+                f.write("        rv = asn_DEF_%s.compare(&asn_DEF_%s, &%s1->%s, &asn_DEF_%s, &%s2->%s); \n" % (ietypeunderscore, ietypeunderscore, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower, ietypeunderscore, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower ))
+                f.write("        if (rv != 0) {rv = rv << 8; rv |= %s_ProtocolIE_ID_id_%s; return rv;}\n" % (fileprefix_first_upper, ienameunderscore))
+            f.write("        assert(0);\n");
+            f.write("    }\n\n")
+
+        else:
+            if ie[2] in ieofielist.keys():
+                f.write("    /* Mandatory collection field */\n")
+                f.write("    rv = %s_compare_%s(&%s1->%s, &%s2->%s);\n" % (fileprefix, ietypeunderscore.lower(), lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower ))
+                f.write("    if (rv != 0) {rv = rv << 8; rv |= %s_ProtocolIE_ID_id_%s; return rv;}\n" % (fileprefix_first_upper, ienameunderscore))
+            else:
+                f.write("    /* Mandatory simple field */\n")
+                f.write("    rv = asn_DEF_%s.compare(&asn_DEF_%s, &%s1->%s, &asn_DEF_%s, &%s2->%s);\n" % (ietypeunderscore, ietypeunderscore, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower, ietypeunderscore, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower ))
+                f.write("    if (rv != 0) {rv = rv << 8; rv |= %s_ProtocolIE_ID_id_%s; return rv;}\n" % (fileprefix_first_upper, ienameunderscore))
+    f.write("    return 0;\n")
+    f.write("}\n\n")
+
+for (key, value) in iesDefs.items():
+    if key not in ieofielist.values():
+        continue
+
+    ie = value["ies"][0]
+    ietypeunderscore = re.sub('-', '_', ie[2])
+    asn1cStruct = re.sub('-', '_', re.sub('IEs', '', re.sub('-IEs', '', key)))
+    asn1cStruct = re.sub('Item', 'List', asn1cStruct)
+    firstwordlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct)))
+
+    for (i, j) in ieofielist.items():
+        if j == key:
+            break
+
+    f.write("extern asn_TYPE_descriptor_t asn_DEF_%s;\n" % (ietypeunderscore))
+
+    f.write("long %s_compare_%s(\n" % (fileprefix, re.sub('-', '_', i).lower()))
+    f.write("    %sIEs_t *%sIEs1,\n" % (re.sub('-', '_', i), lowerFirstCamelWord(re.sub('-', '_', i))))
+    f.write("    %sIEs_t *%sIEs2) {\n\n" % (re.sub('-', '_', i), lowerFirstCamelWord(re.sub('-', '_', i))))
+    f.write("    int i;\n")
+    f.write("    long rv = 0;\n")
+
+    f.write("    assert(%sIEs1 != NULL);\n" % (lowerFirstCamelWord(re.sub('-', '_', i))));
+    f.write("    assert(%sIEs2 != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', i))));
+
+    f.write("    for (i = 0; i < %sIEs1->%s.count; i++) {\n" % (lowerFirstCamelWord(re.sub('-', '_', i)), re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key)))))
+    f.write("        rv = asn_DEF_%s.compare(&asn_DEF_%s, %sIEs1->%s.array[i], &asn_DEF_%s, %sIEs2->%s.array[i]);\n" % (ietypeunderscore, ietypeunderscore, lowerFirstCamelWord(re.sub('-', '_', i)), re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))), ietypeunderscore, lowerFirstCamelWord(re.sub('-', '_', i)), re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key)))))
+    f.write("        if (rv != 0) return rv;\n")
+    f.write("    }\n")
+    f.write("    return 0;\n")
+    f.write("}\n\n")
+
diff --git a/openair3/TEST/EPC_TEST/play_scenario.c b/openair3/TEST/EPC_TEST/play_scenario.c
index f8f334dd9cd0b23535b0813254c40d81363e60a5..216e098a018cec8681f710c002c329733c112702 100644
--- a/openair3/TEST/EPC_TEST/play_scenario.c
+++ b/openair3/TEST/EPC_TEST/play_scenario.c
@@ -318,15 +318,19 @@ int et_compare_et_ip_to_net_ip_address(const et_ip_t * const ip, const net_ip_ad
         S1AP_DEBUG("%s(%s,%s)=%d\n",__FUNCTION__,ip->str, net_ip->ipv4_address, strcmp(ip->str, net_ip->ipv4_address));
         return strcmp(ip->str, net_ip->ipv4_address);
       }
+      S1AP_DEBUG("%s(%s,%s)=-1 (IP version (4) not matching)\n",__FUNCTION__,ip->str, net_ip->ipv4_address);
       return -1;
       break;
     case AF_INET6:
       if (net_ip->ipv6) {
+        S1AP_DEBUG("%s(%s,%s)=%d\n",__FUNCTION__,ip->str, net_ip->ipv4_address, strcmp(ip->str, net_ip->ipv6_address));
         return strcmp(ip->str, net_ip->ipv6_address);
       }
+      S1AP_DEBUG("%s(%s,%s)=-1 (IP version (6) not matching)\n",__FUNCTION__,ip->str, net_ip->ipv6_address);
       return -1;
       break;
     default:
+      S1AP_DEBUG("%s(%s,...)=-1 (unknown IP version)\n",__FUNCTION__,ip->str);
       return -1;
   }
 }
diff --git a/openair3/TEST/EPC_TEST/play_scenario.h b/openair3/TEST/EPC_TEST/play_scenario.h
index 060c77b8eec5934b36453b51bb6b7ddefc94000f..3c8c5faef810f065b942544d8352eddb0fa9c214 100644
--- a/openair3/TEST/EPC_TEST/play_scenario.h
+++ b/openair3/TEST/EPC_TEST/play_scenario.h
@@ -47,6 +47,10 @@
 #include "play_scenario_s1ap_eNB_defs.h"
 #include "hashtable.h"
 
+// powers of 2
+#define ET_BIT_MASK_MATCH_SCTP_STREAM 1
+#define ET_BIT_MASK_MATCH_SCTP_SSN    2
+//#define ET_BIT_MASK_MATCH_S1AP_    2
 
 #define MAX_ENB 16
 
@@ -396,6 +400,8 @@ void et_s1ap_eNB_insert_new_instance(s1ap_eNB_instance_t *new_instance_p);
 struct s1ap_eNB_mme_data_s *et_s1ap_eNB_get_MME(s1ap_eNB_instance_t *instance_p,int32_t assoc_id, uint16_t cnx_id);
 s1ap_eNB_instance_t *et_s1ap_eNB_get_instance(instance_t instance);
 void et_s1ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,uint32_t buffer_length, uint16_t stream);
+int et_s1ap_is_matching(et_s1ap_t * const s1ap1, et_s1ap_t * const s1ap2, const uint32_t constraints);
+et_packet_t* et_build_packet_from_s1ap_data_ind(et_event_s1ap_data_ind_t * const s1ap_data_ind);
 void et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const sctp_data_ind);
 void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t * const sctp_data_ind);
 void et_s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
@@ -428,6 +434,11 @@ void et_parse_sctp(xmlDocPtr doc, const xmlNode const *sctp_node, et_sctp_hdr_t
 et_packet_t* et_parse_xml_packet(xmlDocPtr doc, xmlNodePtr node);
 et_scenario_t* et_generate_scenario(const char  * const et_scenario_filename );
 //-------------------------
+int et_s1ap_ies_is_matching(const S1AP_PDU_PR present, s1ap_message * const m1, s1ap_message * const m2, const uint32_t constraints);
+//-------------------------
+int et_sctp_data_is_matching(sctp_datahdr_t * const sctp1, sctp_datahdr_t * const sctp2, const uint32_t constraints);
+int et_sctp_is_matching(et_sctp_hdr_t * const sctp1, et_sctp_hdr_t * const sctp2, const uint32_t constraints);
+//------------------------------------------------------------------------------
 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);
diff --git a/openair3/TEST/EPC_TEST/play_scenario_fsm.c b/openair3/TEST/EPC_TEST/play_scenario_fsm.c
index 18dba384b0e76d3d82f6549b28756b2a2c8fb5b8..23ef72035cd89275748de4b023429f89c11c2a13 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_fsm.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_fsm.c
@@ -50,6 +50,7 @@
 et_scenario_t    *g_scenario  = NULL;
 pthread_mutex_t   g_fsm_lock  = PTHREAD_MUTEX_INITIALIZER;
 et_fsm_state_t    g_fsm_state = ET_FSM_STATE_NULL;
+uint32_t          g_constraints = ET_BIT_MASK_MATCH_SCTP_STREAM | ET_BIT_MASK_MATCH_SCTP_SSN;
 //------------------------------------------------------------------------------
 int timeval_subtract (struct timeval * const result, struct timeval * const a, struct timeval * const b)
 {
@@ -123,6 +124,9 @@ void et_scenario_schedule_tx_packet(et_packet_t * const packet)
       }
       if (we_are_too_early > 0) {
         // set timer
+        LOG_D(ENB_APP, "Send packet num %u original frame number %u in %ld.%d sec\n",
+            packet->packet_number, packet->original_frame_number, offset.tv_sec, offset.tv_usec);
+
         packet->status = ET_PACKET_STATUS_SCHEDULED_FOR_SENDING;
         if (timer_setup (offset.tv_sec, offset.tv_usec, TASK_S1AP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
                          NULL, &packet->timer_id) < 0) {
@@ -130,7 +134,9 @@ void et_scenario_schedule_tx_packet(et_packet_t * const packet)
         }
         // Done g_fsm_state = ET_FSM_STATE_WAITING_TX_EVENT;
       } else {
+        LOG_D(ENB_APP, "Send packet num %u original frame number %u immediately\n", packet->packet_number, packet->original_frame_number);
         // send immediately
+        AssertFatal(0 == gettimeofday(&packet->timestamp_packet, NULL), "gettimeofday() Failed");
         et_s1ap_eNB_itti_send_sctp_data_req(
             packet->enb_instance,
             packet->sctp_hdr.u.data_hdr.assoc_id,
@@ -161,7 +167,7 @@ et_fsm_state_t et_scenario_fsm_notify_event_state_running(et_event_t event)
       AssertFatal(0, "Event ET_EVENT_TX_TIMED_PACKET not handled in FSM state ET_FSM_STATE_RUNNING");
       break;
     case ET_EVENT_RX_S1AP:
-      AssertFatal(0, "TODO");
+      et_s1ap_process_rx_packet(&event.u.s1ap_data_ind);
       break;
     default:
       AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_RUNNING", event.code);
@@ -185,6 +191,7 @@ et_fsm_state_t et_scenario_fsm_notify_event_state_waiting(et_event_t event)
       break;
     case ET_EVENT_TX_TIMED_PACKET:
       // send immediately
+      AssertFatal(0 == gettimeofday(&event.u.tx_timed_packet->timestamp_packet, NULL), "gettimeofday() Failed");
       et_s1ap_eNB_itti_send_sctp_data_req(
           event.u.tx_timed_packet->enb_instance,
           event.u.tx_timed_packet->sctp_hdr.u.data_hdr.assoc_id,
@@ -290,7 +297,7 @@ et_fsm_state_t et_scenario_fsm_notify_event_state_null(et_event_t event)
         switch (g_scenario->next_packet->sctp_hdr.chunk_type) {
 
           case SCTP_CID_DATA :
-            // no init in this scenario, may be sub-scenario
+            // no init in this scenario, may be sub-scenario, ...
             if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_SEND) {
               et_scenario_schedule_tx_packet(g_scenario->next_packet);
               pthread_mutex_unlock(&g_fsm_lock);
diff --git a/openair3/TEST/EPC_TEST/play_scenario_parse.c b/openair3/TEST/EPC_TEST/play_scenario_parse.c
index 13c4746a5e8a37ef8aff735b45cda05a8239ca24..cb302f229a0c3d7d8a95d4caf6c3ec2d8bc07bff 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_parse.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_parse.c
@@ -518,7 +518,7 @@ int et_generate_xml_scenario(
 
   for (i = 0; i < g_enb_properties.number; i++) {
     // eNB S1-C IPv4 address
-    sprintf(astring, "enb_s1c%d", i);
+    sprintf(astring, "enb%d_s1c", i);
     params[nb_params++] = strdup(astring);
     addr.s_addr = g_enb_properties.properties[i]->enb_ipv4_address_for_S1_MME;
     sprintf(astring, "\"%s\"", inet_ntoa(addr));
@@ -526,7 +526,7 @@ int et_generate_xml_scenario(
 
     // MME S1-C IPv4 address
     for (j = 0; j < g_enb_properties.properties[i]->nb_mme; j++) {
-      sprintf(astring, "mme_s1c%d_%d", i, j);
+      sprintf(astring, "mme%d_s1c_%d", i, j);
       params[nb_params++] = strdup(astring);
       AssertFatal (g_enb_properties.properties[i]->mme_ip_address[j].ipv4_address,
           "Only support MME IPv4 address\n");
diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
index d11d032b430ac9aaf5b97f2181a65d8f8501cba3..408ff72a4a8c44422bad1cbfe08d98cff2b6f12f 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
@@ -40,6 +40,7 @@
 #include <stdint.h>
 #include <unistd.h>
 #include <crypt.h>
+#include <sys/time.h>
 #include "tree.h"
 #include "queue.h"
 
@@ -58,6 +59,7 @@ s1ap_eNB_internal_data_t s1ap_eNB_internal_data;
 RB_GENERATE(s1ap_mme_map, s1ap_eNB_mme_data_s, entry, et_s1ap_eNB_compare_assoc_id);
 //------------------------------------------------------------------------------
 extern et_scenario_t  *g_scenario;
+extern uint32_t        g_constraints;
 //------------------------------------------------------------------------------
 int et_s1ap_eNB_compare_assoc_id(
   struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2)
@@ -187,20 +189,86 @@ void et_s1ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id,
   itti_send_msg_to_task(TASK_SCTP, instance, message_p);
 }
 //------------------------------------------------------------------------------
-void et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const sctp_data_ind)
+int et_s1ap_is_matching(et_s1ap_t * const s1ap1, et_s1ap_t * const s1ap2, const uint32_t constraints)
+{
+  if (s1ap1->pdu.present != s1ap2->pdu.present)     return -6;
+  switch (s1ap1->pdu.present) {
+    case  S1AP_PDU_PR_NOTHING:
+      break;
+    case  S1AP_PDU_PR_initiatingMessage:
+      if (s1ap1->pdu.choice.initiatingMessage.procedureCode != s1ap2->pdu.choice.initiatingMessage.procedureCode) return -7;
+      if (s1ap1->pdu.choice.initiatingMessage.criticality != s1ap2->pdu.choice.initiatingMessage.criticality) return -8;
+      break;
+    case  S1AP_PDU_PR_successfulOutcome:
+      if (s1ap1->pdu.choice.successfulOutcome.procedureCode != s1ap2->pdu.choice.successfulOutcome.procedureCode) return -7;
+      if (s1ap1->pdu.choice.successfulOutcome.criticality != s1ap2->pdu.choice.successfulOutcome.criticality) return -8;
+      break;
+    case  S1AP_PDU_PR_unsuccessfulOutcome:
+      if (s1ap1->pdu.choice.unsuccessfulOutcome.procedureCode != s1ap2->pdu.choice.unsuccessfulOutcome.procedureCode) return -7;
+      if (s1ap1->pdu.choice.unsuccessfulOutcome.criticality != s1ap2->pdu.choice.unsuccessfulOutcome.criticality) return -8;
+      break;
+    default:
+      AssertFatal(0, "Unknown pdu.present %d", s1ap1->pdu.present);
+  }
+
+  if (s1ap1->binary_stream_allocated_size == s1ap2->binary_stream_allocated_size) {
+    if (memcmp((void*)s1ap1->binary_stream, (void*)s1ap2->binary_stream, s1ap1->binary_stream_allocated_size) ==  0) return 0;
+  }
+  // if no matching, may be the scenario need minor corrections (same enb_ue_s1ap_id but need to update mme_ue_s1ap_id)
+  return et_s1ap_ies_is_matching(s1ap1->pdu.present, &s1ap1->message, &s1ap2->message, constraints);
+}
+
+//------------------------------------------------------------------------------
+et_packet_t* et_build_packet_from_s1ap_data_ind(et_event_s1ap_data_ind_t * const s1ap_data_ind)
 {
   et_packet_t     * packet    = NULL;
+  AssertFatal (NULL != s1ap_data_ind, "Bad parameter sctp_data_ind\n");
+  packet = calloc(1, sizeof(*packet));
+  packet->action                                        = ET_PACKET_ACTION_S1C_NULL;
+  //packet->time_relative_to_first_packet.tv_sec          = 0;
+  //packet->time_relative_to_first_packet.tv_usec         = 0;
+  //packet->time_relative_to_last_sent_packet.tv_sec      = 0;
+  //packet->time_relative_to_last_sent_packet.tv_usec     = 0;
+  //packet->time_relative_to_last_received_packet.tv_sec  = 0;
+  //packet->time_relative_to_last_received_packet.tv_usec = 0;
+  //packet->original_frame_number                         = 0;
+  //packet->packet_number                                 = 0;
+  packet->enb_instance = 0; //TODO
+  //packet->ip_hdr;
+  // keep in mind: allocated buffer: sctp_datahdr.payload.binary_stream
+  memcpy((void*)&packet->sctp_hdr, (void*)&s1ap_data_ind->sctp_datahdr, sizeof(packet->sctp_hdr));
+  //packet->next = NULL;
+  packet->status = ET_PACKET_STATUS_RECEIVED;
+  //packet->timer_id = 0;
+  AssertFatal(0 == gettimeofday(&packet->timestamp_packet, NULL), "gettimeofday() Failed");
+  return packet;
+}
+
+
+//------------------------------------------------------------------------------
+void et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const s1ap_data_ind)
+{
+  et_packet_t     * packet    = NULL;
+  et_packet_t     * rx_packet = NULL;
   unsigned long int not_found = 1;
 
+  AssertFatal (NULL != s1ap_data_ind, "Bad parameter sctp_data_ind\n");
+  rx_packet = et_build_packet_from_s1ap_data_ind(s1ap_data_ind);
+
   packet = g_scenario->next_packet;
   // not_found threshold may sure depend on number of mme, may be not sure on number of UE
   while ((NULL != packet) && (not_found < 5)) {
     if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
       //TODO
+      if (et_sctp_is_matching(&packet->sctp_hdr, &rx_packet->sctp_hdr, g_constraints) == 0) {
+        et_scenario_set_packet_received(packet);
+      }
     }
     not_found += 1;
     packet = packet->next;
   }
+  S1AP_DEBUG("Rx packet not found in scenario:\n");
+  et_display_packet_sctp(&rx_packet->sctp_hdr);
 }
 
 //------------------------------------------------------------------------------
@@ -234,7 +302,7 @@ void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t * const sctp_data_ind)
            &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__);
+      AssertFatal (0, "ERROR Cannot decode RX S1AP message!\n");
     }
 
   }
@@ -319,6 +387,7 @@ void et_s1ap_update_assoc_id_of_packets(const int32_t assoc_id,
     switch (packet->sctp_hdr.chunk_type) {
 
       case SCTP_CID_DATA :
+        S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_DATA\n",__FUNCTION__,assoc_id);
         if (ET_PACKET_STATUS_NONE == packet->status) {
           if (0 < old_mme_port) {
             if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_SEND) {
@@ -355,6 +424,7 @@ void et_s1ap_update_assoc_id_of_packets(const int32_t assoc_id,
         // Strong assumption
         // in replayed scenario, the order of SCTP INIT packets is supposed to be the same as in the catched scenario
       case SCTP_CID_INIT:
+        S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_INIT\n",__FUNCTION__,assoc_id);
         ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.dst, &mme_desc_p->mme_net_ip_address);
         if (0 == ret) {
           ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.src, &s1ap_eNB_instance->s1c_net_ip_address);
@@ -363,6 +433,7 @@ void et_s1ap_update_assoc_id_of_packets(const int32_t assoc_id,
               if (ET_PACKET_STATUS_NONE == packet->status) {
                 packet->status = ET_PACKET_STATUS_SENT;
                 old_enb_port = packet->sctp_hdr.src_port;
+                S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_INIT SUCCESS\n",__FUNCTION__,assoc_id);
               }
             }
           }
@@ -370,14 +441,16 @@ void et_s1ap_update_assoc_id_of_packets(const int32_t assoc_id,
         break;
 
       case SCTP_CID_INIT_ACK:
-        ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.dst, &mme_desc_p->mme_net_ip_address);
+        S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_INIT_ACK\n",__FUNCTION__,assoc_id);
+        ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.src, &mme_desc_p->mme_net_ip_address);
         if (0 == ret) {
-          ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.src, &s1ap_eNB_instance->s1c_net_ip_address);
+          ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.dst, &s1ap_eNB_instance->s1c_net_ip_address);
           if (0 == ret) {
             if (old_enb_port == packet->sctp_hdr.dst_port) {
               if (ET_PACKET_STATUS_NONE == packet->status) {
                 packet->status = ET_PACKET_STATUS_RECEIVED;
                 old_mme_port = packet->sctp_hdr.dst_port;
+                S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_INIT_ACK SUCCESS\n",__FUNCTION__,assoc_id);
               }
             }
           }
@@ -475,6 +548,7 @@ void et_s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_
     DevCheck(new_instance->mcc == s1ap_register_eNB->mcc, new_instance->mcc, s1ap_register_eNB->mcc, 0);
     DevCheck(new_instance->mnc == s1ap_register_eNB->mnc, new_instance->mnc, s1ap_register_eNB->mnc, 0);
     DevCheck(new_instance->mnc_digit_length == s1ap_register_eNB->mnc_digit_length, new_instance->mnc_digit_length, s1ap_register_eNB->mnc_digit_length, 0);
+    DevCheck(memcmp((void*)&new_instance->s1c_net_ip_address, (void*)&s1ap_register_eNB->enb_ip_address, sizeof(new_instance->s1c_net_ip_address)) == 0, 0,0,0);
   } else {
     new_instance = calloc(1, sizeof(s1ap_eNB_instance_t));
     DevAssert(new_instance != NULL);
@@ -491,6 +565,7 @@ void et_s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_
     new_instance->mcc              = s1ap_register_eNB->mcc;
     new_instance->mnc              = s1ap_register_eNB->mnc;
     new_instance->mnc_digit_length = s1ap_register_eNB->mnc_digit_length;
+    memcpy((void*)&new_instance->s1c_net_ip_address, (void*)&s1ap_register_eNB->enb_ip_address, sizeof(new_instance->s1c_net_ip_address));
 
     /* Add the new instance to the list of eNB (meaningfull in virtual mode) */
     et_s1ap_eNB_insert_new_instance(new_instance);
diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c
new file mode 100644
index 0000000000000000000000000000000000000000..5ad5708babda376024bfd6fbde16955eb5eca89a
--- /dev/null
+++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c
@@ -0,0 +1,273 @@
+/*******************************************************************************
+    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_compare_ie.c
+                                -------------------
+  AUTHOR  : Lionel GAUTHIER
+  COMPANY : EURECOM
+  EMAIL   : Lionel.Gauthier@eurecom.fr
+ */
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <crypt.h>
+#include "tree.h"
+#include "queue.h"
+
+
+#include "intertask_interface.h"
+#include "timer.h"
+#include "platform_types.h"
+#include "assertions.h"
+#include "conversions.h"
+#include "s1ap_common.h"
+#include "play_scenario_s1ap_eNB_defs.h"
+#include "play_scenario.h"
+#include "msc.h"
+//------------------------------------------------------------------------------
+extern et_scenario_t  *g_scenario;
+extern uint32_t        g_constraints;
+//------------------------------------------------------------------------------
+
+int et_s1ap_ies_is_matching(const S1AP_PDU_PR present, s1ap_message * const m1, s1ap_message * const m2, const uint32_t constraints)
+{
+  long ret = 0;
+  AssertFatal(m1 != NULL, "bad parameter m1");
+  AssertFatal(m2 != NULL, "bad parameter m2");
+  if (m1->procedureCode != m2->procedureCode) return -1;
+
+
+  // some cases can never occur since uplink only.
+  switch (m1->procedureCode) {
+    case  S1ap_ProcedureCode_id_HandoverPreparation:
+      AssertFatal(0, "S1ap_ProcedureCode_id_InitialContextSetup not implemented");
+      break;
+    case  S1ap_ProcedureCode_id_HandoverResourceAllocation:
+      AssertFatal(0, "S1ap_ProcedureCode_id_InitialContextSetup not implemented");
+      break;
+    case  S1ap_ProcedureCode_id_HandoverNotification:
+      AssertFatal(0, "S1ap_ProcedureCode_id_HandoverNotification not implemented");
+      break;
+    case  S1ap_ProcedureCode_id_PathSwitchRequest:
+      ret = s1ap_compare_s1ap_pathswitchrequesties(
+              &m1->msg.s1ap_PathSwitchRequestIEs,
+              &m2->msg.s1ap_PathSwitchRequestIEs);
+      break;
+    case  S1ap_ProcedureCode_id_HandoverCancel:
+      ret = s1ap_compare_s1ap_handovercancelies(
+              &m1->msg.s1ap_HandoverCancelIEs,
+              &m2->msg.s1ap_HandoverCancelIEs);
+      break;
+    case  S1ap_ProcedureCode_id_E_RABSetup:
+    case  S1ap_ProcedureCode_id_E_RABModify:
+    case  S1ap_ProcedureCode_id_E_RABRelease:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        ret = s1ap_compare_s1ap_e_rabreleasecommandies(
+                &m1->msg.s1ap_E_RABReleaseCommandIEs,
+                &m2->msg.s1ap_E_RABReleaseCommandIEs);
+      } else if (present == S1AP_PDU_PR_successfulOutcome) {
+        ret = s1ap_compare_s1ap_e_rabreleaseresponseies(
+                &m1->msg.s1ap_E_RABReleaseResponseIEs,
+                &m2->msg.s1ap_E_RABReleaseResponseIEs);
+      }
+      break;
+    case  S1ap_ProcedureCode_id_E_RABReleaseIndication:
+      ret = s1ap_compare_s1ap_e_rabreleaseindicationies(
+              &m1->msg.s1ap_E_RABReleaseIndicationIEs,
+              &m2->msg.s1ap_E_RABReleaseIndicationIEs);
+      break;
+    case  S1ap_ProcedureCode_id_InitialContextSetup:
+      AssertFatal(0, "S1ap_ProcedureCode_id_InitialContextSetup not implemented");
+      break;
+    case  S1ap_ProcedureCode_id_Paging:
+      ret = s1ap_compare_s1ap_pagingies(
+              &m1->msg.s1ap_PagingIEs,
+              &m2->msg.s1ap_PagingIEs);
+      break;
+    case  S1ap_ProcedureCode_id_downlinkNASTransport:
+      ret = s1ap_compare_s1ap_downlinknastransporties(
+              &m1->msg.s1ap_DownlinkNASTransportIEs,
+              &m2->msg.s1ap_DownlinkNASTransportIEs);
+      break;
+    case  S1ap_ProcedureCode_id_initialUEMessage:
+      ret = s1ap_compare_s1ap_initialuemessageies(
+              &m1->msg.s1ap_InitialUEMessageIEs,
+              &m2->msg.s1ap_InitialUEMessageIEs);
+      break;
+    case  S1ap_ProcedureCode_id_uplinkNASTransport:
+      ret = s1ap_compare_s1ap_uplinknastransporties(
+              &m1->msg.s1ap_UplinkNASTransportIEs,
+              &m2->msg.s1ap_UplinkNASTransportIEs);
+      break;
+    case  S1ap_ProcedureCode_id_Reset:
+      ret = s1ap_compare_s1ap_reseties(
+              &m1->msg.s1ap_ResetIEs,
+              &m2->msg.s1ap_ResetIEs);
+      break;
+    case  S1ap_ProcedureCode_id_ErrorIndication:
+      ret = s1ap_compare_s1ap_errorindicationies(
+              &m1->msg.s1ap_ErrorIndicationIEs,
+              &m2->msg.s1ap_ErrorIndicationIEs);
+      break;
+    case  S1ap_ProcedureCode_id_NASNonDeliveryIndication:
+      ret = s1ap_compare_s1ap_nasnondeliveryindication_ies(
+              &m1->msg.s1ap_NASNonDeliveryIndication_IEs,
+              &m2->msg.s1ap_NASNonDeliveryIndication_IEs);
+      break;
+    case  S1ap_ProcedureCode_id_S1Setup:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        ret = s1ap_compare_s1ap_s1setuprequesties(
+                &m1->msg.s1ap_S1SetupRequestIEs,
+                &m2->msg.s1ap_S1SetupRequestIEs);
+      } else if (present == S1AP_PDU_PR_successfulOutcome) {
+        ret = s1ap_compare_s1ap_s1setupresponseies(
+                &m1->msg.s1ap_S1SetupResponseIEs,
+                &m2->msg.s1ap_S1SetupResponseIEs);
+      } else if (present == S1AP_PDU_PR_unsuccessfulOutcome) {
+        ret = s1ap_compare_s1ap_s1setupfailureies(
+                &m1->msg.s1ap_S1SetupFailureIEs,
+                &m2->msg.s1ap_S1SetupFailureIEs);
+      }
+      break;
+    case  S1ap_ProcedureCode_id_UEContextReleaseRequest:
+      ret = s1ap_compare_s1ap_uecontextreleaserequesties(
+                &m1->msg.s1ap_UEContextReleaseRequestIEs,
+                &m2->msg.s1ap_UEContextReleaseRequestIEs);
+      break;
+    case  S1ap_ProcedureCode_id_DownlinkS1cdma2000tunneling:
+      ret = s1ap_compare_s1ap_downlinks1cdma2000tunnelingies(
+                &m1->msg.s1ap_DownlinkS1cdma2000tunnelingIEs,
+                &m2->msg.s1ap_DownlinkS1cdma2000tunnelingIEs);
+      break;
+    case  S1ap_ProcedureCode_id_UplinkS1cdma2000tunneling:
+      ret = s1ap_compare_s1ap_uplinks1cdma2000tunnelingies(
+                &m1->msg.s1ap_UplinkS1cdma2000tunnelingIEs,
+                &m2->msg.s1ap_UplinkS1cdma2000tunnelingIEs);
+      break;
+    case  S1ap_ProcedureCode_id_UEContextModification:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        ret = s1ap_compare_s1ap_uecontextmodificationrequesties(
+                &m1->msg.s1ap_UEContextModificationRequestIEs,
+                &m2->msg.s1ap_UEContextModificationRequestIEs);
+      } else if (present == S1AP_PDU_PR_successfulOutcome) {
+        ret = s1ap_compare_s1ap_uecontextmodificationresponseies(
+                &m1->msg.s1ap_UEContextModificationResponseIEs,
+                &m2->msg.s1ap_UEContextModificationResponseIEs);
+      } else if (present == S1AP_PDU_PR_unsuccessfulOutcome) {
+        ret = s1ap_compare_s1ap_uecontextmodificationfailureies(
+                &m1->msg.s1ap_UEContextModificationFailureIEs,
+                &m2->msg.s1ap_UEContextModificationFailureIEs);
+      }
+      break;
+    case  S1ap_ProcedureCode_id_UECapabilityInfoIndication:
+      ret = s1ap_compare_s1ap_uecapabilityinfoindicationies(
+                &m1->msg.s1ap_UECapabilityInfoIndicationIEs,
+                &m2->msg.s1ap_UECapabilityInfoIndicationIEs);
+      break;
+    case  S1ap_ProcedureCode_id_UEContextRelease:
+
+      break;
+    case  S1ap_ProcedureCode_id_eNBStatusTransfer:
+      ret = s1ap_compare_s1ap_enbstatustransferies(
+                &m1->msg.s1ap_ENBStatusTransferIEs,
+                &m2->msg.s1ap_ENBStatusTransferIEs);
+      break;
+    case  S1ap_ProcedureCode_id_MMEStatusTransfer:
+      ret = s1ap_compare_s1ap_mmestatustransferies(
+                &m1->msg.s1ap_MMEStatusTransferIEs,
+                &m2->msg.s1ap_MMEStatusTransferIEs);
+      break;
+    case  S1ap_ProcedureCode_id_DeactivateTrace:
+      ret = s1ap_compare_s1ap_deactivatetraceies(
+                &m1->msg.s1ap_DeactivateTraceIEs,
+                &m2->msg.s1ap_DeactivateTraceIEs);
+      break;
+    case  S1ap_ProcedureCode_id_TraceStart:
+      ret = s1ap_compare_s1ap_tracestarties(
+                &m1->msg.s1ap_TraceStartIEs,
+                &m2->msg.s1ap_TraceStartIEs);
+      break;
+    case  S1ap_ProcedureCode_id_TraceFailureIndication:
+      ret = s1ap_compare_s1ap_tracefailureindicationies(
+                &m1->msg.s1ap_TraceFailureIndicationIEs,
+                &m2->msg.s1ap_TraceFailureIndicationIEs);
+      break;
+    case  S1ap_ProcedureCode_id_ENBConfigurationUpdate:
+    case  S1ap_ProcedureCode_id_MMEConfigurationUpdate:
+    case  S1ap_ProcedureCode_id_LocationReportingControl:
+    case  S1ap_ProcedureCode_id_LocationReportingFailureIndication:
+    case  S1ap_ProcedureCode_id_LocationReport:
+    case  S1ap_ProcedureCode_id_OverloadStart:
+    case  S1ap_ProcedureCode_id_OverloadStop:
+    case  S1ap_ProcedureCode_id_WriteReplaceWarning:
+    case  S1ap_ProcedureCode_id_eNBDirectInformationTransfer:
+    case  S1ap_ProcedureCode_id_MMEDirectInformationTransfer:
+    case  S1ap_ProcedureCode_id_PrivateMessage:
+    case  S1ap_ProcedureCode_id_eNBConfigurationTransfer:
+    case  S1ap_ProcedureCode_id_MMEConfigurationTransfer:
+    case  S1ap_ProcedureCode_id_CellTrafficTrace:
+    case  S1ap_ProcedureCode_id_Kill:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        ret = s1ap_compare_s1ap_killrequesties(
+                &m1->msg.s1ap_KillRequestIEs,
+                &m2->msg.s1ap_KillRequestIEs);
+      } else  {
+        ret = s1ap_compare_s1ap_killresponseies(
+                &m1->msg.s1ap_KillResponseIEs,
+                &m2->msg.s1ap_KillResponseIEs);
+      }
+      break;
+    case  S1ap_ProcedureCode_id_downlinkUEAssociatedLPPaTransport:
+      ret = s1ap_compare_s1ap_downlinkueassociatedlppatransport_ies(
+                &m1->msg.s1ap_DownlinkUEAssociatedLPPaTransport_IEs,
+                &m2->msg.s1ap_DownlinkUEAssociatedLPPaTransport_IEs);
+      break;
+    case  S1ap_ProcedureCode_id_uplinkUEAssociatedLPPaTransport:
+      ret = s1ap_compare_s1ap_uplinkueassociatedlppatransport_ies(
+                &m1->msg.s1ap_UplinkUEAssociatedLPPaTransport_IEs,
+                &m2->msg.s1ap_UplinkUEAssociatedLPPaTransport_IEs);
+      break;
+    case  S1ap_ProcedureCode_id_downlinkNonUEAssociatedLPPaTransport:
+      ret = s1ap_compare_s1ap_downlinknonueassociatedlppatransport_ies(
+                &m1->msg.s1ap_DownlinkNonUEAssociatedLPPaTransport_IEs,
+                &m2->msg.s1ap_DownlinkNonUEAssociatedLPPaTransport_IEs);
+      break;
+    case  S1ap_ProcedureCode_id_uplinkNonUEAssociatedLPPaTransport:
+      ret = s1ap_compare_s1ap_uplinknonueassociatedlppatransport_ies(
+                &m1->msg.s1ap_UplinkNonUEAssociatedLPPaTransport_IEs,
+                &m2->msg.s1ap_UplinkNonUEAssociatedLPPaTransport_IEs);
+      break;
+    default:
+      AssertFatal(0, "Unknown procedure code %ld", m1->procedureCode);
+  }
+  return 0;
+}
diff --git a/openair3/TEST/EPC_TEST/play_scenario_sctp.c b/openair3/TEST/EPC_TEST/play_scenario_sctp.c
index 6856cb29336e5850746ffbc8b022736848c69d39..314beae8e17e04e2dbafabb7c09ff66a96f083e2 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_sctp.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_sctp.c
@@ -43,3 +43,48 @@
 #include "assertions.h"
 #include "play_scenario.h"
 
+//------------------------------------------------------------------------------
+int et_sctp_data_is_matching(sctp_datahdr_t * const sctp1, sctp_datahdr_t * const sctp2, const uint32_t constraints)
+{
+  // no comparison for ports
+  if (sctp1->ppid     != sctp2->ppid)     return -4;
+  if (sctp1->assoc_id != sctp2->assoc_id) return -5;
+  if (sctp1->stream != sctp2->stream) {
+    if (constraints & ET_BIT_MASK_MATCH_SCTP_STREAM) {
+      return -2;
+    } else {
+      S1AP_WARN("No Matching SCTP stream %u %u\n", sctp1->stream, sctp2->stream);
+    }
+  }
+  if (sctp1->ssn != sctp2->ssn) {
+    if (constraints & ET_BIT_MASK_MATCH_SCTP_SSN) {
+      return -3;
+    } else {
+      S1AP_WARN("No Matching SCTP ssn %u %u\n", sctp1->ssn, sctp2->ssn);
+    }
+  }
+  return et_s1ap_is_matching(&sctp1->payload, &sctp2->payload,  constraints);
+}
+
+//------------------------------------------------------------------------------
+int et_sctp_is_matching(et_sctp_hdr_t * const sctp1, et_sctp_hdr_t * const sctp2, const uint32_t constraints)
+{
+  // no comparison for ports
+  if (sctp1->chunk_type != sctp2->chunk_type) return -1;
+  switch (sctp1->chunk_type) {
+    case SCTP_CID_DATA:
+      return et_sctp_data_is_matching(&sctp1->u.data_hdr, &sctp2->u.data_hdr, constraints);
+      break;
+
+    case SCTP_CID_INIT:
+      AssertFatal(0, "Not needed now");
+      break;
+    case SCTP_CID_INIT_ACK:
+      AssertFatal(0, "Not needed now");
+      break;
+    default:
+      AssertFatal(0, "Not needed now cid %d", sctp1->chunk_type);
+  }
+
+  return 0;
+}