msc: add check IMEI tests

Extend BSC_ConnHdlr with new check IMEI related parameters. Add tests
for check IMEI and check IMEI early for multiple auth variations, as
well as variants where the HLR would respond with NOK or ERR.

Note that we can safely set "check-imei-rqd 0" in f_init(), because the
latest OsmoMSC version already suppors this VTY command.

Two tests do not always pass, sometimes the RAN connection breaks
before the test finishes (TC_lu_imsi_auth_tmsi_check_imei_err and
TC_lu_imsi_auth_tmsi_check_imei_nack). I have added them as expected
errors in the expected-results.xml.

Related: OS#2542
Change-Id: Ic34bb8dc8547cafb5a53df03884554dd4f72956d
diff --git a/msc/BSC_ConnectionHandler.ttcn b/msc/BSC_ConnectionHandler.ttcn
index 1dd4d05..e951400 100644
--- a/msc/BSC_ConnectionHandler.ttcn
+++ b/msc/BSC_ConnectionHandler.ttcn
@@ -70,7 +70,11 @@
 	OCT1	kc_support,
 	boolean expect_tmsi,
 	boolean	expect_auth,
-	boolean	expect_ciph
+	boolean	expect_ciph,
+	boolean expect_imei,
+	boolean expect_imei_early,
+	GSUP_IMEIResult check_imei_result,
+	boolean check_imei_error
 }
 
 type record BSC_ConnHdlrPars {
@@ -433,6 +437,82 @@
 	}
 }
 
+function f_mm_imei() runs on BSC_ConnHdlr
+{
+	var PDU_DTAP_MT dtap_mt;
+	var GSUP_PDU gsup_msg;
+	var MobileL3_CommonIE_Types.MobileIdentityLV mi;
+
+	if (not g_pars.net.expect_imei) {
+		return
+	}
+
+	/* MSC <-> BSC: ID req/rsp for IMEI */
+	alt {
+	[] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_ID_Req(CM_ID_TYPE_IMEI))) {
+		mi := valueof(ts_MI_IMEI_LV(g_pars.imei));
+		BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_MM_ID_Rsp(mi)));
+		}
+	[] BSSAP.receive(tr_PDU_DTAP_MT(?)) -> value dtap_mt {
+		setverdict(fail, "Expected ID REQ for IMEI DTAP MT message, but got: ", dtap_mt);
+		mtc.stop;
+		}
+	}
+
+	/* MSC <-> HLR: Check IMEI req/res/err */
+	alt {
+	[g_pars.net.check_imei_error] GSUP.receive(tr_GSUP_CHECK_IMEI_REQ(g_pars.imsi, g_pars.imei)) {
+		GSUP.send(ts_GSUP_CHECK_IMEI_ERR(g_pars.imsi, 96 /* Invalid Mandatory Information */));
+		}
+	[not g_pars.net.check_imei_error] GSUP.receive(tr_GSUP_CHECK_IMEI_REQ(g_pars.imsi, g_pars.imei)) {
+		GSUP.send(ts_GSUP_CHECK_IMEI_RES(g_pars.imsi, g_pars.net.check_imei_result));
+		}
+	[] GSUP.receive(?) -> value gsup_msg {
+		setverdict(fail, "Expected CHECK IMEI REQ GSUP message (with IMEI:", g_pars.imei, " and IMSI: ",
+			   g_pars.imsi, "), but got: ", gsup_msg);
+		mtc.stop;
+		}
+	}
+}
+
+function f_mm_imei_early() runs on BSC_ConnHdlr
+{
+	var PDU_DTAP_MT dtap_mt;
+	var GSUP_PDU gsup_msg;
+	var MobileL3_CommonIE_Types.MobileIdentityLV mi;
+
+	if (not g_pars.net.expect_imei_early) {
+		return
+	}
+
+	/* MSC <-> BSC: ID req/rsp for IMEISV */
+	alt {
+	[] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_ID_Req(CM_ID_TYPE_IMEISV))) {
+		mi := valueof(ts_MI_IMEISV_LV(g_pars.imei));
+		BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_MM_ID_Rsp(mi)));
+		}
+	[] BSSAP.receive(tr_PDU_DTAP_MT(?)) -> value dtap_mt {
+		setverdict(fail, "Expected ID REQ for IMEISV DTAP MT message, but got: ", dtap_mt);
+		mtc.stop;
+		}
+	}
+
+	/* MSC <-> HLR: Check IMEI req/res/err */
+	alt {
+	[g_pars.net.check_imei_error] GSUP.receive(tr_GSUP_CHECK_IMEI_REQ(g_pars.imsi, g_pars.imei)) {
+		GSUP.send(ts_GSUP_CHECK_IMEI_ERR(g_pars.imsi, 96 /* Invalid Mandatory Information */));
+		}
+	[not g_pars.net.check_imei_error] GSUP.receive(tr_GSUP_CHECK_IMEI_REQ(g_pars.imsi, g_pars.imei)) {
+		GSUP.send(ts_GSUP_CHECK_IMEI_RES(g_pars.imsi, g_pars.net.check_imei_result));
+		}
+	[] GSUP.receive(?) -> value gsup_msg {
+		setverdict(fail, "Expected CHECK IMEI REQ GSUP message (with IMEI:", g_pars.imei, " and IMSI: ",
+			   g_pars.imsi, "), but got: ", gsup_msg);
+		mtc.stop;
+		}
+	}
+}
+
 function f_mm_common() runs on BSC_ConnHdlr
 {
 	f_mm_auth();
@@ -508,8 +588,10 @@
 		f_ranap_initial_ue(l3_lu);
 	}
 
+	f_mm_imei_early();
 	f_mm_common();
 	f_msc_lu_hlr();
+	f_mm_imei();
 	f_accept_reject_lu();
 	/* FIXME: there could be pending SMS or other common procedures by the MSC, let's ignore them */
 	f_expect_clear();