pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/35386?usp=email )
Change subject: mme: Introduce test TC_ue_cell_reselect_eutran_to_geran ......................................................................
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 --- M library/GTP_Templates.ttcn M mme/MME_Tests.ttcn 2 files changed, 282 insertions(+), 1 deletion(-)
Approvals: osmith: Looks good to me, but someone else must approve Jenkins Builder: Verified daniel: Looks good to me, approved
diff --git a/library/GTP_Templates.ttcn b/library/GTP_Templates.ttcn index 06ba208..839ed28 100644 --- a/library/GTP_Templates.ttcn +++ b/library/GTP_Templates.ttcn @@ -41,6 +41,37 @@ /* FIXME */ };
+ template (value) Cause_gtpc ts_Cause_gtpc(template (value) GTP_Cause cause) := { + type_gtpc := '01'O, + causevalue := enum2oct1_Cause_gtpc_tmpl(cause) + } + private function enum2oct1_Cause_gtpc_tmpl(template GTP_Cause inp) return template OCT1 + { + if (istemplatekind(inp, "omit")) { + return omit; + } else if (istemplatekind(inp, "*")) { + return *; + } else if (istemplatekind(inp, "?")) { + return ?; + } else { + return int2oct(enum2int(valueof(inp)), 1); + } + } + template (present) Cause_gtpc tr_Cause_gtpc(template (present) GTP_Cause cause) := { + type_gtpc := '01'O, + causevalue := enum2oct1_Cause_gtpc_tmpl(cause) + } + function f_tr_Cause_gtpc(template GTP_Cause cause) return + template Cause_gtpc { + if (istemplatekind(cause, "omit")) { + return omit; + } else if (istemplatekind(cause, "*")) { + return *; + } else { + return tr_Cause_gtpc(cause); + } + } + private function f_oct_or_wc(template integer inp, integer len) return template octetstring { if (istemplatekind(inp, "omit")) { return omit; @@ -119,6 +150,18 @@ restartCounter := restart_counter }
+ /* Packet TMSI - 7.7.5 */ + template (value) PacketTMSI ts_PTMSI(OCT4 ptmsi) := { + type_gtpc := '05'O, + p_tmsi := ptmsi + } + + /* PTMSI Signature - 7.7.9 */ + template (value) PTMSI_Signature ts_PTMSI_sig(OCT3 ptmsi_sig) := { + type_gtpc := '0C'O, + ptmsi_Signature := ptmsi_sig + } + /* IMEI(SV) IE TS 29.060 7.7.53 */ template (value) IMEISV_gtpc ts_IMEISV(template (value) OCT8 imeisv) := { type_gtpc := '9A'O, @@ -350,7 +393,7 @@ apn_value := apn }
- template (value) GSN_Address_GTPC ts_GsnAddr(octetstring ip_addr) := { + template (value) GSN_Address_GTPC ts_GsnAddr(template (value) octetstring ip_addr) := { type_gtpc := '85'O, lengthf := lengthof(ip_addr), addressf := ip_addr @@ -402,6 +445,29 @@ digits := digits, padding := 'F'H } + function f_ts_Imsi(template (omit) hexstring digits := omit) return template (omit) IMSI_gtpc { + var template (omit) IMSI_gtpc imsi; + if (istemplatekind(digits, "omit")) { + imsi := omit; + } else { + imsi := ts_Imsi(valueof(digits)); + } + return imsi; + } + template (present) IMSI_gtpc tr_Imsi(template (present) hexstring digits) := { + type_gtpc := '02'O, + digits := digits, + padding := 'F'H + } + function f_tr_Imsi(template hexstring digits := *) return template IMSI_gtpc { + if (istemplatekind(digits, "omit")) { + return omit; + } else if (istemplatekind(digits, "*")) { + return *; + } else { + return tr_Imsi(digits); + } + }
function f_ts_RATType(template (omit) OCT1 ratType := omit) return template (omit) RATType { var template (omit) RATType rt; @@ -417,6 +483,17 @@ return rt; }
+ template (value) RoutingAreaIdentity ts_RoutingAreaIdentity(template (value) hexstring mcc_digits, + template (value) hexstring mnc_digits, + template (value) OCT2 lac, + template (value) OCT1 rac) := { + type_gtpc := '03'O, + mcc_digits := mcc_digits, + mnc_digits := mnc_digits, + lac := lac, + rac := rac + } + template (value) GeographicLocationCGI ts_GeographicLocationCGI(template (value) hexstring mcc, template (value) hexstring mnc, @@ -869,6 +946,101 @@ valueof(ts_DeletePdpRespPDU(cause, pco)), seq) }
+ /* SGSN Context Request - 7.5.3 */ + template (value) GTPC_PDUs ts_SGSNContextReqPDU(template (value) RoutingAreaIdentity rai, + template (value) OCT4 teic, + template (value) octetstring sgsn_addr_control, + template (omit) hexstring imsi := omit, + template (value) BIT1 msValidated := '0'B, + template (omit) TLLI tlli := omit, + template (omit) PacketTMSI ptmsi := omit, + template (omit) PTMSI_Signature ptmsi_sig := omit, + template (omit) OCT1 rat_type := omit) := { + sgsn_ContextRequest := { + imsi := f_ts_Imsi(imsi), + routingAreaIdentity := rai, + tlli := tlli, + packetTMSI := ptmsi, + ptmsi_Signature := ptmsi_sig, + ms_Validated := { + type_gtpc := '0D'O, + msValidated := msValidated, + spare := '1111111'B + }, + teidControlPlane := { + type_gtpc := '11'O, + teidControlPlane := teic + }, + sgsn_addr_controlPlane := ts_GsnAddr(sgsn_addr_control), + alternative_sgsn_addr_controlPlane := omit, + sGSN_Number := omit, + ratType := f_ts_RATType(rat_type), + hopCounter := omit, + private_extension_gtpc := omit + } + } + template (value) Gtp1cUnitdata ts_GTPC_SGSNContextReq(GtpPeer peer, uint16_t seq, + template (value) GTPC_PDUs SGSNContextReqPDU) := { + peer := peer, + gtpc := ts_GTP1C_PDU(sgsnContextRequest, '00000000'O, valueof(SGSNContextReqPDU), seq) + } + + /* SGSN Context Response - 7.5.4 */ + template (present) GTPC_PDUs tr_SGSNContextRespPDU(template (present) GTP_Cause cause := ?, + template hexstring imsi := *) := { + sgsn_ContextResponse := { + cause := tr_Cause_gtpc(cause), + imsi := f_tr_Imsi(imsi), + teidControlPlane := *, + rabContext := *, + radioPrioritySMS := *, + radioPriority := *, + packetFlowID := *, + charging_char := *, + mm_Context := *, + pdp_Context := *, + sgsn_addr_controlPlane := *, + pdpContextPriorization := *, + radioPriority_LCS := *, + mBMS_UE_Context := *, + subscribedRFSP_Index := *, + rFSP_IndexInUse := *, + colocatedGGSN_PGW_FQDN := *, + evolvedAllocationRetentionPriorityII := *, + extendedCommonFlags := *, + ue_network_capability := *, + ue_ambr := *, + apn_ambr_nsapi := *, + signallingPriorityIndication_nsapi := *, + higher_bitrates_than_16mbps_flag := *, + selectionMode_nsapi := *, + localHomeNetworkID_nsapi := *, + uE_UsageType := *, + extendedCommonFlagsII := *, + private_extension_gtpc := * + } + } + template (present) Gtp1cUnitdata tr_GTPC_SGSNContextResp(template (present) GtpPeer peer := ?, + template (present) OCT4 teid := ?, + template (present) GTPC_PDUs SGSNContextRespPDU := ?) + := tr_GTPC_MsgType(peer, sgsnContextResponse, teid, SGSNContextRespPDU); + + /* SGSN Context Acknowledge - 7.5.5 */ + template (value) GTPC_PDUs ts_SGSNContextAckPDU(template (value) GTP_Cause cause := GTP_CAUSE_REQUEST_ACCEPTED) := { + sgsn_ContextAcknowledge := { + cause := ts_Cause_gtpc(cause), + teidDataII := omit, + sgsn_AddressForUserTraffic := omit, + sgsn_Number := omit, + nodeIdentifier := omit, + private_extension_gtpc := omit + } + } + template (value) Gtp1cUnitdata ts_GTPC_SGSNContextAck(GtpPeer peer, uint16_t seq, + template (value) GTPC_PDUs SGSNContextAckPDU := ts_SGSNContextAckPDU(GTP_CAUSE_REQUEST_ACCEPTED)) := { + peer := peer, + gtpc := ts_GTP1C_PDU(sgsnContextAcknowledge, '00000000'O, valueof(SGSNContextAckPDU), seq) + }
/* GTP-C RIM */
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() ); }