asterisk: Introduce TC_ims_call_mo

The test validates establishing and hanging up a MO call:
SIP-UA -> Asterisk -> IMS-CORE.

SYS#6782
Change-Id: I3c6d8c109c392fa6e1036dcb69a7abb90b22fec7
diff --git a/asterisk/Asterisk_Tests.default b/asterisk/Asterisk_Tests.default
index 24c53e3..1de9def 100644
--- a/asterisk/Asterisk_Tests.default
+++ b/asterisk/Asterisk_Tests.default
@@ -1,5 +1,5 @@
 [LOGGING]
-FileMask := LOG_ALL | TTCN_MATCHING;
+FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC;
 mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC;
 
 [TESTPORT_PARAMETERS]
diff --git a/asterisk/Asterisk_Tests.ttcn b/asterisk/Asterisk_Tests.ttcn
index e7d0616..4ac7eaf 100644
--- a/asterisk/Asterisk_Tests.ttcn
+++ b/asterisk/Asterisk_Tests.ttcn
@@ -65,6 +65,14 @@
 
 const charstring broadcast_sip_extension := "0500";
 
+/* TODO: need to find correct RES, CK, IK, values for:
+ * Response: "a19de225d030e6e0ec20f6de5f9dd80d"
+ * CNonce Value: "9a6460bcc3c84a3eac69455a93b67a77"
+ */
+const charstring c_auth_res := "a19de225d030e6e0";
+const charstring c_auth_ck := "9a6460bcc3c84a3eac69455a93b67a77";
+const charstring c_auth_ik := "5238297dfcca759bd05d48ff49bc63fa";
+
 function f_init_ConnHdlrPars(integer idx := 1) runs on test_CT return SIPConnHdlrPars {
 	var template (value) CallPars cp := t_CallPars(mp_local_sip_host, 1234 + 2*idx);
 	var template (value) SIPConnHdlrPars pars := t_Pars(mp_local_sip_host,
@@ -163,7 +171,7 @@
 function f_start_handler_IMS(ims_void_fn fn, IMS_ConnHdlrPars pars)
 runs on test_CT return IMS_ConnHdlr {
 	var IMS_ConnHdlr vc_conn;
-	var charstring id := testcasename() & "-IMS_ConnHdlr-" & pars.user;
+	var charstring id := testcasename() & "-IMS_ConnHdlr-" & pars.subscr.imsi;
 
 	vc_conn := IMS_ConnHdlr.create(id) alive;
 
@@ -359,9 +367,43 @@
 	setverdict(pass);
 }
 
+private function f_AMI_IMS_register(IMS_ConnHdlrPars pars) runs on test_CT
+{
+	/* Give some time for IMS_ConnHdlr to register SIP expect. This could be done through IMS_COORD. */
+	f_sleep(1.0);
+	/* Clear events: */
+	AMI_CLIENT.clear;
+
+	/* Announce network information, this should usually happen when UE
+	 * becomes attached to network and before IMS APN is set up: */
+	f_ami_action_PJSIPAccessNetworkInfo(AMI_CLIENT, mp_volte_ims_outbound_registration,
+					    f_ami_gen_PJSIPAccessNetworkInfo_Info_EUTRAN(pars.subscr.uli_str));
+
+	/* Trigger registration: */
+	f_ami_action_PJSIPRegister(AMI_CLIENT, mp_volte_ims_outbound_registration);
+
+	var charstring rand_str := oct2str(pars.subscr.rand);
+	var charstring autn_str := oct2str(pars.subscr.autn);
+	AMI_CLIENT.receive(tr_AMI_Event_AuthRequest(mp_volte_ims_outbound_registration,
+						    rand := pattern @nocase rand_str,
+						    autn := pattern @nocase autn_str));
+
+	f_ami_action_AuthResponse_RES(AMI_CLIENT,
+				      mp_volte_ims_outbound_registration,
+				      c_auth_res, c_auth_ck, c_auth_ik);
+
+	AMI_CLIENT.receive(tr_AMI_Event_Registry(f_sip_SipAddr_to_str(pars.subscr.local_sip_record),
+						 "sip:" & mp_local_ims_host,
+						 "Registered"));
+
+	 /* TODO: test "Action: PJSIPUnregister" */
+
+	 /* TODO: in another test emulating a call, test "Action: DedicatedBearerStatus" */
+}
+
 /* Test SIP registration of local clients */
 private function f_TC_ims_registration(charstring id) runs on IMS_ConnHdlr {
-	f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.registrar_sip_record.addr)));
+	f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.subscr.registrar_sip_record.addr)));
 	as_IMS_register();
 	setverdict(pass);
 }
