From 6d196de0e8bba425fe1eab313f7c693d6834a97b Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Thu, 13 Jul 2023 16:45:46 +0200 Subject: [PATCH] WIP: Initial implementation of E-UTRAN to GERAN A/Gb mode Inter RAT handover --- src/mme/mme-gn-build.c | 30 +++++++++++++++++- src/mme/mme-gn-build.h | 3 ++ src/mme/mme-gtp-path.c | 37 ++++++++++++++++++++++ src/mme/mme-gtp-path.h | 3 ++ src/mme/s1ap-handler.c | 71 +++++++++++++++++++++++++++++++++++++++++- 5 files changed, 142 insertions(+), 2 deletions(-) diff --git a/src/mme/mme-gn-build.c b/src/mme/mme-gn-build.c index dc88063dd1..f6a713bd35 100644 --- a/src/mme/mme-gn-build.c +++ b/src/mme/mme-gn-build.c @@ -59,4 +59,32 @@ ogs_pkbuf_t *mme_gn_build_ran_information_relay( gtp1_message.h.type = type; return ogs_gtp1_build_msg(>p1_message); -} \ No newline at end of file +} + +/* TS 29.060 7.5.6 Forward Relocation Request */ +ogs_pkbuf_t *mme_gn_build_forward_relocation_request( + mme_ue_t *mme_ue, uint8_t type, const uint8_t *buf, size_t len) +{ + ogs_gtp1_message_t gtp1_message; + ogs_gtp1_forward_relocation_request_t *req = NULL; + //ogs_session_t *sess = mme_default_session(mme_ue); + + ogs_debug("[Gn] build RAN Information Relay"); + + //ogs_assert(sess); + + req = >p1_message.forward_relocation_request; + memset(>p1_message, 0, sizeof(ogs_gtp1_message_t)); + + req->imsi.presence = mme_ue->imsi_len > 0; + req->imsi.data = mme_ue->imsi; + req->imsi.len = mme_ue->imsi_len; + + req->tunnel_endpoint_identifier_control_plane.presence = 1; + req->tunnel_endpoint_identifier_control_plane.u32 = mme_ue->mme_s11_teid; + + /* TODO: implement */ + + gtp1_message.h.type = type; + return ogs_gtp1_build_msg(>p1_message); +}; \ No newline at end of file diff --git a/src/mme/mme-gn-build.h b/src/mme/mme-gn-build.h index fc66282c67..38832c9376 100644 --- a/src/mme/mme-gn-build.h +++ b/src/mme/mme-gn-build.h @@ -34,4 +34,7 @@ ogs_pkbuf_t *mme_gn_build_ran_information_relay( uint8_t type, const uint8_t *buf, size_t len, const ogs_nas_rai_t *rai, uint16_t cell_id); +ogs_pkbuf_t *mme_gn_build_forward_relocation_request( + mme_ue_t *mme_ue, uint8_t type, const uint8_t *buf, size_t len); + #endif /* MME_S11_BUILD_H */ diff --git a/src/mme/mme-gtp-path.c b/src/mme/mme-gtp-path.c index cce8a714ee..386ba94aea 100644 --- a/src/mme/mme-gtp-path.c +++ b/src/mme/mme-gtp-path.c @@ -795,3 +795,40 @@ int mme_gtp1_send_ran_information_relay( return rv; } + +/* TS 29.060 7.5.6 Forward Relocation Request */ +int mme_gtp1_send_forward_relocation_request( + mme_sgsn_t *sgsn, mme_ue_t *mme_ue, const uint8_t *buf, size_t len) +{ + int rv; + ogs_gtp1_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + ogs_gtp_xact_t *xact = NULL; + + ogs_assert(sgsn); + ogs_assert(buf); + + memset(&h, 0, sizeof(ogs_gtp1_header_t)); + h.type = OGS_GTP1_FORWARD_RELOCATION_REQUEST_TYPE; + h.teid = 0; + + pkbuf = mme_gn_build_forward_relocation_request(mme_ue, h.type, buf, len); + if (!pkbuf) { + ogs_error("mme_gn_build_forward_relocation_request() failed"); + return OGS_ERROR; + } + + xact = ogs_gtp1_xact_local_create(&sgsn->gnode, &h, pkbuf, NULL, NULL); + if (!xact) { + ogs_error("ogs_gtp1_xact_local_create() failed"); + return OGS_ERROR; + } + /* TS 29.060 8.2: "The Forward Relocation Request message, where the Tunnel + * Endpoint Identifier shall be set to all zeroes." */ + xact->local_teid = 0; + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} \ No newline at end of file diff --git a/src/mme/mme-gtp-path.h b/src/mme/mme-gtp-path.h index 37773e115d..707197cd56 100644 --- a/src/mme/mme-gtp-path.h +++ b/src/mme/mme-gtp-path.h @@ -59,6 +59,9 @@ int mme_gtp1_send_ran_information_relay( mme_sgsn_t *sgsn, const uint8_t *buf, size_t len, const ogs_nas_rai_t *rai, uint16_t cell_id); +int mme_gtp1_send_forward_relocation_request( + mme_sgsn_t *sgsn, mme_ue_t *mme_ue, const uint8_t *buf, size_t len); + #ifdef __cplusplus } #endif diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index b9e1edaee7..68b002081d 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -2810,6 +2810,73 @@ static void s1ap_handle_handover_required_intralte(enb_ue_t *source_ue, ogs_assert(r != OGS_ERROR); } +/* 3GPP TS 23.401 "D.3.7 E-UTRAN to GERAN A/Gb mode Inter RAT handover" */ +static void s1ap_handle_handover_required_ltetogeran(enb_ue_t *source_ue, + S1AP_Cause_t *Cause, S1AP_TargetID_t *TargetID, + S1AP_Source_ToTarget_TransparentContainer_t *Source_ToTarget_TransparentContainer) +{ + struct S1AP_CGI *cGI = NULL; + ogs_plmn_id_t plmn_id; + ogs_nas_rai_t rai; + uint16_t cell_id; + mme_sgsn_t *target_sgsn = NULL; + mme_ue_t *mme_ue = NULL; + int r; + + ogs_assert(source_ue); + ogs_assert(Cause); + ogs_assert(TargetID); + ogs_assert(Source_ToTarget_TransparentContainer); + + if (TargetID->present != S1AP_TargetID_PR_cGI) { + ogs_error("Unexpected TargetID (%d)", TargetID->present); + r = s1ap_send_handover_preparation_failure(source_ue, + S1AP_Cause_PR_protocol, S1AP_CauseProtocol_semantic_error); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); + return; + } + cGI = TargetID->choice.cGI; + ogs_assert(cGI); + + memcpy(&plmn_id, cGI->pLMNidentity.buf, sizeof(plmn_id)); + ogs_nas_from_plmn_id(&rai.lai.nas_plmn_id, &plmn_id); + memcpy(&rai.lai.lac, cGI->lAC.buf, sizeof(uint16_t)); + rai.lai.lac = be16toh(rai.lai.lac); + if (cGI->rAC) + rai.rac = *cGI->rAC->buf; + else /* FIXME: what to do? how to search properly for target cell? */ + rai.rac = 0xff; + memcpy(&cell_id, cGI->cI.buf, sizeof(uint16_t)); + cell_id = be16toh(cell_id); + ogs_info(" RAI[MCC:%u MNC:%u LAC:%u RAC:%u] CI[%u]", + ogs_plmn_id_mcc(&plmn_id), ogs_plmn_id_mnc(&plmn_id), + rai.lai.lac, rai.rac, cell_id); + + target_sgsn = mme_sgsn_find_by_routing_address(&rai, cell_id); + if (!target_sgsn) { + ogs_warn("No SGSN matching target cell! RAI[MCC:%u MNC:%u LAC:%u RAC:%u] CI[%u]", + ogs_plmn_id_mcc(&plmn_id), ogs_plmn_id_mnc(&plmn_id), + rai.lai.lac, rai.rac, cell_id); + return; + } + + mme_ue = source_ue->mme_ue; + if (!mme_ue) { + ogs_error("No UE(mme-ue) context"); + return; + } + + source_ue->handover_type = S1AP_HandoverType_ltetogeran; + + mme_gtp1_send_forward_relocation_request(target_sgsn, mme_ue, + Source_ToTarget_TransparentContainer->buf, + Source_ToTarget_TransparentContainer->size); + /* FIXME: we send HO Prep Failure because we don't fully support this yet... */ + r = s1ap_send_handover_preparation_failure(source_ue, + S1AP_Cause_PR_protocol, S1AP_CauseProtocol_message_not_compatible_with_receiver_state); +} + void s1ap_handle_handover_required(mme_enb_t *enb, ogs_s1ap_message_t *message) { char buf[OGS_ADDRSTRLEN]; @@ -2951,8 +3018,10 @@ void s1ap_handle_handover_required(mme_enb_t *enb, ogs_s1ap_message_t *message) case S1AP_HandoverType_intralte: s1ap_handle_handover_required_intralte(source_ue, Cause, TargetID, Source_ToTarget_TransparentContainer); break; - case S1AP_HandoverType_ltetoutran: case S1AP_HandoverType_ltetogeran: + s1ap_handle_handover_required_ltetogeran(source_ue, Cause, TargetID, Source_ToTarget_TransparentContainer); + break; + case S1AP_HandoverType_ltetoutran: case S1AP_HandoverType_utrantolte: case S1AP_HandoverType_gerantolte: case S1AP_HandoverType_eps_to_5gs: