From 1b86363795b0931fc47d78899e9d079df659f408 Mon Sep 17 00:00:00 2001
From: gauthier <lionel.gauthier@eurecom.fr>
Date: Tue, 8 Dec 2015 15:08:02 +0100
Subject: [PATCH] Remaining TODO: handle diff MME_UE_S1AP_ID, asn1c compare not
 tested

---
 cmake_targets/CMakeLists.txt                  |   1 +
 openair3/S1AP/MESSAGES/ASN1/asn1cpatch_3.p0   | 848 +++++++++++-------
 openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py   |  87 +-
 openair3/TEST/EPC_TEST/play_scenario.c        |  34 +-
 openair3/TEST/EPC_TEST/play_scenario.h        |  14 +-
 openair3/TEST/EPC_TEST/play_scenario_s1ap.c   | 394 +++++++-
 .../EPC_TEST/play_scenario_s1ap_compare_ie.c  |   6 +-
 openair3/TEST/EPC_TEST/play_scenario_sctp.c   |  31 +-
 8 files changed, 1041 insertions(+), 374 deletions(-)

diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 9c5bbad0de9..a562a5ebc0a 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1677,6 +1677,7 @@ add_executable(test_epc_play_scenario
   ${OPENAIR2_DIR}/COMMON/messages_types.h
   ${OPENAIR_BIN_DIR}/messages_xml.h
   )
+target_include_directories(test_epc_play_scenario PUBLIC /usr/local/share/asn1c)
 target_link_libraries (test_epc_play_scenario
   -Wl,--start-group RRC_LIB S1AP_LIB X2AP_LIB GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}  
   )
diff --git a/openair3/S1AP/MESSAGES/ASN1/asn1cpatch_3.p0 b/openair3/S1AP/MESSAGES/ASN1/asn1cpatch_3.p0
index cf3553c362d..3986a6a83b4 100644
--- a/openair3/S1AP/MESSAGES/ASN1/asn1cpatch_3.p0
+++ b/openair3/S1AP/MESSAGES/ASN1/asn1cpatch_3.p0
@@ -1,20 +1,20 @@
---- ./asn1c/unber.c	2015-12-03 09:43:33.959009150 +0100
-+++ ./asn1c/unber.c	2015-11-30 13:20:40.751264003 +0100
+--- asn1c/unber.c	2015-12-08 14:39:33.282543533 +0100
++++ asn1c/unber.c	2015-12-07 10:46:18.382647000 +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; }
++asn_comp_rval_t *  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
+--- libasn1compiler/asn1c_C.c	2015-12-08 14:39:33.366543533 +0100
++++ libasn1compiler/asn1c_C.c	2015-12-08 08:38:29.002565000 +0100
 @@ -1082,6 +1082,8 @@
  	enum tvm_compat tv_mode;
  	enum etd_spec etd_spec;
  	char *p;
-+  char tmp_buf[512];
-+  int i = 0;
++  //char tmp_buf[512];
++  //int i = 0;
  
  	if(arg->embed) {
  		enum tnfmt tnfmt = TNF_CTYPE;
@@ -28,49 +28,39 @@
  	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 @@
+@@ -1413,6 +1416,39 @@
  	OUT("}\n");
  	OUT("\n");
  
 +
-+  i = 0;
-+  while ((p[i] != '_') && (i < sizeof(tmp_buf))) {
-+    tmp_buf[i] = p[i];
-+    i++;
-+  }
-+  tmp_buf[i] = '\0';
++  //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);
++  //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("asn_comp_rval_t * \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("asn_comp_rval_t * res  = NULL;\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("res = td1->compare(td1, structure1, td2, structure2);\n");
++  OUT("return res;\n");
 +  );
 +  OUT("}\n");
 +  OUT("\n");
@@ -78,7 +68,7 @@
  	p = MKID(expr);
  	
  	if(HIDE_INNER_DEFS) OUT("static ");
-@@ -1450,7 +1496,8 @@
+@@ -1450,7 +1486,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);
@@ -88,7 +78,7 @@
  		}
  	}
  
-@@ -2501,6 +2548,7 @@
+@@ -2501,6 +2538,7 @@
  			OUT("0, 0,\t/* No APER support, "
  				"use \"-gen-PER\" to enable */\n");
  		}
@@ -96,8 +86,8 @@
  
  		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
+--- skeletons/ANY.c	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/ANY.c	2015-11-26 14:40:56.547616000 +0100
 @@ -24,7 +24,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -108,8 +98,101 @@
  	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
+--- skeletons/asn_application.h	2015-12-08 14:39:12.674543554 +0100
++++ skeletons/asn_application.h	2015-12-07 14:36:32.950633000 +0100
+@@ -9,7 +9,8 @@
+ #define	_ASN_APPLICATION_H_
+ 
+ #include "asn_system.h"		/* for platform-dependent types */
+-#include "asn_codecs.h"		/* for ASN.1 codecs specifics */
++#include "asn_codecs.h"   /* for ASN.1 codecs specifics */
++#include "asn_compare.h"
+ 
+ #ifdef __cplusplus
+ extern "C" {
+--- skeletons/asn_compare.h	1970-01-01 01:00:00.000000000 +0100
++++ skeletons/asn_compare.h	2015-12-08 10:34:58.090558000 +0100
+@@ -0,0 +1,78 @@
++#ifndef	_ASN_COMPARE_H_
++#define	_ASN_COMPARE_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++struct asn_TYPE_descriptor_s;	/* Forward declaration */
++
++
++typedef enum COMPARE_ERR_CODE_e {
++  COMPARE_ERR_CODE_START = 0,
++  COMPARE_ERR_CODE_NONE = COMPARE_ERR_CODE_START,
++  COMPARE_ERR_CODE_NO_MATCH,
++  COMPARE_ERR_CODE_TYPE_MISMATCH,
++  COMPARE_ERR_CODE_TYPE_ARG_NULL,
++  COMPARE_ERR_CODE_VALUE_NULL,
++  COMPARE_ERR_CODE_VALUE_ARG_NULL,
++  COMPARE_ERR_CODE_CHOICE_NUM,
++  COMPARE_ERR_CODE_CHOICE_PRESENT,
++  COMPARE_ERR_CODE_CHOICE_MALFORMED,
++  COMPARE_ERR_CODE_SET_MALFORMED,
++  COMPARE_ERR_CODE_COLLECTION_NUM_ELEMENTS,
++  COMPARE_ERR_CODE_END
++} COMPARE_ERR_CODE_t;
++
++typedef struct asn_comp_rval_s {
++  enum COMPARE_ERR_CODE_e err_code;
++  char                   *name; // e_S1ap_ProtocolIE_ID not available for all ASN1 use (RRC vs S1AP, X2AP)
++  void                   *structure1;
++  void                   *structure2;
++  struct asn_comp_rval_s *next;
++} asn_comp_rval_t;
++
++#define COMPARE_CHECK_ARGS(aRg_tYpE_dEf1, aRg_tYpE_dEf2, aRg_vAl1, aRg_vAl2, rEsUlT) \
++    do {\
++      if ((aRg_tYpE_dEf1) && (aRg_tYpE_dEf2)) {\
++        if ((aRg_tYpE_dEf1->name) && (aRg_tYpE_dEf2->name)) {\
++          if (strcmp(aRg_tYpE_dEf1->name, aRg_tYpE_dEf2->name)) {\
++            rEsUlT           = (asn_comp_rval_t *)calloc(1, sizeof(asn_comp_rval_t));\
++            rEsUlT->err_code = COMPARE_ERR_CODE_TYPE_MISMATCH;\
++            rEsUlT->name     = aRg_tYpE_dEf1->name;\
++            return rEsUlT;\
++          }\
++        } else {\
++          if ((aRg_tYpE_dEf1->xml_tag) && (aRg_tYpE_dEf2->xml_tag)) {\
++            if (strcmp(aRg_tYpE_dEf1->xml_tag, aRg_tYpE_dEf2->xml_tag)) {\
++              rEsUlT           = (asn_comp_rval_t *)calloc(1, sizeof(asn_comp_rval_t));\
++              rEsUlT->err_code = COMPARE_ERR_CODE_TYPE_MISMATCH;\
++              rEsUlT->name     = aRg_tYpE_dEf1->xml_tag;\
++              return rEsUlT;\
++            }\
++          }\
++        }\
++      } else {\
++        rEsUlT             = (asn_comp_rval_t *)calloc(1, sizeof(asn_comp_rval_t));\
++        rEsUlT->name       = aRg_tYpE_dEf1->name;\
++        rEsUlT->structure1 = aRg_vAl1;\
++        rEsUlT->structure2 = aRg_vAl2;\
++        rEsUlT->err_code   = COMPARE_ERR_CODE_TYPE_ARG_NULL;\
++        return rEsUlT;\
++      }\
++      if ((NULL == aRg_vAl1) || (NULL == aRg_vAl2)){\
++        rEsUlT             = (asn_comp_rval_t *)calloc(1, sizeof(asn_comp_rval_t));\
++        rEsUlT->name       = aRg_tYpE_dEf1->name;\
++        rEsUlT->structure1 = aRg_vAl1;\
++        rEsUlT->structure2 = aRg_vAl2;\
++        rEsUlT->err_code   = COMPARE_ERR_CODE_VALUE_ARG_NULL;\
++        return rEsUlT;\
++      }\
++    } while (0);
++
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif	/* _ASN_COMPARE_H_ */
+--- skeletons/BIT_STRING.c	2015-12-08 14:39:33.346543533 +0100
++++ skeletons/BIT_STRING.c	2015-11-26 14:41:50.159616000 +0100
 @@ -30,7 +30,8 @@
  	OCTET_STRING_decode_uper,	/* Unaligned PER decoder */
  	OCTET_STRING_encode_uper,	/* Unaligned PER encoder */
@@ -120,8 +203,8 @@
  	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
+--- skeletons/BMPString.c	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/BMPString.c	2015-11-26 14:42:08.487616000 +0100
 @@ -36,7 +36,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -132,8 +215,8 @@
  	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
+--- skeletons/BOOLEAN.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/BOOLEAN.c	2015-12-08 10:37:11.866558000 +0100
 @@ -25,7 +25,8 @@
  	BOOLEAN_decode_uper,	/* Unaligned PER decoder */
  	BOOLEAN_encode_uper,	/* Unaligned PER encoder */
@@ -144,30 +227,31 @@
  	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 @@
+@@ -326,3 +327,22 @@
  
  	_ASN_ENCODED_OK(er);
  }
 +
