diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper
index 46997c277322179c9398e1b4e7dad56c56a61a1c..350dae86a669f299ea383aeece1c0ce480c03ae2 100755
--- a/cmake_targets/tools/build_helper
+++ b/cmake_targets/tools/build_helper
@@ -274,6 +274,7 @@ install_asn1c_from_source(){
     patch -p0 < $OPENAIR_DIR/openair3/S1AP/MESSAGES/ASN1/asn1cpatch.p0 >> /tmp/log_compile_asn1c
     patch -p0 < $OPENAIR_DIR/openair3/S1AP/MESSAGES/ASN1/asn1cpatch_2.p0 >> /tmp/log_compile_asn1c
     patch -p0 < $OPENAIR_DIR/openair2/RRC/LITE/MESSAGES/asn1c/asn1cpatch.p0 >> /tmp/log_compile_asn1c
+    patch -p0 < $OPENAIR_DIR/openair3/S1AP/MESSAGES/ASN1/asn1cpatch_3.p0 >> /tmp/log_compile_asn1c
     ./configure
     make > /tmp/log_compile_asn1c 2>&1
     $SUDO make install
diff --git a/cmake_targets/tools/build_test_epc_tools b/cmake_targets/tools/build_test_epc_tools
index db49fa017b629d4c0fa7fd92d316b97758895a5e..b67cf158109f7c3b24721598552766b39b840ff5 100755
--- a/cmake_targets/tools/build_test_epc_tools
+++ b/cmake_targets/tools/build_test_epc_tools
@@ -141,9 +141,14 @@ function main()
   compilations \
       epc_test test_epc_generate_scenario \
       test_epc_generate_scenario $dbin/test_epc_generate_scenario
+
   compilations \
       epc_test test_epc_play_scenario \
       test_epc_play_scenario $dbin/test_epc_play_scenario
+      
+  $SUDO cp -upv test_epc_generate_scenario /usr/local/bin
+  $SUDO cp -upv test_epc_play_scenario     /usr/local/bin
+  $SUDO cp -upv  $OPENAIR_DIR/openair3/TEST/EPC_TEST/mme_test_s1_pcap2pdml /usr/local/bin
 }
 
 
