From 461cfb7911828ce1db9a716a206d428dd9a96200 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 11 Mar 2025 15:37:07 +0100 Subject: [PATCH] Add NGAP Handover Request decoding and RRC handler This commit introduces the NG Mobility Management Procedure known as Handover Resource Allocation. The inbound message is sent by the AMF and is known as Handover Request. Major changes: (0) Add Handover Resource Allocation initiating message decoding * add case for NGAP initiating message and unsuccessful message decoding (1) handle Handover Request on the target NG-RAN (2) decode NG Handover Request message (3) process payload, e.g. create UE context, store IDs, set UP security and trigger bearer setup Co-authored-by: batuhan duyuler --- openair2/COMMON/ngap_messages_def.h | 1 + openair2/COMMON/ngap_messages_types.h | 68 ++++++-- openair2/RRC/NR/nr_rrc_proto.h | 1 + openair2/RRC/NR/rrc_gNB.c | 7 +- openair2/RRC/NR/rrc_gNB_NGAP.c | 101 +++++++++++- openair2/RRC/NR/rrc_gNB_NGAP.h | 3 + openair2/RRC/NR/rrc_gNB_mobility.c | 2 + openair2/RRC/NR/rrc_gNB_mobility.h | 2 + openair3/NGAP/ngap_common.c | 130 +++++++++++++++ openair3/NGAP/ngap_common.h | 3 + openair3/NGAP/ngap_gNB_decoder.c | 6 + openair3/NGAP/ngap_gNB_encoder.c | 16 +- openair3/NGAP/ngap_gNB_handlers.c | 115 ++++---------- openair3/NGAP/ngap_gNB_mobility_management.c | 158 +++++++++++++++++++ openair3/NGAP/ngap_gNB_mobility_management.h | 1 + openair3/NGAP/ngap_msg_includes.h | 15 ++ 16 files changed, 525 insertions(+), 104 deletions(-) diff --git a/openair2/COMMON/ngap_messages_def.h b/openair2/COMMON/ngap_messages_def.h index 9cf975d34a..53b16350e1 100644 --- a/openair2/COMMON/ngap_messages_def.h +++ b/openair2/COMMON/ngap_messages_def.h @@ -83,6 +83,7 @@ MESSAGE_DEF(NGAP_PDUSESSION_SETUP_REQ , MESSAGE_PRIORITY_MED, ngap_pd MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_REQ , MESSAGE_PRIORITY_MED, ngap_pdusession_modify_req_t , ngap_pdusession_modify_req ) MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_COMMAND , MESSAGE_PRIORITY_MED, ngap_pdusession_release_command_t , ngap_pdusession_release_command) MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_COMMAND, MESSAGE_PRIORITY_MED, ngap_ue_release_command_t , ngap_ue_release_command) +MESSAGE_DEF(NGAP_HANDOVER_REQUEST, MESSAGE_PRIORITY_MED, ngap_handover_request_t, ngap_handover_request) /* NGAP <-> RRC messages (can be initiated either by MME or gNB) */ MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_REQ , MESSAGE_PRIORITY_MED, ngap_ue_release_req_t , ngap_ue_release_req) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 9a3e7a9a45..49212b257c 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -67,6 +67,7 @@ #define NGAP_PAGING_IND(mSGpTR) (mSGpTR)->ittiMsg.ngap_paging_ind #define NGAP_HANDOVER_REQUIRED(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_required #define NGAP_HANDOVER_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_failure +#define NGAP_HANDOVER_REQUEST(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_request #define NGAP_UE_CONTEXT_RELEASE_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_release_req #define NGAP_PDUSESSION_RELEASE_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_release_command @@ -229,6 +230,15 @@ typedef struct ngap_mobility_restriction_s{ plmn_id_t serving_plmn; }ngap_mobility_restriction_t; +/* PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ +typedef struct { + uint8_t nb_qos; + pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; + pdu_session_type_t pdu_session_type; + // UPF endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_incoming; +} pdusession_transfer_t; + typedef enum pdusession_qosflow_mapping_ind_e{ QOSFLOW_MAPPING_INDICATION_UL = 0, QOSFLOW_MAPPING_INDICATION_DL = 1, @@ -558,6 +568,55 @@ typedef struct { ngap_cause_t cause; } ngap_handover_failure_t; +typedef struct { + // Next-Hop NH + uint8_t next_hop[SECURITY_KEY_LENGTH]; + // Next Hop Chaining Count + uint8_t next_hop_chain_count; +} ngap_security_context_t; + +/* Handover Request (3GPP TS 38.413 9.2.3.4) + PDU Session Resource Setup Item */ +typedef struct { + // PDU Session ID + uint8_t pdusession_id; + pdu_session_type_t pdu_session_type; + // S-NSSAI + nssai_t nssai; + // Handover Required Transfer + pdusession_transfer_t pdusessionTransfer; +} ho_request_pdusession_t; + +/* 3GPP TS 38.413 9.2.3.4 */ +typedef struct { + // AMF UE NGAP ID + uint64_t amf_ue_ngap_id; + // Handover Type + ho_type_t ho_type; + // Cause + ngap_cause_t cause; + // UE Aggregate Maximum Bit Rate + ngap_ambr_t ue_ambr; + // UE Security Capabilities + ngap_security_capabilities_t security_capabilities; + // Security Context + ngap_security_context_t security_context; + // PDU Session Resource Setup List + uint8_t nb_of_pdusessions; + ho_request_pdusession_t pduSessionResourceSetupList[NGAP_MAX_PDU_SESSION]; + // Allowed NSSAI + uint8_t nb_allowed_nssais; + nssai_t allowed_nssai[8]; + // Source to Target Transparent Container contents + uint64_t nr_cell_id; + byte_array_t ue_ho_prep_info; + byte_array_t ue_cap; + // Mobility Restriction List + ngap_mobility_restriction_t *mobility_restriction; + // GUAMI + nr_guami_t guami; +} ngap_handover_request_t; + typedef struct ngap_ue_cap_info_ind_s { uint32_t gNB_ue_ngap_id; byte_array_t ue_radio_cap; @@ -628,15 +687,6 @@ typedef struct ngap_downlink_nas_s { byte_array_t nas_pdu; } ngap_downlink_nas_t; -/* PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ -typedef struct { - uint8_t nb_qos; - pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; - pdu_session_type_t pdu_session_type; - // UPF endpoint of the NG-U (N3) transport bearer - gtpu_tunnel_t n3_incoming; -} pdusession_transfer_t; - /* PDU Session Resource Setup/Modify Request Item */ typedef struct { int pdusession_id; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index a1918bdd34..bbaaaf5774 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -127,5 +127,6 @@ f1ap_qos_flow_param_t get_qos_char_from_qos_flow_param(const pdusession_level_qo void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration); NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish); NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish); +void activate_srb(gNB_RRC_UE_t *UE, int srb_id); #endif diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index ad36b9c10d..48ea8e760e 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -354,7 +354,7 @@ void freeSRBlist(NR_SRB_ToAddModList_t *l) ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, l); } -static void activate_srb(gNB_RRC_UE_t *UE, int srb_id) +void activate_srb(gNB_RRC_UE_t *UE, int srb_id) { AssertFatal(srb_id == 1 || srb_id == 2, "handling only SRB 1 or 2\n"); if (UE->Srb[srb_id].Active == 1) { @@ -2944,6 +2944,11 @@ void *rrc_gnb_task(void *args_p) { rrc_gNB_process_PAGING_IND(msg_p, instance); break; + case NGAP_HANDOVER_REQUEST: + rrc_gNB_process_Handover_Request(RC.nrrrc[instance], instance, &NGAP_HANDOVER_REQUEST(msg_p)); + rrc_gNB_free_Handover_Request(&NGAP_HANDOVER_REQUEST(msg_p)); // Free transfered NG message + break; + default: LOG_E(NR_RRC, "[gNB %ld] Received unexpected message %s\n", instance, msg_name_p); break; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 9b4096da4b..68aa502f77 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -83,6 +83,8 @@ #include "rrc_messages_types.h" #include "s1ap_messages_types.h" #include "uper_encoder.h" +#include "rrc_gNB_mobility.h" +#include "rrc_gNB_du.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -163,18 +165,24 @@ static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn) return guami; } +/** @brief Copy NGAP PDU Session Transfer item to RRC pdusession_t struct */ +static void cp_pdusession_transfer_to_pdusession(pdusession_t *dst, const pdusession_transfer_t *src) +{ + dst->nb_qos = src->nb_qos; + for (uint8_t i = 0; i < src->nb_qos && i < QOSFLOW_MAX_VALUE; ++i) { + dst->qos[i] = src->qos[i]; + } + dst->pdu_session_type = src->pdu_session_type; + dst->n3_incoming = src->n3_incoming; +} + /** @brief Copy NGAP PDU Session Resource item to RRC pdusession_t struct */ static void cp_pdusession_resource_item_to_pdusession(pdusession_t *dst, const pdusession_resource_item_t *src) { dst->pdusession_id = src->pdusession_id; dst->nas_pdu = src->nas_pdu; - dst->nb_qos = src->pdusessionTransfer.nb_qos; - for (uint8_t i = 0; i < src->pdusessionTransfer.nb_qos && i < QOSFLOW_MAX_VALUE; ++i) { - dst->qos[i] = src->pdusessionTransfer.qos[i]; - } - dst->pdu_session_type = src->pdusessionTransfer.pdu_session_type; - dst->n3_incoming = src->pdusessionTransfer.n3_incoming; dst->nssai = src->nssai; + cp_pdusession_transfer_to_pdusession(dst, &src->pdusessionTransfer); } /** @@ -1072,6 +1080,87 @@ void rrc_gNB_send_NGAP_HANDOVER_FAILURE(gNB_RRC_INST *rrc, ngap_handover_failure itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); } +/** @brief Process NG Handover Request message (8.4.2.2 3GPP TS 38.413) */ +int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, ngap_handover_request_t *msg) +{ + LOG_I(NR_RRC, "Received Handover Request (on PCI=%lu) \n", msg->nr_cell_id); + struct nr_rrc_du_container_t *du = get_du_by_cell_id(rrc, msg->nr_cell_id); + if (du == NULL) { + /* Cell Not Found! Return HO Request Failure*/ + LOG_E(RRC, "Failed to process Handover Request: no DU found with PCI=%lu \n", msg->nr_cell_id); + ngap_handover_failure_t fail = { + .amf_ue_ngap_id = msg->amf_ue_ngap_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_RADIO_RESOURCES_NOT_AVAILABLE, + }; + rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail); + return -1; + } + + // Create UE context + sctp_assoc_t curr_assoc_id = du->assoc_id; + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_create_ue_context(curr_assoc_id, UINT16_MAX, rrc, UINT64_MAX, UINT32_MAX); + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + + // allocate context for target + if (UE->ho_context != NULL) { + LOG_E(NR_RRC, "Ongoing handover for UE %d, cannot trigger new\n", UE->rrc_ue_id); + return -1; + } + UE->ho_context = alloc_ho_ctx(HO_CTX_TARGET); + + // Store IDs in UE context + UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; + UE->ue_guami = msg->guami; + UE->ho_context->target->ue_ho_prep_info = copy_byte_array(msg->ue_ho_prep_info); + // store the received UE Security Capabilities in the UE context + FREE_AND_ZERO_BYTE_ARRAY(UE->ue_cap_buffer); + UE->ue_cap_buffer = copy_byte_array(msg->ue_cap); + + /* store the received Security Context in the UE context + and take it into use as defined in TS 33.501 */ + set_UE_security_algos(rrc, UE, &msg->security_capabilities); + UE->nh_ncc = msg->security_context.next_hop_chain_count; + memcpy(UE->nh, msg->security_context.next_hop, SECURITY_KEY_LENGTH); + // Reset KgNB + memset(UE->kgnb, 0, SECURITY_KEY_LENGTH); + // Derive KgNB* + const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; + uint32_t ssb_arfcn = get_ssb_arfcn(du); + nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, UE->nh, UE->kgnb); + UE->as_security_active = true; + // Activate SRBs + activate_srb(UE, SRB1); + activate_srb(UE, SRB2); + nr_rrc_pdcp_config_security(UE, false); + + // Copy PDU Session Resource Setup item to RRC struct and do PDU Session Resource Setup procedure + pdusession_t to_setup = { + .nssai = msg->pduSessionResourceSetupList->nssai, + .pdu_session_type = msg->pduSessionResourceSetupList->pdu_session_type , + .pdusession_id = msg->pduSessionResourceSetupList->pdusession_id, + }; + cp_pdusession_transfer_to_pdusession(&to_setup, &msg->pduSessionResourceSetupList->pdusessionTransfer); + if (!trigger_bearer_setup(rrc, UE, msg->nb_of_pdusessions, &to_setup, msg->ue_ambr.br_dl)) { + LOG_E(NR_RRC, "Failed to establish PDU session: handover failed\n"); + ngap_handover_failure_t fail = { + .amf_ue_ngap_id = msg->amf_ue_ngap_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_HO_FAILURE_IN_TARGET_5GC_NGRAN_NODE_OR_TARGET_SYSTEM, + }; + rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail); + } + + return 0; +} + +void rrc_gNB_free_Handover_Request(ngap_handover_request_t *msg) +{ + free_byte_array(msg->ue_cap); + free_byte_array(msg->ue_ho_prep_info); + free(msg->mobility_restriction); +} + /* * Process the NG command NGAP_UE_CONTEXT_RELEASE_COMMAND, sent by AMF. * The gNB should remove all pdu session, NG context, and other context of the UE. diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.h b/openair2/RRC/NR/rrc_gNB_NGAP.h index 7c52843c0f..53e2b51f8c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.h +++ b/openair2/RRC/NR/rrc_gNB_NGAP.h @@ -96,4 +96,7 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc, void rrc_gNB_send_NGAP_HANDOVER_FAILURE(gNB_RRC_INST *rrc, ngap_handover_failure_t *msg); +int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, ngap_handover_request_t *msg); +void rrc_gNB_free_Handover_Request(ngap_handover_request_t *msg); + #endif diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 7b1324d6e5..c9d60422e8 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -57,6 +57,8 @@ nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type) static void free_ho_ctx(nr_handover_context_t *ho_ctx) { free(ho_ctx->source); + if (ho_ctx->target) + FREE_AND_ZERO_BYTE_ARRAY(ho_ctx->target->ue_ho_prep_info); free(ho_ctx->target); free(ho_ctx); } diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index 0bb5faf7fa..77b90ac3e0 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -63,6 +63,8 @@ typedef struct nr_ho_target_cu { uint32_t du_ue_id; /// new (target) RNTI (as for du_ue_id) rnti_t new_rnti; + /// Handover Preparation Buffer + byte_array_t ue_ho_prep_info; /// function pointer to announce handover request acknowledgment ho_req_ack_t ho_req_ack; /// function pointer to announce handover success diff --git a/openair3/NGAP/ngap_common.c b/openair3/NGAP/ngap_common.c index b51c8e80de..9e3e2e9d13 100644 --- a/openair3/NGAP/ngap_common.c +++ b/openair3/NGAP/ngap_common.c @@ -66,6 +66,43 @@ void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in) } } +ngap_cause_t decode_ngap_cause(const NGAP_Cause_t *in) +{ + ngap_cause_t out = {0}; + switch (in->present) { + case NGAP_Cause_PR_radioNetwork: + out.type = NGAP_CAUSE_RADIO_NETWORK; + out.value = in->choice.radioNetwork; + break; + + case NGAP_Cause_PR_transport: + out.type = NGAP_CAUSE_TRANSPORT; + out.value = in->choice.transport; + break; + + case NGAP_Cause_PR_nas: + out.type = NGAP_CAUSE_NAS; + out.value = in->choice.nas; + break; + + case NGAP_Cause_PR_protocol: + out.type = NGAP_CAUSE_PROTOCOL; + out.value = in->choice.protocol; + break; + + case NGAP_Cause_PR_misc: + out.type = NGAP_CAUSE_MISC; + out.value = in->choice.misc; + break; + + default: + out.type = NGAP_CAUSE_NOTHING; + NGAP_ERROR("Unknown failure cause %d\n", in->present); + break; + } + return out; +} + nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in) { nr_guami_t out = {0}; @@ -141,3 +178,96 @@ void encode_ngap_nr_cgi(NGAP_NR_CGI_t *out, const plmn_id_t *plmn, const uint32_ MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &out->pLMNIdentity); NR_CELL_ID_TO_BIT_STRING(cell_id, &out->nRCellIdentity); } + +pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQosParameters_t *params) +{ + pdusession_level_qos_parameter_t out = {0}; + // QFI + out.qfi = qfi; + AssertFatal(params != NULL, "QoS parameters are NULL\n"); + // QosCharacteristics + const NGAP_QosCharacteristics_t *qosChar = ¶ms->qosCharacteristics; + AssertFatal(qosChar != NULL, "QoS characteristics are NULL\n"); + if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { + AssertFatal(qosChar->choice.nonDynamic5QI != NULL, "nonDynamic5QI is NULL\n"); + out.fiveQI_type = NON_DYNAMIC; + out.fiveQI = qosChar->choice.nonDynamic5QI->fiveQI; + } else if (qosChar->present == NGAP_QosCharacteristics_PR_dynamic5QI) { + AssertFatal(qosChar->choice.dynamic5QI != NULL, "dynamic5QI is NULL\n"); + out.fiveQI_type = DYNAMIC; + out.fiveQI = *qosChar->choice.dynamic5QI->fiveQI; + } else { + AssertFatal(0, "Unsupported QoS Characteristics present value: %d\n", qosChar->present); + } + // Allocation and Retention Priority + const NGAP_AllocationAndRetentionPriority_t *arp = ¶ms->allocationAndRetentionPriority; + out.allocation_retention_priority.priority_level = arp->priorityLevelARP; + out.allocation_retention_priority.pre_emp_capability = arp->pre_emptionCapability; + out.allocation_retention_priority.pre_emp_vulnerability = arp->pre_emptionVulnerability; + + return out; +} + +static gtpu_tunnel_t decode_TNLInformation(const NGAP_GTPTunnel_t *gTPTunnel_p) +{ + gtpu_tunnel_t out = {0}; + // Transport layer address + memcpy(out.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); + out.addr.length = gTPTunnel_p->transportLayerAddress.size - gTPTunnel_p->transportLayerAddress.bits_unused; + // GTP tunnel endpoint ID + OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, out.teid); + return out; +} + +void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_STRING_t buf) +{ + void *decoded = NULL; + asn_codec_ctx_t ctx = {.max_stack_size = 100 * 1000}; + asn_dec_rval_t rval = aper_decode(&ctx, td, &decoded, buf.buf, buf.size, 0, 0); + if (rval.code != RC_OK) { + NGAP_ERROR("Decoding failed for %s\n", td->name); + return NULL; + } + return decoded; +} + +/** @brief Decode PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ +bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in) +{ + void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, in); + if (!decoded) { + LOG_E(NR_RRC, "Failed to decode PDUSessionResourceSetupRequestTransfer\n"); + return false; + } + + NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceSetupRequestTransfer_t *)decoded; + for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) { + NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i]; + switch (pdusessionTransfer_ies->id) { + // UL NG-U UP TNL Information (Mandatory) + case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: + out->n3_incoming = decode_TNLInformation(pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel); + break; + + // PDU Session Type (Mandatory) + case NGAP_ProtocolIE_ID_id_PDUSessionType: + out->pdu_session_type = pdusessionTransfer_ies->value.choice.PDUSessionType; + break; + + // QoS Flow Setup Request List (Mandatory) + case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: + out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.count; + for (int i = 0; i < out->nb_qos; i++) { + NGAP_QosFlowSetupRequestItem_t *item = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.array[i]; + out->qos[i] = fill_qos(item->qosFlowIdentifier, &item->qosFlowLevelQosParameters); + } + break; + + default: + LOG_D(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id); + } + } + ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer); + + return true; +} diff --git a/openair3/NGAP/ngap_common.h b/openair3/NGAP/ngap_common.h index 1e53d9dd1a..9afaf47c4b 100644 --- a/openair3/NGAP/ngap_common.h +++ b/openair3/NGAP/ngap_common.h @@ -83,6 +83,7 @@ typedef int (*ngap_message_decoded_callback)(sctp_assoc_t assoc_id, uint32_t str void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in); nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in); +ngap_cause_t decode_ngap_cause(const NGAP_Cause_t *in); ngap_ambr_t decode_ngap_UEAggregateMaximumBitRate(const NGAP_UEAggregateMaximumBitRate_t *in); nssai_t decode_ngap_nssai(const NGAP_S_NSSAI_t *in); ngap_security_capabilities_t decode_ngap_security_capabilities(const NGAP_UESecurityCapabilities_t *in); @@ -90,6 +91,8 @@ ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_Mobility void encode_ngap_target_id(NGAP_HandoverRequiredIEs_t *out, const target_ran_node_id_t *in); void encode_ngap_nr_cgi(NGAP_NR_CGI_t *out, const plmn_id_t *plmn, const uint32_t cell_id); pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQosParameters_t *params); +void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_STRING_t buf); +bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in); /** @}*/ diff --git a/openair3/NGAP/ngap_gNB_decoder.c b/openair3/NGAP/ngap_gNB_decoder.c index 58c70011cf..a56357b55a 100644 --- a/openair3/NGAP/ngap_gNB_decoder.c +++ b/openair3/NGAP/ngap_gNB_decoder.c @@ -94,6 +94,12 @@ static int ngap_gNB_decode_initiating_message(NGAP_NGAP_PDU_t *pdu) { NGAP_INFO("TODO ErrorIndication initiating message\n"); break; + case NGAP_ProcedureCode_id_HandoverResourceAllocation: + res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu); + free(res.buffer); + NGAP_INFO("Handover Resource Allocation initiating message\n"); + break; + default: NGAP_ERROR("Unknown procedure ID (%d) for initiating message\n", (int)pdu->choice.initiatingMessage->procedureCode); diff --git a/openair3/NGAP/ngap_gNB_encoder.c b/openair3/NGAP/ngap_gNB_encoder.c index a6e91ba9c8..056aea2fe6 100644 --- a/openair3/NGAP/ngap_gNB_encoder.c +++ b/openair3/NGAP/ngap_gNB_encoder.c @@ -77,7 +77,8 @@ static inline int ngap_gNB_encode_successfull_outcome(NGAP_NGAP_PDU_t *pdu, uint NGAP_ProcedureCode_id_UEContextRelease, NGAP_ProcedureCode_id_PDUSessionResourceSetup, NGAP_ProcedureCode_id_PDUSessionResourceModify, - NGAP_ProcedureCode_id_PDUSessionResourceRelease}; + NGAP_ProcedureCode_id_PDUSessionResourceRelease, + NGAP_ProcedureCode_id_HandoverResourceAllocation}; int i; for (i = 0; i < sizeofArray(tmp); i++) if (pdu->choice.successfulOutcome->procedureCode == tmp[i]) @@ -98,8 +99,17 @@ static inline int ngap_gNB_encode_unsuccessfull_outcome(NGAP_NGAP_PDU_t *pdu, ui { DevAssert(pdu != NULL); - if (pdu->choice.unsuccessfulOutcome->procedureCode != NGAP_ProcedureCode_id_InitialContextSetup) { - NGAP_DEBUG("Unknown procedure ID (%d) for unsuccessfull outcome message\n", (int)pdu->choice.unsuccessfulOutcome->procedureCode); + const NGAP_ProcedureCode_t id[] = {NGAP_ProcedureCode_id_InitialContextSetup, NGAP_ProcedureCode_id_HandoverResourceAllocation}; + + int i; + for (i = 0; i < sizeofArray(id); i++) { + if (pdu->choice.unsuccessfulOutcome->procedureCode == id[i]) { + break; + } + } + + if (i == sizeofArray(id)) { + NGAP_WARN("Unknown procedure ID (%ld) for successful outcome message\n", pdu->choice.successfulOutcome->procedureCode); return -1; } diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 6a92be9b79..485d37236a 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -44,7 +44,9 @@ #include "ngap_common.h" #include "ngap_gNB_decoder.h" #include "ngap_gNB_defs.h" +#include "ngap_gNB_nnsf.h" #include "ngap_gNB_management_procedures.h" +#include "ngap_gNB_mobility_management.h" #include "ngap_gNB_nas_procedures.h" #include "ngap_gNB_trace.h" #include "ngap_gNB_ue_context.h" @@ -693,97 +695,40 @@ static int ngap_gNB_handle_error_indication(sctp_assoc_t assoc_id, uint32_t stre return 0; } -static void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_STRING_t buf) +/** @brief Handler for NGAP Handover Request message (AMF -> target NG-RAN) + * Decode the NGAP message and transfer to RRC */ +static int ngap_gNB_handle_handover_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) { - void *decoded = NULL; - asn_codec_ctx_t ctx = {.max_stack_size = 100 * 1000}; - asn_dec_rval_t rval = aper_decode(&ctx, td, &decoded, buf.buf, buf.size, 0, 0); - if (rval.code != RC_OK) { - NGAP_ERROR("Decoding failed for %s\n", td->name); - return NULL; - } - return decoded; -} + DevAssert(pdu != NULL); -static pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQosParameters_t *params) -{ - pdusession_level_qos_parameter_t out = {0}; - // QFI - out.qfi = qfi; - AssertFatal(params != NULL, "QoS parameters are NULL\n"); - // QosCharacteristics - const NGAP_QosCharacteristics_t *qosChar = ¶ms->qosCharacteristics; - AssertFatal(qosChar != NULL, "QoS characteristics are NULL\n"); - if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { - AssertFatal(qosChar->choice.nonDynamic5QI != NULL, "nonDynamic5QI is NULL\n"); - out.fiveQI_type = NON_DYNAMIC; - out.fiveQI = qosChar->choice.nonDynamic5QI->fiveQI; - } else if (qosChar->present == NGAP_QosCharacteristics_PR_dynamic5QI) { - AssertFatal(qosChar->choice.dynamic5QI != NULL, "dynamic5QI is NULL\n"); - out.fiveQI_type = DYNAMIC; - out.fiveQI = *qosChar->choice.dynamic5QI->fiveQI; - } else { - AssertFatal(0, "Unsupported QoS Characteristics present value: %d\n", qosChar->present); - } - // Allocation and Retention Priority - const NGAP_AllocationAndRetentionPriority_t *arp = ¶ms->allocationAndRetentionPriority; - out.allocation_retention_priority.priority_level = arp->priorityLevelARP; - out.allocation_retention_priority.pre_emp_capability = arp->pre_emptionCapability; - out.allocation_retention_priority.pre_emp_vulnerability = arp->pre_emptionVulnerability; - - return out; -} - -static gtpu_tunnel_t decode_TNLInformation(const NGAP_GTPTunnel_t *gTPTunnel_p) -{ - gtpu_tunnel_t out = {0}; - // Transport layer address - memcpy(out.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); - out.addr.length = gTPTunnel_p->transportLayerAddress.size - gTPTunnel_p->transportLayerAddress.bits_unused; - // GTP tunnel endpoint ID - OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, out.teid); - return out; -} - -/** @brief Decode PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ -static bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in) -{ - void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, in); - if (!decoded) { - LOG_E(NR_RRC, "Failed to decode PDUSessionResourceSetupRequestTransfer\n"); - return false; + ngap_gNB_amf_data_t *amf_desc_p = ngap_gNB_get_AMF(NULL, assoc_id, 0); + if (amf_desc_p == NULL) { + NGAP_ERROR("Received Handover Request for non existing AMF context\n"); + return -1; } - NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceSetupRequestTransfer_t *)decoded; - for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) { - NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i]; - switch (pdusessionTransfer_ies->id) { - // UL NG-U UP TNL Information (Mandatory) - case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: - out->n3_incoming = decode_TNLInformation(pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel); - break; + MessageDef *message_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_HANDOVER_REQUEST); + ngap_handover_request_t *msg = &NGAP_HANDOVER_REQUEST(message_p); + memset(msg, 0, sizeof(*msg)); - // PDU Session Type (Mandatory) - case NGAP_ProtocolIE_ID_id_PDUSessionType: - out->pdu_session_type = pdusessionTransfer_ies->value.choice.PDUSessionType; - break; - - // QoS Flow Setup Request List (Mandatory) - case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: - out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.count; - for (int i = 0; i < out->nb_qos; i++) { - NGAP_QosFlowSetupRequestItem_t *item = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.array[i]; - out->qos[i] = fill_qos(item->qosFlowIdentifier, &item->qosFlowLevelQosParameters); - } - break; - - default: - LOG_D(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id); - } + if (decode_ng_handover_request(msg, pdu) < 0) { + NGAP_ERROR("Failed to decode NG Handover Request\n"); + ngap_handover_failure_t fail = { + .amf_ue_ngap_id = msg->amf_ue_ngap_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_HO_FAILURE_IN_TARGET_5GC_NGRAN_NODE_OR_TARGET_SYSTEM, + }; + NGAP_INFO("Send NG Handover Failure message (amf_ue_ngap_id %ld) with cause %d \n ", fail.amf_ue_ngap_id, fail.cause.value); + MessageDef *msg_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_HANDOVER_FAILURE); + NGAP_HANDOVER_FAILURE(msg_p) = fail; + itti_send_msg_to_task(TASK_NGAP, amf_desc_p->ngap_gNB_instance->instance, msg_p); + return -1; } - ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer); - return true; + NGAP_INFO("Received NG Handover Request from AMF %s (ID=%lu)\n", amf_desc_p->amf_name, msg->amf_ue_ngap_id); + itti_send_msg_to_task(TASK_RRC_GNB, amf_desc_p->ngap_gNB_instance->instance, message_p); + + return 0; } static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) @@ -1394,7 +1339,7 @@ const ngap_message_decoded_callback ngap_messages_callback[][3] = { {0, 0, 0}, /* HandoverCancel */ {0, 0, 0}, /* HandoverNotification */ {0, 0, 0}, /* HandoverPreparation */ - {0, 0, 0}, /* HandoverResourceAllocation */ + {ngap_gNB_handle_handover_request, 0, 0}, /* HandoverResourceAllocation */ {ngap_gNB_handle_initial_context_request, 0, 0}, /* InitialContextSetup */ {0, 0, 0}, /* InitialUEMessage */ {0, 0, 0}, /* LocationReportingControl */ diff --git a/openair3/NGAP/ngap_gNB_mobility_management.c b/openair3/NGAP/ngap_gNB_mobility_management.c index 9d84fccd09..2aa0056dfe 100644 --- a/openair3/NGAP/ngap_gNB_mobility_management.c +++ b/openair3/NGAP/ngap_gNB_mobility_management.c @@ -30,6 +30,7 @@ #include "ngap_gNB_management_procedures.h" #include "ngap_gNB_encoder.h" #include "ngap_gNB_itti_messaging.h" +#include "conversions.h" /** @brief UE Mobility Management: encode Handover Required * (9.2.3.1 of 3GPP TS 38.413) NG-RAN node → AMF */ @@ -224,3 +225,160 @@ NGAP_NGAP_PDU_t *encode_ng_handover_failure(const ngap_handover_failure_t *msg) return pdu; } + +static void free_ng_handover_request(ngap_handover_request_t *msg) +{ + free_byte_array(msg->ue_ho_prep_info); + free_byte_array(msg->ue_cap); + free(msg->mobility_restriction); +} + +int decode_ng_handover_request(ngap_handover_request_t *out, const NGAP_NGAP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + NGAP_HandoverRequest_t *container = &pdu->choice.initiatingMessage->value.choice.HandoverRequest; + NGAP_HandoverRequestIEs_t *ie; + + // Handover Type (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_HandoverType, true); + out->ho_type = ie->value.choice.HandoverType; + if (out->ho_type != HANDOVER_TYPE_INTRA5GS) { + NGAP_ERROR("Only Intra5GS Handover is supported at the moment!\n"); + return -1; + } + + // AMF UE NGAP ID (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID, true); + asn_INTEGER2ulong(&(ie->value.choice.AMF_UE_NGAP_ID), &out->amf_ue_ngap_id); + + // GUAMI (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_GUAMI, true); + out->guami = decode_ngap_guami(&ie->value.choice.GUAMI); + + // UE Aggregate Maximum Bit Rate (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, true); + out->ue_ambr = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); + + // Allowed NSSAI (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AllowedNSSAI, true); + NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); + out->nb_allowed_nssais = ie->value.choice.AllowedNSSAI.list.count; + for (int i = 0; i < out->nb_allowed_nssais; i++) { + out->allowed_nssai[i] = decode_ngap_nssai(&ie->value.choice.AllowedNSSAI.list.array[i]->s_NSSAI); + } + + // UE Security Capabilities (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UESecurityCapabilities, true); + out->security_capabilities = decode_ngap_security_capabilities(&ie->value.choice.UESecurityCapabilities); + + // Security Context (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_SecurityContext, true); + NGAP_SecurityContext_t *sc = &ie->value.choice.SecurityContext; + memcpy(&out->security_context.next_hop, sc->nextHopNH.buf, sc->nextHopNH.size); + out->security_context.next_hop_chain_count = sc->nextHopChainingCount; + + // Mobility Restriction List (O) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_MobilityRestrictionList, false); + if (ie != NULL) { + out->mobility_restriction = malloc_or_fail(sizeof(*out->mobility_restriction)); + *out->mobility_restriction = decode_ngap_mobility_restriction(&ie->value.choice.MobilityRestrictionList); + } + + // Cause (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_Cause, true); + out->cause = decode_ngap_cause(&ie->value.choice.Cause); + + // Source to Target Transparent Container + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_SourceToTarget_TransparentContainer, + true); + NGAP_SourceToTarget_TransparentContainer_t *choice = &ie->value.choice.SourceToTarget_TransparentContainer; + byte_array_t sourceToTargetTransparentContainer = create_byte_array(choice->size, choice->buf); + NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer_t *source2target = NULL; + asn_dec_rval_t dec_rval = aper_decode_complete(NULL, + &asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, + (void **)&source2target, + sourceToTargetTransparentContainer.buf, + sourceToTargetTransparentContainer.len); + + free_byte_array(sourceToTargetTransparentContainer); + if (dec_rval.code != RC_OK) { + free_ng_handover_request(out); + NGAP_ERROR("Failed to decode sourceToTargetTransparentContainer\n"); + return -1; + } + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, source2target); + + // Extract Cell Identity + BIT_STRING_TO_NR_CELL_IDENTITY(&source2target->targetCell_ID.choice.nR_CGI->nRCellIdentity, out->nr_cell_id); + + // Handover Preparation Information: store and decode + out->ue_ho_prep_info = create_byte_array(source2target->rRCContainer.size, source2target->rRCContainer.buf); + NR_HandoverPreparationInformation_t *hoPrepInformation = NULL; + asn_dec_rval_t hoPrep_dec_rval = uper_decode_complete(NULL, + &asn_DEF_NR_HandoverPreparationInformation, + (void **)&hoPrepInformation, + source2target->rRCContainer.buf, + source2target->rRCContainer.size); + AssertFatal(hoPrep_dec_rval.code == RC_OK && hoPrep_dec_rval.consumed > 0, "Handover Prep Info decode error\n"); + if (hoPrep_dec_rval.code != RC_OK && !hoPrep_dec_rval.consumed) { + NGAP_ERROR("Failed to decode HandoverPreparationInformation, abort Handover Request decoding\n"); + free_ng_handover_request(out); + ASN_STRUCT_FREE(asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, source2target); + return -1; + } + + ASN_STRUCT_FREE(asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, source2target); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_HandoverPreparationInformation, hoPrepInformation); + + // Decode UE capabilities and store + NR_HandoverPreparationInformation_IEs_t *hpi = + hoPrepInformation->criticalExtensions.choice.c1->choice.handoverPreparationInformation; + const NR_UE_CapabilityRAT_ContainerList_t *ue_CapabilityRAT_ContainerList = &hpi->ue_CapabilityRAT_List; + out->ue_cap.len = uper_encode_to_new_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, + NULL, + ue_CapabilityRAT_ContainerList, + (void **)&out->ue_cap.buf); + + ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hoPrepInformation); + + if (out->ue_cap.len <= 0) { + free_ng_handover_request(out); + NGAP_ERROR("could not encode UE-CapabilityRAT-ContainerList\n"); + return -1; + } + + // PDU Session Resource Setup List (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListHOReq, + true); + out->nb_of_pdusessions = ie->value.choice.PDUSessionResourceSetupListHOReq.list.count; + for (int pduSesIdx = 0; pduSesIdx < out->nb_of_pdusessions; ++pduSesIdx) { + NGAP_PDUSessionResourceSetupItemHOReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListHOReq.list.array[pduSesIdx]; + // PDU Session ID (M) + ho_request_pdusession_t *setup = &out->pduSessionResourceSetupList[pduSesIdx]; + setup->pdusession_id = item_p->pDUSessionID; + setup->pdu_session_type = PDUSessionType_ipv4; + // S-NSSAI (M) + setup->nssai = decode_ngap_nssai(&item_p->s_NSSAI); + // Handover Request Transfer (M) + bool ret = decodePDUSessionResourceSetup(&setup->pdusessionTransfer, item_p->handoverRequestTransfer); + if (!ret) { + free_ng_handover_request(out); + NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Initial Context Setup Request\n"); + return -1; + } + } + + + + return 0; +} diff --git a/openair3/NGAP/ngap_gNB_mobility_management.h b/openair3/NGAP/ngap_gNB_mobility_management.h index 6f5cdde742..66e85e644e 100644 --- a/openair3/NGAP/ngap_gNB_mobility_management.h +++ b/openair3/NGAP/ngap_gNB_mobility_management.h @@ -28,5 +28,6 @@ NGAP_NGAP_PDU_t *encode_ng_handover_required(const ngap_handover_required_t *msg); NGAP_NGAP_PDU_t *encode_ng_handover_failure(const ngap_handover_failure_t *msg); +int decode_ng_handover_request(ngap_handover_request_t *out, const NGAP_NGAP_PDU_t *pdu); #endif /* NGAP_GNB_MOBILITY_MANAGEMENT_H_ */ diff --git a/openair3/NGAP/ngap_msg_includes.h b/openair3/NGAP/ngap_msg_includes.h index cf7d0d9f49..a80df29401 100644 --- a/openair3/NGAP/ngap_msg_includes.h +++ b/openair3/NGAP/ngap_msg_includes.h @@ -86,5 +86,20 @@ #include "NGAP_PDUSessionResourceInformationList.h" #include "NGAP_HandoverRequiredTransfer.h" #include "NGAP_SourceNGRANNode-ToTargetNGRANNode-TransparentContainer.h" +#include "NGAP_PDUSessionResourceSetupItemHOReq.h" +#include "NGAP_HandoverCommand.h" +#include "NGAP_HandoverCommandTransfer.h" +#include "NGAP_TargetNGRANNode-ToSourceNGRANNode-TransparentContainer.h" +#include "NGAP_TargetToSource-TransparentContainer.h" +#include "NGAP_UEHistoryInformation.h" +#include "NGAP_Cause.h" +#include "NGAP_PDUSessionResourceHandoverItem.h" +#include "NGAP_SourceToTarget-TransparentContainer.h" +#include "NGAP_HandoverRequest.h" +#include "NGAP_PDUSessionResourceAdmittedList.h" +#include "NGAP_PDUSessionResourceAdmittedItem.h" +#include "NGAP_HandoverRequestAcknowledgeTransfer.h" +#include "NGAP_QosFlowItemWithDataForwarding.h" +#include "NR_HandoverPreparationInformation.h" #endif // NGAP_MSG_INCLUDES_H