-+long
++asn_comp_rval_t *
 +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);
++  asn_comp_rval_t *res = NULL;
++
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
++
++  if (*st1 == *st2) return NULL;
++  res = calloc(1, sizeof(asn_comp_rval_t));
++  res->name = td1->name;
++  res->structure1 = sptr1;
++  res->structure2 = sptr2;
++  res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++  return res;
 +}
 +
---- ./skeletons/BOOLEAN.h	2015-12-03 09:43:33.967009150 +0100
-+++ ./skeletons/BOOLEAN.h	2015-11-26 12:46:58.491623882 +0100
+--- skeletons/BOOLEAN.h	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/BOOLEAN.h	2015-11-26 12:46:58.491623000 +0100
 @@ -30,6 +30,7 @@
  per_type_encoder_f BOOLEAN_encode_uper;
  per_type_decoder_f BOOLEAN_decode_aper;
@@ -176,9 +260,9 @@
  
  #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 @@
+--- skeletons/compare.h	1970-01-01 01:00:00.000000000 +0100
++++ skeletons/compare.h	2015-12-08 08:23:03.694566000 +0100
+@@ -0,0 +1,28 @@
 +/*-
 + * Eurecom 2015.
 + */
@@ -186,7 +270,6 @@
 +#define	_COMPARE_H_
 +
 +#include <asn_application.h>
-+#include <per_support.h>
 +
 +#ifdef __cplusplus
 +extern "C" {
@@ -194,46 +277,37 @@
 +
 +struct asn_TYPE_descriptor_s;	/* Forward declaration */
 +
-+typedef long (type_compare_f)(
++typedef asn_comp_rval_t * (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 @@
+--- skeletons/constr_CHOICE.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/constr_CHOICE.c	2015-12-08 10:39:16.670558000 +0100
+@@ -1272,3 +1272,75 @@
  		assert(pres_size != sizeof(int));
  	}
  }
 +
-+long
++asn_comp_rval_t *
 +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;
++  asn_comp_rval_t *res = NULL;
 +
-+  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;
-+      }
-+    }
-+  }
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
 +
 +  /*
 +   * Figure out which CHOICE element is encoded.
@@ -242,8 +316,22 @@
 +  // 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 (td1->elements_count != td2->elements_count) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_CHOICE_NUM;
++    return res;
++  }
++  if (present1 != present2) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_CHOICE_PRESENT;
++    return res;
++  }
 +  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];
@@ -253,21 +341,36 @@
 +    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;
++      if((!memb_ptr1) || (!memb_ptr2)) {
++        res = calloc(1, sizeof(asn_comp_rval_t));
++        res->name = td1->name;
++        res->structure1 = sptr1;
++        res->structure2 = sptr2;
++        res->err_code = COMPARE_ERR_CODE_VALUE_NULL;
++        return res;
++      }
 +    } 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;
++      res = calloc(1, sizeof(asn_comp_rval_t));
++      res->name = td1->name;
++      res->structure1 = sptr1;
++      res->structure2 = sptr2;
++      res->err_code = COMPARE_ERR_CODE_CHOICE_MALFORMED;
++      return res;
 +    }
 +    return elm1->type->compare(elm1->type, memb_ptr1, elm2->type, memb_ptr2);
 +  }
-+  return 0;
++  res = calloc(1, sizeof(asn_comp_rval_t));
++  res->name = td1->name;
++  res->structure1 = sptr1;
++  res->structure2 = sptr2;
++  res->err_code = COMPARE_ERR_CODE_CHOICE_MALFORMED;
++  return res;
 +}
---- ./skeletons/constr_CHOICE.h	2015-12-03 09:43:33.967009150 +0100
-+++ ./skeletons/constr_CHOICE.h	2015-11-26 14:43:57.647616615 +0100
+--- skeletons/constr_CHOICE.h	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/constr_CHOICE.h	2015-11-26 14:43:57.647616000 +0100
 @@ -39,7 +39,7 @@
  /*
   * A set specialized functions dealing with the CHOICE type.
@@ -287,34 +390,30 @@
  
  #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 @@
+--- skeletons/constr_SEQUENCE.c	2015-12-08 14:39:33.346543533 +0100
++++ skeletons/constr_SEQUENCE.c	2015-12-08 10:39:52.442558000 +0100
+@@ -1761,3 +1761,66 @@
  
  	_ASN_ENCODED_OK(er);
  }
 +
-+long
-+SEQUENCE_compare(asn_TYPE_descriptor_t *td1, void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2) {
++asn_comp_rval_t * SEQUENCE_compare(asn_TYPE_descriptor_t *td1, void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2) {
 +  int edx;
 +  int ret;
++  asn_comp_rval_t *res = NULL;
++  asn_comp_rval_t *res2 = NULL;
 +
-+  if((!sptr1) && (!sptr2)) return -1;
-+  if(!sptr1) return -1;
-+  if(!sptr2) return -1;
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
 +
-+  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) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_COLLECTION_NUM_ELEMENTS;
++    return res;
 +  }
 +
-+  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];
@@ -327,21 +426,41 @@
 +      if((!memb_ptr1) && (!memb_ptr2)) {
 +        if(elm1->optional) continue;
 +      }
-+      if (!memb_ptr1) return -1;
-+      if (!memb_ptr2) return -1;
++      if ((!memb_ptr1) || (!memb_ptr2)) {
++        res2 = calloc(1, sizeof(asn_comp_rval_t));
++        res2->name = elm1->name;
++        res2->structure1 = memb_ptr1;
++        res2->structure2 = memb_ptr2;
++        res->err_code = COMPARE_ERR_CODE_VALUE_NULL;
++        if (NULL == res) {
++          res = res2;
++        } else {
++          res2->next = res;
++          res = res2;
++        }
++        res2 = NULL;
++      }
 +    } 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;
++    res2 = elm1->type->compare(elm1->type, memb_ptr1, elm2->type, memb_ptr2);
++    if(res2) {
++      if (NULL == res) {
++        res = res2;
++      } else {
++        res2->next = res;
++        res = res2;
++      }
++      res2 = NULL;
++    }
 +  }
-+  return  0;
++  return res;
 +}
---- ./skeletons/constr_SEQUENCE.h	2015-12-03 09:43:33.971009150 +0100
-+++ ./skeletons/constr_SEQUENCE.h	2015-11-26 14:48:14.123616350 +0100
+--- skeletons/constr_SEQUENCE.h	2015-12-08 14:39:33.346543533 +0100
++++ skeletons/constr_SEQUENCE.h	2015-11-26 14:48:14.123616000 +0100
 @@ -54,6 +54,7 @@
  per_type_encoder_f SEQUENCE_encode_uper;
  per_type_decoder_f SEQUENCE_decode_aper;
@@ -350,8 +469,8 @@
  
  #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
+--- skeletons/constr_SEQUENCE_OF.h	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/constr_SEQUENCE_OF.h	2015-11-26 15:05:25.399615000 +0100
 @@ -22,7 +22,8 @@
  #define	SEQUENCE_OF_decode_ber	SET_OF_decode_ber
  #define	SEQUENCE_OF_decode_xer	SET_OF_decode_xer
@@ -362,8 +481,8 @@
  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
+--- skeletons/constr_SET.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/constr_SET.c	2015-12-08 10:40:35.066558000 +0100
 @@ -1108,7 +1108,7 @@
  	}
  }
@@ -373,8 +492,67 @@
  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
+@@ -1159,3 +1159,58 @@
+ 
+ 	return 0;
+ }
++
++asn_comp_rval_t *
++SET_compare(asn_TYPE_descriptor_t *td1, void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2)
++{
++  int edx;
++  asn_comp_rval_t *res = NULL;
++  asn_comp_rval_t *res2 = NULL;
++
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
++
++  if (td1->elements_count != td2->elements_count) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_COLLECTION_NUM_ELEMENTS;
++    return res;
++  }
++
++  for(edx = 0; edx < td1->elements_count; edx++) {
++    asn_TYPE_member_t *elm1 = &td1->elements[edx];
++    asn_TYPE_member_t *elm2 = &td2->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) {
++        if(elm1->optional)
++          continue;
++        res = calloc(1, sizeof(asn_comp_rval_t));
++        res->name = td1->name;
++        res->structure1 = sptr1;
++        res->structure2 = sptr2;
++        res->err_code = COMPARE_ERR_CODE_SET_MALFORMED;
++        return res;
++      }
++    } else {
++      memb_ptr1 = (const void *)((const char *)sptr1 + elm1->memb_offset);
++      memb_ptr2 = (const void *)((const char *)sptr2 + elm2->memb_offset);
++    }
++    res2 = elm1->type->compare(elm1->type, memb_ptr1, elm2->type, memb_ptr2);
++    if(res2) {
++      if (NULL == res) {
++        res = res2;
++      } else {
++        res2->next = res;
++        res = res2;
++      }
++      res2 = NULL;
++    }
++  }
++  return res;
++}
+--- skeletons/constr_SET.h	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/constr_SET.h	2015-11-26 14:49:09.243616000 +0100
 @@ -56,6 +56,7 @@
  per_type_decoder_f SET_decode_aper;
  per_type_encoder_f SET_encode_uper;
@@ -383,14 +561,14 @@
  
  /***********************
   * 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 @@
+--- skeletons/constr_SET_OF.c	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/constr_SET_OF.c	2015-12-08 10:45:54.466557000 +0100
+@@ -1039,3 +1039,55 @@
  	rv.consumed = 0;
  	return rv;
  }
 +
-+long
++asn_comp_rval_t *
 +SET_OF_compare(asn_TYPE_descriptor_t *td1, void *sptr1, asn_TYPE_descriptor_t *td2, void *sptr2)
 +{
 +  asn_TYPE_member_t *elm1 = td1->elements;
@@ -399,41 +577,50 @@
 +  const asn_anonymous_set_ *list2 = _A_CSET_FROM_VOID(sptr2);
 +  int ret;
 +  int i;
++  asn_comp_rval_t *res = NULL;
++  asn_comp_rval_t *res2 = NULL;
 +
-+  if((!sptr1) && !(sptr2)) return 0;
-+  if(!sptr1) return -1;
-+  if(!sptr2) return -1;
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
 +
-+  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) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_COLLECTION_NUM_ELEMENTS;
++    return res;
 +  }
 +
-+  if (td1->elements_count != td2->elements_count) return -1;
-+
 +
-+  if (list1->count != list2->count ) return -1;
++  if (list1->count != list2->count ) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_COLLECTION_NUM_ELEMENTS;
++    return res;
++  }
 +
 +  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;
++    res2 = elm1->type->compare(elm1->type, memb_ptr1, elm2->type, memb_ptr2);
++    if(res2) {
++      if (NULL == res) {
++        res = res2;
++      } else {
++        res2->next = res;
++        res = res2;
++      }
++      res2 = NULL;
++    }
 +  }
-+
-+  return  0;
++  return  res;
 +}
---- ./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
+--- skeletons/constr_SET_OF.h	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/constr_SET_OF.h	2015-11-26 14:48:45.067616000 +0100
 @@ -36,6 +36,7 @@
  per_type_encoder_f SET_OF_encode_uper;
  per_type_decoder_f SET_OF_decode_aper;
@@ -442,8 +629,8 @@
  
  #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
+--- skeletons/constr_TYPE.h	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/constr_TYPE.h	2015-11-26 15:28:05.495613000 +0100
 @@ -41,7 +41,8 @@
  #include <xer_encoder.h>	/* Encoder into XER (XML, text) */
  #include <per_decoder.h>	/* Packet Encoding Rules decoder */
