mme: Introduce test TC_ue_cell_reselect_eutran_to_geran

Initial bits to be able to test SGSN Context Request+Response emulating
an UE doing cell reselection from 4G to 2G.

Related: OS#6294
Change-Id: I707cb8c6b39c1440db5ccc2f02d08337b38fb564
diff --git a/mme/MME_Tests.ttcn b/mme/MME_Tests.ttcn
index eca6b04..f43bfbd 100644
--- a/mme/MME_Tests.ttcn
+++ b/mme/MME_Tests.ttcn
@@ -81,6 +81,7 @@
 type record UeParams {
 	hexstring imsi,
 	charstring ue_ip,
+	NAS_EPS_Types.GUTI guti optional,
 
 	/* TEI (Control) local side, S11 (SGW) */
 	OCT4 	s11_teic_local,
@@ -277,6 +278,7 @@
 	uep := {
 		imsi := f_gen_imsi(imsi_suffix),
 		ue_ip := "192.168.123.50",
+		guti := omit,
 		s11_teic_local := '00000000'O,
 		s11_teic_remote := omit,
 		s5c_teic_local := '00000000'O,
@@ -613,6 +615,14 @@
 		var template (value) E_RABSetupListCtxtSURes rab_setup_items;
 		var octetstring esm_enc;
 		var template (value) PDU_NAS_EPS nas;
+		var EPS_MobileIdentityTLV mi_tlv;
+
+		S1AP.receive(tr_NAS_AttachAccept()) -> value rx_nas;
+		mi_tlv := rx_nas.ePS_messages.ePS_MobilityManagement.pDU_NAS_EPS_AttachAccept.gUTI;
+		if (mi_tlv.ePS_MobileIdentity.ePS_MobileIdentity.typeOfIdentity != '110'B) {
+			Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Rx GUTI of unexpected MI type: ", mi_tlv));
+		}
+		g_pars.ue_pars.guti := mi_tlv.ePS_MobileIdentity.ePS_MobileIdentity.oddEvenInd_identity.guti
 
 		rab_setup_it := ts_S1AP_RABSetupItemCtxtSURes(rab_id := 5,
 							      tla := oct2bit(f_inet_addr(mp_mme_ip)),
@@ -1186,6 +1196,91 @@
 	vc_conn.done;
 }
 
+/* Test UE attached to EUTRAN reselecting a GERAN cell. In this scenario, the
+ * new SGSN will attempt to obtain information of the UE from the old SGSN (MME)
+ * through Gn interface using SGSN Context Request/Response procedure (OS#6294). */
+/* TS 23.003 2.8.2.1 */
+private function guti2rai_ptmsi(in NAS_EPS_Types.GUTI guti, out RoutingAreaIdentity rai, out OCT4 ptmsi, out OCT3 ptmsi_sig) runs on ConnHdlr {
+	var bitstring mtmsi_bits := oct2bit(guti.mTMSI);
+	var bitstring ptmsi_bits;
+	var bitstring ptmsi_sig_bits;
+
+	rai := valueof(ts_RoutingAreaIdentity(guti.mccDigit1 & guti.mccDigit2 & guti.mccDigit3,
+					      guti.mncDigit3 & guti.mncDigit1 & guti.mncDigit2,
+					      guti.mMEGI, guti.mMEC));
+	/* 3GPP TS 23.003 2.8.2.0: "P-TMSI shall be of 32 bits length where the two topmost bits are
+	 * reserved and always set to '11'. Hence, for a UE which may handover to GERAN/UTRAN (based on
+	 * subscription and UE capabilities), the corresponding bits in the M-TMSI are set to '11'"
+	 */
+	ptmsi_bits := '11'B & substr(mtmsi_bits, 2, 6) & oct2bit(guti.mMEC) & substr(mtmsi_bits, 16, 16);
+	ptmsi_sig_bits := substr(mtmsi_bits, 8, 8) & oct2bit('0000'O);
+	ptmsi := bit2oct(ptmsi_bits);
+	ptmsi_sig := bit2oct(ptmsi_sig_bits);
+	/* TODO: The UE shall fill the remaining 2 octets of the <P-TMSI signature> according to clauses 9.1.1, 9.4.1, 10.2.1, or
+	 * 10.5.1 of 3GPP TS.33.401 [89] , as appropriate, for RAU/Attach procedures.*/
+	/* TODO: 3GPP TS 33.401 9.1.1 The 16 least significant bits available in
+	 * the P-TMSI signature field shall be filled with the truncated NAS-token
+	 * according to 3GPP TS 23.003 [3].The truncated NAS-token is defined as the 16
+	 * least significant bits of the NAS-token.
+	 * The NAS-token is derived as specified in Annex A.9. The UE shall use the uplink NAS COUNT value that it would use
+	 * in the next NAS message to calculate the NAS-token and increase the stored uplink NAS COUNT value by 1.*/
+	/* TODO: mMEC "also copied into the 8 Most Significant Bits of the NRI field within the P-TMSI" */
+}
+private function f_TC_ue_cell_reselect_eutran_to_geran(ConnHdlrPars pars) runs on ConnHdlr {
+	var template (value) GTPC_PDUs SGSNContextReqPDU;
+	var RoutingAreaIdentity rai;
+	var OCT4 ptmsi;
+	var OCT3 ptmsi_sig;
+	var Gtp1cUnitdata gtpc_pdu;
+
+	f_init_handler(pars);
+	f_gtp_register_imsi(g_pars.ue_pars.imsi);
+	f_attach();
+
+	/* TODO: take GUTI from as_s1ap_handle_IntialCtxSetupReq() in g_pars,
+	 * convert it to P-TMSI and pass P-TMSI below */
+	guti2rai_ptmsi(g_pars.ue_pars.guti, rai, ptmsi, ptmsi_sig);
+
+	SGSNContextReqPDU := ts_SGSNContextReqPDU(rai, '00000000'O, f_inet_addr(mp_gn_local_ip),
+						  ptmsi := ts_PTMSI(ptmsi), ptmsi_sig := ts_PTMSI_sig(ptmsi_sig));
+	GTP.send(ts_GTPC_SGSNContextReq(g_gn_iface_peer, 0, SGSNContextReqPDU));
+
+	timer T := 5.0;
+	T.start;
+	alt {
+	[] GTP.receive(tr_GTPC_SGSNContextResp(g_gn_iface_peer, '00000000'O,
+					       tr_SGSNContextRespPDU(GTP_CAUSE_REQUEST_ACCEPTED,
+					       g_pars.ue_pars.imsi))) -> value gtpc_pdu {
+		setverdict(pass);
+		}
+	[] GTP.receive {
+		setverdict(fail, "unexpected GTPC message from MME");
+		}
+	[] T.timeout {
+		setverdict(fail, "no SGSN Context Response from MME");
+		}
+	}
+
+	GTP.send(ts_GTPC_SGSNContextAck(g_gn_iface_peer, oct2int(gtpc_pdu.gtpc.opt_part.sequenceNumber),
+					ts_SGSNContextAckPDU(GTP_CAUSE_REQUEST_ACCEPTED)));
+	/* Give some time to process the SGSNContextACK: */
+	f_sleep(3.0);
+}
+testcase TC_ue_cell_reselect_eutran_to_geran() runs on MTC_CT {
+	var charstring id := testcasename();
+
+	f_init_diameter(id);
+	f_init_s1ap(id, 4);
+	f_init_gtpv2_s11(id);
+	f_s1ap_setup(0);
+	f_init_gtp(id);
+
+	var ConnHdlrPars pars := f_init_pars(ue_idx := 0);
+	var ConnHdlr vc_conn;
+	vc_conn := f_start_handler_with_pars(refers(f_TC_ue_cell_reselect_eutran_to_geran), pars);
+	vc_conn.done;
+}
+
 control {
 	execute( TC_s1ap_setup_wrong_plmn() );
 	execute( TC_s1ap_setup_wrong_tac() );
@@ -1195,6 +1290,7 @@
 	execute( TC_gn_echo_request() );
 	execute( TC_RIM_RAN_INF() );
 	execute( TC_s1ap_reset() );
+	execute( TC_ue_cell_reselect_eutran_to_geran() );
 }