pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/36950?usp=email )
Change subject: asterisk: Introduce TC_ims_call_mo ......................................................................
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 --- M asterisk/Asterisk_Tests.default M asterisk/Asterisk_Tests.ttcn M asterisk/IMS_ConnectionHandler.ttcn M asterisk/SIP_ConnectionHandler.ttcn M asterisk/expected-results.xml 5 files changed, 350 insertions(+), 89 deletions(-)
Approvals: Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve osmith: Looks good to me, but someone else must approve pespin: Looks good to me, approved
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>