@@ -372,46 +414,67 @@
 	pars := f_init_IMS_ConnHdlrPars();
 	vc_conn := f_start_handler_IMS(refers(f_TC_ims_registration), pars);
 
-	/* Give some time for IMS_ConnHdlr to register SIP expect. This could be done through IMS_COORD. */
-	f_sleep(1.0);
-	/* Clear events: */
-	AMI_CLIENT.clear;
-
-	/* Announce network information, this should usually happen when UE
-	 * becomes attached to network and before IMS APN is set up: */
-	f_ami_action_PJSIPAccessNetworkInfo(AMI_CLIENT, mp_volte_ims_outbound_registration,
-					    f_ami_gen_PJSIPAccessNetworkInfo_Info_EUTRAN(pars.uli_str));
-
-	/* Trigger registration: */
-	f_ami_action_PJSIPRegister(AMI_CLIENT, mp_volte_ims_outbound_registration);
-
-	var charstring rand_str := oct2str(pars.rand);
-	var charstring autn_str := oct2str(pars.autn);
-	AMI_CLIENT.receive(tr_AMI_Event_AuthRequest(mp_volte_ims_outbound_registration,
-						    rand := pattern @nocase rand_str,
-						    autn := pattern @nocase autn_str));
-	/* TODO: need to find correct RES, CK, IK, values for:
-	 * Response: "a19de225d030e6e0ec20f6de5f9dd80d"
-	 * CNonce Value: "9a6460bcc3c84a3eac69455a93b67a77"
-	 */
-	f_ami_action_AuthResponse_RES(AMI_CLIENT,
-				  mp_volte_ims_outbound_registration,
-				  res := "a19de225d030e6e0",
-				  ck := "9a6460bcc3c84a3eac69455a93b67a77",
-				  ik := "5238297dfcca759bd05d48ff49bc63fa");
-
-	AMI_CLIENT.receive(tr_AMI_Event_Registry(f_sip_SipAddr_to_str(pars.local_sip_record),
-						 "sip:" & mp_local_ims_host,
-						 "Registered"));
-
-	 /* TODO: test "Action: PJSIPUnregister" */
-
-	 /* TODO: in another test emulating a call, test "Action: DedicatedBearerStatus" */
+	f_AMI_IMS_register(pars);
 
 	vc_conn.done;
 	f_shutdown();
 }
 
+/* Test SIP registration of local clients */
+private function f_TC_ims_call_mo(charstring id) runs on IMS_ConnHdlr {
+	f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.subscr.registrar_sip_record.addr)));
+	if (ispresent(g_pars.subscr.cp.called)) {
+		f_create_sip_expect(valueof(ts_SipUrl_from_Addr_Union(g_pars.subscr.cp.called.addr)));
+	}
+	as_IMS_register();
+	setverdict(pass);
+	as_IMS_mo_call_accept();
+	setverdict(pass);
+	COORD.send(COORD_CMD_CALL_ESTABLISHED);
+	as_IMS_exp_call_hangup(g_pars.subscr.cp.sip_seq_nr + 1);
+	setverdict(pass);
+}
+testcase TC_ims_call_mo() runs on test_CT {
+	var SIPConnHdlrPars sip_pars;
+	var IMS_ConnHdlrPars ims_pars;
+	var SIPConnHdlr vc_conn_sip;
+	var IMS_ConnHdlr vc_conn_ims;
+	const charstring c_ext_msisdn := "90829";
+
+	f_init();
+
+	sip_pars := f_init_ConnHdlrPars(idx := 1);
+	ims_pars := f_init_IMS_ConnHdlrPars();
+
+	sip_pars.cp.calling := sip_pars.registrar_sip_record;
+	sip_pars.cp.called := valueof(ts_SipAddr(ts_HostPort(sip_pars.remote_sip_host),
+						 ts_UserInfo(c_ext_msisdn)));
+	ims_pars.subscr.cp.calling := valueof(ts_SipAddr(ts_HostPort(ims_pars.local_sip_host),
+							 ts_UserInfo(ims_pars.subscr.msisdn)));
+	ims_pars.subscr.cp.called := valueof(ts_SipAddr(ts_HostPort(ims_pars.local_sip_host),
+							ts_UserInfo(c_ext_msisdn)));
+
+	vc_conn_ims := f_start_handler_IMS(refers(f_TC_ims_call_mo), ims_pars);
+	vc_conn_sip := f_start_handler(refers(f_TC_internal_call_mo), sip_pars);
+
+	COORD.receive(COORD_CMD_REGISTERED) from vc_conn_sip;
+
+	f_AMI_IMS_register(ims_pars);
+
+	COORD.send(COORD_CMD_START) to vc_conn_sip;
+	COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn_sip;
+	IMS_COORD.receive(COORD_CMD_CALL_ESTABLISHED) from vc_conn_ims;
+
+	/* Call on-going */
+	f_sleep(1.0);
+
+	COORD.send(COORD_CMD_HANGUP) to vc_conn_sip;
+
+	vc_conn_sip.done;
+	vc_conn_ims.done;
+	f_shutdown();
+}
+
 control {
 	execute( TC_internal_registration() );
 	execute( TC_internal_call_momt() );
@@ -419,6 +482,7 @@
 	execute( TC_internal_call_all_3registered() );
 	execute( TC_internal_call_all_4registered() );
 	execute( TC_ims_registration() );
+	execute( TC_ims_call_mo() );
 }
 
 }
