mme: Introduce test TC_ue_cell_reselect_geran_to_eutran

This test allows reproducing an idle mobility GERAN->EUTRAN.

Related: OS#6294
Change-Id: I6f8f077b99e83e6467d2b0c05148b81dbcf2ede4
diff --git a/mme/MME_Tests.ttcn b/mme/MME_Tests.ttcn
index 2194e8a..aa23a84 100644
--- a/mme/MME_Tests.ttcn
+++ b/mme/MME_Tests.ttcn
@@ -617,7 +617,7 @@
 }
 
 
-private altstep as_s1ap_handle_IntialCtxSetupReq() runs on ConnHdlr {
+private altstep as_s1ap_handle_IntialCtxSetupReq_Attach_Accept() runs on ConnHdlr {
 	var S1AP_PDU rx_msg;
 	var PDU_NAS_EPS rx_nas;
 	[] S1AP.receive(tr_S1AP_IntialCtxSetupReq) -> value rx_msg {
@@ -654,6 +654,40 @@
 	}
 }
 
+private altstep as_s1ap_handle_IntialCtxSetupReq_TAU_Accept() runs on ConnHdlr {
+	var S1AP_PDU rx_msg;
+	var PDU_NAS_EPS rx_nas;
+	[] S1AP.receive(tr_S1AP_IntialCtxSetupReq) -> value rx_msg {
+		/* 3GPP TS 23.401 D.3.6 step 22: */
+		var template (omit) MME_UE_S1AP_ID mme_ue_id := f_S1AP_get_MME_UE_S1AP_ID(rx_msg);
+		var template (omit) ENB_UE_S1AP_ID enb_ue_id := f_S1AP_get_ENB_UE_S1AP_ID(rx_msg);
+		var template (value) E_RABSetupItemCtxtSURes rab_setup_it;
+		var template (value) E_RABSetupListCtxtSURes rab_setup_items;
+		var S1APEM_Config cfg;
+
+		S1AP.receive(tr_PDU_NAS_EPS_TrackingAreaUpdateAccept)-> value rx_nas;
+
+		/* Configure integrity protection: */
+		cfg := {
+			set_nas_alg_int := NAS_ALG_IP_EIA1
+		};
+		S1AP.send(cfg);
+
+		rab_setup_it := ts_S1AP_RABSetupItemCtxtSURes(rab_id := 5,
+							tla := oct2bit(f_inet_addr(mp_mme_ip)),
+							gtp_teid := '00000002'O);
+		rab_setup_items := ts_S1AP_RABSetupListCtxtSURes(rab_setup_it);
+		S1AP.send(ts_S1AP_InitialCtxSetupResp(valueof(mme_ue_id), valueof(enb_ue_id), rab_setup_items));
+
+		/* 3GPP TS 23.401 D.3.6 step 23: */
+		/* Integrity Protection: TS 24.301 Section 4.4.4.3*/
+		S1AP.send(ts_PDU_NAS_EPS_TrackingAreaUpdateComplete(c_EPS_SEC_IP));
+		}
+	[] S1AP.receive(PDU_NAS_EPS:?) -> value rx_nas {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Rx Unexpected NAS PDU msg: ", rx_nas));
+	}
+}
+
 private altstep as_s1ap_handle_UeContextReleaseCmd(template S1AP_IEs.Cause cause := ?) runs on ConnHdlr {
 	var S1AP_PDU rx_msg;
 	var PDU_NAS_EPS rx_nas;
@@ -925,6 +959,43 @@
 
 }
 
+private altstep as_gtp_sgsn_context_2g_to_4g(OCT4 new_sgsn_teid := 'ABABABAB'O, GTP_Templates.GTP_RATType rat_type := GTP_RAT_TYPE_EUTRAN) runs on ConnHdlr {
+	var Gtp1cUnitdata gtpc_pdu;
+
+	[] GTP.receive(tr_GTPC_SGSNContextReq(g_gn_iface_peer, tr_SGSNContextReqPDU(rat_type := int2oct(enum2int(rat_type), 1)))) -> value gtpc_pdu {
+		var template (value) PDP_Context_GTPC pdp_ctx;
+		var template (value) GTPC_PDUs SGSNContextRespPDU;
+		var Gtp1cUnitdata gtpc_pdu_ack;
+		var OCT4 old_mme_remote_teid := gtpc_pdu.gtpc.gtpc_pdu.sgsn_ContextRequest.teidControlPlane.teidControlPlane;
+
+		const OCT16 ck := '740d62df9803eebde5120acf358433d0'O;
+		const OCT16 ik := '11329aae8e8d2941bb226b2061137c58'O;
+
+		pdp_ctx := ts_PDP_Context_GTPC(f_inet_addr(g_pars.ue_pars.ue_ip),
+					       f_inet_addr(mp_gn_local_ip),
+					       c_NAS_defaultAPN,
+					       ggsn_teic := '12345678'O,
+					       ggsn_teid := '87654321'O);
+		SGSNContextRespPDU := ts_SGSNContextRespPDU(GTP_CAUSE_REQUEST_ACCEPTED,
+							   g_pars.ue_pars.imsi,
+							   new_sgsn_teid,
+							   f_inet_addr(mp_gn_local_ip),
+							   ts_MM_ContextUMTS(ck, ik),
+							   { pdp_ctx });
+		GTP.send(ts_GTPC_SGSNContextResp(g_gn_iface_peer,
+						 old_mme_remote_teid,
+						 oct2int(gtpc_pdu.gtpc.opt_part.sequenceNumber),
+						 SGSNContextRespPDU));
+
+		GTP.receive(tr_GTPC_SGSNContextAck(g_gn_iface_peer, new_sgsn_teid,
+						   tr_SGSNContextAckPDU(GTP_CAUSE_REQUEST_ACCEPTED))) -> value gtpc_pdu;
+		setverdict(pass);
+	}
+	[] GTP.receive {
+		setverdict(fail, "unexpected GTPC message from MME");
+	}
+}
+
 private function f_attach() runs on ConnHdlr {
 	var template (value) EPS_MobileIdentityV mi := ts_NAS_MobileId_IMSI(g_pars.ue_pars.imsi);
 	var template (value) PDU_NAS_EPS nas_esm, nas_emm;
@@ -963,7 +1034,7 @@
 
 	T.start;
 	alt {
-	[] as_s1ap_handle_IntialCtxSetupReq();
+	[] as_s1ap_handle_IntialCtxSetupReq_Attach_Accept();
 	[] T.timeout { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("No message from MME")); }
 	}
 
@@ -1383,6 +1454,109 @@
 	vc_conn.done;
 }
 