diff --git a/openair3/S1AP/MESSAGES/ASN1/asn1cpatch_3.p0 b/openair3/S1AP/MESSAGES/ASN1/asn1cpatch_3.p0
new file mode 100644
index 0000000000000000000000000000000000000000..cf3553c362d25584cfb73d0750fd002cd3960019
--- /dev/null
+++ b/openair3/S1AP/MESSAGES/ASN1/asn1cpatch_3.p0
@@ -0,0 +1,1030 @@
+--- ./asn1c/unber.c	2015-12-03 09:43:33.959009150 +0100
++++ ./asn1c/unber.c	2015-11-30 13:20:40.751264003 +0100
+@@ -779,4 +779,6 @@
+ 
+ asn_enc_rval_t OCTET_STRING_encode_aper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts, void *sptr, asn_per_outp_t *po) { asn_enc_rval_t er = { 0, 0, 0 }; (void)td; (void)cts; (void)sptr; (void)po; return er; }
+ 
++long OCTET_STRING_compare(asn_TYPE_descriptor_t *td1, void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2) { (void)td1; (void)sptr1; (void)td2; (void)sptr2; return 0; }
++
+ size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size) {  (void)chunk_buf; (void)chunk_size; return 0; }
+--- ./libasn1compiler/asn1c_C.c	2015-12-03 09:43:33.971009150 +0100
++++ ./libasn1compiler/asn1c_C.c	2015-11-30 14:29:33.027259725 +0100
+@@ -1082,6 +1082,8 @@
+ 	enum tvm_compat tv_mode;
+ 	enum etd_spec etd_spec;
+ 	char *p;
++  char tmp_buf[512];
++  int i = 0;
+ 
+ 	if(arg->embed) {
+ 		enum tnfmt tnfmt = TNF_CTYPE;
+@@ -1243,7 +1245,8 @@
+ 	OUT("td->uper_decoder   = asn_DEF_%s.uper_decoder;\n",   type_name);
+ 	OUT("td->uper_encoder   = asn_DEF_%s.uper_encoder;\n",   type_name);
+ 	OUT("td->aper_decoder   = asn_DEF_%s.aper_decoder;\n",   type_name);
+-	OUT("td->aper_encoder   = asn_DEF_%s.aper_encoder;\n",   type_name);
++  OUT("td->aper_encoder   = asn_DEF_%s.aper_encoder;\n",   type_name);
++  OUT("td->compare        = asn_DEF_%s.compare;\n",        type_name);
+ 	if(!terminal && !tags_count) {
+ 	  OUT("/* The next four lines are here because of -fknown-extern-type */\n");
+ 	  OUT("td->tags           = asn_DEF_%s.tags;\n",         type_name);
+@@ -1413,6 +1416,49 @@
+ 	OUT("}\n");
+ 	OUT("\n");
+ 
++
++  i = 0;
++  while ((p[i] != '_') && (i < sizeof(tmp_buf))) {
++    tmp_buf[i] = p[i];
++    i++;
++  }
++  tmp_buf[i] = '\0';
++  // hack, only for s1ap
++  if ((strcmp("S1ap", tmp_buf) == 0) || (strcmp("X2ap", tmp_buf) == 0))
++    OUT("#include \"%s-ProtocolIE-ID.h\"\n", tmp_buf);
++
++
++  p = MKID(expr);
++  if(HIDE_INNER_DEFS) OUT("static ");
++              OUT("long\n");
++  OUT("%s", p);
++  if(HIDE_INNER_DEFS) OUT("_%d", expr->_type_unique_index);
++    OUT("_compare(asn_TYPE_descriptor_t *td1,\n");
++  i = 0;
++  while ((p[i] != '_') && (i < sizeof(tmp_buf))) {
++    tmp_buf[i] = p[i];
++    i++;
++  }
++  tmp_buf[i] = '\0';
++  strcat(tmp_buf,"_ProtocolIE_ID_id_");
++  strcat(tmp_buf,&p[++i]);
++  INDENTED(
++  OUT("\tvoid *structure1,\n");
++  OUT("\tasn_TYPE_descriptor_t *td2,\n");
++  OUT("\tvoid *structure2) {\n");
++  OUT("long rv = 0;\n");
++  OUT("%s_%d_inherit_TYPE_descriptor(td1);\n",
++    p, expr->_type_unique_index);
++  OUT("%s_%d_inherit_TYPE_descriptor(td2);\n",
++    p, expr->_type_unique_index);
++  OUT("rv = td1->compare(td1, structure1, td2, structure2);\n");
++  if ((strcmp("S1ap", tmp_buf) == 0) || (strcmp("X2ap", tmp_buf) == 0))
++    OUT("if (rv) { rv = (rv << 8); rv |= %s;}\n", tmp_buf);
++  OUT("return rv;\n");
++  );
++  OUT("}\n");
++  OUT("\n");
++
+ 	p = MKID(expr);
+ 	
+ 	if(HIDE_INNER_DEFS) OUT("static ");
+@@ -1450,7 +1496,8 @@
+ 		OUT("per_type_decoder_f %s_decode_uper;\n", p);
+ 		OUT("per_type_encoder_f %s_encode_uper;\n", p);
+ 		OUT("per_type_decoder_f %s_decode_aper;\n", p);
+-		OUT("per_type_encoder_f %s_encode_aper;\n", p);
++    OUT("per_type_encoder_f %s_encode_aper;\n", p);
++    OUT("type_compare_f     %s_compare;\n", p);
+ 		}
+ 	}
+ 
+@@ -2501,6 +2548,7 @@
+ 			OUT("0, 0,\t/* No APER support, "
+ 				"use \"-gen-PER\" to enable */\n");
+ 		}
++    FUNCREF(compare);
+ 
+ 		if(!terminal || terminal->expr_type == ASN_CONSTR_CHOICE) {
+ 		//if(expr->expr_type == ASN_CONSTR_CHOICE) {
+--- ./skeletons/ANY.c	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/ANY.c	2015-11-26 14:40:56.547616803 +0100
+@@ -24,7 +24,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	0, 0, 0, 0,
+ 	0,	/* No PER visible constraints */
+--- ./skeletons/BIT_STRING.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/BIT_STRING.c	2015-11-26 14:41:50.159616747 +0100
+@@ -30,7 +30,8 @@
+ 	OCTET_STRING_decode_uper,	/* Unaligned PER decoder */
+ 	OCTET_STRING_encode_uper,	/* Unaligned PER encoder */
+ 	OCTET_STRING_decode_aper,	/* Aligned PER decoder */
+-	OCTET_STRING_encode_aper,	/* Aligned PER encoder */
++  OCTET_STRING_encode_aper, /* Aligned PER encoder */
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_BIT_STRING_tags,
+ 	sizeof(asn_DEF_BIT_STRING_tags)
+--- ./skeletons/BMPString.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/BMPString.c	2015-11-26 14:42:08.487616728 +0100
+@@ -36,7 +36,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,	/* Aligned PER decoder */
+-	OCTET_STRING_encode_aper,	/* Aligned PER encoder */
++  OCTET_STRING_encode_aper, /* Aligned PER encoder */
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_BMPString_tags,
+ 	sizeof(asn_DEF_BMPString_tags)
+--- ./skeletons/BOOLEAN.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/BOOLEAN.c	2015-11-30 13:16:30.275264262 +0100
+@@ -25,7 +25,8 @@
+ 	BOOLEAN_decode_uper,	/* Unaligned PER decoder */
+ 	BOOLEAN_encode_uper,	/* Unaligned PER encoder */
+ 	BOOLEAN_decode_aper,	/* Aligned PER decoder */
+-	BOOLEAN_encode_aper,	/* Aligned PER encoder */
++  BOOLEAN_encode_aper,  /* Aligned PER encoder */
++  BOOLEAN_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_BOOLEAN_tags,
+ 	sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]),
+@@ -326,3 +327,21 @@
+ 
+ 	_ASN_ENCODED_OK(er);
+ }
++
++long
++BOOLEAN_compare(asn_TYPE_descriptor_t *td1,
++  void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2) {
++  const BOOLEAN_t *st1 = (const BOOLEAN_t *)sptr1;
++  const BOOLEAN_t *st2 = (const BOOLEAN_t *)sptr2;
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++  return (*st1 != *st2);
++}
++
+--- ./skeletons/BOOLEAN.h	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/BOOLEAN.h	2015-11-26 12:46:58.491623882 +0100
+@@ -30,6 +30,7 @@
+ per_type_encoder_f BOOLEAN_encode_uper;
+ per_type_decoder_f BOOLEAN_decode_aper;
+ per_type_encoder_f BOOLEAN_encode_aper;
++type_compare_f     BOOLEAN_compare;
+ 
+ #ifdef __cplusplus
+ }
+--- ./skeletons/compare.h	1970-01-01 01:00:00.000000000 +0100
++++ ./skeletons/compare.h	2015-11-30 13:15:56.415264297 +0100
+@@ -0,0 +1,27 @@
++/*-
++ * Eurecom 2015.
++ */
++#ifndef	_COMPARE_H_
++#define	_COMPARE_H_
++
++#include <asn_application.h>
++#include <per_support.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++struct asn_TYPE_descriptor_s;	/* Forward declaration */
++
++typedef long (type_compare_f)(
++  struct asn_TYPE_descriptor_s *type_descriptor1,
++  void *struct_ptr1,
++  struct asn_TYPE_descriptor_s *type_descriptor2,
++  void *struct_ptr2
++);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif	/* _COMPARE_H_ */
+--- ./skeletons/constr_CHOICE.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/constr_CHOICE.c	2015-11-30 13:16:49.007264243 +0100
+@@ -1272,3 +1272,57 @@
+ 		assert(pres_size != sizeof(int));
+ 	}
+ }
++
++long
++CHOICE_compare(asn_TYPE_descriptor_t *td1, void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2)
++{
++  asn_CHOICE_specifics_t *specs1 = (asn_CHOICE_specifics_t *)td1->specifics;
++  asn_CHOICE_specifics_t *specs2 = (asn_CHOICE_specifics_t *)td2->specifics;
++  int present1;
++  int present2;
++
++  if ((!sptr1) && (!sptr2)) return 0;
++  if (!sptr1) return -1;
++  if (!sptr2) return -1;
++
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++
++  /*
++   * Figure out which CHOICE element is encoded.
++   */
++  present1 = _fetch_present_idx(sptr1, specs1->pres_offset,specs1->pres_size);
++  // same specs
++  present2 = _fetch_present_idx(sptr2, specs2->pres_offset,specs2->pres_size);
++
++  if (td1->elements_count != td2->elements_count) return -1;
++  if (present1 != present2) return -1;
++  if(present1 > 0 && present1 <= td1->elements_count) {
++    asn_TYPE_member_t *elm1 = &td1->elements[present1-1];
++    asn_TYPE_member_t *elm2 = &td2->elements[present2-1];
++    const void *memb_ptr1;
++    const void *memb_ptr2;
++
++    if((elm1->flags & ATF_POINTER) && (elm1->flags & ATF_POINTER)){
++      memb_ptr1 = *(const void * const *)((const char *)sptr1 + elm1->memb_offset);
++      memb_ptr2 = *(const void * const *)((const char *)sptr2 + elm2->memb_offset);
++      if((!memb_ptr1) && (!memb_ptr2)) return -1;
++      if (!memb_ptr1)  return -1;
++      if (!memb_ptr2)  return -1;
++    } else if (!(elm1->flags & ATF_POINTER) && !(elm1->flags & ATF_POINTER)){
++      memb_ptr1 = (const void *)((const char *)sptr1 + elm1->memb_offset);
++      memb_ptr2 = (const void *)((const char *)sptr2 + elm2->memb_offset);
++    } else {
++      return -1;
++    }
++    return elm1->type->compare(elm1->type, memb_ptr1, elm2->type, memb_ptr2);
++  }
++  return 0;
++}
+--- ./skeletons/constr_CHOICE.h	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/constr_CHOICE.h	2015-11-26 14:43:57.647616615 +0100
+@@ -39,7 +39,7 @@
+ /*
+  * A set specialized functions dealing with the CHOICE type.
+  */
+-asn_struct_free_f CHOICE_free;
++asn_struct_free_f  CHOICE_free;
+ asn_struct_print_f CHOICE_print;
+ asn_constr_check_f CHOICE_constraint;
+ ber_type_decoder_f CHOICE_decode_ber;
+@@ -50,7 +50,8 @@
+ per_type_encoder_f CHOICE_encode_uper;
+ per_type_decoder_f CHOICE_decode_aper;
+ per_type_encoder_f CHOICE_encode_aper;
+-asn_outmost_tag_f CHOICE_outmost_tag;
++type_compare_f     CHOICE_compare;
++asn_outmost_tag_f  CHOICE_outmost_tag;
+ 
+ #ifdef __cplusplus
+ }
+--- ./skeletons/constr_SEQUENCE.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/constr_SEQUENCE.c	2015-11-30 13:17:33.871264196 +0100
+@@ -1761,3 +1761,50 @@
+ 
+ 	_ASN_ENCODED_OK(er);
+ }
++
++long
++SEQUENCE_compare(asn_TYPE_descriptor_t *td1, void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2) {
++  int edx;
++  int ret;
++
++  if((!sptr1) && (!sptr2)) return -1;
++  if(!sptr1) return -1;
++  if(!sptr2) return -1;
++
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++
++  if (td1->elements_count != td2->elements_count) return -1;
++
++  for(edx = 0; edx < td1->elements_count; edx++) {
++    asn_TYPE_member_t *elm1 = &td1->elements[edx];
++    asn_TYPE_member_t *elm2 = &td1->elements[edx];
++    const void *memb_ptr1;
++    const void *memb_ptr2;
++
++    if(elm1->flags & ATF_POINTER) {
++      memb_ptr1 = *(const void * const *)((const char *)sptr1 + elm1->memb_offset);
++      memb_ptr2 = *(const void * const *)((const char *)sptr2 + elm2->memb_offset);
++      if((!memb_ptr1) && (!memb_ptr2)) {
++        if(elm1->optional) continue;
++      }
++      if (!memb_ptr1) return -1;
++      if (!memb_ptr2) return -1;
++    } else {
++      memb_ptr1 = (const void *)((const char *)sptr1 + elm1->memb_offset);
++      memb_ptr2 = (const void *)((const char *)sptr2 + elm2->memb_offset);
++    }
++
++    /* Compare the member itself */
++    ret = elm1->type->compare(elm1->type, memb_ptr1, elm2->type, memb_ptr2);
++    if(ret) return ret;
++  }
++  return  0;
++}
+--- ./skeletons/constr_SEQUENCE.h	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/constr_SEQUENCE.h	2015-11-26 14:48:14.123616350 +0100
+@@ -54,6 +54,7 @@
+ per_type_encoder_f SEQUENCE_encode_uper;
+ per_type_decoder_f SEQUENCE_decode_aper;
+ per_type_encoder_f SEQUENCE_encode_aper;
++type_compare_f     SEQUENCE_compare;
+ 
+ #ifdef __cplusplus
+ }
+--- ./skeletons/constr_SEQUENCE_OF.h	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/constr_SEQUENCE_OF.h	2015-11-26 15:05:25.399615282 +0100
+@@ -22,7 +22,8 @@
+ #define	SEQUENCE_OF_decode_ber	SET_OF_decode_ber
+ #define	SEQUENCE_OF_decode_xer	SET_OF_decode_xer
+ #define	SEQUENCE_OF_decode_uper	SET_OF_decode_uper
+-#define	SEQUENCE_OF_decode_aper	SET_OF_decode_aper
++#define SEQUENCE_OF_decode_aper SET_OF_decode_aper
++#define SEQUENCE_OF_compare     SET_OF_compare
+ der_type_encoder_f SEQUENCE_OF_encode_der;
+ xer_type_encoder_f SEQUENCE_OF_encode_xer;
+ per_type_encoder_f SEQUENCE_OF_encode_uper;
+--- ./skeletons/constr_SET.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/constr_SET.c	2015-11-30 13:17:49.903264180 +0100
+@@ -1108,7 +1108,7 @@
+ 	}
+ }
+ 
+-int
++long
+ SET_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
+ 		asn_app_constraint_failed_f *ctfailcb, void *app_key) {
+ 	int edx;
+--- ./skeletons/constr_SET.h	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/constr_SET.h	2015-11-26 14:49:09.243616293 +0100
+@@ -56,6 +56,7 @@
+ per_type_decoder_f SET_decode_aper;
+ per_type_encoder_f SET_encode_uper;
+ per_type_encoder_f SET_encode_aper;
++type_compare_f     SET_compare;
+ 
+ /***********************
+  * Some handy helpers. *
+--- ./skeletons/constr_SET_OF.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/constr_SET_OF.c	2015-11-30 13:17:42.099264188 +0100
+@@ -1039,3 +1039,46 @@
+ 	rv.consumed = 0;
+ 	return rv;
+ }
++
++long
++SET_OF_compare(asn_TYPE_descriptor_t *td1, void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2)
++{
++  asn_TYPE_member_t *elm1 = td1->elements;
++  asn_TYPE_member_t *elm2 = td2->elements;
++  const asn_anonymous_set_ *list1 = _A_CSET_FROM_VOID(sptr1);
++  const asn_anonymous_set_ *list2 = _A_CSET_FROM_VOID(sptr2);
++  int ret;
++  int i;
++
++  if((!sptr1) && !(sptr2)) return 0;
++  if(!sptr1) return -1;
++  if(!sptr2) return -1;
++
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++
++  if (td1->elements_count != td2->elements_count) return -1;
++
++
++  if (list1->count != list2->count ) return -1;
++
++  for(i = 0; i < list1->count; i++) {
++    const void *memb_ptr1 = list1->array[i];
++    const void *memb_ptr2 = list2->array[i];
++    if ((!memb_ptr1) & (!memb_ptr2)) continue;
++    if(!memb_ptr1) return -1;
++    if(!memb_ptr2) return -1;
++
++    ret = elm1->type->compare(elm1->type, memb_ptr1, elm2->type, memb_ptr2);
++    if(ret) return ret;
++  }
++
++  return  0;
++}
+--- ./skeletons/constr_SET_OF.h	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/constr_SET_OF.h	2015-11-26 14:48:45.067616318 +0100
+@@ -36,6 +36,7 @@
+ per_type_encoder_f SET_OF_encode_uper;
+ per_type_decoder_f SET_OF_decode_aper;
+ per_type_encoder_f SET_OF_encode_aper;
++type_compare_f     SET_OF_compare;
+ 
+ #ifdef __cplusplus
+ }
+--- ./skeletons/constr_TYPE.h	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/constr_TYPE.h	2015-11-26 15:28:05.495613874 +0100
+@@ -41,7 +41,8 @@
+ #include <xer_encoder.h>	/* Encoder into XER (XML, text) */
+ #include <per_decoder.h>	/* Packet Encoding Rules decoder */
+ #include <per_encoder.h>	/* Packet Encoding Rules encoder */
+-#include <constraints.h>	/* Subtype constraints support */
++#include <constraints.h>  /* Subtype constraints support */
++#include <compare.h>      /* Comparison */
+ 
+ /*
+  * Free the structure according to its specification.
+@@ -101,6 +102,7 @@
+ 	per_type_encoder_f *uper_encoder;	/* Unaligned PER encoder */
+ 	per_type_decoder_f *aper_decoder;	/* Aligned PER decoder */
+ 	per_type_encoder_f *aper_encoder;	/* Aligned PER encoder */
++	type_compare_f     *compare;      /* Comparison between 2 instances */
+ 
+ 	/***********************************************************************
+ 	 * Internally useful members. Not to be used by applications directly. *
+--- ./skeletons/ENUMERATED.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/ENUMERATED.c	2015-11-30 13:18:05.399264164 +0100
+@@ -27,7 +27,8 @@
+ 	ENUMERATED_decode_uper,	/* Unaligned PER decoder */
+ 	ENUMERATED_encode_uper,	/* Unaligned PER encoder */
+ 	ENUMERATED_decode_aper,	/* Aligned PER decoder */
+-	ENUMERATED_encode_aper,	/* Aligned PER encoder */
++  ENUMERATED_encode_aper, /* Aligned PER encoder */
++  ENUMERATED_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_ENUMERATED_tags,
+ 	sizeof(asn_DEF_ENUMERATED_tags) / sizeof(asn_DEF_ENUMERATED_tags[0]),
+@@ -103,3 +104,22 @@
+ 	
+ 	return NativeEnumerated_encode_aper(td, constraints, &value, po);
+ }
++
++long
++ENUMERATED_compare(asn_TYPE_descriptor_t *td1, void *sptr1,
++                   asn_TYPE_descriptor_t *td2, void *sptr2) {
++  ENUMERATED_t *st1 = (ENUMERATED_t *)sptr1;
++  ENUMERATED_t *st2 = (ENUMERATED_t *)sptr2;
++
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++  return (*st1 != *st2);
++}
++
+--- ./skeletons/ENUMERATED.h	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/ENUMERATED.h	2015-11-26 12:46:35.523623906 +0100
+@@ -19,6 +19,7 @@
+ per_type_encoder_f ENUMERATED_encode_uper;
+ per_type_decoder_f ENUMERATED_decode_aper;
+ per_type_encoder_f ENUMERATED_encode_aper;
++type_compare_f     ENUMERATED_compare;
+ 
+ #ifdef __cplusplus
+ }
+--- ./skeletons/file-dependencies	2015-12-03 09:43:33.731009150 +0100
++++ ./skeletons/file-dependencies	2015-11-26 16:05:44.923611535 +0100
+@@ -39,7 +39,7 @@
+ constr_SEQUENCE.h constr_SEQUENCE.c
+ constr_SEQUENCE_OF.h constr_SEQUENCE_OF.c asn_SEQUENCE_OF.h constr_SET_OF.h
+ constr_SET.h constr_SET.c
+-constr_SET_OF.h constr_SET_OF.c asn_SET_OF.h
++constr_SET_OF.h constr_SET_OF.c asn_SET_OF.h compare.h
+ 
+ COMMON-FILES:			# THIS IS A SPECIAL SECTION
+ asn_application.h		# Applications should include this file
+--- ./skeletons/GeneralizedTime.c	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/GeneralizedTime.c	2015-11-26 15:09:03.899615056 +0100
+@@ -168,7 +168,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_GeneralizedTime_tags,
+ 	sizeof(asn_DEF_GeneralizedTime_tags)
+--- ./skeletons/GeneralString.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/GeneralString.c	2015-11-26 14:50:11.843616228 +0100
+@@ -25,7 +25,8 @@
+ 	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_GeneralString_tags,
+ 	sizeof(asn_DEF_GeneralString_tags)
+--- ./skeletons/GraphicString.c	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/GraphicString.c	2015-11-26 15:33:33.255613535 +0100
+@@ -25,7 +25,8 @@
+ 	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_GraphicString_tags,
+ 	sizeof(asn_DEF_GraphicString_tags)
+--- ./skeletons/IA5String.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/IA5String.c	2015-11-26 14:50:44.219616194 +0100
+@@ -31,6 +31,7 @@
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+ 	OCTET_STRING_encode_aper,
++	OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_IA5String_tags,
+ 	sizeof(asn_DEF_IA5String_tags)
+--- ./skeletons/INTEGER.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/INTEGER.c	2015-11-30 13:18:18.143264151 +0100
+@@ -35,6 +35,7 @@
+ 	INTEGER_decode_aper,
+ 	INTEGER_encode_aper,
+ #endif	/* ASN_DISABLE_PER_SUPPORT */
++	INTEGER_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_INTEGER_tags,
+ 	sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]),
+@@ -1501,3 +1502,20 @@
+ }
+ 
+ 
++long
++INTEGER_compare(asn_TYPE_descriptor_t *td1, void *sptr1,
++                asn_TYPE_descriptor_t *td2, void *sptr2) {
++  INTEGER_t *st1 = (INTEGER_t *)sptr1;
++  INTEGER_t *st2 = (INTEGER_t *)sptr2;
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++  if (st1->size != st2->size) return -1;
++  return memcmp(st1->buf, st2->buf, st1->size);
++}
+--- ./skeletons/INTEGER.h	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/INTEGER.h	2015-11-26 12:50:41.551623651 +0100
+@@ -43,6 +43,7 @@
+ per_type_encoder_f INTEGER_encode_uper;
+ per_type_decoder_f INTEGER_decode_aper;
+ per_type_encoder_f INTEGER_encode_aper;
++type_compare_f     INTEGER_compare;
+ 
+ /***********************************
+  * Some handy conversion routines. *
+--- ./skeletons/ISO646String.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/ISO646String.c	2015-11-26 12:55:48.327623333 +0100
+@@ -30,7 +30,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_ISO646String_tags,
+ 	sizeof(asn_DEF_ISO646String_tags)
+--- ./skeletons/Makefile.am	2015-12-03 09:43:33.715009150 +0100
++++ ./skeletons/Makefile.am	2015-11-26 15:28:55.887613822 +0100
+@@ -50,7 +50,7 @@
+ 	ber_decoder.c ber_decoder.h			\
+ 	ber_tlv_length.c ber_tlv_length.h		\
+ 	ber_tlv_tag.c ber_tlv_tag.h			\
+-	constr_CHOICE.c constr_CHOICE.h			\
++	comparison.h constr_CHOICE.c constr_CHOICE.h			\
+ 	constr_SEQUENCE.c constr_SEQUENCE.h		\
+ 	constr_SEQUENCE_OF.c constr_SEQUENCE_OF.h	\
+ 	constr_SET.c constr_SET.h			\
+--- ./skeletons/NativeEnumerated.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/NativeEnumerated.c	2015-11-30 13:18:32.015264136 +0100
+@@ -31,7 +31,8 @@
+ 	NativeEnumerated_decode_uper,
+ 	NativeEnumerated_encode_uper,
+ 	NativeEnumerated_decode_aper,
+-	NativeEnumerated_encode_aper,
++  NativeEnumerated_encode_aper,
++  NativeEnumerated_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_NativeEnumerated_tags,
+ 	sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]),
+@@ -335,3 +336,25 @@
+ 
+ 	_ASN_ENCODED_OK(er);
+ }
++
++long
++NativeEnumerated_compare(asn_TYPE_descriptor_t *td1, void *sptr1,
++    asn_TYPE_descriptor_t *td2, void *sptr2) {
++  const asn_INTEGER_enum_map_t *a = sptr1;
++  const asn_INTEGER_enum_map_t *b = sptr2;
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++
++  if(a->nat_value == b->nat_value)
++    return 0;
++  if(a->nat_value < b->nat_value)
++    return -1;
++  return 1;
++}
+--- ./skeletons/NativeEnumerated.h	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/NativeEnumerated.h	2015-11-26 14:51:43.315616133 +0100
+@@ -26,6 +26,7 @@
+ per_type_encoder_f NativeEnumerated_encode_uper;
+ per_type_decoder_f NativeEnumerated_decode_aper;
+ per_type_encoder_f NativeEnumerated_encode_aper;
++type_compare_f     NativeEnumerated_compare;
+ 
+ #ifdef __cplusplus
+ }
+--- ./skeletons/NativeInteger.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/NativeInteger.c	2015-11-30 13:18:39.887264128 +0100
+@@ -32,7 +32,8 @@
+ 	NativeInteger_decode_uper,	/* Unaligned PER decoder */
+ 	NativeInteger_encode_uper,	/* Unaligned PER encoder */
+ 	NativeInteger_decode_aper,	/* Aligned PER decoder */
+-	NativeInteger_encode_aper,	/* Aligned PER encoder */
++  NativeInteger_encode_aper,  /* Aligned PER encoder */
++  NativeInteger_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_NativeInteger_tags,
+ 	sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]),
+@@ -410,3 +411,20 @@
+ 	}
+ }
+ 
++
++long
++NativeInteger_compare(asn_TYPE_descriptor_t *td1, void *sptr1,
++                      asn_TYPE_descriptor_t *td2, void *sptr2) {
++  const long *native1 = (const long *)sptr1;
++  const long *native2 = (const long *)sptr2;
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++  return (*native1 != *native2);
++}
+--- ./skeletons/NativeInteger.h	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/NativeInteger.h	2015-11-26 14:52:13.931616101 +0100
+@@ -31,6 +31,7 @@
+ per_type_encoder_f NativeInteger_encode_uper;
+ per_type_decoder_f NativeInteger_decode_aper;
+ per_type_encoder_f NativeInteger_encode_aper;
++type_compare_f     NativeInteger_compare;
+ 
+ #ifdef __cplusplus
+ }
+--- ./skeletons/NativeReal.c	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/NativeReal.c	2015-11-30 13:18:46.655264121 +0100
+@@ -33,7 +33,8 @@
+ 	NativeReal_decode_uper,
+ 	NativeReal_encode_uper,
+ 	NativeReal_decode_aper,
+-	NativeReal_encode_aper,
++  NativeReal_encode_aper,
++  NativeReal_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_NativeReal_tags,
+ 	sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]),
+@@ -405,3 +406,21 @@
+ 	}
+ }
+ 
++long
++NativeReal_compare(asn_TYPE_descriptor_t *td1, void *sptr1,
++                   asn_TYPE_descriptor_t *td2, void *sptr2) {
++  REAL_t *st1 = (REAL_t *)sptr1;
++  REAL_t *st2 = (REAL_t *)sptr2;
++
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++  if (st1->size != st2->size) return -1;
++  return memcmp(st1->buf, st2->buf, st1->size);
++}
+--- ./skeletons/NativeReal.h	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/NativeReal.h	2015-11-26 14:31:12.631617407 +0100
+@@ -29,6 +29,7 @@
+ per_type_encoder_f NativeReal_encode_uper;
+ per_type_decoder_f NativeReal_decode_aper;
+ per_type_encoder_f NativeReal_encode_aper;
++type_compare_f     NativeReal_compare;
+ 
+ #ifdef __cplusplus
+ }
+--- ./skeletons/NULL.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/NULL.c	2015-11-30 13:18:53.047264114 +0100
+@@ -26,7 +26,8 @@
+ 	NULL_decode_uper,	/* Unaligned PER decoder */
+ 	NULL_encode_uper,	/* Unaligned PER encoder */
+ 	NULL_decode_aper,	/* Aligned PER decoder */
+-	NULL_encode_aper,	/* Aligned PER encoder */
++  NULL_encode_aper, /* Aligned PER encoder */
++  NULL_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_NULL_tags,
+ 	sizeof(asn_DEF_NULL_tags) / sizeof(asn_DEF_NULL_tags[0]),
+@@ -192,3 +193,10 @@
+ 	er.encoded = 0;
+ 	_ASN_ENCODED_OK(er);
+ }
++
++long
++NULL_compare(asn_TYPE_descriptor_t *td1, void *sptr1,
++             asn_TYPE_descriptor_t *td2, void *sptr2) {
++
++  return 0;
++}
+--- ./skeletons/NULL.h	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/NULL.h	2015-11-26 14:53:03.875616050 +0100
+@@ -27,6 +27,7 @@
+ per_type_encoder_f NULL_encode_uper;
+ per_type_decoder_f NULL_decode_aper;
+ per_type_encoder_f NULL_encode_aper;
++type_compare_f     NULL_compare;
+ 
+ #ifdef __cplusplus
+ }
+--- ./skeletons/NumericString.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/NumericString.c	2015-11-26 14:40:39.407616820 +0100
+@@ -50,7 +50,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_NumericString_tags,
+ 	sizeof(asn_DEF_NumericString_tags)
+--- ./skeletons/ObjectDescriptor.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/ObjectDescriptor.c	2015-11-26 14:55:46.227615882 +0100
+@@ -25,7 +25,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_ObjectDescriptor_tags,
+ 	sizeof(asn_DEF_ObjectDescriptor_tags)
+--- ./skeletons/OBJECT_IDENTIFIER.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/OBJECT_IDENTIFIER.c	2015-11-26 14:55:13.311615916 +0100
+@@ -28,7 +28,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_OBJECT_IDENTIFIER_tags,
+ 	sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
+--- ./skeletons/OCTET_STRING.c	2015-12-03 09:43:33.975009150 +0100
++++ ./skeletons/OCTET_STRING.c	2015-11-30 13:19:18.271264088 +0100
+@@ -37,7 +37,8 @@
+ 	OCTET_STRING_decode_uper,	/* Unaligned PER decoder */
+ 	OCTET_STRING_encode_uper,	/* Unaligned PER encoder */
+ 	OCTET_STRING_decode_aper,	/* Aligned PER decoder */
+-	OCTET_STRING_encode_aper,	/* Aligned PER encoder */
++  OCTET_STRING_encode_aper, /* Aligned PER encoder */
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_OCTET_STRING_tags,
+ 	sizeof(asn_DEF_OCTET_STRING_tags)
+@@ -2160,3 +2161,21 @@
+ 	return st;
+ }
+ 
++long
++OCTET_STRING_compare(asn_TYPE_descriptor_t *td1,
++  void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2) {
++  OCTET_STRING_t *st1 = (OCTET_STRING_t *)sptr1;
++  OCTET_STRING_t *st2 = (OCTET_STRING_t *)sptr2;
++
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++  if (st1->size != st2->size) return -1;
++  return memcmp(st1->buf, st2->buf, st1->size);
++}
+--- ./skeletons/OCTET_STRING.h	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/OCTET_STRING.h	2015-11-26 12:56:15.259623305 +0100
+@@ -34,6 +34,7 @@
+ per_type_encoder_f OCTET_STRING_encode_uper;
+ per_type_decoder_f OCTET_STRING_decode_aper;
+ per_type_encoder_f OCTET_STRING_encode_aper;
++type_compare_f     OCTET_STRING_compare;
+ 
+ /******************************
+  * Handy conversion routines. *
+--- ./skeletons/PrintableString.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/PrintableString.c	2015-11-26 14:56:09.787615857 +0100
+@@ -60,7 +60,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_PrintableString_tags,
+ 	sizeof(asn_DEF_PrintableString_tags)
+--- ./skeletons/REAL.c	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/REAL.c	2015-11-30 13:19:27.671264079 +0100
+@@ -46,7 +46,8 @@
+ 	REAL_decode_uper,
+ 	REAL_encode_uper,
+ 	REAL_decode_aper,
+-	REAL_encode_aper,
++  REAL_encode_aper,
++  REAL_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_REAL_tags,
+ 	sizeof(asn_DEF_REAL_tags) / sizeof(asn_DEF_REAL_tags[0]),
+@@ -741,3 +742,23 @@
+ 
+ 	return 0;
+ }
++
++
++long
++REAL_compare(asn_TYPE_descriptor_t *td1, void *sptr1,
++             asn_TYPE_descriptor_t *td2,  void *sptr2) {
++  REAL_t *st1 = (REAL_t *)sptr1;
++  REAL_t *st2 = (REAL_t *)sptr2;
++
++  if ((td1) && (td2)) {
++    if ((td1->name) && (td2->name)) {
++      if (strcmp(td1->name, td2->name)) return -1;
++    } else {
++      if ((td1->xml_tag) && (td2->xml_tag)) {
++        if (strcmp(td1->xml_tag, td2->xml_tag)) return -1;
++      }
++    }
++  }
++  if (st1->size != st2->size) return -1;
++  return memcmp(st1->buf, st2->buf, st1->size);
++}
+--- ./skeletons/REAL.h	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/REAL.h	2015-11-26 13:00:46.183623025 +0100
+@@ -23,6 +23,7 @@
+ per_type_encoder_f REAL_encode_uper;
+ per_type_decoder_f REAL_decode_aper;
+ per_type_encoder_f REAL_encode_aper;
++type_compare_f     REAL_compare;
+ 
+ /***********************************
+  * Some handy conversion routines. *
+--- ./skeletons/RELATIVE-OID.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/RELATIVE-OID.c	2015-11-26 14:56:31.703615834 +0100
+@@ -29,7 +29,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_RELATIVE_OID_tags,
+ 	sizeof(asn_DEF_RELATIVE_OID_tags)
+--- ./skeletons/T61String.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/T61String.c	2015-11-26 14:57:07.235615798 +0100
+@@ -25,7 +25,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_T61String_tags,
+ 	sizeof(asn_DEF_T61String_tags)
+--- ./skeletons/TeletexString.c	2015-12-03 09:43:33.963009150 +0100
++++ ./skeletons/TeletexString.c	2015-11-26 14:57:17.643615787 +0100
+@@ -25,7 +25,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_TeletexString_tags,
+ 	sizeof(asn_DEF_TeletexString_tags)
+--- ./skeletons/UniversalString.c	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/UniversalString.c	2015-11-26 14:57:29.015615775 +0100
+@@ -36,7 +36,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_UniversalString_tags,
+ 	sizeof(asn_DEF_UniversalString_tags)
+--- ./skeletons/UTCTime.c	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/UTCTime.c	2015-11-26 14:57:44.127615759 +0100
+@@ -41,7 +41,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_UTCTime_tags,
+ 	sizeof(asn_DEF_UTCTime_tags)
+--- ./skeletons/UTF8String.c	2015-12-03 09:43:33.959009150 +0100
++++ ./skeletons/UTF8String.c	2015-11-26 14:06:54.563618917 +0100
+@@ -27,6 +27,7 @@
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+ 	OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_UTF8String_tags,
+ 	sizeof(asn_DEF_UTF8String_tags)
+--- ./skeletons/VideotexString.c	2015-12-03 09:43:33.967009150 +0100
++++ ./skeletons/VideotexString.c	2015-11-26 14:07:06.139618905 +0100
+@@ -25,7 +25,8 @@
+ 	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_VideotexString_tags,
+ 	sizeof(asn_DEF_VideotexString_tags)
+--- ./skeletons/VisibleString.c	2015-12-03 09:43:33.971009150 +0100
++++ ./skeletons/VisibleString.c	2015-11-26 14:07:15.283618895 +0100
+@@ -30,7 +30,8 @@
+ 	OCTET_STRING_decode_uper,
+ 	OCTET_STRING_encode_uper,
+ 	OCTET_STRING_decode_aper,
+-	OCTET_STRING_encode_aper,
++  OCTET_STRING_encode_aper,
++  OCTET_STRING_compare,
+ 	0, /* Use generic outmost tag fetcher */
+ 	asn_DEF_VisibleString_tags,
+ 	sizeof(asn_DEF_VisibleString_tags)
diff --git a/openair3/TEST/EPC_TEST/play_scenario.c b/openair3/TEST/EPC_TEST/play_scenario.c
index 9a9cb881b1ed39598e72c5b31e8172d8268ef59a..1aab21642829949e6178e9ce19663cc966d9d4b7 100644
--- a/openair3/TEST/EPC_TEST/play_scenario.c
+++ b/openair3/TEST/EPC_TEST/play_scenario.c
@@ -331,18 +331,18 @@ int et_compare_et_ip_to_net_ip_address(const et_ip_t * const ip, const net_ip_ad
   switch (ip->address_family) {
     case AF_INET:
       if (net_ip->ipv4) {
-        S1AP_DEBUG("%s(%s,%s)=%d\n",__FUNCTION__,ip->str, net_ip->ipv4_address, strcmp(ip->str, net_ip->ipv4_address));
+        //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);
+      //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));
+        //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);
+      //S1AP_DEBUG("%s(%s,%s)=-1 (IP version (6) not matching)\n",__FUNCTION__,ip->str, net_ip->ipv6_address);
       return -1;
       break;
     default:
diff --git a/openair3/TEST/EPC_TEST/play_scenario_fsm.c b/openair3/TEST/EPC_TEST/play_scenario_fsm.c
index b6ff0de85916b0e18eb638ac83ce95756ad27586..1db9df632eec6b87bd23b5a01db05e39fc1c417f 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_fsm.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_fsm.c
@@ -87,6 +87,7 @@ void et_scenario_wait_rx_packet(et_packet_t * const packet)
                    NULL, &packet->timer_id) < 0) {
     AssertFatal(0, " Can not start waiting RX event timer\n");
   }
+  LOG_D(ENB_APP, "Waiting RX packet num %d\n", packet->packet_number);
   g_fsm_state = ET_FSM_STATE_WAITING_RX_EVENT;
   packet->status = ET_PACKET_STATUS_SCHEDULED_FOR_RECEIVING;
 }
