From 4263c52bd4a8d42af2e484eac49500e68bce96c0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 6 Dec 2018 11:56:27 +0100 Subject: WIP: MSC_Tests: Add SGs testcases This extens MSC_Tests.ttcn with an initial set of SGs interface test cases for RESET, LU, DETACH, PAGING, SMS and CSFB procedures In particular the following testcases are added: - TC_sgsap_reset: isolated reset procedure test - TC_sgsap_lu: isolated location update with TMSI realloc - TC_sgsap_lu_imsi_reject: location update, reject case - TC_sgsap_lu_and_nothing: location update with failed TMSI realloc - TC_sgsap_expl_imsi_det_eps: detach from EPS serveces - TC_sgsap_expl_imsi_det_noneps: detach from non-EPS services - TC_sgsap_paging_rej: isolated paging, reject case - TC_sgsap_paging_subscr_rej: isolated paging, subscr rejects call - TC_sgsap_paging_ue_unr: isolated paging, ue is unreachable - TC_sgsap_paging_and_nothing: page, but don't respond - TC_sgsap_paging_and_lu: check paging followed by an LU - TC_sgsap_mt_sms: mobile terminated SMS through SGs Interface - TC_sgsap_mo_sms: mobile originated SMS through SGs Interface - TC_sgsap_mt_sms_and_nothing: trigger SMS, but don't respond to paging - TC_sgsap_mt_sms_and_reject: trigger SMS, but reject paging - TC_sgsap_unexp_ud: Send unexpected unitdata (SGs Association: NULL) - TC_sgsap_unsol_ud: Send unsolicited unitdata (subscriber not in VLR) - TC_bssap_lu_sgsap_lu_and_mt_call: LU on 2G, LU on SGs and CSFB call - TC_sgsap_lu_and_mt_call: LU on SGs, and CSFB call Change-Id: I38543c35a9e74cea276e58d1d7ef01ef07ffe858 Depends: osmo-msc I73359925fc1ca72b33a1466e6ac41307f2f0b11d Related: OS#3645 --- msc/BSC_ConnectionHandler.ttcn | 39 +- msc/MSC_Tests.ttcn | 1028 ++++++++++++++++++++++++++++++++++++++++ msc/expected-results.xml | 19 + msc/gen_links.sh | 2 +- msc/regen_makefile.sh | 2 +- 5 files changed, 1077 insertions(+), 13 deletions(-) (limited to 'msc') diff --git a/msc/BSC_ConnectionHandler.ttcn b/msc/BSC_ConnectionHandler.ttcn index 43a1190f..735cd217 100644 --- a/msc/BSC_ConnectionHandler.ttcn +++ b/msc/BSC_ConnectionHandler.ttcn @@ -39,8 +39,10 @@ import from Osmocom_CTRL_Adapter all; import from TELNETasp_PortType all; import from Osmocom_VTY_Functions all; +import from SGsAP_Emulation all; + /* this component represents a single subscriber connection */ -type component BSC_ConnHdlr extends BSSAP_ConnHdlr, MNCC_ConnHdlr, GSUP_ConnHdlr, MGCP_ConnHdlr, SMPP_ConnHdlr, CTRL_Adapter_CT { +type component BSC_ConnHdlr extends BSSAP_ConnHdlr, MNCC_ConnHdlr, GSUP_ConnHdlr, MGCP_ConnHdlr, SMPP_ConnHdlr, CTRL_Adapter_CT, SGsAP_ConnHdlr { var BSC_ConnHdlrPars g_pars; timer g_Tguard := 60.0; port TELNETasp_PT MSCVTY; @@ -135,6 +137,8 @@ function f_init_handler(BSC_ConnHdlrPars pars, float t_guard := 60.0) runs on BS activate(as_Tguard()); /* Route all SMPP messages for our MSISDN to us */ f_create_smpp_expect(hex2str(pars.msisdn)); + /* Route all SGs message for our IMSI to us */ + f_create_sgsap_expect(pars.imsi); if (g_pars.ipa_ctrl_enable == true) { f_ipa_ctrl_start(g_pars.ipa_ctrl_ip, g_pars.ipa_ctrl_port); @@ -452,21 +456,22 @@ template (value) CallParameters t_CallParams(hexstring called, integer tid) := { mgcp_connection_id_mss := '0'H // }; -function f_mt_call_establish(inout CallParameters cpars) +/* Allocate a call reference and send SETUP via MNCC to MSC */ +function f_mt_call_initate(inout CallParameters cpars) runs on BSC_ConnHdlr { + cpars.mncc_callref := f_rnd_int(2147483648); + MNCC.send(ts_MNCC_SETUP_req(cpars.mncc_callref, hex2str(g_pars.msisdn), + hex2str(cpars.called_party), hex2str(g_pars.imsi))); +} +/* Complete call, begin with a paging response message via BSSAP */ +function f_mt_call_complete(inout CallParameters cpars) +runs on BSC_ConnHdlr { var MNCC_PDU mncc; var MgcpCommand mgcp_cmd; f_bssmap_register_imsi(g_pars.imsi, g_pars.tmsi); - /* Allocate a call reference and send SETUP via MNCC to MSC */ - cpars.mncc_callref := f_rnd_int(2147483648); - MNCC.send(ts_MNCC_SETUP_req(cpars.mncc_callref, hex2str(g_pars.msisdn), - hex2str(cpars.called_party), hex2str(g_pars.imsi))); - /* BSC <- MSC: Expect paging. FIXME: By TMSI or not? */ - BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)); - f_establish_fully(EST_TYPE_PAG_RESP); /* MS <- MSC: Expect CC SETUP */ @@ -476,7 +481,6 @@ runs on BSC_ConnHdlr { BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_ALERTING(cpars.transaction_id))); MNCC.receive(tr_MNCC_ALERT_ind(cpars.mncc_callref)); - /* Create MGCP expect */ f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); /* Ask MSC via MNCC to create the RTP socket on the MSC/MGW side */ @@ -531,6 +535,20 @@ runs on BSC_ConnHdlr { /* MS -> MSC: ALERTING */ BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CONNECT(cpars.transaction_id))); MNCC.receive(tr_MNCC_SETUP_cnf(cpars.mncc_callref)); +} + +function f_mt_call_establish(inout CallParameters cpars) +runs on BSC_ConnHdlr { + + /* Initiate the call via MNCC */ + f_mt_call_initate(cpars); + + /* BSC <- MSC: Expect paging. FIXME: By TMSI or not? */ + f_bssmap_register_imsi(g_pars.imsi, g_pars.tmsi); + BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)); + + /* Complete the call via BSSAP */ + f_mt_call_complete(cpars); setverdict(pass); } @@ -1008,7 +1026,6 @@ runs on BSC_ConnHdlr { } - } diff --git a/msc/MSC_Tests.ttcn b/msc/MSC_Tests.ttcn index ef626bf2..bf703e6b 100644 --- a/msc/MSC_Tests.ttcn +++ b/msc/MSC_Tests.ttcn @@ -42,6 +42,10 @@ import from BSSMAP_Templates all; import from BSSMAP_Emulation all; import from BSC_ConnectionHandler all; +import from SGsAP_Templates all; +import from SGsAP_Types all; +import from SGsAP_Emulation all; + import from MobileL3_Types all; import from MobileL3_CommonIE_Types all; import from MobileL3_SMS_Types all; @@ -57,10 +61,14 @@ import from SCCP_Templates all; import from SS_Types all; import from SS_Templates all; import from USSD_Helpers all; +import from DNS_Helpers all; const integer NUM_BSC := 2; type record of BSSAP_Configuration BSSAP_Configurations; +/* Needed for SGsAP SMS */ +import from MobileL3_SMS_Types all; + type component MTC_CT extends CTRL_Adapter_CT { var boolean g_initialized := false; @@ -72,6 +80,7 @@ type component MTC_CT extends CTRL_Adapter_CT { var GSUP_Emulation_CT vc_GSUP; var IPA_Emulation_CT vc_GSUP_IPA; var SMPP_Emulation_CT vc_SMPP; + var SGsAP_Emulation_CT vc_SGsAP; /* only to get events from IPA underneath GSUP */ port IPA_CTRL_PT GSUP_IPA_EVENT; @@ -107,6 +116,8 @@ modulepar { integer mp_msc_smpp_port := 2775; charstring mp_smpp_system_id := "msc_tester"; charstring mp_smpp_password := "osmocom1"; + charstring mp_mme_name := "mmec01.mmegi0001.mme.epc.mnc070.mcc901.3gppnetwork.org"; + charstring mp_vlr_name := "vlr.example.net"; BSSAP_Configurations mp_bssap_cfg := { { @@ -193,6 +204,25 @@ function f_init_mgcp(charstring id) runs on MTC_CT { vc_MGCP.start(MGCP_Emulation.main(ops, pars, id)); } +function f_init_sgsap(charstring id) runs on MTC_CT { + id := id & "-SGsAP"; + var SGsAPOps ops := { + create_cb := refers(SGsAP_Emulation.ExpectedCreateCallback), + unitdata_cb := refers(SGsAP_Emulation.DummyUnitdataCallback) + } + var SGsAP_conn_parameters pars := { + remote_ip := mp_msc_ip, + remote_sctp_port := 29118, + local_ip := "", + local_sctp_port := -1 + } + + vc_SGsAP := SGsAP_Emulation_CT.create(id); + map(vc_SGsAP:SGsAP, system:SGsAP_CODEC_PT); + vc_SGsAP.start(SGsAP_Emulation.main(ops, pars, id)); +} + + function f_init_gsup(charstring id) runs on MTC_CT { id := id & "-GSUP"; var GsupOps ops := { @@ -247,6 +277,7 @@ function f_init(integer num_bsc := 1) runs on MTC_CT { f_init_mgcp("MSC_Test"); f_init_gsup("MSC_Test"); f_init_smpp("MSC_Test"); + f_init_sgsap("MSC_Test"); map(self:MSCVTY, system:MSCVTY); f_vty_set_prompts(MSCVTY); @@ -485,6 +516,9 @@ function f_start_handler_with_pars(void_fn fn, BSC_ConnHdlrPars pars) runs on MT /* SMPP part */ connect(vc_conn:SMPP, vc_SMPP:SMPP_CLIENT); connect(vc_conn:SMPP_PROC, vc_SMPP:SMPP_PROC); + /* SGs part */ + connect(vc_conn:SGsAP, vc_SGsAP:SGsAP_CLIENT); + connect(vc_conn:SGsAP_PROC, vc_SGsAP:SGsAP_PROC); /* We cannot use vc_conn.start(f_init_handler(fn, id, pars)); as we cannot have * a stand-alone 'derefers()' call, see https://www.eclipse.org/forums/index.php/t/1091364/ */ @@ -2985,6 +3019,980 @@ testcase TC_cipher_complete_with_invalid_cipher() runs on MTC_CT { * too long / short TLV values */ +/* Perform a location updatye at the A-Interface and run some checks to confirm + * that everything is back to normal. */ +private function f_sgsap_bssmap_screening() runs on BSC_ConnHdlr { + var SmsParameters spars := valueof(t_SmsPars); + + /* Perform a location update, the SGs association is expected to fall + * back to NULL */ + f_perform_lu(); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-NULL"); + + /* Trigger a paging request and expect the paging on BSSMAP, this is + * to make sure that pagings are sent throught the A-Interface again + * and not throught the SGs interface.*/ + f_bssmap_register_imsi(g_pars.imsi, g_pars.tmsi); + f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " paging"); + + alt { + [] BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)); { + setverdict(pass); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + /* Send an SMS to make sure that also payload messages are routed + * throught the A-Interface again */ + f_establish_fully(EST_TYPE_MO_SMS); + f_mo_sms(spars); + f_expect_clear(); +} + +private function f_tc_sgsap_reset(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + var charstring vlr_name; + f_init_handler(pars); + + vlr_name := f_sgsap_reset_mme(mp_mme_name); + log("VLR name: ", vlr_name); + setverdict(pass); +} + +testcase TC_sgsap_reset() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_reset), 10); + vc_conn.done; +} + +/* like f_mm_auth() but for SGs */ +function f_mm_auth_sgs() runs on BSC_ConnHdlr { + if (g_pars.net.expect_auth) { + g_pars.vec := f_gen_auth_vec_3g(); + var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G3G(g_pars.vec.rand, + g_pars.vec.sres, + g_pars.vec.kc, + g_pars.vec.ik, + g_pars.vec.ck, + g_pars.vec.autn, + g_pars.vec.res)); + GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); + GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple)); + SGsAP.receive(tr_ML3_MT_MM_AUTH_REQ_3G(g_pars.vec.rand, g_pars.vec.autn)); + SGsAP.send(ts_ML3_MT_MM_AUTH_RESP_3G(g_pars.vec.sres, g_pars.vec.res)); + } +} + +/* like f_perform_lu(), but on SGs rather than BSSAP */ +function f_sgs_perform_lu() runs on BSC_ConnHdlr { + var octetstring mme_name := f_enc_dns_hostname(mp_mme_name); + var PDU_SGsAP lur; + var PDU_SGsAP lua; + var PDU_SGsAP mm_info; + var octetstring mm_info_dtap; + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + lur := valueof(ts_SGsAP_LU_REQ(g_pars.imsi, mme_name, IMSI_attach, + ts_SGsAP_LAI('901'H, '70'H, 2342))); + /* Old LAI, if MS sends it */ + /* TMSI status, if MS has no valid TMSI */ + /* IMEISV, if it supports "automatic device detection" */ + /* TAI, if available in MME */ + /* E-CGI, if available in MME */ + SGsAP.send(lur); + + /* FIXME: is this really done over SGs? The Ue is already authenticated + * via the MME ... */ + f_mm_auth_sgs(); + + /* Expect MSC to perform LU with HLR */ + GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)); + GSUP.send(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn)); + GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi)); + GSUP.send(ts_GSUP_UL_RES(g_pars.imsi)); + + alt { + [] SGsAP.receive(tr_SGsAP_LU_ACCEPT(g_pars.imsi, ?)) -> value lua { + if (isvalue(lua.sGsAP_LOCATION_UPDATE_ACCEPT.newTMSIorIMSI.iD.iD.tmsi_ptmsi.octets)) { + g_pars.tmsi :=lua.sGsAP_LOCATION_UPDATE_ACCEPT.newTMSIorIMSI.iD.iD.tmsi_ptmsi.octets + SGsAP.send(ts_SGsAP_TMSI_REALL_CMPL(g_pars.imsi)); + } + setverdict(pass); + } + [] SGsAP.receive(tr_SGsAP_LU_REJECT(g_pars.imsi, ?, ?)) { + setverdict(fail, "Received LU-REJECT instead of ACCEPT"); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + /* Check MM information */ + if (mp_mm_info == true) { + SGsAP.receive(tr_SGsAP_MM_INFO_REQ(g_pars.imsi, ?)) -> value mm_info; + mm_info_dtap := '0532'O & mm_info.sGsAP_MM_INFORMATION_REQUEST.mM_Information.information; + if (not match(dec_PDU_ML3_NW_MS(mm_info_dtap), tr_ML3_MT_MM_Info)) { + setverdict(fail, "Unexpected MM Information"); + } + } + + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); +} + +private function f_tc_sgsap_lu(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sgs_perform_lu(); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_lu() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_lu), 10); + vc_conn.done; +} + +/* Do LU by IMSI, refuse it on GSUP and expect LU REJ back to MS */ +private function f_tc_sgsap_lu_imsi_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + var PDU_SGsAP lur; + + f_create_gsup_expect(hex2str(g_pars.imsi)); + var octetstring mme_name := f_enc_dns_hostname(mp_mme_name); + lur := valueof(ts_SGsAP_LU_REQ(g_pars.imsi, mme_name, IMSI_attach, + ts_SGsAP_LAI('901'H, '70'H, 2342))); + SGsAP.send(lur); + + GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)); + GSUP.send(ts_GSUP_UL_ERR(g_pars.imsi, 23)); + alt { + [] SGsAP.receive(tr_SGsAP_LU_REJECT(g_pars.imsi, ?, ?)) { + setverdict(pass); + } + [] SGsAP.receive(tr_SGsAP_LU_ACCEPT(g_pars.imsi, ?)) { + setverdict(fail, "Expecting LU REJ, but got ACCEPT"); + mtc.stop; + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_lu_imsi_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_sgsap_lu_imsi_reject), 3); + vc_conn.done; +} + +/* Do LU by IMSI, but then remain silent so that Ts6-1 times out */ +private function f_tc_sgsap_lu_and_nothing(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + var octetstring mme_name := f_enc_dns_hostname(mp_mme_name); + var PDU_SGsAP lur; + + f_init_handler(pars); + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + lur := valueof(ts_SGsAP_LU_REQ(g_pars.imsi, mme_name, IMSI_attach, + ts_SGsAP_LAI('901'H, '70'H, 2342))); + /* Old LAI, if MS sends it */ + /* TMSI status, if MS has no valid TMSI */ + /* IMEISV, if it supports "automatic device detection" */ + /* TAI, if available in MME */ + /* E-CGI, if available in MME */ + SGsAP.send(lur); + + /* FIXME: is this really done over SGs? The Ue is already authenticated + * via the MME ... */ + f_mm_auth_sgs(); + + /* Expect MSC to perform LU with HLR */ + GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)); + GSUP.send(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn)); + GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi)); + GSUP.send(ts_GSUP_UL_RES(g_pars.imsi)); + + alt { + [] SGsAP.receive(tr_SGsAP_LU_ACCEPT(g_pars.imsi, ?)) { + setverdict(pass); + } + [] SGsAP.receive(tr_SGsAP_LU_REJECT(g_pars.imsi, ?, ?)) { + setverdict(fail, "Received LU-REJECT instead of ACCEPT"); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + /* Wait until the VLR has abort the TMSI reallocation procedure */ + f_sleep(45.0); + + /* The outcome does not change the SGs state, see also 5.2.3.4 */ + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_lu_and_nothing() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_sgsap_lu_and_nothing), 3); + vc_conn.done; +} + +private function f_tc_sgsap_expl_imsi_det_eps(charstring id, BSC_ConnHdlrPars pars) +runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sgs_perform_lu(); + f_sleep(3.0); + + var octetstring mme_name := f_enc_dns_hostname(mp_mme_name); + SGsAP.send(ts_SGsAP_EPS_DETACH_IND(g_pars.imsi, mme_name, UE_initiated)); + SGsAP.receive(tr_SGsAP_EPS_DETACH_ACK(g_pars.imsi)); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-NULL"); + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_expl_imsi_det_eps() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_expl_imsi_det_eps), 10); + vc_conn.done; +} + +private function f_tc_sgsap_expl_imsi_det_noneps(charstring id, BSC_ConnHdlrPars pars) +runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sgs_perform_lu(); + f_sleep(3.0); + + var octetstring mme_name := f_enc_dns_hostname(mp_mme_name); + SGsAP.send(ts_SGsAP_IMSI_DETACH_IND(g_pars.imsi, mme_name, combined_UE_initiated)); + SGsAP.receive(tr_SGsAP_IMSI_DETACH_ACK(g_pars.imsi)); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-NULL"); + /* FIXME: How to verify that VLR has removed MM context? */ + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_expl_imsi_det_noneps() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_expl_imsi_det_noneps), 1081); + vc_conn.done; +} + +/* Trigger a paging request via VTY and send a paging reject in response */ +private function f_tc_sgsap_paging_rej(charstring id, BSC_ConnHdlrPars pars) +runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sgs_perform_lu(); + f_sleep(1.0); + + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + var template PDU_SGsAP exp_resp := tr_SGsAP_PAGING_REQ(g_pars.imsi, vlr_name, CS_call_indicator, omit); + var template LocationAreaId exp_lai := ts_SGsAP_IE_Lai(valueof(ts_SGsAP_LAI('901'H, '70'H, 2342))); + exp_resp.sGsAP_PAGING_REQUEST.locationAreaId := exp_lai; + + /* Initiate paging via VTY */ + f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " paging"); + alt { + [] SGsAP.receive(exp_resp) { + setverdict(pass); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + /* Now reject the paging */ + SGsAP.send(ts_SGsAP_PAGING_REJ(g_pars.imsi, IMSI_unknown)); + + /* Wait for the states inside the MSC to settle and check the state + * of the SGs Association */ + f_sleep(1.0); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-NULL"); + + /* FIXME: At the moment we send an IMSI_unknown as cause code, which is fine, + * but we also need to cover tha case where the cause code indicates an + * "IMSI detached for EPS services". In those cases the VLR is expected to + * try paging on tha A/Iu interface. This will be another testcase similar to + * this one, but extended with checks for the presence of the A/Iu paging + * messages. */ + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_paging_rej() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_paging_rej), 1082); + vc_conn.done; +} + +/* Trigger a paging request via VTY and send a paging reject that indicates + * that the subscriber intentionally rejected the call. */ +private function f_tc_sgsap_paging_subscr_rej(charstring id, BSC_ConnHdlrPars pars) +runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sgs_perform_lu(); + f_sleep(1.0); + + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + var template PDU_SGsAP exp_resp := tr_SGsAP_PAGING_REQ(g_pars.imsi, vlr_name, CS_call_indicator, omit); + var template LocationAreaId exp_lai := ts_SGsAP_IE_Lai(valueof(ts_SGsAP_LAI('901'H, '70'H, 2342))); + exp_resp.sGsAP_PAGING_REQUEST.locationAreaId := exp_lai; + + /* Initiate paging via VTY */ + f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " paging"); + alt { + [] SGsAP.receive(exp_resp) { + setverdict(pass); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + /* Now reject the paging */ + SGsAP.send(ts_SGsAP_PAGING_REJ(g_pars.imsi, user_rejected_mobile_terminating_CS_fallback_call)); + + /* Wait for the states inside the MSC to settle and check the state + * of the SGs Association */ + f_sleep(1.0); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + /* FIXME: The VLR is supposed to trigger an User Determined User Busy (UDUB) as specified + * in 3GPP TS 24.082, this is not yet implemented in the MSC or in this tests, we need + * to check back how this works and how it can be tested */ + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_paging_subscr_rej() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_paging_subscr_rej), 1083); + vc_conn.done; +} + +/* Trigger a paging request via VTY and send an UE unreacable messge in response */ +private function f_tc_sgsap_paging_ue_unr(charstring id, BSC_ConnHdlrPars pars) +runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sgs_perform_lu(); + f_sleep(1.0); + + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + var template PDU_SGsAP exp_resp := tr_SGsAP_PAGING_REQ(g_pars.imsi, vlr_name, CS_call_indicator, omit); + var template LocationAreaId exp_lai := ts_SGsAP_IE_Lai(valueof(ts_SGsAP_LAI('901'H, '70'H, 2342))); + exp_resp.sGsAP_PAGING_REQUEST.locationAreaId := exp_lai; + + /* Initiate paging via VTY */ + f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " paging"); + alt { + [] SGsAP.receive(exp_resp) { + setverdict(pass); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + /* Now pretend that the UE is unreachable */ + SGsAP.send(ts_SGsAP_UE_UNREACHABLE(g_pars.imsi, UE_unreachable)); + + /* Wait for the states inside the MSC to settle and check the state + * of the SGs Association. */ + f_sleep(1.0); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_paging_ue_unr() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_paging_ue_unr), 10); + vc_conn.done; +} + +/* Trigger a paging request via VTY but don't respond to it */ +private function f_tc_sgsap_paging_and_nothing(charstring id, BSC_ConnHdlrPars pars) +runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sgs_perform_lu(); + f_sleep(1.0); + + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + var template PDU_SGsAP exp_resp := tr_SGsAP_PAGING_REQ(g_pars.imsi, vlr_name, CS_call_indicator, omit); + var template LocationAreaId exp_lai := ts_SGsAP_IE_Lai(valueof(ts_SGsAP_LAI('901'H, '70'H, 2342))); + exp_resp.sGsAP_PAGING_REQUEST.locationAreaId := exp_lai; + + /* Initiate paging via VTY */ + f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " paging"); + alt { + [] SGsAP.receive(exp_resp) { + setverdict(pass); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + /* Now do nothing, the MSC/VLR should fail silently to page after a + * few seconds, The SGs association must remain unchanged. */ + f_sleep(15.0); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_paging_and_nothing() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_paging_and_nothing), 92); + vc_conn.done; +} + +/* Trigger a paging request via VTY and slip in an LU */ +private function f_tc_sgsap_paging_and_lu(charstring id, BSC_ConnHdlrPars pars) +runs on BSC_ConnHdlr { + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + f_init_handler(pars); + + /* First we prepar the situation, where the SGs association is in state + * NULL and the confirmed by radio contact indicator is set to false + * as well. This can be archived by performing an SGs LU and then + * resetting the VLR */ + f_sgs_perform_lu(); + f_sgsap_reset_mme(mp_mme_name); + f_sleep(1.0); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-NULL"); + + /* Perform a paging, expect the paging messages on the SGs interface */ + f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " paging"); + alt { + [] SGsAP.receive(tr_SGsAP_PAGING_REQ(pars.imsi, vlr_name, CS_call_indicator, omit)) { + setverdict(pass); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + /* Perform the LU as normal */ + f_sgs_perform_lu(); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + /* Expect a new paging request right after the LU */ + alt { + [] SGsAP.receive(tr_SGsAP_PAGING_REQ(pars.imsi, vlr_name, CS_call_indicator, omit)) { + setverdict(pass); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + /* Test is done now, lets round everything up by rejecting the paging + * cleanly. */ + SGsAP.send(ts_SGsAP_PAGING_REJ(g_pars.imsi, user_rejected_mobile_terminating_CS_fallback_call)); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_paging_and_lu() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_paging_and_lu), 9792); + vc_conn.done; +} + +/* Send unexpected unit-data through the SGs interface */ +private function f_tc_sgsap_unexp_ud(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sleep(1.0); + + /* This simulates what happens when a subscriber without SGs + * association gets unitdata via the SGs interface. */ + + /* Make sure the subscriber exists and the SGs association + * is in NULL state */ + f_perform_lu(); + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-NULL"); + + /* Send some random unit data, the MSC/VLR should send a release + * immediately. */ + SGsAP.send(ts_SGsAP_UL_UD(pars.imsi,'1234'O)); + SGsAP.receive(tr_SGsAP_RELEASE_REQ(pars.imsi, IMSI_detached_for_EPS_nonEPS_services)); + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_unexp_ud() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_unexp_ud), 2145); + vc_conn.done; +} + +/* Send unsolicited unit-data through the SGs interface */ +private function f_tc_sgsap_unsol_ud(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sleep(1.0); + + /* This simulates what happens when the MME attempts to send unitdata + * to a subscriber that is completely unknown to the VLR */ + + /* Send some random unit data, the MSC/VLR should send a release + * immediately. */ + SGsAP.send(ts_SGsAP_UL_UD(pars.imsi,'1234'O)); + SGsAP.receive(tr_SGsAP_RELEASE_REQ(pars.imsi, IMSI_unknown)); + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_unsol_ud() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_unsol_ud), 146); + vc_conn.done; +} + +private altstep as_other_sms_sgs() runs on BSC_ConnHdlr { + /* FIXME: Match an actual payload (second questionmark), the type is + * octetstring, how do we use a tr_PDU_DTAP_MT here? */ + [] SGsAP.receive(tr_SGsAP_DL_UD(?,?)) { + setverdict(fail, "Unexpected SMS related PDU from MSC"); + mtc.stop; + } +} + +/* receive a MT-SMS delivered from the MSC/SMSC over an already existing SGsAP connection */ +function f_mt_sms_sgs(inout SmsParameters spars) +runs on BSC_ConnHdlr { + var template (value) TPDU_RP_DATA_MS_SGSN tp_mo; + var template (value) RPDU_MS_SGSN rp_mo; + var template (value) PDU_ML3_MS_NW l3_mo; + + var template TPDU_RP_DATA_SGSN_MS tp_mt; + var template RPDU_SGSN_MS rp_mt; + var template PDU_ML3_NW_MS l3_mt; + + var PDU_ML3_NW_MS sgsap_l3_mt; + + var default d := activate(as_other_sms_sgs()); + + /* Expect CP-DATA(RP-DATA(SMS-DELIVER)) */ + tp_mt := tr_SMS_DELIVER(?, spars.tp.ud, spars.tp.pid, spars.tp.dcs, ?); + rp_mt := tr_RP_DATA_MT(?, ?, omit, tp_mt); + l3_mt := tr_ML3_MT_SMS(?, c_TIF_ORIG, tr_CP_DATA_MT(rp_mt)); + + SGsAP.receive(l3_mt) -> value sgsap_l3_mt; + + /* Extract relevant identifiers */ + spars.tid := bit2int(sgsap_l3_mt.tiOrSkip.transactionId.tio); + spars.rp.msg_ref := sgsap_l3_mt.msgs.sms.cP_DATA.cP_User_Data.cP_RPDU.rP_DATA_SGSN_MS.rP_MessageReference; + + /* send CP-ACK for CP-DATA just received */ + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_REPL, ts_CP_ACK_MO); + + SGsAP.send(l3_mo); + + /* send RP-ACK for RP-DATA */ + rp_mo := ts_RP_ACK_MO(spars.rp.msg_ref); + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_REPL, ts_CP_DATA_MO(rp_mo)); + + SGsAP.send(l3_mo); + + /* expect CP-ACK for CP-DATA(RP-ACK) just sent */ + l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_ORIG, tr_CP_ACK_MT); + + SGsAP.receive(l3_mt); + + deactivate(d); + + setverdict(pass); +} + +/* submit a MO-SMS to MSC/SMSC over an already existing SGsAP connection */ +function f_mo_sms_sgs(inout SmsParameters spars) +runs on BSC_ConnHdlr { + var template (value) TPDU_RP_DATA_MS_SGSN tp_mo; + var template (value) RPDU_MS_SGSN rp_mo; + var template (value) PDU_ML3_MS_NW l3_mo; + + var template TPDU_RP_DATA_SGSN_MS tp_mt; + var template RPDU_SGSN_MS rp_mt; + var template PDU_ML3_NW_MS l3_mt; + + var default d := activate(as_other_sms_sgs()); + + /* just in case this is routed to SMPP.. */ + f_create_smpp_expect(hex2str(spars.tp.da.tP_DA_NoPad.tP_DAValue)); + + tp_mo := ts_SMS_SUBMIT(spars.tp.msg_ref, spars.tp.da, spars.tp.pid, spars.tp.dcs, + spars.tp.udl, spars.tp.ud); + rp_mo := ts_RP_DATA_MO(spars.rp.msg_ref, spars.rp.orig, spars.rp.dest, tp_mo); + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_ORIG, ts_CP_DATA_MO(rp_mo)); + + SGsAP.send(l3_mo); + + /* receive CP-ACK for CP-DATA above */ + SGsAP.receive(tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_ACK_MT)); + + if (ispresent(spars.exp_rp_err)) { + /* expect an RP-ERROR message from MSC with given cause */ + rp_mt := tr_RP_ERROR_MT(spars.rp.msg_ref, spars.exp_rp_err); + l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_DATA_MT(rp_mt)); + SGsAP.receive(l3_mt); + /* send CP-ACK for CP-DATA just received */ + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_ORIG, ts_CP_ACK_MO); + SGsAP.send(l3_mo); + } else { + /* expect RP-ACK for RP-DATA */ + rp_mt := tr_RP_ACK_MT(spars.rp.msg_ref); + l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_DATA_MT(rp_mt)); + SGsAP.receive(l3_mt); + /* send CP-ACO for CP-DATA just received */ + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_ORIG, ts_CP_ACK_MO); + SGsAP.send(l3_mo); + } + + deactivate(d); + + setverdict(pass); +} + +private function f_vty_sms_send_conn_hdlr(charstring imsi, charstring msisdn, charstring text) +runs on BSC_ConnHdlr { + f_vty_transceive(MSCVTY, "subscriber imsi "&imsi&" sms sender msisdn "&msisdn&" send "&text); +} + +/* Send a MT SMS via SGs interface */ +private function f_tc_sgsap_mt_sms(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sgs_perform_lu(); + f_sleep(1.0); + var SmsParameters spars := valueof(t_SmsPars); + spars.tp.ud := 'C8329BFD064D9B53'O; + + /* Trigger SMS via VTY */ + f_vty_sms_send_conn_hdlr(hex2str(pars.imsi), "2342", "Hello SMS"); + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + + /* Expect a paging request and respond accordingly with a service request */ + SGsAP.receive(tr_SGsAP_PAGING_REQ(pars.imsi, vlr_name, SMS_indicator, omit)); + SGsAP.send(ts_SGsAP_SERVICE_REQ(pars.imsi, SMS_indicator, EMM_CONNECTED)); + + /* Connection is now live, receive the MT-SMS */ + f_mt_sms_sgs(spars); + + /* Expect a concluding release from the MSC */ + SGsAP.receive(tr_SGsAP_RELEASE_REQ(pars.imsi, omit)); + + /* Make sure that subscriber is still present and the SGs association is in tact (ref-counting) */ + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} +testcase TC_sgsap_mt_sms() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_mt_sms), 1145); + vc_conn.done; +} + +/* Send a MO SMS via SGs interface */ +private function f_tc_sgsap_mo_sms(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + f_sgs_perform_lu(); + f_sleep(1.0); + var SmsParameters spars := valueof(t_SmsPars); + spars.tp.ud := 'C8329BFD064D9B53'O; + + /* Send the MO-SMS */ + f_mo_sms_sgs(spars); + + /* Expect a concluding release from the MSC/VLR */ + SGsAP.receive(tr_SGsAP_RELEASE_REQ(pars.imsi, omit)); + + /* Make sure that subscriber is still present and the SGs association is in tact (ref-counting) */ + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + setverdict(pass); + + f_sgsap_bssmap_screening() +} +testcase TC_sgsap_mo_sms() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_mo_sms), 3145); + vc_conn.done; +} + +/* Trigger sending of an MT sms via VTY but never respond to anything */ +private function f_tc_sgsap_mt_sms_and_nothing(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars, 170.0); + f_sgs_perform_lu(); + f_sleep(1.0); + + var SmsParameters spars := valueof(t_SmsPars); + spars.tp.ud := 'C8329BFD064D9B53'O; + var integer page_count := 0; + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + var template PDU_SGsAP exp_pag_req := tr_SGsAP_PAGING_REQ(g_pars.imsi, vlr_name, SMS_indicator, omit); + var template LocationAreaId exp_lai := ts_SGsAP_IE_Lai(valueof(ts_SGsAP_LAI('901'H, '70'H, 2342))); + exp_pag_req.sGsAP_PAGING_REQUEST.locationAreaId := exp_lai; + + /* Trigger SMS via VTY */ + f_vty_sms_send_conn_hdlr(hex2str(pars.imsi), "2342", "Hello SMS"); + + /* Expect the MSC/VLR to page exactly 10 times before giving up */ + alt { + [] SGsAP.receive(exp_pag_req) + { + page_count := page_count + 1; + + if (page_count < 10) { + repeat; + } + } + [] SGsAP.receive { + setverdict(fail, "unexpected SGsAP message received"); + self.stop; + } + } + + /* Wait some time to make sure the MSC is not delivering any further + * paging messages or anything else that could be unexpected. */ + timer T := 20.0; + T.start + alt { + [] SGsAP.receive(exp_pag_req) + { + setverdict(fail, "paging seems not to stop!"); + mtc.stop; + } + [] SGsAP.receive { + setverdict(fail, "unexpected SGsAP message received"); + self.stop; + } + [] T.timeout { + setverdict(pass); + } + } + + /* Even on a failed paging the SGs Association should stay intact */ + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + /* Note: We do not execute f_sgsap_bssmap_screening() here since the + * MSC/VLR would re-try to deliver the test SMS trigered above and + * so the screening would fail. */ + + /* Expire the subscriber now to avoid that the MSC will try the SMS + * delivery at some later point. */ + f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " expire"); + + setverdict(pass); +} +testcase TC_sgsap_mt_sms_and_nothing() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_mt_sms_and_nothing), 4581); + vc_conn.done; +} + +/* Trigger sending of an MT sms via VTY but reject the paging immediately */ +private function f_tc_sgsap_mt_sms_and_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars, 150.0); + f_sgs_perform_lu(); + f_sleep(1.0); + + var SmsParameters spars := valueof(t_SmsPars); + spars.tp.ud := 'C8329BFD064D9B53'O; + var integer page_count := 0; + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + var template PDU_SGsAP exp_pag_req := tr_SGsAP_PAGING_REQ(g_pars.imsi, vlr_name, SMS_indicator, omit); + var template LocationAreaId exp_lai := ts_SGsAP_IE_Lai(valueof(ts_SGsAP_LAI('901'H, '70'H, 2342))); + exp_pag_req.sGsAP_PAGING_REQUEST.locationAreaId := exp_lai; + + /* Trigger SMS via VTY */ + f_vty_sms_send_conn_hdlr(hex2str(pars.imsi), "2342", "Hello SMS"); + + /* Expect a paging request and reject it immediately */ + SGsAP.receive(exp_pag_req); + SGsAP.send(ts_SGsAP_PAGING_REJ(g_pars.imsi, IMSI_unknown)); + + /* The MSC/VLR should no longer try to page once the paging has been + * rejected. Wait some time and check if there are no unexpected + * messages on the SGs interface. */ + timer T := 20.0; + T.start + alt { + [] SGsAP.receive(exp_pag_req) + { + setverdict(fail, "paging seems not to stop!"); + mtc.stop; + } + [] SGsAP.receive { + setverdict(fail, "unexpected SGsAP message received"); + self.stop; + } + [] T.timeout { + setverdict(pass); + } + } + + /* A rejected paging with IMSI_unknown (see above) should always send + * the SGs association to NULL. */ + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-NULL"); + + f_sgsap_bssmap_screening(); + + /* Expire the subscriber now to avoid that the MSC will try the SMS + * delivery at some later point. */ + f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " expire"); + + setverdict(pass); +} +testcase TC_sgsap_mt_sms_and_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_sgsap_mt_sms_and_reject), 4145); + vc_conn.done; +} + +/* Perform an MT CSDB call including LU */ +private function f_mt_lu_and_csfb_call(charstring id, BSC_ConnHdlrPars pars, boolean bssmap_lu) runs on BSC_ConnHdlr { + f_init_handler(pars); + + /* Be sure that the BSSMAP reset is done before we begin. */ + f_sleep(2.0); + + /* Testcase variation: See what happens when we do a regular BSSMAP + * LU first (this should not hurt in any way!) */ + if (bssmap_lu) { + f_perform_lu(); + } + + f_sgs_perform_lu(); + f_sleep(1.0); + + var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name); + var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); + cpars.bss_rtp_port := 1110; + cpars.mgcp_connection_id_bss := '10004'H; + cpars.mgcp_connection_id_mss := '10005'H; + + /* Note: This is an optional parameter. When the call-agent (MSC) does + * supply a full endpoint name this setting will be overwritten. */ + cpars.mgcp_ep := "rtpbridge/1@mgw"; + + /* Initiate a call via MNCC interface */ + f_mt_call_initate(cpars); + + /* Expect a paging request and respond accordingly with a service request */ + SGsAP.receive(tr_SGsAP_PAGING_REQ(pars.imsi, vlr_name, CS_call_indicator, omit)); + SGsAP.send(ts_SGsAP_SERVICE_REQ(pars.imsi, CS_call_indicator, EMM_CONNECTED)); + + /* Complete the call, hold it for some time and then tear it down */ + f_mt_call_complete(cpars); + f_sleep(3.0); + f_call_hangup(cpars, true); + + /* Make sure that subscriber is still present and the SGs association is in tact (ref-counting) */ + f_ctrl_get_exp(IPA_CTRL, "fsm.SGs-UE.id.imsi:" & hex2str(g_pars.imsi) & ".state", "SGs-ASSOCIATED"); + + /* Finally simulate the return of the UE to the 4G network */ + SGsAP.send(ts_SGsAP_MO_CSFB_IND(pars.imsi)); + + /* Test for successful return by triggering a paging, when the paging + * request is received via SGs, we can be sure that the MSC/VLR has + * recognized that the UE is now back on 4G */ + f_sleep(1.0); + f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " paging"); + alt { + [] SGsAP.receive(tr_SGsAP_PAGING_REQ(pars.imsi, vlr_name, CS_call_indicator, omit)) { + setverdict(pass); + } + [] SGsAP.receive { + setverdict(fail, "Received unexpected message on SGs"); + } + } + + f_sgsap_bssmap_screening(); + + setverdict(pass); +} + +/* Perform a regular BSSAP LU first, do a SGSAP LU and then make a CSFB call */ +private function f_tc_bssap_lu_sgsap_lu_and_mt_call(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_mt_lu_and_csfb_call(id, pars, true); +} +testcase TC_bssap_lu_sgsap_lu_and_mt_call() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_bssap_lu_sgsap_lu_and_mt_call), 139); + vc_conn.done; +} + + +/* Perform a SGSAP LU and then make a CSFB call */ +private function f_tc_sgsap_lu_and_mt_call(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_mt_lu_and_csfb_call(id, pars, false); +} +testcase TC_sgsap_lu_and_mt_call() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_sgsap_lu_and_mt_call), 239); + vc_conn.done; +} + +/* SGs TODO: + * LU attempt for IMSI without NAM_PS in HLR + * LU attempt with AUTH FAIL due to invalid RES/SRES + * LU attempt with no response from HLR (VLR should timeout + LU REJ) + * LU attempt with new TMSI but without TMSI REALL CMPL baco to VLR + * implicit IMSI detach from EPS + * implicit IMSI detach from non-EPS + * MM INFO + * + */ control { execute( TC_cr_before_reset() ); @@ -3051,6 +4059,26 @@ control { execute( TC_cipher_complete_with_invalid_cipher() ); + execute( TC_sgsap_reset() ); + execute( TC_sgsap_lu() ); + execute( TC_sgsap_lu_imsi_reject() ); + execute( TC_sgsap_lu_and_nothing() ); + execute( TC_sgsap_expl_imsi_det_eps() ); + execute( TC_sgsap_expl_imsi_det_noneps() ); + execute( TC_sgsap_paging_rej() ); + execute( TC_sgsap_paging_subscr_rej() ); + execute( TC_sgsap_paging_ue_unr() ); + execute( TC_sgsap_paging_and_nothing() ); + execute( TC_sgsap_paging_and_lu() ); + execute( TC_sgsap_mt_sms() ); + execute( TC_sgsap_mo_sms() ); + execute( TC_sgsap_mt_sms_and_nothing() ); + execute( TC_sgsap_mt_sms_and_reject() ); + execute( TC_sgsap_unexp_ud() ); + execute( TC_sgsap_unsol_ud() ); + execute( TC_bssap_lu_sgsap_lu_and_mt_call() ); + execute( TC_sgsap_lu_and_mt_call() ); + /* Run this last: at the time of writing this test crashes the MSC */ execute( TC_lu_imsi_auth_tmsi_encr_3_1_log_msc_debug() ); execute( TC_mo_cc_bssmap_clear() ); diff --git a/msc/expected-results.xml b/msc/expected-results.xml index b9c60c03..8a5822d7 100644 --- a/msc/expected-results.xml +++ b/msc/expected-results.xml @@ -74,4 +74,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/msc/gen_links.sh b/msc/gen_links.sh index 5d73feab..117564e1 100755 --- a/msc/gen_links.sh +++ b/msc/gen_links.sh @@ -94,7 +94,7 @@ FILES+="RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunctDef.cc " FILES+="MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunctDef.cc " FILES+="SMPP_CodecPort.ttcn SMPP_CodecPort_CtrlFunct.ttcn SMPP_CodecPort_CtrlFunctDef.cc SMPP_Emulation.ttcn SMPP_Templates.ttcn " FILES+="SS_Templates.ttcn SCCP_Templates.ttcn USSD_Helpers.ttcn " -FILES+="SGsAP_Templates.ttcn " +FILES+="SGsAP_Templates.ttcn SGsAP_CodecPort.ttcn SGsAP_CodecPort_CtrlFunct.ttcn SGsAP_CodecPort_CtrlFunctDef.cc SGsAP_Emulation.ttcn DNS_Helpers.ttcn " gen_links $DIR $FILES ignore_pp_results diff --git a/msc/regen_makefile.sh b/msc/regen_makefile.sh index 556d69e4..5645fdde 100755 --- a/msc/regen_makefile.sh +++ b/msc/regen_makefile.sh @@ -1,6 +1,6 @@ #!/bin/sh -FILES="*.ttcn *.ttcnpp SCCP_EncDec.cc SCTPasp_PT.cc TCCConversion.cc TCCInterface.cc UD_PT.cc MNCC_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc SDP_EncDec.cc RTP_EncDec.cc IPA_CodecPort_CtrlFunctDef.cc RTP_CodecPort_CtrlFunctDef.cc MGCP_CodecPort_CtrlFunctDef.cc TELNETasp_PT.cc Native_FunctionDefs.cc SMPP_EncDec.cc SMPP_CodecPort_CtrlFunctDef.cc MAP_EncDec.cc SS_EncDec.cc TCCEncoding.cc *.c *.asn" +FILES="*.ttcn *.ttcnpp SCCP_EncDec.cc SCTPasp_PT.cc TCCConversion.cc TCCInterface.cc UD_PT.cc MNCC_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc SDP_EncDec.cc RTP_EncDec.cc IPA_CodecPort_CtrlFunctDef.cc RTP_CodecPort_CtrlFunctDef.cc MGCP_CodecPort_CtrlFunctDef.cc TELNETasp_PT.cc Native_FunctionDefs.cc SMPP_EncDec.cc SMPP_CodecPort_CtrlFunctDef.cc MAP_EncDec.cc SS_EncDec.cc TCCEncoding.cc SGsAP_CodecPort_CtrlFunctDef.cc *.c *.asn" export CPPFLAGS_TTCN3="-DIPA_EMULATION_MGCP -DIPA_EMULATION_GSUP -DIPA_EMULATION_SCCP -DUSE_MTP3_DISTRIBUTOR" -- cgit v1.2.3