Merge remote-tracking branch 'origin/f1-ho-prep' into integration_2024_w36

This commit is contained in:
Raphael Defosseux
2024-09-06 14:26:02 +02:00
29 changed files with 344 additions and 279 deletions
+2 -2
View File
@@ -62,12 +62,12 @@ nr_measurement_configuration = {
};
A3 = ({
cell_id = -1; #Default
physCellId = -1; #Default
offset = 10;
hysteresis = 0;
timeToTrigger = 1
}, {
cell_id = 2;
physCellId = 2;
offset = 5;
hysteresis = 1;
timeToTrigger = 2
+8 -8
View File
@@ -1161,9 +1161,9 @@ void nr_timer_stop(NR_timer_t *timer)
timer->counter = 0;
}
bool is_nr_timer_active(NR_timer_t timer)
bool nr_timer_is_active(const NR_timer_t *timer)
{
return timer.active;
return timer->active;
}
bool nr_timer_tick(NR_timer_t *timer)
@@ -1173,23 +1173,23 @@ bool nr_timer_tick(NR_timer_t *timer)
timer->counter += timer->step;
if (timer->target == UINT_MAX) // infinite target, never expires
return false;
expired = nr_timer_expired(*timer);
expired = nr_timer_expired(timer);
if (expired)
timer->active = false;
}
return expired;
}
bool nr_timer_expired(NR_timer_t timer)
bool nr_timer_expired(const NR_timer_t *timer)
{
if (timer.target == UINT_MAX) // infinite target, never expires
if (timer->target == UINT_MAX) // infinite target, never expires
return false;
return (timer.counter >= timer.target);
return timer->counter >= timer->target;
}
uint32_t nr_timer_elapsed_time(NR_timer_t timer)
uint32_t nr_timer_elapsed_time(const NR_timer_t *timer)
{
return timer.counter;
return timer->counter;
}
void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t step)
+3 -3
View File
@@ -163,19 +163,19 @@ void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t ste
* @param timer Timer to be checked
* @return Indication if the timer is expired or not
*/
bool nr_timer_expired(NR_timer_t timer);
bool nr_timer_expired(const NR_timer_t *timer);
/**
* @brief To check if a timer is active
* @param timer Timer to be checked
* @return Indication if the timer is active or not
*/
bool is_nr_timer_active(NR_timer_t timer);
bool nr_timer_is_active(const NR_timer_t *timer);
/**
* @brief To return how much time has passed since start of timer
* @param timer Timer to be checked
* @return Time passed since start of timer
*/
uint32_t nr_timer_elapsed_time(NR_timer_t timer);
uint32_t nr_timer_elapsed_time(const NR_timer_t *timer);
extern const nr_bandentry_t nr_bandtable[];
+4 -4
View File
@@ -29,13 +29,13 @@ TEST(nr_common, nr_timer) {
NR_timer_t timer;
nr_timer_setup(&timer, 10, 1);
nr_timer_start(&timer);
EXPECT_TRUE(is_nr_timer_active(timer));
EXPECT_FALSE(nr_timer_expired(timer));
EXPECT_TRUE(nr_timer_is_active(&timer));
EXPECT_FALSE(nr_timer_expired(&timer));
for (auto i = 0; i < 10; i++) {
nr_timer_tick(&timer);
}
EXPECT_FALSE(is_nr_timer_active(timer));
EXPECT_TRUE(nr_timer_expired(timer));
EXPECT_FALSE(nr_timer_is_active(&timer));
EXPECT_TRUE(nr_timer_expired(&timer));
}
@@ -320,7 +320,7 @@ typedef struct timer_elm_s {
(char *)itti_get_task_name(task_id),
-1,
OAI_PRIORITY_RT);
LOG_I(ITTI,"Created Posix thread %s\n", itti_get_task_name(task_id) );
LOG_D(ITTI,"Created Posix thread %s\n", itti_get_task_name(task_id) );
return 0;
}
-2
View File
@@ -278,8 +278,6 @@ typedef struct pdusession_s {
transport_layer_addr_t upf_addr;
/* Outgoing (UL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */
uint32_t gtp_teid;
/* Stores the DRB ID of the DRBs used by this PDU Session */
uint8_t used_drbs[MAX_DRBS_PER_UE];
/* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */
uint32_t gNB_teid_N3;
transport_layer_addr_t gNB_addr_N3;
+3 -13
View File
@@ -64,27 +64,17 @@ static void cu_task_handle_sctp_association_ind(instance_t instance,
static void cu_task_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) {
DevAssert(sctp_new_association_resp != NULL);
if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) {
enum sctp_state_e state = sctp_new_association_resp->sctp_state;
if (state != SCTP_STATE_ESTABLISHED) {
f1ap_cudu_inst_t *f1ap_cu_data = getCxt(instance);
AssertFatal(f1ap_cu_data != NULL, "illegal state: SCTP shutdown for non-existing F1AP endpoint\n");
LOG_I(F1AP, "Received SCTP shutdown for assoc_id %d, removing endpoint\n", sctp_new_association_resp->assoc_id);
LOG_I(F1AP, "Received SCTP state %d for assoc_id %d, removing endpoint\n", state, sctp_new_association_resp->assoc_id);
/* inform RRC that the DU is gone */
MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_LOST_CONNECTION);
message_p->ittiMsgHeader.originInstance = sctp_new_association_resp->assoc_id;
itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p);
return;
}
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
LOG_W(F1AP, "Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u\n",
sctp_new_association_resp->sctp_state,
instance,
sctp_new_association_resp->ulp_cnx_id);
//if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN)
//proto_agent_stop(instance);
//f1ap_handle_setup_message(instance, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
return; // exit -1 for debugging
}
}
static void cu_task_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) {
@@ -281,12 +281,9 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i
memcpy(f1ap_ue_context_setup_req->rrc_container,
ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size);
f1ap_ue_context_setup_req->rrc_container_length = ieRRC->value.choice.RRCContainer.size;
// AssertFatal(0, "check configuration, send to appropriate handler\n");
} else {
LOG_E(F1AP, " RRCContainer in UEContextSetupRequestIEs size id 0\n");
}
} else {
LOG_W(F1AP, "can't find RRCContainer in UEContextSetupRequestIEs by id %ld \n", F1AP_ProtocolIE_ID_id_RRCContainer);
}
ue_context_setup_request(f1ap_ue_context_setup_req);
@@ -596,6 +593,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_set
F1AP_SRBs_Setup_Item_t *srbs_setup_item=&srbs_setup_item_ies->value.choice.SRBs_Setup_Item;
/* sRBID */
srbs_setup_item->sRBID = resp->srbs_to_be_setup[i].srb_id;
srbs_setup_item->lCID = resp->srbs_to_be_setup[i].lcid;
}
}
+3 -3
View File
@@ -40,13 +40,13 @@ int f1ap_encode_pdu(F1AP_F1AP_PDU_t *pdu, uint8_t **buffer, uint32_t *length) {
LOG_E(F1AP, "----------------- ASN1 ENCODER PRINT END----------------- \n");
}
char errbuf[128]; /* Buffer for error message */
char errbuf[4096]; /* Buffer for error message */
size_t errlen = sizeof(errbuf); /* Size of the buffer */
int ret = asn_check_constraints(&asn_DEF_F1AP_F1AP_PDU, pdu, errbuf, &errlen);
/* assert(errlen < sizeof(errbuf)); // Guaranteed: you may rely on that */
if(ret) {
fprintf(stderr, "Constraint validation failed: %s\n", errbuf);
xer_fprint(stdout, &asn_DEF_F1AP_F1AP_PDU, pdu);
LOG_E(F1AP, "Constraint validation failed: %s\n", errbuf);
}
encoded = aper_encode_to_new_buffer(&asn_DEF_F1AP_F1AP_PDU, 0, pdu, (void **)buffer);
+8 -3
View File
@@ -1598,7 +1598,7 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc
paramdef_t NeighbourCellParams[] = GNBNEIGHBOURCELLPARAMS_DESC;
paramlist_def_t NeighbourCellParamList = {GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, NULL, 0};
config_getlist(config_get_if(), &NeighbourCellParamList, NeighbourCellParams, sizeofArray(NeighbourCellParams), neighbourpath);
LOG_D(GNB_APP, "HO LOG: For the Cell: %d 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;
@@ -1696,12 +1696,17 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc)
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->cell_id = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_CELL_ID_IDX].i64ptr;
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;
if (a3_event->cell_id == -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));
+3 -3
View File
@@ -324,12 +324,12 @@ typedef enum {
#define MEASUREMENT_EVENTS_THRESHOLD "threshold"
#define MEASUREMENT_EVENTS_PERIODICAL_BEAM_MEASUREMENT "includeBeamMeasurements"
#define MEASUREMENT_EVENTS_PERIODICAL_NR_OF_RS_INDEXES "maxNrofRS_IndexesToReport"
#define MEASUREMENT_EVENTS_CELL_ID "cell_id"
#define MEASUREMENT_EVENTS_PCI_ID "physCellId"
#define MEASUREMENT_EVENT_ENABLE "enable"
// clang-format off
#define MEASUREMENT_A3_GLOBALPARAMS_DESC \
{ \
{MEASUREMENT_EVENTS_CELL_ID, "neighbour cellId for A3Report", 0, .i64ptr = NULL, .defint64val = -1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_PCI_ID, "neighbour PCI for A3Report", 0, .i64ptr = NULL, .defint64val = -1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_TIME_TO_TRIGGER, "a3 time to trigger", 0, .i64ptr = NULL, .defint64val = 1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_OFFSET, "a3 offset", 0, .i64ptr = NULL, .defint64val = 60, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_HYSTERESIS, "a3 hysteresis", 0, .i64ptr = NULL, .defint64val = 0, TYPE_INT64, 0}, \
@@ -350,7 +350,7 @@ typedef enum {
}
// clang-format on
#define MEASUREMENT_EVENTS_CELL_ID_IDX 0
#define MEASUREMENT_EVENTS_PCI_ID_IDX 0
#define MEASUREMENT_EVENTS_ENABLE_IDX 0
#define MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX 1
#define MEASUREMENT_EVENTS_A2_THRESHOLD_IDX 2
+2 -2
View File
@@ -790,7 +790,7 @@ void nr_ue_get_rach(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, uint8_t gNB
}
}
if (is_nr_timer_active(ra->contention_resolution_timer)) {
if (nr_timer_is_active(&ra->contention_resolution_timer)) {
nr_ue_contention_resolution(mac, CC_id, frame, nr_slot_tx, prach_resources);
}
}
@@ -851,7 +851,7 @@ void nr_ue_contention_resolution(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame
{
RA_config_t *ra = &mac->ra;
if (nr_timer_expired(ra->contention_resolution_timer)) {
if (nr_timer_expired(&ra->contention_resolution_timer)) {
ra->t_crnti = 0;
nr_timer_stop(&ra->contention_resolution_timer);
// Signal PHY to quit RA procedure
+1 -1
View File
@@ -2543,7 +2543,7 @@ int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_Schedu
sr_id); // todo
// TODO check if the PUCCH resource for the SR transmission occasion does not overlap with a UL-SCH resource
if (!sr_info->pending || is_nr_timer_active(sr_info->prohibitTimer))
if (!sr_info->pending || nr_timer_is_active(&sr_info->prohibitTimer))
return 0;
if (sr_info->counter < sr_info->maxTransmissions) {
+2 -2
View File
@@ -1297,7 +1297,7 @@ static void nr_update_sr(NR_UE_MAC_INST_t *mac)
// if a Regular BSR has been triggered and logicalChannelSR-DelayTimer is not running
if (((sched_info->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR) == 0)
|| is_nr_timer_active(sched_info->sr_DelayTimer))
|| nr_timer_is_active(&sched_info->sr_DelayTimer))
return;
nr_lcordered_info_t *lc_info = get_lc_info_from_lcid(mac, sched_info->regularBSR_trigger_lcid);
@@ -1527,7 +1527,7 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info)
NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
int32_t bj = sched_info->Bj;
if (lc_info->pbr < UINT_MAX) {
uint32_t slots_elapsed = nr_timer_elapsed_time(sched_info->Bj_timer); // slots elapsed since Bj was last incremented
uint32_t slots_elapsed = nr_timer_elapsed_time(&sched_info->Bj_timer); // slots elapsed since Bj was last incremented
// it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s
uint32_t pbr_ms = lc_info->pbr / 1000;
bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms
@@ -560,7 +560,7 @@ static void start_ra_contention_resolution_timer(NR_RA_t *ra, const long ra_Cont
// Value sf8 corresponds to 8 subframes, value sf16 corresponds to 16 subframes, and so on.
// We add 2 * K2 because the timer runs from Msg2 transmission till Msg4 ACK reception
ra->contention_resolution_timer = ((((int)ra_ContentionResolutionTimer + 1) * 8) << scs) + 2 * K2;
LOG_I(NR_MAC,
LOG_D(NR_MAC,
"Starting RA Contention Resolution timer with %d ms + 2 * %d K2 (%d slots) duration\n",
((int)ra_ContentionResolutionTimer + 1) * 8,
K2,
@@ -860,12 +860,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
// re-initialize ta update variables after RA procedure completion
UE->UE_sched_ctrl.ta_frame = frameP;
LOG_I(NR_MAC,
"[gNB %d][RAPROC] PUSCH with TC_RNTI 0x%04x received correctly, "
"adding UE MAC Context RNTI 0x%04x\n",
gnb_mod_idP,
current_rnti,
ra->rnti);
LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frameP, slotP, current_rnti);
NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl;
if (ul_cqi != 0xff) {
@@ -884,7 +879,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, ra->CellGroup->rlc_BearerToAddModList);
nr_clear_ra_proc(ra);
} else {
LOG_A(NR_MAC, "[RAPROC] RA-Msg3 received (sdu_lenP %d)\n", sdu_lenP);
LOG_D(NR_MAC, "[RAPROC] Received Msg3:\n");
for (uint32_t k = 0; k < sdu_lenP; k++) {
LOG_D(NR_MAC, "(%i): 0x%x\n", k, sduP[k]);
@@ -233,7 +233,8 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE,
nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .priority = priority};
nr_mac_add_lcid(&UE->UE_sched_ctrl, &c);
(*resp_srbs)[i] = *srb;
(*resp_srbs)[i].srb_id = srb->srb_id;
(*resp_srbs)[i].lcid = c.lcid;
int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig);
DevAssert(ret == 0);
@@ -669,8 +670,12 @@ void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd)
NR_SCHED_LOCK(&mac->sched_lock);
NR_UE_info_t *UE = find_nr_UE(&mac->UE_info, cmd->gNB_DU_ue_id);
if (UE == NULL) {
LOG_E(MAC, "ERROR: unknown UE with RNTI %04x, ignoring UE Context Release Command\n", cmd->gNB_DU_ue_id);
NR_SCHED_UNLOCK(&mac->sched_lock);
f1ap_ue_context_release_complete_t complete = {
.gNB_CU_ue_id = cmd->gNB_CU_ue_id,
.gNB_DU_ue_id = cmd->gNB_DU_ue_id,
};
mac->mac_rrc.ue_context_release_complete(&complete);
return;
}
@@ -743,7 +748,7 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
* the new UE context (with new C-RNTI), but set up everything to reuse the
* old config. */
NR_UE_info_t *oldUE = find_nr_UE(&mac->UE_info, *dl_rrc->old_gNB_DU_ue_id);
DevAssert(oldUE);
AssertFatal(oldUE, "CU claims we should know UE %04x, but we don't\n", *dl_rrc->old_gNB_DU_ue_id);
pthread_mutex_lock(&mac->sched_lock);
/* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it
* from the current configuration. Also, expect the reconfiguration from
+8 -9
View File
@@ -1165,10 +1165,9 @@ static NR_ReportConfigToAddMod_t *prepare_a2_event_report(const nr_a2_event_t *a
static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a3_event)
{
NR_ReportConfigToAddMod_t *rc_A3 = calloc(1, sizeof(*rc_A3));
rc_A3->reportConfigId =
a3_event->cell_id == -1
? 3
: a3_event->cell_id + 4; // 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID starts from 4
// 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID
// starts from 4
rc_A3->reportConfigId = a3_event->pci == -1 ? 3 : a3_event->pci + 4;
rc_A3->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR;
NR_EventTriggerConfig_t *etrc_A3 = calloc(1, sizeof(*etrc_A3));
etrc_A3->eventId.present = NR_EventTriggerConfig__eventId_PR_eventA3;
@@ -1194,7 +1193,7 @@ static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a
return rc_A3;
}
const nr_a3_event_t *get_a3_configuration(int nr_cellid)
const nr_a3_event_t *get_a3_configuration(int pci)
{
gNB_RRC_INST *rrc = RC.nrrrc[0];
nr_measurement_configuration_t *measurementConfiguration = &rrc->measurementConfiguration;
@@ -1203,7 +1202,7 @@ const nr_a3_event_t *get_a3_configuration(int nr_cellid)
for (uint8_t i = 0; i < measurementConfiguration->a3_event_list->size; i++) {
nr_a3_event_t *a3_event = (nr_a3_event_t *)seq_arr_at(measurementConfiguration->a3_event_list, i);
if (a3_event->cell_id == nr_cellid)
if (a3_event->pci == pci)
return a3_event;
}
@@ -1262,11 +1261,11 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
if (!neighbourCell->isIntraFrequencyNeighbour)
continue;
const nr_a3_event_t *a3Event = get_a3_configuration(neighbourCell->nrcell_id);
const nr_a3_event_t *a3Event = get_a3_configuration(neighbourCell->physicalCellId);
if (!a3Event || is_default_a3_added)
continue;
if (a3Event->cell_id == -1)
if (a3Event->pci == -1)
is_default_a3_added = true;
NR_ReportConfigToAddMod_t *rc_A3 = prepare_a3_event_report(a3Event);
@@ -1368,7 +1367,7 @@ int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi)
LOG_D(NR_RRC, "[gNB %d] do_Paging paging_record: PagingRecordList.count %d\n",
Mod_id, c1->choice.paging->pagingRecordList->list.count);
asn_enc_rval_t enc_rval = uper_encode_to_buffer(
&asn_DEF_NR_PCCH_Message, NULL, (void *)&pcch_msg, buffer, RRC_BUF_SIZE);
&asn_DEF_NR_PCCH_Message, NULL, (void *)&pcch_msg, buffer, NR_RRC_BUF_SIZE);
if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
xer_fprint(stdout, &asn_DEF_NR_PCCH_Message, (void *)&pcch_msg);
+1 -1
View File
@@ -143,7 +143,7 @@ int do_RRCReestablishment(rrc_gNB_ue_context_t *const ue_context_pP,
int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t rrc_TransactionIdentifier);
const nr_a3_event_t *get_a3_configuration(int nr_cellid);
const nr_a3_event_t *get_a3_configuration(int pci);
NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
int band,
int scs,
-8
View File
@@ -26,17 +26,9 @@
#include <stdlib.h>
#include <stdint.h>
#define NR_RRC_HEADER_SIZE_MAX 64
#define NR_RRC_BUFFER_SIZE_MAX 1024
#define NR_NUM_SRB 4 /* Number of Signalling Radio Bearers according to clause 4.2.2 of 3GPP TS 38.331 */
#define NR_K_KEY_SIZE 16 /* K keys have 128 bits length */
typedef struct {
char Payload[NR_RRC_BUFFER_SIZE_MAX];
char Header[NR_RRC_HEADER_SIZE_MAX];
uint16_t payload_size;
} NR_RRC_BUFFER;
typedef enum UE_STATE_NR_e {
NR_RRC_INACTIVE=0,
NR_RRC_IDLE,
+12 -12
View File
@@ -2805,6 +2805,8 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
&& servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count > 0) {
n_dl_bwp = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count;
}
int default_dl_bwp = 0;
int first_active_dl_bwp = 0;
if (n_dl_bwp > 0) {
SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList =
calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList));
@@ -2813,15 +2815,13 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
config_downlinkBWP(bwp, scc, servingcellconfigdedicated, NULL, 0, false, bwp_loop, true);
asn1cSeqAdd(&SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list, bwp);
}
SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id =
calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id));
*SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id =
servingcellconfigdedicated->firstActiveDownlinkBWP_Id ? *servingcellconfigdedicated->firstActiveDownlinkBWP_Id : 1;
SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id =
calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id));
*SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id =
servingcellconfigdedicated->defaultDownlinkBWP_Id ? *servingcellconfigdedicated->defaultDownlinkBWP_Id : 1;
const NR_BWP_Id_t *firstActiveDownlinkBWP_Id = servingcellconfigdedicated->firstActiveDownlinkBWP_Id;
first_active_dl_bwp = firstActiveDownlinkBWP_Id ? *firstActiveDownlinkBWP_Id : 1;
const NR_BWP_Id_t *defaultDownlinkBWP_Id = servingcellconfigdedicated->defaultDownlinkBWP_Id;
default_dl_bwp = defaultDownlinkBWP_Id ? *defaultDownlinkBWP_Id : 1;
}
asn1cCallocOne(SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id, first_active_dl_bwp);
asn1cCallocOne(SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id, default_dl_bwp);
// Uplink BWPs
int n_ul_bwp = 0;
@@ -2830,6 +2830,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
&& servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count > 0) {
n_ul_bwp = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count;
}
int first_active_ul_bwp = 0;
if (n_ul_bwp > 0) {
uplinkConfig->uplinkBWP_ToAddModList = calloc(1, sizeof(*uplinkConfig->uplinkBWP_ToAddModList));
for (int bwp_loop = 0; bwp_loop < n_ul_bwp; bwp_loop++) {
@@ -2837,11 +2838,10 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
config_uplinkBWP(ubwp, bwp_loop, true, uid, configuration, servingcellconfigdedicated, scc, NULL);
asn1cSeqAdd(&uplinkConfig->uplinkBWP_ToAddModList->list, ubwp);
}
uplinkConfig->firstActiveUplinkBWP_Id = calloc(1, sizeof(*uplinkConfig->firstActiveUplinkBWP_Id));
*uplinkConfig->firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id
? *servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id
: 1;
const NR_BWP_Id_t *firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id;
first_active_ul_bwp = firstActiveUplinkBWP_Id ? *firstActiveUplinkBWP_Id : 1;
}
asn1cCallocOne(uplinkConfig->firstActiveUplinkBWP_Id, first_active_ul_bwp);
SpCellConfig->spCellConfigDedicated->csi_MeasConfig = calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->csi_MeasConfig));
SpCellConfig->spCellConfigDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup;
+14 -40
View File
@@ -88,15 +88,6 @@
#define NR_RRC_RECONFIGURATION_DELAY_MS 10
#define NR_RRC_BWP_SWITCHING_DELAY_MS 6
// 3GPP TS 38.133 - Section 8 - Table 8.2.1.2.7-2: Parameters which cause interruption other than SCS
// This table was recently added to 3GPP. It shows that changing the parameters locationAndBandwidth, nrofSRS-Ports or
// maxMIMO-Layers-r16 causes an interruption. This parameter is not yet being used in code, but has been placed here
// for future reference.
#define NR_OF_SRS_PORTS_SWITCHING_DELAY_MS 30
#define NR_UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!!
#define NR_UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1
typedef enum {
NR_RRC_OK=0,
NR_RRC_ConnSetup_failed,
@@ -105,17 +96,11 @@ typedef enum {
NR_RRC_HO_STARTED
} NR_RRC_status_t;
#define RRM_FREE(p) if ( (p) != NULL) { free(p) ; p=NULL ; }
#define RRM_MALLOC(t,n) (t *) malloc16( sizeof(t) * n )
#define RRM_CALLOC(t,n) (t *) malloc16( sizeof(t) * n)
#define RRM_CALLOC2(t,s) (t *) malloc16( s )
#define MAX_MEAS_OBJ 7
#define MAX_MEAS_CONFIG 7
#define MAX_MEAS_ID 7
#define PAYLOAD_SIZE_MAX 1024
#define RRC_BUF_SIZE 1024
#define NR_RRC_BUF_SIZE 4096
#define UNDEF_SECURITY_MODE 0xff
#define NO_SECURITY_MODE 0x20
@@ -129,14 +114,6 @@ typedef struct UE_S_TMSI_NR_s {
uint32_t fiveg_tmsi;
} __attribute__ ((__packed__)) NR_UE_S_TMSI;
typedef enum nr_e_rab_satus_e {
NR_E_RAB_STATUS_NEW,
NR_E_RAB_STATUS_DONE, // from the gNB perspective
NR_E_RAB_STATUS_ESTABLISHED, // get the reconfigurationcomplete form UE
NR_E_RAB_STATUS_FAILED,
} nr_e_rab_status_t;
typedef struct nr_e_rab_param_s {
e_rab_t param;
uint8_t status;
@@ -156,12 +133,10 @@ typedef struct HANDOVER_INFO_NR_s {
//AS_Config_t as_config; /* these two parameters are taken from 36.331 section 10.2.2: HandoverPreparationInformation-r8-IEs */
//AS_Context_t as_context; /* They are mandatory for HO */
uint8_t buf[RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */
uint8_t buf[NR_RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */
int size; /* size of above message in bytes */
} NR_HANDOVER_INFO;
#define NR_RRC_BUFFER_SIZE sizeof(RRC_BUFFER_NR)
typedef struct nr_rrc_guami_s {
uint16_t mcc;
uint16_t mnc;
@@ -194,19 +169,15 @@ typedef struct pdu_session_param_s {
* @brief F1-U tunnel configuration
*/
typedef struct f1u_tunnel_s {
/* Downlink F1-U Tunnel Endpoint Identifier (CU-UP/DU) */
uint32_t cuup_teid_f1u;
/* DL F1-U Transport Layer */
transport_layer_addr_t cuup_addr_f1u;
/* F1-U Tunnel Endpoint Identifier (on DU side) */
uint32_t teid;
/* Downlink F1-U Transport Layer (on DU side) */
transport_layer_addr_t addr;
} f1u_tunnel_t;
typedef struct drb_s {
int status;
int defaultDRBid;
int drb_id;
int reestablishPDCP;
int recoverPDCP;
int daps_Config_r16;
struct cnAssociation_s {
int present;
int eps_BearerIdentity;
@@ -232,8 +203,10 @@ typedef struct drb_s {
int cipheringDisabled;
} ext1;
} pdcp_config;
// F1-U
f1u_tunnel_t f1u_tunnel_config;
// F1-U Downlink Tunnel Config (on DU side)
f1u_tunnel_t du_tunnel_config;
// F1-U Uplink Tunnel Config (on CU-UP side)
f1u_tunnel_t cuup_tunnel_config;
} drb_t;
typedef enum {
@@ -284,7 +257,6 @@ typedef struct gNB_RRC_UE_s {
NR_CipheringAlgorithm_t ciphering_algorithm;
e_NR_IntegrityProtAlgorithm integrity_algorithm;
NR_UE_STATE_t StatusRrc;
rnti_t rnti;
uint64_t random_ue_identity;
@@ -317,6 +289,8 @@ typedef struct gNB_RRC_UE_s {
uint32_t ue_reestablishment_counter;
uint32_t ue_reconfiguration_counter;
bool an_release; // flag if core requested UE release
/* NGUEContextSetup might come with PDU sessions, but setup needs to be
* delayed after security (and capability); PDU sessions are stored here */
int n_initial_pdu;
@@ -368,7 +342,7 @@ typedef struct {
} nr_a2_event_t;
typedef struct {
int cell_id;
int pci;
long a3_offset;
long hysteresis;
long timeToTrigger;
@@ -393,7 +367,7 @@ typedef struct {
} nr_neighbour_gnb_configuration_t;
typedef struct neighbour_cell_configuration_s {
int nr_cell_id;
uint64_t nr_cell_id;
seq_arr_t *neighbour_cells;
} neighbour_cell_configuration_t;
+169 -125
View File
@@ -113,9 +113,9 @@ mui_t rrc_gNB_mui = 0;
// the assoc_id might be 0 (if the DU goes offline). Below helper macro to
// print an error and return from the function in that case
#define RETURN_IF_INVALID_ASSOC_ID(ue_data) \
#define RETURN_IF_INVALID_ASSOC_ID(assoc_id) \
{ \
if (ue_data.du_assoc_id == 0) { \
if (assoc_id == 0) { \
LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n"); \
return; \
} \
@@ -197,7 +197,7 @@ void nr_rrc_transfer_protected_rrc_message(const gNB_RRC_INST *rrc,
{
DevAssert(size > 0);
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
f1ap_dl_rrc_message_t dl_rrc = {.gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, .srb_id = srb_id};
deliver_dl_rrc_message_data_t data = {.rrc = rrc, .dl_rrc = &dl_rrc, .assoc_id = ue_data.du_assoc_id};
nr_pdcp_data_req_srb(ue_p->rrc_ue_id,
@@ -345,7 +345,6 @@ static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish)
if (ue->established_drbs[i].status != DRB_INACTIVE) {
DRB_config = generateDRB_ASN1(&ue->established_drbs[i]);
if (reestablish) {
ue->established_drbs[i].reestablishPDCP = NR_DRB_ToAddMod__reestablishPDCP_true;
asn1cCallocOne(DRB_config->reestablishPDCP, NR_DRB_ToAddMod__reestablishPDCP_true);
}
asn1cSeqAdd(&DRB_configList->list, DRB_config);
@@ -424,7 +423,7 @@ static void rrc_gNB_generate_RRCSetup(instance_t instance,
LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buf, size, "[MSG] RRC Setup\n");
freeSRBlist(SRBs);
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
f1ap_dl_rrc_message_t dl_rrc = {
.gNB_CU_ue_id = ue_p->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
@@ -454,7 +453,7 @@ static void rrc_gNB_generate_RRCReject(module_id_t module_id, rrc_gNB_ue_context
LOG_I(NR_RRC, " [RAPROC] ue %04x Logical Channel DL-CCCH, Generating NR_RRCReject (bytes %d)\n", ue_p->rnti, size);
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
f1ap_dl_rrc_message_t dl_rrc = {
.gNB_CU_ue_id = ue_p->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
@@ -477,7 +476,6 @@ static void rrc_gNB_process_RRCSetupComplete(const protocol_ctxt_t *const ctxt_p
LOG_A(NR_RRC, "UE %d Processing NR_RRCSetupComplete from UE\n", ue_context_pP->ue_context.rrc_ue_id);
ue_context_pP->ue_context.Srb[1].Active = 1;
ue_context_pP->ue_context.Srb[2].Active = 0;
ue_context_pP->ue_context.StatusRrc = NR_RRC_CONNECTED;
AssertFatal(ctxt_pP->rntiMaybeUEid == ue_context_pP->ue_context.rrc_ue_id, "logic bug: inconsistent IDs, must use CU UE ID!\n");
rrc_gNB_send_NGAP_NAS_FIRST_REQ(ctxt_pP, ue_context_pP, rrcSetupComplete);
@@ -549,13 +547,13 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c
ue_p->measConfig = measconfig;
uint8_t buffer[RRC_BUF_SIZE] = {0};
uint8_t buffer[NR_RRC_BUF_SIZE] = {0};
NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false);
NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false);
int size = do_RRCReconfiguration(ue_p,
buffer,
RRC_BUF_SIZE,
NR_RRC_BUF_SIZE,
xid,
SRBs,
DRBs,
@@ -676,10 +674,10 @@ rrc_gNB_modify_dedicatedRRCReconfiguration(
}
NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false);
uint8_t buffer[RRC_BUF_SIZE];
uint8_t buffer[NR_RRC_BUF_SIZE];
int size = do_RRCReconfiguration(ue_p,
buffer,
RRC_BUF_SIZE,
NR_RRC_BUF_SIZE,
xid,
NULL,
DRBs,
@@ -742,10 +740,10 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release(
LOG_W(NR_RRC,"dedlicated NAS list is empty\n");
}
uint8_t buffer[RRC_BUF_SIZE] = {0};
uint8_t buffer[NR_RRC_BUF_SIZE] = {0};
int size = do_RRCReconfiguration(ue_p,
buffer,
RRC_BUF_SIZE,
NR_RRC_BUF_SIZE,
xid,
NULL,
NULL,
@@ -808,7 +806,8 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
return;
/* loop through active DRBs */
for (int drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) {
if (ue_p->established_drbs[drb_id - 1].status == DRB_INACTIVE)
drb_t *drb = get_drb(ue_p, drb_id);
if (drb->status == DRB_INACTIVE)
continue;
/* fetch an existing PDU session for this DRB */
rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue_p, drb_id);
@@ -829,13 +828,11 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify];
drb_e1->id = drb_id;
drb_e1->numDlUpParam = 1;
drb_t *drbs = &ue_p->established_drbs[drb_id];
memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drbs->f1u_tunnel_config.cuup_addr_f1u.buffer, sizeof(uint8_t) * 4);
drb_e1->DlUpParamList[0].teId = drbs->f1u_tunnel_config.cuup_teid_f1u;
memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4);
drb_e1->DlUpParamList[0].teId = drb->du_tunnel_config.teid;
/* PDCP configuration */
bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config;
drb_t *rrc_drb = get_drb(ue_p, drb_id);
set_bearer_context_pdcp_config(pdcp_config, rrc_drb, rrc->configuration.um_on_default_drb);
set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb);
pdcp_config->pDCP_Reestablishment = true;
/* increase DRB to modify counter */
pdu_e1->numDRB2Modify += 1;
@@ -863,12 +860,12 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context
module_id_t module_id = 0;
gNB_RRC_INST *rrc = RC.nrrrc[module_id];
gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context;
uint8_t buffer[RRC_BUF_SIZE] = {0};
uint8_t buffer[NR_RRC_BUF_SIZE] = {0};
uint8_t xid = rrc_gNB_get_next_transaction_identifier(module_id);
ue_p->xids[xid] = RRC_REESTABLISH;
const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
uint32_t ssb_arfcn = get_ssb_arfcn(du);
int size = do_RRCReestablishment(ue_context_pP, buffer, RRC_BUF_SIZE, xid, cell_info->nr_pci, ssb_arfcn);
int size = do_RRCReestablishment(ue_context_pP, buffer, NR_RRC_BUF_SIZE, xid, cell_info->nr_pci, ssb_arfcn);
LOG_I(NR_RRC, "[RAPROC] UE %04x Logical Channel DL-DCCH, Generating NR_RRCReestablishment (bytes %d)\n", ue_p->rnti, size);
@@ -902,7 +899,7 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context
&security_parameters);
/* F1AP DL RRC Message Transfer */
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
uint32_t old_gNB_DU_ue_id = old_rnti;
f1ap_dl_rrc_message_t dl_rrc = {.gNB_CU_ue_id = ue_p->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
@@ -935,7 +932,6 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co
int i = 0;
ue_p->xids[xid] = RRC_ACTION_NONE;
ue_p->StatusRrc = NR_RRC_CONNECTED;
ue_p->Srb[1].Active = 1;
@@ -987,10 +983,10 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co
uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id);
ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE;
uint8_t buffer[RRC_BUF_SIZE] = {0};
uint8_t buffer[NR_RRC_BUF_SIZE] = {0};
int size = do_RRCReconfiguration(ue_p,
buffer,
RRC_BUF_SIZE,
NR_RRC_BUF_SIZE,
new_xid,
SRBs,
DRBs,
@@ -1031,8 +1027,8 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP,
*masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = ul_bwp_id;
}
uint8_t buffer[RRC_BUF_SIZE];
int size = do_RRCReconfiguration(ue_p, buffer, RRC_BUF_SIZE, xid, NULL, NULL, NULL, NULL, NULL, NULL, masterCellGroup);
uint8_t buffer[NR_RRC_BUF_SIZE];
int size = do_RRCReconfiguration(ue_p, buffer, NR_RRC_BUF_SIZE, xid, NULL, NULL, NULL, NULL, NULL, NULL, masterCellGroup);
gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size);
@@ -1120,7 +1116,9 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
uint64_t random_value = 0;
const char *scause = get_reestab_cause(req->reestablishmentCause);
const long physCellId = req->ue_Identity.physCellId;
LOG_D(NR_RRC, "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", msg->crnti, physCellId, scause);
long ngap_cause = NGAP_CAUSE_RADIO_NETWORK_UNSPECIFIED; /* cause in case of NGAP release req */
rrc_gNB_ue_context_t *ue_context_p = NULL;
LOG_I(NR_RRC, "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", msg->crnti, physCellId, scause);
const nr_rrc_du_container_t *du = get_du_by_assoc_id(rrc, assoc_id);
if (du == NULL) {
@@ -1128,6 +1126,13 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
return;
}
// 3GPP TS 38.321 version 15.13.0 Section 7.1 Table 7.1-1: RNTI values
if (req->ue_Identity.c_RNTI < 0x1 || req->ue_Identity.c_RNTI > 0xffef) {
/* c_RNTI range error should not happen */
LOG_E(NR_RRC, "NR_RRCReestablishmentRequest c_RNTI %04lx range error, fallback to RRC setup\n", req->ue_Identity.c_RNTI);
goto fallback_rrc_setup;
}
if (du->mib == NULL || du->sib1 == NULL) {
/* we don't have MIB/SIB1 of the DU, and therefore cannot generate the
* Reestablishment (as we would need the SSB's ARFCN, which we cannot
@@ -1136,12 +1141,22 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
goto fallback_rrc_setup;
}
if (du->mtc == NULL) {
// some UEs don't send MeasurementTimingConfiguration, so we don't know the
// SSB ARFCN and can't do reestablishment. handle it gracefully by doing
// RRC setup procedure instead
LOG_E(NR_RRC, "no MeasurementTimingConfiguration for this cell, cannot perform reestablishment\n");
ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON;
goto fallback_rrc_setup;
}
rnti_t old_rnti = req->ue_Identity.c_RNTI;
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti);
ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti);
if (ue_context_p == NULL) {
LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n");
goto fallback_rrc_setup;
}
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
if (physCellId != cell_info->nr_pci) {
@@ -1150,6 +1165,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
"RRC Reestablishment Request from different physCellId (%ld) than current physCellId (%d), fallback to RRC setup\n",
physCellId,
cell_info->nr_pci);
ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON;
/* 38.401 8.7: "If the UE accessed from a gNB-DU other than the original
* one, the gNB-CU should trigger the UE Context Setup procedure". Let's
* assume that the old DU will trigger a release request, also freeing the
@@ -1157,25 +1173,10 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
goto fallback_rrc_setup;
}
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
// 3GPP TS 38.321 version 15.13.0 Section 7.1 Table 7.1-1: RNTI values
if (req->ue_Identity.c_RNTI < 0x1 || req->ue_Identity.c_RNTI > 0xffef) {
/* c_RNTI range error should not happen */
LOG_E(NR_RRC, "NR_RRCReestablishmentRequest c_RNTI %04lx range error, fallback to RRC setup\n", req->ue_Identity.c_RNTI);
goto fallback_rrc_setup;
}
if (!UE->as_security_active) {
/* no active security context, need to restart entire connection */
LOG_E(NR_RRC, "UE requested Reestablishment without activated AS security\n");
goto fallback_rrc_setup;
}
if (du->mtc == NULL) {
// some UEs don't send MeasurementTimingConfiguration, so we don't know the
// SSB ARFCN and can't do reestablishment. handle it gracefully by doing
// RRC setup procedure instead
LOG_E(NR_RRC, "no MeasurementTimingConfiguration for this cell, cannot perform reestablishment\n");
ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON;
goto fallback_rrc_setup;
}
@@ -1188,8 +1189,6 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
cu_remove_f1_ue_data(UE->rrc_ue_id);
cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data);
LOG_I(NR_RRC, "Accept Reestablishment Request UE physCellId %ld cause %s\n", physCellId, scause);
rrc_gNB_generate_RRCReestablishment(ue_context_p, msg->du2cu_rrc_container, old_rnti, du);
return;
@@ -1197,6 +1196,10 @@ fallback_rrc_setup:
fill_random(&random_value, sizeof(random_value));
random_value = random_value & 0x7fffffffff; /* random value is 39 bits */
/* request release of the "old" UE in case it exists */
if (ue_context_p != NULL)
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(0, ue_context_p, NGAP_CAUSE_RADIO_NETWORK, ngap_cause);
rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id);
activate_srb(&new->ue_context, 1);
rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length);
@@ -1228,11 +1231,11 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report,
switch (event_triggered->eventId.present) {
case NR_EventTriggerConfig__eventId_PR_eventA2:
LOG_I(NR_RRC, "\nHO LOG: Event A2 (Serving becomes worse than threshold)\n");
LOG_I(NR_RRC, "HO LOG: Event A2 (Serving becomes worse than threshold)\n");
break;
case NR_EventTriggerConfig__eventId_PR_eventA3: {
LOG_I(NR_RRC, "\nHO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n");
LOG_I(NR_RRC, "HO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n");
const NR_MeasResults_t *measResults = &measurementReport->criticalExtensions.choice.measurementReport->measResults;
for (int serving_cell_idx = 0; serving_cell_idx < measResults->measResultServingMOList.list.count; serving_cell_idx++) {
@@ -1267,7 +1270,7 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report,
}
LOG_I(NR_RRC,
"HO LOG: Measurement Report has came for the neighbour: %d with RSRP: %d\n",
"HO LOG: Measurement Report for the neighbour %d with RSRP: %d\n",
neighbourCellId,
neighbourCellRSRP);
@@ -1279,7 +1282,7 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report,
// neighbour.
if (!neighbour_cell_du_context && neighbour) {
// No F1 connection but static neighbour configuration is available
const nr_a3_event_t *a3_event_configuration = get_a3_configuration(neighbour->nrcell_id);
const nr_a3_event_t *a3_event_configuration = get_a3_configuration(neighbour->physicalCellId);
// Additional check - This part can be modified according to additional cell specific Handover Margin
if (a3_event_configuration
&& ((a3_event_configuration->a3_offset + a3_event_configuration->hysteresis)
@@ -1864,15 +1867,39 @@ static void fill_e1_bearer_modif(DRB_nGRAN_to_setup_t *drb_e1, const f1ap_drb_to
/**
* @brief Store F1-U DL TL and TEID in RRC
*/
static void f1u_gtp_update(f1u_tunnel_t *f1u, const f1ap_drb_to_be_setup_t *drb_f1)
static void f1u_dl_gtp_update(f1u_tunnel_t *f1u, const f1ap_up_tnl_t *p)
{
f1u->cuup_teid_f1u = drb_f1->up_dl_tnl[0].teid;
memcpy(&f1u->cuup_addr_f1u.buffer, &drb_f1->up_dl_tnl[0].tl_address, sizeof(uint8_t) * 4);
f1u->cuup_addr_f1u.length = sizeof(in_addr_t);
f1u->teid = p->teid;
memcpy(&f1u->addr.buffer, &p->tl_address, sizeof(uint8_t) * 4);
f1u->addr.length = sizeof(in_addr_t);
}
/**
* @brief Update DRB TEID information in RRC storage from received DRB list
*/
static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_RRC_UE_t *ue)
{
for (int i = 0; i < n; i++) {
const f1ap_drb_to_be_setup_t *drb_f1 = &drbs[i];
AssertFatal(drb_f1->up_dl_tnl_length == 1, "can handle only one UP param\n");
AssertFatal(drb_f1->drb_id < MAX_DRBS_PER_UE, "illegal DRB ID %ld\n", drb_f1->drb_id);
drb_t *drb = get_drb(ue, drb_f1->drb_id);
f1u_dl_gtp_update(&drb->du_tunnel_config, &drb_f1->up_dl_tnl[0]);
}
}
/*
* @brief Store F1-U UL TEID and address in RRC
*/
static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p)
{
f1u->teid = p->teId;
memcpy(&f1u->addr.buffer, &p->tlAddress, sizeof(uint8_t) * 4);
f1u->addr.length = sizeof(in_addr_t);
}
/* \brief use list of DRBs and send the corresponding bearer update message via
* E1 to the CU of this UE */
* E1 to the CU of this UE. Also updates TEID info internally */
static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs)
{
// we assume the same UE ID in CU-UP and CU-CP
@@ -1892,7 +1919,6 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f
DevAssert(pdu_e1 != NULL);
pdu_e1->sessionId = pdu_ue->param.pdusession_id;
DRB_nGRAN_to_setup_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify];
f1u_gtp_update(&UE->established_drbs[drb_f1->drb_id].f1u_tunnel_config, drb_f1);
/* Fill E1 bearer context modification */
fill_e1_bearer_modif(drb_e1, drb_f1);
pdu_e1->numDRB2Modify += 1;
@@ -1942,6 +1968,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance
/* Note: we would ideally check that SRB2 is acked, but at least LiteOn DU
* seems buggy and does not ack, so simply check that locally we activated */
AssertFatal(UE->Srb[1].Active && UE->Srb[2].Active, "SRBs 1 and 2 must be active during DRB Establishment");
store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE);
e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup);
}
@@ -2003,7 +2030,13 @@ static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p)
return;
}
rrc_remove_ue(RC.nrrrc[0], ue_context_p);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
if (UE->an_release) {
/* only trigger release if it has been requested by core
* otherwise, it might be CU that requested release on a DU during normal
* operation (i.e, handover) */
rrc_remove_ue(RC.nrrrc[0], ue_context_p);
}
}
static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, instance_t instance)
@@ -2019,6 +2052,7 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
if (resp->drbs_to_be_setup_length > 0) {
store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE);
e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup);
}
@@ -2118,6 +2152,67 @@ static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi,
return NULL;
}
/* \bref return F1AP QoS characteristics based on Qos flow parameters */
static f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param)
{
f1ap_qos_characteristics_t qos_char = {0};
if (qos_param->fiveQI_type == dynamic) {
qos_char.qos_type = dynamic;
qos_char.dynamic.fiveqi = qos_param->fiveQI;
qos_char.dynamic.qos_priority_level = qos_param->qos_priority;
} else {
qos_char.qos_type = non_dynamic;
qos_char.non_dynamic.fiveqi = qos_param->fiveQI;
qos_char.non_dynamic.qos_priority_level = qos_param->qos_priority;
}
return qos_char;
}
/* \brief fills a list of DRBs to be setup from a number of PDU sessions in E1
* bearer setup response */
static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc,
gNB_RRC_UE_t *UE,
const pdu_session_setup_t *pduSession,
int numPduSession,
f1ap_drb_to_be_setup_t drbs[32])
{
int nb_drb = 0;
for (int p = 0; p < numPduSession; ++p) {
rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, pduSession[p].id, false);
DevAssert(RRC_pduSession);
for (int i = 0; i < pduSession[p].numDRBSetup; i++) {
const DRB_nGRAN_setup_t *drb_config = &pduSession[p].DRBnGRanList[i];
f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb];
drb->drb_id = pduSession[p].DRBnGRanList[i].id;
drb->rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM;
drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress;
drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd;
drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId;
drb->up_ul_tnl_length = 1;
/* pass QoS info to MAC */
int nb_qos_flows = drb_config->numQosFlowSetup;
AssertFatal(nb_qos_flows > 0, "must map at least one flow to a DRB\n");
drb->drb_info.flows_to_be_setup_length = nb_qos_flows;
drb->drb_info.flows_mapped_to_drb = calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t));
AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n");
for (int j = 0; j < nb_qos_flows; j++) {
drb->drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi;
pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession);
drb->drb_info.flows_mapped_to_drb[j].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;
/* pass NSSAI info to MAC */
drb->nssai = RRC_pduSession->param.nssai;
nb_drb++;
}
}
return nb_drb;
}
/**
* @brief E1AP Bearer Context Setup Response processing on CU-CP
*/
@@ -2146,56 +2241,20 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
rrc_pdu->param.gNB_teid_N3 = e1_pdu->teId;
memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tlAddress, sizeof(uint8_t) * 4);
rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t);
// save the tunnel address for the DRBs
for (int i = 0; i < e1_pdu->numDRBSetup; i++) {
DRB_nGRAN_setup_t *drb_config = &e1_pdu->DRBnGRanList[i];
// numUpParam only relevant in F1, but not monolithic
AssertFatal(drb_config->numUpParam <= 1, "can only up to one UP param\n");
drb_t *drb = get_drb(UE, drb_config->id);
f1u_ul_gtp_update(&drb->cuup_tunnel_config, &drb_config->UpParamList[0]);
}
}
/* Instruction towards the DU for DRB configuration and tunnel creation */
f1ap_drb_to_be_setup_t drbs[32]; // maximum DRB can be 32
int nb_drb = 0;
for (int p = 0; p < resp->numPDUSessions; ++p) {
rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, resp->pduSession[p].id, false);
DevAssert(RRC_pduSession);
for (int i = 0; i < resp->pduSession[p].numDRBSetup; i++) {
DRB_nGRAN_setup_t *drb_config = &resp->pduSession[p].DRBnGRanList[i];
f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb];
drb->drb_id = resp->pduSession[p].DRBnGRanList[i].id;
drb->rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM;
drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress;
drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd;
drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId;
drb->up_ul_tnl_length = 1;
drb->nssai = RRC_pduSession->param.nssai;
/* pass QoS info to MAC */
int nb_qos_flows = drb_config->numQosFlowSetup;
AssertFatal(nb_qos_flows > 0, "must map at least one flow to a DRB\n");
drb->drb_info.flows_to_be_setup_length = nb_qos_flows;
drb->drb_info.flows_mapped_to_drb = calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t));
AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n");
for (int j = 0; j < nb_qos_flows; j++) {
drb->drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi;
pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession);
f1ap_qos_characteristics_t *qos_char = &drb->drb_info.flows_mapped_to_drb[j].qos_params.qos_characteristics;
if (in_qos_char->fiveQI_type == dynamic) {
qos_char->qos_type = dynamic;
qos_char->dynamic.fiveqi = in_qos_char->fiveQI;
qos_char->dynamic.qos_priority_level = in_qos_char->qos_priority;
} else {
qos_char->qos_type = non_dynamic;
qos_char->non_dynamic.fiveqi = in_qos_char->fiveQI;
qos_char->non_dynamic.qos_priority_level = in_qos_char->qos_priority;
}
}
/* 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;
/* pass NSSAI info to MAC */
drb->nssai = RRC_pduSession->param.nssai;
nb_drb++;
}
}
int nb_drb = fill_drb_to_be_setup_from_e1_resp(rrc, UE, resp->pduSession, resp->numPDUSessions, drbs);
if (!UE->f1_ue_context_active)
rrc_gNB_generate_UeContextSetupRequest(rrc, ue_context_p, nb_drb, drbs);
@@ -2255,20 +2314,6 @@ static void print_rrc_meas(FILE *f, const NR_MeasResults_t *measresults)
}
}
static const char *get_rrc_connection_status_text(NR_UE_STATE_t state)
{
switch (state) {
case NR_RRC_INACTIVE: return "inactive";
case NR_RRC_IDLE: return "idle";
case NR_RRC_SI_RECEIVED: return "SI-received";
case NR_RRC_CONNECTED: return "connected";
case NR_RRC_RECONFIGURED: return "reconfigured";
case NR_RRC_HO_EXECUTION: return "HO-execution";
default: AssertFatal(false, "illegal RRC state %d\n", state); return "illegal";
}
return "illegal";
}
static const char *get_pdusession_status_text(pdu_session_status_t status)
{
switch (status) {
@@ -2316,7 +2361,6 @@ static void write_rrc_stats(const gNB_RRC_INST *rrc)
time_t last_seen = now - ue_ctxt->last_seen;
fprintf(f, " last RRC activity: %ld seconds ago\n", last_seen);
fprintf(f, " RRC status %s\n", get_rrc_connection_status_text(ue_ctxt->StatusRrc));
if (ue_ctxt->nb_of_pdusessions == 0)
fprintf(f, " (no PDU sessions)\n");
@@ -2606,8 +2650,8 @@ rrc_gNB_generate_RRCRelease(
)
//-----------------------------------------------------------------------------
{
uint8_t buffer[RRC_BUF_SIZE] = {0};
int size = do_NR_RRCRelease(buffer, RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id));
uint8_t buffer[NR_RRC_BUF_SIZE] = {0};
int size = do_NR_RRCRelease(buffer, NR_RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id));
LOG_I(NR_RRC,
PROTOCOL_NR_RRC_CTXT_UE_FMT" Logical Channel DL-DCCH, Generate RRCRelease (bytes %d)\n",
@@ -2617,7 +2661,7 @@ rrc_gNB_generate_RRCRelease(
gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
const gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
f1ap_ue_context_release_cmd_t ue_context_release_cmd = {
.gNB_CU_ue_id = UE->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
@@ -2639,7 +2683,7 @@ int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib1, uint
uint32_t N; /* N: min(T,nB). total count of PF in one DRX cycle */
uint32_t Ns = 0; /* Ns: max(1,nB/T) */
uint32_t T; /* DRX cycle */
uint8_t buffer[RRC_BUF_SIZE];
uint8_t buffer[NR_RRC_BUF_SIZE];
/* get default DRX cycle from configuration */
Tc = sib1->servingCellConfigCommon->downlinkConfigCommon.pcch_Config.defaultPagingCycle;
@@ -2743,7 +2787,7 @@ void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc,
/* the callback will fill the UE context setup request and forward it */
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
f1ap_ue_context_setup_t ue_context_setup_req = {
.gNB_CU_ue_id = ue_p->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
@@ -2787,7 +2831,7 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc,
}
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
f1ap_ue_context_modif_req_t ue_context_modif_req = {
.gNB_CU_ue_id = ue_p->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
+1
View File
@@ -1180,6 +1180,7 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_
}
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
UE->an_release = true;
#ifdef E2_AGENT
signal_rrc_state_changed_to(UE, RC_SM_RRC_IDLE);
#endif
+73 -5
View File
@@ -40,12 +40,17 @@ int get_ssb_scs(const struct f1ap_served_cell_info_t *cell_info)
return cell_info->mode == F1AP_MODE_TDD ? cell_info->tdd.tbw.scs : cell_info->fdd.dl_tbw.scs;
}
static int ssb_arfcn_mtc(const NR_MeasurementTimingConfiguration_t *mtc)
{
/* format has been verified when accepting MeasurementTimingConfiguration */
NR_MeasTimingList_t *mtlist = mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming;
return mtlist->list.array[0]->frequencyAndTiming->carrierFreq;
}
int get_ssb_arfcn(const struct nr_rrc_du_container_t *du)
{
DevAssert(du != NULL && du->mtc != NULL);
/* format has been verified when accepting MeasurementTimingConfiguration */
NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming;
return mtlist->list.array[0]->frequencyAndTiming->carrierFreq;
return ssb_arfcn_mtc(du->mtc);
}
static int du_compare(const nr_rrc_du_container_t *a, const nr_rrc_du_container_t *b)
@@ -197,6 +202,58 @@ static void label_intra_frequency_neighbours(gNB_RRC_INST *rrc,
for_each(cell_neighbour_list, (void *)&ssb_arfcn, is_intra_frequency_neighbour);
}
static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_configuration, const f1ap_served_cell_info_t *cell, int ssb_arfcn)
{
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);
if (nc->nrcell_id != cell->nr_cellid)
continue;
// current cell is in the nc config, check that config matches
if (nc->physicalCellId != cell->nr_pci) {
LOG_W(NR_RRC, "Cell %ld in neighbour config: PCI mismatch (%d vs %d)\n", cell->nr_cellid, cell->nr_pci, nc->physicalCellId);
return false;
}
if (cell->tac && nc->tac != *cell->tac) {
LOG_W(NR_RRC, "Cell %ld in neighbour config: TAC mismatch (%d vs %d)\n", cell->nr_cellid, *cell->tac, nc->tac);
return false;
}
if (ssb_arfcn != nc->absoluteFrequencySSB) {
LOG_W(NR_RRC,
"Cell %ld in neighbour config: SSB ARFCN mismatch (%d vs %d)\n",
cell->nr_cellid,
ssb_arfcn,
nc->absoluteFrequencySSB);
return false;
}
if (get_ssb_scs(cell) != nc->subcarrierSpacing) {
LOG_W(NR_RRC,
"Cell %ld in neighbour config: SCS mismatch (%d vs %d)\n",
cell->nr_cellid,
get_ssb_scs(cell),
nc->subcarrierSpacing);
return false;
}
if (cell->plmn.mcc != nc->plmn.mcc || cell->plmn.mnc != nc->plmn.mnc
|| cell->plmn.mnc_digit_length != nc->plmn.mnc_digit_length) {
LOG_W(NR_RRC,
"Cell %ld in neighbour config: PLMN mismatch (%03d.%0*d vs %03d.%0*d)\n",
cell->nr_cellid,
cell->plmn.mcc,
cell->plmn.mnc_digit_length,
cell->plmn.mnc,
nc->plmn.mcc,
nc->plmn.mnc_digit_length,
nc->plmn.mnc);
return false;
}
LOG_D(NR_RRC, "Cell %ld is neighbor of cell %ld\n", cell->nr_cellid, neighbour_config->nr_cell_id);
}
}
return true;
}
void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
{
AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n");
@@ -219,10 +276,12 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
f1ap_served_cell_info_t *cell_info = &req->cell[0].info;
if (!rrc_gNB_plmn_matches(rrc, cell_info)) {
LOG_E(NR_RRC,
"PLMN mismatch: CU %d%d, DU %d%d\n",
"PLMN mismatch: CU %03d.%0*d, DU %03d%0*d\n",
rrc->configuration.mcc[0],
rrc->configuration.mnc_digit_length[0],
rrc->configuration.mnc[0],
cell_info->plmn.mcc,
cell_info->plmn.mnc_digit_length,
cell_info->plmn.mnc);
f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_plmn_not_served_by_the_gNB_CU};
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
@@ -264,6 +323,15 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
NR_MeasurementTimingConfiguration_t *mtc =
extract_mtc(cell_info->measurement_timing_config, cell_info->measurement_timing_config_len);
if (rrc->neighbour_cell_configuration
&& !valid_du_in_neighbour_configs(rrc->neighbour_cell_configuration, cell_info, ssb_arfcn_mtc(mtc))) {
LOG_E(NR_RRC, "problem with DU %ld in neighbor configuration, rejecting DU\n", req->gNB_DU_id);
f1ap_setup_failure_t fail = {.cause = F1AP_CauseMisc_unspecified};
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc);
return;
}
const f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info;
NR_MIB_t *mib = NULL;
NR_SIB1_t *sib1 = NULL;
@@ -501,7 +569,7 @@ void dump_du_info(const gNB_RRC_INST *rrc, FILE *f)
fprintf(f, "assoc_id %d", du->assoc_id);
}
const f1ap_served_cell_info_t *info = &sr->cell[0].info;
fprintf(f, ": nrCellID %ld, PCI %d\n", info->nr_cellid, info->nr_pci);
fprintf(f, ": nrCellID %ld, PCI %d, SSB ARFCN %d\n", info->nr_cellid, info->nr_pci, get_ssb_arfcn(du));
if (info->mode == F1AP_MODE_TDD) {
const f1ap_nr_frequency_info_t *fi = &info->tdd.freqinfo;
+1 -4
View File
@@ -51,7 +51,7 @@ rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id
drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id)
{
DevAssert(drb_id > 0 && drb_id < 32);
DevAssert(drb_id > 0 && drb_id <= 32);
DevAssert(ue != NULL);
return &ue->established_drbs[drb_id - 1];
@@ -96,10 +96,7 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue,
est_drb->status = DRB_ACTIVE;
est_drb->drb_id = drb_id;
est_drb->reestablishPDCP = -1;
est_drb->recoverPDCP = -1;
est_drb->cnAssociation.sdap_config.defaultDRB = true;
est_drb->defaultDRBid = drb_id;
/* SDAP Configuration */
est_drb->cnAssociation.present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config;
+6 -6
View File
@@ -479,7 +479,7 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc,
// Actions following cell selection while T311 is running
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
if (is_nr_timer_active(timers->T311)) {
if (nr_timer_is_active(&timers->T311)) {
nr_timer_stop(&timers->T311);
rrc->ra_trigger = RRC_CONNECTION_REESTABLISHMENT;
@@ -1695,7 +1695,7 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc,
void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded)
{
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
if (ra_succeeded && is_nr_timer_active(timers->T304)) {
if (ra_succeeded && nr_timer_is_active(&timers->T304)) {
// successful Random Access procedure triggered by reconfigurationWithSync
nr_timer_stop(&timers->T304);
// TODO handle the rest of procedures as described in 5.3.5.3 for when
@@ -2130,7 +2130,7 @@ static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_l
process_nsa_message(NR_UE_rrc_inst, nr_SecondaryCellGroupConfig_r15, nr_SecondaryCellGroup_buffer, nr_SecondaryCellGroup_size);
process_nsa_message(NR_UE_rrc_inst, nr_RadioBearerConfigX_r15, nr_RadioBearer_buffer, nr_RadioBearer_size);
LOG_I(NR_RRC, "Calling do_NR_RRCReconfigurationComplete. t_id %ld \n", t_id);
uint8_t buffer[RRC_BUF_SIZE];
uint8_t buffer[NR_RRC_BUF_SIZE];
size_t size = do_NR_RRCReconfigurationComplete_for_nsa(buffer, sizeof(buffer), t_id);
nsa_sendmsg_to_lte_ue(buffer, size, NR_RRC_CONFIG_COMPLETE_REQ);
break;
@@ -2138,7 +2138,7 @@ static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_l
case OAI_TUN_IFACE_NSA: {
LOG_I(NR_RRC, "We got an OAI_TUN_IFACE_NSA!!\n");
char cmd_line[RRC_BUF_SIZE];
char cmd_line[NR_RRC_BUF_SIZE];
memcpy(cmd_line, msg_buffer, sizeof(cmd_line));
LOG_D(NR_RRC, "Command line: %s\n", cmd_line);
if (background_system(cmd_line) != 0)
@@ -2218,14 +2218,14 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
}
}
if (!waitTime) {
if (is_nr_timer_active(tac->T302)) {
if (nr_timer_is_active(&tac->T302)) {
nr_timer_stop(&tac->T302);
// TODO barring alleviation as in 5.3.14.4
// not implemented
LOG_E(NR_RRC,"Go to IDLE. Barring alleviation not implemented\n");
}
}
if (is_nr_timer_active(tac->T390)) {
if (nr_timer_is_active(&tac->T390)) {
nr_timer_stop(&tac->T390);
// TODO barring alleviation as in 5.3.14.4
// not implemented
@@ -560,7 +560,7 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac,
{
if (sync_msg == IN_SYNC) {
tac->N310_cnt = 0;
if (is_nr_timer_active(tac->T310)) {
if (nr_timer_is_active(&tac->T310)) {
tac->N311_cnt++;
// Upon receiving N311 consecutive "in-sync" indications
if (tac->N311_cnt >= tac->N311_k) {
@@ -573,12 +573,12 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac,
else {
// OUT_OF_SYNC
tac->N311_cnt = 0;
if(is_nr_timer_active(tac->T300) ||
is_nr_timer_active(tac->T301) ||
is_nr_timer_active(tac->T304) ||
is_nr_timer_active(tac->T310) ||
is_nr_timer_active(tac->T311) ||
is_nr_timer_active(tac->T319))
if(nr_timer_is_active(&tac->T300) ||
nr_timer_is_active(&tac->T301) ||
nr_timer_is_active(&tac->T304) ||
nr_timer_is_active(&tac->T310) ||
nr_timer_is_active(&tac->T311) ||
nr_timer_is_active(&tac->T319))
return;
tac->N310_cnt++;
// upon receiving N310 consecutive "out-of-sync" indications
+1 -1
View File
@@ -787,7 +787,7 @@ sctp_eNB_read_from_socket(
SCTP_ERROR("sctp_recvmsg (fd %d, len %d ): %s:%d\n", sctp_cnx->sd, n, strerror(errno), errno);
sctp_itti_send_association_resp(
sctp_cnx->task_id, sctp_cnx->instance, -1,
sctp_cnx->task_id, sctp_cnx->instance, sctp_cnx->assoc_id,
sctp_cnx->cnx_id, SCTP_STATE_UNREACHABLE, 0, 0);
close(sctp_cnx->sd);