asterisk: Initial steps to emulate IMS core

Add the initial infrastructure to manage 2 SIPmsg_PT ports, one for the
local SIP UAs and one for the IMS core.
Still missing:
* Trigger Asterisk (through AMI) to do the initial connect + register to it
* Configure ipsec after Unauthorized response from IMS core

Change-Id: Ibbbadd54b7facf4ef7384499704e742f482a1252
diff --git a/asterisk/Asterisk_Tests.default b/asterisk/Asterisk_Tests.default
index 0996545..622a5a9 100644
--- a/asterisk/Asterisk_Tests.default
+++ b/asterisk/Asterisk_Tests.default
@@ -4,7 +4,8 @@
 mtc.FileMask := ERROR | WARNING | PARALLEL | VERDICTOP;
 
 [TESTPORT_PARAMETERS]
-*.*.DEBUG := "yes"
+#*.*.DEBUG := "yes"
+#*.*.debug := "enabled"
 *.AMI.PROMPT1 := "Asterisk Call Manager/9.0.0\n"
 *.AMI.PROMPT2 := "\n"
 #*.AMI.REGEX_PROMPT1 := "^Asterisk Call Manager.*$"
@@ -16,11 +17,20 @@
 *.AMI.CTRL_READMODE := "buffered"
 *.AMI.CTRL_CLIENT_CLEANUP_LINEFEED := "yes"
 *.AMI.CTRL_CRLF := "yes"
-*.SIP.local_sip_port := "5060"
-*.SIP.default_local_address := "127.0.0.2"
-*.SIP.default_sip_protocol := "UDP"
-*.SIP.default_dest_port := "5060"
-*.SIP.default_dest_address := "127.0.0.1"
+# Local SIP UAs:
+Asterisk_Tests_LOCAL_SIP_EMU.SIP.default_sip_protocol := "UDP";
+Asterisk_Tests_LOCAL_SIP_EMU.SIP.local_sip_port := "5060"
+Asterisk_Tests_LOCAL_SIP_EMU.SIP.default_local_address := "127.0.0.2"
+Asterisk_Tests_LOCAL_SIP_EMU.SIP.default_dest_port := "5060"
+Asterisk_Tests_LOCAL_SIP_EMU.SIP.default_dest_address := "127.0.0.1"
+# IMS Core:
+Asterisk_Tests_IMS_SIP_EMU.SIP.default_sip_protocol := "TCP";
+Asterisk_Tests_IMS_SIP_EMU.SIP.listen_enabled := "enabled";
+Asterisk_Tests_IMS_SIP_EMU.SIP.local_sip_port := "5060"
+Asterisk_Tests_IMS_SIP_EMU.SIP.default_local_address := "127.0.0.3"
+# Disabled for Server mode:
+#Asterisk_Tests_IMS_SIP_EMU.SIP.default_dest_address := "127.0.0.1"
+#Asterisk_Tests_IMS_SIP_EMU.SIP.default_dest_port := "5060"
 
 [MODULE_PARAMETERS]
 
diff --git a/asterisk/Asterisk_Tests.ttcn b/asterisk/Asterisk_Tests.ttcn
index caa941c..c94f97f 100644
--- a/asterisk/Asterisk_Tests.ttcn
+++ b/asterisk/Asterisk_Tests.ttcn
@@ -27,6 +27,7 @@
 import from SIP_Templates all;
 
 import from SIP_ConnectionHandler all;
+import from IMS_ConnectionHandler all;
 
 modulepar {
 	charstring mp_local_sip_host := "127.0.0.2";
@@ -34,15 +35,24 @@
 	charstring mp_remote_sip_host := "127.0.0.1";
 	integer mp_remote_sip_port := 5060;
 
+	charstring mp_local_ims_host := "127.0.0.3";
+	integer mp_local_ims_port := 5060;
+
 	/* Asterisk AMI: */
 	charstring mp_ami_user := "test_user";
 	charstring mp_ami_secret := "1234";
 }
 
 type component test_CT {
+	/* Manages all local VoIP users Asterisk is serving: */
 	var SIP_Emulation_CT vc_SIP;
+	/* Manages the IMS server Asterisk connects to: */
+	var SIP_Emulation_CT vc_IMS;
+
 	port TELNETasp_PT AMI;
+
 	port Coord_PT COORD;
+	port IMSCoord_PT IMS_COORD;
 }
 
 const charstring broadcast_sip_extension := "0500";