@@ -462,8 +649,8 @@
  
  	/***********************************************************************
  	 * 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
+--- skeletons/ENUMERATED.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/ENUMERATED.c	2015-12-08 10:40:55.986558000 +0100
 @@ -27,7 +27,8 @@
  	ENUMERATED_decode_uper,	/* Unaligned PER decoder */
  	ENUMERATED_encode_uper,	/* Unaligned PER encoder */
@@ -479,26 +666,26 @@
  	return NativeEnumerated_encode_aper(td, constraints, &value, po);
  }
 +
-+long
++asn_comp_rval_t *
 +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;
++  asn_comp_rval_t *res = NULL;
 +
-+  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);
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
++
++  if (*st1 == *st2) return NULL;
++  res = calloc(1, sizeof(asn_comp_rval_t));
++  res->name = td1->name;
++  res->structure1 = sptr1;
++  res->structure2 = sptr2;
++  res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++  return res;
 +}
 +
---- ./skeletons/ENUMERATED.h	2015-12-03 09:43:33.963009150 +0100
-+++ ./skeletons/ENUMERATED.h	2015-11-26 12:46:35.523623906 +0100
+--- skeletons/ENUMERATED.h	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/ENUMERATED.h	2015-11-26 12:46:35.523623000 +0100
 @@ -19,6 +19,7 @@
  per_type_encoder_f ENUMERATED_encode_uper;
  per_type_decoder_f ENUMERATED_decode_aper;
@@ -507,9 +694,9 @@
  
  #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 @@
+--- skeletons/file-dependencies	2015-12-08 14:39:12.678543554 +0100
++++ skeletons/file-dependencies	2015-12-07 15:34:40.454629000 +0100
+@@ -39,12 +39,13 @@
  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
@@ -517,9 +704,17 @@
 +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
+-asn_application.h		# Applications should include this file
++asn_application.h   # Applications should include this file
+ asn_system.h			# Platform-dependent types
+-asn_codecs.h			# Return types of encoders and decoders
++asn_codecs.h      # Return types of encoders and decoders
++asn_compare.h     # Return type of compare
+ asn_internal.h			# Internal stuff
+ OCTET_STRING.h OCTET_STRING.c	# This one is used too widely
+ BIT_STRING.h BIT_STRING.c	# This one is necessary for the above one
+--- skeletons/GeneralizedTime.c	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/GeneralizedTime.c	2015-11-26 15:09:03.899615000 +0100
 @@ -168,7 +168,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -530,8 +725,8 @@
  	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
+--- skeletons/GeneralString.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/GeneralString.c	2015-11-26 14:50:11.843616000 +0100
 @@ -25,7 +25,8 @@
  	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
  	OCTET_STRING_encode_uper,
@@ -542,8 +737,8 @@
  	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
+--- skeletons/GraphicString.c	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/GraphicString.c	2015-11-26 15:33:33.255613000 +0100
 @@ -25,7 +25,8 @@
  	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
  	OCTET_STRING_encode_uper,
@@ -554,8 +749,8 @@
  	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
+--- skeletons/IA5String.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/IA5String.c	2015-11-26 14:50:44.219616000 +0100
 @@ -31,6 +31,7 @@
  	OCTET_STRING_encode_uper,
  	OCTET_STRING_decode_aper,
@@ -564,8 +759,8 @@
  	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
+--- skeletons/INTEGER.c	2015-12-08 14:39:33.346543533 +0100
++++ skeletons/INTEGER.c	2015-12-08 10:41:08.526558000 +0100
 @@ -35,6 +35,7 @@
  	INTEGER_decode_aper,
  	INTEGER_encode_aper,
@@ -574,29 +769,39 @@
  	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 @@
+@@ -1501,3 +1502,30 @@
  }
  
  
-+long
++asn_comp_rval_t *
 +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;
-+      }
-+    }
++  asn_comp_rval_t *res = NULL;
++
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
++
++  if (st1->size != st2->size) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++    return res;
++  }
++  if (0 != memcmp(st1->buf, st2->buf, st1->size)) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++    return res;
 +  }
-+  if (st1->size != st2->size) return -1;
-+  return memcmp(st1->buf, st2->buf, st1->size);
++  return NULL;
 +}
---- ./skeletons/INTEGER.h	2015-12-03 09:43:33.967009150 +0100
-+++ ./skeletons/INTEGER.h	2015-11-26 12:50:41.551623651 +0100
+--- skeletons/INTEGER.h	2015-12-08 14:39:33.346543533 +0100
++++ skeletons/INTEGER.h	2015-11-26 12:50:41.551623000 +0100
 @@ -43,6 +43,7 @@
  per_type_encoder_f INTEGER_encode_uper;
  per_type_decoder_f INTEGER_decode_aper;
