diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index e179b5f4e8..e97dc1a000 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1350,20 +1350,33 @@ void fill_removal_lists_from_source_measConfig(NR_MeasConfig_t *currentMC, byte_ ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration, rrcReconf); } -int doRRCReconfiguration_from_HandoverCommand(byte_array_t *ba, const byte_array_t handoverCommand) +byte_array_t doRRCReconfiguration_from_HandoverCommand(const byte_array_t handoverCommand) { + DevAssert(handoverCommand.buf); + DevAssert(handoverCommand.len > 0); + byte_array_t msg = {.buf = NULL, .len = 0}; + // Decode Handover Command NR_HandoverCommand_t *hoCommand = NULL; asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_HandoverCommand, (void **)&hoCommand, handoverCommand.buf, handoverCommand.len); - if (dec_rval.code != RC_OK && dec_rval.consumed == 0) { - LOG_E(NR_RRC, "Can not decode Handover Command!\n"); - return -1; + if (dec_rval.code != RC_OK || !hoCommand) { + LOG_E(NR_RRC, "Failed to decode Handover Command (dec_rval.code=%d)!\n", dec_rval.code); + return msg; + } + + // Validate HandoverCommand structure + if (hoCommand->criticalExtensions.present != NR_HandoverCommand__criticalExtensions_PR_c1 + || !hoCommand->criticalExtensions.choice.c1 + || hoCommand->criticalExtensions.choice.c1->present != NR_HandoverCommand__criticalExtensions__c1_PR_handoverCommand + || !hoCommand->criticalExtensions.choice.c1->choice.handoverCommand) { + LOG_E(NR_RRC, "Invalid HandoverCommand in criticalExtensions.choice.c1->choice.handoverCommand\n"); + ASN_STRUCT_FREE(asn_DEF_NR_HandoverCommand, hoCommand); + return msg; } // Prepare DL DCCH message for RRCReconfiguration NR_DL_DCCH_Message_t dl_dcch_msg = {0}; - asn_enc_rval_t enc_rval; dl_dcch_msg.message.present = NR_DL_DCCH_MessageType_PR_c1; asn1cCalloc(dl_dcch_msg.message.choice.c1, c1); c1->present = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; @@ -1371,18 +1384,37 @@ int doRRCReconfiguration_from_HandoverCommand(byte_array_t *ba, const byte_array // Decode RRCReconfiguration from handoverCommandMessage OCTET_STRING_t *ho = &hoCommand->criticalExtensions.choice.c1->choice.handoverCommand->handoverCommandMessage; - uper_decode_complete(NULL, &asn_DEF_NR_RRCReconfiguration, (void **)&rrcReconf, ho->buf, ho->size); + if (!ho->buf || ho->size == 0) { + LOG_E(NR_RRC, "Invalid handoverCommandMessage OCTET_STRING (buf=%p, size=%zu)!\n", ho->buf, ho->size); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); + ASN_STRUCT_FREE(asn_DEF_NR_HandoverCommand, hoCommand); + return msg; + } + asn_dec_rval_t rrc_dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_RRCReconfiguration, (void **)&rrcReconf, ho->buf, ho->size); + if (rrc_dec_rval.code != RC_OK || !rrcReconf) { + LOG_E(NR_RRC, "Failed to decode RRCReconfiguration from Handover Command!\n"); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); + ASN_STRUCT_FREE(asn_DEF_NR_HandoverCommand, hoCommand); + return msg; + } if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); - // Encode DL DCCH message in buffer - enc_rval = uper_encode_to_buffer(&asn_DEF_NR_DL_DCCH_Message, NULL, &dl_dcch_msg, ba->buf, ba->len); - AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + // Encode DL DCCH message to new buffer + int val = uper_encode_to_new_buffer(&asn_DEF_NR_DL_DCCH_Message, NULL, &dl_dcch_msg, (void **)&msg.buf); + if (val <= 0) { + LOG_E(NR_RRC, "Failed to encode RRCReconfiguration from Handover Command!\n"); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); + ASN_STRUCT_FREE(asn_DEF_NR_HandoverCommand, hoCommand); + return msg; + } + msg.len = val; + LOG_D(NR_RRC, "RRCReconfiguration from HandoverCommand: Encoded (%ld bytes)\n", msg.len); ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); ASN_STRUCT_FREE(asn_DEF_NR_HandoverCommand, hoCommand); - return ((enc_rval.encoded + 7) / 8); + return msg; } byte_array_t get_HandoverCommandMessage(nr_rrc_reconfig_param_t *params) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 2e09397e60..a763f854bd 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -175,7 +175,7 @@ int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi); byte_array_t get_HandoverPreparationInformation(nr_rrc_reconfig_param_t *params, int scell_pci); byte_array_t get_HandoverCommandMessage(nr_rrc_reconfig_param_t *params); void fill_removal_lists_from_source_measConfig(NR_MeasConfig_t *measConfig, byte_array_t prep_info); -int doRRCReconfiguration_from_HandoverCommand(byte_array_t *ba, byte_array_t handoverCommand); +byte_array_t doRRCReconfiguration_from_HandoverCommand(byte_array_t handoverCommand); struct NR_UE_NR_Capability *get_ue_nr_capability(int rnti, uint8_t *buf, uint32_t len); NR_UE_NR_Capability_t *decode_nr_ue_capability(int rnti, const NR_UE_CapabilityRAT_ContainerList_t *clist); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 19bab47b67..bf8a797a49 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1276,13 +1276,20 @@ void rrc_gNB_process_HandoverCommand(gNB_RRC_INST *rrc, const ngap_handover_comm } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - uint8_t buffer[NR_RRC_BUF_SIZE]; - byte_array_t ba = {.buf = buffer, .len = sizeof(buffer)}; - int enc = doRRCReconfiguration_from_HandoverCommand(&ba, msg->handoverCommand); - DevAssert(enc > 0); + byte_array_t buffer = doRRCReconfiguration_from_HandoverCommand(msg->handoverCommand); + if (!buffer.buf || buffer.len == 0) { + LOG_E(NR_RRC, "Failed to decode/encode RRCReconfiguration from HandoverCommand\n"); + // Notify AMF that handover was cancelled + DevAssert(UE->ho_context); + DevAssert(UE->ho_context->source); + DevAssert(UE->ho_context->source->ho_cancel); + UE->ho_context->source->ho_cancel(rrc, UE); + return; + } - rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, buffer, enc); + rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, buffer.buf, buffer.len); LOG_A(NR_RRC, "Send reconfiguration (HO Command) to UE %u/RNTI %04x\n", UE->rrc_ue_id, UE->rnti); + free_byte_array(buffer); } void rrc_gNB_free_Handover_Command(ngap_handover_command_t *msg) diff --git a/openair3/NGAP/ngap_gNB_decoder.c b/openair3/NGAP/ngap_gNB_decoder.c index 481cccf876..43110e9037 100644 --- a/openair3/NGAP/ngap_gNB_decoder.c +++ b/openair3/NGAP/ngap_gNB_decoder.c @@ -76,6 +76,12 @@ static int ngap_gNB_decode_initiating_message(NGAP_NGAP_PDU_t *pdu) { NGAP_INFO("Handover Preparation initiating message\n"); break; + case NGAP_ProcedureCode_id_HandoverCancel: + res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu); + free(res.buffer); + NGAP_INFO("Handover Cancel initiating message\n"); + break; + case NGAP_ProcedureCode_id_PDUSessionResourceModify: res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu); free(res.buffer); diff --git a/openair3/NGAP/ngap_gNB_encoder.c b/openair3/NGAP/ngap_gNB_encoder.c index be3945c2f0..ff318ed184 100644 --- a/openair3/NGAP/ngap_gNB_encoder.c +++ b/openair3/NGAP/ngap_gNB_encoder.c @@ -55,6 +55,7 @@ static inline int ngap_gNB_encode_initiating(NGAP_NGAP_PDU_t *pdu, uint8_t **buf NGAP_ProcedureCode_id_PDUSessionResourceModifyIndication, NGAP_ProcedureCode_id_UplinkRANStatusTransfer, NGAP_ProcedureCode_id_HandoverPreparation, + NGAP_ProcedureCode_id_HandoverCancel, NGAP_ProcedureCode_id_HandoverNotification}; int i; for (i = 0; i < sizeofArray(tmp); i++)