@@ -64,9 +74,24 @@
 	f_ami_action_login(AMI, mp_ami_user, mp_ami_secret);
 }
 
+/* Local SIP UAs */
+private function f_init_sip_local() runs on test_CT {
+	var charstring id := "Asterisk_Tests_LOCAL_SIP_EMU";
+	f_init_sip(vc_SIP, id);
+}
+
+/* IMS Server connection */
+private function f_init_sip_ims() runs on test_CT {
+	var charstring id := "Asterisk_Tests_IMS_SIP_EMU";
+	f_init_sip(vc_IMS, id);
+}
+
 function f_init() runs on test_CT {
+	var charstring id;
+
 	f_init_ami();
-	f_init_sip(vc_SIP, "Asterisk_Test_SIP_EMU");
+	f_init_sip_local();
+	f_init_sip_ims();
 	log("end of f_init");
 }
 
diff --git a/asterisk/IMS_ConnectionHandler.ttcn b/asterisk/IMS_ConnectionHandler.ttcn
new file mode 100644
index 0000000..a1baeb4
--- /dev/null
+++ b/asterisk/IMS_ConnectionHandler.ttcn
@@ -0,0 +1,88 @@
+/* Component implementing a IMS server towards Asterisk's IMS UE
+ * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ * 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
+ */
+module IMS_ConnectionHandler {
+
+import from TCCOpenSecurity_Functions all;
+import from General_Types all;
+import from Osmocom_Types all;
+import from Native_Functions all;
+import from Misc_Helpers all;
+
+import from SDP_Types all;
+import from SDP_Templates all;
+
+import from SIP_Emulation all;
+import from SIPmsg_Types all;
+import from SIP_Templates all;
+
+type port IMSCoord_PT message
+{
+	inout charstring;
+} with { extension "internal" };
+
+const charstring IMS_COORD_CMD_REGISTERED := "COORD_CMD_REGISTERED";
+
+type component IMS_ConnHdlr extends SIP_ConnHdlr {
+	var charstring g_name;
+	var IMS_ConnHdlrPars g_pars;
+	timer g_Tguard;
+	var PDU_SIP_Request g_rx_sip_req;
+	var PDU_SIP_Response g_rx_sip_resp;
+
+	port IMSCoord_PT COORD;
+}
+type record of IMS_ConnHdlr IMS_ConnHdlrList;
+
+type record IMS_ConnHdlrPars {
+	float t_guard,
+	charstring remote_sip_host,
+	uint16_t remote_sip_port,
+	charstring user,
+	charstring display_name,
+	charstring password,
+	SipUrl registrar_sip_req_uri,
+	SipAddr registrar_sip_record,
+	CallidString registrar_sip_call_id,
+	integer registrar_sip_seq_nr,
+	Via local_via,
+	SipUrl local_sip_url_ext,
+	SipAddr local_sip_record,
+	Contact local_contact,
+	IMS_CallPars cp optional
+}
+type record of IMS_ConnHdlrPars IMS_ConnHdlrParsList;
+
+type record IMS_CallParsMT {
+	/* Whether to wait for COORD.receive(COORD_CMD_PICKUP) before accepting the call. */
+	boolean wait_coord_cmd_pickup,
+	/* Whether to expect CANCEL instead of ACK as answer to our OK */
+	boolean exp_cancel
+}
+
+type record IMS_CallPars {
+	SipAddr calling optional,
+	SipAddr called optional,
+
+	SipAddr from_addr optional,
+	SipAddr to_addr optional,
+
+	CallidString sip_call_id,
+	integer sip_seq_nr,
+	charstring sip_body optional,
+
+	charstring local_rtp_addr,
+	uint16_t local_rtp_port,
+
+	SDP_Message peer_sdp optional,
+	IMS_CallParsMT mt
+}
+
+}