diff --git a/asterisk/IMS_ConnectionHandler.ttcn b/asterisk/IMS_ConnectionHandler.ttcn
index a253c9f..3f0c380 100644
--- a/asterisk/IMS_ConnectionHandler.ttcn
+++ b/asterisk/IMS_ConnectionHandler.ttcn
@@ -56,14 +56,10 @@
 }
 type record of IMS_ConnHdlr IMS_ConnHdlrList;
 
-type record IMS_ConnHdlrPars {
-	float t_guard,
-	charstring realm,
-	charstring local_sip_host,
-	uint16_t local_sip_port,
+type record IMS_ConnHdlrSubscrPars {
 	charstring remote_sip_host optional,
 	uint16_t remote_sip_port optional,
-	charstring user,
+	charstring imsi,
 	charstring display_name,
 	charstring password,
 	charstring msisdn,
@@ -78,16 +74,26 @@
 	integer ipsec_remote_spi_s optional,
 	uint16_t ipsec_remote_port_c optional,
 	uint16_t ipsec_remote_port_s optional,
-	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_ConnHdlrSubscrPars IMS_ConnHdlrSubscrParsList;
+
+
+type record IMS_ConnHdlrPars {
+	float t_guard,
+	charstring realm,
+	charstring local_sip_host,
+	uint16_t local_sip_port,
+	SipUrl registrar_sip_req_uri,
+	Via local_via,
+	IMS_ConnHdlrSubscrPars subscr optional
+}
 type record of IMS_ConnHdlrPars IMS_ConnHdlrParsList;
 
 type record IMS_CallParsMT {
@@ -105,8 +111,8 @@
 	SipAddr calling optional,
 	SipAddr called optional,
 
-	SipAddr from_addr optional,
-	SipAddr to_addr optional,
+	From from_addr optional,
+	To to_addr optional,
 
 	CallidString sip_call_id,
 	integer sip_seq_nr,
@@ -136,22 +142,19 @@
 	mt := t_IMS_CallParsMT
 }
 
-template (value) IMS_ConnHdlrPars t_IMS_Pars(charstring local_sip_host,
-					uint16_t local_sip_port,
-					charstring user,
-					charstring display_name := "Anonymous",
-					charstring password := "secret",
-					template (omit) IMS_CallPars cp := omit) := {
-	t_guard := 30.0,
-	realm := local_sip_host,
-	local_sip_host := local_sip_host,
-	local_sip_port := local_sip_port,
+template (value) IMS_ConnHdlrSubscrPars t_IMS_SubscrPars(charstring local_sip_host,
+						   uint16_t local_sip_port,
+						   charstring imsi,
+						   charstring msisdn := "90828",
+						   charstring display_name := "Anonymous",
+						   charstring password := "secret",
+						   template (omit) IMS_CallPars cp := omit) := {
 	remote_sip_host := omit,
 	remote_sip_port := omit,
-	user := user,
+	imsi := imsi,
 	display_name := f_sip_str_quote(display_name),
 	password := password,
-	msisdn := "90828",
+	msisdn := msisdn,
 	uli_str := "2380100010000101",
 	/* The Nonce field is the Base64 encoded version of the RAND value and concatenated with the AUTN: */
 	rand := '14987631f65f8e3788a0798b6ebcd08e'O,
@@ -163,28 +166,39 @@
 	ipsec_remote_spi_s := omit,
 	ipsec_remote_port_c := omit,
 	ipsec_remote_port_s := omit,
-	registrar_sip_req_uri := valueof(ts_SipUrlHost(local_sip_host)),
 	registrar_sip_record := ts_SipAddr(ts_HostPort(local_sip_host),
-					   ts_UserInfo(user),
+					   ts_UserInfo(imsi),
 					   f_sip_str_quote(display_name)),
 	registrar_sip_call_id := hex2str(f_rnd_hexstring(15)) & "@" & local_sip_host,
 	registrar_sip_seq_nr := f_sip_rand_seq_nr(),
-	local_via := ts_Via_from(ts_HostPort(local_sip_host, local_sip_port)),
 	local_sip_url_ext := ts_SipUrl(ts_HostPort(local_sip_host, local_sip_port),
-				       ts_UserInfo(user)),
+				       ts_UserInfo(imsi)),
 	local_sip_record := ts_SipAddr(ts_HostPort(local_sip_host),
-				       ts_UserInfo(user)),
+				       ts_UserInfo(imsi)),
 	local_contact := valueof(ts_Contact({
 					ts_ContactAddress(
 						ts_Addr_Union_SipUrl(ts_SipUrl(ts_HostPort(
 										 local_sip_host,
 										 local_sip_port),
-								     ts_UserInfo(user))),
+								     ts_UserInfo(imsi))),
 						omit)
 				})),
 	cp := cp
 }
 
