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>