aboutsummaryrefslogtreecommitdiffstats
path: root/msc/MSC_Tests.ttcn
diff options
context:
space:
mode:
Diffstat (limited to 'msc/MSC_Tests.ttcn')
-rw-r--r--msc/MSC_Tests.ttcn1547
1 files changed, 1365 insertions, 182 deletions
diff --git a/msc/MSC_Tests.ttcn b/msc/MSC_Tests.ttcn
index 5129c5bd..283ced68 100644
--- a/msc/MSC_Tests.ttcn
+++ b/msc/MSC_Tests.ttcn
@@ -13,9 +13,12 @@ module MSC_Tests {
*/
friend module MSC_Tests_Iu;
+friend module MSC_Tests_ASCI;
import from General_Types all;
import from Osmocom_Types all;
+import from Misc_Helpers all;
+import from GSM_Types all;
import from M3UA_Types all;
import from M3UA_Emulation all;
@@ -44,9 +47,11 @@ import from MGCP_Emulation all;
import from MGCP_Types all;
import from MGCP_Templates all;
import from SDP_Types all;
+import from SDP_Templates all;
-import from GSUP_Emulation all;
import from GSUP_Types all;
+import from GSUP_Templates all;
+import from GSUP_Emulation all;
import from IPA_Emulation all;
import from BSSAP_Types all;
@@ -139,6 +144,7 @@ modulepar {
charstring mp_smpp_password := "osmocom1";
charstring mp_mme_name := "mmec01.mmegi0001.mme.epc.mnc070.mcc901.3gppnetwork.org";
charstring mp_vlr_name := "vlr.example.net";
+ integer mp_bssap_reset_retries := 1;
RAN_Configurations mp_bssap_cfg := {
{
@@ -162,10 +168,6 @@ modulepar {
rctx := 1
}
};
-
- boolean mp_enable_cell_id_test := true;
-
- boolean mp_enable_crashing_tests := true;
}
/* altstep for the global guard timer (only used when BSSAP_DIRECT
@@ -179,14 +181,15 @@ private altstep as_Tguard_direct() runs on MTC_CT {
private altstep as_optional_cc_rel(CallParameters cpars, boolean respond := false) runs on BSC_ConnHdlr {
[] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id))) {
- if (respond) {
- var BIT1 tid_remote := '1'B;
- if (cpars.mo_call) {
- tid_remote := '0'B;
- }
- BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id, tid_remote)));
+ if (respond) {
+ var BIT1 tid_remote := '1'B;
+ if (cpars.mo_call) {
+ tid_remote := '0'B;
}
+ BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id, tid_remote)));
}
+ repeat;
+ }
}
function f_init_smpp(charstring id) runs on MTC_CT {
@@ -307,10 +310,34 @@ function f_init(integer num_bsc := 1, boolean sgsap := false, boolean gsup := tr
testcase.stop("excess number of BSC instances requested");
}
+ f_ipa_ctrl_start_client(mp_msc_ip, mp_msc_ctrl_port);
+
+ 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, "msc", "check-imei-rqd 0");
+ f_vty_config(MSCVTY, "network", "encryption a5 0");
+ f_vty_config(MSCVTY, "cs7 instance 0", "sccp-timer ias " & int2str(g_msc_sccp_timer_ias));
+ f_vty_config(MSCVTY, "cs7 instance 0", "sccp-timer iar " & int2str(g_msc_sccp_timer_iar));
+ if (osmux) {
+ f_vty_config(MSCVTY, "msc", "osmux on");
+ } else {
+ f_vty_config(MSCVTY, "msc", "osmux off");
+ }
+
+ /* Configure the MGCP timeout so that a failure to set up all RTP streams triggers within the time that we keep
+ * an otherwise established call open. */
+ f_vty_config(MSCVTY, "msc", "timer mgw X2 3");
+
for (var integer i := 0; i < num_bsc; i := i + 1) {
if (isbound(mp_bssap_cfg[i])) {
var RanOps ranops := BSC_RanOps;
ranops.use_osmux := osmux;
+ ranops.bssap_reset_retries := mp_bssap_reset_retries;
f_ran_adapter_init(g_bssap[i], mp_bssap_cfg[i], "MSC_Test_" & int2str(i), ranops);
f_ran_adapter_start(g_bssap[i]);
} else {
@@ -318,7 +345,6 @@ function f_init(integer num_bsc := 1, boolean sgsap := false, boolean gsup := tr
}
}
- f_ipa_ctrl_start(mp_msc_ip, mp_msc_ctrl_port);
f_init_mncc("MSC_Test");
f_init_mgcp("MSC_Test");
@@ -331,22 +357,6 @@ function f_init(integer num_bsc := 1, boolean sgsap := false, boolean gsup := tr
f_init_sgsap("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, "msc", "check-imei-rqd 0");
- f_vty_config(MSCVTY, "network", "encryption a5 0");
- f_vty_config(MSCVTY, "cs7 instance 0", "sccp-timer ias " & int2str(g_msc_sccp_timer_ias));
- f_vty_config(MSCVTY, "cs7 instance 0", "sccp-timer iar " & int2str(g_msc_sccp_timer_iar));
- if (osmux) {
- f_vty_config(MSCVTY, "msc", "osmux on");
- } else {
- f_vty_config(MSCVTY, "msc", "osmux off");
- }
}
/* Initialize for a direct connection to BSSAP. This function is an alternative
@@ -370,7 +380,11 @@ function f_init_pars(integer imsi_suffix, boolean sgsap := false, boolean gsup :
runs on MTC_CT return BSC_ConnHdlrPars {
var BSC_ConnHdlrNetworkPars net_pars := {
kc_support := '0A'O, /* A5/1 and A5/3 enabled */
+ net_config := { "authentication optional", "encryption a5 0" },
+ expect_attach_success := true,
expect_tmsi := true,
+ expect_auth_attempt := false,
+ hlr_has_auth_info := true,
expect_auth := false,
expect_ciph := false,
expect_imei := false,
@@ -390,6 +404,7 @@ runs on MTC_CT return BSC_ConnHdlrPars {
cm2 := valueof(ts_CM2_default),
cm3 := omit,
vec := omit,
+ vec_keep := false,
net := net_pars,
send_early_cm := true,
ipa_ctrl_ip := mp_msc_ip,
@@ -404,7 +419,9 @@ runs on MTC_CT return BSC_ConnHdlrPars {
ran_is_geran := ran_is_geran,
use_osmux := use_osmux,
use_ipv6 := false,
- verify_cell_id := mp_enable_cell_id_test and verify_cell_id
+ use_csd := false,
+ verify_cell_id := verify_cell_id,
+ common_id_last_eutran_plmn := omit
};
if (not ran_is_geran) {
pars.use_umts_aka := true;
@@ -413,14 +430,15 @@ runs on MTC_CT return BSC_ConnHdlrPars {
return pars;
}
-function f_start_handler_with_pars(void_fn fn, BSC_ConnHdlrPars pars, integer bssap_idx := 0) runs on MTC_CT return BSC_ConnHdlr {
+function f_start_handler_create(BSC_ConnHdlrPars pars) runs on MTC_CT return BSC_ConnHdlr {
var BSC_ConnHdlr vc_conn;
- var charstring id := testcasename() & int2str(bssap_idx);
+ var charstring id := testcasename() & int2str(pars.ran_idx);
vc_conn := BSC_ConnHdlr.create(id);
+
/* BSSMAP part / A interface */
- connect(vc_conn:BSSAP, g_bssap[pars.ran_idx + bssap_idx].vc_RAN:CLIENT);
- connect(vc_conn:BSSAP_PROC, g_bssap[pars.ran_idx + bssap_idx].vc_RAN:PROC);
+ connect(vc_conn:BSSAP, g_bssap[pars.ran_idx].vc_RAN:CLIENT);
+ connect(vc_conn:BSSAP_PROC, g_bssap[pars.ran_idx].vc_RAN:PROC);
/* MNCC part */
connect(vc_conn:MNCC, vc_MNCC:MNCC_CLIENT);
connect(vc_conn:MNCC_PROC, vc_MNCC:MNCC_PROC);
@@ -440,10 +458,20 @@ function f_start_handler_with_pars(void_fn fn, BSC_ConnHdlrPars pars, integer bs
connect(vc_conn:SGsAP, vc_SGsAP:SGsAP_CLIENT);
connect(vc_conn:SGsAP_PROC, vc_SGsAP:SGsAP_PROC);
}
+ return vc_conn;
+}
+function f_start_handler_run(BSC_ConnHdlr vc_conn, void_fn fn, BSC_ConnHdlrPars pars) runs on MTC_CT {
+ var charstring id := testcasename() & int2str(pars.ran_idx);
/* 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));
+}
+
+function f_start_handler_with_pars(void_fn fn, BSC_ConnHdlrPars pars) runs on MTC_CT return BSC_ConnHdlr {
+ var BSC_ConnHdlr vc_conn;
+ vc_conn := f_start_handler_create(pars);
+ f_start_handler_run(vc_conn, fn, pars);
return vc_conn;
}
@@ -935,6 +963,66 @@ testcase TC_lu_clear_request() runs on MTC_CT {
vc_conn.done;
}
+/* Test reaction on Clear Request during a MO Call */
+friend function f_TC_mo_mt_call_clear_request(charstring id, BSC_ConnHdlrPars pars)
+runs on BSC_ConnHdlr {
+ var CallParameters cpars := valueof(t_CallParams);
+ var MNCC_PDU mncc_pdu;
+ timer T := 2.0;
+
+ f_init_handler(pars);
+
+ f_perform_lu();
+
+ /* HACK: reducing code duplication ('66'H - MO, '68'H - MT) */
+ if (pars.imsi == '262420002532766'H)
+ { f_mo_call_establish(cpars); }
+ else
+ { f_mt_call_establish(cpars); }
+
+ /* Hold the line for a while... */
+ f_sleep(2.0);
+
+ /* BSC sends BSSMAP Clear Request (e.g. due to RR failure) */
+ BSSAP.send(ts_BSSMAP_ClearRequest(1));
+
+ /* Expect (optional) CC RELEASE and Clear Command */
+ var default ccrel := activate(as_optional_cc_rel(cpars));
+ f_expect_clear();
+ deactivate(ccrel);
+
+ /* Expect RELease indication on the MNCC socket */
+ T.start;
+ alt {
+ [] MNCC.receive(tr_MNCC_REL_ind(cpars.mncc_callref)) -> value mncc_pdu {
+ log("Rx MNCC REL.ind, cause := ", mncc_pdu.u.signal.cause);
+ setverdict(pass);
+ }
+ [] MNCC.receive(MNCC_PDU:?) -> value mncc_pdu {
+ setverdict(fail, "Rx unexpected MNCC PDU: ", mncc_pdu);
+ }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for MNCC REL.ind");
+ }
+ }
+}
+testcase TC_mo_call_clear_request() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn;
+
+ f_init();
+
+ vc_conn := f_start_handler(refers(f_TC_mo_mt_call_clear_request), 2532766); // '66'H - MO
+ vc_conn.done;
+}
+testcase TC_mt_call_clear_request() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn;
+
+ f_init();
+
+ vc_conn := f_start_handler(refers(f_TC_mo_mt_call_clear_request), 2532768); // '68'H - MT
+ vc_conn.done;
+}
+
/* Test LU but BSC will send a clear request in the middle */
friend function f_tc_lu_disconnect(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
f_init_handler(pars);
@@ -1096,7 +1184,7 @@ private function f_tc_attached_imsi_lu_unknown_tmsi(charstring id, BSC_ConnHdlrP
f_expect_mm_info();
/* wait for normal teardown */
- f_expect_clear();
+ f_expect_clear(verify_vlr_cell_id := false);
/* Now the same IMSI is still attached in the VLR, and a LU with an unknown TMSI reveals the same IMSI only
* later during ID Response. osmo-msc first creates a new vlr_subscr for the unknown TMSI, and as soon as the
@@ -1133,7 +1221,7 @@ private function f_tc_attached_imsi_lu_unknown_tmsi(charstring id, BSC_ConnHdlrP
f_expect_mm_info();
/* wait for normal teardown */
- f_expect_clear();
+ f_expect_clear(verify_vlr_cell_id := false);
}
testcase TC_attached_imsi_lu_unknown_tmsi() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
@@ -1343,7 +1431,9 @@ private function f_tc_cm_reest_req_reject(charstring id, BSC_ConnHdlrPars pars)
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_cl3_or_initial_ue(l3_info);
- BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ(int2oct(32,1))));
+ /* Older osmo-msc returns: GSM48_REJECT_SRV_OPT_NOT_SUPPORTED = 32,
+ * newer osmo-msc with CM Re-Establish support returns: GSM48_REJECT_CALL_CAN_NOT_BE_IDENTIFIED = 38 */
+ BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ( (int2oct(32,1), int2oct(38,1)) )));
f_expect_clear();
}
testcase TC_cm_reest_req_reject() runs on MTC_CT {
@@ -1663,8 +1753,8 @@ friend function f_tc_mt_crcx_ran_reject(charstring id, BSC_ConnHdlrPars pars) ru
repeat;
}
[] MGCP.receive { repeat; }
- [] as_clear_cmd_compl_disc();
- [] as_optional_cc_rel(cpars);
+ [] as_optional_cc_rel(cpars); /* repeats internally */
+ [] as_expect_clear() { setverdict(pass); }
}
}
testcase TC_mt_crcx_ran_reject() runs on MTC_CT {
@@ -1679,46 +1769,89 @@ testcase TC_mt_crcx_ran_reject() runs on MTC_CT {
/* Test MT Call T310 timer */
friend 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;
+ var PDU_BSSAP bssap;
+ timer T310;
+ f_init_handler(pars);
+
+ /* Make sure X2 does not fire in this test. This test does not send a CN RTP port to osmo-msc, which will
+ * trigger X2 timeout. We want to test T310, so make X2 significantly longer than T310=30s. */
+ f_vty_config(MSCVTY, "msc", "timer mgw X2 40");
+
+ /* Initiate a MT call, establish connection */
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 */
+ /* NOTE: MSC is expected to start T310 here */
- /* old libosmocore T310 default timeout is 180s. so let's wait 190 */
- timer T := 190.0;
- T.start;
+ interleave {
+ /* MSC->MGW: CRCX (first) */
+ [] MGCP.receive(tr_CRCX) -> value mgcp_cmd {
+ f_handle_crcx(cpars, mgcp_cmd); /* MSC<-MGW: OK */
+ }
+
+ /* BSC->BSC: BSSMAP ASSIGNMENT REQ */
+ [] BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, ?)) -> value bssap {
+ BSSAP.send(ts_BSSMAP_AssignmentComplete(omit,
+ aoip := f_ts_BSSMAP_IE_AoIP_TLA(cpars.bss_rtp_ip, cpars.bss_rtp_port),
+ speechCodec := ts_BSSMAP_IE_SpeechCodec({ ts_CodecFR })));
+ }
+
+ /* MSC->MGW: MDCX */
+ [] MGCP.receive(tr_MDCX) -> value mgcp_cmd {
+ MGCP.send(ts_MDCX_ACK(mgcp_cmd.line.trans_id, cpars.mgw_conn_1.mgcp_connection_id,
+ sdp := omit));
+ }
+
+ /* MSC->MGW: CRCX (second) */
+ [] MGCP.receive(tr_CRCX) -> value mgcp_cmd {
+ f_handle_crcx(cpars, mgcp_cmd); /* MSC<-MGW: OK */
+ }
+
+ [] MNCC.receive(tr_MNCC_RTP_CREATE(cpars.mncc_callref));
+ }
+
+ /* Reschedule the guard timeout */
+ g_Tguard.start(30.0 + 10.0);
+
+ /* NOTE: the BSC is expected to respond with CC ALERTING at this state, so
+ * the MSC would stop T310. However, the idea is to verify T310 expiration
+ * here, so grab some popcorn and wait for MNCC DISC.ind. */
+ T310.start(30.0 + 2.0);
+ var MNCC_PDU mncc_rx;
alt {
- [] T.timeout {
- setverdict(fail, "Timeout waiting for T310");
+ [] T310.timeout {
+ setverdict(fail, "Timeout waiting for MNCC DISC.ind due to T310");
mtc.stop;
}
[] MNCC.receive(tr_MNCC_DISC_ind(cpars.mncc_callref)) {
MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23))));
+ log("Rx MNCC DISC.ind, T310.read yields ", T310.read);
+ setverdict(pass);
}
+ [] MNCC.receive(MNCC_PDU:?) -> value mncc_rx {
+ log("Rx ", mncc_rx);
+ setverdict(fail, "Expected MNCC DISC.ind, got some other MNCC message instead");
+ mtc.stop;
}
+ }
+
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)));
+ BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id, '1'B)));
alt {
[] 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);
+ // FIXME: f_create_mgcp_delete_ep(cpars.mgcp_ep);
repeat;
}
- [] as_clear_cmd_compl_disc();
+ [] as_expect_clear() { setverdict(pass); }
}
}
testcase TC_mt_t310() runs on MTC_CT {
@@ -1925,6 +2058,84 @@ testcase TC_lu_imsi_auth_tmsi_encr_13_2() runs on MTC_CT {
vc_conn.done;
}
+/* A5/0 + A5/1 + A5/3 + a5/4 only permitted on network side, and MS with only A5/1 support */
+private function f_tc_lu_imsi_auth_tmsi_encr_0134_1(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ pars.net.expect_auth := true;
+ pars.net.expect_ciph := true;
+ pars.net.kc_support := '03'O; /* A5/0 + A5/1 */
+ pars.cm1.a5_1 := '0'B;
+ pars.cm2.a5_1 := '0'B;
+ pars.cm2.classmarkInformationType2_oct5.a5_3 := '0'B;
+ pars.cm2.classmarkInformationType2_oct5.a5_2 := '0'B;
+ pars.cm2.classmarkInformationType2_oct5.cm3 := '0'B;
+ pars.cm3 := omit;
+ pars.use_umts_aka := true;
+
+ f_init_handler(pars, 15.0);
+ f_perform_lu();
+}
+testcase TC_lu_imsi_auth_tmsi_encr_0134_1() 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 0 1 3 4");
+
+ vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi_encr_0134_1), 39);
+ vc_conn.done;
+}
+
+/* A5/0 + A5/1 + A5/3 + a5/4 only permitted on network side, and MS with A5/3 + A5/4 support */
+private function f_tc_lu_imsi_auth_tmsi_encr_0134_34(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ pars.net.expect_auth := true;
+ pars.net.expect_ciph := true;
+ pars.net.kc_support := '19'O; /* A5/3 + A5/4 */
+ pars.cm1.a5_1 := '1'B;
+ pars.cm2.a5_1 := '1'B;
+ pars.cm2.classmarkInformationType2_oct5.a5_3 := '1'B;
+ pars.cm2.classmarkInformationType2_oct5.a5_2 := '0'B;
+ pars.cm2.classmarkInformationType2_oct5.cm3 := '1'B;
+ pars.cm3 := valueof(ts_CM3_default);
+ pars.use_umts_aka := true;
+
+ f_init_handler(pars, 15.0);
+ f_perform_lu();
+}
+testcase TC_lu_imsi_auth_tmsi_encr_0134_34() 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 0 1 3 4");
+
+ vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi_encr_0134_34), 40);
+ vc_conn.done;
+}
+
+/* A5/0 + A5/1 + A5/3 + a5/4 only permitted on network side, and MS with A5/3 support but no CM3 */
+private function f_tc_lu_imsi_auth_tmsi_encr_0134_34_no_cm3(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ pars.net.expect_auth := true;
+ pars.net.expect_ciph := true;
+ pars.net.kc_support := '19'O; /* A5/3 + A5/4 */
+ pars.cm1.a5_1 := '1'B;
+ pars.cm2.a5_1 := '1'B;
+ pars.cm2.classmarkInformationType2_oct5.a5_3 := '1'B;
+ pars.cm2.classmarkInformationType2_oct5.a5_2 := '0'B;
+ pars.cm2.classmarkInformationType2_oct5.cm3 := '0'B;
+ pars.cm3 := omit;
+ pars.use_umts_aka := true;
+
+ f_init_handler(pars, 15.0);
+ f_perform_lu();
+}
+testcase TC_lu_imsi_auth_tmsi_encr_0134_34_no_cm3() 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 0 1 3 4");
+
+ vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi_encr_0134_34_no_cm3), 41);
+ vc_conn.done;
+}
+
/* A5/0 + A5/1 + A5/3 only permitted on network side, and MS with only A5/2 support */
private function f_tc_lu_imsi_auth_tmsi_encr_013_2(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
pars.net.expect_auth := true;
@@ -2017,7 +2228,7 @@ friend function f_tc_lu_and_mt_call_already_paging(charstring id, BSC_ConnHdlrPa
f_expect_paging();
log("MNCC signals MT call, before Paging Response");
- f_mt_call_initate(cpars);
+ f_mt_call_initiate(cpars);
f_ran_register_imsi(g_pars.imsi, g_pars.tmsi);
f_sleep(0.5);
@@ -2330,11 +2541,7 @@ friend function f_tc_lu_and_mt_sms_paging_and_nothing(charstring id, BSC_ConnHdl
timer T := 20.0;
T.start
alt {
- [pars.ran_is_geran] BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)) {
- setverdict(fail, "paging seems not to stop!");
- mtc.stop;
- }
- [not pars.ran_is_geran] BSSAP.receive(tr_RANAP_Paging(cs_domain, imsi_hex2oct(g_pars.imsi))) {
+ [] as_paging_any() {
setverdict(fail, "paging seems not to stop!");
mtc.stop;
}
@@ -2387,13 +2594,18 @@ friend function f_tc_lu_and_mt_sms_paging_repeated(charstring id, BSC_ConnHdlrPa
timer T := 5.0;
T.start;
alt {
- [g_pars.ran_is_geran] BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)) {
- setverdict(fail, "GERAN should not repeat Paging, but received a second Paging");
- mtc.stop;
+ [] as_paging() {
+ if (g_pars.ran_is_geran) {
+ setverdict(fail, "GERAN should not repeat Paging, but received a second Paging");
+ mtc.stop;
+ } else {
+ log("UTRAN: second Paging received, as expected");
+ setverdict(pass);
}
- [not g_pars.ran_is_geran] BSSAP.receive(tr_RANAP_Paging(cs_domain, imsi_hex2oct(g_pars.imsi))) {
- log("UTRAN: second Paging received, as expected");
- setverdict(pass);
+ }
+ [] as_paging_any() {
+ setverdict(fail, "Rx unexpected BSSMAP/RANAP Paging");
+ mtc.stop;
}
[] T.timeout {
if (g_pars.ran_is_geran) {
@@ -2582,8 +2794,7 @@ runs on BSC_ConnHdlr {
setverdict(pass);
}
[] GSUP.receive {
- log("RX unexpected GSUP message");
- setverdict(fail);
+ setverdict(fail, "Rx unexpected GSUP message");
mtc.stop;
}
}
@@ -2638,8 +2849,7 @@ runs on BSC_ConnHdlr {
setverdict(pass);
}
[] GSUP.receive {
- log("RX unexpected GSUP message");
- setverdict(fail);
+ setverdict(fail, "Rx unexpected GSUP message");
mtc.stop;
}
}
@@ -2726,8 +2936,7 @@ runs on BSC_ConnHdlr {
setverdict(pass);
}
[] GSUP.receive {
- log("RX unexpected GSUP message");
- setverdict(fail);
+ setverdict(fail, "Rx unexpected GSUP message");
mtc.stop;
}
}
@@ -2789,8 +2998,7 @@ runs on BSC_ConnHdlr {
mtc.stop;
}
[] GSUP.receive {
- log("RX unexpected GSUP message");
- setverdict(fail);
+ setverdict(fail, "Rx unexpected GSUP message");
mtc.stop;
}
}
@@ -2850,24 +3058,20 @@ runs on BSC_ConnHdlr {
/* Both transaction IDs shall be different */
if (spars1.tid == spars2.tid) {
- log("Both DTAP transaction IDs shall be different");
- setverdict(fail);
+ setverdict(fail, "Both DTAP transaction IDs shall be different");
}
/* Both SM-RP-MR values shall be different */
if (spars1.rp.msg_ref == spars2.rp.msg_ref) {
- log("Both SM-RP-MR values shall be different");
- setverdict(fail);
+ setverdict(fail, "Both SM-RP-MR values shall be different");
}
/* Both SM-RP-MR values shall be assigned */
if (spars1.rp.msg_ref == 'FF'O) {
- log("Unassigned SM-RP-MR value for the 1st SMS");
- setverdict(fail);
+ setverdict(fail, "Unassigned SM-RP-MR value for the 1st SMS");
}
if (spars2.rp.msg_ref == 'FF'O) {
- log("Unassigned SM-RP-MR value for the 2nd SMS");
- setverdict(fail);
+ setverdict(fail, "Unassigned SM-RP-MR value for the 2nd SMS");
}
/* Send the 1st RP-ACK and expect MT-forwardSM-Res on GSUP */
@@ -2881,8 +3085,7 @@ runs on BSC_ConnHdlr {
setverdict(pass);
}
[] GSUP.receive {
- log("RX unexpected GSUP message");
- setverdict(fail);
+ setverdict(fail, "Rx unexpected GSUP message");
mtc.stop;
}
}
@@ -2898,8 +3101,7 @@ runs on BSC_ConnHdlr {
setverdict(pass);
}
[] GSUP.receive {
- log("RX unexpected GSUP message");
- setverdict(fail);
+ setverdict(fail, "Rx unexpected GSUP message");
mtc.stop;
}
}
@@ -2954,8 +3156,7 @@ runs on BSC_ConnHdlr {
setverdict(pass);
}
[] GSUP.receive {
- log("RX unexpected GSUP message");
- setverdict(fail);
+ setverdict(fail, "Rx unexpected GSUP message");
mtc.stop;
}
}
@@ -2971,14 +3172,12 @@ runs on BSC_ConnHdlr {
/* Both SM-RP-MR values shall be different */
if (spars_mo.rp.msg_ref == spars_mt.rp.msg_ref) {
- log("Both SM-RP-MR values shall be different");
- setverdict(fail);
+ setverdict(fail, "Both SM-RP-MR values shall be different");
}
/* SM-RP-MR value for MT SMS shall be assigned */
if (spars_mt.rp.msg_ref == 'FF'O) {
- log("Unassigned SM-RP-MR value for the MT SMS");
- setverdict(fail);
+ setverdict(fail, "Unassigned SM-RP-MR value for the MT SMS");
}
/* Trigger RP-ACK for MO SMMA by sending MO-forwardSM-Res */
@@ -2999,8 +3198,7 @@ runs on BSC_ConnHdlr {
setverdict(pass);
}
[] GSUP.receive {
- log("RX unexpected GSUP message");
- setverdict(fail);
+ setverdict(fail, "Rx unexpected GSUP message");
mtc.stop;
}
}
@@ -3063,8 +3261,7 @@ runs on BSC_ConnHdlr {
setverdict(pass);
}
[] GSUP.receive {
- log("RX unexpected GSUP message");
- setverdict(fail);
+ setverdict(fail, "Rx unexpected GSUP message");
mtc.stop;
}
}
@@ -3086,6 +3283,65 @@ testcase TC_gsup_mt_multi_part_sms() runs on MTC_CT {
f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}
+/* Test X36 (LU delay) timer allowing to deliver MT SMS over the same connection */
+friend function f_TC_gsup_mt_sms_lu_delay(charstring id, BSC_ConnHdlrPars pars)
+runs on BSC_ConnHdlr {
+ var SmsParameters spars := valueof(t_SmsPars);
+
+ f_init_handler(pars);
+
+ /* We need to inspect GSUP activity */
+ f_create_gsup_expect(hex2str(g_pars.imsi));
+
+ /* Perform location update */
+ f_perform_lu(expect_clear := false);
+
+ /* Register an 'expect' for given IMSI (+TMSI) */
+ f_ran_register_imsi(g_pars.imsi, g_pars.tmsi);
+
+ var template GSUP_PDU mt_forwardSM_res := tr_GSUP_MT_FORWARD_SM_RES(
+ imsi := g_pars.imsi,
+ /* NOTE: MSC should assign RP-MR itself */
+ sm_rp_mr := ?
+ );
+
+ /* Some delay to make sure the connection remains alive */
+ f_sleep(0.5);
+
+ /* Submit a MT SMS on GSUP */
+ f_gsup_forwardSM_req(spars);
+
+ /* Wait for MT SMS on DTAP */
+ f_mt_sms_expect(spars);
+
+ /* Send RP-ACK and expect MT-forwardSM-Res on GSUP */
+ f_mt_sms_send_rp_ack(spars);
+ alt {
+ [] GSUP.receive(mt_forwardSM_res) {
+ log("RX MT-forwardSM-Res (RP-ACK)");
+ setverdict(pass);
+ }
+ [] GSUP.receive {
+ setverdict(fail, "Rx unexpected GSUP message");
+ mtc.stop;
+ }
+ }
+
+ f_expect_clear();
+}
+testcase TC_gsup_mt_sms_lu_delay() runs on MTC_CT {
+ var BSC_ConnHdlrPars pars;
+ var BSC_ConnHdlr vc_conn;
+ f_init();
+ pars := f_init_pars(92);
+ f_vty_config(MSCVTY, "msc", "sms-over-gsup");
+ f_vty_config(MSCVTY, "msc", "timer geran X36 2500"); /* 2.5s */
+ vc_conn := f_start_handler_with_pars(refers(f_TC_gsup_mt_sms_lu_delay), pars);
+ vc_conn.done;
+ f_vty_config(MSCVTY, "msc", "timer geran X36 0");
+ f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
+}
+
/* convert GSM L3 TON to SMPP_TON enum */
function f_sm_ton_from_gsm(BIT3 ton) return SMPP_TON {
select (ton) {
@@ -3383,13 +3639,11 @@ runs on BSC_ConnHdlr {
GSUP.send(gsup_req);
T.start;
alt {
- [pars.ran_is_geran] BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)) {
- setverdict(pass);
- }
- [not pars.ran_is_geran] BSSAP.receive(tr_RANAP_Paging(cs_domain, imsi_hex2oct(g_pars.imsi))) {
- setverdict(pass);
+ [] as_paging() { setverdict(pass); }
+ [] as_paging_any() {
+ setverdict(fail, "Rx unexpected BSSMAP/RANAP Paging");
+ mtc.stop;
}
- /* We don't expect anything else */
[] as_unexp_gsup_or_bssap_msg();
[] T.timeout {
setverdict(fail, "Timeout waiting for Paging Request");
@@ -3998,13 +4252,11 @@ runs on BSC_ConnHdlr {
/* Send it to MSC and expect Paging Request */
TP.start;
alt {
- [pars.ran_is_geran] BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)) {
- setverdict(pass);
- }
- [not pars.ran_is_geran] BSSAP.receive(tr_RANAP_Paging(cs_domain, imsi_hex2oct(g_pars.imsi))) {
- setverdict(pass);
+ [] as_paging() { setverdict(pass); }
+ [] as_paging_any() {
+ setverdict(fail, "Rx unexpected BSSMAP/RANAP Paging");
+ mtc.stop;
}
- /* We don't expect anything else */
[] as_unexp_gsup_or_bssap_msg();
[] TP.timeout {
setverdict(fail, "Timeout waiting for Paging Request");
@@ -4072,13 +4324,11 @@ runs on BSC_ConnHdlr {
/* Expect Paging Request */
TP.start;
alt {
- [pars.ran_is_geran] BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)) {
- setverdict(pass);
- }
- [not pars.ran_is_geran] BSSAP.receive(tr_RANAP_Paging(cs_domain, imsi_hex2oct(g_pars.imsi))) {
- setverdict(pass);
+ [] as_paging() { setverdict(pass); }
+ [] as_paging_any() {
+ setverdict(fail, "Rx unexpected BSSMAP/RANAP Paging");
+ mtc.stop;
}
- /* We don't expect anything else */
[] as_unexp_gsup_or_bssap_msg();
[] TP.timeout {
setverdict(fail, "Timeout waiting for Paging Request");
@@ -4230,7 +4480,7 @@ friend function f_tc_lu_with_invalid_mcc_mnc(charstring id, BSC_ConnHdlrPars par
mtc.stop;
}
}
- f_expect_clear();
+ f_expect_clear(verify_vlr_cell_id:=false);
}
testcase TC_lu_with_invalid_mcc_mnc() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
@@ -4282,7 +4532,7 @@ private function f_tc_cipher_complete_without_alg(charstring id, BSC_ConnHdlrPar
/* TODO: Verify MSC is using the best cipher available! How? */
f_msc_lu_hlr();
- f_accept_reject_lu();
+ as_accept_reject_lu();
f_expect_clear();
setverdict(pass);
}
@@ -4375,11 +4625,16 @@ private function f_ctrl_subscr_in_vlr(charstring imsi_or_msisdn) runs on BSC_Con
return true;
}
-/* Perform a location updatye at the A-Interface and run some checks to confirm
+/* Perform a Location Update at the A-Interface and run some checks to confirm
* that everything is back to normal. */
private function f_sgsap_bssmap_screening() runs on BSC_ConnHdlr {
var SmsParameters spars := valueof(t_SmsPars);
+ /* From now on, since we initiated LU from A-Interface, we expect no
+ * LastEutranPLMNId on Common Id, since the SGs interface should be gone
+ */
+ g_pars.common_id_last_eutran_plmn := omit;
+
/* Perform a location update, the SGs association is expected to fall
* back to NULL */
f_perform_lu();
@@ -4392,11 +4647,10 @@ private function f_sgsap_bssmap_screening() runs on BSC_ConnHdlr {
f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " paging");
alt {
- [g_pars.ran_is_geran] BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)); {
- setverdict(pass);
- }
- [not g_pars.ran_is_geran] BSSAP.receive(tr_RANAP_Paging(cs_domain, imsi_hex2oct(g_pars.imsi))) {
- setverdict(pass);
+ [] as_paging() { setverdict(pass); }
+ [] as_paging_any() {
+ setverdict(fail, "Rx unexpected BSSMAP/RANAP Paging");
+ mtc.stop;
}
[] SGsAP.receive {
setverdict(fail, "Received unexpected message on SGs");
@@ -4454,12 +4708,19 @@ function f_sgs_perform_lu() runs on BSC_ConnHdlr {
var PDU_SGsAP lua;
var PDU_SGsAP mm_info;
var octetstring mm_info_dtap;
+ var GsmMcc mcc;
+ var GsmMnc mnc;
+ var template (omit) TrackingAreaIdentityValue tai := omit;
/* tell GSUP dispatcher to send this IMSI to us */
f_create_gsup_expect(hex2str(g_pars.imsi));
-
+ if (g_pars.common_id_last_eutran_plmn != omit) {
+ f_dec_mcc_mnc(g_pars.common_id_last_eutran_plmn, mcc, mnc);
+ tai := ts_SGsAP_TAI(mcc, mnc, 555);
+ }
lur := valueof(ts_SGsAP_LU_REQ(g_pars.imsi, mme_name, IMSI_attach,
- ts_SGsAP_LAI('901'H, '70'H, 2342)));
+ ts_SGsAP_LAI('901'H, '70'H, 2342),
+ tai));
/* Old LAI, if MS sends it */
/* TMSI status, if MS has no valid TMSI */
/* IMEISV, if it supports "automatic device detection" */
@@ -4519,6 +4780,7 @@ testcase TC_sgsap_lu() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11811, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_lu), pars);
vc_conn.done;
}
@@ -4646,6 +4908,7 @@ testcase TC_sgsap_expl_imsi_det_eps() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11814, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_expl_imsi_det_eps), pars);
vc_conn.done;
}
@@ -4670,6 +4933,7 @@ testcase TC_sgsap_impl_imsi_det_eps() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11814, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_impl_imsi_det_eps), pars);
vc_conn.done;
}
@@ -4697,6 +4961,7 @@ testcase TC_sgsap_expl_imsi_det_noneps() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11815, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_expl_imsi_det_noneps), pars);
vc_conn.done;
}
@@ -4724,6 +4989,7 @@ testcase TC_sgsap_impl_imsi_det_noneps() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11815, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_impl_imsi_det_noneps), pars);
vc_conn.done;
}
@@ -4775,6 +5041,7 @@ testcase TC_sgsap_paging_rej() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11816, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_paging_rej), pars);
vc_conn.done;
}
@@ -4824,6 +5091,7 @@ testcase TC_sgsap_paging_subscr_rej() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11817, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_paging_subscr_rej), pars);
vc_conn.done;
}
@@ -4868,6 +5136,7 @@ testcase TC_sgsap_paging_ue_unr() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11818, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_paging_ue_unr), pars);
vc_conn.done;
}
@@ -4927,6 +5196,7 @@ testcase TC_sgsap_paging_and_nothing() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11819, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_paging_and_nothing), pars);
vc_conn.done;
}
@@ -4985,6 +5255,7 @@ testcase TC_sgsap_paging_and_lu() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11820, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_paging_and_lu), pars);
vc_conn.done;
}
@@ -5193,6 +5464,7 @@ testcase TC_sgsap_mt_sms() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11823, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_mt_sms), pars);
vc_conn.done;
}
@@ -5223,6 +5495,7 @@ testcase TC_sgsap_mo_sms() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11824, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_mo_sms), pars);
vc_conn.done;
}
@@ -5286,6 +5559,7 @@ testcase TC_sgsap_mt_sms_and_nothing() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11825, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_mt_sms_and_nothing), pars);
vc_conn.done;
}
@@ -5346,11 +5620,12 @@ testcase TC_sgsap_mt_sms_and_reject() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1, true);
pars := f_init_pars(11826, true);
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
vc_conn := f_start_handler_with_pars(refers(f_tc_sgsap_mt_sms_and_reject), pars);
vc_conn.done;
}
-/* Perform an MT CSDB call including LU */
+/* Perform an MT CSFB call including LU */
private function f_mt_lu_and_csfb_call(charstring id, BSC_ConnHdlrPars pars, boolean bssmap_lu) runs on BSC_ConnHdlr {
f_init_handler(pars);
@@ -5362,6 +5637,7 @@ private function f_mt_lu_and_csfb_call(charstring id, BSC_ConnHdlrPars pars, boo
if (bssmap_lu) {
f_perform_lu();
}
+ pars.common_id_last_eutran_plmn := f_enc_mcc_mnc('901'H, '70'H);
f_sgs_perform_lu();
f_sleep(1.0);
@@ -5370,7 +5646,7 @@ private function f_mt_lu_and_csfb_call(charstring id, BSC_ConnHdlrPars pars, boo
var CallParameters cpars := valueof(t_CallParams('12345'H, 0));
/* Initiate a call via MNCC interface */
- f_mt_call_initate(cpars);
+ f_mt_call_initiate(cpars);
/* Expect a paging request and respond accordingly with a service request */
SGsAP.receive(tr_SGsAP_PAGING_REQ(pars.imsi, vlr_name, CS_call_indicator, omit));
@@ -5510,16 +5786,26 @@ testcase TC_ho_inter_bsc_unknown_cell() runs on MTC_CT {
private altstep as_mgcp_ack_all_mdcx(CallParameters cpars) runs on BSC_ConnHdlr {
var MgcpCommand mgcp_cmd;
[] MGCP.receive(tr_MDCX) -> value mgcp_cmd {
- var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_conn_2.mgw_rtp_ip, cpars.mgw_conn_2.mgw_rtp_ip,
- hex2str(cpars.mgcp_call_id), "42",
- cpars.mgw_conn_2.mgw_rtp_port,
- { 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_MDCX_ACK(mgcp_cmd.line.trans_id, cpars.mgw_conn_2.mgcp_connection_id, sdp));
- repeat;
- }
+ var charstring conn_id;
+ f_mgcp_find_param_entry(mgcp_cmd.params, "I", conn_id);
+ var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_conn_2.mgw_rtp_ip, cpars.mgw_conn_2.mgw_rtp_ip,
+ hex2str(cpars.mgcp_call_id), "42",
+ cpars.mgw_conn_2.mgw_rtp_port,
+ { 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_MDCX_ACK(mgcp_cmd.line.trans_id, str2hex(conn_id), sdp));
+ repeat;
+ }
+}
+
+private altstep as_mgcp_ack_all_dlcx(CallParameters cpars) runs on BSC_ConnHdlr {
+ var MgcpCommand mgcp_cmd;
+ [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd {
+ MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id));
+ repeat;
+ }
}
private function f_tc_ho_inter_bsc0(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
@@ -5531,19 +5817,26 @@ private function f_tc_ho_inter_bsc0(charstring id, BSC_ConnHdlrPars pars) runs o
cpars.mgw_conn_2.mgw_rtp_ip := "::2";
cpars.bss_rtp_ip := "::3";
}
+ if (pars.use_csd) {
+ f_set_cpars_csd(cpars, "BS25T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_4800);
+ }
f_init_handler(pars);
f_vty_transceive(MSCVTY, "configure terminal");
f_vty_transceive(MSCVTY, "msc");
f_vty_transceive(MSCVTY, "neighbor a cgi 262 42 23 42 ran-pc 0.24.1");
- f_vty_transceive(MSCVTY, "neighbor a lac 5 ran-pc 0.24.2");
+ f_vty_transceive(MSCVTY, "neighbor a cgi 023 42 5 6 ran-pc 0.24.2");
f_vty_transceive(MSCVTY, "exit");
f_vty_transceive(MSCVTY, "exit");
f_perform_lu();
f_mo_call_establish(cpars);
+ /* Remember the last n_sd (sequence number),
+ * we will need it when the other BSS hands over back to us. */
+ var N_Sd_Array last_n_sd := f_bssmap_last_n_sd();
+
f_sleep(1.0);
var default ack_mdcx := activate(as_mgcp_ack_all_mdcx(cpars));
@@ -5552,7 +5845,7 @@ private function f_tc_ho_inter_bsc0(charstring id, BSC_ConnHdlrPars pars) runs o
var BssmapCause cause := enum2int(cause_val);
var template BSSMAP_FIELD_CellIdentificationList cil;
- cil := { cIl_LAI := { ts_BSSMAP_CI_LAI('023'H, '42'H, 5) } };
+ cil := { cIl_CGI := { ts_BSSMAP_CI_CGI('023'H, '42'H, 5, 6) } };
/* old BSS sends Handover Required */
BSSAP.send(ts_BSSMAP_HandoverRequired(cause, cil));
@@ -5577,10 +5870,26 @@ private function f_tc_ho_inter_bsc0(charstring id, BSC_ConnHdlrPars pars) runs o
/* Ok, that went well, now the other BSC is handovering back here --
* from now on this here is the new BSS. */
- f_create_bssmap_exp_handoverRequest(193);
-
+ f_create_bssmap_exp_n_connect(193);
+
+ var template BSSMAP_IE_EncryptionInformation encryptionInformation;
+ var template BSSMAP_IE_ChosenEncryptionAlgorithm chosenEncryptionAlgorithm;
+ var template BSSMAP_IE_KC128 kC128;
+ var OCT1 a5_perm_alg;
+ f_get_expected_encryption(encryptionInformation, chosenEncryptionAlgorithm, kC128, a5_perm_alg);
+ var template PDU_BSSAP expect_ho_request := tr_BSSMAP_HandoverRequest(encryptionInformation,
+ chosenEncryptionAlgorithm,
+ kC128, codecList := ?);
var PDU_BSSAP ho_request;
- BSSAP.receive(tr_BSSMAP_HandoverRequest) -> value ho_request;
+ alt {
+ [] BSSAP.receive(expect_ho_request);
+ [] BSSAP.receive(tr_BSSMAP_HandoverRequest) -> value ho_request {
+ log("Error: Wrong handoverRequest received. Expected: ", expect_ho_request,
+ " got ", ho_request);
+ setverdict(fail, "Wrong handoverRequest received");
+ mtc.stop;
+ }
+ }
/* new BSS composes a RR Handover Command */
var PDU_ML3_NW_MS rr_ho_cmd := valueof(ts_RR_HandoverCommand);
@@ -5604,13 +5913,11 @@ private function f_tc_ho_inter_bsc0(charstring id, BSC_ConnHdlrPars pars) runs o
deactivate(ack_mdcx);
- var default ccrel := activate(as_optional_cc_rel(cpars, true));
-
- /* blatant cheating */
- var N_Sd_Array last_n_sd := f_bssmap_last_n_sd();
- last_n_sd[0] := 3;
+ /* Use the n_sd (sequence number) we stored before the first handover.
+ * Otherwise the MSC may treat our DTAP messages as duplicates and discard them. */
f_bssmap_continue_after_n_sd(last_n_sd);
+ var default ccrel := activate(as_optional_cc_rel(cpars, true));
f_call_hangup(cpars, true);
f_sleep(1.0);
deactivate(ccrel);
@@ -5625,11 +5932,26 @@ private function f_tc_ho_inter_bsc1(charstring id, BSC_ConnHdlrPars pars) runs o
bss_rtp_ip := "1.2.3.4";
}
f_init_handler(pars);
- f_create_bssmap_exp_handoverRequest(194);
-
+ f_create_bssmap_exp_n_connect(194);
+
+ var template BSSMAP_IE_EncryptionInformation encryptionInformation;
+ var template BSSMAP_IE_ChosenEncryptionAlgorithm chosenEncryptionAlgorithm;
+ var template BSSMAP_IE_KC128 kC128;
+ var OCT1 a5_perm_alg;
+ f_get_expected_encryption(encryptionInformation, chosenEncryptionAlgorithm, kC128, a5_perm_alg);
+ var template PDU_BSSAP expect_ho_request := tr_BSSMAP_HandoverRequest(encryptionInformation,
+ chosenEncryptionAlgorithm,
+ kC128, codecList := ?);
var PDU_BSSAP ho_request;
- BSSAP.receive(tr_BSSMAP_HandoverRequest) -> value ho_request;
-
+ alt {
+ [] BSSAP.receive(expect_ho_request);
+ [] BSSAP.receive(tr_BSSMAP_HandoverRequest) -> value ho_request {
+ log("Error: Wrong handoverRequest received. Expected: ", expect_ho_request,
+ " got ", ho_request);
+ setverdict(fail, "Wrong handoverRequest received");
+ mtc.stop;
+ }
+ }
/* new BSS composes a RR Handover Command */
var PDU_ML3_NW_MS rr_ho_cmd := valueof(ts_RR_HandoverCommand);
var octetstring rr_ho_cmd_enc := enc_PDU_ML3_NW_MS(rr_ho_cmd);
@@ -5657,7 +5979,7 @@ private function f_tc_ho_inter_bsc1(charstring id, BSC_ConnHdlrPars pars) runs o
var BssmapCause cause := enum2int(cause_val);
var template BSSMAP_FIELD_CellIdentificationList cil;
- cil := { cIl_LAI := { ts_BSSMAP_CI_LAI('262'H, '42'H, 23) } };
+ cil := { cIl_CGI := { ts_BSSMAP_CI_CGI('262'H, '42'H, 23, 42) } };
/* old BSS sends Handover Required */
BSSAP.send(ts_BSSMAP_HandoverRequired(cause, cil));
@@ -5676,27 +5998,70 @@ private function f_tc_ho_inter_bsc1(charstring id, BSC_ConnHdlrPars pars) runs o
f_expect_clear();
setverdict(pass);
}
-function f_tc_ho_inter_bsc_main(boolean use_ipv6 := false) runs on MTC_CT {
+function f_tc_ho_inter_bsc_main(boolean use_ipv6 := false, integer a5_n := 0, boolean use_csd := false) runs on MTC_CT {
var BSC_ConnHdlr vc_conn0;
var BSC_ConnHdlr vc_conn1;
f_init(2);
var BSC_ConnHdlrPars pars0 := f_init_pars(53);
pars0.use_ipv6 := use_ipv6;
+ pars0.use_csd := use_csd;
+ pars0.net.expect_ciph := a5_n > 0;
+ pars0.net.expect_auth := pars0.net.expect_ciph;
+ pars0.net.kc_support := bit2oct('00000001'B << a5_n);
+ pars0.cm2.classmarkInformationType2_oct5.a5_3 := '1'B;
+ pars0.cm2.classmarkInformationType2_oct5.a5_2 := '0'B;
+ pars0.cm2.classmarkInformationType2_oct5.cm3 := '1'B;
+ pars0.cm3 := valueof(ts_CM3_default);
+ pars0.use_umts_aka := true;
+ pars0.vec := f_gen_auth_vec_3g();
+ pars0.vec_keep := true;
+ pars0.ran_idx := 0;
+
var BSC_ConnHdlrPars pars1 := f_init_pars(53);
pars1.use_ipv6 := use_ipv6;
+ pars1.use_csd := use_csd;
+ pars1.net.expect_ciph := pars0.net.expect_ciph;
+ pars1.net.expect_auth := pars0.net.expect_ciph;
+ pars1.net.kc_support := bit2oct('00000001'B << a5_n);
+ pars1.cm2 := pars0.cm2;
+ pars1.cm3 := pars0.cm3;
+ pars1.use_umts_aka := true;
+ /* Both components need the same auth vector info because we expect f_tc_ho_inter_bsc0's ciphering key to be
+ * identical to the one that shows up in f_tc_ho_inter_bsc1. Can only do that by feeding in a vector to both
+ * components and then not overwriting it in BSC_ConnectionHandler. */
+ pars1.vec := pars0.vec;
+ pars1.vec_keep := true;
+ pars1.ran_idx := 1;
+
+ if (a5_n > 0) {
+ f_vty_config(MSCVTY, "network", "authentication required");
+ }
+ f_vty_config(MSCVTY, "network", "encryption a5 " & int2str(a5_n));
- vc_conn0 := f_start_handler_with_pars(refers(f_tc_ho_inter_bsc0), pars0, 0);
- vc_conn1 := f_start_handler_with_pars(refers(f_tc_ho_inter_bsc1), pars1, 1);
+ vc_conn0 := f_start_handler_with_pars(refers(f_tc_ho_inter_bsc0), pars0);
+ vc_conn1 := f_start_handler_with_pars(refers(f_tc_ho_inter_bsc1), pars1);
vc_conn0.done;
vc_conn1.done;
}
testcase TC_ho_inter_bsc() runs on MTC_CT {
- f_tc_ho_inter_bsc_main(false);
+ f_tc_ho_inter_bsc_main(false, a5_n := 0);
+}
+testcase TC_ho_inter_bsc_a5_1() runs on MTC_CT {
+ f_tc_ho_inter_bsc_main(false, a5_n := 1);
+}
+testcase TC_ho_inter_bsc_a5_3() runs on MTC_CT {
+ f_tc_ho_inter_bsc_main(false, a5_n := 3);
+}
+testcase TC_ho_inter_bsc_a5_4() runs on MTC_CT {
+ f_tc_ho_inter_bsc_main(false, a5_n := 4);
}
testcase TC_ho_inter_bsc_ipv6() runs on MTC_CT {
f_tc_ho_inter_bsc_main(true);
}
+testcase TC_ho_inter_bsc_csd() runs on MTC_CT {
+ f_tc_ho_inter_bsc_main(use_csd := true);
+}
function f_ML3_patch_seq_nr_MS_NW(in uint2_t seq_nr, inout octetstring enc_l3) {
log("MS_NW patching N(SD)=", seq_nr, " into dtap ", enc_l3);
@@ -5706,12 +6071,16 @@ function f_ML3_patch_seq_nr_MS_NW(in uint2_t seq_nr, inout octetstring enc_l3) {
private function f_tc_ho_inter_msc_out(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
var CallParameters cpars;
+ var PDU_BSSAP ho_request;
cpars := valueof(t_CallParams('12345'H, 0));
if (pars.use_ipv6) {
- cpars.mgw_conn_1.mgw_rtp_ip := "::1";
- cpars.mgw_conn_2.mgw_rtp_ip := "::2";
- cpars.bss_rtp_ip := "::3";
+ cpars.mgw_conn_1.mgw_rtp_ip := "::1";
+ cpars.mgw_conn_2.mgw_rtp_ip := "::2";
+ cpars.bss_rtp_ip := "::3";
+ }
+ if (pars.use_csd) {
+ f_set_cpars_csd(cpars, "BS25T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_4800);
}
var hexstring ho_number := f_gen_msisdn(99999);
@@ -5736,7 +6105,7 @@ private function f_tc_ho_inter_msc_out(charstring id, BSC_ConnHdlrPars pars) run
var BssmapCause cause := enum2int(cause_val);
var template BSSMAP_FIELD_CellIdentificationList cil;
- cil := { cIl_LAI := { ts_BSSMAP_CI_LAI('017'H, '017'H, 1) } };
+ cil := { cIl_CGI := { ts_BSSMAP_CI_CGI('017'H, '017'H, 1, 1) } };
/* old BSS sends Handover Required */
BSSAP.send(ts_BSSMAP_HandoverRequired(cause, cil));
@@ -5744,21 +6113,47 @@ private function f_tc_ho_inter_msc_out(charstring id, BSC_ConnHdlrPars pars) run
/* The target cell 017-017 LAC 1 is configured to be a remote MSC of name "msc-017-017-1".
* This MSC tries to reach the other MSC via GSUP. */
+ var template BSSMAP_IE_EncryptionInformation encryptionInformation;
+ var template BSSMAP_IE_ChosenEncryptionAlgorithm chosenEncryptionAlgorithm;
+ var template BSSMAP_IE_KC128 kC128;
+ var OCT1 a5_perm_alg;
+ f_get_expected_encryption(encryptionInformation, chosenEncryptionAlgorithm, kC128, a5_perm_alg);
+ var template PDU_BSSAP expect_ho_request := tr_BSSMAP_HandoverRequest(encryptionInformation,
+ chosenEncryptionAlgorithm,
+ kC128, codecList := ?);
+
var octetstring remote_msc_name := '6D73632D3031372D3031372D3100'O; /* "msc-017-017-1\0" as octetstring */
var GSUP_PDU prep_ho_req;
- GSUP.receive(tr_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_REQUEST,
- pars.imsi, destination_name := remote_msc_name)) -> value prep_ho_req;
+ alt {
+ [] GSUP.receive(tr_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_REQUEST,
+ pars.imsi, destination_name := remote_msc_name,
+ an_apdu := t_GSUP_AN_APDU(OSMO_GSUP_AN_PROTO_48006, pdu := ?))) -> value prep_ho_req;
+ [] GSUP.receive(tr_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_REQUEST)) {
+ setverdict(fail, "Wrong OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_REQUEST message received");
+ mtc.stop;
+ }
+ }
var GSUP_IeValue source_name_ie;
f_gsup_find_ie(prep_ho_req, OSMO_GSUP_SOURCE_NAME_IE, source_name_ie);
var octetstring local_msc_name := source_name_ie.source_name;
+ /* Decode PDU to 1) match with expect_ho_request and 2) to forward the actual chosen encryption algorithm. */
+ var GSUP_IeValue an_apdu_ie;
+ f_gsup_find_ie(prep_ho_req, OSMO_GSUP_AN_APDU_IE, an_apdu_ie);
+ ho_request := dec_PDU_BSSAP(an_apdu_ie.an_apdu.pdu);
+ if (not match(ho_request, expect_ho_request)) {
+ setverdict(fail, "Wrong PDU in OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_REQUEST message received");
+ mtc.stop;
+ }
+
/* Remote MSC has figured out its BSC and signals success */
var PDU_ML3_NW_MS rr_ho_cmd := valueof(ts_RR_HandoverCommand);
var octetstring rr_ho_cmd_enc := enc_PDU_ML3_NW_MS(rr_ho_cmd);
var PDU_BSSAP ho_req_ack := valueof(ts_BSSMAP_HandoverRequestAcknowledge(rr_ho_cmd_enc, lengthof(rr_ho_cmd_enc),
- aoIPTransportLayer := omit,
- speechCodec := ts_BSSMAP_IE_SpeechCodec({ts_CodecFR})));
+ aoIPTransportLayer := omit,
+ speechCodec := ts_BSSMAP_IE_SpeechCodec({ts_CodecFR}),
+ chosenEncryptionAlgorithm := ho_request.pdu.bssmap.handoverRequest.chosenEncryptionAlgorithm));
GSUP.send(ts_GSUP_E_PrepareHandoverResult(
pars.imsi,
ho_number,
@@ -5880,7 +6275,7 @@ private function f_tc_ho_inter_msc_out(charstring id, BSC_ConnHdlrPars pars) run
/* inter-MSC handover back to the first MSC */
- f_create_bssmap_exp_handoverRequest(193);
+ f_create_bssmap_exp_n_connect(193);
cil := { cIl_CGI := { ts_BSSMAP_CI_CGI('262'H, '42'H, 23, 42) } };
/* old BSS sends Handover Required, via inter-MSC E link: like
@@ -5894,7 +6289,19 @@ private function f_tc_ho_inter_msc_out(charstring id, BSC_ConnHdlrPars pars) run
));
/* MSC asks local BSS to prepare Handover to it */
- BSSAP.receive(tr_BSSMAP_HandoverRequest);
+ f_get_expected_encryption(encryptionInformation, chosenEncryptionAlgorithm, kC128, a5_perm_alg);
+ expect_ho_request := tr_BSSMAP_HandoverRequest(encryptionInformation,
+ chosenEncryptionAlgorithm,
+ kC128, codecList := ?);
+ alt {
+ [] BSSAP.receive(expect_ho_request) -> value ho_request;
+ [] BSSAP.receive(tr_BSSMAP_HandoverRequest) -> value ho_request {
+ log("Error: Wrong handoverRequest received. Expected: ", expect_ho_request,
+ " got ", ho_request);
+ setverdict(fail, "Wrong handoverRequest received");
+ mtc.stop;
+ }
+ }
/* Make sure the new BSSAP conn continues with the correct N_SD sequence numbers */
f_bssmap_continue_after_n_sd(last_n_sd);
@@ -5905,7 +6312,8 @@ private function f_tc_ho_inter_msc_out(charstring id, BSC_ConnHdlrPars pars) run
var BSSMAP_IE_AoIP_TransportLayerAddress tla :=
valueof(f_ts_BSSMAP_IE_AoIP_TLA(cpars.bss_rtp_ip, cpars.bss_rtp_port));
BSSAP.send(ts_BSSMAP_HandoverRequestAcknowledge(rr_ho_cmd_enc, lengthof(rr_ho_cmd_enc),
- tla, ts_BSSMAP_IE_SpeechCodec({ts_CodecFR})));
+ tla, ts_BSSMAP_IE_SpeechCodec({ts_CodecFR}),
+ chosenEncryptionAlgorithm := ho_request.pdu.bssmap.handoverRequest.chosenEncryptionAlgorithm));
/* HandoverCommand goes out via remote MSC-I */
var GSUP_PDU prep_subsq_ho_res;
@@ -5942,15 +6350,40 @@ private function f_tc_ho_inter_msc_out(charstring id, BSC_ConnHdlrPars pars) run
setverdict(pass);
}
-testcase TC_ho_inter_msc_out() runs on MTC_CT {
+function f_tc_ho_inter_msc_out_a5(integer a5_n) runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1);
var BSC_ConnHdlrPars pars := f_init_pars(54);
+ pars.net.expect_ciph := a5_n > 0;
+ pars.net.expect_auth := pars.net.expect_ciph;
+ pars.net.kc_support := bit2oct('00000001'B << a5_n);
+ pars.cm2.classmarkInformationType2_oct5.a5_3 := '1'B;
+ pars.cm2.classmarkInformationType2_oct5.a5_2 := '0'B;
+ pars.cm2.classmarkInformationType2_oct5.cm3 := '1'B;
+ pars.cm3 := valueof(ts_CM3_default);
+ pars.use_umts_aka := true;
- vc_conn := f_start_handler_with_pars(refers(f_tc_ho_inter_msc_out), pars, 0);
+ if (a5_n > 0) {
+ f_vty_config(MSCVTY, "network", "authentication required");
+ }
+ f_vty_config(MSCVTY, "network", "encryption a5 " & int2str(a5_n));
+
+ vc_conn := f_start_handler_with_pars(refers(f_tc_ho_inter_msc_out), pars);
vc_conn.done;
}
+testcase TC_ho_inter_msc_out() runs on MTC_CT {
+ f_tc_ho_inter_msc_out_a5(0);
+}
+testcase TC_ho_inter_msc_out_a5_1() runs on MTC_CT {
+ f_tc_ho_inter_msc_out_a5(1);
+}
+testcase TC_ho_inter_msc_out_a5_3() runs on MTC_CT {
+ f_tc_ho_inter_msc_out_a5(3);
+}
+testcase TC_ho_inter_msc_out_a5_4() runs on MTC_CT {
+ f_tc_ho_inter_msc_out_a5(4);
+}
testcase TC_ho_inter_msc_out_ipv6() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
f_init(1);
@@ -5958,7 +6391,17 @@ testcase TC_ho_inter_msc_out_ipv6() runs on MTC_CT {
var BSC_ConnHdlrPars pars := f_init_pars(54);
pars.use_ipv6 := true;
- vc_conn := f_start_handler_with_pars(refers(f_tc_ho_inter_msc_out), pars, 0);
+ vc_conn := f_start_handler_with_pars(refers(f_tc_ho_inter_msc_out), pars);
+ vc_conn.done;
+}
+testcase TC_ho_inter_msc_out_csd() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn;
+ f_init(1);
+
+ var BSC_ConnHdlrPars pars := f_init_pars(54);
+ pars.use_csd := true;
+
+ vc_conn := f_start_handler_with_pars(refers(f_tc_ho_inter_msc_out), pars);
vc_conn.done;
}
@@ -6043,7 +6486,7 @@ private function f_tc_lu_imsi_auth_tmsi_check_imei_nack(charstring id, BSC_ConnH
f_msc_lu_hlr();
f_mm_imei();
f_expect_lu_reject();
- f_expect_clear();
+ f_expect_clear(verify_vlr_cell_id:=false);
}
testcase TC_lu_imsi_auth_tmsi_check_imei_nack() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
@@ -6073,7 +6516,7 @@ private function f_tc_lu_imsi_auth_tmsi_check_imei_err(charstring id, BSC_ConnHd
f_msc_lu_hlr();
f_mm_imei();
f_expect_lu_reject();
- f_expect_clear();
+ f_expect_clear(verify_vlr_cell_id:=false);
}
testcase TC_lu_imsi_auth_tmsi_check_imei_err() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
@@ -6164,7 +6607,7 @@ private function f_tc_lu_imsi_auth_tmsi_check_imei_early_nack(charstring id, BSC
f_mm_imei_early();
f_expect_lu_reject();
- f_expect_clear();
+ f_expect_clear(verify_vlr_cell_id:=false);
}
testcase TC_lu_imsi_auth_tmsi_check_imei_early_nack() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
@@ -6192,7 +6635,7 @@ private function f_tc_lu_imsi_auth_tmsi_check_imei_early_err(charstring id, BSC_
f_mm_imei_early();
f_expect_lu_reject();
- f_expect_clear();
+ f_expect_clear(verify_vlr_cell_id:=false);
}
testcase TC_lu_imsi_auth_tmsi_check_imei_early_err() runs on MTC_CT {
var BSC_ConnHdlr vc_conn;
@@ -6227,15 +6670,13 @@ testcase TC_invalid_mgcp_crash() runs on MTC_CT {
vc_conn.done;
}
+/* Test how the MSC handles a malformed MM IDENTITY RESPONSE with no identity. */
friend function f_tc_mm_id_resp_no_identity(charstring id, BSC_ConnHdlrPars pars)
runs on BSC_ConnHdlr {
- pars.tmsi := 'FFFFFFFF'O;
f_init_handler(pars);
- f_create_gsup_expect(hex2str(g_pars.imsi));
-
/* Initiate Location Updating using an unknown TMSI */
- f_bssap_compl_l3(f_build_lu_tmsi(pars.tmsi));
+ f_bssap_compl_l3(f_build_lu_tmsi('FFFFFFFF'O));
/* Expect an Identity Request, send response with no identity */
BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_ID_Req(CM_ID_TYPE_IMSI)));
@@ -6252,7 +6693,10 @@ runs on BSC_ConnHdlr {
}
})));
- f_expect_lu_reject();
+ /* XXX: Current osmo-msc does not react on bad/malformed MM IDENTITY RESPONSE immediately.
+ * It instead relies on expiry of timer X1, which is set to 5.0 seconds by default. This
+ * is not good (DoS vector) and should ideally be fixed, but for now just work it around. */
+ f_expect_lu_reject(Tval := 5.0 + 1.0);
f_expect_clear();
}
testcase TC_mm_id_resp_no_identity() runs on MTC_CT {
@@ -6302,10 +6746,712 @@ testcase TC_lu_and_expire_while_paging() runs on MTC_CT {
vc_conn.done;
}
+private altstep as_mncc_rx_rtp_create(CallParameters cpars) runs on BSC_ConnHdlr {
+ [] MNCC.receive(tr_MNCC_RTP_CREATE(cpars.mncc_callref));
+}
+
+const charstring REEST_LOST_CONNECTION := "REEST_LOST_CONNECTION";
+const charstring REEST_CLEARED := "REEST_CLEARED";
+
+friend function f_tc_call_re_establishment_1(charstring id, BSC_ConnHdlrPars pars)
+ runs on BSC_ConnHdlr {
+ f_init_handler(pars, t_guard := 30.0);
+
+ f_perform_lu();
+
+ var CallParameters cpars := valueof(t_CallParams('12345'H, 0));
+ f_mo_call_establish(cpars);
+ f_sleep(3.0);
+ COORD.send(REEST_LOST_CONNECTION);
+ COORD.send(cpars);
+ f_expect_clear(verify_vlr_cell_id := false);
+ COORD.send(REEST_CLEARED);
+}
+
+friend function f_tc_call_re_establishment_2(charstring id, BSC_ConnHdlrPars pars)
+ runs on BSC_ConnHdlr {
+ f_init_handler(pars, t_guard := 30.0);
+ var CallParameters cpars;
+
+ COORD.receive(REEST_LOST_CONNECTION);
+ COORD.receive(tr_CallParams) -> value cpars;
+
+ f_gsup_change_connhdlr(hex2str(g_pars.imsi));
+ f_create_smpp_expect(hex2str(pars.msisdn));
+
+ /* The MS has lost the first channel and decides to show up on a new conn (on a nearby neighbor cell) to ask for
+ * CM Re-Establishment. Send a Complete Layer 3 to osmo-msc with a CM Re-Establishment Request. */
+ var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
+ var PDU_ML3_MS_NW l3_info := valueof(ts_CM_REESTABL_REQ(mi));
+ f_cl3_or_initial_ue(l3_info);
+
+ /* At this point the other test component should receive the Clear Command for the first A connection. */
+
+ /* This new connection continues with Authentication... */
+ f_mm_common();
+
+ /* ...and with Assignment of a voice channel. */
+ var template BSSMAP_IE_AoIP_TransportLayerAddress tla_ass :=
+ (f_tr_BSSMAP_IE_AoIP_TLA(cpars.mgw_conn_1.mgw_rtp_ip, ?),
+ f_tr_BSSMAP_IE_AoIP_TLA(cpars.mgw_conn_2.mgw_rtp_ip, ?));
+ BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, tla_ass));
+ /* By this Assignment Request, the CM Re-Establishment Request is implicitly accepted. */
+
+ /* Send Assignment Complete from BSC */
+ var template BSSMAP_IE_AoIP_TransportLayerAddress tla;
+ tla := f_ts_BSSMAP_IE_AoIP_TLA(cpars.bss_rtp_ip, cpars.bss_rtp_port);
+ var BSSMAP_IE_SpeechCodec codec;
+ codec := valueof(ts_BSSMAP_IE_SpeechCodec({ts_CodecFR}));
+
+ /* Make really sure the other component is done with its MGCP */
+ COORD.receive(REEST_CLEARED);
+
+ /* Transfer state for this call over to this test component so we can resolve MNCC and MGCP in this function. */
+ f_mncc_change_connhdlr(cpars.mncc_callref);
+ f_mgcp_change_connhdlr(cpars.mgcp_ep);
+
+ /* osmo-msc may redirect the MGW endpoint to the newly allocated channel.
+ * Apparently osmo-msc currently also sends an MDCX to the CN side, just repeating the same configuration that
+ * is already in use. This test accepts any number of or even lack of MDCX. */
+ var default ack_mdcx := activate(as_mgcp_ack_all_mdcx(cpars));
+ var default optional_rtp_create := activate(as_mncc_rx_rtp_create(cpars));
+
+ BSSAP.send(ts_BSSMAP_AssignmentComplete(omit, tla, codec));
+
+ /* The call has been fully re-established.
+ * Let a bit of time pass before hanging up, for everything to settle. */
+ f_sleep(3.0);
+
+ deactivate(optional_rtp_create);
+ deactivate(ack_mdcx);
+
+ /* Hang up the call and clear the new, second A connection */
+ var default ack_dlcx := activate(as_mgcp_ack_all_dlcx(cpars));
+
+ /* CC release. This is the proper MS initiated release sequence as shown by
+ * https://git.osmocom.org/osmo-msc/tree/doc/sequence_charts/voice_call_full.msc?id=e53ecde83e4fb2470209e818e9ad76a2d6a19190
+ * f_call_hangup() seems a bit mixed up, so here a "proper" sequence. Fix of f_call_hangup() pending. */
+ BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_DISC(cpars.transaction_id, '0'B, '0000000'B)));
+ 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_RELEASE(cpars.transaction_id)));
+ BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id, '0'B)));
+ MNCC.receive(tr_MNCC_REL_cnf(cpars.mncc_callref, cause := *));
+
+ /* BSSAP clear */
+ interleave {
+ [] BSSAP.receive(tr_BSSMAP_ClearCommand) {
+ BSSAP.send(ts_BSSMAP_ClearComplete);
+ }
+ [] BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_IND);
+ }
+
+ f_sleep(1.0);
+ deactivate(ack_dlcx);
+}
+
+testcase TC_call_re_establishment() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn1;
+ var BSC_ConnHdlr vc_conn2;
+ f_init();
+
+ var BSC_ConnHdlrPars pars1 := f_init_pars(91);
+ var BSC_ConnHdlrPars pars2 := pars1;
+
+ vc_conn1 := f_start_handler_create(pars1);
+ vc_conn2 := f_start_handler_create(pars2);
+ connect(vc_conn1:COORD, vc_conn2:COORD);
+ f_start_handler_run(vc_conn1, refers(f_tc_call_re_establishment_1), pars1);
+ f_start_handler_run(vc_conn2, refers(f_tc_call_re_establishment_2), pars2);
+ vc_conn1.done;
+ vc_conn2.done;
+}
+
+testcase TC_call_re_establishment_auth() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn1;
+ var BSC_ConnHdlr vc_conn2;
+ f_init();
+
+ f_vty_config(MSCVTY, "network", "authentication required");
+
+ var BSC_ConnHdlrPars pars1 := f_init_pars(92);
+ pars1.net.expect_auth := true;
+ var BSC_ConnHdlrPars pars2 := pars1;
+
+ vc_conn1 := f_start_handler_create(pars1);
+ vc_conn2 := f_start_handler_create(pars2);
+ connect(vc_conn1:COORD, vc_conn2:COORD);
+ f_start_handler_run(vc_conn1, refers(f_tc_call_re_establishment_1), pars1);
+ f_start_handler_run(vc_conn2, refers(f_tc_call_re_establishment_2), pars2);
+ vc_conn1.done;
+ vc_conn2.done;
+}
+
+testcase TC_call_re_establishment_ciph() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn1;
+ var BSC_ConnHdlr vc_conn2;
+ f_init();
+
+ f_vty_config(MSCVTY, "network", "authentication required");
+ f_vty_config(MSCVTY, "network", "encryption a5 3");
+
+ var BSC_ConnHdlrPars pars1 := f_init_pars(92);
+ pars1.net.expect_auth := true;
+ pars1.net.expect_ciph := true;
+ pars1.net.kc_support := '08'O; /* A5/3 only */
+ var BSC_ConnHdlrPars pars2 := pars1;
+
+ vc_conn1 := f_start_handler_create(pars1);
+ vc_conn2 := f_start_handler_create(pars2);
+ connect(vc_conn1:COORD, vc_conn2:COORD);
+ f_start_handler_run(vc_conn1, refers(f_tc_call_re_establishment_1), pars1);
+ f_start_handler_run(vc_conn2, refers(f_tc_call_re_establishment_2), pars2);
+ vc_conn1.done;
+ vc_conn2.done;
+}
+
+/* Establish a conn with a valid Mobile Identity. Then send a CM Service Request containing a mismatching Mobile
+ * Identity on the same conn. Caused a crash, see OS#5532. */
+friend function f_tc_cm_serv_wrong_mi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ f_init_handler(pars);
+
+ /* Set up a fully identified conn */
+ f_perform_lu();
+ f_establish_fully();
+
+ /* CM Serv Req with mismatching Mobile Identity */
+ var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(f_gen_imsi(99999))); /* ensure it is different from below*/
+ BSSAP.send(ts_PDU_DTAP_MO(ts_CM_SERV_REQ(CM_TYPE_MO_SMS, mi)));
+ BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_REJ));
+
+ /* Cancel the first CM Service from f_establish_fully() */
+ BSSAP.send(ts_BSSMAP_ClearRequest(0));
+
+ f_expect_clear();
+}
+testcase TC_cm_serv_wrong_mi() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn;
+ f_init();
+ vc_conn := f_start_handler(refers(f_tc_cm_serv_wrong_mi), 94);
+ vc_conn.done;
+}
+
+/* a5 0 a5 0 a5 0 3 a5 0 3 a5 3 a5 3
+ * HLR has auth info no yes no yes no yes
+ *
+ * test case index [0] [1] [2] [3] [4] [5]
+ * authentication optional No auth No auth attempt auth, auth reject auth
+ * (%) fall back to +ciph +ciph
+ * no-auth
+ *
+ * [6] [7] [8] [9] [10] [11]
+ * authentication mandatory reject auth reject auth reject auth
+ * only +ciph +ciph
+ *
+ * (%): Arguably, when HLR has auth info, the MSC should use it. Current behavior of osmo-msc is to not attempt auth at
+ * all. Related: OS#4830.
+ */
+type record of BSC_ConnHdlrNetworkPars rof_netpars;
+
+const rof_netpars auth_options_testcases := {
+ {
+ /* [0] auth optional, encr a5 0: no-auth" */
+ kc_support := '01'O,
+ net_config := { "authentication optional",
+ "encryption a5 0" },
+ expect_attach_success := true,
+ expect_tmsi := true,
+ expect_auth_attempt := false,
+ hlr_has_auth_info := false,
+ expect_auth := false,
+ expect_ciph := false,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [1] auth optional, encr a5 0, HLR HAS auth info: no-auth */
+ kc_support := '01'O,
+ net_config := { "authentication optional",
+ "encryption a5 0" },
+ expect_attach_success := true,
+ expect_tmsi := true,
+ expect_auth_attempt := false,
+ hlr_has_auth_info := true,
+ expect_auth := false,
+ expect_ciph := false,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [2] auth optional, encr a5 0 3, HLR has NO Auth Info: Fall back to no-auth" */
+ kc_support := '09'O,
+ net_config := { "authentication optional",
+ "encryption a5 0 3" },
+ expect_attach_success := true,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := false,
+ expect_auth := false,
+ expect_ciph := false,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [3] auth optional, encr a5 0 3, HLR HAS Auth Info: Use A5/3 */
+ kc_support := '09'O,
+ net_config := { "authentication optional",
+ "encryption a5 0 3" },
+ expect_attach_success := true,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := true,
+ expect_auth := true,
+ expect_ciph := true,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [4] auth optional, encr a5 3, HLR has NO Auth Info: reject.
+ * Auth is required implicitly because ciph is required. */
+ kc_support := '08'O,
+ net_config := { "authentication optional",
+ "encryption a5 3" },
+ expect_attach_success := false,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := false,
+ expect_auth := false,
+ expect_ciph := false,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [5] auth optional, encr a5 3, HLR HAS Auth Info: auth + ciph.
+ * Auth is required implicitly because ciph is required. */
+ kc_support := '08'O,
+ net_config := { "authentication optional",
+ "encryption a5 3" },
+ expect_attach_success := true,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := true,
+ expect_auth := true,
+ expect_ciph := true,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+
+ /* Same as above, but with 'authentication required' */
+
+ {
+ /* [6] auth required, encr a5 0, HLR has NO auth info: reject */
+ kc_support := '01'O,
+ net_config := { "authentication required",
+ "encryption a5 0" },
+ expect_attach_success := false,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := false,
+ expect_auth := false,
+ expect_ciph := false,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [7] auth required, encr a5 0, HLR HAS auth info: do auth, no ciph" */
+ kc_support := '01'O,
+ net_config := { "authentication required",
+ "encryption a5 0" },
+ expect_attach_success := true,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := true,
+ expect_auth := true,
+ expect_ciph := false,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [8] auth required, encr a5 0 3, HLR has NO Auth Info: reject */
+ kc_support := '09'O,
+ net_config := { "authentication required",
+ "encryption a5 0 3" },
+ expect_attach_success := false,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := false,
+ expect_auth := false,
+ expect_ciph := false,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [9] auth required, encr a5 0 3, HLR HAS Auth Info: Use A5/3 */
+ kc_support := '09'O,
+ net_config := { "authentication required",
+ "encryption a5 0 3" },
+ expect_attach_success := true,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := true,
+ expect_auth := true,
+ expect_ciph := true,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [10] auth required, encr a5 3, HLR has NO Auth Info: reject. */
+ kc_support := '08'O,
+ net_config := { "authentication required",
+ "encryption a5 3" },
+ expect_attach_success := false,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := false,
+ expect_auth := false,
+ expect_ciph := false,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ },
+ {
+ /* [11] auth required, encr a5 3, HLR HAS Auth Info: auth + ciph. */
+ kc_support := '08'O,
+ net_config := { "authentication required",
+ "encryption a5 3" },
+ expect_attach_success := true,
+ expect_tmsi := true,
+ expect_auth_attempt := true,
+ hlr_has_auth_info := true,
+ expect_auth := true,
+ expect_ciph := true,
+ expect_imei := false,
+ expect_imei_early := false,
+ check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+ check_imei_error := false
+ }
+};
+
+private function f_tc_auth_options(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ f_init_handler(pars);
+
+ /* Location Updating */
+ log(MSCVTY, "f_perform_lu() starting");
+ f_perform_lu();
+ log(MSCVTY, "f_perform_lu() done");
+
+ f_sleep(1.0);
+
+ if (not pars.net.expect_attach_success) {
+ /* Expected above LU to fail. In order to test CM Service Request below, a LU has to succeed first. So
+ * run another LU that will be successful. Careful not to load auth tokens into the VLR that may taint
+ * the test for CM Service Request below. */
+
+ log(MSCVTY, "Running a successful LU so that CM Service Request can be tested");
+ var BSC_ConnHdlrNetworkPars saved_net := g_pars.net;
+ g_pars.net.kc_support := '01'O;
+ g_pars.net.expect_attach_success := true;
+ g_pars.net.expect_auth_attempt := false;
+ g_pars.net.expect_auth := false;
+ g_pars.net.expect_ciph := false;
+ f_vty_config3(MSCVTY, {"network"}, {"authentication optional", "encryption a5 0"});
+ f_perform_lu();
+
+ /* Reconfigure like it was before */
+ g_pars.net := saved_net;
+ f_vty_config3(MSCVTY, {"network"}, g_pars.net.net_config);
+ log(MSCVTY, "Running a successful LU done");
+ }
+
+ /* CM Service Request */
+ log(MSCVTY, "f_establish_fully() starting");
+ f_establish_fully();
+ log(MSCVTY, "f_establish_fully() done");
+ BSSAP.send(ts_BSSMAP_ClearRequest(0));
+ f_expect_clear();
+}
+
+function f_TC_auth_options(integer tc_i) runs on MTC_CT {
+ f_init();
+
+ var BSC_ConnHdlrNetworkPars tc := auth_options_testcases[tc_i];
+
+ f_vty_config3(MSCVTY, {"network"}, tc.net_config);
+
+ var BSC_ConnHdlrPars pars := f_init_pars(42300 + tc_i);
+ pars.net := tc;
+
+ var BSC_ConnHdlr vc_conn;
+ vc_conn := f_start_handler_with_pars(refers(f_tc_auth_options), pars);
+ vc_conn.done;
+}
+
+testcase TC_auth_options_0() runs on MTC_CT {
+ f_TC_auth_options(0);
+}
+
+testcase TC_auth_options_1() runs on MTC_CT {
+ f_TC_auth_options(1);
+}
+
+testcase TC_auth_options_2() runs on MTC_CT {
+ f_TC_auth_options(2);
+}
+
+testcase TC_auth_options_3() runs on MTC_CT {
+ f_TC_auth_options(3);
+}
+
+testcase TC_auth_options_4() runs on MTC_CT {
+ f_TC_auth_options(4);
+}
+
+testcase TC_auth_options_5() runs on MTC_CT {
+ f_TC_auth_options(5);
+}
+
+testcase TC_auth_options_6() runs on MTC_CT {
+ f_TC_auth_options(6);
+}
+
+testcase TC_auth_options_7() runs on MTC_CT {
+ f_TC_auth_options(7);
+}
+
+testcase TC_auth_options_8() runs on MTC_CT {
+ f_TC_auth_options(8);
+}
+
+testcase TC_auth_options_9() runs on MTC_CT {
+ f_TC_auth_options(9);
+}
+
+testcase TC_auth_options_10() runs on MTC_CT {
+ f_TC_auth_options(10);
+}
+
+testcase TC_auth_options_11() runs on MTC_CT {
+ f_TC_auth_options(11);
+}
+
+private function f_set_cpars_csd(inout CallParameters cpars, charstring bs_name, BIT1 async,
+ GSM48_bcap_transp transp, GSM48_bcap_user_rate user_rate) {
+ log("-----------------------------------------------");
+ log("CSD Bearer Service: " & bs_name);
+ log("-----------------------------------------------");
+
+ cpars.csd := true;
+
+ cpars.bearer_cap := valueof(ts_Bcap_csd);
+ cpars.bearer_cap.octet6.synchronous_asynchronous := async;
+ cpars.bearer_cap.octet6.connectionElement := int2bit(enum2int(transp), 2);
+ cpars.bearer_cap.octet6.userRate := int2bit(enum2int(user_rate), 4);
+
+ cpars.mncc_bearer_cap := valueof(ts_MNCC_bcap_data);
+ cpars.mncc_bearer_cap.data.async := bit2int(async);
+ cpars.mncc_bearer_cap.data.transp := transp;
+ cpars.mncc_bearer_cap.data.user_rate := user_rate;
+}
+
+friend function f_mo_csd(charstring bs_name, BIT1 async, GSM48_bcap_transp transp, GSM48_bcap_user_rate user_rate)
+ runs on BSC_ConnHdlr {
+ var CallParameters cpars := valueof(t_CallParams);
+
+ g_Tguard.start(20.0);
+ f_set_cpars_csd(cpars, bs_name, async, transp, user_rate);
+ f_perform_lu();
+ f_mo_call(cpars, 0.5);
+}
+
+friend function f_tc_lu_and_mo_csd(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ f_init_handler(pars);
+
+ f_mo_csd("BS21T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_300);
+ f_mo_csd("BS22T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_1200);
+ f_mo_csd("BS24T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_2400);
+ f_mo_csd("BS25T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_4800);
+ f_mo_csd("BS26T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_9600);
+
+ f_mo_csd("BS21NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_300);
+ f_mo_csd("BS22NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_1200);
+ f_mo_csd("BS24NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_2400);
+ f_mo_csd("BS25NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_4800);
+ f_mo_csd("BS26NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_9600);
+
+ f_mo_csd("BS31T", '0'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_1200);
+ f_mo_csd("BS32T", '0'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_2400);
+ f_mo_csd("BS33T", '0'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_4800);
+ f_mo_csd("BS34T", '0'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_9600);
+}
+testcase TC_lu_and_mo_csd() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn;
+ f_init();
+
+ vc_conn := f_start_handler(refers(f_tc_lu_and_mo_csd), 7);
+ vc_conn.done;
+}
+
+friend function f_mt_csd(charstring bs_name, BIT1 async, GSM48_bcap_transp transp, GSM48_bcap_user_rate user_rate)
+ runs on BSC_ConnHdlr {
+ var CallParameters cpars := valueof(t_CallParams);
+
+ g_Tguard.start(20.0);
+ f_set_cpars_csd(cpars, bs_name, async, transp, user_rate);
+ f_perform_lu();
+ f_mt_call(cpars, 0.5);
+}
+friend function f_tc_lu_and_mt_csd(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ f_init_handler(pars);
+
+ f_mt_csd("BS21T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_300);
+ f_mt_csd("BS22T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_1200);
+ f_mt_csd("BS24T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_2400);
+ f_mt_csd("BS25T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_4800);
+ f_mt_csd("BS26T", '1'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_9600);
+
+ f_mt_csd("BS21NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_300);
+ f_mt_csd("BS22NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_1200);
+ f_mt_csd("BS24NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_2400);
+ f_mt_csd("BS25NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_4800);
+ f_mt_csd("BS26NT", '1'B, GSM48_BCAP_TR_RLP, GSM48_BCAP_UR_9600);
+
+ f_mt_csd("BS31T", '0'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_1200);
+ f_mt_csd("BS32T", '0'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_2400);
+ f_mt_csd("BS33T", '0'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_4800);
+ f_mt_csd("BS34T", '0'B, GSM48_BCAP_TR_TRANSP, GSM48_BCAP_UR_9600);
+}
+testcase TC_lu_and_mt_csd() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn;
+ f_init();
+
+ vc_conn := f_start_handler(refers(f_tc_lu_and_mt_csd), 7);
+ vc_conn.done;
+}
+
+/* MSC <-> BSC: ID req/rsp for IMSI */
+private altstep as_id_req_imsi()
+runs on BSC_ConnHdlr {
+ [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_ID_Req(CM_ID_TYPE_IMSI))) {
+ var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
+ BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_MM_ID_Rsp(mi)));
+ repeat;
+ }
+}
+
+/* MSC is configured to not assign a TMSI; MS sends LU Request with a TMSI MI (from another cell), and MSC shall not use
+ * that TMSI. */
+private function f_tc_lu_tmsi_noauth_notmsi(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ f_init_handler(pars, t_guard := 20.0);
+
+ /* Perform Location Updating using an unknown TMSI MI. Expect an ID Request to come from the MSC and answer
+ * that with as_id_req_imsi(). */
+ activate(as_id_req_imsi());
+ f_perform_lu(use_mi := ts_MI_TMSI_LV(pars.tmsi));
+
+ f_sleep(1.0);
+
+ /* Attached by invalid TMSI, and the MSC has asked for the IMSI. Initiate Paging and make sure the MSC doesn't
+ * use the invalid TMSI for it. */
+ f_ran_register_imsi(g_pars.imsi, omit);
+ f_vty_transceive(MSCVTY, "subscriber imsi " & hex2str(g_pars.imsi) & " paging");
+ f_expect_paging_tmsi(omit);
+
+ /* Respond to paging, to clean up internal paging state for this subscriber, so we can get a clean second run
+ * out of this test code. Don't use the TMSI in the paging response. */
+ f_cl3_or_initial_ue(valueof(ts_PAG_RESP(ts_MI_IMSI_LV(pars.imsi))));
+ f_mm_common();
+ /* The paging was by VTY, so nothing happens, just a release. */
+ f_expect_clear();
+
+ /* Clean up ttcn state for the second test run to work out. */
+ f_unregister_gsup_imsi(hex2str(pars.imsi));
+ f_ran_unregister_imsi(pars.imsi);
+}
+testcase TC_lu_tmsi_noauth_notmsi() runs on MTC_CT {
+ var BSC_ConnHdlrPars pars;
+ var BSC_ConnHdlr vc_conn;
+ f_init();
+ f_vty_config(MSCVTY, "msc", "no assign-tmsi");
+ pars := f_init_pars(101);
+ pars.net.expect_tmsi := false;
+ pars.tmsi := '0badbad0'O;
+ pars.mm_info := false;
+ vc_conn := f_start_handler_with_pars(refers(f_tc_lu_tmsi_noauth_notmsi), pars);
+ vc_conn.done;
+
+ /* Now run the same test *again*, to test against an evil twin VLR entry:
+ * A vlr_subscr with the correct IMSI is now present in the VLR.
+ * We again ask for a LU with the 0x0bad TMSI. The VLR will initially create another vlr_subsrc(TMSI=0x0bad).
+ * When it learns the IMSI via ID Request, it needs to realize that this IMSI is already present on the first
+ * vsub, and sort out the VLR record so that only one entry for this IMSI exists.
+ */
+ pars := f_init_pars(101);
+ pars.net.expect_tmsi := false;
+ pars.tmsi := '0badbad0'O;
+ pars.mm_info := false;
+ vc_conn := f_start_handler_with_pars(refers(f_tc_lu_tmsi_noauth_notmsi), pars);
+ vc_conn.done;
+}
+
+friend function f_tc_lu_and_mo_call_reass_for_mt_codec(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ f_init_handler(pars);
+ var CallParameters cpars := valueof(t_CallParams);
+ /* MO will first choose GSM-FR = BSC returns GSM-FR in Assignment Complete's Codec (Chosen) */
+ cpars.ass_compl_chosen_codec := valueof(ts_CodecFR);
+ /* But when the MT call leg responds, we learn that it only supports AMR */
+ cpars.mncc_alert_req_sends_remote_sdp :=
+ "v=0\r\n"
+ & "o=BSC_ConnectionHandler.ttcn 0 0 IN IP4 1.1.1.1\r\n"
+ & "s=GSM Call\r\n"
+ & "c=IN IP4 " & cpars.bss_rtp_ip & "\r\n"
+ & "t=0 0\r\n"
+ & "m=audio " & int2str(cpars.bss_rtp_port) & " RTP/AVP 112\r\n"
+ & "a=rtpmap:112 AMR/8000\r\n"
+ & "a=fmtp:112 octet-align=1\r\n"
+ & "a=ptime:20\r\n";
+ /* MSC should ask for another Assignment after MNCC_ALERT_REQ, that should now contain only the remote call
+ * leg's capabilities, i.e. only AMR. */
+ cpars.expect_re_assignment := true;
+ cpars.re_ass_req_codecs := {valueof(ts_CodecAMR_F), valueof(ts_CodecAMR_H)};
+ /* When the MSC asks for another Assignment after MNCC_ALERT_REQ, we'll give it AMR. */
+ cpars.re_ass_compl_chosen_codec := valueof(ts_CodecAMR_F);
+ f_perform_lu();
+ f_mo_call(cpars);
+}
+testcase TC_lu_and_mo_call_reass_for_mt_codec() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn;
+ f_init();
+
+ vc_conn := f_start_handler(refers(f_tc_lu_and_mo_call_reass_for_mt_codec), 7);
+ vc_conn.done;
+}
+
control {
execute( TC_cr_before_reset() );
execute( TC_lu_imsi_noauth_tmsi() );
execute( TC_lu_imsi_noauth_notmsi() );
+ execute( TC_lu_tmsi_noauth_notmsi() );
execute( TC_lu_imsi_reject() );
execute( TC_lu_imsi_timeout_gsup() );
execute( TC_lu_imsi_auth_tmsi() );
@@ -6319,6 +7465,8 @@ control {
execute( TC_lu_auth_sai_timeout() );
execute( TC_lu_auth_sai_err() );
execute( TC_lu_clear_request() );
+ execute( TC_mo_call_clear_request() );
+ execute( TC_mt_call_clear_request() );
execute( TC_lu_disconnect() );
execute( TC_lu_by_imei() );
execute( TC_lu_by_tmsi_noauth_unknown() );
@@ -6342,7 +7490,7 @@ control {
execute( TC_mo_crcx_ran_reject() );
execute( TC_mt_crcx_ran_reject() );
execute( TC_mo_setup_and_dtmf_dup() );
- //execute( TC_mt_t310() );
+ execute( TC_mt_t310() );
execute( TC_gsup_cancel() );
execute( TC_lu_imsi_auth_tmsi_encr_1_13() );
execute( TC_lu_imsi_auth_tmsi_encr_3_13() );
@@ -6350,6 +7498,10 @@ control {
execute( TC_lu_imsi_auth_tmsi_encr_3_1_no_cm() );
execute( TC_lu_imsi_auth_tmsi_encr_13_2() );
execute( TC_lu_imsi_auth_tmsi_encr_013_2() );
+ execute( TC_lu_imsi_auth_tmsi_encr_0134_1() );
+ execute( TC_lu_imsi_auth_tmsi_encr_0134_34() );
+ execute( TC_lu_imsi_auth_tmsi_encr_0134_34_no_cm3() );
+
execute( TC_mo_release_timeout() );
execute( TC_lu_and_mt_call_no_dlcx_resp() );
execute( TC_reset_two() );
@@ -6375,6 +7527,7 @@ control {
execute( TC_gsup_mt_sms_rp_mr() );
execute( TC_gsup_mo_mt_sms_rp_mr() );
execute( TC_gsup_mt_multi_part_sms() );
+ execute( TC_gsup_mt_sms_lu_delay() );
execute( TC_lu_and_mo_ussd_single_request() );
execute( TC_lu_and_mt_ussd_notification() );
@@ -6423,10 +7576,18 @@ control {
execute( TC_ho_inter_bsc_unknown_cell() );
execute( TC_ho_inter_bsc() );
+ execute( TC_ho_inter_bsc_a5_1() );
+ execute( TC_ho_inter_bsc_a5_3() );
+ execute( TC_ho_inter_bsc_a5_4() );
execute( TC_ho_inter_bsc_ipv6() );
+ execute( TC_ho_inter_bsc_csd() );
execute( TC_ho_inter_msc_out() );
+ execute( TC_ho_inter_msc_out_a5_1() );
+ execute( TC_ho_inter_msc_out_a5_3() );
+ execute( TC_ho_inter_msc_out_a5_4() );
execute( TC_ho_inter_msc_out_ipv6() );
+ execute( TC_ho_inter_msc_out_csd() );
execute( TC_lu_imsi_auth_tmsi_check_imei() );
execute( TC_lu_imsi_auth3g_tmsi_check_imei() );
@@ -6446,10 +7607,32 @@ control {
execute( TC_invalid_mgcp_crash() );
execute( TC_mm_id_resp_no_identity() );
execute( TC_lu_and_expire_while_paging() );
- if (mp_enable_crashing_tests) {
- execute( TC_paging_response_imsi_unknown() );
- execute( TC_paging_response_tmsi_unknown() );
- }
+ execute( TC_paging_response_imsi_unknown() );
+ execute( TC_paging_response_tmsi_unknown() );
+
+ execute( TC_call_re_establishment() );
+ execute( TC_call_re_establishment_auth() );
+ execute( TC_call_re_establishment_ciph() );
+
+ execute( TC_cm_serv_wrong_mi() );
+
+ execute( TC_auth_options_0() );
+ execute( TC_auth_options_1() );
+ execute( TC_auth_options_2() );
+ execute( TC_auth_options_3() );
+ execute( TC_auth_options_4() );
+ execute( TC_auth_options_5() );
+ execute( TC_auth_options_6() );
+ execute( TC_auth_options_7() );
+ execute( TC_auth_options_8() );
+ execute( TC_auth_options_9() );
+ execute( TC_auth_options_10() );
+ execute( TC_auth_options_11() );
+
+ execute( TC_lu_and_mo_csd() );
+ execute( TC_lu_and_mt_csd() );
+
+ execute( TC_lu_and_mo_call_reass_for_mt_codec() );
}