stp: Introduce STP_Tests*.ttcn for testing OsmoSTP

In the past, we were automatically running [large parts of] the nplab
M3UA and SUA test suites, but those implement only a fraction of the
functionality.  Particularly, they don't cover the non-standard IPA
behavior, and they don't cover RKM (routing key management).

Let's introduce an initial set of STP tests with this patch.  We try
to not duplicate nplab here, and implement bits not covered there.

Change-Id: I628a87385cac0dfe708a0d74a5088fbd5a4790cd
diff --git a/library/M3UA_CodecPort.ttcn b/library/M3UA_CodecPort.ttcn
new file mode 100644
index 0000000..94d16d6
--- /dev/null
+++ b/library/M3UA_CodecPort.ttcn
@@ -0,0 +1,84 @@
+module M3UA_CodecPort {
+
+/* Simple M3UA Codec Port, translating between raw SCTP primitives with
+ * octetstring payload towards the IPL4asp provider, and M3UA primitives
+ * which carry the decoded M3UA data types as payload.
+ *
+ * (C) 2019 by Harald Welte <laforge@gnumonks.org>
+ * All rights reserved.
+ *
+ * Released under the terms of GNU General Public License, Version 2 or
+ * (at your option) any later version.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+	import from IPL4asp_PortType all;
+	import from IPL4asp_Types all;
+	import from M3UA_Types all;
+
+	type record M3UA_RecvFrom {
+		ConnectionId	connId,
+		HostName	remName,
+		PortNumber	remPort,
+		HostName	locName,
+		PortNumber	locPort,
+		PDU_M3UA	msg
+	};
+
+	template M3UA_RecvFrom t_M3UA_RecvFrom(template PDU_M3UA msg) := {
+		connId := ?,
+		remName := ?,
+		remPort := ?,
+		locName := ?,
+		locPort := ?,
+		msg := msg
+	}
+
+	type record M3UA_Send {
+		ConnectionId	connId,
+		integer		stream,
+		PDU_M3UA	msg
+	}
+
+	template M3UA_Send t_M3UA_Send(template ConnectionId connId, template PDU_M3UA msg,
+					template (omit) integer stream := omit) := {
+		connId := connId,
+		stream := stream,
+		msg := msg
+	}
+
+	private function IPL4_to_M3UA_RecvFrom(in ASP_RecvFrom pin, out M3UA_RecvFrom pout) {
+		pout.connId := pin.connId;
+		pout.remName := pin.remName;
+		pout.remPort := pin.remPort;
+		pout.locName := pin.locName;
+		pout.locPort := pin.locPort;
+		pout.msg := dec_PDU_M3UA(pin.msg);
+	} with { extension "prototype(fast)" };
+
+	private function M3UA_to_IPL4_Send(in M3UA_Send pin, out ASP_Send pout) {
+		pout.connId := pin.connId;
+		pout.proto := {
+			sctp := {
+				sinfo_stream := pin.stream,
+				sinfo_ppid := 3,
+				remSocks := omit,
+				assocId := omit
+			}
+		};
+		pout.msg := enc_PDU_M3UA(pin.msg);
+	} with { extension "prototype(fast)" };
+
+	type port M3UA_CODEC_PT message {
+		out	M3UA_Send;
+		in	M3UA_RecvFrom,
+			ASP_ConnId_ReadyToRelease,
+			ASP_Event;
+	} with { extension "user IPL4asp_PT
+		out(M3UA_Send -> ASP_Send:function(M3UA_to_IPL4_Send))
+		in(ASP_RecvFrom -> M3UA_RecvFrom: function(IPL4_to_M3UA_RecvFrom);
+		   ASP_ConnId_ReadyToRelease -> ASP_ConnId_ReadyToRelease: simple;
+		   ASP_Event -> ASP_Event: simple)"
+	}
+}
diff --git a/library/M3UA_CodecPort_CtrlFunct.ttcn b/library/M3UA_CodecPort_CtrlFunct.ttcn
new file mode 100644
index 0000000..fc38e43
--- /dev/null
+++ b/library/M3UA_CodecPort_CtrlFunct.ttcn
@@ -0,0 +1,44 @@
+module M3UA_CodecPort_CtrlFunct {
+
+  import from M3UA_CodecPort all;
+  import from IPL4asp_Types all;
+
+  external function f_IPL4_listen(
+    inout M3UA_CODEC_PT portRef,
+    in HostName locName,
+    in PortNumber locPort,
+    in ProtoTuple proto,
+    in OptionList options := {}
+  ) return Result;
+
+  external function f_IPL4_connect(
+    inout M3UA_CODEC_PT portRef,
+    in HostName remName,
+    in PortNumber remPort,
+    in HostName locName,
+    in PortNumber locPort,
+    in ConnectionId connId,
+    in ProtoTuple proto,
+    in OptionList options := {}
+  ) return Result;
+
+  external function f_IPL4_close(
+    inout M3UA_CODEC_PT portRef,
+    in ConnectionId id,
+    in ProtoTuple proto := { unspecified := {} }
+  ) return Result;
+
+  external function f_IPL4_setUserData(
+    inout M3UA_CODEC_PT portRef,
+    in ConnectionId id,
+    in UserData userData
+  ) return Result;
+
+  external function f_IPL4_getUserData(
+    inout M3UA_CODEC_PT portRef,
+    in ConnectionId id,
+    out UserData userData
+  ) return Result;
+
+}
+
diff --git a/library/M3UA_CodecPort_CtrlFunctDef.cc b/library/M3UA_CodecPort_CtrlFunctDef.cc
new file mode 100644
index 0000000..62533de
--- /dev/null
+++ b/library/M3UA_CodecPort_CtrlFunctDef.cc
@@ -0,0 +1,56 @@
+#include "IPL4asp_PortType.hh"
+#include "M3UA_CodecPort.hh"
+#include "IPL4asp_PT.hh"
+
+namespace M3UA__CodecPort__CtrlFunct {
+
+  IPL4asp__Types::Result f__IPL4__listen(
+    M3UA__CodecPort::M3UA__CODEC__PT& portRef,
+    const IPL4asp__Types::HostName& locName,
+    const IPL4asp__Types::PortNumber& locPort,
+    const IPL4asp__Types::ProtoTuple& proto,
+    const IPL4asp__Types::OptionList& options)
+  {
+    return f__IPL4__PROVIDER__listen(portRef, locName, locPort, proto, options);
+  }
+  
+  IPL4asp__Types::Result f__IPL4__connect(
+    M3UA__CodecPort::M3UA__CODEC__PT& portRef,
+    const IPL4asp__Types::HostName& remName,
+    const IPL4asp__Types::PortNumber& remPort,
+    const IPL4asp__Types::HostName& locName,
+    const IPL4asp__Types::PortNumber& locPort,
+    const IPL4asp__Types::ConnectionId& connId,
+    const IPL4asp__Types::ProtoTuple& proto,
+    const IPL4asp__Types::OptionList& options)
+  {
+    return f__IPL4__PROVIDER__connect(portRef, remName, remPort,
+                                      locName, locPort, connId, proto, options);
+  }
+
+  IPL4asp__Types::Result f__IPL4__close(
+    M3UA__CodecPort::M3UA__CODEC__PT& portRef, 
+    const IPL4asp__Types::ConnectionId& connId, 
+    const IPL4asp__Types::ProtoTuple& proto)
+  {
+      return f__IPL4__PROVIDER__close(portRef, connId, proto);
+  }
+
+  IPL4asp__Types::Result f__IPL4__setUserData(
+    M3UA__CodecPort::M3UA__CODEC__PT& portRef,
+    const IPL4asp__Types::ConnectionId& connId,
+    const IPL4asp__Types::UserData& userData)
+  {
+    return f__IPL4__PROVIDER__setUserData(portRef, connId, userData);
+  }
+  
+  IPL4asp__Types::Result f__IPL4__getUserData(
+    M3UA__CodecPort::M3UA__CODEC__PT& portRef,
+    const IPL4asp__Types::ConnectionId& connId,
+    IPL4asp__Types::UserData& userData)
+  {
+    return f__IPL4__PROVIDER__getUserData(portRef, connId, userData);
+  }
+  
+}
+
diff --git a/library/M3UA_Templates.ttcn b/library/M3UA_Templates.ttcn
new file mode 100644
index 0000000..02b493c
--- /dev/null
+++ b/library/M3UA_Templates.ttcn
@@ -0,0 +1,771 @@
+module M3UA_Templates {
+
+/* M3UA Templates, building on top of M3UA_Types from Ericsson.
+ *
+ * (C) 2019 by Harald Welte <laforge@gnumonks.org>
+ * All rights reserved.
+ *
+ * Released under the terms of GNU General Public License, Version 2 or
+ * (at your option) any later version.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+import from M3UA_Types all;
+import from General_Types all;
+import from Osmocom_Types all;
+
+const OCT1 c_M3UA_VERSION := '01'O;
+
+const OCT2 c_M3UA_ST_T_STATE_CHG := '0001'O;
+const OCT2 c_M3UA_ST_I_RESERVED := '0001'O;
+const OCT2 c_M3UA_ST_I_AS_INACTIVE := '0002'O;
+const OCT2 c_M3UA_ST_I_AS_ACTIVE := '0003'O;
+const OCT2 c_M3UA_ST_I_AS_PENDING := '0004'O;
+
+const OCT2 c_M3UA_ST_T_OTHER := '0002'O;
+const OCT2 c_M3UA_ST_I_INSUFF_RESRC := '0001'O
+const OCT2 c_M3UA_ST_I_ALTERNATE_ASP := '0002'O
+const OCT2 c_M3UA_ST_I_ASP_FAILUREP := '0003'O
+
+private function f_aspid_or_omit(template (omit) OCT4 aspid)
+return template (omit) M3UA_ASP_Identifier {
+	var template (omit) M3UA_ASP_Identifier id;
+	if (istemplatekind(aspid, "omit")) {
+		return omit;
+	} else {
+		id.tag := '0011'O;
+		id.lengthInd := 8;
+		id.aSPIdentifier := aspid;
+		return id;
+	}
+}
+
+function tr_M3UA_asp_id(template OCT4 aspid)
+return template M3UA_ASP_Identifier {
+	var template M3UA_ASP_Identifier id := {
+		tag := '0011'O,
+		lengthInd := 8,
+		aSPIdentifier := aspid
+	};
+	if (istemplatekind(aspid, "omit")) {
+		return omit;
+	} else if (istemplatekind(aspid, "*")) {
+		return *;
+	} else {
+		return id;
+	}
+}
+
+
+/***********************************************************************
+ * ASPSM Class
+ ***********************************************************************/
+
+template (value) PDU_M3UA ts_M3UA_ASPUP(template (omit) OCT4 aspid := omit,
+					template (omit) octetstring infostr := omit) := {
+	m3UA_ASPUP := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0301'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			aSP_Identifier := f_aspid_or_omit(aspid),
+			info_String := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_ASPUP(template OCT4 aspid := *,
+					  template octetstring infostr := omit) := {
+	m3UA_ASPUP := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0301'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			aSP_Identifier := tr_M3UA_asp_id(aspid),
+			info_String := *
+		}
+	}
+}
+
+template (value) PDU_M3UA ts_M3UA_ASPUP_ACK := {
+	m3UA_ASPUP_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0304'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			info_String := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_ASPUP_ACK := {
+	m3UA_ASPUP_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0304'O,
+		messageLength := ?,
+		messageParameters := {
+			info_String := *
+		}
+	}
+}
+
+template (value) PDU_M3UA ts_M3UA_ASPDN := {
+	m3UA_ASPDN := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0302'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			info_String := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_ASPDN := {
+	m3UA_ASPDN := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0302'O,
+		messageLength := ?,
+		messageParameters := {
+			info_String := *
+		}
+	}
+}
+
+template (value) PDU_M3UA ts_M3UA_ASPDN_ACK := {
+	m3UA_ASPUP_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0305'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			info_String := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_ASPDN_ACK := {
+	m3UA_ASPUP_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0305'O,
+		messageLength := ?,
+		messageParameters := {
+			info_String := *
+		}
+	}
+}
+
+template (value) M3UA_Heartbeat_Data ts_M3UA_hb_data(template (value) octetstring hb_data) := {
+	tag := '0009'O,
+	lengthInd := 0, // overwritten
+	heartbeat_Data := hb_data
+}
+
+template (present) M3UA_Heartbeat_Data tr_M3UA_hb_data(template (present) octetstring hb_data) := {
+	tag := '0009'O,
+	lengthInd := ?,
+	heartbeat_Data := hb_data
+}
+
+template (value) PDU_M3UA ts_M3UA_BEAT(template (omit) M3UA_Heartbeat_Data hbd := omit) := {
+	m3UA_BEAT := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0303'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			heartbeat_Data := hbd
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_BEAT(template M3UA_Heartbeat_Data hbd := *) := {
+	m3UA_BEAT := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0303'O,
+		messageLength := ?,
+		messageParameters := {
+			heartbeat_Data := hbd
+		}
+	}
+}
+
+template (value) PDU_M3UA ts_M3UA_BEAT_ACK(template (omit) M3UA_Heartbeat_Data hb_data)  := {
+	m3UA_BEAT_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0306'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			heartbeat_Data := hb_data
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_BEAT_ACK(template M3UA_Heartbeat_Data hb_data := *) := {
+	m3UA_BEAT_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0306'O,
+		messageLength := ?,
+		messageParameters := {
+			heartbeat_Data := hb_data
+		}
+	}
+}
+
+
+
+
+/***********************************************************************
+ * ASPTM Class
+ ***********************************************************************/
+
+
+const M3UA_Traffic_Mode_Type c_M3UA_TMT_override := {
+	tag := '000B'O,
+	lengthInd := 8,
+	trafficModeType := int2oct(1, 4)
+}
+
+const M3UA_Traffic_Mode_Type c_M3UA_TMT_loadshare := {
+	tag := '000B'O,
+	lengthInd := 8,
+	trafficModeType := int2oct(2, 4)
+}
+
+const M3UA_Traffic_Mode_Type c_M3UA_TMT_broadcast := {
+	tag := '000B'O,
+	lengthInd := 8,
+	trafficModeType := int2oct(3, 4)
+}
+
+function ts_M3UA_routing_ctx(template (omit) octetstring rctx)
+return template (omit) M3UA_Routing_Context {
+	var template (omit) M3UA_Routing_Context id;
+	if (istemplatekind(rctx, "omit")) {
+		return omit;
+	} else {
+		id.tag := '0006'O;
+		id.lengthInd := 0; // overwritten
+		id.routingContext := rctx;
+		return id;
+	}
+}
+
+function tr_M3UA_routing_ctx(template octetstring rctx)
+return template M3UA_Routing_Context {
+	var template M3UA_Routing_Context id;
+	if (istemplatekind(rctx, "omit")) {
+		return omit;
+	} else if (istemplatekind(rctx, "*")) {
+		return *;
+	} else {
+		id.tag := '0006'O;
+		id.lengthInd := ?;
+		id.routingContext := rctx;
+		return id;
+	}
+}
+
+template (value) PDU_M3UA ts_M3UA_ASPAC(template (omit) M3UA_Traffic_Mode_Type tmt,
+					template (omit) OCT4 rctx) := {
+	m3UA_ASPAC := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0401'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			traffic_Mode_Type := tmt,
+			routing_Context := ts_M3UA_routing_ctx(rctx),
+			info_String := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_ASPAC(template M3UA_Traffic_Mode_Type tmt,
+					  template OCT4 rctx) := {
+	m3UA_ASPAC := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0401'O,
+		messageLength := ?,
+		messageParameters := {
+			traffic_Mode_Type := tmt,
+			routing_Context := tr_M3UA_routing_ctx(rctx),
+			info_String := *
+		}
+	}
+}
+
+template (value) PDU_M3UA ts_M3UA_ASPAC_ACK(template (omit) M3UA_Traffic_Mode_Type tmt,
+					template (omit) OCT4 rctx) := {
+	m3UA_ASPAC_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0403'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			traffic_Mode_Type := tmt,
+			routing_Context := ts_M3UA_routing_ctx(rctx),
+			info_String := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_ASPAC_ACK(template M3UA_Traffic_Mode_Type tmt,
+					      template OCT4 rctx) := {
+	m3UA_ASPAC_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0403'O,
+		messageLength := ?,
+		messageParameters := {
+			traffic_Mode_Type := tmt,
+			routing_Context := tr_M3UA_routing_ctx(rctx),
+			info_String := *
+		}
+	}
+}
+
+template (value) PDU_M3UA ts_M3UA_ASPIA(template (omit) OCT4 rctx) := {
+	m3UA_ASPIA := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0402'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			routing_Context := ts_M3UA_routing_ctx(rctx),
+			info_String := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_ASPIA(template OCT4 rctx) := {
+	m3UA_ASPIA := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0402'O,
+		messageLength := ?,
+		messageParameters := {
+			routing_Context := tr_M3UA_routing_ctx(rctx),
+			info_String := *
+		}
+	}
+}
+
+
+template (value) PDU_M3UA ts_M3UA_ASPIA_ACK(template (omit) OCT4 rctx) := {
+	m3UA_ASPIA_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0404'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			routing_Context := ts_M3UA_routing_ctx(rctx),
+			info_String := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_ASPIA_ACK(template OCT4 rctx) := {
+	m3UA_ASPIA_Ack := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0404'O,
+		messageLength := ?,
+		messageParameters := {
+			routing_Context := tr_M3UA_routing_ctx(rctx),
+			info_String := *
+		}
+	}
+}
+
+
+/***********************************************************************
+ * MGMT Class
+ ***********************************************************************/
+
+template (value) M3UA_Error_Code ts_M3UA_err_code(template (value) OCT4 val) := {
+	tag := '000C'O,
+	lengthInd := 8,
+	errorCode := val
+}
+template (present) M3UA_Error_Code tr_M3UA_err_code(template (present) OCT4 val) := {
+	tag := '000C'O,
+	lengthInd := 8,
+	errorCode := val
+}
+
+template (value) M3UA_Status ts_M3UA_status(template (value) OCT2 status_type,
+					    template (value) OCT2 status_info) := {
+	tag := '000D'O,
+	lengthInd := 8,
+	statusType := status_type,
+	statusInfo := status_info
+}
+
+template (present) M3UA_Status tr_M3UA_status(template (present) OCT2 status_type,
+					      template (present) OCT2 status_info) := {
+	tag := '000D'O,
+	lengthInd := 8,
+	statusType := status_type,
+	statusInfo := status_info
+}
+
+
+template (value) PDU_M3UA ts_M3UA_ERR(template (value) OCT4 err_code,
+				      template (omit) OCT4 rctx) := {
+	m3UA_ERR := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0000'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			error_Code := ts_M3UA_err_code(err_code),
+			routing_Context := ts_M3UA_routing_ctx(rctx),
+			affected_Point_Codes := omit,
+			network_Appearance := omit,
+			diagnostic_information := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_ERR(template (present) OCT4 err_code,
+				      template OCT4 rctx) := {
+	m3UA_ERR := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0000'O,
+		messageLength := ?,
+		messageParameters := {
+			error_Code := tr_M3UA_err_code(err_code),
+			routing_Context := tr_M3UA_routing_ctx(rctx),
+			affected_Point_Codes := *,
+			network_Appearance := *,
+			diagnostic_information := *
+		}
+	}
+}
+
+
+template (value) PDU_M3UA ts_M3UA_NOTIFY(template (value) OCT2 status_type,
+					 template (value) OCT2 status_info,
+					 template (omit) OCT4 rctx,
+					 template (omit) OCT4 aspid := omit,
+					 template (omit) octetstring infostr := omit) := {
+	m3UA_NOTIFY := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0001'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			status := ts_M3UA_status(status_type, status_info),
+			aSP_Identifier := f_aspid_or_omit(aspid),
+			routing_Context := ts_M3UA_routing_ctx(rctx),
+			info_String := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_NOTIFY(template (present) OCT2 status_type,
+					   template (present) OCT2 status_info,
+					   template OCT4 rctx,
+					   template OCT4 aspid := *,
+					   template octetstring infostr := *) := {
+	m3UA_NOTIFY := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0001'O,
+		messageLength := ?,
+		messageParameters := {
+			status := tr_M3UA_status(status_type, status_info),
+			aSP_Identifier := *,
+			routing_Context := tr_M3UA_routing_ctx(rctx),
+			info_String := *
+		}
+	}
+}
+
+/***********************************************************************
+ * Message Transfer Class
+ ***********************************************************************/
+
+template (value) M3UA_Protocol_Data ts_M3UA_protocol_data(template (value) OCT4 opc,
+							  template (value) OCT4 dpc,
+							  template (value) OCT1 si,
+							  template (value) OCT1 ni,
+							  template (value) OCT1 mp,
+							  template (value) OCT1 sls,
+							  template (value) octetstring data) := {
+	tag := '0210'O,
+	lengthInd := 0, // overwritten
+	oPC := opc,
+	dPC := dpc,
+	sI := si,
+	nI := ni,
+	mP := mp,
+	sLS := sls,
+	userProtocolData := data
+}
+template (present) M3UA_Protocol_Data tr_M3UA_protocol_data(template (present) OCT4 opc,
+							  template (present) OCT4 dpc,
+							  template (present) OCT1 si,
+							  template (present) OCT1 ni,
+							  template (present) OCT1 mp,
+							  template (present) OCT1 sls,
+							  template (present) octetstring data) := {
+	tag := '0210'O,
+	lengthInd := ?,
+	oPC := opc,
+	dPC := dpc,
+	sI := si,
+	nI := ni,
+	mP := mp,
+	sLS := sls,
+	userProtocolData := data
+}
+
+
+template (value) PDU_M3UA ts_M3UA_DATA(template (omit) OCT4 rctx,
+				       template (value) M3UA_Protocol_Data data) := {
+	m3UA_DATA := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0101'O,
+		messageLength := 0, // overwritten
+		messageParameters :={
+			network_Appearance := omit,
+			routing_Context := ts_M3UA_routing_ctx(rctx),
+			protocol_Data := data,
+			correlation_ID := omit
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_DATA(template OCT4 rctx,
+				       template (present) M3UA_Protocol_Data data) := {
+	m3UA_DATA := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0101'O,
+		messageLength := ?, // overwritten
+		messageParameters := {
+			network_Appearance := *,
+			routing_Context := tr_M3UA_routing_ctx(rctx),
+			protocol_Data := data,
+			correlation_ID := *
+		}
+	}
+}
+
+/***********************************************************************
+ * Routing Key Management
+ ***********************************************************************/
+
+template (value) M3UA_Local_Routing_Key_Id ts_M3UA_lrkid(template (value) OCT4 id) := {
+	tag := '020a'O,
+	lengthInd := 8,
+	localRkId := id
+}
+
+template (present) M3UA_Local_Routing_Key_Id tr_M3UA_lrkid(template (present) OCT4 id) := {
+	tag := '020a'O,
+	lengthInd := 8,
+	localRkId := id
+}
+
+
+template (value) M3UA_Routing_Key ts_M3UA_rkey(OCT4 id, OCT3 dpc,
+						template (omit) M3UA_Traffic_Mode_Type tmt := omit,
+						template (omit) OCT4 rctx := omit) := {
+	tag := '0207'O,
+	lengthInd := 0, // overwritten
+	routingKey := {
+		local_Routing_Key_Id := ts_M3UA_lrkid(id),
+		routing_Context := ts_M3UA_routing_ctx(rctx),
+		traffic_Mode_Type := tmt,
+		destination_Point_Code := {
+			tag := '020b'O,
+			lengthInd := 8,
+			pointCode := { '00'O, dpc }
+		},
+		network_Appearance := omit,
+		service_Indicators := omit,
+		opc_List := omit
+	}
+}
+template (present) M3UA_Routing_Key tr_M3UA_rkey(template (present) OCT4 id, template (present) OCT3 dpc,
+						template M3UA_Traffic_Mode_Type tmt := *,
+						template OCT4 rctx := *) := {
+	tag := '0207'O,
+	lengthInd := ?,
+	routingKey := {
+		local_Routing_Key_Id := tr_M3UA_lrkid(id),
+		routing_Context := tr_M3UA_routing_ctx(rctx),
+		traffic_Mode_Type := tmt,
+		destination_Point_Code := {
+			tag := '020b'O,
+			lengthInd := 8,
+			pointCode := { '00'O, dpc }
+		},
+		network_Appearance := omit,
+		service_Indicators := omit,
+		opc_List := omit
+	}
+}
+
+
+const OCT4 c_M3UA_REGSTS_SUCCESS := '00000000'O;
+const OCT4 c_M3UA_REGSTS_ERR_UNKNOWN := '00000001'O;
+const OCT4 c_M3UA_REGSTS_ERR_INVAL_DPC := '00000002'O;
+const OCT4 c_M3UA_REGSTS_ERR_INVAL_NA := '00000003'O;
+const OCT4 c_M3UA_REGSTS_ERR_INVAL_RKEY := '00000004'O;
+const OCT4 c_M3UA_REGSTS_ERR_EPERM := '00000005'O;
+// ...
+
+const OCT4 c_m3UA_DEREGSTS_SUCCESS := '00000000'O;
+const OCT4 c_m3UA_DEREGSTS_ERR_UNKNOWN := '00000001'O;
+const OCT4 c_m3UA_DEREGSTS_ERR_INVAL_RCTX := '00000002'O;
+const OCT4 c_m3UA_DEREGSTS_ERR_EPERM := '00000003'O;
+const OCT4 c_m3UA_DEREGSTS_ERR_NOT_REG := '00000004'O;
+const OCT4 c_m3UA_DEREGSTS_ERR_ASP_ACTIVE := '00000005'O;
+
+template (value) M3UA_Registration_Result ts_M3UA_reg_res(template (value) OCT4 id,
+							    template (value) OCT4 status,
+							    template (value) OCT4 rctx) := {
+	tag := '0208'O,
+	lengthInd := 0, // overwritten
+	registrationResult := {
+		local_Routing_Key_Id := ts_M3UA_lrkid(id),
+		registration_Status := {
+			tag := '0212'O,
+			lengthInd := 8,
+			registrationStatus := status
+		},
+		routing_Context := ts_M3UA_routing_ctx(rctx)
+	}
+}
+template (present) M3UA_Registration_Result tr_M3UA_reg_res(template (present) OCT4 id,
+							    template (present) OCT4 status,
+							    template (present) OCT4 rctx) := {
+	tag := '0208'O,
+	lengthInd := ?,
+	registrationResult := {
+		local_Routing_Key_Id := tr_M3UA_lrkid(id),
+		registration_Status := {
+			tag := '0212'O,
+			lengthInd := 8,
+			registrationStatus := status
+		},
+		routing_Context := tr_M3UA_routing_ctx(rctx)
+	}
+}
+
+template (value) M3UA_Deregistration_Result ts_M3UA_dereg_res(template (value) OCT4 rctx,
+							      template (value) OCT4 status) := {
+	tag := '0209'O,
+	lengthInd := 0, // overwritten
+	deregistrationResult := {
+		routing_Context := ts_M3UA_routing_ctx(rctx),
+		deregistration_Status := {
+			tag := '0213'O,
+			lengthInd := 8,
+			deregistrationStatus := status
+		}
+	}
+}
+template (present) M3UA_Deregistration_Result tr_M3UA_dereg_res(template (present) OCT4 rctx,
+								template (present) OCT4 status) := {
+	tag := '0209'O,
+	lengthInd := ?,
+	deregistrationResult := {
+		routing_Context := tr_M3UA_routing_ctx(rctx),
+		deregistration_Status := {
+			tag := '0213'O,
+			lengthInd := 8,
+			deregistrationStatus := status
+		}
+	}
+}
+
+
+template (value) PDU_M3UA ts_M3UA_REG_REQ(template (value) M3UA_Routing_Keys rkeys) := {
+	m3UA_REG_REQ := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0901'O,
+		messageLength := 0, // overwritten
+		messageParameters := rkeys
+	}
+}
+template (present) PDU_M3UA tr_M3UA_REG_REQ(template (present) M3UA_Routing_Keys rkeys) := {
+	m3UA_REG_REQ := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0901'O,
+		messageLength := ?,
+		messageParameters := rkeys
+	}
+}
+
+
+template (value) PDU_M3UA ts_M3UA_REG_RSP(template (value) M3UA_Registration_Results res) := {
+	m3UA_REG_RSP := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0902'O,
+		messageLength := 0, // overwritten
+		messageParameters := res
+	}
+}
+template (present) PDU_M3UA tr_M3UA_REG_RSP(template (present) M3UA_Registration_Results res) := {
+	m3UA_REG_RSP := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0902'O,
+		messageLength := ?,
+		messageParameters := res
+	}
+}
+
+template (value) PDU_M3UA ts_M3UA_DEREG_REQ(template (value) M3UA_Routing_Context rctx) := {
+	m3UA_DEREG_REQ := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0903'O,
+		messageLength := 0, // overwritten
+		messageParameters := {
+			routing_Context := rctx
+		}
+	}
+}
+template (present) PDU_M3UA tr_M3UA_DEREG_REQ(template (present) M3UA_Routing_Context rctx) := {
+	m3UA_DEREG_REQ := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0903'O,
+		messageLength := ?,
+		messageParameters := {
+			routing_Context := rctx
+		}
+	}
+}
+
+template (value) PDU_M3UA ts_M3UA_DEREG_RSP(template (value) M3UA_Deregistration_Results res) := {
+	m3UA_DEREG_RSP := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0904'O,
+		messageLength := 0, // overwritten
+		messageParameters := res
+	}
+}
+template (present) PDU_M3UA tr_M3UA_DEREG_RSP(template (present) M3UA_Deregistration_Results res) := {
+	m3UA_DEREG_RSP := {
+		version := c_M3UA_VERSION,
+		reserved := '00'O,
+		messageClassAndType := '0904'O,
+		messageLength := ?,
+		messageParameters := res
+	}
+}
+
+
+
+}
diff --git a/library/SCCP_Templates.ttcn b/library/SCCP_Templates.ttcn
index a5af073..7c2ffa6 100644
--- a/library/SCCP_Templates.ttcn
+++ b/library/SCCP_Templates.ttcn
@@ -46,4 +46,25 @@
 	}
 }
 
+/* construct a SCCP_PAR_Address with PC + SSN and GT */
+template (value) SCCP_PAR_Address ts_SccpAddr_PC_GT(integer pc, octetstring sio,
+						    charstring sccp_srv_type, hexstring gt_addr) := {
+	addressIndicator := {
+		pointCodeIndic := '1'B,
+		ssnIndicator := '0'B,
+		globalTitleIndic := '0001'B, // NAI only
+		routingIndicator := cg_route_on_GT // route on GT
+	},
+	signPointCode := SCCP_SPC_int2bit(pc, sccp_srv_type, sio),
+	subsystemNumber := omit,
+	globalTitle := {
+		gti0001 := {
+			natureOfAddress := '0000011'B,
+			oddeven := '0'B,
+			globalTitleAddress := gt_addr
+		}
+	}
+}
+
+
 }