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:
Robert Schmidt
2025-06-10 14:59:58 +02:00
29 changed files with 696 additions and 629 deletions
+3
View File
@@ -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;
-28
View File
@@ -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() **
-2
View File
@@ -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.**
+2 -5
View File
@@ -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;
+26 -31
View File
@@ -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);
+90 -93
View File
@@ -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)
+16 -12
View File
@@ -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(&params);
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();
+1 -1
View File
@@ -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;
+10
View File
@@ -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
View File
@@ -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(&params);
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(&params);
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(&params);
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(&params);
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(&params);
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);
}
}
+1 -1
View File
@@ -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};
+2 -2
View File
@@ -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 -45
View File
@@ -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)
+2 -1
View File
@@ -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
+10 -5
View File
@@ -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);
+1 -35
View File
@@ -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];
+48
View File
@@ -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;
}
+5
View File
@@ -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);
/** @}*/
+1
View File
@@ -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:
+30 -94
View File
@@ -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_ */
+18 -27
View File
@@ -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],
+4 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
+84 -15
View File
@@ -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);
}
+6
View File
@@ -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