@@ -144,6 +145,7 @@ void et_scenario_schedule_tx_packet(et_packet_t * const packet)
             packet->sctp_hdr.u.data_hdr.payload.binary_stream_allocated_size,
             packet->sctp_hdr.u.data_hdr.stream);
         packet->status = ET_PACKET_STATUS_SENT;
+        g_scenario->next_packet    = g_scenario->next_packet->next;
         g_fsm_state = ET_FSM_STATE_RUNNING;
       }
       break;
@@ -161,8 +163,76 @@ et_fsm_state_t et_scenario_fsm_notify_event_state_running(et_event_t event)
 
   switch (event.code){
     case ET_EVENT_TICK:
-      //TODO
+      while (NULL != g_scenario->next_packet) {
+        LOG_D(ENB_APP, "EVENT_TICK: Considering packet num %d:\n", g_scenario->next_packet->packet_number);
+        switch (g_scenario->next_packet->sctp_hdr.chunk_type) {
+          case SCTP_CID_DATA :
+            // no init in this scenario, may be sub-scenario
+            if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_SEND) {
+              if (g_scenario->next_packet->status == ET_PACKET_STATUS_NONE) {
+                et_scenario_schedule_tx_packet(g_scenario->next_packet);
+                pthread_mutex_unlock(&g_fsm_lock);
+
+                et_event_t continue_event;
+                continue_event.code = ET_EVENT_TICK;
+                et_scenario_fsm_notify_event(continue_event);
+
+                return g_fsm_state;
+              } else if (g_scenario->next_packet->status != ET_PACKET_STATUS_SCHEDULED_FOR_SENDING) {
+                AssertFatal(0, "Invalid packet status %d", g_scenario->next_packet->status);
+              }
+            } else if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
+              if (g_scenario->next_packet->status == ET_PACKET_STATUS_RECEIVED) {
+                g_scenario->next_packet    = g_scenario->next_packet->next;
+
+              } else if (g_scenario->next_packet->status == ET_PACKET_STATUS_NONE) {
+                et_scenario_wait_rx_packet(g_scenario->next_packet);
+                pthread_mutex_unlock(&g_fsm_lock);
+                return g_fsm_state;
+              } else {
+                AssertFatal(0, "Invalid packet status %d", g_scenario->next_packet->status);
+              }
+            } else {
+              AssertFatal(0, "Invalid packet action %d", g_scenario->next_packet->action);
+            }
+            break;
+
+          case SCTP_CID_INIT:
+          case SCTP_CID_INIT_ACK:
+          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:
+            LOG_D(ENB_APP, "EVENT_TICK: Ignoring packet num %d SCTP CID %s\n",
+                g_scenario->next_packet->packet_number,
+                et_chunk_type_cid2str(g_scenario->next_packet->sctp_hdr.chunk_type));
+            g_scenario->next_packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
+            g_scenario->next_packet = g_scenario->next_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(g_scenario->next_packet->sctp_hdr.chunk_type));
+            break;
 