+template (value) IMS_ConnHdlrPars t_IMS_Pars(charstring local_sip_host,
+					uint16_t local_sip_port,
+					charstring imsi,
+					template (omit) IMS_CallPars cp := omit) := {
+	t_guard := 30.0,
+	realm := local_sip_host,
+	local_sip_host := local_sip_host,
+	local_sip_port := local_sip_port,
+	registrar_sip_req_uri := valueof(ts_SipUrlHost(local_sip_host)),
+	local_via := ts_Via_from(ts_HostPort(local_sip_host, local_sip_port)),
+	subscr := t_IMS_SubscrPars(local_sip_host, local_sip_port, imsi := imsi, cp := cp)
+}
+
 private altstep as_Tguard() runs on IMS_ConnHdlr {
 	[] g_Tguard.timeout {
 		setverdict(fail, "Tguard timeout");
@@ -293,7 +307,7 @@
 
 	/* exp_present: */
 	var template (present) P_Access_Network_Info expl_tmpl :=
-		tr_P_Access_Network_Info({ tr_Access_net_spec_EUTRAN(g_pars.uli_str) });
+		tr_P_Access_Network_Info({ tr_Access_net_spec_EUTRAN(g_pars.subscr.uli_str) });
 
 	if (not ispresent(g_rx_sip_req.msgHeader.p_access_network_info)) {
 		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
@@ -325,13 +339,13 @@
 			continue;
 		}
 		par_val := f_sip_param_get_value_present_or_fail(sec_pars, "spi-c");
-		g_pars.ipsec_remote_spi_c := str2int(par_val);
+		g_pars.subscr.ipsec_remote_spi_c := str2int(par_val);
 		par_val := f_sip_param_get_value_present_or_fail(sec_pars, "spi-s");
-		g_pars.ipsec_remote_spi_s := str2int(par_val);
+		g_pars.subscr.ipsec_remote_spi_s := str2int(par_val);
 		par_val := f_sip_param_get_value_present_or_fail(sec_pars, "port-c");
-		g_pars.ipsec_remote_port_c := str2int(par_val);
+		g_pars.subscr.ipsec_remote_port_c := str2int(par_val);
 		par_val := f_sip_param_get_value_present_or_fail(sec_pars, "port-s");
-		g_pars.ipsec_remote_port_s := str2int(par_val);
+		g_pars.subscr.ipsec_remote_port_s := str2int(par_val);
 		found := true;
 		break;
 	}
@@ -341,8 +355,8 @@
 					log2str(g_name & "alg=hmac-sha-1-96 not found: ", security_client));
 	}
 