@@ -605,8 +810,8 @@
  
  /***********************************
   * 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
+--- skeletons/ISO646String.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/ISO646String.c	2015-11-26 12:55:48.327623000 +0100
 @@ -30,7 +30,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -617,19 +822,25 @@
  	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 @@
+--- skeletons/Makefile.am	2015-12-08 14:39:12.666543554 +0100
++++ skeletons/Makefile.am	2015-12-07 15:54:00.150628000 +0100
+@@ -46,11 +46,11 @@
+ 	asn_SET_OF.c asn_SET_OF.h			\
+ 	asn_application.h asn_codecs.h			\
+ 	asn_codecs_prim.c asn_codecs_prim.h		\
+-	asn_internal.h asn_system.h			\
++	asn_internal.h asn_system.h asn_compare.h			\
  	ber_decoder.c ber_decoder.h			\
  	ber_tlv_length.c ber_tlv_length.h		\
- 	ber_tlv_tag.c ber_tlv_tag.h			\
+-	ber_tlv_tag.c ber_tlv_tag.h			\
 -	constr_CHOICE.c constr_CHOICE.h			\
++	ber_tlv_tag.c ber_tlv_tag.h compare.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
+--- skeletons/NativeEnumerated.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/NativeEnumerated.c	2015-12-08 10:41:17.662558000 +0100
 @@ -31,7 +31,8 @@
  	NativeEnumerated_decode_uper,
  	NativeEnumerated_encode_uper,
@@ -640,34 +851,31 @@
  	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 @@
+@@ -335,3 +336,22 @@
  
  	_ASN_ENCODED_OK(er);
  }
 +
-+long
++asn_comp_rval_t *
 +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;
-+      }
-+    }
-+  }
++  asn_comp_rval_t *res = NULL;
++
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
 +
 +  if(a->nat_value == b->nat_value)
-+    return 0;
-+  if(a->nat_value < b->nat_value)
-+    return -1;
-+  return 1;
++    return NULL;
++  res = calloc(1, sizeof(asn_comp_rval_t));
++  res->name = td1->name;
++  res->structure1 = sptr1;
++  res->structure2 = sptr2;
++  res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++  return res;
 +}
---- ./skeletons/NativeEnumerated.h	2015-12-03 09:43:33.967009150 +0100
-+++ ./skeletons/NativeEnumerated.h	2015-11-26 14:51:43.315616133 +0100
+--- skeletons/NativeEnumerated.h	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/NativeEnumerated.h	2015-11-26 14:51:43.315616000 +0100
 @@ -26,6 +26,7 @@
  per_type_encoder_f NativeEnumerated_encode_uper;
  per_type_decoder_f NativeEnumerated_decode_aper;
@@ -676,8 +884,8 @@
  
  #ifdef __cplusplus
  }
---- ./skeletons/NativeInteger.c	2015-12-03 09:43:33.967009150 +0100
-+++ ./skeletons/NativeInteger.c	2015-11-30 13:18:39.887264128 +0100
+--- skeletons/NativeInteger.c	2015-12-08 14:39:33.346543533 +0100
++++ skeletons/NativeInteger.c	2015-12-08 10:41:24.550558000 +0100
 @@ -32,7 +32,8 @@
  	NativeInteger_decode_uper,	/* Unaligned PER decoder */
  	NativeInteger_encode_uper,	/* Unaligned PER encoder */
@@ -688,29 +896,30 @@
  	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 @@
+@@ -410,3 +411,21 @@
  	}
  }
  
 +
-+long
++asn_comp_rval_t *
 +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);
++  asn_comp_rval_t *res = NULL;
++
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
++
++  if (*native1 == *native2) return NULL;
++  res = calloc(1, sizeof(asn_comp_rval_t));
++  res->name = td1->name;
++  res->structure1 = sptr1;
++  res->structure2 = sptr2;
++  res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++  return res;
 +}
---- ./skeletons/NativeInteger.h	2015-12-03 09:43:33.971009150 +0100
-+++ ./skeletons/NativeInteger.h	2015-11-26 14:52:13.931616101 +0100
+--- skeletons/NativeInteger.h	2015-12-08 14:39:33.346543533 +0100
++++ skeletons/NativeInteger.h	2015-11-26 14:52:13.931616000 +0100
 @@ -31,6 +31,7 @@
  per_type_encoder_f NativeInteger_encode_uper;
  per_type_decoder_f NativeInteger_decode_aper;
@@ -719,8 +928,8 @@
  
  #ifdef __cplusplus
  }
---- ./skeletons/NativeReal.c	2015-12-03 09:43:33.971009150 +0100
-+++ ./skeletons/NativeReal.c	2015-11-30 13:18:46.655264121 +0100
+--- skeletons/NativeReal.c	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/NativeReal.c	2015-12-08 10:41:32.666558000 +0100
 @@ -33,7 +33,8 @@
  	NativeReal_decode_uper,
  	NativeReal_encode_uper,
@@ -731,30 +940,39 @@
  	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 @@
+@@ -405,3 +406,30 @@
  	}
  }
  
-+long
++asn_comp_rval_t *
 +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;
++  asn_comp_rval_t *res = NULL;
 +
-+  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;
-+      }
-+    }
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
++
++  if (st1->size != st2->size) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++    return res;
 +  }
-+  if (st1->size != st2->size) return -1;
-+  return memcmp(st1->buf, st2->buf, st1->size);
++  if (0 != memcmp(st1->buf, st2->buf, st1->size)) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++    return res;
++  }
++  return NULL;
 +}
---- ./skeletons/NativeReal.h	2015-12-03 09:43:33.971009150 +0100
-+++ ./skeletons/NativeReal.h	2015-11-26 14:31:12.631617407 +0100
+--- skeletons/NativeReal.h	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/NativeReal.h	2015-11-26 14:31:12.631617000 +0100
 @@ -29,6 +29,7 @@
  per_type_encoder_f NativeReal_encode_uper;
  per_type_decoder_f NativeReal_decode_aper;
@@ -763,8 +981,8 @@
  
  #ifdef __cplusplus
  }
---- ./skeletons/NULL.c	2015-12-03 09:43:33.963009150 +0100
-+++ ./skeletons/NULL.c	2015-11-30 13:18:53.047264114 +0100
+--- skeletons/NULL.c	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/NULL.c	2015-12-07 10:49:05.178647000 +0100
 @@ -26,7 +26,8 @@
  	NULL_decode_uper,	/* Unaligned PER decoder */
  	NULL_encode_uper,	/* Unaligned PER encoder */
@@ -780,14 +998,14 @@
  	_ASN_ENCODED_OK(er);
  }
 +
-+long
++asn_comp_rval_t *
 +NULL_compare(asn_TYPE_descriptor_t *td1, void *sptr1,
 +             asn_TYPE_descriptor_t *td2, void *sptr2) {
 +
-+  return 0;
++  return NULL;
 +}
---- ./skeletons/NULL.h	2015-12-03 09:43:33.963009150 +0100
-+++ ./skeletons/NULL.h	2015-11-26 14:53:03.875616050 +0100
+--- skeletons/NULL.h	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/NULL.h	2015-11-26 14:53:03.875616000 +0100
 @@ -27,6 +27,7 @@
  per_type_encoder_f NULL_encode_uper;
  per_type_decoder_f NULL_decode_aper;
@@ -796,8 +1014,8 @@
  
  #ifdef __cplusplus
  }
---- ./skeletons/NumericString.c	2015-12-03 09:43:33.963009150 +0100
-+++ ./skeletons/NumericString.c	2015-11-26 14:40:39.407616820 +0100
+--- skeletons/NumericString.c	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/NumericString.c	2015-11-26 14:40:39.407616000 +0100
 @@ -50,7 +50,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -808,8 +1026,8 @@
  	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
+--- skeletons/ObjectDescriptor.c	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/ObjectDescriptor.c	2015-11-26 14:55:46.227615000 +0100
 @@ -25,7 +25,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -820,8 +1038,8 @@
  	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
+--- skeletons/OBJECT_IDENTIFIER.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/OBJECT_IDENTIFIER.c	2015-11-26 14:55:13.311615000 +0100
 @@ -28,7 +28,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -832,8 +1050,8 @@
  	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
+--- skeletons/OCTET_STRING.c	2015-12-08 14:39:44.554543521 +0100
++++ skeletons/OCTET_STRING.c	2015-12-08 10:41:42.838558000 +0100
 @@ -37,7 +37,8 @@
  	OCTET_STRING_decode_uper,	/* Unaligned PER decoder */
  	OCTET_STRING_encode_uper,	/* Unaligned PER encoder */
@@ -844,30 +1062,39 @@
  	0, /* Use generic outmost tag fetcher */
  	asn_DEF_OCTET_STRING_tags,
  	sizeof(asn_DEF_OCTET_STRING_tags)
-@@ -2160,3 +2161,21 @@
+@@ -2160,3 +2161,30 @@
  	return st;
  }
  
-+long
++asn_comp_rval_t *
 +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;
++  asn_comp_rval_t *res = NULL;
 +
-+  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;
-+      }
-+    }
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
++
++  if (st1->size != st2->size) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++    return res;
++  }
++  if (0 != memcmp(st1->buf, st2->buf, st1->size)) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++    return res;
 +  }
-+  if (st1->size != st2->size) return -1;
-+  return memcmp(st1->buf, st2->buf, st1->size);
++  return NULL;
 +}
---- ./skeletons/OCTET_STRING.h	2015-12-03 09:43:33.971009150 +0100
-+++ ./skeletons/OCTET_STRING.h	2015-11-26 12:56:15.259623305 +0100
+--- skeletons/OCTET_STRING.h	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/OCTET_STRING.h	2015-11-26 12:56:15.259623000 +0100
 @@ -34,6 +34,7 @@
  per_type_encoder_f OCTET_STRING_encode_uper;
  per_type_decoder_f OCTET_STRING_decode_aper;
