RRC: improve error handling in doRRCReconfiguration_from_HandoverCommand
- Refactor function to return byte_array_t instead of taking buffer
parameter for consistency with other encoding functions
(do_RRCReconfiguration, do_HO_RRCReconfiguration) and to prevent buffer
overflow issues since the memory size is determined automatically
- Add comprehensive error checking:
* Input validation
* Check return of each decode (HandoverCommand
and RRCReconfiguration)
* Validate HandoverCommand structure before access
* Validate OCTET_STRING before decoding RRCReconfiguration
* Error handling and cleanup for enc/dec failures
- Update caller in rrc_gNB_NGAP.c
* use new signature
* free buffer
* send HO Cancel on decoding failure (source gNB)
Closes #1043
This commit is contained in:
@@ -1318,20 +1318,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;
|
||||
@@ -1339,18 +1352,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)
|
||||
|
||||
@@ -171,7 +171,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);
|
||||
|
||||
@@ -1275,13 +1275,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)
|
||||
|
||||
Reference in New Issue
Block a user