diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 6a7ee77b52..6ab4ffc2fc 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -143,6 +143,7 @@ #include "common/ran_context.h" #include "conversions.h" +#include "ds/byte_array.h" //#define XER_PRINT @@ -499,112 +500,108 @@ int do_NR_RRCRelease(uint8_t *buffer, size_t buffer_size, uint8_t Transaction_id return((enc_rval.encoded+7)/8); } -//------------------------------------------------------------------------------ -int do_RRCReconfiguration(int rrc_ue_id, - uint8_t *buffer, - size_t buffer_size, - uint8_t Transaction_id, - NR_SRB_ToAddModList_t *SRB_configList, - NR_DRB_ToAddModList_t *DRB_configList, - NR_DRB_ToReleaseList_t *DRB_releaseList, - NR_SecurityConfig_t *security_config, - NR_MeasConfig_t *meas_config, - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList, - NR_CellGroupConfig_t *cellGroupConfig) -//------------------------------------------------------------------------------ +/** @brief Build RRCReconfiguration message (3GPP TS 38.331) */ +static NR_RRCReconfiguration_IEs_t *build_RRCReconfiguration_IEs(const nr_rrc_reconfig_param_t *params) { - NR_DL_DCCH_Message_t dl_dcch_msg={0}; - asn_enc_rval_t enc_rval; - NR_RRCReconfiguration_IEs_t *ie; + NR_RRCReconfiguration_IEs_t *ie = calloc_or_fail(1, sizeof(*ie)); - dl_dcch_msg.message.present = NR_DL_DCCH_MessageType_PR_c1; - asn1cCalloc(dl_dcch_msg.message.choice.c1, c1);// = CALLOC(1, sizeof(struct NR_DL_DCCH_MessageType__c1)); - c1->present = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; + // radioBearerConfig + if ((params->srb_config_list && params->srb_config_list->list.size) + || (params->drb_config_list && params->drb_config_list->list.size)) { + ie->radioBearerConfig = calloc_or_fail(1, sizeof(*ie->radioBearerConfig)); + struct NR_RadioBearerConfig *cfg = ie->radioBearerConfig; + cfg->srb_ToAddModList = params->srb_config_list; + cfg->drb_ToAddModList = params->drb_config_list; + cfg->securityConfig = params->security_config; + cfg->srb3_ToRelease = NULL; + cfg->drb_ToReleaseList = params->drb_release_list; + } - asn1cCalloc(c1->choice.rrcReconfiguration, rrcReconf); // = calloc(1, sizeof(NR_RRCReconfiguration_t)); - rrcReconf->rrc_TransactionIdentifier = Transaction_id; - rrcReconf->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration; + /* measConfig */ + ie->measConfig = params->meas_config; - /******************** Radio Bearer Config ********************/ - /* Configure Security */ - // security_config = CALLOC(1, sizeof(NR_SecurityConfig_t)); - // security_config->securityAlgorithmConfig = CALLOC(1, sizeof(*ie->radioBearerConfig->securityConfig->securityAlgorithmConfig)); - // security_config->securityAlgorithmConfig->cipheringAlgorithm = NR_CipheringAlgorithm_nea0; - // security_config->securityAlgorithmConfig->integrityProtAlgorithm = NULL; - // security_config->keyToUse = CALLOC(1, sizeof(*ie->radioBearerConfig->securityConfig->keyToUse)); - // *security_config->keyToUse = NR_SecurityConfig__keyToUse_master; + /* nonCriticalExtension, RRCReconfiguration-v1530-IEs */ + if (params->cell_group_config || params->num_nas_msg) { + // Allocate memory for extension IE + ie->nonCriticalExtension = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension)); + } - ie = calloc(1, sizeof(NR_RRCReconfiguration_IEs_t)); - if ((SRB_configList && SRB_configList->list.size) || - (DRB_configList && DRB_configList->list.size)) { - ie->radioBearerConfig = calloc(1, sizeof(NR_RadioBearerConfig_t)); - ie->radioBearerConfig->srb_ToAddModList = SRB_configList; - ie->radioBearerConfig->drb_ToAddModList = DRB_configList; - ie->radioBearerConfig->securityConfig = security_config; - ie->radioBearerConfig->srb3_ToRelease = NULL; - ie->radioBearerConfig->drb_ToReleaseList = DRB_releaseList; - } - - /******************** Meas Config ********************/ - // measConfig - ie->measConfig = meas_config; - // lateNonCriticalExtension - ie->lateNonCriticalExtension = NULL; - // nonCriticalExtension - - if (cellGroupConfig || dedicatedNAS_MessageList) { - ie->nonCriticalExtension = calloc(1, sizeof(NR_RRCReconfiguration_v1530_IEs_t)); - if (dedicatedNAS_MessageList) - ie->nonCriticalExtension->dedicatedNAS_MessageList = dedicatedNAS_MessageList; - } - - if (cellGroupConfig != NULL) { - uint8_t *buf = NULL; - ssize_t len = uper_encode_to_new_buffer(&asn_DEF_NR_CellGroupConfig, NULL, cellGroupConfig, (void **)&buf); - AssertFatal(len > 0, "ASN1 message encoding failed (%lu)!\n", len); - if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); + // Configure Cell Group Config + if (ie->nonCriticalExtension) { + if (params->num_nas_msg) { + asn1cCalloc(ie->nonCriticalExtension->dedicatedNAS_MessageList, list); + /* dedicatedNAS-MessageList: The field is absent in case of reconfiguration with sync + otherwise it is optionally present */ + for (int i = 0; i < params->num_nas_msg; i++) { + asn1cSequenceAdd(list->list, NR_DedicatedNAS_Message_t, msg); + OCTET_STRING_fromBuf(msg, (char *)params->dedicated_NAS_msg_list[i].buf, params->dedicated_NAS_msg_list[i].len); } - ie->nonCriticalExtension->masterCellGroup = calloc(1,sizeof(OCTET_STRING_t)); - ie->nonCriticalExtension->masterCellGroup->buf = buf; - ie->nonCriticalExtension->masterCellGroup->size = len; } - dl_dcch_msg.message.choice.c1->choice.rrcReconfiguration->criticalExtensions.choice.rrcReconfiguration = ie; - - if (LOG_DEBUGFLAG(DEBUG_ASN1)) { - xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); + /* masterCellGroup */ + if (params->cell_group_config) { + // Encode in extension IE (Master cell group) + uint8_t *buf = NULL; + ssize_t len = uper_encode_to_new_buffer(&asn_DEF_NR_CellGroupConfig, NULL, params->cell_group_config, (void **)&buf); + AssertFatal(len > 0, "ASN1 message encoding failed (%lu)!\n", len); + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)params->cell_group_config); + } + ie->nonCriticalExtension->masterCellGroup = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension->masterCellGroup)); + *ie->nonCriticalExtension->masterCellGroup = (OCTET_STRING_t){.buf = buf, .size = len}; } - enc_rval = uper_encode_to_buffer(&asn_DEF_NR_DL_DCCH_Message, - NULL, - (void *)&dl_dcch_msg, - buffer, - buffer_size); - - AssertFatal(enc_rval.encoded >0, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - - // don't free what we did not allocate, so set fields with pointers to NULL - // if memory comes from outside - ie->measConfig = NULL; - if (ie->radioBearerConfig) { - ie->radioBearerConfig->srb_ToAddModList = NULL; - ie->radioBearerConfig->drb_ToAddModList = NULL; - ie->radioBearerConfig->securityConfig = NULL; - ie->radioBearerConfig->srb3_ToRelease = NULL; - ie->radioBearerConfig->drb_ToReleaseList = NULL; + /* masterKeyUpdate */ + if (params->masterKeyUpdate) { + ie->nonCriticalExtension->masterKeyUpdate = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension->masterKeyUpdate)); + ie->nonCriticalExtension->masterKeyUpdate->keySetChangeIndicator = false; + ie->nonCriticalExtension->masterKeyUpdate->nextHopChainingCount = params->nextHopChainingCount; } - if (ie->nonCriticalExtension) - ie->nonCriticalExtension->dedicatedNAS_MessageList = NULL; + } + + return ie; +} + +byte_array_t do_RRCReconfiguration(const nr_rrc_reconfig_param_t *params) +{ + byte_array_t msg = {.buf = NULL, .len = 0}; + NR_RRCReconfiguration_IEs_t *ie = build_RRCReconfiguration_IEs(params); + + NR_DL_DCCH_Message_t dl_dcch_msg = {0}; + 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; + asn1cCalloc(c1->choice.rrcReconfiguration, rrcReconf); + rrcReconf->rrc_TransactionIdentifier = params->transaction_id; + rrcReconf->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration; + rrcReconf->criticalExtensions.choice.rrcReconfiguration = ie; + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); + } + + 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 DL-DCCH message\n"); ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); - LOG_D(NR_RRC, - "RRCReconfiguration for UE %d: Encoded %zd bits (%zd bytes)\n", - rrc_ue_id, - enc_rval.encoded, - (enc_rval.encoded + 7) / 8); + return msg; + } + msg.len = val; + LOG_D(NR_RRC, "RRCReconfiguration: Encoded (%ld bytes)\n", msg.len); - return((enc_rval.encoded+7)/8); + // Do not free what is not allocated in this context + ie->measConfig = NULL; + if (ie->radioBearerConfig) { + ie->radioBearerConfig->securityConfig = NULL; + ie->radioBearerConfig->drb_ToReleaseList = NULL; + ie->radioBearerConfig->srb_ToAddModList = NULL; + ie->radioBearerConfig->drb_ToAddModList = NULL; + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); + + return msg; } int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv, uint64_t fiveG_S_TMSI) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index afc9226b17..83be12d87b 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -51,10 +51,24 @@ #include "NR_SRB-ToAddModList.h" #include "NR_SecurityConfig.h" #include "ds/seq_arr.h" +#include "ds/byte_array.h" #include "rrc_messages_types.h" -struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList; struct asn_TYPE_descriptor_s; +typedef struct { + uint8_t transaction_id; + NR_SRB_ToAddModList_t *srb_config_list; + NR_DRB_ToAddModList_t *drb_config_list; + NR_DRB_ToReleaseList_t *drb_release_list; + NR_SecurityConfig_t *security_config; + NR_MeasConfig_t *meas_config; + byte_array_t dedicated_NAS_msg_list[MAX_DRBS_PER_UE]; + int num_nas_msg; + NR_CellGroupConfig_t *cell_group_config; + bool masterKeyUpdate; + int nextHopChainingCount; +} nr_rrc_reconfig_param_t; + /* * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) * output into the chosen string buffer. @@ -91,17 +105,7 @@ int do_NR_SA_UECapabilityEnquiry(uint8_t *const buffer, const uint8_t Transactio int do_NR_RRCRelease(uint8_t *buffer, size_t buffer_size, uint8_t Transaction_id); -int do_RRCReconfiguration(int rrc_ue_id, - uint8_t *buffer, - size_t buffer_size, - uint8_t Transaction_id, - NR_SRB_ToAddModList_t *SRB_configList, - NR_DRB_ToAddModList_t *DRB_configList, - NR_DRB_ToReleaseList_t *DRB_releaseList, - NR_SecurityConfig_t *security_config, - NR_MeasConfig_t *meas_config, - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList, - NR_CellGroupConfig_t *cellGroupConfig); +byte_array_t do_RRCReconfiguration(const nr_rrc_reconfig_param_t *params); int do_RRCSetupComplete(uint8_t *buffer, size_t buffer_size, diff --git a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp index 347c35d3ea..1f92c5aae5 100644 --- a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp +++ b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp @@ -20,14 +20,22 @@ */ #include +#ifdef __cplusplus extern "C" { +#endif #include "openair2/RRC/NR/MESSAGES/asn1_msg.h" #include "common/ran_context.h" #include #include "common/utils/assertions.h" #include "common/utils/LOG/log.h" +#include "NR_DRB-ToAddMod.h" +#include "NR_DRB-ToAddModList.h" +#include "NR_SRB-ToAddModList.h" +#include "ds/byte_array.h" RAN_CONTEXT_t RC; +#ifdef __cplusplus } +#endif TEST(nr_asn1, rrc_reject) { @@ -77,6 +85,77 @@ TEST(nr_asn1, paging) EXPECT_GT(do_NR_Paging(0, buf, 0), 0); } +void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) +{ + ASN_STRUCT_FREE(asn_DEF_NR_MeasConfig, params.meas_config); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config); + for (int i = 0; i < params.num_nas_msg; i++) + FREE_AND_ZERO_BYTE_ARRAY(params.dedicated_NAS_msg_list[i]); +} + +TEST(nr_asn1, rrc_reconfiguration) +{ + // SRB Configuration + NR_SRB_ToAddModList_t *srb_config_list = (NR_SRB_ToAddModList_t *)calloc_or_fail(1, sizeof(*srb_config_list)); + for (int i = 0; i < 4; i++) { + if (i == 1 || i == 2) { + NR_SRB_ToAddMod_t *srb = (NR_SRB_ToAddMod_t *)calloc_or_fail(1, sizeof(*srb)); + ASN_SEQUENCE_ADD(&srb_config_list->list, srb); + srb->srb_Identity = i; + if (i == 1 || i == 2) { + srb->reestablishPDCP = (long *)calloc_or_fail(1, sizeof(*srb->reestablishPDCP)); + *srb->reestablishPDCP = 0; + } + } + } + + // DRB Configuration + NR_DRB_ToAddModList_t *drb_config_list = (NR_DRB_ToAddModList_t *)calloc_or_fail(1, sizeof(*drb_config_list)); + for (int i = 0; i < 32; i++) { + if (i == 1 || i == 2) { + NR_DRB_ToAddMod_t *drb = (NR_DRB_ToAddMod_t *)calloc_or_fail(1, sizeof(*drb)); + ASN_SEQUENCE_ADD(&drb_config_list->list, drb); + drb->drb_Identity = i; + drb->reestablishPDCP = (long *)calloc_or_fail(1, sizeof(*drb->reestablishPDCP)); + *drb->reestablishPDCP = 0; + } + } + + // nr_rrc_reconfig_param_t setup + nr_rrc_reconfig_param_t params = {}; + params.srb_config_list = srb_config_list; + params.drb_config_list = drb_config_list; + params.num_nas_msg = 2; + params.masterKeyUpdate = false; + params.nextHopChainingCount = 1; + + byte_array_t nas_pdu_1; + nas_pdu_1.buf = (uint8_t *)malloc_or_fail(4); + memcpy(nas_pdu_1.buf, "NAS1", 4); + nas_pdu_1.len = 4; + + byte_array_t nas_pdu_2; + nas_pdu_2.buf = (uint8_t *)malloc_or_fail(4); + memcpy(nas_pdu_2.buf, "NAS2", 4); + nas_pdu_2.len = 4; + + params.dedicated_NAS_msg_list[0] = nas_pdu_1; + params.dedicated_NAS_msg_list[1] = nas_pdu_2; + + byte_array_t msg = do_RRCReconfiguration(¶ms); + + EXPECT_GT(msg.len, 0); + EXPECT_NE(msg.buf, nullptr); + + LOG_D(NR_RRC, "RRCReconfiguration: Encoded (%ld bytes)\n", msg.len); + + free_byte_array(msg); + free_RRCReconfiguration_params(params); +} + int main(int argc, char **argv) { logInit(); diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 4546f59723..66f9911c8a 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -38,6 +38,7 @@ #include "NR_CG-Config.h" #include "NR_CG-ConfigInfo.h" #include "NR_RRCReconfiguration.h" +#include "RRC/NR/MESSAGES/asn1_msg.h" void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id); void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp); @@ -112,6 +113,8 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, int n_rel_drbs, const f1ap_drb_to_be_released_t *rel_drbs); +void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params); + pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession); f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param); void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b924bfd0d0..e8c0edf441 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -125,12 +125,6 @@ static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_i data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd); } -static void freeDRBlist(NR_DRB_ToAddModList_t *list) -{ - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); - return; -} - static bool eq_cell_id(const void *vval, const void *vit) { const int *cell_id = (const int *)vval; @@ -551,15 +545,23 @@ static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a return rc_A3; } -static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, - gNB_RRC_UE_t *UE, - uint8_t xid, - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *nas_messages, - uint8_t *buf, - int max_len, - bool reestablish) +void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) { - NR_CellGroupConfig_t *cellGroupConfig = UE->masterCellGroup; + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config); + for (int i = 0; i < params.num_nas_msg; i++) + FREE_AND_ZERO_BYTE_ARRAY(params.dedicated_NAS_msg_list[i]); +} + +/** @brief Prepare the instance of RRCReconfigurationParams to be pass to RRC encoding */ +static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + bool srb_reestablish, + bool drb_reestablish) +{ + uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); nr_rrc_du_container_t *du = get_du_for_ue(rrc, UE->rrc_ue_id); DevAssert(du != NULL); f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; @@ -617,71 +619,71 @@ static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, UE->measConfig = measconfig; - NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, reestablish); - NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, reestablish); + // Re-establish PDCP for SRB2 only + NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reestablish); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish); + nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup, + .transaction_id = xid, + .drb_config_list = DRBs, + .drb_release_list = UE->DRB_ReleaseList, + .meas_config = UE->measConfig, + .srb_config_list = SRBs}; + UE->DRB_ReleaseList = NULL; // pointer transferred to params - int size = do_RRCReconfiguration(UE->rrc_ue_id, - buf, - max_len, - xid, - SRBs, - DRBs, - UE->DRB_ReleaseList, - NULL, - measconfig, - nas_messages, - cellGroupConfig); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buf, size, "[MSG] RRC Reconfiguration\n"); - freeSRBlist(SRBs); - freeDRBlist(DRBs); - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, UE->DRB_ReleaseList); - UE->DRB_ReleaseList = NULL; + for (int i = 0; i < UE->nb_of_pdusessions; i++) { + if (UE->pduSession[i].param.nas_pdu.len > 0) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->pduSession[i].param.nas_pdu; + UE->pduSession[i].param.nas_pdu.buf = NULL; + UE->pduSession[i].param.nas_pdu.len = 0; + LOG_D(NR_RRC, "Transfer NAS info with size %ld (pdusession idx %d) to RRCReconfiguration params\n", UE->pduSession[i].param.nas_pdu.len, i); + } + } + if (UE->nas_pdu.len > 0) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->nas_pdu; + UE->nas_pdu.buf = NULL; + UE->nas_pdu.len = 0; + LOG_D(NR_RRC, "Transfer NAS info with size %ld to RRCReconfiguration params\n", UE->nas_pdu.len); + } - return size; + return params; +} + +static byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params) +{ + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); + return msg; + } + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); + return msg; } static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) { - uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); - ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); + /* do not re-establish PDCP for any bearer */ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, false, false); + ue_p->xids[params.transaction_id] = RRC_PDUSESSION_ESTABLISH; + byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, params); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; + } for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { - asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, (char *)ue_p->pduSession[i].param.nas_pdu.buf, ue_p->pduSession[i].param.nas_pdu.len); - - LOG_D(NR_RRC, "add NAS info with size %ld (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.len, i); - ue_p->pduSession[i].xid = xid; + ue_p->pduSession[i].xid = params.transaction_id; } if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; } } - if (ue_p->nas_pdu.len) { - asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buf, ue_p->nas_pdu.len); - } - - /* If list is empty free the list and reset the address */ - if (dedicatedNAS_MessageList->list.count == 0) { - free(dedicatedNAS_MessageList); - dedicatedNAS_MessageList = NULL; - } - - /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) - FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); - - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - // TODO refactor dedicatedNAS_MessageList - int size = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, xid, dedicatedNAS_MessageList, buffer, sizeof(buffer), false); - DevAssert(size > 0 && size <= sizeof(buffer)); - - LOG_UE_DL_EVENT(ue_p, "Generate RRCReconfiguration (bytes %d, xid %d)\n", size, xid); + LOG_UE_DL_EVENT(ue_p, "Generate RRCReconfiguration (bytes %ld, xid %d)\n", msg.len, params.transaction_id); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) @@ -690,8 +692,8 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); ue_p->xids[xid] = RRC_PDUSESSION_MODIFY; - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = - CALLOC(1, sizeof(*dedicatedNAS_MessageList)); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); + nr_rrc_reconfig_param_t params = {.drb_config_list = DRBs, .transaction_id = xid}; for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { rrc_pdu_session_param_t *session = &ue_p->pduSession[i]; @@ -753,42 +755,27 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t session->status = PDU_SESSION_STATUS_DONE; session->xid = xid; - if (session->param.nas_pdu.buf != NULL) { - asn1cSequenceAdd(dedicatedNAS_MessageList->list,NR_DedicatedNAS_Message_t, dedicatedNAS_Message); - OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)session->param.nas_pdu.buf, session->param.nas_pdu.len); - LOG_I(NR_RRC, "add NAS info with size %ld (pdusession id %d)\n", session->param.nas_pdu.len, session->param.pdusession_id); + if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = ue_p->pduSession[i].param.nas_pdu; } } - /* If list is empty free the list and reset the address */ - if (dedicatedNAS_MessageList->list.count == 0) { - free(dedicatedNAS_MessageList); - dedicatedNAS_MessageList = NULL; + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; } - - NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); - uint8_t buffer[NR_RRC_BUF_SIZE]; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - xid, - NULL, - DRBs, - NULL, - NULL, - NULL, - dedicatedNAS_MessageList, - NULL); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - freeDRBlist(DRBs); + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); /* Free all NAS PDUs */ for (int i = 0; i < ue_p->nb_of_pdusessions; i++) FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); - LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d)\n", ue_p->rrc_ue_id, size); + LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } //----------------------------------------------------------------------------- @@ -808,40 +795,22 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, } } - /* If list is empty free the list and reset the address */ - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = NULL; + nr_rrc_reconfig_param_t params = {.drb_release_list = DRB_Release_configList2, .transaction_id = xid}; if (nas_length > 0) { - dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); - asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, dedicatedNAS_Message); - OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)nas_buffer, nas_length); - LOG_I(NR_RRC,"add NAS info with size %d\n", nas_length); - } else { - LOG_W(NR_RRC,"dedlicated NAS list is empty\n"); + params.dedicated_NAS_msg_list[params.num_nas_msg].buf = nas_buffer; + params.dedicated_NAS_msg_list[params.num_nas_msg++].len = nas_length; } - - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - xid, - NULL, - NULL, - DRB_Release_configList2, - NULL, - NULL, - dedicatedNAS_MessageList, - NULL); - LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); - - /* Free all NAS PDUs */ - if (nas_length > 0) { - /* Free the NAS PDU buffer and invalidate it */ - free(nas_buffer); + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; } - - LOG_I(NR_RRC, "UE %d: Generate NR_RRCReconfiguration (bytes %d)\n", ue_p->rrc_ue_id, size); + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); + LOG_I(NR_RRC, "UE %d: Generate NR_RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_information_t *secInfo) @@ -1081,32 +1050,26 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE; - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - new_xid, - SRBs, - DRBs, - NULL, - NULL, - NULL, // MeasObj_list, - NULL, - cellGroupConfig); - freeSRBlist(SRBs); - freeDRBlist(DRBs); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - - AssertFatal(size > 0, "cannot encode RRC Reconfiguration\n"); + nr_rrc_reconfig_param_t params = {.cell_group_config = cellGroupConfig, + .drb_config_list = DRBs, + .srb_config_list = SRBs, + .transaction_id = new_xid}; + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; + } + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); LOG_I(NR_RRC, - "UE %d RNTI %04x: Generate NR_RRCReconfiguration after reestablishment complete (bytes %d)\n", + "UE %d RNTI %04x: Generate NR_RRCReconfiguration after reestablishment complete (bytes %ld)\n", ue_p->rrc_ue_id, ue_p->rnti, - size); + msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } -//----------------------------------------------------------------------------- int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int dl_bwp_id, const int ul_bwp_id) { @@ -1123,22 +1086,16 @@ int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int *masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = ul_bwp_id; } - uint8_t buffer[NR_RRC_BUF_SIZE]; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - xid, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - masterCellGroup); - + nr_rrc_reconfig_param_t params = {.cell_group_config = masterCellGroup, .transaction_id = xid}; + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return -1; + } const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); - + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_byte_array(msg); + free_RRCReconfiguration_params(params); return 0; } @@ -2192,14 +2149,23 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); UE->xids[xid] = RRC_DEDICATED_RECONF; - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = rrc_gNB_encode_RRCReconfiguration(rrc, UE, xid, NULL, buffer, sizeof(buffer), true); - DevAssert(size > 0 && size <= sizeof(buffer)); + /* 3GPP TS 38.331 specifies that PDCP shall be re-established whenever the security key + * used for the radio bearer changes, with some expections for SRB1 (i.e. when resuming + * an RRC connection, or at the first reconfiguration after RRC connection reestablishment + * in NR, do not re-establish PDCP */ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, true, true); + params.transaction_id = xid; + + byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); + return; + } // TODO N2 38.413 sec 9.3.1.21: admitted PDU sessions (in UE), Target to // Source Transparent Container (9.3.1.21) which encodes the RRC // reconfiguration above - UE->ho_context->target->ho_req_ack(rrc, UE, buffer, size); + UE->ho_context->target->ho_req_ack(rrc, UE, msg.buf, msg.len); } }