+/* 3GPP TS 23.401 D.3.6, TS 23.003 2.8.2.2 */
+private function rai_ptmsi2_guti(in RoutingAreaIdentity rai, in OCT4 ptmsi, in OCT3 ptmsi_sig, out NAS_EPS_Types.GUTI guti) runs on ConnHdlr {
+
+
+	var bitstring ptmsi_bits := oct2bit(ptmsi);
+	var bitstring ptmsi_sig_bits := oct2bit(ptmsi_sig);
+	var bitstring mtmsi_bits := '11'B &
+				    substr(ptmsi_bits, 2, 6) &
+				    substr(ptmsi_sig_bits, 0, 8) &
+				    substr(ptmsi_bits, 16, 16);
+	guti := valueof(ts_NAS_GUTI(mcc_mnc := rai.mcc_digits & rai.mnc_digits,
+			    mmegi := rai.lac,
+			    mmec := rai.rac,
+			    tmsi := bit2oct(mtmsi_bits)));
+}
+/* Test UE attached to GERAN reselecting a EUTRAN cell. In this scenario, the
+ * new MME will attempt to obtain information of the UE from the old SGSN
+ * through Gn interface using SGSN Context Request/Response procedure (OS#6294). */
+/* 3GPP TS 23.401 D.3.6, TS 23.003 2.8.2.1 */
+private function f_TC_ue_cell_reselect_geran_to_eutran(ConnHdlrPars pars) runs on ConnHdlr {
+	f_init_handler(pars);
+	f_gtp_register_imsi(g_pars.ue_pars.imsi);
+	f_gtp2_register_imsi(g_pars.ue_pars.imsi);
+	/* SGSN Context Req doesn't necessarily contain IMSI, hence expect it through TEID=0 */
+	f_gtp_register_teid('00000000'O);
+	/* passed in SGSN Context Resp to MME, will be used by MME when answering with SGSN Context Ack: */
+	const OCT4 new_sgsn_teid := 'ABABABAB'O;
+	f_gtp_register_teid(new_sgsn_teid);
+
+	var template (value) EPS_MobileIdentityV mi := ts_NAS_MobileId_IMSI(pars.ue_pars.imsi);
+	var template (value) S1AP_PDU tx;
+	var template (value) PDU_NAS_EPS nas_tau;
+	var RoutingAreaIdentity rai;
+	var OCT4 ptmsi := f_gen_tmsi(suffix := 0, nri_v := 0, nri_bitlen := 8);
+	var OCT3 ptmsi_sig := f_rnd_octstring(3);
+	var NAS_EPS_Types.GUTI guti_val;
+	var template (value) EPS_MobileIdentityLV old_guti;
+	var S1APEM_Config cfg;
+	timer T := 5.0;
+
+	rai := valueof(ts_RoutingAreaIdentity(mp_gn_local_mcc, mp_gn_local_mnc,
+				      int2oct(mp_gn_local_lac, 2), int2oct(mp_gn_local_rac, 1)));
+	rai_ptmsi2_guti(rai, ptmsi, ptmsi_sig, guti_val);
+	old_guti := ts_EPS_MobileId_GUTI_(guti_val);
+
+	nas_tau := ts_PDU_NAS_EPS_TrackingAreaUpdateRequest(old_guti,
+							    ts_PTMSI_SignatureTV(ptmsi_sig),
+							    ts_GUTI_TypeTV(GUTI_TYPE_MAPPED),
+							    ts_NonceTV('12345678'O),
+							    ts_CipheringKeySequenceNumberTV('000'B));
+	tx := ts_S1AP_InitialUE(p_eNB_value := 0, p_nasPdu := enc_PDU_NAS_EPS(valueof(nas_tau)),
+				p_tAI := ts_enb_S1AP_TAI(g_pars.enb_pars[g_pars.mme_idx]),
+				p_eUTRAN_CGI := ts_enb_S1AP_CGI(g_pars.enb_pars[g_pars.mme_idx]),
+				p_rrcCause := mo_Signalling);
+
+	S1AP.send(tx);
+
+	/* NAS counts are reset to zero when a mapped security context is created. */
+	cfg := {
+		reset_nas_counts := {}
+	};
+	S1AP.send(cfg);
+
+	as_gtp_sgsn_context_2g_to_4g(new_sgsn_teid);
+
+	/* We now expect the MME to send a Create Session Request to the SGW-C */
+	T.start;
+	alt {
+	[] as_GTP2C_CreateSession_success();
+	[] T.timeout { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("No message from MME")); }
+	}
+
+	/* 3GPP TS 23.401 D.3.6 steps 14-21: */
+	as_DIA_UpdLoc();
+
+	/* 3GPP TS 23.401 D.3.6 step 22, 23: */
+	as_s1ap_handle_IntialCtxSetupReq_TAU_Accept();
+
+	/* We now expect the MME to send a Modify Bearer Request to the SGW-C */
+	T.start;
+	alt {
+	[] as_GTP2C_ModifyBearer_success();
+	[] T.timeout { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("No message from MME")); }
+	}
+
+	/* Leave some time for MME to handle Modify Bearer Response: */
+	f_sleep(1.0);
+}
+testcase TC_ue_cell_reselect_geran_to_eutran() runs on MTC_CT {
+	var charstring id := testcasename();
+
+	f_init_diameter(id);
+	f_init_s1ap(id, 7);
+	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_geran_to_eutran), pars);
+	vc_conn.done;
+}
+
 control {
 	execute( TC_s1ap_setup_wrong_plmn() );
 	execute( TC_s1ap_setup_wrong_tac() );
@@ -1393,6 +1567,7 @@
 	execute( TC_RIM_RAN_INF() );
 	execute( TC_s1ap_reset() );
 	execute( TC_ue_cell_reselect_eutran_to_geran() );
+	execute( TC_ue_cell_reselect_geran_to_eutran() );
 }