diff --git a/common/utils/ds/seq_arr.h b/common/utils/ds/seq_arr.h index 2fd049fa34..cb771405c5 100644 --- a/common/utils/ds/seq_arr.h +++ b/common/utils/ds/seq_arr.h @@ -34,6 +34,9 @@ SOFTWARE. #include #include +#define FOR_EACH_SEQ_ARR(type, var, arr) \ + for (type var = seq_arr_front(arr); var != seq_arr_end(arr); var = seq_arr_next(arr, var)) + typedef struct seq_arr_s { uint8_t* data; size_t size; diff --git a/common/utils/utils.c b/common/utils/utils.c index 377c4512b7..33797b49df 100644 --- a/common/utils/utils.c +++ b/common/utils/utils.c @@ -7,34 +7,6 @@ #include #include "utils.h" - - -const char *hexdump(const void *data, size_t data_len, char *out, size_t out_len) -{ - char *p = out; - char *endp = out + out_len; - const uint8_t *q = data; - snprintf(p, endp - p, "[%zu]", data_len); - p += strlen(p); - for (size_t i = 0; i < data_len; ++i) - { - if (p >= endp) - { - static const char ellipses[] = "..."; - char *s = endp - sizeof(ellipses); - if (s >= p) - { - strcpy(s, ellipses); - } - break; - } - snprintf(p, endp - p, " %02X", *q++); - p += strlen(p); - } - return out; -} - - /**************************************************************************** ** ** ** Name: hex_char_to_hex_value() ** diff --git a/common/utils/utils.h b/common/utils/utils.h index 841cb2af9c..df188b812f 100644 --- a/common/utils/utils.h +++ b/common/utils/utils.h @@ -109,8 +109,6 @@ static inline void *malloc_or_fail(size_t size) #define PAGE_MASK 0xfffff000 #define virt_to_phys(x) (x) -const char *hexdump(const void *data, size_t data_len, char *out, size_t out_len); - // Converts an hexadecimal ASCII coded digit into its value. ** int hex_char_to_hex_value (char c); // Converts an hexadecimal ASCII coded string into its value.** diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 52cd919338..b899bb33e2 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -664,11 +664,8 @@ typedef struct ngap_pdusession_setup_req_s { /* E RAB setup request */ pdusession_t pdusession_setup_params[NGAP_MAX_PDU_SESSION]; - /* UE Uplink Aggregated Max Bitrates */ - uint64_t ueAggMaxBitRateUplink; - - /* UE Downlink Aggregated Max Bitrates */ - uint64_t ueAggMaxBitRateDownlink; + /* UE Aggregated Max Bitrates */ + ngap_ambr_t ueAggMaxBitRate; } ngap_pdusession_setup_req_t; diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 70e6c026ca..a2112d46eb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1919,9 +1919,8 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc seq_arr_init(rrc->neighbour_cell_configuration, sizeof(neighbour_cell_configuration_t)); for (int elm = 0; elm < neighbour_list_param_list.numelt; ++elm) { - neighbour_cell_configuration_t *cell = calloc(1, sizeof(neighbour_cell_configuration_t)); - AssertFatal(cell != NULL, "out of memory\n"); - cell->nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr; + neighbour_cell_configuration_t cell = {0}; + cell.nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr; char neighbourpath[MAX_OPTNAME_SIZE + 8]; snprintf(neighbourpath, sizeof(neighbourpath), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm); @@ -1930,22 +1929,20 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc GNBNEIGHBOURCELLPARAMS_DESC, GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, neighbourpath); - LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt); + LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell.nr_cell_id, NeighbourCellParamList.numelt); if (NeighbourCellParamList.numelt < 1) continue; - cell->neighbour_cells = malloc(sizeof(seq_arr_t)); - AssertFatal(cell->neighbour_cells != NULL, "Memory exhausted!!!"); - seq_arr_init(cell->neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t)); + cell.neighbour_cells = malloc_or_fail(sizeof(seq_arr_t)); + seq_arr_init(cell.neighbour_cells, sizeof(nr_neighbour_cell_t)); for (int l = 0; l < NeighbourCellParamList.numelt; ++l) { - nr_neighbour_gnb_configuration_t *neighbourCell = calloc(1, sizeof(nr_neighbour_gnb_configuration_t)); - AssertFatal(neighbourCell != NULL, "out of memory\n"); - neighbourCell->gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); - neighbourCell->nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); - neighbourCell->physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; - neighbourCell->subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr; - neighbourCell->absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr; - neighbourCell->tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr; + nr_neighbour_cell_t neighbourCell = {0}; + neighbourCell.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); + neighbourCell.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); + neighbourCell.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; + neighbourCell.subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr; + neighbourCell.absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr; + neighbourCell.tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr; char neighbour_plmn_path[CONFIG_MAXOPTLENGTH]; snprintf(neighbour_plmn_path, @@ -1957,13 +1954,12 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc GNB_CONFIG_STRING_NEIGHBOUR_PLMN); GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, neighbour_plmn_path); - neighbourCell->plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - neighbourCell->plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; - neighbourCell->plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; - seq_arr_push_back(cell->neighbour_cells, neighbourCell, sizeof(nr_neighbour_gnb_configuration_t)); + neighbourCell.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; + neighbourCell.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; + neighbourCell.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; + seq_arr_push_back(cell.neighbour_cells, &neighbourCell, sizeof(neighbourCell)); } - - seq_arr_push_back(rrc->neighbour_cell_configuration, cell, sizeof(neighbour_cell_configuration_t)); + seq_arr_push_back(rrc->neighbour_cell_configuration, &cell, sizeof(cell)); } void *base = seq_arr_front(rrc->neighbour_cell_configuration); size_t nmemb = seq_arr_size(rrc->neighbour_cell_configuration); @@ -2020,22 +2016,21 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) measurementConfig->a3_event_list = malloc(sizeof(seq_arr_t)); seq_arr_init(measurementConfig->a3_event_list, sizeof(nr_a3_event_t)); for (int i = 0; i < A3_EventList.numelt; i++) { - nr_a3_event_t *a3_event = (nr_a3_event_t *)calloc(1, sizeof(nr_a3_event_t)); - AssertFatal(a3_event != NULL, "out of memory\n"); - a3_event->pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; - AssertFatal(a3_event->pci >= -1 && a3_event->pci < 1024, + nr_a3_event_t a3_event = {0}; + a3_event.pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; + AssertFatal(a3_event.pci >= -1 && a3_event.pci < 1024, "entry %s.%s must be -1<=PCI<1024, but is %d\n", measurement_path, MEASUREMENT_EVENTS_PCI_ID, - a3_event->pci); - a3_event->timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr; - a3_event->a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr; - a3_event->hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr; + a3_event.pci); + a3_event.timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr; + a3_event.a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr; + a3_event.hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr; - if (a3_event->pci == -1) + if (a3_event.pci == -1) measurementConfig->is_default_a3_configuration_exists = true; - seq_arr_push_back(measurementConfig->a3_event_list, a3_event, sizeof(nr_a3_event_t)); + seq_arr_push_back(measurementConfig->a3_event_list, &a3_event, sizeof(nr_a3_event_t)); } } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 1922a3420e..b810bf8de6 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -2703,6 +2703,10 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, mac->lc_ordered_list.count); // variable used to build the lcids with positive Bj + if (!mac->lc_ordered_list.count) { + LOG_E(NR_MAC, "Failed to init lcids_bj_pos: mac->lc_ordered_list.count = 0\n"); + return 0; + } nr_lcordered_info_t lcids_bj_pos[mac->lc_ordered_list.count]; int avail_lcids_count = select_logical_channels(mac, lcids_bj_pos); 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_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 7e0789c4ad..640803af2f 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -301,7 +301,7 @@ typedef struct { plmn_identity_t plmn; uint32_t tac; bool isIntraFrequencyNeighbour; -} nr_neighbour_gnb_configuration_t; +} nr_neighbour_cell_t; typedef struct neighbour_cell_configuration_s { uint64_t nr_cell_id; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 4546f59723..3a4fed6411 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -38,6 +38,10 @@ #include "NR_CG-Config.h" #include "NR_CG-ConfigInfo.h" #include "NR_RRCReconfiguration.h" +#include "RRC/NR/MESSAGES/asn1_msg.h" + +#define SRB1 1 +#define SRB2 2 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 +116,12 @@ 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); + +byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params); + +nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, bool drb_reestablish); + 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 78e472ed60..f69e03b810 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -96,6 +96,7 @@ #include "E1AP/lib/e1ap_interface_management.h" #include "NR_DL-DCCH-Message.h" #include "ds/byte_array.h" +#include "alg/find.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -124,45 +125,47 @@ 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) +static bool eq_cell_id(const void *vval, const void *vit) { - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); - return; + const int *cell_id = (const int *)vval; + const neighbour_cell_configuration_t *cell = (const neighbour_cell_configuration_t *)vit; + return cell->nr_cell_id == *cell_id; } -const neighbour_cell_configuration_t *get_neighbour_config(int serving_cell_nr_cellid) +const neighbour_cell_configuration_t *get_neighbour_cell_config(const gNB_RRC_INST *rrc, int cell_id) { - const gNB_RRC_INST *rrc = RC.nrrrc[0]; - seq_arr_t *neighbour_cell_configuration = rrc->neighbour_cell_configuration; - if (!neighbour_cell_configuration) + if (!rrc->neighbour_cell_configuration) return NULL; - - for (int cellIdx = 0; cellIdx < neighbour_cell_configuration->size; cellIdx++) { - neighbour_cell_configuration_t *neighbour_config = - (neighbour_cell_configuration_t *)seq_arr_at(neighbour_cell_configuration, cellIdx); - if (neighbour_config->nr_cell_id == serving_cell_nr_cellid) - return neighbour_config; + seq_arr_t *head = rrc->neighbour_cell_configuration; + LOG_D(NR_RRC, "Number of neighbour cell configurations: %ld\n", head->size); + elm_arr_t e = find_if(head, &cell_id, eq_cell_id); + if (e.found) { + const neighbour_cell_configuration_t *cell = (const neighbour_cell_configuration_t *)e.it; + LOG_D(NR_RRC, "Found matching neighbour cell with Cell ID %ld\n", cell->nr_cell_id); + return cell; } return NULL; } -const nr_neighbour_gnb_configuration_t *get_neighbour_cell_information(int serving_cell_nr_cellid, int neighbour_cell_phy_id) +static bool eq_pci(const void *vval, const void *vit) { - const gNB_RRC_INST *rrc = RC.nrrrc[0]; - seq_arr_t *neighbour_cell_configuration = rrc->neighbour_cell_configuration; - for (int cellIdx = 0; cellIdx < neighbour_cell_configuration->size; cellIdx++) { - neighbour_cell_configuration_t *neighbour_config = - (neighbour_cell_configuration_t *)seq_arr_at(neighbour_cell_configuration, cellIdx); - if (!neighbour_config) - continue; + const int *pci = (const int *)vval; + const nr_neighbour_cell_t *neighbour = (const nr_neighbour_cell_t *)vit; + return neighbour->physicalCellId == *pci; +} - for (int neighbourIdx = 0; neighbourIdx < neighbour_config->neighbour_cells->size; neighbourIdx++) { - nr_neighbour_gnb_configuration_t *neighbour = - (nr_neighbour_gnb_configuration_t *)seq_arr_at(neighbour_config->neighbour_cells, neighbourIdx); - if (neighbour != NULL && neighbour->physicalCellId == neighbour_cell_phy_id) - return neighbour; - } +const nr_neighbour_cell_t *get_neighbour_cell_by_pci(const neighbour_cell_configuration_t *cell, int pci) +{ + seq_arr_t *head = cell->neighbour_cells; + DevAssert(head != NULL); + LOG_D(NR_RRC, "Number of neighbour cells: %ld\n", head->size); + elm_arr_t e = find_if(head, &pci, eq_pci); + if (e.found) { + const nr_neighbour_cell_t *neighbour = (const nr_neighbour_cell_t *)e.it; + LOG_D(NR_RRC, "Found matching neighbour cell with PCI %d and Cell ID %ld\n", neighbour->physicalCellId, neighbour->nrcell_id); + return neighbour; } + LOG_E(NR_RRC, "No matching neighbour cell found for Physical Cell ID: %d\n", pci); return NULL; } @@ -267,12 +270,17 @@ unsigned int rrc_gNB_get_next_transaction_identifier(module_id_t gnb_mod_idP) return tmp; } -/** - * @brief Create srb-ToAddModList for RRCSetup and RRCReconfiguration messages -*/ -static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, bool reestablish) +/** @brief Create srb-ToAddModList for RRCSetup and RRCReconfiguration messages + * @param reestablish bitmap to indicates whether PDCP should be re-established + * for the SRB1 and/or SRB2. For convenience the bitmap is 0-based, with index 1 + * corresponding to SRB1, index 2 to SRB2. 3GPP TS 38.331 RadioBearerConfig + * 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) */ +static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish) { - if (!ue->Srb[1].Active) { + if (!ue->Srb[SRB1].Active) { LOG_E(NR_RRC, "Call SRB list while SRB1 doesn't exist\n"); return NULL; } @@ -281,9 +289,11 @@ static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, bool reestablish) if (ue->Srb[i].Active) { asn1cSequenceAdd(list->list, NR_SRB_ToAddMod_t, srb); srb->srb_Identity = i; - /* Set reestablishPDCP only for SRB2 */ - if (reestablish && i == 2) { + /* Based on the bitmap, set reestablishPDCP for SRB1 and SRB2 */ + if ((i == SRB1 || i == SRB2) && (reestablish & (1 << i))) { asn1cCallocOne(srb->reestablishPDCP, NR_SRB_ToAddMod__reestablishPDCP_true); + } else { + DevAssert(!(reestablish & (1 << i))); } } return list; @@ -312,12 +322,7 @@ static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) static void freeSRBlist(NR_SRB_ToAddModList_t *l) { - if (l) { - for (int i = 0; i < l->list.count; i++) - free(l->list.array[i]); - free(l); - } else - LOG_E(NR_RRC, "Call free SRB list on NULL pointer\n"); + ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, l); } static void activate_srb(gNB_RRC_UE_t *UE, int srb_id) @@ -542,15 +547,20 @@ 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 */ +nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, 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; @@ -564,7 +574,7 @@ static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, int band = get_dl_band(cell_info); const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; const NR_MeasTiming_t *mt = mtlist->list.array[0]; - const neighbour_cell_configuration_t *neighbour_config = get_neighbour_config(cell_info->nr_cellid); + const neighbour_cell_configuration_t *neighbour_config = get_neighbour_cell_config(rrc, cell_info->nr_cellid); seq_arr_t *neighbour_cells = NULL; if (neighbour_config) neighbour_cells = neighbour_config->neighbour_cells; @@ -583,7 +593,7 @@ static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, LOG_D(NR_RRC, "HO LOG: Preparing A3 Event Measurement Configuration!\n"); bool is_default_a3_added = false; for (int i = 0; i < neighbour_cells->size; i++) { - nr_neighbour_gnb_configuration_t *neighbourCell = (nr_neighbour_gnb_configuration_t *)seq_arr_at(neighbour_cells, i); + nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i); if (!neighbourCell->isIntraFrequencyNeighbour) continue; seq_arr_push_back(pci_seq, &neighbourCell->physicalCellId, sizeof(int)); @@ -608,93 +618,91 @@ 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_reest_bitmap); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish); - 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; + 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 - return size; + 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 params; +} + +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, 0, 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) { int qos_flow_index = 0; - 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_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false); + ue_p->xids[params.transaction_id] = RRC_PDUSESSION_MODIFY; for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { rrc_pdu_session_param_t *session = &ue_p->pduSession[i]; // bypass the new and already configured pdu sessions if (session->status >= PDU_SESSION_STATUS_DONE) { - session->xid = xid; + session->xid = params.transaction_id; continue; } if (session->cause.type != NGAP_CAUSE_NOTHING) { // set xid of failure pdu session - session->xid = xid; + session->xid = params.transaction_id; session->status = PDU_SESSION_STATUS_FAILED; continue; } @@ -709,7 +717,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t if (j == MAX_DRBS_PER_UE) { ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_unspecified}; - session->xid = xid; + session->xid = params.transaction_id; session->status = PDU_SESSION_STATUS_FAILED; session->cause = cause; continue; @@ -734,7 +742,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t LOG_E(NR_RRC, "not supported 5qi %lu\n", session->param.qos[qos_flow_index].fiveQI); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_not_supported_5QI_value}; session->status = PDU_SESSION_STATUS_FAILED; - session->xid = xid; + session->xid = params.transaction_id; session->cause = cause; continue; } @@ -742,44 +750,20 @@ 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); - } + session->xid = params.transaction_id; } - /* 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); - - /* 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_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); + 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); } //----------------------------------------------------------------------------- @@ -799,40 +783,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) @@ -1065,39 +1031,35 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR /* PDCP Reestablishment of DRBs according to 5.3.5.6.5 of 3GPP TS 38.331 (over E1) */ cuup_notify_reestablishment(rrc, ue_p); - /* Create srb-ToAddModList */ - NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, true); + /* Create srb-ToAddModList, 3GPP TS 38.331 RadioBearerConfig: + * do not re-establish PDCP for SRB1, when resuming an RRC connection, + * or at the first reconfiguration after RRC connection reestablishment in NR */ + NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, 1 << SRB2); // Re-establish PDCP for SRB2 only /* Create drb-ToAddModList */ NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true); 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) { @@ -1114,22 +1076,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; } @@ -1391,7 +1347,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, int servingCellRSRP = 0; int neighbourCellRSRP = 0; - int servingCellId = -1; + int scell_pci = -1; switch (event_triggered->eventId.present) { case NR_EventTriggerConfig__eventId_PR_eventA2: @@ -1408,7 +1364,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, for (int serving_cell_idx = 0; serving_cell_idx < measResults->measResultServingMOList.list.count; serving_cell_idx++) { const NR_MeasResultServMO_t *meas_result_serv_MO = measResults->measResultServingMOList.list.array[serving_cell_idx]; - servingCellId = *(meas_result_serv_MO->measResultServingCell.physCellId); + scell_pci = *(meas_result_serv_MO->measResultServingCell.physCellId); if (meas_result_serv_MO->measResultServingCell.measResult.cellResults.resultsSSB_Cell) { servingCellRSRP = *(meas_result_serv_MO->measResultServingCell.measResult.cellResults.resultsSSB_Cell->rsrp) - 157; } else { @@ -1426,7 +1382,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, const NR_MeasResultListNR_t *measResultListNR = measResults->measResultNeighCells->choice.measResultListNR; for (int neigh_meas_idx = 0; neigh_meas_idx < measResultListNR->list.count; neigh_meas_idx++) { const NR_MeasResultNR_t *meas_result_neigh_cell = (measResultListNR->list.array[neigh_meas_idx]); - const int neighbourCellId = *(meas_result_neigh_cell->physCellId); + const int neighbour_pci = *(meas_result_neigh_cell->physCellId); // TS 138 133 Table 10.1.6.1-1: SS-RSRP and CSI-RSRP measurement report mapping const struct NR_MeasResultNR__measResult__cellResults *cellResults = &(meas_result_neigh_cell->measResult.cellResults); @@ -1439,13 +1395,13 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, LOG_I(NR_RRC, "HO LOG: Measurement Report for the neighbour %d with RSRP: %d\n", - neighbourCellId, + neighbour_pci, neighbourCellRSRP); - const f1ap_served_cell_info_t *neigh_cell = get_cell_information_by_phycellId(neighbourCellId); - const f1ap_served_cell_info_t *serving_cell = get_cell_information_by_phycellId(servingCellId); - const nr_neighbour_gnb_configuration_t *neighbour = - get_neighbour_cell_information(serving_cell->nr_cellid, neighbourCellId); + const f1ap_served_cell_info_t *neigh_cell = get_cell_information_by_phycellId(neighbour_pci); + const f1ap_served_cell_info_t *serving_cell = get_cell_information_by_phycellId(scell_pci); + const neighbour_cell_configuration_t *cell = get_neighbour_cell_config(rrc, serving_cell->nr_cellid); + const nr_neighbour_cell_t *neighbour = get_neighbour_cell_by_pci(cell, neighbour_pci); // CU does not have f1 connection with neighbour cell context. So check does serving cell has this phyCellId as a // neighbour. if (!neigh_cell && neighbour) { @@ -1465,7 +1421,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, nr_rrc_du_container_t *target_du = get_du_by_cell_id(rrc, neigh_cell->nr_cellid); nr_rrc_trigger_f1_ho(rrc, ue, source_du, target_du); } else { - LOG_W(NR_RRC, "UE %d: received A3 event for stronger neighbor PCI %d, but no such neighbour in configuration\n", ue->rrc_ue_id, neighbourCellId); + LOG_W(NR_RRC, "UE %d: received A3 event for stronger neighbor PCI %d, but no such neighbour in configuration\n", ue->rrc_ue_id, neighbour_pci); } } @@ -2180,17 +2136,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance DevAssert(resp->crnti != NULL); UE->ho_context->target->du_ue_id = resp->gNB_DU_ue_id; UE->ho_context->target->new_rnti = *resp->crnti; - - uint8_t xid = rrc_gNB_get_next_transaction_identifier(0); - 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)); - - // 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); } } diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 82aa7b5a86..1ff31acae1 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -940,7 +940,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return; } - if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink)) { + if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRate.br_dl)) { // Reject PDU Session Resource setup if there's no CU-UP associated LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE}; diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 9e89766acb..a650a03604 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -202,7 +202,7 @@ const struct f1ap_served_cell_info_t *get_cell_information_by_phycellId(int phyC static void is_intra_frequency_neighbour(void *ssb_arfcn, void *neighbour_cell) { uint32_t *ssb_arfcn_ptr = (uint32_t *)ssb_arfcn; - nr_neighbour_gnb_configuration_t *neighbour_cell_ptr = (nr_neighbour_gnb_configuration_t *)neighbour_cell; + nr_neighbour_cell_t *neighbour_cell_ptr = (nr_neighbour_cell_t *)neighbour_cell; if (*ssb_arfcn_ptr == neighbour_cell_ptr->absoluteFrequencySSB) { LOG_D(NR_RRC, "HO LOG: found intra frequency neighbour %lu!\n", neighbour_cell_ptr->nrcell_id); @@ -237,7 +237,7 @@ static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_config for (int c = 0; c < neighbour_cell_configuration->size; c++) { const neighbour_cell_configuration_t *neighbour_config = seq_arr_at(neighbour_cell_configuration, c); for (int ni = 0; ni < neighbour_config->neighbour_cells->size; ni++) { - const nr_neighbour_gnb_configuration_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni); + const nr_neighbour_cell_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni); if (nc->nrcell_id != cell->nr_cellid) continue; // current cell is in the nc config, check that config matches diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index e6e50ffbf1..647f253989 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -61,6 +61,46 @@ static void free_ho_ctx(nr_handover_context_t *ho_ctx) free(ho_ctx); } +static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE]) +{ + int nb_drb = 0; + for (int i = 0; i < MAX_DRBS_PER_UE; ++i) { + drb_t *rrc_drb = &ue->established_drbs[i]; + if (rrc_drb->status == DRB_INACTIVE) + continue; + + f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; + nb_drb++; + drb->drb_id = rrc_drb->drb_id; + drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; + memcpy(&drb->up_ul_tnl[0].tl_address, &rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; + drb->up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid; + drb->up_ul_tnl_length = 1; + + /* fetch an existing PDU session for this DRB */ + rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, drb->drb_id); + AssertFatal(pdu != NULL, "no PDU session for DRB ID %ld\n", drb->drb_id); + drb->nssai = pdu->param.nssai; + + // for the moment, we only support one QoS flow. Put a reminder in case + // this changes + AssertFatal(pdu->param.nb_qos == 1, "only 1 Qos flow supported\n"); + drb->drb_info.flows_to_be_setup_length = 1; + drb->drb_info.flows_mapped_to_drb = calloc_or_fail(1, sizeof(drb->drb_info.flows_mapped_to_drb[0])); + AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n"); + int qfi = rrc_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[0]; + DevAssert(qfi > 0); + drb->drb_info.flows_mapped_to_drb[0].qfi = qfi; + pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(qfi, pdu); + drb->drb_info.flows_mapped_to_drb[0].qos_params.qos_characteristics = get_qos_char_from_qos_flow_param(in_qos_char); + + /* the DRB QoS parameters: we just reuse the ones from the first flow */ + drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params; + } + return nb_drb; +} + /* \brief Initiate a handover of UE to a specific target cell handled by this * CU. * \param ue a UE context for which the handover should be triggered. The UE @@ -73,8 +113,7 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, const nr_rrc_du_container_t *source_du, const nr_rrc_du_container_t *target_du, - uint8_t *ho_prep_buf, - uint32_t ho_prep_len, + byte_array_t *ho_prep_info, ho_req_ack_t ack, ho_success_t success, ho_cancel_t cancel) @@ -83,7 +122,7 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, DevAssert(ue != NULL); DevAssert(target_du != NULL); // source_du might be NULL -> inter-CU handover - DevAssert(ho_prep_buf != NULL && ho_prep_len > 0); + DevAssert(ho_prep_info->buf != NULL && ho_prep_info->len > 0); if (ue->ho_context != NULL) { LOG_E(NR_RRC, "handover for UE %u ongoing, cannot trigger new\n", ue->rrc_ue_id); @@ -130,45 +169,12 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, target_du->setup_req->cell[0].info.nr_pci); cu_to_du_rrc_information_t cu2du = { - .handoverPreparationInfo = ho_prep_buf, - .handoverPreparationInfo_length = ho_prep_len, + .handoverPreparationInfo = ho_prep_info->buf, + .handoverPreparationInfo_length = ho_prep_info->len, }; f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE] = {0}; - int nb_drb = 0; - for (int i = 0; i < sizeofArray(drbs); ++i) { - drb_t *rrc_drb = &ue->established_drbs[i]; - if (rrc_drb->status == DRB_INACTIVE) - continue; - - f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; - nb_drb++; - drb->drb_id = rrc_drb->drb_id; - drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; - memcpy(&drb->up_ul_tnl[0].tl_address, &rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); - drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drb->up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid; - drb->up_ul_tnl_length = 1; - - /* fetch an existing PDU session for this DRB */ - rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, drb->drb_id); - AssertFatal(pdu != NULL, "no PDU session for DRB ID %ld\n", drb->drb_id); - drb->nssai = pdu->param.nssai; - - // for the moment, we only support one QoS flow. Put a reminder in case - // this changes - AssertFatal(pdu->param.nb_qos == 1, "only 1 Qos flow supported\n"); - drb->drb_info.flows_to_be_setup_length = 1; - drb->drb_info.flows_mapped_to_drb = calloc_or_fail(1, sizeof(f1ap_flows_mapped_to_drb_t)); - int qfi = rrc_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[0]; - DevAssert(qfi > 0); - drb->drb_info.flows_mapped_to_drb[0].qfi = qfi; - pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(qfi, pdu); - drb->drb_info.flows_mapped_to_drb[0].qos_params.qos_characteristics = get_qos_char_from_qos_flow_param(in_qos_char); - - /* the DRB QoS parameters: we just reuse the ones from the first flow */ - drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params; - } + int nb_drb = fill_drb_to_be_setup(rrc, ue, drbs); f1ap_srb_to_be_setup_t srbs[2] = {{.srb_id = 1, .lcid = 1}, {.srb_id = 2, .lcid = 2}}; f1ap_served_cell_info_t *cell_info = &target_du->setup_req->cell[0].info; @@ -252,15 +258,24 @@ static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_ #endif } -static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t *rrc_reconf_buf, uint32_t rrc_reconf_len) +static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) { - // N2/Xn HO: fill with UE caps, as-context, rrc reconf, send to source CU - // also, fill the UE->rnti from the new one (in F1 case, happens after - // confirmation of ue ctxt modif + /* 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, (1 << SRB2), true); + UE->xids[params.transaction_id] = RRC_DEDICATED_RECONF; + byte_array_t buffer = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); + free_RRCReconfiguration_params(params); + if (!buffer.len) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); + return; + } // F1 HO: handling of "source CU" information DevAssert(UE->ho_context->source != NULL); - rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, rrc_reconf_buf, rrc_reconf_len); + rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, buffer.buf, buffer.len); LOG_A(NR_RRC, "HO acknowledged: Send reconfiguration for UE %u/RNTI %04x...\n", UE->rrc_ue_id, UE->rnti); /* Re-establish SRB2 according to clause 5.3.5.6.3 of 3GPP TS 38.331 @@ -327,7 +342,8 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_contain ho_req_ack_t ack = nr_rrc_f1_ho_acknowledge; ho_success_t success = nr_rrc_f1_ho_complete; ho_cancel_t cancel = nr_rrc_cancel_f1_ho; - nr_initiate_handover(rrc, ue, source_du, target_du, buf, size, ack, success, cancel); + byte_array_t hpi = {.buf = buf, .len = size}; + nr_initiate_handover(rrc, ue, source_du, target_du, &hpi, ack, success, cancel); } void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue) diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index 5046176c1d..6e9bcbcfe6 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -22,6 +22,7 @@ #define RRC_GNB_MOBILITY_H_ #include +#include "common/utils/ds/byte_array.h" /* forward declarations */ typedef struct gNB_RRC_INST_s gNB_RRC_INST; @@ -49,7 +50,7 @@ typedef struct nr_ho_source_cu { } nr_ho_source_cu_t; /* acknowledgement of handover request. buf+len is the RRC Reconfiguration */ -typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, uint8_t *buf, uint32_t len); +typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); typedef void (*ho_success_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); typedef struct nr_ho_target_cu { /// pointer to the (target) DU structure diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 4abc712507..bb58191e24 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1030,11 +1030,16 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc, NR_Rec return; } - if (reconfigurationWithSync->spCellConfigCommon && - reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon && - reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon->frequencyInfoDL && - reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB) - rrc->arfcn_ssb = *reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB; + if (reconfigurationWithSync->spCellConfigCommon) { + /* if the frequencyInfoDL is included, consider the target SpCell + to be one on the SSB frequency indicated by the frequencyInfoDL */ + const NR_DownlinkConfigCommon_t *dcc = reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon; + if (dcc && dcc->frequencyInfoDL && dcc->frequencyInfoDL->absoluteFrequencySSB) + rrc->arfcn_ssb = *dcc->frequencyInfoDL->absoluteFrequencySSB; + + // consider the target SpCell to be one with a physical cell identity indicated by the physCellId + rrc->phyCellID = *reconfigurationWithSync->spCellConfigCommon->physCellId; + } NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants; nr_timer_stop(&tac->T310); diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index d152a5d4a3..4c5d6fb717 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -71,6 +71,7 @@ #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" #include "ds/byte_array.h" +#include "key_nas_deriver.h" #define MAX_NAS_UE 4 @@ -444,41 +445,6 @@ void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t memcpy(knas, out + 16, 16); } -static void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb) -{ - /* Compute the KDF input parameter - * S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01 - */ - uint8_t input[32] = {0}; - // uint16_t length = 4; - // int offset = 0; - - LOG_TRACE(INFO, "%s with count= %d", __FUNCTION__, count); - memset(input, 0, 32); - input[0] = 0x6E; - // P0 - input[1] = count >> 24; - input[2] = (uint8_t)(count >> 16); - input[3] = (uint8_t)(count >> 8); - input[4] = (uint8_t)count; - // L0 - input[5] = 0; - input[6] = 4; - // P1 - input[7] = 0x01; - // L1 - input[8] = 0; - input[9] = 1; - - byte_array_t data = {.buf = input, .len = 10}; - kdf(kamf, data, 32, kgnb); - - printf("kgnb : "); - for (int pp = 0; pp < 32; pp++) - printf("%02x ", kgnb[pp]); - printf("\n"); -} - static void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) { uint8_t ak[6]; diff --git a/openair3/NGAP/ngap_common.c b/openair3/NGAP/ngap_common.c index 385730f70d..7b960fed0b 100644 --- a/openair3/NGAP/ngap_common.c +++ b/openair3/NGAP/ngap_common.c @@ -28,6 +28,7 @@ */ #include +#include "conversions.h" #include "ngap_common.h" int asn1_xer_print = 0; @@ -66,3 +67,50 @@ void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in) break; } } + +nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in) +{ + nr_guami_t out = {0}; + TBCD_TO_MCC_MNC(&in->pLMNIdentity, out.mcc, out.mnc, out.mnc_len); + OCTET_STRING_TO_INT8(&in->aMFRegionID, out.amf_region_id); + OCTET_STRING_TO_INT16(&in->aMFSetID, out.amf_set_id); + OCTET_STRING_TO_INT8(&in->aMFPointer, out.amf_pointer); + return out; +} + +ngap_ambr_t decode_ngap_UEAggregateMaximumBitRate(const NGAP_UEAggregateMaximumBitRate_t *in) +{ + ngap_ambr_t ambr = {0}; + asn_INTEGER2ulong(&in->uEAggregateMaximumBitRateUL, &ambr.br_ul); + asn_INTEGER2ulong(&in->uEAggregateMaximumBitRateDL, &ambr.br_dl); + return ambr; +} + +nssai_t decode_ngap_nssai(const NGAP_S_NSSAI_t *in) +{ + nssai_t nssai = {0}; + OCTET_STRING_TO_INT8(&in->sST, nssai.sst); + if (in->sD != NULL) { + BUFFER_TO_INT24(in->sD->buf, nssai.sd); + } else { + nssai.sd = 0xffffff; + } + return nssai; +} + +ngap_security_capabilities_t decode_ngap_security_capabilities(const NGAP_UESecurityCapabilities_t *in) +{ + ngap_security_capabilities_t out = {0}; + out.nRencryption_algorithms = BIT_STRING_to_uint16(&in->nRencryptionAlgorithms); + out.nRintegrity_algorithms = BIT_STRING_to_uint16(&in->nRintegrityProtectionAlgorithms); + out.eUTRAencryption_algorithms = BIT_STRING_to_uint16(&in->eUTRAencryptionAlgorithms); + out.eUTRAintegrity_algorithms = BIT_STRING_to_uint16(&in->eUTRAintegrityProtectionAlgorithms); + return out; +} + +ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_MobilityRestrictionList_t *in) +{ + ngap_mobility_restriction_t out = {0}; + TBCD_TO_MCC_MNC(&in->servingPLMN, out.serving_plmn.mcc, out.serving_plmn.mnc, out.serving_plmn.mnc_digit_length); + return out; +} diff --git a/openair3/NGAP/ngap_common.h b/openair3/NGAP/ngap_common.h index 259f0cbb18..82a8fe9234 100644 --- a/openair3/NGAP/ngap_common.h +++ b/openair3/NGAP/ngap_common.h @@ -85,6 +85,11 @@ extern int asn1_xer_print; typedef int (*ngap_message_decoded_callback)(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu); 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_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); +ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_MobilityRestrictionList_t *in); /** @}*/ diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index 488345261d..ae8d806e18 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -313,6 +313,7 @@ void *ngap_gNB_process_itti_msg(void *notUsed) { case NGAP_NAS_FIRST_REQ: ngap_gNB_handle_nas_first_req(instance, &NGAP_NAS_FIRST_REQ(received_msg)); + free_byte_array(NGAP_NAS_FIRST_REQ(received_msg).nas_pdu); break; case NGAP_UPLINK_NAS: diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index ad8efce5a3..3f6b718861 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -747,30 +747,14 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 msg->gNB_ue_ngap_id = ue_desc_p->gNB_ue_ngap_id; msg->amf_ue_ngap_id = ue_desc_p->amf_ue_ngap_id; /* id-UEAggregateMaximumBitRate */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, false); - - if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */ - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL), - &(msg->ue_ambr.br_ul)); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), - &(msg->ue_ambr.br_dl)); - } else { - NGAP_WARN("could not find NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate\n"); + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, false); + if (ie != NULL) { + msg->ue_ambr = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); } - /* id-GUAMI */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_GUAMI, true); - - TBCD_TO_MCC_MNC(&ie->value.choice.GUAMI.pLMNIdentity, msg->guami.mcc, - msg->guami.mnc, msg->guami.mnc_len); - - msg->guami.amf_region_id = BIT_STRING_to_uint8(&ie->value.choice.GUAMI.aMFRegionID); - msg->guami.amf_set_id = BIT_STRING_to_uint16(&ie->value.choice.GUAMI.aMFSetID); - msg->guami.amf_pointer = BIT_STRING_to_uint8(&ie->value.choice.GUAMI.aMFPointer); - + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_GUAMI, true); + msg->guami = decode_ngap_guami(&ie->value.choice.GUAMI); NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListCxtReq, false); if (ie != NULL) { @@ -779,17 +763,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 for (i = 0; i < ie->value.choice.PDUSessionResourceSetupListCxtReq.list.count; i++) { NGAP_PDUSessionResourceSetupItemCxtReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListCxtReq.list.array[i]; msg->pdusession_param[i].pdusession_id = item_p->pDUSessionID; - - OCTET_STRING_TO_INT8(&item_p->s_NSSAI.sST, msg->pdusession_param[i].nssai.sst); - if (item_p->s_NSSAI.sD != NULL) { - uint8_t *sd_p = (uint8_t *)&msg->pdusession_param[i].nssai.sd; - sd_p[0] = item_p->s_NSSAI.sD->buf[0]; - sd_p[1] = item_p->s_NSSAI.sD->buf[1]; - sd_p[2] = item_p->s_NSSAI.sD->buf[2]; - } else { - msg->pdusession_param[i].nssai.sd = 0xffffff; - } - + msg->pdusession_param[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); if (item_p->nAS_PDU) { msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); } @@ -799,62 +773,31 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 } /* id-AllowedNSSAI */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_AllowedNSSAI, true); - - //if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */ - NGAP_AllowedNSSAI_Item_t *allow_nssai_item_p = NULL; - - //NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); - //DevAssert(ie->value.choice.AllowedNSSAI.list.count > 0); - //DevAssert(ie->value.choice.AllowedNSSAI.list.count <= NGAP_maxnoofAllowedS_NSSAIs); - - AssertFatal(ie, "AllowedNSSAI not present, forging 2 NSSAI\n"); - - NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); - msg->nb_allowed_nssais = ie->value.choice.AllowedNSSAI.list.count; - - for(i = 0; i < ie->value.choice.AllowedNSSAI.list.count; i++) { - allow_nssai_item_p = ie->value.choice.AllowedNSSAI.list.array[i]; - - OCTET_STRING_TO_INT8(&allow_nssai_item_p->s_NSSAI.sST, msg->allowed_nssai[i].sst); - - if(allow_nssai_item_p->s_NSSAI.sD != NULL) { - msg->allowed_nssai[i].sd = 0; - BUFFER_TO_INT24((uint8_t *)allow_nssai_item_p->s_NSSAI.sD->buf, msg->allowed_nssai[i].sd); - } else { - msg->allowed_nssai[i].sd = 0xffffff; - } - } + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AllowedNSSAI, true); + NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); + msg->nb_allowed_nssais = ie->value.choice.AllowedNSSAI.list.count; + for (i = 0; i < ie->value.choice.AllowedNSSAI.list.count; i++) { + msg->allowed_nssai[i] = decode_ngap_nssai(&ie->value.choice.AllowedNSSAI.list.array[i]->s_NSSAI); + } /* id-UESecurityCapabilities */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_UESecurityCapabilities, true); + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UESecurityCapabilities, true); + msg->security_capabilities = decode_ngap_security_capabilities(&ie->value.choice.UESecurityCapabilities); - msg->security_capabilities.nRencryption_algorithms = - BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.nRencryptionAlgorithms); - msg->security_capabilities.nRintegrity_algorithms = - BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.nRintegrityProtectionAlgorithms); - msg->security_capabilities.eUTRAencryption_algorithms = - BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAencryptionAlgorithms); - msg->security_capabilities.eUTRAintegrity_algorithms = BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAintegrityProtectionAlgorithms); - - /* id-SecurityKey : Copy the security key */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_SecurityKey, true); - memcpy(&msg->security_key, ie->value.choice.SecurityKey.buf, ie->value.choice.SecurityKey.size); - - /* id-MobilityRestrictionList */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_MobilityRestrictionList, false); - - if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */ - NGAP_MobilityRestrictionList_t *mobility_rest_list_p = NULL; - mobility_rest_list_p = &ie->value.choice.MobilityRestrictionList; - - msg->mobility_restriction_flag = 1; - TBCD_TO_MCC_MNC( - &mobility_rest_list_p->servingPLMN, msg->mobility_restriction.serving_plmn.mcc, msg->mobility_restriction.serving_plmn.mnc, msg->mobility_restriction.serving_plmn.mnc_digit_length); - } + /* id-SecurityKey : Copy the security key */ + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_SecurityKey, true); + memcpy(&msg->security_key, ie->value.choice.SecurityKey.buf, ie->value.choice.SecurityKey.size); + /* id-MobilityRestrictionList */ + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_MobilityRestrictionList, + false); + if (ie != NULL) { + msg->mobility_restriction = decode_ngap_mobility_restriction(&ie->value.choice.MobilityRestrictionList); + msg->mobility_restriction_flag = true; + } /* id-NAS-PDU */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, @@ -984,10 +927,7 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 /* UE Aggregated Maximum Bitrate */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, true); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL), - &msg->ueAggMaxBitRateUplink); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), - &msg->ueAggMaxBitRateDownlink); + msg->ueAggMaxBitRate = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListSUReq, true); @@ -999,12 +939,8 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 msg->pdusession_setup_params[i].pdusession_id = item_p->pDUSessionID; // S-NSSAI - OCTET_STRING_TO_INT8(&item_p->s_NSSAI.sST, msg->pdusession_setup_params[i].nssai.sst); - if (item_p->s_NSSAI.sD != NULL) { - BUFFER_TO_INT24((uint8_t *)item_p->s_NSSAI.sD->buf, msg->pdusession_setup_params[i].nssai.sd); - } else { - msg->pdusession_setup_params[i].nssai.sd = 0xffffff; - } + msg->pdusession_setup_params[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); + OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; msg->pdusession_setup_params[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); msg->pdusession_setup_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); diff --git a/openair3/NGAP/ngap_gNB_management_procedures.c b/openair3/NGAP/ngap_gNB_management_procedures.c index e82fd1401b..6ffce99d9c 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.c +++ b/openair3/NGAP/ngap_gNB_management_procedures.c @@ -39,6 +39,8 @@ #include "queue.h" #include "tree.h" #include "ds/byte_array.h" +#include "BIT_STRING.h" +#include "common/utils/utils.h" static ngap_gNB_internal_data_t ngap_gNB_internal_data; @@ -188,3 +190,13 @@ void ngap_gNB_remove_amf_desc(ngap_gNB_instance_t * instance) free(amf); } } + +void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in) +{ + if (in.length) { + out->buf = malloc_or_fail(in.length); + memcpy(out->buf, in.buffer, in.length); + out->size = in.length; + out->bits_unused = 0; + } +} diff --git a/openair3/NGAP/ngap_gNB_management_procedures.h b/openair3/NGAP/ngap_gNB_management_procedures.h index d71480da30..365fd0dd9d 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.h +++ b/openair3/NGAP/ngap_gNB_management_procedures.h @@ -29,6 +29,7 @@ */ #include "ds/byte_array.h" +#include "BIT_STRING.h" #ifndef NGAP_GNB_MANAGEMENT_PROCEDURES_H_ #define NGAP_GNB_MANAGEMENT_PROCEDURES_H_ @@ -47,4 +48,6 @@ uint16_t ngap_gNB_fetch_add_global_cnx_id(void); void ngap_gNB_prepare_internal_data(void); +void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in); + #endif /* NGAP_GNB_MANAGEMENT_PROCEDURES_H_ */ diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 7729ffa4f2..74130e75f8 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -58,16 +58,6 @@ #include "s1ap_messages_types.h" #include "xer_encoder.h" -static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in) -{ - if (in.length) { - out->buf = malloc(in.length); - memcpy(out->buf, in.buffer, in.length); - out->size = in.length; - out->bits_unused = 0; - } -} - /** @brief Selects the AMF instance for a given UE based on identity information. * It attempts to select an AMF using the following prioritized criteria: * 1. GUAMI, if provided and valid (via Region ID, Set ID, Pointer). @@ -175,16 +165,13 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf head->value.present = NGAP_InitiatingMessage__value_PR_InitialUEMessage; NGAP_InitialUEMessage_t *out = &head->value.choice.InitialUEMessage; - /* Store the UE context in NGAP with: - * selected AMF, selected PLMN identity, gNB ID - * the unique gNB UE NGAP ID, used for the duration of the connectivity */ - struct ngap_gNB_ue_context_s *ue_desc_p = calloc_or_fail(1, sizeof(*ue_desc_p)); - DevAssert(ue_desc_p != NULL); - ue_desc_p->amf_ref = amf; - ue_desc_p->gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id; - ue_desc_p->gNB_instance = instance_p; - ue_desc_p->selected_plmn_identity = UEfirstReq->plmn; - ngap_store_ue_context(ue_desc_p); + /* Create and store NGAP UE context */ + ngap_gNB_ue_context_t ue_desc_p = { + .amf_ref = amf, + .gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id, + .gNB_instance = instance_p, + .selected_plmn_identity = UEfirstReq->plmn, + }; // RAN UE NGAP ID (M) { @@ -192,7 +179,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_RAN_UE_NGAP_ID; - ie->value.choice.RAN_UE_NGAP_ID = ue_desc_p->gNB_ue_ngap_id; + ie->value.choice.RAN_UE_NGAP_ID = ue_desc_p.gNB_ue_ngap_id; } /* NAS-PDU (M): transferred transparently */ @@ -218,7 +205,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - plmn_id_t *plmn = &ue_desc_p->selected_plmn_identity; + plmn_id_t *plmn = &ue_desc_p.selected_plmn_identity; MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); /* In case of network sharing, @@ -265,7 +252,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf DevMessage("Failed to encode initial UE message\n"); /* Update the current NGAP UE state */ - ue_desc_p->ue_state = NGAP_UE_WAITING_CSR; + ue_desc_p.ue_state = NGAP_UE_WAITING_CSR; /* Assign a stream for this UE : * From 3GPP 38.412 7)Transport layers: * Within the SCTP association established between one AMF and gNB pair: @@ -282,9 +269,13 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf if ((amf->nextstream == 0) && (amf->out_streams > 1)) { amf->nextstream += 1; } - ue_desc_p->tx_stream = amf->nextstream; + ue_desc_p.tx_stream = amf->nextstream; + + /* Create and store UE context */ + ngap_store_ue_context(&ue_desc_p); + /* Send encoded message over sctp */ - ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p->tx_stream); + ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p.tx_stream); return 0; } @@ -621,7 +612,7 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].gtp_teid, &tmp->gTP_TEID); - allocAddrCopy(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); + tnl_to_bitstring(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", item->pDUSessionID, @@ -936,7 +927,7 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); GTP_TEID_TO_ASN1(pdusession->gtp_teid, &tmp->gTP_TEID); - allocAddrCopy(&tmp->transportLayerAddress, pdusession->gNB_addr); + tnl_to_bitstring(&tmp->transportLayerAddress, pdusession->gNB_addr); NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", item->pDUSessionID, tmp->transportLayerAddress.buf[0], diff --git a/openair3/NGAP/ngap_gNB_ue_context.c b/openair3/NGAP/ngap_gNB_ue_context.c index c4b7b012ef..d0949b88c2 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.c +++ b/openair3/NGAP/ngap_gNB_ue_context.c @@ -60,8 +60,11 @@ static int ngap_gNB_compare_gNB_ue_ngap_id(struct ngap_gNB_ue_context_s *p1, str RB_GENERATE(ngap_ue_map, ngap_gNB_ue_context_s, entries, ngap_gNB_compare_gNB_ue_ngap_id); -void ngap_store_ue_context(struct ngap_gNB_ue_context_s *ue_desc_p) +void ngap_store_ue_context(const ngap_gNB_ue_context_t *ue) { + LOG_I(NGAP, "Create UE context (ID %d) for AMF '%s' (assoc_id %d)\n", ue->gNB_ue_ngap_id, ue->amf_ref->amf_name, ue->amf_ref->assoc_id); + ngap_gNB_ue_context_t *ue_desc_p = calloc_or_fail(1, sizeof(*ue_desc_p)); + *ue_desc_p = *ue; if (RB_INSERT(ngap_ue_map, &ngap_ue_head, ue_desc_p)) LOG_E(NGAP, "Bug in UE uniq number allocation %u, we try to add a existing UE\n", ue_desc_p->gNB_ue_ngap_id); return; diff --git a/openair3/NGAP/ngap_gNB_ue_context.h b/openair3/NGAP/ngap_gNB_ue_context.h index 4c0c63239f..aaf9e83bbc 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.h +++ b/openair3/NGAP/ngap_gNB_ue_context.h @@ -78,7 +78,7 @@ typedef struct ngap_gNB_ue_context_s { ngap_gNB_instance_t *gNB_instance; } ngap_gNB_ue_context_t; -void ngap_store_ue_context(ngap_gNB_ue_context_t *ue_desc_p); +void ngap_store_ue_context(const ngap_gNB_ue_context_t *ue_desc_p); ngap_gNB_ue_context_t *ngap_get_ue_context(uint32_t gNB_ue_ngap_id); ngap_gNB_ue_context_t *ngap_detach_ue_context(uint32_t gNB_ue_ngap_id); diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 20aba64e1e..a7cf27a1ff 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -41,7 +41,7 @@ #include #define FC_KENB (0x11) -#define FC_NH (0x12) +#define FC_NH (0x6F) // A.10 3GPP TS 33.501 #define FC_KENB_STAR (0x13) /* 33401 #A.7 Algorithm for key derivation function. * This FC should be used for: @@ -57,14 +57,32 @@ #define NR_FC_ALG_KEY_DER (0x69) #define NR_FC_ALG_KEY_NG_RAN_STAR_DER (0x70) -// #define SECU_DEBUG 1 +static void log_hex_buffer(const char *label, const uint8_t *buf, const int len) +{ + char hex_str[len * 2 + 1]; + for (int i = 0; i < len; i++) { + snprintf(&hex_str[i * 2], 3, "%02x", buf[i]); + } + hex_str[len * 2] = '\0'; + LOG_D(UTIL, "%s: %s\n", label, hex_str); +} + +static const char* alg_type_to_str(algorithm_type_dist_t alg_type) +{ + switch (alg_type) { + case NAS_ENC_ALG: return "NAS_ENC_ALG"; + case NAS_INT_ALG: return "NAS_INT_ALG"; + case RRC_ENC_ALG: return "RRC_ENC_ALG"; + case RRC_INT_ALG: return "RRC_INT_ALG"; + case UP_ENC_ALG: return "UP_ENC_ALG"; + case UP_INT_ALG: return "UP_INT_ALG"; + default: return "UNKNOWN_ALG_TYPE"; + } +} static void derive_key_common(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t kasme[32], uint8_t FC, uint8_t out[32]) { uint8_t s[7]; -#if defined(SECU_DEBUG) - int i; -#endif /* FC */ s[0] = FC; @@ -83,18 +101,11 @@ static void derive_key_common(algorithm_type_dist_t alg_type, uint8_t alg_id, co s[5] = 0x00; s[6] = 0x01; -#if defined(SECU_DEBUG) - printf("%s FC %d nas_alg_type distinguisher %d nas_enc_alg_identity %d\n", __FUNCTION__, FC_ALG_KEY_DER, alg_type, alg_id); - - for (i = 0; i < 7; i ++) { - printf("0x%02x ", s[i]); - } - - printf("\n"); -#endif - byte_array_t data = {.len = 7, .buf = s}; kdf(kasme, data, 32, out); + log_hex_buffer("Input key (kgnb)", kasme, 32); + log_hex_buffer("Derivation string (s)", s, 7); + log_hex_buffer(alg_type_to_str(alg_type), out, 32); } /*! @@ -139,6 +150,37 @@ void nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t * NOTE: knas is dynamically allocated by the KDF function */ +/** @brief KgNB derivation (A.9 3GPP TS 33.501) */ +void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb) +{ + /* Compute the KDF input parameter + * S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01 + */ + uint8_t input[32] = {0}; + + input[0] = 0x6E; + // P0 + input[1] = count >> 24; + input[2] = (uint8_t)(count >> 16); + input[3] = (uint8_t)(count >> 8); + input[4] = (uint8_t)count; + // L0 + input[5] = 0; + input[6] = 4; + // P1 + input[7] = 0x01; + // L1 + input[8] = 0; + input[9] = 1; + + byte_array_t data = {.buf = input, .len = 10}; + kdf(kamf, data, 32, kgnb); + + log_hex_buffer("KAMF", kamf, 32); + log_hex_buffer("KDF input for kgnb", input, 10); + log_hex_buffer("Derived kgnb", kgnb, 32); +} + void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB) { uint8_t s[7] = {0}; @@ -228,6 +270,9 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t byte_array_t data = {.buf = s, .len = 10}; const uint32_t len_key = 32; kdf(key, data, len_key, key_ng_ran_star); + log_hex_buffer("Input key", key, 32); + log_hex_buffer("KDF input for ng_ran*", s, 10); + log_hex_buffer("Derived key_ng_ran*", key_ng_ran_star, 32); } void derive_skgNB(const uint8_t *keNB, const uint16_t sk_counter, uint8_t *skgNB) @@ -248,3 +293,27 @@ void derive_skgNB(const uint8_t *keNB, const uint16_t sk_counter, uint8_t *skgNB byte_array_t data = {.buf = s, .len = 5}; kdf(keNB, data, 32, skgNB); } + +/** @brief NH derivation function (A.10 3GPP TS 33.501) + * @param k_amf: input key + * @param sync_input: pointer to the newly derived KgNB for the initial NH derivation, + * and the previous NH for all subsequent derivations + * @param nh: pointer to the derivated NH output */ +void nr_derive_nh(const uint8_t k_amf[SECURITY_KEY_LEN], const uint8_t *sync_input, uint8_t *nh) +{ + uint8_t s[SECURITY_KEY_LEN + 3] = {0}; + // FC + s[0] = FC_NH; + // P0 = SYNC-input + memcpy(&s[1], sync_input, SECURITY_KEY_LEN); + // L0 = length of SYNC-input (i.e. 0x00 0x20) + s[SECURITY_KEY_LEN + 1] = 0x00; + s[SECURITY_KEY_LEN + 2] = 0x20; + + byte_array_t data = {.buf = s, .len = sizeof(s)}; + kdf(k_amf, data, SECURITY_KEY_LEN, nh); + + log_hex_buffer("KDF input (SYNC string)", s, SECURITY_KEY_LEN + 3); + log_hex_buffer("Derived NH", nh, SECURITY_KEY_LEN); + +} diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index 4e84c5f3be..0ab14ad51a 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -5,6 +5,8 @@ #include #include +#define SECURITY_KEY_LEN 32 + typedef enum { NAS_ENC_ALG = 0x01, NAS_INT_ALG = 0x02, @@ -14,6 +16,8 @@ typedef enum { UP_INT_ALG = 0x06 } algorithm_type_dist_t; +void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb); + void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB); void derive_keNB_star(const uint8_t *kenb_32, @@ -30,4 +34,6 @@ void nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t key[32], uint8_t *key_ng_ran_star); +void nr_derive_nh(const uint8_t k_amf[SECURITY_KEY_LEN], const uint8_t *sync_input, uint8_t *nh); + #endif