From 5c0c8ec4f288b3393482cd92235b0fc74fda7eda Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Tue, 11 Jul 2023 14:48:50 +0200 Subject: [PATCH] mme: s1ap: Implement tx of MME DIRECT INFORMATION TRANSFER Triggered when receiving a GTPv1C RAN Information Relay message on Gn interface, targeted at one of the eNBs under the MME. --- src/mme/mme-gn-handler.c | 91 +++++++++++++++++++++++++++++++++++++++- src/mme/s1ap-build.c | 54 ++++++++++++++++++++++++ src/mme/s1ap-build.h | 2 + src/mme/s1ap-path.c | 25 +++++++++++ src/mme/s1ap-path.h | 3 ++ 5 files changed, 174 insertions(+), 1 deletion(-) diff --git a/src/mme/mme-gn-handler.c b/src/mme/mme-gn-handler.c index ccf8020df..b661d0de9 100644 --- a/src/mme/mme-gn-handler.c +++ b/src/mme/mme-gn-handler.c @@ -29,6 +29,8 @@ #include "mme-gn-build.h" #include "mme-gn-handler.h" +#include "s1ap-path.h" + void mme_gn_handle_echo_request( ogs_gtp_xact_t *xact, ogs_gtp1_echo_request_t *req) { @@ -46,10 +48,97 @@ void mme_gn_handle_echo_response( /* Not Implemented */ } +static int decode_global_enb_id(S1AP_Global_ENB_ID_t *glob_enb_id, const uint8_t *buf, size_t buf_len) +{ + asn_dec_rval_t dec_ret = {0}; + memset(glob_enb_id, 0, sizeof(S1AP_Global_ENB_ID_t)); + dec_ret = aper_decode(NULL, &asn_DEF_S1AP_Global_ENB_ID, (void **)&glob_enb_id, + buf, buf_len, 0, 0); + + if (dec_ret.code != RC_OK) { + ogs_warn("Failed to decode ASN-PDU [code:%d,consumed:%d]", + dec_ret.code, (int)dec_ret.consumed); + return OGS_ERROR; + } + + if (ogs_log_get_domain_level(OGS_LOG_DOMAIN) >= OGS_LOG_TRACE) + asn_fprint(stdout, &asn_DEF_S1AP_Global_ENB_ID, glob_enb_id); + + return OGS_OK; +} + +/* TS 29.060 7.5.14.1 */ void mme_gn_handle_ran_information_relay( ogs_gtp_xact_t *xact, ogs_gtp1_ran_information_relay_t *req) { + uint8_t discr; + ogs_eps_tai_t *target_tai; + S1AP_Global_ENB_ID_t global_ENB_ID; + uint32_t target_enb_id; + mme_enb_t *target_enb = NULL; + int rv; + ogs_debug("[Gn] Receiving RAN Information Relay"); - /* Not Implemented */ + + if (req->ran_transparent_container.len == 0 || + req->ran_transparent_container.data == NULL) { + ogs_warn("[Gn] Receiving RAN Information Relay with empty container!"); + return; + } + + /* "If RIM Routing Address Discriminator IE is not included, the RIM Routing + * Address shall be processed as an RNC identifier". Hence, not for us! */ + if (req->rim_routing_address_discriminator.presence == false) { + ogs_warn("[Gn] Rx RAN Information Relay: no RIM Routing Address Discriminator!"); + return; + } + + if (req->rim_routing_address_discriminator.len != 1) { + ogs_warn("[Gn] Rx RAN Information Relay: RIM Routing Address Discriminator len != 1"); + return; + } + + /* 3GPP TS 48.018 RIM Routing Information IE */ + discr = *((uint8_t*)req->rim_routing_address_discriminator.data) & 0x0f; + if (discr != 2) {/* 2: An eNB identifier is used to identify an E-UTRAN eNodeB or HeNB */ + ogs_warn("[Gn] Rx RAN Information Relay: RIM Routing Address Discriminator %u unexpected", discr); + return; + } + + if (req->rim_routing_address.presence == false) { + ogs_warn("[Gn] Rx RAN Information Relay: no RIM Routing Address!"); + return; + } + + if (req->rim_routing_address.len < sizeof(ogs_eps_tai_t)) { + ogs_warn("[Gn] Rx RAN Information Relay: RIM Routing Address len < %zu", sizeof(ogs_eps_tai_t)); + return; + } + target_tai = req->rim_routing_address.data; + + rv = decode_global_enb_id(&global_ENB_ID, + ((uint8_t *)req->rim_routing_address.data) + sizeof(ogs_eps_tai_t), + req->rim_routing_address.len - sizeof(ogs_eps_tai_t)); + if (rv != OGS_OK) + return; + ogs_s1ap_ENB_ID_to_uint32(&global_ENB_ID.eNB_ID, &target_enb_id); + + ogs_debug(" Target : ENB_ID[%s:%d], TAC[%d]", + global_ENB_ID.eNB_ID.present == + S1AP_ENB_ID_PR_homeENB_ID ? "Home" : + global_ENB_ID.eNB_ID.present == + S1AP_ENB_ID_PR_macroENB_ID ? "Macro" : "Others", + target_enb_id, target_tai->tac); + + target_enb = mme_enb_find_by_enb_id(target_enb_id); + if (target_enb == NULL) { + ogs_warn("[Gn] Rx RAN Information Relay: cannot find target eNB-id[0x%x]", target_enb_id); + return; + } + + s1ap_send_mme_direct_information_transfer( + target_enb, + req->ran_transparent_container.data, + req->ran_transparent_container.len); } diff --git a/src/mme/s1ap-build.c b/src/mme/s1ap-build.c index 511baabb1..b880f4822 100644 --- a/src/mme/s1ap-build.c +++ b/src/mme/s1ap-build.c @@ -1559,6 +1559,60 @@ ogs_pkbuf_t *s1ap_build_mme_configuration_transfer( return ogs_s1ap_encode(&pdu); } +/* 3GPP TS 36.413 8.14 MME Direct Information Transfer */ +ogs_pkbuf_t *s1ap_build_direct_information_transfer(const uint8_t *buf, size_t buf_len) +{ + S1AP_S1AP_PDU_t pdu; + S1AP_InitiatingMessage_t *initiatingMessage = NULL; + S1AP_MMEDirectInformationTransfer_t *MMEDirectInformationTransfer = NULL; + + S1AP_MMEDirectInformationTransferIEs_t *ie = NULL; + S1AP_Inter_SystemInformationTransferType_t *Inter_SystemInformationTransferType = NULL; + S1AP_RIMTransfer_t *rIMTransfer = NULL; + + ogs_assert(buf); + ogs_assert(buf_len > 0); + + ogs_debug("MMEDirectInformationTransfer"); + + memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); + pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + + initiatingMessage = pdu.choice.initiatingMessage; + initiatingMessage->procedureCode = + S1AP_ProcedureCode_id_MMEDirectInformationTransfer; + initiatingMessage->criticality = S1AP_Criticality_ignore; + initiatingMessage->value.present = + S1AP_InitiatingMessage__value_PR_MMEDirectInformationTransfer; + + MMEDirectInformationTransfer = + &initiatingMessage->value.choice.MMEDirectInformationTransfer; + + ie = CALLOC(1, sizeof(S1AP_MMEDirectInformationTransferIEs_t)); + ASN_SEQUENCE_ADD(&MMEDirectInformationTransfer->protocolIEs, ie); + + ie->id = S1AP_ProtocolIE_ID_id_Inter_SystemInformationTransferTypeMDT; + ie->criticality = S1AP_Criticality_reject; + ie->value.present = + S1AP_MMEDirectInformationTransferIEs__value_PR_Inter_SystemInformationTransferType; + + Inter_SystemInformationTransferType = &ie->value.choice.Inter_SystemInformationTransferType; + Inter_SystemInformationTransferType->present = S1AP_Inter_SystemInformationTransferType_PR_rIMTransfer; + + Inter_SystemInformationTransferType->choice.rIMTransfer = CALLOC(1, sizeof(S1AP_RIMTransfer_t)); + rIMTransfer = Inter_SystemInformationTransferType->choice.rIMTransfer; + + rIMTransfer->rIMInformation.size = buf_len; + rIMTransfer->rIMInformation.buf = CALLOC(buf_len, sizeof(uint8_t)); + memcpy(rIMTransfer->rIMInformation.buf, buf, buf_len); + + /* "The RIM Routing Address IE shall not be present since the eNB is the final destination node": */ + rIMTransfer->rIMRoutingAddress = NULL; + + return ogs_s1ap_encode(&pdu); +} + ogs_pkbuf_t *s1ap_build_path_switch_ack( mme_ue_t *mme_ue, bool e_rab_to_switched_in_uplink_list) { diff --git a/src/mme/s1ap-build.h b/src/mme/s1ap-build.h index e62a5db8d..6c7423ff9 100644 --- a/src/mme/s1ap-build.h +++ b/src/mme/s1ap-build.h @@ -56,6 +56,8 @@ ogs_pkbuf_t *s1ap_build_paging( ogs_pkbuf_t *s1ap_build_mme_configuration_transfer( S1AP_SONConfigurationTransfer_t *son_configuration_transfer); +ogs_pkbuf_t *s1ap_build_direct_information_transfer(const uint8_t *buf, size_t buf_len); + ogs_pkbuf_t *s1ap_build_path_switch_ack( mme_ue_t *mme_ue, bool e_rab_to_switched_in_uplink_list); ogs_pkbuf_t *s1ap_build_path_switch_failure( diff --git a/src/mme/s1ap-path.c b/src/mme/s1ap-path.c index 8225574ca..15c7142dd 100644 --- a/src/mme/s1ap-path.c +++ b/src/mme/s1ap-path.c @@ -489,6 +489,31 @@ int s1ap_send_mme_configuration_transfer( return rv; } +int s1ap_send_mme_direct_information_transfer( + mme_enb_t *target_enb, const uint8_t *buf, size_t buf_len) +{ + int rv; + ogs_pkbuf_t *s1apbuf = NULL; + + ogs_debug("Tx MME Direct Information Transfer"); + + if (!mme_enb_cycle(target_enb)) { + ogs_error("eNB has already been removed"); + return OGS_NOTFOUND; + } + + s1apbuf = s1ap_build_direct_information_transfer(buf, buf_len); + if (!s1apbuf) { + ogs_error("s1ap_build_direct_information_transfer() failed"); + return OGS_ERROR; + } + + rv = s1ap_send_to_enb(target_enb, s1apbuf, S1AP_NON_UE_SIGNALLING); + ogs_expect(rv == OGS_OK); + + return rv; +} + int s1ap_send_e_rab_modification_confirm(mme_ue_t *mme_ue) { int rv; diff --git a/src/mme/s1ap-path.h b/src/mme/s1ap-path.h index c30b7c0a6..8b1b65fe4 100644 --- a/src/mme/s1ap-path.h +++ b/src/mme/s1ap-path.h @@ -64,6 +64,9 @@ int s1ap_send_mme_configuration_transfer( mme_enb_t *target_enb, S1AP_SONConfigurationTransfer_t *SONConfigurationTransfer); +int s1ap_send_mme_direct_information_transfer( + mme_enb_t *target_enb, const uint8_t *buf, size_t buf_len); + int s1ap_send_e_rab_modification_confirm(mme_ue_t *mme_ue); int s1ap_send_path_switch_ack(