-	log("ipsec: remote_spi_c=", g_pars.ipsec_remote_spi_c, " remote_spi_s=", g_pars.ipsec_remote_spi_s,
-	    "local_spi_c=", g_pars.ipsec_local_spi_c, " local_spi_s=", g_pars.ipsec_local_spi_s);
+	log("ipsec: remote_spi_c=", g_pars.subscr.ipsec_remote_spi_c, " remote_spi_s=", g_pars.subscr.ipsec_remote_spi_s,
+	    "local_spi_c=", g_pars.subscr.ipsec_local_spi_c, " local_spi_s=", g_pars.subscr.ipsec_local_spi_s);
 }
 
 private function f_IMS_exec_sync(charstring cmdline, template (present) integer rc := 0)
@@ -362,12 +376,12 @@
 
 	var charstring cmd := mp_ipsec_setup_script_path & " " &
 		g_pars.local_sip_host & " " &
-		int2str(g_pars.local_sip_port) & " " & int2str(g_pars.ipsec_local_spi_c) & " " &
-		int2str(g_pars.local_sip_port) & " " & int2str(g_pars.ipsec_local_spi_s) & " " &
-		g_pars.remote_sip_host & " " &
-		int2str(g_pars.ipsec_remote_port_c) & " " & int2str(g_pars.ipsec_remote_spi_c) & " " &
-		int2str(g_pars.ipsec_remote_port_s) & " " & int2str(g_pars.ipsec_remote_spi_s) & " " &
-		g_pars.ipsec_auth_key;
+		int2str(g_pars.local_sip_port) & " " & int2str(g_pars.subscr.ipsec_local_spi_c) & " " &
+		int2str(g_pars.local_sip_port) & " " & int2str(g_pars.subscr.ipsec_local_spi_s) & " " &
+		g_pars.subscr.remote_sip_host & " " &
+		int2str(g_pars.subscr.ipsec_remote_port_c) & " " & int2str(g_pars.subscr.ipsec_remote_spi_c) & " " &
+		int2str(g_pars.subscr.ipsec_remote_port_s) & " " & int2str(g_pars.subscr.ipsec_remote_spi_s) & " " &
+		g_pars.subscr.ipsec_auth_key;
 
 	res := f_IMS_exec_sync(cmd);
 
@@ -381,6 +395,57 @@
 	*/
 }
 
+private function f_tr_Via_response(Via via_req) return template (present) Via {
+	template (present) SemicolonParam_List via_resp_params := ?;
+
+	/*via_resp_params := {
+		{ id := "rport", paramValue := int2str(g_pars.subscr.remote_sip_port.subscr.remote_sip_port) },
+		{ id := "received", paramValue := g_pars.subscr.remote_sip_host }
+	}; */
+	return 	tr_Via_from(via_req.viaBody[0].sentBy,
+			    via_req.viaBody[0].sentProtocol.transport,
+			    via_resp_params);
+}
+
+private function f_tr_From(template (value) SipAddr from_req) return template (present) SipAddr {
+	return tr_SipAddr_from_val(from_req);
+}
+
+private altstep as_SIP_expect_req(template (present) PDU_SIP_Request sip_expect, boolean fail_others := true) runs on IMS_ConnHdlr
+{
+	var charstring sip_expect_str := log2str(sip_expect);
+	[] SIP.receive(sip_expect) -> value g_rx_sip_req;
+	[fail_others] as_SIP_fail_req(sip_expect_str);
+	[fail_others] as_SIP_fail_resp(sip_expect_str);
+}
+
+private function f_gen_sdp() runs on IMS_ConnHdlr return charstring {
+	var charstring sdp :=
+		"v=0\r\n" &
+		"o=0502 2390 1824 IN IP4 " & g_pars.subscr.cp.local_rtp_addr & "\r\n" &
+		"s=Talk\r\n" &
+		"c=IN IP4 " & g_pars.subscr.cp.local_rtp_addr & "\r\n" &
+		"t=0 0\r\n" &
+		"a=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\n" &
+		"a=record:off\r\n" &
+		"m=audio " & int2str(g_pars.subscr.cp.local_rtp_port) & " RTP/AVP 8 96 97 98 0 18 99 100 101\r\n" &
+		"a=rtpmap:8 PCMA/8000\r\n" &
+		"a=rtpmap:96 opus/48000/2\r\n" &
+		"a=fmtp:96 useinbandfec=1\r\n" &
+		"a=rtpmap:97 speex/16000\r\n" &
+		"a=fmtp:97 vbr=on\r\n" &
+		"a=rtpmap:98 speex/8000\r\n" &
+		"a=fmtp:98 vbr=on\r\n" &
+		"a=fmtp:18 annexb=yes\r\n" &
+		"a=rtpmap:99 telephone-event/48000\r\n" &
+		"a=rtpmap:100 telephone-event/16000\r\n" &
+		"a=rtpmap:101 telephone-event/8000\r\n" &
+		"a=rtcp:" & int2str(g_pars.subscr.cp.local_rtp_port + 1) & "\r\n" &
+		"a=rtcp-fb:* trr-int 1000\r\n" &
+		"a=rtcp-fb:* ccm tmmbr\r\n";
+	return sdp;
+}
+
 /* Peer is calling us, accept it: */
 altstep as_IMS_register(boolean exp_update_to_direct_rtp := true,
 			boolean fail_others := true) runs on IMS_ConnHdlr
@@ -449,7 +514,13 @@
 					userAgent := omit);
 		SIP.send(tx_resp);
 
-		g_pars.remote_sip_host := valueof(contact.contactBody.contactAddresses[0].addressField.nameAddr.addrSpec.hostPort.host);
+		var HostPort hp := valueof(contact.contactBody.contactAddresses[0].addressField.nameAddr.addrSpec.hostPort);
+		g_pars.subscr.remote_sip_host := hp.host;
+		if (ispresent(hp.portField)) {
+			g_pars.subscr.remote_sip_port := hp.portField;
+		} else {
+			g_pars.subscr.remote_sip_port := 5060;
+		}
 		f_ims_parse_security_client(g_rx_sip_req.msgHeader.security_client);
 		f_ims_setup_ipsec();
 
@@ -459,7 +530,7 @@
 			ts_Param("realm", f_sip_str_quote(g_pars.realm)),
 			ts_Param("qop", f_sip_str_quote("auth")),
 			ts_Param("algorithm", "AKAv1-MD5"),
-			ts_Param("nonce", f_sip_str_quote(f_nonce_from_rand_autn(g_pars.rand, g_pars.autn)))
+			ts_Param("nonce", f_sip_str_quote(f_nonce_from_rand_autn(g_pars.subscr.rand, g_pars.subscr.autn)))
 			/* "opaque not needed in IMS "*/
 		};
 		wwwAuthenticate := ts_WwwAuthenticate( { ts_Challenge_digestCln(digestCln) } )
@@ -469,8 +540,8 @@
 			ts_Param("q", "0.1"),
 			ts_Param("prot", "esp"),
 			ts_Param("mod", "trans"),
-			ts_Param("spi-c", int2str(g_pars.ipsec_local_spi_c)),
-			ts_Param("spi-s", int2str(g_pars.ipsec_local_spi_s)),
+			ts_Param("spi-c", int2str(g_pars.subscr.ipsec_local_spi_c)),
+			ts_Param("spi-s", int2str(g_pars.subscr.ipsec_local_spi_s)),
 			ts_Param("port-c", int2str(g_pars.local_sip_port)),
 			ts_Param("port-s", int2str(g_pars.local_sip_port)),
 			ts_Param("alg", "hmac-sha-1-96"),
@@ -499,12 +570,12 @@
 
 		/* TODO: Generate expected Authoritzation based on AKAv1-MD5: */
 		/*authorization := f_sip_digest_gen_Authorization(valueof(wwwAuthenticate),
-								g_pars.user, g_pars.password,
+								g_pars.user, g_pars.subscr.password,
 								"REGISTER",
-								f_sip_SipUrl_to_str(g_pars.registrar_sip_record.addr.nameAddr.addrSpec))
+								f_sip_SipUrl_to_str(g_pars.subscr.registrar_sip_record.addr.nameAddr.addrSpec))
 		*/
 		authorization := f_tr_Authorization_AKAv1MD5(valueof(wwwAuthenticate),
-							     g_pars.user & "@" & g_pars.realm,
+							     g_pars.subscr.imsi & "@" & g_pars.realm,
 							     f_sip_SipUrl_to_str(g_pars.registrar_sip_req_uri));
 		/* TODO: match Authorization from above: */
 		exp_req :=
