blob: a75f3f45d9973143f66f094fa2e72432ffdc05a5 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2019 Ericsson Telecom AB
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v2.0
// which accompanies this distribution, and is available at
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
///////////////////////////////////////////////////////////////////////////////
//
// File: M3UA_Emulation.ttcn
// Reference: M3UA Protocol Emulation
// Rev: R2A
// 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,
M3UA_Routing_Context rctx 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
//***********************************
private template (value) M3UA_Routing_Context t_RoutingContext(OCT4 rctx) := {
tag := '0006'O,
lengthInd := 8,
routingContext := rctx
}
function f_M3UA_Emulation(SCTP_Association_Address pl_Boot,
template (omit) integer rctx := omit) runs on M3UA_CT
{
// Initialize parameters from the test case.
v_Entity.assoc := pl_Boot;
v_Entity.commStatus := aSP_Down_initial_State;
if (istemplatekind(rctx, "omit")) {
v_Entity.rctx := omit;
} else {
v_Entity.rctx := valueof(t_RoutingContext(int2oct(valueof(rctx), 4)));
}
// 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,
v_Entity.rctx,
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, v_Entity.rctx, 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, v_Entity.rctx, 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");
}
}
}
}