summaryrefslogtreecommitdiffstats
path: root/msc
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2018-01-27 16:03:20 +0100
committerHarald Welte <laforge@gnumonks.org>2018-01-27 19:10:07 +0100
commit3c68a548962ae8cf1a20304f18b735f2e29aae39 (patch)
tree9957f548d2ceeec7c4888b312f8eece2780249c4 /msc
parent89a3249b85c50ec1d48e9efbd29e83c5abfba8d7 (diff)
msc: rename sub-directory from msc_tests to msc (to be in line with bsc, etc.)
Diffstat (limited to 'msc')
-rw-r--r--msc/BSC_ConnectionHandler.ttcn497
-rw-r--r--msc/MSC_Tests.cfg42
-rw-r--r--msc/MSC_Tests.ttcn1479
-rwxr-xr-xmsc/gen_links.sh84
-rwxr-xr-xmsc/regen_makefile.sh5
5 files changed, 2107 insertions, 0 deletions
diff --git a/msc/BSC_ConnectionHandler.ttcn b/msc/BSC_ConnectionHandler.ttcn
new file mode 100644
index 0000000..a7ce1ea
--- /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 0000000..ab8a2ff
--- /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 0000000..d0000d8
--- /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 0000000..4249947
--- /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 0000000..dacd10b
--- /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