From 3c68a548962ae8cf1a20304f18b735f2e29aae39 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 27 Jan 2018 16:03:20 +0100 Subject: msc: rename sub-directory from msc_tests to msc (to be in line with bsc, etc.) Change-Id: Ib219dee5e587bca3b79d29d631836cf1ef2be81c --- Makefile | 2 +- msc/BSC_ConnectionHandler.ttcn | 497 ++++++++++++ msc/MSC_Tests.cfg | 42 + msc/MSC_Tests.ttcn | 1479 ++++++++++++++++++++++++++++++++++ msc/gen_links.sh | 84 ++ msc/regen_makefile.sh | 5 + msc_tests/BSC_ConnectionHandler.ttcn | 497 ------------ msc_tests/MSC_Tests.cfg | 42 - msc_tests/MSC_Tests.ttcn | 1479 ---------------------------------- msc_tests/gen_links.sh | 84 -- msc_tests/regen_makefile.sh | 5 - 11 files changed, 2108 insertions(+), 2108 deletions(-) create mode 100644 msc/BSC_ConnectionHandler.ttcn create mode 100644 msc/MSC_Tests.cfg create mode 100644 msc/MSC_Tests.ttcn create mode 100755 msc/gen_links.sh create mode 100755 msc/regen_makefile.sh delete mode 100644 msc_tests/BSC_ConnectionHandler.ttcn delete mode 100644 msc_tests/MSC_Tests.cfg delete mode 100644 msc_tests/MSC_Tests.ttcn delete mode 100755 msc_tests/gen_links.sh delete mode 100755 msc_tests/regen_makefile.sh diff --git a/Makefile b/Makefile index 80211def..f009560f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -SUBDIRS=bsc bsc-nat ggsn_tests gprs_gb lapdm mgw msc_tests selftest sysinfo +SUBDIRS=bsc bsc-nat ggsn_tests gprs_gb lapdm mgw msc selftest sysinfo PARALLEL_MAKE:=-j4 diff --git a/msc/BSC_ConnectionHandler.ttcn b/msc/BSC_ConnectionHandler.ttcn new file mode 100644 index 00000000..a7ce1eae --- /dev/null +++ b/msc/BSC_ConnectionHandler.ttcn @@ -0,0 +1,497 @@ +module BSC_ConnectionHandler { + +import from General_Types all; +import from Osmocom_Types all; +import from Native_Functions all; +import from GSM_Types all; +import from IPL4asp_Types all; +import from SCCPasp_Types all; +import from BSSAP_Types all; +import from BSSMAP_Emulation all; +import from BSSMAP_Templates all; + +import from GSUP_Types all; +import from GSUP_Emulation all; + +import from MNCC_Types all; +import from MNCC_Emulation all; + +import from MGCP_Types all; +import from MGCP_Emulation all; +import from MGCP_Templates all; +import from SDP_Types all; + +import from MobileL3_Types all; +import from MobileL3_CommonIE_Types all; +import from MobileL3_MM_Types all; +import from MobileL3_CC_Types all; +import from L3_Templates all; + +/* this component represents a single subscriber connection */ +type component BSC_ConnHdlr extends BSSAP_ConnHdlr, MNCC_ConnHdlr, GSUP_ConnHdlr, MGCP_ConnHdlr { + var BSC_ConnHdlrPars g_pars; + timer g_Tguard := 60.0; +} + +type record AuthVector { + OCT16 rand, + OCT4 sres, + OCT8 kc + /* FIXME: 3G elements */ +} + +type record BSC_ConnHdlrPars { + SCCP_PAR_Address sccp_addr_own, + SCCP_PAR_Address sccp_addr_peer, + BSSMAP_IE_CellIdentifier cell_id, + hexstring imei, + hexstring imsi, + hexstring msisdn, + OCT4 tmsi optional, + BSSMAP_IE_ClassmarkInformationType2 cm2, + BSSMAP_IE_ClassmarkInformationType3 cm3 optional, + AuthVector vec optional +}; + +/* altstep for the global guard timer */ +private altstep as_Tguard() runs on BSC_ConnHdlr { + [] g_Tguard.timeout { + setverdict(inconc, "Tguard timeout"); + self.stop; + } +} + +/* init function, called as first function in new BSC_ConnHdlr */ +function f_init_handler(BSC_ConnHdlrPars pars, float t_guard := 60.0) runs on BSC_ConnHdlr { + /* make parameters available via component variable */ + g_pars := pars; + /* Start guard timer and activate it as default */ + g_Tguard.start(t_guard); + activate(as_Tguard()); +} + + +/* Callback function from general BSSMAP_Emulation whenever a connectionless + * BSSMAP message arrives. Canreturn a PDU_BSSAPthat should be sent in return */ +private function BscUnitdataCallback(PDU_BSSAP bssap) +runs on BSSMAP_Emulation_CT return template PDU_BSSAP { + var template PDU_BSSAP resp := omit; + + log("BSSMAP_BscUnitdataCallback"); + /* answer all RESET with RESET ACK */ + if (match(bssap, tr_BSSMAP_Reset)){ + log("BSSMAP_BscUnitdataCallback: Responding to RESET with RESET-ACK"); + resp := ts_BSSMAP_ResetAck; + } + + /* FIXME: Handle paging, etc. */ + return resp; +} + +const BssmapOps BSC_BssmapOps := { + /* Create call-back for inbound connections from MSC (hand-over) */ + create_cb := refers(BSSMAP_Emulation.ExpectedCreateCallback), + unitdata_cb := refers(BscUnitdataCallback), + decode_dtap := true, + role_ms := true +} + + +private function MnccUnitdataCallback(MNCC_PDU mncc) +runs on MNCC_Emulation_CT return template MNCC_PDU { + log("Ignoring MNCC", mncc); + return omit; +} + +const MnccOps BCC_MnccOps := { + create_cb := refers(MNCC_Emulation.ExpectedCreateCallback), + unitdata_cb := refers(MnccUnitdataCallback) +} + + + +template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, PDU_BSSAP bssap) := { + addr_peer := peer, + addr_own := own, + bssap := bssap +}; + +/* Encode 'l3' and ask BSSMAP_Emulation to create new connection with COMPL L3 INFO */ +function f_bssap_compl_l3(PDU_ML3_MS_NW l3) +runs on BSC_ConnHdlr { + log("Sending COMPL L3: ", l3); + var octetstring l3_enc := enc_PDU_ML3_MS_NW(l3); + BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own, + valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, l3_enc)))); + alt { + [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_CONF_IND) {} + [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) { + setverdict(fail, "DISC.ind from SCCP"); + self.stop; + } + } +} + +/* helper function to fully establish a dedicated channel */ +function f_establish_fully(MobileIdentityLV mi, boolean expect_auth, boolean expect_ciph) +runs on BSC_ConnHdlr { + var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi)); + var PDU_DTAP_MT dtap_mt; + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_info); + + f_mm_common(expect_auth, expect_ciph); + if (expect_ciph) { + /* implicit CM SERVICE ACCEPT? */ + } else { + /* explicit CM SERVICE ACCEPT */ + BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC)); + } +} + +/* helper function to fully establish a dedicated channel */ +function f_establish_fully_pag(MobileIdentityLV mi, boolean expect_auth, boolean expect_ciph) +runs on BSC_ConnHdlr { + var PDU_ML3_MS_NW l3_info := valueof(ts_PAG_RESP(mi)); + var PDU_DTAP_MT dtap_mt; + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_info); + + f_mm_common(expect_auth, expect_ciph); +} + + +/* build a PDU_ML3_MS_NW containing a Location Update by IMSI */ +function f_build_lu_imsi(hexstring imsi) return PDU_ML3_MS_NW +{ + var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(imsi)); + return f_build_lu(mi); +} +function f_build_lu_imei(hexstring imei) return PDU_ML3_MS_NW +{ + var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(imei)); + return f_build_lu(mi); +} +function f_build_lu_tmsi(OCT4 tmsi) return PDU_ML3_MS_NW +{ + var MobileIdentityLV mi := valueof(ts_MI_TMSI_LV(tmsi)); + return f_build_lu(mi); +} +private function f_build_lu(MobileIdentityLV mi) return PDU_ML3_MS_NW +{ + var LocationAreaIdentification_V old_lai := { '62F220'O, '9999'O }; + var PDU_ML3_MS_NW l3_info := valueof(ts_ML3_MO_LU_Req(valueof(ts_ML3_IE_LuType_Attach), + old_lai, mi, valueof(ts_CM1))); + return l3_info; +} + +private function f_rnd_oct(integer len) return octetstring { + var integer i; + var octetstring res; + for (i := 0; i < len; i := i + 1) { + res[i] := int2oct(float2int(rnd()*256.0), 1); + } + return res; +} + +function f_gen_auth_vec_2g() return AuthVector { + var AuthVector vec; + vec.rand := f_rnd_oct(16); + vec.sres := f_rnd_oct(4); + vec.kc := f_rnd_oct(8); + return vec; +} + + +function f_mm_common(boolean expect_auth, boolean expect_ciph) runs on BSC_ConnHdlr +{ + if (expect_auth) { + g_pars.vec := f_gen_auth_vec_2g(); + var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand, + g_pars.vec.sres, + g_pars.vec.kc)); + GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); + GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple)); + + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_AUTH_REQ(g_pars.vec.rand))); + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MT_MM_AUTH_RESP_2G(g_pars.vec.sres))); + } + + if (expect_ciph) { + BSSAP.receive(tr_BSSMAP_CipherModeCmd(?, g_pars.vec.kc)); + BSSAP.send(ts_BSSMAP_CipherModeCompl('02'O)); + } +} + +function f_perform_lu(boolean expect_auth, boolean expect_tmsi, boolean send_early_cm, + boolean expect_ciph := false) +runs on BSC_ConnHdlr { + var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) + var PDU_DTAP_MT dtap_mt; + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_lu); + + if (send_early_cm) { + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + } + + f_mm_common(expect_auth, expect_ciph); + + /* 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 { + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) -> value dtap_mt { + var PDU_ML3_LocationUpdateAccept lu_acc := dtap_mt.dtap.msgs.mm.locationUpdateAccept; + if (expect_tmsi) { + if (not ispresent(lu_acc.mobileIdentityTLV) or + not ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) { + setverdict(fail, "Expected TMSI but no TMSI was allocated"); + self.stop; + } else { + g_pars.tmsi := lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi.octets; + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_TmsiRealloc_Cmpl)); + } + } else { + if (ispresent(lu_acc.mobileIdentityTLV) and + ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) { + setverdict(fail, "Expected no TMSI but TMSI was allocated"); + self.stop; + } + } + } + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { + setverdict(fail, "Expected LU ACK, but received LU REJ"); + self.stop; + } + } + /* FIXME: there could be pending SMS or other common procedures by the MSC, let's ignore them */ + BSSAP.receive(tr_BSSMAP_ClearCommand); + BSSAP.send(ts_BSSMAP_ClearComplete); + BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); + setverdict(pass); +} + +function f_foo() runs on BSC_ConnHdlr{ + /* SCCP CC handled by BSSMAP_Emulation_CT.main() */ + /* Expect auth, if enabled */ + + /* TODO: ISD */ + /* Expect encr, if enabled */ + /* Expect encr, if enabled */ + /* Expect ASS CMD, if chan_type != requested */ + /* Send ASS CMPL in successful case */ + + /* Expect AoIP port/ip information for RTP stream */ + /* Expect MSC-originated MGCP to our simulated MGW */ + /* Verify Counters via CTRL */ + /* re-configure MSC behaviour via VTY */ +} + +/* parameters related to a (MO?) voice call */ +type record CallParameters { + boolean expect_auth, /* do we expect AUTHENTICATE from network */ + boolean expect_ciph, /* do we expect CIPHER MODE from network */ + + /* CC related parameters */ + hexstring called_party, /* whom are we calling */ + integer transaction_id optional, /* which TS 04.08 CC transaction ID to use */ + BearerCapability_TLV bearer_cap, /* which bearer capabilities to claim */ + + /* MNCC related parameters */ + uint32_t mncc_callref optional, /* call reference on the MNCC side */ + MNCC_bearer_cap mncc_bearer_cap optional, /* MNCC-side bearer capabilities */ + + /* RTP related parameters */ + HostName bss_rtp_ip optional, /* BSS Side RTP IP */ + PortNumber bss_rtp_port optional, /* BSS Side RTP Port */ + HostName mss_rtp_ip optional, /* MSS Side RTP IP */ + PortNumber mss_rtp_port optional, /* MSS Side RTP Port */ + HostName mgw_rtp_ip_bss, /* BSS-facing MGW RTP IP */ + PortNumber mgw_rtp_port_bss, /* BSS-facing MGW RTP Port */ + HostName mgw_rtp_ip_mss, /* MSS-facing MGW RTP IP */ + PortNumber mgw_rtp_port_mss, /* MSS-facing MGW RTP Port */ + uint7_t rtp_payload_type, /* dynamic RTP payload type */ + charstring rtp_sdp_format, /* AMR/8000 or the like */ + + MgcpCallId mgcp_call_id optional, /* MGCP Call ID; CallAgent allocated */ + MgcpEndpoint mgcp_ep optional /* MGCP Endpoint, CallAgent or MGW allocated */, + MgcpConnectionId mgcp_connection_id_bss, /* MGCP Connection ID BSS Side */ + MgcpConnectionId mgcp_connection_id_mss /* MGCP Connection ID MSS Side */ +} + +template (value) CallParameters t_CallParams(hexstring called, integer tid) := { + expect_auth := false, + expect_ciph := false, + called_party := called, + transaction_id := tid, + bearer_cap := valueof(ts_Bcap_voice), + mncc_callref := omit, + mncc_bearer_cap := valueof(ts_MNCC_bcap_voice), + bss_rtp_ip := "9.8.7.6", + bss_rtp_port := 9000, + mss_rtp_ip := omit, + mss_rtp_port := omit, + mgw_rtp_ip_bss := "1.1.1.1", + mgw_rtp_port_bss := 10000, + mgw_rtp_ip_mss := "1.1.1.1", + mgw_rtp_port_mss := 11000, + rtp_payload_type := 98, + rtp_sdp_format := "AMR/8000", + mgcp_call_id := omit, + mgcp_ep := omit, + mgcp_connection_id_bss := '0'H,// + mgcp_connection_id_mss := '0'H // +}; + + +function f_mo_call(inout CallParameters cpars) +runs on BSC_ConnHdlr { + + var MobileIdentityLV mi; + var MNCC_PDU mncc; + var MgcpCommand mgcp_cmd; + + /* If we have a TMSI, use TMSI instead of IMSI */ + if (ispresent(g_pars.tmsi)) { + mi := valueof(ts_MI_TMSI_LV(g_pars.tmsi)); + } else { + mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); + } + f_establish_fully(mi, cpars.expect_auth, cpars.expect_ciph); + + /* Create MNCC and MGCP expect */ + f_create_mncc_expect(hex2str(cpars.called_party)); + f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); + + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party))); + interleave { + [] MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc { + cpars.mncc_callref := mncc.u.signal.callref; + /* Call Proceeding */ + MNCC.send(ts_MNCC_CALL_PROC_req(cpars.mncc_callref, cpars.mncc_bearer_cap)); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(cpars.transaction_id))); + }; + /* First MGCP CRCX (for BSS/RAN side) */ + [] MGCP.receive(tr_CRCX) -> value mgcp_cmd { + cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); + /* TODO: dynamic EP allocation case */ + cpars.mgcp_ep := mgcp_cmd.line.ep; + var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_bss, cpars.mgw_rtp_ip_bss, + hex2str(cpars.mgcp_call_id), "42", + cpars.mgw_rtp_port_bss, + { int2str(cpars.rtp_payload_type) }, + { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type, + cpars.rtp_sdp_format)), + valueof(ts_SDP_ptime(20)) })); + MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_bss, sdp)); + } + } + /* Second MGCP CRCX (this time for MSS/CN side) */ + MGCP.receive(tr_CRCX(cpars.mgcp_ep)) -> value mgcp_cmd { + var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_mss, cpars.mgw_rtp_ip_mss, + hex2str(cpars.mgcp_call_id), "42", + cpars.mgw_rtp_port_mss, + { int2str(cpars.rtp_payload_type) }, + { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type, + cpars.rtp_sdp_format)), + valueof(ts_SDP_ptime(20)) })); + MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_mss, sdp)); + } + + /* Alerting */ + MNCC.send(ts_MNCC_ALERT_req(cpars.mncc_callref)); + + var BSSMAP_IE_AoIP_TransportLayerAddress tla_ass := + valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.mgw_rtp_ip_bss),cpars.mgw_rtp_port_bss)); + interleave { + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_ALERTING(cpars.transaction_id))) {} + /* expect AoIP IP/Port to match what we returned in CRCX_ACK above */ + [] BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, tla_ass)) { + var BSSMAP_IE_AoIP_TransportLayerAddress tla; + tla := valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.bss_rtp_ip), cpars.bss_rtp_port)); + BSSAP.send(ts_BSSMAP_AssignmentComplete(omit, tla)); + } + } + + /* Answer. MNCC_SETUP_RSP -> CONNECT to MS; CONNECT_ACK from MS */ + MNCC.send(ts_MNCC_SETUP_rsp(cpars.mncc_callref)); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CONNECT(cpars.transaction_id))); + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CONNECT_ACK(cpars.transaction_id))); + + f_sleep(3.0); + + /* Hangup by "B" side */ + MNCC.send(ts_MNCC_DISC_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23)))); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(cpars.transaction_id))); + + /* Release of call */ + MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(42)))); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id))); + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id))); + + /* clearing of radio channel */ + interleave { + [] BSSAP.receive(tr_BSSMAP_ClearCommand) { + BSSAP.send(ts_BSSMAP_ClearComplete); + BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); + } + [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd { + /* TODO: For one or all connections on EP? */ + MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id)); + f_create_mgcp_delete_ep(cpars.mgcp_ep); + } + } + setverdict(pass); +} + +/* expect a clear command */ +function f_expect_clear(float t := 5.0) runs on BSC_ConnHdlr { + timer T := t; + + T.start; + alt { + [] BSSAP.receive(tr_BSSMAP_ClearCommand) { } + [] BSSAP.receive { + setverdict(fail, "Unexpected BSSMAP while waiting for ClearCommand"); + self.stop; + } + [] T.timeout { + setverdict(inconc, "Timeout waiting for ClearCommand"); + self.stop; + } + } + + BSSAP.send(ts_BSSMAP_ClearComplete); + + T.start; + alt { + [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) { + setverdict(pass); + } + [] BSSAP.receive { + setverdict(fail, "Unexpected BSSMAP while waiting for SCCP Release"); + self.stop; + } + [] T.timeout { + setverdict(inconc, "Timeout waiting for SCCP Release"); + self.stop; + } + } +} + + + + +} + + diff --git a/msc/MSC_Tests.cfg b/msc/MSC_Tests.cfg new file mode 100644 index 00000000..ab8a2ff0 --- /dev/null +++ b/msc/MSC_Tests.cfg @@ -0,0 +1,42 @@ +[LOGGING] +SourceInfoFormat := Single; +#FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC; +#ConsoleMask := ERROR | WARNING | TESTCASE | TTCN_MATCHING | DEBUG_ENCDEC +FileMask := LOG_ALL | TTCN_MATCHING; + +BSSAP.FileMask := LOG_NOTHING; +"MSC_Test-M3UA".FileMask := ERROR | WARNING; +"MSC_Test-SCCP".FileMask := ERROR | WARNING; +"MSC_Test-GSUP-IPA".FileMask := ERROR | WARNING; +"MSC_Test-GSUP".FileMask := ERROR | WARNING; +"IPA-CTRL-IPA".FileMask := ERROR | WARNING; +mtc.FileMask := ERROR | WARNING; + +[TESTPORT_PARAMETERS] +#*.*.udpReuseAddress := "yes"; +"MSC_Test-MNCC".MNCC.socket_type := "SEQPACKET"; +*.MSCVTY.CTRL_MODE := "client" +*.MSCVTY.CTRL_HOSTNAME := "127.0.0.1" +*.MSCVTY.CTRL_PORTNUM := "4254" +*.MSCVTY.CTRL_LOGIN_SKIPPED := "yes" +*.MSCVTY.CTRL_DETECT_SERVER_DISCONNECTED := "yes" +*.MSCVTY.CTRL_READMODE := "buffered" +*.MSCVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes" +*.MSCVTY.PROMPT1 := "OsmoMSC> " + + +[MODULE_PARAMETERS] +M3UA_Emulation.tsp_logVerbose := true; +BSSAP_Adapter.mp_own_pc := 193; /* 0.23.3 */ +BSSAP_Adapter.mp_peer_pc := 185; /* 0.23.1 */ +BSSAP_Adapter.mp_sctp_addr := { 23906, "127.0.0.1", 2905, "127.0.0.1" }; +Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoMSC"; + +[MAIN_CONTROLLER] + +[EXECUTE] +#MSC_Tests.TC_reset +#MSC_Tests.TC_cmserv_imsi_unknown +#MSC_Tests.TC_lu_imsi_noauth_tmsi +#MSC_Tests.TC_lu_imsi_noauth_notmsi +MSC_Tests.TC_lu_imsi_reject diff --git a/msc/MSC_Tests.ttcn b/msc/MSC_Tests.ttcn new file mode 100644 index 00000000..d0000d84 --- /dev/null +++ b/msc/MSC_Tests.ttcn @@ -0,0 +1,1479 @@ +module MSC_Tests { + +import from General_Types all; +import from Osmocom_Types all; + +import from M3UA_Types all; +import from M3UA_Emulation all; + +import from MTP3asp_Types all; +import from MTP3asp_PortType all; + +import from SCCPasp_Types all; +import from SCCP_Types all; +import from SCCP_Emulation all; + +import from SCTPasp_Types all; +import from SCTPasp_PortType all; + +import from Osmocom_CTRL_Functions all; +import from Osmocom_CTRL_Types all; +import from Osmocom_CTRL_Adapter all; + +import from TELNETasp_PortType all; +import from Osmocom_VTY_Functions all; + +import from MNCC_Emulation all; +import from MNCC_Types all; + +import from MGCP_Emulation all; +import from MGCP_Types all; +import from MGCP_Templates all; +import from SDP_Types all; + +import from GSUP_Emulation all; +import from GSUP_Types all; +import from IPA_Emulation all; + +import from BSSAP_Types all; +import from BSSAP_Adapter all; +import from BSSAP_CodecPort all; +import from BSSMAP_Templates all; +import from BSSMAP_Emulation all; +import from BSC_ConnectionHandler all; + +import from MobileL3_Types all; +import from MobileL3_CommonIE_Types all; +import from L3_Templates all; + + +type component MTC_CT extends BSSAP_Adapter_CT, CTRL_Adapter_CT { + var boolean g_initialized := false; + + /* no 'adapter_CT' for MNCC or GSUP */ + var MNCC_Emulation_CT vc_MNCC; + var MGCP_Emulation_CT vc_MGCP; + var GSUP_Emulation_CT vc_GSUP; + var IPA_Emulation_CT vc_GSUP_IPA; + + /* only to get events from IPA underneath GSUP */ + port IPA_CTRL_PT GSUP_IPA_EVENT; + /* VTY to MSC */ + port TELNETasp_PT MSCVTY; +} + +modulepar { + /* remote parameters of IUT */ + charstring mp_msc_ip := "127.0.0.1"; + integer mp_msc_ctrl_port := 4255; + integer mp_msc_vty_port := 4254; + + /* local parameters of emulated HLR */ + charstring mp_hlr_ip := "127.0.0.1"; + integer mp_hlr_port := 4222; + + charstring mp_msc_mncc := "/tmp/mncc"; +} + + +function f_init_mncc(charstring id) runs on MTC_CT { + id := id & "-MNCC"; + var MnccOps ops := { + create_cb := refers(MNCC_Emulation.ExpectedCreateCallback), + unitdata_cb := refers(MNCC_Emulation.DummyUnitdataCallback) + } + + vc_MNCC := MNCC_Emulation_CT.create(id); + map(vc_MNCC:MNCC, system:MNCC_CODEC_PT); + vc_MNCC.start(MNCC_Emulation.main(ops, id, mp_msc_mncc)); +} + +function f_init_mgcp(charstring id) runs on MTC_CT { + id := id & "-MGCP"; + var MGCPOps ops := { + create_cb := refers(MGCP_Emulation.ExpectedCreateCallback), + unitdata_cb := refers(MGCP_Emulation.DummyUnitdataCallback) + } + var MGCP_conn_parameters pars := { + callagent_ip := "127.0.0.1", + callagent_udp_port := -1, + mgw_ip := "127.0.0.1", + mgw_udp_port := 2427 + } + + vc_MGCP := MGCP_Emulation_CT.create(id); + map(vc_MGCP:MGCP, system:MGCP_CODEC_PT); + vc_MGCP.start(MGCP_Emulation.main(ops, pars, id)); +} + +function f_init_gsup(charstring id) runs on MTC_CT { + id := id & "-GSUP"; + var GsupOps ops := { + create_cb := refers(GSUP_Emulation.ExpectedCreateCallback) + } + + vc_GSUP_IPA := IPA_Emulation_CT.create(id & "-IPA"); + vc_GSUP := GSUP_Emulation_CT.create(id); + + map(vc_GSUP_IPA:IPA_PORT, system:IPA_CODEC_PT); + connect(vc_GSUP:GSUP, vc_GSUP_IPA:IPA_GSUP_PORT); + /* we use this hack to get events like ASP_IPA_EVENT_UP */ + connect(vc_GSUP_IPA:IPA_CTRL_PORT, self:GSUP_IPA_EVENT); + + vc_GSUP.start(GSUP_Emulation.main(ops, id)); + vc_GSUP_IPA.start(IPA_Emulation.main_server(mp_hlr_ip, mp_hlr_port)); + + /* wait for incoming connection to GSUP port before proceeding */ + timer T := 10.0; + T.start; + alt { + [] GSUP_IPA_EVENT.receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP)) { } + [] T.timeout { + setverdict(inconc, "No connection to GSUP Port"); + self.stop + } + } +} + +function f_init() runs on MTC_CT { + + if (g_initialized == true) { + return; + } + g_initialized := true; + + f_bssap_init("MSC_Test", BSC_BssmapOps); + f_ipa_ctrl_start(mp_msc_ip, mp_msc_ctrl_port); + f_init_mncc("MSC_Test"); + f_init_mgcp("MSC_Test"); + f_init_gsup("MSC_Test"); + + map(self:MSCVTY, system:MSCVTY); + f_vty_set_prompts(MSCVTY); + f_vty_transceive(MSCVTY, "enable"); + + /* set some defaults */ + f_vty_config(MSCVTY, "network", "authentication optional"); + f_vty_config(MSCVTY, "msc", "assign-tmsi"); + f_vty_config(MSCVTY, "network", "encryption a5 0"); +} + +template PDU_BSSAP ts_BSSAP_BSSMAP := { + discriminator := '0'B, + spare := '0000000'B, + dlci := omit, + lengthIndicator := 0, /* overwritten by codec */ + pdu := ? +} + +template PDU_BSSAP tr_BSSAP_BSSMAP := { + discriminator := '0'B, + spare := '0000000'B, + dlci := omit, + lengthIndicator := ?, + pdu := { + bssmap := ? + } +} + + +type integer BssmapCause; + +template (value) BSSMAP_IE_Cause ts_BSSMAP_IE_Cause(BssmapCause val) := { + elementIdentifier := '04'O, + lengthIndicator := 0, + causeValue := int2bit(val, 7), + extensionCauseValue := '0'B, + spare1 := omit +} + +template (value) PDU_BSSAP ts_BSSMAP_Reset(BssmapCause cause) modifies ts_BSSAP_BSSMAP := { + pdu := { + bssmap := { + reset := { + messageType := '30'O, + cause := ts_BSSMAP_IE_Cause(cause), + a_InterfaceSelectorForReset := omit + } + } + } +} + +template (value) PDU_BSSAP ts_BSSMAP_ResetAck modifies ts_BSSAP_BSSMAP := { + pdu := { + bssmap := { + resetAck := { + messageType := '31'O, + a_InterfaceSelectorForReset := omit + } + } + } +} + +template PDU_BSSAP tr_BSSMAP_ResetAck modifies tr_BSSAP_BSSMAP := { + pdu := { + bssmap := { + resetAck := { + messageType := '31'O, + a_InterfaceSelectorForReset := * + } + } + } +} + +template BSSMAP_IE_CellIdentifier ts_BSSMAP_IE_CellID := { + elementIdentifier := '05'O, + lengthIndicator := 0, + cellIdentifierDiscriminator := '0000'B, + spare1_4 := '0000'B, + cellIdentification := ? +} + +type uint16_t BssmapLAC; +type uint16_t BssmapCI; + +/* +template BSSMAP_IE_CellIdentifier ts_CellId_CGI(mcc, mnc, lac, ci) +modifies ts_BSSMAP_IE_CellID := { + cellIdentification := { + cI_LAC_CGI := { + mnc_mcc := FIXME, + lac := int2oct(lac, 2), + ci := int2oct(ci, 2) + } + } +} +*/ + +template BSSMAP_IE_CellIdentifier ts_CellID_LAC_CI(BssmapLAC lac, BssmapCI ci) +modifies ts_BSSMAP_IE_CellID := { + cellIdentification := { + cI_LAC_CI := { + lac := int2oct(lac, 2), + ci := int2oct(ci, 2) + } + } +} + +template BSSMAP_IE_CellIdentifier ts_CellId_CI(BssmapCI ci) +modifies ts_BSSMAP_IE_CellID := { + cellIdentification := { + cI_CI := int2oct(ci, 2) + } +} + +template BSSMAP_IE_CellIdentifier ts_CellId_none +modifies ts_BSSMAP_IE_CellID := { + cellIdentification := { + cI_noCell := ''O + } +} + + +template BSSMAP_IE_Layer3Information ts_BSSMAP_IE_L3Info(octetstring l3info) := { + elementIdentifier := '17'O, + lengthIndicator := 0, + layer3info := l3info +} + +template PDU_BSSAP ts_BSSMAP_ComplL3(BSSMAP_IE_CellIdentifier cell_id, octetstring l3_info) +modifies ts_BSSAP_BSSMAP := { + pdu := { + bssmap := { + completeLayer3Information := { + messageType := '57'O, + cellIdentifier := cell_id, + layer3Information := ts_BSSMAP_IE_L3Info(l3_info), + chosenChannel := omit, + lSAIdentifier := omit, + aPDU := omit, + codecList := omit, + redirectAttemptFlag := omit, + sendSequenceNumber := omit, + iMSI := omit + } + } + } +} + +template PDU_BSSAP ts_BSSMAP_HandoReq(BssmapCause cause, BSSMAP_IE_CellIdentifierList cid_list) +modifies ts_BSSAP_BSSMAP := { + pdu := { + bssmap := { + handoverRequired := { + messageType := '11'O, + cause := ts_BSSMAP_IE_Cause(cause), + responseRequest := omit, + cellIdentifierList := cid_list, + circuitPoolList := omit, + currentChannelType1 := omit, + speechVersion := omit, + queueingIndicator := omit, + oldToNewBSSInfo := omit, + sourceToTargetRNCTransparentInfo := omit, + sourceToTargetRNCTransparentInfoCDMA := omit, + gERANClassmark := omit, + talkerPriority := omit, + speechCodec := omit, + cSG_Identifier := omit + } + } + } +} + +// enc_PDU_BSSAP + +function f_send_BSSAP_UNITDATA(template PDU_BSSAP bssap) runs on MTC_CT { + BSSAP.send(ts_BSSAP_UNITDATA_req(g_sccp_addr_peer, g_sccp_addr_own, bssap)) +} + +type function void_fn(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr; + +private function f_concat_pad(integer tot_len, hexstring prefix, integer suffix) return hexstring { + var integer suffix_len := tot_len - lengthof(prefix); + var charstring suffix_ch := int2str(suffix); + var integer pad_len := suffix_len - lengthof(suffix_ch); + + return prefix & int2hex(0, pad_len) & str2hex(suffix_ch); +} + +function f_gen_imei(integer suffix) return hexstring { + return f_concat_pad(15, '49999'H, suffix); +} + +function f_gen_imsi(integer suffix) return hexstring { + return f_concat_pad(15, '26242'H, suffix); +} + +function f_gen_msisdn(integer suffix) return hexstring { + return f_concat_pad(12, '49123'H, suffix); +} + +/* FIXME: move into BSC_ConnectionHandler? */ +function f_start_handler(void_fn fn, charstring id, integer imsi_suffix) runs on MTC_CT return BSC_ConnHdlr { + var BSC_ConnHdlr vc_conn; + var BSC_ConnHdlrPars pars := { + sccp_addr_own := g_sccp_addr_own, + sccp_addr_peer := g_sccp_addr_peer, + cell_id := valueof(ts_CellId_CGI('262'H, '042'H, 23, 42)), + imei := f_gen_imei(imsi_suffix), + imsi := f_gen_imsi(imsi_suffix), + msisdn := f_gen_msisdn(imsi_suffix), + tmsi := omit, + cm2 := valueof(ts_CM2_default), + cm3 := omit, + vec := omit + }; + + vc_conn := BSC_ConnHdlr.create(id); + /* BSSMAP part / A interface */ + connect(vc_conn:BSSAP, vc_BSSMAP:CLIENT); + connect(vc_conn:BSSAP_PROC, vc_BSSMAP:PROC); + /* MNCC part */ + connect(vc_conn:MNCC, vc_MNCC:MNCC_CLIENT); + connect(vc_conn:MNCC_PROC, vc_MNCC:MNCC_PROC); + /* MGCP part */ + connect(vc_conn:MGCP, vc_MGCP:MGCP_CLIENT); + connect(vc_conn:MGCP_PROC, vc_MGCP:MGCP_PROC); + /* GSUP part */ + connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT); + connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_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/ */ + vc_conn.start(derefers(fn)(id, pars)); + return vc_conn; +} + +function f_vty_config(TELNETasp_PT pt, charstring config_node, charstring cmd) +{ + /* enter config mode; enter node */ + f_vty_enter_config(pt); + f_vty_transceive(pt, config_node); + /* execute command */ + f_vty_transceive(pt, cmd); + /* leave config mode */ + f_vty_transceive(pt, "end"); +} + +private function f_tc_lu_imsi_noauth_tmsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + f_perform_lu(false, true, true); +} +testcase TC_lu_imsi_noauth_tmsi() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_lu_imsi_noauth_tmsi), testcasename(), 1); + vc_conn.done; +} + +private function f_tc_lu_imsi_noauth_notmsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + f_perform_lu(false, false, true); +} +testcase TC_lu_imsi_noauth_notmsi() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + f_vty_config(MSCVTY, "msc", "no assign-tmsi"); + + vc_conn := f_start_handler(refers(f_tc_lu_imsi_noauth_notmsi), testcasename(), 2); + vc_conn.done; +} + +/* Do LU by IMSI, refuse it on GSUP and expect LU REJ back to MS */ +private function f_tc_lu_imsi_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi); + + f_create_gsup_expect(hex2str(g_pars.imsi)); + f_bssap_compl_l3(l3_lu); + GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)); + GSUP.send(ts_GSUP_UL_ERR(g_pars.imsi, 23)); + alt { + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej(int2oct(23,1)))) { } + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) { + setverdict(fail, "Expecting LU REJ, but got ACCEPT"); + self.stop; + } + } + f_expect_clear(); +} +testcase TC_lu_imsi_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_lu_imsi_reject), testcasename(), 3); + vc_conn.done; +} + +/* Do LU by IMSI, timeout on GSUP */ +private function f_tc_lu_imsi_timeout_gsup(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi); + + f_create_gsup_expect(hex2str(g_pars.imsi)); + f_bssap_compl_l3(l3_lu); + GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)); + /* Normally the HLR would need to respond here, but we decide to force a timeout here */ + alt { + /* FIXME: Expect specific reject cause */ + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { } + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) { + setverdict(fail, "Expecting LU REJ, but got ACCEPT"); + self.stop; + } + } + f_expect_clear(); +} +testcase TC_lu_imsi_timeout_gsup() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_lu_imsi_timeout_gsup), testcasename(), 4); + vc_conn.done; +} + +private function f_tc_lu_imsi_auth_tmsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + f_perform_lu(true, true, true); +} +testcase TC_lu_imsi_auth_tmsi() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + f_vty_config(MSCVTY, "network", "authentication required"); + + vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi), testcasename(), 5); + vc_conn.done; +} + + +/* Send CM SERVICE REQ for IMSI that has never performed LU before */ +private function f_tc_cmserv_imsi_unknown(charstring id, BSC_ConnHdlrPars pars) +runs on BSC_ConnHdlr { + f_init_handler(pars); + + var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); + var BSSMAP_IE_CellIdentifier cell_id := valueof(ts_CellId_CGI('262'H, '042'H, 23, 42)); + var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi)); + + f_create_gsup_expect(hex2str(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_info); + + timer T := 10.0; + T.start; + alt { + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ)) { } + //[] BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC)) { } + [] BSSAP.receive { setverdict(fail, "Received unexpected BSSAP"); } + [] GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)) { + setverdict(fail, "Unexpected GSUP UL REQ"); + } + [] T.timeout { setverdict(inconc, "Timeout waiting for CM SERV REQ"); } + } + + f_expect_clear(); +} +testcase TC_cmserv_imsi_unknown() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_cmserv_imsi_unknown), testcasename(), 6); + vc_conn.done; +} + +private function f_tc_lu_and_mo_call(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); + cpars.bss_rtp_port := 1110; + cpars.mgcp_connection_id_bss := '22222'H; + cpars.mgcp_connection_id_mss := '33333'H; + + f_perform_lu(cpars.expect_auth, true, true); + f_mo_call(cpars); +} +testcase TC_lu_and_mo_call() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_lu_and_mo_call), testcasename(), 7); + vc_conn.done; +} + +/* Test LU (with authentication enabled), where HLR times out sending SAI response */ +private function f_tc_lu_auth_sai_timeout(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) + var PDU_DTAP_MT dtap_mt; + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_lu); + + /* Send Early Classmark, just for the fun of it */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + + GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); + /* The HLR would normally return an auth vector here, but we fail to do so. */ + + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)); + f_expect_clear(); +} +testcase TC_lu_auth_sai_timeout() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + f_vty_config(MSCVTY, "network", "authentication required"); + + vc_conn := f_start_handler(refers(f_tc_lu_auth_sai_timeout), testcasename(), 8); + vc_conn.done; +} + +/* Test LU (with authentication enabled), where HLR rejects sending SAI error */ +private function f_tc_lu_auth_sai_err(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) + var PDU_DTAP_MT dtap_mt; + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_lu); + + /* Send Early Classmark, just for the fun of it */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + + GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); + GSUP.send(ts_GSUP_SAI_ERR(g_pars.imsi, 13)); + + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)); + f_expect_clear(); +} +testcase TC_lu_auth_sai_err() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + f_vty_config(MSCVTY, "network", "authentication required"); + + vc_conn := f_start_handler(refers(f_tc_lu_auth_sai_err), testcasename(), 9); + vc_conn.done; +} + +/* Test LU but BSC will send a clear request in the middle */ +private function f_tc_lu_clear_request(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) + var PDU_DTAP_MT dtap_mt; + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_lu); + + /* Send Early Classmark, just for the fun of it */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + + f_sleep(1.0); + /* send clear request in the middle of the LU */ + BSSAP.send(ts_BSSMAP_ClearRequest(0)); + BSSAP.receive(tr_BSSMAP_ClearCommand); + BSSAP.send(ts_BSSMAP_ClearComplete); + alt { + /* See https://osmocom.org/issues/2862 */ + [] BSSAP.receive(tr_BSSMAP_ClearCommand) { repeat; } + [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {} + } + setverdict(pass); +} +testcase TC_lu_clear_request() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_lu_clear_request), testcasename(), 10); + vc_conn.done; +} + +/* Test LU but BSC will send a clear request in the middle */ +private function f_tc_lu_disconnect(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) + var PDU_DTAP_MT dtap_mt; + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_lu); + + /* Send Early Classmark, just for the fun of it */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + + f_sleep(1.0); + /* send clear request in the middle of the LU */ + BSSAP.send(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_REQ); + setverdict(pass); +} +testcase TC_lu_disconnect() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_lu_disconnect), testcasename(), 11); + vc_conn.done; +} + + +/* Test LU but with illegal mobile identity type = IMEI */ +private function f_tc_lu_by_imei(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var PDU_ML3_MS_NW l3_lu := f_build_lu_imei(g_pars.imei) + var PDU_DTAP_MT dtap_mt; + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_lu); + + /* Send Early Classmark, just for the fun of it */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + /* wait for LU reject, ignore any ID REQ */ + alt { + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { } + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_ID_Req)) { repeat; } + } + /* wait for normal teardown */ + f_expect_clear(); +} +testcase TC_lu_by_imei() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_lu_by_imei), testcasename(), 12); + vc_conn.done; +} + +/* Test LU by TMSI with unknown TMSI, expect (and answer) ID REQ. */ +private function f_tc_lu_tmsi_noauth_unknown(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var PDU_ML3_MS_NW l3_lu := f_build_lu_tmsi('01020304'O); /* FIXME: Random */ + var PDU_DTAP_MT dtap_mt; + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_lu); + + /* Send Early Classmark, just for the fun of it */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + + /* Wait for + respond to ID REQ (IMSI) */ + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_ID_Req('001'B))); + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_MM_ID_Rsp_IMSI(g_pars.imsi))); + + /* Expect MSC to do UpdateLocation to HLR; respond to it */ + 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 { + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) { + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_TmsiRealloc_Cmpl)); + } + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { + setverdict(fail, "Expected LU ACK, but received REJ"); + } + } + + /* wait for normal teardown */ + f_expect_clear(); +} +testcase TC_lu_by_tmsi_noauth_unknown() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_lu_tmsi_noauth_unknown), testcasename(), 13); + vc_conn.done; +} + + +/* Test IMSI DETACH (MI=IMSI) */ +private function f_tc_imsi_detach_by_imsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(valueof(ts_ML3_MO_MM_IMSI_DET_Ind(mi))); + + /* Send Early Classmark, just for the fun of it? */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + + /* wait for normal teardown */ + f_expect_clear(); +} +testcase TC_imsi_detach_by_imsi() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_imsi_detach_by_imsi), testcasename(), 14); + vc_conn.done; +} + +/* Test IMSI DETACH (MI=TMSI) */ +private function f_tc_imsi_detach_by_tmsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var MobileIdentityLV mi := valueof(ts_MI_TMSI_LV('01020304'O)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(valueof(ts_ML3_MO_MM_IMSI_DET_Ind(mi))); + + /* Send Early Classmark, just for the fun of it? */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + + /* wait for normal teardown */ + f_expect_clear(); +} +testcase TC_imsi_detach_by_tmsi() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_imsi_detach_by_tmsi), testcasename(), 15); + vc_conn.done; +} + +/* Test IMSI DETACH (MI=IMEI), which is illegal */ +private function f_tc_imsi_detach_by_imei(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(g_pars.imei)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(valueof(ts_ML3_MO_MM_IMSI_DET_Ind(mi))); + + /* Send Early Classmark, just for the fun of it? */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + + /* wait for normal teardown */ + f_expect_clear(); +} +testcase TC_imsi_detach_by_imei() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_imsi_detach_by_imei), testcasename(), 16); + vc_conn.done; +} + + +/* helper function for an emergency call. caller passes in mobile identity to use */ +private function f_emerg_call(MobileIdentityLV mi) runs on BSC_ConnHdlr { + + var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_EMERG_CALL, mi)); + f_bssap_compl_l3(l3_info); + BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC)); + + var hexstring called := '112'H; + var integer tid := 0; + var MNCC_PDU mncc; + f_create_mncc_expect(hex2str(called)); + + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_EMERG_SETUP(tid))); + MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(called)))) -> value mncc; + /* FIXME: extract call_id */ + + /* Call Proceeding */ + MNCC.send(ts_MNCC_CALL_PROC_req(mncc.u.signal.callref, ts_MNCC_bcap_voice)); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(tid))); + + /* Alerting */ + MNCC.send(ts_MNCC_ALERT_req(mncc.u.signal.callref)); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_ALERTING(tid))); + + /* Answer. This causes TCH assignment in case of "late assignment" */ + //MNCC.send(ts_MNCC_SETUP_COMPL_req(mncc.u.signal.callref)); + MNCC.send(ts_MNCC_SETUP_rsp(mncc.u.signal.callref)); + + f_sleep(3.0); + + /* Hangup by "B" side */ + MNCC.send(ts_MNCC_DISC_req(mncc.u.signal.callref, valueof(ts_MNCC_cause(23)))); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(tid))); + + /* Release of call */ + MNCC.send(ts_MNCC_REL_req(mncc.u.signal.callref, valueof(ts_MNCC_cause(42)))); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(tid))); + + /* clearing of radio channel */ + f_expect_clear(); +} + +/* establish an emergency call by IMEI, no SIM inserted (and hence no IMSI) */ +private function f_tc_emerg_call_imei_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(g_pars.imei)); + var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_EMERG_CALL, mi)); + f_bssap_compl_l3(l3_info); + BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ('05'O))); + f_expect_clear(); +} +testcase TC_emerg_call_imei_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_emerg_call_imei_reject), testcasename(), 17); + vc_conn.done; +} + +/* establish an emergency call by IMSI, SIM inserted (and hence IMSI) */ +private function f_tc_emerg_call_imsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + /* First perform location update to ensure subscriber is known */ + f_perform_lu(false, true, true); + /* Then issue emergency call identified by IMSI */ + f_emerg_call(valueof(ts_MI_IMSI_LV(g_pars.imsi))); +} +testcase TC_emerg_call_imsi() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_emerg_call_imsi), testcasename(), 18); + vc_conn.done; +} + +/* CM Service Request for VGCS -> reject */ +private function f_tc_cm_serv_req_vgcs_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + /* First perform location update to ensure subscriber is known */ + f_perform_lu(false, true, true); + + var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); + var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_VGCS, mi)); + f_bssap_compl_l3(l3_info); + BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ(int2oct(32,1)))); + f_expect_clear(); +} +testcase TC_cm_serv_req_vgcs_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_cm_serv_req_vgcs_reject), testcasename(), 19); + vc_conn.done; +} + +/* CM Service Request for VBS -> reject */ +private function f_tc_cm_serv_req_vbs_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + /* First perform location update to ensure subscriber is known */ + f_perform_lu(false, true, true); + + var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); + var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_VBS, mi)); + f_bssap_compl_l3(l3_info); + BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ(int2oct(32,1)))); + f_expect_clear(); +} +testcase TC_cm_serv_req_vbs_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_cm_serv_req_vbs_reject), testcasename(), 20); + vc_conn.done; +} + +/* CM Service Request for LCS -> reject */ +private function f_tc_cm_serv_req_lcs_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + /* First perform location update to ensure subscriber is known */ + f_perform_lu(false, true, true); + + var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); + var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_LCS, mi)); + f_bssap_compl_l3(l3_info); + BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ(int2oct(32,1)))); + f_expect_clear(); +} +testcase TC_cm_serv_req_lcs_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_cm_serv_req_lcs_reject), testcasename(), 21); + vc_conn.done; +} + +/* CM Re-Establishment Request */ +private function f_tc_cm_reest_req_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + /* First perform location update to ensure subscriber is known */ + f_perform_lu(false, true, true); + + var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); + var PDU_ML3_MS_NW l3_info := valueof(ts_CM_REEST_REQ(0, mi)); + f_bssap_compl_l3(l3_info); + BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ(int2oct(32,1)))); + f_expect_clear(); +} +testcase TC_cm_reest_req_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_cm_reest_req_reject), testcasename(), 22); + vc_conn.done; +} + +/* Test LU (with authentication enabled), with wrong response from MS */ +private function f_tc_lu_auth_2G_fail(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) + + /* tell GSUP dispatcher to send this IMSI to us */ + f_create_gsup_expect(hex2str(g_pars.imsi)); + + /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ + f_bssap_compl_l3(l3_lu); + + /* Send Early Classmark, just for the fun of it */ + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); + + var AuthVector vec := f_gen_auth_vec_2g(); + var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(vec.rand, vec.sres, vec.kc)); + GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); + GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple)); + + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_AUTH_REQ(vec.rand))); + /* Send back wrong auth response */ + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MT_MM_AUTH_RESP_2G('00000000'O))); + + /* Expect GSUP AUTH FAIL REP to HLR */ + GSUP.receive(tr_GSUP_AUTH_FAIL_IND(g_pars.imsi)); + + /* Expect LU REJECT with Cause == Illegal MS */ + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej('03'O))); + f_expect_clear(); +} +testcase TC_lu_auth_2G_fail() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + f_vty_config(MSCVTY, "network", "authentication required"); + + vc_conn := f_start_handler(refers(f_tc_lu_auth_2G_fail), testcasename(), 23); + vc_conn.done; +} + +private function f_tc_lu_imsi_auth_tmsi_encr_13_13(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + f_perform_lu(true, true, true, true); +} +testcase TC_lu_imsi_auth_tmsi_encr_13_13() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + f_vty_config(MSCVTY, "network", "authentication required"); + f_vty_config(MSCVTY, "network", "encryption a5 1 3"); + + vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi_encr_13_13), testcasename(), 24); + vc_conn.done; +} + +/* Test Complete L3 without payload */ +private function f_tc_cl3_no_payload(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + /* Send Complete L3 Info with empty L3 frame */ + BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own, + valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, ''O)))); + + timer T := 5.0; + T.start; + alt { + [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {} + /* Expect LU REJECT with Cause == Illegal MS */ + [] BSSAP.receive(tr_BSSMAP_ClearCommand) { + BSSAP.send(ts_BSSMAP_ClearComplete); + BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); + } + [] T.timeout { + setverdict(inconc, "Timeout waiting for ClearCommand or SCCP Release"); + self.stop; + } + } + setverdict(pass); +} +testcase TC_cl3_no_payload() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_cl3_no_payload), testcasename(), 24); + vc_conn.done; +} + +/* Test Complete L3 with random payload */ +private function f_tc_cl3_rnd_payload(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var integer len := float2int(rnd() * 256.0); + var octetstring payl := f_rnd_octstring(len); + + /* Send Complete L3 Info with empty L3 frame */ + BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own, + valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, payl)))); + + timer T := 5.0; + T.start; + alt { + /* Immediate disconnect */ + [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {} + /* Expect LU REJECT with Cause == Illegal MS */ + [] BSSAP.receive(tr_BSSMAP_ClearCommand) { + BSSAP.send(ts_BSSMAP_ClearComplete); + BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); + } + [] BSSAP.receive(tr_PDU_DTAP_MT(?)) { repeat; } + [] T.timeout { + setverdict(inconc, "Timeout waiting for ClearCommand or SCCP Release"); + self.stop; + } + } + setverdict(pass); +} +testcase TC_cl3_rnd_payload() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_cl3_rnd_payload), testcasename(), 24); + vc_conn.done; +} + +/* Test Complete L3 with random payload */ +private function f_tc_establish_and_nothing(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + f_perform_lu(false, true, true, false); + + f_establish_fully(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); + f_expect_clear(); +} +testcase TC_establish_and_nothing() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_establish_and_nothing), testcasename(), 25); + vc_conn.done; +} + +/* Test MO Call SETUP with no response from MNCC */ +private function f_tc_mo_setup_and_nothing(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + + var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); + + f_perform_lu(false, true, true, false); + + f_establish_fully(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); + f_create_mncc_expect(hex2str(cpars.called_party)); + f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); + + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party))); + + f_expect_clear(30.0); +} +testcase TC_mo_setup_and_nothing() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_mo_setup_and_nothing), testcasename(), 26); + vc_conn.done; +} + +/* Test MO Call with no response to RAN-side CRCX */ +private function f_tc_mo_crcx_ran_timeout(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); + var MNCC_PDU mncc; + var MgcpCommand mgcp_cmd; + + f_perform_lu(false, true, true, false); + + f_establish_fully(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); + f_create_mncc_expect(hex2str(cpars.called_party)); + f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); + + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party))); + MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc; + cpars.mncc_callref := mncc.u.signal.callref; + MNCC.send(ts_MNCC_CALL_PROC_req(cpars.mncc_callref, cpars.mncc_bearer_cap)); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(cpars.transaction_id))); + + MGCP.receive(tr_CRCX) -> value mgcp_cmd; + cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); + cpars.mgcp_ep := mgcp_cmd.line.ep; + /* never respond to this */ + + f_expect_clear(30.0); +} +testcase TC_mo_crcx_ran_timeout() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_mo_crcx_ran_timeout), testcasename(), 27); + vc_conn.done; +} + +/* Test MO Call with reject to RAN-side CRCX */ +private function f_tc_mo_crcx_ran_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); + var MNCC_PDU mncc; + var MgcpCommand mgcp_cmd; + + f_perform_lu(false, true, true, false); + + f_establish_fully(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); + f_create_mncc_expect(hex2str(cpars.called_party)); + f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); + + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party))); + MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc; + cpars.mncc_callref := mncc.u.signal.callref; + MNCC.send(ts_MNCC_CALL_PROC_req(cpars.mncc_callref, cpars.mncc_bearer_cap)); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(cpars.transaction_id))); + + MGCP.receive(tr_CRCX) -> value mgcp_cmd; + cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); + cpars.mgcp_ep := mgcp_cmd.line.ep; + /* Respond to CRCX with error */ + var MgcpResponse mgcp_rsp := { + line := { + code := "542", + trans_id := mgcp_cmd.line.trans_id, + string := "FORCED_FAIL" + }, + params := omit, + sdp := omit + } + MGCP.send(mgcp_rsp); + + timer T := 30.0; + T.start; + alt { + [] T.timeout { setverdict(fail, "Timeout waiting for channel release"); self.stop; } + [] BSSAP.receive(tr_BSSMAP_ClearCommand) { + BSSAP.send(ts_BSSMAP_ClearComplete); + BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); + setverdict(pass); + } + [] BSSAP.receive { repeat; } + [] MNCC.receive { repeat; } + [] GSUP.receive { repeat; } + [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd { + MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id)); + f_create_mgcp_delete_ep(cpars.mgcp_ep); + repeat; + } + [] MGCP.receive { repeat; } + } +} +testcase TC_mo_crcx_ran_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_mo_crcx_ran_reject), testcasename(), 28); + vc_conn.done; +} + + +/* helper function to start a MT call: MNCC SETUP; Paging; DChan est.; DTAP SETUP */ +private function f_mt_call_start(inout CallParameters cpars) runs on BSC_ConnHdlr { + var MNCC_PDU mncc; + var MgcpCommand mgcp_cmd; + var OCT4 tmsi; + + f_perform_lu(false, true, true, false); + if (isvalue(g_pars.tmsi)) { + tmsi := g_pars.tmsi; + } else { + tmsi := 'FFFFFFFF'O; + } + f_bssmap_register_imsi(g_pars.imsi, tmsi); + + /* Allocate 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))); + + /* MSC->BSC: expect PAGING from MSC */ + BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)); + /* MS -> MSC: PAGING RESPONSE */ + f_establish_fully_pag(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); + + f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); + + /* MSC->MS: SETUP */ + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_SETUP(cpars.transaction_id, *, cpars.called_party))); +} + +/* Test MT Call */ +private function f_tc_mt_crcx_ran_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + var CallParameters cpars := valueof(t_CallParams('123456'H, 0)); + var MNCC_PDU mncc; + var MgcpCommand mgcp_cmd; + + f_mt_call_start(cpars); + + /* MS->MSC: CALL CONFIRMED */ + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CALL_CONF(cpars.transaction_id))); + + MNCC.receive(tr_MNCC_CALL_CONF_ind(cpars.mncc_callref)); + + MGCP.receive(tr_CRCX) -> value mgcp_cmd; + cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); + cpars.mgcp_ep := mgcp_cmd.line.ep; + /* Respond to CRCX with error */ + var MgcpResponse mgcp_rsp := { + line := { + code := "542", + trans_id := mgcp_cmd.line.trans_id, + string := "FORCED_FAIL" + }, + params := omit, + sdp := omit + } + MGCP.send(mgcp_rsp); + + timer T := 30.0; + T.start; + alt { + [] T.timeout { setverdict(fail, "Timeout waiting for channel release"); self.stop; } + [] BSSAP.receive(tr_BSSMAP_ClearCommand) { + BSSAP.send(ts_BSSMAP_ClearComplete); + BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); + setverdict(pass); + } + [] BSSAP.receive { repeat; } + [] MNCC.receive { repeat; } + [] GSUP.receive { repeat; } + [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd { + MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id)); + f_create_mgcp_delete_ep(cpars.mgcp_ep); + repeat; + } + [] MGCP.receive { repeat; } + } +} +testcase TC_mt_crcx_ran_reject() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_mt_crcx_ran_reject), testcasename(), 29); + vc_conn.done; +} + + +/* Test MT Call T310 timer */ +private function f_tc_mt_t310(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars, 200.0); + var CallParameters cpars := valueof(t_CallParams('123456'H, 0)); + var MNCC_PDU mncc; + var MgcpCommand mgcp_cmd; + + f_mt_call_start(cpars); + + /* MS->MSC: CALL CONFIRMED */ + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CALL_CONF(cpars.transaction_id))); + MNCC.receive(tr_MNCC_CALL_CONF_ind(cpars.mncc_callref)); + + MGCP.receive(tr_CRCX) -> value mgcp_cmd; + cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); + cpars.mgcp_ep := mgcp_cmd.line.ep; + /* FIXME: Respond to CRCX */ + + /* old libosmocore T310 default timeout is 180s. so let's wait 190 */ + timer T := 190.0; + T.start; + alt { + [] T.timeout { setverdict(fail, "Timeout waiting for T310"); self.stop; } + [] MNCC.receive(tr_MNCC_DISC_ind(cpars.mncc_callref)) { + MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23)))); + } + } + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(cpars.transaction_id))); + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id))); + /* FIXME: We're sending this with TIflag 0: allocated by sender, which is wrong */ + BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id))); + + alt { + [] BSSAP.receive(tr_BSSMAP_ClearCommand) { + BSSAP.send(ts_BSSMAP_ClearComplete); + BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); + setverdict(pass); + } + [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd { + MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id)); + f_create_mgcp_delete_ep(cpars.mgcp_ep); + repeat; + } + } +} +testcase TC_mt_t310() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_mt_t310), testcasename(), 30); + vc_conn.done; +} + +/* Perform successful LU + MO call, then GSUP LocationCancel. Subscriber must be denied CM SERV */ +private function f_tc_gsup_cancel(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + f_init_handler(pars); + var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); + cpars.bss_rtp_port := 1110; + cpars.mgcp_connection_id_bss := '22222'H; + cpars.mgcp_connection_id_mss := '33333'H; + + /* Location Update to make subscriber known */ + f_perform_lu(cpars.expect_auth, true, true); + + /* First MO call should succeed */ + f_mo_call(cpars); + + /* Cancel the subscriber in the VLR */ + GSUP.send(ts_GSUP_CL_REQ(g_pars.imsi, OSMO_GSUP_CANCEL_TYPE_WITHDRAW)); + alt { + [] GSUP.receive(tr_GSUP_CL_RES(g_pars.imsi)) { } + [] GSUP.receive(tr_GSUP_CL_ERR(g_pars.imsi)) { + setverdict(fail, "Received GSUP Location Cancel Error"); + self.stop; + } + } + + /* Follow-up transactions should fail */ + var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); + var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi)); + f_bssap_compl_l3(l3_info); + alt { + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ)) { } + [] BSSAP.receive { + setverdict(fail, "Received unexpected BSSAP instead of CM SERV REJ"); + self.stop; + } + } + setverdict(pass); +} +testcase TC_gsup_cancel() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + + vc_conn := f_start_handler(refers(f_tc_gsup_cancel), testcasename(), 31); + vc_conn.done; +} + + + +/* TODO: + * continue to send repeated MO signalling messages to keep channel open: does MSC tmeout? + * malformed messages (missing IE, invalid message type): properly rejected? + * MT call while LU or is ongoing: Do we use existing lchan or page while lchan active? + * 3G/2G auth permutations + * encryption algorithms vs. classmark vs. vty config + * send new transaction after/during clear (like SMS, ...) + * too long L3 INFO in DTAP + * too long / padded BSSAP + * too long / short TLV values + */ + + +control { + execute( TC_lu_imsi_noauth_tmsi() ); + execute( TC_lu_imsi_noauth_notmsi() ); + execute( TC_lu_imsi_reject() ); + execute( TC_lu_imsi_timeout_gsup() ); + execute( TC_lu_imsi_auth_tmsi() ); + execute( TC_cmserv_imsi_unknown() ); + execute( TC_lu_and_mo_call() ); + execute( TC_lu_auth_sai_timeout() ); + execute( TC_lu_auth_sai_err() ); + execute( TC_lu_clear_request() ); + execute( TC_lu_disconnect() ); + execute( TC_lu_by_imei() ); + execute( TC_lu_by_tmsi_noauth_unknown() ); + execute( TC_imsi_detach_by_imsi() ); + execute( TC_imsi_detach_by_tmsi() ); + execute( TC_imsi_detach_by_imei() ); + execute( TC_emerg_call_imei_reject() ); + execute( TC_emerg_call_imsi() ); + execute( TC_cm_serv_req_vgcs_reject() ); + execute( TC_cm_serv_req_vbs_reject() ); + execute( TC_cm_serv_req_lcs_reject() ); + execute( TC_cm_reest_req_reject() ); + execute( TC_lu_auth_2G_fail() ); + execute( TC_lu_imsi_auth_tmsi_encr_13_13() ); + execute( TC_cl3_no_payload() ); + execute( TC_cl3_rnd_payload() ); + execute( TC_establish_and_nothing() ); + execute( TC_mo_setup_and_nothing() ); + execute( TC_mo_crcx_ran_timeout() ); + execute( TC_mo_crcx_ran_reject() ); + execute( TC_mt_crcx_ran_reject() ); + execute( TC_mt_t310() ); + execute( TC_gsup_cancel() ); +} + + +} diff --git a/msc/gen_links.sh b/msc/gen_links.sh new file mode 100755 index 00000000..42499476 --- /dev/null +++ b/msc/gen_links.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +BASEDIR=../deps + +gen_links() { + DIR=$1 + FILES=$* + for f in $FILES; do + echo "Linking $f" + ln -sf $DIR/$f $f + done +} + +DIR=$BASEDIR/titan.TestPorts.UNIX_DOMAIN_SOCKETasp/src +FILES="UD_PT.cc UD_PT.hh UD_PortType.ttcn UD_Types.ttcn" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src +FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCConversion.hh TCCInterface.cc TCCInterface_ip.h" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src +FILES="Socket_API_Definitions.ttcn" +gen_links $DIR $FILES + +# Required by MGCP and IPA +DIR=$BASEDIR/titan.TestPorts.IPL4asp/src +FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn IPL4asp_discovery.cc IPL4asp_protocol_L234.hh" +gen_links $DIR $FILES + +# required by M3UA_Emulation +DIR=$BASEDIR/titan.ProtocolModules.M3UA/src +FILES="M3UA_Types.ttcn" +gen_links $DIR $FILES + +# required by M3UA_Emulation +DIR=$BASEDIR/titan.TestPorts.SCTPasp/src +FILES="SCTPasp_PT.cc SCTPasp_PT.hh SCTPasp_PortType.ttcn SCTPasp_Types.ttcn" +gen_links $DIR $FILES + +# required by M3UA Emulation +DIR=../MTP3asp_CNL113337/src +FILES="MTP3asp_PortType.ttcn MTP3asp_Types.ttcn" +gen_links $DIR $FILES + +# required by SCCP Emulation +DIR=../M3UA_CNL113537/src +FILES="M3UA_Emulation.ttcn" +gen_links $DIR $FILES + +DIR=../SCCP_CNL113341/src +FILES="SCCP_Emulation.ttcn SCCP_EncDec.cc SCCP_Mapping.ttcnpp SCCP_Types.ttcn SCCPasp_Types.ttcn" +gen_links $DIR $FILES +ln -s SCCP_Mapping.ttcnpp SCCP_Mapping.ttcn + +DIR=$BASEDIR/titan.ProtocolModules.BSSMAP_v11.2.0/src +FILES="BSSAP_Types.ttcn" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.ProtocolModules.MobileL3_v13.4.0/src +FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn MobileL3_GMM_SM_Types.ttcn MobileL3_MM_Types.ttcn MobileL3_RRM_Types.ttcn MobileL3_SMS_Types.ttcn MobileL3_SS_Types.ttcn MobileL3_Types.ttcn" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.ProtocolModules.SDP/src +FILES="SDP_EncDec.cc SDP_Types.ttcn SDP_parse_.tab.c SDP_parse_.tab.h SDP_parse_parser.h SDP_parser.l +SDP_parser.y lex.SDP_parse_.c" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.ProtocolModules.RTP/src +FILES="RTP_EncDec.cc RTP_Types.ttcn" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.TELNETasp/src +FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn" +gen_links $DIR $FILES + +DIR=../library +FILES="General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn MNCC_Types.ttcn MNCC_EncDec.cc MNCC_CodecPort.ttcn mncc.h MNCC_Emulation.ttcn Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc " +FILES+="IPA_Types.ttcn IPA_Emulation.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc RSL_Types.ttcn GSUP_Types.ttcn GSUP_Emulation.ttcn " +FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn L3_Templates.ttcn L3_Templates.ttcn " +FILES+="BSSMAP_Emulation.ttcn BSSAP_CodecPort.ttcn BSSMAP_Templates.ttcn BSSAP_Adapter.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_Emulation.ttcn IPA_Emulation.ttcn " +FILES+="RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunctDef.cc " +FILES+="MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunctDef.cc " +gen_links $DIR $FILES diff --git a/msc/regen_makefile.sh b/msc/regen_makefile.sh new file mode 100755 index 00000000..dacd10b5 --- /dev/null +++ b/msc/regen_makefile.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +FILES="*.ttcn 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 *.c" + +../regen-makefile.sh MSC_Tests.ttcn $FILES diff --git a/msc_tests/BSC_ConnectionHandler.ttcn b/msc_tests/BSC_ConnectionHandler.ttcn deleted file mode 100644 index a7ce1eae..00000000 --- a/msc_tests/BSC_ConnectionHandler.ttcn +++ /dev/null @@ -1,497 +0,0 @@ -module BSC_ConnectionHandler { - -import from General_Types all; -import from Osmocom_Types all; -import from Native_Functions all; -import from GSM_Types all; -import from IPL4asp_Types all; -import from SCCPasp_Types all; -import from BSSAP_Types all; -import from BSSMAP_Emulation all; -import from BSSMAP_Templates all; - -import from GSUP_Types all; -import from GSUP_Emulation all; - -import from MNCC_Types all; -import from MNCC_Emulation all; - -import from MGCP_Types all; -import from MGCP_Emulation all; -import from MGCP_Templates all; -import from SDP_Types all; - -import from MobileL3_Types all; -import from MobileL3_CommonIE_Types all; -import from MobileL3_MM_Types all; -import from MobileL3_CC_Types all; -import from L3_Templates all; - -/* this component represents a single subscriber connection */ -type component BSC_ConnHdlr extends BSSAP_ConnHdlr, MNCC_ConnHdlr, GSUP_ConnHdlr, MGCP_ConnHdlr { - var BSC_ConnHdlrPars g_pars; - timer g_Tguard := 60.0; -} - -type record AuthVector { - OCT16 rand, - OCT4 sres, - OCT8 kc - /* FIXME: 3G elements */ -} - -type record BSC_ConnHdlrPars { - SCCP_PAR_Address sccp_addr_own, - SCCP_PAR_Address sccp_addr_peer, - BSSMAP_IE_CellIdentifier cell_id, - hexstring imei, - hexstring imsi, - hexstring msisdn, - OCT4 tmsi optional, - BSSMAP_IE_ClassmarkInformationType2 cm2, - BSSMAP_IE_ClassmarkInformationType3 cm3 optional, - AuthVector vec optional -}; - -/* altstep for the global guard timer */ -private altstep as_Tguard() runs on BSC_ConnHdlr { - [] g_Tguard.timeout { - setverdict(inconc, "Tguard timeout"); - self.stop; - } -} - -/* init function, called as first function in new BSC_ConnHdlr */ -function f_init_handler(BSC_ConnHdlrPars pars, float t_guard := 60.0) runs on BSC_ConnHdlr { - /* make parameters available via component variable */ - g_pars := pars; - /* Start guard timer and activate it as default */ - g_Tguard.start(t_guard); - activate(as_Tguard()); -} - - -/* Callback function from general BSSMAP_Emulation whenever a connectionless - * BSSMAP message arrives. Canreturn a PDU_BSSAPthat should be sent in return */ -private function BscUnitdataCallback(PDU_BSSAP bssap) -runs on BSSMAP_Emulation_CT return template PDU_BSSAP { - var template PDU_BSSAP resp := omit; - - log("BSSMAP_BscUnitdataCallback"); - /* answer all RESET with RESET ACK */ - if (match(bssap, tr_BSSMAP_Reset)){ - log("BSSMAP_BscUnitdataCallback: Responding to RESET with RESET-ACK"); - resp := ts_BSSMAP_ResetAck; - } - - /* FIXME: Handle paging, etc. */ - return resp; -} - -const BssmapOps BSC_BssmapOps := { - /* Create call-back for inbound connections from MSC (hand-over) */ - create_cb := refers(BSSMAP_Emulation.ExpectedCreateCallback), - unitdata_cb := refers(BscUnitdataCallback), - decode_dtap := true, - role_ms := true -} - - -private function MnccUnitdataCallback(MNCC_PDU mncc) -runs on MNCC_Emulation_CT return template MNCC_PDU { - log("Ignoring MNCC", mncc); - return omit; -} - -const MnccOps BCC_MnccOps := { - create_cb := refers(MNCC_Emulation.ExpectedCreateCallback), - unitdata_cb := refers(MnccUnitdataCallback) -} - - - -template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, PDU_BSSAP bssap) := { - addr_peer := peer, - addr_own := own, - bssap := bssap -}; - -/* Encode 'l3' and ask BSSMAP_Emulation to create new connection with COMPL L3 INFO */ -function f_bssap_compl_l3(PDU_ML3_MS_NW l3) -runs on BSC_ConnHdlr { - log("Sending COMPL L3: ", l3); - var octetstring l3_enc := enc_PDU_ML3_MS_NW(l3); - BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own, - valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, l3_enc)))); - alt { - [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_CONF_IND) {} - [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) { - setverdict(fail, "DISC.ind from SCCP"); - self.stop; - } - } -} - -/* helper function to fully establish a dedicated channel */ -function f_establish_fully(MobileIdentityLV mi, boolean expect_auth, boolean expect_ciph) -runs on BSC_ConnHdlr { - var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi)); - var PDU_DTAP_MT dtap_mt; - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_info); - - f_mm_common(expect_auth, expect_ciph); - if (expect_ciph) { - /* implicit CM SERVICE ACCEPT? */ - } else { - /* explicit CM SERVICE ACCEPT */ - BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC)); - } -} - -/* helper function to fully establish a dedicated channel */ -function f_establish_fully_pag(MobileIdentityLV mi, boolean expect_auth, boolean expect_ciph) -runs on BSC_ConnHdlr { - var PDU_ML3_MS_NW l3_info := valueof(ts_PAG_RESP(mi)); - var PDU_DTAP_MT dtap_mt; - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_info); - - f_mm_common(expect_auth, expect_ciph); -} - - -/* build a PDU_ML3_MS_NW containing a Location Update by IMSI */ -function f_build_lu_imsi(hexstring imsi) return PDU_ML3_MS_NW -{ - var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(imsi)); - return f_build_lu(mi); -} -function f_build_lu_imei(hexstring imei) return PDU_ML3_MS_NW -{ - var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(imei)); - return f_build_lu(mi); -} -function f_build_lu_tmsi(OCT4 tmsi) return PDU_ML3_MS_NW -{ - var MobileIdentityLV mi := valueof(ts_MI_TMSI_LV(tmsi)); - return f_build_lu(mi); -} -private function f_build_lu(MobileIdentityLV mi) return PDU_ML3_MS_NW -{ - var LocationAreaIdentification_V old_lai := { '62F220'O, '9999'O }; - var PDU_ML3_MS_NW l3_info := valueof(ts_ML3_MO_LU_Req(valueof(ts_ML3_IE_LuType_Attach), - old_lai, mi, valueof(ts_CM1))); - return l3_info; -} - -private function f_rnd_oct(integer len) return octetstring { - var integer i; - var octetstring res; - for (i := 0; i < len; i := i + 1) { - res[i] := int2oct(float2int(rnd()*256.0), 1); - } - return res; -} - -function f_gen_auth_vec_2g() return AuthVector { - var AuthVector vec; - vec.rand := f_rnd_oct(16); - vec.sres := f_rnd_oct(4); - vec.kc := f_rnd_oct(8); - return vec; -} - - -function f_mm_common(boolean expect_auth, boolean expect_ciph) runs on BSC_ConnHdlr -{ - if (expect_auth) { - g_pars.vec := f_gen_auth_vec_2g(); - var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand, - g_pars.vec.sres, - g_pars.vec.kc)); - GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); - GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple)); - - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_AUTH_REQ(g_pars.vec.rand))); - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MT_MM_AUTH_RESP_2G(g_pars.vec.sres))); - } - - if (expect_ciph) { - BSSAP.receive(tr_BSSMAP_CipherModeCmd(?, g_pars.vec.kc)); - BSSAP.send(ts_BSSMAP_CipherModeCompl('02'O)); - } -} - -function f_perform_lu(boolean expect_auth, boolean expect_tmsi, boolean send_early_cm, - boolean expect_ciph := false) -runs on BSC_ConnHdlr { - var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) - var PDU_DTAP_MT dtap_mt; - - /* tell GSUP dispatcher to send this IMSI to us */ - f_create_gsup_expect(hex2str(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_lu); - - if (send_early_cm) { - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - } - - f_mm_common(expect_auth, expect_ciph); - - /* 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 { - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) -> value dtap_mt { - var PDU_ML3_LocationUpdateAccept lu_acc := dtap_mt.dtap.msgs.mm.locationUpdateAccept; - if (expect_tmsi) { - if (not ispresent(lu_acc.mobileIdentityTLV) or - not ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) { - setverdict(fail, "Expected TMSI but no TMSI was allocated"); - self.stop; - } else { - g_pars.tmsi := lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi.octets; - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_TmsiRealloc_Cmpl)); - } - } else { - if (ispresent(lu_acc.mobileIdentityTLV) and - ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) { - setverdict(fail, "Expected no TMSI but TMSI was allocated"); - self.stop; - } - } - } - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { - setverdict(fail, "Expected LU ACK, but received LU REJ"); - self.stop; - } - } - /* FIXME: there could be pending SMS or other common procedures by the MSC, let's ignore them */ - BSSAP.receive(tr_BSSMAP_ClearCommand); - BSSAP.send(ts_BSSMAP_ClearComplete); - BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); - setverdict(pass); -} - -function f_foo() runs on BSC_ConnHdlr{ - /* SCCP CC handled by BSSMAP_Emulation_CT.main() */ - /* Expect auth, if enabled */ - - /* TODO: ISD */ - /* Expect encr, if enabled */ - /* Expect encr, if enabled */ - /* Expect ASS CMD, if chan_type != requested */ - /* Send ASS CMPL in successful case */ - - /* Expect AoIP port/ip information for RTP stream */ - /* Expect MSC-originated MGCP to our simulated MGW */ - /* Verify Counters via CTRL */ - /* re-configure MSC behaviour via VTY */ -} - -/* parameters related to a (MO?) voice call */ -type record CallParameters { - boolean expect_auth, /* do we expect AUTHENTICATE from network */ - boolean expect_ciph, /* do we expect CIPHER MODE from network */ - - /* CC related parameters */ - hexstring called_party, /* whom are we calling */ - integer transaction_id optional, /* which TS 04.08 CC transaction ID to use */ - BearerCapability_TLV bearer_cap, /* which bearer capabilities to claim */ - - /* MNCC related parameters */ - uint32_t mncc_callref optional, /* call reference on the MNCC side */ - MNCC_bearer_cap mncc_bearer_cap optional, /* MNCC-side bearer capabilities */ - - /* RTP related parameters */ - HostName bss_rtp_ip optional, /* BSS Side RTP IP */ - PortNumber bss_rtp_port optional, /* BSS Side RTP Port */ - HostName mss_rtp_ip optional, /* MSS Side RTP IP */ - PortNumber mss_rtp_port optional, /* MSS Side RTP Port */ - HostName mgw_rtp_ip_bss, /* BSS-facing MGW RTP IP */ - PortNumber mgw_rtp_port_bss, /* BSS-facing MGW RTP Port */ - HostName mgw_rtp_ip_mss, /* MSS-facing MGW RTP IP */ - PortNumber mgw_rtp_port_mss, /* MSS-facing MGW RTP Port */ - uint7_t rtp_payload_type, /* dynamic RTP payload type */ - charstring rtp_sdp_format, /* AMR/8000 or the like */ - - MgcpCallId mgcp_call_id optional, /* MGCP Call ID; CallAgent allocated */ - MgcpEndpoint mgcp_ep optional /* MGCP Endpoint, CallAgent or MGW allocated */, - MgcpConnectionId mgcp_connection_id_bss, /* MGCP Connection ID BSS Side */ - MgcpConnectionId mgcp_connection_id_mss /* MGCP Connection ID MSS Side */ -} - -template (value) CallParameters t_CallParams(hexstring called, integer tid) := { - expect_auth := false, - expect_ciph := false, - called_party := called, - transaction_id := tid, - bearer_cap := valueof(ts_Bcap_voice), - mncc_callref := omit, - mncc_bearer_cap := valueof(ts_MNCC_bcap_voice), - bss_rtp_ip := "9.8.7.6", - bss_rtp_port := 9000, - mss_rtp_ip := omit, - mss_rtp_port := omit, - mgw_rtp_ip_bss := "1.1.1.1", - mgw_rtp_port_bss := 10000, - mgw_rtp_ip_mss := "1.1.1.1", - mgw_rtp_port_mss := 11000, - rtp_payload_type := 98, - rtp_sdp_format := "AMR/8000", - mgcp_call_id := omit, - mgcp_ep := omit, - mgcp_connection_id_bss := '0'H,// - mgcp_connection_id_mss := '0'H // -}; - - -function f_mo_call(inout CallParameters cpars) -runs on BSC_ConnHdlr { - - var MobileIdentityLV mi; - var MNCC_PDU mncc; - var MgcpCommand mgcp_cmd; - - /* If we have a TMSI, use TMSI instead of IMSI */ - if (ispresent(g_pars.tmsi)) { - mi := valueof(ts_MI_TMSI_LV(g_pars.tmsi)); - } else { - mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); - } - f_establish_fully(mi, cpars.expect_auth, cpars.expect_ciph); - - /* Create MNCC and MGCP expect */ - f_create_mncc_expect(hex2str(cpars.called_party)); - f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); - - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party))); - interleave { - [] MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc { - cpars.mncc_callref := mncc.u.signal.callref; - /* Call Proceeding */ - MNCC.send(ts_MNCC_CALL_PROC_req(cpars.mncc_callref, cpars.mncc_bearer_cap)); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(cpars.transaction_id))); - }; - /* First MGCP CRCX (for BSS/RAN side) */ - [] MGCP.receive(tr_CRCX) -> value mgcp_cmd { - cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); - /* TODO: dynamic EP allocation case */ - cpars.mgcp_ep := mgcp_cmd.line.ep; - var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_bss, cpars.mgw_rtp_ip_bss, - hex2str(cpars.mgcp_call_id), "42", - cpars.mgw_rtp_port_bss, - { int2str(cpars.rtp_payload_type) }, - { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type, - cpars.rtp_sdp_format)), - valueof(ts_SDP_ptime(20)) })); - MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_bss, sdp)); - } - } - /* Second MGCP CRCX (this time for MSS/CN side) */ - MGCP.receive(tr_CRCX(cpars.mgcp_ep)) -> value mgcp_cmd { - var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_mss, cpars.mgw_rtp_ip_mss, - hex2str(cpars.mgcp_call_id), "42", - cpars.mgw_rtp_port_mss, - { int2str(cpars.rtp_payload_type) }, - { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type, - cpars.rtp_sdp_format)), - valueof(ts_SDP_ptime(20)) })); - MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_mss, sdp)); - } - - /* Alerting */ - MNCC.send(ts_MNCC_ALERT_req(cpars.mncc_callref)); - - var BSSMAP_IE_AoIP_TransportLayerAddress tla_ass := - valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.mgw_rtp_ip_bss),cpars.mgw_rtp_port_bss)); - interleave { - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_ALERTING(cpars.transaction_id))) {} - /* expect AoIP IP/Port to match what we returned in CRCX_ACK above */ - [] BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, tla_ass)) { - var BSSMAP_IE_AoIP_TransportLayerAddress tla; - tla := valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.bss_rtp_ip), cpars.bss_rtp_port)); - BSSAP.send(ts_BSSMAP_AssignmentComplete(omit, tla)); - } - } - - /* Answer. MNCC_SETUP_RSP -> CONNECT to MS; CONNECT_ACK from MS */ - MNCC.send(ts_MNCC_SETUP_rsp(cpars.mncc_callref)); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CONNECT(cpars.transaction_id))); - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CONNECT_ACK(cpars.transaction_id))); - - f_sleep(3.0); - - /* Hangup by "B" side */ - MNCC.send(ts_MNCC_DISC_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23)))); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(cpars.transaction_id))); - - /* Release of call */ - MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(42)))); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id))); - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id))); - - /* clearing of radio channel */ - interleave { - [] BSSAP.receive(tr_BSSMAP_ClearCommand) { - BSSAP.send(ts_BSSMAP_ClearComplete); - BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); - } - [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd { - /* TODO: For one or all connections on EP? */ - MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id)); - f_create_mgcp_delete_ep(cpars.mgcp_ep); - } - } - setverdict(pass); -} - -/* expect a clear command */ -function f_expect_clear(float t := 5.0) runs on BSC_ConnHdlr { - timer T := t; - - T.start; - alt { - [] BSSAP.receive(tr_BSSMAP_ClearCommand) { } - [] BSSAP.receive { - setverdict(fail, "Unexpected BSSMAP while waiting for ClearCommand"); - self.stop; - } - [] T.timeout { - setverdict(inconc, "Timeout waiting for ClearCommand"); - self.stop; - } - } - - BSSAP.send(ts_BSSMAP_ClearComplete); - - T.start; - alt { - [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) { - setverdict(pass); - } - [] BSSAP.receive { - setverdict(fail, "Unexpected BSSMAP while waiting for SCCP Release"); - self.stop; - } - [] T.timeout { - setverdict(inconc, "Timeout waiting for SCCP Release"); - self.stop; - } - } -} - - - - -} - - diff --git a/msc_tests/MSC_Tests.cfg b/msc_tests/MSC_Tests.cfg deleted file mode 100644 index ab8a2ff0..00000000 --- a/msc_tests/MSC_Tests.cfg +++ /dev/null @@ -1,42 +0,0 @@ -[LOGGING] -SourceInfoFormat := Single; -#FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC; -#ConsoleMask := ERROR | WARNING | TESTCASE | TTCN_MATCHING | DEBUG_ENCDEC -FileMask := LOG_ALL | TTCN_MATCHING; - -BSSAP.FileMask := LOG_NOTHING; -"MSC_Test-M3UA".FileMask := ERROR | WARNING; -"MSC_Test-SCCP".FileMask := ERROR | WARNING; -"MSC_Test-GSUP-IPA".FileMask := ERROR | WARNING; -"MSC_Test-GSUP".FileMask := ERROR | WARNING; -"IPA-CTRL-IPA".FileMask := ERROR | WARNING; -mtc.FileMask := ERROR | WARNING; - -[TESTPORT_PARAMETERS] -#*.*.udpReuseAddress := "yes"; -"MSC_Test-MNCC".MNCC.socket_type := "SEQPACKET"; -*.MSCVTY.CTRL_MODE := "client" -*.MSCVTY.CTRL_HOSTNAME := "127.0.0.1" -*.MSCVTY.CTRL_PORTNUM := "4254" -*.MSCVTY.CTRL_LOGIN_SKIPPED := "yes" -*.MSCVTY.CTRL_DETECT_SERVER_DISCONNECTED := "yes" -*.MSCVTY.CTRL_READMODE := "buffered" -*.MSCVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes" -*.MSCVTY.PROMPT1 := "OsmoMSC> " - - -[MODULE_PARAMETERS] -M3UA_Emulation.tsp_logVerbose := true; -BSSAP_Adapter.mp_own_pc := 193; /* 0.23.3 */ -BSSAP_Adapter.mp_peer_pc := 185; /* 0.23.1 */ -BSSAP_Adapter.mp_sctp_addr := { 23906, "127.0.0.1", 2905, "127.0.0.1" }; -Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoMSC"; - -[MAIN_CONTROLLER] - -[EXECUTE] -#MSC_Tests.TC_reset -#MSC_Tests.TC_cmserv_imsi_unknown -#MSC_Tests.TC_lu_imsi_noauth_tmsi -#MSC_Tests.TC_lu_imsi_noauth_notmsi -MSC_Tests.TC_lu_imsi_reject diff --git a/msc_tests/MSC_Tests.ttcn b/msc_tests/MSC_Tests.ttcn deleted file mode 100644 index d0000d84..00000000 --- a/msc_tests/MSC_Tests.ttcn +++ /dev/null @@ -1,1479 +0,0 @@ -module MSC_Tests { - -import from General_Types all; -import from Osmocom_Types all; - -import from M3UA_Types all; -import from M3UA_Emulation all; - -import from MTP3asp_Types all; -import from MTP3asp_PortType all; - -import from SCCPasp_Types all; -import from SCCP_Types all; -import from SCCP_Emulation all; - -import from SCTPasp_Types all; -import from SCTPasp_PortType all; - -import from Osmocom_CTRL_Functions all; -import from Osmocom_CTRL_Types all; -import from Osmocom_CTRL_Adapter all; - -import from TELNETasp_PortType all; -import from Osmocom_VTY_Functions all; - -import from MNCC_Emulation all; -import from MNCC_Types all; - -import from MGCP_Emulation all; -import from MGCP_Types all; -import from MGCP_Templates all; -import from SDP_Types all; - -import from GSUP_Emulation all; -import from GSUP_Types all; -import from IPA_Emulation all; - -import from BSSAP_Types all; -import from BSSAP_Adapter all; -import from BSSAP_CodecPort all; -import from BSSMAP_Templates all; -import from BSSMAP_Emulation all; -import from BSC_ConnectionHandler all; - -import from MobileL3_Types all; -import from MobileL3_CommonIE_Types all; -import from L3_Templates all; - - -type component MTC_CT extends BSSAP_Adapter_CT, CTRL_Adapter_CT { - var boolean g_initialized := false; - - /* no 'adapter_CT' for MNCC or GSUP */ - var MNCC_Emulation_CT vc_MNCC; - var MGCP_Emulation_CT vc_MGCP; - var GSUP_Emulation_CT vc_GSUP; - var IPA_Emulation_CT vc_GSUP_IPA; - - /* only to get events from IPA underneath GSUP */ - port IPA_CTRL_PT GSUP_IPA_EVENT; - /* VTY to MSC */ - port TELNETasp_PT MSCVTY; -} - -modulepar { - /* remote parameters of IUT */ - charstring mp_msc_ip := "127.0.0.1"; - integer mp_msc_ctrl_port := 4255; - integer mp_msc_vty_port := 4254; - - /* local parameters of emulated HLR */ - charstring mp_hlr_ip := "127.0.0.1"; - integer mp_hlr_port := 4222; - - charstring mp_msc_mncc := "/tmp/mncc"; -} - - -function f_init_mncc(charstring id) runs on MTC_CT { - id := id & "-MNCC"; - var MnccOps ops := { - create_cb := refers(MNCC_Emulation.ExpectedCreateCallback), - unitdata_cb := refers(MNCC_Emulation.DummyUnitdataCallback) - } - - vc_MNCC := MNCC_Emulation_CT.create(id); - map(vc_MNCC:MNCC, system:MNCC_CODEC_PT); - vc_MNCC.start(MNCC_Emulation.main(ops, id, mp_msc_mncc)); -} - -function f_init_mgcp(charstring id) runs on MTC_CT { - id := id & "-MGCP"; - var MGCPOps ops := { - create_cb := refers(MGCP_Emulation.ExpectedCreateCallback), - unitdata_cb := refers(MGCP_Emulation.DummyUnitdataCallback) - } - var MGCP_conn_parameters pars := { - callagent_ip := "127.0.0.1", - callagent_udp_port := -1, - mgw_ip := "127.0.0.1", - mgw_udp_port := 2427 - } - - vc_MGCP := MGCP_Emulation_CT.create(id); - map(vc_MGCP:MGCP, system:MGCP_CODEC_PT); - vc_MGCP.start(MGCP_Emulation.main(ops, pars, id)); -} - -function f_init_gsup(charstring id) runs on MTC_CT { - id := id & "-GSUP"; - var GsupOps ops := { - create_cb := refers(GSUP_Emulation.ExpectedCreateCallback) - } - - vc_GSUP_IPA := IPA_Emulation_CT.create(id & "-IPA"); - vc_GSUP := GSUP_Emulation_CT.create(id); - - map(vc_GSUP_IPA:IPA_PORT, system:IPA_CODEC_PT); - connect(vc_GSUP:GSUP, vc_GSUP_IPA:IPA_GSUP_PORT); - /* we use this hack to get events like ASP_IPA_EVENT_UP */ - connect(vc_GSUP_IPA:IPA_CTRL_PORT, self:GSUP_IPA_EVENT); - - vc_GSUP.start(GSUP_Emulation.main(ops, id)); - vc_GSUP_IPA.start(IPA_Emulation.main_server(mp_hlr_ip, mp_hlr_port)); - - /* wait for incoming connection to GSUP port before proceeding */ - timer T := 10.0; - T.start; - alt { - [] GSUP_IPA_EVENT.receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP)) { } - [] T.timeout { - setverdict(inconc, "No connection to GSUP Port"); - self.stop - } - } -} - -function f_init() runs on MTC_CT { - - if (g_initialized == true) { - return; - } - g_initialized := true; - - f_bssap_init("MSC_Test", BSC_BssmapOps); - f_ipa_ctrl_start(mp_msc_ip, mp_msc_ctrl_port); - f_init_mncc("MSC_Test"); - f_init_mgcp("MSC_Test"); - f_init_gsup("MSC_Test"); - - map(self:MSCVTY, system:MSCVTY); - f_vty_set_prompts(MSCVTY); - f_vty_transceive(MSCVTY, "enable"); - - /* set some defaults */ - f_vty_config(MSCVTY, "network", "authentication optional"); - f_vty_config(MSCVTY, "msc", "assign-tmsi"); - f_vty_config(MSCVTY, "network", "encryption a5 0"); -} - -template PDU_BSSAP ts_BSSAP_BSSMAP := { - discriminator := '0'B, - spare := '0000000'B, - dlci := omit, - lengthIndicator := 0, /* overwritten by codec */ - pdu := ? -} - -template PDU_BSSAP tr_BSSAP_BSSMAP := { - discriminator := '0'B, - spare := '0000000'B, - dlci := omit, - lengthIndicator := ?, - pdu := { - bssmap := ? - } -} - - -type integer BssmapCause; - -template (value) BSSMAP_IE_Cause ts_BSSMAP_IE_Cause(BssmapCause val) := { - elementIdentifier := '04'O, - lengthIndicator := 0, - causeValue := int2bit(val, 7), - extensionCauseValue := '0'B, - spare1 := omit -} - -template (value) PDU_BSSAP ts_BSSMAP_Reset(BssmapCause cause) modifies ts_BSSAP_BSSMAP := { - pdu := { - bssmap := { - reset := { - messageType := '30'O, - cause := ts_BSSMAP_IE_Cause(cause), - a_InterfaceSelectorForReset := omit - } - } - } -} - -template (value) PDU_BSSAP ts_BSSMAP_ResetAck modifies ts_BSSAP_BSSMAP := { - pdu := { - bssmap := { - resetAck := { - messageType := '31'O, - a_InterfaceSelectorForReset := omit - } - } - } -} - -template PDU_BSSAP tr_BSSMAP_ResetAck modifies tr_BSSAP_BSSMAP := { - pdu := { - bssmap := { - resetAck := { - messageType := '31'O, - a_InterfaceSelectorForReset := * - } - } - } -} - -template BSSMAP_IE_CellIdentifier ts_BSSMAP_IE_CellID := { - elementIdentifier := '05'O, - lengthIndicator := 0, - cellIdentifierDiscriminator := '0000'B, - spare1_4 := '0000'B, - cellIdentification := ? -} - -type uint16_t BssmapLAC; -type uint16_t BssmapCI; - -/* -template BSSMAP_IE_CellIdentifier ts_CellId_CGI(mcc, mnc, lac, ci) -modifies ts_BSSMAP_IE_CellID := { - cellIdentification := { - cI_LAC_CGI := { - mnc_mcc := FIXME, - lac := int2oct(lac, 2), - ci := int2oct(ci, 2) - } - } -} -*/ - -template BSSMAP_IE_CellIdentifier ts_CellID_LAC_CI(BssmapLAC lac, BssmapCI ci) -modifies ts_BSSMAP_IE_CellID := { - cellIdentification := { - cI_LAC_CI := { - lac := int2oct(lac, 2), - ci := int2oct(ci, 2) - } - } -} - -template BSSMAP_IE_CellIdentifier ts_CellId_CI(BssmapCI ci) -modifies ts_BSSMAP_IE_CellID := { - cellIdentification := { - cI_CI := int2oct(ci, 2) - } -} - -template BSSMAP_IE_CellIdentifier ts_CellId_none -modifies ts_BSSMAP_IE_CellID := { - cellIdentification := { - cI_noCell := ''O - } -} - - -template BSSMAP_IE_Layer3Information ts_BSSMAP_IE_L3Info(octetstring l3info) := { - elementIdentifier := '17'O, - lengthIndicator := 0, - layer3info := l3info -} - -template PDU_BSSAP ts_BSSMAP_ComplL3(BSSMAP_IE_CellIdentifier cell_id, octetstring l3_info) -modifies ts_BSSAP_BSSMAP := { - pdu := { - bssmap := { - completeLayer3Information := { - messageType := '57'O, - cellIdentifier := cell_id, - layer3Information := ts_BSSMAP_IE_L3Info(l3_info), - chosenChannel := omit, - lSAIdentifier := omit, - aPDU := omit, - codecList := omit, - redirectAttemptFlag := omit, - sendSequenceNumber := omit, - iMSI := omit - } - } - } -} - -template PDU_BSSAP ts_BSSMAP_HandoReq(BssmapCause cause, BSSMAP_IE_CellIdentifierList cid_list) -modifies ts_BSSAP_BSSMAP := { - pdu := { - bssmap := { - handoverRequired := { - messageType := '11'O, - cause := ts_BSSMAP_IE_Cause(cause), - responseRequest := omit, - cellIdentifierList := cid_list, - circuitPoolList := omit, - currentChannelType1 := omit, - speechVersion := omit, - queueingIndicator := omit, - oldToNewBSSInfo := omit, - sourceToTargetRNCTransparentInfo := omit, - sourceToTargetRNCTransparentInfoCDMA := omit, - gERANClassmark := omit, - talkerPriority := omit, - speechCodec := omit, - cSG_Identifier := omit - } - } - } -} - -// enc_PDU_BSSAP - -function f_send_BSSAP_UNITDATA(template PDU_BSSAP bssap) runs on MTC_CT { - BSSAP.send(ts_BSSAP_UNITDATA_req(g_sccp_addr_peer, g_sccp_addr_own, bssap)) -} - -type function void_fn(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr; - -private function f_concat_pad(integer tot_len, hexstring prefix, integer suffix) return hexstring { - var integer suffix_len := tot_len - lengthof(prefix); - var charstring suffix_ch := int2str(suffix); - var integer pad_len := suffix_len - lengthof(suffix_ch); - - return prefix & int2hex(0, pad_len) & str2hex(suffix_ch); -} - -function f_gen_imei(integer suffix) return hexstring { - return f_concat_pad(15, '49999'H, suffix); -} - -function f_gen_imsi(integer suffix) return hexstring { - return f_concat_pad(15, '26242'H, suffix); -} - -function f_gen_msisdn(integer suffix) return hexstring { - return f_concat_pad(12, '49123'H, suffix); -} - -/* FIXME: move into BSC_ConnectionHandler? */ -function f_start_handler(void_fn fn, charstring id, integer imsi_suffix) runs on MTC_CT return BSC_ConnHdlr { - var BSC_ConnHdlr vc_conn; - var BSC_ConnHdlrPars pars := { - sccp_addr_own := g_sccp_addr_own, - sccp_addr_peer := g_sccp_addr_peer, - cell_id := valueof(ts_CellId_CGI('262'H, '042'H, 23, 42)), - imei := f_gen_imei(imsi_suffix), - imsi := f_gen_imsi(imsi_suffix), - msisdn := f_gen_msisdn(imsi_suffix), - tmsi := omit, - cm2 := valueof(ts_CM2_default), - cm3 := omit, - vec := omit - }; - - vc_conn := BSC_ConnHdlr.create(id); - /* BSSMAP part / A interface */ - connect(vc_conn:BSSAP, vc_BSSMAP:CLIENT); - connect(vc_conn:BSSAP_PROC, vc_BSSMAP:PROC); - /* MNCC part */ - connect(vc_conn:MNCC, vc_MNCC:MNCC_CLIENT); - connect(vc_conn:MNCC_PROC, vc_MNCC:MNCC_PROC); - /* MGCP part */ - connect(vc_conn:MGCP, vc_MGCP:MGCP_CLIENT); - connect(vc_conn:MGCP_PROC, vc_MGCP:MGCP_PROC); - /* GSUP part */ - connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT); - connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_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/ */ - vc_conn.start(derefers(fn)(id, pars)); - return vc_conn; -} - -function f_vty_config(TELNETasp_PT pt, charstring config_node, charstring cmd) -{ - /* enter config mode; enter node */ - f_vty_enter_config(pt); - f_vty_transceive(pt, config_node); - /* execute command */ - f_vty_transceive(pt, cmd); - /* leave config mode */ - f_vty_transceive(pt, "end"); -} - -private function f_tc_lu_imsi_noauth_tmsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - f_perform_lu(false, true, true); -} -testcase TC_lu_imsi_noauth_tmsi() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_lu_imsi_noauth_tmsi), testcasename(), 1); - vc_conn.done; -} - -private function f_tc_lu_imsi_noauth_notmsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - f_perform_lu(false, false, true); -} -testcase TC_lu_imsi_noauth_notmsi() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - f_vty_config(MSCVTY, "msc", "no assign-tmsi"); - - vc_conn := f_start_handler(refers(f_tc_lu_imsi_noauth_notmsi), testcasename(), 2); - vc_conn.done; -} - -/* Do LU by IMSI, refuse it on GSUP and expect LU REJ back to MS */ -private function f_tc_lu_imsi_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi); - - f_create_gsup_expect(hex2str(g_pars.imsi)); - f_bssap_compl_l3(l3_lu); - GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)); - GSUP.send(ts_GSUP_UL_ERR(g_pars.imsi, 23)); - alt { - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej(int2oct(23,1)))) { } - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) { - setverdict(fail, "Expecting LU REJ, but got ACCEPT"); - self.stop; - } - } - f_expect_clear(); -} -testcase TC_lu_imsi_reject() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_lu_imsi_reject), testcasename(), 3); - vc_conn.done; -} - -/* Do LU by IMSI, timeout on GSUP */ -private function f_tc_lu_imsi_timeout_gsup(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi); - - f_create_gsup_expect(hex2str(g_pars.imsi)); - f_bssap_compl_l3(l3_lu); - GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)); - /* Normally the HLR would need to respond here, but we decide to force a timeout here */ - alt { - /* FIXME: Expect specific reject cause */ - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { } - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) { - setverdict(fail, "Expecting LU REJ, but got ACCEPT"); - self.stop; - } - } - f_expect_clear(); -} -testcase TC_lu_imsi_timeout_gsup() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_lu_imsi_timeout_gsup), testcasename(), 4); - vc_conn.done; -} - -private function f_tc_lu_imsi_auth_tmsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - f_perform_lu(true, true, true); -} -testcase TC_lu_imsi_auth_tmsi() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - f_vty_config(MSCVTY, "network", "authentication required"); - - vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi), testcasename(), 5); - vc_conn.done; -} - - -/* Send CM SERVICE REQ for IMSI that has never performed LU before */ -private function f_tc_cmserv_imsi_unknown(charstring id, BSC_ConnHdlrPars pars) -runs on BSC_ConnHdlr { - f_init_handler(pars); - - var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); - var BSSMAP_IE_CellIdentifier cell_id := valueof(ts_CellId_CGI('262'H, '042'H, 23, 42)); - var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi)); - - f_create_gsup_expect(hex2str(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_info); - - timer T := 10.0; - T.start; - alt { - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ)) { } - //[] BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC)) { } - [] BSSAP.receive { setverdict(fail, "Received unexpected BSSAP"); } - [] GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)) { - setverdict(fail, "Unexpected GSUP UL REQ"); - } - [] T.timeout { setverdict(inconc, "Timeout waiting for CM SERV REQ"); } - } - - f_expect_clear(); -} -testcase TC_cmserv_imsi_unknown() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - vc_conn := f_start_handler(refers(f_tc_cmserv_imsi_unknown), testcasename(), 6); - vc_conn.done; -} - -private function f_tc_lu_and_mo_call(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); - cpars.bss_rtp_port := 1110; - cpars.mgcp_connection_id_bss := '22222'H; - cpars.mgcp_connection_id_mss := '33333'H; - - f_perform_lu(cpars.expect_auth, true, true); - f_mo_call(cpars); -} -testcase TC_lu_and_mo_call() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_lu_and_mo_call), testcasename(), 7); - vc_conn.done; -} - -/* Test LU (with authentication enabled), where HLR times out sending SAI response */ -private function f_tc_lu_auth_sai_timeout(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) - var PDU_DTAP_MT dtap_mt; - - /* tell GSUP dispatcher to send this IMSI to us */ - f_create_gsup_expect(hex2str(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_lu); - - /* Send Early Classmark, just for the fun of it */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - - GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); - /* The HLR would normally return an auth vector here, but we fail to do so. */ - - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)); - f_expect_clear(); -} -testcase TC_lu_auth_sai_timeout() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - f_vty_config(MSCVTY, "network", "authentication required"); - - vc_conn := f_start_handler(refers(f_tc_lu_auth_sai_timeout), testcasename(), 8); - vc_conn.done; -} - -/* Test LU (with authentication enabled), where HLR rejects sending SAI error */ -private function f_tc_lu_auth_sai_err(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) - var PDU_DTAP_MT dtap_mt; - - /* tell GSUP dispatcher to send this IMSI to us */ - f_create_gsup_expect(hex2str(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_lu); - - /* Send Early Classmark, just for the fun of it */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - - GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); - GSUP.send(ts_GSUP_SAI_ERR(g_pars.imsi, 13)); - - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)); - f_expect_clear(); -} -testcase TC_lu_auth_sai_err() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - f_vty_config(MSCVTY, "network", "authentication required"); - - vc_conn := f_start_handler(refers(f_tc_lu_auth_sai_err), testcasename(), 9); - vc_conn.done; -} - -/* Test LU but BSC will send a clear request in the middle */ -private function f_tc_lu_clear_request(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) - var PDU_DTAP_MT dtap_mt; - - /* tell GSUP dispatcher to send this IMSI to us */ - f_create_gsup_expect(hex2str(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_lu); - - /* Send Early Classmark, just for the fun of it */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - - f_sleep(1.0); - /* send clear request in the middle of the LU */ - BSSAP.send(ts_BSSMAP_ClearRequest(0)); - BSSAP.receive(tr_BSSMAP_ClearCommand); - BSSAP.send(ts_BSSMAP_ClearComplete); - alt { - /* See https://osmocom.org/issues/2862 */ - [] BSSAP.receive(tr_BSSMAP_ClearCommand) { repeat; } - [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {} - } - setverdict(pass); -} -testcase TC_lu_clear_request() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_lu_clear_request), testcasename(), 10); - vc_conn.done; -} - -/* Test LU but BSC will send a clear request in the middle */ -private function f_tc_lu_disconnect(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) - var PDU_DTAP_MT dtap_mt; - - /* tell GSUP dispatcher to send this IMSI to us */ - f_create_gsup_expect(hex2str(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_lu); - - /* Send Early Classmark, just for the fun of it */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - - f_sleep(1.0); - /* send clear request in the middle of the LU */ - BSSAP.send(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_REQ); - setverdict(pass); -} -testcase TC_lu_disconnect() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_lu_disconnect), testcasename(), 11); - vc_conn.done; -} - - -/* Test LU but with illegal mobile identity type = IMEI */ -private function f_tc_lu_by_imei(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var PDU_ML3_MS_NW l3_lu := f_build_lu_imei(g_pars.imei) - var PDU_DTAP_MT dtap_mt; - - /* tell GSUP dispatcher to send this IMSI to us */ - f_create_gsup_expect(hex2str(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_lu); - - /* Send Early Classmark, just for the fun of it */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - /* wait for LU reject, ignore any ID REQ */ - alt { - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { } - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_ID_Req)) { repeat; } - } - /* wait for normal teardown */ - f_expect_clear(); -} -testcase TC_lu_by_imei() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_lu_by_imei), testcasename(), 12); - vc_conn.done; -} - -/* Test LU by TMSI with unknown TMSI, expect (and answer) ID REQ. */ -private function f_tc_lu_tmsi_noauth_unknown(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var PDU_ML3_MS_NW l3_lu := f_build_lu_tmsi('01020304'O); /* FIXME: Random */ - var PDU_DTAP_MT dtap_mt; - - /* tell GSUP dispatcher to send this IMSI to us */ - f_create_gsup_expect(hex2str(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_lu); - - /* Send Early Classmark, just for the fun of it */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - - /* Wait for + respond to ID REQ (IMSI) */ - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_ID_Req('001'B))); - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_MM_ID_Rsp_IMSI(g_pars.imsi))); - - /* Expect MSC to do UpdateLocation to HLR; respond to it */ - 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 { - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) { - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_TmsiRealloc_Cmpl)); - } - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { - setverdict(fail, "Expected LU ACK, but received REJ"); - } - } - - /* wait for normal teardown */ - f_expect_clear(); -} -testcase TC_lu_by_tmsi_noauth_unknown() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_lu_tmsi_noauth_unknown), testcasename(), 13); - vc_conn.done; -} - - -/* Test IMSI DETACH (MI=IMSI) */ -private function f_tc_imsi_detach_by_imsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(valueof(ts_ML3_MO_MM_IMSI_DET_Ind(mi))); - - /* Send Early Classmark, just for the fun of it? */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - - /* wait for normal teardown */ - f_expect_clear(); -} -testcase TC_imsi_detach_by_imsi() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_imsi_detach_by_imsi), testcasename(), 14); - vc_conn.done; -} - -/* Test IMSI DETACH (MI=TMSI) */ -private function f_tc_imsi_detach_by_tmsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var MobileIdentityLV mi := valueof(ts_MI_TMSI_LV('01020304'O)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(valueof(ts_ML3_MO_MM_IMSI_DET_Ind(mi))); - - /* Send Early Classmark, just for the fun of it? */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - - /* wait for normal teardown */ - f_expect_clear(); -} -testcase TC_imsi_detach_by_tmsi() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_imsi_detach_by_tmsi), testcasename(), 15); - vc_conn.done; -} - -/* Test IMSI DETACH (MI=IMEI), which is illegal */ -private function f_tc_imsi_detach_by_imei(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(g_pars.imei)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(valueof(ts_ML3_MO_MM_IMSI_DET_Ind(mi))); - - /* Send Early Classmark, just for the fun of it? */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - - /* wait for normal teardown */ - f_expect_clear(); -} -testcase TC_imsi_detach_by_imei() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_imsi_detach_by_imei), testcasename(), 16); - vc_conn.done; -} - - -/* helper function for an emergency call. caller passes in mobile identity to use */ -private function f_emerg_call(MobileIdentityLV mi) runs on BSC_ConnHdlr { - - var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_EMERG_CALL, mi)); - f_bssap_compl_l3(l3_info); - BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC)); - - var hexstring called := '112'H; - var integer tid := 0; - var MNCC_PDU mncc; - f_create_mncc_expect(hex2str(called)); - - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_EMERG_SETUP(tid))); - MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(called)))) -> value mncc; - /* FIXME: extract call_id */ - - /* Call Proceeding */ - MNCC.send(ts_MNCC_CALL_PROC_req(mncc.u.signal.callref, ts_MNCC_bcap_voice)); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(tid))); - - /* Alerting */ - MNCC.send(ts_MNCC_ALERT_req(mncc.u.signal.callref)); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_ALERTING(tid))); - - /* Answer. This causes TCH assignment in case of "late assignment" */ - //MNCC.send(ts_MNCC_SETUP_COMPL_req(mncc.u.signal.callref)); - MNCC.send(ts_MNCC_SETUP_rsp(mncc.u.signal.callref)); - - f_sleep(3.0); - - /* Hangup by "B" side */ - MNCC.send(ts_MNCC_DISC_req(mncc.u.signal.callref, valueof(ts_MNCC_cause(23)))); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(tid))); - - /* Release of call */ - MNCC.send(ts_MNCC_REL_req(mncc.u.signal.callref, valueof(ts_MNCC_cause(42)))); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(tid))); - - /* clearing of radio channel */ - f_expect_clear(); -} - -/* establish an emergency call by IMEI, no SIM inserted (and hence no IMSI) */ -private function f_tc_emerg_call_imei_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(g_pars.imei)); - var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_EMERG_CALL, mi)); - f_bssap_compl_l3(l3_info); - BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ('05'O))); - f_expect_clear(); -} -testcase TC_emerg_call_imei_reject() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_emerg_call_imei_reject), testcasename(), 17); - vc_conn.done; -} - -/* establish an emergency call by IMSI, SIM inserted (and hence IMSI) */ -private function f_tc_emerg_call_imsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - /* First perform location update to ensure subscriber is known */ - f_perform_lu(false, true, true); - /* Then issue emergency call identified by IMSI */ - f_emerg_call(valueof(ts_MI_IMSI_LV(g_pars.imsi))); -} -testcase TC_emerg_call_imsi() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_emerg_call_imsi), testcasename(), 18); - vc_conn.done; -} - -/* CM Service Request for VGCS -> reject */ -private function f_tc_cm_serv_req_vgcs_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - /* First perform location update to ensure subscriber is known */ - f_perform_lu(false, true, true); - - var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); - var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_VGCS, mi)); - f_bssap_compl_l3(l3_info); - BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ(int2oct(32,1)))); - f_expect_clear(); -} -testcase TC_cm_serv_req_vgcs_reject() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_cm_serv_req_vgcs_reject), testcasename(), 19); - vc_conn.done; -} - -/* CM Service Request for VBS -> reject */ -private function f_tc_cm_serv_req_vbs_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - /* First perform location update to ensure subscriber is known */ - f_perform_lu(false, true, true); - - var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); - var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_VBS, mi)); - f_bssap_compl_l3(l3_info); - BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ(int2oct(32,1)))); - f_expect_clear(); -} -testcase TC_cm_serv_req_vbs_reject() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_cm_serv_req_vbs_reject), testcasename(), 20); - vc_conn.done; -} - -/* CM Service Request for LCS -> reject */ -private function f_tc_cm_serv_req_lcs_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - /* First perform location update to ensure subscriber is known */ - f_perform_lu(false, true, true); - - var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); - var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_LCS, mi)); - f_bssap_compl_l3(l3_info); - BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ(int2oct(32,1)))); - f_expect_clear(); -} -testcase TC_cm_serv_req_lcs_reject() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_cm_serv_req_lcs_reject), testcasename(), 21); - vc_conn.done; -} - -/* CM Re-Establishment Request */ -private function f_tc_cm_reest_req_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - /* First perform location update to ensure subscriber is known */ - f_perform_lu(false, true, true); - - var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); - var PDU_ML3_MS_NW l3_info := valueof(ts_CM_REEST_REQ(0, mi)); - f_bssap_compl_l3(l3_info); - BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ(int2oct(32,1)))); - f_expect_clear(); -} -testcase TC_cm_reest_req_reject() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_cm_reest_req_reject), testcasename(), 22); - vc_conn.done; -} - -/* Test LU (with authentication enabled), with wrong response from MS */ -private function f_tc_lu_auth_2G_fail(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi) - - /* tell GSUP dispatcher to send this IMSI to us */ - f_create_gsup_expect(hex2str(g_pars.imsi)); - - /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */ - f_bssap_compl_l3(l3_lu); - - /* Send Early Classmark, just for the fun of it */ - BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)); - - var AuthVector vec := f_gen_auth_vec_2g(); - var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(vec.rand, vec.sres, vec.kc)); - GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); - GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple)); - - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_AUTH_REQ(vec.rand))); - /* Send back wrong auth response */ - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MT_MM_AUTH_RESP_2G('00000000'O))); - - /* Expect GSUP AUTH FAIL REP to HLR */ - GSUP.receive(tr_GSUP_AUTH_FAIL_IND(g_pars.imsi)); - - /* Expect LU REJECT with Cause == Illegal MS */ - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej('03'O))); - f_expect_clear(); -} -testcase TC_lu_auth_2G_fail() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - f_vty_config(MSCVTY, "network", "authentication required"); - - vc_conn := f_start_handler(refers(f_tc_lu_auth_2G_fail), testcasename(), 23); - vc_conn.done; -} - -private function f_tc_lu_imsi_auth_tmsi_encr_13_13(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - f_perform_lu(true, true, true, true); -} -testcase TC_lu_imsi_auth_tmsi_encr_13_13() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - f_vty_config(MSCVTY, "network", "authentication required"); - f_vty_config(MSCVTY, "network", "encryption a5 1 3"); - - vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi_encr_13_13), testcasename(), 24); - vc_conn.done; -} - -/* Test Complete L3 without payload */ -private function f_tc_cl3_no_payload(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - /* Send Complete L3 Info with empty L3 frame */ - BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own, - valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, ''O)))); - - timer T := 5.0; - T.start; - alt { - [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {} - /* Expect LU REJECT with Cause == Illegal MS */ - [] BSSAP.receive(tr_BSSMAP_ClearCommand) { - BSSAP.send(ts_BSSMAP_ClearComplete); - BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); - } - [] T.timeout { - setverdict(inconc, "Timeout waiting for ClearCommand or SCCP Release"); - self.stop; - } - } - setverdict(pass); -} -testcase TC_cl3_no_payload() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_cl3_no_payload), testcasename(), 24); - vc_conn.done; -} - -/* Test Complete L3 with random payload */ -private function f_tc_cl3_rnd_payload(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var integer len := float2int(rnd() * 256.0); - var octetstring payl := f_rnd_octstring(len); - - /* Send Complete L3 Info with empty L3 frame */ - BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own, - valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, payl)))); - - timer T := 5.0; - T.start; - alt { - /* Immediate disconnect */ - [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {} - /* Expect LU REJECT with Cause == Illegal MS */ - [] BSSAP.receive(tr_BSSMAP_ClearCommand) { - BSSAP.send(ts_BSSMAP_ClearComplete); - BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); - } - [] BSSAP.receive(tr_PDU_DTAP_MT(?)) { repeat; } - [] T.timeout { - setverdict(inconc, "Timeout waiting for ClearCommand or SCCP Release"); - self.stop; - } - } - setverdict(pass); -} -testcase TC_cl3_rnd_payload() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_cl3_rnd_payload), testcasename(), 24); - vc_conn.done; -} - -/* Test Complete L3 with random payload */ -private function f_tc_establish_and_nothing(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - f_perform_lu(false, true, true, false); - - f_establish_fully(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); - f_expect_clear(); -} -testcase TC_establish_and_nothing() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_establish_and_nothing), testcasename(), 25); - vc_conn.done; -} - -/* Test MO Call SETUP with no response from MNCC */ -private function f_tc_mo_setup_and_nothing(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - - var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); - - f_perform_lu(false, true, true, false); - - f_establish_fully(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); - f_create_mncc_expect(hex2str(cpars.called_party)); - f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); - - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party))); - - f_expect_clear(30.0); -} -testcase TC_mo_setup_and_nothing() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_mo_setup_and_nothing), testcasename(), 26); - vc_conn.done; -} - -/* Test MO Call with no response to RAN-side CRCX */ -private function f_tc_mo_crcx_ran_timeout(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); - var MNCC_PDU mncc; - var MgcpCommand mgcp_cmd; - - f_perform_lu(false, true, true, false); - - f_establish_fully(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); - f_create_mncc_expect(hex2str(cpars.called_party)); - f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); - - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party))); - MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc; - cpars.mncc_callref := mncc.u.signal.callref; - MNCC.send(ts_MNCC_CALL_PROC_req(cpars.mncc_callref, cpars.mncc_bearer_cap)); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(cpars.transaction_id))); - - MGCP.receive(tr_CRCX) -> value mgcp_cmd; - cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); - cpars.mgcp_ep := mgcp_cmd.line.ep; - /* never respond to this */ - - f_expect_clear(30.0); -} -testcase TC_mo_crcx_ran_timeout() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_mo_crcx_ran_timeout), testcasename(), 27); - vc_conn.done; -} - -/* Test MO Call with reject to RAN-side CRCX */ -private function f_tc_mo_crcx_ran_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); - var MNCC_PDU mncc; - var MgcpCommand mgcp_cmd; - - f_perform_lu(false, true, true, false); - - f_establish_fully(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); - f_create_mncc_expect(hex2str(cpars.called_party)); - f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); - - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party))); - MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc; - cpars.mncc_callref := mncc.u.signal.callref; - MNCC.send(ts_MNCC_CALL_PROC_req(cpars.mncc_callref, cpars.mncc_bearer_cap)); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(cpars.transaction_id))); - - MGCP.receive(tr_CRCX) -> value mgcp_cmd; - cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); - cpars.mgcp_ep := mgcp_cmd.line.ep; - /* Respond to CRCX with error */ - var MgcpResponse mgcp_rsp := { - line := { - code := "542", - trans_id := mgcp_cmd.line.trans_id, - string := "FORCED_FAIL" - }, - params := omit, - sdp := omit - } - MGCP.send(mgcp_rsp); - - timer T := 30.0; - T.start; - alt { - [] T.timeout { setverdict(fail, "Timeout waiting for channel release"); self.stop; } - [] BSSAP.receive(tr_BSSMAP_ClearCommand) { - BSSAP.send(ts_BSSMAP_ClearComplete); - BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); - setverdict(pass); - } - [] BSSAP.receive { repeat; } - [] MNCC.receive { repeat; } - [] GSUP.receive { repeat; } - [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd { - MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id)); - f_create_mgcp_delete_ep(cpars.mgcp_ep); - repeat; - } - [] MGCP.receive { repeat; } - } -} -testcase TC_mo_crcx_ran_reject() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_mo_crcx_ran_reject), testcasename(), 28); - vc_conn.done; -} - - -/* helper function to start a MT call: MNCC SETUP; Paging; DChan est.; DTAP SETUP */ -private function f_mt_call_start(inout CallParameters cpars) runs on BSC_ConnHdlr { - var MNCC_PDU mncc; - var MgcpCommand mgcp_cmd; - var OCT4 tmsi; - - f_perform_lu(false, true, true, false); - if (isvalue(g_pars.tmsi)) { - tmsi := g_pars.tmsi; - } else { - tmsi := 'FFFFFFFF'O; - } - f_bssmap_register_imsi(g_pars.imsi, tmsi); - - /* Allocate 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))); - - /* MSC->BSC: expect PAGING from MSC */ - BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)); - /* MS -> MSC: PAGING RESPONSE */ - f_establish_fully_pag(valueof(ts_MI_IMSI_LV(g_pars.imsi)), false, false); - - f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit}); - - /* MSC->MS: SETUP */ - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_SETUP(cpars.transaction_id, *, cpars.called_party))); -} - -/* Test MT Call */ -private function f_tc_mt_crcx_ran_reject(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - var CallParameters cpars := valueof(t_CallParams('123456'H, 0)); - var MNCC_PDU mncc; - var MgcpCommand mgcp_cmd; - - f_mt_call_start(cpars); - - /* MS->MSC: CALL CONFIRMED */ - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CALL_CONF(cpars.transaction_id))); - - MNCC.receive(tr_MNCC_CALL_CONF_ind(cpars.mncc_callref)); - - MGCP.receive(tr_CRCX) -> value mgcp_cmd; - cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); - cpars.mgcp_ep := mgcp_cmd.line.ep; - /* Respond to CRCX with error */ - var MgcpResponse mgcp_rsp := { - line := { - code := "542", - trans_id := mgcp_cmd.line.trans_id, - string := "FORCED_FAIL" - }, - params := omit, - sdp := omit - } - MGCP.send(mgcp_rsp); - - timer T := 30.0; - T.start; - alt { - [] T.timeout { setverdict(fail, "Timeout waiting for channel release"); self.stop; } - [] BSSAP.receive(tr_BSSMAP_ClearCommand) { - BSSAP.send(ts_BSSMAP_ClearComplete); - BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); - setverdict(pass); - } - [] BSSAP.receive { repeat; } - [] MNCC.receive { repeat; } - [] GSUP.receive { repeat; } - [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd { - MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id)); - f_create_mgcp_delete_ep(cpars.mgcp_ep); - repeat; - } - [] MGCP.receive { repeat; } - } -} -testcase TC_mt_crcx_ran_reject() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_mt_crcx_ran_reject), testcasename(), 29); - vc_conn.done; -} - - -/* Test MT Call T310 timer */ -private function f_tc_mt_t310(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars, 200.0); - var CallParameters cpars := valueof(t_CallParams('123456'H, 0)); - var MNCC_PDU mncc; - var MgcpCommand mgcp_cmd; - - f_mt_call_start(cpars); - - /* MS->MSC: CALL CONFIRMED */ - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CALL_CONF(cpars.transaction_id))); - MNCC.receive(tr_MNCC_CALL_CONF_ind(cpars.mncc_callref)); - - MGCP.receive(tr_CRCX) -> value mgcp_cmd; - cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd); - cpars.mgcp_ep := mgcp_cmd.line.ep; - /* FIXME: Respond to CRCX */ - - /* old libosmocore T310 default timeout is 180s. so let's wait 190 */ - timer T := 190.0; - T.start; - alt { - [] T.timeout { setverdict(fail, "Timeout waiting for T310"); self.stop; } - [] MNCC.receive(tr_MNCC_DISC_ind(cpars.mncc_callref)) { - MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23)))); - } - } - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(cpars.transaction_id))); - BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id))); - /* FIXME: We're sending this with TIflag 0: allocated by sender, which is wrong */ - BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id))); - - alt { - [] BSSAP.receive(tr_BSSMAP_ClearCommand) { - BSSAP.send(ts_BSSMAP_ClearComplete); - BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND); - setverdict(pass); - } - [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd { - MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id)); - f_create_mgcp_delete_ep(cpars.mgcp_ep); - repeat; - } - } -} -testcase TC_mt_t310() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_mt_t310), testcasename(), 30); - vc_conn.done; -} - -/* Perform successful LU + MO call, then GSUP LocationCancel. Subscriber must be denied CM SERV */ -private function f_tc_gsup_cancel(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { - f_init_handler(pars); - var CallParameters cpars := valueof(t_CallParams('12345'H, 0)); - cpars.bss_rtp_port := 1110; - cpars.mgcp_connection_id_bss := '22222'H; - cpars.mgcp_connection_id_mss := '33333'H; - - /* Location Update to make subscriber known */ - f_perform_lu(cpars.expect_auth, true, true); - - /* First MO call should succeed */ - f_mo_call(cpars); - - /* Cancel the subscriber in the VLR */ - GSUP.send(ts_GSUP_CL_REQ(g_pars.imsi, OSMO_GSUP_CANCEL_TYPE_WITHDRAW)); - alt { - [] GSUP.receive(tr_GSUP_CL_RES(g_pars.imsi)) { } - [] GSUP.receive(tr_GSUP_CL_ERR(g_pars.imsi)) { - setverdict(fail, "Received GSUP Location Cancel Error"); - self.stop; - } - } - - /* Follow-up transactions should fail */ - var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi)); - var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi)); - f_bssap_compl_l3(l3_info); - alt { - [] BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ)) { } - [] BSSAP.receive { - setverdict(fail, "Received unexpected BSSAP instead of CM SERV REJ"); - self.stop; - } - } - setverdict(pass); -} -testcase TC_gsup_cancel() runs on MTC_CT { - var BSC_ConnHdlr vc_conn; - f_init(); - - vc_conn := f_start_handler(refers(f_tc_gsup_cancel), testcasename(), 31); - vc_conn.done; -} - - - -/* TODO: - * continue to send repeated MO signalling messages to keep channel open: does MSC tmeout? - * malformed messages (missing IE, invalid message type): properly rejected? - * MT call while LU or is ongoing: Do we use existing lchan or page while lchan active? - * 3G/2G auth permutations - * encryption algorithms vs. classmark vs. vty config - * send new transaction after/during clear (like SMS, ...) - * too long L3 INFO in DTAP - * too long / padded BSSAP - * too long / short TLV values - */ - - -control { - execute( TC_lu_imsi_noauth_tmsi() ); - execute( TC_lu_imsi_noauth_notmsi() ); - execute( TC_lu_imsi_reject() ); - execute( TC_lu_imsi_timeout_gsup() ); - execute( TC_lu_imsi_auth_tmsi() ); - execute( TC_cmserv_imsi_unknown() ); - execute( TC_lu_and_mo_call() ); - execute( TC_lu_auth_sai_timeout() ); - execute( TC_lu_auth_sai_err() ); - execute( TC_lu_clear_request() ); - execute( TC_lu_disconnect() ); - execute( TC_lu_by_imei() ); - execute( TC_lu_by_tmsi_noauth_unknown() ); - execute( TC_imsi_detach_by_imsi() ); - execute( TC_imsi_detach_by_tmsi() ); - execute( TC_imsi_detach_by_imei() ); - execute( TC_emerg_call_imei_reject() ); - execute( TC_emerg_call_imsi() ); - execute( TC_cm_serv_req_vgcs_reject() ); - execute( TC_cm_serv_req_vbs_reject() ); - execute( TC_cm_serv_req_lcs_reject() ); - execute( TC_cm_reest_req_reject() ); - execute( TC_lu_auth_2G_fail() ); - execute( TC_lu_imsi_auth_tmsi_encr_13_13() ); - execute( TC_cl3_no_payload() ); - execute( TC_cl3_rnd_payload() ); - execute( TC_establish_and_nothing() ); - execute( TC_mo_setup_and_nothing() ); - execute( TC_mo_crcx_ran_timeout() ); - execute( TC_mo_crcx_ran_reject() ); - execute( TC_mt_crcx_ran_reject() ); - execute( TC_mt_t310() ); - execute( TC_gsup_cancel() ); -} - - -} diff --git a/msc_tests/gen_links.sh b/msc_tests/gen_links.sh deleted file mode 100755 index 42499476..00000000 --- a/msc_tests/gen_links.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash - -BASEDIR=../deps - -gen_links() { - DIR=$1 - FILES=$* - for f in $FILES; do - echo "Linking $f" - ln -sf $DIR/$f $f - done -} - -DIR=$BASEDIR/titan.TestPorts.UNIX_DOMAIN_SOCKETasp/src -FILES="UD_PT.cc UD_PT.hh UD_PortType.ttcn UD_Types.ttcn" -gen_links $DIR $FILES - -DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src -FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCConversion.hh TCCInterface.cc TCCInterface_ip.h" -gen_links $DIR $FILES - -DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src -FILES="Socket_API_Definitions.ttcn" -gen_links $DIR $FILES - -# Required by MGCP and IPA -DIR=$BASEDIR/titan.TestPorts.IPL4asp/src -FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn IPL4asp_discovery.cc IPL4asp_protocol_L234.hh" -gen_links $DIR $FILES - -# required by M3UA_Emulation -DIR=$BASEDIR/titan.ProtocolModules.M3UA/src -FILES="M3UA_Types.ttcn" -gen_links $DIR $FILES - -# required by M3UA_Emulation -DIR=$BASEDIR/titan.TestPorts.SCTPasp/src -FILES="SCTPasp_PT.cc SCTPasp_PT.hh SCTPasp_PortType.ttcn SCTPasp_Types.ttcn" -gen_links $DIR $FILES - -# required by M3UA Emulation -DIR=../MTP3asp_CNL113337/src -FILES="MTP3asp_PortType.ttcn MTP3asp_Types.ttcn" -gen_links $DIR $FILES - -# required by SCCP Emulation -DIR=../M3UA_CNL113537/src -FILES="M3UA_Emulation.ttcn" -gen_links $DIR $FILES - -DIR=../SCCP_CNL113341/src -FILES="SCCP_Emulation.ttcn SCCP_EncDec.cc SCCP_Mapping.ttcnpp SCCP_Types.ttcn SCCPasp_Types.ttcn" -gen_links $DIR $FILES -ln -s SCCP_Mapping.ttcnpp SCCP_Mapping.ttcn - -DIR=$BASEDIR/titan.ProtocolModules.BSSMAP_v11.2.0/src -FILES="BSSAP_Types.ttcn" -gen_links $DIR $FILES - -DIR=$BASEDIR/titan.ProtocolModules.MobileL3_v13.4.0/src -FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn MobileL3_GMM_SM_Types.ttcn MobileL3_MM_Types.ttcn MobileL3_RRM_Types.ttcn MobileL3_SMS_Types.ttcn MobileL3_SS_Types.ttcn MobileL3_Types.ttcn" -gen_links $DIR $FILES - -DIR=$BASEDIR/titan.ProtocolModules.SDP/src -FILES="SDP_EncDec.cc SDP_Types.ttcn SDP_parse_.tab.c SDP_parse_.tab.h SDP_parse_parser.h SDP_parser.l -SDP_parser.y lex.SDP_parse_.c" -gen_links $DIR $FILES - -DIR=$BASEDIR/titan.ProtocolModules.RTP/src -FILES="RTP_EncDec.cc RTP_Types.ttcn" -gen_links $DIR $FILES - -DIR=$BASEDIR/titan.TestPorts.TELNETasp/src -FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn" -gen_links $DIR $FILES - -DIR=../library -FILES="General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn MNCC_Types.ttcn MNCC_EncDec.cc MNCC_CodecPort.ttcn mncc.h MNCC_Emulation.ttcn Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc " -FILES+="IPA_Types.ttcn IPA_Emulation.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc RSL_Types.ttcn GSUP_Types.ttcn GSUP_Emulation.ttcn " -FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn L3_Templates.ttcn L3_Templates.ttcn " -FILES+="BSSMAP_Emulation.ttcn BSSAP_CodecPort.ttcn BSSMAP_Templates.ttcn BSSAP_Adapter.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_Emulation.ttcn IPA_Emulation.ttcn " -FILES+="RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunctDef.cc " -FILES+="MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunctDef.cc " -gen_links $DIR $FILES diff --git a/msc_tests/regen_makefile.sh b/msc_tests/regen_makefile.sh deleted file mode 100755 index dacd10b5..00000000 --- a/msc_tests/regen_makefile.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -FILES="*.ttcn 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 *.c" - -../regen-makefile.sh MSC_Tests.ttcn $FILES -- cgit v1.2.3