@@ -539,9 +610,9 @@
 
 		p_associated_uri := ts_P_Associated_Uri({
 				ts_P_Assoc_uri_spec(ts_NameAddr(ts_SipUrl(ts_HostPort(g_pars.realm),
-									  ts_UserInfo(g_pars.msisdn),
+									  ts_UserInfo(g_pars.subscr.msisdn),
 									  scheme := "sip"))),
-				ts_P_Assoc_uri_spec(ts_NameAddr(ts_SipUrl(ts_HostPort(g_pars.msisdn),
+				ts_P_Assoc_uri_spec(ts_NameAddr(ts_SipUrl(ts_HostPort(g_pars.subscr.msisdn),
 									  omit,
 									  scheme := "tel"))),
 				ts_P_Assoc_uri_spec(g_rx_sip_req.msgHeader.toField.addressField.nameAddr)
@@ -568,4 +639,115 @@
 
 }
 
+private function f_ConnHdlr_parse_initial_SIP_INVITE(PDU_SIP_Request rx_sip_req) runs on IMS_ConnHdlr
+{
+	f_SDP_decodeMessage(rx_sip_req.messageBody, g_pars.subscr.cp.peer_sdp);
+	log("Rx Initial MO INVITE decoded SDP: ", g_pars.subscr.cp.peer_sdp);
+
+	/* Obtain params: */
+	g_pars.subscr.cp.sip_call_id := rx_sip_req.msgHeader.callId.callid;
+	g_pars.subscr.cp.from_addr := rx_sip_req.msgHeader.fromField;
+	g_pars.subscr.cp.to_addr := rx_sip_req.msgHeader.toField;
+	g_pars.subscr.cp.to_addr.toParams := f_sip_param_set(g_pars.subscr.cp.to_addr.toParams, "tag", f_sip_rand_tag());
+	g_pars.subscr.cp.sip_seq_nr := rx_sip_req.msgHeader.cSeq.seqNumber;
+}
+
+/* Peer is calling us, accept it: */
+altstep as_IMS_mo_call_accept(boolean exp_update_to_direct_rtp := false,
+			      boolean fail_others := true) runs on IMS_ConnHdlr
+{
+	var template (present) PDU_SIP_Request exp_req :=
+		tr_SIP_INVITE(f_tr_SipUrl_opt_defport(ts_SipUrl_from_Addr_Union(g_pars.subscr.cp.called.addr)),
+			      ?,
+			      ( /* FIXME: We should be sending with MSISDN here, aka 2nd option below, but we receive IMSI (first opt): */
+			        tr_From(tr_Addr_Union_from_val(g_pars.subscr.local_sip_record.addr), *),
+			        tr_From(tr_Addr_Union_from_val(g_pars.subscr.cp.calling.addr), *)
+			      ),
+			      tr_To(tr_Addr_Union_from_val(g_pars.subscr.cp.called.addr), *),
+			      tr_Via_from(f_tr_HostPort(g_pars.subscr.remote_sip_host, g_pars.subscr.remote_sip_port)),
+			      ?, ?);
+	var charstring sip_expect_str := log2str(exp_req);
+
+	[] SIP.receive(exp_req) -> value g_rx_sip_req {
+		var template (value) PDU_SIP_Response tx_resp;
+		var Via via;
+		var charstring tx_sdp;
+
+		/* Obtain params: */
+		f_ConnHdlr_parse_initial_SIP_INVITE(g_rx_sip_req);
+		via := g_rx_sip_req.msgHeader.via;
+
+
+		/* Tx 180 Ringing */
+		tx_resp := ts_SIP_Response_Ringing(g_pars.subscr.cp.sip_call_id,
+						   g_pars.subscr.cp.from_addr,
+						   g_pars.subscr.cp.to_addr,
+						   via,
+						   g_pars.subscr.cp.sip_seq_nr);
+		SIP.send(tx_resp);
+
+		/* Tx 200 OK */
+		tx_sdp := f_gen_sdp();
+		tx_resp := ts_SIP_Response(g_pars.subscr.cp.sip_call_id,
+					   g_pars.subscr.cp.from_addr,
+					   g_pars.subscr.cp.to_addr,
+					   "INVITE", 200,
+					   g_pars.subscr.cp.sip_seq_nr,
+					   "OK",
+					   via,
+					   body := tx_sdp);
+		SIP.send(tx_resp);
+
+		/* Wait for ACK */
+		exp_req := tr_SIP_ACK(f_tr_SipUrl_opt_defport(ts_SipUrl_from_Addr_Union(g_pars.subscr.cp.called.addr)),
+				      g_pars.subscr.cp.sip_call_id,
+				      g_pars.subscr.cp.from_addr,
+				      g_pars.subscr.cp.to_addr,
+				      f_tr_Via_response(via),
+				      g_pars.subscr.cp.sip_seq_nr, *);
+		as_SIP_expect_req(exp_req);
+	}
+	[fail_others] as_SIP_fail_resp(sip_expect_str);
+	[fail_others] as_SIP_fail_req(sip_expect_str);
+
+}
+
+/* Call is terminated by peer: */
+altstep as_IMS_exp_call_hangup(template (present) integer exp_seq_nr := ?, boolean fail_others := true) runs on IMS_ConnHdlr
+{
+	var template (present) PDU_SIP_Request exp_req :=
+		tr_SIP_BYE(f_tr_SipUrl_opt_defport(ts_SipUrl_from_Addr_Union(g_pars.subscr.cp.called.addr)),
+			   g_pars.subscr.cp.sip_call_id,
+			   g_pars.subscr.cp.from_addr,
+			   g_pars.subscr.cp.to_addr,
+			   tr_Via_from(f_tr_HostPort(g_pars.subscr.remote_sip_host, g_pars.subscr.remote_sip_port)),
+			   exp_seq_nr);
+	var charstring sip_expect_str := log2str(exp_req);
+
+	[] SIP.receive(exp_req) -> value g_rx_sip_req {
+		var template (value) PDU_SIP_Response tx_resp;
+		var charstring tx_sdp;
+		var Via via;
+
+		/* Update parameters: */
+		g_pars.subscr.cp.sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
+		/* "branch" has changed: */
+		via := g_rx_sip_req.msgHeader.via;
+
+		/* Tx 200 OK */
+		tx_sdp := f_gen_sdp();
+		tx_resp := ts_SIP_Response(g_pars.subscr.cp.sip_call_id,
+					g_pars.subscr.cp.from_addr,
+					g_pars.subscr.cp.to_addr,
+					"BYE", 200,
+					g_pars.subscr.cp.sip_seq_nr,
+					"OK",
+					via,
+					body := tx_sdp);
+		SIP.send(tx_resp);
+	}
+	[fail_others] as_SIP_fail_resp(sip_expect_str);
+	[fail_others] as_SIP_fail_req(sip_expect_str);
+}
+
 }
diff --git a/asterisk/SIP_ConnectionHandler.ttcn b/asterisk/SIP_ConnectionHandler.ttcn
index 41a29e4..a14dd03 100644
--- a/asterisk/SIP_ConnectionHandler.ttcn
+++ b/asterisk/SIP_ConnectionHandler.ttcn
@@ -241,7 +241,8 @@
 		"t=0 0\r\n" &
 		"a=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\n" &
 		"a=record:off\r\n" &
-		"m=audio " & int2str(g_pars.cp.local_rtp_port) & " RTP/AVP 96 97 98 0 8 18 99 100 101\r\n" &
+		"m=audio " & int2str(g_pars.cp.local_rtp_port) & " RTP/AVP 8 96 97 98 0 18 99 100 101\r\n" &
+		"a=rtpmap:8 PCMA/8000\r\n" &
 		"a=rtpmap:96 opus/48000/2\r\n" &
 		"a=fmtp:96 useinbandfec=1\r\n" &
 		"a=rtpmap:97 speex/16000\r\n" &
diff --git a/asterisk/expected-results.xml b/asterisk/expected-results.xml
index 49f92bf..78c5ee4 100644
--- a/asterisk/expected-results.xml
+++ b/asterisk/expected-results.xml
@@ -6,4 +6,5 @@
     <testcase classname='Asterisk_Tests' name='TC_internal_call_all_3registered' time='MASKED'/>
     <testcase classname='Asterisk_Tests' name='TC_internal_call_all_4registered' time='MASKED'/>
     <testcase classname='Asterisk_Tests' name='TC_ims_registration' time='MASKED'/>
+    <testcase classname='Asterisk_Tests' name='TC_ims_call_mo' time='MASKED'/>
 </testsuite>