+          default:
+            LOG_D(ENB_APP, "EVENT_TICK: Ignoring packet num %d SCTP CID %s\n",
+                g_scenario->next_packet->packet_number,
+                et_chunk_type_cid2str(g_scenario->next_packet->sctp_hdr.chunk_type));
+            g_scenario->next_packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
+            g_scenario->next_packet = g_scenario->next_packet->next;
+        }
+      }
+      fprintf(stderr, "No Packet found in this scenario: %s\n", g_scenario->name);
+      g_fsm_state = ET_FSM_STATE_NULL;
+      pthread_mutex_unlock(&g_fsm_lock);
+      return g_fsm_state;
       break;
     case ET_EVENT_RX_PACKET_TIME_OUT:
       AssertFatal(0, "Event ET_EVENT_RX_PACKET_TIME_OUT not handled in FSM state ET_FSM_STATE_RUNNING");
@@ -186,6 +256,7 @@ et_fsm_state_t et_scenario_fsm_notify_event_state_waiting_tx(et_event_t event)
   int rv = 0;
   switch (event.code){
     case ET_EVENT_TICK:
+      fprintf(stdout, "EVENT_TICK: waiting for tx event\n");
       break;
 
     case ET_EVENT_RX_S1AP:
@@ -202,6 +273,7 @@ et_fsm_state_t et_scenario_fsm_notify_event_state_waiting_tx(et_event_t event)
           event.u.tx_timed_packet->sctp_hdr.u.data_hdr.payload.binary_stream_allocated_size,
           event.u.tx_timed_packet->sctp_hdr.u.data_hdr.stream);
       event.u.tx_timed_packet->status = ET_PACKET_STATUS_SENT;