@@ -876,8 +1103,8 @@
  
  /******************************
   * 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
+--- skeletons/PrintableString.c	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/PrintableString.c	2015-11-26 14:56:09.787615000 +0100
 @@ -60,7 +60,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -888,8 +1115,8 @@
  	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
+--- skeletons/REAL.c	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/REAL.c	2015-12-08 10:41:55.178558000 +0100
 @@ -46,7 +46,8 @@
  	REAL_decode_uper,
  	REAL_encode_uper,
@@ -900,32 +1127,41 @@
  	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 @@
+@@ -741,3 +742,32 @@
  
  	return 0;
  }
 +
 +
-+long
++asn_comp_rval_t *
 +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;
++  asn_comp_rval_t *res = NULL;
 +
-+  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;
-+      }
-+    }
++  COMPARE_CHECK_ARGS(td1, td2, sptr1, sptr2, res)
++
++  if (st1->size != st2->size) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++    return res;
++  }
++  if (0 != memcmp(st1->buf, st2->buf, st1->size)) {
++    res = calloc(1, sizeof(asn_comp_rval_t));
++    res->name = td1->name;
++    res->structure1 = sptr1;
++    res->structure2 = sptr2;
++    res->err_code = COMPARE_ERR_CODE_NO_MATCH;
++    return res;
 +  }
-+  if (st1->size != st2->size) return -1;
-+  return memcmp(st1->buf, st2->buf, st1->size);
++  return NULL;
 +}
---- ./skeletons/REAL.h	2015-12-03 09:43:33.971009150 +0100
-+++ ./skeletons/REAL.h	2015-11-26 13:00:46.183623025 +0100
+--- skeletons/REAL.h	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/REAL.h	2015-11-26 13:00:46.183623000 +0100
 @@ -23,6 +23,7 @@
  per_type_encoder_f REAL_encode_uper;
  per_type_decoder_f REAL_decode_aper;
@@ -934,8 +1170,8 @@
  
  /***********************************
   * 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
+--- skeletons/RELATIVE-OID.c	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/RELATIVE-OID.c	2015-11-26 14:56:31.703615000 +0100
 @@ -29,7 +29,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -946,8 +1182,8 @@
  	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
+--- skeletons/T61String.c	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/T61String.c	2015-11-26 14:57:07.235615000 +0100
 @@ -25,7 +25,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -958,8 +1194,8 @@
  	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
+--- skeletons/TeletexString.c	2015-12-08 14:39:33.338543533 +0100
++++ skeletons/TeletexString.c	2015-11-26 14:57:17.643615000 +0100
 @@ -25,7 +25,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -970,8 +1206,8 @@
  	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
+--- skeletons/UniversalString.c	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/UniversalString.c	2015-11-26 14:57:29.015615000 +0100
 @@ -36,7 +36,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -982,8 +1218,8 @@
  	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
+--- skeletons/UTCTime.c	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/UTCTime.c	2015-11-26 14:57:44.127615000 +0100
 @@ -41,7 +41,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
@@ -994,8 +1230,8 @@
  	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
+--- skeletons/UTF8String.c	2015-12-08 14:39:33.314543533 +0100
++++ skeletons/UTF8String.c	2015-11-26 14:06:54.563618000 +0100
 @@ -27,6 +27,7 @@
  	OCTET_STRING_encode_uper,
  	OCTET_STRING_decode_aper,
@@ -1004,8 +1240,8 @@
  	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
+--- skeletons/VideotexString.c	2015-12-08 14:39:33.342543533 +0100
++++ skeletons/VideotexString.c	2015-11-26 14:07:06.139618000 +0100
 @@ -25,7 +25,8 @@
  	OCTET_STRING_decode_uper,    /* Implemented in terms of OCTET STRING */
  	OCTET_STRING_encode_uper,
@@ -1016,8 +1252,8 @@
  	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
+--- skeletons/VisibleString.c	2015-12-08 14:39:33.350543533 +0100
++++ skeletons/VisibleString.c	2015-11-26 14:07:15.283618000 +0100
 @@ -30,7 +30,8 @@
  	OCTET_STRING_decode_uper,
  	OCTET_STRING_encode_uper,
