initial chekin of code received by Ericsson on 20170410
diff --git a/M3UA_CNL113537/src/M3UA_Emulation.ttcn b/M3UA_CNL113537/src/M3UA_Emulation.ttcn
new file mode 100644
index 0000000..7a4a7e9
--- /dev/null
+++ b/M3UA_CNL113537/src/M3UA_Emulation.ttcn
@@ -0,0 +1,1307 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// Copyright Test Competence Center (TCC) ETH 2009                           //
+//                                                                           //
+// The copyright to the computer  program(s) herein  is the property of TCC. //
+// The program(s) may be used and/or copied only with the written permission //
+// of TCC or in accordance with  the terms and conditions  stipulated in the //
+// agreement/contract under which the program(s) have been supplied          //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+//
+//  File:         M3UA_Emulation.ttcn
+//  Reference:    M3UA Protocol Emulation
+//  Rev:          R1B01
+//  Prodnr:       CNL 113 537
+//  Updated:      2009-01-06
+//  Contact:      http://ttcn.ericsson.se
+
+module M3UA_Emulation
+{
+
+modulepar
+{
+  boolean tsp_logVerbose := false;
+  float tsp_Timer := 2.0;                     // General timer used in M3UA emulation.
+  float tsp_ASPUP_Resend_Timer := 2.0;
+  float tsp_ASPAC_Resend_Timer := 2.0;
+  float tsp_Assoc_Restart_Timer := 60.0;
+  float tsp_Heartbeat_Timer := 30.0;
+  integer tsp_SCTP_PayloadProtocolID := 3;    // 3 for M3UA.
+  boolean tsp_Enable_M3UA_Heartbeat := false; // Send SCTP packets periodically.
+  boolean tsp_SCTP_Server_Mode := false;
+  boolean tsp_M3UA_Server_Mode := false;
+}
+
+import from General_Types all;
+import from M3UA_Types all;
+import from SCTPasp_Types all;
+import from SCTPasp_PortType all;
+import from MTP3asp_Types all;
+
+type record of ASP_MTP3_TRANSFERreq TRANSFERreq_Buffer;
+
+type record SCTP_Association_Address
+{
+  integer local_sctp_port,
+  charstring local_ip_addr,
+  integer remote_sctp_port,
+  charstring remote_ip_addr
+}
+
+// Definition of M3UA_Entity which contains M3UA entity data.
+type record M3UA_Entity
+{
+  M3UA_CommStatus commStatus optional,
+  integer sCTP_Assoc_ID optional,
+  SCTP_Association_Address assoc
+}
+
+// Type for status of SCTP communication for an M3UA entity.
+type enumerated M3UA_CommStatus
+{
+  aSP_Down_initial_State (0),
+  aSP_Down_sCTP_Initialize_Done (1),
+  aSP_Down_sCTP_Associate_done (2),
+  aSP_Down_commUP_Received (3),
+  aSP_Down_ASPUP_Sent (4),
+  aSP_Inactive (5),
+  aSP_Inact_ASPAC_Sent (6),
+  aSP_Active (7) // aSPAC_Ack_Received
+}
+
+// We need an internal port to communicate with the MTP3 side.
+// internal in name
+type port MTP3asp_SP_PT_Int message
+{
+  in ASP_MTP3_TRANSFERreq;
+  out ASP_MTP3_TRANSFERind;
+  // out ASP_MTP3_PAUSE;
+  // out ASP_MTP3_RESUME;
+  // out ASP_MTP3_STATUS;  
+} with {
+  extension "internal"
+}
+
+// M3UA emulation component.
+type component M3UA_CT
+{
+  var M3UA_Entity v_Entity;
+  var TRANSFERreq_Buffer v_TRANSFERreq_Buffer := {};
+
+  var ASP_SCTP v_ASP_SCTP;
+  var ASP_SCTP_SEND_FAILED v_ASP_SCTP_SEND_FAILED;
+  var ASP_SCTP_RESULT v_ASP_SCTP_RESULT;
+  var ASP_SCTP_Connected v_ASP_SCTP_Connected;
+  var ASP_SCTP_ASSOC_CHANGE v_ASP_SCTP_ASSOC_CHANGE;
+  var ASP_SCTP_SHUTDOWN_EVENT v_ASP_SCTP_SHUTDOWN_EVENT;
+
+  var PDU_M3UA v_PDU_M3UA;
+
+  // Component timers.
+  timer T_Timer := tsp_Timer;
+  timer T_ASPUP_resend := tsp_ASPUP_Resend_Timer;
+  timer T_ASPAC_resend := tsp_ASPAC_Resend_Timer;
+  timer T_Heartbeat := tsp_Heartbeat_Timer;
+  timer T_Assoc_restart := tsp_Assoc_Restart_Timer;
+  
+  // Port declarations.
+  port MTP3asp_SP_PT_Int MTP3_SP_PORT; // Port towards MTP3/M3UA.
+  port SCTPasp_PT SCTP_PORT;           // Port towards target through SCTP.
+}
+
+//********************************
+// Start of SCTP related templates
+//********************************
+template ASP_SCTP t_S_SCTP_Send
+  (in template integer pl_associationID,
+   in template integer pl_streamID,
+   in template octetstring pl_userData,
+   in template integer pl_protocolID) :=
+{
+  client_id := pl_associationID,
+  sinfo_stream := pl_streamID,
+  sinfo_ppid := pl_protocolID,
+  data := pl_userData
+}
+
+template ASP_SCTP_SEND_FAILED t_ASP_SCTP_SEND_FAILED
+  (in template integer pl_streamID) :=
+{
+  client_id := pl_streamID
+}
+
+template ASP_SCTP_Listen t_ASP_SCTP_Listen
+  (template charstring pl_local_hostname,
+   template integer pl_local_portnumber) :=
+{
+  local_hostname := pl_local_hostname,
+  local_portnumber := pl_local_portnumber
+}
+
+template ASP_SCTP_Connected tr_ASP_SCTP_Connected
+  (template integer pl_client_id,
+   template charstring pl_local_hostname,
+   template integer pl_local_portnumber,
+   template charstring pl_peer_hostname,
+   template integer pl_peer_portnumber) :=
+{
+  client_id := pl_client_id,
+  local_hostname := pl_local_hostname,
+  local_portnumber := pl_local_portnumber,
+  peer_hostname := pl_peer_hostname,
+  peer_portnumber := pl_peer_portnumber
+}
+
+template ASP_SCTP_ConnectFrom t_ASP_SCTP_ConnectFrom
+  (template charstring pl_local_hostname,
+   template integer pl_local_portnumber,
+   template charstring pl_peer_hostname,
+   template integer pl_peer_portnumber) :=
+{
+  local_hostname := pl_local_hostname,
+  local_portnumber := pl_local_portnumber,
+  peer_hostname := pl_peer_hostname,
+  peer_portnumber := pl_peer_portnumber
+}
+
+template ASP_SCTP_RESULT t_ASP_SCTP_RESULT
+  (template integer pl_client_id,
+   template boolean pl_error_status,
+   template charstring pl_error_message) :=
+{
+  client_id := pl_client_id,
+  error_status := pl_error_status,
+  error_message := pl_error_message
+}
+
+template ASP_SCTP_ASSOC_CHANGE tr_S_SCTP_CommunicationUp
+  (in template integer pl_associationID) :=
+{
+  client_id := pl_associationID,
+  sac_state := SCTP_COMM_UP
+}
+
+template ASP_SCTP_ASSOC_CHANGE tr_S_SCTP_CommunicationLost
+  (in template integer pl_associationID) :=
+{
+  client_id := pl_associationID,
+  sac_state := SCTP_COMM_LOST
+}
+
+template ASP_SCTP_ASSOC_CHANGE tr_S_SCTP_ShutdownComplete
+  (in template integer pl_associationID) :=
+{
+  client_id := pl_associationID,
+  sac_state := SCTP_SHUTDOWN_COMP
+}
+
+template ASP_SCTP_SHUTDOWN_EVENT tr_S_SCTP_ShutdownEvent
+  (in template integer pl_associationID) :=
+{
+  client_id := pl_associationID
+}
+
+template ASP_SCTP_ASSOC_CHANGE tr_S_SCTP_Restart
+  (in template integer pl_associationID) :=
+{
+  client_id := pl_associationID,
+  sac_state := SCTP_RESTART
+}
+
+template ASP_SCTP_ASSOC_CHANGE tr_S_SCTP_CANT_STR_ASSOC
+  (in template integer pl_associationID) :=
+{
+  client_id := pl_associationID,
+  sac_state := SCTP_CANT_STR_ASSOC
+}
+
+template ASP_SCTP tr_S_SCTP_DataArrive
+  (in template integer pl_associationID,
+   in template integer pl_streamID,
+   in template integer pl_protocolID,
+   in template PDU_SCTP pl_data) :=
+{
+  client_id := pl_associationID,
+  sinfo_stream := pl_streamID,
+  sinfo_ppid := pl_protocolID,
+  data := pl_data
+}
+
+template ASP_SCTP_Close t_ASP_SCTP_Close
+  (in template integer pl_associationID) :=
+{
+  client_id := pl_associationID
+}
+//******************************
+// End of SCTP related templates
+//******************************
+
+//*****************************
+// Start of M3UA PDU templates.
+//*****************************
+template PDU_M3UA t_PDU_M3UA_ASPUP
+  (in template M3UA_ASP_Identifier pl_aSP_Identifier,
+   in template M3UA_Info_String pl_info_String) :=
+{
+  m3UA_ASPUP := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0301'O,
+    messageLength := 0,
+    messageParameters := {
+      aSP_Identifier := pl_aSP_Identifier,
+      info_String := pl_info_String
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_ASPUP_Ack :=
+{
+  m3UA_ASPUP_Ack := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0304'O,
+    messageLength := 0,
+    messageParameters := {
+      info_String := omit
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_ASPDN :=
+{
+  m3UA_ASPDN := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0302'O,
+    messageLength := 0,
+    messageParameters := {
+      info_String := omit
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_ASPDN_Ack :=
+{
+  m3UA_ASPDN_Ack := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0305'O,
+    messageLength := 0,
+    messageParameters := {
+      info_String := omit
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_ASPAC
+  (in template M3UA_Traffic_Mode_Type pl_traffic_Mode_Type,
+   in template M3UA_Routing_Context pl_routing_Context,
+   in template M3UA_Info_String pl_info_String) :=
+{
+  m3UA_ASPAC := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0401'O,
+    messageLength := 0,
+    messageParameters := {
+      traffic_Mode_Type := pl_traffic_Mode_Type,
+      routing_Context := pl_routing_Context,
+      info_String := pl_info_String
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_ASPAC_Ack
+  (in template M3UA_Traffic_Mode_Type pl_traffic_mode_type,
+   in template M3UA_Routing_Context pl_routing_Context) :=
+{
+  m3UA_ASPAC_Ack := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0403'O,
+    messageLength := 0,
+    messageParameters := {
+      traffic_Mode_Type := pl_traffic_mode_type,
+      routing_Context := pl_routing_Context,
+      info_String := omit
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_ASPIA
+  (in template M3UA_Routing_Context pl_routing_Context,
+   in template M3UA_Info_String pl_info_String) :=
+{
+  m3UA_ASPIA := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0402'O,
+    messageLength := 0,
+    messageParameters := {
+      routing_Context := pl_routing_Context,
+      info_String := pl_info_String
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_ASPIA_Ack
+  (in template M3UA_Routing_Context pl_routing_Context) :=
+{
+  m3UA_ASPIA_Ack := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0404'O,
+    messageLength := 0,
+    messageParameters := {
+      routing_Context := pl_routing_Context,
+      info_String := omit
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_Heartbeat
+  (in template M3UA_Heartbeat_Data pl_heartbeat_Data) :=
+{
+  m3UA_BEAT := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0303'O,
+    messageLength := 0,
+    messageParameters := {
+      heartbeat_Data := pl_heartbeat_Data
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_Beat_Ack
+  (in template M3UA_Heartbeat_Data pl_heartbeat_Data) :=
+{
+  m3UA_BEAT_Ack := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0306'O,
+    messageLength := 0,
+    messageParameters := {
+      heartbeat_Data := pl_heartbeat_Data
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_DATA
+  (in template M3UA_Network_Appearance pl_network_Appearance,
+   in template M3UA_Routing_Context pl_routing_Context,
+   in template M3UA_Protocol_Data pl_protocol_Data,
+   in template M3UA_Correlation_ID pl_correlation_ID) :=
+{
+  m3UA_DATA := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0101'O,
+    messageLength := 0,
+    messageParameters := {
+      network_Appearance := pl_network_Appearance,
+      routing_Context := pl_routing_Context,
+      protocol_Data := pl_protocol_Data,
+      correlation_ID := pl_correlation_ID
+    }
+  }
+}
+
+template PDU_M3UA t_PDU_M3UA_DAVA
+  (in template M3UA_Network_Appearance pl_network_Appearance,
+   in template M3UA_Routing_Context pl_routing_Context,
+   in template M3UA_Affected_Point_Codes pl_affected_Point_Codes,
+   in template M3UA_Info_String pl_info_String) :=
+{
+  m3UA_DAVA := {
+    version := '01'O,
+    reserved := '00'O,
+    messageClassAndType := '0202'O,
+    messageLength := 0,
+    messageParameters := {
+      network_Appearance := pl_network_Appearance,
+      routing_Context := pl_routing_Context,
+      affected_Point_Codes := pl_affected_Point_Codes,
+      info_String := pl_info_String
+    }    
+  }
+}
+//**************************
+// End of M3UA PDU templates
+//**************************
+
+//**********************************
+// Start of M3UA parameter templates
+//**********************************
+template M3UA_Protocol_Data t_M3UA_Protocol_Data
+  (template OCT4 pl_oPC,
+   template OCT4 pl_dPC,
+   template OCT1 pl_sI,
+   template OCT1 pl_nI,
+   template OCT1 pl_mP,
+   template OCT1 pl_sLS,
+   template octetstring pl_userProtocolData) :=
+{
+  tag := '0210'O,
+  lengthInd := 0,
+  oPC := pl_oPC,
+  dPC := pl_dPC,
+  sI := pl_sI,
+  nI := pl_nI,
+  mP := pl_mP,
+  sLS := pl_sLS,
+  userProtocolData := pl_userProtocolData
+}
+//********************************
+// End of M3UA parameter templates
+//********************************
+
+//***********************************
+// Dynamic part of the M3UA emulation
+//***********************************
+
+function f_M3UA_Emulation(SCTP_Association_Address pl_Boot) runs on M3UA_CT
+{
+  // Initialize parameters from the test case.
+  v_Entity.assoc := pl_Boot;
+  v_Entity.commStatus := aSP_Down_initial_State;
+
+  // At this point, we assume that the ports are already connected and mapped
+  // properly by the user.
+  log("*************************************************");
+  log("M3UA emulation initiated, the test can be started");
+  log("*************************************************");
+  
+  f_Initialize_SCTP();
+
+  // Start the main function in an infinte loop.
+  f_M3UA_ScanEvents();
+}
+
+// Initialize the SCTP layer with parameters read from the configuration file.
+// We have only a single association.
+function f_Initialize_SCTP() runs on M3UA_CT
+{
+  v_Entity.commStatus := aSP_Down_sCTP_Initialize_Done;
+  if (tsp_SCTP_Server_Mode) {
+    // Send out a LISTEN message.  The communication status doesn't change
+    // here.
+    SCTP_PORT.send
+      (t_ASP_SCTP_Listen(v_Entity.assoc.local_ip_addr,
+                         v_Entity.assoc.local_sctp_port));
+  }
+  else {
+    // Send ConnectFrom sequentially, wait for RESULT messages.
+    f_Associate();
+    T_Assoc_restart.start;
+  }
+
+  if (tsp_SCTP_PayloadProtocolID == 3) {
+    if (not tsp_M3UA_Server_Mode) {
+      T_ASPUP_resend.start;
+      T_ASPAC_resend.start;
+    }
+    if (tsp_Enable_M3UA_Heartbeat) {
+      T_Heartbeat.start;
+    }
+  }
+}
+
+// Associate SCTP connection for a M3UA entity.
+function f_Associate() runs on M3UA_CT
+{
+  SCTP_PORT.send(t_ASP_SCTP_ConnectFrom
+    (v_Entity.assoc.local_ip_addr,
+     v_Entity.assoc.local_sctp_port,
+     v_Entity.assoc.remote_ip_addr,
+     v_Entity.assoc.remote_sctp_port));
+
+  T_Timer.start;
+  alt {
+    [] SCTP_PORT.receive(t_ASP_SCTP_RESULT(*, ?, *)) -> value v_ASP_SCTP_RESULT {
+      if (v_ASP_SCTP_RESULT.error_status) {
+        log("Connect failed: ", v_ASP_SCTP_RESULT.error_message);
+      }
+      else {
+        v_Entity.sCTP_Assoc_ID := v_ASP_SCTP_RESULT.client_id;
+        v_Entity.commStatus := aSP_Down_sCTP_Associate_done;
+        log("SCTP_ConnectResult -> connection established from: ",
+          v_Entity.assoc.local_ip_addr, ":", v_Entity.assoc.local_sctp_port,
+          " to server: ", v_Entity.assoc.remote_ip_addr, ":",
+          v_Entity.assoc.remote_sctp_port, " association #",
+	  v_Entity.sCTP_Assoc_ID);
+        if (tsp_logVerbose) {
+          log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to ",
+            v_Entity.commStatus);
+        }
+      }
+      T_Timer.stop;
+    }
+    [] T_Timer.timeout {
+      log("----------------------------------------------");
+      log("No response received to t_ASP_SCTP_ConnectFrom");
+      log("----------------------------------------------");
+      setverdict(fail);
+      // mtc.stop;
+    }
+  }
+}
+
+// Starts M3UA emulation execution.
+function f_M3UA_ScanEvents() runs on M3UA_CT
+{
+  var ASP_MTP3_TRANSFERreq vl_ASP_MTP3_TRANSFERreq;
+
+  alt {
+    [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq : ?)
+      -> value vl_ASP_MTP3_TRANSFERreq {
+      f_Send_MTP3_TRANSFERreq(vl_ASP_MTP3_TRANSFERreq);
+      repeat;
+    }
+    [] as_SCTP_CommunicationUp()
+    [] as_SCTP_DataArrive()
+    [] as_SCTP_Connected()
+    [] as_Unexpected_SCTP_Events()
+    [] as_handleM3UA_timers()
+    [] as_handleSCTP_timers()
+  }
+}
+
+function f_Send_MTP3_TRANSFERreq(ASP_MTP3_TRANSFERreq pl_ASP_MTP3_TRANSFERreq)
+  runs on M3UA_CT
+{
+  if (v_Entity.commStatus == aSP_Active) {
+    if (tsp_SCTP_PayloadProtocolID == 3) { // M3UA
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          1,
+          enc_PDU_M3UA
+            (valueof
+             (t_PDU_M3UA_DATA
+              (omit,
+               omit,
+               t_M3UA_Protocol_Data
+                 (int2oct(pl_ASP_MTP3_TRANSFERreq.opc, 4),               // OPC
+                  int2oct(pl_ASP_MTP3_TRANSFERreq.dpc, 4),               // DPC
+                  bit2oct('0000'B & pl_ASP_MTP3_TRANSFERreq.sio.si),     // SIO
+                  bit2oct('000000'B & pl_ASP_MTP3_TRANSFERreq.sio.ni),
+                  bit2oct('000000'B & pl_ASP_MTP3_TRANSFERreq.sio.prio),
+                  int2oct(pl_ASP_MTP3_TRANSFERreq.sls, 1),               // SLS
+                  pl_ASP_MTP3_TRANSFERreq.data),
+                omit))),
+          tsp_SCTP_PayloadProtocolID));
+    }
+    else { // Non-M3UA
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          1,
+          pl_ASP_MTP3_TRANSFERreq.data,
+          tsp_SCTP_PayloadProtocolID));
+    }
+    if (tsp_logVerbose) {
+      log("MTP3_SP_PORT: ASP_MTP3_TRANSFERreq received -> message sent " &
+          "via SCTP");
+    }
+  }
+  else {
+    // If the SCTP association is not yet running, we have to buffer the data
+    // messages arrived from the MTP3 side.  Sending of buffered data messages
+    // should occure when the SCTP association is up and before sending the
+    // data message in reply for a new ASP_MTP3_TRANSFERreq data message.  The
+    // buffer should be checked before sending.
+    v_TRANSFERreq_Buffer[sizeof(v_TRANSFERreq_Buffer)] :=
+      pl_ASP_MTP3_TRANSFERreq;
+    if (tsp_logVerbose) {
+      log("MTP3_SP_PORT: ASP_MTP3_TRANSFERreq received in an inactive state " &
+          "-> message was buffered");
+    }
+  }
+}
+
+// Handle communication up messages of users which performed associate earlier.
+// We have only one association.
+altstep as_SCTP_CommunicationUp() runs on M3UA_CT
+{
+  [] SCTP_PORT.receive(tr_S_SCTP_CommunicationUp(?))
+    -> value v_ASP_SCTP_ASSOC_CHANGE {
+    if (v_Entity.sCTP_Assoc_ID == v_ASP_SCTP_ASSOC_CHANGE.client_id) {
+      if (v_Entity.commStatus == aSP_Down_sCTP_Associate_done) {
+        v_Entity.commStatus := aSP_Down_commUP_Received;
+        if (tsp_SCTP_PayloadProtocolID != 3) { // Non-M3UA
+          v_Entity.commStatus := aSP_Active;
+          var integer v_i;
+          for (v_i := 0; v_i < sizeof(v_TRANSFERreq_Buffer); v_i := v_i + 1) {
+            log("Sending buffered message #", v_i);
+            f_Send_MTP3_TRANSFERreq(v_TRANSFERreq_Buffer[v_i]);
+          }
+          v_TRANSFERreq_Buffer := {};
+	  // MTP3_SP_PORT.send(ASP_MTP3_RESUME : {});
+        }
+        if (tsp_logVerbose) {
+          log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+	      v_Entity.commStatus);
+	} 
+	if ((not tsp_M3UA_Server_Mode) and
+	    (tsp_SCTP_PayloadProtocolID == 3)) { // M3UA
+	  f_ASPUP_Sending();
+	}
+      }
+      else {
+        if (tsp_logVerbose) {
+          log("SCTP_CommunicationUp received in wrong state (i.e. not after " &
+	      "SCTP_Associate is done) in state: ", v_Entity.commStatus);
+	}
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("Association does not exists, received in CommunicationUp");
+      }
+    }
+    repeat;
+  }
+}
+
+// This altstep handles the data received from SCTP.
+altstep as_SCTP_DataArrive() runs on M3UA_CT
+{
+  [] SCTP_PORT.receive(tr_S_SCTP_DataArrive
+                       (?, // associationID
+                        ?, // streamID
+                        ?, // protocolID
+                        ?  // data
+                      )) -> value v_ASP_SCTP {
+    // Checking the identifier for the association is not necessary, because we
+    // have only only one association.
+    if (f_Assoc_Exists(v_ASP_SCTP.client_id)) {
+      if (tsp_logVerbose) {
+        log("Message received on association #", v_Entity.sCTP_Assoc_ID);
+      }
+      if (tsp_SCTP_PayloadProtocolID == 3) { // M3UA
+        v_PDU_M3UA := dec_PDU_M3UA(v_ASP_SCTP.data);
+        f_handle_M3UA_msg(v_PDU_M3UA);
+      }
+      else { // Non-M3UA
+        f_handle_nonM3UA_msg(v_ASP_SCTP.data);
+      }
+    }
+    else{
+      log("Message received on unknown association #", v_Entity.sCTP_Assoc_ID,
+          " -> closing connection");
+      SCTP_PORT.send(t_ASP_SCTP_Close(v_Entity.sCTP_Assoc_ID));
+      log("SCTP connection closed");
+    }
+    repeat;
+  }
+}
+
+// Handle the SCTP connected messages.  It is sent from the SCTP side and it
+// signals, that we're on the right track to create the association.  This is
+// for server mode.
+altstep as_SCTP_Connected() runs on M3UA_CT
+{
+  [tsp_SCTP_Server_Mode] SCTP_PORT.receive(tr_ASP_SCTP_Connected(?, ?, ?, ?, ?))
+    -> value v_ASP_SCTP_Connected {
+    // Message from the configured endpoint.
+    if ((v_ASP_SCTP_Connected.local_portnumber ==
+         v_Entity.assoc.local_sctp_port) and
+        (v_ASP_SCTP_Connected.local_hostname ==
+         v_Entity.assoc.local_ip_addr) and
+        (v_ASP_SCTP_Connected.peer_portnumber ==
+         v_Entity.assoc.remote_sctp_port) and
+        (v_ASP_SCTP_Connected.peer_hostname ==
+         v_Entity.assoc.remote_ip_addr)) {
+      v_Entity.sCTP_Assoc_ID := v_ASP_SCTP_Connected.client_id;
+      v_Entity.commStatus := aSP_Down_sCTP_Associate_done;
+      log("ASP_SCTP_Connected -> accepted connection from client: ",
+          v_ASP_SCTP_Connected.peer_hostname, ":",
+          v_ASP_SCTP_Connected.peer_portnumber, " on server: ",
+          v_ASP_SCTP_Connected.local_hostname, ":",
+          v_ASP_SCTP_Connected.local_portnumber, " with association #",
+          v_Entity.sCTP_Assoc_ID);
+    }
+    else {
+      log("ASP_SCTP_Connected -> connection from unknown client: ",
+          v_ASP_SCTP_Connected.peer_hostname, ":",
+          v_ASP_SCTP_Connected.peer_portnumber);
+    }
+    repeat;
+  }
+}
+
+// Handle error messages of users.
+altstep as_Unexpected_SCTP_Events() runs on M3UA_CT
+{
+  // Handle communications lost message.  State of user with given index jumps
+  // back to initial state and stays there.  That user will not be able to
+  // communicate anymore.
+  [] SCTP_PORT.receive(tr_S_SCTP_CommunicationLost(?))
+    -> value v_ASP_SCTP_ASSOC_CHANGE {
+    if (f_Assoc_Exists(v_ASP_SCTP_ASSOC_CHANGE.client_id)) {
+      if (v_Entity.commStatus == aSP_Active) {
+	// MTP3_SP_PORT.send(ASP_MTP3_PAUSE : {});
+      }
+      v_Entity.commStatus := aSP_Down_sCTP_Initialize_Done;
+      v_Entity.sCTP_Assoc_ID := omit;
+      if (tsp_logVerbose) {
+        log("SCTP_CommunicationLost received");
+        log("Association #", v_Entity.sCTP_Assoc_ID, " cleared, state " &
+            "changed to: ", v_Entity.commStatus);
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("Association does not exist, received in CommunicationLost");
+      }
+    }
+    repeat;
+  }
+  [] SCTP_PORT.receive(tr_S_SCTP_ShutdownComplete(?))
+    -> value v_ASP_SCTP_ASSOC_CHANGE {
+    if (f_Assoc_Exists(v_ASP_SCTP_ASSOC_CHANGE.client_id)) {
+      if (v_Entity.commStatus == aSP_Active) {
+        // MTP3_SP_PORT.send(ASP_MTP3_PAUSE : {});
+      }
+      v_Entity.commStatus := aSP_Down_sCTP_Initialize_Done;
+      if (tsp_logVerbose) {
+        log("SCTP_ShutdownComplete received");
+	log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+	    v_Entity.commStatus);
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("Association does not exist, received in ShutdownComplete");
+      }
+    }
+    repeat;
+  }
+  [] SCTP_PORT.receive(tr_S_SCTP_ShutdownEvent(?))
+    -> value v_ASP_SCTP_SHUTDOWN_EVENT {
+    if (f_Assoc_Exists(v_ASP_SCTP_SHUTDOWN_EVENT.client_id)) {
+      if (v_Entity.commStatus == aSP_Active) {
+	// MTP3_SP_PORT.send(ASP_MTP3_PAUSE : {});	
+      }
+      v_Entity.commStatus := aSP_Down_sCTP_Initialize_Done;
+      if (tsp_logVerbose) {
+        log("SCTP_ShutdownEvent received");
+	log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+	    v_Entity.commStatus);
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("Association does not exist, received in ShutdownEvent");
+      }
+    }
+    repeat;
+  }
+  [] SCTP_PORT.receive(tr_ASP_SCTP_Connected(?, ?, ?, ?, ?))
+    -> value v_ASP_SCTP_Connected {
+    log("Unexpected ASP_SCTP_Connected");
+    repeat;
+  }
+  [] SCTP_PORT.receive(tr_S_SCTP_Restart(?)) -> value v_ASP_SCTP_ASSOC_CHANGE {
+    if (f_Assoc_Exists(v_ASP_SCTP_ASSOC_CHANGE.client_id)) {
+      log("SCTP_Restart received");
+      v_Entity.commStatus := aSP_Down_commUP_Received;
+      if (tsp_logVerbose) {
+        log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+	    v_Entity.commStatus);
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("Association does not exist, received in SCTP_Restart");
+      }
+    }
+    repeat;
+  }
+  [] SCTP_PORT.receive(t_ASP_SCTP_SEND_FAILED(?))
+    -> value v_ASP_SCTP_SEND_FAILED {
+    log("SCTP_Send failed for association #", v_Entity.sCTP_Assoc_ID);
+    if (f_Assoc_Exists(v_ASP_SCTP_SEND_FAILED.client_id)) {
+      // Daemon sends an error status message here.
+      // MTP3_SP_PORT.send(ASP_MTP3_PAUSE : {});
+    }
+    else {
+      log("Send error received for association that doesn't exist");
+    }
+    repeat;
+  }
+  [] SCTP_PORT.receive(tr_S_SCTP_CANT_STR_ASSOC(?)) {
+    repeat;
+  }
+  [] SCTP_PORT.receive {
+    repeat;
+  }
+}
+
+// After reception of SCTP_CommunicationUp M3UA ASPUP/ASPAC is resent by the
+// entity if it didn't receive ASPUP_Ack/ASPAC_Ack.
+altstep as_handleM3UA_timers() runs on M3UA_CT
+{
+  [] T_ASPUP_resend.timeout {
+    if ((v_Entity.commStatus == aSP_Down_commUP_Received) or
+        (v_Entity.commStatus == aSP_Down_ASPUP_Sent)) {
+      // Try to send ASPUP again.
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          0,
+          enc_PDU_M3UA(valueof(t_PDU_M3UA_ASPUP(omit, omit))),
+          tsp_SCTP_PayloadProtocolID));
+      v_Entity.commStatus := aSP_Down_ASPUP_Sent;
+      if (tsp_logVerbose) {
+        log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+          v_Entity.commStatus);
+      }
+    }
+    T_ASPUP_resend.start;
+    repeat;
+  }
+  
+  [] T_ASPAC_resend.timeout {
+    if ((v_Entity.commStatus == aSP_Inactive) or
+        (v_Entity.commStatus == aSP_Inact_ASPAC_Sent)) {
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          0,
+          enc_PDU_M3UA(valueof(t_PDU_M3UA_ASPAC(omit, omit, omit))),
+          tsp_SCTP_PayloadProtocolID));
+      v_Entity.commStatus := aSP_Inact_ASPAC_Sent;
+      if (tsp_logVerbose) {
+        log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+            v_Entity.commStatus);
+      }
+    }
+    T_ASPAC_resend.start;
+    repeat;
+  }
+  
+  [tsp_Enable_M3UA_Heartbeat] T_Heartbeat.timeout {
+    if (v_Entity.commStatus == aSP_Active) {
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          0,
+          enc_PDU_M3UA(valueof(t_PDU_M3UA_Heartbeat(omit))),
+          tsp_SCTP_PayloadProtocolID));
+      if (tsp_logVerbose) {
+        log("Heartbeat sent to association #", v_Entity.sCTP_Assoc_ID);
+      }
+    }
+    T_Heartbeat.start;
+    repeat;
+  }
+}
+
+// Handles SCTP timer events.  In server mode we don't associate.
+altstep as_handleSCTP_timers() runs on M3UA_CT
+{
+  [not tsp_SCTP_Server_Mode] T_Assoc_restart.timeout {
+    if (v_Entity.commStatus == aSP_Down_sCTP_Initialize_Done) {
+      f_Associate();
+    }
+    T_Assoc_restart.start;
+    repeat;
+  }
+}
+
+// After reception of SCTP CommunicationUp messages M3UA ASPUP is sent by
+// every entity and the M3UA ASPUP_Ack is received by every entity.
+function f_ASPUP_Sending() runs on M3UA_CT
+{
+  SCTP_PORT.send
+    (t_S_SCTP_Send
+     (v_Entity.sCTP_Assoc_ID,
+      0, // streamID
+      enc_PDU_M3UA(valueof(t_PDU_M3UA_ASPUP(omit, omit))),
+      tsp_SCTP_PayloadProtocolID));
+  v_Entity.commStatus := aSP_Down_ASPUP_Sent;
+  if (tsp_logVerbose) {
+    log("M3UA_ASPUP sent");
+    log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+        v_Entity.commStatus);
+  }
+}
+
+
+// Test if an association with assocID exists or not.  We have only one
+// association at the moment, we just check if the given assocID is the same,
+// that is associated with our single entity.  If we would have more entities
+// in a table, the index of it should be returned instead of a boolean value.
+function f_Assoc_Exists(integer pl_assocID) runs on M3UA_CT return boolean
+{
+  if (v_Entity.sCTP_Assoc_ID == pl_assocID) {
+    return true;
+  }
+  else {
+    if (tsp_logVerbose) {
+      log("Association #", v_Entity.sCTP_Assoc_ID, " not found");
+    }
+  }
+  return false;
+}
+
+function f_handle_M3UA_msg(PDU_M3UA pl_PDU_M3UA) runs on M3UA_CT
+{
+  if (ischosen(pl_PDU_M3UA.m3UA_DATA)) {
+    if (v_Entity.commStatus == aSP_Active) {
+      // Send ASP_MTP3_TRANSFERind message.
+      MTP3_SP_PORT.send
+        (valueof
+         (tr_ASP_MTP3_TRANSFERind_sio
+          (substr(oct2bit(pl_PDU_M3UA.m3UA_DATA.messageParameters.protocol_Data.nI), 6, 2),
+           substr(oct2bit(pl_PDU_M3UA.m3UA_DATA.messageParameters.protocol_Data.mP), 6, 2),
+           substr(oct2bit(pl_PDU_M3UA.m3UA_DATA.messageParameters.protocol_Data.sI), 4, 4),
+           oct2int(pl_PDU_M3UA.m3UA_DATA.messageParameters.protocol_Data.oPC),
+           oct2int(pl_PDU_M3UA.m3UA_DATA.messageParameters.protocol_Data.dPC),
+           oct2int(pl_PDU_M3UA.m3UA_DATA.messageParameters.protocol_Data.sLS),
+           pl_PDU_M3UA.m3UA_DATA.messageParameters.protocol_Data.userProtocolData)));
+      if (tsp_logVerbose) {
+        log("MTP3_SP_PORT: Data received -> TRANSFERind sent");
+      }
+    }
+    else {
+      // Buffering indication messages?
+      if (tsp_logVerbose) {
+        log("MTP3_SP_PORT: Data received, no user connected -> discard");
+      }
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_BEAT)) {
+    if (v_Entity.commStatus == aSP_Active) {
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          0,
+          enc_PDU_M3UA
+	    (valueof
+             (t_PDU_M3UA_Beat_Ack
+              (pl_PDU_M3UA.m3UA_BEAT.messageParameters.heartbeat_Data))),
+          tsp_SCTP_PayloadProtocolID));
+      if (tsp_logVerbose) {
+        log("M3UA_BEAT received -> M3UA_BEAT_Ack sent");
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("M3UA_BEAT received in wrong state");
+      }
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_BEAT_Ack)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_BEAT_Ack -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_ERR)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_ERR -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_NOTIFY)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_NOTIFY -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_DUNA)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_DUNA -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_DAVA)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_DAVA -> discard");
+    }
+  }
+  // In server mode ASP_M3UA_DAUD messages can be received.  In response the
+  // server must send ASP_M3UA_DAVA messages.  It's not checked if we're
+  // servers or not.
+  else if (ischosen(pl_PDU_M3UA.m3UA_DAUD)) {
+    if ((v_Entity.commStatus == aSP_Inactive) or
+        (v_Entity.commStatus == aSP_Inact_ASPAC_Sent) or
+        (v_Entity.commStatus == aSP_Active)) {
+      // Send ASP_M3UA_DAVA message.
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          0,
+          enc_PDU_M3UA
+            (valueof
+             (t_PDU_M3UA_DAVA
+              (pl_PDU_M3UA.m3UA_DAUD.messageParameters.network_Appearance,
+               pl_PDU_M3UA.m3UA_DAUD.messageParameters.routing_Context,
+               pl_PDU_M3UA.m3UA_DAUD.messageParameters.affected_Point_Codes,
+               pl_PDU_M3UA.m3UA_DAUD.messageParameters.info_String))),
+          tsp_SCTP_PayloadProtocolID));
+      if (tsp_logVerbose) {
+        log("M3UA_DAUD received -> DAVA sent");
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("M3UA_DAUD received in wrong state");
+      }
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_SCON)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_SCON -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_DUPU)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_DUPU -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_DRST)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_DRST -> discard");
+    }
+  }
+  // In server mode we can receive M3UA_ASPUP messages.  The answer will be a
+  // M3UA_ASPUP_Ack message to the client.
+  else if (ischosen(pl_PDU_M3UA.m3UA_ASPUP)) {
+    if (((v_Entity.commStatus == aSP_Down_commUP_Received) or
+        (v_Entity.commStatus == aSP_Down_ASPUP_Sent)) and
+	tsp_M3UA_Server_Mode) {
+      v_Entity.commStatus := aSP_Inactive;
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          0,
+          enc_PDU_M3UA(valueof(t_PDU_M3UA_ASPUP_Ack)),
+          tsp_SCTP_PayloadProtocolID));
+      if (tsp_logVerbose) {
+        log("M3UA_ASPUP received -> M3UA_ASPUP_Ack sent");
+        log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+          v_Entity.commStatus);
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("M3UA_ASPUP received in wrong state or the emulation is not in " &
+	    "M3UA server mode");
+      }
+    }
+  }
+  // Receives a M3UA_ASPDN message and sends a M3UA_ASPDN_Ack message in
+  // response.
+  else if (ischosen(pl_PDU_M3UA.m3UA_ASPDN)) {
+    if ((v_Entity.commStatus == aSP_Inactive) or
+        (v_Entity.commStatus == aSP_Inact_ASPAC_Sent) or
+        (v_Entity.commStatus == aSP_Active)) {
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          0,
+          enc_PDU_M3UA(valueof(t_PDU_M3UA_ASPDN_Ack)),
+          tsp_SCTP_PayloadProtocolID));
+      if (v_Entity.commStatus == aSP_Active) {
+        // MTP3_SP_PORT.send(ASP_MTP3_PAUSE : {});
+      }
+      v_Entity.commStatus := aSP_Down_commUP_Received;
+      if (tsp_logVerbose) {
+        log("M3UA_ASPDN received -> ASPDN_Ack sent");
+        log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+            v_Entity.commStatus);
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("ASPDN received in wrong state or the emulation is not in M3UA " &
+	    "server mode");
+      }
+    }
+  }
+  // The M3UA client receives M3UA_ASPUP_Ack messages from the server.  In
+  // response of a M3UA_ASPUP message sent by the client.
+  else if (ischosen(pl_PDU_M3UA.m3UA_ASPUP_Ack)) {
+    if (((v_Entity.commStatus == aSP_Down_ASPUP_Sent) or
+        (v_Entity.commStatus == aSP_Inactive)) and
+	not tsp_M3UA_Server_Mode) {
+      v_Entity.commStatus := aSP_Inactive;
+      if (tsp_logVerbose) {
+        log("M3UA_ASPUP_Ack received -> send M3UA_ASPAC");
+        log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+            v_Entity.commStatus);
+      }
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          0,
+          enc_PDU_M3UA(valueof(t_PDU_M3UA_ASPAC(omit, omit, omit))),
+          tsp_SCTP_PayloadProtocolID));
+      // The state changes again after sending the M3UA_ASPAC message.
+      v_Entity.commStatus := aSP_Inact_ASPAC_Sent;
+      if (tsp_logVerbose) {
+        log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+            v_Entity.commStatus);
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("M3UA_ASPUP_Ack received in wrong state or the emulation is not " &
+	    "in M3UA client mode");
+      }
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_ASPDN_Ack)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_ASPDN_Ack -> discard");
+    }
+  }
+  // M3UA_ASPAC messages are received on the server side.  The server sends a
+  // M3UA_ASPAC_Ack message back to the client.  This step makes the
+  // association active on both sides.
+  else if (ischosen(pl_PDU_M3UA.m3UA_ASPAC)) {
+    if (((v_Entity.commStatus == aSP_Inactive) or
+        (v_Entity.commStatus == aSP_Inact_ASPAC_Sent)) and
+	tsp_M3UA_Server_Mode) {
+      v_Entity.commStatus := aSP_Active;
+      if (tsp_logVerbose) {
+        log("M3UA_ASPAC received -> M3UA_ASPAC_Ack sent");
+	log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+	    v_Entity.commStatus);
+      }
+      var integer v_i;
+      for (v_i := 0; v_i < sizeof(v_TRANSFERreq_Buffer); v_i := v_i + 1) {
+        log("Sending buffered message #", v_i);
+        f_Send_MTP3_TRANSFERreq(v_TRANSFERreq_Buffer[v_i]);
+      }
+      v_TRANSFERreq_Buffer := {};
+      // Send M3UA_ASPAC_Ack.
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+	 (v_Entity.sCTP_Assoc_ID,
+	  0,
+	  enc_PDU_M3UA
+	    (valueof
+	     (t_PDU_M3UA_ASPAC_Ack
+	      (pl_PDU_M3UA.m3UA_ASPAC.messageParameters.traffic_Mode_Type,
+	       pl_PDU_M3UA.m3UA_ASPAC.messageParameters.routing_Context))),
+	  tsp_SCTP_PayloadProtocolID));
+      // MTP3_SP_PORT.send(ASP_MTP3_RESUME : {});
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("M3UA_ASPAC received in wrong state or the emulation is not in " &
+	    "M3UA server mode");
+      }
+    }
+  }
+  // The client receives M3UA_ASPAC_Ack messages from the server.  The
+  // association will be activated.  The buffered messages should be send here.
+  else if (ischosen(pl_PDU_M3UA.m3UA_ASPAC_Ack)) {
+    if (((v_Entity.commStatus == aSP_Inact_ASPAC_Sent) or
+        (v_Entity.commStatus == aSP_Active)) and
+	not tsp_M3UA_Server_Mode) {
+      // MTP3_SP_PORT.send(ASP_MTP3_RESUME : {});
+      v_Entity.commStatus := aSP_Active;
+      if (tsp_logVerbose) {
+        log("ASPAC_Ack received for association #", v_Entity.sCTP_Assoc_ID);
+        log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+            v_Entity.commStatus);
+      }
+      var integer v_i;
+      for (v_i := 0; v_i < sizeof(v_TRANSFERreq_Buffer); v_i := v_i + 1) {
+        log("Sending buffered message #", v_i);
+        f_Send_MTP3_TRANSFERreq(v_TRANSFERreq_Buffer[v_i]);
+      }
+      v_TRANSFERreq_Buffer := {};
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("M3UA_ASPAC_Ack received in wrong state on association #",
+            v_Entity.sCTP_Assoc_ID, " or the emulation is not in M3UA " &
+	    "client mode");
+      }
+    }
+  }
+  // Receives a M3UA_ASPIA message and sends back a M3UA_ASPIA_Ack message in
+  // response.
+  else if (ischosen(pl_PDU_M3UA.m3UA_ASPIA)) {
+    if (v_Entity.commStatus == aSP_Active) {
+      SCTP_PORT.send
+        (t_S_SCTP_Send
+         (v_Entity.sCTP_Assoc_ID,
+          0,
+          enc_PDU_M3UA
+	    (valueof
+             (t_PDU_M3UA_ASPIA_Ack
+	      (pl_PDU_M3UA.m3UA_ASPIA.messageParameters.routing_Context))),
+          tsp_SCTP_PayloadProtocolID));
+      // MTP3_SP_PORT.send(ASP_MTP3_PAUSE : {});
+      v_Entity.commStatus := aSP_Inactive;
+      if (tsp_logVerbose) {
+        log("M3UA_ASPIA received -> M3UA_ASPIA_Ack sent");
+        log("Association #", v_Entity.sCTP_Assoc_ID, " state changed to: ",
+          v_Entity.commStatus);
+      }
+    }
+    else {
+      if (tsp_logVerbose) {
+        log("M3UA_ASPIA received in wrong state or the emulation is not " &
+	    "running in M3UA server mode");
+      }
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_ASPIA_Ack)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_ASPIA_Ack -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_REG_REQ)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_REG_REQ -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_REG_RSP)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_REG_RSP -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_DEREG_REQ)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_DEREG_REQ -> discard");
+    }
+  }
+  else if (ischosen(pl_PDU_M3UA.m3UA_DEREG_RSP)) {
+    if (tsp_logVerbose) {
+      log("Received M3UA_DEREG_RSP -> discard");
+    }
+  }
+}
+
+function f_handle_nonM3UA_msg(octetstring pl_PDU) runs on M3UA_CT
+{
+  if (v_Entity.commStatus == aSP_Active) {
+    // Send TRANSFERind message.
+    MTP3_SP_PORT.send(valueof
+                      (tr_ASP_MTP3_TRANSFERind_sio
+                       ('00'B,
+                        '00'B,
+                        '0000'B,
+                        0,
+                        0,
+                        0,
+                        pl_PDU)));
+    if (tsp_logVerbose) {
+      log("Non-M3UA DATA received -> TRANSFERind sent");
+    }
+  }
+  else {
+    if (tsp_logVerbose) {
+      log("DATA received, but no user connected -> discard");
+    }
+  }
+}
+
+}