+      g_scenario->next_packet    = event.u.tx_timed_packet->next;
       g_fsm_state = ET_FSM_STATE_RUNNING;
       break;
 
@@ -219,6 +291,7 @@ et_fsm_state_t et_scenario_fsm_notify_event_state_waiting_rx(et_event_t event)
   int rv = 0;
   switch (event.code){
     case ET_EVENT_TICK:
+      fprintf(stdout, "EVENT_TICK: waiting for rx event\n");
       break;
 
     case ET_EVENT_RX_PACKET_TIME_OUT:
@@ -272,7 +345,6 @@ et_fsm_state_t et_scenario_fsm_notify_event_state_connecting_s1c(et_event_t even
             } else if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
               if (g_scenario->next_packet->status == ET_PACKET_STATUS_RECEIVED) {
                 g_scenario->last_rx_packet = g_scenario->next_packet;
-                g_scenario->next_packet    = g_scenario->next_packet->next;
                 g_scenario->time_last_rx_packet = g_scenario->last_rx_packet->timestamp_packet;
                 g_scenario->next_packet    = g_scenario->next_packet->next;
 
@@ -357,7 +429,6 @@ et_fsm_state_t et_scenario_fsm_notify_event_state_null(et_event_t event)
             } else if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
               if (g_scenario->next_packet->status == ET_PACKET_STATUS_RECEIVED) {
                 g_scenario->last_rx_packet = g_scenario->next_packet;
-                g_scenario->next_packet    = g_scenario->next_packet->next;
                 g_scenario->time_last_rx_packet = g_scenario->last_rx_packet->timestamp_packet;
                 g_scenario->next_packet    = g_scenario->next_packet->next;
 
diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
index 336dc547d52e38dbff80d8084e3b52792c37dc5d..142ab069e93e1bdec8f59aed74f85659ba40a9cb 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
@@ -250,9 +250,24 @@ et_packet_t* et_build_packet_from_s1ap_data_ind(et_event_s1ap_data_ind_t * const
 // return 0 if packet was waited
 int et_scenario_set_packet_received(et_packet_t * const packet)
 {
-  int rc = 0;
+  et_packet_t * p = NULL;
+  int           rc = 0;
+
   packet->status = ET_PACKET_STATUS_RECEIVED;
   S1AP_DEBUG("Packet num %d received\n", packet->packet_number);
+
+  p = g_scenario->last_rx_packet;
+  while (NULL != p) {
+    if (p->action == ET_PACKET_ACTION_S1C_RECEIVE) {
+      if (p->status == ET_PACKET_STATUS_RECEIVED) {
+        g_scenario->last_rx_packet = p;
+      } else {
+        break;
+      }
+    }
+    p = p->next;
+  }
+
   if (packet->timer_id != 0) {
     rc = timer_remove(packet->timer_id);
     AssertFatal(rc == 0, "TODO: Debug Timer on Rx packet num %d unknown", packet->packet_number);
@@ -278,6 +293,7 @@ int et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const s1ap_data_ind)
       if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
         if (packet->status == ET_PACKET_STATUS_RECEIVED) {
           g_scenario->last_rx_packet = packet;
+          g_scenario->time_last_rx_packet = g_scenario->last_rx_packet->timestamp_packet;
         } else {
           break;
         }
@@ -286,7 +302,7 @@ int et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const s1ap_data_ind)
     }
     packet = g_scenario->list_packet;
   } else {
-    packet = g_scenario->last_rx_packet;
+    packet = g_scenario->last_rx_packet->next;
   }
   // not_found threshold may sure depend on number of mme, may be not sure on number of UE
   while ((NULL != packet) && (not_found < 5)) {
@@ -308,8 +324,8 @@ int et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const s1ap_data_ind)
     not_found += 1;
     packet = packet->next;
   }
-  S1AP_DEBUG("Rx packet not found in scenario:\n");
   et_display_packet_sctp(&rx_packet->sctp_hdr);
+  AssertFatal(0, "Rx packet not found in scenario (see dump above)");
   return -1;
 }