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/stp/STP_Tests.ttcn b/stp/STP_Tests.ttcn
new file mode 100644
index 0000000..023c53d
--- /dev/null
+++ b/stp/STP_Tests.ttcn
@@ -0,0 +1,249 @@
+module STP_Tests {
+
+/* Osmocom STP test suite in in TTCN-3
+ * (C) 2019 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 General_Types all;
+import from Osmocom_Types all;
+import from IPL4asp_Types all;
+
+import from Osmocom_VTY_Functions all;
+
+import from M3UA_Types all;
+import from M3UA_Templates all;
+import from M3UA_CodecPort all;
+import from M3UA_CodecPort_CtrlFunct all;
+
+import from M3UA_Emulation all;
+import from MTP3asp_Types all;
+import from MTP3asp_PortType all;
+
+import from SCCP_Types all;
+import from SCCP_Templates all;
+import from SCCPasp_Types all;
+import from SCCP_Emulation all;
+
+import from IPA_Emulation all;
+
+import from STP_Tests_Common all;
+import from STP_Tests_IPA all;
+import from STP_Tests_M3UA all;
+
+
+type component IPA_M3UA_CT extends RAW_M3UA_CT, IPA_CT {
+};
+
+const OCT1 c_M3UA_SI_SCCP := '03'O;
+
+
+/* copy+pasted from SCCP_Emulation.ttcn, where for some reason it is marked as "runs on SCCP_CT"
+ * without depending on anything of that component */
+  function ConvertASPAddressToEncodedAddress_itu( in SCCP_PAR_Address pl_ASPAddress)
+    return SCCP_param_CPartyAddressEnc
+  {
+
+    var SCCP_param_CPartyAddress_itu vl_PDUAddress; //structured fit to encoding
+    var SCCP_param_CPartyAddressEnc vl_PDUAddressEncoded;
+
+    vl_PDUAddress.addressIndicator.pointCodeIndic:=
+      pl_ASPAddress.addressIndicator.pointCodeIndic;
+
+    vl_PDUAddress.addressIndicator.ssnIndicator:=
+      pl_ASPAddress.addressIndicator.ssnIndicator;
+
+    vl_PDUAddress.addressIndicator.globalTitleIndic:=
+     pl_ASPAddress.addressIndicator.globalTitleIndic;
+
+    vl_PDUAddress.addressIndicator.routingIndicator:=
+      pl_ASPAddress.addressIndicator.routingIndicator;
+
+    vl_PDUAddress.addressIndicator.reserved:='0'B;
+    // if (ischosen(pl_ASPAddress.signPointCode) ) not used because it is mandatory field (???)
+
+    //----signPointCode handling
+    if ( ispresent( pl_ASPAddress.signPointCode )) {
+      vl_PDUAddress.signPointCode :=
+        '00'B&pl_ASPAddress.signPointCode;
+    } else {
+      vl_PDUAddress.signPointCode := omit;
+    };
+
+    //----subsystemNumber handling
+    if ( ispresent( pl_ASPAddress.subsystemNumber ) ){
+      vl_PDUAddress.subsystemNumber := pl_ASPAddress.subsystemNumber;
+    } else {
+      vl_PDUAddress.subsystemNumber :=omit;
+    };
+
+    // --- globalTitle handling--
+    if ( ispresent(pl_ASPAddress.globalTitle))
+    {//startif1
+
+      var SCCP_ASPfield_GlobalTitle tmpGT ;
+      tmpGT := pl_ASPAddress.globalTitle;
+
+      if (ischosen(tmpGT.gti0001))
+      {
+        vl_PDUAddress.globalTitle.gti0001.natureOfAddress:=tmpGT.gti0001.natureOfAddress;
+        vl_PDUAddress.globalTitle.gti0001.oddeven:=tmpGT.gti0001.oddeven;
+        vl_PDUAddress.globalTitle.gti0001.globalTitleAddress:=tmpGT.gti0001.globalTitleAddress;
+      }
+      else if (ischosen(tmpGT.gti0010))
+      {
+        vl_PDUAddress.globalTitle.gti0010.translationType:=tmpGT.gti0010.translationType;
+        vl_PDUAddress.globalTitle.gti0010.globalTitleAddress:=tmpGT.gti0010.globalTitleAddress;
+      }
+      else if (ischosen(tmpGT.gti0011))
+      {
+        vl_PDUAddress.globalTitle.gti0011.translationType:=tmpGT.gti0011.translationType;
+        vl_PDUAddress.globalTitle.gti0011.encodingScheme:=tmpGT.gti0011.encodingScheme;
+        vl_PDUAddress.globalTitle.gti0011.numberingPlan:=tmpGT.gti0011.numberingPlan;
+        vl_PDUAddress.globalTitle.gti0011.globalTitleAddress:=tmpGT.gti0011.globalTitleAddress;
+      }
+      else if (ischosen(tmpGT.gti0100))
+      {
+        vl_PDUAddress.globalTitle.gti0100.translationType:=tmpGT.gti0100.translationType;
+        vl_PDUAddress.globalTitle.gti0100.encodingScheme:=tmpGT.gti0100.encodingScheme;
+        vl_PDUAddress.globalTitle.gti0100.numberingPlan:=tmpGT.gti0100.numberingPlan;
+        vl_PDUAddress.globalTitle.gti0100.natureOfAddress:=tmpGT.gti0100.natureOfAddress;
+        vl_PDUAddress.globalTitle.gti0100.reserved:='0'B;
+        vl_PDUAddress.globalTitle.gti0100.globalTitleAddress:=tmpGT.gti0100.globalTitleAddress;
+      }
+    }
+    else
+    {
+        vl_PDUAddress.globalTitle := omit;
+    };
+
+    vl_PDUAddressEncoded.addr:= enc_PDU_SCCP_Address_itu( vl_PDUAddress);
+    vl_PDUAddressEncoded.paramLength:= lengthof(vl_PDUAddressEncoded.addr);
+
+    return vl_PDUAddressEncoded;
+
+  } //ConvertASPAddressToEncodedAddress_itu
+
+template (value) PDU_SCCP ts_SCCP_UDT(SCCP_PAR_Address called, SCCP_PAR_Address calling,
+					template (value) octetstring data,
+					template (value) BIT4 msg_hdl := '0000'B) := {
+	unitdata := {
+		messageType := udt,
+		protClass := {'0000'B, msg_hdl},
+		pointer1 := 0,
+		pointer2 := 0,
+		pointer3 := 0,
+		calledPAddress := ConvertASPAddressToEncodedAddress_itu(called),
+		callingPAddress := ConvertASPAddressToEncodedAddress_itu(calling),
+		data := {
+			paramLength := 0,
+			data := data
+		}
+	}
+}
+
+/* Test routing of SCCP between an M3UA and an IPA ASP */
+testcase TC_m3ua_to_ipa() runs on IPA_M3UA_CT {
+	var OCT4 rctx_sender := int2oct(1023, 4);
+	var OCT4 pc_sender := int2oct(23, 4);
+	var OCT4 pc_receiver := int2oct(5, 4);
+
+	f_init_m3ua();
+	f_init_ipa();
+
+	f_M3UA_asp_up_act(0, omit, omit); // TODO: rctx
+
+	/* send a well-formed, encoded SCCP message via M3UA */
+	var octetstring data := f_rnd_octstring(f_rnd_int(100));
+	var SCCP_PAR_Address called := valueof(ts_SccpAddr_GT('1234'H));
+	var SCCP_PAR_Address calling := valueof(ts_SccpAddr_GT('5678'H));
+	var PDU_SCCP sccp := valueof(ts_SCCP_UDT(called, calling, data));
+	var octetstring sccp_enc := enc_PDU_SCCP(sccp);
+	var template (value) M3UA_Protocol_Data tx_pd;
+	tx_pd := ts_M3UA_protocol_data(pc_sender, pc_receiver, c_M3UA_SI_SCCP, '00'O, '00'O, '00'O, sccp_enc);
+	f_M3UA_send(0, ts_M3UA_DATA(rctx_sender, tx_pd), 1);
+
+	/* expect to receive it via IPA */
+	f_IPA_exp(0, sccp_enc);
+}
+
+/* test routing an SCCP message from IPA ASP to M3UA ASP */
+testcase TC_ipa_to_m3ua() runs on IPA_M3UA_CT {
+	var OCT4 pc_sender := int2oct(5, 4);
+	var OCT4 rctx_receiver := int2oct(1023, 4);
+	var OCT4 pc_receiver := int2oct(23, 4);
+
+	f_init_common();
+	f_vty_config2(VTY, {"cs7 instance 0", "as mahlzeit ipa"},
+		      "point-code override patch-sccp disabled");
+
+	f_init_m3ua();
+	f_init_ipa();
+
+	f_M3UA_asp_up_act(0, omit, omit); // TODO: rctx
+
+	/* send a well-formed, encoded SCCP message via IPA */
+	var octetstring data := f_rnd_octstring(f_rnd_int(100));
+	var SCCP_PAR_Address called := valueof(ts_SccpAddr_GT('1234'H));
+	var SCCP_PAR_Address calling := valueof(ts_SccpAddr_GT('5678'H));
+	var PDU_SCCP sccp := valueof(ts_SCCP_UDT(called, calling, data));
+	var octetstring sccp_enc := enc_PDU_SCCP(sccp);
+	f_IPA_send(0, sccp_enc);
+
+	/* expect to receive it via M3UA */
+	var template (present) M3UA_Protocol_Data rx_pd;
+	rx_pd := tr_M3UA_protocol_data(pc_sender, pc_receiver, c_M3UA_SI_SCCP, '00'O, '00'O, '00'O, sccp_enc);
+	f_M3UA_exp(0, tr_M3UA_DATA(rctx_receiver, rx_pd));
+}
+
+/* test routing an SCCP message from IPA ASP to M3UA ASP while patching PC into SCCP addresses */
+testcase TC_ipa_to_m3ua_patch_sccp() runs on IPA_M3UA_CT {
+	var OCT4 pc_sender := int2oct(5, 4);
+	var OCT4 rctx_receiver := int2oct(1023, 4);
+	var OCT4 pc_receiver := int2oct(23, 4);
+
+	f_init_common();
+	f_vty_config2(VTY, {"cs7 instance 0", "as mahlzeit ipa"},
+			"point-code override patch-sccp both");
+
+	f_init_m3ua();
+	f_init_ipa();
+
+	f_M3UA_asp_up_act(0, omit, omit); // TODO: rctx
+
+	/* send a well-formed, encoded SCCP message via IPA */
+	var octetstring data := f_rnd_octstring(f_rnd_int(100));
+	var SCCP_PAR_Address called := valueof(ts_SccpAddr_GT('1234'H));
+	var SCCP_PAR_Address calling := valueof(ts_SccpAddr_GT('5678'H));
+	var PDU_SCCP sccp := valueof(ts_SCCP_UDT(called, calling, data));
+	f_IPA_send(0, enc_PDU_SCCP(sccp));
+
+	/* patch point codes into addresses */
+	called := valueof(ts_SccpAddr_PC_GT(oct2int(pc_receiver), '83'O, "mtp3_itu", '1234'H));
+	calling := valueof(ts_SccpAddr_PC_GT(oct2int(pc_sender), '83'O, "mtp3_itu", '5678'H));
+	var PDU_SCCP sccp_exp := valueof(ts_SCCP_UDT(called, calling, data));
+
+	/* expect to receive it via M3UA */
+	var template (present) M3UA_Protocol_Data rx_pd;
+	rx_pd := tr_M3UA_protocol_data(pc_sender, pc_receiver, c_M3UA_SI_SCCP, '00'O, '00'O, '00'O,
+					enc_PDU_SCCP(sccp_exp));
+	f_M3UA_exp(0, tr_M3UA_DATA(rctx_receiver, rx_pd));
+}
+
+
+
+control {
+	/* M3UA <-> IPA Tests */
+	execute( TC_m3ua_to_ipa() );
+	execute( TC_ipa_to_m3ua() );
+	execute( TC_ipa_to_m3ua_patch_sccp() );
+}
+
+
+
+}