Merge remote-tracking branch 'origin/n2-ho-preparation-work' into integration_2025_w24 (!3354)
Preparation Work for N2 Handover This MR introduces preliminary improvements to support !3334. Refactored utility NGAP functions - Moved allocAddrCopy to NGAP utilities Decoding Functions for NGAP IEs: - Added common decoding functions (decode_ngap_guami, decode_ngap_UEAggregateMaximumBitRate, decode_ngap_nssai, etc.) - Adopted these functions across the NGAP stack Improvements to RRC and Handover Handling: - Enhanced get_neighbour_cell_information and get_neighbour_config to differentiate input parameters (cell by NR Cell ID vs. gNB by PCI) - Used byte_array_t in nr_initiate_handover - Introduced RRCReconfigurationParams_t to structure RRCReconfiguration IEs - Added a function to build NR_RRCReconfiguration_IEs_t - Adopted this approach in do_RRCReconfiguration and refactored the function - Refactored the handling of Dedicated NAS message list - Add masterKeyUpdate handling in RRCReconfiguration generation PDCP Re-Establishment Improvements: - Enabled PDCP re-establishment for SRB1/SRB2 based on a bitmap in createSRBlist (3GPP TS 38.331 RadioBearerConfig) NH & KgNB Key Management: - Added NH derivation function as per 3GPP TS 33.501 A.10 - Moved KgNB derivation function to key_nas_deriver utilities
This commit is contained in:
@@ -34,6 +34,9 @@ SOFTWARE.
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -7,34 +7,6 @@
|
||||
#include <errno.h>
|
||||
#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() **
|
||||
|
||||
@@ -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.**
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -20,14 +20,22 @@
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "openair2/RRC/NR/MESSAGES/asn1_msg.h"
|
||||
#include "common/ran_context.h"
|
||||
#include <stdbool.h>
|
||||
#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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+176
-230
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#define RRC_GNB_MOBILITY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
/** @}*/
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user