pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/35513?usp=email )
Change subject: mme: Introduce test TC_ue_cell_reselect_geran_to_eutran ......................................................................
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 --- M library/NAS_Templates.ttcn M library/S1AP_Emulation.ttcn M mme/MME_Tests.ttcn 3 files changed, 241 insertions(+), 6 deletions(-)
Approvals: daniel: Looks good to me, approved Jenkins Builder: Verified
diff --git a/library/NAS_Templates.ttcn b/library/NAS_Templates.ttcn index 944d857..d45dc7d 100644 --- a/library/NAS_Templates.ttcn +++ b/library/NAS_Templates.ttcn @@ -44,6 +44,9 @@ }
const BIT4 c_EPS_SEC_NONE := '0000'B; +const BIT4 c_EPS_SEC_IP := '0001'B; +const BIT4 c_EPS_SEC_IP_CIPH := '0010'B; + const BIT4 c_EPS_NAS_PD_EMM := '0111'B; const BIT4 c_EPS_NAS_PD_ESM := '0010'B;
@@ -58,6 +61,16 @@ content := inp }
+/* 9.9.3.4A - 10.5.1.2/24.008 */ +template (value) CipheringKeySequenceNumberTV +ts_CipheringKeySequenceNumberTV(template (value) BIT3 key_seq) := { + keySequence := { + keySequence := key_seq, + spare := '0'B + }, + elementIdentifier := '1000'B +} + private template (value) MobileIdentityLV ts_NAS_MobileIdLV(template (value) MobileIdentityV mid) := { lengthIndicator := 0, @@ -178,6 +191,19 @@ ePS_MobileIdentity := ts_NAS_MobileId_GUTI(guti) }
+/* 9.9.3.25 Nonce */ +template (value) NonceTV +ts_NonceTV(template (value) OCT4 nonce) := { + elementIdentifier := '55'O, + noncevalue := nonce +} +function f_ts_NonceTV(template (omit) OCT4 nonce) return template (omit) NonceTV { + if (istemplatekind(nonce, "omit")) { + return omit; + } + return ts_NonceTV(nonce); +} + /* 9.9.3.26 P-TMSI signature */ template (value) P_TMSISignatureTV ts_PTMSI_SignatureTV(template (value) OCT3 ptmsi_sig) := { @@ -408,6 +434,20 @@ } }
+/* 8.2.27 Tracking Area Update Complete */ +template (value) PDU_NAS_EPS +ts_PDU_NAS_EPS_TrackingAreaUpdateComplete(template (value) BIT4 securityHeaderType := c_EPS_SEC_NONE) := { + protocolDiscriminator := c_EPS_NAS_PD_EMM, + ePS_messages := { + ePS_MobilityManagement := { + pDU_NAS_EPS_TrackingAreaUpdateComplete := { + securityHeaderType := securityHeaderType, + messageType := '01001010'B + } + } + } +} + /* 8.2.28 Tracking Area Update Reject */ template (present) PDU_NAS_EPS tr_PDU_NAS_EPS_TrackingAreaUpdateReject(template (present) EMM_CauseV cause := ?) := { @@ -429,7 +469,9 @@ template (value) PDU_NAS_EPS ts_PDU_NAS_EPS_TrackingAreaUpdateRequest(template (value) EPS_MobileIdentityLV old_guti, template (omit) P_TMSISignatureTV old_ptmsi_sig := omit, - template (omit) GUTI_TypeTV old_guti_type := omit) := { + template (omit) GUTI_TypeTV old_guti_type := omit, + template (omit) NonceTV nonce_ue := omit, + template (omit) CipheringKeySequenceNumberTV gprs_cksn := omit) := { protocolDiscriminator := c_EPS_NAS_PD_EMM, ePS_messages := { ePS_MobilityManagement := { @@ -440,10 +482,10 @@ nasKeySetId := ts_NAS_KeySetIdentifierV, oldGUTI := old_guti, nonCurrentNative_nasKeySetId := omit, - gprsCipheringKeySequenceNumber := omit, + gprsCipheringKeySequenceNumber := gprs_cksn, old_P_TMSISignature := old_ptmsi_sig, additionalGUTI := omit, - nonce := omit, + nonce := nonce_ue, uENetworkCapability := omit, lastVisitedRegisteredTAI := omit, dRXParameter := omit, diff --git a/library/S1AP_Emulation.ttcn b/library/S1AP_Emulation.ttcn index e3e3216..955c690 100644 --- a/library/S1AP_Emulation.ttcn +++ b/library/S1AP_Emulation.ttcn @@ -72,7 +72,8 @@ }; type union S1APEM_Config { NAS_Keys set_nas_keys, - ResetNAScounts reset_nas_counts + ResetNAScounts reset_nas_counts, + NAS_ALG_INT set_nas_alg_int };
type enumerated S1APEM_EventUpDown { @@ -453,6 +454,11 @@ S1apAssociationTable[assoc_id].nus.rx_count := 0; S1apAssociationTable[assoc_id].nus.tx_count := 0; } + /* Configuration primitive from client */ + [] S1AP_CLIENT.receive(S1APEM_Config:{set_nas_alg_int:=?}) -> value s1cfg sender vc_conn { + var integer assoc_id := f_assoc_id_by_comp(vc_conn); + S1apAssociationTable[assoc_id].nus.alg_int := s1cfg.set_nas_alg_int; + } /* S1AP from client: InitialUE */ [] S1AP_CLIENT.receive(tr_S1AP_InitialUE) -> value msg sender vc_conn { /* create a table entry about this connection */ 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() ); }