diff --git a/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py b/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py
index f5daf03c254..446266d6a37 100644
--- a/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py
+++ b/openair3/S1AP/MESSAGES/ASN1/asn1tostruct.py
@@ -36,7 +36,7 @@ def outputHeaderToFile(f, filename):
     f.write("""/*******************************************************************************
 
   Eurecom OpenAirInterface
-  Copyright(c) 1999 - 2013 Eurecom
+  Copyright(c) 1999 - 2015 Eurecom
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -267,7 +267,7 @@ for key in iesDefs:
     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("asn_comp_rval_t *  %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))))
 
@@ -311,7 +311,7 @@ for key in iesDefs:
     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("asn_comp_rval_t *  %s_compare_%s(\n" % (fileprefix, firstlower.lower()))
     f.write("    %sIEs_t *%s1,\n"    % (asn1cStruct, firstlower))
     f.write("    %sIEs_t *%s2);\n\n" % (asn1cStruct, firstlower))
 
@@ -761,11 +761,12 @@ for key in iesDefs:
     if len(iesDefs[key]["ies"]) == 0:
         continue
 
-    f.write("long %s_compare_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower())))
+    f.write("asn_comp_rval_t * %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("    asn_comp_rval_t *rv = NULL;\n\n")
+    f.write("    asn_comp_rval_t *rv2 = NULL;\n\n")
 
     f.write("    assert(%s1 != NULL);\n" % (lowerFirstCamelWord(re.sub('-', '_', key))));
     f.write("    assert(%s2 != NULL);\n" % (lowerFirstCamelWord(re.sub('-', '_', key))));
@@ -784,7 +785,7 @@ for key in iesDefs:
             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))))
+                f.write("    if (%s1->presenceMask != %s2->presenceMask) {rv=calloc(1,sizeof(asn_comp_rval_t));rv->name = asn_DEF_%s.name;rv->structure1 = %s1;rv->structure2 = %s2;rv->err_code = COMPARE_ERR_CODE_VALUE_NULL; return rv;}\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), lowerFirstCamelWord(re.sub('-', '_', key)), ietypeunderscore, lowerFirstCamelWord(re.sub('-', '_', key)), lowerFirstCamelWord(re.sub('-', '_', key))))
 
             if ie[3] == "optional":
                 f.write("    /* Optional field */\n")
@@ -795,25 +796,61 @@ for key in iesDefs:
 
             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))
+                f.write("        rv2 = %s_compare_%s(&%s1->%s, &%s2->%s);\n" % (fileprefix, ietypeunderscore.lower(), lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower ))
+                f.write("        if(rv2) {")
+                f.write("          if (NULL == rv) {")
+                f.write("            rv = rv2;")
+                f.write("          } else {")
+                f.write("            rv2->next = rv;")
+                f.write("            rv = rv2;")
+                f.write("          }")
+                f.write("          rv2 = NULL;")
+                f.write("        }")
             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("        rv2 = 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 (rv2) {")
+                f.write("          if (NULL == rv) {")
+                f.write("            rv = rv2;")
+                f.write("          } else {")
+                f.write("            rv2->next = rv;")
+                f.write("            rv = rv2;")
+                f.write("          }")
+                f.write("          rv2 = NULL;")
+                f.write("          if (!rv->name) rv->name = asn_DEF_%s.name;" % (ietypeunderscore))
+                f.write("        }")
+
             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))
+                f.write("    rv2 = %s_compare_%s(&%s1->%s, &%s2->%s);\n" % (fileprefix, ietypeunderscore.lower(), lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower ))
+                f.write("    if (rv2) {\n")
+                f.write("      if (NULL == rv) {\n")
+                f.write("        rv = rv2;\n")
+                f.write("      } else {\n")
+                f.write("        rv2->next = rv;\n")
+                f.write("        rv = rv2;\n")
+                f.write("      }\n")
+                f.write("      rv2 = NULL;\n")
+                f.write("    }\n")
+
             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("    rv2 = 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(rv2) {\n")
+                f.write("      if (NULL == rv) {\n")
+                f.write("        rv = rv2;\n")
+                f.write("      } else {\n")
+                f.write("        rv2->next = rv;\n")
+                f.write("        rv = rv2;\n")
+                f.write("      }\n")
+                f.write("      rv2 = NULL;\n")
+                f.write("      if (!rv->name) rv->name = asn_DEF_%s.name;\n" % (ietypeunderscore))
+                f.write("    }\n")
+    f.write("    return rv;\n")
     f.write("}\n\n")
 
 for (key, value) in iesDefs.items():
@@ -832,19 +869,29 @@ for (key, value) in iesDefs.items():
 
     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("asn_comp_rval_t * %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("    asn_comp_rval_t *rv = NULL;\n\n")
+    f.write("    asn_comp_rval_t *rv2 = NULL;\n\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("        rv2 = 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(rv2) {")
+    f.write("          if (NULL == rv) {")
+    f.write("            rv = rv2;")
+    f.write("          } else {")
+    f.write("            rv2->next = rv;")
+    f.write("            rv = rv2;")
+    f.write("          }")
+    f.write("          rv2 = NULL;")
+    f.write("        }")
     f.write("    }\n")
-    f.write("    return 0;\n")
+    f.write("    return rv;\n")
     f.write("}\n\n")
 
diff --git a/openair3/TEST/EPC_TEST/play_scenario.c b/openair3/TEST/EPC_TEST/play_scenario.c
index 1aab2164282..133e9adf4bc 100644
--- a/openair3/TEST/EPC_TEST/play_scenario.c
+++ b/openair3/TEST/EPC_TEST/play_scenario.c
@@ -286,14 +286,26 @@ const char * const et_chunk_type_cid2str(const sctp_cid_t chunk_type)
 const char * const et_error_match2str(const int err)
 {
   switch (err) {
-    case  -ET_ERROR_MATCH_PACKET_SCTP_CHUNK_TYPE:       return "SCTP_CHUNK_TYPE"; break;
-    case  -ET_ERROR_MATCH_PACKET_SCTP_PPID:             return "SCTP_PPID"; break;
-    case  -ET_ERROR_MATCH_PACKET_SCTP_ASSOC_ID:         return "SCTP_ASSOC_ID"; break;
-    case  -ET_ERROR_MATCH_PACKET_SCTP_STREAM_ID:        return "SCTP_STREAM_ID"; break;
-    case  -ET_ERROR_MATCH_PACKET_SCTP_SSN:              return "SCTP_SSN"; break;
-    case  -ET_ERROR_MATCH_PACKET_S1AP_PRESENT:          return "S1AP_PRESENT"; break;
-    case  -ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE:   return "S1AP_PROCEDURE_CODE"; break;
-    case  -ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY:      return "S1AP_CRITICALITY"; break;
+    // from asn_compare.h
+    case  COMPARE_ERR_CODE_NO_MATCH:                   return "CODE_NO_MATCH"; break;
+    case  COMPARE_ERR_CODE_TYPE_MISMATCH:              return "TYPE_MISMATCH"; break;
+    case  COMPARE_ERR_CODE_TYPE_ARG_NULL:              return "TYPE_ARG_NULL"; break;
+    case  COMPARE_ERR_CODE_VALUE_NULL:                 return "VALUE_NULL"; break;
+    case  COMPARE_ERR_CODE_VALUE_ARG_NULL:             return "VALUE_ARG_NULL"; break;
+    case  COMPARE_ERR_CODE_CHOICE_NUM:                 return "CHOICE_NUM"; break;
+    case  COMPARE_ERR_CODE_CHOICE_PRESENT:             return "CHOICE_PRESENT"; break;
+    case  COMPARE_ERR_CODE_CHOICE_MALFORMED:           return "CHOICE_MALFORMED"; break;
+    case  COMPARE_ERR_CODE_SET_MALFORMED:              return "SET_MALFORMED"; break;
+    case  COMPARE_ERR_CODE_COLLECTION_NUM_ELEMENTS:    return "COLLECTION_NUM_ELEMENTS"; break;
+    // from play_scenario.h
+    case  ET_ERROR_MATCH_PACKET_SCTP_CHUNK_TYPE:       return "SCTP_CHUNK_TYPE"; break;
+    case  ET_ERROR_MATCH_PACKET_SCTP_PPID:             return "SCTP_PPID"; break;
+    case  ET_ERROR_MATCH_PACKET_SCTP_ASSOC_ID:         return "SCTP_ASSOC_ID"; break;
+    case  ET_ERROR_MATCH_PACKET_SCTP_STREAM_ID:        return "SCTP_STREAM_ID"; break;
+    case  ET_ERROR_MATCH_PACKET_SCTP_SSN:              return "SCTP_SSN"; break;
+    case  ET_ERROR_MATCH_PACKET_S1AP_PRESENT:          return "S1AP_PRESENT"; break;
+    case  ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE:   return "S1AP_PROCEDURE_CODE"; break;
+    case  ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY:      return "S1AP_CRITICALITY"; break;
     default:
       AssertFatal (0, "ERROR: Unknown match error %d!(TODO handle an1c error codes)\n", err);
   }
@@ -792,9 +804,9 @@ static void et_usage (
   fprintf (stdout, "Please report any bug to: %s\n",PACKAGE_BUGREPORT);
   fprintf (stdout, "Usage: %s [options]\n\n", argv[0]);
   fprintf (stdout, "\n");
-  fprintf (stdout, "Client options:\n");
-  fprintf (stdout, "\t-S | --server         <server network @>  File name (with no path) of a test scenario that has to be replayed (TODO in future?)\n");
-  fprintf (stdout, "Server options:\n");
+  //fprintf (stdout, "Client options:\n");
+  //fprintf (stdout, "\t-S | --server         <server network @>  File name (with no path) of a test scenario that has to be replayed (TODO in future?)\n");
+  //fprintf (stdout, "Server options:\n");
   fprintf (stdout, "\t-d | --test-dir       <dir>               Directory where a set of files related to a particular test are located\n");
   fprintf (stdout, "\t-c | --enb-conf-file  <file>              Provide an eNB config file, valid for the testbed\n");
   fprintf (stdout, "\t-s | --scenario       <file>              File name (with no path) of a test scenario that has to be replayed ()\n");
diff --git a/openair3/TEST/EPC_TEST/play_scenario.h b/openair3/TEST/EPC_TEST/play_scenario.h
index a926ea55e49..f44974dae01 100644
--- a/openair3/TEST/EPC_TEST/play_scenario.h
+++ b/openair3/TEST/EPC_TEST/play_scenario.h
@@ -46,6 +46,7 @@
 #include "s1ap_ies_defs.h"
 #include "play_scenario_s1ap_eNB_defs.h"
 #include "hashtable.h"
+#include "asn_compare.h"
 
 // powers of 2
 #define ET_BIT_MASK_MATCH_SCTP_STREAM 1
@@ -179,8 +180,10 @@ typedef enum {
   ET_FSM_STATE_END
 } et_fsm_state_t;
 
+enum COMPARE_ERR_CODE_e;
+
 typedef enum {
-  ET_ERROR_MATCH_START = 1,
+  ET_ERROR_MATCH_START = COMPARE_ERR_CODE_END,
   ET_ERROR_MATCH_PACKET_SCTP_CHUNK_TYPE = ET_ERROR_MATCH_START,
   ET_ERROR_MATCH_PACKET_SCTP_PPID,
   ET_ERROR_MATCH_PACKET_SCTP_ASSOC_ID,
@@ -415,7 +418,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);
-long et_s1ap_is_matching(et_s1ap_t * const s1ap1, et_s1ap_t * const s1ap2, const uint32_t constraints);
+int et_handle_s1ap_mismatch(et_packet_t * const spacket, et_packet_t * const rx_packet);
+asn_comp_rval_t* 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);
 int et_scenario_set_packet_received(et_packet_t * const packet);
 int  et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const sctp_data_ind);
@@ -451,10 +455,10 @@ 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 );
 //-------------------------
-long et_s1ap_ies_is_matching(const S1AP_PDU_PR present, s1ap_message * const m1, s1ap_message * const m2, const uint32_t constraints);
+asn_comp_rval_t * et_s1ap_ies_is_matching(const S1AP_PDU_PR present, s1ap_message * const m1, s1ap_message * const m2, const uint32_t constraints);
 //-------------------------
-long et_sctp_data_is_matching(sctp_datahdr_t * const sctp1, sctp_datahdr_t * const sctp2, const uint32_t constraints);
-long et_sctp_is_matching(et_sctp_hdr_t * const sctp1, et_sctp_hdr_t * const sctp2, const uint32_t constraints);
+asn_comp_rval_t * et_sctp_data_is_matching(sctp_datahdr_t * const sctp1, sctp_datahdr_t * const sctp2, const uint32_t constraints);
+asn_comp_rval_t * 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);
diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
index df26de97c2d..d58b16c2d35 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
@@ -189,30 +189,363 @@ 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);
 }
 //------------------------------------------------------------------------------
-long et_s1ap_is_matching(et_s1ap_t * const s1ap1, et_s1ap_t * const s1ap2, const uint32_t constraints)
+int et_handle_s1ap_mismatch(et_packet_t * const spacket, et_packet_t * const rx_packet)
 {
-  if (s1ap1->pdu.present != s1ap2->pdu.present)     return -ET_ERROR_MATCH_PACKET_S1AP_PRESENT;
+  S1ap_MME_UE_S1AP_ID_t scenario_mme_ue_s1ap_id = 0;
+  S1ap_MME_UE_S1AP_ID_t rx_mme_ue_s1ap_id       = 0;
+  S1AP_PDU_PR           present;
+
+  present = rx_packet->sctp_hdr.u.data_hdr.payload.pdu.present;
+
+  switch (rx_packet->sctp_hdr.u.data_hdr.payload.message.procedureCode) {
+    case  S1ap_ProcedureCode_id_HandoverPreparation:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequiredIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequiredIEs.mme_ue_s1ap_id;
+      } else {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverCommandIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverCommandIEs.mme_ue_s1ap_id;
+      }
+      break;
+
+    case  S1ap_ProcedureCode_id_HandoverResourceAllocation:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequestIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequestIEs.mme_ue_s1ap_id;
+      } else if (present == S1AP_PDU_PR_successfulOutcome) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequestAcknowledgeIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequestAcknowledgeIEs.mme_ue_s1ap_id;
+      } else if (present == S1AP_PDU_PR_unsuccessfulOutcome) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverFailureIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverFailureIEs.mme_ue_s1ap_id;
+      }
+      break;
+
+    case  S1ap_ProcedureCode_id_HandoverNotification:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverNotifyIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverNotifyIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_PathSwitchRequest:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_PathSwitchRequestIEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_PathSwitchRequestIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_HandoverCancel:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverCancelIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverCancelIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_E_RABSetup:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABSetupRequestIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABSetupRequestIEs.mme_ue_s1ap_id;
+      } else  {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABSetupResponseIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABSetupResponseIEs.mme_ue_s1ap_id;
+      }
+      break;
+
+    case  S1ap_ProcedureCode_id_E_RABModify:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABModifyRequestIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABModifyRequestIEs.mme_ue_s1ap_id;
+      } else  {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABModifyResponseIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABModifyResponseIEs.mme_ue_s1ap_id;
+      }
+      break;
+
+    case  S1ap_ProcedureCode_id_E_RABRelease:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseCommandIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseCommandIEs.mme_ue_s1ap_id;
+      } else  {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseResponseIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseResponseIEs.mme_ue_s1ap_id;
+      }
+      break;
+
+    case  S1ap_ProcedureCode_id_E_RABReleaseIndication:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseIndicationIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseIndicationIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_InitialContextSetup:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialContextSetupRequestIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialContextSetupRequestIEs.mme_ue_s1ap_id;
+      } else  {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialContextSetupResponseIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialContextSetupResponseIEs.mme_ue_s1ap_id;
+      }
+      break;
+
+    case  S1ap_ProcedureCode_id_Paging:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_PagingIEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_PagingIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_downlinkNASTransport:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkNASTransportIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkNASTransportIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_initialUEMessage:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialUEMessageIEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialUEMessageIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_uplinkNASTransport:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkNASTransportIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkNASTransportIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_Reset:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ResetIEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ResetIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_ErrorIndication:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ErrorIndicationIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ErrorIndicationIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_NASNonDeliveryIndication:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_NASNonDeliveryIndication_IEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_NASNonDeliveryIndication_IEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_S1Setup:
+      /*if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupRequestIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupRequestIEs.mme_ue_s1ap_id;
+      } else if (present == S1AP_PDU_PR_successfulOutcome) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupResponseIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupResponseIEs.mme_ue_s1ap_id;
+      } else if (present == S1AP_PDU_PR_unsuccessfulOutcome) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupFailureIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupFailureIEs.mme_ue_s1ap_id;
+      }*/
+      break;
+
+    case  S1ap_ProcedureCode_id_UEContextReleaseRequest:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseRequestIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseRequestIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_DownlinkS1cdma2000tunneling:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkS1cdma2000tunnelingIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkS1cdma2000tunnelingIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_UplinkS1cdma2000tunneling:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkS1cdma2000tunnelingIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkS1cdma2000tunnelingIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_UEContextModification:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationRequestIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationRequestIEs.mme_ue_s1ap_id;
+      } else if (present == S1AP_PDU_PR_successfulOutcome) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationResponseIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationResponseIEs.mme_ue_s1ap_id;
+      } else if (present == S1AP_PDU_PR_unsuccessfulOutcome) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationFailureIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationFailureIEs.mme_ue_s1ap_id;
+      }
+      break;
+
+    case  S1ap_ProcedureCode_id_UECapabilityInfoIndication:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UECapabilityInfoIndicationIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UECapabilityInfoIndicationIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_UEContextRelease:
+      if (present == S1AP_PDU_PR_initiatingMessage) {
+        //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCommandIEs.mme_ue_s1ap_id;
+        //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCommandIEs.mme_ue_s1ap_id;
+      } else  {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCompleteIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCompleteIEs.mme_ue_s1ap_id;
+      }
+      break;
+
+    case  S1ap_ProcedureCode_id_eNBStatusTransfer:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBStatusTransferIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBStatusTransferIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_MMEStatusTransfer:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEStatusTransferIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEStatusTransferIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_DeactivateTrace:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DeactivateTraceIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DeactivateTraceIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_TraceStart:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_TraceStartIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_TraceStartIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_TraceFailureIndication:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_TraceFailureIndicationIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_TraceFailureIndicationIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_ENBConfigurationUpdate:
+      /*if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateIEs.mme_ue_s1ap_id;
+      } else if (present == S1AP_PDU_PR_successfulOutcome) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateAcknowledgeIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateAcknowledgeIEs.mme_ue_s1ap_id;
+      } else {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateFailureIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateFailureIEs.mme_ue_s1ap_id;
+      }*/
+      break;
+
+    case  S1ap_ProcedureCode_id_MMEConfigurationUpdate:
+      /*if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateIEs.mme_ue_s1ap_id;
+      } else if (present == S1AP_PDU_PR_successfulOutcome) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateAcknowledgeIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateAcknowledgeIEs.mme_ue_s1ap_id;
+      } else {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateFailureIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateFailureIEs.mme_ue_s1ap_id;
+      }*/
+      break;
+
+    case  S1ap_ProcedureCode_id_LocationReportingControl:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportingControlIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportingControlIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_LocationReportingFailureIndication:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportingFailureIndicationIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportingFailureIndicationIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_LocationReport:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_OverloadStart:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_OverloadStartIEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_OverloadStartIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_OverloadStop:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_OverloadStopIEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_OverloadStopIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_WriteReplaceWarning:
+      /*if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_WriteReplaceWarningRequestIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_WriteReplaceWarningRequestIEs.mme_ue_s1ap_id;
+      } else  {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_WriteReplaceWarningResponseIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_WriteReplaceWarningResponseIEs.mme_ue_s1ap_id;
+      }*/
+      break;
+
+    case  S1ap_ProcedureCode_id_eNBDirectInformationTransfer:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBDirectInformationTransferIEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBDirectInformationTransferIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_MMEDirectInformationTransfer:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEDirectInformationTransferIEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEDirectInformationTransferIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_PrivateMessage:
+    case  S1ap_ProcedureCode_id_eNBConfigurationTransfer:
+    case  S1ap_ProcedureCode_id_MMEConfigurationTransfer:
+      AssertFatal(0, "TODO");
+      break;
+
+    case  S1ap_ProcedureCode_id_CellTrafficTrace:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_CellTrafficTraceIEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_CellTrafficTraceIEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_Kill:
+      /*if (present == S1AP_PDU_PR_initiatingMessage) {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_KillRequestIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_KillRequestIEs.mme_ue_s1ap_id;
+      } else  {
+        rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_KillResponseIEs.mme_ue_s1ap_id;
+        scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_KillResponseIEs.mme_ue_s1ap_id;
+      }*/
+      break;
+
+    case  S1ap_ProcedureCode_id_downlinkUEAssociatedLPPaTransport:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_uplinkUEAssociatedLPPaTransport:
+      rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
+      scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_downlinkNonUEAssociatedLPPaTransport:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkNonUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkNonUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
+      break;
+
+    case  S1ap_ProcedureCode_id_uplinkNonUEAssociatedLPPaTransport:
+      //rx_mme_ue_s1ap_id       = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkNonUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
+      //scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkNonUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
+      break;
+
+    default:
+      AssertFatal(0, "Unknown procedure code %ld", rx_packet->sctp_hdr.u.data_hdr.payload.message.procedureCode);
+  }
+  return 0;
+}
+//------------------------------------------------------------------------------
+asn_comp_rval_t * et_s1ap_is_matching(et_s1ap_t * const s1ap1, et_s1ap_t * const s1ap2, const uint32_t constraints)
+{
+  asn_comp_rval_t *rv = NULL;
+  if (s1ap1->pdu.present != s1ap2->pdu.present)  {rv  = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_PRESENT; return rv;}
   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 -ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE;
-      if (s1ap1->pdu.choice.initiatingMessage.criticality != s1ap2->pdu.choice.initiatingMessage.criticality) return -ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY;
+      if (s1ap1->pdu.choice.initiatingMessage.procedureCode != s1ap2->pdu.choice.initiatingMessage.procedureCode)
+        {rv  = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE; return rv;}
+      if (s1ap1->pdu.choice.initiatingMessage.criticality != s1ap2->pdu.choice.initiatingMessage.criticality)
+        {rv  = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY; return rv;}
       break;
     case  S1AP_PDU_PR_successfulOutcome:
-      if (s1ap1->pdu.choice.successfulOutcome.procedureCode != s1ap2->pdu.choice.successfulOutcome.procedureCode) return -ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE;
-      if (s1ap1->pdu.choice.successfulOutcome.criticality != s1ap2->pdu.choice.successfulOutcome.criticality) return -ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY;
+      if (s1ap1->pdu.choice.successfulOutcome.procedureCode != s1ap2->pdu.choice.successfulOutcome.procedureCode)
+        {rv  = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE; return rv;}
+      if (s1ap1->pdu.choice.successfulOutcome.criticality != s1ap2->pdu.choice.successfulOutcome.criticality)
+        {rv  = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY; return rv;}
       break;
     case  S1AP_PDU_PR_unsuccessfulOutcome:
-      if (s1ap1->pdu.choice.unsuccessfulOutcome.procedureCode != s1ap2->pdu.choice.unsuccessfulOutcome.procedureCode) return -ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE;
-      if (s1ap1->pdu.choice.unsuccessfulOutcome.criticality != s1ap2->pdu.choice.unsuccessfulOutcome.criticality) return -ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY;
+      if (s1ap1->pdu.choice.unsuccessfulOutcome.procedureCode != s1ap2->pdu.choice.unsuccessfulOutcome.procedureCode)
+        {rv  = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE; return rv;}
+      if (s1ap1->pdu.choice.unsuccessfulOutcome.criticality != s1ap2->pdu.choice.unsuccessfulOutcome.criticality)
+        {rv  = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY; return rv;}
       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 (memcmp((void*)s1ap1->binary_stream, (void*)s1ap2->binary_stream, s1ap1->binary_stream_allocated_size) ==  0) return NULL;
   }
   // 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);
@@ -284,10 +617,12 @@ int et_scenario_set_packet_received(et_packet_t * const packet)
 //------------------------------------------------------------------------------
 int 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;
-  long              rv        = 0;
+  et_packet_t      *packet       = NULL;
+  et_packet_t      *rx_packet    = NULL;
+  unsigned long int not_found    = 1;
+  asn_comp_rval_t  *comp_results = NULL;
+  asn_comp_rval_t  *comp_results2 = NULL;
+  unsigned char     error_code   = 0;
 
   AssertFatal (NULL != s1ap_data_ind, "Bad parameter sctp_data_ind\n");
   rx_packet = et_build_packet_from_s1ap_data_ind(s1ap_data_ind);
@@ -317,20 +652,35 @@ int et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const s1ap_data_ind)
   // 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) {
-      rv = et_sctp_is_matching(&packet->sctp_hdr, &rx_packet->sctp_hdr, g_constraints);
-      if (0 == rv) {
+      comp_results = et_sctp_is_matching(&packet->sctp_hdr, &rx_packet->sctp_hdr, g_constraints);
+      if (NULL == comp_results) {
         S1AP_DEBUG("Compare RX packet with packet: num %u  | original frame number %u \n", packet->packet_number, packet->original_frame_number);
         packet->timestamp_packet.tv_sec = rx_packet->timestamp_packet.tv_sec;
         packet->timestamp_packet.tv_usec = rx_packet->timestamp_packet.tv_usec;
         return et_scenario_set_packet_received(packet);
       } else {
-        S1AP_DEBUG("Compare RX packet with packet: num %u  | original frame number %u failed:%s\n",
-            packet->packet_number, packet->original_frame_number, et_error_match2str(rv));
-        // asn1 compare no match return code, may not collide with non asn1 error return codes
-        // (each asn1 rc <= 166 (enum e_S1ap_ProtocolIE_ID, in generated file S1ap_ProtocolIE_ID.h))
-        if ((rv > 0) || (rv <= -ET_ERROR_MATCH_END)) {
-          //TODO MME_UE_S1AP_ID, etc.
-          AssertFatal(0,"Some work needed there");
+        S1AP_DEBUG("Compare RX packet with packet: num %u  | original frame number %u failed\n",
+          packet->packet_number, packet->original_frame_number);
+        while (comp_results) {
+          S1AP_DEBUG("Result err code %s(%u) ASN1 struct name %s\n",
+              et_error_match2str(comp_results->err_code), comp_results->err_code, comp_results->name);
+          // (each asn1 rc <= 166 (enum e_S1ap_ProtocolIE_ID, in generated file S1ap_ProtocolIE_ID.h))
+          if (comp_results->err_code == COMPARE_ERR_CODE_NO_MATCH) {
+            //TODO MME_UE_S1AP_ID, etc.
+            // get latest error code
+            if (strcmp(comp_results->name, "S1ap-MME-UE-S1AP-ID") == 0) {
+              if (0 == et_handle_s1ap_mismatch((et_packet_t *const)packet, (et_packet_t *const)rx_packet)) {
+                packet->timestamp_packet.tv_sec = rx_packet->timestamp_packet.tv_sec;
+                packet->timestamp_packet.tv_usec = rx_packet->timestamp_packet.tv_usec;
+                return et_scenario_set_packet_received(packet);
+              }
+            } else {
+              AssertFatal(0,"Some work needed there");
+            }
+          }
+          comp_results2 = comp_results;
+          comp_results = comp_results2->next;
+          et_free_pointer(comp_results2);
         }
       }
     }
diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c
index 5300476e982..213be2b3473 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c
@@ -58,9 +58,9 @@ extern et_scenario_t  *g_scenario;
 extern uint32_t        g_constraints;
 //------------------------------------------------------------------------------
 
-long et_s1ap_ies_is_matching(const S1AP_PDU_PR present, s1ap_message * const m1, s1ap_message * const m2, const uint32_t constraints)
+asn_comp_rval_t * 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;
+  asn_comp_rval_t *ret = NULL;
   AssertFatal(m1 != NULL, "bad parameter m1");
   AssertFatal(m2 != NULL, "bad parameter m2");
   AssertFatal((present == S1AP_PDU_PR_initiatingMessage) ||
@@ -401,6 +401,8 @@ long et_s1ap_ies_is_matching(const S1AP_PDU_PR present, s1ap_message * const m1,
     case  S1ap_ProcedureCode_id_PrivateMessage:
     case  S1ap_ProcedureCode_id_eNBConfigurationTransfer:
     case  S1ap_ProcedureCode_id_MMEConfigurationTransfer:
+      AssertFatal(0, "TODO");
+      break;
 
     case  S1ap_ProcedureCode_id_CellTrafficTrace:
       ret = s1ap_compare_s1ap_celltraffictraceies(
diff --git a/openair3/TEST/EPC_TEST/play_scenario_sctp.c b/openair3/TEST/EPC_TEST/play_scenario_sctp.c
index 07206f53b81..181009c2c9d 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_sctp.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_sctp.c
@@ -44,27 +44,36 @@
 #include "play_scenario.h"
 
 //------------------------------------------------------------------------------
-long et_sctp_data_is_matching(sctp_datahdr_t * const sctp1, sctp_datahdr_t * const sctp2, const uint32_t constraints)
+asn_comp_rval_t * et_sctp_data_is_matching(sctp_datahdr_t * const sctp1, sctp_datahdr_t * const sctp2, const uint32_t constraints)
 {
+  asn_comp_rval_t *rv = NULL;
   // no comparison for ports
   if (sctp1->ppid     != sctp2->ppid) {
     S1AP_WARN("No Matching SCTP PPID %u %u\n", sctp1->ppid, sctp2->ppid);
-    return -ET_ERROR_MATCH_PACKET_SCTP_PPID;
+    rv  = calloc(1, sizeof(asn_comp_rval_t));
+    rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_PPID;
+    return rv;
   }
   if (sctp1->assoc_id != sctp2->assoc_id) {
     S1AP_WARN("No Matching SCTP assoc id %u %u\n", sctp1->assoc_id, sctp2->assoc_id);
-    return -ET_ERROR_MATCH_PACKET_SCTP_ASSOC_ID;
+    rv  = calloc(1, sizeof(asn_comp_rval_t));
+    rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_ASSOC_ID;
+    return rv;
   }
   if (sctp1->stream != sctp2->stream) {
     if (constraints & ET_BIT_MASK_MATCH_SCTP_STREAM) {
-      return -ET_ERROR_MATCH_PACKET_SCTP_STREAM_ID;
+      rv  = calloc(1, sizeof(asn_comp_rval_t));
+      rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_STREAM_ID;
+      return rv;
     } 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 -ET_ERROR_MATCH_PACKET_SCTP_SSN;
+      rv  = calloc(1, sizeof(asn_comp_rval_t));
+      rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_SSN;
+      return rv;
     } else {
       S1AP_WARN("No Matching SCTP STREAM SN %u %u\n", sctp1->ssn, sctp2->ssn);
     }
@@ -73,10 +82,16 @@ long et_sctp_data_is_matching(sctp_datahdr_t * const sctp1, sctp_datahdr_t * con
 }
 
 //------------------------------------------------------------------------------
-long et_sctp_is_matching(et_sctp_hdr_t * const sctp1, et_sctp_hdr_t * const sctp2, const uint32_t constraints)
+asn_comp_rval_t *  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 -ET_ERROR_MATCH_PACKET_SCTP_CHUNK_TYPE;
+  asn_comp_rval_t *rv = NULL;
+  if (sctp1->chunk_type != sctp2->chunk_type){
+    S1AP_WARN("No Matching chunk_type %u %u\n", sctp1->chunk_type, sctp2->chunk_type);
+    rv  = calloc(1, sizeof(asn_comp_rval_t));
+    rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_CHUNK_TYPE;
+    return rv;
+  }
   switch (sctp1->chunk_type) {
     case SCTP_CID_DATA:
       return et_sctp_data_is_matching(&sctp1->u.data_hdr, &sctp2->u.data_hdr, constraints);
@@ -92,5 +107,5 @@ long et_sctp_is_matching(et_sctp_hdr_t * const sctp1, et_sctp_hdr_t * const sctp
       AssertFatal(0, "Not needed now cid %d", sctp1->chunk_type);
   }
 
-  return 0;
+  return NULL;
 }
-- 
GitLab